Skip to content

Commit f3bbf35

Browse files
committed
fix(codex): stabilize session binding and clean transcript replay
Resolve Codex session identity drift by separating provisional runtime session IDs from durable thread IDs and deferring initial binding until a stable ID is resolved. Normalize session/list results and matching so load/bind flows accept both raw and stable references. Improve transcript replay by filtering bootstrap wrapper prompts and extracting real user requests from known Codex wrapper formats. Update the session panel new-session action to icon-only and avoid replay noise when transitioning from unbound to newly bound sessions. Document the behavior in decisions and known issues with follow-up items for session sidebar title normalization.
1 parent 53cd842 commit f3bbf35

File tree

9 files changed

+571
-61
lines changed

9 files changed

+571
-61
lines changed

PROGRESS.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,24 @@ 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-09)
14+
## Latest Update (2026-03-11)
15+
16+
- `Post-M8` codex session identity and replay normalization completed:
17+
- 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.
18+
- 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.
19+
- normalized Codex transcript replay by filtering bootstrap user messages injected by the desktop wrapper (`AGENTS.md` / `environment_context`) and extracting the actual user request from known wrapper formats:
20+
- `[Conversation Summary] ... [Current User Input]`
21+
- `# Context from my IDE setup: ... ## My request for Codex:`
22+
- verified with real local Codex and Playwright against `http://127.0.0.1:8687/`:
23+
- `New session` now produces distinct stable Codex session ids and no longer mixes first-session messages into the second-session chat.
24+
- switching between the two replayed sessions in the Web UI now shows only the expected user/assistant pairs.
25+
- direct `session-history` API responses for the repro sessions now return cleaned transcript messages.
26+
- validation:
27+
- pass: `go test ./internal/agents/codex -run 'Test(ParseSessionTranscriptMessage|CodexShouldDeferInitialSessionBinding|NormalizeCodexSessionListResultUsesStableThreadID|CodexSessionMatchesIDAcceptsStableAndRawIDs|CodexStableSessionIDFallsBackToRawSessionID)$' -count=1`
28+
- pass: `cd internal/webui/web && npm run build`
29+
- pass: `go test ./...`
30+
31+
## Previous Update (2026-03-09)
1532

1633
- Kimi CLI ACP integration completed:
1734
- implemented `internal/agents/kimi` with one-turn ACP stdio lifecycle and fail-closed permission handling.

docs/DECISIONS.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,31 @@
3737
- ADR-033: Surface ACP plan updates as first-class SSE and Web UI state. (Accepted)
3838
- ADR-034: Source Kimi config catalogs from local config to avoid empty sessions. (Accepted)
3939
- ADR-035: Add opt-in ACP debug tracing behind `--debug`. (Accepted)
40+
- ADR-036: Persist stable Codex session ids and normalize Codex transcript replay. (Accepted)
41+
42+
## ADR-036: Persist Stable Codex Session IDs and Normalize Codex Transcript Replay
43+
44+
- Status: Accepted
45+
- Date: 2026-03-11
46+
- Context:
47+
- embedded Codex `session/new` can initially return only a provisional runtime-scoped id like `session-1`, while the durable session identity arrives later via `session/list` metadata (`_meta.threadId`).
48+
- persisting the provisional id caused fresh `New session` turns to collapse back onto the same thread session binding.
49+
- Codex transcript files also include wrapper-generated user messages for bootstrap context (`AGENTS.md`, `environment_context`) and prompt wrappers (`[Current User Input]`, IDE setup metadata), which polluted Web UI session replay.
50+
- Decision:
51+
- treat the durable Codex session id as the canonical thread binding and defer fresh-session `session_bound` persistence/emission when the only known id still matches the provisional raw runtime id.
52+
- after the first prompt completes, retry `session/list` briefly to resolve the stable id, then update in-memory client state and persisted thread `agentOptions.sessionId` with that durable id.
53+
- normalize Codex session transcript replay on the backend before returning it to the Web UI:
54+
- drop bootstrap wrapper messages injected by the desktop environment.
55+
- extract the actual user prompt from known wrapper formats such as `[Current User Input]` and `## My request for Codex:`.
56+
- Consequences:
57+
- fresh `New session` flows now bind to durable Codex session identities and no longer merge unrelated turns under one provisional raw id.
58+
- Web UI session replay shows user-visible prompts instead of provider/bootstrap scaffolding.
59+
- session list titles from provider metadata remain raw for now; only replayed message bodies are normalized.
60+
- Alternatives considered:
61+
- persist the first raw runtime id immediately and rely on later correction.
62+
- leave transcript normalization to the frontend merge logic.
63+
- Follow-up actions:
64+
- evaluate normalizing Codex `session/list` titles/previews in the backend so the session sidebar also hides wrapper-generated summary text.
4065

4166
## ADR-018: Embedded Web UI via Go embed
4267

docs/KNOWN_ISSUES.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,15 @@
195195
- Status: Open
196196
- Severity: Medium
197197
- Affects: threads that select an existing ACP `sessionId` from the Web UI/API
198-
- Symptom: after choosing an existing session, ngent resumes context through ACP `session/load`, but the center chat/history panel still shows only turns created through ngent itself; earlier provider-owned transcript is not imported into SQLite or rendered in the chat area.
199-
- Workaround: select the target session before starting new hub turns, and rely on the provider's restored context for continuity even though older messages are not shown locally.
200-
- Follow-up plan: evaluate reconstructing/importing transcript data from `session/load` replayed `session/update` events into local hub history without duplicating future turns.
198+
- Symptom: ngent now replays prior provider transcript into the center chat area when a session is selected, but that replay is still reconstructed on demand and is not imported into SQLite `turns/events`; history APIs remain source-of-truth only for hub-created turns.
199+
- Workaround: use the center chat/session replay for browsing earlier context, but rely on persisted hub history only for turns created through ngent itself.
200+
- Follow-up plan: evaluate importing selected provider transcript into local persisted history without duplicating future hub-originated turns.
201+
202+
- ID: KI-022
203+
- Title: Codex session sidebar titles can still show provider wrapper text
204+
- Status: Open
205+
- Severity: Low
206+
- Affects: Codex `session/list` entries rendered in the Web UI session sidebar
207+
- Symptom: Codex provider metadata can expose long summary-style titles/previews such as `[Conversation Summary] ... [Current User Input] ...`; replayed chat messages are normalized, but the sidebar item title itself can still look noisy.
208+
- Workaround: use the thread title or open the session to inspect the normalized chat content when the sidebar label is ambiguous.
209+
- Follow-up plan: normalize Codex `session/list` display titles in the backend, likely by preferring the first replayable user prompt over raw provider preview text when available.

0 commit comments

Comments
 (0)