fix(summarizer): set excludeTurns on ephemeral Codex thread/fork - #166
Conversation
…a#158) codex-cli 0.150 rejects an ephemeral thread/fork against a paginated (i.e. reasonably large) thread with: thread/fork failed: {"code":-32600,"message":"ephemeral paginated thread/fork requires `excludeTurns: true`"} summarizeConversation() catches this and silently falls back to transcript-text summarization, so the Codex-native path stops being used for exactly the conversations it matters most for: the long ones. The only trace is a 'Codex summarizer unavailable, falling back to transcript text' log line. excludeTurns governs pagination of the fork response, not the fork's context/semantics — the forked thread still carries full session history with the flag set, so summaries after this change remain accurate. Fixes obra#158.
obra
left a comment
There was a problem hiding this comment.
Verified rather than taken on trust. Clean — merging.
The test genuinely catches the bug. Removed excludeTurns: true from src/summarizer.ts (i.e. reinstated the original defect) and the fork test went red on exactly the right assertion; restored, green again. That's the property that matters, and it isn't automatic — the assertion had to be added inside the fake server's thread/fork handler to see it.
dist and src agree, and a fresh npm run build produces no diff against the committed dist/summarizer.js, so the built artifact isn't carrying anything the source doesn't.
Full suite: 62 files, 348 tests, zero failures.
Why this is worth landing beyond the one flag
The failure mode is the interesting part: summarizeConversation() catches the -32600 and silently falls back to transcript-text summarization. So the Codex-native path quietly stopped being used for exactly the conversations it matters most for — the long ones — with the only trace a log line nobody reads. A degradation that announces itself as success is worse than a crash, and this repo has a few of those.
One thing to note for later, not blocking
The fix is right and the reasoning in the description is right (excludeTurns governs pagination of the fork response, not the fork's context). But nothing in the repo pins the codex-cli version this behaviour depends on, so if a future codex-cli changes the requirement again, the same silent fallback returns and the same log line is the only signal. Worth considering whether that fallback should be loud, or at least counted, rather than swallowed. Separate change.
Also worth knowing: this repo now has CI (landed today — build, typecheck, tests across Node 22 and 24, and it runs on fork PRs). Your future PRs here will get real checks. This one predates it and shows none; I ran the equivalent locally.
Summary
thread/forkrejects the summarizer's ephemeral fork for any paginated (i.e. reasonably large) Codex thread on codex-cli 0.150+:summarizeConversation()catches this and silently falls back to transcript-text summarization, so the Codex-native path stops being used for exactly the conversations it matters most for: the long ones. The only trace is aCodex summarizer unavailable, falling back to transcript text: ...log line — nothing surfaces as an error to the user.Root cause
The ephemeral
thread/forkrequest insummarizeConversation()didn't setexcludeTurns: true. Newer codex-cli requires it for paginated (large) threads. The flag governs pagination of the fork response, not the fork's context — the forked thread still carries full session history with the flag set, so summaries produced after this change remain accurate.Fix
Add
excludeTurns: trueto the ephemeral fork params insrc/summarizer.ts:const fork = await send('thread/fork', { threadId: command.sessionId, ephemeral: true, + excludeTurns: true, sandbox: 'read-only', approvalPolicy: 'never', ...(command.model ? { model: command.model } : {}), });dist/summarizer.jsregenerated vianpm run buildand committed alongsidesrc/summarizer.ts.Test plan
thread/forkmock assertion intest/summarizer-options.test.tsto requireexcludeTurns === true, matching the existingephemeral/sandboxchecksnpx vitest run test/summarizer-options.test.ts— 29/29 passnpm test(full suite) — 348/348 pass, 62 test files, no regressionsnpm run build— cleanFixes #158.