agent-inspect 6.31.5 → 6.31.7

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +1 -1
  3. package/docs/AI-SDK-ADOPTION.md +62 -34
  4. package/docs/SAFE-TRACE-SHARING.md +1 -1
  5. package/package.json +1 -1
  6. package/packages/cli/dist/{chunk-LKEPABND.mjs → chunk-QV73NM25.mjs} +100 -31
  7. package/packages/cli/dist/chunk-QV73NM25.mjs.map +1 -0
  8. package/packages/cli/dist/index.cjs +474 -92
  9. package/packages/cli/dist/index.cjs.map +1 -1
  10. package/packages/cli/dist/index.mjs +379 -67
  11. package/packages/cli/dist/index.mjs.map +1 -1
  12. package/packages/cli/dist/{src-4WYF5RFI.mjs → src-KFOBXFPN.mjs} +3 -3
  13. package/packages/cli/dist/{src-4WYF5RFI.mjs.map → src-KFOBXFPN.mjs.map} +1 -1
  14. package/packages/core/dist/advanced.cjs +95 -23
  15. package/packages/core/dist/advanced.cjs.map +1 -1
  16. package/packages/core/dist/advanced.mjs +11 -11
  17. package/packages/core/dist/checks.cjs +2 -5
  18. package/packages/core/dist/checks.cjs.map +1 -1
  19. package/packages/core/dist/checks.mjs +3 -3
  20. package/packages/core/dist/{chunk-OSGNGRHF.mjs → chunk-3RV3JILQ.mjs} +34 -16
  21. package/packages/core/dist/chunk-3RV3JILQ.mjs.map +1 -0
  22. package/packages/core/dist/{chunk-NY4ILMXK.mjs → chunk-7YYS742B.mjs} +50 -13
  23. package/packages/core/dist/chunk-7YYS742B.mjs.map +1 -0
  24. package/packages/core/dist/{chunk-2KJR6X4V.mjs → chunk-DK3OW6UI.mjs} +3 -3
  25. package/packages/core/dist/chunk-DK3OW6UI.mjs.map +1 -0
  26. package/packages/core/dist/{chunk-PKDBFBJ7.mjs → chunk-LXYPM2ZO.mjs} +5 -8
  27. package/packages/core/dist/{chunk-PKDBFBJ7.mjs.map → chunk-LXYPM2ZO.mjs.map} +1 -1
  28. package/packages/core/dist/{chunk-INE5IWLN.mjs → chunk-N5PZAI6Q.mjs} +3 -3
  29. package/packages/core/dist/{chunk-INE5IWLN.mjs.map → chunk-N5PZAI6Q.mjs.map} +1 -1
  30. package/packages/core/dist/{chunk-Q5SLKV2Y.mjs → chunk-QLYUWKK7.mjs} +19 -2
  31. package/packages/core/dist/chunk-QLYUWKK7.mjs.map +1 -0
  32. package/packages/core/dist/{chunk-MTMTXTJL.mjs → chunk-VQUB3WRI.mjs} +4 -4
  33. package/packages/core/dist/{chunk-MTMTXTJL.mjs.map → chunk-VQUB3WRI.mjs.map} +1 -1
  34. package/packages/core/dist/exporters.cjs +253 -50
  35. package/packages/core/dist/exporters.cjs.map +1 -1
  36. package/packages/core/dist/exporters.mjs +208 -42
  37. package/packages/core/dist/exporters.mjs.map +1 -1
  38. package/packages/core/dist/index.cjs +1 -1
  39. package/packages/core/dist/index.cjs.map +1 -1
  40. package/packages/core/dist/index.mjs +4 -4
  41. package/packages/core/dist/persisted.cjs +17 -0
  42. package/packages/core/dist/persisted.cjs.map +1 -1
  43. package/packages/core/dist/persisted.mjs +2 -2
  44. package/packages/core/dist/readers.cjs +48 -13
  45. package/packages/core/dist/readers.cjs.map +1 -1
  46. package/packages/core/dist/readers.mjs +2 -2
  47. package/packages/core/dist/writers.cjs +1 -1
  48. package/packages/core/dist/writers.cjs.map +1 -1
  49. package/packages/core/dist/writers.mjs +1 -1
  50. package/packages/cli/dist/chunk-LKEPABND.mjs.map +0 -1
  51. package/packages/core/dist/chunk-2KJR6X4V.mjs.map +0 -1
  52. package/packages/core/dist/chunk-NY4ILMXK.mjs.map +0 -1
  53. package/packages/core/dist/chunk-OSGNGRHF.mjs.map +0 -1
  54. package/packages/core/dist/chunk-Q5SLKV2Y.mjs.map +0 -1
