Skip to content

[Bug] V2 custom-parent → custom-child delegation needs current-dev trace #418

Closed as not planned

Description

@brunoflma

Area

V2 multi-agent delegation / routed providers

Current status

This issue originally reported that a custom-routed parent → custom-routed child V2 delegation failed on OpenCodex 2.7.39.

The original failure was:

failed to parse function arguments: missing field `message` at line 1 column 2

with no completed child result surfaced to the parent.

Subsequent testing has narrowed the problem, but has not yet reproduced the original custom-parent → custom-child failure on current dev.

The issue therefore remains open pending one current same-run trace across the relevant boundaries.

What has been established

The generic Responses bridge is not unconditionally dropping tool arguments

A 2.7.39 control capture showed ordinary structured tool calls arriving from a custom-routed provider with non-empty arguments and being emitted correctly through:

response.output_item.added
response.function_call_arguments.delta
response.function_call_arguments.done
response.output_item.done

That rules out a generic unconditional argument-loss bug in the OpenAI-compatible adapter / Responses bridge.

A later V2 delegation run completed, but on the wrong model

A later reproduction on OpenCodex 2.10.0 used:

  • native parent: gpt-5.6-luna
  • requested custom child: google-antigravity/gemini-3.6-flash
  • fork_turns: "none"
  • reasoning effort: medium

The collaboration completed and returned the expected sentinel.

However, the parent-generated spawn_agent arguments omitted the model field:

{
  "task_name": "custom_child_sentinel",
  "fork_turns": "none",
  "message": "<opaque payload>"
}

The proxy therefore received no explicit child-model override and all requests remained on the inherited native route.

No request reached the requested custom provider.

This is a different failure from the original 2.7.39 custom-parent → custom-child report.

Current OpenCodex behavior

The current branch advertises valid V2 model overrides and its collaboration guidance tells the parent to honor a user-named model.

The relevant guidance is emitted from:

src/server/responses/collaboration.ts

The remaining question is whether a current custom-routed parent:

  1. emits a correct model field when asked to use a specific custom child model; and
  2. successfully creates and completes that routed child.

Needed reproduction

Run one test against current dev with:

  • a custom-routed parent
  • a different custom-routed child
  • an explicitly named child model
  • fork_turns: "none"
  • a deterministic sentinel response

Capture all three boundaries from the same run.

Boundary 1 — provider output

Capture the provider-emitted spawn_agent call, including:

  • tool name
  • presence/value of model
  • argument byte length or redacted arguments
  • finish reason

Boundary 2 — OpenCodex translation

Capture the corresponding:

response.output_item.*
response.function_call_arguments.*

events and the route selected for the child.

Boundary 3 — Codex collaboration lifecycle

Capture whether Codex reports:

  • child creation
  • child completion
  • child failure
  • returned child result

How to interpret the result

Provider omits model

If the custom parent is explicitly told to use another model but emits no model field, the remaining defect is in the model guidance / collaboration prompt surface.

That is actionable in OpenCodex.

Provider emits the correct model, but the child does not route or complete

If the provider emits the requested model correctly and the OpenCodex bridge preserves it, but the child still fails to appear or complete, the failure is further downstream in the V2 collaboration lifecycle.

That boundary should then be investigated separately.

Relationship to #92

Related to, but not a duplicate of, #92.

#418

Custom-routed parent → custom-routed child.

Current question:

Does an explicitly requested custom child model survive spawn_agent and complete?

#92

Native parent → routed child with an upstream encrypted NEW_TASK payload.

The two issues share the V2 collaboration surface but have different failure boundaries and should remain separate.

Workaround

Until the current custom→custom path is conclusively traced:

  • use V1 delegation; or
  • inherit the parent model instead of explicitly routing the child to another custom model.

Acceptance / closure criteria

This issue can move out of needs-info when a current-dev custom-parent → custom-child run provides the three-boundary trace above.

It can be closed when either:

  • current dev successfully honors the explicit custom child model and completes the child, showing that the historical failure no longer reproduces; or
  • a deterministic current failure is isolated and fixed with regression coverage.

Checks

