agentid-sdk 0.1.12 → 0.1.14

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.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AgentID, a as AgentIDCallbackHandler, G as GuardParams, b as GuardResponse, L as LogParams, P as PreparedInput, R as RequestOptions } from './langchain-BGP3qxvW.mjs';
1
+ export { A as AgentID, a as AgentIDCallbackHandler, G as GuardParams, b as GuardResponse, L as LogParams, P as PreparedInput, R as RequestOptions } from './langchain-CmUK7sna.mjs';
2
2
 
3
3
  type PIIMapping = Record<string, string>;
4
4
  declare class PIIManager {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as AgentID, a as AgentIDCallbackHandler, G as GuardParams, b as GuardResponse, L as LogParams, P as PreparedInput, R as RequestOptions } from './langchain-BGP3qxvW.js';
1
+ export { A as AgentID, a as AgentIDCallbackHandler, G as GuardParams, b as GuardResponse, L as LogParams, P as PreparedInput, R as RequestOptions } from './langchain-CmUK7sna.js';
2
2
 
3
3
  type PIIMapping = Record<string, string>;
4
4
  declare class PIIManager {
package/dist/index.js CHANGED
@@ -1809,6 +1809,10 @@ var MIN_GUARD_TIMEOUT_MS = 500;
1809
1809
  var MAX_GUARD_TIMEOUT_MS = 15e3;
1810
1810
  var GUARD_MAX_ATTEMPTS = 3;
1811
1811
  var GUARD_RETRY_DELAYS_MS = [250, 500];
1812
+ var INGEST_MAX_ATTEMPTS = 3;
1813
+ var INGEST_RETRY_DELAYS_MS = [250, 500];
1814
+ var GUARD_VERDICT_CACHE_TTL_MS = 15e3;
1815
+ var MAX_INGEST_TEXT_CHARS = 32e3;
1812
1816
  function normalizeBaseUrl3(baseUrl) {
1813
1817
  return baseUrl.replace(/\/+$/, "");
1814
1818
  }
@@ -1882,18 +1886,41 @@ function isUuidLike(value) {
1882
1886
  value
1883
1887
  );
1884
1888
  }
1889
+ function createPseudoUuidV4() {
1890
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (token) => {
1891
+ const rand = Math.floor(Math.random() * 16);
1892
+ const value = token === "x" ? rand : rand & 3 | 8;
1893
+ return value.toString(16);
1894
+ });
1895
+ }
1896
+ function sanitizeIngestText(value) {
1897
+ const text = typeof value === "string" ? value : String(value ?? "");
1898
+ return text.slice(0, MAX_INGEST_TEXT_CHARS);
1899
+ }
1900
+ function createEventId(seed) {
1901
+ if (isUuidLike(seed)) return seed;
1902
+ if (typeof globalThis.crypto?.randomUUID === "function") {
1903
+ return globalThis.crypto.randomUUID();
1904
+ }
1905
+ return createPseudoUuidV4();
1906
+ }
1885
1907
  function createCorrelationId(seed) {
1886
1908
  if (isUuidLike(seed)) return seed;
1887
1909
  if (typeof globalThis.crypto?.randomUUID === "function") {
1888
1910
  return globalThis.crypto.randomUUID();
1889
1911
  }
1890
- return `cid_${Date.now()}_${Math.random().toString(36).slice(2)}`;
1912
+ return createPseudoUuidV4();
1891
1913
  }
1892
1914
  async function waitForRetry(attemptIndex) {
1893
1915
  const delay = GUARD_RETRY_DELAYS_MS[attemptIndex];
1894
1916
  if (!delay) return;
1895
1917
  await new Promise((resolve) => setTimeout(resolve, delay));
1896
1918
  }
