GenerateSaaS

AI

Build AI features on @repo/ai, a thin provider-agnostic re-export of the AI SDK.

@repo/ai is a deliberately thin, provider-agnostic re-export of the AI SDK v6 core (ai@^6). It ships no provider, no client, and no @repo/config flag - bring your own model SDK in the package that calls an LLM, so AI is opt-in by import alone.

What it exports

The whole package is one barrel (packages/ai/src/index.ts) re-exporting the core surface. It depends only on ai and is sideEffects: false, so unused exports tree-shake away.

ExportKindPurpose
streamTextfnStream tokens - pipe straight to an HTTP response
generateTextfnOne-shot text completion
generateObjectfnTyped JSON output validated by a Zod schema
toolfnDefine a function the model can call
convertToModelMessagesfnMap UI messages to model messages
UIMessagetypeShape your UI sends
ModelMessagetypeShape the model expects
LanguageModeltypeA configured provider model

Bring your own provider

@repo/ai depends on no provider SDK by design. Pick one and add it to the package that calls the model.

ProviderPackageKey env var
OpenAI@ai-sdk/openaiOPENAI_API_KEY
Claude@ai-sdk/anthropicANTHROPIC_API_KEY
Many models, one key@openrouter/ai-sdk-providerOPENROUTER_API_KEY

Install the provider into the package that owns the model call:

pnpm --filter @repo/api add @ai-sdk/openai

Never expose a provider key to the client. Store keys as environment variables (document them in .env.example, see Environment Variables) and keep every model call server-side on the shared backend (API).

Streaming and structured output

streamText returns a stream you can pipe to an HTTP response; convertToModelMessages maps the UIMessage[] your UI sends into the ModelMessage[] the model expects.

import { streamText, convertToModelMessages } from "@repo/ai";
import { openai } from "@ai-sdk/openai";

const result = streamText({
  model: openai("gpt-4o-mini"),
  messages: await convertToModelMessages(uiMessages),
});

return result.toUIMessageStreamResponse();

For typed JSON instead of free text, use generateObject with a Zod schema:

const { object } = await generateObject({
  model: openai("gpt-4o-mini"),
  schema: z.object({ title: z.string(), tags: z.array(z.string()) }),
  prompt: "Summarize this article…",
});

tool defines a function the model can call - pass tools to streamText or generateText to let the model invoke your own logic.

Frequently asked questions

Which feature flag turns AI on? None. There is no @repo/config flag - the package does nothing until your code imports it and calls a model, so hide any AI UI behind your own conditional.

Does importing @repo/ai add bundle weight? No. It re-exports only ai and is sideEffects: false, so anything you don't use tree-shakes away and no LLM is ever called implicitly.

Where do model calls belong? On the shared backend so the provider key never reaches the browser. Define the endpoint once in @repo/api; streaming-vs-fetch and client hooks differ per framework, see Data Fetching.

On this page