@agent-inspect/viewer 6.31.21 → 6.31.23
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.cjs +280 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +280 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -2748,22 +2748,192 @@ function runTraceChecks(input, options = {}) {
|
|
|
2748
2748
|
};
|
|
2749
2749
|
}
|
|
2750
2750
|
|
|
2751
|
+
// packages/core/src/checks/canonical-equality.ts
|
|
2752
|
+
var DEFAULT_MAX_DEPTH = 8;
|
|
2753
|
+
var DEFAULT_MAX_BYTES = 16384;
|
|
2754
|
+
function sortKeysDeep(input, depth, maxDepth) {
|
|
2755
|
+
if (depth > maxDepth) {
|
|
2756
|
+
throw new Error("AI_CHECK_CANONICAL_DEPTH_EXCEEDED");
|
|
2757
|
+
}
|
|
2758
|
+
if (input === null || typeof input !== "object") return input;
|
|
2759
|
+
if (Array.isArray(input)) {
|
|
2760
|
+
return input.map((item) => sortKeysDeep(item, depth + 1, maxDepth));
|
|
2761
|
+
}
|
|
2762
|
+
const record = input;
|
|
2763
|
+
const out = {};
|
|
2764
|
+
for (const key of Object.keys(record).sort()) {
|
|
2765
|
+
out[key] = sortKeysDeep(record[key], depth + 1, maxDepth);
|
|
2766
|
+
}
|
|
2767
|
+
return out;
|
|
2768
|
+
}
|
|
2769
|
+
function encodeCanonicalStructured(value, limits) {
|
|
2770
|
+
const maxDepth = DEFAULT_MAX_DEPTH;
|
|
2771
|
+
const maxBytes = DEFAULT_MAX_BYTES;
|
|
2772
|
+
try {
|
|
2773
|
+
const sorted = sortKeysDeep(value, 0, maxDepth);
|
|
2774
|
+
const encoded = JSON.stringify(sorted);
|
|
2775
|
+
if (encoded === void 0) {
|
|
2776
|
+
return {
|
|
2777
|
+
ok: false,
|
|
2778
|
+
reason: "Value is not JSON-serializable for canonical comparison.",
|
|
2779
|
+
code: "AI_CHECK_CANONICAL_UNSERIALIZABLE"
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2782
|
+
if (Buffer.byteLength(encoded, "utf8") > maxBytes) {
|
|
2783
|
+
return {
|
|
2784
|
+
ok: false,
|
|
2785
|
+
reason: "Canonical structured value exceeds bounded size limit.",
|
|
2786
|
+
code: "AI_CHECK_CANONICAL_SIZE_EXCEEDED"
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
return { ok: true, value: encoded };
|
|
2790
|
+
} catch (error) {
|
|
2791
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2792
|
+
if (message === "AI_CHECK_CANONICAL_DEPTH_EXCEEDED") {
|
|
2793
|
+
return {
|
|
2794
|
+
ok: false,
|
|
2795
|
+
reason: "Canonical structured value exceeds bounded depth limit.",
|
|
2796
|
+
code: "AI_CHECK_CANONICAL_DEPTH_EXCEEDED"
|
|
2797
|
+
};
|
|
2798
|
+
}
|
|
2799
|
+
return {
|
|
2800
|
+
ok: false,
|
|
2801
|
+
reason: "Canonical structured encoding failed.",
|
|
2802
|
+
code: "AI_CHECK_CANONICAL_UNSERIALIZABLE"
|
|
2803
|
+
};
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
// packages/core/src/persisted/delivery-identity.ts
|
|
2808
|
+
var DELIVERY_CONFLICT_ATTR = "agent_inspect.delivery_conflict";
|
|
2809
|
+
var DELIVERY_EVENT_BASE_ATTR = "agent_inspect.delivery_event_base";
|
|
2810
|
+
var MAX_DELIVERY_BASE_LEN = 500;
|
|
2811
|
+
function stripReaderDeliveryDiscriminator(eventId, attributes) {
|
|
2812
|
+
if (!eventId) return eventId;
|
|
2813
|
+
const rawBase = attributes?.[DELIVERY_EVENT_BASE_ATTR];
|
|
2814
|
+
if (typeof rawBase !== "string" || rawBase.trim() === "") return eventId;
|
|
2815
|
+
const base = rawBase.trim().slice(0, MAX_DELIVERY_BASE_LEN);
|
|
2816
|
+
if (eventId === base) return base;
|
|
2817
|
+
const prefix = `${base}:`;
|
|
2818
|
+
if (!eventId.startsWith(prefix)) return eventId;
|
|
2819
|
+
const suffix = eventId.slice(prefix.length);
|
|
2820
|
+
if (/^\d+$/.test(suffix)) return base;
|
|
2821
|
+
return eventId;
|
|
2822
|
+
}
|
|
2823
|
+
function deliveryEventBaseFromIndexedId(eventId) {
|
|
2824
|
+
if (!/:\d+$/.test(eventId)) return void 0;
|
|
2825
|
+
const base = eventId.replace(/:\d+$/, "");
|
|
2826
|
+
return base.length > 0 ? base.slice(0, MAX_DELIVERY_BASE_LEN) : void 0;
|
|
2827
|
+
}
|
|
2828
|
+
function canonicalDigest(value) {
|
|
2829
|
+
if (value === void 0) return null;
|
|
2830
|
+
const encoded = encodeCanonicalStructured(value);
|
|
2831
|
+
return encoded.ok ? encoded.value : `unencodable:${encoded.code}`;
|
|
2832
|
+
}
|
|
2833
|
+
function capturedContentDigest(attributes) {
|
|
2834
|
+
if (!attributes || typeof attributes !== "object") {
|
|
2835
|
+
return { args: null, result: null };
|
|
2836
|
+
}
|
|
2837
|
+
const nested = attributes.metadata && typeof attributes.metadata === "object" ? attributes.metadata : void 0;
|
|
2838
|
+
const args = attributes.arguments ?? attributes.args ?? attributes.input ?? nested?.arguments ?? nested?.args ?? nested?.input;
|
|
2839
|
+
const result = attributes.result ?? attributes.output ?? attributes.response ?? nested?.result ?? nested?.output ?? nested?.response;
|
|
2840
|
+
return {
|
|
2841
|
+
args: args === void 0 ? null : canonicalDigest(args),
|
|
2842
|
+
result: result === void 0 ? null : canonicalDigest(result)
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
function timeKey(fields) {
|
|
2846
|
+
if (typeof fields.startedAt === "string" && fields.startedAt.trim() !== "") {
|
|
2847
|
+
return fields.startedAt;
|
|
2848
|
+
}
|
|
2849
|
+
if (typeof fields.timestamp === "string" && fields.timestamp.trim() !== "") {
|
|
2850
|
+
return fields.timestamp;
|
|
2851
|
+
}
|
|
2852
|
+
if (typeof fields.timestamp === "number" && Number.isFinite(fields.timestamp)) {
|
|
2853
|
+
return String(fields.timestamp);
|
|
2854
|
+
}
|
|
2855
|
+
return null;
|
|
2856
|
+
}
|
|
2857
|
+
function deliverySemanticFingerprint(fields) {
|
|
2858
|
+
const content = capturedContentDigest(fields.attributes);
|
|
2859
|
+
return JSON.stringify({
|
|
2860
|
+
stableEventId: stripReaderDeliveryDiscriminator(fields.eventId, fields.attributes),
|
|
2861
|
+
runId: fields.runId,
|
|
2862
|
+
kind: fields.kind,
|
|
2863
|
+
name: fields.name,
|
|
2864
|
+
status: fields.status ?? null,
|
|
2865
|
+
parentId: fields.parentId ?? null,
|
|
2866
|
+
sourceType: fields.sourceType ?? null,
|
|
2867
|
+
time: timeKey(fields),
|
|
2868
|
+
operationId: fields.operationId ?? null,
|
|
2869
|
+
attemptId: fields.attemptId ?? null,
|
|
2870
|
+
attemptNumber: fields.attemptNumber ?? null,
|
|
2871
|
+
retryOf: fields.retryOf ?? null,
|
|
2872
|
+
argsDigest: content.args,
|
|
2873
|
+
resultDigest: content.result
|
|
2874
|
+
});
|
|
2875
|
+
}
|
|
2876
|
+
function identityFieldsFromAttributes(attributes) {
|
|
2877
|
+
if (!attributes || typeof attributes !== "object") {
|
|
2878
|
+
return {
|
|
2879
|
+
operationId: null,
|
|
2880
|
+
attemptId: null,
|
|
2881
|
+
attemptNumber: null,
|
|
2882
|
+
retryOf: null
|
|
2883
|
+
};
|
|
2884
|
+
}
|
|
2885
|
+
const nested = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? attributes.metadata : void 0;
|
|
2886
|
+
const pickString2 = (key) => {
|
|
2887
|
+
const direct = attributes[key];
|
|
2888
|
+
if (typeof direct === "string" && direct.trim() !== "") return direct.trim();
|
|
2889
|
+
const nestedValue = nested?.[key];
|
|
2890
|
+
if (typeof nestedValue === "string" && nestedValue.trim() !== "") {
|
|
2891
|
+
return nestedValue.trim();
|
|
2892
|
+
}
|
|
2893
|
+
return null;
|
|
2894
|
+
};
|
|
2895
|
+
const pickNumber = () => {
|
|
2896
|
+
const direct = attributes.attemptNumber ?? attributes.attempt;
|
|
2897
|
+
if (typeof direct === "number" && Number.isFinite(direct)) return direct;
|
|
2898
|
+
const nestedValue = nested?.attemptNumber ?? nested?.attempt;
|
|
2899
|
+
if (typeof nestedValue === "number" && Number.isFinite(nestedValue)) {
|
|
2900
|
+
return nestedValue;
|
|
2901
|
+
}
|
|
2902
|
+
return null;
|
|
2903
|
+
};
|
|
2904
|
+
return {
|
|
2905
|
+
operationId: pickString2("operationId"),
|
|
2906
|
+
attemptId: pickString2("attemptId"),
|
|
2907
|
+
retryOf: pickString2("retryOf"),
|
|
2908
|
+
attemptNumber: pickNumber()
|
|
2909
|
+
};
|
|
2910
|
+
}
|
|
2911
|
+
function stampDeliveryConflict(event) {
|
|
2912
|
+
return {
|
|
2913
|
+
...event,
|
|
2914
|
+
attributes: {
|
|
2915
|
+
...event.attributes ?? {},
|
|
2916
|
+
[DELIVERY_CONFLICT_ATTR]: true
|
|
2917
|
+
}
|
|
2918
|
+
};
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2751
2921
|
// packages/core/src/checks/contract.ts
|
|
2752
2922
|
new Set(OBSERVED_OUTCOME_METHODS);
|
|
2753
2923
|
|
|
2754
2924
|
// packages/core/src/exporters/helpers.ts
|
|
2755
|
-
function
|
|
2925
|
+
function sortKeysDeep2(input) {
|
|
2756
2926
|
if (input === null || typeof input !== "object") return input;
|
|
2757
|
-
if (Array.isArray(input)) return input.map(
|
|
2927
|
+
if (Array.isArray(input)) return input.map(sortKeysDeep2);
|
|
2758
2928
|
const o = input;
|
|
2759
2929
|
const out = {};
|
|
2760
2930
|
for (const k of Object.keys(o).sort()) {
|
|
2761
|
-
out[k] =
|
|
2931
|
+
out[k] = sortKeysDeep2(o[k]);
|
|
2762
2932
|
}
|
|
2763
2933
|
return out;
|
|
2764
2934
|
}
|
|
2765
2935
|
function stableJson(value, pretty) {
|
|
2766
|
-
const sorted =
|
|
2936
|
+
const sorted = sortKeysDeep2(value);
|
|
2767
2937
|
return JSON.stringify(sorted);
|
|
2768
2938
|
}
|
|
2769
2939
|
|
|
@@ -3641,6 +3811,11 @@ function compactAttributes(entries) {
|
|
|
3641
3811
|
}
|
|
3642
3812
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
3643
3813
|
}
|
|
3814
|
+
function stampDeliveryEventBase(eventId, attributes) {
|
|
3815
|
+
const base = deliveryEventBaseFromIndexedId(eventId);
|
|
3816
|
+
if (!base) return attributes;
|
|
3817
|
+
return { ...attributes ?? {}, [DELIVERY_EVENT_BASE_ATTR]: base };
|
|
3818
|
+
}
|
|
3644
3819
|
function traceEventToPersistedInspectEvent(event, options) {
|
|
3645
3820
|
const eventIndex = options?.eventIndex ?? 0;
|
|
3646
3821
|
const eventId = createPersistedEventId(event, eventIndex);
|
|
@@ -3670,7 +3845,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3670
3845
|
startedAt: tsStart.iso,
|
|
3671
3846
|
confidence: "explicit",
|
|
3672
3847
|
source,
|
|
3673
|
-
attributes
|
|
3848
|
+
attributes: stampDeliveryEventBase(eventId, attributes)
|
|
3674
3849
|
};
|
|
3675
3850
|
}
|
|
3676
3851
|
case "run_completed": {
|
|
@@ -3693,7 +3868,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3693
3868
|
durationMs: event.durationMs,
|
|
3694
3869
|
confidence: "explicit",
|
|
3695
3870
|
source,
|
|
3696
|
-
attributes,
|
|
3871
|
+
attributes: stampDeliveryEventBase(eventId, attributes),
|
|
3697
3872
|
error
|
|
3698
3873
|
};
|
|
3699
3874
|
}
|
|
@@ -3718,7 +3893,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3718
3893
|
startedAt: tsStart.iso,
|
|
3719
3894
|
confidence: "explicit",
|
|
3720
3895
|
source,
|
|
3721
|
-
attributes
|
|
3896
|
+
attributes: stampDeliveryEventBase(eventId, attributes)
|
|
3722
3897
|
};
|
|
3723
3898
|
if (event.parentId !== void 0) {
|
|
3724
3899
|
out.parentId = event.parentId;
|
|
@@ -3749,7 +3924,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3749
3924
|
durationMs: event.durationMs,
|
|
3750
3925
|
confidence: "explicit",
|
|
3751
3926
|
source,
|
|
3752
|
-
attributes,
|
|
3927
|
+
attributes: stampDeliveryEventBase(eventId, attributes),
|
|
3753
3928
|
error
|
|
3754
3929
|
};
|
|
3755
3930
|
}
|
|
@@ -3776,7 +3951,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3776
3951
|
timestamp: tsMain.iso,
|
|
3777
3952
|
confidence: "explicit",
|
|
3778
3953
|
source,
|
|
3779
|
-
attributes
|
|
3954
|
+
attributes: stampDeliveryEventBase(eventId, attributes)
|
|
3780
3955
|
};
|
|
3781
3956
|
if (event.parentId !== void 0) {
|
|
3782
3957
|
out.parentId = event.parentId;
|
|
@@ -3929,7 +4104,47 @@ var TreeBuilder = class {
|
|
|
3929
4104
|
const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
|
|
3930
4105
|
const nodes = /* @__PURE__ */ new Map();
|
|
3931
4106
|
for (const e of sorted) {
|
|
3932
|
-
nodes.
|
|
4107
|
+
const existing = nodes.get(e.eventId);
|
|
4108
|
+
if (!existing) {
|
|
4109
|
+
nodes.set(e.eventId, { event: e, children: [], depth: 0 });
|
|
4110
|
+
continue;
|
|
4111
|
+
}
|
|
4112
|
+
const existingAttrs = existing.event.attributes && typeof existing.event.attributes === "object" ? existing.event.attributes : void 0;
|
|
4113
|
+
const nextAttrs = e.attributes && typeof e.attributes === "object" ? e.attributes : void 0;
|
|
4114
|
+
const existingIdentity = identityFieldsFromAttributes(existingAttrs);
|
|
4115
|
+
const nextIdentity = identityFieldsFromAttributes(nextAttrs);
|
|
4116
|
+
const existingFp = deliverySemanticFingerprint({
|
|
4117
|
+
eventId: existing.event.eventId,
|
|
4118
|
+
runId: existing.event.runId,
|
|
4119
|
+
kind: existing.event.kind,
|
|
4120
|
+
name: existing.event.name,
|
|
4121
|
+
status: existing.event.status,
|
|
4122
|
+
parentId: existing.event.parentId,
|
|
4123
|
+
timestamp: existing.event.timestamp,
|
|
4124
|
+
sourceType: existing.event.source?.type,
|
|
4125
|
+
attributes: existingAttrs,
|
|
4126
|
+
...existingIdentity
|
|
4127
|
+
});
|
|
4128
|
+
const nextFp = deliverySemanticFingerprint({
|
|
4129
|
+
eventId: e.eventId,
|
|
4130
|
+
runId: e.runId,
|
|
4131
|
+
kind: e.kind,
|
|
4132
|
+
name: e.name,
|
|
4133
|
+
status: e.status,
|
|
4134
|
+
parentId: e.parentId,
|
|
4135
|
+
timestamp: e.timestamp,
|
|
4136
|
+
sourceType: e.source?.type,
|
|
4137
|
+
attributes: nextAttrs,
|
|
4138
|
+
...nextIdentity
|
|
4139
|
+
});
|
|
4140
|
+
if (existingFp === nextFp) {
|
|
4141
|
+
continue;
|
|
4142
|
+
}
|
|
4143
|
+
nodes.set(e.eventId, {
|
|
4144
|
+
event: stampDeliveryConflict(e),
|
|
4145
|
+
children: [],
|
|
4146
|
+
depth: 0
|
|
4147
|
+
});
|
|
3933
4148
|
}
|
|
3934
4149
|
const { roots, summary } = linkNodesVisibilityFirst(nodes);
|
|
3935
4150
|
const confidenceBreakdown = {
|
|
@@ -5394,6 +5609,12 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
|
|
|
5394
5609
|
["agent_inspect.retry_of", "retryOf", "string"],
|
|
5395
5610
|
["agent_inspect.attempt_number", "attemptNumber", "int"]
|
|
5396
5611
|
];
|
|
5612
|
+
const conflictMapping = [
|
|
5613
|
+
["agent_inspect.identity_conflict.operation_id", "operationId", "string"],
|
|
5614
|
+
["agent_inspect.identity_conflict.attempt_id", "attemptId", "string"],
|
|
5615
|
+
["agent_inspect.identity_conflict.retry_of", "retryOf", "string"],
|
|
5616
|
+
["agent_inspect.identity_conflict.attempt_number", "attemptNumber", "int"]
|
|
5617
|
+
];
|
|
5397
5618
|
const metadata = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? { ...attributes.metadata } : {};
|
|
5398
5619
|
for (const [dotted, camel, kind] of mapping) {
|
|
5399
5620
|
const raw = attributes[dotted];
|
|
@@ -5445,6 +5666,55 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
|
|
|
5445
5666
|
if (direct === void 0) attributes[camel] = promoted;
|
|
5446
5667
|
if (nested === void 0) metadata[camel] = promoted;
|
|
5447
5668
|
}
|
|
5669
|
+
for (const [dotted, camel, kind] of conflictMapping) {
|
|
5670
|
+
const raw = attributes[dotted];
|
|
5671
|
+
if (raw === void 0 || raw === null) continue;
|
|
5672
|
+
let alternate;
|
|
5673
|
+
if (kind === "int") {
|
|
5674
|
+
const n = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
|
|
5675
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
5676
|
+
warnings.push({
|
|
5677
|
+
code: "otlp_identity_invalid",
|
|
5678
|
+
message: `Ignoring invalid ${dotted} identity conflict value.`,
|
|
5679
|
+
severity: "warning",
|
|
5680
|
+
field: `${pathPrefix}.${dotted}`
|
|
5681
|
+
});
|
|
5682
|
+
continue;
|
|
5683
|
+
}
|
|
5684
|
+
alternate = Math.trunc(n);
|
|
5685
|
+
} else if (typeof raw === "string" && raw.trim() !== "") {
|
|
5686
|
+
alternate = raw.trim();
|
|
5687
|
+
} else {
|
|
5688
|
+
warnings.push({
|
|
5689
|
+
code: "otlp_identity_invalid",
|
|
5690
|
+
message: `Ignoring non-string ${dotted} identity conflict value.`,
|
|
5691
|
+
severity: "warning",
|
|
5692
|
+
field: `${pathPrefix}.${dotted}`
|
|
5693
|
+
});
|
|
5694
|
+
continue;
|
|
5695
|
+
}
|
|
5696
|
+
const preferred = attributes[camel];
|
|
5697
|
+
if (preferred !== void 0 && preferred !== alternate) {
|
|
5698
|
+
metadata[camel] = alternate;
|
|
5699
|
+
warnings.push({
|
|
5700
|
+
code: "otlp_identity_conflict",
|
|
5701
|
+
message: `Conflicting ${camel}: attributes.${camel} vs nested alternate from ${dotted}; retaining both.`,
|
|
5702
|
+
severity: "warning",
|
|
5703
|
+
field: `${pathPrefix}.${dotted}`
|
|
5704
|
+
});
|
|
5705
|
+
} else if (preferred === void 0) {
|
|
5706
|
+
metadata[camel] = alternate;
|
|
5707
|
+
}
|
|
5708
|
+
}
|
|
5709
|
+
const conflictFields = attributes["agent_inspect.identity_conflict.fields"];
|
|
5710
|
+
if (typeof conflictFields === "string" && conflictFields.trim() !== "") {
|
|
5711
|
+
warnings.push({
|
|
5712
|
+
code: "otlp_identity_conflict",
|
|
5713
|
+
message: `Identity representation conflict fields retained after OTLP bounding: ${conflictFields.trim().slice(0, 200)}.`,
|
|
5714
|
+
severity: "warning",
|
|
5715
|
+
field: `${pathPrefix}.agent_inspect.identity_conflict.fields`
|
|
5716
|
+
});
|
|
5717
|
+
}
|
|
5448
5718
|
if (Object.keys(metadata).length > 0) {
|
|
5449
5719
|
attributes.metadata = metadata;
|
|
5450
5720
|
}
|