Skip to main content
agent.run() returns a RunResult<TOutput> once the run completes. agent.stream() and agent.runStreamEvents() return a StreamResult<TOutput> immediately and resolve the final values lazily. Both carry the structured output, complete message history, new messages added in this run, and token usage.

Output modes

When you set outputSchema, Vibes has three strategies for requesting structured output from the model:
ModeHow it worksBest for
'tool' (default)Framework exposes a special final_result tool; model calls it to return structured dataMost providers; supports partialOutput streaming
'native'Uses the provider’s native JSON mode (e.g. OpenAI response_format)Providers with built-in JSON mode support
'prompted'Schema description is injected into the system prompt as text; model formats the responseProviders without tool or JSON mode support

Structured output with outputSchema

Define a Zod schema and the agent will parse the model’s response and return it as a typed value.
import { Agent } from "@vibesjs/sdk";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";

const Schema = z.object({
  answer: z.string(),
  confidence: z.number(),
});

const agent = new Agent<undefined, z.infer<typeof Schema>>({
  model: anthropic("claude-sonnet-4-6"),
  outputSchema: Schema,
});

const result = await agent.run("What is the capital of France?");
console.log(result.output.answer);      // "Paris"
console.log(result.output.confidence);  // 0.99
result.output is fully typed as { answer: string; confidence: number }.

Output modes

const agent = new Agent({
  model,
  outputSchema: Schema,
  outputMode: "tool",    // default - uses final_result tool
  // outputMode: "native",   // provider JSON mode
  // outputMode: "prompted", // schema in system prompt
  outputTemplate: true,  // default - injects schema description into system prompt
});
outputTemplate is a boolean, not a string. Setting outputTemplate: true (the default) tells Vibes to inject the JSON schema description into the system prompt. You cannot customize the injected text.

Union types as outputSchema

Pass an array of Zod schemas to let the model choose which one applies. This is useful for agents that can return different structured shapes depending on the task.
const AgentOutput = z.discriminatedUnion("kind", [
  z.object({ kind: z.literal("answer"), text: z.string() }),
  z.object({ kind: z.literal("clarify"), question: z.string() }),
]);

const agent = new Agent<undefined, z.infer<typeof AgentOutput>>({
  model,
  outputSchema: [
    z.object({ kind: z.literal("answer"), text: z.string() }),
    z.object({ kind: z.literal("clarify"), question: z.string() }),
  ],
});

Result validators

resultValidators are post-parse validation functions that run after Vibes parses the output. Throw an error to reject the output and trigger a retry.
const agent = new Agent<undefined, z.infer<typeof Schema>>({
  model,
  outputSchema: Schema,
  maxRetries: 3,
  resultValidators: [
    (ctx, output) => {
      if (output.confidence < 0.5) {
        throw new Error("Confidence too low - please try again.");
      }
    },
  ],
});
maxRetries controls how many times the agent retries on validation failure before throwing MaxRetriesError.

RunResult interface

agent.run() resolves to a RunResult<TOutput>:
FieldTypeDescription
outputTOutputThe structured (or string) output
messagesModelMessage[]Full conversation history including this run
newMessagesModelMessage[]Only messages added during this run
usageUsageAccumulated token usage for this run
const result = await agent.run("Summarize this document.");

console.log(result.output);       // TOutput
console.log(result.messages);     // full history
console.log(result.newMessages);  // messages from this run only
console.log(result.usage);        // { promptTokens, completionTokens, totalTokens }

StreamResult interface

agent.stream() returns a StreamResult<TOutput> immediately. Consume the async iterables first, then await the promises.
FieldTypeDescription
textStreamAsyncIterable<string>Token-by-token text stream
partialOutputAsyncIterable<TOutput>Progressive structured output (tool outputMode only)
outputPromise<TOutput>Final structured output
messagesPromise<ModelMessage[]>Full conversation history
newMessagesPromise<ModelMessage[]>Messages added during this run
usagePromise<Usage>Accumulated token usage
const stream = agent.stream("Tell me a story.");

// Stream tokens as they arrive
for await (const chunk of stream.textStream) {
  process.stdout.write(chunk);
}

// Await final values after consuming textStream
const output = await stream.output;
const messages = await stream.messages;
const newMessages = await stream.newMessages;
const usage = await stream.usage;
For progressive structured output during streaming (tool outputMode only):
for await (const partial of stream.partialOutput) {
  console.log("Partial:", partial);
}