Skip to content

Commit 9b57636

Browse files
authored
Merge pull request #24 from beyond5959/dev
Dev
2 parents cdea4c9 + 44afc98 commit 9b57636

22 files changed

+1706
-84
lines changed

PROGRESS.md

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,33 @@ This file is the source of milestone progress, validation commands, and next act
1111

1212
- `Post-M8` ACP multi-agent readiness and maintenance.
1313

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.
27+
- validation:
28+
- pass: `cd internal/webui/web && npm run build`
29+
- pass: `go test ./...`
30+
31+
- `Post-M8` deferred thread config apply completed:
32+
- 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)
1541

1642
- `Post-M8` Web UI thinking tense alignment completed:
1743
- 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
2046
- pass: `cd internal/webui/web && npm run build`
2147
- pass: `go test ./...`
2248

23-
## Previous Update (2026-03-14)
24-
2549
- `Post-M8` Web UI thinking markdown rendering completed:
2650
- switched finalized `Thinking` content from escaped plain text to the same sanitized markdown renderer used by finalized assistant replies.
2751
- 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
129153
- `Post-M8` codex session identity and replay normalization completed:
130154
- 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.
131155
- 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.
135156
- validation:
136157
- pass: `go test ./internal/agents/codex -run 'Test(CodexShouldDeferInitialSessionBinding|NormalizeCodexSessionListResultUsesStableThreadID|CodexSessionMatchesIDAcceptsStableAndRawIDs|CodexStableSessionIDFallsBackToRawSessionID)$' -count=1`
137158

@@ -540,17 +561,17 @@ This file is the source of milestone progress, validation commands, and next act
540561
- model controls are disabled while model lists load and during streaming turns.
541562
- executed validation:
542563

543-
- `Post-F9` thread session model config switched to ACP `configOptions` + immediate apply:
564+
- `Post-F9` thread session model config switched to ACP `configOptions`:
544565
- added thread-scoped config options APIs:
545566
- `GET /v1/threads/{threadId}/config-options`
546567
- `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:
570+
- embedded: `codex`, `claude` (cached runtime session sync).
571+
- stdio: `opencode`, `qwen`, `gemini`, `kimi` (per-turn ACP handshake plus persisted selection forwarding).
551572
- Web UI changes:
552573
- removed thread header `Apply` button.
553-
- model dropdown now applies immediately on selection.
574+
- model dropdown persists immediately on selection.
554575
- model source switched from agent-level model catalog to thread-level `configOptions` (`category=model`).
555576
- model option descriptions are rendered under the selector in the chat header.
556577
- thread metadata sync:
@@ -716,7 +737,6 @@ This file is the source of milestone progress, validation commands, and next act
716737
- executed validation:
717738
- pass: `cd internal/webui/web && npm run build`
718739
- 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 `[]`
720740

721741
- 2026-03-13: fixed Kimi slash-command loss in the ACP turn pipeline.
722742
- 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
727747
- pass: `go test ./...`
728748
- 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`
729749
- 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
731750

732751
- 2026-03-13: forced a backend slash-command refresh on each new `/` interaction in the Web UI.
733752
- 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
782801
- pass: `go test ./internal/httpapi -run 'Test(ThreadSlashCommandsPersistAndLoad|ThreadSlashCommandsPersistAcrossRestart|ThreadConfigOptionsBackfillsSlashCommandsWhenCatalogAlreadyStored)$' -count=1`
783802
- pass: real local ngent + codex test on `http://127.0.0.1:8796`
784803
- 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`
786804

787805
- 2026-03-13: fixed fresh-thread Qwen slash commands by probing providers on `/slash-commands` cache miss.
788806
- 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
792810
- pass: `go test ./internal/agents/qwen ./internal/httpapi -run 'Test(StreamCapturesSlashCommandsEmittedBeforePrompt|SlashCommandsAfterConfigOptionsInit|ThreadConfigOptionsBackfillsSlashCommandsWhenCatalogAlreadyStored|ThreadSlashCommandsEndpointBackfillsMissingSnapshot)$' -count=1`
793811
- pass: real local ngent + qwen test on `http://127.0.0.1:8798`
794812
- 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
796813

797814
- 2026-03-13: unified provider-local ACP slash-command caching across the direct stdio agents.
798815
- 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.

