Choose your SDK
Same feature surface across both runtimes. Pick one — examples adapt automatically.
Installation
npm install @execlave/sdkZero runtime dependencies. Supports Node.js 18+ and modern bundlers for browser-side usage. TypeScript types included.
Initialization
import { Execlave } from '@execlave/sdk'; const ag = new Execlave({ apiKey: process.env.EXECLAVE_API_KEY!, // required baseUrl: 'https://api.execlave.com', // default environment: 'production', // default asyncMode: true, // default: buffer traces batchSize: 100, // max traces per flush flushIntervalMs: 10_000, // 10s flush interval debug: false, // verbose logging enableControlChannel: true, // kill-switch polling pollIntervalMs: 15_000, // poll interval enableInjectionScan: true, // tags traces with injection score (does NOT block) enforcementOnOutage: 'fail_open', // fail_open | fail_closed policyCacheTtlMs: 60_000, // policy decision cache TTL});Create a single Execlave instance and share it across your app. The SDK manages connection pooling, batching, and background flushing internally.
Methods
registerAgent
ag.registerAgent(config: AgentConfig): Promise<Agent>Register a new agent or update an existing one. Idempotent — safe to call on every app startup.
§ Parameters
agentIdstringUnique identifier for the agentnamestringDisplay nametype?stringchatbot | copilot | autonomous | workflow | data_processingplatform?stringcustom | openai | anthropic | langchainenvironment?'development' | 'staging' | 'production'Defaults to development. Pin to production when running in prod.description?stringAgent descriptionownerEmail?stringSurfaced in the dashboard and on policy violation alerts.allowedDataSources?string[]Governance allowlist of data sources the agent may read (e.g. ["s3://bucket-x", "postgres://orders"]). Enforced by data-access policies.allowedActions?string[]Governance allowlist of tool/action names this agent may invoke. Anything not on the list is blocked by default.requiresHumanApprovalFor?string[]Action names that always go to the human-approval queue regardless of policy outcome (e.g. ["wire_transfer", "delete_customer"]).tags?string[]Tags for filteringmetadata?Record<string, unknown>Free-form metadata stored on the agent record (cost-center IDs, owning team, ticket links).§ Returns
Promise<Agent>await ag.registerAgent({ agentId: 'support-bot', name: 'Customer Support Bot', type: 'chatbot', platform: 'openai', environment: 'production', ownerEmail: 'support-team@example.com', allowedDataSources: ['postgres://customers'], allowedActions: ['search_kb', 'create_ticket'], requiresHumanApprovalFor: ['issue_refund'], tags: ['support', 'tier-1'], metadata: { costCenter: 'CS-101' },});enforcePolicy
ag.enforcePolicy(opts): Promise<EnforcementDecision>Synchronous pre-execution policy check. Call this BEFORE every LLM invocation. Throws PolicyBlockedError on a block-mode violation, AgentPausedError if the agent is kill-switched, and EnforcementUnavailableError only when enforcementOnOutage is 'fail_closed'. Tracing alone does NOT block — this method is the gate.
§ Parameters
agentIdstringAgent performing the callinputstringUser input being sent to the LLMenvironment?EnvironmentOverride the client environment for this checkmetadata?Record<string, unknown>Optional metadata for custom validatorsestimatedCost?numberEstimated call cost in USD (for budget policies)tools?string[]Tool names the agent intends to use (for action_approval policies)§ Returns
Promise<EnforcementDecision>. Throws PolicyBlockedError if blocked.import { AgentPausedError, PolicyBlockedError } from '@execlave/sdk'; try { await ag.enforcePolicy({ agentId: 'support-bot', input: userQuestion }); const answer = await llm.call(userQuestion);} catch (err) { if (err instanceof PolicyBlockedError) { // err.violations: list of { policyType, policyName, severity, message, enforcementMode } return 'Your input was blocked by our content policies.'; } if (err instanceof AgentPausedError) { return 'Service temporarily unavailable.'; } throw err;}startTrace
ag.startTrace(opts: TraceOptions): TraceStart a new trace to record an LLM interaction. Returns a chainable Trace object. Tracing is post-hoc — it does NOT block the LLM call. Pair with enforcePolicy() to actually block requests.
§ Parameters
agentIdstringAgent performing the tracesessionId?stringGroup traces into conversations§ Returns
Traceconst trace = ag.startTrace({ agentId: 'support-bot' });trace .setInput('How do I reset my password?') .setOutput('Go to Settings > Security...') .setModel('gpt-4') .setTokens(150, 320) .setCost(0.0045) .finish(); // Or finish with error:trace.finish('error', 'LLM call timed out');wrap
ag.wrap<T>(fn, opts): (input: string) => Promise<T>Wrap a function with automatic tracing. Input/output are captured, and the trace is finished on return or error.
§ Parameters
fnFunctionAsync function to wrapopts.agentIdstringAgent performing the call§ Returns
Wrapped function with same signatureconst tracedAnswer = ag.wrap( async (question: string) => { const res = await openai.chat.completions.create({ model: 'gpt-4', messages: [{ role: 'user', content: question }], }); return res.choices[0].message.content; }, { agentId: 'support-bot' }); // Usage — fully traced automaticallyconst answer = await tracedAnswer('How do I upgrade?');shutdown
ag.shutdown(): Promise<void>Flush all buffered traces and close connections. Call on process exit.
§ Returns
Promise<void>process.on('SIGTERM', async () => { await ag.shutdown(); process.exit(0);});Error types
Thrown when a trace is started for an agent that has been paused via the kill switch. Your app should catch this and return a graceful fallback to the user.
Thrown when a pre-execution policy check blocks the request. Contains the violated policy name and enforcement mode.
Privacy & PII scrubbing
The TypeScript SDK can score every input for prompt-injection likelihood and tag the resulting trace with that score. This is metadata only — it does not block the LLM call. To actually block injection attempts, create an injection_scan policy in block mode and call ag.enforcePolicy() before your LLM invocation. Server-side PII scrubbing is performed by the processing service on ingestion.
const ag = new Execlave({ apiKey: process.env.EXECLAVE_API_KEY!, enableInjectionScan: true, // tags traces with injection score (does NOT block)}); // To block: create a block-mode injection_scan policy in the dashboard,// then gate every LLM call with enforcePolicy().await ag.enforcePolicy({ agentId: 'support-bot', input: userQuestion });OpenTelemetry integration
Switch the SDK into OTLP transport by setting mode: 'otlp' and pointing otlpEndpoint at the base URL of your OTLP collector (the SDK appends /v1/traces automatically). Use an OTLP-capable collector — do not point this at the Execlave REST API.
import { Execlave } from '@execlave/sdk'; const exe = new Execlave({ apiKey: process.env.EXECLAVE_API_KEY!, mode: 'otlp', // Base URL of your OTLP collector — exporter appends /v1/traces. // e.g. http://localhost:4317 or your managed collector's base URL. otlpEndpoint: process.env.OTLP_ENDPOINT!,}); // Traces emitted by the SDK are exported via OTLP instead of the// native REST ingest, so they flow through your existing collector// pipeline alongside the rest of your telemetry.