feat(codex): detect turn starts so the Turn column counts codex turns - #646
Merged
Conversation
Codex sessions never set `is_turn_start`, so the TUI/CLI Turn column was
always 0 ("—") for codex while ClaudeCode and Kiro reported real counts
(turn_count is gated on msg.is_turn_start during daily/hourly/model
aggregation). The codex parser never flipped the flag — verified across all
branches and history; turn detection existed only in claudecode.rs and
kiro.rs.
Detect human turns from `event_msg` `user_message` events: set a deferred
`pending_turn_start` on CodexParseState, then mark the next
token_count-derived message (the assistant's reply, which carries the
tokens) as a turn start. System-injected messages whose body begins with
`<` (e.g. <environment_context>, <user_instructions>) are excluded as
non-human input, mirroring claudecode::is_human_turn. The flag is
`#[serde(default)]` so a pending turn survives incremental cache re-parses.
`codex exec` one-shots count too: headless but carrying a real human
prompt, so each is exactly one turn. Verified end-to-end against a real
`codex exec` session (1 user_message -> turn_count 1), including the
agent_message that interleaves between the prompt and the token_count.
Adds 4 unit tests: human turn, system-injected (xml), exec one-shot (with
interleaved agent_message), and incremental-parse continuity.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bf287bc7e8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Contributor
There was a problem hiding this comment.
2 issues found across 1 file
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
The incremental Codex parse state gained a serde(default) pending_turn_start field, but old cache files written before it existed load the field as false. If the cache boundary fell between a human user_message and the token_count line that closes that turn, re-parsing the appended chunk would start with pending_turn_start=false and silently drop the turn boundary. Bumping CACHE_SCHEMA_VERSION discards stale caches so the first run after upgrade re-parses from scratch with the field present.
codex_message_is_human_turn rejected every message whose trimmed body starts with '<', which also drops legitimate human prompts that begin with markup (asking about a <div>, pasting an XML snippet, etc.). Match the specific known injected prefixes (<environment_context>, <system-reminder>, <user_instructions>) instead, and add a unit test covering both the markup-prompt and injected-context cases.
crhan
force-pushed
the
contrib/codex-turn-detection
branch
from
May 31, 2026 07:17
acb9b50 to
058110a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Codex sessions never set
is_turn_start, so the TUI/CLI Turn column is always0(—) for codex, while ClaudeCode and Kiro report real counts.turn_countis gated onmsg.is_turn_startduring daily/hourly/model aggregation, and the codex parser never flips the flag — turn detection currently exists only inclaudecode.rsandkiro.rs.Approach
Detect human turns from
event_msguser_messageevents: set a deferredpending_turn_startonCodexParseState, then mark the next token_count-derived message (the assistant reply that carries the tokens) as a turn start. System-injected messages whose body begins with<(<environment_context>,<user_instructions>, …) are excluded as non-human input, mirroringclaudecode::is_human_turn. The flag is#[serde(default)]so a pending turn survives incremental cache re-parses.codex execone-shots count too: they are headless but carry a real human prompt, so each is exactly one turn.Verification
codex execsession: oneuser_message→turn_count = 1, including theagent_messagethat interleaves between the prompt and the token_count.agent_message), incremental-parse continuity.cargo test -p tokscale-coregreen (42 codex tests);codex.rsisclippy-clean.🤖 Generated with Claude Code
Summary by cubic
Detects human turn starts in Codex so the TUI/CLI Turn column and aggregations show correct counts. Matches ClaudeCode and Kiro, refines injected-message filtering to avoid dropping real markup prompts, and bumps the cache to keep incremental parsing accurate.
New Features
pending_turn_startfromevent_msguser_messageto the next token-bearingtoken_count.<environment_context>,<system-reminder>,<user_instructions>.codex execone-shots; an interleavedagent_messagedoesn’t break the turn.Bug Fixes
16to invalidate old caches so pending turns aren’t lost across incremental parse boundaries.Written for commit 058110a. Summary will update on new commits.