agent-inspect 0.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/LICENSE +21 -0
- package/README.md +339 -0
- package/package.json +82 -0
- package/packages/cli/dist/index.cjs +888 -0
- package/packages/cli/dist/index.cjs.map +1 -0
- package/packages/cli/dist/index.d.cts +7 -0
- package/packages/cli/dist/index.d.ts +7 -0
- package/packages/cli/dist/index.mjs +878 -0
- package/packages/cli/dist/index.mjs.map +1 -0
- package/packages/core/dist/index.cjs +979 -0
- package/packages/core/dist/index.cjs.map +1 -0
- package/packages/core/dist/index.d.cts +324 -0
- package/packages/core/dist/index.d.ts +324 -0
- package/packages/core/dist/index.mjs +919 -0
- package/packages/core/dist/index.mjs.map +1 -0
|
@@ -0,0 +1,919 @@
|
|
|
1
|
+
import { mkdir, writeFile, readFile, readdir, stat, appendFile } from 'fs/promises';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { nanoid } from 'nanoid';
|
|
5
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
// packages/core/src/types.ts
|
|
9
|
+
var STEP_TYPES = [
|
|
10
|
+
"run",
|
|
11
|
+
"llm",
|
|
12
|
+
"tool",
|
|
13
|
+
"decision",
|
|
14
|
+
"logic",
|
|
15
|
+
"state",
|
|
16
|
+
"custom"
|
|
17
|
+
];
|
|
18
|
+
var STEP_STATUSES = [
|
|
19
|
+
"running",
|
|
20
|
+
"success",
|
|
21
|
+
"error"
|
|
22
|
+
];
|
|
23
|
+
function isRecord(value) {
|
|
24
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
function isStepType(value) {
|
|
27
|
+
return typeof value === "string" && STEP_TYPES.includes(value);
|
|
28
|
+
}
|
|
29
|
+
function isStepStatus(value) {
|
|
30
|
+
return typeof value === "string" && STEP_STATUSES.includes(value);
|
|
31
|
+
}
|
|
32
|
+
function isTraceEvent(value) {
|
|
33
|
+
if (!isRecord(value)) return false;
|
|
34
|
+
if (value.schemaVersion !== "0.1") return false;
|
|
35
|
+
if (typeof value.timestamp !== "number") return false;
|
|
36
|
+
if (typeof value.event !== "string") return false;
|
|
37
|
+
switch (value.event) {
|
|
38
|
+
case "run_started": {
|
|
39
|
+
return typeof value.runId === "string" && typeof value.name === "string" && typeof value.startTime === "number";
|
|
40
|
+
}
|
|
41
|
+
case "run_completed": {
|
|
42
|
+
return typeof value.runId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
|
|
43
|
+
}
|
|
44
|
+
case "step_started": {
|
|
45
|
+
return typeof value.runId === "string" && typeof value.stepId === "string" && typeof value.name === "string" && isStepType(value.type) && typeof value.startTime === "number";
|
|
46
|
+
}
|
|
47
|
+
case "step_completed": {
|
|
48
|
+
return typeof value.runId === "string" && typeof value.stepId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
|
|
49
|
+
}
|
|
50
|
+
default:
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
var DEFAULT_TRACE_DIR_NAME = ".agent-inspect";
|
|
55
|
+
var RUNS_DIR_NAME = "runs";
|
|
56
|
+
var FALLBACK_TRACE_DIR = path.join(
|
|
57
|
+
os.tmpdir(),
|
|
58
|
+
"agent-inspect",
|
|
59
|
+
RUNS_DIR_NAME
|
|
60
|
+
);
|
|
61
|
+
var MAX_NAME_LENGTH = 100;
|
|
62
|
+
function createRunId() {
|
|
63
|
+
return `run_${nanoid(10)}`;
|
|
64
|
+
}
|
|
65
|
+
function createStepId() {
|
|
66
|
+
return `step_${nanoid(10)}`;
|
|
67
|
+
}
|
|
68
|
+
function formatDuration(ms) {
|
|
69
|
+
if (!Number.isFinite(ms) || ms < 0) {
|
|
70
|
+
return "0ms";
|
|
71
|
+
}
|
|
72
|
+
if (ms < 1e3) {
|
|
73
|
+
return `${Math.floor(ms)}ms`;
|
|
74
|
+
}
|
|
75
|
+
const seconds = ms / 1e3;
|
|
76
|
+
return `${(Math.round(seconds * 10) / 10).toFixed(1)}s`;
|
|
77
|
+
}
|
|
78
|
+
function formatTimestamp(timestamp) {
|
|
79
|
+
if (!Number.isFinite(timestamp)) {
|
|
80
|
+
return "Invalid date";
|
|
81
|
+
}
|
|
82
|
+
const d = new Date(timestamp);
|
|
83
|
+
if (Number.isNaN(d.getTime())) {
|
|
84
|
+
return "Invalid date";
|
|
85
|
+
}
|
|
86
|
+
const y = d.getFullYear();
|
|
87
|
+
const mo = String(d.getMonth() + 1).padStart(2, "0");
|
|
88
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
89
|
+
const h = String(d.getHours()).padStart(2, "0");
|
|
90
|
+
const min = String(d.getMinutes()).padStart(2, "0");
|
|
91
|
+
const s = String(d.getSeconds()).padStart(2, "0");
|
|
92
|
+
return `${y}-${mo}-${day} ${h}:${min}:${s}`;
|
|
93
|
+
}
|
|
94
|
+
function getDefaultTraceDir() {
|
|
95
|
+
try {
|
|
96
|
+
const home = os.homedir();
|
|
97
|
+
if (typeof home !== "string" || home.trim() === "") {
|
|
98
|
+
return FALLBACK_TRACE_DIR;
|
|
99
|
+
}
|
|
100
|
+
return path.join(home, DEFAULT_TRACE_DIR_NAME, RUNS_DIR_NAME);
|
|
101
|
+
} catch {
|
|
102
|
+
return FALLBACK_TRACE_DIR;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function getTraceFilePath(runId, traceDir) {
|
|
106
|
+
const baseDir = traceDir ?? getDefaultTraceDir();
|
|
107
|
+
let safeId = typeof runId === "string" && runId.trim() !== "" ? runId.trim() : "run_unknown";
|
|
108
|
+
safeId = path.basename(safeId);
|
|
109
|
+
if (safeId === "" || safeId === "." || safeId === "..") {
|
|
110
|
+
safeId = "run_unknown";
|
|
111
|
+
}
|
|
112
|
+
return path.join(baseDir, `${safeId}.jsonl`);
|
|
113
|
+
}
|
|
114
|
+
async function ensureTraceDir(traceDir) {
|
|
115
|
+
const primary = path.resolve(traceDir);
|
|
116
|
+
try {
|
|
117
|
+
await mkdir(primary, { recursive: true });
|
|
118
|
+
return primary;
|
|
119
|
+
} catch {
|
|
120
|
+
warn(`Failed to create trace directory: ${primary}`);
|
|
121
|
+
const fallback = path.resolve(FALLBACK_TRACE_DIR);
|
|
122
|
+
try {
|
|
123
|
+
await mkdir(fallback, { recursive: true });
|
|
124
|
+
return fallback;
|
|
125
|
+
} catch {
|
|
126
|
+
warn(`Failed to create fallback trace directory: ${fallback}`);
|
|
127
|
+
return primary;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function formatError(error) {
|
|
132
|
+
if (error instanceof Error) {
|
|
133
|
+
const out = { message: error.message };
|
|
134
|
+
if (typeof error.stack === "string" && error.stack.length > 0) {
|
|
135
|
+
out.stack = error.stack;
|
|
136
|
+
}
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
if (typeof error === "string") {
|
|
140
|
+
return { message: error };
|
|
141
|
+
}
|
|
142
|
+
if (error === null) {
|
|
143
|
+
return { message: "Unknown error: null" };
|
|
144
|
+
}
|
|
145
|
+
if (error === void 0) {
|
|
146
|
+
return { message: "Unknown error: undefined" };
|
|
147
|
+
}
|
|
148
|
+
if (typeof error === "number" || typeof error === "boolean" || typeof error === "bigint") {
|
|
149
|
+
return { message: String(error) };
|
|
150
|
+
}
|
|
151
|
+
if (typeof error === "object") {
|
|
152
|
+
try {
|
|
153
|
+
return { message: JSON.stringify(error) };
|
|
154
|
+
} catch {
|
|
155
|
+
return { message: "Unknown error" };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return { message: "Unknown error" };
|
|
159
|
+
}
|
|
160
|
+
function truncateName(name, maxLength = MAX_NAME_LENGTH) {
|
|
161
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
162
|
+
return "unnamed";
|
|
163
|
+
}
|
|
164
|
+
const trimmed = name.trim();
|
|
165
|
+
if (trimmed.length <= maxLength) {
|
|
166
|
+
return trimmed;
|
|
167
|
+
}
|
|
168
|
+
const ellipsis = "...";
|
|
169
|
+
const head = Math.max(0, maxLength - ellipsis.length);
|
|
170
|
+
return `${trimmed.slice(0, head)}${ellipsis}`;
|
|
171
|
+
}
|
|
172
|
+
function warn(message, error) {
|
|
173
|
+
const base = `[AgentInspect] ${message}`;
|
|
174
|
+
if (error === void 0) {
|
|
175
|
+
console.warn(base);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
console.warn(`${base}: ${formatError(error).message}`);
|
|
179
|
+
}
|
|
180
|
+
var storage = new AsyncLocalStorage();
|
|
181
|
+
function toPublicContext(ctx) {
|
|
182
|
+
return {
|
|
183
|
+
runId: ctx.runId,
|
|
184
|
+
runName: ctx.runName,
|
|
185
|
+
traceDir: ctx.traceDir,
|
|
186
|
+
silent: ctx.silent,
|
|
187
|
+
metadata: ctx.metadata
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function invoke(fn) {
|
|
191
|
+
return new Promise((resolve, reject) => {
|
|
192
|
+
try {
|
|
193
|
+
Promise.resolve(fn()).then(resolve, reject);
|
|
194
|
+
} catch (e) {
|
|
195
|
+
reject(e);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function getCurrentContext() {
|
|
200
|
+
try {
|
|
201
|
+
const s = storage.getStore();
|
|
202
|
+
if (!s) return void 0;
|
|
203
|
+
return toPublicContext(s);
|
|
204
|
+
} catch {
|
|
205
|
+
return void 0;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function getCurrentRunId() {
|
|
209
|
+
try {
|
|
210
|
+
return storage.getStore()?.runId;
|
|
211
|
+
} catch {
|
|
212
|
+
return void 0;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function getCurrentRunName() {
|
|
216
|
+
try {
|
|
217
|
+
return storage.getStore()?.runName;
|
|
218
|
+
} catch {
|
|
219
|
+
return void 0;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function getCurrentStepId() {
|
|
223
|
+
try {
|
|
224
|
+
return storage.getStore()?.currentStepId;
|
|
225
|
+
} catch {
|
|
226
|
+
return void 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function getParentStepId() {
|
|
230
|
+
return getCurrentStepId();
|
|
231
|
+
}
|
|
232
|
+
function getCurrentDepth() {
|
|
233
|
+
try {
|
|
234
|
+
const d = storage.getStore()?.currentDepth;
|
|
235
|
+
return typeof d === "number" && Number.isFinite(d) ? d : 0;
|
|
236
|
+
} catch {
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function hasActiveContext() {
|
|
241
|
+
try {
|
|
242
|
+
return storage.getStore() !== void 0;
|
|
243
|
+
} catch {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function getTraceDirFromContext() {
|
|
248
|
+
try {
|
|
249
|
+
return storage.getStore()?.traceDir;
|
|
250
|
+
} catch {
|
|
251
|
+
return void 0;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function isSilentContext() {
|
|
255
|
+
try {
|
|
256
|
+
const s = storage.getStore();
|
|
257
|
+
return s ? s.silent : false;
|
|
258
|
+
} catch {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function runWithContext(context, fn) {
|
|
263
|
+
const runtime = {
|
|
264
|
+
runId: context.runId,
|
|
265
|
+
runName: context.runName,
|
|
266
|
+
traceDir: context.traceDir,
|
|
267
|
+
silent: context.silent,
|
|
268
|
+
metadata: context.metadata,
|
|
269
|
+
currentDepth: 0
|
|
270
|
+
};
|
|
271
|
+
return new Promise((resolve, reject) => {
|
|
272
|
+
storage.run(runtime, () => {
|
|
273
|
+
try {
|
|
274
|
+
Promise.resolve(fn()).then(resolve, reject);
|
|
275
|
+
} catch (e) {
|
|
276
|
+
reject(e);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
function runWithStepContext(stepId, fn) {
|
|
282
|
+
let parent;
|
|
283
|
+
try {
|
|
284
|
+
parent = storage.getStore();
|
|
285
|
+
} catch {
|
|
286
|
+
parent = void 0;
|
|
287
|
+
}
|
|
288
|
+
if (!parent) {
|
|
289
|
+
return invoke(fn);
|
|
290
|
+
}
|
|
291
|
+
const derived = {
|
|
292
|
+
runId: parent.runId,
|
|
293
|
+
runName: parent.runName,
|
|
294
|
+
traceDir: parent.traceDir,
|
|
295
|
+
silent: parent.silent,
|
|
296
|
+
metadata: parent.metadata,
|
|
297
|
+
currentStepId: stepId,
|
|
298
|
+
currentDepth: parent.currentDepth + 1
|
|
299
|
+
};
|
|
300
|
+
return new Promise((resolve, reject) => {
|
|
301
|
+
storage.run(derived, () => {
|
|
302
|
+
try {
|
|
303
|
+
Promise.resolve(fn()).then(resolve, reject);
|
|
304
|
+
} catch (e) {
|
|
305
|
+
reject(e);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function isRecord2(value) {
|
|
311
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
312
|
+
}
|
|
313
|
+
function nonEmptyString(value) {
|
|
314
|
+
return typeof value === "string" && value.trim() !== "";
|
|
315
|
+
}
|
|
316
|
+
function finiteNumber(value) {
|
|
317
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
318
|
+
}
|
|
319
|
+
function optionalErrorInfo(value) {
|
|
320
|
+
if (value === void 0) return true;
|
|
321
|
+
if (!isRecord2(value)) return false;
|
|
322
|
+
if (typeof value.message !== "string") return false;
|
|
323
|
+
if ("stack" in value && value.stack !== void 0) {
|
|
324
|
+
if (typeof value.stack !== "string") return false;
|
|
325
|
+
}
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
function validateEvent(event) {
|
|
329
|
+
if (!isRecord2(event)) return false;
|
|
330
|
+
if (event.schemaVersion !== "0.1") return false;
|
|
331
|
+
if (!finiteNumber(event.timestamp)) return false;
|
|
332
|
+
if (typeof event.event !== "string") return false;
|
|
333
|
+
switch (event.event) {
|
|
334
|
+
case "run_started": {
|
|
335
|
+
if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
if (event.metadata !== void 0 && !isRecord2(event.metadata)) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
case "run_completed": {
|
|
344
|
+
return nonEmptyString(event.runId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
345
|
+
}
|
|
346
|
+
case "step_started": {
|
|
347
|
+
if (!nonEmptyString(event.runId) || !nonEmptyString(event.stepId) || !nonEmptyString(event.name) || !isStepType(event.type) || !finiteNumber(event.startTime)) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
if (event.parentId !== void 0 && typeof event.parentId !== "string") {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
if (event.metadata !== void 0 && !isRecord2(event.metadata)) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
case "step_completed": {
|
|
359
|
+
return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
|
|
360
|
+
}
|
|
361
|
+
default:
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function serializeEvent(event) {
|
|
366
|
+
try {
|
|
367
|
+
return JSON.stringify(event);
|
|
368
|
+
} catch {
|
|
369
|
+
return "";
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async function initializeTraceFile(runId, traceDir) {
|
|
373
|
+
try {
|
|
374
|
+
const usable = await ensureTraceDir(traceDir);
|
|
375
|
+
const filePath = getTraceFilePath(runId, usable);
|
|
376
|
+
await writeFile(filePath, "", "utf-8");
|
|
377
|
+
return filePath;
|
|
378
|
+
} catch (e) {
|
|
379
|
+
warn("Failed to initialize trace file", e);
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
const usable = await ensureTraceDir(FALLBACK_TRACE_DIR);
|
|
383
|
+
const filePath = getTraceFilePath(runId, usable);
|
|
384
|
+
await writeFile(filePath, "", "utf-8");
|
|
385
|
+
return filePath;
|
|
386
|
+
} catch (e) {
|
|
387
|
+
warn("Failed to initialize trace file on fallback directory", e);
|
|
388
|
+
return void 0;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async function writeTraceEvent(event, traceDir) {
|
|
392
|
+
if (!validateEvent(event)) {
|
|
393
|
+
warn("Skipped invalid trace event (validation failed)");
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const line = serializeEvent(event);
|
|
397
|
+
if (line === "") {
|
|
398
|
+
warn("Skipped trace event (serialization failed)");
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const payload = `${line}
|
|
402
|
+
`;
|
|
403
|
+
const tryAppend = async (dir) => {
|
|
404
|
+
try {
|
|
405
|
+
const usable = await ensureTraceDir(dir);
|
|
406
|
+
const filePath = getTraceFilePath(event.runId, usable);
|
|
407
|
+
await appendFile(filePath, payload, "utf-8");
|
|
408
|
+
return true;
|
|
409
|
+
} catch {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
if (await tryAppend(traceDir)) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
warn(`Failed to append trace event for run ${event.runId}`);
|
|
417
|
+
if (await tryAppend(FALLBACK_TRACE_DIR)) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
warn("Failed to append trace event to fallback directory");
|
|
421
|
+
}
|
|
422
|
+
async function readTraceFile(runId, traceDir) {
|
|
423
|
+
try {
|
|
424
|
+
const filePath = getTraceFilePath(runId, traceDir);
|
|
425
|
+
return await readFile(filePath, "utf-8");
|
|
426
|
+
} catch (e) {
|
|
427
|
+
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
428
|
+
return void 0;
|
|
429
|
+
}
|
|
430
|
+
warn("Unexpected error reading trace file", e);
|
|
431
|
+
return void 0;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
async function readTraceEvents(runId, traceDir) {
|
|
435
|
+
const out = [];
|
|
436
|
+
try {
|
|
437
|
+
const raw = await readTraceFile(runId, traceDir);
|
|
438
|
+
if (raw === void 0) {
|
|
439
|
+
return out;
|
|
440
|
+
}
|
|
441
|
+
const lines = raw.split("\n");
|
|
442
|
+
for (const line of lines) {
|
|
443
|
+
const trimmed = line.trim();
|
|
444
|
+
if (trimmed === "") continue;
|
|
445
|
+
let parsed;
|
|
446
|
+
try {
|
|
447
|
+
parsed = JSON.parse(trimmed);
|
|
448
|
+
} catch {
|
|
449
|
+
warn("Skipped invalid JSON line in trace file");
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (validateEvent(parsed)) {
|
|
453
|
+
out.push(parsed);
|
|
454
|
+
} else {
|
|
455
|
+
warn("Skipped invalid trace event line in trace file");
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
} catch (e) {
|
|
459
|
+
warn("Failed to read trace events", e);
|
|
460
|
+
}
|
|
461
|
+
return out;
|
|
462
|
+
}
|
|
463
|
+
async function listTraceFiles(traceDir) {
|
|
464
|
+
try {
|
|
465
|
+
const usable = path.resolve(traceDir);
|
|
466
|
+
const names = await readdir(usable);
|
|
467
|
+
const jsonl = names.filter((n) => n.endsWith(".jsonl"));
|
|
468
|
+
const withStat = await Promise.all(
|
|
469
|
+
jsonl.map(async (name) => {
|
|
470
|
+
try {
|
|
471
|
+
const st = await stat(path.join(usable, name));
|
|
472
|
+
return { name, mtime: st.mtimeMs };
|
|
473
|
+
} catch {
|
|
474
|
+
return { name, mtime: 0 };
|
|
475
|
+
}
|
|
476
|
+
})
|
|
477
|
+
);
|
|
478
|
+
withStat.sort((a, b) => {
|
|
479
|
+
if (b.mtime !== a.mtime) return b.mtime - a.mtime;
|
|
480
|
+
return a.name.localeCompare(b.name);
|
|
481
|
+
});
|
|
482
|
+
return withStat.map((x) => x.name);
|
|
483
|
+
} catch {
|
|
484
|
+
return [];
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
function getRunIdFromTraceFileName(fileName) {
|
|
488
|
+
try {
|
|
489
|
+
const base = path.basename(fileName);
|
|
490
|
+
if (!base.endsWith(".jsonl")) return void 0;
|
|
491
|
+
const id = base.slice(0, -".jsonl".length);
|
|
492
|
+
return id === "" ? void 0 : id;
|
|
493
|
+
} catch {
|
|
494
|
+
return void 0;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
var TERMINAL_INDENT = " ";
|
|
498
|
+
var MAX_TERMINAL_NAME_LENGTH = 80;
|
|
499
|
+
var MAX_TERMINAL_DEPTH = 10;
|
|
500
|
+
function normalizeDepth(depth) {
|
|
501
|
+
if (!Number.isFinite(depth) || depth < 0) {
|
|
502
|
+
return 0;
|
|
503
|
+
}
|
|
504
|
+
return Math.min(Math.floor(depth), MAX_TERMINAL_DEPTH);
|
|
505
|
+
}
|
|
506
|
+
function safePrint(line = "") {
|
|
507
|
+
try {
|
|
508
|
+
console.log(line);
|
|
509
|
+
} catch {
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function getIndent(depth) {
|
|
513
|
+
return TERMINAL_INDENT.repeat(normalizeDepth(depth));
|
|
514
|
+
}
|
|
515
|
+
function formatTerminalName(name) {
|
|
516
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
517
|
+
return "unnamed";
|
|
518
|
+
}
|
|
519
|
+
return truncateName(name, MAX_TERMINAL_NAME_LENGTH);
|
|
520
|
+
}
|
|
521
|
+
function getStatusIcon(status) {
|
|
522
|
+
if (status === "success") return chalk.green("\u2714");
|
|
523
|
+
if (status === "error") return chalk.red("\u2716");
|
|
524
|
+
return chalk.yellow("\u23F3");
|
|
525
|
+
}
|
|
526
|
+
function renderStepLine(name, durationMs, status, depth) {
|
|
527
|
+
try {
|
|
528
|
+
const nm = formatTerminalName(name);
|
|
529
|
+
const ind = getIndent(depth ?? 0);
|
|
530
|
+
if (status === "running" && durationMs === void 0) {
|
|
531
|
+
return `${ind}${chalk.yellow("\u23F3")} ${nm}`;
|
|
532
|
+
}
|
|
533
|
+
const hasDur = durationMs !== void 0 && Number.isFinite(durationMs);
|
|
534
|
+
const dur = hasDur ? formatDuration(durationMs) : void 0;
|
|
535
|
+
if (status === "running") {
|
|
536
|
+
return dur !== void 0 ? `${ind}${chalk.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${chalk.yellow("\u23F3")} ${nm}`;
|
|
537
|
+
}
|
|
538
|
+
if (!hasDur || dur === void 0) {
|
|
539
|
+
return `${ind}${chalk.yellow("\u23F3")} ${nm}`;
|
|
540
|
+
}
|
|
541
|
+
if (status === "success") {
|
|
542
|
+
return `${ind}${getStatusIcon("success")} ${nm} (${dur})`;
|
|
543
|
+
}
|
|
544
|
+
return `${ind}${getStatusIcon("error")} ${nm} (${dur})`;
|
|
545
|
+
} catch {
|
|
546
|
+
return "";
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function renderErrorLine(error, depth) {
|
|
550
|
+
try {
|
|
551
|
+
const msg = typeof error.message === "string" ? error.message : "";
|
|
552
|
+
const ind = getIndent((depth ?? 0) + 1);
|
|
553
|
+
return `${ind}Error: ${msg}`;
|
|
554
|
+
} catch {
|
|
555
|
+
return "";
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function renderRunSummary(durationMs, status, traceFilePath) {
|
|
559
|
+
try {
|
|
560
|
+
const dur = Number.isFinite(durationMs) ? formatDuration(durationMs) : formatDuration(0);
|
|
561
|
+
const head = status === "error" ? `Failed in ${dur}` : `Completed in ${dur}`;
|
|
562
|
+
const lines = [head];
|
|
563
|
+
if (traceFilePath !== void 0 && traceFilePath.trim() !== "") {
|
|
564
|
+
lines.push(`Trace: ${traceFilePath}`);
|
|
565
|
+
}
|
|
566
|
+
return lines;
|
|
567
|
+
} catch {
|
|
568
|
+
return [];
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function printRunStart(runId, name) {
|
|
572
|
+
if (isSilentContext()) return;
|
|
573
|
+
try {
|
|
574
|
+
safePrint("");
|
|
575
|
+
const header = `${chalk.cyan.bold("\u{1F50D} AgentInspect:")} ${formatTerminalName(name)} ${chalk.dim(`(${runId})`)}`;
|
|
576
|
+
safePrint(header);
|
|
577
|
+
} catch {
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
function printStepStart(name, depth = 0) {
|
|
581
|
+
if (isSilentContext()) return;
|
|
582
|
+
try {
|
|
583
|
+
safePrint(renderStepLine(name, void 0, "running", depth));
|
|
584
|
+
} catch {
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function printStepComplete(name, durationMs, status, depth = 0) {
|
|
588
|
+
if (isSilentContext()) return;
|
|
589
|
+
try {
|
|
590
|
+
safePrint(renderStepLine(name, durationMs, status, depth));
|
|
591
|
+
} catch {
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
function printError(error, depth = 0) {
|
|
595
|
+
if (isSilentContext()) return;
|
|
596
|
+
try {
|
|
597
|
+
safePrint(renderErrorLine(error, depth));
|
|
598
|
+
} catch {
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function printRunComplete(_name, _runId, durationMs, status, traceFilePath) {
|
|
602
|
+
if (isSilentContext()) return;
|
|
603
|
+
try {
|
|
604
|
+
const lines = renderRunSummary(durationMs, status, traceFilePath);
|
|
605
|
+
for (let i = 0; i < lines.length; i++) {
|
|
606
|
+
const line = lines[i];
|
|
607
|
+
if (i === 0) {
|
|
608
|
+
const color = status === "error" ? chalk.red : status === "running" ? chalk.yellow : chalk.green;
|
|
609
|
+
safePrint(color(line));
|
|
610
|
+
} else {
|
|
611
|
+
safePrint(chalk.dim(line));
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
} catch {
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
function printFailedAt(stepName) {
|
|
618
|
+
if (isSilentContext()) return;
|
|
619
|
+
try {
|
|
620
|
+
safePrint(`Failed at: ${formatTerminalName(stepName)}`);
|
|
621
|
+
} catch {
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// packages/core/src/inspect-run.ts
|
|
626
|
+
function normalizeRunName(name) {
|
|
627
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
628
|
+
return "unnamed-run";
|
|
629
|
+
}
|
|
630
|
+
return truncateName(name.trim(), 100);
|
|
631
|
+
}
|
|
632
|
+
async function safeInstrumentation(label, op) {
|
|
633
|
+
try {
|
|
634
|
+
await Promise.resolve(op());
|
|
635
|
+
} catch (e) {
|
|
636
|
+
warn(`inspectRun: ${label}`, e);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
async function inspectRun(name, fn, options) {
|
|
640
|
+
if (typeof fn !== "function") {
|
|
641
|
+
throw new TypeError("inspectRun requires `fn` to be a function");
|
|
642
|
+
}
|
|
643
|
+
const runName = normalizeRunName(name);
|
|
644
|
+
const runId = createRunId();
|
|
645
|
+
const traceDir = typeof options?.traceDir === "string" && options.traceDir.trim() !== "" ? options.traceDir.trim() : getDefaultTraceDir();
|
|
646
|
+
const context = {
|
|
647
|
+
runId,
|
|
648
|
+
runName,
|
|
649
|
+
traceDir,
|
|
650
|
+
silent: options?.silent ?? false,
|
|
651
|
+
metadata: options?.metadata
|
|
652
|
+
};
|
|
653
|
+
return runWithContext(context, async () => {
|
|
654
|
+
const startTime = Date.now();
|
|
655
|
+
let traceFilePath;
|
|
656
|
+
await safeInstrumentation("initializeTraceFile", async () => {
|
|
657
|
+
traceFilePath = await initializeTraceFile(runId, traceDir);
|
|
658
|
+
});
|
|
659
|
+
await safeInstrumentation("writeTraceEvent(run_started)", async () => {
|
|
660
|
+
const started = {
|
|
661
|
+
schemaVersion: "0.1",
|
|
662
|
+
event: "run_started",
|
|
663
|
+
timestamp: startTime,
|
|
664
|
+
runId,
|
|
665
|
+
name: runName,
|
|
666
|
+
startTime,
|
|
667
|
+
...options?.metadata !== void 0 ? { metadata: options.metadata } : {}
|
|
668
|
+
};
|
|
669
|
+
await writeTraceEvent(started, traceDir);
|
|
670
|
+
});
|
|
671
|
+
await safeInstrumentation("printRunStart", () => {
|
|
672
|
+
printRunStart(runId, runName);
|
|
673
|
+
});
|
|
674
|
+
let result;
|
|
675
|
+
try {
|
|
676
|
+
result = await Promise.resolve(fn());
|
|
677
|
+
} catch (userError) {
|
|
678
|
+
const endTime2 = Date.now();
|
|
679
|
+
const durationMs2 = endTime2 - startTime;
|
|
680
|
+
const formatted = formatError(userError);
|
|
681
|
+
const printPath2 = traceFilePath ?? getTraceFilePath(runId, traceDir);
|
|
682
|
+
await safeInstrumentation("writeTraceEvent(run_completed error)", async () => {
|
|
683
|
+
const completed = {
|
|
684
|
+
schemaVersion: "0.1",
|
|
685
|
+
event: "run_completed",
|
|
686
|
+
timestamp: endTime2,
|
|
687
|
+
runId,
|
|
688
|
+
status: "error",
|
|
689
|
+
endTime: endTime2,
|
|
690
|
+
durationMs: durationMs2,
|
|
691
|
+
error: formatted
|
|
692
|
+
};
|
|
693
|
+
await writeTraceEvent(completed, traceDir);
|
|
694
|
+
});
|
|
695
|
+
await safeInstrumentation("printRunComplete(error)", () => {
|
|
696
|
+
printRunComplete(runName, runId, durationMs2, "error", printPath2);
|
|
697
|
+
});
|
|
698
|
+
throw userError;
|
|
699
|
+
}
|
|
700
|
+
const endTime = Date.now();
|
|
701
|
+
const durationMs = endTime - startTime;
|
|
702
|
+
const printPath = traceFilePath ?? getTraceFilePath(runId, traceDir);
|
|
703
|
+
await safeInstrumentation("writeTraceEvent(run_completed success)", async () => {
|
|
704
|
+
const completed = {
|
|
705
|
+
schemaVersion: "0.1",
|
|
706
|
+
event: "run_completed",
|
|
707
|
+
timestamp: endTime,
|
|
708
|
+
runId,
|
|
709
|
+
status: "success",
|
|
710
|
+
endTime,
|
|
711
|
+
durationMs
|
|
712
|
+
};
|
|
713
|
+
await writeTraceEvent(completed, traceDir);
|
|
714
|
+
});
|
|
715
|
+
await safeInstrumentation("printRunComplete(success)", () => {
|
|
716
|
+
printRunComplete(runName, runId, durationMs, "success", printPath);
|
|
717
|
+
});
|
|
718
|
+
return result;
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// packages/core/src/step.ts
|
|
723
|
+
function normalizeStepName(name) {
|
|
724
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
725
|
+
return "unnamed-step";
|
|
726
|
+
}
|
|
727
|
+
return truncateName(name.trim(), 100);
|
|
728
|
+
}
|
|
729
|
+
async function safeInstrumentation2(label, op) {
|
|
730
|
+
try {
|
|
731
|
+
await Promise.resolve(op());
|
|
732
|
+
} catch (e) {
|
|
733
|
+
warn(`step: ${label}`, e);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async function stepImpl(name, fn, options) {
|
|
737
|
+
if (typeof fn !== "function") {
|
|
738
|
+
throw new TypeError("step requires `fn` to be a function");
|
|
739
|
+
}
|
|
740
|
+
const stepName = normalizeStepName(name);
|
|
741
|
+
const context = getCurrentContext();
|
|
742
|
+
if (!context) {
|
|
743
|
+
warn("step() called outside inspectRun(); executing without instrumentation");
|
|
744
|
+
return Promise.resolve(fn());
|
|
745
|
+
}
|
|
746
|
+
const stepId = createStepId();
|
|
747
|
+
const renderDepth = getCurrentDepth();
|
|
748
|
+
const parentId = getParentStepId();
|
|
749
|
+
const stepType = options?.type ?? "logic";
|
|
750
|
+
const metadata = options?.metadata;
|
|
751
|
+
const startTime = Date.now();
|
|
752
|
+
await safeInstrumentation2("writeTraceEvent(step_started)", async () => {
|
|
753
|
+
const started = {
|
|
754
|
+
schemaVersion: "0.1",
|
|
755
|
+
event: "step_started",
|
|
756
|
+
timestamp: startTime,
|
|
757
|
+
runId: context.runId,
|
|
758
|
+
stepId,
|
|
759
|
+
...typeof parentId === "string" && parentId.trim() !== "" ? { parentId } : {},
|
|
760
|
+
name: stepName,
|
|
761
|
+
type: stepType,
|
|
762
|
+
startTime,
|
|
763
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
764
|
+
};
|
|
765
|
+
await writeTraceEvent(started, context.traceDir);
|
|
766
|
+
});
|
|
767
|
+
await safeInstrumentation2("printStepStart", () => {
|
|
768
|
+
printStepStart(stepName, renderDepth);
|
|
769
|
+
});
|
|
770
|
+
let result;
|
|
771
|
+
try {
|
|
772
|
+
result = await runWithStepContext(stepId, async () => {
|
|
773
|
+
return await Promise.resolve(fn());
|
|
774
|
+
});
|
|
775
|
+
} catch (userError) {
|
|
776
|
+
const endTime2 = Date.now();
|
|
777
|
+
const durationMs2 = endTime2 - startTime;
|
|
778
|
+
const formatted = formatError(userError);
|
|
779
|
+
await safeInstrumentation2("writeTraceEvent(step_completed error)", async () => {
|
|
780
|
+
const completed = {
|
|
781
|
+
schemaVersion: "0.1",
|
|
782
|
+
event: "step_completed",
|
|
783
|
+
timestamp: endTime2,
|
|
784
|
+
runId: context.runId,
|
|
785
|
+
stepId,
|
|
786
|
+
status: "error",
|
|
787
|
+
endTime: endTime2,
|
|
788
|
+
durationMs: durationMs2,
|
|
789
|
+
error: formatted
|
|
790
|
+
};
|
|
791
|
+
await writeTraceEvent(completed, context.traceDir);
|
|
792
|
+
});
|
|
793
|
+
await safeInstrumentation2("printStepComplete(error)", () => {
|
|
794
|
+
printStepComplete(stepName, durationMs2, "error", renderDepth);
|
|
795
|
+
});
|
|
796
|
+
await safeInstrumentation2("printError", () => {
|
|
797
|
+
printError(formatted, renderDepth);
|
|
798
|
+
});
|
|
799
|
+
await safeInstrumentation2("printFailedAt", () => {
|
|
800
|
+
printFailedAt(stepName);
|
|
801
|
+
});
|
|
802
|
+
throw userError;
|
|
803
|
+
}
|
|
804
|
+
const endTime = Date.now();
|
|
805
|
+
const durationMs = endTime - startTime;
|
|
806
|
+
await safeInstrumentation2("writeTraceEvent(step_completed success)", async () => {
|
|
807
|
+
const completed = {
|
|
808
|
+
schemaVersion: "0.1",
|
|
809
|
+
event: "step_completed",
|
|
810
|
+
timestamp: endTime,
|
|
811
|
+
runId: context.runId,
|
|
812
|
+
stepId,
|
|
813
|
+
status: "success",
|
|
814
|
+
endTime,
|
|
815
|
+
durationMs
|
|
816
|
+
};
|
|
817
|
+
await writeTraceEvent(completed, context.traceDir);
|
|
818
|
+
});
|
|
819
|
+
await safeInstrumentation2("printStepComplete(success)", () => {
|
|
820
|
+
printStepComplete(stepName, durationMs, "success", renderDepth);
|
|
821
|
+
});
|
|
822
|
+
return result;
|
|
823
|
+
}
|
|
824
|
+
async function stepLlm(model, fn) {
|
|
825
|
+
const modelName = typeof model === "string" && model.trim() !== "" ? model.trim() : "unknown-model";
|
|
826
|
+
return stepImpl(`llm:${modelName}`, fn, {
|
|
827
|
+
type: "llm",
|
|
828
|
+
metadata: { model: modelName }
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
async function stepTool(toolName, fn) {
|
|
832
|
+
const normalized = typeof toolName === "string" && toolName.trim() !== "" ? toolName.trim() : "unknown-tool";
|
|
833
|
+
return stepImpl(`tool:${normalized}`, fn, {
|
|
834
|
+
type: "tool",
|
|
835
|
+
metadata: { toolName: normalized }
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
var step = Object.assign(stepImpl, {
|
|
839
|
+
llm: stepLlm,
|
|
840
|
+
tool: stepTool
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
// packages/core/src/observe.ts
|
|
844
|
+
var INSTRUMENTABLE_METHODS = ["run", "execute", "invoke"];
|
|
845
|
+
function isInstrumentableProp(prop) {
|
|
846
|
+
if (typeof prop !== "string") return false;
|
|
847
|
+
return INSTRUMENTABLE_METHODS.includes(prop);
|
|
848
|
+
}
|
|
849
|
+
function getAgentLabel(target) {
|
|
850
|
+
try {
|
|
851
|
+
const ctor = Reflect.get(target, "constructor");
|
|
852
|
+
const name = ctor?.name;
|
|
853
|
+
if (typeof name === "string" && name.trim() !== "" && name !== "Object") {
|
|
854
|
+
return name.trim();
|
|
855
|
+
}
|
|
856
|
+
} catch {
|
|
857
|
+
}
|
|
858
|
+
return "Agent";
|
|
859
|
+
}
|
|
860
|
+
function buildRunName(target, methodKey) {
|
|
861
|
+
const label = getAgentLabel(target);
|
|
862
|
+
return truncateName(`${label}.${methodKey}`, 100);
|
|
863
|
+
}
|
|
864
|
+
function observe(agent, options) {
|
|
865
|
+
if (agent === null || agent === void 0) {
|
|
866
|
+
warn("observe() requires an object");
|
|
867
|
+
return agent;
|
|
868
|
+
}
|
|
869
|
+
const agentType = typeof agent;
|
|
870
|
+
if (agentType !== "object" && agentType !== "function") {
|
|
871
|
+
warn("observe() requires an object");
|
|
872
|
+
return agent;
|
|
873
|
+
}
|
|
874
|
+
const target = agent;
|
|
875
|
+
const handlers = {
|
|
876
|
+
get(proxyTarget, prop, receiver) {
|
|
877
|
+
try {
|
|
878
|
+
const value = Reflect.get(proxyTarget, prop, receiver);
|
|
879
|
+
if (isInstrumentableProp(prop)) {
|
|
880
|
+
if (typeof value !== "function") {
|
|
881
|
+
return value;
|
|
882
|
+
}
|
|
883
|
+
const methodKey = prop;
|
|
884
|
+
return function observedWrapper(...args) {
|
|
885
|
+
let runName;
|
|
886
|
+
try {
|
|
887
|
+
runName = buildRunName(proxyTarget, methodKey);
|
|
888
|
+
} catch (e) {
|
|
889
|
+
warn("observe() method wrapping failed", e);
|
|
890
|
+
return value.apply(proxyTarget, args);
|
|
891
|
+
}
|
|
892
|
+
return inspectRun(runName, () => value.apply(proxyTarget, args), options);
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
if (typeof value === "function" && prop !== "constructor") {
|
|
896
|
+
return value.bind(proxyTarget);
|
|
897
|
+
}
|
|
898
|
+
return value;
|
|
899
|
+
} catch (e) {
|
|
900
|
+
warn("observe() method wrapping failed", e);
|
|
901
|
+
try {
|
|
902
|
+
return Reflect.get(proxyTarget, prop, receiver);
|
|
903
|
+
} catch {
|
|
904
|
+
return void 0;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
try {
|
|
910
|
+
return new Proxy(target, handlers);
|
|
911
|
+
} catch (e) {
|
|
912
|
+
warn("observe() failed", e);
|
|
913
|
+
return agent;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
export { DEFAULT_TRACE_DIR_NAME, FALLBACK_TRACE_DIR, MAX_NAME_LENGTH, MAX_TERMINAL_DEPTH, MAX_TERMINAL_NAME_LENGTH, RUNS_DIR_NAME, TERMINAL_INDENT, createRunId, createStepId, ensureTraceDir, formatDuration, formatError, formatTerminalName, formatTimestamp, getCurrentContext, getCurrentDepth, getCurrentRunId, getCurrentRunName, getCurrentStepId, getDefaultTraceDir, getIndent, getParentStepId, getRunIdFromTraceFileName, getTraceDirFromContext, getTraceFilePath, hasActiveContext, initializeTraceFile, inspectRun, isSilentContext, isStepStatus, isStepType, isTraceEvent, listTraceFiles, observe, printError, printFailedAt, printRunComplete, printRunStart, printStepComplete, printStepStart, readTraceEvents, readTraceFile, renderErrorLine, renderRunSummary, renderStepLine, runWithContext, runWithStepContext, serializeEvent, step, truncateName, validateEvent, warn, writeTraceEvent };
|
|
918
|
+
//# sourceMappingURL=index.mjs.map
|
|
919
|
+
//# sourceMappingURL=index.mjs.map
|