feat(claude): expose agent.output_format for structured output - #11
Merged
Conversation
Design for a new optional agent.output_format manifest key that maps onto a2a-claude's claude.outputFormat (added in 0.2.1-beta.6), letting callers constrain a Claude turn's output to a JSON Schema. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01My4JH7AAyLhe9Hb5626Gdv
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01My4JH7AAyLhe9Hb5626Gdv
Final review caught operator-facing claims that nothing in the SDK or wrapper substantiates: - Dropped the assertion that the text part carries the JSON payload under a structured format. `result` and `structured_output` are independent fields on SDKResultSuccess and nothing documents one replacing the other; the wrapper's own README says text-only clients are unaffected. Docs now state only what is established. - Noted that the application/json data part is conditional: the wrapper appends it only for a non-null, non-array object, so an array or scalar top-level schema produces no data part. - Softened the retry-exhaustion diagnosis — the same message is reported when structured output is retracted by a model fallback. - initialise returns 202, not 200. Also restores coverage for an omitted `schema` key, the likeliest real manifest error, which an earlier review round removed on the incorrect grounds that it was unreachable through JSON. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01My4JH7AAyLhe9Hb5626Gdv
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an optional
agent.output_formatkey to thePOST /api/initialisemanifest, letting a caller constrain a Claude turn's output to a JSON Schema. Maps ontoclaude.outputFormat, which a2a-wrapper#33 added and@col/a2a-claude@0.2.1-beta.6ships.Spec:
docs/superpowers/specs/2026-08-18-claude-output-format-design.mdPlan:
docs/superpowers/plans/2026-08-18-claude-output-format.mdWhat it looks like
Omitting the key leaves the wrapper's freeform-text default in place, so no existing manifest changes behaviour.
Validation contract
Throng validates the wrapper shape only:
type !== "json_schema"agent.output_formatschemamissing / not an object / an arrayagent.output_format.schemaoutputFormatleft unsetThe
schemabody itself is not inspected. Throng doesn't own JSON Schema validity — an invalid schema surfaces from the SDK at turn time, not at initialise.This duplicates a shape check a2a-claude also performs, deliberately. The wrapper validates inside
initialize(), so a bad value there fails the boot after initialise has already returned 202. Validating here turns that into a field-level 400 at the API boundary, consistent with howpermission_mode,model,effortandthinkingare already handled. The accepted cost is that a future wrapper release adding a second output-format type would be blocked by our whitelist until updated here too.Verbatim schema pass-through
Only the outer key is renamed (
output_format→outputFormat). Unlikethinking.budget_tokens→budgetTokens, nothing rewrites keys insideschema— they're JSON Schema's own vocabulary (additionalProperties,patternProperties, …) and renaming them would corrupt the schema. Tests at both the validation and mapping layers pin this with a nested schema that survives deep-equal.Operational notes
application/jsondata part on theresponseartifact; the text part still publishes first, so text-only clients are unaffected. The data part is only appended when the result is a JSON object — an array or scalar top-level schema produces no data part.One claim was deliberately not made: whether the text part carries the JSON payload instead of prose under a structured format.
resultandstructured_outputare independent fields onSDKResultSuccessand nothing in the SDK or wrapper documents one replacing the other, so the docs assert only what's established. Worth confirming with a live turn before anyone relies on the text part's contents.Verification
npm run build,npm run typecheck,npm test -- --forceall pass from the repo root — 7/7 turbo tasks, 364 tests (249 core, 87 claude, 22 codex, 6 agent).Out of scope
No default schema — Throng ships none, the manifest producer decides. No changes to
packages/core,throng-agent, orthrong-agent-codex. No other unexposedClaudeConfigfield wired up.🤖 Generated with Claude Code
https://claude.ai/code/session_01My4JH7AAyLhe9Hb5626Gdv