You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: PROGRESS.md
+33-16Lines changed: 33 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,7 +11,33 @@ This file is the source of milestone progress, validation commands, and next act
11
11
12
12
-`Post-M8` ACP multi-agent readiness and maintenance.
13
13
14
-
## Latest Update (2026-03-14)
14
+
## Latest Update (2026-03-16)
15
+
16
+
-`Post-M8` ACP tool-call streaming completed:
17
+
- extended shared ACP `session/update` parsing to preserve structured `tool_call` and `tool_call_update` payloads, including `toolCallId`, status/title/kind, content blocks, locations, and raw input/output payloads.
18
+
- added first-class turn callbacks plus HTTP/SSE/history persistence for those tool-call events instead of dropping them at the provider boundary.
19
+
- updated the Web UI stream state and history reconstruction to merge tool-call events by `toolCallId` and render live/persisted tool-call cards alongside plan/reasoning/message output.
20
+
- validation:
21
+
- pass: `cd internal/webui/web && npm run build`
22
+
- pass: `go test ./...`
23
+
24
+
-`Post-M8` Web UI fresh-session reset fix completed:
25
+
- explicit `New session` now allocates a client-side fresh-session scope even when the active thread already has no persisted `sessionId`, so repeated `New session` clicks no longer reuse the same anonymous chat buffer.
26
+
- empty-session history replay now drops cancelled turns that never emitted `session_bound` and never produced visible response text, preventing stale cancelled placeholders from reappearing after reload.
- changed `POST /v1/threads/{threadId}/config-options` to validate against available config options and persist thread `agentOptions.modelId` / `agentOptions.configOverrides` without mutating the live provider.
33
+
- narrowed cached provider scope from full `agentOptions` to thread + session/fresh-session identity, so picker edits no longer evict the current session provider by themselves.
34
+
- added turn-start config sync: right before streaming a new turn, ngent compares persisted thread selections against the cached provider's current model/reasoning state and only then applies changed options.
35
+
- updated acceptance/spec/ADR docs to describe the new "persist now, apply on next turn" behavior.
36
+
- validation:
37
+
- pass: `cd internal/webui/web && npm run build`
38
+
- pass: `go test ./...`
39
+
40
+
## Previous Update (2026-03-14)
15
41
16
42
-`Post-M8` Web UI thinking tense alignment completed:
17
43
- kept the live reasoning toggle label as `Thinking` while deltas are still streaming.
@@ -20,8 +46,6 @@ This file is the source of milestone progress, validation commands, and next act
20
46
- pass: `cd internal/webui/web && npm run build`
21
47
- pass: `go test ./...`
22
48
23
-
## Previous Update (2026-03-14)
24
-
25
49
-`Post-M8` Web UI thinking markdown rendering completed:
26
50
- switched finalized `Thinking` content from escaped plain text to the same sanitized markdown renderer used by finalized assistant replies.
27
51
- kept streaming reasoning as plain text so partial markdown does not reflow while deltas are still arriving.
@@ -129,9 +153,6 @@ This file is the source of milestone progress, validation commands, and next act
129
153
-`Post-M8` codex session identity and replay normalization completed:
130
154
- fixed fresh Codex `New session` persistence so ngent no longer stores provisional runtime ids like `session-1` as the thread session binding when a durable `_meta.threadId` is not yet available.
131
155
- deferred initial `session_bound` persistence/emission for fresh Codex sessions until a stable session id can be resolved after the first prompt, then updated in-memory and persisted thread `agentOptions.sessionId` with the durable id.
132
-
- verified with real local Codex and Playwright against `http://127.0.0.1:8687/`:
133
-
-`New session` now produces distinct stable Codex session ids and no longer mixes first-session messages into the second-session chat.
134
-
- switching between the two replayed sessions in the Web UI no longer mixes first-session messages into the second-session chat.
135
156
- validation:
136
157
- pass: `go test ./internal/agents/codex -run 'Test(CodexShouldDeferInitialSessionBinding|NormalizeCodexSessionListResultUsesStableThreadID|CodexSessionMatchesIDAcceptsStableAndRawIDs|CodexStableSessionIDFallsBackToRawSessionID)$' -count=1`
137
158
@@ -540,17 +561,17 @@ This file is the source of milestone progress, validation commands, and next act
540
561
- model controls are disabled while model lists load and during streaming turns.
541
562
- executed validation:
542
563
543
-
-`Post-F9` thread session model config switched to ACP `configOptions` + immediate apply:
564
+
-`Post-F9` thread session model config switched to ACP `configOptions`:
544
565
- added thread-scoped config options APIs:
545
566
-`GET /v1/threads/{threadId}/config-options`
546
567
-`POST /v1/threads/{threadId}/config-options`
547
-
-`POST`now applies model changes through ACP `session/set_config_option` (no separate apply endpoint/action).
548
-
- provider-side config option support added across all built-in agents:
549
-
- embedded: `codex`, `claude` (in-session `session/set_config_option` on cached runtime).
550
-
- stdio: `opencode`, `qwen`, `gemini`, `kimi` (ACP handshake + `session/set_config_option` apply path, then persist selected model for next turns).
568
+
-`POST`persists selected model/config state directly into sqlite thread metadata (no separate apply endpoint/action).
569
+
- provider-side config option support added across all built-in agents so persisted thread selections can be synchronized at turn boundaries:
- model dropdown now applies immediately on selection.
574
+
- model dropdown persists immediately on selection.
554
575
- model source switched from agent-level model catalog to thread-level `configOptions` (`category=model`).
555
576
- model option descriptions are rendered under the selector in the chat header.
556
577
- thread metadata sync:
@@ -716,7 +737,6 @@ This file is the source of milestone progress, validation commands, and next act
716
737
- executed validation:
717
738
- pass: `cd internal/webui/web && npm run build`
718
739
- pass: `go test ./...`
719
-
- pass: Playwright MCP verified no `/slash-commands` request on thread open, one request after typing `/`, and normal `/` message send when the endpoint returned `[]`
720
740
721
741
- 2026-03-13: fixed Kimi slash-command loss in the ACP turn pipeline.
722
742
- root cause: real Kimi `kimi acp` emits `available_commands_update` immediately after `session/new` and before `session/prompt`, while the ngent Kimi provider had been installing its `session/update` handler too late and silently dropped that notification.
@@ -727,7 +747,6 @@ This file is the source of milestone progress, validation commands, and next act
727
747
- pass: `go test ./...`
728
748
- pass: real local ngent + Kimi test on `http://127.0.0.1:8788` confirmed `session/update.available_commands_update` was logged between `session/new` and `session/prompt`
729
749
- pass: `GET /v1/threads/{threadId}/slash-commands` returned 8 persisted Kimi commands after the first turn
730
-
- pass: Playwright MCP confirmed typing `/` in a fresh Kimi thread opened the slash-command picker with the persisted Kimi commands
731
750
732
751
- 2026-03-13: forced a backend slash-command refresh on each new `/` interaction in the Web UI.
733
752
- root cause: once a thread had already populated the client-side slash-command cache, typing `/` reused that cache and did not issue another `GET /v1/threads/{threadId}/slash-commands`, which made the real network behavior diverge from the expected "query sqlite on slash entry" flow.
@@ -782,7 +801,6 @@ This file is the source of milestone progress, validation commands, and next act
782
801
- pass: `go test ./internal/httpapi -run 'Test(ThreadSlashCommandsPersistAndLoad|ThreadSlashCommandsPersistAcrossRestart|ThreadConfigOptionsBackfillsSlashCommandsWhenCatalogAlreadyStored)$' -count=1`
783
802
- pass: real local ngent + codex test on `http://127.0.0.1:8796`
784
803
- pass: fresh Codex thread returned the 7-command slash snapshot from `GET /v1/threads/{threadId}/slash-commands` immediately after `GET /v1/threads/{threadId}/config-options`, before any turn was sent
785
-
- pass: Playwright MCP confirmed typing `/` on that fresh Codex thread opened the slash-command picker showing `/review`, `/review-branch`, `/review-commit`, `/init`, `/compact`, `/logout`, and `/mcp`
786
804
787
805
- 2026-03-13: fixed fresh-thread Qwen slash commands by probing providers on `/slash-commands` cache miss.
788
806
- root cause: a user could type `/` before the thread-opening `config-options` request finished; for Qwen that meant `GET /v1/threads/{threadId}/slash-commands` read sqlite too early and returned `[]` even though the provider emitted `available_commands_update` a moment later.
@@ -792,7 +810,6 @@ This file is the source of milestone progress, validation commands, and next act
792
810
- pass: `go test ./internal/agents/qwen ./internal/httpapi -run 'Test(StreamCapturesSlashCommandsEmittedBeforePrompt|SlashCommandsAfterConfigOptionsInit|ThreadConfigOptionsBackfillsSlashCommandsWhenCatalogAlreadyStored|ThreadSlashCommandsEndpointBackfillsMissingSnapshot)$' -count=1`
793
811
- pass: real local ngent + qwen test on `http://127.0.0.1:8798`
794
812
- pass: fresh Qwen thread returned `/bug`, `/compress`, `/init`, and `/summary` from the very first `GET /v1/threads/{threadId}/slash-commands` before any turn was sent
795
-
- pass: Playwright MCP confirmed typing `/` on that fresh Qwen thread opened the slash-command picker immediately
796
813
797
814
- 2026-03-13: unified provider-local ACP slash-command caching across the direct stdio agents.
798
815
- Kimi, Qwen, OpenCode, and Gemini all share the same underlying ACP behavior: `available_commands_update` can arrive during `session/new` in both turn streaming and config-session probes, so probing slash commands only from sqlite is not enough for fresh threads.
Copy file name to clipboardExpand all lines: docs/ACCEPTANCE.md
+29-6Lines changed: 29 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -219,7 +219,8 @@ This checklist defines executable acceptance checks for requirements 1-16.
219
219
- Expected:
220
220
- model selector data source is thread-level ACP `configOptions` (`category=model` / `id=model`).
221
221
- reasoning selector data source is thread-level ACP `configOptions` (`category=reasoning`).
222
-
- selected model changes immediately via ACP `session/set_config_option`.
222
+
- selected model/reasoning changes are persisted immediately into sqlite thread state without an extra Apply button.
223
+
- if the cached session/provider is still using older model/reasoning selections, ngent applies the diff only on the next turn, before `session/prompt` is sent.
223
224
- returned and persisted current values stay consistent:
- non-model current values are mirrored into `thread.agentOptions.configOverrides`
@@ -313,9 +314,11 @@ This checklist defines executable acceptance checks for requirements 1-16.
313
314
- first-page load on active thread selection.
314
315
-`Show more` pagination when `nextCursor` is present.
315
316
-`New session` action that clears the selected `sessionId`.
317
+
- repeated `New session` clicks while the thread is still unbound must still open a blank fresh-session view instead of reusing the prior anonymous buffer.
316
318
- selecting an existing session requests provider-owned transcript replay before the next turn.
317
319
- turn SSE emits `session_bound`, and the thread persists `agentOptions.sessionId`.
318
320
- once a thread is session-bound, subsequent prompt building no longer injects prior local turns into the provider prompt.
321
+
- cancelled turns that never emitted `session_bound` and never produced visible response text do not reappear when the user opens a newer fresh session or reloads the thread.
319
322
- Verification commands (executed 2026-03-13):
320
323
-`go test ./internal/httpapi -run 'TestThreadSessionsListEndpoint|TestTurnSessionBoundPersistsSessionIDAndSkipsContextInjection|TestNewSessionResetSkipsContextInjection' -count=1`
321
324
-`cd internal/webui/web && npm run build`
@@ -330,6 +333,11 @@ This checklist defines executable acceptance checks for requirements 1-16.
-`go run ./cmd/ngent --port 8787 --db-path /tmp/ngent-kimi-real-3.db --debug`
357
-
- Playwright MCP: created a Kimi thread in the Web UI, confirmed no `/slash-commands` request on thread open, confirmed one `/slash-commands` request after typing `/`, and confirmed `/` sent to Kimi as a normal message without freezing the page.
358
365
- Additional verification commands (executed 2026-03-13 after Kimi timing fix):
359
366
-`go test ./internal/agents/kimi -run 'TestStream(CapturesSlashCommandsEmittedBeforePrompt|WithFakeProcess|WithFakeProcessModelID)$' -count=1`
360
367
-`go run ./cmd/ngent --port 8788 --db-path /tmp/ngent-kimi-acp-trace.db --debug`
361
368
- real local Kimi thread: confirmed `GET /v1/threads/{threadId}/slash-commands` returned the 8 persisted Kimi commands after the first turn
362
-
- Playwright MCP: created a fresh Kimi thread in the Web UI and confirmed typing `/` opened the slash-command picker showing `/init`, `/compact`, `/clear`, `/yolo`, `/plan`, `/add-dir`, `/export`, and `/import`
363
369
- Additional verification commands (executed 2026-03-13 after slash-entry refresh fix):
364
370
-`cd internal/webui/web && npm run build`
365
371
-`go test ./...`
366
372
-`go run ./cmd/ngent --port 8789 --db-path /tmp/ngent-slash-refresh.db --debug`
367
-
- Playwright MCP: opened that Kimi thread, confirmed no `/slash-commands` request occurred while merely loading the thread, confirmed typing `/` triggered `GET /v1/threads/{threadId}/slash-commands`, and confirmed clearing the input and typing `/` again triggered a second request while still opening the slash-command picker
-`go test ./internal/agents/codex -run 'TestStream(CapturesSlashCommandsEmittedBeforePrompt|ReplaysCachedSlashCommandsAfterConfigOptionsInit)$' -count=1`
370
375
-`go run ./cmd/ngent --port 8793 --db-path /tmp/ngent-codex-fix.db --debug`
@@ -388,14 +393,32 @@ This checklist defines executable acceptance checks for requirements 1-16.
388
393
-`go run ./cmd/ngent --port 8796 --db-path /tmp/ngent-codex-slash-fix.db --debug`
389
394
- real local Codex thread: confirmed `GET /v1/threads/{threadId}/config-options` initialized the embedded provider and `GET /v1/threads/{threadId}/slash-commands` then returned the 7-command snapshot before any turn was sent
390
395
- sqlite check: `select agent_id, commands_json from agent_slash_commands where agent_id = 'codex';` returned the persisted codex command list
391
-
- Playwright MCP: created a fresh Codex thread, confirmed the UI loaded `config-options`, then typed `/` and observed the slash-command picker open with `/review`, `/review-branch`, `/review-commit`, `/init`, `/compact`, `/logout`, and `/mcp`
-`go test ./internal/agents/qwen ./internal/httpapi -run 'Test(StreamCapturesSlashCommandsEmittedBeforePrompt|SlashCommandsAfterConfigOptionsInit|ThreadConfigOptionsBackfillsSlashCommandsWhenCatalogAlreadyStored|ThreadSlashCommandsEndpointBackfillsMissingSnapshot)$' -count=1`
394
398
-`go run ./cmd/ngent --port 8798 --db-path /tmp/ngent-qwen-slash-fix-v2.db --debug`
395
399
- real local Qwen thread: confirmed the very first `GET /v1/threads/{threadId}/slash-commands` returned `/bug`, `/compress`, `/init`, and `/summary` before any turn was sent
396
400
- sqlite check: `select agent_id, commands_json from agent_slash_commands where agent_id = 'qwen';` returned the persisted qwen command list
397
-
- Playwright MCP: created a fresh Qwen thread, typed `/`, and observed the slash-command picker open immediately with the 4 Qwen commands
398
401
- Additional verification commands (executed 2026-03-13 after unifying direct ACP provider slash-command caches):
399
402
-`go test ./internal/agents/kimi ./internal/agents/opencode ./internal/agents/gemini ./internal/agents/qwen -run 'Test(StreamCapturesSlashCommandsEmittedBeforePrompt|SlashCommandsAfterConfigOptionsInit|WithFakeProcess|WithFakeProcessModelID)$' -count=1`
400
403
-`go test ./...`
401
404
- Kimi, OpenCode, Gemini, and Qwen now all keep the latest `available_commands_update` snapshot in the same provider-local cache across both `Stream()` and `ConfigOptions()` probes, so `/slash-commands` backfill uses one consistent source for these direct ACP agents
405
+
406
+
## Requirement 25: ACP Tool-Call Streaming and History
407
+
408
+
- Operation:
409
+
- run a turn against an ACP-backed agent that emits `tool_call` followed by `tool_call_update` for the same `toolCallId`.
410
+
- observe the SSE stream from `POST /v1/threads/{threadId}/turns`.
- open the same thread in the Web UI during streaming and again after reload/history fetch.
413
+
- Expected:
414
+
- shared ACP parsing accepts `tool_call` and `tool_call_update` without flattening them into plain text or dropping their structured payload.
415
+
- SSE emits `tool_call` / `tool_call_update` events with `turnId`, `toolCallId`, and the corresponding structured ACP fields (`status`, `content`, `locations`, `rawInput`, `rawOutput`) when present.
416
+
- turn history persists those same event types and payloads.
417
+
- the Web UI merges updates by `toolCallId`, so the same tool-call card progresses from its initial state to its updated/final state both live and after reload.
418
+
- tool-call cards remain separate from the main assistant text bubble.
419
+
- Verification commands (executed 2026-03-16):
420
+
-`go test ./internal/agents -run 'TestParseACPUpdateToolCall|TestParseACPUpdateToolCallUpdateKeepsExplicitClears' -count=1`
421
+
-`go test ./internal/agents -run 'TestNewACPNotificationHandlerRoutesToolCallsToToolCallHandler' -count=1`
422
+
-`go test ./internal/httpapi -run 'TestTurnsSSEIncludesToolCallUpdatesAndPersistsHistory' -count=1`
0 commit comments