agentid-sdk 0.1.22 → 0.1.24

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
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AgentID: () => AgentID,
34
+ AgentIDTransparencyBadge: () => AgentIDTransparencyBadge,
34
35
  InjectionScanner: () => InjectionScanner,
35
36
  OpenAIAdapter: () => OpenAIAdapter,
36
37
  PIIManager: () => PIIManager,
@@ -84,7 +85,7 @@ var OpenAIAdapter = class {
84
85
 
85
86
  // src/sdk-version.ts
86
87
  var FALLBACK_SDK_VERSION = "js-0.0.0-dev";
87
- var AGENTID_SDK_VERSION_HEADER = "js-0.1.22".trim().length > 0 ? "js-0.1.22" : FALLBACK_SDK_VERSION;
88
+ var AGENTID_SDK_VERSION_HEADER = "js-0.1.24".trim().length > 0 ? "js-0.1.24" : FALLBACK_SDK_VERSION;
88
89
 
89
90
  // src/pii-national-identifiers.ts
90
91
  var MAX_CANDIDATES_PER_RULE = 256;
@@ -1016,11 +1017,87 @@ var PHONE_CONTEXT_RE = new RegExp(
1016
1017
  `(?:^|[^\\p{L}])(?:${PHONE_CONTEXT_KEYWORDS.map(escapeRegex).join("|")})(?:$|[^\\p{L}])`,
1017
1018
  "iu"
1018
1019
  );
1020
+ var PERSON_NAME_STOPWORDS = /* @__PURE__ */ new Set([
1021
+ "write",
1022
+ "code",
1023
+ "script",
1024
+ "query",
1025
+ "curl",
1026
+ "http",
1027
+ "https",
1028
+ "import",
1029
+ "python",
1030
+ "javascript",
1031
+ "typescript",
1032
+ "node",
1033
+ "bash",
1034
+ "powershell",
1035
+ "shell",
1036
+ "command",
1037
+ "example",
1038
+ "demo",
1039
+ "developer",
1040
+ "mode",
1041
+ "system",
1042
+ "prompt",
1043
+ "policy",
1044
+ "security",
1045
+ "instructions",
1046
+ "instruction",
1047
+ "rules",
1048
+ "rule",
1049
+ "json",
1050
+ "output",
1051
+ "input",
1052
+ "database",
1053
+ "sql",
1054
+ "mongo",
1055
+ "openai",
1056
+ "agentid",
1057
+ "risk",
1058
+ "score",
1059
+ "summary"
1060
+ ]);
1061
+ var TECHNICAL_CONTEXT_WORD_REGEX = /\b(?:curl|http|https|import|python|javascript|typescript|sql|nosql|mongo|database|query|script|code|os\.system|eval|exec|node|npm|api|endpoint|regex|json|xml|yaml|bash|powershell)\b/i;
1062
+ var TECHNICAL_CONTEXT_SYMBOL_REGEX = /:\/\/|`|\{|\}|\[|\]|\(|\)|;|\$|=>|::|\/\//;
1019
1063
  function hasPhoneContext(text, matchStartIndex, windowSize = 50) {
1020
1064
  const start = Math.max(0, matchStartIndex - windowSize);
1021
1065
  const windowLower = text.slice(start, matchStartIndex).toLowerCase();
1022
1066
  return PHONE_CONTEXT_RE.test(windowLower);
1023
1067
  }
1068
+ function normalizePersonWord(value) {
1069
+ return value.normalize("NFD").replace(/\p{M}+/gu, "").toLowerCase();
1070
+ }
1071
+ function buildContextWindow(source, index, length) {
1072
+ const start = Math.max(0, index - 28);
1073
+ const end = Math.min(source.length, index + length + 28);
1074
+ return source.slice(start, end);
1075
+ }
1076
+ function isTechnicalContext(contextWindow) {
1077
+ return TECHNICAL_CONTEXT_WORD_REGEX.test(contextWindow) || TECHNICAL_CONTEXT_SYMBOL_REGEX.test(contextWindow);
1078
+ }
1079
+ function isLikelyPersonNameCandidate(candidate, contextWindow) {
1080
+ const words = candidate.trim().split(/\s+/);
1081
+ if (words.length !== 2) {
1082
+ return false;
1083
+ }
1084
+ if (isTechnicalContext(contextWindow)) {
1085
+ return false;
1086
+ }
1087
+ for (const rawWord of words) {
1088
+ const normalized = normalizePersonWord(rawWord);
1089
+ if (normalized.length < 2) {
1090
+ return false;
1091
+ }
1092
+ if (PERSON_NAME_STOPWORDS.has(normalized)) {
1093
+ return false;
1094
+ }
1095
+ if (!/^\p{L}[\p{L}'-]+$/u.test(rawWord)) {
1096
+ return false;
1097
+ }
1098
+ }
1099
+ return true;
1100
+ }
1024
1101
  var PIIManager = class {
1025
1102
  /**
1026
1103
  * Reversible local-first masking using <TYPE_INDEX> placeholders.
@@ -1065,7 +1142,12 @@ var PIIManager = class {
1065
1142
  const personRe = /(?<!\p{L})\p{Lu}\p{Ll}{2,}\s+\p{Lu}\p{Ll}{2,}(?!\p{L})/gu;
1066
1143
  for (const m of text.matchAll(personRe)) {
1067
1144
  if (m.index == null) continue;
1068
- detections.push({ start: m.index, end: m.index + m[0].length, type: "PERSON", text: m[0] });
1145
+ const candidate = m[0];
1146
+ const contextWindow = buildContextWindow(text, m.index, candidate.length);
1147
+ if (!isLikelyPersonNameCandidate(candidate, contextWindow)) {
1148
+ continue;
1149
+ }
1150
+ detections.push({ start: m.index, end: m.index + candidate.length, type: "PERSON", text: candidate });
1069
1151
  }
1070
1152
  const nationalIdMatches = detectNationalIdentifiers(text, {
1071
1153
  deadlineMs: defaultScanDeadlineMs,
@@ -1120,12 +1202,21 @@ var DEFAULT_FAIL_OPEN_CONFIG = {
1120
1202
  strict_security_mode: false,
1121
1203
  failure_mode: "fail_open",
1122
1204
  block_on_heuristic: false,
1205
+ inject_transparency_metadata: false,
1123
1206
  block_pii_leakage: false,
1124
1207
  block_db_access: false,
1125
1208
  block_code_execution: false,
1126
1209
  block_toxicity: false
1127
1210
  };
1128
1211
  var SQL_DATABASE_ACCESS_PATTERN = /\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER)\b[\s\S]+?\b(FROM|INTO|TABLE|DATABASE|VIEW|INDEX)\b/i;
1212
+ var NOSQL_DATABASE_ACCESS_PATTERNS = [
1213
+ /\bdb\.[A-Za-z_][A-Za-z0-9_]*\.(find|findOne|aggregate|updateOne|updateMany|deleteOne|deleteMany|insertOne|insertMany)\s*\(/i,
1214
+ /\b(collection|mongodb)\.(find|findOne|aggregate|updateOne|updateMany|deleteOne|deleteMany|insertOne|insertMany)\s*\(/i,
1215
+ /\b\$where\b/i,
1216
+ /\b\$expr\b/i,
1217
+ /\b\$regex\b/i,
1218
+ /\bMongoClient\.connect\s*\(/i
1219
+ ];
1129
1220
  var PYTHON_GENERAL_RCE_PATTERN = /(import\s+(os|sys|subprocess)|from\s+(os|sys|subprocess)\s+import|exec\s*\(|eval\s*\(|__import__)/i;
1130
1221
  var SHELL_BASH_RCE_PATTERN = /(wget\s+|curl\s+|rm\s+-rf|chmod\s+\+x|cat\s+\/etc\/passwd|\/bin\/sh|\/bin\/bash)/i;
1131
1222
  var JAVASCRIPT_RCE_PATTERN = /(new\s+Function\(|process\.env|child_process)/i;
@@ -1139,8 +1230,15 @@ var SecurityPolicyViolationError = class extends Error {
1139
1230
  }
1140
1231
  };
1141
1232
  function detectCapabilityViolation(text, config) {
1142
- if (config.block_db_access && SQL_DATABASE_ACCESS_PATTERN.test(text)) {
1143
- return "SQL_INJECTION_ATTEMPT";
1233
+ if (config.block_db_access) {
1234
+ if (SQL_DATABASE_ACCESS_PATTERN.test(text)) {
1235
+ return "SQL_INJECTION_ATTEMPT";
1236
+ }
1237
+ for (const pattern of NOSQL_DATABASE_ACCESS_PATTERNS) {
1238
+ if (pattern.test(text)) {
1239
+ return "SQL_INJECTION_ATTEMPT";
1240
+ }
1241
+ }
1144
1242
  }
1145
1243
  if (config.block_code_execution && (PYTHON_GENERAL_RCE_PATTERN.test(text) || SHELL_BASH_RCE_PATTERN.test(text) || JAVASCRIPT_RCE_PATTERN.test(text))) {
1146
1244
  return "RCE_ATTEMPT";
@@ -1287,6 +1385,11 @@ function normalizeCapabilityConfig(payload) {
1287
1385
  strict_security_mode: effectiveStrictMode,
1288
1386
  failure_mode: effectiveStrictMode ? "fail_close" : "fail_open",
1289
1387
  block_on_heuristic: blockOnHeuristic,
1388
+ inject_transparency_metadata: readOptionalBooleanAliases(
1389
+ body,
1390
+ ["inject_transparency_metadata", "transparency_metadata_enabled"],
1391
+ false
1392
+ ),
1290
1393
  block_pii_leakage: readBooleanField(body, "block_pii_leakage", "block_pii"),
1291
1394
  block_db_access: readBooleanField(body, "block_db_access", "block_db"),
1292
1395
  block_code_execution: readBooleanField(
@@ -1473,15 +1576,15 @@ var DE_STOPWORDS = /* @__PURE__ */ new Set(["bitte", "anweisung", "system", "reg
1473
1576
  var HEURISTIC_RULES = [
1474
1577
  {
1475
1578
  name: "heuristic_combo_ignore_instructions",
1476
- re: /\b(ignore|disregard|forget|override|bypass|disable|jailbreak|dan|ignoruj|zapomen|obejdi|prepis)\b[\s\S]{0,120}\b(instruction(?:s)?|previous|system|developer|policy|rules|guardrails|safety|instrukce|pokyny|pravidla|syst[eé]m|bezpecnost|politika)\b/i
1579
+ re: /\b(ignore|disregard|forget|override|bypass|disable|jailbreak|dan|ignoruj|zapomen|obejdi|prepis)\b[\s\S]{0,160}\b(instruction(?:s)?|previous|system|developer|policy|rules?|guardrails|safety|instrukce|pokyny|pravidla|systemove?|bezpecnost(?:ni)?|politika)\b/i
1477
1580
  },
1478
1581
  {
1479
1582
  name: "heuristic_combo_instruction_override_reverse",
1480
- re: /\b(instruction(?:s)?|previous|system|developer|policy|rules|guardrails|safety|instrukce|pokyny|pravidla|syst[eé]m|bezpecnost|politika)\b[\s\S]{0,120}\b(ignore|disregard|forget|override|bypass|disable|jailbreak|dan|ignoruj|zapomen|obejdi|prepis)\b/i
1583
+ re: /\b(instruction(?:s)?|previous|system|developer|policy|rules?|guardrails|safety|instrukce|pokyny|pravidla|systemove?|bezpecnost(?:ni)?|politika)\b[\s\S]{0,160}\b(ignore|disregard|forget|override|bypass|disable|jailbreak|dan|ignoruj|zapomen|obejdi|prepis)\b/i
1481
1584
  },
1482
1585
  {
1483
1586
  name: "heuristic_combo_exfil_system_prompt",
1484
- re: /\b(show|reveal|print|dump|leak|display|expose|tell|extract|ukaz|zobraz|vypis|odhal|prozrad)\b[\s\S]{0,140}\b(system prompt|system instruction(?:s)?|developer message|hidden prompt|internal instruction(?:s)?|policy|guardrails|intern[ií] instrukce)\b/i
1587
+ re: /\b(show|reveal|print|dump|leak|display|expose|tell|extract|ukaz|zobraz|vypis|odhal|prozrad)\b[\s\S]{0,180}\b(system prompt|system instruction(?:s)?|developer message|hidden prompt|internal instruction(?:s)?|policy|guardrails|interni instrukce|systemove nastaveni)\b/i
1485
1588
  },
1486
1589
  {
1487
1590
  name: "heuristic_role_prefix_system_developer",
@@ -1490,6 +1593,14 @@ var HEURISTIC_RULES = [
1490
1593
  {
1491
1594
  name: "heuristic_delimiter_system_prompt",
1492
1595
  re: /\b(begin|start)\s+(system|developer)\s+prompt\b|\bend\s+(system|developer)\s+prompt\b/i
1596
+ },
1597
+ {
1598
+ name: "heuristic_developer_mode_override",
1599
+ re: /\b(developer\s*mode|dev\s*mode)\b[\s\S]{0,200}\b(ignore|bypass|disable|override|ignoruj|obejdi|zapomen)\b/i
1600
+ },
1601
+ {
1602
+ name: "heuristic_czech_injection_phrase",
1603
+ re: /\b(zapomen|ignoruj)\b[\s\S]{0,220}\b(predchozi\s+instrukce|bezpecnostni\s+pravidla|systemove\s+nastaveni)\b/i
1493
1604
  }
1494
1605
  ];
1495
1606
  var scannerSingleton = null;
@@ -1540,6 +1651,9 @@ ${input.slice(-WINDOW_SLICE_SIZE)}`;
1540
1651
  [...]
1541
1652
  ${input.slice(tailStart)}`;
1542
1653
  }
1654
+ function normalizeForHeuristics(input) {
1655
+ return input.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\s+/g, " ").trim();
1656
+ }
1543
1657
  function scoreStopwords(tokens, stopwords) {
1544
1658
  let score = 0;
1545
1659
  for (const token of tokens) {
@@ -1582,9 +1696,10 @@ function findRegexMatch(prompt) {
1582
1696
  if (!prompt) {
1583
1697
  return null;
1584
1698
  }
1699
+ const normalizedPrompt = normalizeForHeuristics(prompt);
1585
1700
  for (const rule of HEURISTIC_RULES) {
1586
1701
  try {
1587
- const match = rule.re.exec(prompt);
1702
+ const match = rule.re.exec(normalizedPrompt);
1588
1703
  if (match && typeof match[0] === "string" && match[0].trim()) {
1589
1704
  return {
1590
1705
  rule: rule.name,
@@ -1993,6 +2108,53 @@ async function safeReadJson2(response) {
1993
2108
  return null;
1994
2109
  }
1995
2110
  }
2111
+ function coerceTransparencyMetadata(value) {
2112
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2113
+ return void 0;
2114
+ }
2115
+ const raw = value;
2116
+ if (raw.is_ai_generated !== true) {
2117
+ return void 0;
2118
+ }
2119
+ if (raw.disclosure !== "You are interacting with an AI.") {
2120
+ return void 0;
2121
+ }
2122
+ if (raw.article !== "EU_AI_ACT_ARTICLE_50") {
2123
+ return void 0;
2124
+ }
2125
+ if (raw.injection_mode !== "deterministic") {
2126
+ return void 0;
2127
+ }
2128
+ return {
2129
+ is_ai_generated: true,
2130
+ disclosure: "You are interacting with an AI.",
2131
+ article: "EU_AI_ACT_ARTICLE_50",
2132
+ injection_mode: "deterministic"
2133
+ };
2134
+ }
2135
+ function attachTransparencyMetadata(target, transparency) {
2136
+ if (!transparency) {
2137
+ return target;
2138
+ }
2139
+ if (!target || typeof target !== "object" && typeof target !== "function") {
2140
+ return target;
2141
+ }
2142
+ try {
2143
+ Object.defineProperty(target, "agentid_transparency", {
2144
+ value: transparency,
2145
+ enumerable: false,
2146
+ configurable: true,
2147
+ writable: false
2148
+ });
2149
+ return target;
2150
+ } catch {
2151
+ try {
2152
+ target.agentid_transparency = transparency;
2153
+ } catch {
2154
+ }
2155
+ return target;
2156
+ }
2157
+ }
1996
2158
  function createCompletionChunkCollector() {
1997
2159
  if (typeof TransformStream === "function") {
1998
2160
  const stream = new TransformStream({
@@ -2317,6 +2479,16 @@ var AgentID = class {
2317
2479
  * strictMode=true: FAIL-CLOSED and throws on connectivity/timeouts.
2318
2480
  */
2319
2481
  async guard(params, options) {
2482
+ const guardStartedAt = Date.now();
2483
+ const withGuardLatency = (response) => {
2484
+ if (typeof response.guard_latency_ms === "number" && Number.isFinite(response.guard_latency_ms)) {
2485
+ return response;
2486
+ }
2487
+ return {
2488
+ ...response,
2489
+ guard_latency_ms: Math.max(0, Date.now() - guardStartedAt)
2490
+ };
2491
+ };
2320
2492
  const effectiveApiKey = this.resolveApiKey(options?.apiKey);
2321
2493
  const effectiveStrictMode = await this.resolveEffectiveStrictMode({
2322
2494
  apiKey: effectiveApiKey
@@ -2328,7 +2500,7 @@ var AgentID = class {
2328
2500
  const guardCacheKey = this.buildGuardCacheKey(payload);
2329
2501
  const cachedVerdict = this.readCachedGuardVerdict(guardCacheKey);
2330
2502
  if (cachedVerdict) {
2331
- return cachedVerdict;
2503
+ return withGuardLatency(cachedVerdict);
2332
2504
  }
2333
2505
  const correlationId = createCorrelationId(payload.client_event_id);
2334
2506
  let lastStatusCode = null;
@@ -2352,7 +2524,12 @@ var AgentID = class {
2352
2524
  lastStatusCode = res.status;
2353
2525
  const responseBody = await safeReadJson2(res);
2354
2526
  if (responseBody && typeof responseBody.allowed === "boolean") {
2355
- const verdict = responseBody;
2527
+ const rawVerdict = responseBody;
2528
+ const transparency = coerceTransparencyMetadata(rawVerdict.transparency);
2529
+ const verdict = {
2530
+ ...rawVerdict,
2531
+ ...transparency ? { transparency } : {}
2532
+ };
2356
2533
  const infrastructureFailure = verdict.allowed === false && (isInfrastructureGuardReason(verdict.reason) || !verdict.reason && res.status >= 500);
2357
2534
  if (infrastructureFailure) {
2358
2535
  if (attempt < GUARD_MAX_ATTEMPTS - 1) {
@@ -2363,7 +2540,10 @@ var AgentID = class {
2363
2540
  console.warn(
2364
2541
  `[AgentID] Guard API infrastructure failure in strict mode (${verdict.reason ?? `http_${res.status}`}). Blocking request.`
2365
2542
  );
2366
- return { allowed: false, reason: verdict.reason ?? "network_error_strict_mode" };
2543
+ return withGuardLatency({
2544
+ allowed: false,
2545
+ reason: verdict.reason ?? "network_error_strict_mode"
2546
+ });
2367
2547
  }
2368
2548
  console.warn(
2369
2549
  `[AgentID] Guard API infrastructure fallback in fail-open mode (${verdict.reason ?? `http_${res.status}`}).`
@@ -2374,10 +2554,10 @@ var AgentID = class {
2374
2554
  guardParams: params,
2375
2555
  apiKey: effectiveApiKey
2376
2556
  });
2377
- return { allowed: true, reason: "system_failure_fail_open" };
2557
+ return withGuardLatency({ allowed: true, reason: "system_failure_fail_open" });
2378
2558
  }
2379
2559
  this.cacheGuardVerdict(guardCacheKey, verdict);
2380
- return verdict;
2560
+ return withGuardLatency(verdict);
2381
2561
  }
2382
2562
  if (!res.ok) {
2383
2563
  if (res.status >= 500 && attempt < GUARD_MAX_ATTEMPTS - 1) {
@@ -2407,9 +2587,9 @@ var AgentID = class {
2407
2587
  apiKey: effectiveApiKey
2408
2588
  });
2409
2589
  if (effectiveStrictMode) {
2410
- return { allowed: false, reason: "network_error_strict_mode" };
2590
+ return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
2411
2591
  }
2412
- return { allowed: true, reason: "timeout_fallback" };
2592
+ return withGuardLatency({ allowed: true, reason: "timeout_fallback" });
2413
2593
  }
2414
2594
  console.warn(
2415
2595
  effectiveStrictMode ? "[AgentID] Guard check failed (Strict mode active):" : "[AgentID] Guard check failed (Fail-Open active):",
@@ -2422,33 +2602,33 @@ var AgentID = class {
2422
2602
  apiKey: effectiveApiKey
2423
2603
  });
2424
2604
  if (effectiveStrictMode) {
2425
- return { allowed: false, reason: "network_error_strict_mode" };
2605
+ return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
2426
2606
  }
2427
- return { allowed: true, reason: "guard_unreachable" };
2607
+ return withGuardLatency({ allowed: true, reason: "guard_unreachable" });
2428
2608
  } finally {
2429
2609
  clearTimeout(timeoutId);
2430
2610
  }
2431
2611
  }
2432
2612
  if (lastAbort) {
2433
2613
  if (effectiveStrictMode) {
2434
- return { allowed: false, reason: "network_error_strict_mode" };
2614
+ return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
2435
2615
  }
2436
- return { allowed: true, reason: "timeout_fallback" };
2616
+ return withGuardLatency({ allowed: true, reason: "timeout_fallback" });
2437
2617
  }
2438
2618
  if (typeof lastStatusCode === "number" && lastStatusCode >= 500) {
2439
2619
  if (effectiveStrictMode) {
2440
- return { allowed: false, reason: "server_error" };
2620
+ return withGuardLatency({ allowed: false, reason: "server_error" });
2441
2621
  }
2442
- return { allowed: true, reason: "system_failure_fail_open" };
2622
+ return withGuardLatency({ allowed: true, reason: "system_failure_fail_open" });
2443
2623
  }
2444
2624
  console.warn(
2445
2625
  effectiveStrictMode ? "[AgentID] Guard check failed (Strict mode active):" : "[AgentID] Guard check failed (Fail-Open active):",
2446
2626
  lastError
2447
2627
  );
2448
2628
  if (effectiveStrictMode) {
2449
- return { allowed: false, reason: "network_error_strict_mode" };
2629
+ return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
2450
2630
  }
2451
- return { allowed: true, reason: "guard_unreachable" };
2631
+ return withGuardLatency({ allowed: true, reason: "guard_unreachable" });
2452
2632
  }
2453
2633
  async sendIngest(params, options) {
2454
2634
  const effectiveApiKey = this.resolveApiKey(options?.apiKey);
@@ -2457,13 +2637,18 @@ var AgentID = class {
2457
2637
  const metadata = {
2458
2638
  ...params.metadata ?? {}
2459
2639
  };
2640
+ const metadataClientEventId = typeof metadata.client_event_id === "string" && isUuidLike(metadata.client_event_id) ? metadata.client_event_id : null;
2641
+ const canonicalClientEventId = metadataClientEventId ?? eventId;
2642
+ if (!metadataClientEventId) {
2643
+ metadata.client_event_id = canonicalClientEventId;
2644
+ }
2460
2645
  if (!Object.prototype.hasOwnProperty.call(metadata, "agentid_base_url")) {
2461
2646
  metadata.agentid_base_url = this.baseUrl;
2462
2647
  }
2463
2648
  void this.getCapabilityConfig(false, { apiKey: effectiveApiKey }).catch(() => void 0);
2464
2649
  const payload = {
2465
2650
  ...params,
2466
- event_id: eventId,
2651
+ event_id: canonicalClientEventId,
2467
2652
  timestamp,
2468
2653
  input: sanitizeIngestText(params.input),
2469
2654
  output: sanitizeIngestText(params.output),
@@ -2480,6 +2665,7 @@ var AgentID = class {
2480
2665
  headers: {
2481
2666
  "Content-Type": "application/json",
2482
2667
  "x-agentid-api-key": effectiveApiKey,
2668
+ "x-correlation-id": canonicalClientEventId,
2483
2669
  "X-AgentID-SDK-Version": AGENTID_SDK_VERSION_HEADER
2484
2670
  },
2485
2671
  body: JSON.stringify(payload),
@@ -2663,6 +2849,7 @@ var AgentID = class {
2663
2849
  return async (...args) => {
2664
2850
  const normalizedCreateArgs = normalizeOpenAICreateArgs(args);
2665
2851
  const req = normalizedCreateArgs?.[0] ?? {};
2852
+ const pipelineStartedAt = Date.now();
2666
2853
  const requestLevelApiKey = options.resolveApiKey?.(req) ?? options.apiKey ?? options.api_key;
2667
2854
  const effectiveApiKey = this.resolveApiKey(requestLevelApiKey);
2668
2855
  const requestOptions = { apiKey: effectiveApiKey };
@@ -2730,6 +2917,8 @@ var AgentID = class {
2730
2917
  }
2731
2918
  const canonicalClientEventId = typeof verdict.client_event_id === "string" && isUuidLike(verdict.client_event_id) ? verdict.client_event_id : clientEventId;
2732
2919
  const guardEventId = typeof verdict.guard_event_id === "string" && verdict.guard_event_id.length > 0 ? verdict.guard_event_id : null;
2920
+ const guardLatencyMs = typeof verdict.guard_latency_ms === "number" && Number.isFinite(verdict.guard_latency_ms) ? Math.max(0, Math.trunc(verdict.guard_latency_ms)) : Math.max(0, Date.now() - pipelineStartedAt);
2921
+ const transparency = coerceTransparencyMetadata(verdict.transparency);
2733
2922
  const isShadowMode = verdict.shadow_mode === true;
2734
2923
  const transformedInput = isShadowMode ? maskedText : typeof verdict.transformed_input === "string" && verdict.transformed_input.length > 0 ? verdict.transformed_input : maskedText;
2735
2924
  if (transformedInput !== maskedText) {
@@ -2743,6 +2932,7 @@ var AgentID = class {
2743
2932
  createArgs = nextCreateArgs;
2744
2933
  }
2745
2934
  if (stream) {
2935
+ const modelStartedAt2 = Date.now();
2746
2936
  const streamResponse = await originalCreate.apply(compTarget, createArgs);
2747
2937
  const wrappedCompletion = this.wrapCompletion(
2748
2938
  isAsyncIterable(streamResponse) ? streamResponse : (async function* () {
@@ -2753,6 +2943,8 @@ var AgentID = class {
2753
2943
  );
2754
2944
  if (maskedText && wrappedCompletion.mode === "stream") {
2755
2945
  void wrappedCompletion.done.then(async (result) => {
2946
+ const modelLatencyMs2 = Math.max(0, Date.now() - modelStartedAt2);
2947
+ const totalPipelineLatencyMs2 = Math.max(0, Date.now() - pipelineStartedAt);
2756
2948
  const outputForLog = isShadowMode ? result.rawOutput : result.transformedOutput;
2757
2949
  const ingestResult = await this.sendIngest({
2758
2950
  event_id: canonicalClientEventId,
@@ -2762,7 +2954,7 @@ var AgentID = class {
2762
2954
  output: outputForLog,
2763
2955
  model: adapter.getModelName(maskedReq),
2764
2956
  usage: void 0,
2765
- latency: void 0,
2957
+ latency: modelLatencyMs2,
2766
2958
  event_type: "complete",
2767
2959
  metadata: {
2768
2960
  transformed_input: maskedText,
@@ -2772,8 +2964,12 @@ var AgentID = class {
2772
2964
  simulated_decision: verdict.simulated_decision ?? null,
2773
2965
  simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
2774
2966
  response_streamed: true,
2967
+ guard_latency_ms: guardLatencyMs,
2968
+ model_latency_ms: modelLatencyMs2,
2969
+ total_pipeline_latency_ms: totalPipelineLatencyMs2,
2775
2970
  guard_event_id: guardEventId,
2776
- client_event_id: canonicalClientEventId
2971
+ client_event_id: canonicalClientEventId,
2972
+ transparency
2777
2973
  },
2778
2974
  client_capabilities: this.buildClientCapabilities("openai", false)
2779
2975
  }, requestOptions);
@@ -2786,11 +2982,15 @@ var AgentID = class {
2786
2982
  console.error("[AgentID] Stream completion wrapping failed:", error);
2787
2983
  });
2788
2984
  }
2789
- return wrappedCompletion.mode === "stream" ? wrappedCompletion.completion : streamResponse;
2985
+ if (wrappedCompletion.mode === "stream") {
2986
+ return attachTransparencyMetadata(wrappedCompletion.completion, transparency);
2987
+ }
2988
+ return attachTransparencyMetadata(streamResponse, transparency);
2790
2989
  }
2791
- const start = Date.now();
2990
+ const modelStartedAt = Date.now();
2792
2991
  const res = await originalCreate.apply(compTarget, createArgs);
2793
- const latency = Date.now() - start;
2992
+ const modelLatencyMs = Math.max(0, Date.now() - modelStartedAt);
2993
+ const totalPipelineLatencyMs = Math.max(0, Date.now() - pipelineStartedAt);
2794
2994
  if (maskedText) {
2795
2995
  const output = adapter.extractOutput(res);
2796
2996
  const wrappedCompletion = this.wrapCompletion(output);
@@ -2805,7 +3005,7 @@ var AgentID = class {
2805
3005
  output: outputForLog,
2806
3006
  model,
2807
3007
  usage,
2808
- latency,
3008
+ latency: modelLatencyMs,
2809
3009
  event_type: "complete",
2810
3010
  metadata: {
2811
3011
  transformed_input: maskedText,
@@ -2815,8 +3015,12 @@ var AgentID = class {
2815
3015
  simulated_decision: verdict.simulated_decision ?? null,
2816
3016
  simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
2817
3017
  response_streamed: false,
3018
+ guard_latency_ms: guardLatencyMs,
3019
+ model_latency_ms: modelLatencyMs,
3020
+ total_pipeline_latency_ms: totalPipelineLatencyMs,
2818
3021
  guard_event_id: guardEventId,
2819
- client_event_id: canonicalClientEventId
3022
+ client_event_id: canonicalClientEventId,
3023
+ transparency
2820
3024
  },
2821
3025
  client_capabilities: this.buildClientCapabilities("openai", false)
2822
3026
  }, requestOptions);
@@ -2843,7 +3047,7 @@ var AgentID = class {
2843
3047
  } catch {
2844
3048
  }
2845
3049
  }
2846
- return res;
3050
+ return attachTransparencyMetadata(res, transparency);
2847
3051
  };
2848
3052
  }
2849
3053
  });
@@ -2861,9 +3065,169 @@ var AgentID = class {
2861
3065
  });
2862
3066
  }
2863
3067
  };
3068
+
3069
+ // src/transparency-badge.tsx
3070
+ var React = __toESM(require("react"));
3071
+ var import_jsx_runtime = require("react/jsx-runtime");
3072
+ var DEFAULT_MESSAGE = "You are interacting with an AI.";
3073
+ var DEFAULT_BASE_URL = "https://api.getagentid.com/v1";
3074
+ function resolveBadgeMessage(params) {
3075
+ if (typeof params.message === "string" && params.message.trim().length > 0) {
3076
+ return params.message.trim();
3077
+ }
3078
+ if (params.metadata?.disclosure) {
3079
+ return params.metadata.disclosure;
3080
+ }
3081
+ return DEFAULT_MESSAGE;
3082
+ }
3083
+ function normalizeBaseUrl4(baseUrl) {
3084
+ const candidate = typeof baseUrl === "string" && baseUrl.trim().length > 0 ? baseUrl.trim() : DEFAULT_BASE_URL;
3085
+ return candidate.replace(/\/+$/, "");
3086
+ }
3087
+ function createEventId2() {
3088
+ try {
3089
+ if (typeof globalThis !== "undefined" && globalThis.crypto?.randomUUID) {
3090
+ return globalThis.crypto.randomUUID();
3091
+ }
3092
+ } catch {
3093
+ }
3094
+ const seed = Math.random().toString(16).slice(2).padEnd(12, "0").slice(0, 12);
3095
+ return `00000000-0000-4000-8000-${seed}`;
3096
+ }
3097
+ async function sendTransparencyBadgeRenderedTelemetry(params) {
3098
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3099
+ const eventId = createEventId2();
3100
+ const payload = {
3101
+ event_id: eventId,
3102
+ system_id: params.telemetry.systemId,
3103
+ input: "__agentid_transparency_badge_rendered__",
3104
+ output: params.disclosureText,
3105
+ model: params.telemetry.model ?? "agentid-transparency-badge",
3106
+ user_id: params.telemetry.userId,
3107
+ event_type: "transparency_badge_rendered",
3108
+ severity: "info",
3109
+ timestamp,
3110
+ metadata: {
3111
+ compliance_event: "transparency_badge_rendered",
3112
+ rendered_at: timestamp,
3113
+ placement: params.placement,
3114
+ disclosure_text: params.disclosureText,
3115
+ ...params.telemetry.metadata ?? {}
3116
+ }
3117
+ };
3118
+ const targetIngestUrl = typeof params.telemetry.ingestUrl === "string" && params.telemetry.ingestUrl.trim().length > 0 ? params.telemetry.ingestUrl.trim() : `${normalizeBaseUrl4(params.telemetry.baseUrl)}/ingest`;
3119
+ const headers = {
3120
+ "Content-Type": "application/json",
3121
+ "X-AgentID-SDK-Version": "js-1.1.0",
3122
+ ...params.telemetry.headers ?? {}
3123
+ };
3124
+ if (typeof params.telemetry.apiKey === "string" && params.telemetry.apiKey.trim().length > 0) {
3125
+ headers["x-agentid-api-key"] = params.telemetry.apiKey.trim();
3126
+ }
3127
+ const response = await fetch(targetIngestUrl, {
3128
+ method: "POST",
3129
+ headers,
3130
+ body: JSON.stringify(payload),
3131
+ keepalive: true
3132
+ });
3133
+ if (!response.ok) {
3134
+ throw new Error(
3135
+ `AgentID transparency badge telemetry failed (status=${response.status})`
3136
+ );
3137
+ }
3138
+ }
3139
+ function AgentIDTransparencyBadge(props) {
3140
+ const placement = props.placement ?? "chat-header";
3141
+ const fixed = props.fixed ?? true;
3142
+ const text = resolveBadgeMessage({
3143
+ metadata: props.metadata,
3144
+ message: props.message
3145
+ });
3146
+ const hasLoggedRenderRef = React.useRef(false);
3147
+ React.useEffect(() => {
3148
+ if (hasLoggedRenderRef.current) {
3149
+ return;
3150
+ }
3151
+ hasLoggedRenderRef.current = true;
3152
+ void sendTransparencyBadgeRenderedTelemetry({
3153
+ telemetry: props.telemetry,
3154
+ disclosureText: text,
3155
+ placement
3156
+ }).catch((error) => {
3157
+ if (typeof props.telemetry.onError === "function") {
3158
+ props.telemetry.onError(error);
3159
+ return;
3160
+ }
3161
+ console.warn(error);
3162
+ });
3163
+ }, [placement, props.telemetry, text]);
3164
+ const containerStyle = placement === "watermark-overlay" ? {
3165
+ position: fixed ? "fixed" : "absolute",
3166
+ right: 16,
3167
+ bottom: 16,
3168
+ zIndex: 2147483e3,
3169
+ pointerEvents: "none",
3170
+ opacity: 0.95
3171
+ } : {
3172
+ position: fixed ? "fixed" : "sticky",
3173
+ top: 0,
3174
+ left: 0,
3175
+ right: 0,
3176
+ zIndex: 2147483e3,
3177
+ pointerEvents: "none"
3178
+ };
3179
+ const badgeStyle = placement === "watermark-overlay" ? {
3180
+ display: "inline-flex",
3181
+ alignItems: "center",
3182
+ gap: 8,
3183
+ background: "rgba(15, 23, 42, 0.9)",
3184
+ color: "#f8fafc",
3185
+ borderRadius: 9999,
3186
+ padding: "8px 12px",
3187
+ fontFamily: "ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif",
3188
+ fontSize: 12,
3189
+ fontWeight: 600,
3190
+ boxShadow: "0 8px 24px rgba(15, 23, 42, 0.28)",
3191
+ pointerEvents: "none"
3192
+ } : {
3193
+ display: "flex",
3194
+ alignItems: "center",
3195
+ justifyContent: "center",
3196
+ gap: 8,
3197
+ background: "#0f172a",
3198
+ color: "#f8fafc",
3199
+ borderBottom: "1px solid rgba(148, 163, 184, 0.35)",
3200
+ padding: "9px 12px",
3201
+ fontFamily: "ui-sans-serif, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif",
3202
+ fontSize: 13,
3203
+ fontWeight: 600,
3204
+ pointerEvents: "none"
3205
+ };
3206
+ const iconStyle = {
3207
+ width: 22,
3208
+ height: 22,
3209
+ minWidth: 22,
3210
+ borderRadius: 9999,
3211
+ background: "#2563eb",
3212
+ color: "#eff6ff",
3213
+ display: "inline-flex",
3214
+ alignItems: "center",
3215
+ justifyContent: "center",
3216
+ fontSize: 10,
3217
+ fontWeight: 800,
3218
+ letterSpacing: 0.5,
3219
+ lineHeight: 1,
3220
+ border: "1px solid rgba(191, 219, 254, 0.55)"
3221
+ };
3222
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: props.className, style: containerStyle, "aria-live": "polite", role: "status", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: badgeStyle, children: [
3223
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", style: iconStyle, children: "AI" }),
3224
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: text })
3225
+ ] }) });
3226
+ }
2864
3227
  // Annotate the CommonJS export names for ESM import in node:
2865
3228
  0 && (module.exports = {
2866
3229
  AgentID,
3230
+ AgentIDTransparencyBadge,
2867
3231
  InjectionScanner,
2868
3232
  OpenAIAdapter,
2869
3233
  PIIManager,