Skip to content

[Provider compatibility] persisted default.* tool names break later Codex side-chat compaction #5095

Closed

Description

@ShianMike

Client or integration

Codex App

Provider or upstream service

Command Code (OAuth) / command-code/meta-muse-spark-1.3-contributor

OpenCodex version

  • 2.58.0 when the malformed function-call items were emitted and persisted
  • 2.59.0 when replaying that history in a side chat failed

Endpoint or capability

/v1/responses, streamed tool calls, and side-chat / compaction history replay

Current behaviour

A routed Command Code Muse turn can reach Codex App with dotted function-call names that violate the Responses name schema:

{"type":"function_call","name":"default.view_image","arguments":"{}"}
{"type":"function_call","name":"default.apply_patch","arguments":"{}"}

Codex App persisted both calls in the parent task history. Each was followed by an unsupported-call output:

unsupported call: default.view_image
unsupported call: default.apply_patch

Opening a side chat from that long-running parent task and sending a trivial message triggered automatic context compaction. The retained history was then rejected before the new turn could run:

[StringParam] [input[877].name] [invalid_string] Invalid 'input[877].name':
string does not match pattern. Expected a string that matches the pattern
'^[a-zA-Z0-9_-]+$'.

The malformed calls were created while 2.58.0 was installed. OpenCodex was upgraded to 2.59.0 before the side-chat attempt, but the already-persisted history remained unusable.

Expected behaviour

OpenCodex should never emit a Responses function_call.name that violates the upstream schema.

Known provider-added default. aliases should be restored to the request-declared canonical tool/helper before the item reaches Codex App. An upgrade should also make affected histories recoverable: when a later request replays known legacy dotted aliases, OpenCodex should safely normalize them before forwarding the request upstream (while remaining fail-closed for unknown or ambiguous names).

Minimal redacted request or reproduction

1. Run Codex App through OpenCodex 2.58.0.
2. Select command-code/meta-muse-spark-1.3-contributor.
3. Ask for work that causes image inspection and/or a patch tool call.
4. Observe a persisted function_call named default.view_image or
   default.apply_patch, followed by "unsupported call".
5. Upgrade OpenCodex to 2.59.0.
6. From the same long parent task, open a side chat and send "Hi".
7. Automatic compaction/replay fails on input[N].name with the regex error.

This was observed twice in one real task: once for default.view_image and once for default.apply_patch. The parent transcript contained no other invalid function_call.name values.

Actual response or error

[StringParam] [input[877].name] [invalid_string] Invalid 'input[877].name':
string does not match pattern. Expected a string that matches the pattern
'^[a-zA-Z0-9_-]+$'.

Upstream documentation

Suggested mapping or implementation notes

Related completed fixes cover the immediate-call paths but did not prevent or recover this history-replay case:

Suggested regressions:

  1. A Command Code Muse response containing default.apply_patch or default.view_image must not leave the proxy as an invalid dotted function_call.name.
  2. Replaying a legacy input array containing those known aliases must be normalized before an OpenAI Responses or compaction request.
  3. Unknown or ambiguous dotted names must remain rejected.
  4. A Codex side chat created from the repaired history must complete compaction and accept a new user turn.

Additional context and attachments

  • Windows 11, build 26200
  • Codex App 26.915.4065.0
  • Codex runtime 0.155.0-alpha.9.2
  • OpenCodex routing chain: Codex App -> local OpenCodex proxy -> Command Code -> Muse Spark
  • No credentials, request headers, account IDs, or private prompt contents are included.

Checks

  • I searched existing provider and compatibility issues.
  • The request and response were redacted.
  • The expected behaviour is based on the upstream Responses schema and the concrete Codex side-chat requirement.

Activity

  1. added
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    toolstool_calls, MCP, web-search / sidecar tools
    on Sep 19, 2026
  2. ShianMike commented on Sep 19, 2026

    @ShianMike
    Author

    Additional long-run reproduction evidence

    The parent was not just a large transcript; it was an active goal run showing 11h 43m 13s elapsed. The screenshot also captures the cross-model boundary:

    • Parent task: commandcode-auth/meta-muse-spark... at Max effort
    • Side chat: GPT-5.6 Luna at Max effort
    • The first side-chat prompt immediately displayed Context automatically compacted and then failed at input[877].name.

    This makes the long-running context a likely trigger/reproduction condition: a short task may never force the inherited history through compaction, whereas this long task did. The invalid persisted default.* function names remain the underlying data defect; the long run appears to be what made side-chat replay encounter them.

    Long-running parent task and side-chat compaction failure
  3. lidge-jun commented on Sep 19, 2026

    @lidge-jun
    Owner

    Both halves are on dev: #5100 as 04761a1882 and #5101 as 4e45e1770f.

    The cause was not a missing mechanism. Two resolvers were answering the same question differently. undeclaredNameInItem resolves an emitted name through normalizeDeclaredToolName, which maps a default.-prefixed code-mode helper onto the declared exec (#4412) as well as a default.-prefixed bare tool (#4176) — so default.view_image under a code-mode catalog was admitted as exec. The emit-side rewrite had implemented only the bare-tool half, so it forwarded the name unchanged. The guard's own conclusion never reached your client, and Codex stored a name the upstream schema rejects.

    #5100 makes the two agree: the rewrite falls back to the same resolver the guard used, gated on the emitted name actually failing ^[a-zA-Z0-9_-]+$, so a name the upstream accepts can never be reshaped by it. A name that resolves to nothing declared is still refused by the existing guard rather than being dropped or invented — an invalid name that means nothing has to end the turn visibly instead of entering stored history. A dotted name your own catalog declared is a real tool identity and passes through byte-identical.

    #5101 is the part that matters for the conversation you already have. A stored default.view_image or default.apply_patch is repaired on the way out, at two places: the Responses passthrough before the canonical-destination split, because your failure was a side chat on a plain OpenAI model inheriting history a routed provider had damaged, and the compact endpoint, which forwards its body directly and so needs the same repair — a damaged item there refuses the compaction itself, which is the request a long task depends on to keep going.

    The recovery vocabulary is deliberately bounded to the code-mode helper spellings rather than a rule. "Strip everything before the first dot" would silently rewrite a legitimate tool name containing a dot in some other provider's vocabulary, and a replayed history item is the worst place to guess, because it names a call that already happened. A code-mode catalog never declares those helper names — they exist only as tools.<helper>(...) inside exec — so a recorded call under one of them can only have come from a provider echoing the helper. Anything outside that set is left alone and stays refused.

    Your 11h43m parent task should be usable again without any action on your side: the repair happens on the request that replays the history, so the next side chat or compaction from that task carries the corrected names. The stored items themselves are not rewritten, since OpenCodex does not own that history.

    CI was green on every leg at both exact heads, 582383769f and 23fcfc7058. No local suite was run. Thank you for the reproduction — the screenshot pairing the long parent with the immediate compaction failure is what made the trigger condition obvious.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    providerProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reportstoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions