@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.cjs
CHANGED
|
@@ -2755,22 +2755,192 @@ function runTraceChecks(input, options = {}) {
|
|
|
2755
2755
|
};
|
|
2756
2756
|
}
|
|
2757
2757
|
|
|
2758
|
+
// packages/core/src/checks/canonical-equality.ts
|
|
2759
|
+
var DEFAULT_MAX_DEPTH = 8;
|
|
2760
|
+
var DEFAULT_MAX_BYTES = 16384;
|
|
2761
|
+
function sortKeysDeep(input, depth, maxDepth) {
|
|
2762
|
+
if (depth > maxDepth) {
|
|
2763
|
+
throw new Error("AI_CHECK_CANONICAL_DEPTH_EXCEEDED");
|
|
2764
|
+
}
|
|
2765
|
+
if (input === null || typeof input !== "object") return input;
|
|
2766
|
+
if (Array.isArray(input)) {
|
|
2767
|
+
return input.map((item) => sortKeysDeep(item, depth + 1, maxDepth));
|
|
2768
|
+
}
|
|
2769
|
+
const record = input;
|
|
2770
|
+
const out = {};
|
|
2771
|
+
for (const key of Object.keys(record).sort()) {
|
|
2772
|
+
out[key] = sortKeysDeep(record[key], depth + 1, maxDepth);
|
|
2773
|
+
}
|
|
2774
|
+
return out;
|
|
2775
|
+
}
|
|
2776
|
+
function encodeCanonicalStructured(value, limits) {
|
|
2777
|
+
const maxDepth = DEFAULT_MAX_DEPTH;
|
|
2778
|
+
const maxBytes = DEFAULT_MAX_BYTES;
|
|
2779
|
+
try {
|
|
2780
|
+
const sorted = sortKeysDeep(value, 0, maxDepth);
|
|
2781
|
+
const encoded = JSON.stringify(sorted);
|
|
2782
|
+
if (encoded === void 0) {
|
|
2783
|
+
return {
|
|
2784
|
+
ok: false,
|
|
2785
|
+
reason: "Value is not JSON-serializable for canonical comparison.",
|
|
2786
|
+
code: "AI_CHECK_CANONICAL_UNSERIALIZABLE"
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
if (Buffer.byteLength(encoded, "utf8") > maxBytes) {
|
|
2790
|
+
return {
|
|
2791
|
+
ok: false,
|
|
2792
|
+
reason: "Canonical structured value exceeds bounded size limit.",
|
|
2793
|
+
code: "AI_CHECK_CANONICAL_SIZE_EXCEEDED"
|
|
2794
|
+
};
|
|
2795
|
+
}
|
|
2796
|
+
return { ok: true, value: encoded };
|
|
2797
|
+
} catch (error) {
|
|
2798
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2799
|
+
if (message === "AI_CHECK_CANONICAL_DEPTH_EXCEEDED") {
|
|
2800
|
+
return {
|
|
2801
|
+
ok: false,
|
|
2802
|
+
reason: "Canonical structured value exceeds bounded depth limit.",
|
|
2803
|
+
code: "AI_CHECK_CANONICAL_DEPTH_EXCEEDED"
|
|
2804
|
+
};
|
|
2805
|
+
}
|
|
2806
|
+
return {
|
|
2807
|
+
ok: false,
|
|
2808
|
+
reason: "Canonical structured encoding failed.",
|
|
2809
|
+
code: "AI_CHECK_CANONICAL_UNSERIALIZABLE"
|
|
2810
|
+
};
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
// packages/core/src/persisted/delivery-identity.ts
|
|
2815
|
+
var DELIVERY_CONFLICT_ATTR = "agent_inspect.delivery_conflict";
|
|
2816
|
+
var DELIVERY_EVENT_BASE_ATTR = "agent_inspect.delivery_event_base";
|
|
2817
|
+
var MAX_DELIVERY_BASE_LEN = 500;
|
|
2818
|
+
function stripReaderDeliveryDiscriminator(eventId, attributes) {
|
|
2819
|
+
if (!eventId) return eventId;
|
|
2820
|
+
const rawBase = attributes?.[DELIVERY_EVENT_BASE_ATTR];
|
|
2821
|
+
if (typeof rawBase !== "string" || rawBase.trim() === "") return eventId;
|
|
2822
|
+
const base = rawBase.trim().slice(0, MAX_DELIVERY_BASE_LEN);
|
|
2823
|
+
if (eventId === base) return base;
|
|
2824
|
+
const prefix = `${base}:`;
|
|
2825
|
+
if (!eventId.startsWith(prefix)) return eventId;
|
|
2826
|
+
const suffix = eventId.slice(prefix.length);
|
|
2827
|
+
if (/^\d+$/.test(suffix)) return base;
|
|
2828
|
+
return eventId;
|
|
2829
|
+
}
|
|
2830
|
+
function deliveryEventBaseFromIndexedId(eventId) {
|
|
2831
|
+
if (!/:\d+$/.test(eventId)) return void 0;
|
|
2832
|
+
const base = eventId.replace(/:\d+$/, "");
|
|
2833
|
+
return base.length > 0 ? base.slice(0, MAX_DELIVERY_BASE_LEN) : void 0;
|
|
2834
|
+
}
|
|
2835
|
+
function canonicalDigest(value) {
|
|
2836
|
+
if (value === void 0) return null;
|
|
2837
|
+
const encoded = encodeCanonicalStructured(value);
|
|
2838
|
+
return encoded.ok ? encoded.value : `unencodable:${encoded.code}`;
|
|
2839
|
+
}
|
|
2840
|
+
function capturedContentDigest(attributes) {
|
|
2841
|
+
if (!attributes || typeof attributes !== "object") {
|
|
2842
|
+
return { args: null, result: null };
|
|
2843
|
+
}
|
|
2844
|
+
const nested = attributes.metadata && typeof attributes.metadata === "object" ? attributes.metadata : void 0;
|
|
2845
|
+
const args = attributes.arguments ?? attributes.args ?? attributes.input ?? nested?.arguments ?? nested?.args ?? nested?.input;
|
|
2846
|
+
const result = attributes.result ?? attributes.output ?? attributes.response ?? nested?.result ?? nested?.output ?? nested?.response;
|
|
2847
|
+
return {
|
|
2848
|
+
args: args === void 0 ? null : canonicalDigest(args),
|
|
2849
|
+
result: result === void 0 ? null : canonicalDigest(result)
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
function timeKey(fields) {
|
|
2853
|
+
if (typeof fields.startedAt === "string" && fields.startedAt.trim() !== "") {
|
|
2854
|
+
return fields.startedAt;
|
|
2855
|
+
}
|
|
2856
|
+
if (typeof fields.timestamp === "string" && fields.timestamp.trim() !== "") {
|
|
2857
|
+
return fields.timestamp;
|
|
2858
|
+
}
|
|
2859
|
+
if (typeof fields.timestamp === "number" && Number.isFinite(fields.timestamp)) {
|
|
2860
|
+
return String(fields.timestamp);
|
|
2861
|
+
}
|
|
2862
|
+
return null;
|
|
2863
|
+
}
|
|
2864
|
+
function deliverySemanticFingerprint(fields) {
|
|
2865
|
+
const content = capturedContentDigest(fields.attributes);
|
|
2866
|
+
return JSON.stringify({
|
|
2867
|
+
stableEventId: stripReaderDeliveryDiscriminator(fields.eventId, fields.attributes),
|
|
2868
|
+
runId: fields.runId,
|
|
2869
|
+
kind: fields.kind,
|
|
2870
|
+
name: fields.name,
|
|
2871
|
+
status: fields.status ?? null,
|
|
2872
|
+
parentId: fields.parentId ?? null,
|
|
2873
|
+
sourceType: fields.sourceType ?? null,
|
|
2874
|
+
time: timeKey(fields),
|
|
2875
|
+
operationId: fields.operationId ?? null,
|
|
2876
|
+
attemptId: fields.attemptId ?? null,
|
|
2877
|
+
attemptNumber: fields.attemptNumber ?? null,
|
|
2878
|
+
retryOf: fields.retryOf ?? null,
|
|
2879
|
+
argsDigest: content.args,
|
|
2880
|
+
resultDigest: content.result
|
|
2881
|
+
});
|
|
2882
|
+
}
|
|
2883
|
+
function identityFieldsFromAttributes(attributes) {
|
|
2884
|
+
if (!attributes || typeof attributes !== "object") {
|
|
2885
|
+
return {
|
|
2886
|
+
operationId: null,
|
|
2887
|
+
attemptId: null,
|
|
2888
|
+
attemptNumber: null,
|
|
2889
|
+
retryOf: null
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2892
|
+
const nested = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? attributes.metadata : void 0;
|
|
2893
|
+
const pickString2 = (key) => {
|
|
2894
|
+
const direct = attributes[key];
|
|
2895
|
+
if (typeof direct === "string" && direct.trim() !== "") return direct.trim();
|
|
2896
|
+
const nestedValue = nested?.[key];
|
|
2897
|
+
if (typeof nestedValue === "string" && nestedValue.trim() !== "") {
|
|
2898
|
+
return nestedValue.trim();
|
|
2899
|
+
}
|
|
2900
|
+
return null;
|
|
2901
|
+
};
|
|
2902
|
+
const pickNumber = () => {
|
|
2903
|
+
const direct = attributes.attemptNumber ?? attributes.attempt;
|
|
2904
|
+
if (typeof direct === "number" && Number.isFinite(direct)) return direct;
|
|
2905
|
+
const nestedValue = nested?.attemptNumber ?? nested?.attempt;
|
|
2906
|
+
if (typeof nestedValue === "number" && Number.isFinite(nestedValue)) {
|
|
2907
|
+
return nestedValue;
|
|
2908
|
+
}
|
|
2909
|
+
return null;
|
|
2910
|
+
};
|
|
2911
|
+
return {
|
|
2912
|
+
operationId: pickString2("operationId"),
|
|
2913
|
+
attemptId: pickString2("attemptId"),
|
|
2914
|
+
retryOf: pickString2("retryOf"),
|
|
2915
|
+
attemptNumber: pickNumber()
|
|
2916
|
+
};
|
|
2917
|
+
}
|
|
2918
|
+
function stampDeliveryConflict(event) {
|
|
2919
|
+
return {
|
|
2920
|
+
...event,
|
|
2921
|
+
attributes: {
|
|
2922
|
+
...event.attributes ?? {},
|
|
2923
|
+
[DELIVERY_CONFLICT_ATTR]: true
|
|
2924
|
+
}
|
|
2925
|
+
};
|
|
2926
|
+
}
|
|
2927
|
+
|
|
2758
2928
|
// packages/core/src/checks/contract.ts
|
|
2759
2929
|
new Set(OBSERVED_OUTCOME_METHODS);
|
|
2760
2930
|
|
|
2761
2931
|
// packages/core/src/exporters/helpers.ts
|
|
2762
|
-
function
|
|
2932
|
+
function sortKeysDeep2(input) {
|
|
2763
2933
|
if (input === null || typeof input !== "object") return input;
|
|
2764
|
-
if (Array.isArray(input)) return input.map(
|
|
2934
|
+
if (Array.isArray(input)) return input.map(sortKeysDeep2);
|
|
2765
2935
|
const o = input;
|
|
2766
2936
|
const out = {};
|
|
2767
2937
|
for (const k of Object.keys(o).sort()) {
|
|
2768
|
-
out[k] =
|
|
2938
|
+
out[k] = sortKeysDeep2(o[k]);
|
|
2769
2939
|
}
|
|
2770
2940
|
return out;
|
|
2771
2941
|
}
|
|
2772
2942
|
function stableJson(value, pretty) {
|
|
2773
|
-
const sorted =
|
|
2943
|
+
const sorted = sortKeysDeep2(value);
|
|
2774
2944
|
return JSON.stringify(sorted);
|
|
2775
2945
|
}
|
|
2776
2946
|
|
|
@@ -3648,6 +3818,11 @@ function compactAttributes(entries) {
|
|
|
3648
3818
|
}
|
|
3649
3819
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
3650
3820
|
}
|
|
3821
|
+
function stampDeliveryEventBase(eventId, attributes) {
|
|
3822
|
+
const base = deliveryEventBaseFromIndexedId(eventId);
|
|
3823
|
+
if (!base) return attributes;
|
|
3824
|
+
return { ...attributes ?? {}, [DELIVERY_EVENT_BASE_ATTR]: base };
|
|
3825
|
+
}
|
|
3651
3826
|
function traceEventToPersistedInspectEvent(event, options) {
|
|
3652
3827
|
const eventIndex = options?.eventIndex ?? 0;
|
|
3653
3828
|
const eventId = createPersistedEventId(event, eventIndex);
|
|
@@ -3677,7 +3852,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3677
3852
|
startedAt: tsStart.iso,
|
|
3678
3853
|
confidence: "explicit",
|
|
3679
3854
|
source,
|
|
3680
|
-
attributes
|
|
3855
|
+
attributes: stampDeliveryEventBase(eventId, attributes)
|
|
3681
3856
|
};
|
|
3682
3857
|
}
|
|
3683
3858
|
case "run_completed": {
|
|
@@ -3700,7 +3875,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3700
3875
|
durationMs: event.durationMs,
|
|
3701
3876
|
confidence: "explicit",
|
|
3702
3877
|
source,
|
|
3703
|
-
attributes,
|
|
3878
|
+
attributes: stampDeliveryEventBase(eventId, attributes),
|
|
3704
3879
|
error
|
|
3705
3880
|
};
|
|
3706
3881
|
}
|
|
@@ -3725,7 +3900,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3725
3900
|
startedAt: tsStart.iso,
|
|
3726
3901
|
confidence: "explicit",
|
|
3727
3902
|
source,
|
|
3728
|
-
attributes
|
|
3903
|
+
attributes: stampDeliveryEventBase(eventId, attributes)
|
|
3729
3904
|
};
|
|
3730
3905
|
if (event.parentId !== void 0) {
|
|
3731
3906
|
out.parentId = event.parentId;
|
|
@@ -3756,7 +3931,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3756
3931
|
durationMs: event.durationMs,
|
|
3757
3932
|
confidence: "explicit",
|
|
3758
3933
|
source,
|
|
3759
|
-
attributes,
|
|
3934
|
+
attributes: stampDeliveryEventBase(eventId, attributes),
|
|
3760
3935
|
error
|
|
3761
3936
|
};
|
|
3762
3937
|
}
|
|
@@ -3783,7 +3958,7 @@ function traceEventToPersistedInspectEvent(event, options) {
|
|
|
3783
3958
|
timestamp: tsMain.iso,
|
|
3784
3959
|
confidence: "explicit",
|
|
3785
3960
|
source,
|
|
3786
|
-
attributes
|
|
3961
|
+
attributes: stampDeliveryEventBase(eventId, attributes)
|
|
3787
3962
|
};
|
|
3788
3963
|
if (event.parentId !== void 0) {
|
|
3789
3964
|
out.parentId = event.parentId;
|
|
@@ -3936,7 +4111,47 @@ var TreeBuilder = class {
|
|
|
3936
4111
|
const sorted = [...runEvents].sort((a, b) => a.timestamp - b.timestamp);
|
|
3937
4112
|
const nodes = /* @__PURE__ */ new Map();
|
|
3938
4113
|
for (const e of sorted) {
|
|
3939
|
-
nodes.
|
|
4114
|
+
const existing = nodes.get(e.eventId);
|
|
4115
|
+
if (!existing) {
|
|
4116
|
+
nodes.set(e.eventId, { event: e, children: [], depth: 0 });
|
|
4117
|
+
continue;
|
|
4118
|
+
}
|
|
4119
|
+
const existingAttrs = existing.event.attributes && typeof existing.event.attributes === "object" ? existing.event.attributes : void 0;
|
|
4120
|
+
const nextAttrs = e.attributes && typeof e.attributes === "object" ? e.attributes : void 0;
|
|
4121
|
+
const existingIdentity = identityFieldsFromAttributes(existingAttrs);
|
|
4122
|
+
const nextIdentity = identityFieldsFromAttributes(nextAttrs);
|
|
4123
|
+
const existingFp = deliverySemanticFingerprint({
|
|
4124
|
+
eventId: existing.event.eventId,
|
|
4125
|
+
runId: existing.event.runId,
|
|
4126
|
+
kind: existing.event.kind,
|
|
4127
|
+
name: existing.event.name,
|
|
4128
|
+
status: existing.event.status,
|
|
4129
|
+
parentId: existing.event.parentId,
|
|
4130
|
+
timestamp: existing.event.timestamp,
|
|
4131
|
+
sourceType: existing.event.source?.type,
|
|
4132
|
+
attributes: existingAttrs,
|
|
4133
|
+
...existingIdentity
|
|
4134
|
+
});
|
|
4135
|
+
const nextFp = deliverySemanticFingerprint({
|
|
4136
|
+
eventId: e.eventId,
|
|
4137
|
+
runId: e.runId,
|
|
4138
|
+
kind: e.kind,
|
|
4139
|
+
name: e.name,
|
|
4140
|
+
status: e.status,
|
|
4141
|
+
parentId: e.parentId,
|
|
4142
|
+
timestamp: e.timestamp,
|
|
4143
|
+
sourceType: e.source?.type,
|
|
4144
|
+
attributes: nextAttrs,
|
|
4145
|
+
...nextIdentity
|
|
4146
|
+
});
|
|
4147
|
+
if (existingFp === nextFp) {
|
|
4148
|
+
continue;
|
|
4149
|
+
}
|
|
4150
|
+
nodes.set(e.eventId, {
|
|
4151
|
+
event: stampDeliveryConflict(e),
|
|
4152
|
+
children: [],
|
|
4153
|
+
depth: 0
|
|
4154
|
+
});
|
|
3940
4155
|
}
|
|
3941
4156
|
const { roots, summary } = linkNodesVisibilityFirst(nodes);
|
|
3942
4157
|
const confidenceBreakdown = {
|
|
@@ -5401,6 +5616,12 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
|
|
|
5401
5616
|
["agent_inspect.retry_of", "retryOf", "string"],
|
|
5402
5617
|
["agent_inspect.attempt_number", "attemptNumber", "int"]
|
|
5403
5618
|
];
|
|
5619
|
+
const conflictMapping = [
|
|
5620
|
+
["agent_inspect.identity_conflict.operation_id", "operationId", "string"],
|
|
5621
|
+
["agent_inspect.identity_conflict.attempt_id", "attemptId", "string"],
|
|
5622
|
+
["agent_inspect.identity_conflict.retry_of", "retryOf", "string"],
|
|
5623
|
+
["agent_inspect.identity_conflict.attempt_number", "attemptNumber", "int"]
|
|
5624
|
+
];
|
|
5404
5625
|
const metadata = attributes.metadata && typeof attributes.metadata === "object" && !Array.isArray(attributes.metadata) ? { ...attributes.metadata } : {};
|
|
5405
5626
|
for (const [dotted, camel, kind] of mapping) {
|
|
5406
5627
|
const raw = attributes[dotted];
|
|
@@ -5452,6 +5673,55 @@ function promoteAgentInspectWorkflowIdentity(attributes, pathPrefix) {
|
|
|
5452
5673
|
if (direct === void 0) attributes[camel] = promoted;
|
|
5453
5674
|
if (nested === void 0) metadata[camel] = promoted;
|
|
5454
5675
|
}
|
|
5676
|
+
for (const [dotted, camel, kind] of conflictMapping) {
|
|
5677
|
+
const raw = attributes[dotted];
|
|
5678
|
+
if (raw === void 0 || raw === null) continue;
|
|
5679
|
+
let alternate;
|
|
5680
|
+
if (kind === "int") {
|
|
5681
|
+
const n = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
|
|
5682
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
5683
|
+
warnings.push({
|
|
5684
|
+
code: "otlp_identity_invalid",
|
|
5685
|
+
message: `Ignoring invalid ${dotted} identity conflict value.`,
|
|
5686
|
+
severity: "warning",
|
|
5687
|
+
field: `${pathPrefix}.${dotted}`
|
|
5688
|
+
});
|
|
5689
|
+
continue;
|
|
5690
|
+
}
|
|
5691
|
+
alternate = Math.trunc(n);
|
|
5692
|
+
} else if (typeof raw === "string" && raw.trim() !== "") {
|
|
5693
|
+
alternate = raw.trim();
|
|
5694
|
+
} else {
|
|
5695
|
+
warnings.push({
|
|
5696
|
+
code: "otlp_identity_invalid",
|
|
5697
|
+
message: `Ignoring non-string ${dotted} identity conflict value.`,
|
|
5698
|
+
severity: "warning",
|
|
5699
|
+
field: `${pathPrefix}.${dotted}`
|
|
5700
|
+
});
|
|
5701
|
+
continue;
|
|
5702
|
+
}
|
|
5703
|
+
const preferred = attributes[camel];
|
|
5704
|
+
if (preferred !== void 0 && preferred !== alternate) {
|
|
5705
|
+
metadata[camel] = alternate;
|
|
5706
|
+
warnings.push({
|
|
5707
|
+
code: "otlp_identity_conflict",
|
|
5708
|
+
message: `Conflicting ${camel}: attributes.${camel} vs nested alternate from ${dotted}; retaining both.`,
|
|
5709
|
+
severity: "warning",
|
|
5710
|
+
field: `${pathPrefix}.${dotted}`
|
|
5711
|
+
});
|
|
5712
|
+
} else if (preferred === void 0) {
|
|
5713
|
+
metadata[camel] = alternate;
|
|
5714
|
+
}
|
|
5715
|
+
}
|
|
5716
|
+
const conflictFields = attributes["agent_inspect.identity_conflict.fields"];
|
|
5717
|
+
if (typeof conflictFields === "string" && conflictFields.trim() !== "") {
|
|
5718
|
+
warnings.push({
|
|
5719
|
+
code: "otlp_identity_conflict",
|
|
5720
|
+
message: `Identity representation conflict fields retained after OTLP bounding: ${conflictFields.trim().slice(0, 200)}.`,
|
|
5721
|
+
severity: "warning",
|
|
5722
|
+
field: `${pathPrefix}.agent_inspect.identity_conflict.fields`
|
|
5723
|
+
});
|
|
5724
|
+
}
|
|
5455
5725
|
if (Object.keys(metadata).length > 0) {
|
|
5456
5726
|
attributes.metadata = metadata;
|
|
5457
5727
|
}
|