Skip to content

feat: use native Output.object() for structured output#18450

Open
potlee wants to merge 2 commits intoanomalyco:devfrom
potlee:native-structured-output
Open

feat: use native Output.object() for structured output#18450
potlee wants to merge 2 commits intoanomalyco:devfrom
potlee:native-structured-output

Conversation

@potlee
Copy link

@potlee potlee commented Mar 20, 2026

Issue for this PR

Closes #

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Switches structured output from a custom StructuredOutput tool to the AI SDK's native Output.object() via experimental_output.

Previously, when format.type === "json_schema" was set, the code would:

  1. Inject a synthetic StructuredOutput tool
  2. Add a system prompt telling the model to call that tool
  3. Force toolChoice: "required" so the model had to call it
  4. Capture the tool args as the structured output

This was fragile — it consumed a tool slot, required prompt engineering to make the model cooperate, and bypassed the provider's native JSON mode support.

Now it passes experimental_output: Output.object({ schema }) to streamText(), which sets responseFormat: { type: "json", schema } on the underlying provider call. Providers that support native JSON schema will use their built-in mechanisms, AI SDK handles the fallback to using a tool when structured output is not supported. The model outputs JSON text directly, the processor parses it, and tools still work alongside structured output for multi-step workflows.

Net removal of ~300 lines of tool scaffolding, system prompt injection, and manual plumbing.

How did you verify your code works?

  • bun typecheck passes with 0 errors (from packages/opencode)
  • bun test test/session/structured-output.test.ts — 13 pass, 0 fail
  • bun test test/session/structured-output-integration.test.ts — 1 pass, 4 skipped (require API key), 0 fail

Screenshots / recordings

N/A — no UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

…ool-based approach

Use the AI SDK's experimental_output with Output.object() to leverage
providers' native JSON mode (response_format) instead of a synthetic
StructuredOutput tool with forced toolChoice.
@potlee potlee marked this pull request as ready for review March 20, 2026 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant