feat(codex): republish todo_list revisions as they are ticked off - #473
Open
declan-scale wants to merge 2 commits into
Open
feat(codex): republish todo_list revisions as they are ticked off#473declan-scale wants to merge 2 commits into
declan-scale wants to merge 2 commits into
Conversation
Codex does not reopen its plan: one `todo_list` item is opened at the start of a turn and revised in place through `item.updated`, with `item.completed` only arriving at the very end. The tap dropped those updates, so a consumer saw the plan exactly twice — as first written (nothing done) and then, at end of turn, fully finished. Forward each revision as a `ToolResponseContent` under the item's existing `tool_call_id`. Consumers that key responses by call id (the GenAI Ops Hub chat does) now render the checklist filling in as the turn runs, and the last response received is still the final state. Scoped to `todo_list` via `_PROGRESSIVE_TOOL_ITEMS`: the other tool item types carry no intermediate state worth acting on, and republishing `command_execution` output on every chunk would be pure noise. Updates for an item that was never opened are ignored — there is no request for them to answer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
declan-scale
force-pushed
the
declan-scale/codex-todo-list-updates
branch
from
July 28, 2026 14:08
078bfad to
da3b575
Compare
CI lint has been red on `next` since c67e177 added this file: - ruff I001: typing import block not sorted per the repo's isort config - pyright reportPrivateImportUsage: `tracer` is not re-exported from `ddtrace`, so it must be imported from `ddtrace.trace` The `except ImportError` guard still covers ddtrace being absent, and `ddtrace.trace.tracer` exists in the pinned ddtrace 4.10.1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
What
Codex does not reopen its plan. One
todo_listitem is opened at the start of a turn and revised in place throughitem.updated, withitem.completedonly arriving at the very end. The tap dropped those updates, so a consumer saw the plan exactly twice:Real trace from the golden agent (
item_1), request vs response of the same call:Nothing in between, though the agent ticked them off over ~7 minutes.
This forwards each revision as a
ToolResponseContentunder the item's existingtool_call_id. Consumers that key responses by call id (the GenAI Ops Hub chat does) now render the checklist filling in as the turn runs, and the last response received is still the final state.Scope
_PROGRESSIVE_TOOL_ITEMSis{"todo_list"}only. The other tool item types carry no intermediate state worth acting on, and republishingcommand_executionoutput on every chunk would be pure noise. Updates for an item that was never opened are ignored — there is no request for them to answer.tool_call_countstill counts the call once, not once per revision.Testing
pytest tests/lib/adk/test_codex_sync.py— 55 pass, 4 new (TestTodoListUpdates: republish per revision, call counted once, orphan update ignored, other tool items unaffected)pytest tests/lib/core/harness/test_harness_codex_sync.py— 9 pass./scripts/lint— ruff + pyright cleanPaired change
The GenAI Ops Hub side of this is scaleapi/scaleapi#153721's follow-up, which maps every codex tool name onto a real chat block. It already takes the newest response per call id, so it picks these up with no further change.
🤖 Generated with Claude Code
Greptile Summary
This PR fixes a gap in the Codex event-stream parser where
todo_listchecklist revisions were silently dropped between the initial open and final completion, meaning consumers only ever saw the plan at its two extremes. Eachitem.updatedfor atodo_listitem is now forwarded as aToolResponseContentunder the sametool_call_id, letting consumers render the checklist filling in progressively during a turn._codex_sync.py: Adds a_PROGRESSIVE_TOOL_ITEMSfrozenset ({"todo_list"}) and a newitem.updatedbranch in_handle_itemthat emits an intermediateStreamTaskMessageFull(ToolResponseContent)for every revision, guarded byitem_id in self._tool_openso orphan updates (no precedingitem.started) are silently ignored.tool_call_countis incremented only onitem.started, preserving the existing count semantics.obs_ids.py: Updates theddtracetracer import path fromddtracetoddtrace.traceto match the newerddtraceAPI; the existingImportErrorcatch ensures graceful degradation on older installs.TestTodoListUpdatescover progressive republish, single-count invariant, orphan-update guard, and the negative case confirming other tool types remain unaffected.Confidence Score: 5/5
Safe to merge — the change is additive and well-tested, with clear guards against the orphan-update edge case.
The new
item.updatedpath is additive: it only activates fortodo_listitems that already have an openitem.started, and the guard is unit-tested. Theitem.completedhandler is unchanged and still emits the definitive final response. Theobs_ids.pychange degrades gracefully on olderddtraceinstalls. All four new tests pass and cover the meaningful edge cases.Files Needing Attention: No files require special attention.
Important Files Changed
item.updatedforwarding fortodo_listtool items as intermediateToolResponseContentunder the sametool_call_id; guard on_tool_openprevents dangling responses for orphan updates. Logic is correct and well-isolated.ddtracetracer import fromddtracetoddtrace.traceto match newer API;ImportErrorcatch ensures graceful fallback on older installs. Import order resorting is cosmetic.Reviews (3): Last reviewed commit: "fix(tracing): satisfy ruff and pyright o..." | Re-trigger Greptile