Skip to content

feat(acp): endpoint registry + RemoteState per-agent keying (agent-consoles slice 1) - #66

Merged
brettchien merged 1 commit into
mainfrom
feat/adr49-slice1-registry
Aug 16, 2026
Merged

feat(acp): endpoint registry + RemoteState per-agent keying (agent-consoles slice 1)#66
brettchien merged 1 commit into
mainfrom
feat/adr49-slice1-registry

Conversation

@brettchien

Copy link
Copy Markdown
Contributor

What

Slice 1 of 4 for the agent-consoles ADR (#49). Generalizes Studio's single /acp connection into a registry of named endpoints and rekeys the live-connection state per agent — the foundation N agent consoles need. Backend-only; the current single management console is unchanged.

Changes

  • crates/acp-tunnel/config.rsAgentEndpoint (name + url/token/cwd + management flag) and AgentRegistry ([[agent]] in agents.toml). Explicit fields + a conn() accessor reuse RemoteConfig's validation as one source of truth (no serde(flatten) — it's order-fragile under toml serialization). from_legacy adopts a remote.toml as one management = true entry. Structural validate (unique non-empty names, ≤1 management). Fully unit-tested.
  • src-tauri/remote.rsRemote is now HashMap<name, RemoteState>; each agent console owns its task/status/reconnect. Reverse-MCP oab tools are declared only for the management endpoint (least privilege, ADR Part A) — an ordinary agent console runs chat-only. remote-status / agent-update events now carry an agent field for per-console routing. agents.toml preferred; legacy remote.toml adopted when absent. disconnect_all on teardown.
  • src-tauri/lib.rsremote_connect/remote_disconnect + agent_prompt/agent_cancel take an optional agent (None ⇒ management, so the existing UI's arg-less calls keep working). New remote_agents command lists the registry + live status for the slice-2 selector.

Back-compat

No agents.toml yet? The registry adopts the existing remote.toml as the sole management entry, and every command defaults to it. The frontend is untouched in this slice, so behaviour is identical until slice 2 adds the selector.

Testing

cargo test -p acp-tunnel green (registry parse / legacy shim / validate / round-trip). The desktop crate (src-tauri) needs GTK/glib and is compiled by the bundle-macos CI job.

Stacked slices to follow: 2 (agent console shell + per-endpoint chat), 3 (file-editor read path), 4 (write/apply behind the upstream fs/* wire).

🤖 Generated with Claude Code

…nsoles slice 1)

ADR agent-consoles Part B: generalize the single `remote.toml` connection into a
registry of named `/acp` endpoints and rekey the live-connection state per agent,
so Studio can reach N agents instead of one.

- crates/acp-tunnel/config.rs: add `AgentEndpoint` (name + url/token/cwd +
  `management` flag) and `AgentRegistry` (`[[agent]]` in agents.toml). Explicit
  fields + a `conn()` accessor reuse `RemoteConfig` validation as one source of
  truth (no serde-flatten, which is order-fragile under toml). `from_legacy`
  adopts a `remote.toml` as one `management = true` entry. Structural `validate`
  (unique non-empty names, ≤1 management). Unit-tested.
- src-tauri/remote.rs: `Remote` is now `HashMap<name, RemoteState>` — each agent
  console has its own task/status/reconnect. `oab` reverse-MCP tools are declared
  only when the endpoint is `management` (least privilege, Part A); an ordinary
  agent console runs chat-only. `remote-status` / `agent-update` events carry an
  `agent` field so the UI can route per console. `agents.toml` preferred, legacy
  `remote.toml` adopted when absent. `disconnect_all` on app teardown.
- src-tauri/lib.rs: remote_connect/disconnect + agent_prompt/cancel take an
  optional `agent` (None ⇒ management, so the current single-console UI is
  unchanged); new `remote_agents` command lists the registry + live status for
  the slice-2 selector.

Backend-only; the frontend still drives the management endpoint. Desktop crate
is built by the bundle-macos CI job (GTK libs absent locally).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@brettchien
brettchien merged commit 3774680 into main Aug 16, 2026
2 checks passed
@brettchien
brettchien deleted the feat/adr49-slice1-registry branch August 16, 2026 15:54
brettchien added a commit that referenced this pull request Aug 17, 2026
…s slice 2) (#67)

* feat(acp): per-agent endpoint registry + RemoteState keying (agent-consoles slice 1) (#66)

ADR agent-consoles Part B: generalize the single `remote.toml` connection into a
registry of named `/acp` endpoints and rekey the live-connection state per agent,
so Studio can reach N agents instead of one.

- crates/acp-tunnel/config.rs: add `AgentEndpoint` (name + url/token/cwd +
  `management` flag) and `AgentRegistry` (`[[agent]]` in agents.toml). Explicit
  fields + a `conn()` accessor reuse `RemoteConfig` validation as one source of
  truth (no serde-flatten, which is order-fragile under toml). `from_legacy`
  adopts a `remote.toml` as one `management = true` entry. Structural `validate`
  (unique non-empty names, ≤1 management). Unit-tested.
- src-tauri/remote.rs: `Remote` is now `HashMap<name, RemoteState>` — each agent
  console has its own task/status/reconnect. `oab` reverse-MCP tools are declared
  only when the endpoint is `management` (least privilege, Part A); an ordinary
  agent console runs chat-only. `remote-status` / `agent-update` events carry an
  `agent` field so the UI can route per console. `agents.toml` preferred, legacy
  `remote.toml` adopted when absent. `disconnect_all` on app teardown.
- src-tauri/lib.rs: remote_connect/disconnect + agent_prompt/cancel take an
  optional `agent` (None ⇒ management, so the current single-console UI is
  unchanged); new `remote_agents` command lists the registry + live status for
  the slice-2 selector.

Backend-only; the frontend still drives the management endpoint. Desktop crate
is built by the bundle-macos CI job (GTK libs absent locally).

Co-authored-by: Orca <orca@openab.dev>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* feat(console): reusable chat panel + agent-console shell (agent-consoles slice 2 · pt2)

Turns the chat panel into the per-endpoint primitive the ADR calls for and adds
the agent-console shell on top of it (ADR agent-consoles Parts A/C):

- chatPanel.ts: extract the management chat wiring (transcript, one-turn queue,
  streaming spinner, stop/copy) into `createChatPanel({agent, source, mock})`.
  Each panel owns its own state + DOM listeners (AbortController-scoped) and is
  keyed by endpoint name; `onChunk`/`onTurnEnd`/`setConnected` feed it events.
- main.ts: the management console now mounts this primitive. One `agent-update`
  /`remote-status` subscription routes each event to the owning panel by name
  (`chatPanels` map); the management endpoint's name is learned from the registry.
- agentConsole.ts: selector over `remote_agents` + a per-agent console that dials
  on open (`remote_connect(agent)`), tears down on close, shows read-only config,
  and mounts a chat panel bound to that agent. One console open at a time.
- render.ts: pure `agentListHtml` + `agentConsoleHeaderHtml`.
- index.html: the agents section (selector + console with its own chat region).

Read-only per ADR §6 — the file editor's write path waits on the openab `fs/*`
wire (slices 3–4). Reverse-MCP `oab` stays gated to the management binding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(console): agent selector/header render tests + agent-console styles

- render.test.ts: cover `agentListHtml` (openable vs management vs unconfigured
  rows, open-marking, escaping) and `agentConsoleHeaderHtml` (identity/target/
  status, no token leak, read-only note). 75 tests green.
- styles.css: the agents selector + open-console layout, reusing the chat-wrap
  and identity `id-field` primitives so the surfaces read as one system.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Orca <orca@openab.dev>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant