/** Policy decision returned by the AxioRank gateway. */ type Decision = "allow" | "deny"; interface AxioRankOptions { /** * Your agent's API key (looks like `axr_live_...`). Optional only if you * supply a federated `subjectToken` / `subjectTokenProvider` instead. */ apiKey?: string; /** * Exchange your long-lived key (or a federated OIDC token) for short-lived, * auto-refreshed gateway tokens instead of sending a static key on every call * - the recommended Zero Trust posture. Implied `true` when `subjectToken` or * `subjectTokenProvider` is set. Falls back to the static key automatically if * the gateway has no token endpoint. * @default false */ useTokens?: boolean; /** * A platform OIDC token (GitHub Actions / AWS / GCP …) for the federated * grant - the agent then holds NO long-lived AxioRank secret at all. */ subjectToken?: string; /** * Lazily supply/refresh the federated OIDC token (e.g. read it from the CI/ * cloud runtime on each exchange). Preferred over a static `subjectToken`. */ subjectTokenProvider?: () => string | Promise; /** Narrow the minted token's scopes (defaults to the credential's full scopes). */ tokenScopes?: string[]; /** Requested token lifetime in seconds (the gateway clamps to ≤ 3600). */ tokenTtlSeconds?: number; /** * Base URL of your AxioRank deployment. * @default "https://app.axiorank.com" */ baseUrl?: string; /** * Per-request timeout in milliseconds. * @default 10000 */ timeoutMs?: number; /** * Max time to wait for a human to resolve a `require_approval` hold before the * call resolves to `deny`. The gateway also auto-denies a hold after its own * server-side TTL. * @default 300000 */ approvalTimeoutMs?: number; /** * Custom fetch implementation (useful for tests or non-standard runtimes). * Defaults to the global `fetch`. */ fetch?: typeof fetch; /** * Default trace id applied to every call that doesn't pass its own - correlates * an agent run for kill-chain detection. Usually you'll prefer {@link AxioRank.trace}. */ traceId?: string; /** * Default session id applied to every call that doesn't pass its own. A session * groups multiple traces (one conversation → N runs) on the Agent Runs page. */ sessionId?: string; /** * What to assume when the AxioRank gateway is UNREACHABLE (a timeout, network * error, or 5xx) - NOT when it returns a real verdict. `fail_open` resolves the * call to `allow` so an outage never halts your agents; `fail_closed` resolves to * `deny` so no ungoverned call proceeds. When unset, the SDK follows the per-agent * / workspace posture the gateway returns on each verdict, defaulting to * `fail_open` until it has seen one. Set this to override the server posture. */ onUnavailable?: "fail_open" | "fail_closed"; /** * Called when a call resolves from the unavailability path (a degraded verdict) * instead of a real gateway decision - wire it to your own metric/log so a silent * outage is visible. Best-effort; exceptions thrown here are swallowed. */ onDegraded?: (info: { tool: string; reason: "timeout" | "network" | "5xx"; decision: Decision; }) => void; } interface ToolCallParams { /** Fully-qualified tool name, e.g. `github.createPR` or `aws.delete`. */ tool: string; /** Arbitrary arguments for the tool call (recorded in the audit log). */ arguments?: Record; /** * Correlate this call into an agent run/trace so the gateway can detect * multi-step "kill chains" (e.g. read a secret → exfiltrate it). Optional; * prefer {@link AxioRank.trace} to avoid threading an id through every call. */ traceId?: string; /** 0-based position of this call within its trace. Auto-assigned by {@link AxioRank.trace}. */ stepIndex?: number; /** * Session id grouping multiple traces into one conversation (uuid). Filterable * on the Agent Runs page. Prefer {@link AxioRank.trace} with `{ sessionId }` * or the constructor-level default to avoid threading it through every call. */ sessionId?: string; /** * Small metadata tag map surfaced on the run timeline (e.g. environment, * feature, your own user/request id). At most 16 keys, keys up to 64 chars, * string values up to 256 chars, 2KB serialized. Values are redacted at write * (never store a secret here); oversized maps are dropped, never an error. */ metadata?: Record; /** * Sub-agent nesting: the step index (same trace) of the call that spawned * this step. The run timeline indents the step under its parent. Prefer * {@link AxioTrace.child}, which sets it for every call on the child handle. */ parentStepIndex?: number; /** * Spend (USD) you attribute to this call, e.g. the model cost of the turn * that produced it. Feeds the policy engine's `budget` predicate so a * `cost_usd` cap can deny or hold the agent once it is over budget. */ costUsd?: number; /** * The model this call used (e.g. `"claude-opus-4-8"` or `"gpt-4o"`). With * {@link inputTokens}/{@link outputTokens}, AxioRank computes the cost from * its price catalog when you don't pass {@link costUsd} - so spend governance * works without you pricing each turn. Also lets a policy match on the model. */ model?: string; /** Prompt (input) tokens for this call - used to compute cost from {@link model}. */ inputTokens?: number; /** Completion (output) tokens for this call - used to compute cost from {@link model}. */ outputTokens?: number; /** * Wall-clock you measured around the actual tool/model execution, in * milliseconds. The gateway authorizes BEFORE the tool runs, so it cannot time * the upstream itself on this path; report it here (typically on the completion * phase, alongside {@link inputTokens}/{@link outputTokens}) and it surfaces as * the call's upstream latency in Observability. Optional and display-only. */ durationMs?: number; /** * The user task this run serves (e.g. the user's request, summarized). Stored * once per trace, redacted, and used by the AI flow judge to auto-release * data-flow holds that clearly serve the task. Prefer * {@link AxioRank.trace} with `{ intent }` to send it once per run. */ intent?: string; /** * Opt in to minting an {@link ActionPassport} for this call: a portable, signed * proof-of-governance returned on {@link ToolCallResult.passport} that you can * present to a counterparty, who verifies it offline. Only honored when the * workspace enabled passports (a Team+ capability); otherwise ignored. */ passport?: boolean; /** * Where this call originated. Defaults to `"sdk"`. Set `"coding-agent"` when * reporting an AI coding agent's action (Claude Code / Cursor / Codex / Copilot) * so dev-session traffic is distinguishable in the audit log and the Coding * Sessions view. */ source?: "sdk" | "mcp" | "coding-agent"; } /** * Report a tool's RESULT to the gateway for information-flow-control taint * tracking. The guard wrappers call this automatically for untrusted-source tools * when the workspace enforces IFC; you rarely call it directly. */ interface ToolResultParams { /** The tool whose output this is (the same name used for the request). */ tool: string; /** The tool's output, stringified. The gateway fingerprints it; the raw value is never stored. */ resultText: string; /** Correlate the result into the same trace as the request that produced it. */ traceId?: string; stepIndex?: number; /** * A {@link ToolCallResult.taintHandle} from the agent that produced this output * (cross-agent / A2A). Pass it when the result you are reporting came from * ANOTHER agent so the gateway re-seeds this run's taint from it - a value * laundered through that agent is then still caught at your sink. */ taintHandle?: string; } /** * A trace-bound view of the client: every call made through it shares one trace * id and gets an auto-incrementing step index, so the gateway correlates them * into a single agent run. Created by {@link AxioRank.trace}. */ interface AxioTrace { /** The trace id shared by every call on this handle. */ readonly id: string; toolCall(params: ToolCallParams): Promise; enforce(params: ToolCallParams): Promise; /** Report a tool RESULT correlated into this trace (IFC taint tracking). */ reportResult(params: ToolResultParams): Promise; /** Inspect a tool RESULT correlated into this trace; resolves with the decision. */ inspectResult(params: ToolResultParams): Promise; /** * Correlation headers for AI Gateway model calls: point any OpenAI-compatible * client at the AxioRank proxy with these as default headers and its LLM turns * stitch into this run on /runs, next to the tool calls. * * @example * ```ts * const t = axio.trace({ sessionId }); * const openai = new OpenAI({ * baseURL: "https://www.axiorank.com/api/proxy/v1", * defaultHeaders: { "X-AxioRank-Key": key, ...t.headers() }, * }); * ``` */ headers(): Record; /** * A sub-agent view of this run: every call made through the child handle * nests under the spawning step on the run timeline (parentStepIndex), while * sharing the run's trace id, session, and step numbering. * * By default the parent is the step most recently issued by THIS handle * (typically the tool call that spawned the sub-agent); pass * `parentStepIndex` to pin a different one. Child metadata merges over the * handle's metadata. * * @example * ```ts * await t.enforce({ tool: "agents.spawn_researcher" }); // step 2 * const sub = t.child(); // children of step 2 * await sub.enforce({ tool: "web.search" }); // step 3, nested * ``` */ child(options?: { parentStepIndex?: number; metadata?: Record; }): AxioTrace; } /** Category of a content-inspection finding. The last two are inbound-only. */ type SignalCategory = "secret" | "pii" | "destructive" | "injection" | "egress" | "bot_spoof" | "rate_abuse"; /** A redacted content-inspection finding on the tool-call payload. */ interface ToolCallSignal { /** Stable detector id, e.g. `"secret.aws_access_key"`. */ detector: string; category: SignalCategory; severity: "low" | "medium" | "high" | "critical"; /** Human-readable label, e.g. `"AWS access key id"`. */ label: string; /** Argument path where it was found, e.g. `"env.AWS_SECRET"`. */ location: string; /** Redacted evidence (fingerprint/mask) - never the raw value. */ evidence: string; } /** * An Agent Action Passport: a compact, Ed25519-signed proof that one action was * governed, returned when you opt in via {@link ToolCallParams.passport} and the * workspace enabled passports. Present it to a counterparty (for example as an * `AxioRank-Action-Passport` header); they verify it OFFLINE against AxioRank's * published JWKS with the `@axiorank/audit-verify` package, with zero trust in * AxioRank. Mirrors the server shape (apps/web/lib/audit-integrity/passport.ts). */ interface ActionPassport { passportVersion: number; kind: "axiorank-action-passport-v1"; auditLogId: string; workspaceId: string; agentId: string; toolName: string; /** The governance verdict at action time (a `hold` passport proves a human gate fired). */ decision: "allow" | "deny" | "hold"; riskScore: number; signalCategories: string[]; /** Hex SHA-256 commitment to the audit leaf sealed into the transparency log. */ rowHash: string; logId: string; issuedAt: string; expiresAt: string; /** The embedded, independently-signed provenance token (verify offline). */ provenance: Record; keyId: string; algorithm: "EdDSA"; signature: string; } interface ToolCallResult { /** `allow` or `deny`. */ decision: Decision; /** Human-readable explanation for the decision. */ reason: string; /** Risk score (0–100) AxioRank assigned to this call. */ risk: number; /** ID of the audit-log row recorded for this call. */ auditLogId: string; /** * Redacted content-inspection signals that contributed to the risk score. * Optional - older gateways may not return it. */ signals?: ToolCallSignal[]; /** * True when the workspace enforces information-flow control. The guard wrappers * use it to decide whether to report this tool's result for taint tracking. */ ifc?: boolean; /** * Set to "redact" when a `redact` policy masked a model completion. The decision * stays "allow"; swap in {@link redactedText}. Only on the model-I/O path. */ transform?: "redact"; /** * The masked completion to return to the caller, byte-identical to the audited * payload. Present only when {@link transform} is "redact". */ redactedText?: string; /** * A signed taint handle for this run's accumulated taint, returned on a * `result`-phase call. Attach it to an A2A handoff (pass it as the receiving * agent's {@link ToolResultParams.taintHandle}) so taint follows the value * across agents. Present only when there is taint to carry forward. */ taintHandle?: string; /** * True when this result did NOT come from a real gateway decision but from the * client's unavailability posture (the gateway was unreachable). The `decision` * reflects `fail_open` (allow) or `fail_closed` (deny). Lets callers and telemetry * tell a degraded allow apart from a governed one. */ degraded?: boolean; /** * The unavailability posture the gateway reports for this agent/workspace - what * the SDK assumes if the gateway later becomes unreachable. The client caches the * last value it sees. Older gateways omit it. */ unavailabilityBehavior?: "fail_open" | "fail_closed"; /** * An {@link ActionPassport} for this call - a portable, signed proof-of-governance * you can hand to a counterparty for offline verification. Present only when you * opted in via {@link ToolCallParams.passport} AND the workspace enabled passports. */ passport?: ActionPassport; } /** Three-way verdict for an inbound agent request. */ type InboundDecision = "allow" | "challenge" | "block"; /** How (or whether) a visiting agent proved its identity. */ type VerificationStatus = "verified" | "unverified" | "spoofed" | "unknown"; /** The method that produced the verification status. */ type VerificationMethod = "web_bot_auth" | "reverse_dns" | "known_ua" | "unverifiable" | "agent_card" | "oauth_token" | "mtls_spiffe" | "api_key" | "governance_passport"; /** Kind of inbound surface an agent reaches into. */ type InboundSurfaceKind = "website" | "http_api" | "mcp_server" | "a2a_agent" | "webhook"; /** * How a caller should ENFORCE a `challenge`/`block` verdict, per surface kind. * The verdict itself is always allow/challenge/block; this is the wire mapping * the SDK applies (HTTP status, JSON-RPC error, OAuth step-up, or A2A task state). */ interface ChallengeInstruction { transport: "http" | "http_stepup" | "jsonrpc" | "a2a_task"; httpStatus?: number; httpHeaders?: Record; jsonRpcError?: { code: number; message: string; data?: unknown; }; a2aTaskState?: "auth-required" | "rejected"; } /** Result of verifying an inbound request against AxioRank. */ interface VerifyRequestResult { /** `allow`, `challenge`, or `block`. Already reflects the site's posture. */ decision: InboundDecision; reason: string; /** Risk score (0–100) for the request. */ risk: number; verification: { status: VerificationStatus; method: VerificationMethod | null; /** known_agents slug, e.g. "openai-gptbot", or null. */ agentSlug: string | null; /** Human label, e.g. "GPTBot", or null. */ agentLabel: string | null; /** 0..100 - cryptographic proof = 100, reverse-DNS = 70, UA match = 40. */ confidence: number; }; /** false under `monitor` posture: computed + logged, but not acted on. */ enforced: boolean; signals?: ToolCallSignal[]; /** ID of the inbound request log row, or "" when AxioRank was unreachable. */ requestId: string; /** * Per-kind enforcement instruction for a non-allow verdict (HTTP status / * JSON-RPC error / OAuth step-up / A2A task state). Returned by newer gateways * for every surface kind; older gateways omit it. */ challenge?: ChallengeInstruction; /** * When the caller presented an Agent Action Passport, the governance verdict it * carried: what AxioRank decided about the calling agent's action. Lets you act on * the decision, not just the identity. Present only for a passport handshake. */ governance?: { decision: string; toolName: string; riskScore: number; auditLogId: string; expired: boolean; }; } /** * Parameters for {@link verifySurface} - verify the agent reaching into a * non-website surface you operate (an MCP server, an A2A agent, an HTTP API, or a * webhook), where there is no standard `Request` to hand to {@link verifyRequest}. */ interface VerifySurfaceParams { /** The kind of surface being called. */ surfaceKind: Exclude; /** Operation invoked: MCP tool name, JSON-RPC method, or API operationId. */ operation?: string; /** mcp_server / a2a_agent: the connecting agent's signed card, inline. */ agentCard?: unknown; /** mcp_server / a2a_agent: a URL to fetch the caller's card from. */ agentCardUrl?: string; /** http_api: the caller's OAuth/OIDC bearer token (no `Bearer ` prefix). */ authToken?: string; /** * http_api / webhook: forwarded request headers. Carry the mTLS/SPIFFE id * (`x-forwarded-client-cert` / `x-spiffe-id`) or an API-key header here. */ headers?: Record; /** http_api / webhook: HTTP method, when the surface is HTTP-shaped. */ method?: string; /** http_api / webhook: the host the caller hit. */ authority?: string; /** http_api / webhook: the request path. */ path?: string; /** The calling agent's IP, if you have it. */ clientIp?: string; /** The caller's user-agent, if any. */ userAgent?: string; /** A bounded, redacted sample of the request body for content inspection. */ bodySample?: string; /** * An Agent Action Passport the caller presented (the agent-to-service handshake). * When set, it is the identity material: AxioRank verifies it and returns the * carried governance verdict on {@link VerifyRequestResult.governance}. */ governancePassport?: unknown; } interface AxioGuardOptions { /** Your property's site key (looks like `axr_site_...`). */ apiKey: string; /** @default "https://app.axiorank.com" */ baseUrl?: string; /** * Per-request timeout in milliseconds. Kept short - inbound verification sits * in the hot path of your site's requests. * @default 800 */ timeoutMs?: number; fetch?: typeof fetch; /** * Bytes of the request body to sample and forward for inspection. * @default 16384 */ bodySampleBytes?: number; /** * What verdict to assume if AxioRank is unreachable or slow. Defaults to * fail-open so a verification outage never takes your site down. * @default "allow" */ onError?: InboundDecision; /** * When false, never block - verify and record only (the verdict is still * computed and logged server-side). Useful for a monitor-first rollout. * @default true */ enforce?: boolean; /** * Map a `challenge` decision to a custom Response (e.g. a redirect to a * human-verification interstitial). Return undefined to fall back to a 401. */ onChallenge?: (req: Request, result: VerifyRequestResult) => Response | undefined; } /** Discovery + Identity protocols AxioRank can preflight. */ type ProtocolId = "a2a" | "mcp"; /** Three-way verdict for a card preflight. Precedence: deny > review > allow. */ type CardDecision = "allow" | "review" | "deny"; interface VerifyCardParams { /** URL to fetch the target's card from (A2A Agent Card URL / MCP server base). */ url?: string; /** An inline card document you already hold (skips the network fetch). */ document?: unknown; /** Optional protocol hint; otherwise auto-detected. */ protocol?: ProtocolId; } /** Result of preflighting an external MCP server / A2A agent. */ interface CardVerifyResult { /** `allow`, `review` (hold for a human), or `deny`. */ decision: CardDecision; reason: string; /** Risk score (0–100) for the target. */ risk: number; protocol: ProtocolId; identity: { name: string | null; provider: string | null; /** The card carried a signature. */ signed: boolean; /** true = verified · false = forged · null = unsigned / key unresolvable. */ signatureValid: boolean | null; keySource: "embedded" | "jwks" | "none"; /** The verifying key is anchored to the card's own domain. */ keyDomainBound: boolean; keyId: string | null; sourceUrl: string; }; capabilities: { count: number; sample: { kind: string; name: string; }[]; }; auth: { schemes: string[]; protectedResource: boolean; }; warnings: string[]; signals?: ToolCallSignal[]; /** ID of the recorded card_verifications row. */ cardId: string; } export type { AxioRankOptions as A, CardVerifyResult as C, Decision as D, InboundDecision as I, ProtocolId as P, SignalCategory as S, ToolCallResult as T, VerifyCardParams as V, ToolCallParams as a, ToolResultParams as b, AxioTrace as c, ToolCallSignal as d, AxioGuardOptions as e, VerifyRequestResult as f, VerifySurfaceParams as g, CardDecision as h, ChallengeInstruction as i, InboundSurfaceKind as j, VerificationMethod as k, VerificationStatus as l };