Docs menuVercel AI SDK

Docs Integrations

Vercel AI SDK

Wrap the model and tools you pass to generateText or streamText to record every step, and let a policy stop a tool before it runs. About five minutes.

Before you begin

  • A Runback account and a Send only key. In the app, open Settings › Keys and access › API key, keep Send only selected, select Generate API key and copy it (it is shown once and starts rb_cloud_). The quickstart walks through it.
  • Node.js 20 or later (node --version) and the AI SDK (ai) v6.
  • An OpenAI API key (the example uses @ai-sdk/openai; any AI SDK provider works).

Steps

  1. Install the SDK

    terminalShell
    npm install @runback/sdk ai @ai-sdk/openai zod
    Expected output
    npm finishes without errors. ai is a peer dependency you may already have.
  2. Set your keys

    Runback reads its key from RUNBACK_API_KEY; the model client reads its own.

    terminalShell
    export RUNBACK_API_KEY="<RUNBACK_API_KEY>"
    export OPENAI_API_KEY="sk-..."
    Expected output
    Nothing is printed. echo $RUNBACK_API_KEY should print your key.
  3. Wrap the model and tools, then run it

    dbg.model records each model call, streamed or not; dbg.tools(...) records each tool call and is where a policy can stop one before it runs. Save this as agent.mjs and run node agent.mjs.

    agent.mjsJavaScript
    // agent.mjs: npm install @runback/sdk ai @ai-sdk/openai zod
    import { withDebugger } from "@runback/sdk";
    import { generateText, tool, stepCountIs } from "ai";
    import { openai } from "@ai-sdk/openai";
    import { z } from "zod";
    
    const task = "What's the weather in Paris?";
    const dbg = withDebugger(openai("gpt-4o-mini"), { runName: "weather-agent", input: task });
    
    const res = await generateText({
      model: dbg.model,
      tools: dbg.tools({
        get_weather: tool({
          description: "Weather for a city",
          inputSchema: z.object({ city: z.string() }),
          execute: async ({ city }) => ({ city, forecast: "sunny" }),
        }),
      }),
      stopWhen: stepCountIs(3),
      prompt: task,
    });
    
    await dbg.finish({ output: res.text, status: "success" });
    console.log(res.text);
    Expected output
    The agent's answer and no [runback] line. A [runback] line means the run was not sent; see Troubleshooting.
  4. Check the run arrived

    Open Runs in the app. Your run is at the top, named weather-agent. Open it to step through what the agent did.

Troubleshooting

You seeWhat it meansFix
[runback] no RUNBACK_API_KEY set — dropped 3 eventsThe key is not set in the terminal you ran the agent from.Export RUNBACK_API_KEY in the same terminal (a new tab starts without it), then run the agent again.
[runback] ingest failed 401 {"error":"Invalid API key"}Runback rejected the key: mistyped, revoked or expired.Copy the whole key again, or create a new one in Settings › Keys and access › API key.
OpenAIError: Missing credentialsOPENAI_API_KEY (or your provider's key) is not set.Run the agent with the provider key set, e.g. OPENAI_API_KEY=sk-... node agent.mjs.
Failed to load the ES module (Node 22+) or Cannot use import statement outside a module (Node 20)The file is not treated as an ES module.Name it .mjs, or add "type": "module" to package.json.
The agent ran, but the run is not in RunsThe key belongs to a different workspace, or you are looking at the shared demo.Check the workspace name in the top right of the app is the one the key came from.

Your agent never fails because of Runback: if recording fails, the model call still returns and Runback prints one [runback] line saying why.

What Runback records

withDebugger around the Vercel AI SDK's generateText, scripted model, one tool. 5 events, captured 19 Oct 2026.

  1. Runstart · weather-agent
    {
      "schema_version": 1,
      "run_id": "01M59REJ7HE9EBFAT3KA2YJ22R",
      "span_id": "01M59REJ7JWGK5ZJ6RWWPAJ7ZK",
      "parent_span_id": null,
      "seq": 0,
      "ts_start": "2026-10-19T09:38:57.394Z",
      "ts_end": null,
      "type": "run",
      "phase": "start",
      "name": "weather-agent",
      "input": "Weather in Paris? cc [redacted:email]",
      "output": null,
      "status": "running",
      "error": null,
      "metadata": {}
    }
  2. Modelgpt-4o-mini → get_weather17 tokens · called a tool
    {
      "ts_start": "2026-10-19T09:38:57.430Z",
      "ts_end": "2026-10-19T09:38:57.430Z",
      "model": {
        "provider": "openai",
        "model_id": "gpt-4o-mini"
      },
      "request": {
        "system": "You are a weather bot.",
        "messages": [
          {
            "role": "user",
            "content": [
              {
                "type": "text",
                "text": "Weather in Paris? cc [redacted:email]"
              }
            ]
          }
        ],
        "tools": [
          {
            "name": "get_weather",
            "description": "Weather for a city",
            "parameters": {
              "type": "object",
              "properties": {
                "city": {
                  "type": "string"
                }
              },
              "required": [
                "city"
              ],
              "additionalProperties": false,
              "$schema": "http://json-schema.org/draft-07/schema#"
            }
          }
        ],
        "params": {}
      },
      "response": {
        "text": null,
        "reasoning": null,
        "finish_reason": "tool-calls",
        "tool_calls": [
          {
            "tool_call_id": "call_1",
            "tool_name": "get_weather",
            "input": {
              "city": "Paris"
            }
          }
        ]
      },
      "usage": {
        "input_tokens": 12,
        "output_tokens": 5,
        "total_tokens": 17
      },
      "latency_ms": 0,
      "error": null,
      "schema_version": 1,
      "run_id": "01M59REJ7HE9EBFAT3KA2YJ22R",
      "span_id": "01M59REJ8PJA1RY80H1W2769SY",
      "parent_span_id": "01M59REJ7JWGK5ZJ6RWWPAJ7ZK",
      "seq": 1,
      "type": "llm"
    }
  3. Toolget_weather
    {
      "schema_version": 1,
      "run_id": "01M59REJ7HE9EBFAT3KA2YJ22R",
      "span_id": "01M59REJ8S94YYN6AWFMYKKKK2",
      "parent_span_id": "01M59REJ8PJA1RY80H1W2769SY",
      "seq": 2,
      "ts_start": "2026-10-19T09:38:57.433Z",
      "ts_end": "2026-10-19T09:38:57.433Z",
      "type": "tool",
      "tool_name": "get_weather",
      "tool_call_id": "call_1",
      "input": {
        "city": "Paris"
      },
      "output": {
        "city": "Paris",
        "forecast": "sunny"
      },
      "latency_ms": 0,
      "error": null
    }
  4. Modelgpt-4o-mini27 tokens · finished
    {
      "ts_start": "2026-10-19T09:38:57.434Z",
      "ts_end": "2026-10-19T09:38:57.434Z",
      "model": {
        "provider": "openai",
        "model_id": "gpt-4o-mini"
      },
      "request": {
        "system": "You are a weather bot.",
        "messages": [
          {
            "role": "user",
            "content": [
              {
                "type": "text",
                "text": "Weather in Paris? cc [redacted:email]"
              }
            ]
          },
          {
            "role": "assistant",
            "content": [
              {
                "type": "tool-call",
                "toolCallId": "call_1",
                "toolName": "get_weather",
                "input": {
                  "city": "Paris"
                }
              }
            ]
          },
          {
            "role": "tool",
            "content": [
              {
                "type": "tool-result",
                "toolCallId": "call_1",
                "toolName": "get_weather",
                "output": {
                  "type": "json",
                  "value": {
                    "city": "Paris",
                    "forecast": "sunny"
                  }
                }
              }
            ]
          }
        ],
        "tools": [
          {
            "name": "get_weather",
            "description": "Weather for a city",
            "parameters": {
              "type": "object",
              "properties": {
                "city": {
                  "type": "string"
                }
              },
              "required": [
                "city"
              ],
              "additionalProperties": false,
              "$schema": "http://json-schema.org/draft-07/schema#"
            }
          }
        ],
        "params": {}
      },
      "response": {
        "text": "It is sunny in Paris.",
        "reasoning": null,
        "finish_reason": "stop",
        "tool_calls": []
      },
      "usage": {
        "input_tokens": 20,
        "output_tokens": 7,
        "total_tokens": 27
      },
      "latency_ms": 0,
      "error": null,
      "schema_version": 1,
      "run_id": "01M59REJ7HE9EBFAT3KA2YJ22R",
      "span_id": "01M59REJ8T86BGPWDR3DYP9N58",
      "parent_span_id": "01M59REJ7JWGK5ZJ6RWWPAJ7ZK",
      "seq": 3,
      "type": "llm"
    }
  5. Runend · weather-agentsucceeded
    {
      "schema_version": 1,
      "run_id": "01M59REJ7HE9EBFAT3KA2YJ22R",
      "span_id": "01M59REJ8V9Z66RXMXBQ9WP97G",
      "parent_span_id": "01M59REJ7JWGK5ZJ6RWWPAJ7ZK",
      "seq": 4,
      "ts_start": "2026-10-19T09:38:57.435Z",
      "ts_end": "2026-10-19T09:38:57.435Z",
      "type": "run",
      "phase": "end",
      "name": "weather-agent",
      "input": null,
      "output": "It is sunny in Paris.",
      "status": "success",
      "error": null,
      "metadata": {
        "cassette_digest": "d2556ed7eba1ac4ec6c06303f0cbc1b609955ed2ea5ab5b698f00190f19f178b",
        "cassette_entries": 3,
        "redaction_count": 3,
        "redaction_by_type": {
          "email": 3
        },
        "truncated_fields": 0
      }
    }

The events this integration really sent, redacted in its own process, from a run in Runback's test suite. The model is scripted, so its name and its answers are the test's. The suite re-checks them on every change.

What it can and cannot do

Vercel AI SDK

QuestionAnswerWhy
ContextFullSystem prompt, messages, tools and parameters, streamed or not.
RedactionIn your processOn by default, before anything is buffered or sent.
Stop before it runsYesA policy rule is checked before a wrapped tool executes.
ReplayWhole runEvery tool result is kept. Re-running the run with those results held fixed is on the Enterprise plan.
Signed recordYesEach run is hash-chained and can be exported as a signed record.

Next steps

  • See what a run holds: Capture.
  • Stop a tool call before it runs: Control.
Last updated 2 Nov 2026.