lukasa1993/tanstack-skills-extracted/tanstack-ai-core-structured-outputs
Claude Code and agent skill by lukasa1993/tanstack-skills-extracted
- community
Checking that the SKILL.md file is still in the repository.
Type-safe JSON schema responses from LLMs using outputSchema on chat() and useChat(). Supports Zod, ArkType, and Valibot schemas. The adapter handles provider-specific strategies transparently — never configure structured output at the provider level. Pass stream:true alongside outputSchema for incremental JSON deltas + a completed typed object via the `structured-output.complete` event. Each successfully completed structured-output run adds a typed `StructuredOutputPart` to message history. pa…
Install
npx vskill@latest install lukasa1993/tanstack-skills-extracted/tanstack-ai-core-structured-outputsSKILL.md
Structured Outputs
Dependency note: This skill builds on ai-core. Read it first for critical rules. TheuseChatpatterns below build on ai-core/chat-experience — read that for the base hook surface, then come back here for the structured-output specifics.
Setup
When outputSchema is provided, chat() returns Promise<InferSchemaType<TSchema>> instead of AsyncIterable<StreamChunk>. The result is fully typed.
Adding stream: true switches the return to StructuredOutputStream<InferSchemaType<TSchema>> — incremental JSON deltas plus a terminal validated object. See Pattern 3 below for direct iteration, Pattern 4 for the useChat shape on the client, Pattern 5 for multi-turn structured chats, and Pattern 6 for harness adapters.
Decision: which pattern fits
| Building this | Use | |
|---|---|---|
| One prompt in → one typed object out (script, server endpoint, CLI) | Pattern 1 (basic) or 2 (nested) | |
| A UI that fills in field by field as the model streams (progressive form, live card) | Pattern 4 — useChat({ outputSchema }) | |
| Direct iteration of the stream in Node or tests | Pattern 3 — async iterable | |
| Users iterate on a structured object across multiple turns (recipe builder, ticket refinement) | Pattern 5 — multi-turn structured chat | |
| Tools that gather info, then return a typed object | Combine any of the above with tools — see ai-core/tool-calling | |
| A coding agent in a sandbox inspects files, then returns a typed object | Pattern 6 — harness outputSchema |
Core Patterns
Pattern 1: Basic structured output with Zod
Pattern 2: Complex nested schemas
Pattern 3: Direct stream iteration
Pass stream: true alongside outputSchema to get an async iterable of standard streaming chunks plus a completed typed object. Use this when you're a single process end-to-end — Node script, CLI, test, or a server endpoint that responds with one JSON blob. For the in-browser progressive-UI case, jump to Pattern 4 instead.
The terminal event is a CUSTOM chunk: { type: 'CUSTOM', name: 'structured-output.complete', value: { object: T, raw: string, reasoning?: string } }. The return type of chat({ outputSchema, stream: true }) carries T through, so a plain discriminated narrow (chunk.type === 'CUSTOM' && chunk.name === 'structured-output.complete') is enough — no type guard helper.
Adapter coverage for streaming:
| Adapter | outputSchema + stream: true | |
|---|---|---|
@tanstack/ai-openai (Responses + Chat Completions) | Native combined mode (#605) — schema wired into the regular chatStream call alongside tools; engine harvests JSON, no finalization round-trip | |
@tanstack/ai-anthropic (Claude 4.5+ only) | Native combined mode (#605) — output_config.format + tools in one beta Messages call. Older Claude models fall back | |
@tanstack/ai-gemini (Gemini 3.x only) | Native combined mode (#605) — responseSchema + tools in one generateContentStream. Gemini 2.x falls back | |
@tanstack/ai-grok | Native combined mode (#605) — OpenAI Responses text.format + tools for grok-4.6, grok-4.5, grok-4.3, and grok-build-0.1 | |
@tanstack/ai-openrouter | Native single-request stream (legacy structuredOutputStream path; per-call combined-mode lookup is a follow-up) | |
@tanstack/ai-groq | Legacy structuredOutputStream only (no tools — Groq's API rejects schema + tools + stream) | |
@tanstack/ai-bedrock | Separate native structuredOutputStream finalization through Converse or an OpenAI-compatible API | |
@tanstack/ai-byteplus | Native combined mode on supported models; unsupported models emit RUN_ERROR | |
@tanstack/ai-cloudflare | Native structuredOutputStream without tools; with tools, a separate finalization call (Workers AI models answer the tool turn in prose) | |
@tanstack/ai-claude-code | Combined + event source — --json-schema on the same harness turn. Read useChat().final. See Pattern 6. | |
@tanstack/ai-codex | Combined + event source — --output-schema on the same harness turn. Read useChat().final. See Pattern 6. | |
@tanstack/ai-opencode | Combined + event source — prompt-and-parse. Read useChat().final. See Pattern 6. | |
@tanstack/ai-grok-build | Combined + event source — prompt-and-parse (ACP and streaming-json). Read useChat().final or the structured-output part. See Pattern 6. | |
@tanstack/ai-acp (acpCompatible) | Combined + event source — prompt-and-parse. Read useChat().final or the structured-output part. See Pattern 6. |
JSON mode (`json_object`). Some OpenRouter and Groq models reject strict json_schema. For those models the adapter sends json_object and adds the schema as a system prompt. The model is asked for the shape but is not held to it. A caller can force JSON mode with modelOptions (responseFormat: { type: 'json_object' } on OpenRouter, response_format on Groq and other OpenAI-base adapters). JSON mode is never combined with tools: the schema prompt goes only on the finalization call. Only await chat({ outputSchema }) with a Standard Schema validates the reply, so prefer Zod/Valibot/ArkType over a plain JSON Schema on these models.
Native-combined output vs separate finalization is signaled by the adapter's optional supportsCombinedToolsAndSchema(modelOptions) method. When it returns true, the engine wires the JSON Schema into the regular chatStream call and harvests the final-turn text — middleware sees the run through beforeModel / modelStream as usual, and the 'structuredOutput' middleware phase does not fire. When it returns false (or is omitted), the engine takes the legacy finalization path: agent loop, then a separate structuredOutput / structuredOutputStream call with 'structuredOutput' phase tagging.
Consumer code is identical across providers — always read the final object off structured-output.complete.
Pattern 4: useChat with outputSchema (progressive UI)
Pass outputSchema to useChat and you get a partial field that fills in as JSON streams in, plus a final field that snaps to the completed typed object on the terminal event. No onChunk ceremony, no manual JSON accumulation, no parsePartialJSON calls.
Server (same as Pattern 3, just behind an SSE endpoint):
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/tanstack-ai-core-structured-outputs/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/lukasa1993/tanstack-skills-extracted/tanstack-ai-core-structured-outputs)