TypeScript SDK
El paquete oficial @shieldagent/sdk proporciona un cliente con tipos para la API REST de ShieldAgent. Funciona en Node.js 18+ y empaquetadores modernos.
Instalación
Aún no disponible en npm
El paquete @shieldagent/sdk no ha sido publicado en npm todavía. Instala desde el repositorio fuente:
git clone https://github.com/shieldagent-io/shieldagent.git
npm install ./shieldagent/backend/packages/sdk-tsInicio rápido
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',
});Reenvío de llamadas API a través del proxy
Usa client.apiProxy() para enrutar las llamadas REST del agente a través de ShieldAgent. Cada solicitud es autenticada, verificada por políticas, escaneada por DLP y registrada en auditoría antes de ser reenviada al upstream registrado.
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 — escanear y confirmar
Usa client.scan() para enviar una llamada de herramienta a ShieldAgent antes de ejecutarla. El proxy devuelve un veredicto (allow / block / human_review) pero no lo aplica— tu código debe comprobar el veredicto y bloquear la ejecución cuando la acción sea "block". Llama a client.confirmExecution() después para cerrar el ciclo de auditoría y respaldar las declaraciones de cumplimiento del Art. 9 de la Ley de IA de la UE.
Cuando el proxy se ejecuta en un host diferente al de la API de gestión, pasa proxyUrl al constructor del cliente.
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)Gestión de políticas
// 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);Monitoreo de riesgo y detección de anomalías
// 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);
}Flujos de trabajo de incidentes y revisiones
// 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' });
}Manejo de errores
Clases de error con tipos
ForbiddenError403 — La política de ShieldAgent bloqueó la llamada. Consulta err.code para el ID de regla coincidente.RateLimitError429 — Límite de tasa por tenant o por agente superado. err.retryAfter indica el timestamp de restablecimiento.BadGatewayError502 — Servicio upstream inalcanzable o devolvió 5xx. Seguro reintentar con backoff.ShieldAgentErrorClase base para todos los errores del SDK. err.status · err.code · err.message siempre presentes.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);
}
}