agentid-sdk 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,5 @@
1
+ import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
2
+
1
3
  type CapabilityConfig = {
2
4
  shadow_mode: boolean;
3
5
  block_pii_leakage: boolean;
@@ -82,7 +84,6 @@ declare class AgentID {
82
84
  private pii;
83
85
  private localEnforcer;
84
86
  private injectionScanner;
85
- private requestClientEventIds;
86
87
  private recentGuardVerdicts;
87
88
  constructor(config: AgentIDConfig);
88
89
  private buildClientCapabilities;
@@ -114,17 +115,17 @@ declare class AgentID {
114
115
  private wrapCompletion;
115
116
  /**
116
117
  * LOG: Sends telemetry after execution.
117
- * Non-blocking / Fire-and-forget.
118
+ * Returns a Promise so callers can await persistence when needed.
118
119
  */
119
- log(params: LogParams, options?: RequestOptions): void;
120
+ log(params: LogParams, options?: RequestOptions): Promise<void>;
120
121
  /**
121
122
  * Analytics alias for telemetry logging.
122
123
  */
123
- analytics(params: LogParams, options?: RequestOptions): void;
124
+ analytics(params: LogParams, options?: RequestOptions): Promise<void>;
124
125
  /**
125
126
  * Trace alias for telemetry logging.
126
127
  */
127
- trace(params: LogParams, options?: RequestOptions): void;
128
+ trace(params: LogParams, options?: RequestOptions): Promise<void>;
128
129
  /**
129
130
  * Wrap an OpenAI client once; AgentID will automatically:
130
131
  * - run guard() before chat.completions.create
@@ -146,7 +147,8 @@ declare class AgentID {
146
147
  * Usage (LangChain):
147
148
  * callbacks: [new AgentIDCallbackHandler(agent, { system_id: "..." })]
148
149
  */
149
- declare class AgentIDCallbackHandler {
150
+ declare class AgentIDCallbackHandler extends BaseCallbackHandler {
151
+ name: string;
150
152
  private agent;
151
153
  private systemId;
152
154
  private apiKeyOverride?;
@@ -1,3 +1,5 @@
1
+ import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
2
+
1
3
  type CapabilityConfig = {
2
4
  shadow_mode: boolean;
3
5
  block_pii_leakage: boolean;
@@ -82,7 +84,6 @@ declare class AgentID {
82
84
  private pii;
83
85
  private localEnforcer;
84
86
  private injectionScanner;
85
- private requestClientEventIds;
86
87
  private recentGuardVerdicts;
87
88
  constructor(config: AgentIDConfig);
88
89
  private buildClientCapabilities;
@@ -114,17 +115,17 @@ declare class AgentID {
114
115
  private wrapCompletion;
115
116
  /**
116
117
  * LOG: Sends telemetry after execution.
117
- * Non-blocking / Fire-and-forget.
118
+ * Returns a Promise so callers can await persistence when needed.
118
119
  */
119
- log(params: LogParams, options?: RequestOptions): void;
120
+ log(params: LogParams, options?: RequestOptions): Promise<void>;
120
121
  /**
121
122
  * Analytics alias for telemetry logging.
122
123
  */
123
- analytics(params: LogParams, options?: RequestOptions): void;
124
+ analytics(params: LogParams, options?: RequestOptions): Promise<void>;
124
125
  /**
125
126
  * Trace alias for telemetry logging.
126
127
  */
127
- trace(params: LogParams, options?: RequestOptions): void;
128
+ trace(params: LogParams, options?: RequestOptions): Promise<void>;
128
129
  /**
129
130
  * Wrap an OpenAI client once; AgentID will automatically:
130
131
  * - run guard() before chat.completions.create
@@ -146,7 +147,8 @@ declare class AgentID {
146
147
  * Usage (LangChain):
147
148
  * callbacks: [new AgentIDCallbackHandler(agent, { system_id: "..." })]
148
149
  */
149
- declare class AgentIDCallbackHandler {
150
+ declare class AgentIDCallbackHandler extends BaseCallbackHandler {
151
+ name: string;
150
152
  private agent;
151
153
  private systemId;
152
154
  private apiKeyOverride?;
@@ -1 +1,2 @@
1
- export { a as AgentIDCallbackHandler } from './langchain-CmUK7sna.mjs';
1
+ import '@langchain/core/callbacks/base';
2
+ export { a as AgentIDCallbackHandler } from './langchain-BykeB2WB.mjs';
@@ -1 +1,2 @@
1
- export { a as AgentIDCallbackHandler } from './langchain-CmUK7sna.js';
1
+ import '@langchain/core/callbacks/base';
2
+ export { a as AgentIDCallbackHandler } from './langchain-BykeB2WB.js';
package/dist/langchain.js CHANGED
@@ -23,9 +23,68 @@ __export(langchain_exports, {
23
23
  AgentIDCallbackHandler: () => AgentIDCallbackHandler
24
24
  });
25
25
  module.exports = __toCommonJS(langchain_exports);
26
+ var import_base = require("@langchain/core/callbacks/base");
26
27
  function safeString(val) {
27
28
  return typeof val === "string" ? val : "";
28
29
  }
30
+ function callbackDebugEnabled() {
31
+ try {
32
+ return typeof process !== "undefined" && process?.env?.AGENTID_DEBUG_CALLBACK === "1";
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+ function logCallbackDebug(message, details) {
38
+ if (!callbackDebugEnabled()) return;
39
+ if (details) {
40
+ console.log(`[AgentID][LC] ${message}`, details);
41
+ return;
42
+ }
43
+ console.log(`[AgentID][LC] ${message}`);
44
+ }
45
+ function extractTextFromContent(content) {
46
+ if (typeof content === "string") {
47
+ return content;
48
+ }
49
+ if (Array.isArray(content)) {
50
+ const parts = content.map((item) => {
51
+ if (typeof item === "string") return item;
52
+ if (!item || typeof item !== "object") return "";
53
+ const record = item;
54
+ if (typeof record.text === "string") return record.text;
55
+ if (typeof record.content === "string") return record.content;
56
+ return "";
57
+ }).filter((part) => part.length > 0);
58
+ return parts.join("\n");
59
+ }
60
+ if (content && typeof content === "object") {
61
+ const record = content;
62
+ if (typeof record.text === "string") return record.text;
63
+ if (typeof record.content === "string") return record.content;
64
+ }
65
+ return "";
66
+ }
67
+ function getMessageRole(msg) {
68
+ if (!msg || typeof msg !== "object") return null;
69
+ const typed = msg;
70
+ if (typeof typed.role === "string") return typed.role;
71
+ if (typeof typed.type === "string") return typed.type;
72
+ if (typeof typed._getType === "function") {
73
+ try {
74
+ const role = typed._getType();
75
+ if (typeof role === "string") return role;
76
+ } catch {
77
+ }
78
+ }
79
+ if (typeof typed.getType === "function") {
80
+ try {
81
+ const role = typed.getType();
82
+ if (typeof role === "string") return role;
83
+ } catch {
84
+ }
85
+ }
86
+ return null;
87
+ }
29
88
  function extractPromptFromPrompts(prompts) {
30
89
  if (Array.isArray(prompts) && prompts.length > 0) {
31
90
  return safeString(prompts[prompts.length - 1]);
@@ -46,7 +105,7 @@ function extractPromptFromMessages(messages) {
46
105
  let last = null;
47
106
  for (const msg of flat) {
48
107
  const typed = msg;
49
- const role = typed?.role ?? typed?.type;
108
+ const role = getMessageRole(msg);
50
109
  if (role === "user" || role === "human") {
51
110
  last = typed;
52
111
  }
@@ -55,7 +114,7 @@ function extractPromptFromMessages(messages) {
55
114
  return "";
56
115
  }
57
116
  const typedLast = last;
58
- return safeString(typedLast.content ?? typedLast.text);
117
+ return extractTextFromContent(typedLast.content ?? typedLast.text);
59
118
  }
60
119
  function setPromptInPrompts(prompts, sanitizedInput) {
61
120
  if (!Array.isArray(prompts) || prompts.length === 0) {
@@ -101,13 +160,33 @@ function setPromptInMessages(messages, sanitizedInput) {
101
160
  }
102
161
  function extractModel(serialized, kwargs) {
103
162
  const kw = (kwargs && typeof kwargs === "object" ? kwargs : null) ?? null;
104
- const model = kw?.model ?? kw?.model_name ?? kw?.modelName;
105
- if (typeof model === "string" && model) return model;
163
+ const directModel = kw?.model ?? kw?.model_name ?? kw?.modelName;
164
+ if (typeof directModel === "string" && directModel) return directModel;
165
+ const invocationModel = kw?.invocation_params?.model ?? kw?.invocation_params?.model_name ?? kw?.invocation_params?.modelName;
166
+ if (typeof invocationModel === "string" && invocationModel) return invocationModel;
167
+ const nestedModel = kw?.options?.model ?? kw?.options?.model_name ?? kw?.options?.modelName ?? kw?.kwargs?.model ?? kw?.kwargs?.model_name ?? kw?.kwargs?.modelName;
168
+ if (typeof nestedModel === "string" && nestedModel) return nestedModel;
106
169
  const ser = (serialized && typeof serialized === "object" ? serialized : null) ?? null;
170
+ const serKw = (ser?.kwargs && typeof ser.kwargs === "object" ? ser.kwargs : null) ?? null;
171
+ const serModel = serKw?.model ?? serKw?.model_name ?? serKw?.modelName;
172
+ if (typeof serModel === "string" && serModel) return serModel;
107
173
  const name = ser?.name ?? ser?.id;
108
174
  if (typeof name === "string" && name) return name;
109
175
  return void 0;
110
176
  }
177
+ function extractModelFromOutput(output) {
178
+ const llmOutput = output?.llmOutput ?? output?.llm_output;
179
+ const llmModel = llmOutput?.model ?? llmOutput?.model_name ?? llmOutput?.modelName;
180
+ if (typeof llmModel === "string" && llmModel) return llmModel;
181
+ const first = output?.generations?.[0]?.[0];
182
+ const responseMeta = first?.message?.response_metadata ?? first?.message?.responseMetadata;
183
+ const responseModel = responseMeta?.model_name ?? responseMeta?.model ?? responseMeta?.modelName;
184
+ if (typeof responseModel === "string" && responseModel) return responseModel;
185
+ const generationInfo = first?.generation_info ?? first?.generationInfo;
186
+ const genModel = generationInfo?.model_name ?? generationInfo?.model ?? generationInfo?.modelName;
187
+ if (typeof genModel === "string" && genModel) return genModel;
188
+ return void 0;
189
+ }
111
190
  function extractOutputText(output) {
112
191
  const gens = output?.generations;
113
192
  const first = gens?.[0]?.[0];
@@ -117,7 +196,33 @@ function extractOutputText(output) {
117
196
  function extractTokenUsage(output) {
118
197
  const llmOutput = output?.llmOutput ?? output?.llm_output;
119
198
  const usage = llmOutput?.tokenUsage ?? llmOutput?.token_usage ?? llmOutput?.usage ?? void 0;
120
- return usage && typeof usage === "object" ? usage : void 0;
199
+ if (usage && typeof usage === "object") {
200
+ return usage;
201
+ }
202
+ const first = output?.generations?.[0]?.[0];
203
+ const usageMetadata = first?.message?.usage_metadata;
204
+ if (usageMetadata && typeof usageMetadata === "object") {
205
+ return usageMetadata;
206
+ }
207
+ const responseTokenUsage = first?.message?.response_metadata?.token_usage ?? first?.message?.response_metadata?.tokenUsage ?? void 0;
208
+ if (responseTokenUsage && typeof responseTokenUsage === "object") {
209
+ return responseTokenUsage;
210
+ }
211
+ const generationTokenUsage = first?.generation_info?.token_usage ?? first?.generation_info?.tokenUsage ?? void 0;
212
+ if (generationTokenUsage && typeof generationTokenUsage === "object") {
213
+ return generationTokenUsage;
214
+ }
215
+ return void 0;
216
+ }
217
+ function isUuidLike(value) {
218
+ return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value.trim());
219
+ }
220
+ function createClientEventId() {
221
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
222
+ return crypto.randomUUID();
223
+ }
224
+ const segment = () => Math.floor((1 + Math.random()) * 65536).toString(16).slice(1);
225
+ return `${segment()}${segment()}-${segment()}-4${segment().slice(1)}-a${segment().slice(1)}-${segment()}${segment()}${segment()}`;
121
226
  }
122
227
  function readBooleanField(value) {
123
228
  return typeof value === "boolean" ? value : null;
@@ -137,8 +242,10 @@ function extractStreamFlag(serialized, extraParams) {
137
242
  const kwargs = serializedRecord?.kwargs && typeof serializedRecord.kwargs === "object" ? serializedRecord.kwargs : null;
138
243
  return readBooleanField(kwargs?.stream) ?? readBooleanField(kwargs?.streaming) ?? false;
139
244
  }
140
- var AgentIDCallbackHandler = class {
245
+ var AgentIDCallbackHandler = class extends import_base.BaseCallbackHandler {
141
246
  constructor(agent, options) {
247
+ super();
248
+ this.name = "agentid_callback_handler";
142
249
  this.runs = /* @__PURE__ */ new Map();
143
250
  this.agent = agent;
144
251
  this.systemId = options.system_id;
@@ -172,8 +279,9 @@ var AgentIDCallbackHandler = class {
172
279
  async handleLLMStart(serialized, prompts, runId, _parentRunId, extraParams) {
173
280
  const input = extractPromptFromPrompts(prompts);
174
281
  const id = String(runId ?? "");
282
+ logCallbackDebug("handleLLMStart", { runId: id, hasInput: input.length > 0 });
175
283
  if (!input) {
176
- throw new Error("AgentID: No prompt found. Security guard requires string input.");
284
+ return;
177
285
  }
178
286
  const stream = extractStreamFlag(serialized, extraParams);
179
287
  const sanitizedInput = await this.preflight(input, stream);
@@ -185,34 +293,46 @@ var AgentIDCallbackHandler = class {
185
293
  );
186
294
  }
187
295
  }
296
+ const requestedClientEventId = isUuidLike(id) ? id.trim() : createClientEventId();
297
+ const modelName = extractModel(serialized, extraParams);
188
298
  const verdict = await this.agent.guard({
189
299
  input: sanitizedInput,
190
300
  system_id: this.systemId,
301
+ model: modelName,
302
+ client_event_id: requestedClientEventId,
191
303
  client_capabilities: this.getLangchainCapabilities()
192
304
  }, this.requestOptions);
193
305
  if (!verdict.allowed) {
194
306
  throw new Error(`AgentID: Security Blocked (${verdict.reason ?? "guard_denied"})`);
195
307
  }
196
- const transformedInput = typeof verdict.transformed_input === "string" && verdict.transformed_input.length > 0 ? verdict.transformed_input : sanitizedInput;
308
+ const canonicalClientEventId = isUuidLike(verdict.client_event_id) ? verdict.client_event_id.trim() : requestedClientEventId;
309
+ const guardEventId = typeof verdict.guard_event_id === "string" && verdict.guard_event_id.length > 0 ? verdict.guard_event_id : void 0;
310
+ let transformedInput = typeof verdict.transformed_input === "string" && verdict.transformed_input.length > 0 ? verdict.transformed_input : sanitizedInput;
197
311
  if (transformedInput !== sanitizedInput) {
198
312
  const mutated = setPromptInPrompts(prompts, transformedInput);
199
313
  if (!mutated) {
200
- throw new Error(
201
- "AgentID: Guard transformed input could not be applied to LangChain prompt payload."
202
- );
314
+ transformedInput = sanitizedInput;
203
315
  }
204
316
  }
205
317
  this.runs.set(id, {
206
318
  input: transformedInput,
207
319
  startedAtMs: Date.now(),
208
- model: extractModel(serialized, extraParams)
320
+ model: modelName,
321
+ clientEventId: canonicalClientEventId,
322
+ guardEventId
323
+ });
324
+ logCallbackDebug("handleLLMStart state_set", {
325
+ runId: id,
326
+ clientEventId: canonicalClientEventId,
327
+ guardEventId: guardEventId ?? null
209
328
  });
210
329
  }
211
330
  async handleChatModelStart(serialized, messages, runId, _parentRunId, extraParams) {
212
331
  const input = extractPromptFromMessages(messages);
213
332
  const id = String(runId ?? "");
333
+ logCallbackDebug("handleChatModelStart", { runId: id, hasInput: input.length > 0 });
214
334
  if (!input) {
215
- throw new Error("AgentID: No user message found. Security guard requires string input.");
335
+ return;
216
336
  }
217
337
  const stream = extractStreamFlag(serialized, extraParams);
218
338
  const sanitizedInput = await this.preflight(input, stream);
@@ -224,62 +344,100 @@ var AgentIDCallbackHandler = class {
224
344
  );
225
345
  }
226
346
  }
347
+ const requestedClientEventId = isUuidLike(id) ? id.trim() : createClientEventId();
348
+ const modelName = extractModel(serialized, extraParams);
227
349
  const verdict = await this.agent.guard({
228
350
  input: sanitizedInput,
229
351
  system_id: this.systemId,
352
+ model: modelName,
353
+ client_event_id: requestedClientEventId,
230
354
  client_capabilities: this.getLangchainCapabilities()
231
355
  }, this.requestOptions);
232
356
  if (!verdict.allowed) {
233
357
  throw new Error(`AgentID: Security Blocked (${verdict.reason ?? "guard_denied"})`);
234
358
  }
235
- const transformedInput = typeof verdict.transformed_input === "string" && verdict.transformed_input.length > 0 ? verdict.transformed_input : sanitizedInput;
359
+ const canonicalClientEventId = isUuidLike(verdict.client_event_id) ? verdict.client_event_id.trim() : requestedClientEventId;
360
+ const guardEventId = typeof verdict.guard_event_id === "string" && verdict.guard_event_id.length > 0 ? verdict.guard_event_id : void 0;
361
+ let transformedInput = typeof verdict.transformed_input === "string" && verdict.transformed_input.length > 0 ? verdict.transformed_input : sanitizedInput;
236
362
  if (transformedInput !== sanitizedInput) {
237
363
  const mutated = setPromptInMessages(messages, transformedInput);
238
364
  if (!mutated) {
239
- throw new Error(
240
- "AgentID: Guard transformed input could not be applied to LangChain message payload."
241
- );
365
+ transformedInput = sanitizedInput;
242
366
  }
243
367
  }
244
368
  this.runs.set(id, {
245
369
  input: transformedInput,
246
370
  startedAtMs: Date.now(),
247
- model: extractModel(serialized, extraParams)
371
+ model: modelName,
372
+ clientEventId: canonicalClientEventId,
373
+ guardEventId
374
+ });
375
+ logCallbackDebug("handleChatModelStart state_set", {
376
+ runId: id,
377
+ clientEventId: canonicalClientEventId,
378
+ guardEventId: guardEventId ?? null
248
379
  });
249
380
  }
250
381
  async handleLLMEnd(output, runId) {
251
382
  const id = String(runId ?? "");
383
+ logCallbackDebug("handleLLMEnd", { runId: id });
252
384
  const state = this.runs.get(id);
253
- if (!state) return;
385
+ if (!state) {
386
+ logCallbackDebug("handleLLMEnd missing_state", { runId: id });
387
+ return;
388
+ }
254
389
  this.runs.delete(id);
255
390
  const latency = Date.now() - state.startedAtMs;
256
391
  const outText = extractOutputText(output);
257
392
  const usage = extractTokenUsage(output);
258
- this.agent.log({
393
+ const metadata = {};
394
+ if (state.clientEventId) {
395
+ metadata.client_event_id = state.clientEventId;
396
+ }
397
+ if (state.guardEventId) {
398
+ metadata.guard_event_id = state.guardEventId;
399
+ }
400
+ const resolvedModel = state.model ?? extractModelFromOutput(output) ?? "unknown";
401
+ await this.agent.log({
259
402
  system_id: this.systemId,
260
403
  input: state.input,
261
404
  output: outText,
262
- model: state.model ?? "unknown",
405
+ event_id: state.clientEventId,
406
+ model: resolvedModel,
263
407
  usage,
264
408
  latency,
409
+ metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
265
410
  client_capabilities: this.getLangchainCapabilities()
266
411
  }, this.requestOptions);
412
+ logCallbackDebug("handleLLMEnd logged", {
413
+ runId: id,
414
+ clientEventId: state.clientEventId ?? null
415
+ });
267
416
  }
268
417
  async handleLLMError(err, runId) {
269
418
  const id = String(runId ?? "");
419
+ logCallbackDebug("handleLLMError", { runId: id });
270
420
  const state = this.runs.get(id);
271
421
  if (state) this.runs.delete(id);
272
422
  const message = err && typeof err === "object" && "message" in err ? String(err.message) : String(err ?? "");
273
- this.agent.log({
423
+ const metadata = {
424
+ error_message: message
425
+ };
426
+ if (state?.clientEventId) {
427
+ metadata.client_event_id = state.clientEventId;
428
+ }
429
+ if (state?.guardEventId) {
430
+ metadata.guard_event_id = state.guardEventId;
431
+ }
432
+ await this.agent.log({
274
433
  system_id: this.systemId,
275
434
  input: state?.input ?? "",
276
435
  output: "",
436
+ event_id: state?.clientEventId,
277
437
  model: state?.model ?? "unknown",
278
438
  event_type: "error",
279
439
  severity: "error",
280
- metadata: {
281
- error_message: message
282
- },
440
+ metadata,
283
441
  client_capabilities: this.getLangchainCapabilities()
284
442
  }, this.requestOptions);
285
443
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AgentIDCallbackHandler
3
- } from "./chunk-DXUA5DKG.mjs";
3
+ } from "./chunk-6YR4ECGB.mjs";
4
4
  export {
5
5
  AgentIDCallbackHandler
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentid-sdk",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "AgentID JavaScript/TypeScript SDK for guard, ingest, tracing, and analytics.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://agentid.ai",
@@ -32,17 +32,21 @@
32
32
  "dist"
33
33
  ],
34
34
  "scripts": {
35
- "build": "tsup src/index.ts src/langchain.ts --format esm,cjs --dts --clean",
35
+ "build": "tsup --config tsup.config.ts",
36
36
  "prepublishOnly": "npm run build"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public"
40
40
  },
41
41
  "peerDependencies": {
42
+ "@langchain/core": "^0.3.0 || ^1.0.0",
42
43
  "openai": "^4.0.0 || ^5.0.0 || ^6.0.0",
43
44
  "langchain": "^0.1.0"
44
45
  },
45
46
  "peerDependenciesMeta": {
47
+ "@langchain/core": {
48
+ "optional": true
49
+ },
46
50
  "langchain": {
47
51
  "optional": true
48
52
  }