5.3 KiB
Agent Note: Product subagents expose minimal actionable diagnostics
Status: implemented
English | 中文
Problem
The Claude Code and Codex providers receive structured failures from independently versioned product runtimes. Mirroring every member of those upstream error unions into model-visible diagnostics makes each runtime upgrade expand the Provider contract even when the parent agent would take the same next action for several categories.
Raw SDK errors, app-server payloads, stderr, commands, paths, task content, environment values, and credentials cannot replace the structured mapping because they cross the product process boundary without a stable safety guarantee. The parent still needs enough information to distinguish a product limit, access restriction, service or transport problem, invalid result, and managed process failure.
Decision
Each product Provider derives a small action category from the current operation and safe structured product facts. The existing SubagentResult.diagnostic string remains the only public representation: consumers display it but do not parse it, and the shared subagent result boundary continues to enforce the complete 4096-byte UTF-8 limit.
Claude Code maps Agent SDK results into five categories:
| Category | Safe input |
|---|---|
limit |
Turn, budget, or structured-output retry limits |
product-error |
A general SDK execution failure |
invalid-result |
An error-marked or blank success, or no terminal result |
process |
The managed CLI exits before a terminal result |
unknown |
Startup, teardown, unrecognized SDK values, or failures without a more specific safe fact |
The diagnostic also retains the derived query-start, query-run, process, or teardown stage and independently observed exit code and signal. A contributing permission decision follows the failure line. Successful completion and local cancellation expose no failure diagnostic, and original SDK text remains only on the internal cause chain and in Host observation.
Codex currently retains the version-pinned categories documented by the structured failure-facts decision. The two providers may adopt the minimal mapping independently because neither shares a public error enum or asks a consumer to branch on category text.
Ownership and lifecycle
| Fact or operation | Owner | Result |
|---|---|---|
| Product error interpretation | Official product runtime | The Provider consumes only structured facts exposed by its pinned integration |
| Action category and stage | One product Provider run | Derived at the failure site and discarded after result settlement |
| Exit code and signal | dsh-subprocess handle |
Displayed independently when observed, without inferring missing values |
| Permission decision | Product Provider permission callbacks or protocol | Appended only when it contributed to the failed run |
| Diagnostic delivery and byte limit | dsh-subagent and its foreground or Job consumers |
One bounded optional string remains separate from assistant output |
Verification
Claude Code package tests cover every coarse category, all four stages, unknown structured values, permission ordering, raw-text exclusion, success and cancellation omission, concurrent-run isolation, and independent exit code and signal fields. The real Agent SDK 0.3.241 and Claude Code 2.1.241 fixture produces an actual max-turns limit, process failure, permission denial, strict final answer, cancellation, and whole-tree quiescence. Loader and keyless product compositions continue to expose static tools without a diagnostic parser or model-visible category input.
Alternatives considered
Preserve every upstream enum member. Several members lead to the same parent action, while the display-only consumer gains no behavior from their exact names. Keeping them would make routine product upgrades redefine a larger Harness-facing promise.
Return raw product text or classify general stderr. Free-form text can contain sensitive task and environment data and has no stable versioned meaning. Only structured product facts, Provider stage, permission decisions, and managed process outcomes qualify as input.
Add a shared structured error type. The products version their failures independently, and current consumers only present a bounded string. A shared enum would move product release churn into the provider-neutral seam without a consumer that needs it.
Retry or fall back based on the category. The Provider owns one one-shot run and has no retry authority, fallback model, persistent product session, or recovery state. The category informs the parent; it does not start another product action.
Consequences
Claude Code upgrades no longer require a model-visible promise for every SDK error subtype. Parents still distinguish a limit, general product failure, invalid result, managed process exit, and unknown failure while retaining stage, permission, and process facts.
The diagnostic remains safe display text rather than a recovery protocol. This change adds no raw error forwarding, fallback model, automatic retry, product session persistence, public structured result field, or dynamic provider and model selection.