TypeScript SDK
The official @shieldagent/sdk package provides a typed client for the ShieldAgent REST API. Works in Node.js 18+ and modern bundlers.
Installation
Not yet on npm
The @shieldagent/sdk package has not been published to npm yet. Install from the source repository:
git clone https://github.com/shieldagent-io/shieldagent.git
npm install ./shieldagent/backend/packages/sdk-tsQuick start
import { ShieldAgentClient } from '@shieldagent/sdk';
const client = new ShieldAgentClient({
apiKey: '{your-api-key}',
baseUrl: 'https://api.shieldagent.io',
});
// List agents for a tenant
const agents = await client.agents.list({ tenantId: 'ten_abc123' });
console.log(agents);
// Register a new agent
const agent = await client.agents.create({
tenantId: 'ten_abc123',
name: 'my-assistant',
description: 'Coding assistant agent',
});
console.log(agent.agentKey); // sa_live_...
// Fetch recent audit events
const events = await client.audit.list({
tenantId: 'ten_abc123',
limit: 50,
order: 'desc',
});Proxy-forwarding API calls
Use client.apiProxy() to route agent REST calls through ShieldAgent. Every request is authenticated, policy-checked, DLP-scanned, and audit-logged before being forwarded to the registered upstream.
import { ShieldAgentClient, ForbiddenError, RateLimitError, BadGatewayError } from '@shieldagent/sdk';
const client = new ShieldAgentClient({
apiKey: '{your-agent-key}', // agent key, not admin key
baseUrl: 'https://proxy.shieldagent.io',
});
// ── POST through the proxy ─────────────────────────────────────────────────
const charge = await client.apiProxy('stripe', {
method: 'POST',
path: '/charges',
body: { amount: 2000, currency: 'usd', source: 'tok_visa' },
});
// ── GET a specific resource ────────────────────────────────────────────────
const customer = await client.apiProxy('stripe', {
method: 'GET',
path: '/customers/cus_abc123',
});
// ── Send a Slack message ───────────────────────────────────────────────────
await client.apiProxy('slack', {
method: 'POST',
path: '/chat.postMessage',
body: { channel: '#alerts', text: 'Anomaly detected on agent my-assistant' },
});
// ── Call an internal microservice ─────────────────────────────────────────
const result = await client.apiProxy('order-service', {
method: 'POST',
path: '/orders',
body: { customerId: 'cust_42', items: [{ sku: 'ABC', qty: 1 }] },
});
// ── Error handling ─────────────────────────────────────────────────────────
try {
await client.apiProxy('stripe', { method: 'DELETE', path: '/charges/ch_123' });
} catch (err) {
if (err instanceof ForbiddenError) {
// Policy denied the call — ShieldAgent blocked it
console.error('Blocked by policy:', err.code, err.message);
} else if (err instanceof RateLimitError) {
// Per-tenant rate limit exceeded
console.error('Rate limited. Retry after:', err.retryAfter);
} else if (err instanceof BadGatewayError) {
// Upstream unreachable or returned 5xx
console.error('Upstream error:', err.message);
}
}Verdict API — scan & confirm
Use client.scan() to submit a tool call to ShieldAgent before executing it. The proxy returns a verdict (allow / block / human_review) but does not enforce it — your code must check the verdict and block execution when the action is "block". Call client.confirmExecution() afterwards to close the audit loop and support EU AI Act Art. 9 compliance claims.
When the proxy runs on a different host from the Management API, pass proxyUrl to the client constructor.
import { ShieldAgentClient } from '@shieldagent/sdk';
const client = new ShieldAgentClient({
apiKey: '{your-agent-key}',
baseUrl: 'https://api.shieldagent.io', // Management API
proxyUrl: 'https://proxy.shieldagent.io', // Proxy (omit if same host)
});
// ── 1. Scan before executing ───────────────────────────────────────────────
const verdict = await client.scan({
tenantId: 'ten_abc123',
toolName: 'read_file',
params: { path: '/etc/passwd' },
agentId: 'agt_xyz789', // optional — improves policy matching
includeFindings: true, // optional — request detailed findings
});
// IMPORTANT: YOU must enforce the verdict. ShieldAgent does not block the call.
if (verdict.action === 'block') {
throw new Error(`Tool call blocked: ${verdict.reason}`);
}
if (verdict.action === 'human_review') {
// Pause and wait for a human reviewer to approve via the dashboard
throw new Error(`Tool call requires human review (reviewId: ${verdict.reviewId})`);
}
// ── 2. Execute the tool ────────────────────────────────────────────────────
const fileContent = await readFile('/etc/passwd');
// ── 3. Confirm execution to close the audit loop ───────────────────────────
await client.confirmExecution('ten_abc123', verdict.auditEventId, {
executed: true,
});
// ── Verdict shape ──────────────────────────────────────────────────────────
// verdict.action — 'allow' | 'block' | 'human_review'
// verdict.reason — human-readable explanation
// verdict.riskScore — 0–100 risk score at scan time
// verdict.auditEventId — use with confirmExecution()
// verdict.reviewId — review ID when action is 'human_review', else null
// verdict.findings[] — detailed findings (only when includeFindings: true)Policy management
// Apply a policy template (e.g. "pii-protection") to a tenant
const result = await client.policyTemplates.apply('ten_abc123', 'pii-protection');
console.log(`Created ${result.policiesCreated} policies from template "${result.templateName}"`);
// Create a custom deny rule — block DELETE on the Stripe endpoint for a specific agent
await client.policies.create('ten_abc123', {
agentId: agent.id,
toolName: 'rest:stripe',
action: 'deny',
conditions: { method: 'DELETE' },
});
// List active policies for an agent
const policies = await client.policies.list('ten_abc123', { agentId: agent.id });
console.log(policies.data);Risk monitoring & anomaly detection
// Get current risk scores for all agents
const scores = await client.risk.list('ten_abc123');
const highRisk = scores.data.filter(s => s.riskTier === 'high' || s.riskTier === 'critical');
console.log('High-risk agents:', highRisk.map(s => s.agentName));
// Drill into a specific agent's risk trend
const detail = await client.risk.getDetail('ten_abc123', agent.id);
console.log(`Risk: ${detail.score} (${detail.trend}) — delta 24h: ${detail.deltaVs24h}`);
// Analyze a batch of recent events for anomalies
const anomalies = await client.anomalies.analyzeBatch('ten_abc123', {
agentId: agent.id,
windowHours: 24,
});
if (anomalies.anomaliesDetected > 0) {
console.warn('Anomalies detected:', anomalies.results);
}Incident & review workflows
// Open an incident when a critical threat is detected
const incident = await client.incidents.create('ten_abc123', {
agentId: agent.id,
title: 'Prompt injection detected in session ses_xyz',
severity: 'critical',
type: 'injection',
data: { sessionId: 'ses_xyz', payload: '...' },
});
// Move incident to "investigating"
await client.incidents.update(incident.id, { status: 'investigating' });
// Process the human-review queue — approve or deny pending tool calls
const pending = await client.reviews.list('ten_abc123', { status: 'pending' });
for (const review of pending.data) {
const decision = review.toolName.startsWith('rest:stripe') ? 'denied' : 'approved';
await client.reviews.decide(review.id, { decision, comment: 'Reviewed by on-call' });
}Error handling
Typed error classes
ForbiddenError403 — ShieldAgent policy blocked the call. Check err.code for the matching rule ID.RateLimitError429 — Per-tenant or per-agent rate limit exceeded. err.retryAfter gives the reset timestamp.BadGatewayError502 — Upstream service unreachable or returned 5xx. Safe to retry with backoff.ShieldAgentErrorBase class for all SDK errors. err.status · err.code · err.message always present.import { ShieldAgentError } from '@shieldagent/sdk';
try {
await client.agents.create({ tenantId: 'bad-id', name: 'x' });
} catch (err) {
if (err instanceof ShieldAgentError) {
console.error(err.status, err.code, err.message);
}
}