agentflow-dashboard 0.7.0 → 0.7.1

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/README.md CHANGED
@@ -1,9 +1,13 @@
1
- # AgentFlow Dashboard v0.5.0
1
+ # AgentFlow Dashboard v0.7.1
2
2
 
3
3
  Real-time monitoring dashboard for AI agent systems. Visualize execution graphs, session transcripts, and performance metrics from any agent framework.
4
4
 
5
5
  ## Features
6
6
 
7
+ ### Error Surfacing
8
+ - **Crystal-clear error tracking** — Failed node errors (`state.error` and `metadata.error`) are surfaced in all detail views: Flame Chart, Agent Flow, Summary, and Transcript
9
+ - Error messages like `"403 Forbidden — Key limit exceeded"` appear directly in the UI — no more digging through log files
10
+
7
11
  ### Universal Agent Monitoring
8
12
  - **Multi-Format Ingestion** - AgentFlow JSON traces, JSONL session logs (Claude Code compatible), structured log files, cron run logs
9
13
  - **Auto-Discovery** - Recursively scans directories for trace files, watches for new files in real-time
@@ -2061,11 +2061,23 @@ async function startDashboard() {
2061
2061
  case "--cors":
2062
2062
  config.enableCors = true;
2063
2063
  break;
2064
+ case "--no-collector":
2065
+ config.enableCollector = false;
2066
+ break;
2067
+ case "--collector-token":
2068
+ config.collectorAuthToken = args[++i];
2069
+ break;
2064
2070
  case "--help":
2065
2071
  printHelp();
2066
2072
  process.exit(0);
2067
2073
  }
2068
2074
  }
2075
+ if (!config.collectorAuthToken && process.env.AGENTFLOW_COLLECTOR_TOKEN) {
2076
+ config.collectorAuthToken = process.env.AGENTFLOW_COLLECTOR_TOKEN;
2077
+ }
2078
+ if (process.env.AGENTFLOW_NO_COLLECTOR === "true") {
2079
+ config.enableCollector = false;
2080
+ }
2069
2081
  const tracesPath = path2.resolve(config.tracesDir);
2070
2082
  if (!fs2.existsSync(tracesPath)) {
2071
2083
  fs2.mkdirSync(tracesPath, { recursive: true });
@@ -2108,6 +2120,8 @@ Options:
2108
2120
  -h, --host <address> Host address (default: localhost)
2109
2121
  --data-dir <path> Extra data directory for process discovery (repeatable)
2110
2122
  --cors Enable CORS headers
2123
+ --no-collector Disable OTLP trace collector (POST /v1/traces)
2124
+ --collector-token <tok> Require auth token for collector (or set AGENTFLOW_COLLECTOR_TOKEN)
2111
2125
  --help Show this help message
2112
2126
 
2113
2127
  Examples:
@@ -2686,46 +2700,54 @@ var DashboardServer = class {
2686
2700
  res.status(500).json({ error: "Failed to update directory config" });
2687
2701
  }
2688
2702
  });
