agentid-sdk 0.1.25 → 0.1.28

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.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TransparencyMetadata } from './agentid-B5Y1g2Ko.js';
2
- export { A as AgentID, D as DependencyError, G as GuardParams, a as GuardResponse, L as LogParams, P as PreparedInput, R as RequestOptions, S as SecurityBlockError } from './agentid-B5Y1g2Ko.js';
1
+ import { T as TransparencyMetadata } from './agentid-agvYW2vW.js';
2
+ export { A as AgentID, D as DependencyError, G as GuardParams, a as GuardResponse, L as LogParams, P as PreparedInput, R as RequestOptions, S as SecurityBlockError } from './agentid-agvYW2vW.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
 
5
5
  type PIIMapping = Record<string, string>;
@@ -16,7 +16,7 @@ declare class PIIManager {
16
16
  deanonymize(text: string, mapping: PIIMapping): string;
17
17
  }
18
18
 
19
- type TokenUsage = Record<string, number>;
19
+ type TokenUsage = Record<string, unknown>;
20
20
  interface LLMAdapter {
21
21
  extractInput(req: unknown): string | null;
22
22
  getModelName(req: unknown, res?: unknown): string;
@@ -43,6 +43,7 @@ type InjectionScanParams = {
43
43
  systemId?: string;
44
44
  eventId?: string;
45
45
  clientEventId?: string;
46
+ telemetryMetadata?: Record<string, unknown>;
46
47
  };
47
48
  declare function scanWithRegex(prompt: string): string | null;
48
49
  declare class InjectionScanner {
@@ -55,6 +56,7 @@ declare class InjectionScanner {
55
56
  systemId?: string;
56
57
  eventId?: string;
57
58
  clientEventId?: string;
59
+ telemetryMetadata?: Record<string, unknown>;
58
60
  }): Promise<void>;
59
61
  scan(params: InjectionScanParams): Promise<void>;
60
62
  }
