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/index.d.ts
CHANGED
|
@@ -276,6 +276,224 @@ interface MutableExecutionNode {
|
|
|
276
276
|
*/
|
|
277
277
|
declare function createGraphBuilder(config?: AgentFlowConfig): GraphBuilder;
|
|
278
278
|
|
|
279
|
+
/**
|
|
280
|
+
* Pure query functions for interrogating a built `ExecutionGraph`.
|
|
281
|
+
* Every function takes a frozen graph and returns derived data without mutation.
|
|
282
|
+
* @module
|
|
283
|
+
*/
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Find a node by its ID.
|
|
287
|
+
*
|
|
288
|
+
* @param graph - The execution graph to search.
|
|
289
|
+
* @param nodeId - The node ID to look up.
|
|
290
|
+
* @returns The node, or `undefined` if not found.
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```ts
|
|
294
|
+
* const node = getNode(graph, 'node_002');
|
|
295
|
+
* if (node) console.log(node.name);
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
declare function getNode(graph: ExecutionGraph, nodeId: string): ExecutionNode | undefined;
|
|
299
|
+
/**
|
|
300
|
+
* Get the direct children of a node.
|
|
301
|
+
*
|
|
302
|
+
* @param graph - The execution graph to search.
|
|
303
|
+
* @param nodeId - The parent node ID.
|
|
304
|
+
* @returns Array of child nodes (may be empty).
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* ```ts
|
|
308
|
+
* const children = getChildren(graph, rootId);
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
declare function getChildren(graph: ExecutionGraph, nodeId: string): ExecutionNode[];
|
|
312
|
+
/**
|
|
313
|
+
* Get the parent of a node.
|
|
314
|
+
*
|
|
315
|
+
* @param graph - The execution graph to search.
|
|
316
|
+
* @param nodeId - The child node ID.
|
|
317
|
+
* @returns The parent node, or `undefined` if root or not found.
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```ts
|
|
321
|
+
* const parent = getParent(graph, toolId);
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
declare function getParent(graph: ExecutionGraph, nodeId: string): ExecutionNode | undefined;
|
|
325
|
+
/**
|
|
326
|
+
* Find all nodes with a failure-category status: `failed`, `hung`, or `timeout`.
|
|
327
|
+
*
|
|
328
|
+
* @param graph - The execution graph to search.
|
|
329
|
+
* @returns Array of nodes with failure statuses (may be empty).
|
|
330
|
+
*/
|
|
331
|
+
declare function getFailures(graph: ExecutionGraph): ExecutionNode[];
|
|
332
|
+
/**
|
|
333
|
+
* Find all nodes that are still running (status `'running'`, no endTime).
|
|
334
|
+
*
|
|
335
|
+
* @param graph - The execution graph to search.
|
|
336
|
+
* @returns Array of running/hung nodes.
|
|
337
|
+
*/
|
|
338
|
+
declare function getHungNodes(graph: ExecutionGraph): ExecutionNode[];
|
|
339
|
+
/**
|
|
340
|
+
* Find the critical path: the longest-duration path from the root to any leaf node.
|
|
341
|
+
* Uses node duration (endTime - startTime) as the weight.
|
|
342
|
+
* Running nodes use `Date.now()` as a provisional endTime.
|
|
343
|
+
*
|
|
344
|
+
* @param graph - The execution graph to analyse.
|
|
345
|
+
* @returns Nodes ordered from root to the deepest leaf on the longest path.
|
|
346
|
+
*/
|
|
347
|
+
declare function getCriticalPath(graph: ExecutionGraph): ExecutionNode[];
|
|
348
|
+
/**
|
|
349
|
+
* Find what a node is waiting on.
|
|
350
|
+
* Returns nodes connected via `waited_on` edges where the given nodeId is the `from` side.
|
|
351
|
+
*
|
|
352
|
+
* @param graph - The execution graph to search.
|
|
353
|
+
* @param nodeId - The node that is doing the waiting.
|
|
354
|
+
* @returns Array of nodes that are being waited on.
|
|
355
|
+
*/
|
|
356
|
+
declare function findWaitingOn(graph: ExecutionGraph, nodeId: string): ExecutionNode[];
|
|
357
|
+
/**
|
|
358
|
+
* Get all descendants of a node (children, grandchildren, etc.) in breadth-first order.
|
|
359
|
+
* The given node itself is NOT included.
|
|
360
|
+
*
|
|
361
|
+
* @param graph - The execution graph to search.
|
|
362
|
+
* @param nodeId - The ancestor node ID.
|
|
363
|
+
* @returns All descendant nodes in BFS order.
|
|
364
|
+
*/
|
|
365
|
+
declare function getSubtree(graph: ExecutionGraph, nodeId: string): ExecutionNode[];
|
|
366
|
+
/**
|
|
367
|
+
* Total wall-clock duration of the graph in milliseconds.
|
|
368
|
+
* If the graph is still running, uses `Date.now()` as the provisional end.
|
|
369
|
+
*
|
|
370
|
+
* @param graph - The execution graph.
|
|
371
|
+
* @returns Duration in milliseconds.
|
|
372
|
+
*/
|
|
373
|
+
declare function getDuration(graph: ExecutionGraph): number;
|
|
374
|
+
/**
|
|
375
|
+
* Maximum nesting depth of the graph. The root node is depth 0.
|
|
376
|
+
*
|
|
377
|
+
* @param graph - The execution graph.
|
|
378
|
+
* @returns The maximum depth (0 for a single-node graph, -1 for empty).
|
|
379
|
+
*/
|
|
380
|
+
declare function getDepth(graph: ExecutionGraph): number;
|
|
381
|
+
/**
|
|
382
|
+
* Compute aggregate statistics for the execution graph.
|
|
383
|
+
*
|
|
384
|
+
* @param graph - The execution graph to analyse.
|
|
385
|
+
* @returns Statistics including node counts by type and status, depth, duration, and failure counts.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```ts
|
|
389
|
+
* const stats = getStats(graph);
|
|
390
|
+
* console.log(`${stats.totalNodes} nodes, ${stats.failureCount} failures`);
|
|
391
|
+
* ```
|
|
392
|
+
*/
|
|
393
|
+
declare function getStats(graph: ExecutionGraph): GraphStats;
|
|
394
|
+
|
|
395
|
+
declare function groupByTraceId(graphs: ExecutionGraph[]): Map<string, ExecutionGraph[]>;
|
|
396
|
+
declare function stitchTrace(graphs: ExecutionGraph[]): DistributedTrace;
|
|
397
|
+
declare function getTraceTree(trace: DistributedTrace): ExecutionGraph[];
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Runtime guards for detecting problematic agent behaviors during graph construction.
|
|
401
|
+
*
|
|
402
|
+
* Guards operate on ExecutionGraph snapshots and detect three types of violations:
|
|
403
|
+
* - Long-running spans: nodes that exceed timeout thresholds for their type
|
|
404
|
+
* - Reasoning loops: consecutive nodes of the same type in a parent-child chain
|
|
405
|
+
* - Spawn explosion: excessive depth or agent/subagent spawn counts
|
|
406
|
+
*
|
|
407
|
+
* @module
|
|
408
|
+
*/
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Configuration for runtime guard detection.
|
|
412
|
+
*/
|
|
413
|
+
interface GuardConfig {
|
|
414
|
+
/** Timeout thresholds per node type in milliseconds. */
|
|
415
|
+
readonly timeouts?: Partial<Record<NodeType, number>>;
|
|
416
|
+
/** Maximum consecutive same-type nodes before flagging reasoning loop (default: 25). */
|
|
417
|
+
readonly maxReasoningSteps?: number;
|
|
418
|
+
/** Maximum graph depth before flagging spawn explosion (default: 10). */
|
|
419
|
+
readonly maxDepth?: number;
|
|
420
|
+
/** Maximum total agent/subagent nodes before flagging spawn explosion (default: 50). */
|
|
421
|
+
readonly maxAgentSpawns?: number;
|
|
422
|
+
/** Action to take when guard violations are detected. */
|
|
423
|
+
readonly onViolation?: 'warn' | 'error' | 'abort';
|
|
424
|
+
/** Custom logger for warnings (defaults to console.warn). */
|
|
425
|
+
readonly logger?: (message: string) => void;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* A detected guard violation.
|
|
429
|
+
*/
|
|
430
|
+
interface GuardViolation {
|
|
431
|
+
readonly type: 'timeout' | 'reasoning-loop' | 'spawn-explosion';
|
|
432
|
+
readonly nodeId: string;
|
|
433
|
+
readonly message: string;
|
|
434
|
+
readonly timestamp: number;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Check an execution graph for guard violations.
|
|
438
|
+
*
|
|
439
|
+
* This is a pure function that analyzes a graph snapshot and returns detected violations
|
|
440
|
+
* without modifying the graph or producing side effects.
|
|
441
|
+
*
|
|
442
|
+
* @param graph - The execution graph to analyze.
|
|
443
|
+
* @param config - Optional guard configuration.
|
|
444
|
+
* @returns Array of detected violations (may be empty).
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```ts
|
|
448
|
+
* const violations = checkGuards(graph, { maxDepth: 5 });
|
|
449
|
+
* if (violations.length > 0) {
|
|
450
|
+
* console.log(`Found ${violations.length} violations`);
|
|
451
|
+
* }
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
454
|
+
declare function checkGuards(graph: ExecutionGraph, config?: GuardConfig): readonly GuardViolation[];
|
|
455
|
+
/**
|
|
456
|
+
* Create a guard-aware wrapper around a GraphBuilder.
|
|
457
|
+
*
|
|
458
|
+
* The returned builder has an identical interface to the original but intercepts
|
|
459
|
+
* `endNode` and `build` calls to check for guard violations. Violations are handled
|
|
460
|
+
* according to the `onViolation` configuration.
|
|
461
|
+
*
|
|
462
|
+
* @param builder - The original GraphBuilder to wrap.
|
|
463
|
+
* @param config - Guard configuration.
|
|
464
|
+
* @returns A GraphBuilder with identical interface but guard protection.
|
|
465
|
+
*
|
|
466
|
+
* @example
|
|
467
|
+
* ```ts
|
|
468
|
+
* const raw = createGraphBuilder({ agentId: 'test' });
|
|
469
|
+
* const guarded = withGuards(raw, { maxDepth: 5, onViolation: 'abort' });
|
|
470
|
+
*
|
|
471
|
+
* // Use exactly like a normal builder
|
|
472
|
+
* const root = guarded.startNode({ type: 'agent', name: 'main' });
|
|
473
|
+
* guarded.endNode(root); // Will check for violations
|
|
474
|
+
* ```
|
|
475
|
+
*/
|
|
476
|
+
declare function withGuards(builder: GraphBuilder, config?: GuardConfig): GraphBuilder;
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* AgentFlow Live Monitor — real-time terminal dashboard for any agent system.
|
|
480
|
+
*
|
|
481
|
+
* Auto-detects and displays data from any JSON/JSONL files in the watched
|
|
482
|
+
* directory. Works with agentflow traces, generic state files, job
|
|
483
|
+
* schedulers, session logs — no configuration needed.
|
|
484
|
+
*
|
|
485
|
+
* File detection:
|
|
486
|
+
* .json with `nodes` + `agentId` → AgentFlow trace (full analysis)
|
|
487
|
+
* .json with array of objects with `state` → Job/task list (per-item status)
|
|
488
|
+
* .json with `status`/`pid`/`tools` → Process/worker state
|
|
489
|
+
* .json with any other structure → Generic state (mtime-based)
|
|
490
|
+
* .jsonl → Session log (last entry status)
|
|
491
|
+
*
|
|
492
|
+
* @module
|
|
493
|
+
*/
|
|
494
|
+
|
|
495
|
+
declare function startLive(argv: string[]): void;
|
|
496
|
+
|
|
279
497
|
/**
|
|
280
498
|
* Load and deserialize execution graphs from JSON.
|
|
281
499
|
*
|
|
@@ -378,23 +596,89 @@ interface RunResult {
|
|
|
378
596
|
declare function runTraced(config: RunConfig): Promise<RunResult>;
|
|
379
597
|
|
|
380
598
|
/**
|
|
381
|
-
*
|
|
599
|
+
* JSON file-based trace storage for ExecutionGraphs.
|
|
382
600
|
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
* schedulers, session logs — no configuration needed.
|
|
601
|
+
* One JSON file per graph, using existing graphToJson/loadGraph for serialization.
|
|
602
|
+
* Compatible with `agentflow watch` auto-detection.
|
|
386
603
|
*
|
|
387
|
-
*
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
*
|
|
392
|
-
|
|
604
|
+
* @module
|
|
605
|
+
*/
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Trace storage interface for saving, loading, and querying execution graphs.
|
|
609
|
+
*/
|
|
610
|
+
interface TraceStore {
|
|
611
|
+
/** Save a graph to disk. Returns the file path. */
|
|
612
|
+
save(graph: ExecutionGraph): Promise<string>;
|
|
613
|
+
/** Load a graph by ID. Returns null if not found. */
|
|
614
|
+
get(graphId: string): Promise<ExecutionGraph | null>;
|
|
615
|
+
/** List all stored graphs, optionally filtered by status. */
|
|
616
|
+
list(opts?: {
|
|
617
|
+
status?: GraphStatus;
|
|
618
|
+
limit?: number;
|
|
619
|
+
}): Promise<ExecutionGraph[]>;
|
|
620
|
+
/** Find all nodes with stuck status (running/hung/timeout) across all stored traces. */
|
|
621
|
+
getStuckSpans(): Promise<ExecutionNode[]>;
|
|
622
|
+
/** Find reasoning loops: consecutive same-type node sequences exceeding threshold. */
|
|
623
|
+
getReasoningLoops(threshold?: number): Promise<ReadonlyArray<{
|
|
624
|
+
graphId: string;
|
|
625
|
+
nodes: ExecutionNode[];
|
|
626
|
+
}>>;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Create a JSON file-based trace store.
|
|
630
|
+
*
|
|
631
|
+
* @param dir - Directory to store trace JSON files.
|
|
632
|
+
* @returns A TraceStore instance.
|
|
633
|
+
*
|
|
634
|
+
* @example
|
|
635
|
+
* ```ts
|
|
636
|
+
* const store = createTraceStore('./traces');
|
|
637
|
+
* await store.save(graph);
|
|
638
|
+
* const loaded = await store.get(graph.id);
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
641
|
+
declare function createTraceStore(dir: string): TraceStore;
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Trace visualization: ASCII tree and timeline rendering for ExecutionGraphs.
|
|
645
|
+
*
|
|
646
|
+
* All functions are pure — they take an ExecutionGraph and return formatted strings.
|
|
393
647
|
*
|
|
394
648
|
* @module
|
|
395
649
|
*/
|
|
396
650
|
|
|
397
|
-
|
|
651
|
+
/**
|
|
652
|
+
* Render an ExecutionGraph as an ASCII tree showing parent-child hierarchy.
|
|
653
|
+
*
|
|
654
|
+
* @param graph - The execution graph to render.
|
|
655
|
+
* @returns A multi-line string showing the tree with status icons, durations, and metadata.
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* ```ts
|
|
659
|
+
* console.log(toAsciiTree(graph));
|
|
660
|
+
* // ✓ main (agent) 4.2s
|
|
661
|
+
* // ├─ ✓ search (tool) 1.1s
|
|
662
|
+
* // └─ ✗ analyze (tool) 0.5s — Error: rate limit
|
|
663
|
+
* ```
|
|
664
|
+
*/
|
|
665
|
+
declare function toAsciiTree(graph: ExecutionGraph): string;
|
|
666
|
+
/**
|
|
667
|
+
* Render an ExecutionGraph as a horizontal timeline/waterfall.
|
|
668
|
+
*
|
|
669
|
+
* @param graph - The execution graph to render.
|
|
670
|
+
* @returns A multi-line string showing spans as horizontal bars relative to graph start.
|
|
671
|
+
*
|
|
672
|
+
* @example
|
|
673
|
+
* ```ts
|
|
674
|
+
* console.log(toTimeline(graph));
|
|
675
|
+
* // 0s 1s 2s 3s
|
|
676
|
+
* // ├─────────┼─────────┼─────────┤
|
|
677
|
+
* // ████████████████████████████████ main (4.2s)
|
|
678
|
+
* // ██████████ search (1.1s)
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
declare function toTimeline(graph: ExecutionGraph): string;
|
|
398
682
|
|
|
399
683
|
/**
|
|
400
684
|
* AgentFlow Watch — headless alert system for agent infrastructure.
|
|
@@ -459,124 +743,4 @@ interface AlertPayload {
|
|
|
459
743
|
readonly dirs: readonly string[];
|
|
460
744
|
}
|
|
461
745
|
|
|
462
|
-
|
|
463
|
-
declare function stitchTrace(graphs: ExecutionGraph[]): DistributedTrace;
|
|
464
|
-
declare function getTraceTree(trace: DistributedTrace): ExecutionGraph[];
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* Pure query functions for interrogating a built `ExecutionGraph`.
|
|
468
|
-
* Every function takes a frozen graph and returns derived data without mutation.
|
|
469
|
-
* @module
|
|
470
|
-
*/
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* Find a node by its ID.
|
|
474
|
-
*
|
|
475
|
-
* @param graph - The execution graph to search.
|
|
476
|
-
* @param nodeId - The node ID to look up.
|
|
477
|
-
* @returns The node, or `undefined` if not found.
|
|
478
|
-
*
|
|
479
|
-
* @example
|
|
480
|
-
* ```ts
|
|
481
|
-
* const node = getNode(graph, 'node_002');
|
|
482
|
-
* if (node) console.log(node.name);
|
|
483
|
-
* ```
|
|
484
|
-
*/
|
|
485
|
-
declare function getNode(graph: ExecutionGraph, nodeId: string): ExecutionNode | undefined;
|
|
486
|
-
/**
|
|
487
|
-
* Get the direct children of a node.
|
|
488
|
-
*
|
|
489
|
-
* @param graph - The execution graph to search.
|
|
490
|
-
* @param nodeId - The parent node ID.
|
|
491
|
-
* @returns Array of child nodes (may be empty).
|
|
492
|
-
*
|
|
493
|
-
* @example
|
|
494
|
-
* ```ts
|
|
495
|
-
* const children = getChildren(graph, rootId);
|
|
496
|
-
* ```
|
|
497
|
-
*/
|
|
498
|
-
declare function getChildren(graph: ExecutionGraph, nodeId: string): ExecutionNode[];
|
|
499
|
-
/**
|
|
500
|
-
* Get the parent of a node.
|
|
501
|
-
*
|
|
502
|
-
* @param graph - The execution graph to search.
|
|
503
|
-
* @param nodeId - The child node ID.
|
|
504
|
-
* @returns The parent node, or `undefined` if root or not found.
|
|
505
|
-
*
|
|
506
|
-
* @example
|
|
507
|
-
* ```ts
|
|
508
|
-
* const parent = getParent(graph, toolId);
|
|
509
|
-
* ```
|
|
510
|
-
*/
|
|
511
|
-
declare function getParent(graph: ExecutionGraph, nodeId: string): ExecutionNode | undefined;
|
|
512
|
-
/**
|
|
513
|
-
* Find all nodes with a failure-category status: `failed`, `hung`, or `timeout`.
|
|
514
|
-
*
|
|
515
|
-
* @param graph - The execution graph to search.
|
|
516
|
-
* @returns Array of nodes with failure statuses (may be empty).
|
|
517
|
-
*/
|
|
518
|
-
declare function getFailures(graph: ExecutionGraph): ExecutionNode[];
|
|
519
|
-
/**
|
|
520
|
-
* Find all nodes that are still running (status `'running'`, no endTime).
|
|
521
|
-
*
|
|
522
|
-
* @param graph - The execution graph to search.
|
|
523
|
-
* @returns Array of running/hung nodes.
|
|
524
|
-
*/
|
|
525
|
-
declare function getHungNodes(graph: ExecutionGraph): ExecutionNode[];
|
|
526
|
-
/**
|
|
527
|
-
* Find the critical path: the longest-duration path from the root to any leaf node.
|
|
528
|
-
* Uses node duration (endTime - startTime) as the weight.
|
|
529
|
-
* Running nodes use `Date.now()` as a provisional endTime.
|
|
530
|
-
*
|
|
531
|
-
* @param graph - The execution graph to analyse.
|
|
532
|
-
* @returns Nodes ordered from root to the deepest leaf on the longest path.
|
|
533
|
-
*/
|
|
534
|
-
declare function getCriticalPath(graph: ExecutionGraph): ExecutionNode[];
|
|
535
|
-
/**
|
|
536
|
-
* Find what a node is waiting on.
|
|
537
|
-
* Returns nodes connected via `waited_on` edges where the given nodeId is the `from` side.
|
|
538
|
-
*
|
|
539
|
-
* @param graph - The execution graph to search.
|
|
540
|
-
* @param nodeId - The node that is doing the waiting.
|
|
541
|
-
* @returns Array of nodes that are being waited on.
|
|
542
|
-
*/
|
|
543
|
-
declare function findWaitingOn(graph: ExecutionGraph, nodeId: string): ExecutionNode[];
|
|
544
|
-
/**
|
|
545
|
-
* Get all descendants of a node (children, grandchildren, etc.) in breadth-first order.
|
|
546
|
-
* The given node itself is NOT included.
|
|
547
|
-
*
|
|
548
|
-
* @param graph - The execution graph to search.
|
|
549
|
-
* @param nodeId - The ancestor node ID.
|
|
550
|
-
* @returns All descendant nodes in BFS order.
|
|
551
|
-
*/
|
|
552
|
-
declare function getSubtree(graph: ExecutionGraph, nodeId: string): ExecutionNode[];
|
|
553
|
-
/**
|
|
554
|
-
* Total wall-clock duration of the graph in milliseconds.
|
|
555
|
-
* If the graph is still running, uses `Date.now()` as the provisional end.
|
|
556
|
-
*
|
|
557
|
-
* @param graph - The execution graph.
|
|
558
|
-
* @returns Duration in milliseconds.
|
|
559
|
-
*/
|
|
560
|
-
declare function getDuration(graph: ExecutionGraph): number;
|
|
561
|
-
/**
|
|
562
|
-
* Maximum nesting depth of the graph. The root node is depth 0.
|
|
563
|
-
*
|
|
564
|
-
* @param graph - The execution graph.
|
|
565
|
-
* @returns The maximum depth (0 for a single-node graph, -1 for empty).
|
|
566
|
-
*/
|
|
567
|
-
declare function getDepth(graph: ExecutionGraph): number;
|
|
568
|
-
/**
|
|
569
|
-
* Compute aggregate statistics for the execution graph.
|
|
570
|
-
*
|
|
571
|
-
* @param graph - The execution graph to analyse.
|
|
572
|
-
* @returns Statistics including node counts by type and status, depth, duration, and failure counts.
|
|
573
|
-
*
|
|
574
|
-
* @example
|
|
575
|
-
* ```ts
|
|
576
|
-
* const stats = getStats(graph);
|
|
577
|
-
* console.log(`${stats.totalNodes} nodes, ${stats.failureCount} failures`);
|
|
578
|
-
* ```
|
|
579
|
-
*/
|
|
580
|
-
declare function getStats(graph: ExecutionGraph): GraphStats;
|
|
581
|
-
|
|
582
|
-
export { type Adapter, type AgentFlowConfig, type AlertCondition, type AlertPayload, type DistributedTrace, type EdgeType, type ExecutionEdge, type ExecutionGraph, type ExecutionNode, type GraphBuilder, type GraphStats, type GraphStatus, type MutableExecutionNode, type NodeStatus, type NodeType, type NotifyChannel, type RunConfig, type RunResult, type StartNodeOptions, type TraceEvent, type TraceEventType, type WatchConfig, type Writer, createGraphBuilder, findWaitingOn, getChildren, getCriticalPath, getDepth, getDuration, getFailures, getHungNodes, getNode, getParent, getStats, getSubtree, getTraceTree, graphToJson, groupByTraceId, loadGraph, runTraced, startLive, startWatch, stitchTrace };
|
|
746
|
+
export { type Adapter, type AgentFlowConfig, type AlertCondition, type AlertPayload, type DistributedTrace, type EdgeType, type ExecutionEdge, type ExecutionGraph, type ExecutionNode, type GraphBuilder, type GraphStats, type GraphStatus, type GuardConfig, type GuardViolation, type MutableExecutionNode, type NodeStatus, type NodeType, type NotifyChannel, type RunConfig, type RunResult, type StartNodeOptions, type TraceEvent, type TraceEventType, type TraceStore, type WatchConfig, type Writer, checkGuards, createGraphBuilder, createTraceStore, findWaitingOn, getChildren, getCriticalPath, getDepth, getDuration, getFailures, getHungNodes, getNode, getParent, getStats, getSubtree, getTraceTree, graphToJson, groupByTraceId, loadGraph, runTraced, startLive, startWatch, stitchTrace, toAsciiTree, toTimeline, withGuards };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createGraphBuilder,
|
|
3
|
+
createTraceStore,
|
|
3
4
|
findWaitingOn,
|
|
4
5
|
getChildren,
|
|
5
6
|
getCriticalPath,
|
|
@@ -12,16 +13,180 @@ import {
|
|
|
12
13
|
getStats,
|
|
13
14
|
getSubtree,
|
|
14
15
|
getTraceTree,
|
|
15
|
-
graphToJson,
|
|
16
16
|
groupByTraceId,
|
|
17
|
-
loadGraph,
|
|
18
17
|
runTraced,
|
|
19
18
|
startLive,
|
|
20
19
|
startWatch,
|
|
21
|
-
stitchTrace
|
|
22
|
-
|
|
20
|
+
stitchTrace,
|
|
21
|
+
toAsciiTree,
|
|
22
|
+
toTimeline
|
|
23
|
+
} from "./chunk-DHCTDCDI.js";
|
|
24
|
+
import {
|
|
25
|
+
graphToJson,
|
|
26
|
+
loadGraph
|
|
27
|
+
} from "./chunk-DY7YHFIB.js";
|
|
28
|
+
|
|
29
|
+
// src/guards.ts
|
|
30
|
+
var DEFAULT_TIMEOUTS = {
|
|
31
|
+
tool: 3e4,
|
|
32
|
+
// 30s
|
|
33
|
+
agent: 3e5,
|
|
34
|
+
// 5m
|
|
35
|
+
subagent: 3e5,
|
|
36
|
+
// 5m
|
|
37
|
+
wait: 6e5,
|
|
38
|
+
// 10m
|
|
39
|
+
decision: 3e4,
|
|
40
|
+
// 30s
|
|
41
|
+
custom: 3e4
|
|
42
|
+
// 30s
|
|
43
|
+
};
|
|
44
|
+
function checkGuards(graph, config) {
|
|
45
|
+
const violations = [];
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
const timeouts = { ...DEFAULT_TIMEOUTS, ...config?.timeouts };
|
|
48
|
+
const maxReasoningSteps = config?.maxReasoningSteps ?? 25;
|
|
49
|
+
const maxDepth = config?.maxDepth ?? 10;
|
|
50
|
+
const maxAgentSpawns = config?.maxAgentSpawns ?? 50;
|
|
51
|
+
for (const node of graph.nodes.values()) {
|
|
52
|
+
if (node.status === "running" && node.endTime === null) {
|
|
53
|
+
const timeoutThreshold = timeouts[node.type];
|
|
54
|
+
const elapsed = now - node.startTime;
|
|
55
|
+
if (elapsed > timeoutThreshold) {
|
|
56
|
+
violations.push({
|
|
57
|
+
type: "timeout",
|
|
58
|
+
nodeId: node.id,
|
|
59
|
+
message: `Node ${node.id} (${node.type}: ${node.name}) has been running for ${elapsed}ms, exceeding timeout of ${timeoutThreshold}ms`,
|
|
60
|
+
timestamp: now
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const depth = getDepth(graph);
|
|
66
|
+
if (depth > maxDepth) {
|
|
67
|
+
violations.push({
|
|
68
|
+
type: "spawn-explosion",
|
|
69
|
+
nodeId: graph.rootNodeId,
|
|
70
|
+
message: `Graph depth ${depth} exceeds maximum depth of ${maxDepth}`,
|
|
71
|
+
timestamp: now
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
let agentCount = 0;
|
|
75
|
+
for (const node of graph.nodes.values()) {
|
|
76
|
+
if (node.type === "agent" || node.type === "subagent") {
|
|
77
|
+
agentCount++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (agentCount > maxAgentSpawns) {
|
|
81
|
+
violations.push({
|
|
82
|
+
type: "spawn-explosion",
|
|
83
|
+
nodeId: graph.rootNodeId,
|
|
84
|
+
message: `Total agent/subagent count ${agentCount} exceeds maximum of ${maxAgentSpawns}`,
|
|
85
|
+
timestamp: now
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
violations.push(...detectReasoningLoops(graph, maxReasoningSteps, now));
|
|
89
|
+
return violations;
|
|
90
|
+
}
|
|
91
|
+
function detectReasoningLoops(graph, maxSteps, timestamp) {
|
|
92
|
+
const violations = [];
|
|
93
|
+
const reported = /* @__PURE__ */ new Set();
|
|
94
|
+
function walk(nodeId, consecutiveCount, consecutiveType) {
|
|
95
|
+
const node = getNode(graph, nodeId);
|
|
96
|
+
if (!node) return;
|
|
97
|
+
let newCount;
|
|
98
|
+
let newType;
|
|
99
|
+
if (node.type === consecutiveType) {
|
|
100
|
+
newCount = consecutiveCount + 1;
|
|
101
|
+
newType = node.type;
|
|
102
|
+
} else {
|
|
103
|
+
newCount = 1;
|
|
104
|
+
newType = node.type;
|
|
105
|
+
}
|
|
106
|
+
if (newCount > maxSteps && !reported.has(newType)) {
|
|
107
|
+
reported.add(newType);
|
|
108
|
+
violations.push({
|
|
109
|
+
type: "reasoning-loop",
|
|
110
|
+
nodeId: node.id,
|
|
111
|
+
message: `Detected ${newCount} consecutive ${newType} nodes along path to ${node.name}`,
|
|
112
|
+
timestamp
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const children = getChildren(graph, nodeId);
|
|
116
|
+
for (const child of children) {
|
|
117
|
+
walk(child.id, newCount, newType);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
walk(graph.rootNodeId, 0, null);
|
|
121
|
+
return violations;
|
|
122
|
+
}
|
|
123
|
+
function withGuards(builder, config) {
|
|
124
|
+
const logger = config?.logger ?? ((msg) => console.warn(`[AgentFlow Guard] ${msg}`));
|
|
125
|
+
const onViolation = config?.onViolation ?? "warn";
|
|
126
|
+
function handleViolations(violations) {
|
|
127
|
+
if (violations.length === 0) return;
|
|
128
|
+
for (const violation of violations) {
|
|
129
|
+
const message = `Guard violation: ${violation.message}`;
|
|
130
|
+
switch (onViolation) {
|
|
131
|
+
case "warn":
|
|
132
|
+
logger(message);
|
|
133
|
+
break;
|
|
134
|
+
case "error":
|
|
135
|
+
logger(message);
|
|
136
|
+
builder.pushEvent({
|
|
137
|
+
eventType: "custom",
|
|
138
|
+
nodeId: violation.nodeId,
|
|
139
|
+
data: {
|
|
140
|
+
guardViolation: violation.type,
|
|
141
|
+
message: violation.message,
|
|
142
|
+
severity: "error"
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
break;
|
|
146
|
+
case "abort":
|
|
147
|
+
throw new Error(`AgentFlow guard violation: ${violation.message}`);
|
|
148
|
+
default:
|
|
149
|
+
logger(message);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
get graphId() {
|
|
155
|
+
return builder.graphId;
|
|
156
|
+
},
|
|
157
|
+
get traceContext() {
|
|
158
|
+
return builder.traceContext;
|
|
159
|
+
},
|
|
160
|
+
startNode: (opts) => builder.startNode(opts),
|
|
161
|
+
endNode: (nodeId, status) => {
|
|
162
|
+
builder.endNode(nodeId, status);
|
|
163
|
+
const snapshot = builder.getSnapshot();
|
|
164
|
+
const violations = checkGuards(snapshot, config);
|
|
165
|
+
handleViolations(violations);
|
|
166
|
+
},
|
|
167
|
+
failNode: (nodeId, error) => {
|
|
168
|
+
builder.failNode(nodeId, error);
|
|
169
|
+
const snapshot = builder.getSnapshot();
|
|
170
|
+
const violations = checkGuards(snapshot, config);
|
|
171
|
+
handleViolations(violations);
|
|
172
|
+
},
|
|
173
|
+
addEdge: (from, to, type) => builder.addEdge(from, to, type),
|
|
174
|
+
pushEvent: (event) => builder.pushEvent(event),
|
|
175
|
+
updateState: (nodeId, state) => builder.updateState(nodeId, state),
|
|
176
|
+
withParent: (parentId, fn) => builder.withParent(parentId, fn),
|
|
177
|
+
getSnapshot: () => builder.getSnapshot(),
|
|
178
|
+
build: () => {
|
|
179
|
+
const snapshot = builder.getSnapshot();
|
|
180
|
+
const violations = checkGuards(snapshot, config);
|
|
181
|
+
handleViolations(violations);
|
|
182
|
+
return builder.build();
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
23
186
|
export {
|
|
187
|
+
checkGuards,
|
|
24
188
|
createGraphBuilder,
|
|
189
|
+
createTraceStore,
|
|
25
190
|
findWaitingOn,
|
|
26
191
|
getChildren,
|
|
27
192
|
getCriticalPath,
|
|
@@ -40,5 +205,8 @@ export {
|
|
|
40
205
|
runTraced,
|
|
41
206
|
startLive,
|
|
42
207
|
startWatch,
|
|
43
|
-
stitchTrace
|
|
208
|
+
stitchTrace,
|
|
209
|
+
toAsciiTree,
|
|
210
|
+
toTimeline,
|
|
211
|
+
withGuards
|
|
44
212
|
};
|
package/package.json
CHANGED