2689
- this.app.post("/v1/traces", express.json({ limit: "10mb" }), (req, res) => {
2690
- try {
2691
- const traces = parseOtlpPayload(req.body);
2692
- let ingested = 0;
2693
- for (const trace of traces) {
2694
- const nodes = /* @__PURE__ */ new Map();
2695
- for (const [id, node] of Object.entries(trace.nodes)) {
2696
- nodes.set(id, { ...node, state: {} });
2703
+ if (this.config.enableCollector !== false) {
2704
+ this.app.post("/v1/traces", express.json({ limit: "10mb" }), (req, res) => {
2705
+ try {
2706
+ if (this.config.collectorAuthToken) {
2707
+ const auth = req.headers.authorization;
2708
+ if (!auth || auth !== `Bearer ${this.config.collectorAuthToken}`) {
2709
+ return res.status(401).json({ error: "Unauthorized \u2014 provide Authorization: Bearer <token>" });
2710
+ }
2697
2711
  }
2698
- const watched = {
2699
- id: trace.id,
2700
- rootNodeId: Object.keys(trace.nodes)[0] ?? "",
2701
- agentId: trace.agentId,
2702
- name: trace.name,
2703
- trigger: trace.trigger,
2704
- startTime: trace.startTime,
2705
- endTime: trace.endTime,
2706
- status: trace.status,
2707
- nodes,
2708
- edges: [],
2709
- events: [],
2710
- metadata: { ...trace.metadata, adapterSource: "otel" },
2711
- sessionEvents: [],
2712
- sourceType: "session",
2713
- filename: `otel-${trace.id}`,
2714
- lastModified: Date.now(),
2715
- sourceDir: "http-collector"
2716
- };
2717
- this.watcher.traces.set(`otel:${trace.id}`, watched);
2718
- ingested++;
2719
- }
2720
- if (ingested > 0) {
2721
- this.broadcast({ type: "traces-updated", count: ingested });
2712
+ const traces = parseOtlpPayload(req.body);
2713
+ let ingested = 0;
2714
+ for (const trace of traces) {
2715
+ const nodes = /* @__PURE__ */ new Map();
2716
+ for (const [id, node] of Object.entries(trace.nodes)) {
2717
+ nodes.set(id, { ...node, state: {} });
2718
+ }
2719
+ const watched = {
2720
+ id: trace.id,
2721
+ rootNodeId: Object.keys(trace.nodes)[0] ?? "",
2722
+ agentId: trace.agentId,
2723
+ name: trace.name,
2724
+ trigger: trace.trigger,
2725
+ startTime: trace.startTime,
2726
+ endTime: trace.endTime,
2727
+ status: trace.status,
2728
+ nodes,
2729
+ edges: [],
2730
+ events: [],
2731
+ metadata: { ...trace.metadata, adapterSource: "otel" },
2732
+ sessionEvents: [],
2733
+ sourceType: "session",
2734
+ filename: `otel-${trace.id}`,
2735
+ lastModified: Date.now(),
2736
+ sourceDir: "http-collector"
2737
+ };
2738
+ this.watcher.traces.set(`otel:${trace.id}`, watched);
2739
+ ingested++;
2740
+ }
2741
+ if (ingested > 0) {
2742
+ this.broadcast({ type: "traces-updated", count: ingested });
2743
+ }
2744
+ res.json({ ok: true, tracesIngested: ingested });
2745
+ } catch (error) {
2746
+ console.error("OTLP collector error:", error);
2747
+ res.status(400).json({ error: "Failed to parse OTLP payload" });
2722
2748
  }
2723
- res.json({ ok: true, tracesIngested: ingested });
2724
- } catch (error) {
2725
- console.error("OTLP collector error:", error);
2726
- res.status(400).json({ error: "Failed to parse OTLP payload" });
2727
- }
2728
- });
2749
+ });
2750
+ }
2729
2751
  this.app.get("/health", (_req, res) => {
2730
2752
  res.json({
2731
2753
  status: "ok",
package/dist/cli.cjs CHANGED
@@ -2563,46 +2563,54 @@ var DashboardServer = class {
2563
2563
  res.status(500).json({ error: "Failed to update directory config" });
2564
2564
  }
2565
2565
  });
2566
- this.app.post("/v1/traces", import_express.default.json({ limit: "10mb" }), (req, res) => {
2567
- try {
2568
- const traces = parseOtlpPayload(req.body);
2569
- let ingested = 0;
2570
- for (const trace of traces) {
2571
- const nodes = /* @__PURE__ */ new Map();
2572
- for (const [id, node] of Object.entries(trace.nodes)) {
2573
- nodes.set(id, { ...node, state: {} });
2566
+ if (this.config.enableCollector !== false) {
2567
+ this.app.post("/v1/traces", import_express.default.json({ limit: "10mb" }), (req, res) => {
2568
+ try {
2569
+ if (this.config.collectorAuthToken) {
2570
+ const auth = req.headers.authorization;
2571
+ if (!auth || auth !== `Bearer ${this.config.collectorAuthToken}`) {
2572
+ return res.status(401).json({ error: "Unauthorized \u2014 provide Authorization: Bearer <token>" });
2573
+ }
2574
2574
  }
2575
- const watched = {
2576
- id: trace.id,
2577
- rootNodeId: Object.keys(trace.nodes)[0] ?? "",
2578
- agentId: trace.agentId,
2579
- name: trace.name,
2580
- trigger: trace.trigger,
2581
- startTime: trace.startTime,
2582
- endTime: trace.endTime,
2583
- status: trace.status,
2584
- nodes,
2585
- edges: [],
2586
- events: [],
2587
- metadata: { ...trace.metadata, adapterSource: "otel" },
2588
- sessionEvents: [],
2589
- sourceType: "session",
2590
- filename: `otel-${trace.id}`,
2591
- lastModified: Date.now(),
2592
- sourceDir: "http-collector"
2593
- };
2594
- this.watcher.traces.set(`otel:${trace.id}`, watched);
2595
- ingested++;
2596
- }
2597
- if (ingested > 0) {
2598
- this.broadcast({ type: "traces-updated", count: ingested });
2575
+ const traces = parseOtlpPayload(req.body);
2576
+ let ingested = 0;
2577
+ for (const trace of traces) {
2578
+ const nodes = /* @__PURE__ */ new Map();
2579
+ for (const [id, node] of Object.entries(trace.nodes)) {
2580
+ nodes.set(id, { ...node, state: {} });
2581
+ }
2582
+ const watched = {
2583
+ id: trace.id,
2584
+ rootNodeId: Object.keys(trace.nodes)[0] ?? "",
2585
+ agentId: trace.agentId,
2586
+ name: trace.name,
2587
+ trigger: trace.trigger,
2588
+ startTime: trace.startTime,
2589
+ endTime: trace.endTime,
2590
+ status: trace.status,
2591
+ nodes,
2592
+ edges: [],
2593
+ events: [],
2594
+ metadata: { ...trace.metadata, adapterSource: "otel" },
2595
+ sessionEvents: [],
2596
+ sourceType: "session",
2597
+ filename: `otel-${trace.id}`,
2598
+ lastModified: Date.now(),
2599
+ sourceDir: "http-collector"
2600
+ };
2601
+ this.watcher.traces.set(`otel:${trace.id}`, watched);
2602
+ ingested++;
2603
+ }
2604
+ if (ingested > 0) {
2605
+ this.broadcast({ type: "traces-updated", count: ingested });
2606
+ }
2607
+ res.json({ ok: true, tracesIngested: ingested });
2608
+ } catch (error) {
2609
+ console.error("OTLP collector error:", error);
2610
+ res.status(400).json({ error: "Failed to parse OTLP payload" });
2599
2611
  }
2600
- res.json({ ok: true, tracesIngested: ingested });
2601
- } catch (error) {
2602
- console.error("OTLP collector error:", error);
2603
- res.status(400).json({ error: "Failed to parse OTLP payload" });
2604
- }
2605
- });
2612
+ });
2613
+ }
2606
2614
  this.app.get("/health", (_req, res) => {
2607
2615
  res.json({
2608
2616
  status: "ok",
@@ -2981,11 +2989,23 @@ async function startDashboard() {
2981
2989
  case "--cors":
2982
2990
  config.enableCors = true;
2983
2991
  break;
2992
+ case "--no-collector":
2993
+ config.enableCollector = false;
2994
+ break;
2995
+ case "--collector-token":
2996
+ config.collectorAuthToken = args[++i];
2997
+ break;
2984
2998
  case "--help":
2985
2999
  printHelp();
2986
3000
  process.exit(0);
2987
3001
  }
2988
3002
  }
3003
+ if (!config.collectorAuthToken && process.env.AGENTFLOW_COLLECTOR_TOKEN) {
3004
+ config.collectorAuthToken = process.env.AGENTFLOW_COLLECTOR_TOKEN;
3005
+ }
3006
+ if (process.env.AGENTFLOW_NO_COLLECTOR === "true") {
3007
+ config.enableCollector = false;
3008
+ }
2989
3009
  const tracesPath = path3.resolve(config.tracesDir);
2990
3010
  if (!fs3.existsSync(tracesPath)) {
2991
3011
  fs3.mkdirSync(tracesPath, { recursive: true });
@@ -3028,6 +3048,8 @@ Options:
3028
3048
  -h, --host <address> Host address (default: localhost)
3029
3049
  --data-dir <path> Extra data directory for process discovery (repeatable)
3030
3050
  --cors Enable CORS headers
3051
+ --no-collector Disable OTLP trace collector (POST /v1/traces)
3052
+ --collector-token <tok> Require auth token for collector (or set AGENTFLOW_COLLECTOR_TOKEN)
3031
3053
  --help Show this help message
3032
3054
 
3033
3055
  Examples:
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startDashboard
3
- } from "./chunk-GA2Y6E62.js";
3
+ } from "./chunk-3S4AAIPA.js";
4
4
  export {
5
5
  startDashboard
6
6
  };