@@ -1,8 +1,8 @@
1
- import { buildRunWhatSummary, renderRunWhat, renderTimeline, buildRunTimeline } from './chunk-NY4ILMXK.mjs';
2
- import { summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml } from './chunk-INE5IWLN.mjs';
1
+ import { buildRunWhatSummary, renderRunWhat, renderTimeline, buildRunTimeline } from './chunk-7YYS742B.mjs';
2
+ import { summarizeObservedOutcomes, extractOutcomesFromTraceEvents, renderObservedOutcomesMarkdown, renderObservedOutcomesHtml } from './chunk-N5PZAI6Q.mjs';
3
3
  import { escapeHtml, flattenTree, safeString, compactAttributes, stableJson, escapeMarkdown, zeroKinds } from './chunk-CAWPF22J.mjs';
4
4
  export { compactAttributes, escapeHtml, escapeMarkdown, flattenTree, safeString, stableJson, summarizeTree } from './chunk-CAWPF22J.mjs';
5
- import { resolveRedactionProfile, applyProfileMetadataCaps, truncateStringForProfile, stringContainsHighConfidenceCredential } from './chunk-2KJR6X4V.mjs';
5
+ import { resolveRedactionProfile, applyProfileMetadataCaps, truncateStringForProfile, stringContainsHighConfidenceCredential } from './chunk-DK3OW6UI.mjs';
6
6
  import { Redactor, DEFAULT_REDACT_KEYS, isCredentialSensitiveKey } from './chunk-VLVCLAPB.mjs';
7
7
  import './chunk-7DHSWDKB.mjs';
8
8
  import './chunk-EE5Z2GQ3.mjs';
@@ -27,6 +27,8 @@ var CONNECTION_PROTOCOLS = /* @__PURE__ */ new Set([
27
27
  "amqps:"
28
28
  ]);