Activity

  1. Ingwannu commented on Jul 24, 2026

    @Ingwannu
    Owner

    Thanks for the follow-up. The earlier 2.7.33 four-boundary capture established that OpenCodex preserved the incoming/outgoing spawn_agent schema and that the custom upstream returned a function call with a zero-byte argument string. That specific capture therefore pins the loss before the Responses event bridge rather than proving an OpenCodex argument-drop defect.

    The 2.7.39 report is still useful, but it no longer reproduces the empty-arguments signature and currently only establishes an end-to-end delegation failure. Please capture, from the same 2.7.39 run, (1) the raw provider tool-call name/arguments and finish reason, (2) emitted response.output_item.* / response.function_call_arguments.* events, and (3) whether Codex emits any collaboration child-created/completed notification. A redacted trace is sufficient. We will keep this open while separating provider structured-tool emission from a Codex V2 collaboration lifecycle failure. The reliable workaround remains V1 or inheriting the parent model.

  2. brunoflma commented on Jul 24, 2026

    @brunoflma
    Author

    Thanks. I repeated the investigation on the same local 2.7.39 installation and separated the observations below. All provider-specific names, credentials, request headers, and private task content are omitted; the parent and child were custom-routed models.

    Environment

    • OpenCodex: 2.7.39
    • Codex CLI: 0.145.0
    • Node: 24.16.0
    • Windows 11 x64, build 26200
    • V2 configuration at the time of the runs: multi_agent_v2: OFF, multi_agent_mode: v2
    • The configured subagent effort cap was medium.
    • The local proxy health endpoint was healthy before and after the capture.

    Original end-to-end custom-parent -> custom-child probe

    The parent was a custom-routed model. It was instructed to create exactly one child with an explicit custom-routed model override, reasoning_effort: "medium", fork_turns: "none", and a self-contained child task whose expected output was a fixed sentinel. The parent was instructed to wait and return only that child result.

    Observed client-side result from the 2.7.39 probe:

    failed to parse function arguments: missing field `message` at line 1 column 2
    

    This occurred repeatedly during the parent turn. The corresponding local, sanitized usage records show successful custom-routed upstream HTTP responses during that interval. No child sentinel was returned and no successful child result was surfaced to the parent.

    I did not see any Codex collaboration child-created or child-completed notification in the CLI JSON output for that failing run. The CLI only showed the parent turn progressing/retrying and then the argument-validation failure above.

    Important limitation: the temporary raw-boundary instrumentation was installed after this particular failing run, so I cannot honestly claim a raw provider spawn_agent argument record for that same run.

    2.7.39 transport control capture

    I then instrumented the local 2.7.39 OpenAI-compatible adapter and Responses bridge briefly, with a local-only trace. It recorded only tool name, argument byte length, finish reason, and Responses event shape. The instrumentation was removed afterwards and the proxy was restarted cleanly.

    For ordinary structured tool calls in the same running 2.7.39 proxy, the transport path was intact:

    raw provider tool call:
      name: shell_command
      arguments byte lengths: 224, 451, 468
      finish_reason: tool_calls
    
    emitted Responses events, per call:
      response.output_item.added
        item.type: function_call
        status: in_progress
        arguments: ""                 # expected initial item state
      response.function_call_arguments.delta
        arguments: full non-empty JSON argument object
      response.function_call_arguments.done
        arguments: the same full non-empty JSON argument object
      response.output_item.done
        item.type: function_call
        status: completed
        arguments: the same full non-empty JSON argument object
    

    The actual tool arguments are deliberately not included because they contained local paths and unrelated operational commands. The byte lengths above are retained to make clear that they were non-empty. This control confirms that 2.7.39 can preserve non-empty structured-call arguments through this adapter and the Responses event bridge. It does not prove that spawn_agent takes the same path in the failing collaboration case.

    Attempts to obtain the matching spawn_agent trace

    1. I first requested the parent to use the abstract custom-routing alias previously used in the investigation. Codex declined before calling spawn_agent, reporting that the requested child model was not available on the collaboration surface. No provider tool call or lifecycle event was emitted in that attempt.
    2. I resolved the actual custom-routed model identifier exposed by the current collaboration surface and repeated the one-child probe with fork_turns: "none" and reasoning_effort: "medium".
    3. That second attempt was blocked by a client usage-limit response before any spawn_agent call was made. Therefore it produced no raw provider tool-call record, no response.output_item.* function-call events for spawn_agent, and no child-created/completed notification.

    I am including those failed capture attempts because they distinguish two separate issues:

    • the already-observed 2.7.39 end-to-end collaboration failure, where the client repeatedly reported missing field message and no child completed; and
    • a current testability limitation preventing a new, same-run raw spawn_agent capture after the instrumentation was added.

    Current conclusion

    The control trace rules out a general, unconditional argument loss in the 2.7.39 OpenAI-compatible adapter/Responses bridge: non-empty ordinary function-call arguments arrived from the custom-routed upstream and were emitted as non-empty response.function_call_arguments.delta, .done, and completed output-item arguments.

    However, the custom-parent -> custom-child V2 path remains unresolved. The original 2.7.39 end-to-end probe still produced repeated client validation failures (missing field message), no child result, and no observed collaboration child lifecycle notification. Because I could not obtain a new raw spawn_agent call after the limit was reached, I cannot yet attribute the current failure to provider structured-tool emission versus Codex V2 collaboration lifecycle handling.

    When the client usage limit clears, I will repeat exactly this controlled one-child probe with instrumentation already prepared and provide the requested three boundary records from one run:

    1. raw provider spawn_agent name, argument byte length/redacted arguments, and finish reason;
    2. every emitted response.output_item.* and response.function_call_arguments.* event for that call; and
    3. the presence or absence of Codex child-created and child-completed notifications.

    For now, I agree with the workaround recommendation: use V1 or inherit the parent model for delegated work until this V2 custom-parent -> custom-child path can be conclusively traced and fixed.

  3. Wibias commented on Jul 26, 2026

    @Wibias
    Contributor

    Cross-link

    Related to (but not the same as) #92.

    This issue (#418) #92
    Pairing custom-routed parent → custom-routed child native parent → routed child
    Failure stage Parent spawn_agent args / validation (missing field message; no child lifecycle) Child receives NEW_TASK as Fernet encrypted_content
    Mechanism Empty/invalid tool arguments (still needs a same-run spawn trace) Codex client ciphertext the proxy cannot decrypt

    Same V2 collaboration surface; different root causes. Do not close either as a duplicate of the other. #92 remains upstream-blocked; this issue stays open pending the three-boundary spawn_agent capture already requested.

  4. github-actions commented on Jul 26, 2026

    @github-actions
    Contributor

    Automated translation bookkeeping — detected language: English.

  5. lidge-jun commented on Aug 2, 2026

    @lidge-jun
    Owner

    Triage status: to assign this failure we need one same-run trace across the three boundaries — (1) what the custom provider actually emitted, (2) what the proxy translated/forwarded, (3) what the Codex lifecycle received at spawn_agent. A single repro run with those three captures lets us name the faulty layer instead of guessing.

  6. brunoflma commented on Aug 2, 2026

    @brunoflma
    Author

    Here is the same-run trace across the three boundaries, on 2.10.0. I instrumented the proxy temporarily to tee (1) the body sent upstream and (2) the raw body the provider returned, keyed per turn; (3) comes from the Codex CLI run itself. The instrumentation was reverted afterwards.

    It does not fail the way the original report described any more — and I think the layer is now nameable. The run completes and returns the sentinel. What does not happen is the child ever reaching the requested custom provider: it silently inherits the parent's model.

    Setup

    • OpenCodex 2.10.0, Codex CLI 0.146.0, Windows 11, multi_agent_mode: v2
    • Parent: gpt-5.6-luna (native passthrough)
    • Child requested in the prompt: google-antigravity/gemini-3.6-flash (custom-routed), reasoning effort medium, fork_turns none
    • Prompt: delegate exactly one subtask, child replies with exactly CUSTOM-CHILD-SENTINEL OK, parent waits and returns it verbatim, explicitly told not to do the task itself

    I could not use a custom-routed parent for this run: my AGR-* provider currently returns 401 unauthorized client detected before any request reaches the proxy, so the parent had to be a native model. Boundary 3 is therefore native-parent → custom-child rather than custom → custom. Everything below is still about the child override, which is the part that fails.

    Boundary 3 — what the Codex lifecycle did

    hook: PostToolUse
    collab: Wait
    codex
    CUSTOM-CHILD-SENTINEL OK
    tokens used 34.612       exit 0
    

    The tool ran, the collaboration surface entered Wait, and the sentinel came back. From the client's point of view this is a success.

    Boundary 1 — what the parent actually emitted

    Two spawn_agent-family calls, from response.function_call_arguments.done:

    {"task_name":"custom_child_sentinel","fork_turns":"none","message":"gAAAAAB…<248 chars, opaque>"}
    {"timeout_ms":3600000}

    There is no model field. Reproduced identically across two runs. The message is an opaque Fernet-style blob rather than the plaintext task — worth noting given the missing field \message`` / zero-byte-argument history in #290, though nothing failed on it here.

    Boundary 2 — what the proxy forwarded

    Four upstream calls, all of them:

    url: https://chatgpt.com/backend-api/codex/responses     status: 200
    

    No call to google-antigravity at any point. The child ran on the parent's inherited route. Routing did exactly what it was told — it was never told anything else.

    The interesting part is why the parent omitted model. The spawn_agent tool description carries the injected roster, and it reads:

    Available model overrides (optional; inherited parent model is preferred):
    - `AGR-OAI/gpt-5.6-sol`: Routed via opencodex → AGR-OAI (AGR-OAI). Reasoning efforts: …
    - `google-antigravity/gemini-3.6-flash`: Routed via opencodex → google-antigravity …
    - `gpt-5.6-luna`: Fast and affordable agentic coding model. …
    …
    Spawned agents inherit your current model by default. Omit `model` to use that
    preferred default; set `model` only when an explicit override is needed.
    

    So the requested model is advertised and correctly described as routed via opencodex — the roster injection works. But the same text tells the model that inheriting is preferred and to omit model. Faced with a user instruction naming a specific child model and tool guidance saying the inherited default is preferred, the parent followed the guidance.

    Where that points

    This looks like a guidance/prompt-surface issue rather than a routing one:

    • routing: fine — never asked to route the child anywhere
    • roster injection: fine — the model is listed with the right provider
    • the model parameter: available, just steered away from

    Two things that might be worth deciding separately:

    1. The wording is doing more work than intended. "inherited parent model is preferred" plus "Omit model" reads as a recommendation against overrides in general, not as a description of the default. Something like "omit model to inherit; set it whenever the task names a specific model" would leave the default intact while not discouraging an explicit request.
    2. The failure is silent. A child that was asked to run on a custom model and instead inherits the parent's produces a completed, plausible-looking result on the wrong model. There is nothing in the run output distinguishing it from a correct one — I only found it because the upstream capture showed four calls to the same host.

    I have the full per-turn captures (request bodies and raw upstream SSE). They contain conversation content and provider headers so I have not attached them, but I am happy to extract any specific frame you want, or to re-run with a different parent/child pair.

    One caveat on the original report

    My run does not reproduce "no child sentinel is returned". Either that part was fixed between 2.7.39 and 2.10.0, or it is specific to a custom-routed parent, which I cannot test until my AGR-* access is back. If you would like the custom→custom case specifically, say so and I will re-run once that clears.

  7. lidge-jun commented on Aug 2, 2026

    @lidge-jun
    Owner

    Triage: the branch now advertises valid V2 overrides and instructs the parent to honor a user-named model (src/server/responses/collaboration.ts:266), but coverage is guidance/catalog-level — no same-run custom-parent → custom-child live trace exists. Leaving open pending a live reproduction on the latest dev.

  8. lidge-jun commented on Aug 3, 2026

    @lidge-jun
    Owner

    Re-triaged against current dev. Not stale, and not a duplicate of #92 — but the newest trace attached here does not show the failure you originally reported, and that distinction matters for what to fix.

    The V2 delegation path still exists: model guidance is emitted at src/server/responses/collaboration.ts:266-275, including the "use [preferred] unless the user names another" instruction. So the code is there to examine.

    The trace from 2.10.0 completed on the inherited native model because model was omitted from the spawn arguments. That is a different failure from the custom-parent → custom-child pairing in the original report: one is guidance not producing a model argument, the other is a routed child never surfacing. They would need different fixes, and I cannot tell from here which one you are still hitting.

    What would settle it: one run on current dev with a custom parent delegating to a custom child, showing the provider-emitted spawn_agent arguments, the proxy events, and the child's lifecycle. If the provider emits no model argument at all, this is guidance and I can fix it; if it emits one and the child still never surfaces, the problem is downstream and I will trace it from there.

    The 2.7.39 version in the title is old enough that I would not want to debug against it — a current trace is worth more than anything I can reconstruct from the original.

  9. added
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    toolstool_calls, MCP, web-search / sidecar tools
    needs-infoWaiting on reporter for a concrete spec or reproduction
    on Aug 3, 2026
  10. added
    upstream-trackingBlocked on an upstream (Codex CLI/Desktop) fix; kept open for discoverability
    on Aug 4, 2026
  11. changed the title [-]V2 custom-parent to custom-child delegation still fails on 2.7.39[/-] [+][Bug] V2 custom-parent → custom-child delegation needs current-dev trace[/+] on Aug 9, 2026
  12. removed
    upstream-trackingBlocked on an upstream (Codex CLI/Desktop) fix; kept open for discoverability
    on Aug 9, 2026
  13. Wibias commented on Aug 11, 2026

    @Wibias
    Contributor

    The last response was 7 days ago. If you still encounter this problem @brunoflma feel free to open a new issue with the newest trace. Thank you.

    Closing this.

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

    bugSomething isn't workingneeds-infoWaiting on reporter for a concrete spec or reproductionproviderProvider adapters, OpenAI-compat presets, upstream API quirkstoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions