Skip to content

fix(runtime): codex tool loop, full-trajectory events, and protocol fidelity#593

Merged
yaozheng-fang merged 1 commit into
mainfrom
fix/codex-runtime-toolloop
Jun 9, 2026
Merged

fix(runtime): codex tool loop, full-trajectory events, and protocol fidelity#593
yaozheng-fang merged 1 commit into
mainfrom
fix/codex-runtime-toolloop

Conversation

@yaozheng-fang

Copy link
Copy Markdown
Collaborator

Follow-up to #592 (the remaining codex-runtime fixes that landed on the branch after #592 was merged).

Makes Agent(runtime="codex") work for multi-step tool turns and forward the whole turn faithfully, by aligning the shim and the ADK mapping with the Codex Responses protocol and genai/ADK event shapes.

proxy.py — the Responses shim

  • Stream function_call output items (output_item.addedfunction_call_arguments.delta/.doneoutput_item.done). Previously only message/reasoning were streamed, so the model's tool call was dropped, Codex never executed it, and the turn ended at the preamble ("let me look…"). Now the tool loop runs to a real answer.
  • Backfill status="completed" on replayed assistant messages in input. On multi-step turns Codex replays a prior assistant message without status; Ark's Responses API requires it and rejects with MissingParameter: input.status, which Codex retries until it degrades to a generic "high demand" error. Reproduced (a "state your plan, then ls" prompt failed every time before; 5/5 after).

translate.py — Codex result → ADK events

Forward every Codex ThreadItem in order instead of collapsing to final_response, mapping each onto the correct genai part:

Codex thread item ADK / genai part
reasoning Part(text=…, thought=True)
commandExecution function_call(exec_command) + function_response
mcpToolCall function_call(server.tool) + function_response(result/error)
dynamicToolCall function_call(namespace.tool) + function_response(content/success)
fileChange function_call(apply_patch) + function_response(status)
webSearch function_call(web_search) + function_response
agentMessage / plan / any text-bearing item Part(text=…)
userMessage skipped (ADK already owns the user turn)

Tool-call arguments are coerced to a dict and status enums normalized to their value. Falls back to final_response so a turn is never silently empty. Previously only commandExecution was handled, so MCP/dynamic tool calls and file changes were dropped.

Verification

A multi-step turn now emits, in order: thought → text(preamble) → function_call:exec_command → function_response → thought → text(final answer), and returns the real result. ruff + pyright clean.

…idelity

Follow-up to #592. Makes the codex runtime work for multi-step tool turns and
forward the whole turn faithfully, by aligning the shim and the ADK mapping
with the Codex Responses protocol and the genai/ADK event shapes.

proxy.py (the Responses shim):
- Stream `function_call` output items (output_item.added ->
  function_call_arguments.delta/.done -> output_item.done). Previously only
  message/reasoning were streamed, so a tool call was dropped and the turn
  ended at the model's preamble.
- Backfill `status="completed"` on replayed assistant messages in `input`;
  Ark's Responses API requires it (MissingParameter: input.status) and Codex
  replays them without it on multi-step turns.

translate.py (result -> ADK events):
- Forward every Codex thread item in order instead of collapsing to
  final_response: reasoning -> thought text; commandExecution / mcpToolCall /
  dynamicToolCall / fileChange / webSearch -> function_call + function_response;
  agentMessage / plan / any text-bearing item -> text; userMessage skipped.
- Coerce tool-call arguments to a dict and normalize status enums; fall back to
  final_response so a turn is never silently empty.
@yaozheng-fang yaozheng-fang merged commit 76c02cb into main Jun 9, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants