> ## Documentation Index
> Fetch the complete documentation index at: https://runinfra.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Vercel AI SDK

> Use RunInfra with the Vercel AI SDK. Works with Next.js, SvelteKit, Nuxt, and Remix.

The Vercel AI SDK ships a first-class OpenAI adapter. Override the base URL and key to route through RunInfra.

## Install

```bash theme={"dark"}
npm i ai @ai-sdk/openai-compatible @ai-sdk/react zod
```

## Configure the provider

```typescript theme={"dark"}
// lib/runinfra.ts
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";

const apiKey = process.env.RUNINFRA_GATEWAY_KEY;
if (!apiKey) {
  throw new Error("Set RUNINFRA_GATEWAY_KEY.");
}

export const runinfra = createOpenAICompatible({
  name: "runinfra",
  baseURL: "https://api.runinfra.ai/v1",
  apiKey,
});

export function getRunInfraModel(): string {
  const model = process.env.RUNINFRA_MODEL;
  if (!model) {
    throw new Error("Set RUNINFRA_MODEL from GET /v1/models.");
  }
  return model;
}
```

## Stream text in a Next.js route

```typescript theme={"dark"}
// app/api/chat/route.ts
import { convertToModelMessages, streamText } from "ai";
import { getRunInfraModel, runinfra } from "@/lib/runinfra";

export async function POST(req: Request) {
  const { messages } = await req.json();
  const result = streamText({
    model: runinfra(getRunInfraModel()),
    messages: convertToModelMessages(messages),
  });
  return result.toUIMessageStreamResponse();
}
```

## Generate structured data

```typescript theme={"dark"}
import { generateObject } from "ai";
import { getRunInfraModel, runinfra } from "@/lib/runinfra";
import { z } from "zod";

const { object } = await generateObject({
  model: runinfra(getRunInfraModel()),
  schema: z.object({
    merchant: z.string(),
    total_usd: z.number(),
    items: z.array(z.string()),
  }),
  prompt: "Extract receipt fields: $12.50 at Blue Bottle for coffee and a muffin",
});
```

## Tool calling

```typescript theme={"dark"}
import { streamText, tool } from "ai";
import { getRunInfraModel, runinfra } from "@/lib/runinfra";
import { z } from "zod";

const result = streamText({
  model: runinfra(getRunInfraModel()),
  prompt: "What is the weather in Austin?",
  tools: {
    getWeather: tool({
      description: "Get weather for a city",
      inputSchema: z.object({ city: z.string() }),
      execute: async ({ city }) => ({ city, temp: 21 }),
    }),
  },
});
```

## Client hook

The SDK's `useChat` hook needs no change. It hits your `/api/chat` route; your route calls RunInfra:

```typescript theme={"dark"}
"use client";
import { useChat } from "@ai-sdk/react";
import { useState } from "react";

export function Chat() {
  const [input, setInput] = useState("");
  const { messages, sendMessage, status } = useChat();

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const text = input.trim();
        if (!text) return;
        void sendMessage({ text });
        setInput("");
      }}
    >
      {messages.map((message) => (
        <div key={message.id}>
          {message.role}:{" "}
          {message.parts.map((part, index) =>
            part.type === "text" ? <span key={index}>{part.text}</span> : null,
          )}
        </div>
      ))}
      <input
        value={input}
        disabled={status !== "ready"}
        onChange={(event) => setInput(event.currentTarget.value)}
      />
    </form>
  );
}
```

## Next steps

<Columns cols={2}>
  <Card title="Streaming cookbook" icon="zap" href="/cookbook/streaming">
    Streaming patterns from scratch.
  </Card>

  <Card title="Tool calling cookbook" icon="wrench" href="/cookbook/tool-calling">
    Tool-loop patterns at the API level.
  </Card>

  <Card title="Structured output cookbook" icon="braces" href="/cookbook/structured-output">
    JSON Schema responses.
  </Card>

  <Card title="OpenAI compatibility" icon="plug" href="/tools-sdks/openai-compatibility">
    The contract this integration rides on.
  </Card>
</Columns>
