SDKs & API
Node.js / TypeScript SDK
Guard, mask and log LLM calls from Node.js with agentid-sdk, including an OpenAI wrapper, LangChain callbacks and workflow telemetry.
agentid-sdk (version 0.1.43) runs on Node.js 18 or later, in server and serverless runtimes.
Install
npm install agentid-sdk openainpm install agentid-sdk openai @langchain/core @langchain/openainpm install agentid-sdkexport AGENTID_API_KEY="sk_live_..."
export AGENTID_SYSTEM_ID="00000000-0000-0000-0000-000000000000"Initialize
import { AgentID } from "agentid-sdk";
const agent = new AgentID(); // reads AGENTID_API_KEYCreate one instance and reuse it across requests.
apiKeystringAPI key. Defaults to AGENTID_API_KEY.
baseUrlstringDefaults to https://app.getagentid.com/api/v1.
strictModebooleanFail-closed on Guard connectivity failures. Cannot be combined with failureMode: fail_open.
failureMode"fail_open" | "fail_close"Overrides the system's failure mode. Omit to follow the dashboard.
piiMaskingbooleanForce local masking of personal data. Omit to follow the dashboard.
secretMaskingbooleanForce local masking of secrets. Omit to follow the dashboard.
clientFastFailbooleanRun a local prompt-injection preflight before Guard. Off by default.
guardTimeoutMsnumberGuard timeout, default 30000 (500 to 120000).
ingestTimeoutMsnumberIngest timeout, default 10000 (500 to 15000).
Wrap the OpenAI client
The wrapper guards, masks and logs every chat.completions.create call, including stream: true (logged when the stream ends).
import OpenAI from "openai";
import { AgentID, SecurityBlockError } from "agentid-sdk";
const agent = new AgentID();
const openai = agent.wrapOpenAI(new OpenAI(), {
system_id: process.env.AGENTID_SYSTEM_ID!,
user_id: "customer-123",
expected_languages: ["en"],
});
try {
const response = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: fullConversationHistory,
});
console.log(response.choices[0]?.message?.content);
} catch (error) {
if (error instanceof SecurityBlockError) {
console.error("Blocked by AgentID:", error.reason);
} else {
throw error;
}
}wrapOpenAI(openai, options) options: system_id (required), user_id, expected_languages, request_identity, telemetry, apiKey or resolveApiKey(request), and deanonymizeOutputForClient.
Its pre-flight guard() input is the last user message (plus supported inline attachments on it). With SDK-side masking on, the full history sent to the provider is masked locally.
Manual guard and log
import { AgentID } from "agentid-sdk";
const agent = new AgentID();
const systemId = process.env.AGENTID_SYSTEM_ID!;
const verdict = await agent.guard({
system_id: systemId,
input: userMessage,
model: "gpt-4o-mini",
user_id: "customer-123",
});
if (!verdict.allowed) throw new Error(`Blocked: ${verdict.reason}`);
const protectedInput = verdict.transformed_input ?? userMessage;
const started = Date.now();
const completion = await callModel(protectedInput);
await agent.log({
system_id: systemId,
event_id: verdict.client_event_id,
model: "gpt-4o-mini",
input: protectedInput,
output: completion.text,
usage: completion.usage,
latency: Date.now() - started,
});guard(params, options?) accepts the Guard request fields (input, system_id, prompt_context, attachments, model, user_id, client_event_id, expected_languages, request_identity, metadata, pii_detection_mode). options.apiKey overrides the key for one call.
Masking and restoration
- The wrappers follow Mask Personal Information and Mask Secrets & API Keys from the dashboard. Set
piiMasking/secretMaskingonly to force local masking on. - Local masking covers e-mails, phone numbers, card numbers, IBANs, national IDs, person names, provider API keys and tokens, bearer tokens and JWTs, password and credential assignments, PEM private keys, and Azure connection strings and SAS tokens. It produces placeholders such as
<PERSON_1>and<EMAIL_1>. - From version 0.1.40, local masking stays on when Guard or the configuration endpoint is unreachable in fail-open mode.
- With Restore masked values for the end user on, the wrapper restores placeholders in the result returned to your code; the provider request and AgentID's logs stay masked. Opt out per wrapper with
deanonymizeOutputForClient: false.
For your own routes, protect the exact history you send:
import { protectMessageHistory, protectChatState } from "agentid-sdk";
const protectedHistory = protectMessageHistory(body.messages, { pii: true, secrets: true });
await provider.chat.completions.create({ model: "gpt-4o-mini", messages: protectedHistory.messages });
// Separate views for UI, provider and storage:
const chat = protectChatState(body.messages, {
transcript: { ui: "raw", provider: "masked", persistence: "masked" },
});protectMessageHistory returns messages, transformed, textPartsCount, transformedTextPartsCount and placeholderMapping. Keep the mapping in memory; do not persist it.
PIIManager gives direct access: new PIIManager().anonymize(text, { pii, secrets }) returns { maskedText, mapping }, and deanonymize(text, mapping) restores it.
LangChain
import { AgentID } from "agentid-sdk";
import { AgentIDCallbackHandler } from "agentid-sdk/langchain";
import { ChatOpenAI } from "@langchain/openai";
const agent = new AgentID();
const handler = new AgentIDCallbackHandler(agent, {
system_id: process.env.AGENTID_SYSTEM_ID!,
expected_languages: ["en"],
});
const model = new ChatOpenAI({ model: "gpt-4o-mini" });
const answer = await model.invoke("What is the capital of the Czech Republic?", {
callbacks: [handler],
});The handler guards before the model runs and logs on completion. Blocked prompts throw SecurityBlockError. Override telemetry per invocation with { metadata: { agentid_telemetry: { ... } } }.
Agent workflows
Log tool calls and operational steps as separate events grouped by one workflow run id:
import {
AgentID,
createAgentIdCorrelationId,
createAgentIdTelemetryContext,
createAgentIdWorkflowTrail,
} from "agentid-sdk";
const agent = new AgentID();
const trail = createAgentIdWorkflowTrail({
agent,
system_id: process.env.AGENTID_SYSTEM_ID!,
telemetry: createAgentIdTelemetryContext({
workflowRunId: createAgentIdCorrelationId(),
workflowName: "Invoice follow-up",
}),
});
await trail.runStep(
{
telemetry: createAgentIdTelemetryContext({
workflowStepName: "lookup_invoice",
toolName: "finance.invoice_lookup",
toolTargetType: "invoice",
eventCategory: "tool",
}),
},
async () => lookupInvoice(),
);runStep logs started, completed or failed automatically. For a single event use agent.logOperation({ system_id, telemetry, event_category, event_status }). Keep one client_event_id per event; group with workflowRunId.
Transparency badge
agentid-sdk/transparency-badge exports a React component that renders an AI disclosure and logs a transparency_badge_rendered event as evidence that the user saw it:
import { AgentIDTransparencyBadge } from "agentid-sdk/transparency-badge";
<AgentIDTransparencyBadge
telemetry={{
systemId: process.env.NEXT_PUBLIC_AGENTID_SYSTEM_ID!,
ingestUrl: "/api/agentid/transparency-render", // your backend relay; keep the API key server-side
userId: "customer-123",
}}
placement="chat-header"
/>;Errors
| Error | When |
|---|---|
SecurityBlockError (reason) | A wrapped call or LangChain run was blocked |
DependencyError (dependency, reason, status) | Ingest failed in fail-closed mode |
guard() itself does not throw on a block; it returns allowed: false. Ingest retries 5xx and 429 responses and logs a warning if it cannot store the event. See Errors and rate limits.