TypeScript SDK
The TypeScript SDK is the path of least resistance when you control the agent’s
source. Install, call init(), and every LLM call your code makes routes through
Lupid’s enforcement pipeline transparently.
Install
Section titled “Install”npm install @lupid/agentum-sdk# orpnpm add @lupid/agentum-sdkBootstrap
Section titled “Bootstrap”-
Get an API key for your agent. From the dashboard’s Admin → API Keys page, or from the CLI:
Terminal window agentum admin api-keys mint \--email "support-bot@yourco.com" \--role adminThe response includes a
plaintext_key— copy it now, it’s only shown once. -
Set environment variables for the agent process:
Terminal window export LUPID_BASE_URL=http://localhost:3000 # or your dashboard URLexport LUPID_API_KEY=ak_... # the plaintext key from step 1 -
Initialise the SDK at agent startup:
import { Lupid } from "@lupid/agentum-sdk";const lupid = await Lupid.init({baseUrl: process.env.LUPID_BASE_URL!,apiKey: process.env.LUPID_API_KEY!,agentName: "support-bot",declaredTools: ["search_kb", "create_ticket"],});init()does three things:- Resolves your
agentNameto the agent’s UUID (registers the agent if it doesn’t exist). - Installs
fetchinterceptors for the LLM hosts in the registry: OpenAI, Anthropic, Cohere, Google (Gemini /generativelanguage.googleapis.com), Azure OpenAI (*.openai.azure.com), plus the OpenAI-compatible providers Together, Mistral, Groq, DeepSeek, X.AI, Perplexity, OpenRouter, Fireworks, and Anyscale. Anyfetch()to one of those goes through Lupid’s policy engine before it leaves. - Returns a handle you can use for explicit policy checks (see below).
- Resolves your
That’s it. From this point on, your existing LLM call code runs unchanged but each call is policy-checked and audited.
Explicit tool-call gating
Section titled “Explicit tool-call gating”The fetch interceptors cover the transport. For policy decisions on app-level
tool dispatch (e.g. a LangChain agent picking create_ticket), call the gate
directly:
const decision = await lupid.evaluateToolCall("create_ticket", { customerId: "c_123", priority: "urgent",});
if (decision.allowed) { await createTicket(/* ... */);} else { // decision.rule_id and decision.reason are populated console.warn(`Lupid blocked create_ticket: ${decision.reason}`);}evaluateToolCall returns allow, deny, or require_hitl. On require_hitl,
the call parks in the approval queue and the promise resolves when an operator
clicks through (or after the timeout you set).
Streaming responses
Section titled “Streaming responses”The SDK handles streaming LLM responses transparently. Server-Sent Event chunks pass
through; the DLP-on-response check fires at the SSE boundary. If a chunk contains a
PII/secret hit above the block threshold, the stream is cut and the agent receives
a clean termination with the audit row pointing to the offending chunk’s hash.
Per-request overrides
Section titled “Per-request overrides”Most calls inherit the agent context from init(). To override per-request:
await lupid.evaluateToolCall("create_ticket", { ... }, { sessionId: "user-session-42", // bind the call to a user session userId: "u_alice", // bind to a specific end-user trustLevel: "low", // override the default trust level});The audit row records these on the event, so you can query “every action this user caused this agent to take” later.
Errors
Section titled “Errors”The SDK throws LupidPolicyError (for deny), LupidHitlError (for require_hitl
that timed out), and LupidNetworkError (for transport failures). Catch them
specifically:
import { Lupid, LupidPolicyError } from "@lupid/agentum-sdk";
try { await lupid.evaluateToolCall("delete_user", { id: 42 });} catch (e) { if (e instanceof LupidPolicyError) { // Policy denied — log and show user-friendly message return reply.status(403).send({ error: "not authorised" }); } throw e; // unknown error, let it propagate}Verifying the SDK is wired up
Section titled “Verifying the SDK is wired up”Right after init(), log a deliberate denied tool call and check the dashboard’s
audit page (/audit). You should see a tool_call event with outcome=deny
within a second. If you don’t, double-check LUPID_BASE_URL and that the API key
hasn’t been revoked.