29
29
  var CONNECTION_URI = /^(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/[^\s]+$/i;
30
+ var CONNECTION_USERINFO = /^(postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/([^@/?#]+)@(.+)$/i;
31
+ var CONNECTION_HAS_USERINFO = /^(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/[^@/?#]+@/i;
30
32
  var UUID_SEGMENT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
31
33
  var HEX_SEGMENT = /^[0-9a-f]{12,}$/i;
32
34
  var NUMERIC_SEGMENT = /^\d{5,}$/;
@@ -50,6 +52,28 @@ function parseRedactableUrl(value) {
50
52
  return void 0;
51
53
  }
52
54
  }
55
+ function redactConnectionUserinfoFallback(value, replacement) {
56
+ const trimmed = value.trim();
57
+ const match = CONNECTION_USERINFO.exec(trimmed);
58
+ if (match) {
59
+ const [, scheme, , rest] = match;
60
+ if (scheme && rest && rest.length > 0) {
61
+ return {
62
+ value: `${scheme}://${rest}`,
63
+ credentialRedacted: true,
64
+ identifiersMasked: false
65
+ };
66
+ }
67
+ }
68
+ if (looksLikeConnectionUri(trimmed) && CONNECTION_HAS_USERINFO.test(trimmed)) {
69
+ return {
70
+ value: replacement,
71
+ credentialRedacted: true,
72
+ identifiersMasked: false
73
+ };
74
+ }
75
+ return void 0;
76
+ }
53
77
  function isHttpProtocol(protocol) {
54
78
  return protocol === "http:" || protocol === "https:";
55
79
  }
@@ -91,9 +115,11 @@ function redactUrlString(value, options) {
91
115
  identifiersMasked: false
92
116
  };
93
117
  if (!looksLikeUrlForRedaction(value)) return unchanged;
94
- const url = parseRedactableUrl(value);
95
- if (!url) return unchanged;
96
118
  const replacement = options.replacement ?? "[REDACTED]";
119
+ const url = parseRedactableUrl(value);
120
+ if (!url) {
121
+ return redactConnectionUserinfoFallback(value, replacement) ?? unchanged;
122
+ }
97
123
  const idPlaceholder = options.idPlaceholder ?? "[id]";
98
124
  const http = isHttpProtocol(url.protocol);
99
125
  let credentialRedacted = url.username.length > 0 || url.password.length > 0;
@@ -782,6 +808,10 @@ function exportOpenInference(tree, options) {
782
808
  warnings
783
809
  };
784
810
  }
811
+ var OTLP_STATUS_CODE_UNSET = 0;
812
+ var OTLP_STATUS_CODE_OK = 1;
813
+ var OTLP_STATUS_CODE_ERROR = 2;
814
+ var OTLP_SPAN_KIND_INTERNAL = 1;
785
815
  function hexFrom2(seed, byteLen) {
786
816
  return crypto.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, byteLen * 2);
787
817
  }
@@ -794,7 +824,19 @@ function stringAttr(key, value) {
794
824
  return { key, value: { stringValue: value } };
795
825
  }
796
826
  function intAttr(key, value) {
797
- return { key, value: { intValue: String(value) } };
827
+ return { key, value: { intValue: String(Math.trunc(value)) } };
828
+ }
829
+ function doubleAttr(key, value) {
830
+ return { key, value: { doubleValue: value } };
831
+ }
832
+ function boolAttr(key, value) {
833
+ return { key, value: { boolValue: value } };
834
+ }
835
+ function numberAttr(key, value) {
836
+ if (Number.isFinite(value) && !Number.isInteger(value)) {
837
+ return doubleAttr(key, value);
838
+ }
839
+ return intAttr(key, value);
798
840
  }
799
841
  function genAiOperationName(kind) {
800
842
  switch (kind) {
@@ -808,10 +850,27 @@ function genAiOperationName(kind) {
808
850
  return void 0;
809
851
  }
810
852
  }
853
+ function resolveSpanTimes(ev) {
854
+ const startedAtMs = typeof ev.attributes?.startedAtMs === "number" && Number.isFinite(ev.attributes.startedAtMs) ? ev.attributes.startedAtMs : void 0;
855
+ const endedAtMs = typeof ev.attributes?.endedAtMs === "number" && Number.isFinite(ev.attributes.endedAtMs) ? ev.attributes.endedAtMs : void 0;
856
+ const startMs = startedAtMs ?? ev.timestamp;
857
+ const startNs = String(unixNano2(startMs));
858
+ if (endedAtMs !== void 0) {
859
+ return { startNs, endNs: String(unixNano2(endedAtMs)) };
860
+ }
861
+ if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
862
+ return {
863
+ startNs,
864
+ endNs: String(unixNano2(startMs) + unixNano2(ev.durationMs))
865
+ };
866
+ }
867
+ return { startNs };
868
+ }
811
869
  function exportOtlpJson(tree, options) {
812
870
  const warnings = [
813
871
  "OTLP JSON export uses OTel GenAI-aligned attributes where applicable; experimental until verified against specific collectors.",
814
- "Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload."
872
+ "Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload.",
873
+ "Status and span kind use OTLP numeric enums (StatusCode 0/1/2, SpanKind INTERNAL=1)."
815
874
  ];
816
875
  const traceId = hexFrom2(`trace:${tree.runId}`, 16);
817
876
  const includeAttributes = options?.includeAttributes ?? false;
@@ -823,11 +882,7 @@ function exportOtlpJson(tree, options) {
823
882
  const ev = n.event;
824
883
  const spanId = hexFrom2(`${tree.runId}:${ev.eventId}`, 8);
825
884
  const parentSpanId = ev.parentId ? hexFrom2(`${tree.runId}:${ev.parentId}`, 8) : void 0;
826
- const startNs = String(unixNano2(ev.timestamp));
827
- let endNs;
828
- if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
829
- endNs = String(unixNano2(ev.timestamp) + unixNano2(ev.durationMs));
830
- }
885
+ const { startNs, endNs } = resolveSpanTimes(ev);
831
886
  const attrs = [
832
887
  stringAttr("agent_inspect.kind", ev.kind),
833
888
  stringAttr("agent_inspect.confidence", ev.confidence),
@@ -857,29 +912,28 @@ function exportOtlpJson(tree, options) {
857
912
  if (includeAttributes && meta && typeof meta === "object") {
858
913
  for (const [k, v] of Object.entries(meta)) {
859
914
  if (k === "tokens" || k === "model") continue;
860
- if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
861
- attrs.push(
862
- stringAttr(
863
- `agent_inspect.preview.${k}`,
864
- typeof v === "string" ? v.slice(0, maxLen) : String(v)
865
- )
866
- );
915
+ if (typeof v === "string") {
916
+ attrs.push(stringAttr(`agent_inspect.preview.${k}`, v.slice(0, maxLen)));
917
+ } else if (typeof v === "number" && Number.isFinite(v)) {
918
+ attrs.push(numberAttr(`agent_inspect.preview.${k}`, v));
919
+ } else if (typeof v === "boolean") {
920
+ attrs.push(boolAttr(`agent_inspect.preview.${k}`, v));
867
921
  }
868
922
  }
869
923
  }
870
- let statusCode = "STATUS_CODE_UNSET";
924
+ let statusCode = OTLP_STATUS_CODE_UNSET;
871
925
  let statusMessage;
872
926
  if (ev.status === "error") {
873
- statusCode = "STATUS_CODE_ERROR";
927
+ statusCode = OTLP_STATUS_CODE_ERROR;
874
928
  statusMessage = meta && typeof meta.error === "object" && meta.error !== null ? String(meta.error.message ?? "error").slice(0, maxLen) : "error";
875
929
  } else if (ev.status === "ok") {
876
- statusCode = "STATUS_CODE_OK";
930
+ statusCode = OTLP_STATUS_CODE_OK;
877
931
  }
878
932
  const spanJson = {
879
933
  traceId,
880
934
  spanId,
881
935
  name: ev.name,
882
- kind: "SPAN_KIND_INTERNAL",
936
+ kind: OTLP_SPAN_KIND_INTERNAL,
883
937
  startTimeUnixNano: startNs,
884
938
  attributes: attrs,
885
939
  status: {
@@ -921,6 +975,136 @@ function exportOtlpJson(tree, options) {
921
975
 
922
976
  // packages/core/src/exporters/validation.ts
923
977
  var EXPERIMENTAL = "Experimental compatibility export \u2014 verify against your target tooling before relying on it.";
978
+ function pushPath(errors, path, message) {
979
+ errors.push(`${path}: ${message}`);
980
+ }
981
+ function isRecord2(value) {
982
+ return value !== null && typeof value === "object" && !Array.isArray(value);
983
+ }
984
+ function validateOtlpJson(content) {
985
+ const errors = [];
986
+ const warnings = [
987
+ EXPERIMENTAL,
988
+ "OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation.",
989
+ "protocol-valid \u2260 profile-complete \u2260 fixture-complete \u2014 nested path diagnostics report protocol shape only."
990
+ ];
991
+ let parsed;
992
+ try {
993
+ parsed = JSON.parse(content);
994
+ } catch {
995
+ pushPath(errors, "$", "OTLP JSON export is not valid JSON");
996
+ return { ok: false, format: "otlp-json", errors, warnings };
997
+ }
998
+ if (!isRecord2(parsed)) {
999
+ pushPath(errors, "$", "OTLP JSON export must be an object");
1000
+ return { ok: false, format: "otlp-json", errors, warnings };
1001
+ }
1002
+ if (!Array.isArray(parsed.resourceSpans)) {
1003
+ pushPath(errors, "$.resourceSpans", "must be an array");
1004
+ return { ok: false, format: "otlp-json", errors, warnings };
1005
+ }
1006
+ parsed.resourceSpans.forEach((resourceSpan, rsi) => {
1007
+ const rsPath = `$.resourceSpans[${rsi}]`;
1008
+ if (!isRecord2(resourceSpan)) {
1009
+ pushPath(errors, rsPath, "must be an object");
1010
+ return;
1011
+ }
1012
+ if (!Array.isArray(resourceSpan.scopeSpans)) {
1013
+ pushPath(errors, `${rsPath}.scopeSpans`, "must be an array");
1014
+ return;
1015
+ }
1016
+ resourceSpan.scopeSpans.forEach((scopeSpan, ssi) => {
1017
+ const ssPath = `${rsPath}.scopeSpans[${ssi}]`;
1018
+ if (!isRecord2(scopeSpan)) {
1019
+ pushPath(errors, ssPath, "must be an object");
1020
+ return;
1021
+ }
1022
+ if (!Array.isArray(scopeSpan.spans)) {
1023
+ pushPath(errors, `${ssPath}.spans`, "must be an array");
1024
+ return;
1025
+ }
1026
+ scopeSpan.spans.forEach((span, spi) => {
1027
+ const spanPath = `${ssPath}.spans[${spi}]`;
1028
+ if (!isRecord2(span)) {
1029
+ pushPath(errors, spanPath, "must be an object");
1030
+ return;
1031
+ }
1032
+ if (typeof span.traceId !== "string" || span.traceId.length === 0) {
1033
+ pushPath(errors, `${spanPath}.traceId`, "must be a non-empty string");
1034
+ }
1035
+ if (typeof span.spanId !== "string" || span.spanId.length === 0) {
1036
+ pushPath(errors, `${spanPath}.spanId`, "must be a non-empty string");
1037
+ }
1038
+ if (typeof span.name !== "string") {
1039
+ pushPath(errors, `${spanPath}.name`, "must be a string");
1040
+ }
1041
+ if (typeof span.startTimeUnixNano !== "string" || !/^\d+$/.test(span.startTimeUnixNano)) {
1042
+ pushPath(
1043
+ errors,
1044
+ `${spanPath}.startTimeUnixNano`,
1045
+ "must be a decimal-string 64-bit integer"
1046
+ );
1047
+ }
1048
+ if (span.endTimeUnixNano !== void 0 && (typeof span.endTimeUnixNano !== "string" || !/^\d+$/.test(span.endTimeUnixNano))) {
1049
+ pushPath(
1050
+ errors,
1051
+ `${spanPath}.endTimeUnixNano`,
1052
+ "must be a decimal-string 64-bit integer when present"
1053
+ );
1054
+ }
1055
+ if (typeof span.kind === "number") {
1056
+ if (!Number.isInteger(span.kind)) {
1057
+ pushPath(errors, `${spanPath}.kind`, "must be an integer SpanKind enum");
1058
+ }
1059
+ } else if (typeof span.kind === "string") {
1060
+ warnings.push(
1061
+ `${spanPath}.kind: string SpanKind enum is legacy; prefer numeric (INTERNAL=1)`
1062
+ );
1063
+ } else if (span.kind !== void 0) {
1064
+ pushPath(
1065
+ errors,
1066
+ `${spanPath}.kind`,
1067
+ "must be numeric SpanKind or historical string enum"
1068
+ );
1069
+ }
1070
+ if (!isRecord2(span.status)) {
1071
+ pushPath(errors, `${spanPath}.status`, "must be an object");
1072
+ } else {
1073
+ const code = span.status.code;
1074
+ if (typeof code === "number") {
1075
+ if (![0, 1, 2].includes(code)) {
1076
+ pushPath(
1077
+ errors,
1078
+ `${spanPath}.status.code`,
1079
+ "must be numeric StatusCode 0 (UNSET), 1 (OK), or 2 (ERROR)"
1080
+ );
1081
+ }
1082
+ } else if (typeof code === "string") {
1083
+ const upper = code.toUpperCase();
1084
+ if (upper !== "STATUS_CODE_UNSET" && upper !== "STATUS_CODE_OK" && upper !== "STATUS_CODE_ERROR" && upper !== "UNSET" && upper !== "OK" && upper !== "ERROR" && !/^[012]$/.test(code.trim())) {
1085
+ pushPath(
1086
+ errors,
1087
+ `${spanPath}.status.code`,
1088
+ "unrecognized StatusCode string"
1089
+ );
1090
+ } else {
1091
+ warnings.push(
1092
+ `${spanPath}.status.code: string StatusCode is legacy; prefer numeric 0/1/2`
1093
+ );
1094
+ }
1095
+ } else {
1096
+ pushPath(
1097
+ errors,
1098
+ `${spanPath}.status.code`,
1099
+ "must be numeric StatusCode 0/1/2 or historical string enum"
1100
+ );
1101
+ }
1102
+ }
1103
+ });
1104
+ });
1105
+ });
1106
+ return { ok: errors.length === 0, format: "otlp-json", errors, warnings };
1107
+ }
924
1108
  function validateExportContent(format, content) {
925
1109
  const errors = [];
926
1110
  const warnings = [EXPERIMENTAL];
@@ -966,25 +1150,7 @@ function validateExportContent(format, content) {
966
1150
  return { ok: errors.length === 0, format, errors, warnings };
967
1151
  }
968
1152
  if (format === "otlp-json") {
969
- let parsed;
970
- try {
971
- parsed = JSON.parse(content);
972
- } catch {
973
- errors.push("OTLP JSON export is not valid JSON");
974
- return { ok: false, format, errors, warnings };
975
- }
976
- if (!parsed || typeof parsed !== "object") {
977
- errors.push("OTLP JSON export must be an object");
978
- return { ok: false, format, errors, warnings };
979
- }
980
- const o = parsed;
981
- if (!Array.isArray(o.resourceSpans)) {
982
- errors.push("OTLP JSON export must include resourceSpans array");
983
- }
984
- warnings.push(
985
- "OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation."
986
- );
987
- return { ok: errors.length === 0, format, errors, warnings };
1153
+ return validateOtlpJson(content);
988
1154
  }
989
1155
  errors.push(`Unsupported export format`);
990
1156
  return { ok: false, format, errors, warnings };