Repository navigation
[EPIC-V][LOU-V4] Structured output: createAgent({ output: zodSchema }) yields a typed, validated result.object - #90
Merged
Conversation
…) yields a typed, validated result.object
- ExecuteOptions.output / createAgent({ output }): the system prompt gets an
"## Output format" block (schema as JSON Schema via the ai SDK's zodSchema),
and every model call carries GenerateOptions.responseFormat
({ type: 'json', schema }), which the ai-SDK providers map to a JSON-mode
experimental_output that leaves prompt and text untouched.
- The final reply is parsed (code fences tolerated) and validated; an invalid
reply gets one repair step (a user message listing the issues, counted
against maxSteps); still invalid -> finishReason 'output-invalid',
no object, outputError { message, issues }.
- result.object is typed z.output<schema> for createAgent() agents
(SimpleAgent / AgentRun / ExecutionResult gain a defaulted type param);
run.done gains an optional, additive `object` field.
- toolArgsValidation exports parseWithIssues()/formatIssues() so tool args
and output share the zod issue formatting.
- Docs: docs/structured-output.md, api-overview, streaming, README, CHANGELOG,
regenerated llms files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bY29ibQgv3MDdjAbUT4YR
# Conflicts: # CHANGELOG.md
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.
What
createAgent({ output: zodSchema })andExecuteOptions.output: the agent's final reply must be a JSON object that matches the schema.send(),run.resultandagent.approvals.resolve()resolve with it asresult.object. ForcreateAgent()agents it is typedz.output<typeof schema>:SimpleAgent<TObject>,AgentRun<TObject>andExecutionResult<TObject>gain a type parameter that defaults tounknown.result.textkeeps the raw JSON.## Output formatblock with the schema rendered as JSON Schema by theaiSDK'szodSchema().aiis a required peer dependency that the executor already imports at runtime, so no dependency is added.GenerateOptions.responseFormat: { type: 'json', schema? }hint.aiSdkProvidermaps it toexperimental_output, a smallOutputthat turns on JSON mode. It sends the schema only to models that support structured outputs, asOutput.object()does, and leaves the prompt and reply text unchanged. Providers without a JSON mode ignore the hint.[output-invalid] … N issues (path: message)goes to the model. The repair step counts as a step and respectsmaxSteps. If the reply is still invalid, the run resolves with the newfinishReason: 'output-invalid', noobject, andoutputError: { message, issues }. Tool calls still work before the final answer.run.donegains an optionalobjectfield. docs/streaming.md allows new optional fields without changingv, so the schema version stays 1.toolArgsValidation.tsnow exportsparseWithIssues()andformatIssues(), so tool arguments and output use the same zod issue formatting.'output-invalid'added to the finish reasons.run.donerow mentionsobject.Why
Parity gap with eve's output schemas (Epic V). Callers who want machine-readable results currently have to parse and validate free text themselves.
Acceptance criteria
createAgent({ output })andExecuteOptions.outputmake the final reply a JSON object validated by the schema.send()resolves withresult.objecttyped asz.output<typeof schema>(type test), andresult.textkeeps the raw JSON.agent.stream():run.resultandrun.donecarryobject. The field is additive and allowed by the docs/streaming.md versioning rules.responseFormathint, whichaiSdkProvidermaps to theaiv4 JSON mode (experimental_output).maxSteps). If that fails too, the run ends with'output-invalid',object: undefinedandoutputError. Tool calls still work before the final answer.mockModel:'output-invalid'maxStepsbudgetstream()path, valid and invalidoutputunchangedresult.objectHow verified
npx tsc --noEmit: no errorsnpm run lint: 0 errors, 422 warnings. These are all on lines that existed before; none of the touched files has a new warning.npm run test:types: 6 files, 26 tests passed, no type errorsnpx vitest run: 147 files passed; 2109 tests passed, 3 skipped. Run afternpm run build, which the dist-dependent tests need.npm run build && npm run build --workspace=packages/create-loushy-agent: successnpm run docs:verify-snippets -- --skip-build: all 105 snippets type-check against src/; 6 also run cleanlynpm run docs:llms:check: exit 0npm run test:coverage && npm run fallow: both exit 0. Fallow reports no dead code. Its one duplication note (OpenAIProvider/AnthropicProvider, 15 lines) was already on main and is in files this PR does not touch.Notes:
output:childOptions()in delegation.ts picks fields explicitly, and that file is out of scope.session()wiring was not edited. Session turns get the same runtime validation because they shareexecuteOptions, butsession.send()stays untyped (object: unknown).🤖 Generated with Claude Code
https://claude.ai/code/session_016bY29ibQgv3MDdjAbUT4YR
Generated by Claude Code