Skip to content
Merged
5 changes: 5 additions & 0 deletions .changeset/a2a-claude-beta-6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"throng-agent-claude": minor
---

Move `@col/a2a-claude` to `0.2.1-beta.6`, which adds `claude.outputFormat` — structured JSON output constrained to a caller-supplied JSON Schema. No behaviour changes for agents that do not set it; the field is absent from Throng's generated config unless a manifest asks for it.
16 changes: 16 additions & 0 deletions .changeset/claude-output-format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"throng-agent-claude": minor
---

Add `agent.output_format`, a new optional initialise key that constrains a Claude turn's output to a JSON Schema.

```jsonc
"agent": {
"platform": "claude",
"output_format": { "type": "json_schema", "schema": { /* … */ } }
}
```

Throng validates the wrapper shape only — `type` must be `json_schema` and `schema` must be an object — and returns a field-level 400 from `POST /api/initialise` when either is wrong. The schema body itself is forwarded verbatim: it is never inspected or key-transformed, so JSON Schema's own vocabulary survives intact, and an invalid schema surfaces from the SDK at turn time rather than at initialise. Omitting the key leaves the wrapper's freeform-text default in place, so no existing manifest changes behaviour.

Two operational notes for anyone enabling it. The structured result arrives as an additional `application/json` data part on the `response` artifact, with the text part still published alongside it — text-only clients are unaffected. That data part is only added when the result is a JSON object, so a schema whose top level is an array or a scalar reaches clients through the text part alone. And an unsatisfiable schema fails the turn with "Structured output retries exhausted." rather than degrading to freeform output; that message usually means a schema bug, though the SDK reports the same exhaustion when structured output is retracted by a model fallback.
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ Throng agent works best when run on a platform such as [E2B.dev](https://e2b.dev
"permission_mode": "plan", // engine-specific (claude)
"thinking": { "type": "adaptive" }, // engine-specific (claude)
"effort": "high", // engine-specific (claude)
"output_format": { // engine-specific (claude) — structured output
"type": "json_schema",
"schema": { "type": "object" }
},
"plugins": [] // engine-specific (claude)
}
}
Expand Down Expand Up @@ -139,6 +143,41 @@ it.
- **`effort`** is optional and sets the reasoning effort level: one of
`low`, `medium`, `high`, `xhigh`, `max`.

### `output_format` (claude)

Optional. Constrains the model's turn output to a JSON Schema. Omit it and the
agent returns freeform text, which is the default.

```jsonc
"output_format": {
"type": "json_schema", // the only type the SDK supports
"schema": { /* any JSON Schema object */ }
}
```

Throng validates the wrapper shape only — that `type` is `json_schema` and that
`schema` is an object. The schema body is forwarded to the SDK **verbatim**; it
is never inspected or key-transformed, so JSON Schema's own vocabulary
(`additionalProperties`, `patternProperties`, …) survives intact. A schema that
is not valid JSON Schema is reported by the SDK at turn time, not at initialise.

Two consequences worth knowing before you enable it:

- **The structured result is an additional part, not a replacement.** On success
the parsed object is published as an `application/json` data part on the
`response` artifact, and the text part is still published alongside it, first —
text-only clients are unaffected. The data part is only added when the result
is a JSON **object**: a schema whose top level is an array or a scalar produces
no data part, and such a result reaches clients through the text part alone.
- **An unsatisfiable schema fails the turn.** The SDK retries when output does
not match, and on exhaustion the turn fails with *"Structured output retries
exhausted."* It does not fall back to freeform text. A schema that no output
can satisfy — for example one whose `required` names a property that
`properties` never declares while `additionalProperties` is `false` — fails
every turn. That message usually means a schema bug, but not always: the SDK
reports the same exhaustion when structured output is retracted by a model
fallback, so rule out the schema before concluding the model is at fault.

### `credentials`, `github_token` and `user_identity`

- **`credentials`** is how the agent gets GitHub tokens in production. `git` uses
Expand Down
Loading