The opencode acp binary streams agent_message_chunk notifications with
an EMPTY messageId. The backend was already correct (it groups when a
messageId is present), but the UI rendered every chunk as its own
bubble, so a single 'count 1 to 5' reply showed as 9 separate bubbles.
Backend:
- internal/acp/history.go: add MessageID to Message; new AppendOrCreate
method that finds or creates an entry by messageId and appends text
to it (preserving the original timestamp).
- internal/acp/client.go: agent_message_chunk and user_message_chunk
use AppendOrCreate.
- internal/model/acp.go: expose MessageID in the wire response.
- internal/service/acp_service.go: copy MessageID into the API DTO.
- internal/acp/client_test.go: add TestHistoryAppendOrCreateGroupsByMessageID.
Frontend:
- web/src/components/acp/groupMessages.ts: new pure helper that
coalesces consecutive same-role history entries into a single bubble
(keeps the first chunk's time + messageId).
- web/src/components/acp/AcpPanel.tsx: render coalesced messages;
auto-scroll effect now depends on coalesced so it fires as the
agent streams.
Verified via e2e: 'count from 1 to 5' now returns a single agent entry
with text '1\n2\n3\n4\n5' instead of 9 separate entries.
- terminal: on workspaceId change call terminal.clear() and
terminal.reset() so the previous workspace's scrollback is wiped
before the new shell's output appears.
- terminal: set macOptionIsMeta: false. With the default (true),
Mac Option+key sequences (e.g. Option+[ emits ESC) leak a literal
0x1b into the shell's stdin, which crashes downstream REPLs like
Python's with "invalid non-printable character U+001B".
- web: add react-markdown + remark-gfm + react-syntax-highlighter
- web: new lib/api/acp.ts (useAcpStatus/History/Prompt/Cancel)
- web: new components/acp/ (AcpPanel + MessageBubble + MarkdownView +
ThinkingIndicator). Markdown rendering with code highlighting via
Prism oneDark. Auto-scroll to bottom when near it; error toasts
fade after 5s.
- web: WorkspaceShell now renders a tabbed bottom panel (Terminal |
Agent) when the bottom panel is visible. Tab state in
workspace-ui-store.
- web: StatusBar shows agent status (ready / initializing / error)
when the ACP session is initialized.
- web: pnpm-workspace.yaml: add packages ['.'] so pnpm install works
in this workspace.
Conversation: 019f3562-9382-7e00-ad92-3162341e9274