@tangle-network/traces 0.9.4 → 0.9.6
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/{chunk-BKGWYQR4.js → chunk-NP3ZIUR2.js} +190 -81
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
|
@@ -920,10 +920,12 @@ function classifyReaction(text) {
|
|
|
920
920
|
var CORRECTIVE_REACTIONS = ["correction", "frustration", "jargon", "structure"];
|
|
921
921
|
|
|
922
922
|
// src/adapters/claude.ts
|
|
923
|
+
import { createHash as createHash4 } from "crypto";
|
|
923
924
|
import { readdir as readdir3, stat as stat2 } from "fs/promises";
|
|
924
925
|
import { homedir as homedir2 } from "os";
|
|
925
926
|
import { basename as basename2, join as join2 } from "path";
|
|
926
927
|
var SERVICE2 = "claude-code";
|
|
928
|
+
var EPOCH = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
927
929
|
function asBlocks(content) {
|
|
928
930
|
return Array.isArray(content) ? content : [];
|
|
929
931
|
}
|
|
@@ -943,10 +945,93 @@ function stringifyToolResult(content) {
|
|
|
943
945
|
function createClaudeStream(startStep) {
|
|
944
946
|
return { spans: [], toolSpanByUseId: /* @__PURE__ */ new Map(), step: startStep, sawUserTurn: false };
|
|
945
947
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
948
|
+
var ClaudeEventConflictError = class extends Error {
|
|
949
|
+
sourcePath;
|
|
950
|
+
eventId;
|
|
951
|
+
constructor(sourcePath, eventId) {
|
|
952
|
+
super(`${sourcePath}: Claude transcript event ${JSON.stringify(eventId)} has conflicting payloads`);
|
|
953
|
+
this.name = "ClaudeEventConflictError";
|
|
954
|
+
this.sourcePath = sourcePath;
|
|
955
|
+
this.eventId = eventId;
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
function projectToolResult(toolUseId, isError, output) {
|
|
959
|
+
return {
|
|
960
|
+
toolUseId,
|
|
961
|
+
isError,
|
|
962
|
+
attributes: toolIoAttributes({ output }),
|
|
963
|
+
message: stringifyToolResult(output).slice(0, 500)
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
function projectClaudeEvent(event) {
|
|
967
|
+
const timestamp = event.timestamp ?? EPOCH;
|
|
968
|
+
if (event.type === "assistant" && event.message) {
|
|
969
|
+
const tools = [];
|
|
970
|
+
for (const block of asBlocks(event.message.content)) {
|
|
971
|
+
if (block.type !== "tool_use" || !block.name) continue;
|
|
972
|
+
tools.push({ id: block.id || null, name: block.name, attributes: toolIoAttributes({ input: block.input }) });
|
|
973
|
+
}
|
|
974
|
+
return {
|
|
975
|
+
kind: "assistant",
|
|
976
|
+
timestamp,
|
|
977
|
+
model: event.message.model ?? null,
|
|
978
|
+
inputTokens: event.message.usage?.input_tokens ?? null,
|
|
979
|
+
outputTokens: event.message.usage?.output_tokens ?? null,
|
|
980
|
+
cachedInputTokens: event.message.usage?.cache_read_input_tokens ?? null,
|
|
981
|
+
cacheWriteInputTokens: event.message.usage?.cache_creation_input_tokens ?? null,
|
|
982
|
+
content: textOf2(event.message.content) || null,
|
|
983
|
+
tools
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
if (event.type === "user" && event.message) {
|
|
987
|
+
const results = [];
|
|
988
|
+
for (const block of asBlocks(event.message.content)) {
|
|
989
|
+
if (block.type !== "tool_result" || !block.tool_use_id) continue;
|
|
990
|
+
results.push(projectToolResult(block.tool_use_id, block.is_error === true, block.content));
|
|
991
|
+
}
|
|
992
|
+
const prompt = textOf2(event.message.content);
|
|
993
|
+
return {
|
|
994
|
+
kind: "user",
|
|
995
|
+
timestamp,
|
|
996
|
+
prompt: prompt || null,
|
|
997
|
+
...prompt ? { isSidechain: event.isSidechain === true, userType: event.userType ?? null } : {},
|
|
998
|
+
results
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
if (event.type === "attachment" && event.attachment?.type === "tool_result" && event.attachment.toolUseID) {
|
|
1002
|
+
return {
|
|
1003
|
+
kind: "attachment",
|
|
1004
|
+
timestamp,
|
|
1005
|
+
result: projectToolResult(
|
|
1006
|
+
event.attachment.toolUseID,
|
|
1007
|
+
typeof event.attachment.exitCode === "number" && event.attachment.exitCode !== 0,
|
|
1008
|
+
event.attachment.stderr ?? ""
|
|
1009
|
+
)
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
return { kind: "ignored" };
|
|
1013
|
+
}
|
|
1014
|
+
function fingerprintClaudeEvent(event) {
|
|
1015
|
+
return createHash4("sha256").update(JSON.stringify(event)).digest("hex");
|
|
1016
|
+
}
|
|
1017
|
+
function consumeDistinctClaudeEvent(event, ctx, state, seen, sourcePath) {
|
|
1018
|
+
const projection = projectClaudeEvent(event);
|
|
1019
|
+
if (event.uuid) {
|
|
1020
|
+
const fingerprint = fingerprintClaudeEvent(projection);
|
|
1021
|
+
const previous = seen.get(event.uuid);
|
|
1022
|
+
if (previous !== void 0) {
|
|
1023
|
+
if (previous !== fingerprint) {
|
|
1024
|
+
throw new ClaudeEventConflictError(sourcePath, event.uuid);
|
|
1025
|
+
}
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1028
|
+
seen.set(event.uuid, fingerprint);
|
|
1029
|
+
}
|
|
1030
|
+
consumeClaudeEvent(projection, event.uuid ?? `${ctx.idPrefix}step${state.step}`, ctx, state);
|
|
1031
|
+
return true;
|
|
1032
|
+
}
|
|
1033
|
+
function consumeClaudeEvent(event, uid, ctx, state) {
|
|
1034
|
+
if (event.kind === "assistant") {
|
|
950
1035
|
const llmId = `${ctx.idPrefix}${uid}`;
|
|
951
1036
|
state.spans.push(
|
|
952
1037
|
span({
|
|
@@ -955,47 +1040,45 @@ function consumeClaudeEvent(ev, ctx, state) {
|
|
|
955
1040
|
parentSpanId: ctx.rootParent,
|
|
956
1041
|
name: "llm.turn",
|
|
957
1042
|
kind: "LLM",
|
|
958
|
-
startTime:
|
|
1043
|
+
startTime: event.timestamp,
|
|
959
1044
|
service: SERVICE2,
|
|
960
1045
|
agent: ctx.agent,
|
|
961
|
-
model:
|
|
962
|
-
inputTokens:
|
|
963
|
-
outputTokens:
|
|
964
|
-
cachedInputTokens:
|
|
965
|
-
cacheWriteInputTokens:
|
|
1046
|
+
model: event.model,
|
|
1047
|
+
inputTokens: event.inputTokens,
|
|
1048
|
+
outputTokens: event.outputTokens,
|
|
1049
|
+
cachedInputTokens: event.cachedInputTokens,
|
|
1050
|
+
cacheWriteInputTokens: event.cacheWriteInputTokens,
|
|
966
1051
|
step: state.step,
|
|
967
|
-
content:
|
|
1052
|
+
content: event.content
|
|
968
1053
|
})
|
|
969
1054
|
);
|
|
970
1055
|
state.step += 1;
|
|
971
1056
|
let toolIdx = 0;
|
|
972
|
-
for (const
|
|
973
|
-
if (block.type !== "tool_use" || !block.name) continue;
|
|
1057
|
+
for (const tool of event.tools) {
|
|
974
1058
|
const toolSpan = span({
|
|
975
1059
|
traceId: ctx.traceId,
|
|
976
1060
|
spanId: `${ctx.idPrefix}${uid}:tool:${toolIdx}`,
|
|
977
1061
|
parentSpanId: llmId,
|
|
978
|
-
name: `tool.${
|
|
1062
|
+
name: `tool.${tool.name}`,
|
|
979
1063
|
kind: "TOOL",
|
|
980
|
-
startTime:
|
|
1064
|
+
startTime: event.timestamp,
|
|
981
1065
|
service: SERVICE2,
|
|
982
1066
|
agent: ctx.agent,
|
|
983
|
-
tool:
|
|
1067
|
+
tool: tool.name,
|
|
984
1068
|
step: state.step,
|
|
985
|
-
extra:
|
|
1069
|
+
extra: tool.attributes
|
|
986
1070
|
});
|
|
987
1071
|
state.spans.push(toolSpan);
|
|
988
|
-
if (
|
|
1072
|
+
if (tool.id) state.toolSpanByUseId.set(tool.id, toolSpan);
|
|
989
1073
|
toolIdx += 1;
|
|
990
1074
|
state.step += 1;
|
|
991
1075
|
}
|
|
992
|
-
} else if (
|
|
993
|
-
|
|
994
|
-
if (prompt) {
|
|
1076
|
+
} else if (event.kind === "user") {
|
|
1077
|
+
if (event.prompt) {
|
|
995
1078
|
const actor = claudeActor({
|
|
996
|
-
text: prompt,
|
|
997
|
-
isSidechain:
|
|
998
|
-
userType:
|
|
1079
|
+
text: event.prompt,
|
|
1080
|
+
isSidechain: event.isSidechain,
|
|
1081
|
+
userType: event.userType ?? null,
|
|
999
1082
|
isFirstUserTurn: !state.sawUserTurn
|
|
1000
1083
|
});
|
|
1001
1084
|
state.sawUserTurn = true;
|
|
@@ -1004,41 +1087,49 @@ function consumeClaudeEvent(ev, ctx, state) {
|
|
|
1004
1087
|
traceId: ctx.traceId,
|
|
1005
1088
|
spanId: `${ctx.idPrefix}${uid}:user`,
|
|
1006
1089
|
parentSpanId: ctx.rootParent,
|
|
1007
|
-
startTime:
|
|
1090
|
+
startTime: event.timestamp,
|
|
1008
1091
|
service: SERVICE2,
|
|
1009
1092
|
agent: ctx.agent,
|
|
1010
1093
|
step: state.step,
|
|
1011
|
-
content: prompt,
|
|
1094
|
+
content: event.prompt,
|
|
1012
1095
|
actor
|
|
1013
1096
|
})
|
|
1014
1097
|
);
|
|
1015
1098
|
state.step += 1;
|
|
1016
1099
|
}
|
|
1017
|
-
for (const
|
|
1018
|
-
|
|
1019
|
-
backfillResult(
|
|
1020
|
-
state.toolSpanByUseId.get(block.tool_use_id),
|
|
1021
|
-
ts,
|
|
1022
|
-
block.is_error === true,
|
|
1023
|
-
block.content
|
|
1024
|
-
);
|
|
1100
|
+
for (const result of event.results) {
|
|
1101
|
+
backfillResult(state.toolSpanByUseId.get(result.toolUseId), event.timestamp, result);
|
|
1025
1102
|
}
|
|
1026
|
-
} else if (
|
|
1027
|
-
|
|
1028
|
-
backfillResult(state.toolSpanByUseId.get(ev.attachment.toolUseID), ts, err, ev.attachment.stderr ?? "");
|
|
1103
|
+
} else if (event.kind === "attachment") {
|
|
1104
|
+
backfillResult(state.toolSpanByUseId.get(event.result.toolUseId), event.timestamp, event.result);
|
|
1029
1105
|
}
|
|
1030
1106
|
}
|
|
1031
1107
|
function finishClaudeStream(state) {
|
|
1032
1108
|
return { spans: state.spans, toolSpanByUseId: state.toolSpanByUseId, nextStep: state.step };
|
|
1033
1109
|
}
|
|
1034
|
-
function
|
|
1110
|
+
function setRootTimeBounds(root, spans) {
|
|
1111
|
+
let firstTimestamp;
|
|
1112
|
+
let lastTimestamp;
|
|
1113
|
+
for (const item of spans) {
|
|
1114
|
+
if (item === root) continue;
|
|
1115
|
+
for (const source of [item.start_time, item.end_time]) {
|
|
1116
|
+
if (!source) continue;
|
|
1117
|
+
const value = Date.parse(source);
|
|
1118
|
+
if (!Number.isFinite(value)) continue;
|
|
1119
|
+
if (!firstTimestamp || value < firstTimestamp.value) firstTimestamp = { value, source };
|
|
1120
|
+
if (!lastTimestamp || value > lastTimestamp.value) lastTimestamp = { value, source };
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
if (firstTimestamp) root.start_time = firstTimestamp.source;
|
|
1124
|
+
if (lastTimestamp) root.end_time = lastTimestamp.source;
|
|
1125
|
+
}
|
|
1126
|
+
function backfillResult(s, endTime, result) {
|
|
1035
1127
|
if (!s) return;
|
|
1036
1128
|
s.end_time = endTime;
|
|
1037
|
-
const code = isError ? "ERROR" : "OK";
|
|
1129
|
+
const code = result.isError ? "ERROR" : "OK";
|
|
1038
1130
|
s.status = { code };
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
if (isError && message) s.status.message = message.slice(0, 500);
|
|
1131
|
+
Object.assign(s.attributes, result.attributes);
|
|
1132
|
+
if (result.isError && result.message) s.status.message = result.message;
|
|
1042
1133
|
}
|
|
1043
1134
|
var ClaudeAdapter = class {
|
|
1044
1135
|
harness = "claude-code";
|
|
@@ -1096,17 +1187,10 @@ var ClaudeAdapter = class {
|
|
|
1096
1187
|
};
|
|
1097
1188
|
const state = createClaudeStream(ctx.startStep);
|
|
1098
1189
|
let discoveredTraceId;
|
|
1099
|
-
|
|
1100
|
-
let lastTimestamp;
|
|
1101
|
-
let sawEvent = false;
|
|
1190
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1102
1191
|
for await (const event of readJsonl(ref.path, sessionJsonlOptions(ref, options))) {
|
|
1103
|
-
if (!sawEvent) {
|
|
1104
|
-
firstTimestamp = event.timestamp;
|
|
1105
|
-
sawEvent = true;
|
|
1106
|
-
}
|
|
1107
|
-
lastTimestamp = event.timestamp;
|
|
1108
1192
|
if (!discoveredTraceId && event.sessionId) discoveredTraceId = event.sessionId;
|
|
1109
|
-
|
|
1193
|
+
if (!consumeDistinctClaudeEvent(event, ctx, state, seen, ref.path)) continue;
|
|
1110
1194
|
}
|
|
1111
1195
|
const main = finishClaudeStream(state);
|
|
1112
1196
|
const traceId = discoveredTraceId ?? sourceTraceId;
|
|
@@ -1115,21 +1199,20 @@ var ClaudeAdapter = class {
|
|
|
1115
1199
|
item.trace_id = traceId;
|
|
1116
1200
|
if (item.parent_span_id === sourceRootId) item.parent_span_id = rootId;
|
|
1117
1201
|
}
|
|
1118
|
-
const
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
})
|
|
1130
|
-
];
|
|
1202
|
+
const root = span({
|
|
1203
|
+
traceId,
|
|
1204
|
+
spanId: rootId,
|
|
1205
|
+
parentSpanId: null,
|
|
1206
|
+
name: "session",
|
|
1207
|
+
kind: "AGENT",
|
|
1208
|
+
startTime: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
1209
|
+
service: SERVICE2,
|
|
1210
|
+
agent: SERVICE2
|
|
1211
|
+
});
|
|
1212
|
+
const spans = [root];
|
|
1131
1213
|
appendAll(spans, main.spans);
|
|
1132
1214
|
await this.foldSubagents(ref, traceId, main, spans, options);
|
|
1215
|
+
setRootTimeBounds(root, spans);
|
|
1133
1216
|
return spans;
|
|
1134
1217
|
}
|
|
1135
1218
|
/** Parse `<session>/subagents/agent-*.jsonl`, parenting each under its Agent call. */
|
|
@@ -1162,11 +1245,12 @@ var ClaudeAdapter = class {
|
|
|
1162
1245
|
rootParent: parent
|
|
1163
1246
|
};
|
|
1164
1247
|
const state = createClaudeStream(ctx.startStep);
|
|
1248
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1165
1249
|
for await (const event of readJsonl(
|
|
1166
1250
|
join2(subDir, file),
|
|
1167
1251
|
sessionJsonlOptions(ref, options)
|
|
1168
1252
|
)) {
|
|
1169
|
-
|
|
1253
|
+
consumeDistinctClaudeEvent(event, ctx, state, seen, join2(subDir, file));
|
|
1170
1254
|
}
|
|
1171
1255
|
const parsed = finishClaudeStream(state);
|
|
1172
1256
|
appendAll(out, parsed.spans);
|
|
@@ -3483,7 +3567,7 @@ async function applyRedactor(spans, redactor) {
|
|
|
3483
3567
|
}
|
|
3484
3568
|
|
|
3485
3569
|
// src/file-export.ts
|
|
3486
|
-
import { createHash as
|
|
3570
|
+
import { createHash as createHash5 } from "crypto";
|
|
3487
3571
|
import { mkdtemp as mkdtemp2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
3488
3572
|
import { tmpdir as tmpdir2 } from "os";
|
|
3489
3573
|
import { join as join13 } from "path";
|
|
@@ -3521,7 +3605,7 @@ function stableJson(value) {
|
|
|
3521
3605
|
});
|
|
3522
3606
|
}
|
|
3523
3607
|
function hashId(value, chars = 16) {
|
|
3524
|
-
return
|
|
3608
|
+
return createHash5("sha256").update(stableJson(value)).digest("hex").slice(0, chars);
|
|
3525
3609
|
}
|
|
3526
3610
|
function isoTime(value) {
|
|
3527
3611
|
if (typeof value === "string") {
|
|
@@ -4455,9 +4539,9 @@ function skillDocumentNames(s) {
|
|
|
4455
4539
|
}
|
|
4456
4540
|
return [...names];
|
|
4457
4541
|
}
|
|
4458
|
-
function telemetryStatus(
|
|
4459
|
-
if (
|
|
4460
|
-
if (
|
|
4542
|
+
function telemetryStatus(measured2, unsupported, unknown) {
|
|
4543
|
+
if (measured2 > 0 && unsupported === 0 && unknown === 0) return "measured";
|
|
4544
|
+
if (measured2 > 0) return "partial";
|
|
4461
4545
|
if (unsupported > 0 && unknown === 0) return "unsupported";
|
|
4462
4546
|
return "unknown";
|
|
4463
4547
|
}
|
|
@@ -4684,6 +4768,12 @@ import {
|
|
|
4684
4768
|
} from "@tangle-network/agent-eval/analyst";
|
|
4685
4769
|
import { OtlpFileTraceStore } from "@tangle-network/agent-eval/traces";
|
|
4686
4770
|
var GENERATED_TRACE_FILE_CEILING = 512 * 1024 * 1024;
|
|
4771
|
+
function mergeCostProvenance(first, second, totalCostUsd) {
|
|
4772
|
+
if (!first || !second || first.kind === "uncaptured" || second.kind === "uncaptured") {
|
|
4773
|
+
return { kind: "uncaptured", usd: null };
|
|
4774
|
+
}
|
|
4775
|
+
return first.kind === "estimated" || second.kind === "estimated" ? { kind: "estimated", usd: totalCostUsd } : { kind: "observed", usd: totalCostUsd };
|
|
4776
|
+
}
|
|
4687
4777
|
async function analyzeSpans(spans, opts = {}) {
|
|
4688
4778
|
if (spans.length === 0) throw new Error("analyzeSpans: no spans to analyze");
|
|
4689
4779
|
const otlpPath = await writeOtlpFile(spans, opts.otlpOutPath);
|
|
@@ -4716,7 +4806,13 @@ async function analyzeSpans(spans, opts = {}) {
|
|
|
4716
4806
|
});
|
|
4717
4807
|
result.findings.push(...agResult.findings);
|
|
4718
4808
|
result.per_analyst.push(...agResult.per_analyst);
|
|
4719
|
-
result.total_cost_usd
|
|
4809
|
+
const totalCostUsd = result.total_cost_usd + agResult.total_cost_usd;
|
|
4810
|
+
result.total_cost_provenance = mergeCostProvenance(
|
|
4811
|
+
result.total_cost_provenance,
|
|
4812
|
+
agResult.total_cost_provenance,
|
|
4813
|
+
totalCostUsd
|
|
4814
|
+
);
|
|
4815
|
+
result.total_cost_usd = totalCostUsd;
|
|
4720
4816
|
}
|
|
4721
4817
|
return { otlpPath, execution, result };
|
|
4722
4818
|
}
|
|
@@ -4842,9 +4938,12 @@ function decimal(value, digits = 1) {
|
|
|
4842
4938
|
maximumFractionDigits: digits
|
|
4843
4939
|
});
|
|
4844
4940
|
}
|
|
4941
|
+
function measured(value, render) {
|
|
4942
|
+
return value === null ? "not captured" : render(value);
|
|
4943
|
+
}
|
|
4845
4944
|
function distributionRow(label, distribution, unit = "") {
|
|
4846
4945
|
if (distribution.n === 0) return `| ${label} | 0 | not captured | not captured | not captured | not captured | not captured |`;
|
|
4847
|
-
const value = (number) => `${decimal(
|
|
4946
|
+
const value = (number) => measured(number, (captured) => `${decimal(captured)}${unit}`);
|
|
4848
4947
|
return `| ${label} | ${count(distribution.n)} | ${value(distribution.min)} | ${value(distribution.mean)} | ${value(distribution.p50)} | ${value(distribution.p95)} | ${value(distribution.max)} |`;
|
|
4849
4948
|
}
|
|
4850
4949
|
function tokenRows(usage) {
|
|
@@ -4856,14 +4955,23 @@ function tokenRows(usage) {
|
|
|
4856
4955
|
["Cache write", usage.totals.cacheWrite, usage.cacheWrite]
|
|
4857
4956
|
];
|
|
4858
4957
|
return rows.map(
|
|
4859
|
-
([label, total, values]) => `| ${label} | ${count(total)} | ${count(values.n)} | ${
|
|
4958
|
+
([label, total, values]) => `| ${label} | ${count(total)} | ${count(values.n)} | ${measured(values.mean, decimal)} | ${measured(values.p50, decimal)} | ${measured(values.p95, decimal)} | ${measured(values.max, count)} |`
|
|
4860
4959
|
);
|
|
4861
4960
|
}
|
|
4961
|
+
function analysisCost(result) {
|
|
4962
|
+
const cost = `$${result.total_cost_usd.toFixed(4)}`;
|
|
4963
|
+
if (result.total_cost_provenance?.kind === "observed") return `Analysis cost: ${cost} observed.`;
|
|
4964
|
+
if (result.total_cost_provenance?.kind === "estimated") return `Analysis cost: ${cost} estimated.`;
|
|
4965
|
+
return `Known analysis cost: ${cost}; additional cost was not captured.`;
|
|
4966
|
+
}
|
|
4862
4967
|
function renderExecution(report) {
|
|
4863
4968
|
const execution = report.execution;
|
|
4864
4969
|
const lines = ["## execution facts", ""];
|
|
4865
4970
|
lines.push(
|
|
4866
|
-
`- **Sessions:** ${count(execution.durationMs.n)} | **Model-call runs:** ${count(execution.modelCalls.runs)} | **Model-call events:** ${count(execution.modelCalls.events)} | **Sessions with
|
|
4971
|
+
`- **Sessions:** ${count(execution.durationMs.n)} | **Model-call runs:** ${count(execution.modelCalls.runs)} | **Model-call events:** ${count(execution.modelCalls.events)} | **Sessions with execution errors:** ${count(execution.executionErrors.runs)}/${count(execution.executionErrors.reportingRuns)} (${measured(execution.executionErrors.fraction, (fraction) => `${decimal(fraction * 100, 2)}%`)})`
|
|
4972
|
+
);
|
|
4973
|
+
lines.push(
|
|
4974
|
+
`- **Terminal outcomes:** ${count(execution.terminalOutcomes.succeeded)} succeeded | ${count(execution.terminalOutcomes.failed)} failed | ${count(execution.terminalOutcomes.cancelled)} cancelled | ${count(execution.terminalOutcomes.incomplete)} incomplete | ${count(execution.terminalOutcomes.unknown)} unknown`
|
|
4867
4975
|
);
|
|
4868
4976
|
lines.push("- **Task quality:** not measured; these traces do not include comparable task outcome labels.");
|
|
4869
4977
|
lines.push("");
|
|
@@ -4936,7 +5044,7 @@ function renderReport(result, meta) {
|
|
|
4936
5044
|
lines.push("");
|
|
4937
5045
|
const sessionSummary = meta.unassignedTraceCount ? `${meta.sessionCount} identified session(s) + ${meta.unassignedTraceCount} ${plural(meta.unassignedTraceCount, "trace")} without a single stable session identity` : `${meta.sessionCount} session(s)`;
|
|
4938
5046
|
lines.push(
|
|
4939
|
-
`${sessionSummary}, ${meta.spanCount} spans \u2192 **${findingSummary}** across ${result.per_analyst.length} analyst(s).
|
|
5047
|
+
`${sessionSummary}, ${meta.spanCount} spans \u2192 **${findingSummary}** across ${result.per_analyst.length} analyst(s). ${analysisCost(result)}`
|
|
4940
5048
|
);
|
|
4941
5049
|
lines.push("");
|
|
4942
5050
|
if (meta.unassignedTraceCount) {
|
|
@@ -5736,7 +5844,7 @@ async function saveReport(path, report) {
|
|
|
5736
5844
|
}
|
|
5737
5845
|
|
|
5738
5846
|
// src/live.ts
|
|
5739
|
-
import { createHash as
|
|
5847
|
+
import { createHash as createHash6 } from "crypto";
|
|
5740
5848
|
var VERIFY_RE = /\b(test|tests|vitest|jest|pytest|go test|cargo test|tsc|typecheck|lint|biome|eslint|build|check:invariants|preflight)\b/i;
|
|
5741
5849
|
var CHANGE_RE = /\b(apply_patch|edit|write|create|delete|rename|replace|update|git apply|sed -i|perl -pi|tee\s|cat\s+>)/i;
|
|
5742
5850
|
var CLAIM_DONE_RE = /\b(done|fixed|complete|completed|implemented|merged|verified|all green|tests pass|ready|works now)\b/i;
|
|
@@ -5756,7 +5864,7 @@ var sleep = (ms, signal) => new Promise((resolve2) => {
|
|
|
5756
5864
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5757
5865
|
});
|
|
5758
5866
|
function hash(parts) {
|
|
5759
|
-
return
|
|
5867
|
+
return createHash6("sha256").update(parts.join("\0")).digest("hex").slice(0, 16);
|
|
5760
5868
|
}
|
|
5761
5869
|
function asString(value) {
|
|
5762
5870
|
if (typeof value === "string" && value.trim()) return value;
|
|
@@ -6516,7 +6624,7 @@ async function sessionMeta(item) {
|
|
|
6516
6624
|
if (branch) meta[ATTR.GIT_BRANCH] = branch;
|
|
6517
6625
|
return meta;
|
|
6518
6626
|
}
|
|
6519
|
-
var msToNano = (
|
|
6627
|
+
var msToNano = (epochMs) => (BigInt(epochMs) * 1000000n).toString();
|
|
6520
6628
|
function toTraceSpanEvents(spans, rootMeta) {
|
|
6521
6629
|
return spans.map((s) => {
|
|
6522
6630
|
const attributes = {};
|
|
@@ -6527,14 +6635,15 @@ function toTraceSpanEvents(spans, rootMeta) {
|
|
|
6527
6635
|
attributes[ATTR.SESSION_ID] = s.trace_id;
|
|
6528
6636
|
attributes[ATTR.INGEST_SOURCE] = INGEST_SOURCE_CLI;
|
|
6529
6637
|
if (s.parent_span_id === null) Object.assign(attributes, rootMeta);
|
|
6530
|
-
const
|
|
6638
|
+
const startMs = parseIsoToEpochMs(s.start_time);
|
|
6639
|
+
const endMs = Math.max(startMs, parseIsoToEpochMs(s.end_time));
|
|
6531
6640
|
return {
|
|
6532
6641
|
traceId: s.trace_id,
|
|
6533
6642
|
spanId: s.span_id,
|
|
6534
6643
|
...s.parent_span_id ? { parentSpanId: s.parent_span_id } : {},
|
|
6535
6644
|
name: s.name,
|
|
6536
|
-
startTimeUnixNano:
|
|
6537
|
-
endTimeUnixNano:
|
|
6645
|
+
startTimeUnixNano: msToNano(startMs),
|
|
6646
|
+
endTimeUnixNano: msToNano(endMs),
|
|
6538
6647
|
attributes,
|
|
6539
6648
|
...s.status.code === "UNSET" ? {} : { status: { code: s.status.code, ...s.status.message ? { message: s.status.message } : {} } }
|
|
6540
6649
|
};
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/traces",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "Point it at your coding-agent session traces (Claude Code, Codex, OpenCode, Gemini, Pi, …) and get failure-mode + efficiency findings. CLI + SDK over the @tangle-network/agent-eval analyst suite — observe live sessions, run your own analysts, redact, and upload to the Tangle Intelligence Platform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@ax-llm/ax": "^23.0.1",
|
|
48
|
-
"@tangle-network/agent-eval": "^0.
|
|
48
|
+
"@tangle-network/agent-eval": "^0.133.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node": "^22.0.0",
|