package/dist/index.js CHANGED
@@ -86,7 +86,7 @@ var OpenAIAdapter = class {
86
86
 
87
87
  // src/sdk-version.ts
88
88
  var FALLBACK_SDK_VERSION = "js-0.0.0-dev";
89
- var AGENTID_SDK_VERSION_HEADER = "js-0.1.25".trim().length > 0 ? "js-0.1.25" : FALLBACK_SDK_VERSION;
89
+ var AGENTID_SDK_VERSION_HEADER = "js-0.1.28".trim().length > 0 ? "js-0.1.28" : FALLBACK_SDK_VERSION;
90
90
 
91
91
  // src/pii-national-identifiers.ts
92
92
  var MAX_CANDIDATES_PER_RULE = 256;
@@ -1308,8 +1308,8 @@ var LocalSecurityEnforcer = class {
1308
1308
 
1309
1309
  // src/capability-config.ts
1310
1310
  var CONFIG_TTL_MS = 5 * 60 * 1e3;
1311
- var CONFIG_TIMEOUT_MS = 8e3;
1312
- var CONFIG_RETRY_DELAY_MS = 1e3;
1311
+ var CONFIG_TIMEOUT_MS = 1500;
1312
+ var CONFIG_RETRY_DELAY_MS = 150;
1313
1313
  var MAX_CAPABILITY_CACHE_ENTRIES = 500;
1314
1314
  var CapabilityConfigFetchError = class extends Error {
1315
1315
  constructor(message, params) {
@@ -1561,6 +1561,79 @@ async function ensureCapabilityConfig(params) {
1561
1561
  return pending;
1562
1562
  }
1563
1563
 
1564
+ // src/context-intent.ts
1565
+ var EDUCATIONAL_MARKERS = [
1566
+ "explain",
1567
+ "analysis",
1568
+ "analyze",
1569
+ "analyse",
1570
+ "review",
1571
+ "summarize",
1572
+ "summarise",
1573
+ "summary",
1574
+ "plain-language explanation",
1575
+ "red flags",
1576
+ "security workshop",
1577
+ "training",
1578
+ "lesson",
1579
+ "quoted attack",
1580
+ "quoted example",
1581
+ "attack example",
1582
+ "security event",
1583
+ "security log",
1584
+ "audit log",
1585
+ "incident report",
1586
+ "trace timeline"
1587
+ ];
1588
+ var WARNING_MARKERS = [
1589
+ "dangerous",
1590
+ "risky",
1591
+ "risk",
1592
+ "warning",
1593
+ "warn",
1594
+ "malicious",
1595
+ "security indicator",
1596
+ "red flags"
1597
+ ];
1598
+ var NON_EXECUTION_MARKERS = [
1599
+ "do not execute",
1600
+ "do not run",
1601
+ "do not return commands",
1602
+ "do not output commands",
1603
+ "do not provide executable steps",
1604
+ "for explanation only",
1605
+ "non-executable"
1606
+ ];
1607
+ function normalizeIntentInput(input) {
1608
+ return input.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\s+/g, " ").trim();
1609
+ }
1610
+ function hasAnyMarker(input, markers) {
1611
+ return markers.some((marker) => input.includes(marker));
1612
+ }
1613
+ function classifyInjectionContextIntent(input) {
1614
+ const normalized = normalizeIntentInput(input ?? "");
1615
+ if (!normalized) {
1616
+ return {
1617
+ educational: false,
1618
+ quotedExample: false,
1619
+ warningOnly: false,
1620
+ nonExecutableConstraint: false,
1621
+ promptInjectionExempt: false
1622
+ };
1623
+ }
1624
+ const educational = hasAnyMarker(normalized, EDUCATIONAL_MARKERS);
1625
+ const warningOnly = hasAnyMarker(normalized, WARNING_MARKERS);
1626
+ const nonExecutableConstraint = hasAnyMarker(normalized, NON_EXECUTION_MARKERS);
1627
+ const quotedExample = /["'`]/.test(input) || normalized.includes("quoted") || normalized.includes("quote") || normalized.includes("phrase") || normalized.includes("attack example");
1628
+ return {
1629
+ educational,
1630
+ quotedExample,
1631
+ warningOnly,
1632
+ nonExecutableConstraint,
1633
+ promptInjectionExempt: educational && (quotedExample || warningOnly || nonExecutableConstraint || normalized.includes("prompt injection indicator") || normalized.includes("jailbreak prompt"))
1634
+ };
1635
+ }
1636
+
1564
1637
  // src/security.ts
1565
1638
  var MAX_ANALYSIS_WINDOW = 8192;
1566
1639
  var WINDOW_SLICE_SIZE = 4e3;
@@ -1723,6 +1796,10 @@ function findRegexMatch(prompt) {
1723
1796
  if (!prompt) {
1724
1797
  return null;
1725
1798
  }
1799
+ const contextIntent = classifyInjectionContextIntent(prompt);
1800
+ if (contextIntent.promptInjectionExempt) {
1801
+ return null;
1802
+ }
1726
1803
  const normalizedPrompt = normalizeForHeuristics(prompt);
1727
1804
  for (const rule of HEURISTIC_RULES) {
1728
1805
  try {
@@ -1856,7 +1933,8 @@ async function reportSecurityEvent(options) {
1856
1933
  language: options.language,
1857
1934
  ai_scan_status: options.aiStatus ?? null,
1858
1935
  reason: options.reason ?? null,
1859
- client_event_id: eventId
1936
+ client_event_id: eventId,
1937
+ ...options.telemetryMetadata ?? {}
1860
1938
  };
1861
1939
  if (options.storePii) {
1862
1940
  metadata.snippet = snippet;
@@ -1904,7 +1982,8 @@ var InjectionScanner = class _InjectionScanner {
1904
1982
  source: options?.source,
1905
1983
  systemId: options?.systemId,
1906
1984
  eventId: options?.eventId,
1907
- clientEventId: options?.clientEventId
1985
+ clientEventId: options?.clientEventId,
1986
+ telemetryMetadata: options?.telemetryMetadata
1908
1987
  });
1909
1988
  }
1910
1989
  async scan(params) {
@@ -1916,6 +1995,11 @@ var InjectionScanner = class _InjectionScanner {
1916
1995
  const storePii = params.storePii === true;
1917
1996
  const aiScanEnabled = params.aiScanEnabled !== false;
1918
1997
  const language = detectLanguageTag(prompt);
1998
+ const scanStartedAt = Date.now();
1999
+ const buildTelemetryMetadata = () => ({
2000
+ ...params.telemetryMetadata ?? {},
2001
+ sdk_local_scan_ms: Math.max(0, Date.now() - scanStartedAt)
2002
+ });
1919
2003
  const regexMatch = findRegexMatch(prompt);
1920
2004
  if (regexMatch) {
1921
2005
  await reportSecurityEvent({
@@ -1930,7 +2014,8 @@ var InjectionScanner = class _InjectionScanner {
1930
2014
  language,
1931
2015
  systemId: params.systemId,
1932
2016
  eventId: params.eventId,
1933
- clientEventId: params.clientEventId
2017
+ clientEventId: params.clientEventId,
2018
+ telemetryMetadata: buildTelemetryMetadata()
1934
2019
  });
1935
2020
  throw new Error(`AgentID: Prompt injection blocked (${regexMatch.rule})`);
1936
2021
  }
@@ -1954,7 +2039,8 @@ var InjectionScanner = class _InjectionScanner {
1954
2039
  reason: "ai_scan_disabled_for_high_risk_language",
1955
2040
  systemId: params.systemId,
1956
2041
  eventId: params.eventId,
1957
- clientEventId: params.clientEventId
2042
+ clientEventId: params.clientEventId,
2043
+ telemetryMetadata: buildTelemetryMetadata()
1958
2044
  });
1959
2045
  return;
1960
2046
  }
@@ -1976,7 +2062,8 @@ var InjectionScanner = class _InjectionScanner {
1976
2062
  reason: aiResult.reason,
1977
2063
  systemId: params.systemId,
1978
2064
  eventId: params.eventId,
1979
- clientEventId: params.clientEventId
2065
+ clientEventId: params.clientEventId,
2066
+ telemetryMetadata: buildTelemetryMetadata()
1980
2067
  });
1981
2068
  return;
1982
2069
  }
@@ -1995,7 +2082,8 @@ var InjectionScanner = class _InjectionScanner {
1995
2082
  reason: aiResult.reason,
1996
2083
  systemId: params.systemId,
1997
2084
  eventId: params.eventId,
1998
- clientEventId: params.clientEventId
2085
+ clientEventId: params.clientEventId,
2086
+ telemetryMetadata: buildTelemetryMetadata()
1999
2087
  });
2000
2088
  throw new Error(`AgentID: Prompt injection blocked (${aiResult.reason})`);
2001
2089
  }
@@ -2094,6 +2182,19 @@ function normalizeIngestTimeoutMs(value) {
2094
2182
  }
2095
2183
  return rounded;
2096
2184
  }
2185
+ function setFiniteDurationMetadata(metadata, key, value) {
2186
+ if (typeof value === "number" && Number.isFinite(value)) {
2187
+ metadata[key] = Math.max(0, Math.trunc(value));
2188
+ }
2189
+ }
2190
+ function buildSdkTimingMetadata(params) {
2191
+ const metadata = {};
2192
+ setFiniteDurationMetadata(metadata, "sdk_config_fetch_ms", params.sdkConfigFetchMs);
2193
+ setFiniteDurationMetadata(metadata, "sdk_local_scan_ms", params.sdkLocalScanMs);
2194
+ setFiniteDurationMetadata(metadata, "sdk_guard_ms", params.sdkGuardMs);
2195
+ setFiniteDurationMetadata(metadata, "sdk_ingest_ms", params.sdkIngestMs);
2196
+ return metadata;
2197
+ }
2097
2198
  function resolveConfiguredApiKey(value) {
2098
2199
  const explicit = typeof value === "string" ? value.trim() : "";
2099
2200
  const fromEnv = globalThis.process?.env?.AGENTID_API_KEY ?? "";
@@ -2107,6 +2208,9 @@ function isInfrastructureGuardReason(reason) {
2107
2208
  if (!reason) return false;
2108
2209
  return reason === "system_failure" || reason === "system_failure_db_unavailable" || reason === "logging_failed" || reason === "server_error" || reason === "guard_unreachable" || reason === "api_key_pepper_missing" || reason === "encryption_key_missing";
2109
2210
  }
2211
+ function isGuardFailureEligibleForLocalFallback(reason) {
2212
+ return reason === "network_error_strict_mode" || reason === "server_error" || isInfrastructureGuardReason(reason);
2213
+ }
2110
2214
  function isFailCloseIngestReason(reason) {
2111
2215
  if (!reason) return false;
2112
2216
  return reason === "system_failure" || reason === "system_failure_db_unavailable" || reason === "server_error" || reason === "redis_rate_limit_unavailable" || reason === "redis_quota_unavailable" || reason === "redis_token_quota_unavailable";
@@ -2316,6 +2420,7 @@ var AgentID = class {
2316
2420
  this.baseUrl = normalizeBaseUrl3(config.baseUrl ?? "https://app.getagentid.com/api/v1");
2317
2421
  this.configuredPiiMasking = typeof config.piiMasking === "boolean" ? config.piiMasking : null;
2318
2422
  this.checkInjection = config.checkInjection !== false;
2423
+ this.clientFastFail = config.clientFastFail === true || config.client_fast_fail === true;
2319
2424
  this.aiScanEnabled = config.aiScanEnabled !== false;
2320
2425
  this.storePii = config.storePii === true;
2321
2426
  this.strictMode = config.strictMode === true;
@@ -2418,6 +2523,14 @@ var AgentID = class {
2418
2523
  force
2419
2524
  });
2420
2525
  }
2526
+ async getCapabilityConfigWithTelemetry(force = false, options) {
2527
+ const configStartedAt = Date.now();
2528
+ const capabilityConfig = await this.getCapabilityConfig(force, options);
2529
+ return {
2530
+ capabilityConfig,
2531
+ sdkConfigFetchMs: Math.max(0, Date.now() - configStartedAt)
2532
+ };
2533
+ }
2421
2534
  getCachedCapabilityConfig(options) {
2422
2535
  const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2423
2536
  return getCachedCapabilityConfig({
@@ -2461,37 +2574,45 @@ var AgentID = class {
2461
2574
  }
2462
2575
  return config.block_on_heuristic;
2463
2576
  }
2464
- async prepareInputForDispatch(params, options) {
2465
- const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2466
- const capabilityConfig = await this.getCapabilityConfig(false, options);
2467
- if (!params.skipInjectionScan && params.input && this.shouldRunLocalInjectionScan(capabilityConfig)) {
2577
+ async applyLocalPolicyChecks(params) {
2578
+ const localScanStartedAt = Date.now();
2579
+ if (params.runPromptInjectionCheck && params.input && this.shouldRunLocalInjectionScan(params.capabilityConfig)) {
2468
2580
  await this.injectionScanner.scan({
2469
2581
  prompt: params.input,
2470
- apiKey: effectiveApiKey,
2582
+ apiKey: params.apiKey,
2471
2583
  baseUrl: this.baseUrl,
2472
2584
  aiScanEnabled: this.aiScanEnabled,
2473
2585
  storePii: this.storePii,
2474
2586
  piiManager: this.pii,
2475
- source: "js_sdk"
2587
+ source: "js_sdk",
2588
+ systemId: params.systemId,
2589
+ eventId: params.clientEventId,
2590
+ clientEventId: params.clientEventId,
2591
+ telemetryMetadata: buildSdkTimingMetadata({
2592
+ sdkConfigFetchMs: params.sdkConfigFetchMs
2593
+ })
2476
2594
  });
2477
2595
  }
2478
2596
  try {
2479
2597
  const enforced = this.localEnforcer.enforce({
2480
2598
  input: params.input,
2481
2599
  stream: params.stream,
2482
- config: capabilityConfig
2600
+ config: params.capabilityConfig
2483
2601
  });
2602
+ const sdkLocalScanMs = Math.max(0, Date.now() - localScanStartedAt);
2484
2603
  for (const event of enforced.events) {
2485
2604
  this.logSecurityPolicyViolation({
2486
2605
  systemId: params.systemId,
2487
2606
  violationType: event.violationType,
2488
2607
  actionTaken: event.actionTaken,
2489
- apiKey: effectiveApiKey
2608
+ apiKey: params.apiKey,
2609
+ sdkConfigFetchMs: params.sdkConfigFetchMs,
2610
+ sdkLocalScanMs
2490
2611
  });
2491
2612
  }
2492
2613
  return {
2493
2614
  sanitizedInput: enforced.sanitizedInput,
2494
- capabilityConfig
2615
+ sdkLocalScanMs
2495
2616
  };
2496
2617
  } catch (error) {
2497
2618
  if (error instanceof SecurityPolicyViolationError) {
@@ -2499,17 +2620,76 @@ var AgentID = class {
2499
2620
  systemId: params.systemId,
2500
2621
  violationType: error.violationType,
2501
2622
  actionTaken: error.actionTaken,
2502
- apiKey: effectiveApiKey
2623
+ apiKey: params.apiKey,
2624
+ sdkConfigFetchMs: params.sdkConfigFetchMs,
2625
+ sdkLocalScanMs: Math.max(0, Date.now() - localScanStartedAt)
2503
2626
  });
2504
2627
  }
2505
2628
  throw error;
2506
2629
  }
2507
2630
  }
2631
+ async prepareInputForDispatch(params, options) {
2632
+ const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2633
+ const { capabilityConfig, sdkConfigFetchMs } = await this.getCapabilityConfigWithTelemetry(
2634
+ false,
2635
+ options
2636
+ );
2637
+ if (!this.clientFastFail) {
2638
+ return {
2639
+ sanitizedInput: params.input,
2640
+ capabilityConfig,
2641
+ sdkConfigFetchMs,
2642
+ sdkLocalScanMs: 0
2643
+ };
2644
+ }
2645
+ const enforced = await this.applyLocalPolicyChecks({
2646
+ input: params.input,
2647
+ systemId: params.systemId,
2648
+ stream: params.stream,
2649
+ capabilityConfig,
2650
+ apiKey: effectiveApiKey,
2651
+ clientEventId: params.clientEventId,
2652
+ sdkConfigFetchMs,
2653
+ runPromptInjectionCheck: !params.skipInjectionScan
2654
+ });
2655
+ return {
2656
+ sanitizedInput: enforced.sanitizedInput,
2657
+ capabilityConfig,
2658
+ sdkConfigFetchMs,
2659
+ sdkLocalScanMs: enforced.sdkLocalScanMs
2660
+ };
2661
+ }
2662
+ async applyLocalFallbackForGuardFailure(params, options) {
2663
+ const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2664
+ const resolvedConfig = params.capabilityConfig && typeof params.sdkConfigFetchMs === "number" ? {
2665
+ capabilityConfig: params.capabilityConfig,
2666
+ sdkConfigFetchMs: params.sdkConfigFetchMs
2667
+ } : await this.getCapabilityConfigWithTelemetry(false, options);
2668
+ const enforced = await this.applyLocalPolicyChecks({
2669
+ input: params.input,
2670
+ systemId: params.systemId,
2671
+ stream: params.stream,
2672
+ capabilityConfig: resolvedConfig.capabilityConfig,
2673
+ apiKey: effectiveApiKey,
2674
+ clientEventId: params.clientEventId,
2675
+ sdkConfigFetchMs: resolvedConfig.sdkConfigFetchMs,
2676
+ runPromptInjectionCheck: true
2677
+ });
2678
+ return {
2679
+ sanitizedInput: enforced.sanitizedInput,
2680
+ capabilityConfig: resolvedConfig.capabilityConfig,
2681
+ sdkConfigFetchMs: resolvedConfig.sdkConfigFetchMs,
2682
+ sdkLocalScanMs: enforced.sdkLocalScanMs
2683
+ };
2684
+ }
2508
2685
  async scanPromptInjection(input, options) {
2509
2686
  if (!input) {
2510
2687
  return;
2511
2688
  }
2512
- const capabilityConfig = await this.getCapabilityConfig(false, options);
2689
+ const { capabilityConfig, sdkConfigFetchMs } = await this.getCapabilityConfigWithTelemetry(
2690
+ false,
2691
+ options
2692
+ );
2513
2693
  if (!this.shouldRunLocalInjectionScan(capabilityConfig)) {
2514
2694
  return;
2515
2695
  }
@@ -2524,7 +2704,10 @@ var AgentID = class {
2524
2704
  source: "js_sdk",
2525
2705
  systemId: options?.systemId,
2526
2706
  eventId: options?.clientEventId,
2527
- clientEventId: options?.clientEventId
2707
+ clientEventId: options?.clientEventId,
2708
+ telemetryMetadata: buildSdkTimingMetadata({
2709
+ sdkConfigFetchMs
2710
+ })
2528
2711
  });
2529
2712
  }
2530
2713
  withMaskedOpenAIRequest(req, maskedText) {
@@ -2573,7 +2756,11 @@ var AgentID = class {
2573
2756
  system_id: params.systemId,
2574
2757
  violation_type: params.violationType,
2575
2758
  input_snippet: "[REDACTED_SAMPLE]",
2576
- action_taken: params.actionTaken
2759
+ action_taken: params.actionTaken,
2760
+ ...buildSdkTimingMetadata({
2761
+ sdkConfigFetchMs: params.sdkConfigFetchMs,
2762
+ sdkLocalScanMs: params.sdkLocalScanMs
2763
+ })
2577
2764
  }
2578
2765
  }, { apiKey: params.apiKey });
2579
2766
  }
@@ -2599,6 +2786,42 @@ var AgentID = class {
2599
2786
  { apiKey: params.apiKey }
2600
2787
  );
2601
2788
  }
2789
+ async finalizeIngestTelemetry(params) {
2790
+ const controller = new AbortController();
2791
+ const timeoutId = setTimeout(
2792
+ () => controller.abort(),
2793
+ Math.min(this.ingestTimeoutMs, 2e3)
2794
+ );
2795
+ try {
2796
+ const response = await fetch(`${this.baseUrl}/ingest/finalize`, {
2797
+ method: "POST",
2798
+ headers: {
2799
+ "Content-Type": "application/json",
2800
+ "x-agentid-api-key": params.apiKey,
2801
+ "x-correlation-id": params.clientEventId,
2802
+ "X-AgentID-SDK-Version": AGENTID_SDK_VERSION_HEADER
2803
+ },
2804
+ body: JSON.stringify({
2805
+ client_event_id: params.clientEventId,
2806
+ system_id: params.systemId,
2807
+ sdk_ingest_ms: params.sdkIngestMs
2808
+ }),
2809
+ signal: controller.signal
2810
+ });
2811
+ if (!response.ok) {
2812
+ console.warn(
2813
+ `[AgentID] Ingest telemetry finalize failed (status=${response.status}, client_event_id=${params.clientEventId}).`
2814
+ );
2815
+ }
2816
+ } catch (error) {
2817
+ const label = error && typeof error === "object" && error.name === "AbortError" ? "timeout" : "network";
2818
+ console.warn(
2819
+ `[AgentID] Ingest telemetry finalize failed (${label}, client_event_id=${params.clientEventId}).`
2820
+ );
2821
+ } finally {
2822
+ clearTimeout(timeoutId);
2823
+ }
2824
+ }
2602
2825
  /**
2603
2826
  * GUARD: Checks limits, PII, and security before execution.
2604
2827
  * strictMode=false (default): FAIL-OPEN on connectivity/timeouts.
@@ -2756,15 +2979,16 @@ var AgentID = class {
2756
2979
  }
2757
2980
  return withGuardLatency({ allowed: true, reason: "guard_unreachable" });
2758
2981
  }
2759
- async sendIngest(params, options) {
2982
+ async sendIngest(params, options, internal) {
2983
+ const ingestStartedAt = Date.now();
2760
2984
  const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2761
- const eventId = createEventId2(params.event_id);
2985
+ const transportEventId = createEventId2(internal?.transportEventId ?? params.event_id);
2762
2986
  const timestamp = params.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
2763
2987
  const metadata = {
2764
2988
  ...params.metadata ?? {}
2765
2989
  };
2766
2990
  const metadataClientEventId = typeof metadata.client_event_id === "string" && isUuidLike2(metadata.client_event_id) ? metadata.client_event_id : null;
2767
- const canonicalClientEventId = metadataClientEventId ?? eventId;
2991
+ const canonicalClientEventId = metadataClientEventId ?? transportEventId;
2768
2992
  if (!metadataClientEventId) {
2769
2993
  metadata.client_event_id = canonicalClientEventId;
2770
2994
  }
@@ -2774,7 +2998,7 @@ var AgentID = class {
2774
2998
  void this.getCapabilityConfig(false, { apiKey: effectiveApiKey }).catch(() => void 0);
2775
2999
  const payload = {
2776
3000
  ...params,
2777
- event_id: canonicalClientEventId,
3001
+ event_id: internal?.transportEventId ? transportEventId : canonicalClientEventId,
2778
3002
  timestamp,
2779
3003
  input: sanitizeIngestText(params.input),
2780
3004
  output: sanitizeIngestText(params.output),
@@ -2799,6 +3023,14 @@ var AgentID = class {
2799
3023
  });
2800
3024
  const responseBody = await safeReadJson2(response);
2801
3025
  if (response.ok) {
3026
+ if (!internal?.disableFinalize) {
3027
+ void this.finalizeIngestTelemetry({
3028
+ apiKey: effectiveApiKey,
3029
+ clientEventId: canonicalClientEventId,
3030
+ systemId: params.system_id,
3031
+ sdkIngestMs: Math.max(0, Date.now() - ingestStartedAt)
3032
+ });
3033
+ }
2802
3034
  return { ok: true, status: response.status, reason: null };
2803
3035
  }
2804
3036
  const reason = responseBody && typeof responseBody === "object" && typeof responseBody.reason === "string" ? responseBody.reason ?? null : null;
@@ -2859,6 +3091,13 @@ var AgentID = class {
2859
3091
  }
2860
3092
  return text;
2861
3093
  }
3094
+ extractStreamChunkUsage(chunk) {
3095
+ if (!chunk || typeof chunk !== "object") {
3096
+ return void 0;
3097
+ }
3098
+ const usage = chunk.usage;
3099
+ return usage && typeof usage === "object" && !Array.isArray(usage) ? usage : void 0;
3100
+ }
2862
3101
  wrapCompletion(completion) {
2863
3102
  if (typeof completion === "string") {
2864
3103
  const masked = this.pii.anonymize(completion);
@@ -2882,7 +3121,9 @@ var AgentID = class {
2882
3121
  const source = completion;
2883
3122
  const collector = createCompletionChunkCollector();
2884
3123
  const extractStreamChunkText = this.extractStreamChunkText.bind(this);
3124
+ const extractStreamChunkUsage = this.extractStreamChunkUsage.bind(this);
2885
3125
  const piiManager = this.pii;
3126
+ let lastUsage;
2886
3127
  let resolveDone = null;
2887
3128
  let rejectDone = null;
2888
3129
  const done = new Promise((resolve, reject) => {
@@ -2897,6 +3138,10 @@ var AgentID = class {
2897
3138
  if (chunkText) {
2898
3139
  await collector.push(chunkText);
2899
3140
  }
3141
+ const chunkUsage = extractStreamChunkUsage(chunk);
3142
+ if (chunkUsage) {
3143
+ lastUsage = chunkUsage;
3144
+ }
2900
3145
  yield chunk;
2901
3146
  }
2902
3147
  await collector.close();
@@ -2906,7 +3151,8 @@ var AgentID = class {
2906
3151
  mode: "static",
2907
3152
  rawOutput,
2908
3153
  transformedOutput: masked.maskedText,
2909
- outputMasked: masked.maskedText !== rawOutput
3154
+ outputMasked: masked.maskedText !== rawOutput,
3155
+ usage: lastUsage
2910
3156
  });
2911
3157
  } catch (error) {
2912
3158
  await collector.abort(error);
@@ -2956,7 +3202,7 @@ var AgentID = class {
2956
3202
  * Wrap an OpenAI client once; AgentID will automatically:
2957
3203
  * - run guard() before chat.completions.create
2958
3204
  * - measure latency
2959
- * - fire-and-forget ingest logging
3205
+ * - persist ingest telemetry for the wrapped call
2960
3206
  */
2961
3207
  wrapOpenAI(openai, options) {
2962
3208
  const systemId = options.system_id;
@@ -2999,20 +3245,19 @@ var AgentID = class {
2999
3245
  let createArgs = normalizedCreateArgs;
3000
3246
  let mapping = {};
3001
3247
  let shouldDeanonymize = false;
3248
+ let sdkConfigFetchMs = 0;
3249
+ let sdkLocalScanMs = 0;
3002
3250
  if (userText) {
3003
- await this.scanPromptInjection(userText, {
3004
- ...requestOptions,
3005
- clientEventId,
3006
- systemId
3007
- });
3008
3251
  const prepared = await this.prepareInputForDispatch({
3009
3252
  input: userText,
3010
3253
  systemId,
3011
3254
  stream,
3012
- skipInjectionScan: true
3255
+ clientEventId
3013
3256
  }, requestOptions);
3014
3257
  capabilityConfig = prepared.capabilityConfig;
3015
3258
  maskedText = prepared.sanitizedInput;
3259
+ sdkConfigFetchMs = prepared.sdkConfigFetchMs ?? 0;
3260
+ sdkLocalScanMs = prepared.sdkLocalScanMs ?? 0;
3016
3261
  if (maskedText !== userText) {
3017
3262
  maskedReq = this.withMaskedOpenAIRequest(
3018
3263
  req,
@@ -3053,14 +3298,46 @@ var AgentID = class {
3053
3298
  user_id: options.user_id,
3054
3299
  client_event_id: clientEventId,
3055
3300
  expected_languages: expectedLanguages,
3301
+ request_identity: options.request_identity,
3056
3302
  client_capabilities: this.buildClientCapabilities(
3057
3303
  "openai",
3058
3304
  false,
3059
3305
  capabilityConfig
3060
3306
  )
3061
3307
  }, requestOptions);
3308
+ let localFallbackApplied = false;
3309
+ let localFallbackReason = null;
3062
3310
  if (!verdict.allowed) {
3063
- throw new SecurityBlockError(verdict.reason ?? "guard_denied");
3311
+ if (effectiveStrictMode && isGuardFailureEligibleForLocalFallback(verdict.reason)) {
3312
+ localFallbackApplied = true;
3313
+ localFallbackReason = verdict.reason ?? "guard_unreachable";
3314
+ if (sdkLocalScanMs === 0) {
3315
+ const fallback = await this.applyLocalPolicyChecks({
3316
+ input: maskedText,
3317
+ systemId,
3318
+ stream,
3319
+ capabilityConfig,
3320
+ apiKey: effectiveApiKey,
3321
+ clientEventId,
3322
+ sdkConfigFetchMs,
3323
+ runPromptInjectionCheck: true
3324
+ });
3325
+ maskedText = fallback.sanitizedInput;
3326
+ sdkLocalScanMs = fallback.sdkLocalScanMs;
3327
+ }
3328
+ } else {
3329
+ throw new SecurityBlockError(verdict.reason ?? "guard_denied");
3330
+ }
3331
+ }
3332
+ const currentRequestInput = adapter.extractInput(maskedReq);
3333
+ if (maskedText !== currentRequestInput) {
3334
+ maskedReq = this.withMaskedOpenAIRequest(
3335
+ req,
3336
+ maskedText
3337
+ );
3338
+ const nextCreateArgs = [...normalizedCreateArgs];
3339
+ nextCreateArgs[0] = maskedReq;
3340
+ createArgs = nextCreateArgs;
3064
3341
  }
3065
3342
  const canonicalClientEventId = typeof verdict.client_event_id === "string" && isUuidLike2(verdict.client_event_id) ? verdict.client_event_id : clientEventId;
3066
3343
  const guardEventId = typeof verdict.guard_event_id === "string" && verdict.guard_event_id.length > 0 ? verdict.guard_event_id : null;
@@ -3097,10 +3374,11 @@ var AgentID = class {
3097
3374
  event_id: canonicalClientEventId,
3098
3375
  system_id: systemId,
3099
3376
  user_id: options.user_id,
3377
+ request_identity: options.request_identity,
3100
3378
  input: maskedText,
3101
3379
  output: outputForLog,
3102
3380
  model: adapter.getModelName(maskedReq),
3103
- usage: void 0,
3381
+ usage: result.usage,
3104
3382
  latency: modelLatencyMs2,
3105
3383
  event_type: "complete",
3106
3384
  metadata: {
@@ -3111,12 +3389,19 @@ var AgentID = class {
3111
3389
  simulated_decision: verdict.simulated_decision ?? null,
3112
3390
  simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
3113
3391
  response_streamed: true,
3392
+ sdk_local_fallback_applied: localFallbackApplied,
3393
+ sdk_local_fallback_reason: localFallbackReason,
3114
3394
  guard_latency_ms: guardLatencyMs,
3115
3395
  model_latency_ms: modelLatencyMs2,
3116
3396
  total_pipeline_latency_ms: totalPipelineLatencyMs2,
3117
3397
  guard_event_id: guardEventId,
3118
3398
  client_event_id: canonicalClientEventId,
3119
- transparency
3399
+ transparency,
3400
+ ...buildSdkTimingMetadata({
3401
+ sdkConfigFetchMs,
3402
+ sdkLocalScanMs,
3403
+ sdkGuardMs: guardLatencyMs
3404
+ })
3120
3405
  },
3121
3406
  client_capabilities: this.buildClientCapabilities(
3122
3407
  "openai",
@@ -3156,6 +3441,7 @@ var AgentID = class {
3156
3441
  event_id: canonicalClientEventId,
3157
3442
  system_id: systemId,
3158
3443
  user_id: options.user_id,
3444
+ request_identity: options.request_identity,
3159
3445
  input: maskedText,
3160
3446
  output: outputForLog,
3161
3447
  model,
@@ -3170,12 +3456,19 @@ var AgentID = class {
3170
3456
  simulated_decision: verdict.simulated_decision ?? null,
3171
3457
  simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
3172
3458
  response_streamed: false,
3459
+ sdk_local_fallback_applied: localFallbackApplied,
3460
+ sdk_local_fallback_reason: localFallbackReason,
3173
3461
  guard_latency_ms: guardLatencyMs,
3174
3462
  model_latency_ms: modelLatencyMs,
3175
3463
  total_pipeline_latency_ms: totalPipelineLatencyMs,
3176
3464
  guard_event_id: guardEventId,
3177
3465
  client_event_id: canonicalClientEventId,
3178
- transparency
3466
+ transparency,
3467
+ ...buildSdkTimingMetadata({
3468
+ sdkConfigFetchMs,
3469
+ sdkLocalScanMs,
3470
+ sdkGuardMs: guardLatencyMs
3471
+ })
3179
3472
  },
3180
3473
  client_capabilities: this.buildClientCapabilities(
3181
3474
  "openai",