agentid-sdk 0.1.25 → 0.1.26

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.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.26".trim().length > 0 ? "js-0.1.26" : 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;
@@ -2999,20 +3231,19 @@ var AgentID = class {
2999
3231
  let createArgs = normalizedCreateArgs;
3000
3232
  let mapping = {};
3001
3233
  let shouldDeanonymize = false;
3234
+ let sdkConfigFetchMs = 0;
3235
+ let sdkLocalScanMs = 0;
3002
3236
  if (userText) {
3003
- await this.scanPromptInjection(userText, {
3004
- ...requestOptions,
3005
- clientEventId,
3006
- systemId
3007
- });
3008
3237
  const prepared = await this.prepareInputForDispatch({
3009
3238
  input: userText,
3010
3239
  systemId,
3011
3240
  stream,
3012
- skipInjectionScan: true
3241
+ clientEventId
3013
3242
  }, requestOptions);
3014
3243
  capabilityConfig = prepared.capabilityConfig;
3015
3244
  maskedText = prepared.sanitizedInput;
3245
+ sdkConfigFetchMs = prepared.sdkConfigFetchMs ?? 0;
3246
+ sdkLocalScanMs = prepared.sdkLocalScanMs ?? 0;
3016
3247
  if (maskedText !== userText) {
3017
3248
  maskedReq = this.withMaskedOpenAIRequest(
3018
3249
  req,
@@ -3059,8 +3290,39 @@ var AgentID = class {
3059
3290
  capabilityConfig
3060
3291
  )
3061
3292
  }, requestOptions);
3293
+ let localFallbackApplied = false;
3294
+ let localFallbackReason = null;
3062
3295
  if (!verdict.allowed) {
3063
- throw new SecurityBlockError(verdict.reason ?? "guard_denied");
3296
+ if (effectiveStrictMode && isGuardFailureEligibleForLocalFallback(verdict.reason)) {
3297
+ localFallbackApplied = true;
3298
+ localFallbackReason = verdict.reason ?? "guard_unreachable";
3299
+ if (sdkLocalScanMs === 0) {
3300
+ const fallback = await this.applyLocalPolicyChecks({
3301
+ input: maskedText,
3302
+ systemId,
3303
+ stream,
3304
+ capabilityConfig,
3305
+ apiKey: effectiveApiKey,
3306
+ clientEventId,
3307
+ sdkConfigFetchMs,
3308
+ runPromptInjectionCheck: true
3309
+ });
3310
+ maskedText = fallback.sanitizedInput;
3311
+ sdkLocalScanMs = fallback.sdkLocalScanMs;
3312
+ }
3313
+ } else {
3314
+ throw new SecurityBlockError(verdict.reason ?? "guard_denied");
3315
+ }
3316
+ }
3317
+ const currentRequestInput = adapter.extractInput(maskedReq);
3318
+ if (maskedText !== currentRequestInput) {
3319
+ maskedReq = this.withMaskedOpenAIRequest(
3320
+ req,
3321
+ maskedText
3322
+ );
3323
+ const nextCreateArgs = [...normalizedCreateArgs];
3324
+ nextCreateArgs[0] = maskedReq;
3325
+ createArgs = nextCreateArgs;
3064
3326
  }
3065
3327
  const canonicalClientEventId = typeof verdict.client_event_id === "string" && isUuidLike2(verdict.client_event_id) ? verdict.client_event_id : clientEventId;
3066
3328
  const guardEventId = typeof verdict.guard_event_id === "string" && verdict.guard_event_id.length > 0 ? verdict.guard_event_id : null;
@@ -3111,12 +3373,19 @@ var AgentID = class {
3111
3373
  simulated_decision: verdict.simulated_decision ?? null,
3112
3374
  simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
3113
3375
  response_streamed: true,
3376
+ sdk_local_fallback_applied: localFallbackApplied,
3377
+ sdk_local_fallback_reason: localFallbackReason,
3114
3378
  guard_latency_ms: guardLatencyMs,
3115
3379
  model_latency_ms: modelLatencyMs2,
3116
3380
  total_pipeline_latency_ms: totalPipelineLatencyMs2,
3117
3381
  guard_event_id: guardEventId,
3118
3382
  client_event_id: canonicalClientEventId,
3119
- transparency
3383
+ transparency,
3384
+ ...buildSdkTimingMetadata({
3385
+ sdkConfigFetchMs,
3386
+ sdkLocalScanMs,
3387
+ sdkGuardMs: guardLatencyMs
3388
+ })
3120
3389
  },
3121
3390
  client_capabilities: this.buildClientCapabilities(
3122
3391
  "openai",
@@ -3170,12 +3439,19 @@ var AgentID = class {
3170
3439
  simulated_decision: verdict.simulated_decision ?? null,
3171
3440
  simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
3172
3441
  response_streamed: false,
3442
+ sdk_local_fallback_applied: localFallbackApplied,
3443
+ sdk_local_fallback_reason: localFallbackReason,
3173
3444
  guard_latency_ms: guardLatencyMs,
3174
3445
  model_latency_ms: modelLatencyMs,
3175
3446
  total_pipeline_latency_ms: totalPipelineLatencyMs,
3176
3447
  guard_event_id: guardEventId,
3177
3448
  client_event_id: canonicalClientEventId,
3178
- transparency
3449
+ transparency,
3450
+ ...buildSdkTimingMetadata({
3451
+ sdkConfigFetchMs,
3452
+ sdkLocalScanMs,
3453
+ sdkGuardMs: guardLatencyMs
3454
+ })
3179
3455
  },
3180
3456
  client_capabilities: this.buildClientCapabilities(
3181
3457
  "openai",
package/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  SecurityBlockError,
8
8
  getInjectionScanner,
9
9
  scanWithRegex
10
- } from "./chunk-3PLUMWYC.mjs";
10
+ } from "./chunk-JIQGHFHI.mjs";
11
11
 
12
12
  // src/transparency-badge.tsx
13
13
  import * as React from "react";
@@ -1,5 +1,5 @@
1
1
  import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
2
- import { A as AgentID } from './agentid-B5Y1g2Ko.mjs';
2
+ import { A as AgentID } from './agentid-DviYzyAM.mjs';
3
3
 
4
4
  /**
5
5
  * LangChainJS callback handler (dependency-free shape).
@@ -1,5 +1,5 @@
1
1
  import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
2
- import { A as AgentID } from './agentid-B5Y1g2Ko.js';
2
+ import { A as AgentID } from './agentid-DviYzyAM.js';
3
3
 
4
4
  /**
5
5
  * LangChainJS callback handler (dependency-free shape).