---
title: "@playstack/ai"
description: "Tenant-aware keys, preflight, metering, telemetry, and cache context around the Vercel AI SDK."
tags: ["package","intelligence","ai","metering","free"]
---

{/* package-access:start */}

> **Free.** MIT licensed. Check preview availability before installing. See [package access](/docs/packages#access-policy).

{/* package-access:end */}

`@playstack/ai` supplies tenant-aware keys, entitlement and rate-limit preflight, idempotent usage metering, safe telemetry, and deterministic cache context around native Vercel AI SDK calls.

{/* package-install:start */}

## Install

After confirming [preview access](/docs/packages#access-policy), install the package at your application's shared Playstack version:

```sh
npm install --save-exact @playstack/ai@0.1.0-beta.1
```

Check the peer requirements below before choosing a runtime or provider.

{/* package-install:end */}

## Install and compose

```ts
import { createAi } from '@playstack/ai'
import { streamText } from 'ai'

const ai = createAi({
  persistence,
  events,
  connections,
  rateLimiter,
  entitlements,
  connectionScope: 'account',
  allowPlatformFallback: false,
  providers: [{
    id: 'anthropic',
    createModel: (modelId, { apiKey }) => anthropic(modelId, { apiKey }),
  }],
  prices: {
    'anthropic:claude-sonnet-4-6': {
      inputMicrosPerMillionTokens: configuredInputPrice,
      outputMicrosPerMillionTokens: configuredOutputPrice,
      currency: 'USD',
    },
  },
  clock,
  ids,
})

const call = await ai.beginCall('anthropic:claude-sonnet-4-6', { accountId, actorId })
const result = await streamText({ model: call.model, prompt })
await ai.completeCall(call, {
  promptTokens: result.usage.inputTokens,
  completionTokens: result.usage.outputTokens,
})
```

`call.model` is the provider’s exact model object. Streaming, tools, structured output, and UI hooks remain native SDK APIs.

## Core configuration

| `AiOptions` property | Required | Purpose |
| --- | --- | --- |
| `persistence` | Yes | Transactional idempotent usage records and summaries. |
| `events` | Yes | Emits billable `ai.call.completed` inside the usage transaction. |
| `connections` | Yes | Lists scoped BYO connections and decrypts selected access tokens. |
| `rateLimiter` | Yes | Consumes fail-closed `ai.generate` account and user buckets. |
| `entitlements` | Yes | Authorizes provider/model and may supply rate-limit overrides. |
| `providers` | Yes | Provider ID, native model factory, and optional platform key resolver. |
| `prices` | Yes | Model-ref input/output micros per million tokens and currency. |
| `connectionScope` | Yes | `user`, `accountMember`, or `account`. |
| `allowPlatformFallback` | No | Enables platform keys only when a provider supplies one. |
| `telemetry`, `errorReporter`, `scrubber` | No | Application-owned operational bridges. |
| `recordContent` | No | Includes scrubbed prompt/completion telemetry; defaults false. |
| `cache` | No | Explicit `{ enabled, hasher }`; disabled when absent. |
| `clock`, `ids` | Yes | Call timing and identifiers. |

## Provider and policy bridges

| Contract | Responsibility |
| --- | --- |
| `AiProvider` | `createModel(modelId, { apiKey })` and optional `platformApiKey()`. |
| `AiConnections` | Scoped `list` plus decrypted `accessToken(connectionId)`. |
| `AiEntitlements` | Authorize account/actor/provider/model and return optional bucket overrides. |
| `AiRateLimiter` | Consume `ai.generate` with both account and user subjects. |
| `AiUsagePersistence` | Transactional `record` with created/duplicate result and account/time summary. |
| `AiTelemetry` | Isolated started/completed/failed observations. |
| `AiErrorReporter` | Receives scrubbed failure reports. |
| `AiCacheHasher` | SHA-256 digest for normalized deterministic inputs. |

A present but unusable BYO connection never falls back. Platform fallback requires both the global opt-in and a provider resolver. Bypassed/open rate-limit decisions are rejected so inference stays fail-closed.

## Metering, telemetry, and caching

`completeCall` records by `callId`; a duplicate with identical usage is safe, while conflicting billable usage fails. Provider prices are captured into the receipt and event so billing consumers do not own the price table.

Prompt/completion recording is off by default. When enabled, content is scrubbed before telemetry and credentials never enter receipts, errors, events, or traces. `cacheKey()` returns a key only when caching is enabled and temperature is zero; storage remains an application-selected concern.

## Persistence and boundary

`@playstack/ai/prisma` supplies structural PostgreSQL persistence and a managed, non-ejectable schema fragment. Applications own clients and migrations. The package does not wrap the AI SDK, store cache results, load keys, define subscription plans, or hide provider-native behavior.

{/* package-reference:start */}

## API entry points and requirements

Reference snapshot: `@playstack/ai@0.1.0-beta.1`. Import only the entry point your runtime needs. Paths below are relative to the installed package; use **Go to Definition** in your editor to inspect exact parameters, return types and overloads. Do not import the declaration-file paths directly.

| Public entry point | Declaration file |
| --- | --- |
| `@playstack/ai` | `./dist/index.d.ts` |
| `@playstack/ai/errors` | `./dist/errors.d.ts` |
| `@playstack/ai/prisma` | `./dist/prisma.d.ts` |
| `@playstack/ai/testing` | `./dist/testing.d.ts` |
| `@playstack/ai/playstack.artifacts.json` | No TypeScript declaration (asset or metadata export). |
| `@playstack/ai/package.json` | No TypeScript declaration (asset or metadata export). |

Node.js engine requirement: `>=20`. This is not a claim that every entry point works in browsers or Workers.

### Peer dependencies

Keep existing framework versions that satisfy these ranges. Install optional peers only when using the corresponding adapter. The package manager resolves ordinary dependencies separately.

| Peer | Compatible range | When needed |
| --- | --- | --- |
| `@playstack/connections` | `0.1.0-beta.1` | Required by the package. |
| `@playstack/rate-limit` | `0.1.0-beta.1` | Required by the package. |

For a complete first program, start with [Getting started](/docs/getting-started). For API lookup and partial-example conventions, see [Reading the reference](/docs/packages#reading-the-reference). Provider failures, lifecycle requirements and application responsibilities remain described in the guide above; types alone do not establish production safety.

{/* package-reference:end */}
