agent-inspect 4.0.0 → 4.1.0
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/CHANGELOG.md +11 -0
- package/docs/CLI.md +20 -0
- package/package.json +2 -2
- package/packages/cli/dist/chunk-MT5G7JFO.mjs +3234 -0
- package/packages/cli/dist/chunk-MT5G7JFO.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +2406 -683
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +384 -3414
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/src-DUGEOAZ7.mjs +1157 -0
- package/packages/cli/dist/src-DUGEOAZ7.mjs.map +1 -0
|
@@ -1,3207 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { resolveTraceDir, TraceDirectory, parseDuration, extractMetadata, filterTraces, truncateName, getTraceFilePath, buildRunSummary, formatDuration, formatTimestamp, isAgentInspectTrace, loadTraceMetadataList, loadSessionRunRecords, filterMetasBySessionScope, aggregateSessionCheckResults, buildRunTimeline, renderTimeline, buildTraceStats, renderTraceStats, parseDurationFilter, searchTraces, buildRunWhatSummary, renderRunWhat, buildLocalExplanation, persistedInspectEventsToTraceEvents, renderStepLine, renderErrorLine, getIndent, Redactor, validateEvent, isPersistedInspectEvent, buildSessionIndex, nanoid, resolveRedactionProfile, applyProfileMetadataCaps, extractCorrelationMetadata, truncateStringForProfile, parseTraceJsonl } from './chunk-MT5G7JFO.mjs';
|
|
3
|
+
import { realpathSync, constants as constants$1 } from 'fs';
|
|
4
|
+
import path10 from 'path';
|
|
4
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
6
|
import { Command, Option } from 'commander';
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import os from 'os';
|
|
10
|
-
import process3, { stdin, stdout } from 'process';
|
|
11
|
-
import tty from 'tty';
|
|
12
|
-
import { createInterface } from 'readline';
|
|
7
|
+
import { unlink, stat, mkdir, writeFile, appendFile, rm, access, readFile, open, readdir, constants } from 'fs/promises';
|
|
8
|
+
import process2, { stdin, stdout } from 'process';
|
|
9
|
+
import crypto, { createHash } from 'crypto';
|
|
13
10
|
import { createServer } from 'http';
|
|
14
11
|
import { createRequire } from 'module';
|
|
15
12
|
|
|
16
13
|
// package.json
|
|
17
|
-
var version = "4.
|
|
18
|
-
|
|
19
|
-
// packages/core/src/correlation-metadata.ts
|
|
20
|
-
var TRACE_CORRELATION_KEYS = [
|
|
21
|
-
"correlationId",
|
|
22
|
-
"requestId",
|
|
23
|
-
"decisionId",
|
|
24
|
-
"groupId"
|
|
25
|
-
];
|
|
26
|
-
function isNonEmptyString(value) {
|
|
27
|
-
return typeof value === "string" && value.length > 0;
|
|
28
|
-
}
|
|
29
|
-
function extractCorrelationMetadata(record) {
|
|
30
|
-
if (!record) {
|
|
31
|
-
return void 0;
|
|
32
|
-
}
|
|
33
|
-
const out = {};
|
|
34
|
-
let found = false;
|
|
35
|
-
for (const key of TRACE_CORRELATION_KEYS) {
|
|
36
|
-
const value = record[key];
|
|
37
|
-
if (isNonEmptyString(value)) {
|
|
38
|
-
out[key] = value;
|
|
39
|
-
found = true;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return found ? out : void 0;
|
|
43
|
-
}
|
|
44
|
-
var DEFAULT_REDACT_KEYS = [
|
|
45
|
-
"authorization",
|
|
46
|
-
"cookie",
|
|
47
|
-
"token",
|
|
48
|
-
"apiKey",
|
|
49
|
-
"password",
|
|
50
|
-
"secret",
|
|
51
|
-
"email"
|
|
52
|
-
];
|
|
53
|
-
function isRecord(v) {
|
|
54
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
55
|
-
}
|
|
56
|
-
function toKey(s) {
|
|
57
|
-
return s.toLowerCase();
|
|
58
|
-
}
|
|
59
|
-
function stableHash(value) {
|
|
60
|
-
const h = crypto.createHash("sha256").update(value, "utf8").digest("hex");
|
|
61
|
-
return h.slice(0, 8);
|
|
62
|
-
}
|
|
63
|
-
function compileRules(rules, extraKeys) {
|
|
64
|
-
const out = /* @__PURE__ */ new Map();
|
|
65
|
-
const set = (r) => {
|
|
66
|
-
const k = toKey(r.key);
|
|
67
|
-
out.set(k, { ...r, key: k });
|
|
68
|
-
};
|
|
69
|
-
for (const k of DEFAULT_REDACT_KEYS) {
|
|
70
|
-
set({ key: k, strategy: "full" });
|
|
71
|
-
}
|
|
72
|
-
for (const k of extraKeys ?? []) {
|
|
73
|
-
if (typeof k === "string" && k.length > 0) {
|
|
74
|
-
set({ key: k, strategy: "full" });
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
for (const r of rules ?? []) {
|
|
78
|
-
if (typeof r === "string") {
|
|
79
|
-
set({ key: r, strategy: "full" });
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
const key = r.key;
|
|
83
|
-
if (r.strategy === "full") set({ key, strategy: "full" });
|
|
84
|
-
if (r.strategy === "hash") set({ key, strategy: "hash" });
|
|
85
|
-
if (r.strategy === "prefix") {
|
|
86
|
-
set({ key, strategy: "prefix", keep: typeof r.keep === "number" ? r.keep : 8 });
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return [...out.values()];
|
|
90
|
-
}
|
|
91
|
-
var Redactor = class {
|
|
92
|
-
#rules;
|
|
93
|
-
constructor(options) {
|
|
94
|
-
this.#rules = compileRules(options?.rules, options?.extraKeys);
|
|
95
|
-
}
|
|
96
|
-
redactValue(key, value) {
|
|
97
|
-
const k = toKey(key);
|
|
98
|
-
const rule = this.#rules.find((r) => r.key === k);
|
|
99
|
-
if (!rule) {
|
|
100
|
-
return this.#redactNested(value);
|
|
101
|
-
}
|
|
102
|
-
if (rule.strategy === "full") return "[REDACTED]";
|
|
103
|
-
const asString = typeof value === "string" ? value : typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" ? String(value) : void 0;
|
|
104
|
-
if (rule.strategy === "prefix") {
|
|
105
|
-
if (asString === void 0) return "[REDACTED]";
|
|
106
|
-
const keep = Math.max(0, Math.floor(rule.keep));
|
|
107
|
-
return asString.length <= keep ? `${asString}\u2026` : `${asString.slice(0, keep)}\u2026`;
|
|
108
|
-
}
|
|
109
|
-
if (rule.strategy === "hash") {
|
|
110
|
-
if (asString === void 0) return "[HASH:unknown]";
|
|
111
|
-
return `[HASH:${stableHash(asString)}]`;
|
|
112
|
-
}
|
|
113
|
-
return this.#redactNested(value);
|
|
114
|
-
}
|
|
115
|
-
redactRecord(record) {
|
|
116
|
-
const out = {};
|
|
117
|
-
for (const [k, v] of Object.entries(record)) {
|
|
118
|
-
out[k] = this.redactValue(k, v);
|
|
119
|
-
}
|
|
120
|
-
return out;
|
|
121
|
-
}
|
|
122
|
-
#redactNested(value) {
|
|
123
|
-
if (Array.isArray(value)) {
|
|
124
|
-
return value.map((v) => this.#redactNested(v));
|
|
125
|
-
}
|
|
126
|
-
if (isRecord(value)) {
|
|
127
|
-
const out = {};
|
|
128
|
-
for (const [k, v] of Object.entries(value)) {
|
|
129
|
-
out[k] = this.redactValue(k, v);
|
|
130
|
-
}
|
|
131
|
-
return out;
|
|
132
|
-
}
|
|
133
|
-
return value;
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
// packages/core/src/redaction-profiles.ts
|
|
138
|
-
var SHARE_PROFILE_EXTRA_KEYS = [
|
|
139
|
-
"userEmail",
|
|
140
|
-
"customerEmail",
|
|
141
|
-
"phone",
|
|
142
|
-
"phoneNumber",
|
|
143
|
-
"address",
|
|
144
|
-
"ip",
|
|
145
|
-
"ipAddress",
|
|
146
|
-
"sessionId",
|
|
147
|
-
"requestId",
|
|
148
|
-
"correlationId",
|
|
149
|
-
"decisionId",
|
|
150
|
-
"groupId",
|
|
151
|
-
"customerId",
|
|
152
|
-
"userId",
|
|
153
|
-
"accountId",
|
|
154
|
-
"tenantId",
|
|
155
|
-
"orgId",
|
|
156
|
-
"organizationId",
|
|
157
|
-
"traceId",
|
|
158
|
-
"spanId",
|
|
159
|
-
"parentSpanId"
|
|
160
|
-
];
|
|
161
|
-
var STRICT_PROFILE_EXTRA_KEYS = [
|
|
162
|
-
"prompt",
|
|
163
|
-
"completion",
|
|
164
|
-
"input",
|
|
165
|
-
"output",
|
|
166
|
-
"inputPreview",
|
|
167
|
-
"outputPreview",
|
|
168
|
-
"message",
|
|
169
|
-
"messages",
|
|
170
|
-
"transcript",
|
|
171
|
-
"context",
|
|
172
|
-
"document",
|
|
173
|
-
"documents",
|
|
174
|
-
"chunk",
|
|
175
|
-
"chunks",
|
|
176
|
-
"retrieval",
|
|
177
|
-
"query"
|
|
178
|
-
];
|
|
179
|
-
function resolveRedactionProfile(profile = "local") {
|
|
180
|
-
switch (profile) {
|
|
181
|
-
case "local":
|
|
182
|
-
return { profile: "local", extraKeys: [] };
|
|
183
|
-
case "share":
|
|
184
|
-
return {
|
|
185
|
-
profile: "share",
|
|
186
|
-
extraKeys: SHARE_PROFILE_EXTRA_KEYS,
|
|
187
|
-
maxMetadataValueLengthCap: 500,
|
|
188
|
-
maxPreviewLengthCap: 200
|
|
189
|
-
};
|
|
190
|
-
case "strict":
|
|
191
|
-
return {
|
|
192
|
-
profile: "strict",
|
|
193
|
-
extraKeys: [...SHARE_PROFILE_EXTRA_KEYS, ...STRICT_PROFILE_EXTRA_KEYS],
|
|
194
|
-
maxMetadataValueLengthCap: 200,
|
|
195
|
-
maxPreviewLengthCap: 80
|
|
196
|
-
};
|
|
197
|
-
default:
|
|
198
|
-
return { profile: "local", extraKeys: [] };
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
function isPreviewKey(key) {
|
|
202
|
-
return key.toLowerCase().includes("preview");
|
|
203
|
-
}
|
|
204
|
-
function applyProfileMetadataCaps(maxMetadataValueLength, maxPreviewLength, resolved) {
|
|
205
|
-
let meta = maxMetadataValueLength;
|
|
206
|
-
let preview = maxPreviewLength;
|
|
207
|
-
if (resolved.maxMetadataValueLengthCap !== void 0) {
|
|
208
|
-
meta = Math.min(meta, resolved.maxMetadataValueLengthCap);
|
|
209
|
-
}
|
|
210
|
-
if (resolved.maxPreviewLengthCap !== void 0) {
|
|
211
|
-
preview = Math.min(preview, resolved.maxPreviewLengthCap);
|
|
212
|
-
}
|
|
213
|
-
return { maxMetadataValueLength: meta, maxPreviewLength: preview };
|
|
214
|
-
}
|
|
215
|
-
function truncateStringForProfile(value, key, maxMetadataValueLength, maxPreviewLength) {
|
|
216
|
-
const max = isPreviewKey(key) ? maxPreviewLength : maxMetadataValueLength;
|
|
217
|
-
if (max <= 0) return "\u2026";
|
|
218
|
-
if (value.length <= max) return value;
|
|
219
|
-
return `${value.slice(0, max)}\u2026`;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// packages/core/src/types.ts
|
|
223
|
-
var STEP_TYPES = [
|
|
224
|
-
"run",
|
|
225
|
-
"llm",
|
|
226
|
-
"tool",
|
|
227
|
-
"decision",
|
|
228
|
-
"logic",
|
|
229
|
-
"state",
|
|
230
|
-
"custom"
|
|
231
|
-
];
|
|
232
|
-
function isRecord2(value) {
|
|
233
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
234
|
-
}
|
|
235
|
-
function isStepType(value) {
|
|
236
|
-
return typeof value === "string" && STEP_TYPES.includes(value);
|
|
237
|
-
}
|
|
238
|
-
function isTraceEvent(value) {
|
|
239
|
-
if (!isRecord2(value)) return false;
|
|
240
|
-
if (value.schemaVersion !== "0.1") return false;
|
|
241
|
-
if (typeof value.timestamp !== "number") return false;
|
|
242
|
-
if (typeof value.event !== "string") return false;
|
|
243
|
-
switch (value.event) {
|
|
244
|
-
case "run_started": {
|
|
245
|
-
return typeof value.runId === "string" && typeof value.name === "string" && typeof value.startTime === "number";
|
|
246
|
-
}
|
|
247
|
-
case "run_completed": {
|
|
248
|
-
return typeof value.runId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
|
|
249
|
-
}
|
|
250
|
-
case "step_started": {
|
|
251
|
-
return typeof value.runId === "string" && typeof value.stepId === "string" && typeof value.name === "string" && isStepType(value.type) && typeof value.startTime === "number";
|
|
252
|
-
}
|
|
253
|
-
case "step_completed": {
|
|
254
|
-
return typeof value.runId === "string" && typeof value.stepId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
|
|
255
|
-
}
|
|
256
|
-
default:
|
|
257
|
-
return false;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// packages/core/src/types/persisted-inspect-event.ts
|
|
262
|
-
var INSPECT_KINDS = [
|
|
263
|
-
"RUN",
|
|
264
|
-
"AGENT",
|
|
265
|
-
"LLM",
|
|
266
|
-
"TOOL",
|
|
267
|
-
"CHAIN",
|
|
268
|
-
"RETRIEVER",
|
|
269
|
-
"DECISION",
|
|
270
|
-
"RESULT",
|
|
271
|
-
"ERROR",
|
|
272
|
-
"LOGIC",
|
|
273
|
-
"LOG"
|
|
274
|
-
];
|
|
275
|
-
var ATTRIBUTION_CONFIDENCES = [
|
|
276
|
-
"explicit",
|
|
277
|
-
"correlated",
|
|
278
|
-
"heuristic",
|
|
279
|
-
"unknown"
|
|
280
|
-
];
|
|
281
|
-
var PERSISTED_EVENT_SOURCE_TYPES = [
|
|
282
|
-
"manual",
|
|
283
|
-
"json-log",
|
|
284
|
-
"log4js",
|
|
285
|
-
"adapter",
|
|
286
|
-
"ai-sdk",
|
|
287
|
-
"otel"
|
|
288
|
-
];
|
|
289
|
-
var PERSISTED_EVENT_STATUSES = [
|
|
290
|
-
"running",
|
|
291
|
-
"ok",
|
|
292
|
-
"error",
|
|
293
|
-
"unknown"
|
|
294
|
-
];
|
|
295
|
-
function isRecord3(value) {
|
|
296
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
297
|
-
}
|
|
298
|
-
function isString(value) {
|
|
299
|
-
return typeof value === "string";
|
|
300
|
-
}
|
|
301
|
-
function isNonEmptyString2(value) {
|
|
302
|
-
return typeof value === "string" && value.length > 0;
|
|
303
|
-
}
|
|
304
|
-
function isOptionalString(value) {
|
|
305
|
-
return value === void 0 || isString(value);
|
|
306
|
-
}
|
|
307
|
-
function isNonNegativeNumber(value) {
|
|
308
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
309
|
-
}
|
|
310
|
-
function isOptionalNonNegativeNumber(value) {
|
|
311
|
-
return value === void 0 || isNonNegativeNumber(value);
|
|
312
|
-
}
|
|
313
|
-
function isInspectKind(value) {
|
|
314
|
-
return typeof value === "string" && INSPECT_KINDS.includes(value);
|
|
315
|
-
}
|
|
316
|
-
function isAttributionConfidence(value) {
|
|
317
|
-
return typeof value === "string" && ATTRIBUTION_CONFIDENCES.includes(value);
|
|
318
|
-
}
|
|
319
|
-
function isPersistedEventSourceType(value) {
|
|
320
|
-
return typeof value === "string" && PERSISTED_EVENT_SOURCE_TYPES.includes(value);
|
|
321
|
-
}
|
|
322
|
-
function isPersistedEventStatus(value) {
|
|
323
|
-
return typeof value === "string" && PERSISTED_EVENT_STATUSES.includes(value);
|
|
324
|
-
}
|
|
325
|
-
function isPersistedEventSource(value) {
|
|
326
|
-
if (!isRecord3(value)) return false;
|
|
327
|
-
if (!isPersistedEventSourceType(value.type)) return false;
|
|
328
|
-
if (!isOptionalString(value.name)) return false;
|
|
329
|
-
if (!isOptionalString(value.version)) return false;
|
|
330
|
-
return true;
|
|
331
|
-
}
|
|
332
|
-
function isPersistedInspectError(value) {
|
|
333
|
-
if (!isRecord3(value)) return false;
|
|
334
|
-
if (!isNonEmptyString2(value.message)) return false;
|
|
335
|
-
if (!isOptionalString(value.name)) return false;
|
|
336
|
-
if (!isOptionalString(value.code)) return false;
|
|
337
|
-
return true;
|
|
338
|
-
}
|
|
339
|
-
function isPersistedTokenUsage(value) {
|
|
340
|
-
if (!isRecord3(value)) return false;
|
|
341
|
-
if (!isOptionalNonNegativeNumber(value.input)) return false;
|
|
342
|
-
if (!isOptionalNonNegativeNumber(value.output)) return false;
|
|
343
|
-
if (!isOptionalNonNegativeNumber(value.total)) return false;
|
|
344
|
-
if (!isOptionalNonNegativeNumber(value.cached)) return false;
|
|
345
|
-
return true;
|
|
346
|
-
}
|
|
347
|
-
function isPersistedTraceContext(value) {
|
|
348
|
-
if (!isRecord3(value)) return false;
|
|
349
|
-
if (!isOptionalString(value.traceId)) return false;
|
|
350
|
-
if (!isOptionalString(value.spanId)) return false;
|
|
351
|
-
if (!isOptionalString(value.parentSpanId)) return false;
|
|
352
|
-
return true;
|
|
353
|
-
}
|
|
354
|
-
function isPersistedInspectEvent(value) {
|
|
355
|
-
if (!isRecord3(value)) return false;
|
|
356
|
-
if (value.schemaVersion !== "0.2" && value.schemaVersion !== "1.0") {
|
|
357
|
-
return false;
|
|
358
|
-
}
|
|
359
|
-
if (!isNonEmptyString2(value.eventId)) return false;
|
|
360
|
-
if (!isNonEmptyString2(value.runId)) return false;
|
|
361
|
-
if (!isInspectKind(value.kind)) return false;
|
|
362
|
-
if (!isNonEmptyString2(value.name)) return false;
|
|
363
|
-
if (!isNonEmptyString2(value.timestamp)) return false;
|
|
364
|
-
if (!isAttributionConfidence(value.confidence)) return false;
|
|
365
|
-
if (!isPersistedEventSource(value.source)) return false;
|
|
366
|
-
if (value.parentId !== void 0 && !isNonEmptyString2(value.parentId)) {
|
|
367
|
-
return false;
|
|
368
|
-
}
|
|
369
|
-
if (value.status !== void 0 && !isPersistedEventStatus(value.status)) {
|
|
370
|
-
return false;
|
|
371
|
-
}
|
|
372
|
-
if (!isOptionalString(value.startedAt)) return false;
|
|
373
|
-
if (!isOptionalString(value.endedAt)) return false;
|
|
374
|
-
if (value.durationMs !== void 0 && !isNonNegativeNumber(value.durationMs)) {
|
|
375
|
-
return false;
|
|
376
|
-
}
|
|
377
|
-
if (value.attributes !== void 0 && !isRecord3(value.attributes)) {
|
|
378
|
-
return false;
|
|
379
|
-
}
|
|
380
|
-
if (value.error !== void 0 && !isPersistedInspectError(value.error)) {
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
383
|
-
if (value.tokenUsage !== void 0 && !isPersistedTokenUsage(value.tokenUsage)) {
|
|
384
|
-
return false;
|
|
385
|
-
}
|
|
386
|
-
if (value.trace !== void 0 && !isPersistedTraceContext(value.trace)) {
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
return true;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// packages/core/src/persisted/to-trace-event.ts
|
|
393
|
-
function parseIsoToMs(iso) {
|
|
394
|
-
const parsed = Date.parse(iso);
|
|
395
|
-
return Number.isFinite(parsed) ? parsed : 0;
|
|
396
|
-
}
|
|
397
|
-
function mapInspectKindToStepType(kind) {
|
|
398
|
-
switch (kind) {
|
|
399
|
-
case "LLM":
|
|
400
|
-
return "llm";
|
|
401
|
-
case "TOOL":
|
|
402
|
-
return "tool";
|
|
403
|
-
case "DECISION":
|
|
404
|
-
return "decision";
|
|
405
|
-
case "RUN":
|
|
406
|
-
return "run";
|
|
407
|
-
default:
|
|
408
|
-
return "logic";
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
function mapPersistedStatusToStepStatus(status) {
|
|
412
|
-
switch (status) {
|
|
413
|
-
case "ok":
|
|
414
|
-
return "success";
|
|
415
|
-
case "error":
|
|
416
|
-
return "error";
|
|
417
|
-
case "running":
|
|
418
|
-
return "running";
|
|
419
|
-
default:
|
|
420
|
-
return void 0;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
function mapPersistedStatusToRunStatus(status) {
|
|
424
|
-
switch (status) {
|
|
425
|
-
case "ok":
|
|
426
|
-
return "success";
|
|
427
|
-
case "error":
|
|
428
|
-
return "error";
|
|
429
|
-
case "running":
|
|
430
|
-
return "running";
|
|
431
|
-
default:
|
|
432
|
-
return void 0;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
function mapPersistedError(error, attributes) {
|
|
436
|
-
if (!error?.message) return void 0;
|
|
437
|
-
const out = { message: error.message };
|
|
438
|
-
const stack = typeof attributes?.errorStack === "string" && attributes.errorStack.length > 0 ? attributes.errorStack : void 0;
|
|
439
|
-
if (stack) {
|
|
440
|
-
out.stack = stack;
|
|
441
|
-
}
|
|
442
|
-
return out;
|
|
443
|
-
}
|
|
444
|
-
function mapTokenUsageToMetadata(tokenUsage, attributes) {
|
|
445
|
-
const metadata = {};
|
|
446
|
-
if (attributes?.metadata && typeof attributes.metadata === "object") {
|
|
447
|
-
Object.assign(metadata, attributes.metadata);
|
|
448
|
-
}
|
|
449
|
-
if (tokenUsage) {
|
|
450
|
-
metadata.tokens = {
|
|
451
|
-
...tokenUsage.input !== void 0 ? { input: tokenUsage.input } : {},
|
|
452
|
-
...tokenUsage.output !== void 0 ? { output: tokenUsage.output } : {},
|
|
453
|
-
...tokenUsage.total !== void 0 ? { total: tokenUsage.total } : {},
|
|
454
|
-
...tokenUsage.cached !== void 0 ? { cached: tokenUsage.cached } : {}
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
458
|
-
}
|
|
459
|
-
function pickRunMetadata(attributes) {
|
|
460
|
-
if (!attributes) return void 0;
|
|
461
|
-
const metadata = attributes.metadata && typeof attributes.metadata === "object" ? { ...attributes.metadata } : {};
|
|
462
|
-
for (const key of [
|
|
463
|
-
"correlationId",
|
|
464
|
-
"requestId",
|
|
465
|
-
"decisionId",
|
|
466
|
-
"groupId"
|
|
467
|
-
]) {
|
|
468
|
-
const value = attributes[key];
|
|
469
|
-
if (typeof value === "string" && value.trim() !== "") {
|
|
470
|
-
metadata[key] = value;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
474
|
-
}
|
|
475
|
-
function resolveStepId(event) {
|
|
476
|
-
const attrs = event.attributes;
|
|
477
|
-
if (attrs && typeof attrs.stepId === "string" && attrs.stepId.trim() !== "") {
|
|
478
|
-
return attrs.stepId;
|
|
479
|
-
}
|
|
480
|
-
return event.eventId;
|
|
481
|
-
}
|
|
482
|
-
function resolveStepType(event) {
|
|
483
|
-
const attrs = event.attributes;
|
|
484
|
-
if (attrs && typeof attrs.stepType === "string") {
|
|
485
|
-
const t = attrs.stepType;
|
|
486
|
-
if (t === "run" || t === "llm" || t === "tool" || t === "decision" || t === "logic" || t === "state" || t === "custom") {
|
|
487
|
-
return t;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
return mapInspectKindToStepType(event.kind);
|
|
491
|
-
}
|
|
492
|
-
function resolveTimes(event) {
|
|
493
|
-
const timestamp = parseIsoToMs(event.timestamp);
|
|
494
|
-
const startTime = event.startedAt !== void 0 ? parseIsoToMs(event.startedAt) : timestamp;
|
|
495
|
-
let endTime = event.endedAt !== void 0 ? parseIsoToMs(event.endedAt) : timestamp;
|
|
496
|
-
if (event.durationMs !== void 0 && Number.isFinite(event.durationMs) && event.durationMs >= 0 && event.endedAt === void 0) {
|
|
497
|
-
endTime = startTime + event.durationMs;
|
|
498
|
-
}
|
|
499
|
-
return { timestamp, startTime, endTime };
|
|
500
|
-
}
|
|
501
|
-
function fromLegacyRunStarted(event) {
|
|
502
|
-
const { timestamp, startTime } = resolveTimes(event);
|
|
503
|
-
const out = {
|
|
504
|
-
schemaVersion: "0.1",
|
|
505
|
-
event: "run_started",
|
|
506
|
-
timestamp,
|
|
507
|
-
runId: event.runId,
|
|
508
|
-
name: event.name,
|
|
509
|
-
startTime
|
|
510
|
-
};
|
|
511
|
-
const metadata = pickRunMetadata(event.attributes);
|
|
512
|
-
if (metadata) out.metadata = metadata;
|
|
513
|
-
return out;
|
|
514
|
-
}
|
|
515
|
-
function fromLegacyRunCompleted(event) {
|
|
516
|
-
const { timestamp, endTime } = resolveTimes(event);
|
|
517
|
-
const status = mapPersistedStatusToRunStatus(event.status) ?? "success";
|
|
518
|
-
const out = {
|
|
519
|
-
schemaVersion: "0.1",
|
|
520
|
-
event: "run_completed",
|
|
521
|
-
timestamp,
|
|
522
|
-
runId: event.runId,
|
|
523
|
-
status: status === "running" ? "success" : status,
|
|
524
|
-
endTime,
|
|
525
|
-
durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
|
|
526
|
-
};
|
|
527
|
-
const error = mapPersistedError(event.error, event.attributes);
|
|
528
|
-
if (error) out.error = error;
|
|
529
|
-
return out;
|
|
530
|
-
}
|
|
531
|
-
function fromLegacyStepStarted(event) {
|
|
532
|
-
const { timestamp, startTime } = resolveTimes(event);
|
|
533
|
-
const out = {
|
|
534
|
-
schemaVersion: "0.1",
|
|
535
|
-
event: "step_started",
|
|
536
|
-
timestamp,
|
|
537
|
-
runId: event.runId,
|
|
538
|
-
stepId: resolveStepId(event),
|
|
539
|
-
name: event.name,
|
|
540
|
-
type: resolveStepType(event),
|
|
541
|
-
startTime
|
|
542
|
-
};
|
|
543
|
-
if (event.parentId !== void 0) out.parentId = event.parentId;
|
|
544
|
-
const metadata = mapTokenUsageToMetadata(event.tokenUsage, event.attributes);
|
|
545
|
-
if (metadata) out.metadata = metadata;
|
|
546
|
-
return out;
|
|
547
|
-
}
|
|
548
|
-
function fromLegacyStepCompleted(event) {
|
|
549
|
-
const { timestamp, endTime } = resolveTimes(event);
|
|
550
|
-
const status = mapPersistedStatusToStepStatus(event.status) ?? "success";
|
|
551
|
-
const out = {
|
|
552
|
-
schemaVersion: "0.1",
|
|
553
|
-
event: "step_completed",
|
|
554
|
-
timestamp,
|
|
555
|
-
runId: event.runId,
|
|
556
|
-
stepId: resolveStepId(event),
|
|
557
|
-
status: status === "running" ? "success" : status,
|
|
558
|
-
endTime,
|
|
559
|
-
durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
|
|
560
|
-
};
|
|
561
|
-
const error = mapPersistedError(event.error, event.attributes);
|
|
562
|
-
if (error) out.error = error;
|
|
563
|
-
return out;
|
|
564
|
-
}
|
|
565
|
-
function fromNativeRun(event) {
|
|
566
|
-
const { timestamp, startTime, endTime } = resolveTimes(event);
|
|
567
|
-
const runStatus = mapPersistedStatusToRunStatus(event.status);
|
|
568
|
-
const out = [];
|
|
569
|
-
if (runStatus === "running" || event.startedAt !== void 0) {
|
|
570
|
-
const started = {
|
|
571
|
-
schemaVersion: "0.1",
|
|
572
|
-
event: "run_started",
|
|
573
|
-
timestamp,
|
|
574
|
-
runId: event.runId,
|
|
575
|
-
name: event.name,
|
|
576
|
-
startTime
|
|
577
|
-
};
|
|
578
|
-
const metadata = pickRunMetadata(event.attributes);
|
|
579
|
-
if (metadata) started.metadata = metadata;
|
|
580
|
-
out.push(started);
|
|
581
|
-
}
|
|
582
|
-
if (runStatus === "success" || runStatus === "error" || event.endedAt !== void 0) {
|
|
583
|
-
const completed = {
|
|
584
|
-
schemaVersion: "0.1",
|
|
585
|
-
event: "run_completed",
|
|
586
|
-
timestamp,
|
|
587
|
-
runId: event.runId,
|
|
588
|
-
status: runStatus === "error" ? "error" : "success",
|
|
589
|
-
endTime,
|
|
590
|
-
durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
|
|
591
|
-
};
|
|
592
|
-
const error = mapPersistedError(event.error, event.attributes);
|
|
593
|
-
if (error) completed.error = error;
|
|
594
|
-
out.push(completed);
|
|
595
|
-
}
|
|
596
|
-
if (out.length === 0) {
|
|
597
|
-
out.push(fromLegacyRunStarted(event));
|
|
598
|
-
}
|
|
599
|
-
return out;
|
|
600
|
-
}
|
|
601
|
-
function fromNativeStep(event) {
|
|
602
|
-
const { timestamp, startTime, endTime } = resolveTimes(event);
|
|
603
|
-
const stepStatus = mapPersistedStatusToStepStatus(event.status);
|
|
604
|
-
const stepId = resolveStepId(event);
|
|
605
|
-
const out = [];
|
|
606
|
-
const shouldEmitStarted = stepStatus === "running" || event.startedAt !== void 0 || stepStatus === "success" || stepStatus === "error";
|
|
607
|
-
if (shouldEmitStarted) {
|
|
608
|
-
const started = {
|
|
609
|
-
schemaVersion: "0.1",
|
|
610
|
-
event: "step_started",
|
|
611
|
-
timestamp,
|
|
612
|
-
runId: event.runId,
|
|
613
|
-
stepId,
|
|
614
|
-
name: event.name,
|
|
615
|
-
type: resolveStepType(event),
|
|
616
|
-
startTime
|
|
617
|
-
};
|
|
618
|
-
if (event.parentId !== void 0) started.parentId = event.parentId;
|
|
619
|
-
const metadata = mapTokenUsageToMetadata(event.tokenUsage, event.attributes);
|
|
620
|
-
if (metadata) started.metadata = metadata;
|
|
621
|
-
out.push(started);
|
|
622
|
-
}
|
|
623
|
-
if (stepStatus === "success" || stepStatus === "error" || event.endedAt !== void 0 || event.durationMs !== void 0) {
|
|
624
|
-
const completed = {
|
|
625
|
-
schemaVersion: "0.1",
|
|
626
|
-
event: "step_completed",
|
|
627
|
-
timestamp,
|
|
628
|
-
runId: event.runId,
|
|
629
|
-
stepId,
|
|
630
|
-
status: stepStatus === "error" ? "error" : "success",
|
|
631
|
-
endTime,
|
|
632
|
-
durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
|
|
633
|
-
};
|
|
634
|
-
const error = mapPersistedError(event.error, event.attributes);
|
|
635
|
-
if (error) completed.error = error;
|
|
636
|
-
out.push(completed);
|
|
637
|
-
}
|
|
638
|
-
if (out.length === 0) {
|
|
639
|
-
out.push(fromLegacyStepStarted(event));
|
|
640
|
-
}
|
|
641
|
-
return out;
|
|
642
|
-
}
|
|
643
|
-
function persistedInspectEventToTraceEvents(event) {
|
|
644
|
-
if (!isPersistedInspectEvent(event)) {
|
|
645
|
-
throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
|
|
646
|
-
}
|
|
647
|
-
const legacyEvent = event.attributes?.legacyEvent;
|
|
648
|
-
if (legacyEvent === "run_started") return [fromLegacyRunStarted(event)];
|
|
649
|
-
if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
|
|
650
|
-
if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
|
|
651
|
-
if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
|
|
652
|
-
if (event.kind === "RUN") {
|
|
653
|
-
return fromNativeRun(event);
|
|
654
|
-
}
|
|
655
|
-
return fromNativeStep(event);
|
|
656
|
-
}
|
|
657
|
-
function persistedInspectEventsToTraceEvents(events, options) {
|
|
658
|
-
const out = [];
|
|
659
|
-
events.forEach((event, index) => {
|
|
660
|
-
const rows = persistedInspectEventToTraceEvents(event);
|
|
661
|
-
if (rows.length === 0 && options?.eventIndex !== void 0) ;
|
|
662
|
-
out.push(...rows);
|
|
663
|
-
});
|
|
664
|
-
return out;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
// node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/url-alphabet/index.js
|
|
668
|
-
var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
669
|
-
|
|
670
|
-
// node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/index.js
|
|
671
|
-
var POOL_SIZE_MULTIPLIER = 128;
|
|
672
|
-
var pool;
|
|
673
|
-
var poolOffset;
|
|
674
|
-
function fillPool(bytes) {
|
|
675
|
-
if (bytes < 0 || bytes > 1024) throw new RangeError("Wrong ID size");
|
|
676
|
-
if (!pool || pool.length < bytes) {
|
|
677
|
-
pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
|
|
678
|
-
webcrypto.getRandomValues(pool);
|
|
679
|
-
poolOffset = 0;
|
|
680
|
-
} else if (poolOffset + bytes > pool.length) {
|
|
681
|
-
webcrypto.getRandomValues(pool);
|
|
682
|
-
poolOffset = 0;
|
|
683
|
-
}
|
|
684
|
-
poolOffset += bytes;
|
|
685
|
-
}
|
|
686
|
-
function nanoid(size = 21) {
|
|
687
|
-
fillPool(size |= 0);
|
|
688
|
-
let id = "";
|
|
689
|
-
for (let i = poolOffset - size; i < poolOffset; i++) {
|
|
690
|
-
id += urlAlphabet[pool[i] & 63];
|
|
691
|
-
}
|
|
692
|
-
return id;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
// packages/core/src/utils/duration.ts
|
|
696
|
-
function parseDuration(duration) {
|
|
697
|
-
const raw = typeof duration === "string" ? duration.trim() : "";
|
|
698
|
-
const match = raw.match(/^(\d+)(ms|[smhd])$/);
|
|
699
|
-
if (!match) {
|
|
700
|
-
throw new Error(
|
|
701
|
-
`Invalid duration format: ${duration}. Use a positive integer followed by ms, s, m, h, or d (e.g. 500ms, 30s, 5m, 2h, 7d).`
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
const amount = Number.parseInt(match[1], 10);
|
|
705
|
-
const unit = match[2];
|
|
706
|
-
if (!Number.isFinite(amount) || amount <= 0) {
|
|
707
|
-
throw new Error(
|
|
708
|
-
`Invalid duration amount: ${duration}. Amount must be a positive integer.`
|
|
709
|
-
);
|
|
710
|
-
}
|
|
711
|
-
switch (unit) {
|
|
712
|
-
case "ms":
|
|
713
|
-
return amount;
|
|
714
|
-
case "s":
|
|
715
|
-
return amount * 1e3;
|
|
716
|
-
case "m":
|
|
717
|
-
return amount * 60 * 1e3;
|
|
718
|
-
case "h":
|
|
719
|
-
return amount * 60 * 60 * 1e3;
|
|
720
|
-
case "d":
|
|
721
|
-
return amount * 24 * 60 * 60 * 1e3;
|
|
722
|
-
default: {
|
|
723
|
-
throw new Error(`Unknown duration unit: ${unit}`);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
function formatDuration(ms) {
|
|
728
|
-
if (!Number.isFinite(ms)) {
|
|
729
|
-
return "0ms";
|
|
730
|
-
}
|
|
731
|
-
if (ms < 0) {
|
|
732
|
-
throw new Error(`formatDuration: ms must be non-negative (got ${ms})`);
|
|
733
|
-
}
|
|
734
|
-
if (ms < 1e3) {
|
|
735
|
-
return `${Math.floor(ms)}ms`;
|
|
736
|
-
}
|
|
737
|
-
if (ms < 6e4) {
|
|
738
|
-
return `${(ms / 1e3).toFixed(2)}s`;
|
|
739
|
-
}
|
|
740
|
-
if (ms < 36e5) {
|
|
741
|
-
return `${(ms / 6e4).toFixed(1)}m`;
|
|
742
|
-
}
|
|
743
|
-
return `${(ms / 36e5).toFixed(1)}h`;
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// packages/core/src/utils.ts
|
|
747
|
-
var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
748
|
-
var RUNS_DIR_NAME = "runs";
|
|
749
|
-
var FALLBACK_TRACE_DIR = path14.join(
|
|
750
|
-
os.tmpdir(),
|
|
751
|
-
"agent-inspect",
|
|
752
|
-
RUNS_DIR_NAME
|
|
753
|
-
);
|
|
754
|
-
var MAX_NAME_LENGTH = 100;
|
|
755
|
-
function formatDuration2(ms) {
|
|
756
|
-
return formatDuration(ms);
|
|
757
|
-
}
|
|
758
|
-
function formatTimestamp(timestamp) {
|
|
759
|
-
if (!Number.isFinite(timestamp)) {
|
|
760
|
-
return "Invalid date";
|
|
761
|
-
}
|
|
762
|
-
const d = new Date(timestamp);
|
|
763
|
-
if (Number.isNaN(d.getTime())) {
|
|
764
|
-
return "Invalid date";
|
|
765
|
-
}
|
|
766
|
-
const y = d.getFullYear();
|
|
767
|
-
const mo = String(d.getMonth() + 1).padStart(2, "0");
|
|
768
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
769
|
-
const h = String(d.getHours()).padStart(2, "0");
|
|
770
|
-
const min = String(d.getMinutes()).padStart(2, "0");
|
|
771
|
-
const s = String(d.getSeconds()).padStart(2, "0");
|
|
772
|
-
return `${y}-${mo}-${day} ${h}:${min}:${s}`;
|
|
773
|
-
}
|
|
774
|
-
function getDefaultTraceDir() {
|
|
775
|
-
const envDir = process.env.AGENT_INSPECT_TRACE_DIR;
|
|
776
|
-
if (typeof envDir === "string" && envDir.trim() !== "") {
|
|
777
|
-
return envDir.trim();
|
|
778
|
-
}
|
|
779
|
-
try {
|
|
780
|
-
const home = os.homedir();
|
|
781
|
-
if (typeof home !== "string" || home.trim() === "") {
|
|
782
|
-
return FALLBACK_TRACE_DIR;
|
|
783
|
-
}
|
|
784
|
-
return path14.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
785
|
-
} catch {
|
|
786
|
-
return FALLBACK_TRACE_DIR;
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
function getTraceFilePath(runId, traceDir) {
|
|
790
|
-
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
791
|
-
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
792
|
-
safeId = path14.basename(safeId);
|
|
793
|
-
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
794
|
-
safeId = "run_unknown";
|
|
795
|
-
}
|
|
796
|
-
return path14.join(baseDir, `${safeId}.jsonl`);
|
|
797
|
-
}
|
|
798
|
-
function formatError(error) {
|
|
799
|
-
if (error instanceof Error) {
|
|
800
|
-
const out = { message: error.message };
|
|
801
|
-
if (typeof error.stack === "string" && error.stack.length > 0) {
|
|
802
|
-
out.stack = error.stack;
|
|
803
|
-
}
|
|
804
|
-
return out;
|
|
805
|
-
}
|
|
806
|
-
if (typeof error === "string") {
|
|
807
|
-
return { message: error };
|
|
808
|
-
}
|
|
809
|
-
if (error === null) {
|
|
810
|
-
return { message: "Unknown error: null" };
|
|
811
|
-
}
|
|
812
|
-
if (error === void 0) {
|
|
813
|
-
return { message: "Unknown error: undefined" };
|
|
814
|
-
}
|
|
815
|
-
if (typeof error === "number" || typeof error === "boolean" || typeof error === "bigint") {
|
|
816
|
-
return { message: String(error) };
|
|
817
|
-
}
|
|
818
|
-
if (typeof error === "object") {
|
|
819
|
-
try {
|
|
820
|
-
return { message: JSON.stringify(error) };
|
|
821
|
-
} catch {
|
|
822
|
-
return { message: "Unknown error" };
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
return { message: "Unknown error" };
|
|
826
|
-
}
|
|
827
|
-
function truncateName(name, maxLength = MAX_NAME_LENGTH) {
|
|
828
|
-
if (typeof name !== "string" || name.trim() === "") {
|
|
829
|
-
return "unnamed";
|
|
830
|
-
}
|
|
831
|
-
const trimmed = name.trim();
|
|
832
|
-
if (trimmed.length <= maxLength) {
|
|
833
|
-
return trimmed;
|
|
834
|
-
}
|
|
835
|
-
const ellipsis = "...";
|
|
836
|
-
const head = Math.max(0, maxLength - ellipsis.length);
|
|
837
|
-
return `${trimmed.slice(0, head)}${ellipsis}`;
|
|
838
|
-
}
|
|
839
|
-
function warn(message, error) {
|
|
840
|
-
const base = `[AgentInspect] ${message}`;
|
|
841
|
-
if (error === void 0) {
|
|
842
|
-
console.warn(base);
|
|
843
|
-
return;
|
|
844
|
-
}
|
|
845
|
-
console.warn(`${base}: ${formatError(error).message}`);
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
// packages/core/src/read-trace.ts
|
|
849
|
-
function isRecord4(value) {
|
|
850
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
851
|
-
}
|
|
852
|
-
function detectLineFormat(parsed) {
|
|
853
|
-
if (!isRecord4(parsed)) return "unknown";
|
|
854
|
-
if (parsed.schemaVersion === "0.1") return "0.1";
|
|
855
|
-
if (parsed.schemaVersion === "0.2") return "0.2";
|
|
856
|
-
if (parsed.schemaVersion === "1.0") return "1.0";
|
|
857
|
-
return "unknown";
|
|
858
|
-
}
|
|
859
|
-
function parseTraceJsonl(raw, options = {}) {
|
|
860
|
-
const validate = options.validate ?? isTraceEvent;
|
|
861
|
-
const emitWarning = (message) => {
|
|
862
|
-
if (options.warnings !== false) warn(message);
|
|
863
|
-
};
|
|
864
|
-
const persisted = [];
|
|
865
|
-
const traceEvents = [];
|
|
866
|
-
const rows = [];
|
|
867
|
-
let sourceEventCount = 0;
|
|
868
|
-
let saw01 = false;
|
|
869
|
-
let saw02 = false;
|
|
870
|
-
let saw10 = false;
|
|
871
|
-
let lineNumber = 0;
|
|
872
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
873
|
-
lineNumber += 1;
|
|
874
|
-
const trimmed = line.trim();
|
|
875
|
-
if (trimmed === "") continue;
|
|
876
|
-
let parsed;
|
|
877
|
-
try {
|
|
878
|
-
parsed = JSON.parse(trimmed);
|
|
879
|
-
} catch {
|
|
880
|
-
emitWarning("Skipped invalid JSON line in trace file");
|
|
881
|
-
continue;
|
|
882
|
-
}
|
|
883
|
-
const format2 = detectLineFormat(parsed);
|
|
884
|
-
if (format2 === "0.1") {
|
|
885
|
-
saw01 = true;
|
|
886
|
-
if (validate(parsed)) {
|
|
887
|
-
sourceEventCount += 1;
|
|
888
|
-
traceEvents.push(parsed);
|
|
889
|
-
rows.push({ format: "0.1", event: parsed, sourceLine: lineNumber });
|
|
890
|
-
} else {
|
|
891
|
-
emitWarning("Skipped invalid trace event line in trace file");
|
|
892
|
-
}
|
|
893
|
-
continue;
|
|
894
|
-
}
|
|
895
|
-
if (format2 === "0.2" || format2 === "1.0") {
|
|
896
|
-
if (format2 === "0.2") saw02 = true;
|
|
897
|
-
else saw10 = true;
|
|
898
|
-
if (isPersistedInspectEvent(parsed)) {
|
|
899
|
-
sourceEventCount += 1;
|
|
900
|
-
persisted.push(parsed);
|
|
901
|
-
rows.push({ format: format2, event: parsed, sourceLine: lineNumber });
|
|
902
|
-
traceEvents.push(...persistedInspectEventToTraceEvents(parsed));
|
|
903
|
-
} else {
|
|
904
|
-
emitWarning("Skipped invalid persisted inspect event line in trace file");
|
|
905
|
-
}
|
|
906
|
-
continue;
|
|
907
|
-
}
|
|
908
|
-
emitWarning("Skipped trace line with unknown schemaVersion");
|
|
909
|
-
}
|
|
910
|
-
const seenFormats = [saw01, saw02, saw10].filter(Boolean).length;
|
|
911
|
-
if (seenFormats > 1) {
|
|
912
|
-
emitWarning(
|
|
913
|
-
"Trace file mixes AgentInspect schemaVersion rows; normalizing all rows"
|
|
914
|
-
);
|
|
915
|
-
}
|
|
916
|
-
let format = "empty";
|
|
917
|
-
if (seenFormats > 1) format = "mixed";
|
|
918
|
-
else if (saw01) format = "0.1";
|
|
919
|
-
else if (saw02) format = "0.2";
|
|
920
|
-
else if (saw10) format = "1.0";
|
|
921
|
-
return { format, sourceEventCount, events: traceEvents, persisted, rows };
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
// packages/core/src/storage.ts
|
|
925
|
-
function isRecord5(value) {
|
|
926
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
927
|
-
}
|
|
928
|
-
function nonEmptyString(value) {
|
|
929
|
-
return typeof value === "string" && value.trim() !== "";
|
|
930
|
-
}
|
|
931
|
-
function finiteNumber(value) {
|
|
932
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
933
|
-
}
|
|
934
|
-
function optionalErrorInfo(value) {
|
|
935
|
-
if (value === void 0) return true;
|
|
936
|
-
if (!isRecord5(value)) return false;
|
|
937
|
-
if (typeof value.message !== "string") return false;
|
|
938
|
-
if ("stack" in value && value.stack !== void 0) {
|
|
939
|
-
if (typeof value.stack !== "string") return false;
|
|
940
|
-
}
|
|
941
|
-
return true;
|
|
942
|
-
}
|
|
943
|
-
function validateEvent(event) {
|
|
944
|
-
if (!isRecord5(event)) return false;
|
|
945
|
-
if (event.schemaVersion !== "0.1") return false;
|
|
946
|
-
if (!finiteNumber(event.timestamp)) return false;
|
|
947
|
-
if (typeof event.event !== "string") return false;
|
|
948
|
-
switch (event.event) {
|
|
949
|
-
case "run_started": {
|
|
950
|
-
if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
|
|
951
|
-
return false;
|
|
952
|
-
}
|
|
953
|
-
if (event.metadata !== void 0 && !isRecord5(event.metadata)) {
|
|
954
|
-
return false;
|
|
955
|
-
}
|
|
956
|
-
return true;
|
|
957
|
-
}
|
|
958
|
-
case "run_completed": {
|
|
959
|
-
return nonEmptyString(event.runId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
960
|
-
}
|
|
961
|
-
case "step_started": {
|
|
962
|
-
if (!nonEmptyString(event.runId) || !nonEmptyString(event.stepId) || !nonEmptyString(event.name) || !isStepType(event.type) || !finiteNumber(event.startTime)) {
|
|
963
|
-
return false;
|
|
964
|
-
}
|
|
965
|
-
if (event.parentId !== void 0 && typeof event.parentId !== "string") {
|
|
966
|
-
return false;
|
|
967
|
-
}
|
|
968
|
-
if (event.metadata !== void 0 && !isRecord5(event.metadata)) {
|
|
969
|
-
return false;
|
|
970
|
-
}
|
|
971
|
-
return true;
|
|
972
|
-
}
|
|
973
|
-
case "step_completed": {
|
|
974
|
-
return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
975
|
-
}
|
|
976
|
-
default:
|
|
977
|
-
return false;
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
async function readTraceEventsFromFile(filePath) {
|
|
981
|
-
try {
|
|
982
|
-
const raw = await readFile(filePath, "utf-8");
|
|
983
|
-
return parseTraceJsonl(raw, { validate: validateEvent }).events;
|
|
984
|
-
} catch (e) {
|
|
985
|
-
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
986
|
-
return [];
|
|
987
|
-
}
|
|
988
|
-
warn("Failed to read trace events from file", e);
|
|
989
|
-
return [];
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// packages/core/src/context.ts
|
|
994
|
-
new AsyncLocalStorage();
|
|
995
|
-
|
|
996
|
-
// node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
997
|
-
var ANSI_BACKGROUND_OFFSET = 10;
|
|
998
|
-
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
999
|
-
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
|
|
1000
|
-
var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
|
|
1001
|
-
var styles = {
|
|
1002
|
-
modifier: {
|
|
1003
|
-
reset: [0, 0],
|
|
1004
|
-
// 21 isn't widely supported and 22 does the same thing
|
|
1005
|
-
bold: [1, 22],
|
|
1006
|
-
dim: [2, 22],
|
|
1007
|
-
italic: [3, 23],
|
|
1008
|
-
underline: [4, 24],
|
|
1009
|
-
overline: [53, 55],
|
|
1010
|
-
inverse: [7, 27],
|
|
1011
|
-
hidden: [8, 28],
|
|
1012
|
-
strikethrough: [9, 29]
|
|
1013
|
-
},
|
|
1014
|
-
color: {
|
|
1015
|
-
black: [30, 39],
|
|
1016
|
-
red: [31, 39],
|
|
1017
|
-
green: [32, 39],
|
|
1018
|
-
yellow: [33, 39],
|
|
1019
|
-
blue: [34, 39],
|
|
1020
|
-
magenta: [35, 39],
|
|
1021
|
-
cyan: [36, 39],
|
|
1022
|
-
white: [37, 39],
|
|
1023
|
-
// Bright color
|
|
1024
|
-
blackBright: [90, 39],
|
|
1025
|
-
gray: [90, 39],
|
|
1026
|
-
// Alias of `blackBright`
|
|
1027
|
-
grey: [90, 39],
|
|
1028
|
-
// Alias of `blackBright`
|
|
1029
|
-
redBright: [91, 39],
|
|
1030
|
-
greenBright: [92, 39],
|
|
1031
|
-
yellowBright: [93, 39],
|
|
1032
|
-
blueBright: [94, 39],
|
|
1033
|
-
magentaBright: [95, 39],
|
|
1034
|
-
cyanBright: [96, 39],
|
|
1035
|
-
whiteBright: [97, 39]
|
|
1036
|
-
},
|
|
1037
|
-
bgColor: {
|
|
1038
|
-
bgBlack: [40, 49],
|
|
1039
|
-
bgRed: [41, 49],
|
|
1040
|
-
bgGreen: [42, 49],
|
|
1041
|
-
bgYellow: [43, 49],
|
|
1042
|
-
bgBlue: [44, 49],
|
|
1043
|
-
bgMagenta: [45, 49],
|
|
1044
|
-
bgCyan: [46, 49],
|
|
1045
|
-
bgWhite: [47, 49],
|
|
1046
|
-
// Bright color
|
|
1047
|
-
bgBlackBright: [100, 49],
|
|
1048
|
-
bgGray: [100, 49],
|
|
1049
|
-
// Alias of `bgBlackBright`
|
|
1050
|
-
bgGrey: [100, 49],
|
|
1051
|
-
// Alias of `bgBlackBright`
|
|
1052
|
-
bgRedBright: [101, 49],
|
|
1053
|
-
bgGreenBright: [102, 49],
|
|
1054
|
-
bgYellowBright: [103, 49],
|
|
1055
|
-
bgBlueBright: [104, 49],
|
|
1056
|
-
bgMagentaBright: [105, 49],
|
|
1057
|
-
bgCyanBright: [106, 49],
|
|
1058
|
-
bgWhiteBright: [107, 49]
|
|
1059
|
-
}
|
|
1060
|
-
};
|
|
1061
|
-
Object.keys(styles.modifier);
|
|
1062
|
-
var foregroundColorNames = Object.keys(styles.color);
|
|
1063
|
-
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
1064
|
-
[...foregroundColorNames, ...backgroundColorNames];
|
|
1065
|
-
function assembleStyles() {
|
|
1066
|
-
const codes = /* @__PURE__ */ new Map();
|
|
1067
|
-
for (const [groupName, group] of Object.entries(styles)) {
|
|
1068
|
-
for (const [styleName, style] of Object.entries(group)) {
|
|
1069
|
-
styles[styleName] = {
|
|
1070
|
-
open: `\x1B[${style[0]}m`,
|
|
1071
|
-
close: `\x1B[${style[1]}m`
|
|
1072
|
-
};
|
|
1073
|
-
group[styleName] = styles[styleName];
|
|
1074
|
-
codes.set(style[0], style[1]);
|
|
1075
|
-
}
|
|
1076
|
-
Object.defineProperty(styles, groupName, {
|
|
1077
|
-
value: group,
|
|
1078
|
-
enumerable: false
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
Object.defineProperty(styles, "codes", {
|
|
1082
|
-
value: codes,
|
|
1083
|
-
enumerable: false
|
|
1084
|
-
});
|
|
1085
|
-
styles.color.close = "\x1B[39m";
|
|
1086
|
-
styles.bgColor.close = "\x1B[49m";
|
|
1087
|
-
styles.color.ansi = wrapAnsi16();
|
|
1088
|
-
styles.color.ansi256 = wrapAnsi256();
|
|
1089
|
-
styles.color.ansi16m = wrapAnsi16m();
|
|
1090
|
-
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
1091
|
-
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
1092
|
-
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
1093
|
-
Object.defineProperties(styles, {
|
|
1094
|
-
rgbToAnsi256: {
|
|
1095
|
-
value(red, green, blue) {
|
|
1096
|
-
if (red === green && green === blue) {
|
|
1097
|
-
if (red < 8) {
|
|
1098
|
-
return 16;
|
|
1099
|
-
}
|
|
1100
|
-
if (red > 248) {
|
|
1101
|
-
return 231;
|
|
1102
|
-
}
|
|
1103
|
-
return Math.round((red - 8) / 247 * 24) + 232;
|
|
1104
|
-
}
|
|
1105
|
-
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
1106
|
-
},
|
|
1107
|
-
enumerable: false
|
|
1108
|
-
},
|
|
1109
|
-
hexToRgb: {
|
|
1110
|
-
value(hex) {
|
|
1111
|
-
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
1112
|
-
if (!matches) {
|
|
1113
|
-
return [0, 0, 0];
|
|
1114
|
-
}
|
|
1115
|
-
let [colorString] = matches;
|
|
1116
|
-
if (colorString.length === 3) {
|
|
1117
|
-
colorString = [...colorString].map((character) => character + character).join("");
|
|
1118
|
-
}
|
|
1119
|
-
const integer = Number.parseInt(colorString, 16);
|
|
1120
|
-
return [
|
|
1121
|
-
/* eslint-disable no-bitwise */
|
|
1122
|
-
integer >> 16 & 255,
|
|
1123
|
-
integer >> 8 & 255,
|
|
1124
|
-
integer & 255
|
|
1125
|
-
/* eslint-enable no-bitwise */
|
|
1126
|
-
];
|
|
1127
|
-
},
|
|
1128
|
-
enumerable: false
|
|
1129
|
-
},
|
|
1130
|
-
hexToAnsi256: {
|
|
1131
|
-
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
|
|
1132
|
-
enumerable: false
|
|
1133
|
-
},
|
|
1134
|
-
ansi256ToAnsi: {
|
|
1135
|
-
value(code) {
|
|
1136
|
-
if (code < 8) {
|
|
1137
|
-
return 30 + code;
|
|
1138
|
-
}
|
|
1139
|
-
if (code < 16) {
|
|
1140
|
-
return 90 + (code - 8);
|
|
1141
|
-
}
|
|
1142
|
-
let red;
|
|
1143
|
-
let green;
|
|
1144
|
-
let blue;
|
|
1145
|
-
if (code >= 232) {
|
|
1146
|
-
red = ((code - 232) * 10 + 8) / 255;
|
|
1147
|
-
green = red;
|
|
1148
|
-
blue = red;
|
|
1149
|
-
} else {
|
|
1150
|
-
code -= 16;
|
|
1151
|
-
const remainder = code % 36;
|
|
1152
|
-
red = Math.floor(code / 36) / 5;
|
|
1153
|
-
green = Math.floor(remainder / 6) / 5;
|
|
1154
|
-
blue = remainder % 6 / 5;
|
|
1155
|
-
}
|
|
1156
|
-
const value = Math.max(red, green, blue) * 2;
|
|
1157
|
-
if (value === 0) {
|
|
1158
|
-
return 30;
|
|
1159
|
-
}
|
|
1160
|
-
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
1161
|
-
if (value === 2) {
|
|
1162
|
-
result += 60;
|
|
1163
|
-
}
|
|
1164
|
-
return result;
|
|
1165
|
-
},
|
|
1166
|
-
enumerable: false
|
|
1167
|
-
},
|
|
1168
|
-
rgbToAnsi: {
|
|
1169
|
-
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
|
|
1170
|
-
enumerable: false
|
|
1171
|
-
},
|
|
1172
|
-
hexToAnsi: {
|
|
1173
|
-
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
|
|
1174
|
-
enumerable: false
|
|
1175
|
-
}
|
|
1176
|
-
});
|
|
1177
|
-
return styles;
|
|
1178
|
-
}
|
|
1179
|
-
var ansiStyles = assembleStyles();
|
|
1180
|
-
var ansi_styles_default = ansiStyles;
|
|
1181
|
-
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process3.argv) {
|
|
1182
|
-
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
1183
|
-
const position = argv.indexOf(prefix + flag);
|
|
1184
|
-
const terminatorPosition = argv.indexOf("--");
|
|
1185
|
-
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
1186
|
-
}
|
|
1187
|
-
var { env } = process3;
|
|
1188
|
-
var flagForceColor;
|
|
1189
|
-
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
1190
|
-
flagForceColor = 0;
|
|
1191
|
-
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
1192
|
-
flagForceColor = 1;
|
|
1193
|
-
}
|
|
1194
|
-
function envForceColor() {
|
|
1195
|
-
if ("FORCE_COLOR" in env) {
|
|
1196
|
-
if (env.FORCE_COLOR === "true") {
|
|
1197
|
-
return 1;
|
|
1198
|
-
}
|
|
1199
|
-
if (env.FORCE_COLOR === "false") {
|
|
1200
|
-
return 0;
|
|
1201
|
-
}
|
|
1202
|
-
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
function translateLevel(level) {
|
|
1206
|
-
if (level === 0) {
|
|
1207
|
-
return false;
|
|
1208
|
-
}
|
|
1209
|
-
return {
|
|
1210
|
-
level,
|
|
1211
|
-
hasBasic: true,
|
|
1212
|
-
has256: level >= 2,
|
|
1213
|
-
has16m: level >= 3
|
|
1214
|
-
};
|
|
1215
|
-
}
|
|
1216
|
-
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
1217
|
-
const noFlagForceColor = envForceColor();
|
|
1218
|
-
if (noFlagForceColor !== void 0) {
|
|
1219
|
-
flagForceColor = noFlagForceColor;
|
|
1220
|
-
}
|
|
1221
|
-
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
1222
|
-
if (forceColor === 0) {
|
|
1223
|
-
return 0;
|
|
1224
|
-
}
|
|
1225
|
-
if (sniffFlags) {
|
|
1226
|
-
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
1227
|
-
return 3;
|
|
1228
|
-
}
|
|
1229
|
-
if (hasFlag("color=256")) {
|
|
1230
|
-
return 2;
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
1234
|
-
return 1;
|
|
1235
|
-
}
|
|
1236
|
-
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
1237
|
-
return 0;
|
|
1238
|
-
}
|
|
1239
|
-
const min = forceColor || 0;
|
|
1240
|
-
if (env.TERM === "dumb") {
|
|
1241
|
-
return min;
|
|
1242
|
-
}
|
|
1243
|
-
if (process3.platform === "win32") {
|
|
1244
|
-
const osRelease = os.release().split(".");
|
|
1245
|
-
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
1246
|
-
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
1247
|
-
}
|
|
1248
|
-
return 1;
|
|
1249
|
-
}
|
|
1250
|
-
if ("CI" in env) {
|
|
1251
|
-
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
|
|
1252
|
-
return 3;
|
|
1253
|
-
}
|
|
1254
|
-
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
1255
|
-
return 1;
|
|
1256
|
-
}
|
|
1257
|
-
return min;
|
|
1258
|
-
}
|
|
1259
|
-
if ("TEAMCITY_VERSION" in env) {
|
|
1260
|
-
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
1261
|
-
}
|
|
1262
|
-
if (env.COLORTERM === "truecolor") {
|
|
1263
|
-
return 3;
|
|
1264
|
-
}
|
|
1265
|
-
if (env.TERM === "xterm-kitty") {
|
|
1266
|
-
return 3;
|
|
1267
|
-
}
|
|
1268
|
-
if (env.TERM === "xterm-ghostty") {
|
|
1269
|
-
return 3;
|
|
1270
|
-
}
|
|
1271
|
-
if (env.TERM === "wezterm") {
|
|
1272
|
-
return 3;
|
|
1273
|
-
}
|
|
1274
|
-
if ("TERM_PROGRAM" in env) {
|
|
1275
|
-
const version2 = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
1276
|
-
switch (env.TERM_PROGRAM) {
|
|
1277
|
-
case "iTerm.app": {
|
|
1278
|
-
return version2 >= 3 ? 3 : 2;
|
|
1279
|
-
}
|
|
1280
|
-
case "Apple_Terminal": {
|
|
1281
|
-
return 2;
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
if (/-256(color)?$/i.test(env.TERM)) {
|
|
1286
|
-
return 2;
|
|
1287
|
-
}
|
|
1288
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
1289
|
-
return 1;
|
|
1290
|
-
}
|
|
1291
|
-
if ("COLORTERM" in env) {
|
|
1292
|
-
return 1;
|
|
1293
|
-
}
|
|
1294
|
-
return min;
|
|
1295
|
-
}
|
|
1296
|
-
function createSupportsColor(stream, options = {}) {
|
|
1297
|
-
const level = _supportsColor(stream, {
|
|
1298
|
-
streamIsTTY: stream && stream.isTTY,
|
|
1299
|
-
...options
|
|
1300
|
-
});
|
|
1301
|
-
return translateLevel(level);
|
|
1302
|
-
}
|
|
1303
|
-
var supportsColor = {
|
|
1304
|
-
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
1305
|
-
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
1306
|
-
};
|
|
1307
|
-
var supports_color_default = supportsColor;
|
|
1308
|
-
|
|
1309
|
-
// node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/utilities.js
|
|
1310
|
-
function stringReplaceAll(string, substring, replacer) {
|
|
1311
|
-
let index = string.indexOf(substring);
|
|
1312
|
-
if (index === -1) {
|
|
1313
|
-
return string;
|
|
1314
|
-
}
|
|
1315
|
-
const substringLength = substring.length;
|
|
1316
|
-
let endIndex = 0;
|
|
1317
|
-
let returnValue = "";
|
|
1318
|
-
do {
|
|
1319
|
-
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
1320
|
-
endIndex = index + substringLength;
|
|
1321
|
-
index = string.indexOf(substring, endIndex);
|
|
1322
|
-
} while (index !== -1);
|
|
1323
|
-
returnValue += string.slice(endIndex);
|
|
1324
|
-
return returnValue;
|
|
1325
|
-
}
|
|
1326
|
-
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
1327
|
-
let endIndex = 0;
|
|
1328
|
-
let returnValue = "";
|
|
1329
|
-
do {
|
|
1330
|
-
const gotCR = string[index - 1] === "\r";
|
|
1331
|
-
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
1332
|
-
endIndex = index + 1;
|
|
1333
|
-
index = string.indexOf("\n", endIndex);
|
|
1334
|
-
} while (index !== -1);
|
|
1335
|
-
returnValue += string.slice(endIndex);
|
|
1336
|
-
return returnValue;
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
// node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js
|
|
1340
|
-
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
1341
|
-
var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
|
|
1342
|
-
var STYLER = /* @__PURE__ */ Symbol("STYLER");
|
|
1343
|
-
var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
|
|
1344
|
-
var levelMapping = [
|
|
1345
|
-
"ansi",
|
|
1346
|
-
"ansi",
|
|
1347
|
-
"ansi256",
|
|
1348
|
-
"ansi16m"
|
|
1349
|
-
];
|
|
1350
|
-
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
1351
|
-
var applyOptions = (object, options = {}) => {
|
|
1352
|
-
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
1353
|
-
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
1354
|
-
}
|
|
1355
|
-
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
1356
|
-
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
1357
|
-
};
|
|
1358
|
-
var chalkFactory = (options) => {
|
|
1359
|
-
const chalk2 = (...strings) => strings.join(" ");
|
|
1360
|
-
applyOptions(chalk2, options);
|
|
1361
|
-
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
1362
|
-
return chalk2;
|
|
1363
|
-
};
|
|
1364
|
-
function createChalk(options) {
|
|
1365
|
-
return chalkFactory(options);
|
|
1366
|
-
}
|
|
1367
|
-
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
1368
|
-
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
1369
|
-
styles2[styleName] = {
|
|
1370
|
-
get() {
|
|
1371
|
-
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
1372
|
-
Object.defineProperty(this, styleName, { value: builder });
|
|
1373
|
-
return builder;
|
|
1374
|
-
}
|
|
1375
|
-
};
|
|
1376
|
-
}
|
|
1377
|
-
styles2.visible = {
|
|
1378
|
-
get() {
|
|
1379
|
-
const builder = createBuilder(this, this[STYLER], true);
|
|
1380
|
-
Object.defineProperty(this, "visible", { value: builder });
|
|
1381
|
-
return builder;
|
|
1382
|
-
}
|
|
1383
|
-
};
|
|
1384
|
-
var getModelAnsi = (model, level, type, ...arguments_) => {
|
|
1385
|
-
if (model === "rgb") {
|
|
1386
|
-
if (level === "ansi16m") {
|
|
1387
|
-
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
1388
|
-
}
|
|
1389
|
-
if (level === "ansi256") {
|
|
1390
|
-
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
1391
|
-
}
|
|
1392
|
-
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
1393
|
-
}
|
|
1394
|
-
if (model === "hex") {
|
|
1395
|
-
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
1396
|
-
}
|
|
1397
|
-
return ansi_styles_default[type][model](...arguments_);
|
|
1398
|
-
};
|
|
1399
|
-
var usedModels = ["rgb", "hex", "ansi256"];
|
|
1400
|
-
for (const model of usedModels) {
|
|
1401
|
-
styles2[model] = {
|
|
1402
|
-
get() {
|
|
1403
|
-
const { level } = this;
|
|
1404
|
-
return function(...arguments_) {
|
|
1405
|
-
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
1406
|
-
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
};
|
|
1410
|
-
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
1411
|
-
styles2[bgModel] = {
|
|
1412
|
-
get() {
|
|
1413
|
-
const { level } = this;
|
|
1414
|
-
return function(...arguments_) {
|
|
1415
|
-
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
1416
|
-
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
1417
|
-
};
|
|
1418
|
-
}
|
|
1419
|
-
};
|
|
1420
|
-
}
|
|
1421
|
-
var proto = Object.defineProperties(() => {
|
|
1422
|
-
}, {
|
|
1423
|
-
...styles2,
|
|
1424
|
-
level: {
|
|
1425
|
-
enumerable: true,
|
|
1426
|
-
get() {
|
|
1427
|
-
return this[GENERATOR].level;
|
|
1428
|
-
},
|
|
1429
|
-
set(level) {
|
|
1430
|
-
this[GENERATOR].level = level;
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
});
|
|
1434
|
-
var createStyler = (open3, close, parent) => {
|
|
1435
|
-
let openAll;
|
|
1436
|
-
let closeAll;
|
|
1437
|
-
if (parent === void 0) {
|
|
1438
|
-
openAll = open3;
|
|
1439
|
-
closeAll = close;
|
|
1440
|
-
} else {
|
|
1441
|
-
openAll = parent.openAll + open3;
|
|
1442
|
-
closeAll = close + parent.closeAll;
|
|
1443
|
-
}
|
|
1444
|
-
return {
|
|
1445
|
-
open: open3,
|
|
1446
|
-
close,
|
|
1447
|
-
openAll,
|
|
1448
|
-
closeAll,
|
|
1449
|
-
parent
|
|
1450
|
-
};
|
|
1451
|
-
};
|
|
1452
|
-
var createBuilder = (self, _styler, _isEmpty) => {
|
|
1453
|
-
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
1454
|
-
Object.setPrototypeOf(builder, proto);
|
|
1455
|
-
builder[GENERATOR] = self;
|
|
1456
|
-
builder[STYLER] = _styler;
|
|
1457
|
-
builder[IS_EMPTY] = _isEmpty;
|
|
1458
|
-
return builder;
|
|
1459
|
-
};
|
|
1460
|
-
var applyStyle = (self, string) => {
|
|
1461
|
-
if (self.level <= 0 || !string) {
|
|
1462
|
-
return self[IS_EMPTY] ? "" : string;
|
|
1463
|
-
}
|
|
1464
|
-
let styler = self[STYLER];
|
|
1465
|
-
if (styler === void 0) {
|
|
1466
|
-
return string;
|
|
1467
|
-
}
|
|
1468
|
-
const { openAll, closeAll } = styler;
|
|
1469
|
-
if (string.includes("\x1B")) {
|
|
1470
|
-
while (styler !== void 0) {
|
|
1471
|
-
string = stringReplaceAll(string, styler.close, styler.open);
|
|
1472
|
-
styler = styler.parent;
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
const lfIndex = string.indexOf("\n");
|
|
1476
|
-
if (lfIndex !== -1) {
|
|
1477
|
-
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
1478
|
-
}
|
|
1479
|
-
return openAll + string + closeAll;
|
|
1480
|
-
};
|
|
1481
|
-
Object.defineProperties(createChalk.prototype, styles2);
|
|
1482
|
-
var chalk = createChalk();
|
|
1483
|
-
createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
1484
|
-
var source_default = chalk;
|
|
1485
|
-
|
|
1486
|
-
// packages/core/src/terminal.ts
|
|
1487
|
-
var TERMINAL_INDENT = " ";
|
|
1488
|
-
var MAX_TERMINAL_NAME_LENGTH = 80;
|
|
1489
|
-
var MAX_TERMINAL_DEPTH = 10;
|
|
1490
|
-
function normalizeDepth(depth) {
|
|
1491
|
-
if (!Number.isFinite(depth) || depth < 0) {
|
|
1492
|
-
return 0;
|
|
1493
|
-
}
|
|
1494
|
-
return Math.min(Math.floor(depth), MAX_TERMINAL_DEPTH);
|
|
1495
|
-
}
|
|
1496
|
-
function getIndent(depth) {
|
|
1497
|
-
return TERMINAL_INDENT.repeat(normalizeDepth(depth));
|
|
1498
|
-
}
|
|
1499
|
-
function formatTerminalName(name) {
|
|
1500
|
-
if (typeof name !== "string" || name.trim() === "") {
|
|
1501
|
-
return "unnamed";
|
|
1502
|
-
}
|
|
1503
|
-
return truncateName(name, MAX_TERMINAL_NAME_LENGTH);
|
|
1504
|
-
}
|
|
1505
|
-
function getStatusIcon(status) {
|
|
1506
|
-
if (status === "success") return source_default.green("\u2714");
|
|
1507
|
-
if (status === "error") return source_default.red("\u2716");
|
|
1508
|
-
return source_default.yellow("\u23F3");
|
|
1509
|
-
}
|
|
1510
|
-
function renderStepLine(name, durationMs2, status, depth) {
|
|
1511
|
-
try {
|
|
1512
|
-
const nm = formatTerminalName(name);
|
|
1513
|
-
const ind = getIndent(depth ?? 0);
|
|
1514
|
-
if (status === "running" && durationMs2 === void 0) {
|
|
1515
|
-
return `${ind}${source_default.yellow("\u23F3")} ${nm}`;
|
|
1516
|
-
}
|
|
1517
|
-
const hasDur = durationMs2 !== void 0 && Number.isFinite(durationMs2);
|
|
1518
|
-
const dur = hasDur ? formatDuration2(durationMs2) : void 0;
|
|
1519
|
-
if (status === "running") {
|
|
1520
|
-
return dur !== void 0 ? `${ind}${source_default.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${source_default.yellow("\u23F3")} ${nm}`;
|
|
1521
|
-
}
|
|
1522
|
-
if (!hasDur || dur === void 0) {
|
|
1523
|
-
return `${ind}${source_default.yellow("\u23F3")} ${nm}`;
|
|
1524
|
-
}
|
|
1525
|
-
if (status === "success") {
|
|
1526
|
-
return `${ind}${getStatusIcon("success")} ${nm} (${dur})`;
|
|
1527
|
-
}
|
|
1528
|
-
return `${ind}${getStatusIcon("error")} ${nm} (${dur})`;
|
|
1529
|
-
} catch {
|
|
1530
|
-
return "";
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
function renderErrorLine(error, depth) {
|
|
1534
|
-
try {
|
|
1535
|
-
const msg = typeof error.message === "string" ? error.message : "";
|
|
1536
|
-
const ind = getIndent((depth ?? 0) + 1);
|
|
1537
|
-
return `${ind}Error: ${msg}`;
|
|
1538
|
-
} catch {
|
|
1539
|
-
return "";
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
function resolveTraceDir(options = {}) {
|
|
1543
|
-
if (typeof options.dir === "string" && options.dir.trim() !== "") {
|
|
1544
|
-
return options.dir.trim();
|
|
1545
|
-
}
|
|
1546
|
-
const envDir = process.env.AGENT_INSPECT_TRACE_DIR;
|
|
1547
|
-
if (typeof envDir === "string" && envDir.trim() !== "") {
|
|
1548
|
-
return envDir.trim();
|
|
1549
|
-
}
|
|
1550
|
-
return getDefaultTraceDir();
|
|
1551
|
-
}
|
|
1552
|
-
var TraceDirectory = class {
|
|
1553
|
-
#dir;
|
|
1554
|
-
constructor(options = {}) {
|
|
1555
|
-
this.#dir = resolveTraceDir(options);
|
|
1556
|
-
}
|
|
1557
|
-
getPath(filename) {
|
|
1558
|
-
return filename ? path14.join(this.#dir, filename) : this.#dir;
|
|
1559
|
-
}
|
|
1560
|
-
async list() {
|
|
1561
|
-
try {
|
|
1562
|
-
const files = await readdir(this.#dir);
|
|
1563
|
-
return files.filter((f) => f.endsWith(".jsonl"));
|
|
1564
|
-
} catch (e) {
|
|
1565
|
-
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
1566
|
-
return [];
|
|
1567
|
-
}
|
|
1568
|
-
throw e;
|
|
1569
|
-
}
|
|
1570
|
-
}
|
|
1571
|
-
async getFileStats(filename) {
|
|
1572
|
-
return await stat(this.getPath(filename));
|
|
1573
|
-
}
|
|
1574
|
-
};
|
|
1575
|
-
function isFiniteNumber(v) {
|
|
1576
|
-
return typeof v === "number" && Number.isFinite(v);
|
|
1577
|
-
}
|
|
1578
|
-
function parseIsoToMs2(value) {
|
|
1579
|
-
if (value === void 0) return void 0;
|
|
1580
|
-
const parsed = Date.parse(value);
|
|
1581
|
-
return Number.isFinite(parsed) ? parsed : void 0;
|
|
1582
|
-
}
|
|
1583
|
-
async function extractMetadata(filePath, _quickScan) {
|
|
1584
|
-
const stats = await stat(filePath);
|
|
1585
|
-
let runIdFromFile = path14.basename(filePath);
|
|
1586
|
-
if (runIdFromFile.endsWith(".jsonl")) {
|
|
1587
|
-
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
1588
|
-
}
|
|
1589
|
-
const raw = await readFile(filePath, "utf-8");
|
|
1590
|
-
const parsedTrace = parseTraceJsonl(raw, { warnings: false });
|
|
1591
|
-
let runId;
|
|
1592
|
-
let name;
|
|
1593
|
-
let startedAt;
|
|
1594
|
-
let endedAt;
|
|
1595
|
-
let explicitDurationMs;
|
|
1596
|
-
let hasRunStarted = false;
|
|
1597
|
-
let hasRunCompleted = false;
|
|
1598
|
-
let runCompletedStatus;
|
|
1599
|
-
let anyStepError = false;
|
|
1600
|
-
const anyKnownEvent = parsedTrace.sourceEventCount > 0;
|
|
1601
|
-
let persistedStatus;
|
|
1602
|
-
const persistedRun = parsedTrace.persisted.find(
|
|
1603
|
-
(event) => event.kind === "RUN"
|
|
1604
|
-
);
|
|
1605
|
-
if (persistedRun) {
|
|
1606
|
-
runId = persistedRun.runId;
|
|
1607
|
-
if (persistedRun.name.trim() !== "") {
|
|
1608
|
-
name = persistedRun.name;
|
|
1609
|
-
}
|
|
1610
|
-
startedAt = parseIsoToMs2(persistedRun.startedAt) ?? parseIsoToMs2(persistedRun.timestamp);
|
|
1611
|
-
endedAt = parseIsoToMs2(persistedRun.endedAt);
|
|
1612
|
-
if (isFiniteNumber(persistedRun.durationMs)) {
|
|
1613
|
-
explicitDurationMs = persistedRun.durationMs;
|
|
1614
|
-
if (endedAt === void 0 && startedAt !== void 0) {
|
|
1615
|
-
endedAt = startedAt + persistedRun.durationMs;
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
if (persistedRun.status === "ok") persistedStatus = "success";
|
|
1619
|
-
else if (persistedRun.status === "error") persistedStatus = "error";
|
|
1620
|
-
else if (persistedRun.status === "running") persistedStatus = "running";
|
|
1621
|
-
else if (persistedRun.status === "unknown") persistedStatus = "unknown";
|
|
1622
|
-
} else {
|
|
1623
|
-
runId = parsedTrace.persisted[0]?.runId;
|
|
1624
|
-
}
|
|
1625
|
-
for (const e of parsedTrace.events) {
|
|
1626
|
-
if (runId === void 0 && typeof e.runId === "string") {
|
|
1627
|
-
runId = e.runId;
|
|
1628
|
-
}
|
|
1629
|
-
if (e.event === "run_started") {
|
|
1630
|
-
hasRunStarted = true;
|
|
1631
|
-
const rs = e;
|
|
1632
|
-
if (typeof rs.name === "string" && rs.name.trim() !== "") {
|
|
1633
|
-
name = rs.name;
|
|
1634
|
-
}
|
|
1635
|
-
if (isFiniteNumber(rs.startTime)) {
|
|
1636
|
-
startedAt = rs.startTime;
|
|
1637
|
-
} else if (isFiniteNumber(rs.timestamp)) {
|
|
1638
|
-
startedAt = rs.timestamp;
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
if (e.event === "run_completed") {
|
|
1642
|
-
hasRunCompleted = true;
|
|
1643
|
-
const rc = e;
|
|
1644
|
-
runCompletedStatus = rc.status;
|
|
1645
|
-
if (isFiniteNumber(rc.endTime)) endedAt = rc.endTime;
|
|
1646
|
-
else if (isFiniteNumber(rc.timestamp)) endedAt = rc.timestamp;
|
|
1647
|
-
if (isFiniteNumber(rc.durationMs)) explicitDurationMs = rc.durationMs;
|
|
1648
|
-
}
|
|
1649
|
-
if (e.event === "step_completed") {
|
|
1650
|
-
const sc = e;
|
|
1651
|
-
if (sc.status === "error") {
|
|
1652
|
-
anyStepError = true;
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
const resolvedRunId = runId ?? runIdFromFile;
|
|
1657
|
-
let status = "unknown";
|
|
1658
|
-
if (hasRunCompleted && (runCompletedStatus === "success" || runCompletedStatus === "error")) {
|
|
1659
|
-
status = runCompletedStatus;
|
|
1660
|
-
} else if (anyStepError) {
|
|
1661
|
-
status = "error";
|
|
1662
|
-
} else if (persistedStatus !== void 0) {
|
|
1663
|
-
status = persistedStatus;
|
|
1664
|
-
} else if (hasRunStarted && !hasRunCompleted) {
|
|
1665
|
-
status = "running";
|
|
1666
|
-
} else if (anyKnownEvent) {
|
|
1667
|
-
status = "unknown";
|
|
1668
|
-
} else {
|
|
1669
|
-
status = "unknown";
|
|
1670
|
-
}
|
|
1671
|
-
const durationMs2 = explicitDurationMs ?? (startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt ? endedAt - startedAt : void 0);
|
|
1672
|
-
return {
|
|
1673
|
-
runId: resolvedRunId,
|
|
1674
|
-
name,
|
|
1675
|
-
status,
|
|
1676
|
-
startedAt,
|
|
1677
|
-
endedAt,
|
|
1678
|
-
durationMs: durationMs2,
|
|
1679
|
-
eventCount: parsedTrace.sourceEventCount,
|
|
1680
|
-
filePath,
|
|
1681
|
-
fileSize: stats.size,
|
|
1682
|
-
createdAt: stats.birthtime
|
|
1683
|
-
};
|
|
1684
|
-
}
|
|
1685
|
-
function isNonNegativeFiniteNumber(value) {
|
|
1686
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
1687
|
-
}
|
|
1688
|
-
function buildRunSummary(events) {
|
|
1689
|
-
const started = events.find(
|
|
1690
|
-
(e) => e.event === "run_started"
|
|
1691
|
-
);
|
|
1692
|
-
const completed = events.filter(
|
|
1693
|
-
(e) => e.event === "run_completed"
|
|
1694
|
-
);
|
|
1695
|
-
const lastCompleted = completed[completed.length - 1];
|
|
1696
|
-
const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
|
|
1697
|
-
const name = typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0;
|
|
1698
|
-
const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
|
|
1699
|
-
const durationMs2 = lastCompleted && isFiniteNumber(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
1700
|
-
started && isFiniteNumber(started.startTime) ? started.startTime : void 0;
|
|
1701
|
-
const steps = /* @__PURE__ */ new Map();
|
|
1702
|
-
for (const e of events) {
|
|
1703
|
-
if (e.event === "step_started") {
|
|
1704
|
-
const s = e;
|
|
1705
|
-
steps.set(s.stepId, {
|
|
1706
|
-
type: s.type,
|
|
1707
|
-
name: s.name,
|
|
1708
|
-
status: "running",
|
|
1709
|
-
parentId: s.parentId,
|
|
1710
|
-
tokensInput: isNonNegativeFiniteNumber(s.metadata?.tokens?.input) ? s.metadata.tokens.input : void 0,
|
|
1711
|
-
tokensOutput: isNonNegativeFiniteNumber(s.metadata?.tokens?.output) ? s.metadata.tokens.output : void 0,
|
|
1712
|
-
tokensTotal: isNonNegativeFiniteNumber(s.metadata?.tokens?.total) ? s.metadata.tokens.total : void 0,
|
|
1713
|
-
tokensCached: isNonNegativeFiniteNumber(s.metadata?.tokens?.cached) ? s.metadata.tokens.cached : void 0
|
|
1714
|
-
});
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
for (const e of events) {
|
|
1718
|
-
if (e.event === "step_completed") {
|
|
1719
|
-
const c = e;
|
|
1720
|
-
const existing = steps.get(c.stepId);
|
|
1721
|
-
if (!existing) continue;
|
|
1722
|
-
existing.status = c.status;
|
|
1723
|
-
existing.durationMs = c.durationMs;
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1726
|
-
let totalSteps = 0;
|
|
1727
|
-
let llmSteps = 0;
|
|
1728
|
-
let toolSteps = 0;
|
|
1729
|
-
let logicSteps = 0;
|
|
1730
|
-
let errorSteps = 0;
|
|
1731
|
-
let maxDepth = 0;
|
|
1732
|
-
let longestStep;
|
|
1733
|
-
let totalTokensInput = 0;
|
|
1734
|
-
let totalTokensOutput = 0;
|
|
1735
|
-
let totalTokensTotal = 0;
|
|
1736
|
-
let totalTokensCached = 0;
|
|
1737
|
-
let tokenBearingSteps = 0;
|
|
1738
|
-
let stepsWithKnownTotal = 0;
|
|
1739
|
-
let hasCachedTokens = false;
|
|
1740
|
-
const depthCache = /* @__PURE__ */ new Map();
|
|
1741
|
-
const computeDepth = (stepId) => {
|
|
1742
|
-
const cached = depthCache.get(stepId);
|
|
1743
|
-
if (cached !== void 0) return cached;
|
|
1744
|
-
const node = steps.get(stepId);
|
|
1745
|
-
if (!node) return 0;
|
|
1746
|
-
const parent = node.parentId;
|
|
1747
|
-
if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
|
|
1748
|
-
depthCache.set(stepId, 0);
|
|
1749
|
-
return 0;
|
|
1750
|
-
}
|
|
1751
|
-
const d = Math.min(1e3, computeDepth(parent) + 1);
|
|
1752
|
-
depthCache.set(stepId, d);
|
|
1753
|
-
return d;
|
|
1754
|
-
};
|
|
1755
|
-
for (const [id, s] of steps.entries()) {
|
|
1756
|
-
totalSteps += 1;
|
|
1757
|
-
if (s.type === "llm") llmSteps += 1;
|
|
1758
|
-
else if (s.type === "tool") toolSteps += 1;
|
|
1759
|
-
else logicSteps += 1;
|
|
1760
|
-
if (s.status === "error") errorSteps += 1;
|
|
1761
|
-
const depth = computeDepth(id);
|
|
1762
|
-
if (depth > maxDepth) maxDepth = depth;
|
|
1763
|
-
if (typeof s.durationMs === "number" && Number.isFinite(s.durationMs)) {
|
|
1764
|
-
if (!longestStep || s.durationMs > longestStep.durationMs) {
|
|
1765
|
-
longestStep = { name: s.name, durationMs: s.durationMs, type: s.type };
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
if (s.tokensInput !== void 0 || s.tokensOutput !== void 0 || s.tokensTotal !== void 0 || s.tokensCached !== void 0) {
|
|
1769
|
-
tokenBearingSteps += 1;
|
|
1770
|
-
if (s.tokensInput !== void 0) totalTokensInput += s.tokensInput;
|
|
1771
|
-
if (s.tokensOutput !== void 0) totalTokensOutput += s.tokensOutput;
|
|
1772
|
-
if (s.tokensTotal !== void 0) {
|
|
1773
|
-
totalTokensTotal += s.tokensTotal;
|
|
1774
|
-
stepsWithKnownTotal += 1;
|
|
1775
|
-
} else if (s.tokensInput !== void 0 && s.tokensOutput !== void 0) {
|
|
1776
|
-
totalTokensTotal += s.tokensInput + s.tokensOutput;
|
|
1777
|
-
stepsWithKnownTotal += 1;
|
|
1778
|
-
}
|
|
1779
|
-
if (s.tokensCached !== void 0) {
|
|
1780
|
-
totalTokensCached += s.tokensCached;
|
|
1781
|
-
hasCachedTokens = true;
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
|
-
}
|
|
1785
|
-
const summary = {
|
|
1786
|
-
runId,
|
|
1787
|
-
name,
|
|
1788
|
-
status,
|
|
1789
|
-
durationMs: durationMs2,
|
|
1790
|
-
totalSteps,
|
|
1791
|
-
llmSteps,
|
|
1792
|
-
toolSteps,
|
|
1793
|
-
logicSteps,
|
|
1794
|
-
errorSteps,
|
|
1795
|
-
maxDepth,
|
|
1796
|
-
...longestStep ? { longestStep } : {},
|
|
1797
|
-
...tokenBearingSteps > 0 ? {
|
|
1798
|
-
totalTokens: {
|
|
1799
|
-
input: totalTokensInput,
|
|
1800
|
-
output: totalTokensOutput,
|
|
1801
|
-
...stepsWithKnownTotal === tokenBearingSteps ? { total: totalTokensTotal } : {},
|
|
1802
|
-
...hasCachedTokens ? { cached: totalTokensCached } : {}
|
|
1803
|
-
}
|
|
1804
|
-
} : {}
|
|
1805
|
-
};
|
|
1806
|
-
return summary;
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
// packages/core/src/trace-filter.ts
|
|
1810
|
-
function toLower(s) {
|
|
1811
|
-
return typeof s === "string" ? s.toLowerCase() : "";
|
|
1812
|
-
}
|
|
1813
|
-
function filterTraces(traces, options) {
|
|
1814
|
-
const input3 = [...traces];
|
|
1815
|
-
let out = input3.filter((t) => {
|
|
1816
|
-
if (options.status && t.status !== options.status) return false;
|
|
1817
|
-
if (options.name) {
|
|
1818
|
-
const q = options.name.toLowerCase();
|
|
1819
|
-
const hay = `${toLower(t.name)} ${toLower(t.runId)}`;
|
|
1820
|
-
if (!hay.includes(q)) return false;
|
|
1821
|
-
}
|
|
1822
|
-
if (options.since) {
|
|
1823
|
-
const windowMs = parseDuration(options.since);
|
|
1824
|
-
const cutoff = Date.now() - windowMs;
|
|
1825
|
-
const started = typeof t.startedAt === "number" ? t.startedAt : void 0;
|
|
1826
|
-
const basis = started ?? t.createdAt.getTime();
|
|
1827
|
-
if (!Number.isFinite(basis) || basis < cutoff) return false;
|
|
1828
|
-
}
|
|
1829
|
-
return true;
|
|
1830
|
-
});
|
|
1831
|
-
out.sort((a, b) => {
|
|
1832
|
-
const aTime = (typeof a.startedAt === "number" ? a.startedAt : void 0) ?? a.createdAt.getTime();
|
|
1833
|
-
const bTime = (typeof b.startedAt === "number" ? b.startedAt : void 0) ?? b.createdAt.getTime();
|
|
1834
|
-
return bTime - aTime;
|
|
1835
|
-
});
|
|
1836
|
-
if (typeof options.limit === "number" && Number.isFinite(options.limit)) {
|
|
1837
|
-
const n = Math.max(0, Math.floor(options.limit));
|
|
1838
|
-
out = out.slice(0, n);
|
|
1839
|
-
}
|
|
1840
|
-
return out;
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
// packages/core/src/timeline.ts
|
|
1844
|
-
function finite(n) {
|
|
1845
|
-
return typeof n === "number" && Number.isFinite(n);
|
|
1846
|
-
}
|
|
1847
|
-
function pickStreamingMeta(metadata) {
|
|
1848
|
-
if (!metadata || typeof metadata !== "object") return void 0;
|
|
1849
|
-
const chunkCount = metadata.chunkCount;
|
|
1850
|
-
const streamDurationMs = metadata.streamDurationMs;
|
|
1851
|
-
const streamedCharCount = metadata.streamedCharCount;
|
|
1852
|
-
if (!finite(chunkCount) && !finite(streamDurationMs) && !finite(streamedCharCount)) {
|
|
1853
|
-
return void 0;
|
|
1854
|
-
}
|
|
1855
|
-
return {
|
|
1856
|
-
...finite(chunkCount) ? { chunkCount } : {},
|
|
1857
|
-
...finite(streamDurationMs) ? { streamDurationMs } : {},
|
|
1858
|
-
...finite(streamedCharCount) ? { streamedCharCount } : {}
|
|
1859
|
-
};
|
|
1860
|
-
}
|
|
1861
|
-
function pickCorrelation(metadata) {
|
|
1862
|
-
if (!metadata || typeof metadata !== "object") return void 0;
|
|
1863
|
-
const out = {};
|
|
1864
|
-
for (const key of [
|
|
1865
|
-
"correlationId",
|
|
1866
|
-
"requestId",
|
|
1867
|
-
"decisionId",
|
|
1868
|
-
"groupId"
|
|
1869
|
-
]) {
|
|
1870
|
-
const v = metadata[key];
|
|
1871
|
-
if (typeof v === "string" && v.trim() !== "") {
|
|
1872
|
-
out[key] = v;
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
return Object.keys(out).length > 0 ? out : void 0;
|
|
1876
|
-
}
|
|
1877
|
-
function buildRunTimeline(events, options = {}) {
|
|
1878
|
-
const started = events.find(
|
|
1879
|
-
(e) => e.event === "run_started"
|
|
1880
|
-
);
|
|
1881
|
-
const completed = events.filter(
|
|
1882
|
-
(e) => e.event === "run_completed"
|
|
1883
|
-
);
|
|
1884
|
-
const lastCompleted = completed[completed.length - 1];
|
|
1885
|
-
const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
|
|
1886
|
-
const runStart = started && finite(started.startTime) ? started.startTime : started && finite(started.timestamp) ? started.timestamp : void 0;
|
|
1887
|
-
const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
|
|
1888
|
-
const steps = /* @__PURE__ */ new Map();
|
|
1889
|
-
for (const e of events) {
|
|
1890
|
-
if (e.event === "step_started") {
|
|
1891
|
-
const s = e;
|
|
1892
|
-
steps.set(s.stepId, {
|
|
1893
|
-
name: s.name,
|
|
1894
|
-
type: s.type,
|
|
1895
|
-
parentId: s.parentId,
|
|
1896
|
-
startedAt: finite(s.startTime) ? s.startTime : s.timestamp,
|
|
1897
|
-
status: "running",
|
|
1898
|
-
metadata: s.metadata
|
|
1899
|
-
});
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
for (const e of events) {
|
|
1903
|
-
if (e.event !== "step_completed") continue;
|
|
1904
|
-
const c = e;
|
|
1905
|
-
const node = steps.get(c.stepId);
|
|
1906
|
-
if (!node) continue;
|
|
1907
|
-
node.status = c.status;
|
|
1908
|
-
if (finite(c.durationMs)) node.durationMs = c.durationMs;
|
|
1909
|
-
}
|
|
1910
|
-
const depthCache = /* @__PURE__ */ new Map();
|
|
1911
|
-
const computeDepth = (stepId) => {
|
|
1912
|
-
const cached = depthCache.get(stepId);
|
|
1913
|
-
if (cached !== void 0) return cached;
|
|
1914
|
-
const node = steps.get(stepId);
|
|
1915
|
-
if (!node) return 0;
|
|
1916
|
-
const parent = node.parentId;
|
|
1917
|
-
if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
|
|
1918
|
-
depthCache.set(stepId, 0);
|
|
1919
|
-
return 0;
|
|
1920
|
-
}
|
|
1921
|
-
const d = Math.min(1e3, computeDepth(parent) + 1);
|
|
1922
|
-
depthCache.set(stepId, d);
|
|
1923
|
-
return d;
|
|
1924
|
-
};
|
|
1925
|
-
const entries = [];
|
|
1926
|
-
for (const [stepId, s] of steps.entries()) {
|
|
1927
|
-
const offsetMs = runStart !== void 0 && finite(s.startedAt) ? Math.max(0, s.startedAt - runStart) : 0;
|
|
1928
|
-
entries.push({
|
|
1929
|
-
stepId,
|
|
1930
|
-
name: s.name,
|
|
1931
|
-
type: s.type,
|
|
1932
|
-
status: s.status,
|
|
1933
|
-
depth: computeDepth(stepId),
|
|
1934
|
-
startedAt: s.startedAt,
|
|
1935
|
-
offsetMs,
|
|
1936
|
-
durationMs: s.durationMs,
|
|
1937
|
-
isError: s.status === "error",
|
|
1938
|
-
streaming: pickStreamingMeta(s.metadata)
|
|
1939
|
-
});
|
|
1940
|
-
}
|
|
1941
|
-
entries.sort((a, b) => a.startedAt - b.startedAt);
|
|
1942
|
-
const slowTopN = options.slowTopN ?? 3;
|
|
1943
|
-
if (options.focus === "slow" && entries.length > 0) {
|
|
1944
|
-
const ranked = [...entries].filter((e) => finite(e.durationMs)).sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
|
|
1945
|
-
const slowIds = new Set(
|
|
1946
|
-
ranked.slice(0, slowTopN).map((e) => e.stepId)
|
|
1947
|
-
);
|
|
1948
|
-
for (const e of entries) {
|
|
1949
|
-
if (slowIds.has(e.stepId)) e.slow = true;
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
return {
|
|
1953
|
-
runId,
|
|
1954
|
-
name: typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0,
|
|
1955
|
-
status,
|
|
1956
|
-
startedAt: runStart,
|
|
1957
|
-
endedAt: lastCompleted && finite(lastCompleted.endTime) ? lastCompleted.endTime : void 0,
|
|
1958
|
-
durationMs: lastCompleted && finite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0,
|
|
1959
|
-
correlation: pickCorrelation(
|
|
1960
|
-
started?.metadata
|
|
1961
|
-
),
|
|
1962
|
-
entries
|
|
1963
|
-
};
|
|
1964
|
-
}
|
|
1965
|
-
function renderTimeline(timeline, options = {}) {
|
|
1966
|
-
const lines = [];
|
|
1967
|
-
lines.push(`Timeline: ${timeline.name ?? timeline.runId}`);
|
|
1968
|
-
lines.push(`Run ID: ${timeline.runId}`);
|
|
1969
|
-
lines.push(`Status: ${timeline.status}`);
|
|
1970
|
-
if (timeline.startedAt !== void 0) {
|
|
1971
|
-
lines.push(`Started: ${formatTimestamp(timeline.startedAt)}`);
|
|
1972
|
-
}
|
|
1973
|
-
if (timeline.durationMs !== void 0) {
|
|
1974
|
-
lines.push(`Duration: ${formatDuration2(timeline.durationMs)}`);
|
|
1975
|
-
}
|
|
1976
|
-
if (timeline.correlation) {
|
|
1977
|
-
const parts = Object.entries(timeline.correlation).filter(([, v]) => typeof v === "string").map(([k, v]) => `${k}=${v}`);
|
|
1978
|
-
if (parts.length > 0) {
|
|
1979
|
-
lines.push(`Correlation: ${parts.join(", ")}`);
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
lines.push("");
|
|
1983
|
-
lines.push("Steps (chronological):");
|
|
1984
|
-
const show = timeline.entries.filter((e) => {
|
|
1985
|
-
if (options.focus === "slow") return e.slow === true;
|
|
1986
|
-
return true;
|
|
1987
|
-
});
|
|
1988
|
-
if (show.length === 0) {
|
|
1989
|
-
lines.push(
|
|
1990
|
-
options.focus === "slow" ? "(no steps with duration for slow focus)" : "(no steps)"
|
|
1991
|
-
);
|
|
1992
|
-
return lines.join("\n");
|
|
1993
|
-
}
|
|
1994
|
-
for (const e of show) {
|
|
1995
|
-
const prefix = e.slow ? "[slow] " : "";
|
|
1996
|
-
const typeTag = e.type === "llm" ? "llm" : e.type === "tool" ? "tool" : e.type;
|
|
1997
|
-
const dur = e.durationMs !== void 0 ? formatDuration2(e.durationMs) : "-";
|
|
1998
|
-
const err = e.isError ? " error" : "";
|
|
1999
|
-
const off = formatDuration2(e.offsetMs);
|
|
2000
|
-
let line = `${prefix}+${off} ${typeTag}:${e.name} (${dur})${err}`;
|
|
2001
|
-
if (e.streaming?.chunkCount !== void 0) {
|
|
2002
|
-
line += ` chunks=${e.streaming.chunkCount}`;
|
|
2003
|
-
}
|
|
2004
|
-
if (e.streaming?.streamDurationMs !== void 0) {
|
|
2005
|
-
line += ` stream=${formatDuration2(e.streaming.streamDurationMs)}`;
|
|
2006
|
-
}
|
|
2007
|
-
lines.push(line);
|
|
2008
|
-
}
|
|
2009
|
-
return lines.join("\n");
|
|
2010
|
-
}
|
|
2011
|
-
|
|
2012
|
-
// packages/core/src/what.ts
|
|
2013
|
-
function pickCorrelation2(metadata) {
|
|
2014
|
-
if (!metadata) return void 0;
|
|
2015
|
-
const out = {};
|
|
2016
|
-
for (const key of [
|
|
2017
|
-
"correlationId",
|
|
2018
|
-
"requestId",
|
|
2019
|
-
"decisionId",
|
|
2020
|
-
"groupId"
|
|
2021
|
-
]) {
|
|
2022
|
-
const value = metadata[key];
|
|
2023
|
-
if (typeof value === "string" && value.trim() !== "") {
|
|
2024
|
-
out[key] = value;
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
|
-
return Object.keys(out).length > 0 ? out : void 0;
|
|
2028
|
-
}
|
|
2029
|
-
function stepMixLine(summary) {
|
|
2030
|
-
const parts = [];
|
|
2031
|
-
if (summary.llmSteps > 0) parts.push(`${summary.llmSteps} LLM`);
|
|
2032
|
-
if (summary.toolSteps > 0) parts.push(`${summary.toolSteps} tool`);
|
|
2033
|
-
if (summary.logicSteps > 0) parts.push(`${summary.logicSteps} logic`);
|
|
2034
|
-
return parts.length > 0 ? parts.join(", ") : "none";
|
|
2035
|
-
}
|
|
2036
|
-
function outcomeLine(summary) {
|
|
2037
|
-
if (summary.status === "success") {
|
|
2038
|
-
return summary.errorSteps > 0 ? "Completed with step errors recorded." : "Completed successfully.";
|
|
2039
|
-
}
|
|
2040
|
-
if (summary.status === "error") {
|
|
2041
|
-
if (summary.failedStepNames.length > 0) {
|
|
2042
|
-
const names = summary.failedStepNames.slice(0, 3).join(", ");
|
|
2043
|
-
const suffix = summary.failedStepNames.length > 3 ? ` (+${summary.failedStepNames.length - 3} more)` : "";
|
|
2044
|
-
return `Failed at step(s): ${names}${suffix}.`;
|
|
2045
|
-
}
|
|
2046
|
-
if (summary.runErrorMessage) {
|
|
2047
|
-
return `Run failed: ${summary.runErrorMessage}`;
|
|
2048
|
-
}
|
|
2049
|
-
return "Run failed.";
|
|
2050
|
-
}
|
|
2051
|
-
if (summary.status === "running") {
|
|
2052
|
-
return "Run is still in progress (no run_completed).";
|
|
2053
|
-
}
|
|
2054
|
-
return "Outcome unknown \u2014 inspect events may be incomplete.";
|
|
2055
|
-
}
|
|
2056
|
-
function buildRunWhatSummary(events) {
|
|
2057
|
-
const base = buildRunSummary(events);
|
|
2058
|
-
const started = events.find(
|
|
2059
|
-
(e) => e.event === "run_started"
|
|
2060
|
-
);
|
|
2061
|
-
const completed = events.filter(
|
|
2062
|
-
(e) => e.event === "run_completed"
|
|
2063
|
-
);
|
|
2064
|
-
const lastCompleted = completed[completed.length - 1];
|
|
2065
|
-
const failedStepNames = [];
|
|
2066
|
-
const stepNames = /* @__PURE__ */ new Map();
|
|
2067
|
-
for (const e of events) {
|
|
2068
|
-
if (e.event === "step_started") {
|
|
2069
|
-
const s = e;
|
|
2070
|
-
stepNames.set(s.stepId, s.name);
|
|
2071
|
-
}
|
|
2072
|
-
}
|
|
2073
|
-
for (const e of events) {
|
|
2074
|
-
if (e.event === "step_completed") {
|
|
2075
|
-
const sc = e;
|
|
2076
|
-
if (sc.status === "error") {
|
|
2077
|
-
failedStepNames.push(stepNames.get(sc.stepId) ?? sc.stepId);
|
|
2078
|
-
}
|
|
2079
|
-
}
|
|
2080
|
-
}
|
|
2081
|
-
return {
|
|
2082
|
-
runId: base.runId,
|
|
2083
|
-
name: base.name,
|
|
2084
|
-
status: base.status,
|
|
2085
|
-
durationMs: base.durationMs,
|
|
2086
|
-
totalSteps: base.totalSteps,
|
|
2087
|
-
llmSteps: base.llmSteps,
|
|
2088
|
-
toolSteps: base.toolSteps,
|
|
2089
|
-
logicSteps: base.logicSteps,
|
|
2090
|
-
errorSteps: base.errorSteps,
|
|
2091
|
-
maxDepth: base.maxDepth,
|
|
2092
|
-
longestStep: base.longestStep,
|
|
2093
|
-
totalTokens: base.totalTokens,
|
|
2094
|
-
correlation: pickCorrelation2(started?.metadata),
|
|
2095
|
-
failedStepNames,
|
|
2096
|
-
runErrorMessage: lastCompleted?.error?.message
|
|
2097
|
-
};
|
|
2098
|
-
}
|
|
2099
|
-
function renderRunWhat(summary, options = {}) {
|
|
2100
|
-
const showCorrelation = options.correlation !== false;
|
|
2101
|
-
const lines = [];
|
|
2102
|
-
const label = summary.name ?? summary.runId;
|
|
2103
|
-
lines.push(`What: ${label}`);
|
|
2104
|
-
const duration = summary.durationMs !== void 0 ? formatDuration2(summary.durationMs) : "\u2014";
|
|
2105
|
-
lines.push(
|
|
2106
|
-
`Status: ${summary.status} \xB7 Duration: ${duration} \xB7 Steps: ${summary.totalSteps} (${stepMixLine(summary)})`
|
|
2107
|
-
);
|
|
2108
|
-
if (summary.totalTokens) {
|
|
2109
|
-
const tokenParts = [
|
|
2110
|
-
`${summary.totalTokens.input} in`,
|
|
2111
|
-
`${summary.totalTokens.output} out`
|
|
2112
|
-
];
|
|
2113
|
-
if (summary.totalTokens.total !== void 0) {
|
|
2114
|
-
tokenParts.push(`${summary.totalTokens.total} total`);
|
|
2115
|
-
}
|
|
2116
|
-
if (summary.totalTokens.cached !== void 0) {
|
|
2117
|
-
tokenParts.push(`${summary.totalTokens.cached} cached`);
|
|
2118
|
-
}
|
|
2119
|
-
lines.push(`Tokens: ${tokenParts.join(" / ")}`);
|
|
2120
|
-
}
|
|
2121
|
-
if (showCorrelation && summary.correlation) {
|
|
2122
|
-
const parts = [];
|
|
2123
|
-
if (summary.correlation.correlationId) {
|
|
2124
|
-
parts.push(`correlationId=${summary.correlation.correlationId}`);
|
|
2125
|
-
}
|
|
2126
|
-
if (summary.correlation.requestId) {
|
|
2127
|
-
parts.push(`requestId=${summary.correlation.requestId}`);
|
|
2128
|
-
}
|
|
2129
|
-
if (summary.correlation.decisionId) {
|
|
2130
|
-
parts.push(`decisionId=${summary.correlation.decisionId}`);
|
|
2131
|
-
}
|
|
2132
|
-
if (summary.correlation.groupId) {
|
|
2133
|
-
parts.push(`groupId=${summary.correlation.groupId}`);
|
|
2134
|
-
}
|
|
2135
|
-
if (parts.length > 0) {
|
|
2136
|
-
lines.push(`Correlation: ${parts.join(", ")}`);
|
|
2137
|
-
}
|
|
2138
|
-
}
|
|
2139
|
-
lines.push(`Outcome: ${outcomeLine(summary)}`);
|
|
2140
|
-
if (summary.longestStep && summary.totalSteps > 0) {
|
|
2141
|
-
lines.push(
|
|
2142
|
-
`Slowest: ${summary.longestStep.name} (${formatDuration2(summary.longestStep.durationMs)}, ${summary.longestStep.type})`
|
|
2143
|
-
);
|
|
2144
|
-
}
|
|
2145
|
-
if (summary.maxDepth > 0) {
|
|
2146
|
-
lines.push(`Max depth: ${summary.maxDepth}`);
|
|
2147
|
-
}
|
|
2148
|
-
return lines.join("\n");
|
|
2149
|
-
}
|
|
2150
|
-
|
|
2151
|
-
// packages/core/src/explain.ts
|
|
2152
|
-
function flatten(nodes, out = []) {
|
|
2153
|
-
for (const node of nodes) {
|
|
2154
|
-
out.push({ node, index: out.length + 1 });
|
|
2155
|
-
flatten(node.children, out);
|
|
2156
|
-
}
|
|
2157
|
-
return out;
|
|
2158
|
-
}
|
|
2159
|
-
function redactValue(redactor, key, value) {
|
|
2160
|
-
return redactor.redactValue(key, value);
|
|
2161
|
-
}
|
|
2162
|
-
function fact(id, label, value, redactor) {
|
|
2163
|
-
return {
|
|
2164
|
-
id,
|
|
2165
|
-
label,
|
|
2166
|
-
value: redactValue(redactor, id.split(".").at(-1) ?? id, value),
|
|
2167
|
-
source: "trace",
|
|
2168
|
-
confidence: "observed"
|
|
2169
|
-
};
|
|
2170
|
-
}
|
|
2171
|
-
function topKinds(run) {
|
|
2172
|
-
return Object.entries(run.metadata.kinds).filter(([, count]) => count > 0).sort((a, b) => {
|
|
2173
|
-
if (b[1] !== a[1]) return b[1] - a[1];
|
|
2174
|
-
return a[0].localeCompare(b[0]);
|
|
2175
|
-
}).slice(0, 5).map(([kind, count]) => `${kind}:${count}`);
|
|
2176
|
-
}
|
|
2177
|
-
function countErrorNodes(nodes) {
|
|
2178
|
-
return nodes.filter((entry) => entry.node.event.status === "error").length;
|
|
2179
|
-
}
|
|
2180
|
-
function slowestNode(nodes) {
|
|
2181
|
-
return nodes.filter((entry) => entry.node.event.durationMs !== void 0).sort((a, b) => {
|
|
2182
|
-
const delta = (b.node.event.durationMs ?? 0) - (a.node.event.durationMs ?? 0);
|
|
2183
|
-
return delta !== 0 ? delta : a.index - b.index;
|
|
2184
|
-
})[0];
|
|
2185
|
-
}
|
|
2186
|
-
function attributeFacts(nodes, redactor) {
|
|
2187
|
-
const facts = [];
|
|
2188
|
-
for (const entry of nodes) {
|
|
2189
|
-
const attrs = entry.node.event.attributes;
|
|
2190
|
-
if (attrs === void 0) continue;
|
|
2191
|
-
for (const key of Object.keys(attrs).sort()) {
|
|
2192
|
-
facts.push({
|
|
2193
|
-
id: `node.${entry.index}.attributes.${key}`,
|
|
2194
|
-
label: `${entry.node.event.name} attribute ${key}`,
|
|
2195
|
-
value: redactValue(redactor, key, attrs[key]),
|
|
2196
|
-
source: "trace",
|
|
2197
|
-
confidence: "observed"
|
|
2198
|
-
});
|
|
2199
|
-
if (facts.length >= 8) return facts;
|
|
2200
|
-
}
|
|
2201
|
-
}
|
|
2202
|
-
return facts;
|
|
2203
|
-
}
|
|
2204
|
-
function buildFacts(run, redactor) {
|
|
2205
|
-
const nodes = flatten(run.children);
|
|
2206
|
-
const facts = [
|
|
2207
|
-
fact("run.id", "Run id", run.runId, redactor),
|
|
2208
|
-
fact("run.name", "Run name", run.name ?? run.runId, redactor),
|
|
2209
|
-
fact("run.status", "Run status", run.status ?? "unknown", redactor),
|
|
2210
|
-
fact("run.totalEvents", "Total events", run.metadata.totalEvents, redactor),
|
|
2211
|
-
fact("run.stepCount", "Top-level step count", run.children.length, redactor),
|
|
2212
|
-
fact("run.nodeCount", "Total node count", nodes.length, redactor),
|
|
2213
|
-
fact("run.errorNodeCount", "Error node count", countErrorNodes(nodes), redactor),
|
|
2214
|
-
fact("run.kinds", "Observed kind mix", topKinds(run), redactor)
|
|
2215
|
-
];
|
|
2216
|
-
if (run.durationMs !== void 0) {
|
|
2217
|
-
facts.push(fact("run.durationMs", "Run duration milliseconds", run.durationMs, redactor));
|
|
2218
|
-
}
|
|
2219
|
-
const slowest = slowestNode(nodes);
|
|
2220
|
-
if (slowest !== void 0) {
|
|
2221
|
-
facts.push(
|
|
2222
|
-
fact("run.slowestNode", "Slowest observed node", {
|
|
2223
|
-
name: slowest.node.event.name,
|
|
2224
|
-
kind: slowest.node.event.kind,
|
|
2225
|
-
durationMs: slowest.node.event.durationMs
|
|
2226
|
-
}, redactor)
|
|
2227
|
-
);
|
|
2228
|
-
}
|
|
2229
|
-
facts.push(...attributeFacts(nodes, redactor));
|
|
2230
|
-
return facts;
|
|
2231
|
-
}
|
|
2232
|
-
function buildInferences(run, facts) {
|
|
2233
|
-
const inferences = [];
|
|
2234
|
-
const errorFact = facts.find((item) => item.id === "run.errorNodeCount");
|
|
2235
|
-
const kindFact = facts.find((item) => item.id === "run.kinds");
|
|
2236
|
-
const durationFact = facts.find((item) => item.id === "run.durationMs");
|
|
2237
|
-
const errorNodeCount = typeof errorFact?.value === "number" ? errorFact.value : 0;
|
|
2238
|
-
if (run.status === "error" || errorNodeCount > 0) {
|
|
2239
|
-
inferences.push({
|
|
2240
|
-
id: "outcome.error",
|
|
2241
|
-
label: "Outcome",
|
|
2242
|
-
text: "The run recorded an error status or at least one error node.",
|
|
2243
|
-
evidence: ["run.status", "run.errorNodeCount"],
|
|
2244
|
-
confidence: "deterministic"
|
|
2245
|
-
});
|
|
2246
|
-
} else if (run.status === "ok") {
|
|
2247
|
-
inferences.push({
|
|
2248
|
-
id: "outcome.success",
|
|
2249
|
-
label: "Outcome",
|
|
2250
|
-
text: "The run completed without observed error nodes.",
|
|
2251
|
-
evidence: ["run.status", "run.errorNodeCount"],
|
|
2252
|
-
confidence: "deterministic"
|
|
2253
|
-
});
|
|
2254
|
-
}
|
|
2255
|
-
if (kindFact !== void 0) {
|
|
2256
|
-
inferences.push({
|
|
2257
|
-
id: "shape.kind-mix",
|
|
2258
|
-
label: "Trace shape",
|
|
2259
|
-
text: "The explanation is based on the observed event kind mix, not generated content.",
|
|
2260
|
-
evidence: [kindFact.id],
|
|
2261
|
-
confidence: "deterministic"
|
|
2262
|
-
});
|
|
2263
|
-
}
|
|
2264
|
-
if (durationFact !== void 0) {
|
|
2265
|
-
inferences.push({
|
|
2266
|
-
id: "timing.duration",
|
|
2267
|
-
label: "Timing",
|
|
2268
|
-
text: "Timing claims are limited to persisted duration fields in the trace.",
|
|
2269
|
-
evidence: [durationFact.id],
|
|
2270
|
-
confidence: "deterministic"
|
|
2271
|
-
});
|
|
2272
|
-
}
|
|
2273
|
-
return inferences;
|
|
2274
|
-
}
|
|
2275
|
-
function buildLocalExplanation(run, options = {}) {
|
|
2276
|
-
const redactionProfile = options.redactionProfile ?? "local";
|
|
2277
|
-
const resolved = resolveRedactionProfile(redactionProfile);
|
|
2278
|
-
const redactor = new Redactor({ extraKeys: resolved.extraKeys });
|
|
2279
|
-
const mode = options.mode ?? "local";
|
|
2280
|
-
const facts = buildFacts(run, redactor);
|
|
2281
|
-
return {
|
|
2282
|
-
mode,
|
|
2283
|
-
runId: String(redactValue(redactor, "runId", run.runId)),
|
|
2284
|
-
...run.name !== void 0 ? { name: String(redactValue(redactor, "name", run.name)) } : {},
|
|
2285
|
-
...run.status !== void 0 ? { status: run.status } : {},
|
|
2286
|
-
redactionProfile,
|
|
2287
|
-
facts,
|
|
2288
|
-
inferences: mode === "dry-run" ? [] : buildInferences(run, facts),
|
|
2289
|
-
notes: [
|
|
2290
|
-
"Generated locally without provider or network calls.",
|
|
2291
|
-
"Facts are observed from normalized trace data; inferences are deterministic labels."
|
|
2292
|
-
]
|
|
2293
|
-
};
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
|
-
// packages/core/src/stats.ts
|
|
2297
|
-
function percentile(sorted, p) {
|
|
2298
|
-
if (sorted.length === 0) return void 0;
|
|
2299
|
-
const idx = Math.min(
|
|
2300
|
-
sorted.length - 1,
|
|
2301
|
-
Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
|
|
2302
|
-
);
|
|
2303
|
-
return sorted[idx];
|
|
2304
|
-
}
|
|
2305
|
-
async function readRunStartedMetadata(filePath) {
|
|
2306
|
-
try {
|
|
2307
|
-
const events = await readTraceEventsFromFile(filePath);
|
|
2308
|
-
for (const event of events) {
|
|
2309
|
-
if (event.event !== "run_started") continue;
|
|
2310
|
-
const rs = event;
|
|
2311
|
-
if (rs.metadata && typeof rs.metadata === "object") {
|
|
2312
|
-
return rs.metadata;
|
|
2313
|
-
}
|
|
2314
|
-
return void 0;
|
|
2315
|
-
}
|
|
2316
|
-
} catch {
|
|
2317
|
-
}
|
|
2318
|
-
return void 0;
|
|
2319
|
-
}
|
|
2320
|
-
function metaMatchesCorrelation(metadata, correlationId, groupId) {
|
|
2321
|
-
if (correlationId) {
|
|
2322
|
-
const v = metadata?.correlationId;
|
|
2323
|
-
if (typeof v !== "string" || v !== correlationId) return false;
|
|
2324
|
-
}
|
|
2325
|
-
if (groupId) {
|
|
2326
|
-
const v = metadata?.groupId;
|
|
2327
|
-
if (typeof v !== "string" || v !== groupId) return false;
|
|
2328
|
-
}
|
|
2329
|
-
return true;
|
|
2330
|
-
}
|
|
2331
|
-
async function buildTraceStats(metas, options) {
|
|
2332
|
-
let filtered = filterTraces(metas, { since: options.since });
|
|
2333
|
-
if (options.correlationId || options.groupId) {
|
|
2334
|
-
const next = [];
|
|
2335
|
-
for (const m of filtered) {
|
|
2336
|
-
const md = await readRunStartedMetadata(m.filePath);
|
|
2337
|
-
if (metaMatchesCorrelation(md, options.correlationId, options.groupId)) {
|
|
2338
|
-
next.push(m);
|
|
2339
|
-
}
|
|
2340
|
-
}
|
|
2341
|
-
filtered = next;
|
|
2342
|
-
}
|
|
2343
|
-
let successCount = 0;
|
|
2344
|
-
let errorCount = 0;
|
|
2345
|
-
let runningCount = 0;
|
|
2346
|
-
let unknownCount = 0;
|
|
2347
|
-
const durations = [];
|
|
2348
|
-
let totalSteps = 0;
|
|
2349
|
-
let totalLlmSteps = 0;
|
|
2350
|
-
let totalToolSteps = 0;
|
|
2351
|
-
let totalErrorSteps = 0;
|
|
2352
|
-
const slowestRuns = [];
|
|
2353
|
-
const slowestSteps = [];
|
|
2354
|
-
for (const m of filtered) {
|
|
2355
|
-
if (m.status === "success") successCount += 1;
|
|
2356
|
-
else if (m.status === "error") errorCount += 1;
|
|
2357
|
-
else if (m.status === "running") runningCount += 1;
|
|
2358
|
-
else unknownCount += 1;
|
|
2359
|
-
if (typeof m.durationMs === "number" && Number.isFinite(m.durationMs) && m.durationMs >= 0) {
|
|
2360
|
-
durations.push(m.durationMs);
|
|
2361
|
-
slowestRuns.push({
|
|
2362
|
-
runId: m.runId,
|
|
2363
|
-
name: m.name,
|
|
2364
|
-
durationMs: m.durationMs,
|
|
2365
|
-
status: m.status
|
|
2366
|
-
});
|
|
2367
|
-
}
|
|
2368
|
-
try {
|
|
2369
|
-
const events = await readTraceEventsFromFile(m.filePath);
|
|
2370
|
-
if (events.length === 0) continue;
|
|
2371
|
-
const summary = buildRunSummary(events);
|
|
2372
|
-
totalSteps += summary.totalSteps;
|
|
2373
|
-
totalLlmSteps += summary.llmSteps;
|
|
2374
|
-
totalToolSteps += summary.toolSteps;
|
|
2375
|
-
totalErrorSteps += summary.errorSteps;
|
|
2376
|
-
const steps = collectCompletedSteps(events, m.runId);
|
|
2377
|
-
for (const s of steps) {
|
|
2378
|
-
slowestSteps.push(s);
|
|
2379
|
-
}
|
|
2380
|
-
} catch {
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
slowestRuns.sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
|
|
2384
|
-
slowestSteps.sort((a, b) => b.durationMs - a.durationMs);
|
|
2385
|
-
const runLimit = options.slowRunLimit ?? 5;
|
|
2386
|
-
const stepLimit = options.slowStepLimit ?? 5;
|
|
2387
|
-
const sortedDur = [...durations].sort((a, b) => a - b);
|
|
2388
|
-
const totalRuns = filtered.length;
|
|
2389
|
-
const errorRate = totalRuns > 0 ? errorCount / totalRuns : 0;
|
|
2390
|
-
const sumDur = durations.reduce((a, b) => a + b, 0);
|
|
2391
|
-
return {
|
|
2392
|
-
traceDir: options.traceDir,
|
|
2393
|
-
...options.since ? { since: options.since } : {},
|
|
2394
|
-
...options.correlationId ? { correlationId: options.correlationId } : {},
|
|
2395
|
-
...options.groupId ? { groupId: options.groupId } : {},
|
|
2396
|
-
totalRuns,
|
|
2397
|
-
successCount,
|
|
2398
|
-
errorCount,
|
|
2399
|
-
runningCount,
|
|
2400
|
-
unknownCount,
|
|
2401
|
-
errorRate,
|
|
2402
|
-
duration: {
|
|
2403
|
-
...sortedDur.length > 0 ? {
|
|
2404
|
-
minMs: sortedDur[0],
|
|
2405
|
-
maxMs: sortedDur[sortedDur.length - 1],
|
|
2406
|
-
avgMs: sumDur / sortedDur.length,
|
|
2407
|
-
p50Ms: percentile(sortedDur, 50),
|
|
2408
|
-
p95Ms: percentile(sortedDur, 95)
|
|
2409
|
-
} : {}
|
|
2410
|
-
},
|
|
2411
|
-
totalSteps,
|
|
2412
|
-
avgStepsPerRun: totalRuns > 0 ? totalSteps / totalRuns : 0,
|
|
2413
|
-
totalLlmSteps,
|
|
2414
|
-
totalToolSteps,
|
|
2415
|
-
totalErrorSteps,
|
|
2416
|
-
slowestRuns: slowestRuns.slice(0, runLimit),
|
|
2417
|
-
slowestSteps: slowestSteps.slice(0, stepLimit)
|
|
2418
|
-
};
|
|
2419
|
-
}
|
|
2420
|
-
function collectCompletedSteps(events, runId) {
|
|
2421
|
-
const started = /* @__PURE__ */ new Map();
|
|
2422
|
-
const out = [];
|
|
2423
|
-
for (const e of events) {
|
|
2424
|
-
if (e.event === "step_started") {
|
|
2425
|
-
const s = e;
|
|
2426
|
-
started.set(s.stepId, { name: s.name, type: s.type });
|
|
2427
|
-
}
|
|
2428
|
-
if (e.event === "step_completed") {
|
|
2429
|
-
const c = e;
|
|
2430
|
-
if (c.status !== "success" && c.status !== "error") continue;
|
|
2431
|
-
if (typeof c.durationMs !== "number" || !Number.isFinite(c.durationMs)) {
|
|
2432
|
-
continue;
|
|
2433
|
-
}
|
|
2434
|
-
const meta = started.get(c.stepId);
|
|
2435
|
-
out.push({
|
|
2436
|
-
runId,
|
|
2437
|
-
stepName: meta?.name ?? c.stepId,
|
|
2438
|
-
stepType: meta?.type ?? "logic",
|
|
2439
|
-
durationMs: c.durationMs
|
|
2440
|
-
});
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
return out;
|
|
2444
|
-
}
|
|
2445
|
-
function renderTraceStats(stats) {
|
|
2446
|
-
const lines = [];
|
|
2447
|
-
lines.push("Trace stats (local)");
|
|
2448
|
-
lines.push(`Directory: ${stats.traceDir}`);
|
|
2449
|
-
if (stats.since) lines.push(`Since: ${stats.since}`);
|
|
2450
|
-
if (stats.correlationId) lines.push(`Correlation ID: ${stats.correlationId}`);
|
|
2451
|
-
if (stats.groupId) lines.push(`Group ID: ${stats.groupId}`);
|
|
2452
|
-
lines.push("");
|
|
2453
|
-
lines.push(`Runs: ${stats.totalRuns}`);
|
|
2454
|
-
lines.push(
|
|
2455
|
-
` success: ${stats.successCount} error: ${stats.errorCount} running: ${stats.runningCount} unknown: ${stats.unknownCount}`
|
|
2456
|
-
);
|
|
2457
|
-
lines.push(`Error rate: ${(stats.errorRate * 100).toFixed(1)}%`);
|
|
2458
|
-
if (stats.duration.avgMs !== void 0) {
|
|
2459
|
-
lines.push(
|
|
2460
|
-
`Duration: min ${formatDuration2(stats.duration.minMs ?? 0)} | avg ${formatDuration2(stats.duration.avgMs)} | p50 ${formatDuration2(stats.duration.p50Ms ?? 0)} | p95 ${formatDuration2(stats.duration.p95Ms ?? 0)} | max ${formatDuration2(stats.duration.maxMs ?? 0)}`
|
|
2461
|
-
);
|
|
2462
|
-
}
|
|
2463
|
-
lines.push("");
|
|
2464
|
-
lines.push(`Steps: ${stats.totalSteps} (avg ${stats.avgStepsPerRun.toFixed(1)} per run)`);
|
|
2465
|
-
lines.push(
|
|
2466
|
-
` LLM: ${stats.totalLlmSteps} tool: ${stats.totalToolSteps} errors: ${stats.totalErrorSteps}`
|
|
2467
|
-
);
|
|
2468
|
-
if (stats.slowestRuns.length > 0) {
|
|
2469
|
-
lines.push("");
|
|
2470
|
-
lines.push("Slowest runs:");
|
|
2471
|
-
for (const r of stats.slowestRuns) {
|
|
2472
|
-
lines.push(
|
|
2473
|
-
` ${r.runId} | ${r.name ?? "-"} | ${formatDuration2(r.durationMs ?? 0)} | ${r.status}`
|
|
2474
|
-
);
|
|
2475
|
-
}
|
|
2476
|
-
}
|
|
2477
|
-
if (stats.slowestSteps.length > 0) {
|
|
2478
|
-
lines.push("");
|
|
2479
|
-
lines.push("Slowest steps:");
|
|
2480
|
-
for (const s of stats.slowestSteps) {
|
|
2481
|
-
lines.push(
|
|
2482
|
-
` ${s.runId} | ${s.stepType}:${s.stepName} | ${formatDuration2(s.durationMs)}`
|
|
2483
|
-
);
|
|
2484
|
-
}
|
|
2485
|
-
}
|
|
2486
|
-
return lines.join("\n");
|
|
2487
|
-
}
|
|
2488
|
-
|
|
2489
|
-
// packages/core/src/search.ts
|
|
2490
|
-
function parseDurationFilter(expr) {
|
|
2491
|
-
const raw = expr.trim();
|
|
2492
|
-
const m = raw.match(/^(>=|<=|>|<)\s*(.+)$/);
|
|
2493
|
-
if (!m) {
|
|
2494
|
-
throw new Error(
|
|
2495
|
-
`Invalid --duration "${expr}". Use forms like >5s, >=500ms, <2m.`
|
|
2496
|
-
);
|
|
2497
|
-
}
|
|
2498
|
-
const op = m[1];
|
|
2499
|
-
const ms = parseDuration(m[2].trim());
|
|
2500
|
-
return { op, ms };
|
|
2501
|
-
}
|
|
2502
|
-
function durationMatches(valueMs, filter) {
|
|
2503
|
-
if (valueMs === void 0 || !Number.isFinite(valueMs)) return false;
|
|
2504
|
-
switch (filter.op) {
|
|
2505
|
-
case ">":
|
|
2506
|
-
return valueMs > filter.ms;
|
|
2507
|
-
case ">=":
|
|
2508
|
-
return valueMs >= filter.ms;
|
|
2509
|
-
case "<":
|
|
2510
|
-
return valueMs < filter.ms;
|
|
2511
|
-
case "<=":
|
|
2512
|
-
return valueMs <= filter.ms;
|
|
2513
|
-
default:
|
|
2514
|
-
return false;
|
|
2515
|
-
}
|
|
2516
|
-
}
|
|
2517
|
-
function normalizeStepTypeFilter(kind, type) {
|
|
2518
|
-
const v = (kind ?? type)?.trim().toLowerCase();
|
|
2519
|
-
return v && v !== "" ? v : void 0;
|
|
2520
|
-
}
|
|
2521
|
-
function nameMatches(hay, needle) {
|
|
2522
|
-
return hay.toLowerCase().includes(needle.toLowerCase());
|
|
2523
|
-
}
|
|
2524
|
-
async function searchTraces(metas, options) {
|
|
2525
|
-
let filtered = filterTraces(metas, { since: options.since });
|
|
2526
|
-
const stepTypeFilter = normalizeStepTypeFilter(options.kind, options.type);
|
|
2527
|
-
const nameQuery = options.name?.trim();
|
|
2528
|
-
const toolQuery = options.tool?.trim();
|
|
2529
|
-
let durationFilter;
|
|
2530
|
-
if (options.duration) {
|
|
2531
|
-
durationFilter = parseDurationFilter(options.duration);
|
|
2532
|
-
}
|
|
2533
|
-
const limit = options.limit ?? 50;
|
|
2534
|
-
const sessionId = options.session?.trim();
|
|
2535
|
-
const hasContentFilter = Boolean(
|
|
2536
|
-
options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
|
|
2537
|
-
);
|
|
2538
|
-
const results = [];
|
|
2539
|
-
const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
|
|
2540
|
-
if (!hasContentFilter) {
|
|
2541
|
-
for (const m of filtered) {
|
|
2542
|
-
results.push({
|
|
2543
|
-
runId: m.runId,
|
|
2544
|
-
runName: m.name,
|
|
2545
|
-
runStatus: m.status,
|
|
2546
|
-
timestamp: m.startedAt,
|
|
2547
|
-
durationMs: m.durationMs,
|
|
2548
|
-
matchReason: sessionLabel ? `trace in session ${sessionLabel}` : "trace in directory",
|
|
2549
|
-
matchedFields: sessionLabel ? ["run", "session"] : ["run"],
|
|
2550
|
-
filePath: m.filePath,
|
|
2551
|
-
...sessionLabel ? { sessionId: sessionLabel } : {}
|
|
2552
|
-
});
|
|
2553
|
-
}
|
|
2554
|
-
return results.slice(0, limit);
|
|
2555
|
-
}
|
|
2556
|
-
for (const m of filtered) {
|
|
2557
|
-
if (options.status && m.status !== options.status) continue;
|
|
2558
|
-
let events = [];
|
|
2559
|
-
try {
|
|
2560
|
-
events = await readTraceEventsFromFile(m.filePath);
|
|
2561
|
-
} catch {
|
|
2562
|
-
continue;
|
|
2563
|
-
}
|
|
2564
|
-
if (events.length === 0) continue;
|
|
2565
|
-
const runMatches = matchRunLevel(m, {
|
|
2566
|
-
stepTypeFilter,
|
|
2567
|
-
nameQuery,
|
|
2568
|
-
toolQuery,
|
|
2569
|
-
durationFilter,
|
|
2570
|
-
statusFilter: options.status
|
|
2571
|
-
});
|
|
2572
|
-
results.push(...runMatches);
|
|
2573
|
-
const stepMatches = matchStepLevel(m, events, {
|
|
2574
|
-
stepTypeFilter,
|
|
2575
|
-
nameQuery,
|
|
2576
|
-
toolQuery,
|
|
2577
|
-
durationFilter,
|
|
2578
|
-
statusFilter: options.status
|
|
2579
|
-
});
|
|
2580
|
-
results.push(...stepMatches);
|
|
2581
|
-
}
|
|
2582
|
-
results.sort((a, b) => {
|
|
2583
|
-
const ta = a.timestamp ?? 0;
|
|
2584
|
-
const tb = b.timestamp ?? 0;
|
|
2585
|
-
if (ta !== tb) return ta - tb;
|
|
2586
|
-
const runCmp = a.runId.localeCompare(b.runId);
|
|
2587
|
-
if (runCmp !== 0) return runCmp;
|
|
2588
|
-
return (a.stepName ?? "").localeCompare(b.stepName ?? "");
|
|
2589
|
-
});
|
|
2590
|
-
return results.slice(0, limit);
|
|
2591
|
-
}
|
|
2592
|
-
function matchRunLevel(m, opts) {
|
|
2593
|
-
if (opts.stepTypeFilter || opts.toolQuery) return [];
|
|
2594
|
-
const out = [];
|
|
2595
|
-
const fields = [];
|
|
2596
|
-
if (opts.statusFilter && m.status === opts.statusFilter) {
|
|
2597
|
-
fields.push("run.status");
|
|
2598
|
-
}
|
|
2599
|
-
if (opts.nameQuery && nameMatches(m.name ?? m.runId, opts.nameQuery)) {
|
|
2600
|
-
fields.push("run.name");
|
|
2601
|
-
}
|
|
2602
|
-
if (opts.durationFilter && durationMatches(m.durationMs, opts.durationFilter)) {
|
|
2603
|
-
fields.push("run.durationMs");
|
|
2604
|
-
}
|
|
2605
|
-
if (fields.length === 0) return out;
|
|
2606
|
-
out.push({
|
|
2607
|
-
runId: m.runId,
|
|
2608
|
-
runName: m.name,
|
|
2609
|
-
runStatus: m.status,
|
|
2610
|
-
timestamp: m.startedAt,
|
|
2611
|
-
durationMs: m.durationMs,
|
|
2612
|
-
matchReason: `run match: ${fields.join(", ")}`,
|
|
2613
|
-
matchedFields: fields,
|
|
2614
|
-
filePath: m.filePath
|
|
2615
|
-
});
|
|
2616
|
-
return out;
|
|
2617
|
-
}
|
|
2618
|
-
function matchStepLevel(m, events, opts) {
|
|
2619
|
-
const out = [];
|
|
2620
|
-
const started = /* @__PURE__ */ new Map();
|
|
2621
|
-
for (const e of events) {
|
|
2622
|
-
if (e.event === "step_started") {
|
|
2623
|
-
started.set(e.stepId, e);
|
|
2624
|
-
}
|
|
2625
|
-
}
|
|
2626
|
-
for (const e of events) {
|
|
2627
|
-
if (e.event !== "step_completed") continue;
|
|
2628
|
-
const c = e;
|
|
2629
|
-
const s = started.get(c.stepId);
|
|
2630
|
-
if (!s) continue;
|
|
2631
|
-
const fields = [];
|
|
2632
|
-
const stepType = s.type;
|
|
2633
|
-
if (opts.stepTypeFilter && stepType !== opts.stepTypeFilter) {
|
|
2634
|
-
continue;
|
|
2635
|
-
}
|
|
2636
|
-
const hasStepFilters = opts.stepTypeFilter || opts.nameQuery || opts.toolQuery || opts.durationFilter || opts.statusFilter === "error" || opts.statusFilter === "success";
|
|
2637
|
-
if (!hasStepFilters) continue;
|
|
2638
|
-
if (opts.statusFilter === "error" && c.status === "error") {
|
|
2639
|
-
fields.push("step.status");
|
|
2640
|
-
} else if (opts.statusFilter === "success" && c.status === "success") {
|
|
2641
|
-
fields.push("step.status");
|
|
2642
|
-
} else if (opts.statusFilter === "error" || opts.statusFilter === "success") {
|
|
2643
|
-
continue;
|
|
2644
|
-
}
|
|
2645
|
-
if (opts.nameQuery) {
|
|
2646
|
-
if (!nameMatches(s.name, opts.nameQuery)) continue;
|
|
2647
|
-
fields.push("step.name");
|
|
2648
|
-
}
|
|
2649
|
-
if (opts.toolQuery) {
|
|
2650
|
-
const toolName2 = typeof s.metadata?.toolName === "string" ? s.metadata.toolName : s.name;
|
|
2651
|
-
if (!nameMatches(toolName2, opts.toolQuery)) continue;
|
|
2652
|
-
fields.push("step.tool");
|
|
2653
|
-
}
|
|
2654
|
-
if (opts.durationFilter) {
|
|
2655
|
-
if (!durationMatches(c.durationMs, opts.durationFilter)) continue;
|
|
2656
|
-
fields.push("step.durationMs");
|
|
2657
|
-
}
|
|
2658
|
-
if (opts.stepTypeFilter) {
|
|
2659
|
-
fields.push("step.type");
|
|
2660
|
-
}
|
|
2661
|
-
if (fields.length === 0) continue;
|
|
2662
|
-
out.push({
|
|
2663
|
-
runId: m.runId,
|
|
2664
|
-
runName: m.name,
|
|
2665
|
-
runStatus: m.status,
|
|
2666
|
-
stepId: c.stepId,
|
|
2667
|
-
stepName: s.name,
|
|
2668
|
-
stepType,
|
|
2669
|
-
timestamp: s.startTime ?? s.timestamp,
|
|
2670
|
-
durationMs: c.durationMs,
|
|
2671
|
-
matchReason: `step match: ${fields.join(", ")}`,
|
|
2672
|
-
matchedFields: fields,
|
|
2673
|
-
filePath: m.filePath
|
|
2674
|
-
});
|
|
2675
|
-
}
|
|
2676
|
-
return out;
|
|
2677
|
-
}
|
|
2678
|
-
async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
|
|
2679
|
-
const metas = [];
|
|
2680
|
-
for (const fileName of fileNames) {
|
|
2681
|
-
try {
|
|
2682
|
-
const filePath = getPath(fileName);
|
|
2683
|
-
const meta = await extractMetadata(filePath);
|
|
2684
|
-
metas.push(meta);
|
|
2685
|
-
} catch {
|
|
2686
|
-
}
|
|
2687
|
-
}
|
|
2688
|
-
return metas;
|
|
2689
|
-
}
|
|
2690
|
-
|
|
2691
|
-
// packages/core/src/sessions/metadata.ts
|
|
2692
|
-
function isNonEmptyString3(value) {
|
|
2693
|
-
return typeof value === "string" && value.trim() !== "";
|
|
2694
|
-
}
|
|
2695
|
-
function finitePositiveInt(value) {
|
|
2696
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
|
|
2697
|
-
return void 0;
|
|
2698
|
-
}
|
|
2699
|
-
return Math.trunc(value);
|
|
2700
|
-
}
|
|
2701
|
-
function extractSessionWorkflowMetadata(record) {
|
|
2702
|
-
if (!record) return void 0;
|
|
2703
|
-
const out = {};
|
|
2704
|
-
let found = false;
|
|
2705
|
-
const assignString = (key, value) => {
|
|
2706
|
-
if (isNonEmptyString3(value)) {
|
|
2707
|
-
out[key] = value.trim();
|
|
2708
|
-
found = true;
|
|
2709
|
-
}
|
|
2710
|
-
};
|
|
2711
|
-
assignString("sessionId", record.sessionId);
|
|
2712
|
-
assignString("conversationId", record.conversationId);
|
|
2713
|
-
assignString("groupId", record.groupId);
|
|
2714
|
-
assignString("parentGroupId", record.parentGroupId);
|
|
2715
|
-
assignString("retryOf", record.retryOf);
|
|
2716
|
-
assignString("retryReason", record.retryReason);
|
|
2717
|
-
assignString("handoffFrom", record.handoffFrom);
|
|
2718
|
-
assignString("handoffTo", record.handoffTo);
|
|
2719
|
-
assignString("subAgentId", record.subAgentId);
|
|
2720
|
-
assignString("subAgentName", record.subAgentName);
|
|
2721
|
-
assignString("jobId", record.jobId);
|
|
2722
|
-
assignString("queueName", record.queueName);
|
|
2723
|
-
assignString("workflowName", record.workflowName);
|
|
2724
|
-
assignString("workflowStep", record.workflowStep);
|
|
2725
|
-
assignString("toolCallId", record.toolCallId);
|
|
2726
|
-
assignString("mcpToolCallId", record.mcpToolCallId);
|
|
2727
|
-
assignString("linkedStepId", record.linkedStepId);
|
|
2728
|
-
assignString("correlationId", record.correlationId);
|
|
2729
|
-
assignString("requestId", record.requestId);
|
|
2730
|
-
assignString("decisionId", record.decisionId);
|
|
2731
|
-
const attempt = finitePositiveInt(record.attempt);
|
|
2732
|
-
if (attempt !== void 0) {
|
|
2733
|
-
out.attempt = attempt;
|
|
2734
|
-
found = true;
|
|
2735
|
-
}
|
|
2736
|
-
return found ? out : void 0;
|
|
2737
|
-
}
|
|
2738
|
-
function sessionKeyForRun(meta, options) {
|
|
2739
|
-
if (meta?.sessionId) return meta.sessionId;
|
|
2740
|
-
if (options?.correlateByGroupId && meta?.groupId) {
|
|
2741
|
-
return `group:${meta.groupId}`;
|
|
2742
|
-
}
|
|
2743
|
-
return void 0;
|
|
2744
|
-
}
|
|
2745
|
-
|
|
2746
|
-
// packages/core/src/sessions/load.ts
|
|
2747
|
-
async function enrichSessionRunRecord(meta) {
|
|
2748
|
-
let metadata;
|
|
2749
|
-
try {
|
|
2750
|
-
const events = await readTraceEventsFromFile(meta.filePath);
|
|
2751
|
-
for (const event of events) {
|
|
2752
|
-
if (event.event !== "run_started") continue;
|
|
2753
|
-
if (event.metadata && typeof event.metadata === "object") {
|
|
2754
|
-
metadata = event.metadata;
|
|
2755
|
-
}
|
|
2756
|
-
break;
|
|
2757
|
-
}
|
|
2758
|
-
} catch {
|
|
2759
|
-
}
|
|
2760
|
-
return {
|
|
2761
|
-
runId: meta.runId,
|
|
2762
|
-
name: meta.name,
|
|
2763
|
-
status: meta.status,
|
|
2764
|
-
startedAt: meta.startedAt,
|
|
2765
|
-
endedAt: meta.endedAt,
|
|
2766
|
-
durationMs: meta.durationMs,
|
|
2767
|
-
filePath: meta.filePath,
|
|
2768
|
-
metadata
|
|
2769
|
-
};
|
|
2770
|
-
}
|
|
2771
|
-
async function loadSessionRunRecords(metas) {
|
|
2772
|
-
const out = [];
|
|
2773
|
-
for (const meta of metas) {
|
|
2774
|
-
out.push(await enrichSessionRunRecord(meta));
|
|
2775
|
-
}
|
|
2776
|
-
return out;
|
|
2777
|
-
}
|
|
2778
|
-
|
|
2779
|
-
// packages/core/src/sessions/scope.ts
|
|
2780
|
-
function filterMetasBySessionScope(metas, records, options) {
|
|
2781
|
-
const sessionId = options.sessionId?.trim();
|
|
2782
|
-
const groupId = options.groupId?.trim();
|
|
2783
|
-
const warnings = [];
|
|
2784
|
-
if (sessionId) {
|
|
2785
|
-
const index = buildSessionIndex(records, {
|
|
2786
|
-
correlateByGroupId: options.correlateByGroupId === true
|
|
2787
|
-
});
|
|
2788
|
-
warnings.push(...index.warnings);
|
|
2789
|
-
const session = index.sessions.find((item) => item.sessionId === sessionId);
|
|
2790
|
-
if (!session) {
|
|
2791
|
-
return {
|
|
2792
|
-
metas: [],
|
|
2793
|
-
scopeLabel: sessionId,
|
|
2794
|
-
scopeKind: "session",
|
|
2795
|
-
runIds: [],
|
|
2796
|
-
warnings,
|
|
2797
|
-
notFound: true
|
|
2798
|
-
};
|
|
2799
|
-
}
|
|
2800
|
-
const runIdSet = new Set(session.runIds);
|
|
2801
|
-
const filtered = metas.filter((meta) => runIdSet.has(meta.runId));
|
|
2802
|
-
return {
|
|
2803
|
-
metas: filtered,
|
|
2804
|
-
scopeLabel: sessionId,
|
|
2805
|
-
scopeKind: "session",
|
|
2806
|
-
runIds: session.runIds,
|
|
2807
|
-
warnings,
|
|
2808
|
-
notFound: false
|
|
2809
|
-
};
|
|
2810
|
-
}
|
|
2811
|
-
if (groupId) {
|
|
2812
|
-
const runIds = records.filter((run) => extractSessionWorkflowMetadata(run.metadata)?.groupId === groupId).map((run) => run.runId).sort();
|
|
2813
|
-
if (runIds.length === 0) {
|
|
2814
|
-
return {
|
|
2815
|
-
metas: [],
|
|
2816
|
-
scopeLabel: groupId,
|
|
2817
|
-
scopeKind: "group",
|
|
2818
|
-
runIds: [],
|
|
2819
|
-
warnings,
|
|
2820
|
-
notFound: true
|
|
2821
|
-
};
|
|
2822
|
-
}
|
|
2823
|
-
const runIdSet = new Set(runIds);
|
|
2824
|
-
return {
|
|
2825
|
-
metas: metas.filter((meta) => runIdSet.has(meta.runId)),
|
|
2826
|
-
scopeLabel: groupId,
|
|
2827
|
-
scopeKind: "group",
|
|
2828
|
-
runIds,
|
|
2829
|
-
warnings,
|
|
2830
|
-
notFound: false
|
|
2831
|
-
};
|
|
2832
|
-
}
|
|
2833
|
-
return {
|
|
2834
|
-
metas: [...metas],
|
|
2835
|
-
scopeLabel: "",
|
|
2836
|
-
scopeKind: "session",
|
|
2837
|
-
runIds: [],
|
|
2838
|
-
warnings,
|
|
2839
|
-
notFound: false
|
|
2840
|
-
};
|
|
2841
|
-
}
|
|
2842
|
-
|
|
2843
|
-
// packages/core/src/sessions/checks.ts
|
|
2844
|
-
function emptySummary() {
|
|
2845
|
-
return { passed: 0, failed: 0, warnings: 0, errors: 0 };
|
|
2846
|
-
}
|
|
2847
|
-
function mergeSummary(target, source) {
|
|
2848
|
-
return {
|
|
2849
|
-
passed: target.passed + source.passed,
|
|
2850
|
-
failed: target.failed + source.failed,
|
|
2851
|
-
warnings: target.warnings + source.warnings,
|
|
2852
|
-
errors: target.errors + source.errors
|
|
2853
|
-
};
|
|
2854
|
-
}
|
|
2855
|
-
function sessionDiagnostic(code, message) {
|
|
2856
|
-
return { code, message, severity: "error" };
|
|
2857
|
-
}
|
|
2858
|
-
function aggregateSessionCheckResults(perRun, scope) {
|
|
2859
|
-
if (scope.notFound) {
|
|
2860
|
-
return {
|
|
2861
|
-
ok: false,
|
|
2862
|
-
status: "error",
|
|
2863
|
-
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
2864
|
-
scopeKind: scope.scopeKind,
|
|
2865
|
-
scopeLabel: scope.scopeLabel,
|
|
2866
|
-
runIds: [],
|
|
2867
|
-
runResults: [],
|
|
2868
|
-
summary: { ...emptySummary(), errors: 1 },
|
|
2869
|
-
findings: [],
|
|
2870
|
-
diagnostics: [
|
|
2871
|
-
sessionDiagnostic(
|
|
2872
|
-
"AI_CHECK_INVALID_ARGUMENTS",
|
|
2873
|
-
`${scope.scopeKind} not found: ${scope.scopeLabel}`
|
|
2874
|
-
)
|
|
2875
|
-
],
|
|
2876
|
-
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
2877
|
-
};
|
|
2878
|
-
}
|
|
2879
|
-
if (scope.empty || perRun.length === 0) {
|
|
2880
|
-
return {
|
|
2881
|
-
ok: false,
|
|
2882
|
-
status: "error",
|
|
2883
|
-
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
2884
|
-
scopeKind: scope.scopeKind,
|
|
2885
|
-
scopeLabel: scope.scopeLabel,
|
|
2886
|
-
runIds: scope.runIds,
|
|
2887
|
-
runResults: [],
|
|
2888
|
-
summary: { ...emptySummary(), errors: 1 },
|
|
2889
|
-
findings: [],
|
|
2890
|
-
diagnostics: [
|
|
2891
|
-
sessionDiagnostic(
|
|
2892
|
-
"AI_CHECK_TRACE_UNREADABLE",
|
|
2893
|
-
`No readable traces in ${scope.scopeKind}: ${scope.scopeLabel}`
|
|
2894
|
-
)
|
|
2895
|
-
],
|
|
2896
|
-
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
2897
|
-
};
|
|
2898
|
-
}
|
|
2899
|
-
let summary = emptySummary();
|
|
2900
|
-
const findings = [];
|
|
2901
|
-
const diagnostics = [];
|
|
2902
|
-
const runResults = [];
|
|
2903
|
-
for (const result of perRun) {
|
|
2904
|
-
summary = mergeSummary(summary, result.summary);
|
|
2905
|
-
findings.push(...result.findings);
|
|
2906
|
-
diagnostics.push(...result.diagnostics);
|
|
2907
|
-
if (result.runId) {
|
|
2908
|
-
runResults.push({ runId: result.runId, status: result.status });
|
|
2909
|
-
}
|
|
2910
|
-
}
|
|
2911
|
-
runResults.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
2912
|
-
findings.sort((a, b) => {
|
|
2913
|
-
const runCmp = (a.evidence[0]?.runId ?? "").localeCompare(
|
|
2914
|
-
b.evidence[0]?.runId ?? ""
|
|
2915
|
-
);
|
|
2916
|
-
if (runCmp !== 0) return runCmp;
|
|
2917
|
-
return a.ruleId.localeCompare(b.ruleId);
|
|
2918
|
-
});
|
|
2919
|
-
const hasErrors = diagnostics.some((item) => item.severity === "error");
|
|
2920
|
-
const status = hasErrors ? "error" : summary.failed > 0 ? "fail" : "pass";
|
|
2921
|
-
return {
|
|
2922
|
-
ok: status === "pass",
|
|
2923
|
-
status,
|
|
2924
|
-
format: perRun[0]?.format ?? "agent-inspect-jsonl",
|
|
2925
|
-
scopeKind: scope.scopeKind,
|
|
2926
|
-
scopeLabel: scope.scopeLabel,
|
|
2927
|
-
runIds: scope.runIds,
|
|
2928
|
-
runResults,
|
|
2929
|
-
summary,
|
|
2930
|
-
findings,
|
|
2931
|
-
diagnostics,
|
|
2932
|
-
...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
|
|
2933
|
-
};
|
|
2934
|
-
}
|
|
2935
|
-
|
|
2936
|
-
// packages/core/src/sessions/index.ts
|
|
2937
|
-
function compareRuns(a, b) {
|
|
2938
|
-
const aStart = a.startedAt ?? 0;
|
|
2939
|
-
const bStart = b.startedAt ?? 0;
|
|
2940
|
-
if (aStart !== bStart) return aStart - bStart;
|
|
2941
|
-
return a.runId.localeCompare(b.runId);
|
|
2942
|
-
}
|
|
2943
|
-
function buildGroups(runIds, metaByRunId) {
|
|
2944
|
-
const byGroup = /* @__PURE__ */ new Map();
|
|
2945
|
-
for (const runId of runIds) {
|
|
2946
|
-
const groupId = metaByRunId.get(runId)?.groupId;
|
|
2947
|
-
if (!groupId) continue;
|
|
2948
|
-
const existing = byGroup.get(groupId);
|
|
2949
|
-
if (existing) {
|
|
2950
|
-
existing.runIds.push(runId);
|
|
2951
|
-
} else {
|
|
2952
|
-
byGroup.set(groupId, {
|
|
2953
|
-
groupId,
|
|
2954
|
-
parentGroupId: metaByRunId.get(runId)?.parentGroupId,
|
|
2955
|
-
runIds: [runId]
|
|
2956
|
-
});
|
|
2957
|
-
}
|
|
2958
|
-
}
|
|
2959
|
-
return [...byGroup.values()].map((group) => ({
|
|
2960
|
-
...group,
|
|
2961
|
-
runIds: [...group.runIds].sort((a, b) => a.localeCompare(b))
|
|
2962
|
-
}));
|
|
2963
|
-
}
|
|
2964
|
-
function buildHandoffs(runIds, metaByRunId, warnings, sessionId) {
|
|
2965
|
-
const edges = [];
|
|
2966
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2967
|
-
const pushEdge = (edge) => {
|
|
2968
|
-
const key = `${edge.from}->${edge.to}:${edge.confidence}`;
|
|
2969
|
-
if (seen.has(key)) return;
|
|
2970
|
-
seen.add(key);
|
|
2971
|
-
edges.push(edge);
|
|
2972
|
-
};
|
|
2973
|
-
for (const runId of runIds) {
|
|
2974
|
-
const meta = metaByRunId.get(runId);
|
|
2975
|
-
if (!meta) continue;
|
|
2976
|
-
if (meta.handoffFrom && meta.handoffTo) {
|
|
2977
|
-
pushEdge({
|
|
2978
|
-
from: meta.handoffFrom,
|
|
2979
|
-
to: meta.handoffTo,
|
|
2980
|
-
source: "manual",
|
|
2981
|
-
confidence: "explicit"
|
|
2982
|
-
});
|
|
2983
|
-
continue;
|
|
2984
|
-
}
|
|
2985
|
-
if (meta.handoffFrom) {
|
|
2986
|
-
pushEdge({
|
|
2987
|
-
from: meta.handoffFrom,
|
|
2988
|
-
to: runId,
|
|
2989
|
-
source: "manual",
|
|
2990
|
-
confidence: "explicit"
|
|
2991
|
-
});
|
|
2992
|
-
}
|
|
2993
|
-
if (meta.handoffTo) {
|
|
2994
|
-
pushEdge({
|
|
2995
|
-
from: runId,
|
|
2996
|
-
to: meta.handoffTo,
|
|
2997
|
-
source: "manual",
|
|
2998
|
-
confidence: "explicit"
|
|
2999
|
-
});
|
|
3000
|
-
}
|
|
3001
|
-
if (meta.subAgentId && meta.parentGroupId && !meta.handoffFrom && !meta.handoffTo) {
|
|
3002
|
-
pushEdge({
|
|
3003
|
-
from: meta.parentGroupId,
|
|
3004
|
-
to: meta.subAgentId,
|
|
3005
|
-
source: "inferred",
|
|
3006
|
-
confidence: "correlated"
|
|
3007
|
-
});
|
|
3008
|
-
warnings.push({
|
|
3009
|
-
code: "ambiguous-handoff-endpoints",
|
|
3010
|
-
message: "Handoff inferred from parentGroupId and subAgentId without explicit handoffFrom/handoffTo.",
|
|
3011
|
-
runId,
|
|
3012
|
-
sessionId
|
|
3013
|
-
});
|
|
3014
|
-
}
|
|
3015
|
-
}
|
|
3016
|
-
return edges.sort((a, b) => {
|
|
3017
|
-
const from = a.from.localeCompare(b.from);
|
|
3018
|
-
if (from !== 0) return from;
|
|
3019
|
-
return a.to.localeCompare(b.to);
|
|
3020
|
-
});
|
|
3021
|
-
}
|
|
3022
|
-
function buildRetries(runIds, metaByRunId, warnings, sessionId) {
|
|
3023
|
-
const retries = [];
|
|
3024
|
-
for (const runId of runIds) {
|
|
3025
|
-
const meta = metaByRunId.get(runId);
|
|
3026
|
-
if (!meta) continue;
|
|
3027
|
-
if (meta.retryOf) {
|
|
3028
|
-
retries.push({
|
|
3029
|
-
runId,
|
|
3030
|
-
retryOf: meta.retryOf,
|
|
3031
|
-
attempt: meta.attempt,
|
|
3032
|
-
source: "manual",
|
|
3033
|
-
confidence: "explicit"
|
|
3034
|
-
});
|
|
3035
|
-
continue;
|
|
3036
|
-
}
|
|
3037
|
-
if (meta.attempt !== void 0 && meta.attempt > 1) {
|
|
3038
|
-
retries.push({
|
|
3039
|
-
runId,
|
|
3040
|
-
attempt: meta.attempt,
|
|
3041
|
-
source: "inferred",
|
|
3042
|
-
confidence: "correlated"
|
|
3043
|
-
});
|
|
3044
|
-
warnings.push({
|
|
3045
|
-
code: "ambiguous-retry-link",
|
|
3046
|
-
message: "attempt > 1 without retryOf; retry link is correlated only.",
|
|
3047
|
-
runId,
|
|
3048
|
-
sessionId
|
|
3049
|
-
});
|
|
3050
|
-
}
|
|
3051
|
-
}
|
|
3052
|
-
return retries.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
3053
|
-
}
|
|
3054
|
-
function buildCriticalPath(runs, handoffs) {
|
|
3055
|
-
const runById = new Map(runs.map((run) => [run.runId, run]));
|
|
3056
|
-
const explicitTargets = new Set(
|
|
3057
|
-
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.to)
|
|
3058
|
-
);
|
|
3059
|
-
const explicitSources = new Set(
|
|
3060
|
-
handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
|
|
3061
|
-
);
|
|
3062
|
-
const ordered = [...runs].sort(compareRuns);
|
|
3063
|
-
const path20 = [];
|
|
3064
|
-
const visited = /* @__PURE__ */ new Set();
|
|
3065
|
-
const pushRun = (run, confidence, source) => {
|
|
3066
|
-
if (visited.has(run.runId)) return;
|
|
3067
|
-
visited.add(run.runId);
|
|
3068
|
-
path20.push({
|
|
3069
|
-
runId: run.runId,
|
|
3070
|
-
name: run.name,
|
|
3071
|
-
startedAt: run.startedAt,
|
|
3072
|
-
durationMs: run.durationMs,
|
|
3073
|
-
confidence,
|
|
3074
|
-
source
|
|
3075
|
-
});
|
|
3076
|
-
};
|
|
3077
|
-
for (const edge of handoffs) {
|
|
3078
|
-
if (edge.confidence !== "explicit") continue;
|
|
3079
|
-
const fromRun = [...runById.values()].find(
|
|
3080
|
-
(run) => run.runId === edge.from || metaRunIdMatches(run, edge.from, runById)
|
|
3081
|
-
);
|
|
3082
|
-
const toRun = [...runById.values()].find(
|
|
3083
|
-
(run) => run.runId === edge.to || metaRunIdMatches(run, edge.to, runById)
|
|
3084
|
-
);
|
|
3085
|
-
if (fromRun) pushRun(fromRun, "explicit", "manual");
|
|
3086
|
-
if (toRun) pushRun(toRun, "explicit", "manual");
|
|
3087
|
-
}
|
|
3088
|
-
for (const run of ordered) {
|
|
3089
|
-
if (visited.has(run.runId)) continue;
|
|
3090
|
-
const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
|
|
3091
|
-
pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
|
|
3092
|
-
}
|
|
3093
|
-
return path20;
|
|
3094
|
-
}
|
|
3095
|
-
function metaRunIdMatches(run, token, runById) {
|
|
3096
|
-
const meta = extractSessionWorkflowMetadata(run.metadata);
|
|
3097
|
-
return meta?.subAgentId === token || meta?.groupId === token || runById.has(token);
|
|
3098
|
-
}
|
|
3099
|
-
function buildSessionIndex(inputRuns, options = {}) {
|
|
3100
|
-
const warnings = [];
|
|
3101
|
-
const runs = [...inputRuns].sort(compareRuns);
|
|
3102
|
-
const metaByRunId = /* @__PURE__ */ new Map();
|
|
3103
|
-
for (const run of runs) {
|
|
3104
|
-
metaByRunId.set(run.runId, extractSessionWorkflowMetadata(run.metadata));
|
|
3105
|
-
}
|
|
3106
|
-
const sessionsByKey = /* @__PURE__ */ new Map();
|
|
3107
|
-
const unscopedRunIds = [];
|
|
3108
|
-
for (const run of runs) {
|
|
3109
|
-
const meta = metaByRunId.get(run.runId);
|
|
3110
|
-
const key = sessionKeyForRun(meta, {
|
|
3111
|
-
correlateByGroupId: options.correlateByGroupId === true
|
|
3112
|
-
});
|
|
3113
|
-
if (!key) {
|
|
3114
|
-
unscopedRunIds.push(run.runId);
|
|
3115
|
-
continue;
|
|
3116
|
-
}
|
|
3117
|
-
const bucket = sessionsByKey.get(key) ?? [];
|
|
3118
|
-
bucket.push(run);
|
|
3119
|
-
sessionsByKey.set(key, bucket);
|
|
3120
|
-
}
|
|
3121
|
-
const sessions = [...sessionsByKey.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([sessionId, sessionRuns]) => {
|
|
3122
|
-
const runIds = sessionRuns.map((run) => run.runId).sort();
|
|
3123
|
-
const handoffs = buildHandoffs(runIds, metaByRunId, warnings, sessionId);
|
|
3124
|
-
const retries = buildRetries(runIds, metaByRunId, warnings, sessionId);
|
|
3125
|
-
const groups = buildGroups(runIds, metaByRunId);
|
|
3126
|
-
const criticalPath = buildCriticalPath(sessionRuns, handoffs);
|
|
3127
|
-
const confidences = new Set(handoffs.map((edge) => edge.confidence));
|
|
3128
|
-
if (confidences.has("explicit") && confidences.has("correlated")) {
|
|
3129
|
-
warnings.push({
|
|
3130
|
-
code: "mixed-confidence-group",
|
|
3131
|
-
message: "Session aggregates explicit and correlated handoff edges.",
|
|
3132
|
-
sessionId
|
|
3133
|
-
});
|
|
3134
|
-
}
|
|
3135
|
-
return {
|
|
3136
|
-
sessionId,
|
|
3137
|
-
runIds,
|
|
3138
|
-
groups,
|
|
3139
|
-
handoffs,
|
|
3140
|
-
retries,
|
|
3141
|
-
criticalPath
|
|
3142
|
-
};
|
|
3143
|
-
});
|
|
3144
|
-
if (sessions.length === 0 && runs.length > 0) {
|
|
3145
|
-
warnings.push({
|
|
3146
|
-
code: "missing-session-id",
|
|
3147
|
-
message: "No sessionId (or correlated groupId) found on input runs."
|
|
3148
|
-
});
|
|
3149
|
-
}
|
|
3150
|
-
warnings.sort((a, b) => {
|
|
3151
|
-
const code = a.code.localeCompare(b.code);
|
|
3152
|
-
if (code !== 0) return code;
|
|
3153
|
-
return (a.runId ?? "").localeCompare(b.runId ?? "");
|
|
3154
|
-
});
|
|
3155
|
-
return {
|
|
3156
|
-
runs,
|
|
3157
|
-
sessions,
|
|
3158
|
-
unscopedRunIds: unscopedRunIds.sort(),
|
|
3159
|
-
warnings
|
|
3160
|
-
};
|
|
3161
|
-
}
|
|
3162
|
-
var KNOWN_EVENTS = /* @__PURE__ */ new Set([
|
|
3163
|
-
"run_started",
|
|
3164
|
-
"run_completed",
|
|
3165
|
-
"step_started",
|
|
3166
|
-
"step_completed"
|
|
3167
|
-
]);
|
|
3168
|
-
function isRecord6(value) {
|
|
3169
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3170
|
-
}
|
|
3171
|
-
function safeParse(line) {
|
|
3172
|
-
try {
|
|
3173
|
-
return JSON.parse(line);
|
|
3174
|
-
} catch {
|
|
3175
|
-
return void 0;
|
|
3176
|
-
}
|
|
3177
|
-
}
|
|
3178
|
-
async function isAgentInspectTrace(filePath) {
|
|
3179
|
-
try {
|
|
3180
|
-
const rl = createInterface({
|
|
3181
|
-
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
3182
|
-
crlfDelay: Infinity
|
|
3183
|
-
});
|
|
3184
|
-
let checked = 0;
|
|
3185
|
-
for await (const line of rl) {
|
|
3186
|
-
const trimmed = line.trim();
|
|
3187
|
-
if (trimmed === "") continue;
|
|
3188
|
-
const parsed = safeParse(trimmed);
|
|
3189
|
-
if (!parsed) continue;
|
|
3190
|
-
if (!isRecord6(parsed)) continue;
|
|
3191
|
-
checked += 1;
|
|
3192
|
-
if (isTraceEvent(parsed)) return true;
|
|
3193
|
-
const ev = parsed.event;
|
|
3194
|
-
const runId = parsed.runId;
|
|
3195
|
-
if (typeof ev === "string" && KNOWN_EVENTS.has(ev) && typeof runId === "string") {
|
|
3196
|
-
return true;
|
|
3197
|
-
}
|
|
3198
|
-
if (checked >= 20) break;
|
|
3199
|
-
}
|
|
3200
|
-
return false;
|
|
3201
|
-
} catch {
|
|
3202
|
-
return false;
|
|
3203
|
-
}
|
|
3204
|
-
}
|
|
14
|
+
var version = "4.1.0";
|
|
3205
15
|
|
|
3206
16
|
// packages/cli/src/trace-dir-scale.ts
|
|
3207
17
|
var TRACE_COUNT_WARN = 1e3;
|
|
@@ -3276,7 +86,7 @@ function statusIcon(status) {
|
|
|
3276
86
|
function durationCell(status, durationMs2) {
|
|
3277
87
|
if (status === "running" || status === "unknown") return "-";
|
|
3278
88
|
if (durationMs2 !== void 0 && Number.isFinite(durationMs2)) {
|
|
3279
|
-
return
|
|
89
|
+
return formatDuration(durationMs2);
|
|
3280
90
|
}
|
|
3281
91
|
return "-";
|
|
3282
92
|
}
|
|
@@ -3372,8 +182,8 @@ function stableSortNewestFirst(a, b) {
|
|
|
3372
182
|
return a.runId.localeCompare(b.runId);
|
|
3373
183
|
}
|
|
3374
184
|
async function confirmDeletion(count) {
|
|
3375
|
-
const { createInterface
|
|
3376
|
-
const rl =
|
|
185
|
+
const { createInterface } = await import('readline/promises');
|
|
186
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
3377
187
|
try {
|
|
3378
188
|
const answer = await rl.question(
|
|
3379
189
|
`Delete ${count} AgentInspect trace file(s)? Type "yes" to continue: `
|
|
@@ -3506,14 +316,14 @@ async function clean(options = {}) {
|
|
|
3506
316
|
}
|
|
3507
317
|
|
|
3508
318
|
// packages/core/src/persisted/token-usage.ts
|
|
3509
|
-
function
|
|
319
|
+
function isRecord(value) {
|
|
3510
320
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3511
321
|
}
|
|
3512
322
|
function nonNegativeFinite(value) {
|
|
3513
323
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
3514
324
|
}
|
|
3515
325
|
function normalizeTokenUsage(value) {
|
|
3516
|
-
if (!
|
|
326
|
+
if (!isRecord(value)) return void 0;
|
|
3517
327
|
const input3 = nonNegativeFinite(value.input);
|
|
3518
328
|
const output2 = nonNegativeFinite(value.output);
|
|
3519
329
|
const suppliedTotal = nonNegativeFinite(value.total);
|
|
@@ -3748,7 +558,7 @@ function compactAttributes2(entries) {
|
|
|
3748
558
|
}
|
|
3749
559
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
3750
560
|
}
|
|
3751
|
-
function
|
|
561
|
+
function parseIsoToMs(iso) {
|
|
3752
562
|
const parsed = Date.parse(iso);
|
|
3753
563
|
if (!Number.isFinite(parsed)) {
|
|
3754
564
|
return { ms: 0, invalidTimestamp: true };
|
|
@@ -3829,7 +639,7 @@ function persistedInspectEventToInspectEvent(event) {
|
|
|
3829
639
|
if (!isPersistedInspectEvent(event)) {
|
|
3830
640
|
throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
|
|
3831
641
|
}
|
|
3832
|
-
const ts =
|
|
642
|
+
const ts = parseIsoToMs(event.timestamp);
|
|
3833
643
|
const attrs = buildInspectAttributes(event);
|
|
3834
644
|
if (ts.invalidTimestamp) {
|
|
3835
645
|
attrs.invalidTimestamp = true;
|
|
@@ -4085,7 +895,7 @@ function findReaderByFormat(format, readers) {
|
|
|
4085
895
|
}
|
|
4086
896
|
async function jsonlFilesInDirectory(dirPath) {
|
|
4087
897
|
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
4088
|
-
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) =>
|
|
898
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path10.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
|
|
4089
899
|
}
|
|
4090
900
|
async function resolveInput(input3) {
|
|
4091
901
|
const cached = resolvedInputCache.get(input3);
|
|
@@ -4234,28 +1044,28 @@ function persistedEventsForParsedTrace(parsed) {
|
|
|
4234
1044
|
sourceName: "agent-inspect-jsonl-reader"
|
|
4235
1045
|
});
|
|
4236
1046
|
}
|
|
4237
|
-
function
|
|
1047
|
+
function isRecord2(value) {
|
|
4238
1048
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4239
1049
|
}
|
|
4240
|
-
function
|
|
1050
|
+
function isNonEmptyString(value) {
|
|
4241
1051
|
return typeof value === "string" && value.trim() !== "";
|
|
4242
1052
|
}
|
|
4243
1053
|
function readStringField(record, keys) {
|
|
4244
1054
|
for (const key of keys) {
|
|
4245
1055
|
const value = record[key];
|
|
4246
|
-
if (
|
|
1056
|
+
if (isNonEmptyString(value)) return value;
|
|
4247
1057
|
}
|
|
4248
1058
|
return void 0;
|
|
4249
1059
|
}
|
|
4250
1060
|
function readRecordField(record, key) {
|
|
4251
1061
|
const value = record[key];
|
|
4252
|
-
return
|
|
1062
|
+
return isRecord2(value) ? value : void 0;
|
|
4253
1063
|
}
|
|
4254
1064
|
function parseJsonDocument(content) {
|
|
4255
1065
|
return JSON.parse(content);
|
|
4256
1066
|
}
|
|
4257
1067
|
function looksLikeOpenInferenceSpan(value) {
|
|
4258
|
-
if (!
|
|
1068
|
+
if (!isRecord2(value)) return false;
|
|
4259
1069
|
const attributes = readRecordField(value, "attributes");
|
|
4260
1070
|
return readStringField(value, ["trace_id", "traceId"]) !== void 0 && readStringField(value, ["span_id", "spanId"]) !== void 0 && (readStringField(value, ["name"]) !== void 0 || attributes?.["openinference.span.kind"] !== void 0);
|
|
4261
1071
|
}
|
|
@@ -4280,7 +1090,7 @@ function extractOpenInferenceDocument(root) {
|
|
|
4280
1090
|
unsupportedFields
|
|
4281
1091
|
};
|
|
4282
1092
|
}
|
|
4283
|
-
if (!
|
|
1093
|
+
if (!isRecord2(root)) return void 0;
|
|
4284
1094
|
const rootFormat = root.format;
|
|
4285
1095
|
const rootCompatibility = root.compatibility;
|
|
4286
1096
|
const version2 = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
|
|
@@ -4377,7 +1187,7 @@ function parseUnixNanoToIso(value) {
|
|
|
4377
1187
|
return void 0;
|
|
4378
1188
|
}
|
|
4379
1189
|
function parseIsoTime(value) {
|
|
4380
|
-
if (!
|
|
1190
|
+
if (!isNonEmptyString(value)) return void 0;
|
|
4381
1191
|
const ms = Date.parse(value);
|
|
4382
1192
|
if (!Number.isFinite(ms)) return void 0;
|
|
4383
1193
|
return new Date(ms).toISOString();
|
|
@@ -4420,7 +1230,7 @@ function summarizeAttributeValue(value) {
|
|
|
4420
1230
|
if (Array.isArray(value)) {
|
|
4421
1231
|
return { type: "array", length: value.length };
|
|
4422
1232
|
}
|
|
4423
|
-
if (
|
|
1233
|
+
if (isRecord2(value)) {
|
|
4424
1234
|
return { type: "object", keyCount: Object.keys(value).length };
|
|
4425
1235
|
}
|
|
4426
1236
|
if (value === null) {
|
|
@@ -4507,7 +1317,7 @@ function mapOpenInferenceKind(span, attributes, pathPrefix) {
|
|
|
4507
1317
|
}
|
|
4508
1318
|
}
|
|
4509
1319
|
function mapOpenInferenceStatus(status) {
|
|
4510
|
-
if (!
|
|
1320
|
+
if (!isRecord2(status)) return void 0;
|
|
4511
1321
|
const rawCode = status.code;
|
|
4512
1322
|
if (typeof rawCode !== "string") return void 0;
|
|
4513
1323
|
switch (rawCode.toUpperCase()) {
|
|
@@ -4607,7 +1417,7 @@ function mapOpenInferenceSpan(span, index, version2) {
|
|
|
4607
1417
|
warnings.push(...kindWarnings);
|
|
4608
1418
|
const status = mapOpenInferenceStatus(span.status);
|
|
4609
1419
|
const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
|
|
4610
|
-
const errorMessage =
|
|
1420
|
+
const errorMessage = isRecord2(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
|
|
4611
1421
|
const event = {
|
|
4612
1422
|
schemaVersion: "0.2",
|
|
4613
1423
|
eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
|
|
@@ -4753,7 +1563,7 @@ var openInferenceJsonReader = {
|
|
|
4753
1563
|
}
|
|
4754
1564
|
};
|
|
4755
1565
|
function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
|
|
4756
|
-
if (!
|
|
1566
|
+
if (!isRecord2(value)) {
|
|
4757
1567
|
unsupportedFields.push(field);
|
|
4758
1568
|
warnings.push({
|
|
4759
1569
|
code: "otlp_attribute_value_invalid",
|
|
@@ -4775,15 +1585,15 @@ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
|
|
|
4775
1585
|
if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
|
|
4776
1586
|
return value.doubleValue;
|
|
4777
1587
|
}
|
|
4778
|
-
if (
|
|
1588
|
+
if (isRecord2(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
|
|
4779
1589
|
return value.arrayValue.values.map(
|
|
4780
1590
|
(item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
|
|
4781
1591
|
);
|
|
4782
1592
|
}
|
|
4783
|
-
if (
|
|
1593
|
+
if (isRecord2(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
|
|
4784
1594
|
const out = {};
|
|
4785
1595
|
for (const [index, item] of value.kvlistValue.values.entries()) {
|
|
4786
|
-
if (!
|
|
1596
|
+
if (!isRecord2(item) || typeof item.key !== "string") {
|
|
4787
1597
|
unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
|
|
4788
1598
|
continue;
|
|
4789
1599
|
}
|
|
@@ -4834,7 +1644,7 @@ function parseOtlpAttributes(value, pathPrefix) {
|
|
|
4834
1644
|
}
|
|
4835
1645
|
for (const [index, item] of value.entries()) {
|
|
4836
1646
|
const field = `${pathPrefix}[${index}]`;
|
|
4837
|
-
if (!
|
|
1647
|
+
if (!isRecord2(item) || typeof item.key !== "string") {
|
|
4838
1648
|
unsupportedFields.push(field);
|
|
4839
1649
|
warnings.push({
|
|
4840
1650
|
code: "otlp_attribute_invalid",
|
|
@@ -4857,16 +1667,16 @@ function parseOtlpAttributes(value, pathPrefix) {
|
|
|
4857
1667
|
return { attributes, warnings, unsupportedFields };
|
|
4858
1668
|
}
|
|
4859
1669
|
function looksLikeOtlpSpan(value) {
|
|
4860
|
-
return
|
|
1670
|
+
return isRecord2(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
|
|
4861
1671
|
}
|
|
4862
1672
|
function extractOtlpDocument(root) {
|
|
4863
|
-
if (!
|
|
1673
|
+
if (!isRecord2(root) || !Array.isArray(root.resourceSpans)) return void 0;
|
|
4864
1674
|
const spans = [];
|
|
4865
1675
|
const warnings = [];
|
|
4866
1676
|
const unsupportedFields = [];
|
|
4867
1677
|
for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
|
|
4868
1678
|
const resourcePath = `resourceSpans[${resourceIndex}]`;
|
|
4869
|
-
if (!
|
|
1679
|
+
if (!isRecord2(resourceSpan)) {
|
|
4870
1680
|
unsupportedFields.push(resourcePath);
|
|
4871
1681
|
continue;
|
|
4872
1682
|
}
|
|
@@ -4889,7 +1699,7 @@ function extractOtlpDocument(root) {
|
|
|
4889
1699
|
}
|
|
4890
1700
|
for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
|
|
4891
1701
|
const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
|
|
4892
|
-
if (!
|
|
1702
|
+
if (!isRecord2(scopeSpan)) {
|
|
4893
1703
|
unsupportedFields.push(scopePath);
|
|
4894
1704
|
continue;
|
|
4895
1705
|
}
|
|
@@ -4956,7 +1766,7 @@ function extractOtlpDocument(root) {
|
|
|
4956
1766
|
};
|
|
4957
1767
|
}
|
|
4958
1768
|
function mapOtlpStatus(status) {
|
|
4959
|
-
if (!
|
|
1769
|
+
if (!isRecord2(status)) return void 0;
|
|
4960
1770
|
const rawCode = status.code;
|
|
4961
1771
|
if (typeof rawCode !== "string") return void 0;
|
|
4962
1772
|
switch (rawCode.toUpperCase()) {
|
|
@@ -5056,7 +1866,7 @@ function mapOtlpEvents(value, pathPrefix) {
|
|
|
5056
1866
|
const events = [];
|
|
5057
1867
|
for (const [index, event] of value.entries()) {
|
|
5058
1868
|
const eventPath = `${pathPrefix}[${index}]`;
|
|
5059
|
-
if (!
|
|
1869
|
+
if (!isRecord2(event)) {
|
|
5060
1870
|
unsupportedFields.push(eventPath);
|
|
5061
1871
|
continue;
|
|
5062
1872
|
}
|
|
@@ -5194,7 +2004,7 @@ function mapOtlpSpan(context) {
|
|
|
5194
2004
|
warnings.push(...kindWarnings);
|
|
5195
2005
|
const status = mapOtlpStatus(span.status);
|
|
5196
2006
|
const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
|
|
5197
|
-
const errorMessage =
|
|
2007
|
+
const errorMessage = isRecord2(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
|
|
5198
2008
|
const event = {
|
|
5199
2009
|
schemaVersion: "0.2",
|
|
5200
2010
|
eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
|
|
@@ -5659,7 +2469,7 @@ function printSummary(summary) {
|
|
|
5659
2469
|
console.log(`Name: ${summary.name ?? "unnamed"}`);
|
|
5660
2470
|
console.log(`Status: ${summary.status}`);
|
|
5661
2471
|
console.log(
|
|
5662
|
-
`Duration: ${summary.durationMs !== void 0 ?
|
|
2472
|
+
`Duration: ${summary.durationMs !== void 0 ? formatDuration(summary.durationMs) : "-"}`
|
|
5663
2473
|
);
|
|
5664
2474
|
console.log(`Total steps: ${summary.totalSteps}`);
|
|
5665
2475
|
console.log(`LLM steps: ${summary.llmSteps}`);
|
|
@@ -5669,7 +2479,7 @@ function printSummary(summary) {
|
|
|
5669
2479
|
console.log(`Max depth: ${summary.maxDepth}`);
|
|
5670
2480
|
if (summary.longestStep) {
|
|
5671
2481
|
console.log(
|
|
5672
|
-
`Longest step: ${summary.longestStep.name} (${
|
|
2482
|
+
`Longest step: ${summary.longestStep.name} (${formatDuration(
|
|
5673
2483
|
summary.longestStep.durationMs
|
|
5674
2484
|
)}, ${summary.longestStep.type})`
|
|
5675
2485
|
);
|
|
@@ -5687,7 +2497,7 @@ function printMetadata(meta) {
|
|
|
5687
2497
|
`Ended: ${meta.endedAt !== void 0 ? formatTimestamp(meta.endedAt) : "-"}`
|
|
5688
2498
|
);
|
|
5689
2499
|
console.log(
|
|
5690
|
-
`Duration: ${meta.durationMs !== void 0 ?
|
|
2500
|
+
`Duration: ${meta.durationMs !== void 0 ? formatDuration(meta.durationMs) : "-"}`
|
|
5691
2501
|
);
|
|
5692
2502
|
console.log(`Event count: ${meta.eventCount}`);
|
|
5693
2503
|
console.log(`File path: ${meta.filePath}`);
|
|
@@ -5798,7 +2608,7 @@ async function view(runId, options = {}) {
|
|
|
5798
2608
|
);
|
|
5799
2609
|
const last = completed[completed.length - 1];
|
|
5800
2610
|
const status = last ? last.status : "running";
|
|
5801
|
-
const durationLine = last !== void 0 && Number.isFinite(last.durationMs) ?
|
|
2611
|
+
const durationLine = last !== void 0 && Number.isFinite(last.durationMs) ? formatDuration(last.durationMs) : "-";
|
|
5802
2612
|
const startedTs = Number.isFinite(started.startTime) ? started.startTime : started.timestamp;
|
|
5803
2613
|
const startedLabel = formatTimestamp(startedTs);
|
|
5804
2614
|
console.log(`AgentInspect Run: ${started.name}`);
|
|
@@ -5822,7 +2632,7 @@ async function view(runId, options = {}) {
|
|
|
5822
2632
|
process.exitCode = 1;
|
|
5823
2633
|
}
|
|
5824
2634
|
}
|
|
5825
|
-
function
|
|
2635
|
+
function isRecord3(v) {
|
|
5826
2636
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
5827
2637
|
}
|
|
5828
2638
|
function isNonEmptyStringArray(v) {
|
|
@@ -5834,7 +2644,7 @@ function validateRedact(redact2) {
|
|
|
5834
2644
|
}
|
|
5835
2645
|
for (const r of redact2) {
|
|
5836
2646
|
if (typeof r === "string") continue;
|
|
5837
|
-
if (!
|
|
2647
|
+
if (!isRecord3(r)) {
|
|
5838
2648
|
throw new Error("Invalid config: redact entries must be strings or objects");
|
|
5839
2649
|
}
|
|
5840
2650
|
if (typeof r.key !== "string" || r.key.trim() === "") {
|
|
@@ -5853,7 +2663,7 @@ function validateRedact(redact2) {
|
|
|
5853
2663
|
}
|
|
5854
2664
|
}
|
|
5855
2665
|
function validateMappings(mappings) {
|
|
5856
|
-
if (!
|
|
2666
|
+
if (!isRecord3(mappings)) {
|
|
5857
2667
|
throw new Error("Invalid config: mappings must be an object");
|
|
5858
2668
|
}
|
|
5859
2669
|
}
|
|
@@ -5903,7 +2713,7 @@ async function loadLogIngestConfig(configPath) {
|
|
|
5903
2713
|
const msg = e instanceof Error ? e.message : String(e);
|
|
5904
2714
|
throw new Error(`Invalid JSON in config file: ${configPath} (${msg})`);
|
|
5905
2715
|
}
|
|
5906
|
-
if (!
|
|
2716
|
+
if (!isRecord3(parsed)) {
|
|
5907
2717
|
throw new Error("Invalid config: expected a JSON object at top-level");
|
|
5908
2718
|
}
|
|
5909
2719
|
const user = parsed;
|
|
@@ -5940,7 +2750,7 @@ async function loadLogIngestConfig(configPath) {
|
|
|
5940
2750
|
}
|
|
5941
2751
|
return mergeLogIngestConfig(DEFAULT_LOG_INGEST_CONFIG, user);
|
|
5942
2752
|
}
|
|
5943
|
-
function
|
|
2753
|
+
function isRecord4(v) {
|
|
5944
2754
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
5945
2755
|
}
|
|
5946
2756
|
var JsonLogParser = class {
|
|
@@ -5965,7 +2775,7 @@ var JsonLogParser = class {
|
|
|
5965
2775
|
});
|
|
5966
2776
|
continue;
|
|
5967
2777
|
}
|
|
5968
|
-
if (!
|
|
2778
|
+
if (!isRecord4(parsed)) {
|
|
5969
2779
|
warnings.push({
|
|
5970
2780
|
code: "MALFORMED_JSON",
|
|
5971
2781
|
message: "JSON log line must be an object",
|
|
@@ -5996,7 +2806,7 @@ var JsonLogParser = class {
|
|
|
5996
2806
|
return this.parseLines(lines, filePath);
|
|
5997
2807
|
}
|
|
5998
2808
|
};
|
|
5999
|
-
function
|
|
2809
|
+
function isRecord5(v) {
|
|
6000
2810
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
6001
2811
|
}
|
|
6002
2812
|
function findLastJsonObjectSubstring(line) {
|
|
@@ -6072,7 +2882,7 @@ var Log4jsParser = class {
|
|
|
6072
2882
|
});
|
|
6073
2883
|
continue;
|
|
6074
2884
|
}
|
|
6075
|
-
if (!
|
|
2885
|
+
if (!isRecord5(parsed)) {
|
|
6076
2886
|
warnings.push({
|
|
6077
2887
|
code: "UNSUPPORTED_LOG4JS_PAYLOAD",
|
|
6078
2888
|
message: "Embedded JSON payload must be an object",
|
|
@@ -6143,7 +2953,7 @@ function matchMapping(eventName, mappings) {
|
|
|
6143
2953
|
}
|
|
6144
2954
|
|
|
6145
2955
|
// packages/core/src/logs/normalizer.ts
|
|
6146
|
-
function
|
|
2956
|
+
function isFiniteNumber(v) {
|
|
6147
2957
|
return typeof v === "number" && Number.isFinite(v);
|
|
6148
2958
|
}
|
|
6149
2959
|
function safeString(v) {
|
|
@@ -6152,7 +2962,7 @@ function safeString(v) {
|
|
|
6152
2962
|
return t === "" ? void 0 : t;
|
|
6153
2963
|
}
|
|
6154
2964
|
function parseTimestamp(v) {
|
|
6155
|
-
if (
|
|
2965
|
+
if (isFiniteNumber(v)) return v;
|
|
6156
2966
|
if (typeof v === "string") {
|
|
6157
2967
|
const t = Date.parse(v);
|
|
6158
2968
|
if (Number.isFinite(t)) return t;
|
|
@@ -6235,8 +3045,8 @@ var EventNormalizer = class {
|
|
|
6235
3045
|
const durationKey = cfg.durationKey;
|
|
6236
3046
|
if (durationKey) {
|
|
6237
3047
|
const v = raw[durationKey];
|
|
6238
|
-
if (
|
|
6239
|
-
} else if (
|
|
3048
|
+
if (isFiniteNumber(v)) durationMs2 = v;
|
|
3049
|
+
} else if (isFiniteNumber(raw.durationMs)) {
|
|
6240
3050
|
durationMs2 = raw.durationMs;
|
|
6241
3051
|
}
|
|
6242
3052
|
let status;
|
|
@@ -6720,8 +3530,8 @@ function sleep(ms) {
|
|
|
6720
3530
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6721
3531
|
}
|
|
6722
3532
|
async function* readStdinLines() {
|
|
6723
|
-
const { createInterface
|
|
6724
|
-
const rl =
|
|
3533
|
+
const { createInterface } = await import('readline');
|
|
3534
|
+
const rl = createInterface({ input: stdin, crlfDelay: Infinity });
|
|
6725
3535
|
try {
|
|
6726
3536
|
for await (const line of rl) {
|
|
6727
3537
|
yield line;
|
|
@@ -6929,7 +3739,7 @@ async function tail(options = {}) {
|
|
|
6929
3739
|
var EXPORT_PAYLOAD_VERSION = "0.1.2";
|
|
6930
3740
|
|
|
6931
3741
|
// packages/core/src/exporters/redact-export.ts
|
|
6932
|
-
function
|
|
3742
|
+
function isRecord6(value) {
|
|
6933
3743
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6934
3744
|
}
|
|
6935
3745
|
function deepClone(value) {
|
|
@@ -7003,7 +3813,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
|
|
|
7003
3813
|
0
|
|
7004
3814
|
);
|
|
7005
3815
|
const err = bounded.error;
|
|
7006
|
-
if (
|
|
3816
|
+
if (isRecord6(err) && typeof err.message === "string") {
|
|
7007
3817
|
bounded.error = {
|
|
7008
3818
|
...err,
|
|
7009
3819
|
message: truncateStringForProfile(
|
|
@@ -7033,7 +3843,7 @@ function redactErrorInfo(error, redactor, maxMetadataValueLength, maxPreviewLeng
|
|
|
7033
3843
|
maxPreviewLength
|
|
7034
3844
|
);
|
|
7035
3845
|
const redacted = record?.error;
|
|
7036
|
-
if (!
|
|
3846
|
+
if (!isRecord6(redacted) || typeof redacted.message !== "string") {
|
|
7037
3847
|
return void 0;
|
|
7038
3848
|
}
|
|
7039
3849
|
return {
|
|
@@ -8214,9 +5024,9 @@ Trace directory: ${traceDir}`);
|
|
|
8214
5024
|
if (validation !== void 0 && !validation.ok) {
|
|
8215
5025
|
process.exitCode = 1;
|
|
8216
5026
|
}
|
|
8217
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
5027
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path10.resolve(options.output.trim()) : void 0;
|
|
8218
5028
|
if (outPath !== void 0) {
|
|
8219
|
-
await mkdir(
|
|
5029
|
+
await mkdir(path10.dirname(outPath), { recursive: true });
|
|
8220
5030
|
await writeFile(outPath, result.content, "utf-8");
|
|
8221
5031
|
const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
|
|
8222
5032
|
console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
|
|
@@ -8393,13 +5203,13 @@ function pairSteps(left, right) {
|
|
|
8393
5203
|
return pairs;
|
|
8394
5204
|
}
|
|
8395
5205
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
8396
|
-
const
|
|
5206
|
+
const path17 = buildPath(segments);
|
|
8397
5207
|
if (L.name !== R.name) {
|
|
8398
5208
|
out.push({
|
|
8399
5209
|
kind: "structure",
|
|
8400
5210
|
severity: "warning",
|
|
8401
5211
|
message: "Step name differs",
|
|
8402
|
-
path:
|
|
5212
|
+
path: path17,
|
|
8403
5213
|
left: L.name,
|
|
8404
5214
|
right: R.name
|
|
8405
5215
|
});
|
|
@@ -8409,7 +5219,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8409
5219
|
kind: "step-type",
|
|
8410
5220
|
severity: "warning",
|
|
8411
5221
|
message: "Step type differs",
|
|
8412
|
-
path:
|
|
5222
|
+
path: path17,
|
|
8413
5223
|
left: L.type,
|
|
8414
5224
|
right: R.type
|
|
8415
5225
|
});
|
|
@@ -8419,7 +5229,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8419
5229
|
kind: "step-status",
|
|
8420
5230
|
severity: "warning",
|
|
8421
5231
|
message: "Step status differs",
|
|
8422
|
-
path:
|
|
5232
|
+
path: path17,
|
|
8423
5233
|
left: L.status,
|
|
8424
5234
|
right: R.status
|
|
8425
5235
|
});
|
|
@@ -8431,7 +5241,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8431
5241
|
kind: "error",
|
|
8432
5242
|
severity: "error",
|
|
8433
5243
|
message: "Step error message differs",
|
|
8434
|
-
path:
|
|
5244
|
+
path: path17,
|
|
8435
5245
|
left: le || void 0,
|
|
8436
5246
|
right: re || void 0
|
|
8437
5247
|
});
|
|
@@ -8449,7 +5259,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8449
5259
|
kind: "duration",
|
|
8450
5260
|
severity: "info",
|
|
8451
5261
|
message: "Step duration differs",
|
|
8452
|
-
path:
|
|
5262
|
+
path: path17,
|
|
8453
5263
|
left: ld,
|
|
8454
5264
|
right: rd
|
|
8455
5265
|
});
|
|
@@ -8462,7 +5272,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8462
5272
|
kind: "metadata",
|
|
8463
5273
|
severity: "info",
|
|
8464
5274
|
message: "Step metadata differs",
|
|
8465
|
-
path:
|
|
5275
|
+
path: path17,
|
|
8466
5276
|
left: L.metadata,
|
|
8467
5277
|
right: R.metadata
|
|
8468
5278
|
});
|
|
@@ -8474,7 +5284,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
8474
5284
|
kind: "output",
|
|
8475
5285
|
severity: "info",
|
|
8476
5286
|
message: "Output preview differs",
|
|
8477
|
-
path:
|
|
5287
|
+
path: path17,
|
|
8478
5288
|
left: L.outputPreview,
|
|
8479
5289
|
right: R.outputPreview
|
|
8480
5290
|
});
|
|
@@ -8634,11 +5444,11 @@ function diffRuns(left, right, options) {
|
|
|
8634
5444
|
}
|
|
8635
5445
|
|
|
8636
5446
|
// packages/core/src/diff/renderer.ts
|
|
8637
|
-
function formatPath(
|
|
8638
|
-
if (
|
|
5447
|
+
function formatPath(path17) {
|
|
5448
|
+
if (path17 === void 0 || path17.path.length === 0) {
|
|
8639
5449
|
return "(run)";
|
|
8640
5450
|
}
|
|
8641
|
-
return
|
|
5451
|
+
return path17.path.map((s) => s.name).join(" > ");
|
|
8642
5452
|
}
|
|
8643
5453
|
function formatValue(v, verbose) {
|
|
8644
5454
|
if (v === void 0) return "(undefined)";
|
|
@@ -9271,9 +6081,9 @@ async function reportCommand(runId, options = {}) {
|
|
|
9271
6081
|
redactionProfile,
|
|
9272
6082
|
correlation: !options.noCorrelation
|
|
9273
6083
|
});
|
|
9274
|
-
const outPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
6084
|
+
const outPath = options.output !== void 0 && options.output.trim() !== "" ? path10.resolve(options.output.trim()) : void 0;
|
|
9275
6085
|
if (outPath !== void 0) {
|
|
9276
|
-
await mkdir(
|
|
6086
|
+
await mkdir(path10.dirname(outPath), { recursive: true });
|
|
9277
6087
|
await writeFile(outPath, result.content, "utf-8");
|
|
9278
6088
|
console.log(`Wrote ${result.fileExtension} report to ${outPath}`);
|
|
9279
6089
|
}
|
|
@@ -9302,7 +6112,7 @@ var DEFAULT_REDACT_KEYS2 = [
|
|
|
9302
6112
|
"secret",
|
|
9303
6113
|
"email"
|
|
9304
6114
|
];
|
|
9305
|
-
var
|
|
6115
|
+
var SHARE_PROFILE_EXTRA_KEYS = [
|
|
9306
6116
|
"userEmail",
|
|
9307
6117
|
"customerEmail",
|
|
9308
6118
|
"phone",
|
|
@@ -9325,7 +6135,7 @@ var SHARE_PROFILE_EXTRA_KEYS2 = [
|
|
|
9325
6135
|
"spanId",
|
|
9326
6136
|
"parentSpanId"
|
|
9327
6137
|
];
|
|
9328
|
-
var
|
|
6138
|
+
var STRICT_PROFILE_EXTRA_KEYS = [
|
|
9329
6139
|
"prompt",
|
|
9330
6140
|
"completion",
|
|
9331
6141
|
"input",
|
|
@@ -9343,13 +6153,13 @@ var STRICT_PROFILE_EXTRA_KEYS2 = [
|
|
|
9343
6153
|
"retrieval",
|
|
9344
6154
|
"query"
|
|
9345
6155
|
];
|
|
9346
|
-
function
|
|
6156
|
+
function isRecord7(value) {
|
|
9347
6157
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9348
6158
|
}
|
|
9349
|
-
function
|
|
6159
|
+
function toKey(key) {
|
|
9350
6160
|
return key.toLowerCase();
|
|
9351
6161
|
}
|
|
9352
|
-
function
|
|
6162
|
+
function stableHash(value) {
|
|
9353
6163
|
const hash = crypto.createHash("sha256").update(value, "utf8").digest("hex");
|
|
9354
6164
|
return hash.slice(0, 8);
|
|
9355
6165
|
}
|
|
@@ -9471,10 +6281,10 @@ function builtInDetectorsForProfile(profile) {
|
|
|
9471
6281
|
if (profile === "local") return credentialDetectors;
|
|
9472
6282
|
return [...credentialDetectors, ...identifierDetectors];
|
|
9473
6283
|
}
|
|
9474
|
-
function
|
|
6284
|
+
function compileRules(rules, extraKeys) {
|
|
9475
6285
|
const out = /* @__PURE__ */ new Map();
|
|
9476
6286
|
const set = (rule) => {
|
|
9477
|
-
const key =
|
|
6287
|
+
const key = toKey(rule.key);
|
|
9478
6288
|
out.set(key, { ...rule, key });
|
|
9479
6289
|
};
|
|
9480
6290
|
for (const key of DEFAULT_REDACT_KEYS2) {
|
|
@@ -9516,21 +6326,21 @@ function applyRule(rule, value, replacement) {
|
|
|
9516
6326
|
}
|
|
9517
6327
|
if (rule.strategy === "hash") {
|
|
9518
6328
|
if (asString === void 0) return "[HASH:unknown]";
|
|
9519
|
-
return `[HASH:${
|
|
6329
|
+
return `[HASH:${stableHash(asString)}]`;
|
|
9520
6330
|
}
|
|
9521
6331
|
return value;
|
|
9522
6332
|
}
|
|
9523
|
-
function childPath(
|
|
6333
|
+
function childPath(path17, key) {
|
|
9524
6334
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
9525
|
-
return
|
|
6335
|
+
return path17 ? `${path17}.${key}` : key;
|
|
9526
6336
|
}
|
|
9527
|
-
return `${
|
|
6337
|
+
return `${path17 || "$"}[${JSON.stringify(key)}]`;
|
|
9528
6338
|
}
|
|
9529
|
-
function indexPath(
|
|
9530
|
-
return `${
|
|
6339
|
+
function indexPath(path17, index) {
|
|
6340
|
+
return `${path17 || "$"}[${index}]`;
|
|
9531
6341
|
}
|
|
9532
|
-
function makeFinding(
|
|
9533
|
-
return preview === void 0 ? { path:
|
|
6342
|
+
function makeFinding(path17, detector, action, matchKind, severity = "warning", preview) {
|
|
6343
|
+
return preview === void 0 ? { path: path17, detector, action, severity, matchKind } : { path: path17, detector, action, severity, matchKind, preview };
|
|
9534
6344
|
}
|
|
9535
6345
|
function createRedactionProfile(profile = "local") {
|
|
9536
6346
|
switch (profile) {
|
|
@@ -9539,14 +6349,14 @@ function createRedactionProfile(profile = "local") {
|
|
|
9539
6349
|
case "share":
|
|
9540
6350
|
return {
|
|
9541
6351
|
profile: "share",
|
|
9542
|
-
extraKeys:
|
|
6352
|
+
extraKeys: SHARE_PROFILE_EXTRA_KEYS,
|
|
9543
6353
|
maxMetadataValueLengthCap: 500,
|
|
9544
6354
|
maxPreviewLengthCap: 200
|
|
9545
6355
|
};
|
|
9546
6356
|
case "strict":
|
|
9547
6357
|
return {
|
|
9548
6358
|
profile: "strict",
|
|
9549
|
-
extraKeys: [...
|
|
6359
|
+
extraKeys: [...SHARE_PROFILE_EXTRA_KEYS, ...STRICT_PROFILE_EXTRA_KEYS],
|
|
9550
6360
|
maxMetadataValueLengthCap: 200,
|
|
9551
6361
|
maxPreviewLengthCap: 80
|
|
9552
6362
|
};
|
|
@@ -9562,7 +6372,7 @@ var Redactor2 = class {
|
|
|
9562
6372
|
constructor(options) {
|
|
9563
6373
|
const resolved = createRedactionProfile(options?.profile ?? "local");
|
|
9564
6374
|
this.#profile = resolved.profile;
|
|
9565
|
-
this.#rules =
|
|
6375
|
+
this.#rules = compileRules(options?.rules, [
|
|
9566
6376
|
...resolved.extraKeys,
|
|
9567
6377
|
...options?.extraKeys ?? []
|
|
9568
6378
|
]);
|
|
@@ -9599,32 +6409,32 @@ var Redactor2 = class {
|
|
|
9599
6409
|
#recordFinding(state, finding) {
|
|
9600
6410
|
if (this.#collectFindings) state.findings.push(finding);
|
|
9601
6411
|
}
|
|
9602
|
-
#redactValue(value, key,
|
|
6412
|
+
#redactValue(value, key, path17, depth, state) {
|
|
9603
6413
|
if (depth > this.#maxDepth) {
|
|
9604
6414
|
this.#recordFinding(
|
|
9605
6415
|
state,
|
|
9606
|
-
makeFinding(
|
|
6416
|
+
makeFinding(path17, "structure.maxDepth", "truncate", "value", "warning")
|
|
9607
6417
|
);
|
|
9608
6418
|
return "[Truncated]";
|
|
9609
6419
|
}
|
|
9610
6420
|
if (key !== void 0) {
|
|
9611
|
-
const rule = this.#rules.find((candidate) => candidate.key ===
|
|
6421
|
+
const rule = this.#rules.find((candidate) => candidate.key === toKey(key));
|
|
9612
6422
|
if (rule) {
|
|
9613
6423
|
this.#recordFinding(
|
|
9614
6424
|
state,
|
|
9615
|
-
makeFinding(
|
|
6425
|
+
makeFinding(path17, `key.${rule.key}`, actionForRule(rule), "key", "warning")
|
|
9616
6426
|
);
|
|
9617
6427
|
return applyRule(rule, value, this.#replacement);
|
|
9618
6428
|
}
|
|
9619
6429
|
}
|
|
9620
6430
|
for (const detector of this.#detectors) {
|
|
9621
|
-
const detections = detector.detect({ path:
|
|
6431
|
+
const detections = detector.detect({ path: path17, key, value });
|
|
9622
6432
|
for (const detection of detections) {
|
|
9623
6433
|
const action = detection.action ?? "replace";
|
|
9624
6434
|
this.#recordFinding(
|
|
9625
6435
|
state,
|
|
9626
6436
|
makeFinding(
|
|
9627
|
-
|
|
6437
|
+
path17,
|
|
9628
6438
|
detector.id,
|
|
9629
6439
|
action,
|
|
9630
6440
|
detection.matchKind ?? detector.matchKind ?? "custom",
|
|
@@ -9642,11 +6452,11 @@ var Redactor2 = class {
|
|
|
9642
6452
|
const out = [];
|
|
9643
6453
|
state.seen.set(value, out);
|
|
9644
6454
|
value.forEach((item, index) => {
|
|
9645
|
-
out[index] = this.#redactValue(item, void 0, indexPath(
|
|
6455
|
+
out[index] = this.#redactValue(item, void 0, indexPath(path17, index), depth + 1, state);
|
|
9646
6456
|
});
|
|
9647
6457
|
return out;
|
|
9648
6458
|
}
|
|
9649
|
-
if (
|
|
6459
|
+
if (isRecord7(value)) {
|
|
9650
6460
|
if (state.seen.has(value)) return state.seen.get(value);
|
|
9651
6461
|
const out = {};
|
|
9652
6462
|
state.seen.set(value, out);
|
|
@@ -9654,7 +6464,7 @@ var Redactor2 = class {
|
|
|
9654
6464
|
out[entryKey] = this.#redactValue(
|
|
9655
6465
|
entryValue,
|
|
9656
6466
|
entryKey,
|
|
9657
|
-
childPath(
|
|
6467
|
+
childPath(path17 === "$" ? "" : path17, entryKey),
|
|
9658
6468
|
depth + 1,
|
|
9659
6469
|
state
|
|
9660
6470
|
);
|
|
@@ -9842,8 +6652,8 @@ function renderHuman(result) {
|
|
|
9842
6652
|
"",
|
|
9843
6653
|
"Facts:"
|
|
9844
6654
|
];
|
|
9845
|
-
for (const
|
|
9846
|
-
lines.push(`- ${
|
|
6655
|
+
for (const fact of result.facts) {
|
|
6656
|
+
lines.push(`- ${fact.id}: ${JSON.stringify(fact.value)}`);
|
|
9847
6657
|
}
|
|
9848
6658
|
lines.push("", "Inferences:");
|
|
9849
6659
|
if (result.inferences.length === 0) {
|
|
@@ -9975,7 +6785,7 @@ function printWarnings(result) {
|
|
|
9975
6785
|
function printNode(node, depth) {
|
|
9976
6786
|
const ev = node.event;
|
|
9977
6787
|
const status = ev.status !== void 0 ? ` ${ev.status}` : "";
|
|
9978
|
-
const duration = ev.durationMs !== void 0 ? ` ${
|
|
6788
|
+
const duration = ev.durationMs !== void 0 ? ` ${formatDuration(ev.durationMs)}` : "";
|
|
9979
6789
|
console.log(`${getIndent(depth)}${ev.kind.toLowerCase()}: ${ev.name}${status}${duration}`);
|
|
9980
6790
|
for (const child of node.children) {
|
|
9981
6791
|
printNode(child, depth + 1);
|
|
@@ -9990,7 +6800,7 @@ function printRun(result, run) {
|
|
|
9990
6800
|
console.log(`Started: ${formatTimestamp(run.startedAt)}`);
|
|
9991
6801
|
}
|
|
9992
6802
|
if (run.durationMs !== void 0) {
|
|
9993
|
-
console.log(`Duration: ${
|
|
6803
|
+
console.log(`Duration: ${formatDuration(run.durationMs)}`);
|
|
9994
6804
|
}
|
|
9995
6805
|
console.log(`Events: ${run.metadata.totalEvents}`);
|
|
9996
6806
|
for (const node of run.children) {
|
|
@@ -10079,7 +6889,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
|
|
|
10079
6889
|
}
|
|
10080
6890
|
}
|
|
10081
6891
|
}
|
|
10082
|
-
function
|
|
6892
|
+
function isRecord8(value) {
|
|
10083
6893
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10084
6894
|
}
|
|
10085
6895
|
function parseTarget(value) {
|
|
@@ -10088,7 +6898,7 @@ function parseTarget(value) {
|
|
|
10088
6898
|
throw new Error('Unsupported migration target. Use "--to 1.0".');
|
|
10089
6899
|
}
|
|
10090
6900
|
function formatOf(value) {
|
|
10091
|
-
if (!
|
|
6901
|
+
if (!isRecord8(value)) return "unknown";
|
|
10092
6902
|
if (value.schemaVersion === "0.1") return "0.1";
|
|
10093
6903
|
if (value.schemaVersion === "0.2") return "0.2";
|
|
10094
6904
|
if (value.schemaVersion === "1.0") return "1.0";
|
|
@@ -10101,14 +6911,14 @@ function uniqueSorted(values) {
|
|
|
10101
6911
|
return [...new Set(values)].sort();
|
|
10102
6912
|
}
|
|
10103
6913
|
function isWithinDirectory(child, parent) {
|
|
10104
|
-
const relative =
|
|
10105
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
6914
|
+
const relative = path10.relative(parent, child);
|
|
6915
|
+
return relative === "" || !relative.startsWith("..") && !path10.isAbsolute(relative);
|
|
10106
6916
|
}
|
|
10107
6917
|
async function resolveOutputPath(inputPath, output2, force) {
|
|
10108
6918
|
if (output2 === void 0 || output2.trim() === "") return void 0;
|
|
10109
|
-
const inputAbs =
|
|
10110
|
-
const outputAbs =
|
|
10111
|
-
const inputDir =
|
|
6919
|
+
const inputAbs = path10.resolve(inputPath);
|
|
6920
|
+
const outputAbs = path10.resolve(output2.trim());
|
|
6921
|
+
const inputDir = path10.dirname(inputAbs);
|
|
10112
6922
|
if (!isWithinDirectory(outputAbs, inputDir)) {
|
|
10113
6923
|
throw new Error("Refusing to write migrated output outside the input directory.");
|
|
10114
6924
|
}
|
|
@@ -10229,7 +7039,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
10229
7039
|
process.exitCode = 1;
|
|
10230
7040
|
return;
|
|
10231
7041
|
}
|
|
10232
|
-
const inputPath =
|
|
7042
|
+
const inputPath = path10.resolve(input3.trim());
|
|
10233
7043
|
const dryRun = options.dryRun === true;
|
|
10234
7044
|
if (!dryRun && (options.output === void 0 || options.output.trim() === "")) {
|
|
10235
7045
|
console.error("migrate requires --dry-run or --output <path>.");
|
|
@@ -10248,7 +7058,7 @@ async function migrateCommand(input3, options = {}) {
|
|
|
10248
7058
|
);
|
|
10249
7059
|
const result = await buildMigration(inputPath, outputPath);
|
|
10250
7060
|
if (!dryRun && outputPath !== void 0) {
|
|
10251
|
-
await mkdir(
|
|
7061
|
+
await mkdir(path10.dirname(outputPath), { recursive: true });
|
|
10252
7062
|
await writeFile(outputPath, result.content, "utf-8");
|
|
10253
7063
|
}
|
|
10254
7064
|
printSummary2(result, dryRun);
|
|
@@ -10325,7 +7135,7 @@ function diagnostic(code, message, ruleId) {
|
|
|
10325
7135
|
...ruleId ? { ruleId } : {}
|
|
10326
7136
|
};
|
|
10327
7137
|
}
|
|
10328
|
-
function
|
|
7138
|
+
function emptySummary() {
|
|
10329
7139
|
return {
|
|
10330
7140
|
passed: 0,
|
|
10331
7141
|
failed: 0,
|
|
@@ -10340,7 +7150,7 @@ function errorResult(input3, diagnostics, selectedRun) {
|
|
|
10340
7150
|
format: input3.read.format,
|
|
10341
7151
|
...selectedRun ? { runId: selectedRun.runId } : {},
|
|
10342
7152
|
summary: {
|
|
10343
|
-
...
|
|
7153
|
+
...emptySummary(),
|
|
10344
7154
|
errors: diagnostics.filter((item) => item.severity === "error").length
|
|
10345
7155
|
},
|
|
10346
7156
|
findings: [],
|
|
@@ -10350,7 +7160,7 @@ function errorResult(input3, diagnostics, selectedRun) {
|
|
|
10350
7160
|
function flattenNodes(nodes) {
|
|
10351
7161
|
return nodes.flatMap((node) => [node, ...flattenNodes(node.children)]);
|
|
10352
7162
|
}
|
|
10353
|
-
function
|
|
7163
|
+
function buildFacts(input3, selectedRun) {
|
|
10354
7164
|
const scopedRuns = selectedRun ? [selectedRun] : input3.read.runs;
|
|
10355
7165
|
const scopedRunIds = new Set(scopedRuns.map((run) => run.runId));
|
|
10356
7166
|
const scopedEvents = selectedRun === void 0 ? input3.read.events : input3.read.events.filter((event) => scopedRunIds.has(event.runId));
|
|
@@ -10526,7 +7336,7 @@ function stripPrefix(name, prefixes) {
|
|
|
10526
7336
|
}
|
|
10527
7337
|
return name;
|
|
10528
7338
|
}
|
|
10529
|
-
function eventEvidence(event,
|
|
7339
|
+
function eventEvidence(event, path17) {
|
|
10530
7340
|
return {
|
|
10531
7341
|
runId: event.runId,
|
|
10532
7342
|
eventId: event.eventId,
|
|
@@ -10536,7 +7346,7 @@ function eventEvidence(event, path20) {
|
|
|
10536
7346
|
kind: event.kind,
|
|
10537
7347
|
name: event.name,
|
|
10538
7348
|
status: event.status,
|
|
10539
|
-
...
|
|
7349
|
+
...path17 ? { path: path17 } : {}
|
|
10540
7350
|
};
|
|
10541
7351
|
}
|
|
10542
7352
|
function runEvidence(run) {
|
|
@@ -10573,7 +7383,7 @@ function finishedEvents(context, kind) {
|
|
|
10573
7383
|
(event) => (kind === void 0 || event.kind === kind) && event.status !== "running"
|
|
10574
7384
|
);
|
|
10575
7385
|
}
|
|
10576
|
-
function
|
|
7386
|
+
function isRecord9(value) {
|
|
10577
7387
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10578
7388
|
}
|
|
10579
7389
|
function eventMap(events) {
|
|
@@ -10599,9 +7409,9 @@ function eventEndMs(event) {
|
|
|
10599
7409
|
function normalizedKey(value) {
|
|
10600
7410
|
return value.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
10601
7411
|
}
|
|
10602
|
-
function lastPathSegment(
|
|
10603
|
-
const parts =
|
|
10604
|
-
return parts[parts.length - 1] ??
|
|
7412
|
+
function lastPathSegment(path17) {
|
|
7413
|
+
const parts = path17.split(".");
|
|
7414
|
+
return parts[parts.length - 1] ?? path17;
|
|
10605
7415
|
}
|
|
10606
7416
|
function valueType(value) {
|
|
10607
7417
|
if (Array.isArray(value)) return "array";
|
|
@@ -10615,22 +7425,22 @@ function serializedByteLength(value) {
|
|
|
10615
7425
|
return void 0;
|
|
10616
7426
|
}
|
|
10617
7427
|
}
|
|
10618
|
-
function pushValueEntries(entries, event, value,
|
|
10619
|
-
entries.push({ event, path:
|
|
7428
|
+
function pushValueEntries(entries, event, value, path17, key, depth = 0) {
|
|
7429
|
+
entries.push({ event, path: path17, key, value });
|
|
10620
7430
|
if (depth >= 8) return;
|
|
10621
7431
|
if (Array.isArray(value)) {
|
|
10622
7432
|
for (const [index, item] of value.entries()) {
|
|
10623
|
-
pushValueEntries(entries, event, item, `${
|
|
7433
|
+
pushValueEntries(entries, event, item, `${path17}.${index}`, String(index), depth + 1);
|
|
10624
7434
|
}
|
|
10625
7435
|
return;
|
|
10626
7436
|
}
|
|
10627
|
-
if (!
|
|
7437
|
+
if (!isRecord9(value)) return;
|
|
10628
7438
|
for (const nestedKey of Object.keys(value).sort((a, b) => a.localeCompare(b))) {
|
|
10629
7439
|
pushValueEntries(
|
|
10630
7440
|
entries,
|
|
10631
7441
|
event,
|
|
10632
7442
|
value[nestedKey],
|
|
10633
|
-
`${
|
|
7443
|
+
`${path17}.${nestedKey}`,
|
|
10634
7444
|
nestedKey,
|
|
10635
7445
|
depth + 1
|
|
10636
7446
|
);
|
|
@@ -10711,9 +7521,9 @@ function eventDurationMs(event) {
|
|
|
10711
7521
|
}
|
|
10712
7522
|
function treeShape(nodes) {
|
|
10713
7523
|
const lines = [];
|
|
10714
|
-
const visit = (node,
|
|
10715
|
-
lines.push(`${
|
|
10716
|
-
node.children.forEach((child, index) => visit(child, `${
|
|
7524
|
+
const visit = (node, path17) => {
|
|
7525
|
+
lines.push(`${path17}:${node.event.kind}:${node.event.name}:${node.event.status ?? "unknown"}`);
|
|
7526
|
+
node.children.forEach((child, index) => visit(child, `${path17}.${index}`));
|
|
10717
7527
|
};
|
|
10718
7528
|
nodes.forEach((node, index) => visit(node, String(index)));
|
|
10719
7529
|
return lines;
|
|
@@ -10762,9 +7572,9 @@ function retrievalShape(context) {
|
|
|
10762
7572
|
function guardrailShape(context) {
|
|
10763
7573
|
return guardrailEvents(context).map((event) => signalName(event, ["guardrailName", "guardrail", "guardrailId"], ["guardrail:"])).sort((a, b) => a.localeCompare(b));
|
|
10764
7574
|
}
|
|
10765
|
-
function firstEvidenceForKind(context, kind,
|
|
7575
|
+
function firstEvidenceForKind(context, kind, path17) {
|
|
10766
7576
|
const event = context.events.find((candidate) => candidate.kind === kind);
|
|
10767
|
-
return event ? [eventEvidence(event,
|
|
7577
|
+
return event ? [eventEvidence(event, path17)] : runEvidence(context.selectedRun);
|
|
10768
7578
|
}
|
|
10769
7579
|
function baselineDiffFinding(message, evidence, expected, actual) {
|
|
10770
7580
|
return failFinding("baseline.regression", message, evidence, expected, actual);
|
|
@@ -11114,13 +7924,13 @@ function createStructureCycleRule() {
|
|
|
11114
7924
|
const seenCycles = /* @__PURE__ */ new Set();
|
|
11115
7925
|
const findings = [];
|
|
11116
7926
|
for (const event of [...context.events].sort((a, b) => a.eventId.localeCompare(b.eventId))) {
|
|
11117
|
-
const
|
|
7927
|
+
const path17 = [];
|
|
11118
7928
|
const seenAt = /* @__PURE__ */ new Map();
|
|
11119
7929
|
let current = event;
|
|
11120
7930
|
while (current) {
|
|
11121
7931
|
const existing = seenAt.get(current.eventId);
|
|
11122
7932
|
if (existing !== void 0) {
|
|
11123
|
-
const cycle =
|
|
7933
|
+
const cycle = path17.slice(existing);
|
|
11124
7934
|
const key = cycle.map((item) => item.eventId).sort().join("\0");
|
|
11125
7935
|
if (!seenCycles.has(key)) {
|
|
11126
7936
|
seenCycles.add(key);
|
|
@@ -11136,8 +7946,8 @@ function createStructureCycleRule() {
|
|
|
11136
7946
|
}
|
|
11137
7947
|
break;
|
|
11138
7948
|
}
|
|
11139
|
-
seenAt.set(current.eventId,
|
|
11140
|
-
|
|
7949
|
+
seenAt.set(current.eventId, path17.length);
|
|
7950
|
+
path17.push(current);
|
|
11141
7951
|
current = current.parentId ? byId.get(current.parentId) : void 0;
|
|
11142
7952
|
}
|
|
11143
7953
|
}
|
|
@@ -11411,7 +8221,7 @@ function createSafetyOversizedAttributeRule(options) {
|
|
|
11411
8221
|
)
|
|
11412
8222
|
);
|
|
11413
8223
|
}
|
|
11414
|
-
if (
|
|
8224
|
+
if (isRecord9(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
|
|
11415
8225
|
findings.push(
|
|
11416
8226
|
failFinding(
|
|
11417
8227
|
"safety.oversizedAttribute",
|
|
@@ -11460,7 +8270,7 @@ function createBaselineRegressionRule(options) {
|
|
|
11460
8270
|
)
|
|
11461
8271
|
];
|
|
11462
8272
|
}
|
|
11463
|
-
const baselineFacts =
|
|
8273
|
+
const baselineFacts = buildFacts(options.baseline, baselineSelection.run);
|
|
11464
8274
|
const baselineContext = {
|
|
11465
8275
|
...baselineFacts,
|
|
11466
8276
|
selectedRun: baselineSelection.run,
|
|
@@ -11579,7 +8389,7 @@ function runTraceChecks(input3, options = {}) {
|
|
|
11579
8389
|
if (rules.diagnostics.length > 0) {
|
|
11580
8390
|
return errorResult(input3, rules.diagnostics, selected.run);
|
|
11581
8391
|
}
|
|
11582
|
-
const facts =
|
|
8392
|
+
const facts = buildFacts(input3, selected.run);
|
|
11583
8393
|
const context = {
|
|
11584
8394
|
...facts,
|
|
11585
8395
|
...selected.run ? { selectedRun: selected.run } : {},
|
|
@@ -11934,23 +8744,23 @@ function evaluatePromptInjection(text, options = {}) {
|
|
|
11934
8744
|
}
|
|
11935
8745
|
return fail(ruleId, `Matched ${evidence.length} injection pattern(s).`, evidence, "warning");
|
|
11936
8746
|
}
|
|
11937
|
-
function validateSchemaField(value, field,
|
|
8747
|
+
function validateSchemaField(value, field, path17, evidence) {
|
|
11938
8748
|
const ruleId = "guardrail.structured-output";
|
|
11939
8749
|
if (field.type) {
|
|
11940
8750
|
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
11941
8751
|
if (actual !== field.type) {
|
|
11942
|
-
evidence.push({ ruleId, path:
|
|
8752
|
+
evidence.push({ ruleId, path: path17, preview: `expected ${field.type}, got ${actual}` });
|
|
11943
8753
|
return;
|
|
11944
8754
|
}
|
|
11945
8755
|
}
|
|
11946
8756
|
if (field.enum && !field.enum.some((item) => Object.is(item, value))) {
|
|
11947
|
-
evidence.push({ ruleId, path:
|
|
8757
|
+
evidence.push({ ruleId, path: path17, preview: "value not in enum" });
|
|
11948
8758
|
}
|
|
11949
8759
|
if (field.type === "object" && field.required && value && typeof value === "object" && !Array.isArray(value)) {
|
|
11950
8760
|
const record = value;
|
|
11951
8761
|
for (const key of field.required) {
|
|
11952
8762
|
if (!(key in record)) {
|
|
11953
|
-
evidence.push({ ruleId, path: `${
|
|
8763
|
+
evidence.push({ ruleId, path: `${path17}.${key}`, preview: "missing required key" });
|
|
11954
8764
|
}
|
|
11955
8765
|
}
|
|
11956
8766
|
}
|
|
@@ -12277,7 +9087,7 @@ function asConfig(value) {
|
|
|
12277
9087
|
}
|
|
12278
9088
|
async function loadConfig(configPath) {
|
|
12279
9089
|
if (configPath === void 0) return {};
|
|
12280
|
-
const extension =
|
|
9090
|
+
const extension = path10.extname(configPath);
|
|
12281
9091
|
if (TS_CONFIG_EXTENSIONS.has(extension)) {
|
|
12282
9092
|
throw new Error(
|
|
12283
9093
|
"TypeScript check configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -12286,7 +9096,7 @@ async function loadConfig(configPath) {
|
|
|
12286
9096
|
if (!CONFIG_EXTENSIONS.has(extension)) {
|
|
12287
9097
|
throw new Error("Unsupported check config extension. Use .json, .js, .mjs, or .cjs.");
|
|
12288
9098
|
}
|
|
12289
|
-
const absolute =
|
|
9099
|
+
const absolute = path10.resolve(configPath);
|
|
12290
9100
|
if (extension === ".json") {
|
|
12291
9101
|
const raw = await readFile(absolute, "utf-8");
|
|
12292
9102
|
return asConfig(JSON.parse(raw));
|
|
@@ -12435,10 +9245,10 @@ function printHuman(result) {
|
|
|
12435
9245
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
12436
9246
|
}
|
|
12437
9247
|
for (const finding of result.findings) {
|
|
12438
|
-
const
|
|
9248
|
+
const path17 = finding.evidence[0]?.path;
|
|
12439
9249
|
const run = finding.evidence[0]?.runId;
|
|
12440
9250
|
const runPrefix = run ? `[${run}] ` : "";
|
|
12441
|
-
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${
|
|
9251
|
+
console.log(`- ${runPrefix}${finding.ruleId}: ${finding.message}${path17 ? ` (${path17})` : ""}`);
|
|
12442
9252
|
}
|
|
12443
9253
|
}
|
|
12444
9254
|
function readErrorResult(error) {
|
|
@@ -12638,7 +9448,7 @@ function createViewerServer(options = {}) {
|
|
|
12638
9448
|
return sendJson(res, 200, {
|
|
12639
9449
|
ok: true,
|
|
12640
9450
|
readOnly: true,
|
|
12641
|
-
traceDir:
|
|
9451
|
+
traceDir: path10.resolve(traceDir)
|
|
12642
9452
|
});
|
|
12643
9453
|
}
|
|
12644
9454
|
const td = new TraceDirectory({ dir: traceDir });
|
|
@@ -12656,7 +9466,7 @@ function createViewerServer(options = {}) {
|
|
|
12656
9466
|
runId: meta.runId,
|
|
12657
9467
|
name: meta.name,
|
|
12658
9468
|
status: meta.status,
|
|
12659
|
-
file:
|
|
9469
|
+
file: path10.basename(meta.filePath),
|
|
12660
9470
|
startedAt: meta.startedAt,
|
|
12661
9471
|
durationMs: meta.durationMs
|
|
12662
9472
|
}))
|
|
@@ -12771,7 +9581,7 @@ function startViewerServer(options = {}) {
|
|
|
12771
9581
|
resolve({
|
|
12772
9582
|
host,
|
|
12773
9583
|
port: resolvedPort,
|
|
12774
|
-
traceDir:
|
|
9584
|
+
traceDir: path10.resolve(traceDir),
|
|
12775
9585
|
url: `http://${host}:${resolvedPort}`
|
|
12776
9586
|
});
|
|
12777
9587
|
});
|
|
@@ -12849,8 +9659,8 @@ function diagnosticFromError(error) {
|
|
|
12849
9659
|
message: error instanceof Error ? error.message : String(error)
|
|
12850
9660
|
};
|
|
12851
9661
|
}
|
|
12852
|
-
function
|
|
12853
|
-
return nodes.flatMap((node) => [node, ...
|
|
9662
|
+
function flatten(nodes) {
|
|
9663
|
+
return nodes.flatMap((node) => [node, ...flatten(node.children)]);
|
|
12854
9664
|
}
|
|
12855
9665
|
function selectRun3(read, runId) {
|
|
12856
9666
|
if (runId !== void 0) {
|
|
@@ -12943,7 +9753,7 @@ async function evalRun(input3, options = {}) {
|
|
|
12943
9753
|
const context = {
|
|
12944
9754
|
format: resolved.read.format,
|
|
12945
9755
|
run: selected.run,
|
|
12946
|
-
nodes:
|
|
9756
|
+
nodes: flatten(selected.run.children),
|
|
12947
9757
|
events: resolved.read.events.filter((event) => event.runId === selected.run?.runId)
|
|
12948
9758
|
};
|
|
12949
9759
|
const diagnostics = [];
|
|
@@ -12976,10 +9786,10 @@ async function evalRun(input3, options = {}) {
|
|
|
12976
9786
|
diagnostics: []
|
|
12977
9787
|
};
|
|
12978
9788
|
}
|
|
12979
|
-
function evidenceForRun(run,
|
|
12980
|
-
return [{ runId: run.runId, ...
|
|
9789
|
+
function evidenceForRun(run, path17) {
|
|
9790
|
+
return [{ runId: run.runId, ...path17 !== void 0 ? { path: path17 } : {} }];
|
|
12981
9791
|
}
|
|
12982
|
-
function evidenceForEvent(event,
|
|
9792
|
+
function evidenceForEvent(event, path17) {
|
|
12983
9793
|
return [
|
|
12984
9794
|
{
|
|
12985
9795
|
runId: event.runId,
|
|
@@ -12987,7 +9797,7 @@ function evidenceForEvent(event, path20) {
|
|
|
12987
9797
|
...event.parentId !== void 0 ? { parentId: event.parentId } : {},
|
|
12988
9798
|
kind: event.kind,
|
|
12989
9799
|
name: event.name,
|
|
12990
|
-
...
|
|
9800
|
+
...path17 !== void 0 ? { path: path17 } : {}
|
|
12991
9801
|
}
|
|
12992
9802
|
];
|
|
12993
9803
|
}
|
|
@@ -13145,9 +9955,9 @@ function collectTextFields(nodes, keys, preferredKinds = []) {
|
|
|
13145
9955
|
function tokenize(text) {
|
|
13146
9956
|
return [...text.toLowerCase().matchAll(/[a-z0-9][a-z0-9'-]{2,}/g)].map((match) => match[0].replace(/^['-]+|['-]+$/g, "")).filter((token) => token.length > 2 && !STOP_WORDS.has(token));
|
|
13147
9957
|
}
|
|
13148
|
-
function firstEvidence(fields, run,
|
|
9958
|
+
function firstEvidence(fields, run, path17) {
|
|
13149
9959
|
const first = fields[0];
|
|
13150
|
-
return first === void 0 ? evidenceForRun(run,
|
|
9960
|
+
return first === void 0 ? evidenceForRun(run, path17) : evidenceForEvent(first.node.event, first.path);
|
|
13151
9961
|
}
|
|
13152
9962
|
function collectSourceIds(nodes, keys) {
|
|
13153
9963
|
const wanted = keySet(keys);
|
|
@@ -13524,8 +10334,8 @@ function renderEvalMarkdown(result) {
|
|
|
13524
10334
|
if (result.findings.length > 0) {
|
|
13525
10335
|
lines.push("", "## Findings");
|
|
13526
10336
|
for (const finding of result.findings) {
|
|
13527
|
-
const
|
|
13528
|
-
lines.push(`- ${finding.ruleId}: ${finding.message}${
|
|
10337
|
+
const path17 = finding.evidence[0]?.path;
|
|
10338
|
+
lines.push(`- ${finding.ruleId}: ${finding.message}${path17 ? ` (${path17})` : ""}`);
|
|
13529
10339
|
}
|
|
13530
10340
|
}
|
|
13531
10341
|
return `${lines.join("\n")}
|
|
@@ -13572,7 +10382,7 @@ function asConfig2(value) {
|
|
|
13572
10382
|
}
|
|
13573
10383
|
async function loadConfig2(configPath) {
|
|
13574
10384
|
if (configPath === void 0) return {};
|
|
13575
|
-
const extension =
|
|
10385
|
+
const extension = path10.extname(configPath);
|
|
13576
10386
|
if (TS_CONFIG_EXTENSIONS2.has(extension)) {
|
|
13577
10387
|
throw new Error(
|
|
13578
10388
|
"TypeScript eval configs require an explicit precompiled JavaScript config or future --config-loader support."
|
|
@@ -13581,7 +10391,7 @@ async function loadConfig2(configPath) {
|
|
|
13581
10391
|
if (!CONFIG_EXTENSIONS2.has(extension)) {
|
|
13582
10392
|
throw new Error("Unsupported eval config extension. Use .json, .js, .mjs, or .cjs.");
|
|
13583
10393
|
}
|
|
13584
|
-
const absolute =
|
|
10394
|
+
const absolute = path10.resolve(configPath);
|
|
13585
10395
|
if (extension === ".json") {
|
|
13586
10396
|
const raw = await readFile(absolute, "utf-8");
|
|
13587
10397
|
return asConfig2(JSON.parse(raw));
|
|
@@ -13718,8 +10528,8 @@ function printHuman2(result) {
|
|
|
13718
10528
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
13719
10529
|
}
|
|
13720
10530
|
for (const finding of result.findings) {
|
|
13721
|
-
const
|
|
13722
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
10531
|
+
const path17 = finding.evidence[0]?.path;
|
|
10532
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path17 ? ` (${path17})` : ""}`);
|
|
13723
10533
|
}
|
|
13724
10534
|
}
|
|
13725
10535
|
function readErrorResult2(error) {
|
|
@@ -13957,8 +10767,8 @@ function printHuman3(result) {
|
|
|
13957
10767
|
console.log(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
13958
10768
|
}
|
|
13959
10769
|
for (const finding of result.findings) {
|
|
13960
|
-
const
|
|
13961
|
-
console.log(`- ${finding.ruleId}: ${finding.message}${
|
|
10770
|
+
const path17 = finding.evidence[0]?.path;
|
|
10771
|
+
console.log(`- ${finding.ruleId}: ${finding.message}${path17 ? ` (${path17})` : ""}`);
|
|
13962
10772
|
}
|
|
13963
10773
|
console.log(`Note: ${result.note}`);
|
|
13964
10774
|
}
|
|
@@ -14077,8 +10887,8 @@ function renderCheckSection(result) {
|
|
|
14077
10887
|
`Diagnostics: ${result.diagnostics.length}`
|
|
14078
10888
|
];
|
|
14079
10889
|
for (const finding of result.findings.slice(0, 10)) {
|
|
14080
|
-
const
|
|
14081
|
-
lines.push(`- ${finding.ruleId}: ${finding.message} (${
|
|
10890
|
+
const path17 = finding.evidence[0]?.path ?? "(run)";
|
|
10891
|
+
lines.push(`- ${finding.ruleId}: ${finding.message} (${path17})`);
|
|
14082
10892
|
}
|
|
14083
10893
|
for (const diagnostic4 of result.diagnostics.slice(0, 10)) {
|
|
14084
10894
|
lines.push(`- ${diagnostic4.code}: ${diagnostic4.message}`);
|
|
@@ -14156,8 +10966,8 @@ function renderHtml(trace, check, diff) {
|
|
|
14156
10966
|
`;
|
|
14157
10967
|
}
|
|
14158
10968
|
async function writeArtifact(outputDir, relativePath, content, files) {
|
|
14159
|
-
const outPath =
|
|
14160
|
-
await mkdir(
|
|
10969
|
+
const outPath = path10.join(outputDir, relativePath);
|
|
10970
|
+
await mkdir(path10.dirname(outPath), { recursive: true });
|
|
14161
10971
|
await writeFile(outPath, content, "utf-8");
|
|
14162
10972
|
files.push(relativePath);
|
|
14163
10973
|
}
|
|
@@ -14173,7 +10983,7 @@ function manifestStatus(check, diff) {
|
|
|
14173
10983
|
return "ok";
|
|
14174
10984
|
}
|
|
14175
10985
|
async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
14176
|
-
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ?
|
|
10986
|
+
const outputDir = options.outputDir !== void 0 && options.outputDir.trim() !== "" ? path10.resolve(options.outputDir.trim()) : "";
|
|
14177
10987
|
if (outputDir === "") {
|
|
14178
10988
|
console.error("--output-dir is required.");
|
|
14179
10989
|
process.exitCode = 1;
|
|
@@ -14239,8 +11049,8 @@ async function artifactsCommand(target, options = {}, stdin = process.stdin) {
|
|
|
14239
11049
|
await writeArtifact(outputDir, "report.html", renderHtml(trace, check, diff), files);
|
|
14240
11050
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
14241
11051
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
14242
|
-
await mkdir(
|
|
14243
|
-
await appendFile(
|
|
11052
|
+
await mkdir(path10.dirname(path10.resolve(summaryTarget)), { recursive: true });
|
|
11053
|
+
await appendFile(path10.resolve(summaryTarget), `
|
|
14244
11054
|
${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
14245
11055
|
}
|
|
14246
11056
|
const manifestFiles = [...files, "manifest.json"].sort((a, b) => a.localeCompare(b));
|
|
@@ -14259,10 +11069,10 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
14259
11069
|
findings: diff?.findings.length ?? 0,
|
|
14260
11070
|
diagnostics: diff?.diagnostics.length ?? 0
|
|
14261
11071
|
},
|
|
14262
|
-
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary:
|
|
11072
|
+
...summaryTarget !== void 0 && summaryTarget.trim() !== "" ? { githubSummary: path10.resolve(summaryTarget) } : {},
|
|
14263
11073
|
note: NOTE
|
|
14264
11074
|
};
|
|
14265
|
-
await writeFile(
|
|
11075
|
+
await writeFile(path10.join(outputDir, "manifest.json"), writeJson3(manifest), "utf-8");
|
|
14266
11076
|
if (options.json === true) {
|
|
14267
11077
|
console.log(writeJson3(manifest).trimEnd());
|
|
14268
11078
|
} else {
|
|
@@ -14274,7 +11084,7 @@ ${renderMarkdown(trace, check, diff)}`, "utf-8");
|
|
|
14274
11084
|
}
|
|
14275
11085
|
}
|
|
14276
11086
|
function validateReporterArtifactPath(options) {
|
|
14277
|
-
const outputDir =
|
|
11087
|
+
const outputDir = path10.resolve(options.outputDir);
|
|
14278
11088
|
const diagnostics = [];
|
|
14279
11089
|
const rawPath = options.relativePath;
|
|
14280
11090
|
if (rawPath.length === 0) {
|
|
@@ -14294,7 +11104,7 @@ function validateReporterArtifactPath(options) {
|
|
|
14294
11104
|
});
|
|
14295
11105
|
return { ok: false, outputDir, diagnostics };
|
|
14296
11106
|
}
|
|
14297
|
-
if (
|
|
11107
|
+
if (path10.isAbsolute(rawPath) || path10.win32.isAbsolute(rawPath)) {
|
|
14298
11108
|
diagnostics.push({
|
|
14299
11109
|
code: "artifact_path_absolute",
|
|
14300
11110
|
severity: "error",
|
|
@@ -14303,7 +11113,7 @@ function validateReporterArtifactPath(options) {
|
|
|
14303
11113
|
});
|
|
14304
11114
|
return { ok: false, outputDir, diagnostics };
|
|
14305
11115
|
}
|
|
14306
|
-
const normalized =
|
|
11116
|
+
const normalized = path10.posix.normalize(rawPath.replace(/\\/g, "/"));
|
|
14307
11117
|
const segments = normalized.split("/");
|
|
14308
11118
|
if (normalized === "." || normalized.startsWith("../") || segments.some((segment) => segment === "..")) {
|
|
14309
11119
|
diagnostics.push({
|
|
@@ -14314,9 +11124,9 @@ function validateReporterArtifactPath(options) {
|
|
|
14314
11124
|
});
|
|
14315
11125
|
return { ok: false, outputDir, diagnostics };
|
|
14316
11126
|
}
|
|
14317
|
-
const absolutePath =
|
|
14318
|
-
const relFromOutput =
|
|
14319
|
-
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") ||
|
|
11127
|
+
const absolutePath = path10.resolve(outputDir, normalized);
|
|
11128
|
+
const relFromOutput = path10.relative(outputDir, absolutePath);
|
|
11129
|
+
if (relFromOutput.length === 0 || relFromOutput.startsWith("..") || path10.isAbsolute(relFromOutput)) {
|
|
14320
11130
|
diagnostics.push({
|
|
14321
11131
|
code: "artifact_path_escape",
|
|
14322
11132
|
severity: "error",
|
|
@@ -14462,23 +11272,23 @@ function readManifestDocument(value) {
|
|
|
14462
11272
|
};
|
|
14463
11273
|
}
|
|
14464
11274
|
function cwdRelative(filePath) {
|
|
14465
|
-
const relative =
|
|
14466
|
-
if (relative === "" || relative.startsWith("../") ||
|
|
14467
|
-
return
|
|
11275
|
+
const relative = path10.relative(process.cwd(), path10.resolve(filePath)).replace(/\\/g, "/");
|
|
11276
|
+
if (relative === "" || relative.startsWith("../") || path10.isAbsolute(relative)) {
|
|
11277
|
+
return path10.basename(filePath);
|
|
14468
11278
|
}
|
|
14469
11279
|
return relative;
|
|
14470
11280
|
}
|
|
14471
11281
|
async function readReporterManifest(filePath) {
|
|
14472
|
-
const absolute =
|
|
11282
|
+
const absolute = path10.resolve(filePath);
|
|
14473
11283
|
const raw = await readFile(absolute, "utf-8");
|
|
14474
11284
|
const document = readManifestDocument(JSON.parse(raw));
|
|
14475
11285
|
const manifest = document.manifest;
|
|
14476
11286
|
const results = manifest.results.map((result) => ({
|
|
14477
11287
|
testId: safeText(result.testId),
|
|
14478
11288
|
name: safeText(result.name),
|
|
14479
|
-
...result.file === void 0 ? {} : { file: safeText(
|
|
11289
|
+
...result.file === void 0 ? {} : { file: safeText(path10.basename(result.file)) },
|
|
14480
11290
|
status: result.status,
|
|
14481
|
-
...result.tracePath === void 0 ? {} : { tracePath: safeText(
|
|
11291
|
+
...result.tracePath === void 0 ? {} : { tracePath: safeText(path10.basename(result.tracePath)) },
|
|
14482
11292
|
artifacts: result.artifacts,
|
|
14483
11293
|
diagnostics: result.diagnostics
|
|
14484
11294
|
}));
|
|
@@ -14617,15 +11427,15 @@ async function ciSummaryCommand(manifestPaths, options = {}) {
|
|
|
14617
11427
|
return;
|
|
14618
11428
|
}
|
|
14619
11429
|
const markdown = renderMarkdown2(result);
|
|
14620
|
-
const outputPath = options.output !== void 0 && options.output.trim() !== "" ?
|
|
11430
|
+
const outputPath = options.output !== void 0 && options.output.trim() !== "" ? path10.resolve(options.output.trim()) : void 0;
|
|
14621
11431
|
if (outputPath !== void 0) {
|
|
14622
|
-
await mkdir(
|
|
11432
|
+
await mkdir(path10.dirname(outputPath), { recursive: true });
|
|
14623
11433
|
await writeFile(outputPath, markdown, "utf-8");
|
|
14624
11434
|
}
|
|
14625
11435
|
const summaryTarget = options.githubSummary ?? process.env.GITHUB_STEP_SUMMARY;
|
|
14626
11436
|
if (summaryTarget !== void 0 && summaryTarget.trim() !== "") {
|
|
14627
|
-
const summaryPath =
|
|
14628
|
-
await mkdir(
|
|
11437
|
+
const summaryPath = path10.resolve(summaryTarget);
|
|
11438
|
+
await mkdir(path10.dirname(summaryPath), { recursive: true });
|
|
14629
11439
|
await appendFile(summaryPath, `
|
|
14630
11440
|
${markdown}`, "utf-8");
|
|
14631
11441
|
}
|
|
@@ -14773,8 +11583,8 @@ jobs:
|
|
|
14773
11583
|
}
|
|
14774
11584
|
async function planInit(options = {}) {
|
|
14775
11585
|
const framework = normalizeFramework(options.framework);
|
|
14776
|
-
const cwd =
|
|
14777
|
-
const demoPath = framework === "custom" ?
|
|
11586
|
+
const cwd = path10.resolve(options.cwd ?? process.cwd());
|
|
11587
|
+
const demoPath = framework === "custom" ? path10.join("examples", "agent-inspect-demo.mjs") : path10.join("examples", `agent-inspect-${framework}-demo.mjs`);
|
|
14778
11588
|
const candidates = [
|
|
14779
11589
|
{ rel: CONFIG_FILE, content: configTemplate(framework) },
|
|
14780
11590
|
{ rel: GITKEEP, content: "" },
|
|
@@ -14788,7 +11598,7 @@ async function planInit(options = {}) {
|
|
|
14788
11598
|
}
|
|
14789
11599
|
const files = [];
|
|
14790
11600
|
for (const candidate of candidates) {
|
|
14791
|
-
const abs =
|
|
11601
|
+
const abs = path10.join(cwd, candidate.rel);
|
|
14792
11602
|
try {
|
|
14793
11603
|
await access(abs);
|
|
14794
11604
|
files.push({
|
|
@@ -14809,12 +11619,12 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
14809
11619
|
if (entry.action === "skip") {
|
|
14810
11620
|
continue;
|
|
14811
11621
|
}
|
|
14812
|
-
const abs =
|
|
11622
|
+
const abs = path10.join(cwd, entry.path);
|
|
14813
11623
|
if (options.dryRun) {
|
|
14814
11624
|
written.push(entry.path);
|
|
14815
11625
|
continue;
|
|
14816
11626
|
}
|
|
14817
|
-
await mkdir(
|
|
11627
|
+
await mkdir(path10.dirname(abs), { recursive: true });
|
|
14818
11628
|
const content = entry.path === CONFIG_FILE ? configTemplate(plan.framework) : entry.path === GITKEEP ? "" : entry.path.endsWith(".yml") ? githubWorkflowTemplate() : demoTemplate(plan.framework);
|
|
14819
11629
|
await writeFile(abs, content, "utf-8");
|
|
14820
11630
|
written.push(entry.path);
|
|
@@ -14822,7 +11632,7 @@ async function writePlannedFiles(plan, cwd, options) {
|
|
|
14822
11632
|
return written;
|
|
14823
11633
|
}
|
|
14824
11634
|
async function initCommand(options = {}) {
|
|
14825
|
-
const cwd =
|
|
11635
|
+
const cwd = path10.resolve(options.cwd ?? process.cwd());
|
|
14826
11636
|
try {
|
|
14827
11637
|
const plan = await planInit({ ...options, cwd });
|
|
14828
11638
|
const toWrite = plan.files.filter((file) => file.action === "create").map((f) => f.path);
|
|
@@ -14878,25 +11688,25 @@ var OPTIONAL_PACKAGES = {
|
|
|
14878
11688
|
langchain: ["@agent-inspect/langchain"]
|
|
14879
11689
|
};
|
|
14880
11690
|
function nodeVersionCheck() {
|
|
14881
|
-
const major = Number(
|
|
11691
|
+
const major = Number(process2.versions.node.split(".")[0]);
|
|
14882
11692
|
if (Number.isNaN(major) || major < 20) {
|
|
14883
11693
|
return {
|
|
14884
11694
|
id: "node-version",
|
|
14885
11695
|
status: "fail",
|
|
14886
|
-
message: `Node ${
|
|
11696
|
+
message: `Node ${process2.versions.node} is below the supported minimum (20).`,
|
|
14887
11697
|
remediation: "Upgrade to Node 20 LTS or newer.",
|
|
14888
|
-
evidence:
|
|
11698
|
+
evidence: process2.versions.node
|
|
14889
11699
|
};
|
|
14890
11700
|
}
|
|
14891
11701
|
return {
|
|
14892
11702
|
id: "node-version",
|
|
14893
11703
|
status: "pass",
|
|
14894
|
-
message: `Node ${
|
|
14895
|
-
evidence:
|
|
11704
|
+
message: `Node ${process2.versions.node} meets the minimum (>=20).`,
|
|
11705
|
+
evidence: process2.versions.node
|
|
14896
11706
|
};
|
|
14897
11707
|
}
|
|
14898
11708
|
function envCheck(name, optional = true) {
|
|
14899
|
-
const value =
|
|
11709
|
+
const value = process2.env[name];
|
|
14900
11710
|
if (value === void 0 || value.trim() === "") {
|
|
14901
11711
|
return {
|
|
14902
11712
|
id: `env-${name.toLowerCase()}`,
|
|
@@ -14913,7 +11723,7 @@ function envCheck(name, optional = true) {
|
|
|
14913
11723
|
};
|
|
14914
11724
|
}
|
|
14915
11725
|
async function traceDirWritable(traceDir) {
|
|
14916
|
-
const resolved =
|
|
11726
|
+
const resolved = path10.resolve(traceDir);
|
|
14917
11727
|
try {
|
|
14918
11728
|
await mkdir(resolved, { recursive: true });
|
|
14919
11729
|
await access(resolved, constants.W_OK);
|
|
@@ -14934,7 +11744,7 @@ async function traceDirWritable(traceDir) {
|
|
|
14934
11744
|
}
|
|
14935
11745
|
}
|
|
14936
11746
|
function resolvePackage(cwd, name) {
|
|
14937
|
-
const require2 = createRequire(
|
|
11747
|
+
const require2 = createRequire(path10.join(cwd, "package.json"));
|
|
14938
11748
|
try {
|
|
14939
11749
|
const pkgPath = require2.resolve(`${name}/package.json`);
|
|
14940
11750
|
const pkg = require2(pkgPath);
|
|
@@ -14945,7 +11755,7 @@ function resolvePackage(cwd, name) {
|
|
|
14945
11755
|
}
|
|
14946
11756
|
function importSmoke(cwd) {
|
|
14947
11757
|
const results = [];
|
|
14948
|
-
const require2 = createRequire(
|
|
11758
|
+
const require2 = createRequire(path10.join(cwd, "package.json"));
|
|
14949
11759
|
try {
|
|
14950
11760
|
require2.resolve("agent-inspect");
|
|
14951
11761
|
results.push({
|
|
@@ -15028,8 +11838,8 @@ function versionMismatchCheck(cwd) {
|
|
|
15028
11838
|
};
|
|
15029
11839
|
}
|
|
15030
11840
|
async function runDoctorChecks(options = {}) {
|
|
15031
|
-
const cwd =
|
|
15032
|
-
const traceDir = options.traceDir?.trim() ||
|
|
11841
|
+
const cwd = path10.resolve(options.cwd ?? process2.cwd());
|
|
11842
|
+
const traceDir = options.traceDir?.trim() || process2.env.AGENT_INSPECT_TRACE_DIR?.trim() || ".agent-inspect";
|
|
15033
11843
|
const checks2 = [
|
|
15034
11844
|
nodeVersionCheck(),
|
|
15035
11845
|
{
|
|
@@ -15066,7 +11876,7 @@ async function doctorCommand(options = {}) {
|
|
|
15066
11876
|
2
|
|
15067
11877
|
)
|
|
15068
11878
|
);
|
|
15069
|
-
if (failed > 0)
|
|
11879
|
+
if (failed > 0) process2.exitCode = 1;
|
|
15070
11880
|
return;
|
|
15071
11881
|
}
|
|
15072
11882
|
console.log("AgentInspect doctor");
|
|
@@ -15077,7 +11887,7 @@ async function doctorCommand(options = {}) {
|
|
|
15077
11887
|
}
|
|
15078
11888
|
console.log(`
|
|
15079
11889
|
Summary: ${failed} failed, ${warned} warnings`);
|
|
15080
|
-
if (failed > 0)
|
|
11890
|
+
if (failed > 0) process2.exitCode = 1;
|
|
15081
11891
|
}
|
|
15082
11892
|
|
|
15083
11893
|
// packages/adapter-sdk/src/indexer.ts
|
|
@@ -15140,7 +11950,7 @@ function createTraceDirectoryIndexer() {
|
|
|
15140
11950
|
// packages/cli/src/index-cmd.ts
|
|
15141
11951
|
var INDEX_FILENAME = ".agent-inspect-index.json";
|
|
15142
11952
|
function traceIndexPath(traceDir) {
|
|
15143
|
-
return
|
|
11953
|
+
return path10.join(traceDir, INDEX_FILENAME);
|
|
15144
11954
|
}
|
|
15145
11955
|
function parseMaxEntries(raw) {
|
|
15146
11956
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
@@ -15247,6 +12057,141 @@ async function indexCleanCommand(options = {}) {
|
|
|
15247
12057
|
process.exitCode = 1;
|
|
15248
12058
|
}
|
|
15249
12059
|
}
|
|
12060
|
+
var PACKAGE = "@agent-inspect/index-sqlite";
|
|
12061
|
+
function isModuleNotFound2(e) {
|
|
12062
|
+
return e !== null && typeof e === "object" && "code" in e && (e.code === "ERR_MODULE_NOT_FOUND" || e.code === "MODULE_NOT_FOUND");
|
|
12063
|
+
}
|
|
12064
|
+
async function loadIndexSqlite() {
|
|
12065
|
+
try {
|
|
12066
|
+
return await import('./src-DUGEOAZ7.mjs');
|
|
12067
|
+
} catch (e) {
|
|
12068
|
+
if (isModuleNotFound2(e)) {
|
|
12069
|
+
console.error(
|
|
12070
|
+
`The optional SQLite index is not installed. Run: npm install ${PACKAGE}`
|
|
12071
|
+
);
|
|
12072
|
+
process.exitCode = 1;
|
|
12073
|
+
return null;
|
|
12074
|
+
}
|
|
12075
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
12076
|
+
console.error(`[AgentInspect] failed to load ${PACKAGE}: ${msg}`);
|
|
12077
|
+
process.exitCode = 1;
|
|
12078
|
+
return null;
|
|
12079
|
+
}
|
|
12080
|
+
}
|
|
12081
|
+
function parsePositiveInt(raw, flag) {
|
|
12082
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
12083
|
+
const parsed = Number.parseInt(raw, 10);
|
|
12084
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
12085
|
+
throw new Error(`${flag} must be a positive integer.`);
|
|
12086
|
+
}
|
|
12087
|
+
return parsed;
|
|
12088
|
+
}
|
|
12089
|
+
async function newestTraceMtimeMs(traceDir) {
|
|
12090
|
+
let newest = 0;
|
|
12091
|
+
try {
|
|
12092
|
+
const files = await readdir(traceDir);
|
|
12093
|
+
for (const file of files) {
|
|
12094
|
+
if (!file.endsWith(".jsonl")) continue;
|
|
12095
|
+
try {
|
|
12096
|
+
const s = await stat(path10.join(traceDir, file));
|
|
12097
|
+
if (s.mtimeMs > newest) newest = s.mtimeMs;
|
|
12098
|
+
} catch {
|
|
12099
|
+
}
|
|
12100
|
+
}
|
|
12101
|
+
} catch {
|
|
12102
|
+
}
|
|
12103
|
+
return newest;
|
|
12104
|
+
}
|
|
12105
|
+
async function indexSqliteBuildCommand(options = {}) {
|
|
12106
|
+
const mod = await loadIndexSqlite();
|
|
12107
|
+
if (!mod) return;
|
|
12108
|
+
const result = await mod.buildIndex({
|
|
12109
|
+
traceDir: options.dir,
|
|
12110
|
+
maxRuns: parsePositiveInt(options.maxRuns, "--max-runs")
|
|
12111
|
+
});
|
|
12112
|
+
if (options.json) {
|
|
12113
|
+
console.log(JSON.stringify({ ok: true, ...result }, null, 2));
|
|
12114
|
+
return;
|
|
12115
|
+
}
|
|
12116
|
+
console.log(`Built SQLite index: ${result.dbPath}`);
|
|
12117
|
+
console.log(`Runs: ${result.runs} Steps: ${result.steps} Errors: ${result.errors}`);
|
|
12118
|
+
for (const warning of result.warnings) console.log(`warning: ${warning}`);
|
|
12119
|
+
}
|
|
12120
|
+
async function indexSqliteStatusCommand(options = {}) {
|
|
12121
|
+
const mod = await loadIndexSqlite();
|
|
12122
|
+
if (!mod) return;
|
|
12123
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
12124
|
+
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
12125
|
+
const status = mod.indexStatus(dbPath);
|
|
12126
|
+
const stale = mod.isIndexStale(dbPath, await newestTraceMtimeMs(traceDir));
|
|
12127
|
+
if (options.json) {
|
|
12128
|
+
console.log(JSON.stringify({ ok: true, traceDir, stale, ...status }, null, 2));
|
|
12129
|
+
return;
|
|
12130
|
+
}
|
|
12131
|
+
if (!status.exists) {
|
|
12132
|
+
console.log(`No SQLite index at ${dbPath}`);
|
|
12133
|
+
console.log("Run: agent-inspect index sqlite build");
|
|
12134
|
+
return;
|
|
12135
|
+
}
|
|
12136
|
+
console.log(`Index: ${status.dbPath}`);
|
|
12137
|
+
console.log(`Healthy: ${status.healthy ? "yes" : "no"}`);
|
|
12138
|
+
console.log(`Built: ${status.builtAt ?? "unknown"}`);
|
|
12139
|
+
console.log(`Runs: ${status.runs} Steps: ${status.steps}`);
|
|
12140
|
+
console.log(`Stale: ${stale ? "yes" : "no"}`);
|
|
12141
|
+
}
|
|
12142
|
+
async function indexSqliteQueryCommand(options = {}) {
|
|
12143
|
+
const mod = await loadIndexSqlite();
|
|
12144
|
+
if (!mod) return;
|
|
12145
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
12146
|
+
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
12147
|
+
const status = mod.indexStatus(dbPath);
|
|
12148
|
+
if (!status.exists || !status.healthy) {
|
|
12149
|
+
if (options.json) {
|
|
12150
|
+
console.log(JSON.stringify({ ok: false, reason: "index-missing", dbPath }, null, 2));
|
|
12151
|
+
} else {
|
|
12152
|
+
console.log("No usable SQLite index. Run: agent-inspect index sqlite build");
|
|
12153
|
+
}
|
|
12154
|
+
process.exitCode = 1;
|
|
12155
|
+
return;
|
|
12156
|
+
}
|
|
12157
|
+
const rows = mod.queryRuns(dbPath, {
|
|
12158
|
+
status: options.status,
|
|
12159
|
+
sessionId: options.session,
|
|
12160
|
+
name: options.name,
|
|
12161
|
+
kind: options.kind,
|
|
12162
|
+
tool: options.tool,
|
|
12163
|
+
limit: parsePositiveInt(options.limit, "--limit")
|
|
12164
|
+
});
|
|
12165
|
+
if (options.json) {
|
|
12166
|
+
console.log(JSON.stringify({ ok: true, count: rows.length, runs: rows }, null, 2));
|
|
12167
|
+
return;
|
|
12168
|
+
}
|
|
12169
|
+
if (rows.length === 0) {
|
|
12170
|
+
console.log("No matching runs.");
|
|
12171
|
+
return;
|
|
12172
|
+
}
|
|
12173
|
+
for (const run of rows) {
|
|
12174
|
+
const parts = [
|
|
12175
|
+
run.runId,
|
|
12176
|
+
run.status ?? "unknown",
|
|
12177
|
+
run.name ?? "",
|
|
12178
|
+
run.durationMs != null ? `${run.durationMs}ms` : ""
|
|
12179
|
+
].filter((p) => p !== "");
|
|
12180
|
+
console.log(parts.join(" "));
|
|
12181
|
+
}
|
|
12182
|
+
}
|
|
12183
|
+
async function indexSqliteCleanCommand(options = {}) {
|
|
12184
|
+
const mod = await loadIndexSqlite();
|
|
12185
|
+
if (!mod) return;
|
|
12186
|
+
const traceDir = resolveTraceDir({ dir: options.dir });
|
|
12187
|
+
const dbPath = mod.resolveIndexDbPath(traceDir);
|
|
12188
|
+
await mod.cleanIndex(dbPath);
|
|
12189
|
+
if (options.json) {
|
|
12190
|
+
console.log(JSON.stringify({ ok: true, removed: dbPath }, null, 2));
|
|
12191
|
+
return;
|
|
12192
|
+
}
|
|
12193
|
+
console.log(`Removed SQLite index: ${dbPath}`);
|
|
12194
|
+
}
|
|
15250
12195
|
|
|
15251
12196
|
// packages/core/src/workspace/types.ts
|
|
15252
12197
|
var WORKSPACE_SCHEMA_VERSION = "1.0";
|
|
@@ -15427,19 +12372,19 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
15427
12372
|
}
|
|
15428
12373
|
var INDEX_DIR_NAME = "index";
|
|
15429
12374
|
function resolveWorkspaceLocation(cwd = process.cwd()) {
|
|
15430
|
-
const projectRoot =
|
|
15431
|
-
const workspaceDir =
|
|
12375
|
+
const projectRoot = path10.resolve(cwd);
|
|
12376
|
+
const workspaceDir = path10.join(projectRoot, WORKSPACE_DIR_NAME);
|
|
15432
12377
|
return {
|
|
15433
12378
|
projectRoot,
|
|
15434
12379
|
workspaceDir,
|
|
15435
|
-
manifestPath:
|
|
12380
|
+
manifestPath: path10.join(workspaceDir, WORKSPACE_MANIFEST_FILENAME)
|
|
15436
12381
|
};
|
|
15437
12382
|
}
|
|
15438
12383
|
function resolveInsideWorkspace(workspaceDir, relative) {
|
|
15439
|
-
const base =
|
|
15440
|
-
const resolved =
|
|
15441
|
-
const rel =
|
|
15442
|
-
if (rel === "" || rel === "." || !rel.startsWith("..") && !
|
|
12384
|
+
const base = path10.resolve(workspaceDir);
|
|
12385
|
+
const resolved = path10.resolve(base, relative);
|
|
12386
|
+
const rel = path10.relative(base, resolved);
|
|
12387
|
+
if (rel === "" || rel === "." || !rel.startsWith("..") && !path10.isAbsolute(rel)) {
|
|
15443
12388
|
return resolved;
|
|
15444
12389
|
}
|
|
15445
12390
|
throw new Error(
|
|
@@ -15508,7 +12453,7 @@ async function createWorkspace(options = {}) {
|
|
|
15508
12453
|
created = false;
|
|
15509
12454
|
adopted = true;
|
|
15510
12455
|
} else {
|
|
15511
|
-
const project = options.project?.trim() ||
|
|
12456
|
+
const project = options.project?.trim() || path10.basename(location.projectRoot) || "workspace";
|
|
15512
12457
|
const traceDirs = detectedExistingTraces ? ["runs", "."] : ["runs"];
|
|
15513
12458
|
manifest = createDefaultWorkspaceManifest({
|
|
15514
12459
|
project,
|
|
@@ -15647,7 +12592,7 @@ async function doctorWorkspace(location) {
|
|
|
15647
12592
|
const abs = resolveInsideWorkspace(location.workspaceDir, rel);
|
|
15648
12593
|
for (const file of await listJsonl(abs)) {
|
|
15649
12594
|
try {
|
|
15650
|
-
const s = await stat(
|
|
12595
|
+
const s = await stat(path10.join(abs, file));
|
|
15651
12596
|
newestTraceMtime = Math.max(newestTraceMtime, s.mtimeMs);
|
|
15652
12597
|
} catch {
|
|
15653
12598
|
checks2.push({ id: "trace-readability", status: "warn", message: `cannot stat ${rel}/${file}` });
|
|
@@ -15695,7 +12640,7 @@ async function cleanWorkspace(location, manifest, options = {}) {
|
|
|
15695
12640
|
const relPath = `${rel}/${entry}`;
|
|
15696
12641
|
removed.push(relPath);
|
|
15697
12642
|
if (!dryRun) {
|
|
15698
|
-
await rm(
|
|
12643
|
+
await rm(path10.join(abs, entry), { recursive: true, force: true });
|
|
15699
12644
|
}
|
|
15700
12645
|
}
|
|
15701
12646
|
}
|
|
@@ -16181,6 +13126,31 @@ function createCliProgram() {
|
|
|
16181
13126
|
indexCmd.command("clean").description("Remove the local index file").option("--dir <path>", "trace directory").option("--json", "print JSON result").action((opts) => {
|
|
16182
13127
|
runCommand(() => indexCleanCommand(opts));
|
|
16183
13128
|
});
|
|
13129
|
+
const sqliteCmd = indexCmd.command("sqlite").description(
|
|
13130
|
+
"Optional SQLite-backed trace index (requires @agent-inspect/index-sqlite)"
|
|
13131
|
+
);
|
|
13132
|
+
sqliteCmd.command("build").description("Build or rebuild the local SQLite index").option("--dir <path>", "trace directory").option("--max-runs <n>", "cap indexed trace files (default 10000)").option("--json", "print JSON result").action((opts) => {
|
|
13133
|
+
runCommand(() => indexSqliteBuildCommand(opts));
|
|
13134
|
+
});
|
|
13135
|
+
sqliteCmd.command("rebuild").description("Alias for build (full, idempotent rebuild)").option("--dir <path>", "trace directory").option("--max-runs <n>", "cap indexed trace files (default 10000)").option("--json", "print JSON result").action((opts) => {
|
|
13136
|
+
runCommand(() => indexSqliteBuildCommand(opts));
|
|
13137
|
+
});
|
|
13138
|
+
sqliteCmd.command("status").description("Show SQLite index health, counts, and staleness").option("--dir <path>", "trace directory").option("--json", "print JSON result").action((opts) => {
|
|
13139
|
+
runCommand(() => indexSqliteStatusCommand(opts));
|
|
13140
|
+
});
|
|
13141
|
+
sqliteCmd.command("query").description("Query indexed runs (fast; falls back with a hint if absent)").option("--dir <path>", "trace directory").addOption(
|
|
13142
|
+
new Option("--status <status>", "filter by run status").choices([
|
|
13143
|
+
"success",
|
|
13144
|
+
"error",
|
|
13145
|
+
"running",
|
|
13146
|
+
"unknown"
|
|
13147
|
+
])
|
|
13148
|
+
).option("--session <id>", "filter by session id").option("--name <query>", "substring match on run name").option("--kind <kind>", "match runs containing a step of this kind").option("--tool <query>", "match runs containing a tool step (substring)").option("--limit <n>", "max results (default 100)").option("--json", "print JSON result").action((opts) => {
|
|
13149
|
+
runCommand(() => indexSqliteQueryCommand(opts));
|
|
13150
|
+
});
|
|
13151
|
+
sqliteCmd.command("clean").description("Remove the SQLite index (traces are never touched)").option("--dir <path>", "trace directory").option("--json", "print JSON result").action((opts) => {
|
|
13152
|
+
runCommand(() => indexSqliteCleanCommand(opts));
|
|
13153
|
+
});
|
|
16184
13154
|
const workspaceCmd = program.command("workspace").description("Manage a project-local AgentInspect workspace (.agent-inspect)");
|
|
16185
13155
|
workspaceCmd.command("init").description("Create or adopt a local workspace (never deletes traces)").option("--project <name>", "project name (default: directory name)").addOption(
|
|
16186
13156
|
new Option("--redaction-profile <profile>", "default redaction posture").choices([
|
|
@@ -16210,9 +13180,9 @@ function isPrimaryModule() {
|
|
|
16210
13180
|
if (!entry) return false;
|
|
16211
13181
|
const selfPath = fileURLToPath(import.meta.url);
|
|
16212
13182
|
try {
|
|
16213
|
-
return realpathSync(
|
|
13183
|
+
return realpathSync(path10.resolve(entry)) === realpathSync(path10.resolve(selfPath));
|
|
16214
13184
|
} catch {
|
|
16215
|
-
return
|
|
13185
|
+
return path10.resolve(entry) === path10.resolve(selfPath);
|
|
16216
13186
|
}
|
|
16217
13187
|
}
|
|
16218
13188
|
if (isPrimaryModule()) {
|