# Vercel AI SDK (/docs/integrations/vercel-ai-sdk)

Call codai from the Vercel AI SDK 7 through the OpenAI-compatible provider, with streaming, tools and the cost receipt.

The AI SDK reaches codai through `@ai-sdk/openai-compatible`: base URL `https://ai.codai.ro/v1`, your `codai_…` key and the model `codai`. This is the same setup the Ask-the-docs assistant on this site runs in production.

## Before you start [#before-you-start]

- A codai key from [hub.codai.ro](https://hub.codai.ro) → **Keys → Create key** (details in the [quickstart](../gateway/index.mdx)), stored as `CODAI_API_KEY`.
- AI SDK 7 (`ai`) and the OpenAI-compatible provider. The SDK is ESM-only.

```bash
pnpm add ai @ai-sdk/openai-compatible
```

## Create the provider [#create-the-provider]

```ts title="lib/codai.ts"
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';

export const codai = createOpenAICompatible({
  name: 'codai',
  baseURL: 'https://ai.codai.ro/v1',
  apiKey: process.env.CODAI_API_KEY,
  // Optional codai headers — see the request headers page.
  headers: { 'X-Codai-Effort': 'medium' },
  includeUsage: true,
});
```

- `includeUsage: true` asks for the final usage chunk on streams, so token counts reach `onEnd` / `usage`.
- Use `codai.chatModel('codai')`. The gateway speaks Chat Completions natively; `codai` is the default model, other aliases are on [models](../gateway/models.mdx).

## Generate text [#generate-text]

```ts title="generate.ts"
import { generateText } from 'ai';
import { codai } from './lib/codai';

const result = await generateText({
  model: codai.chatModel('codai'),
  instructions: 'You are a terse senior engineer.',
  prompt: 'Explain Promise.all in three sentences.',
});

console.log(result.text);
console.log(result.usage);
// What actually served the call, and what it cost (micro-USD) when known before the first byte:
console.log(result.response.headers?.['x-codai-routed-to']);
console.log(result.response.headers?.['x-codai-cost-micro-usd']);
```

AI SDK 7 uses `instructions` for the system prompt (it replaced `system`).

## Stream, with tools [#stream-with-tools]

```ts title="app/api/chat/route.ts"
import { createTextStreamResponse, isStepCount, streamText, toTextStream, tool } from 'ai';
import { z } from 'zod';
import { codai } from '@/lib/codai';

export async function POST(req: Request) {
  const { prompt } = (await req.json()) as { prompt: string };
  const result = streamText({
    model: codai.chatModel('codai'),
    prompt,
    stopWhen: isStepCount(3),
    tools: {
      weather: tool({
        description: 'Current temperature for a city.',
        inputSchema: z.object({ city: z.string() }),
        execute: async ({ city }) => ({ city, celsius: 18 }),
      }),
    },
  });
  return createTextStreamResponse({ stream: toTextStream({ stream: result.stream }) });
}
```

In AI SDK 7 the stream helpers are stateless top-level exports; `result.toTextStreamResponse()` still works but is deprecated. Function tools are forwarded as OpenAI `tools` and come back as `tool_calls`; the SDK runs them and continues the loop. On streams the cost is not known at header time: the gateway sends `x-codai-cost-estimate: pending` and the exact figure is in [`GET /v1/receipt`](../gateway/limits-pricing.mdx#cost-receipt).

## Troubleshooting [#troubleshooting]

- **`404`** — the base URL lacks `/v1`. It must be exactly `https://ai.codai.ro/v1`.
- **`401 invalid_api_key`** — `CODAI_API_KEY` is not set where the code runs (server env, not the browser).
- **Usage is empty on streams** — add `includeUsage: true` to the provider.
- **`429`** — read `error.code`; see [limits and pricing](../gateway/limits-pricing.mdx). The SDK retries failed calls twice by default (`maxRetries`).

## Sources [#sources]

Checked 2026-10-18.

- [AI SDK — OpenAI Compatible provider](https://ai-sdk.dev/providers/openai-compatible-providers)
- [AI SDK 7 migration guide](https://ai-sdk.dev/docs/migration-guides/migration-guide-7-0)
