agentflow-core 0.3.3 → 0.4.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/dist/{chunk-M5CGDXAO.js → chunk-DHCTDCDI.js} +1612 -1306
- package/dist/chunk-DY7YHFIB.js +56 -0
- package/dist/cli.cjs +1185 -577
- package/dist/cli.js +217 -9
- package/dist/index.cjs +936 -416
- package/dist/index.d.cts +296 -132
- package/dist/index.d.ts +296 -132
- package/dist/index.js +173 -5
- package/dist/loader-LYRR6LMM.js +8 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,14 +1,211 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
createTraceStore,
|
|
3
4
|
runTraced,
|
|
4
5
|
startLive,
|
|
5
|
-
startWatch
|
|
6
|
-
|
|
6
|
+
startWatch,
|
|
7
|
+
toAsciiTree,
|
|
8
|
+
toTimeline
|
|
9
|
+
} from "./chunk-DHCTDCDI.js";
|
|
10
|
+
import "./chunk-DY7YHFIB.js";
|
|
7
11
|
|
|
8
12
|
// src/cli.ts
|
|
9
13
|
import { basename } from "path";
|
|
14
|
+
|
|
15
|
+
// src/trace-cli.ts
|
|
16
|
+
import { resolve } from "path";
|
|
17
|
+
function getTracesDir(argv) {
|
|
18
|
+
const idx = argv.indexOf("--traces-dir");
|
|
19
|
+
if (idx !== -1 && argv[idx + 1]) {
|
|
20
|
+
return resolve(argv[idx + 1]);
|
|
21
|
+
}
|
|
22
|
+
return resolve("./traces");
|
|
23
|
+
}
|
|
24
|
+
function getFlag(argv, name) {
|
|
25
|
+
const idx = argv.indexOf(name);
|
|
26
|
+
if (idx !== -1 && argv[idx + 1]) {
|
|
27
|
+
return argv[idx + 1];
|
|
28
|
+
}
|
|
29
|
+
return void 0;
|
|
30
|
+
}
|
|
31
|
+
function printTraceHelp() {
|
|
32
|
+
console.log(
|
|
33
|
+
`
|
|
34
|
+
AgentFlow Trace \u2014 inspect saved execution traces.
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
agentflow trace <command> [options]
|
|
38
|
+
|
|
39
|
+
Commands:
|
|
40
|
+
list [--status <status>] [--limit <n>] List saved traces
|
|
41
|
+
show <graph-id> Show trace as ASCII tree
|
|
42
|
+
timeline <graph-id> Show trace as timeline waterfall
|
|
43
|
+
stuck Show all stuck/hung/timeout spans
|
|
44
|
+
loops [--threshold <n>] Detect reasoning loops
|
|
45
|
+
|
|
46
|
+
Options:
|
|
47
|
+
--traces-dir <path> Directory containing trace files (default: ./traces)
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
agentflow trace list --status failed --limit 10
|
|
51
|
+
agentflow trace show abc-123
|
|
52
|
+
agentflow trace timeline abc-123
|
|
53
|
+
agentflow trace stuck
|
|
54
|
+
agentflow trace loops --threshold 10
|
|
55
|
+
`.trim()
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
async function traceList(argv) {
|
|
59
|
+
const dir = getTracesDir(argv);
|
|
60
|
+
const store = createTraceStore(dir);
|
|
61
|
+
const status = getFlag(argv, "--status");
|
|
62
|
+
const limitStr = getFlag(argv, "--limit");
|
|
63
|
+
const limit = limitStr ? Number.parseInt(limitStr, 10) : void 0;
|
|
64
|
+
const graphs = await store.list({ status, limit });
|
|
65
|
+
if (graphs.length === 0) {
|
|
66
|
+
console.log("No traces found.");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
console.log(`Found ${graphs.length} trace(s) in ${dir}:
|
|
70
|
+
`);
|
|
71
|
+
for (const g of graphs) {
|
|
72
|
+
const duration = g.endTime ? `${((g.endTime - g.startTime) / 1e3).toFixed(1)}s` : "running";
|
|
73
|
+
const date = new Date(g.startTime).toISOString().replace("T", " ").replace(/\.\d+Z$/, "");
|
|
74
|
+
const icon = g.status === "completed" ? "\u2713" : g.status === "failed" ? "\u2717" : "\u231B";
|
|
75
|
+
console.log(
|
|
76
|
+
` ${icon} ${g.id} ${g.status.padEnd(10)} ${duration.padEnd(8)} ${date} ${g.agentId}`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function traceShow(argv) {
|
|
81
|
+
const dir = getTracesDir(argv);
|
|
82
|
+
const store = createTraceStore(dir);
|
|
83
|
+
const showIdx = argv.indexOf("show");
|
|
84
|
+
const graphId = showIdx !== -1 ? argv[showIdx + 1] : void 0;
|
|
85
|
+
if (!graphId || graphId.startsWith("--")) {
|
|
86
|
+
console.error("Usage: agentflow trace show <graph-id>");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
let graph = await store.get(graphId);
|
|
90
|
+
if (!graph) {
|
|
91
|
+
const { readFile } = await import("fs/promises");
|
|
92
|
+
const { join } = await import("path");
|
|
93
|
+
const fname = graphId.endsWith(".json") ? graphId : `${graphId}.json`;
|
|
94
|
+
try {
|
|
95
|
+
const { loadGraph } = await import("./loader-LYRR6LMM.js");
|
|
96
|
+
const content = await readFile(join(dir, fname), "utf-8");
|
|
97
|
+
graph = loadGraph(content);
|
|
98
|
+
} catch {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!graph) {
|
|
102
|
+
console.error(`Trace "${graphId}" not found in ${dir}`);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
console.log(`Trace: ${graph.id} (${graph.status})
|
|
106
|
+
`);
|
|
107
|
+
console.log(toAsciiTree(graph));
|
|
108
|
+
}
|
|
109
|
+
async function traceTimeline(argv) {
|
|
110
|
+
const dir = getTracesDir(argv);
|
|
111
|
+
const store = createTraceStore(dir);
|
|
112
|
+
const timelineIdx = argv.indexOf("timeline");
|
|
113
|
+
const graphId = timelineIdx !== -1 ? argv[timelineIdx + 1] : void 0;
|
|
114
|
+
if (!graphId || graphId.startsWith("--")) {
|
|
115
|
+
console.error("Usage: agentflow trace timeline <graph-id>");
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
let graph = await store.get(graphId);
|
|
119
|
+
if (!graph) {
|
|
120
|
+
const { readFile } = await import("fs/promises");
|
|
121
|
+
const { join } = await import("path");
|
|
122
|
+
const fname = graphId.endsWith(".json") ? graphId : `${graphId}.json`;
|
|
123
|
+
try {
|
|
124
|
+
const { loadGraph } = await import("./loader-LYRR6LMM.js");
|
|
125
|
+
const content = await readFile(join(dir, fname), "utf-8");
|
|
126
|
+
graph = loadGraph(content);
|
|
127
|
+
} catch {
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (!graph) {
|
|
131
|
+
console.error(`Trace "${graphId}" not found in ${dir}`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
console.log(`Trace: ${graph.id} (${graph.status})
|
|
135
|
+
`);
|
|
136
|
+
console.log(toTimeline(graph));
|
|
137
|
+
}
|
|
138
|
+
async function traceStuck(argv) {
|
|
139
|
+
const dir = getTracesDir(argv);
|
|
140
|
+
const store = createTraceStore(dir);
|
|
141
|
+
const stuck = await store.getStuckSpans();
|
|
142
|
+
if (stuck.length === 0) {
|
|
143
|
+
console.log("No stuck spans found.");
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
console.log(`Found ${stuck.length} stuck span(s):
|
|
147
|
+
`);
|
|
148
|
+
for (const node of stuck) {
|
|
149
|
+
const elapsed = Date.now() - node.startTime;
|
|
150
|
+
const icon = node.status === "timeout" ? "\u231B" : node.status === "hung" ? "\u231B" : "\u231B";
|
|
151
|
+
console.log(
|
|
152
|
+
` ${icon} ${node.id} ${node.type.padEnd(10)} ${node.name.padEnd(20)} ${node.status.padEnd(8)} ${(elapsed / 1e3).toFixed(0)}s`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function traceLoops(argv) {
|
|
157
|
+
const dir = getTracesDir(argv);
|
|
158
|
+
const store = createTraceStore(dir);
|
|
159
|
+
const thresholdStr = getFlag(argv, "--threshold");
|
|
160
|
+
const threshold = thresholdStr ? Number.parseInt(thresholdStr, 10) : void 0;
|
|
161
|
+
const loops = await store.getReasoningLoops(threshold);
|
|
162
|
+
if (loops.length === 0) {
|
|
163
|
+
console.log("No reasoning loops detected.");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
console.log(`Found reasoning loops in ${loops.length} trace(s):
|
|
167
|
+
`);
|
|
168
|
+
for (const { graphId, nodes } of loops) {
|
|
169
|
+
console.log(` Graph: ${graphId}`);
|
|
170
|
+
for (const node of nodes) {
|
|
171
|
+
console.log(` - ${node.id} (${node.type}: ${node.name})`);
|
|
172
|
+
}
|
|
173
|
+
console.log("");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async function handleTrace(argv) {
|
|
177
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
178
|
+
printTraceHelp();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const traceIdx = argv.indexOf("trace");
|
|
182
|
+
const subcommand = traceIdx !== -1 ? argv[traceIdx + 1] : void 0;
|
|
183
|
+
switch (subcommand) {
|
|
184
|
+
case "list":
|
|
185
|
+
await traceList(argv);
|
|
186
|
+
break;
|
|
187
|
+
case "show":
|
|
188
|
+
await traceShow(argv);
|
|
189
|
+
break;
|
|
190
|
+
case "timeline":
|
|
191
|
+
await traceTimeline(argv);
|
|
192
|
+
break;
|
|
193
|
+
case "stuck":
|
|
194
|
+
await traceStuck(argv);
|
|
195
|
+
break;
|
|
196
|
+
case "loops":
|
|
197
|
+
await traceLoops(argv);
|
|
198
|
+
break;
|
|
199
|
+
default:
|
|
200
|
+
printTraceHelp();
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/cli.ts
|
|
10
206
|
function printHelp() {
|
|
11
|
-
console.log(
|
|
207
|
+
console.log(
|
|
208
|
+
`
|
|
12
209
|
AgentFlow CLI \u2014 execution tracing and live monitoring for AI agent systems.
|
|
13
210
|
|
|
14
211
|
Usage:
|
|
@@ -18,6 +215,7 @@ Commands:
|
|
|
18
215
|
run [options] -- <cmd> Wrap a command with automatic execution tracing
|
|
19
216
|
live [dir...] [options] Real-time terminal monitor (auto-detects any JSON/JSONL)
|
|
20
217
|
watch [dir...] [options] Headless alert system \u2014 detects failures, sends notifications
|
|
218
|
+
trace <command> [options] Inspect saved execution traces (list, show, timeline, stuck, loops)
|
|
21
219
|
|
|
22
220
|
Run \`agentflow <command> --help\` for command-specific options.
|
|
23
221
|
|
|
@@ -27,7 +225,8 @@ Examples:
|
|
|
27
225
|
agentflow live ./traces ./cron ./workers -R
|
|
28
226
|
agentflow watch ./data --alert-on error --notify telegram
|
|
29
227
|
agentflow watch ./data ./cron --alert-on stale:15m --notify webhook:https://...
|
|
30
|
-
`.trim()
|
|
228
|
+
`.trim()
|
|
229
|
+
);
|
|
31
230
|
}
|
|
32
231
|
function parseRunArgs(argv) {
|
|
33
232
|
const result = {
|
|
@@ -88,7 +287,8 @@ function parseRunArgs(argv) {
|
|
|
88
287
|
return result;
|
|
89
288
|
}
|
|
90
289
|
function printRunUsage() {
|
|
91
|
-
console.log(
|
|
290
|
+
console.log(
|
|
291
|
+
`
|
|
92
292
|
AgentFlow Run \u2014 wrap any command with automatic execution tracing.
|
|
93
293
|
|
|
94
294
|
Usage:
|
|
@@ -106,7 +306,8 @@ Examples:
|
|
|
106
306
|
agentflow run -- python -m myagent process
|
|
107
307
|
agentflow run --watch-dir ./data -- python worker.py
|
|
108
308
|
agentflow run --traces-dir ./my-traces --agent-id recon -- node agent.js
|
|
109
|
-
`.trim()
|
|
309
|
+
`.trim()
|
|
310
|
+
);
|
|
110
311
|
}
|
|
111
312
|
async function runCommand(argv) {
|
|
112
313
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
@@ -115,7 +316,9 @@ async function runCommand(argv) {
|
|
|
115
316
|
}
|
|
116
317
|
const parsed = parseRunArgs(argv);
|
|
117
318
|
if (parsed.command.length === 0) {
|
|
118
|
-
console.error(
|
|
319
|
+
console.error(
|
|
320
|
+
"Error: No command specified. Use -- to separate agentflow flags from the command."
|
|
321
|
+
);
|
|
119
322
|
console.error("Example: agentflow run -- python -m myagent process");
|
|
120
323
|
process.exit(1);
|
|
121
324
|
}
|
|
@@ -139,7 +342,9 @@ async function runCommand(argv) {
|
|
|
139
342
|
try {
|
|
140
343
|
const result = await runTraced(config);
|
|
141
344
|
console.log("");
|
|
142
|
-
console.log(
|
|
345
|
+
console.log(
|
|
346
|
+
`\u2705 Command completed (exit code ${result.exitCode}, ${result.duration.toFixed(1)}s)`
|
|
347
|
+
);
|
|
143
348
|
if (result.tracePaths.length > 0) {
|
|
144
349
|
console.log("\u{1F4DD} Traces saved:");
|
|
145
350
|
const orchPath = result.tracePaths[0];
|
|
@@ -164,7 +369,7 @@ async function runCommand(argv) {
|
|
|
164
369
|
}
|
|
165
370
|
async function main() {
|
|
166
371
|
const argv = process.argv.slice(2);
|
|
167
|
-
const knownCommands = ["run", "live", "watch"];
|
|
372
|
+
const knownCommands = ["run", "live", "watch", "trace"];
|
|
168
373
|
if (argv.length === 0 || !knownCommands.includes(argv[0]) && (argv.includes("--help") || argv.includes("-h"))) {
|
|
169
374
|
printHelp();
|
|
170
375
|
process.exit(0);
|
|
@@ -180,6 +385,9 @@ async function main() {
|
|
|
180
385
|
case "watch":
|
|
181
386
|
startWatch(argv);
|
|
182
387
|
break;
|
|
388
|
+
case "trace":
|
|
389
|
+
await handleTrace(argv);
|
|
390
|
+
break;
|
|
183
391
|
default:
|
|
184
392
|
if (!subcommand?.startsWith("-")) {
|
|
185
393
|
startLive(["live", ...argv]);
|