docs/ACCEPTANCE.md

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ This checklist defines executable acceptance checks for requirements 1-16.
219219
- Expected:
220220
- model selector data source is thread-level ACP `configOptions` (`category=model` / `id=model`).
221221
- 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.
223224
- returned and persisted current values stay consistent:
224225
- `configOptions.model.currentValue` == thread `agentOptions.modelId`
225226
- non-model current values are mirrored into `thread.agentOptions.configOverrides`
@@ -313,9 +314,11 @@ This checklist defines executable acceptance checks for requirements 1-16.
313314
- first-page load on active thread selection.
314315
- `Show more` pagination when `nextCursor` is present.
315316
- `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.
316318
- selecting an existing session requests provider-owned transcript replay before the next turn.
317319
- turn SSE emits `session_bound`, and the thread persists `agentOptions.sessionId`.
318320
- 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.
319322
- Verification commands (executed 2026-03-13):
320323
- `go test ./internal/httpapi -run 'TestThreadSessionsListEndpoint|TestTurnSessionBoundPersistsSessionIDAndSkipsContextInjection|TestNewSessionResetSkipsContextInjection' -count=1`
321324
- `cd internal/webui/web && npm run build`
@@ -330,6 +333,11 @@ This checklist defines executable acceptance checks for requirements 1-16.
330333
- Additional verification commands (executed 2026-03-13):
331334
- `go test ./internal/storage ./internal/httpapi -run 'Test(SessionTranscriptCacheCRUD|ThreadSessionHistoryEndpoint|ThreadSessionHistoryEndpointUsesSQLiteCacheAcrossRestart)$' -count=1`
332335
- `go test ./...`
336+
- Additional verification commands (executed 2026-03-16 after fresh-session scope reset fix):
337+
- `cd internal/webui/web && npm run build`
338+
- `go test ./...`
339+
- `go run ./cmd/ngent --port 8798 --db-path /tmp/ngent-session-bug.db --debug`
340+
- reload the page, reopen the same thread, and confirm the empty cancelled placeholder still does not reappear
333341

334342
## Requirement 24: ACP Slash Commands Cache and Composer Picker
335343

@@ -354,17 +362,14 @@ This checklist defines executable acceptance checks for requirements 1-16.
354362
- `go test ./...`
355363
- Additional verification commands (executed 2026-03-13):
356364
- `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.
358365
- Additional verification commands (executed 2026-03-13 after Kimi timing fix):
359366
- `go test ./internal/agents/kimi -run 'TestStream(CapturesSlashCommandsEmittedBeforePrompt|WithFakeProcess|WithFakeProcessModelID)$' -count=1`
360367
- `go run ./cmd/ngent --port 8788 --db-path /tmp/ngent-kimi-acp-trace.db --debug`
361368
- 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`
363369
- Additional verification commands (executed 2026-03-13 after slash-entry refresh fix):
364370
- `cd internal/webui/web && npm run build`
365371
- `go test ./...`
366372
- `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
368373
- Additional verification commands (executed 2026-03-13 after codex embedded timing fix):
369374
- `go test ./internal/agents/codex -run 'TestStream(CapturesSlashCommandsEmittedBeforePrompt|ReplaysCachedSlashCommandsAfterConfigOptionsInit)$' -count=1`
370375
- `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.
388393
- `go run ./cmd/ngent --port 8796 --db-path /tmp/ngent-codex-slash-fix.db --debug`
389394
- 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
390395
- 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`
392396
- Additional verification commands (executed 2026-03-13 after Qwen slash-command probe fallback):
393397
- `go test ./internal/agents/qwen ./internal/httpapi -run 'Test(StreamCapturesSlashCommandsEmittedBeforePrompt|SlashCommandsAfterConfigOptionsInit|ThreadConfigOptionsBackfillsSlashCommandsWhenCatalogAlreadyStored|ThreadSlashCommandsEndpointBackfillsMissingSnapshot)$' -count=1`
394398
- `go run ./cmd/ngent --port 8798 --db-path /tmp/ngent-qwen-slash-fix-v2.db --debug`
395399
- 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
396400
- 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
398401
- Additional verification commands (executed 2026-03-13 after unifying direct ACP provider slash-command caches):
399402
- `go test ./internal/agents/kimi ./internal/agents/opencode ./internal/agents/gemini ./internal/agents/qwen -run 'Test(StreamCapturesSlashCommandsEmittedBeforePrompt|SlashCommandsAfterConfigOptionsInit|WithFakeProcess|WithFakeProcessModelID)$' -count=1`
400403
- `go test ./...`
401404
- 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`.
411+
- query `GET /v1/threads/{threadId}/history?includeEvents=true`.
412+
- 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`
423+
- `cd internal/webui/web && npm run build`
424+
- `go test ./...`

0 commit comments

Comments
 (0)