For the complete documentation index, see llms.txt. This page is also available as Markdown.

Vercel AI SDK

Record and replay AI SDK 7 ToolLoopAgent and generateText calls with the Kitaru Vercel AI SDK adapter.

@zenml-io/kitaru-vercel-ai adds Kitaru recording and replay to the Vercel AI SDK 7 ToolLoopAgent and generateText APIs. Use createKitaruToolLoopAgent(...) for an AI SDK Agent object or createKitaruGenerateText(...) for the direct function API. Both return native AI SDK results.

Version 0.1.0 is the initial stable package release. Kitaru records non-streaming Agent generate() and direct generateText calls. Agent stream() remains available outside replay as a native, recording-free passthrough; standalone streamText is not wrapped.

Install

Use Node 22.22 or later in the Node 22 release line. Install the adapter with AI SDK 7 and the provider package used by your agent. This OpenAI example uses the versions verified in the repository:

pnpm add @zenml-io/kitaru-vercel-ai@0.1.0 ai@7.0.65 @ai-sdk/openai@4.0.20 zod@4.4.3

The adapter includes @zenml-io/kitaru, the framework-neutral TypeScript SDK, as a dependency.

Record an Agent

Pass native ToolLoopAgent settings and Kitaru configuration to createKitaruToolLoopAgent:

import { openai } from "@ai-sdk/openai";
import { createKitaruToolLoopAgent } from "@zenml-io/kitaru-vercel-ai";
import { tool } from "ai";
import { z } from "zod";

const agentId = process.env.KITARU_AGENT_ID;
if (!agentId) {
  throw new Error("KITARU_AGENT_ID is required");
}

const agent = createKitaruToolLoopAgent(
  {
    id: "support-agent",
    instructions: "Investigate the request before answering.",
    model: openai("gpt-5-nano"),
    tools: {
      lookupOrder: tool({
        description: "Look up an order",
        inputSchema: z.object({ orderId: z.string() }),
        execute: async ({ orderId }) => findOrder(orderId),
      }),
    },
  },
  { agentId },
);

const result = await agent.generate({
  prompt: "Why is order ord-123 delayed?",
});

console.log(result.text);

The returned object implements AI SDK's public Agent interface. version, id, typed tools, all four Agent generic parameters, call-option validation, prepareCall, callbacks, runtime context, structured output, retries, timeouts, abort signals, and the native result object remain available. Each overlapping generate() invocation gets an independent Kitaru recorder and tool state.

AI SDK's Agent interface also requires stream(). During ordinary execution, the adapter delegates that method directly to a native ToolLoopAgent without starting a Kitaru session. This preserves compatibility with native consumers, but Kitaru does not record the stream. When KITARU_REPLAY_ID is set, stream() rejects before provider or tool execution because streaming replay is unsupported.

Record a direct generation

Register an agent in Kitaru, then pass its ID to the adapter:

Configure the adapter subprocess with KITARU_API_URL and either KITARU_API_TOKEN or KITARU_API_KEY. You can also pass apiUrl and apiKey to createKitaruGenerateText. A separate Node management process can use createKitaruClient() to reuse kitaru login without exporting a token.

The direct wrapper calls AI SDK's public generateText, callbacks, and local tool execute functions. It does not reproduce the AI SDK generation loop. Native options, callbacks, generic types, and return behavior therefore remain available. The direct wrapper sets maxRetries to 0 so Kitaru records one provider attempt rather than hiding retries inside a node. The Agent API preserves native retry settings.

Each run creates a Kitaru session. It records one llm_call node per model step and one tool_call node per local tool execution, including model identity, provider, tokens, tool arguments, tool results, failures, and optional estimated cost. The adapter deliberately records null for LLM-node inputs rather than copying provider request data. Session inputs retain the effective prompt or messages, and the completed session summary retains the generated text and other bounded result metadata.

Structured output

AI SDK structured output works through the native output option. Read it from the native result.output property:

When AI SDK produces the object, Kitaru includes it in the session summary. If generation ends without a usable structured object, such as a length stop, the adapter still completes the session and omits the object from the summary.

Replay

