Skip to content

fix(codex-responses): cap over-long call_id instead of failing the request - #72006

Closed
Imacx-maria wants to merge 1 commit into
NousResearch:mainfrom
Imacx-maria:fix/codex-responses-call-id-cap
Closed

fix(codex-responses): cap over-long call_id instead of failing the request#72006
Imacx-maria wants to merge 1 commit into
NousResearch:mainfrom
Imacx-maria:fix/codex-responses-call-id-cap

Conversation

@Imacx-maria

Copy link
Copy Markdown

Problem

The codex app-server names MCP tool calls codex_mcp__<server>__<tool>_exec-<uuid4>. A 36-character uuid plus _exec- already leaves only 22 characters for the server and tool names, so real ids run well past the Responses API's 64-character call_id limit. Measured on a live install:

94  codex_mcp__codex_apps__google_calendar.search_events_exec-<uuid>
93  codex_mcp__codex_apps__google_calendar.create_event_exec-<uuid>
92  codex_mcp__openaiDeveloperDocs__search_openai_docs_exec-<uuid>
82  codex_mcp__hermes-tools__kanban_complete_exec-<uuid>

Replaying such a transcript over the Responses wire — a background-review fork, or any codex_app_server -> codex_responses downgrade — then dies on:

Invalid 'input[187].call_id': string too long. Expected a string with maximum
length 64, but got a string with length 71 instead.

code: string_above_max_length, a non-retryable client error, so the entire call is lost. Observed repeatedly on a live gateway: every background-review pass failed this way, meaning the runtime's self-review stage silently never ran at all. Any MCP-heavy transcript on this runtime is affected, because effectively every MCP call id exceeds the limit.

Fix

Cap instead of fail. _cap_call_id keeps a readable prefix and appends a sha256 digest of the full original id, so distinct calls cannot collide and the result is exactly 64 characters:

codex_mcp__hermes-tools__kanban_complete_exec-34a055fe-... (82)
  -> codex_mcp__hermes-tools__kanban_complete_exec-3_b8856af42f398dab (64)

It is a pure function of the input, so replays and prefix caches stay stable (AGENTS.md Pitfall #16 — deterministic IDs in tool call history). Ids already within the limit are returned untouched, leaving the ordinary call_... shape completely unaffected.

Applied inside _preflight_codex_input_items — the single choke point every request passes through — at all three write sites: function_call plus both function_call_output branches (string and multimodal array). Uniform application within one pass is what keeps a call and its output referencing the same id.

Tests

  • an over-long pair is capped and still matched (the pairing assertion is the important one)
  • the multimodal array-output branch is capped too, since it is a separate write site
  • normal call_... ids are untouched
  • the derivation is deterministic and collision-resistant for ids differing only in their last character (identical truncated prefix — only the digest can separate them)

…quest

The codex app-server names MCP tool calls
``codex_mcp__<server>__<tool>_exec-<uuid4>``. A 36-character uuid plus
``_exec-`` already leaves only 22 characters for the server and tool names, so
real ids run well past the Responses API's 64-character ``call_id`` limit.
Measured on a live install:

    94  codex_mcp__codex_apps__google_calendar.search_events_exec-<uuid>
    93  codex_mcp__codex_apps__google_calendar.create_event_exec-<uuid>
    92  codex_mcp__openaiDeveloperDocs__search_openai_docs_exec-<uuid>
    82  codex_mcp__hermes-tools__kanban_complete_exec-<uuid>

Replaying such a transcript over the Responses wire — a background-review
fork, or any codex_app_server -> codex_responses downgrade — then dies on:

    Invalid 'input[187].call_id': string too long. Expected a string with
    maximum length 64, but got a string with length 71 instead.

That is a non-retryable client error, so the entire call is lost. Observed
repeatedly on a live gateway: every background-review pass failed this way,
meaning the runtime's self-review stage silently never ran.

Cap instead of fail. ``_cap_call_id`` keeps a readable prefix and appends a
sha256 digest of the FULL original id, so distinct calls cannot collide and
the result is exactly 64 characters. It is a pure function of the input, so
replays and prefix caches stay stable (AGENTS.md Pitfall NousResearch#16 — deterministic
IDs in tool call history). Ids already within the limit are returned
untouched, leaving the ordinary ``call_...`` shape unaffected.

Applied inside ``_preflight_codex_input_items``, the single choke point every
request passes through, at all three write sites — function_call plus both
function_call_output branches (string and multimodal array). Uniform
application in one pass is what keeps a call and its output referencing the
same id; the tests assert that pairing explicitly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tF9BacnKsd4w7KXmFeKP6
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/openai OpenAI / Codex Responses API tool/mcp MCP client and OAuth P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Jul 26, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #49224: both hash-clamp oversized replayed call_id values in agent/codex_responses_adapter.py before the Responses request. #49224 is the earlier broader patch and also sanitizes invalid replayed function names.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused regression coverage. This is an automated hermes-sweeper review; current main already implements the requested bounded, deterministic replay IDs.

  • e45f2b39e291a44991a6cb65c3fde9baa11f24e2 (fix(codex): clamp oversized Responses call_id so MCP tools don't brick sessions (#73492)) is an ancestor of current main.
  • agent/codex_responses_adapter.py:195-214 bounds oversized IDs with a deterministic SHA-256-derived call_... surrogate while preserving short IDs.
  • agent/codex_responses_adapter.py:572 and :615 apply that same mapping to both function_call and function_call_output emission paths.
  • tests/agent/test_codex_responses_adapter.py:88-118 already verifies an oversized MCP-shaped call/output pair remains bounded and matched.

The member triage note correctly identified this as duplicate work; the current-main implementation now provides the requested behavior and regression coverage.

@teknium1 teknium1 closed this Jul 30, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists provider/openai OpenAI / Codex Responses API sweeper:implemented-on-main Sweeper: behavior already present on current main tool/mcp MCP client and OAuth type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants