docs: mark opencode ACP panel integration as completed in plan.md
This commit is contained in:
@@ -27,6 +27,8 @@ The frontend still uses `window.prompt`, `window.confirm`, and an absolute-posit
|
|||||||
|
|
||||||
`opencode acp` exposes the editor as an **Agent Client Protocol** server. The current `opencode` process is started in the background but the user has no way to interact with it. The next phase adds a first-class ACP client panel in the web IDE.
|
`opencode acp` exposes the editor as an **Agent Client Protocol** server. The current `opencode` process is started in the background but the user has no way to interact with it. The next phase adds a first-class ACP client panel in the web IDE.
|
||||||
|
|
||||||
|
**Status: ✅ Completed** (commits: ACP backend `feat(backend): add opencode ACP ...`, ACP frontend `feat(web): add ACP chat panel ...`, bug fix `fix(acp): parse session/update content as ContentBlock, not string`).
|
||||||
|
|
||||||
### Why
|
### Why
|
||||||
|
|
||||||
The terminal currently runs `bash` (the shell subsystem). The `opencode` process is started via the toolbar and is meant to be controlled by an ACP client — the same protocol that editors like Zed use to talk to coding agents. Without an ACP panel, the opencode process is invisible: it has a PID and a status indicator, but no way to send it prompts or read responses.
|
The terminal currently runs `bash` (the shell subsystem). The `opencode` process is started via the toolbar and is meant to be controlled by an ACP client — the same protocol that editors like Zed use to talk to coding agents. Without an ACP panel, the opencode process is invisible: it has a PID and a status indicator, but no way to send it prompts or read responses.
|
||||||
@@ -34,54 +36,46 @@ The terminal currently runs `bash` (the shell subsystem). The `opencode` process
|
|||||||
### Scope
|
### Scope
|
||||||
|
|
||||||
1. **Backend: switch the opencode process to ACP mode**
|
1. **Backend: switch the opencode process to ACP mode**
|
||||||
- Change the default `opencodeCommand` from `opencode` to `opencode acp` (or add a new `process.acpArgs` config field).
|
- Default `opencodeCommand` stays `opencode`; new `process.args` field defaults to `["acp"]` so the launched command is `opencode acp`. Configurable via `configs/config.yaml` and the `CODESPACE_OPENCODE_ARGS` env var.
|
||||||
- The `internal/process` package already captures stdout/stderr and exposes stdin via the WebSocket. ACP over stdio maps directly onto this — no transport changes needed; the same `/api/workspaces/:id/process/ws` route can be used.
|
- The `internal/process` package still captures stdout/stderr and exposes stdin via the WebSocket. ACP over stdio sits on top in the new `internal/acp` package — no transport changes to the existing process WS route.
|
||||||
- Optionally, add a thin ACP-aware layer in the service so the frontend can call high-level methods (send a prompt, cancel, get history) without speaking raw JSON-RPC.
|
|
||||||
|
|
||||||
2. **Backend: ACP-aware HTTP API**
|
2. **Backend: ACP-aware HTTP API**
|
||||||
- Add a small JSON-RPC helper that speaks the ACP protocol over the existing process WS, OR add new HTTP routes per ACP method (simpler, more debuggable).
|
- Implemented as four HTTP routes per ACP method. The frontend does not need to know JSON-RPC.
|
||||||
- For v1, prefer HTTP routes per method. The frontend does not need to know JSON-RPC.
|
- Routes:
|
||||||
- Routes (proposed):
|
- `GET /api/workspaces/:id/acp/status` — observational: `{workspaceId, ready, sessionId, running, pid, error}`. Does NOT start the process.
|
||||||
- `POST /api/workspaces/:id/acp/prompt` — body `{ content: string }`, streams or returns the agent's response.
|
- `GET /api/workspaces/:id/acp/history` — accumulated `{sessionId, messages: [{role, text, time}]}`, oldest first. In-memory only.
|
||||||
- `POST /api/workspaces/:id/acp/cancel` — cancel an in-flight prompt.
|
- `POST /api/workspaces/:id/acp/prompt` — body `{content: string}`. Returns `{sessionId, stopReason, text}`. Starts the process + session on demand (synchronous, 5-min default timeout).
|
||||||
- `GET /api/workspaces/:id/acp/history` — return past messages.
|
- `POST /api/workspaces/:id/acp/cancel` — best-effort interrupt.
|
||||||
- `GET /api/workspaces/:id/acp/status` — return agent readiness.
|
|
||||||
|
|
||||||
3. **Frontend: ACP panel**
|
3. **Frontend: ACP panel**
|
||||||
- A new `AcpPanel` component, placed next to the terminal in the bottom panel group.
|
- Implemented as `web/src/components/acp/AcpPanel.tsx` with subcomponents `MessageBubble`, `MarkdownView`, `ThinkingIndicator`. Renders markdown with code-block highlighting (react-markdown + react-syntax-highlighter Prism oneDark), with auto-scroll, error toast fade, and a "thinking…" indicator while in flight.
|
||||||
- Chat-like UI: a scrollable list of user/agent message bubbles, an input box at the bottom, a "send" button (Cmd/Ctrl+Enter), a "cancel" button while a request is in flight.
|
- Hooks: `useAcpStatus` (3s poll), `useAcpHistory` (5s poll), `useAcpPrompt` (mutation), `useAcpCancel` (mutation).
|
||||||
- Show the agent's "thinking" indicator while waiting, the response text on completion, and any tool-call invocations inline.
|
|
||||||
- Use `useAcpStatus`, `useAcpHistory`, `useAcpSend`, `useAcpCancel` hooks (mirror the existing API-hook pattern).
|
|
||||||
- Render markdown (use a small library like `react-markdown` with a code highlighter) so code blocks look right.
|
|
||||||
- On the first response, fetch history to populate the list (since ACP may already have context from the start of the process).
|
|
||||||
|
|
||||||
4. **Frontend: integration with the workspace shell**
|
4. **Frontend: integration with the workspace shell**
|
||||||
- The bottom panel group currently has `EditorPanel` on top and `TerminalPanel` on bottom (only when visible).
|
- Bottom panel converted to a tabbed area: `Terminal` / `Agent` (decided on **Tabs + Sibling tab**, not replace, not split). Tab state lives in `workspaceUiStore.bottomTab`.
|
||||||
- Add a third tab/panel for `AcpPanel` next to the terminal, or make the bottom panel a tabbed area (`Terminal` / `Agent`).
|
- `StatusBar` shows `agent: ready` / `initializing…` / `<error>` pill when the ACP session is initialized; hides when not.
|
||||||
- Status bar shows the agent status alongside the opencode running status.
|
- The existing `process/*` routes and raw process WebSocket remain untouched (the new acp routes are additive).
|
||||||
|
|
||||||
### Concrete tasks (rough, to be expanded into a full plan when we start)
|
### Concrete tasks — all done
|
||||||
|
|
||||||
1. Switch `opencodeCommand` default to `opencode acp`; document the change in `README.md`.
|
1. ✅ Switched opencode default to `opencode acp` via `process.args`.
|
||||||
2. Add `internal/acp` package: ACP JSON-RPC client, speaks stdio to the opencode process. Or use a Go ACP SDK if one exists.
|
2. ✅ Added `internal/acp` package: NDJSON transport + JSON-RPC 2.0 client (NDJSON framing with split-line buffering, request/response correlation, notification dispatch, per-workspace `Client` + `Service`).
|
||||||
3. Add `internal/api/acp_handler.go` with the four routes above.
|
3. ✅ Added `internal/api/acp_handler.go` with the four routes.
|
||||||
4. Add `web/src/lib/api/acp.ts` with the four hooks.
|
4. ✅ Added `web/src/lib/api/acp.ts` with the four hooks.
|
||||||
5. Add `web/src/components/acp/AcpPanel.tsx` and supporting subcomponents (`MessageBubble`, `PromptInput`, `ToolCallBlock`).
|
5. ✅ Added `web/src/components/acp/AcpPanel.tsx` + subcomponents.
|
||||||
6. Add `react-markdown` and a code highlighter (`react-syntax-highlighter` or `shiki`) to `web/package.json`.
|
6. ✅ Added `react-markdown` + `react-syntax-highlighter` + `remark-gfm` to `web/package.json`.
|
||||||
7. Wire the ACP panel into `WorkspaceShell.tsx` as a tabbed bottom panel.
|
7. ✅ Wired the ACP panel into `WorkspaceShell.tsx` as a tabbed bottom panel.
|
||||||
8. Document the ACP routes in `README.md`.
|
8. ✅ Documented the ACP routes in `README.md` (section + env var + example curl).
|
||||||
|
|
||||||
### Out of scope (for v1)
|
### Tests
|
||||||
|
- `internal/acp/client_test.go` covers NDJSON split-lines, request/response correlation, notification dispatch, and agent-initiated request handling for `fs/*` (real dispatch) and `terminal/*` (MethodNotFound).
|
||||||
|
- E2E smoke test against the live `opencode acp` binary: created a workspace, sent a prompt, received `text: "Hi there!"` non-empty, history has 4 messages (1 user + 3 agent chunks), 0 `invalid session/update` log entries.
|
||||||
|
|
||||||
- Streaming responses (use a single round-trip per prompt; add SSE or stream-over-WS later).
|
### Out of scope (deferred to v2)
|
||||||
- Tool-call approval UI (rely on the agent's own sandboxing for v1; the user can interrupt if it does something wrong).
|
- Streaming responses over WebSocket (v1 is single round-trip per prompt).
|
||||||
|
- Tool-call approval UI.
|
||||||
- Multiple agents / agent switching.
|
- Multiple agents / agent switching.
|
||||||
- Authentication.
|
- Authentication.
|
||||||
- Cross-workspace agent memory.
|
- Cross-workspace agent memory.
|
||||||
- ACP session persistence across opencode restarts (lose context on restart; accept this for v1).
|
- ACP session persistence across opencode restarts (history is in-memory and cleared on process restart — acceptable for v1).
|
||||||
|
- `terminal/*` agent tool calls (return `MethodNotFound -32601`; the agent will fail those tool calls gracefully).
|
||||||
### Open questions to resolve before implementation
|
|
||||||
|
|
||||||
- Does the opencode ACP server expect framing on stdio (LSP-style `Content-Length:` headers) or newline-delimited JSON? (Will check when we start.)
|
|
||||||
- Should the ACP panel replace the terminal in the bottom area, or live as a sibling tab?
|
|
||||||
- Do we want the ACP panel to share the bottom area with the terminal (tabs), or always be visible alongside it (split)?
|
|
||||||
|
|||||||
Reference in New Issue
Block a user