1919
+ async function waitForIngestRetry(attemptIndex) {
1920
+ const delay = INGEST_RETRY_DELAYS_MS[attemptIndex];
1921
+ if (!delay) return;
1922
+ await new Promise((resolve) => setTimeout(resolve, delay));
1923
+ }
1897
1924
  async function safeReadJson2(response) {
1898
1925
  try {
1899
1926
  return await response.json();
@@ -1968,6 +1995,8 @@ function createCompletionChunkCollector() {
1968
1995
  var AgentID = class {
1969
1996
  constructor(config) {
1970
1997
  this.injectionScanner = getInjectionScanner();
1998
+ this.requestClientEventIds = /* @__PURE__ */ new WeakMap();
1999
+ this.recentGuardVerdicts = /* @__PURE__ */ new Map();
1971
2000
  this.apiKey = config.apiKey.trim();
1972
2001
  this.baseUrl = normalizeBaseUrl3(config.baseUrl ?? "https://app.getagentid.com/api/v1");
1973
2002
  this.piiMasking = Boolean(config.piiMasking);
@@ -1996,6 +2025,60 @@ var AgentID = class {
1996
2025
  }
1997
2026
  return this.apiKey;
1998
2027
  }
2028
+ resolveClientEventId(requestBody) {
2029
+ const directClientEventId = requestBody.client_event_id;
2030
+ if (typeof directClientEventId === "string" && isUuidLike(directClientEventId)) {
2031
+ return directClientEventId;
2032
+ }
2033
+ const metadata = requestBody.metadata;
2034
+ if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
2035
+ const metadataClientEventId = metadata.client_event_id;
2036
+ if (typeof metadataClientEventId === "string" && isUuidLike(metadataClientEventId)) {
2037
+ return metadataClientEventId;
2038
+ }
2039
+ }
2040
+ const cached = this.requestClientEventIds.get(requestBody);
2041
+ if (cached) {
2042
+ return cached;
2043
+ }
2044
+ const generated = createEventId();
2045
+ this.requestClientEventIds.set(requestBody, generated);
2046
+ return generated;
2047
+ }
2048
+ buildGuardCacheKey(params) {
2049
+ if (!params.system_id || !params.input) {
2050
+ return null;
2051
+ }
2052
+ const userId = params.user_id?.trim() ?? "";
2053
+ const normalizedInput = params.input.slice(0, 2048);
2054
+ return `${params.system_id}|${userId}|${normalizedInput.length}|${normalizedInput}`;
2055
+ }
2056
+ readCachedGuardVerdict(cacheKey) {
2057
+ if (!cacheKey) return null;
2058
+ const cached = this.recentGuardVerdicts.get(cacheKey);
2059
+ if (!cached) return null;
2060
+ if (Date.now() > cached.expiresAt) {
2061
+ this.recentGuardVerdicts.delete(cacheKey);
2062
+ return null;
2063
+ }
2064
+ return cached.verdict;
2065
+ }
2066
+ cacheGuardVerdict(cacheKey, verdict) {
2067
+ if (!cacheKey || !verdict.allowed) {
2068
+ return;
2069
+ }
2070
+ this.recentGuardVerdicts.set(cacheKey, {
2071
+ verdict,
2072
+ expiresAt: Date.now() + GUARD_VERDICT_CACHE_TTL_MS
2073
+ });
2074
+ if (this.recentGuardVerdicts.size > 100) {
2075
+ for (const [key, value] of this.recentGuardVerdicts.entries()) {
2076
+ if (Date.now() > value.expiresAt) {
2077
+ this.recentGuardVerdicts.delete(key);
2078
+ }
2079
+ }
2080
+ }
2081
+ }
1999
2082
  async getCapabilityConfig(force = false, options) {
2000
2083
  const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2001
2084
  return ensureCapabilityConfig({
@@ -2153,6 +2236,11 @@ var AgentID = class {
2153
2236
  ...params,
2154
2237
  client_capabilities: params.client_capabilities ?? this.buildClientCapabilities()
2155
2238
  };
2239
+ const guardCacheKey = this.buildGuardCacheKey(payload);
2240
+ const cachedVerdict = this.readCachedGuardVerdict(guardCacheKey);
2241
+ if (cachedVerdict) {
2242
+ return cachedVerdict;
2243
+ }
2156
2244
  const correlationId = createCorrelationId(payload.client_event_id);
2157
2245
  let lastStatusCode = null;
2158
2246
  let lastAbort = false;
@@ -2199,6 +2287,7 @@ var AgentID = class {
2199
2287
  });
2200
2288
  return { allowed: true, reason: "system_failure_fail_open" };
2201
2289
  }
2290
+ this.cacheGuardVerdict(guardCacheKey, verdict);
2202
2291
  return verdict;
2203
2292
  }
2204
2293
  if (!res.ok) {
@@ -2272,6 +2361,59 @@ var AgentID = class {
2272
2361
  }
2273
2362
  return { allowed: true, reason: "guard_unreachable" };
2274
2363
  }
2364
+ async sendIngest(params, options) {
2365
+ const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2366
+ const eventId = createEventId(params.event_id);
2367
+ const timestamp = params.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
2368
+ const metadata = {
2369
+ ...params.metadata ?? {}
2370
+ };
2371
+ if (!Object.prototype.hasOwnProperty.call(metadata, "agentid_base_url")) {
2372
+ metadata.agentid_base_url = this.baseUrl;
2373
+ }
2374
+ void this.getCapabilityConfig(false, { apiKey: effectiveApiKey }).catch(() => void 0);
2375
+ const payload = {
2376
+ ...params,
2377
+ event_id: eventId,
2378
+ timestamp,
2379
+ input: sanitizeIngestText(params.input),
2380
+ output: sanitizeIngestText(params.output),
2381
+ metadata,
2382
+ client_capabilities: params.client_capabilities ?? this.buildClientCapabilities()
2383
+ };
2384
+ for (let attempt = 0; attempt < INGEST_MAX_ATTEMPTS; attempt += 1) {
2385
+ try {
2386
+ const response = await fetch(`${this.baseUrl}/ingest`, {
2387
+ method: "POST",
2388
+ keepalive: true,
2389
+ headers: {
2390
+ "Content-Type": "application/json",
2391
+ "x-agentid-api-key": effectiveApiKey,
2392
+ "X-AgentID-SDK-Version": AGENTID_SDK_VERSION_HEADER2
2393
+ },
2394
+ body: JSON.stringify(payload)
2395
+ });
2396
+ const responseBody = await safeReadJson2(response);
2397
+ if (response.ok) {
2398
+ return { ok: true, status: response.status, reason: null };
2399
+ }
2400
+ const reason = responseBody && typeof responseBody === "object" && typeof responseBody.reason === "string" ? responseBody.reason ?? null : null;
2401
+ const retryable = response.status >= 500 || response.status === 429;
2402
+ if (retryable && attempt < INGEST_MAX_ATTEMPTS - 1) {
2403
+ await waitForIngestRetry(attempt);
2404
+ continue;
2405
+ }
2406
+ return { ok: false, status: response.status, reason };
2407
+ } catch {
2408
+ if (attempt < INGEST_MAX_ATTEMPTS - 1) {
2409
+ await waitForIngestRetry(attempt);
2410
+ continue;
2411
+ }
2412
+ return { ok: false, status: null, reason: "network_error" };
2413
+ }
2414
+ }
2415
+ return { ok: false, status: null, reason: "unknown_ingest_failure" };
2416
+ }
2275
2417
  extractStreamChunkText(chunk) {
2276
2418
  if (typeof chunk === "string") {
2277
2419
  return chunk;
@@ -2373,35 +2515,11 @@ var AgentID = class {
2373
2515
  log(params, options) {
2374
2516
  queueMicrotask(() => {
2375
2517
  void (async () => {
2376
- try {
2377
- const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2378
- const eventId = params.event_id ?? (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `evt_${Date.now()}_${Math.random().toString(36).slice(2)}`);
2379
- const timestamp = params.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
2380
- void this.getCapabilityConfig(false, { apiKey: effectiveApiKey }).catch(() => void 0);
2381
- const metadata = {
2382
- ...params.metadata ?? {}
2383
- };
2384
- if (!Object.prototype.hasOwnProperty.call(metadata, "agentid_base_url")) {
2385
- metadata.agentid_base_url = this.baseUrl;
2386
- }
2387
- await fetch(`${this.baseUrl}/ingest`, {
2388
- method: "POST",
2389
- keepalive: true,
2390
- headers: {
2391
- "Content-Type": "application/json",
2392
- "x-agentid-api-key": effectiveApiKey,
2393
- "X-AgentID-SDK-Version": AGENTID_SDK_VERSION_HEADER2
2394
- },
2395
- body: JSON.stringify({
2396
- ...params,
2397
- event_id: eventId,
2398
- timestamp,
2399
- metadata,
2400
- client_capabilities: params.client_capabilities ?? this.buildClientCapabilities()
2401
- })
2402
- });
2403
- } catch (error) {
2404
- console.error("[AgentID] Log failed:", error);
2518
+ const result = await this.sendIngest(params, options);
2519
+ if (!result.ok) {
2520
+ console.warn(
2521
+ `[AgentID] Ingest telemetry failed (status=${result.status ?? "network"}, reason=${result.reason ?? "unknown"}).`
2522
+ );
2405
2523
  }
2406
2524
  })();
2407
2525
  });
@@ -2501,7 +2619,7 @@ var AgentID = class {
2501
2619
  "AgentID: No user message found. Security guard requires string input."
2502
2620
  );
2503
2621
  }
2504
- const clientEventId = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `evt_${Date.now()}_${Math.random().toString(36).slice(2)}`;
2622
+ const clientEventId = this.resolveClientEventId(req);
2505
2623
  const verdict = await this.guard({
2506
2624
  input: maskedText,
2507
2625
  system_id: systemId,
@@ -2515,6 +2633,8 @@ var AgentID = class {
2515
2633
  `AgentID: Security Blocked (${verdict.reason ?? "guard_denied"})`
2516
2634
  );
2517
2635
  }
2636
+ const canonicalClientEventId = typeof verdict.client_event_id === "string" && isUuidLike(verdict.client_event_id) ? verdict.client_event_id : clientEventId;
2637
+ const guardEventId = typeof verdict.guard_event_id === "string" && verdict.guard_event_id.length > 0 ? verdict.guard_event_id : null;
2518
2638
  const isShadowMode = verdict.shadow_mode === true;
2519
2639
  const transformedInput = isShadowMode ? maskedText : typeof verdict.transformed_input === "string" && verdict.transformed_input.length > 0 ? verdict.transformed_input : maskedText;
2520
2640
  if (transformedInput !== maskedText) {
@@ -2537,10 +2657,10 @@ var AgentID = class {
2537
2657
  })()
2538
2658
  );
2539
2659
  if (maskedText && wrappedCompletion.mode === "stream") {
2540
- void wrappedCompletion.done.then((result) => {
2660
+ void wrappedCompletion.done.then(async (result) => {
2541
2661
  const outputForLog = isShadowMode ? result.rawOutput : result.transformedOutput;
2542
- this.log({
2543
- event_id: clientEventId,
2662
+ const ingestResult = await this.sendIngest({
2663
+ event_id: canonicalClientEventId,
2544
2664
  system_id: systemId,
2545
2665
  user_id: options.user_id,
2546
2666
  input: maskedText,
@@ -2548,6 +2668,7 @@ var AgentID = class {
2548
2668
  model: adapter.getModelName(maskedReq),
2549
2669
  usage: void 0,
2550
2670
  latency: void 0,
2671
+ event_type: "complete",
2551
2672
  metadata: {
2552
2673
  transformed_input: maskedText,
2553
2674
  transformed_output: result.transformedOutput,
@@ -2555,10 +2676,17 @@ var AgentID = class {
2555
2676
  shadow_mode: isShadowMode,
2556
2677
  simulated_decision: verdict.simulated_decision ?? null,
2557
2678
  simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
2558
- response_streamed: true
2679
+ response_streamed: true,
2680
+ guard_event_id: guardEventId,
2681
+ client_event_id: canonicalClientEventId
2559
2682
  },
2560
2683
  client_capabilities: this.buildClientCapabilities("openai", false)
2561
2684
  }, requestOptions);
2685
+ if (!ingestResult.ok) {
2686
+ console.warn(
2687
+ `[AgentID] Stream ingest telemetry failed (status=${ingestResult.status ?? "network"}, reason=${ingestResult.reason ?? "unknown"}).`
2688
+ );
2689
+ }
2562
2690
  }).catch((error) => {
2563
2691
  console.error("[AgentID] Stream completion wrapping failed:", error);
2564
2692
  });
@@ -2574,8 +2702,8 @@ var AgentID = class {
2574
2702
  const model = adapter.getModelName(maskedReq, res);
2575
2703
  const usage = adapter.getTokenUsage(res);
2576
2704
  const outputForLog = isShadowMode ? wrappedCompletion.rawOutput : wrappedCompletion.transformedOutput;
2577
- this.log({
2578
- event_id: clientEventId,
2705
+ const ingestResult = await this.sendIngest({
2706
+ event_id: canonicalClientEventId,
2579
2707
  system_id: systemId,
2580
2708
  user_id: options.user_id,
2581
2709
  input: maskedText,
@@ -2583,6 +2711,7 @@ var AgentID = class {
2583
2711
  model,
2584
2712
  usage,
2585
2713
  latency,
2714
+ event_type: "complete",
2586
2715
  metadata: {
2587
2716
  transformed_input: maskedText,
2588
2717
  transformed_output: wrappedCompletion.transformedOutput,
@@ -2590,10 +2719,17 @@ var AgentID = class {
2590
2719
  shadow_mode: isShadowMode,
2591
2720
  simulated_decision: verdict.simulated_decision ?? null,
2592
2721
  simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
2593
- response_streamed: false
2722
+ response_streamed: false,
2723
+ guard_event_id: guardEventId,
2724
+ client_event_id: canonicalClientEventId
2594
2725
  },
2595
2726
  client_capabilities: this.buildClientCapabilities("openai", false)
2596
2727
  }, requestOptions);
2728
+ if (!ingestResult.ok) {
2729
+ console.warn(
2730
+ `[AgentID] Ingest telemetry failed (status=${ingestResult.status ?? "network"}, reason=${ingestResult.reason ?? "unknown"}).`
2731
+ );
2732
+ }
2597
2733
  }
2598
2734
  if (!capabilityConfig.block_pii_leakage && this.piiMasking && shouldDeanonymize) {
2599
2735
  const deanon = this.pii.deanonymize(adapter.extractOutput(res), mapping);
package/dist/index.mjs CHANGED
@@ -1771,6 +1771,10 @@ var MIN_GUARD_TIMEOUT_MS = 500;
1771
1771
  var MAX_GUARD_TIMEOUT_MS = 15e3;
1772
1772
  var GUARD_MAX_ATTEMPTS = 3;
1773
1773
  var GUARD_RETRY_DELAYS_MS = [250, 500];
1774
+ var INGEST_MAX_ATTEMPTS = 3;
1775
+ var INGEST_RETRY_DELAYS_MS = [250, 500];
1776
+ var GUARD_VERDICT_CACHE_TTL_MS = 15e3;
1777
+ var MAX_INGEST_TEXT_CHARS = 32e3;
1774
1778
  function normalizeBaseUrl3(baseUrl) {
1775
1779
  return baseUrl.replace(/\/+$/, "");
1776
1780
  }
@@ -1844,18 +1848,41 @@ function isUuidLike(value) {
1844
1848
  value
1845
1849
  );
1846
1850
  }
1851
+ function createPseudoUuidV4() {
1852
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (token) => {
1853
+ const rand = Math.floor(Math.random() * 16);
1854
+ const value = token === "x" ? rand : rand & 3 | 8;
1855
+ return value.toString(16);
1856
+ });
1857
+ }
1858
+ function sanitizeIngestText(value) {
1859
+ const text = typeof value === "string" ? value : String(value ?? "");
1860
+ return text.slice(0, MAX_INGEST_TEXT_CHARS);
1861
+ }
1862
+ function createEventId(seed) {
1863
+ if (isUuidLike(seed)) return seed;
1864
+ if (typeof globalThis.crypto?.randomUUID === "function") {
1865
+ return globalThis.crypto.randomUUID();
1866
+ }
1867
+ return createPseudoUuidV4();
1868
+ }
1847
1869
  function createCorrelationId(seed) {
1848
1870
  if (isUuidLike(seed)) return seed;
1849
1871
  if (typeof globalThis.crypto?.randomUUID === "function") {
1850
1872
  return globalThis.crypto.randomUUID();
1851
1873
  }
1852
- return `cid_${Date.now()}_${Math.random().toString(36).slice(2)}`;
1874
+ return createPseudoUuidV4();
1853
1875
  }
1854
1876
  async function waitForRetry(attemptIndex) {
1855
1877
  const delay = GUARD_RETRY_DELAYS_MS[attemptIndex];
1856
1878
  if (!delay) return;
1857
1879
  await new Promise((resolve) => setTimeout(resolve, delay));
1858
1880
  }
1881
+ async function waitForIngestRetry(attemptIndex) {
1882
+ const delay = INGEST_RETRY_DELAYS_MS[attemptIndex];
1883
+ if (!delay) return;
1884
+ await new Promise((resolve) => setTimeout(resolve, delay));
1885
+ }
1859
1886
  async function safeReadJson2(response) {
1860
1887
  try {
1861
1888
  return await response.json();
@@ -1930,6 +1957,8 @@ function createCompletionChunkCollector() {
1930
1957
  var AgentID = class {
1931
1958
  constructor(config) {
1932
1959
  this.injectionScanner = getInjectionScanner();
1960
+ this.requestClientEventIds = /* @__PURE__ */ new WeakMap();
1961
+ this.recentGuardVerdicts = /* @__PURE__ */ new Map();
1933
1962
  this.apiKey = config.apiKey.trim();
1934
1963
  this.baseUrl = normalizeBaseUrl3(config.baseUrl ?? "https://app.getagentid.com/api/v1");
1935
1964
  this.piiMasking = Boolean(config.piiMasking);
@@ -1958,6 +1987,60 @@ var AgentID = class {
1958
1987
  }
1959
1988
  return this.apiKey;
1960
1989
  }
1990
+ resolveClientEventId(requestBody) {
1991
+ const directClientEventId = requestBody.client_event_id;
1992
+ if (typeof directClientEventId === "string" && isUuidLike(directClientEventId)) {
1993
+ return directClientEventId;
1994
+ }
1995
+ const metadata = requestBody.metadata;
1996
+ if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
1997
+ const metadataClientEventId = metadata.client_event_id;
1998
+ if (typeof metadataClientEventId === "string" && isUuidLike(metadataClientEventId)) {
1999
+ return metadataClientEventId;
2000
+ }
2001
+ }
2002
+ const cached = this.requestClientEventIds.get(requestBody);
2003
+ if (cached) {
2004
+ return cached;
2005
+ }
2006
+ const generated = createEventId();
2007
+ this.requestClientEventIds.set(requestBody, generated);
2008
+ return generated;
2009
+ }
2010
+ buildGuardCacheKey(params) {
2011
+ if (!params.system_id || !params.input) {
2012
+ return null;
2013
+ }
2014
+ const userId = params.user_id?.trim() ?? "";
2015
+ const normalizedInput = params.input.slice(0, 2048);
2016
+ return `${params.system_id}|${userId}|${normalizedInput.length}|${normalizedInput}`;
2017
+ }
2018
+ readCachedGuardVerdict(cacheKey) {
2019
+ if (!cacheKey) return null;
2020
+ const cached = this.recentGuardVerdicts.get(cacheKey);
2021
+ if (!cached) return null;
2022
+ if (Date.now() > cached.expiresAt) {
2023
+ this.recentGuardVerdicts.delete(cacheKey);
2024
+ return null;
2025
+ }
2026
+ return cached.verdict;
2027
+ }
2028
+ cacheGuardVerdict(cacheKey, verdict) {
2029
+ if (!cacheKey || !verdict.allowed) {
2030
+ return;
2031
+ }
2032
+ this.recentGuardVerdicts.set(cacheKey, {
2033
+ verdict,
2034
+ expiresAt: Date.now() + GUARD_VERDICT_CACHE_TTL_MS
2035
+ });
2036
+ if (this.recentGuardVerdicts.size > 100) {
2037
+ for (const [key, value] of this.recentGuardVerdicts.entries()) {
2038
+ if (Date.now() > value.expiresAt) {
2039
+ this.recentGuardVerdicts.delete(key);
2040
+ }
2041
+ }
2042
+ }
2043
+ }
1961
2044
  async getCapabilityConfig(force = false, options) {
1962
2045
  const effectiveApiKey = this.resolveApiKey(options?.apiKey);
1963
2046
  return ensureCapabilityConfig({
@@ -2115,6 +2198,11 @@ var AgentID = class {
2115
2198
  ...params,
2116
2199
  client_capabilities: params.client_capabilities ?? this.buildClientCapabilities()
2117
2200
  };
2201
+ const guardCacheKey = this.buildGuardCacheKey(payload);
2202
+ const cachedVerdict = this.readCachedGuardVerdict(guardCacheKey);
2203
+ if (cachedVerdict) {
2204
+ return cachedVerdict;
2205
+ }
2118
2206
  const correlationId = createCorrelationId(payload.client_event_id);
2119
2207
  let lastStatusCode = null;
2120
2208
  let lastAbort = false;
@@ -2161,6 +2249,7 @@ var AgentID = class {
2161
2249
  });
2162
2250
  return { allowed: true, reason: "system_failure_fail_open" };
2163
2251
  }
2252
+ this.cacheGuardVerdict(guardCacheKey, verdict);
2164
2253
  return verdict;
2165
2254
  }
2166
2255
  if (!res.ok) {
@@ -2234,6 +2323,59 @@ var AgentID = class {
2234
2323
  }
2235
2324
  return { allowed: true, reason: "guard_unreachable" };
2236
2325
  }
2326
+ async sendIngest(params, options) {
2327
+ const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2328
+ const eventId = createEventId(params.event_id);
2329
+ const timestamp = params.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
2330
+ const metadata = {
2331
+ ...params.metadata ?? {}
2332
+ };
2333
+ if (!Object.prototype.hasOwnProperty.call(metadata, "agentid_base_url")) {
2334
+ metadata.agentid_base_url = this.baseUrl;
2335
+ }
2336
+ void this.getCapabilityConfig(false, { apiKey: effectiveApiKey }).catch(() => void 0);
2337
+ const payload = {
2338
+ ...params,
2339
+ event_id: eventId,
2340
+ timestamp,
2341
+ input: sanitizeIngestText(params.input),
2342
+ output: sanitizeIngestText(params.output),
2343
+ metadata,
2344
+ client_capabilities: params.client_capabilities ?? this.buildClientCapabilities()
2345
+ };
2346
+ for (let attempt = 0; attempt < INGEST_MAX_ATTEMPTS; attempt += 1) {
2347
+ try {
2348
+ const response = await fetch(`${this.baseUrl}/ingest`, {
2349
+ method: "POST",
2350
+ keepalive: true,
2351
+ headers: {
2352
+ "Content-Type": "application/json",
2353
+ "x-agentid-api-key": effectiveApiKey,
2354
+ "X-AgentID-SDK-Version": AGENTID_SDK_VERSION_HEADER2
2355
+ },
2356
+ body: JSON.stringify(payload)
2357
+ });
2358
+ const responseBody = await safeReadJson2(response);
2359
+ if (response.ok) {
2360
+ return { ok: true, status: response.status, reason: null };
2361
+ }
2362
+ const reason = responseBody && typeof responseBody === "object" && typeof responseBody.reason === "string" ? responseBody.reason ?? null : null;
2363
+ const retryable = response.status >= 500 || response.status === 429;
2364
+ if (retryable && attempt < INGEST_MAX_ATTEMPTS - 1) {
2365
+ await waitForIngestRetry(attempt);
2366
+ continue;
2367
+ }
2368
+ return { ok: false, status: response.status, reason };
2369
+ } catch {
2370
+ if (attempt < INGEST_MAX_ATTEMPTS - 1) {
2371
+ await waitForIngestRetry(attempt);
2372
+ continue;
2373
+ }
2374
+ return { ok: false, status: null, reason: "network_error" };
2375
+ }
2376
+ }
2377
+ return { ok: false, status: null, reason: "unknown_ingest_failure" };
2378
+ }
2237
2379
  extractStreamChunkText(chunk) {
2238
2380
  if (typeof chunk === "string") {
2239
2381
  return chunk;
@@ -2335,35 +2477,11 @@ var AgentID = class {
2335
2477
  log(params, options) {
2336
2478
  queueMicrotask(() => {
2337
2479
  void (async () => {
2338
- try {
2339
- const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2340
- const eventId = params.event_id ?? (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `evt_${Date.now()}_${Math.random().toString(36).slice(2)}`);
2341
- const timestamp = params.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
2342
- void this.getCapabilityConfig(false, { apiKey: effectiveApiKey }).catch(() => void 0);
2343
- const metadata = {
2344
- ...params.metadata ?? {}
2345
- };
2346
- if (!Object.prototype.hasOwnProperty.call(metadata, "agentid_base_url")) {
2347
- metadata.agentid_base_url = this.baseUrl;
2348
- }
2349
- await fetch(`${this.baseUrl}/ingest`, {
2350
- method: "POST",
2351
- keepalive: true,
2352
- headers: {
2353
- "Content-Type": "application/json",
2354
- "x-agentid-api-key": effectiveApiKey,
2355
- "X-AgentID-SDK-Version": AGENTID_SDK_VERSION_HEADER2
2356
- },
2357
- body: JSON.stringify({
2358
- ...params,
2359
- event_id: eventId,
2360
- timestamp,
2361
- metadata,
2362
- client_capabilities: params.client_capabilities ?? this.buildClientCapabilities()
2363
- })
2364
- });
2365
- } catch (error) {
2366
- console.error("[AgentID] Log failed:", error);
2480
+ const result = await this.sendIngest(params, options);
2481
+ if (!result.ok) {
2482
+ console.warn(
2483
+ `[AgentID] Ingest telemetry failed (status=${result.status ?? "network"}, reason=${result.reason ?? "unknown"}).`
2484
+ );
2367
2485
  }
2368
2486
  })();
2369
2487
  });
@@ -2463,7 +2581,7 @@ var AgentID = class {
2463
2581
  "AgentID: No user message found. Security guard requires string input."
2464
2582
  );
2465
2583
  }
2466
- const clientEventId = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `evt_${Date.now()}_${Math.random().toString(36).slice(2)}`;
2584
+ const clientEventId = this.resolveClientEventId(req);
2467
2585
  const verdict = await this.guard({
2468
2586
  input: maskedText,
2469
2587
  system_id: systemId,
@@ -2477,6 +2595,8 @@ var AgentID = class {
2477
2595
  `AgentID: Security Blocked (${verdict.reason ?? "guard_denied"})`
2478
2596
  );
2479
2597
  }
2598
+ const canonicalClientEventId = typeof verdict.client_event_id === "string" && isUuidLike(verdict.client_event_id) ? verdict.client_event_id : clientEventId;
2599
+ const guardEventId = typeof verdict.guard_event_id === "string" && verdict.guard_event_id.length > 0 ? verdict.guard_event_id : null;
2480
2600
  const isShadowMode = verdict.shadow_mode === true;
2481
2601
  const transformedInput = isShadowMode ? maskedText : typeof verdict.transformed_input === "string" && verdict.transformed_input.length > 0 ? verdict.transformed_input : maskedText;
2482
2602
  if (transformedInput !== maskedText) {
@@ -2499,10 +2619,10 @@ var AgentID = class {
2499
2619
  })()
2500
2620
  );
2501
2621
  if (maskedText && wrappedCompletion.mode === "stream") {
2502
- void wrappedCompletion.done.then((result) => {
2622
+ void wrappedCompletion.done.then(async (result) => {
2503
2623
  const outputForLog = isShadowMode ? result.rawOutput : result.transformedOutput;
2504
- this.log({
2505
- event_id: clientEventId,
2624
+ const ingestResult = await this.sendIngest({
2625
+ event_id: canonicalClientEventId,
2506
2626
  system_id: systemId,
2507
2627
  user_id: options.user_id,
2508
2628
  input: maskedText,
@@ -2510,6 +2630,7 @@ var AgentID = class {
2510
2630
  model: adapter.getModelName(maskedReq),
2511
2631
  usage: void 0,
2512
2632
  latency: void 0,
2633
+ event_type: "complete",
2513
2634
  metadata: {
2514
2635
  transformed_input: maskedText,
2515
2636
  transformed_output: result.transformedOutput,
@@ -2517,10 +2638,17 @@ var AgentID = class {
2517
2638
  shadow_mode: isShadowMode,
2518
2639
  simulated_decision: verdict.simulated_decision ?? null,
2519
2640
  simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
2520
- response_streamed: true
2641
+ response_streamed: true,
2642
+ guard_event_id: guardEventId,
2643
+ client_event_id: canonicalClientEventId
2521
2644
  },
2522
2645
  client_capabilities: this.buildClientCapabilities("openai", false)
2523
2646
  }, requestOptions);
2647
+ if (!ingestResult.ok) {
2648
+ console.warn(
2649
+ `[AgentID] Stream ingest telemetry failed (status=${ingestResult.status ?? "network"}, reason=${ingestResult.reason ?? "unknown"}).`
2650
+ );
2651
+ }
2524
2652
  }).catch((error) => {
2525
2653
  console.error("[AgentID] Stream completion wrapping failed:", error);
2526
2654
  });
@@ -2536,8 +2664,8 @@ var AgentID = class {
2536
2664
  const model = adapter.getModelName(maskedReq, res);
2537
2665
  const usage = adapter.getTokenUsage(res);
2538
2666
  const outputForLog = isShadowMode ? wrappedCompletion.rawOutput : wrappedCompletion.transformedOutput;
2539
- this.log({
2540
- event_id: clientEventId,
2667
+ const ingestResult = await this.sendIngest({
2668
+ event_id: canonicalClientEventId,
2541
2669
  system_id: systemId,
2542
2670
  user_id: options.user_id,
2543
2671
  input: maskedText,
@@ -2545,6 +2673,7 @@ var AgentID = class {
2545
2673
  model,
2546
2674
  usage,
2547
2675
  latency,
2676
+ event_type: "complete",
2548
2677
  metadata: {
2549
2678
  transformed_input: maskedText,
2550
2679
  transformed_output: wrappedCompletion.transformedOutput,
@@ -2552,10 +2681,17 @@ var AgentID = class {
2552
2681
  shadow_mode: isShadowMode,
2553
2682
  simulated_decision: verdict.simulated_decision ?? null,
2554
2683
  simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
2555
- response_streamed: false
2684
+ response_streamed: false,
2685
+ guard_event_id: guardEventId,
2686
+ client_event_id: canonicalClientEventId
2556
2687
  },
2557
2688
  client_capabilities: this.buildClientCapabilities("openai", false)
2558
2689
  }, requestOptions);
2690
+ if (!ingestResult.ok) {
2691
+ console.warn(
2692
+ `[AgentID] Ingest telemetry failed (status=${ingestResult.status ?? "network"}, reason=${ingestResult.reason ?? "unknown"}).`
2693
+ );
2694
+ }
2559
2695
  }
2560
2696
  if (!capabilityConfig.block_pii_leakage && this.piiMasking && shouldDeanonymize) {
2561
2697
  const deanon = this.pii.deanonymize(adapter.extractOutput(res), mapping);
@@ -82,9 +82,15 @@ declare class AgentID {
82
82
  private pii;
83
83
  private localEnforcer;
84
84
  private injectionScanner;
85
+ private requestClientEventIds;
86
+ private recentGuardVerdicts;
85
87
  constructor(config: AgentIDConfig);
86
88
  private buildClientCapabilities;
87
89
  private resolveApiKey;
90
+ private resolveClientEventId;
91
+ private buildGuardCacheKey;
92
+ private readCachedGuardVerdict;
93
+ private cacheGuardVerdict;
88
94
  getCapabilityConfig(force?: boolean, options?: RequestOptions): Promise<CapabilityConfig>;
89
95
  private getCachedCapabilityConfig;
90
96
  prepareInputForDispatch(params: {
@@ -103,6 +109,7 @@ declare class AgentID {
103
109
  * strictMode=true: FAIL-CLOSED and throws on connectivity/timeouts.
104
110
  */
105
111
  guard(params: GuardParams, options?: RequestOptions): Promise<GuardResponse>;
112
+ private sendIngest;
106
113
  private extractStreamChunkText;
107
114
  private wrapCompletion;
108
115
  /**
@@ -82,9 +82,15 @@ declare class AgentID {
82
82
  private pii;
83
83
  private localEnforcer;
84
84
  private injectionScanner;
85
+ private requestClientEventIds;
86
+ private recentGuardVerdicts;
85
87
  constructor(config: AgentIDConfig);
86
88
  private buildClientCapabilities;
87
89
  private resolveApiKey;
90
+ private resolveClientEventId;
91
+ private buildGuardCacheKey;
92
+ private readCachedGuardVerdict;
93
+ private cacheGuardVerdict;
88
94
  getCapabilityConfig(force?: boolean, options?: RequestOptions): Promise<CapabilityConfig>;
89
95
  private getCachedCapabilityConfig;
90
96
  prepareInputForDispatch(params: {
@@ -103,6 +109,7 @@ declare class AgentID {
103
109
  * strictMode=true: FAIL-CLOSED and throws on connectivity/timeouts.
104
110
  */
105
111
  guard(params: GuardParams, options?: RequestOptions): Promise<GuardResponse>;
112
+ private sendIngest;
106
113
  private extractStreamChunkText;
107
114
  private wrapCompletion;
108
115
  /**
@@ -1 +1 @@
1
- export { a as AgentIDCallbackHandler } from './langchain-BGP3qxvW.mjs';
1
+ export { a as AgentIDCallbackHandler } from './langchain-CmUK7sna.mjs';
@@ -1 +1 @@
1
- export { a as AgentIDCallbackHandler } from './langchain-BGP3qxvW.js';
1
+ export { a as AgentIDCallbackHandler } from './langchain-CmUK7sna.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentid-sdk",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "AgentID JavaScript/TypeScript SDK for guard, ingest, tracing, and analytics.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://agentid.ai",