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

# AI SDK Adapter

> Gate AI model access to subscribers

## Install

```bash theme={null}
npm install @stellartools/aisdk-adapter ai
```

## Usage

```ts theme={null}
import { shield } from "@stellartools/aisdk-adapter";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

const result = await generateText({
  model: shield(openai("gpt-4o"), {
    apiKey: process.env.STELLAR_TOOLS_API_KEY!,
    customerId: "cus_xxx",
    productId: "prod_xxx",
  }),
  prompt: "Write a haiku about Stellar",
});

console.log(result.text);
```

Streaming works the same way:

```ts theme={null}
import { shield } from "@stellartools/aisdk-adapter";
import { streamText } from "ai";

const { textStream } = await streamText({
  model: shield(openai("gpt-4o"), {
    apiKey: process.env.STELLAR_TOOLS_API_KEY!,
    customerId: req.user.stellartoolsCustomerId,
    productId: "prod_xxx",
  }),
  messages: [{ role: "user", content: "Hello" }],
});
```

## Error handling

If the customer has no active subscription for the product, `shield` throws a `ShieldError` before the model is ever called.

```ts theme={null}
import { shield, ShieldError } from "@stellartools/aisdk-adapter";

try {
  const result = await generateText({
    model: shield(openai("gpt-4o"), config),
    prompt: "Hello",
  });
} catch (err) {
  if (err instanceof ShieldError) {
    return res.status(403).json({ error: err.message });
  }
  throw err;
}
```

## Config

<ParamField body="apiKey" type="string" required>
  Your StellarTools API key.
</ParamField>

<ParamField body="customerId" type="string" required>
  The StellarTools customer ID to check.
</ParamField>

<ParamField body="productId" type="string" required>
  The product the customer must have an active subscription to.
</ParamField>
