Commit Graph

1 Commits

  • core: surface terminal subagent errors to parent agents (#28375)
    ## Why
    
    When a subagent exhausts its retries, it emits an `Error`, but the
    generic task lifecycle then emits `TurnComplete(None)`. That completion
    used to overwrite the subagent's `Errored` status with
    `Completed(None)`, so the parent received an empty completion
    notification.
    
    This made a failed child look indistinguishable from a child that
    completed without an answer. In unattended or long-running multi-agent
    work, the root could silently continue without knowing that delegated
    work failed or how to restart it.
    
    ## Behavior
    
    Before, a terminal stream failure was reduced to an empty completion:
    
    ```text
    <subagent_notification>
    {"agent_path":"/root/worker","status":{"completed":null}}
    </subagent_notification>
    ```
    
    Now the parent receives the actual terminal error, bounded to 1,000
    tokens, together with an actionable recovery hint:
    
    ```text
    <subagent_notification>
    {
      "agent_path": "/root/worker",
      "status": {
        "errored": "stream disconnected before completion: stream closed before response.completed"
      },
      "next_action": "This agent's turn failed. If you still need this agent, use `followup_task` to give it another task."
    }
    </subagent_notification>
    ```
    
    The notification remains queue-only: it does not wake the root or replay
    the failed request. The root sees it at the next sampling boundary and
    can use `followup_task` to start a new turn for that agent.
    
    ## What changed
    
    - Added terminal-error precedence to the [agent status
    reducer](https://github.com/openai/codex/blob/e95fcfe2bb6a02f1a75650afa20048859f556511/codex-rs/core/src/agent/status.rs#L23-L34),
    so a closing `TurnComplete` cannot erase an immediately preceding
    `Errored` status.
    - Made MultiAgentV2 completion forwarding use the retained session
    status instead of re-deriving `Completed(None)` from the final event.
    - Extended the [subagent notification
    fragment](https://github.com/openai/codex/blob/e95fcfe2bb6a02f1a75650afa20048859f556511/codex-rs/core/src/context/subagent_notification.rs#L6-L60)
    with a `next_action` for terminal errors and a hard cap on model-visible
    error text.
    - Kept successful completions and interrupted turns unchanged.
    
    ## Verification
    
    - Added a status-reducer test proving that `Errored` survives the
    trailing `TurnComplete`.
    - Added an integration test that exhausts a subagent's stream retries
    and verifies the exact `agent_message` delivered to the parent,
    including the error and `followup_task` guidance.
    - Re-ran the existing successful-completion and interrupted-turn
    notification tests.