@axiorank/ai-sdk
v0.2.1
Published
AxioRank guardrail middleware for the Vercel AI SDK. Inspect and redact prompts, completions, and proposed tool calls on every generateText and streamText.
Maintainers
Readme
@axiorank/ai-sdk
AxioRank guardrail middleware for the Vercel AI SDK. One
wrapLanguageModel call governs every generateText, streamText, and
generateObject through a model: the prompt is inspected before it is sent, the
completion is inspected and optionally redacted before your app sees it, and the
tool calls the model proposes are inspected before the SDK executes them.
It catches leaked secrets, prompt injection, PII, and destructive tool calls, using the same detectors and risk scoring as the rest of AxioRank, the security gateway for AI agents.
Install
npm install @axiorank/ai-sdk aiai (v7 or later) is a peer dependency.
Quickstart
import { wrapLanguageModel } from "ai";
import { openai } from "@ai-sdk/openai";
import { createAxioRankMiddleware } from "@axiorank/ai-sdk";
const model = wrapLanguageModel({
model: openai("gpt-4o"),
middleware: createAxioRankMiddleware({ apiKey: process.env.AXIORANK_KEY }),
});
// governed: prompt, completion, and proposed tool calls are all inspected
const { text } = await generateText({ model, prompt: "..." });Streaming works the same way:
const { textStream } = await streamText({ model, prompt: "..." });Try it with no key
Leave the API key off and the middleware runs the detectors in-process (no signup, no network) as an advisory guard:
const model = wrapLanguageModel({
model: openai("gpt-4o"),
middleware: createAxioRankMiddleware(), // local mode
});What it inspects
| Surface | When | Default action on a block | | --- | --- | --- | | Prompt | Before the model is called | Return a refusal (the model is never called) | | Completion | After the model responds | Redact (hosted policy) or replace with a refusal | | Tool calls | On the calls the model proposes | Strip the denied call so the SDK never runs it |
A denied call is handled gracefully by default (onDeny: "block"): the surface
is refused, redacted, or stripped, and generation continues. Set
onDeny: "throw" to raise AxioRankDeniedError instead.
Hosted vs local
- Hosted (an API key is present): calls the AxioRank gateway, so your workspace's real policy applies, every call lands in the audit log, and the gateway can return a redacted completion. Enable model I/O enforcement in your workspace settings so prompt and completion governance is active; otherwise the gateway inspects but does not block them.
- Local (no API key): runs the bundled detectors in-process against the default posture. Advisory and block-on-deny only (no policy, no redaction).
Streaming
streamText forwards tokens as they arrive, so a secret that appears mid-stream
would reach the client before it could be caught. The stream option controls
the trade-off:
"buffer"(default): accumulate the streamed text, inspect it, then release it. Redaction and blocking are correct, at the cost of some first-token latency."passthrough": stream tokens live and inspect at the end for audit only. It cannot retract text that has already been sent, so it never redacts.
Options
createAxioRankMiddleware({
apiKey, // else AXIORANK_API_KEY, then AXIORANK_KEY
baseUrl, // else AXIORANK_BASE_URL, then https://app.axiorank.com
mode, // "hosted" | "local" (auto: hosted when a key is present)
onDeny, // "block" (default) | "throw"
failOpen, // default true: an AxioRank outage never breaks your app
inspectPrompts, // default true
inspectCompletions,// default true
inspectToolCalls, // default true
stream, // "buffer" (default) | "passthrough"
refusal, // text substituted for a blocked prompt or completion
onDecision, // (phase, verdict) => void, for logging and metrics
timeoutMs, // default 10000
model, // model label sent to the gateway (defaults to the call's id)
});Relationship to @axiorank/sdk
This middleware guards the model: its prompts, its completions, and the tool
calls it proposes. To guard tool execution (the code your tools actually
run), use guardTools from @axiorank/sdk/vercel. The two are complementary and
compose:
import { AxioRank } from "@axiorank/sdk";
import { guardTools } from "@axiorank/sdk/vercel";
import { createAxioRankMiddleware } from "@axiorank/ai-sdk";
const axio = new AxioRank({ apiKey: process.env.AXIORANK_KEY });
const model = wrapLanguageModel({
model: openai("gpt-4o"),
middleware: createAxioRankMiddleware({ apiKey: process.env.AXIORANK_KEY }),
});
await generateText({
model,
tools: guardTools(myTools, axio),
prompt: "...",
});AxioRankDeniedError is re-exported here and is the same class @axiorank/sdk
throws, so a single catch handles both.