The same program records ordinary runs and executes replays. When a worker starts the registered command, it injects the task-scoped Kitaru connection, task ID, replay ID, and baseline inputs. The adapter resolves an Agent's prepareCall first, then:

  1. replaces the caller's prompt or messages with the replay input;

  2. applies supported prompt, instruction, model-setting, and allowlisted model overrides;

  3. runs the native Agent or generateText call again; and

  4. answers each local tool call according to the replay's tool policy.

Model replacement is opt-in. Set allowedReplayModels and provide resolveModel to map each allowed Kitaru model ID to an AI SDK LanguageModel:

Pass replayOptions as the Kitaru options to either factory. Unsafe or unallowlisted overrides fail before a model call begins.

Tool policies

Replay supports local executable tools under these policies:

Policy
Replay behavior

history

Looks up the recorded result by tool name and arguments. The original execute function is not called on a hit.

static

Returns the configured matching value. The original execute function is not called.

passthrough

Calls the original execute function with the current input and AI SDK execution options.

The llm tool policy is not supported. A replay that configures it fails with a tool-policy error.

History compatibility is guaranteed only when both the baseline and replay use this Vercel AI SDK adapter. Frameworks can validate, default, or serialize the same logical arguments differently, so history recorded through another adapter is not a compatibility promise. If a baseline calls the same tool more than once with identical arguments, replay consumes those calls in baseline order. Agent- and cohort-version-scoped history use the newest completed matching call.

A matched recorded failure throws ToolPolicyError with the stored error text and aborts generateText unless application code catches it. Kitaru does not recreate the original exception class or convert the failure into a native tool-error result.

Static and history results are validated against the tool's outputSchema when one is declared. A schema created with jsonSchema() must include its optional runtime validate callback for replay to enforce it; otherwise replay fails closed. A configured error_result is an error sentinel rather than a successful tool value, so it bypasses output-schema validation and records a failed tool node.

Baseline execution retains AI SDK tool concurrency. During replay, the adapter runs local tools one at a time in model-output order. It registers the complete ordered set before local execution starts, so an earlier policy failure prevents later queued tools from producing side effects.

Run replays with a worker

Compile the TypeScript entrypoint and register its Node command. Registration creates the agent and its first version; retrieve the new ID, then register a replay-ready version that stores that ID in its run environment. The TypeScript adapter requires the script to pass agentId explicitly.

Start a worker with access to the compiled program, its Node dependencies, model credentials, and any systems used by passthrough tools:

The program should call the wrapped generateText function normally. It does not need a replay branch. See Workers for the task lifecycle and Replay for creating and running a replay.

Supported boundary

Version 0.1.0 supports:

  • AI SDK >=7.0.60 <8.0.0;

  • non-streaming ToolLoopAgent.generate() with the public AI SDK Agent type;

  • native, recording-free Agent stream() passthrough outside replay;

  • non-streaming generateText;

  • prompt strings and message arrays;

  • local tools with an execute function;

  • native structured output;

  • history, static, and passthrough replay policies; and

  • bounded prompt, instruction, model-setting, and allowlisted model replacement during replay.

It does not record streaming generation and does not wrap standalone streamText. Agent stream() rejects when replay is active. Provider-executed tools, dynamic tools, tool approval, sandboxed replay, per-step overrides through prepareStep, async-iterable tools during replay, and the llm tool policy are unsupported in replay. Async-iterable local tools remain native during baseline recording, but cannot be replayed.

Manual approval is a two-call workflow in AI SDK, but Kitaru cannot persist a waiting Agent run without server and worker changes. When baseline generate() returns an unresolved manual approval request, the adapter returns the native result unchanged and marks the Kitaru session failed with manual_approval_continuation_unsupported. Automatic approval decisions complete normally. Agent replay rejects approval configuration and approval messages before any provider or tool side effect.

Runnable examples

  • Vercel AI SDK support triage is the smaller adapter-focused example. It shows a support agent, local tools, model replacement, and optional cost calculation.

  • Vercel AI SDK ticket resolver is the full end-to-end walkthrough. It records a deterministic ten-ticket baseline, reviews failures, creates an evaluator and cohorts, and runs target and control replays through a worker. Its synthetic tools make passthrough safe within that example only.

Last updated

Was this helpful?