Repository navigation
[Provider compatibility] persisted default.* tool names break later Codex side-chat compaction #5095
Description
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
- Responses compaction and retained tool interactions: https://developers.openai.com/api/docs/guides/compaction
- Function calling: https://developers.openai.com/api/docs/guides/function-calling
Suggested mapping or implementation notes
Related completed fixes cover the immediate-call paths but did not prevent or recover this history-replay case:
- [bug] muse-spark via opencode-go: undeclared client tool "default.apply_patch" kills subagent turns #3402 / fix(proxy): accept dotted ns.name tool echo alongside ns__name #3403 — dotted
default.apply_patchaliases - [bug] routed provider prefixes bare Codex tool with
default.:default.view_imagerejected as undeclared #4176 / fix(responses): normalize invented default. namespace back to the declared bare tool #4264 — provider-addeddefault.prefix for a declared bare tool - [bug] code-mode exec catalog rejects routed default.view_image as undeclared #4412 / fix(responses): execute code-mode view_image through unified exec #4475 — code-mode
default.view_imagecompatibility
Suggested regressions:
- A Command Code Muse response containing
default.apply_patchordefault.view_imagemust not leave the proxy as an invalid dottedfunction_call.name. - Replaying a legacy input array containing those known aliases must be normalized before an OpenAI Responses or compaction request.
- Unknown or ambiguous dotted names must remain rejected.
- 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
ShianMike commentedon Sep 19, 2026
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:
commandcode-auth/meta-muse-spark...at Max effortGPT-5.6 Lunaat Max effortinput[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.fix(responses): emit the tool name the undeclared-tool guard authoriz…
fix(responses): emit the tool name the undeclared-tool guard authoriz…
fix(responses): repair legacy dotted call names on replay (#5095)
fix(responses): repair legacy dotted call names on replay (#5095) (#5101
lidge-jun commentedon Sep 19, 2026
Both halves are on
dev: #5100 as04761a1882and #5101 as4e45e1770f.The cause was not a missing mechanism. Two resolvers were answering the same question differently.
undeclaredNameInItemresolves an emitted name throughnormalizeDeclaredToolName, which maps adefault.-prefixed code-mode helper onto the declaredexec(#4412) as well as adefault.-prefixed bare tool (#4176) — sodefault.view_imageunder a code-mode catalog was admitted asexec. 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_imageordefault.apply_patchis 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>(...)insideexec— 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,
582383769fand23fcfc7058. 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.fix(guard): apply emitted call-shape repair in the native passthrough…