checkrd

Vercel AI SDK

Add Checkrd policy enforcement to the Vercel AI SDK via LanguageModelV2Middleware.

Vercel AI SDK

Checkrd ships a LanguageModelV2Middleware that hooks into every generateText, streamText, generateObject, and streamObject call. The middleware policy-evaluates the call before the model runs and emits structured telemetry on completion (including streaming token counts).

Install

bash
npm install checkrd ai @ai-sdk/openai

Quickstart

typescript
import { initAsync, getEngine, getSink } from "checkrd";
import { checkrdMiddleware } from "checkrd/ai-sdk";
import { generateText, wrapLanguageModel } from "ai";
import { openai } from "@ai-sdk/openai";

await initAsync({
  agentId: "01234567-89ab-cdef-0123-456789abcdef",
  apiKey: process.env.CHECKRD_API_KEY!,
});

const model = wrapLanguageModel({
  model: openai("gpt-4o"),
  middleware: checkrdMiddleware({
    engine: getEngine(),
    enforce: true,
    agentId: "01234567-89ab-cdef-0123-456789abcdef",
    sink: getSink(),
  }),
});

const result = await generateText({
  model,
  prompt: "Tell me a joke",
});

Where does the policy come from?

initAsync fetches your agent's currently-published DSSE-signed bundle from the control plane and installs it before resolving — your dashboard is the source of truth for what checkrdMiddleware enforces. Edit the policy in the dashboard; updates stream to the process over SSE.

Streaming

The middleware wraps the model's stream with a TransformStream that accumulates token usage as chunks flow through. The completion telemetry event fires when the stream's flush runs:

typescript
const { textStream } = await streamText({
  model,
  prompt: "...",
});

for await (const chunk of textStream) {
  process.stdout.write(chunk);
}
// Telemetry event with input_tokens / output_tokens emits here.

What gets enforced

AI SDK callSynthetic URLOperation
generateTextai-sdk://{provider}/{modelId}generate
streamTextai-sdk://{provider}/{modelId}stream
generateObjectai-sdk://{provider}/{modelId}generate
streamObjectai-sdk://{provider}/{modelId}stream

Body fields exposed for matchers: messages, prompt, mode, temperature, topP, maxTokens.

yaml
default: allow

rules:
  - name: deny-gpt4-for-cheap-tier
    deny:
      url: "ai-sdk://openai/gpt-4**"
      headers:
        - name: x-tenant-tier
          exact: free

  - name: only-approved-models
    allow:
      url: "ai-sdk://**"
      body:
        - jsonpath: "$.model"
          in: ["gpt-4o-mini", "gpt-4o"]

Edge runtimes

The Vercel AI SDK runs in Edge Runtime, Cloudflare Workers, and Deno. Use initAsync (not init) so the WASM core loads via fetch + WebAssembly.compile instead of node:fs.readFileSync. The middleware itself is runtime-agnostic.

typescript
// Cloudflare Workers entry
import { initAsync, getEngine, getSink } from "checkrd";
import { checkrdMiddleware } from "checkrd/ai-sdk";

export default {
  async fetch(req, env) {
    await initAsync({
      apiKey: env.CHECKRD_API_KEY,
      agentId: "01234567-89ab-cdef-0123-456789abcdef",
    });
    const middleware = checkrdMiddleware({
      engine: getEngine(),
      enforce: true,
      agentId: "01234567-89ab-cdef-0123-456789abcdef",
      sink: getSink(),
    });
    // ... use middleware in wrapLanguageModel(...) ...
  },
};

Observation mode

Set enforce: false to log denies without aborting:

typescript
checkrdMiddleware({
  engine: getEngine(),
  enforce: false, // observation mode
  agentId: "01234567-89ab-cdef-0123-456789abcdef",
  sink: getSink(),
});

Caveats

  • The AI SDK passes streaming chunks through flush. Token counts are only available at end-of-stream; they're not in the gate event, only the completion event.
  • Only the v2 middleware shape is supported. AI SDK 4.x uses LanguageModelV2Middleware. The legacy v1 middleware shape is not supported.
  • Provider name detection. The middleware reads provider from the model spec. Custom providers (createOpenAICompatible) report their configured name.