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}',
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) {
console.error('Blocked by policy:', err.code, err.message);
} else if (err instanceof RateLimitError) {
console.error('Rate limited. Retry after:', err.retryAfter);
} else if (err instanceof BadGatewayError) {
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',
proxyUrl: 'https://proxy.shieldagent.io',
});
// ── 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') {
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);
}
}