@railtownai/railtracks-visualizer 0.0.69 → 0.0.70

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/cjs/index.js CHANGED
@@ -12939,7 +12939,7 @@ const createLucideIcon = (iconName, iconNode)=>{
12939
12939
  return Component;
12940
12940
  };
12941
12941
 
12942
- const __iconNode$A = [
12942
+ const __iconNode$C = [
12943
12943
  [
12944
12944
  "path",
12945
12945
  {
@@ -12955,9 +12955,9 @@ const __iconNode$A = [
12955
12955
  }
12956
12956
  ]
12957
12957
  ];
12958
- const ArrowLeft = createLucideIcon("arrow-left", __iconNode$A);
12958
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$C);
12959
12959
 
12960
- const __iconNode$z = [
12960
+ const __iconNode$B = [
12961
12961
  [
12962
12962
  "path",
12963
12963
  {
@@ -12973,9 +12973,9 @@ const __iconNode$z = [
12973
12973
  }
12974
12974
  ]
12975
12975
  ];
12976
- const ArrowRight = createLucideIcon("arrow-right", __iconNode$z);
12976
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$B);
12977
12977
 
12978
- const __iconNode$y = [
12978
+ const __iconNode$A = [
12979
12979
  [
12980
12980
  "path",
12981
12981
  {
@@ -13023,9 +13023,9 @@ const __iconNode$y = [
13023
13023
  }
13024
13024
  ]
13025
13025
  ];
13026
- const Bot = createLucideIcon("bot", __iconNode$y);
13026
+ const Bot = createLucideIcon("bot", __iconNode$A);
13027
13027
 
13028
- const __iconNode$x = [
13028
+ const __iconNode$z = [
13029
13029
  [
13030
13030
  "path",
13031
13031
  {
@@ -13059,9 +13059,9 @@ const __iconNode$x = [
13059
13059
  }
13060
13060
  ]
13061
13061
  ];
13062
- const Calendar = createLucideIcon("calendar", __iconNode$x);
13062
+ const Calendar = createLucideIcon("calendar", __iconNode$z);
13063
13063
 
13064
- const __iconNode$w = [
13064
+ const __iconNode$y = [
13065
13065
  [
13066
13066
  "path",
13067
13067
  {
@@ -13118,9 +13118,9 @@ const __iconNode$w = [
13118
13118
  }
13119
13119
  ]
13120
13120
  ];
13121
- const ChartNetwork = createLucideIcon("chart-network", __iconNode$w);
13121
+ const ChartNetwork = createLucideIcon("chart-network", __iconNode$y);
13122
13122
 
13123
- const __iconNode$v = [
13123
+ const __iconNode$x = [
13124
13124
  [
13125
13125
  "path",
13126
13126
  {
@@ -13129,9 +13129,9 @@ const __iconNode$v = [
13129
13129
  }
13130
13130
  ]
13131
13131
  ];
13132
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$v);
13132
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$x);
13133
13133
 
13134
- const __iconNode$u = [
13134
+ const __iconNode$w = [
13135
13135
  [
13136
13136
  "path",
13137
13137
  {
@@ -13140,9 +13140,9 @@ const __iconNode$u = [
13140
13140
  }
13141
13141
  ]
13142
13142
  ];
13143
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$u);
13143
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$w);
13144
13144
 
13145
- const __iconNode$t = [
13145
+ const __iconNode$v = [
13146
13146
  [
13147
13147
  "path",
13148
13148
  {
@@ -13158,9 +13158,9 @@ const __iconNode$t = [
13158
13158
  }
13159
13159
  ]
13160
13160
  ];
13161
- const ChevronsDown = createLucideIcon("chevrons-down", __iconNode$t);
13161
+ const ChevronsDown = createLucideIcon("chevrons-down", __iconNode$v);
13162
13162
 
13163
- const __iconNode$s = [
13163
+ const __iconNode$u = [
13164
13164
  [
13165
13165
  "path",
13166
13166
  {
@@ -13176,9 +13176,9 @@ const __iconNode$s = [
13176
13176
  }
13177
13177
  ]
13178
13178
  ];
13179
- const ChevronsUp = createLucideIcon("chevrons-up", __iconNode$s);
13179
+ const ChevronsUp = createLucideIcon("chevrons-up", __iconNode$u);
13180
13180
 
13181
- const __iconNode$r = [
13181
+ const __iconNode$t = [
13182
13182
  [
13183
13183
  "circle",
13184
13184
  {
@@ -13209,9 +13209,9 @@ const __iconNode$r = [
13209
13209
  }
13210
13210
  ]
13211
13211
  ];
13212
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$r);
13212
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$t);
13213
13213
 
13214
- const __iconNode$q = [
13214
+ const __iconNode$s = [
13215
13215
  [
13216
13216
  "path",
13217
13217
  {
@@ -13227,9 +13227,9 @@ const __iconNode$q = [
13227
13227
  }
13228
13228
  ]
13229
13229
  ];
13230
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$q);
13230
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$s);
13231
13231
 
13232
- const __iconNode$p = [
13232
+ const __iconNode$r = [
13233
13233
  [
13234
13234
  "circle",
13235
13235
  {
@@ -13254,9 +13254,9 @@ const __iconNode$p = [
13254
13254
  }
13255
13255
  ]
13256
13256
  ];
13257
- const CircleDollarSign = createLucideIcon("circle-dollar-sign", __iconNode$p);
13257
+ const CircleDollarSign = createLucideIcon("circle-dollar-sign", __iconNode$r);
13258
13258
 
13259
- const __iconNode$o = [
13259
+ const __iconNode$q = [
13260
13260
  [
13261
13261
  "circle",
13262
13262
  {
@@ -13274,9 +13274,9 @@ const __iconNode$o = [
13274
13274
  }
13275
13275
  ]
13276
13276
  ];
13277
- const Clock = createLucideIcon("clock", __iconNode$o);
13277
+ const Clock = createLucideIcon("clock", __iconNode$q);
13278
13278
 
13279
- const __iconNode$n = [
13279
+ const __iconNode$p = [
13280
13280
  [
13281
13281
  "rect",
13282
13282
  {
@@ -13297,9 +13297,9 @@ const __iconNode$n = [
13297
13297
  }
13298
13298
  ]
13299
13299
  ];
13300
- const Copy = createLucideIcon("copy", __iconNode$n);
13300
+ const Copy = createLucideIcon("copy", __iconNode$p);
13301
13301
 
13302
- const __iconNode$m = [
13302
+ const __iconNode$o = [
13303
13303
  [
13304
13304
  "path",
13305
13305
  {
@@ -13407,9 +13407,9 @@ const __iconNode$m = [
13407
13407
  }
13408
13408
  ]
13409
13409
  ];
13410
- const Cpu = createLucideIcon("cpu", __iconNode$m);
13410
+ const Cpu = createLucideIcon("cpu", __iconNode$o);
13411
13411
 
13412
- const __iconNode$l = [
13412
+ const __iconNode$n = [
13413
13413
  [
13414
13414
  "line",
13415
13415
  {
@@ -13428,9 +13428,9 @@ const __iconNode$l = [
13428
13428
  }
13429
13429
  ]
13430
13430
  ];
13431
- const DollarSign = createLucideIcon("dollar-sign", __iconNode$l);
13431
+ const DollarSign = createLucideIcon("dollar-sign", __iconNode$n);
13432
13432
 
13433
- const __iconNode$k = [
13433
+ const __iconNode$m = [
13434
13434
  [
13435
13435
  "path",
13436
13436
  {
@@ -13460,9 +13460,9 @@ const __iconNode$k = [
13460
13460
  }
13461
13461
  ]
13462
13462
  ];
13463
- const FileInput = createLucideIcon("file-input", __iconNode$k);
13463
+ const FileInput = createLucideIcon("file-input", __iconNode$m);
13464
13464
 
13465
- const __iconNode$j = [
13465
+ const __iconNode$l = [
13466
13466
  [
13467
13467
  "path",
13468
13468
  {
@@ -13492,9 +13492,9 @@ const __iconNode$j = [
13492
13492
  }
13493
13493
  ]
13494
13494
  ];
13495
- const FileOutput = createLucideIcon("file-output", __iconNode$j);
13495
+ const FileOutput = createLucideIcon("file-output", __iconNode$l);
13496
13496
 
13497
- const __iconNode$i = [
13497
+ const __iconNode$k = [
13498
13498
  [
13499
13499
  "path",
13500
13500
  {
@@ -13552,9 +13552,27 @@ const __iconNode$i = [
13552
13552
  }
13553
13553
  ]
13554
13554
  ];
13555
- const FoldVertical = createLucideIcon("fold-vertical", __iconNode$i);
13555
+ const FoldVertical = createLucideIcon("fold-vertical", __iconNode$k);
13556
13556
 
13557
- const __iconNode$h = [
13557
+ const __iconNode$j = [
13558
+ [
13559
+ "path",
13560
+ {
13561
+ d: "m12 14 4-4",
13562
+ key: "9kzdfg"
13563
+ }
13564
+ ],
13565
+ [
13566
+ "path",
13567
+ {
13568
+ d: "M3.34 19a10 10 0 1 1 17.32 0",
13569
+ key: "19p75a"
13570
+ }
13571
+ ]
13572
+ ];
13573
+ const Gauge = createLucideIcon("gauge", __iconNode$j);
13574
+
13575
+ const __iconNode$i = [
13558
13576
  [
13559
13577
  "line",
13560
13578
  {
@@ -13596,9 +13614,9 @@ const __iconNode$h = [
13596
13614
  }
13597
13615
  ]
13598
13616
  ];
13599
- const Hash = createLucideIcon("hash", __iconNode$h);
13617
+ const Hash = createLucideIcon("hash", __iconNode$i);
13600
13618
 
13601
- const __iconNode$g = [
13619
+ const __iconNode$h = [
13602
13620
  [
13603
13621
  "circle",
13604
13622
  {
@@ -13623,9 +13641,9 @@ const __iconNode$g = [
13623
13641
  }
13624
13642
  ]
13625
13643
  ];
13626
- const Info = createLucideIcon("info", __iconNode$g);
13644
+ const Info = createLucideIcon("info", __iconNode$h);
13627
13645
 
13628
- const __iconNode$f = [
13646
+ const __iconNode$g = [
13629
13647
  [
13630
13648
  "path",
13631
13649
  {
@@ -13662,9 +13680,9 @@ const __iconNode$f = [
13662
13680
  }
13663
13681
  ]
13664
13682
  ];
13665
- const ListChecks = createLucideIcon("list-checks", __iconNode$f);
13683
+ const ListChecks = createLucideIcon("list-checks", __iconNode$g);
13666
13684
 
13667
- const __iconNode$e = [
13685
+ const __iconNode$f = [
13668
13686
  [
13669
13687
  "path",
13670
13688
  {
@@ -13694,9 +13712,9 @@ const __iconNode$e = [
13694
13712
  }
13695
13713
  ]
13696
13714
  ];
13697
- const MessageSquareText = createLucideIcon("message-square-text", __iconNode$e);
13715
+ const MessageSquareText = createLucideIcon("message-square-text", __iconNode$f);
13698
13716
 
13699
- const __iconNode$d = [
13717
+ const __iconNode$e = [
13700
13718
  [
13701
13719
  "path",
13702
13720
  {
@@ -13712,9 +13730,9 @@ const __iconNode$d = [
13712
13730
  }
13713
13731
  ]
13714
13732
  ];
13715
- const MessagesSquare = createLucideIcon("messages-square", __iconNode$d);
13733
+ const MessagesSquare = createLucideIcon("messages-square", __iconNode$e);
13716
13734
 
13717
- const __iconNode$c = [
13735
+ const __iconNode$d = [
13718
13736
  [
13719
13737
  "rect",
13720
13738
  {
@@ -13734,9 +13752,9 @@ const __iconNode$c = [
13734
13752
  }
13735
13753
  ]
13736
13754
  ];
13737
- const PanelLeft = createLucideIcon("panel-left", __iconNode$c);
13755
+ const PanelLeft = createLucideIcon("panel-left", __iconNode$d);
13738
13756
 
13739
- const __iconNode$b = [
13757
+ const __iconNode$c = [
13740
13758
  [
13741
13759
  "rect",
13742
13760
  {
@@ -13763,9 +13781,9 @@ const __iconNode$b = [
13763
13781
  }
13764
13782
  ]
13765
13783
  ];
13766
- const PanelRightOpen = createLucideIcon("panel-right-open", __iconNode$b);
13784
+ const PanelRightOpen = createLucideIcon("panel-right-open", __iconNode$c);
13767
13785
 
13768
- const __iconNode$a = [
13786
+ const __iconNode$b = [
13769
13787
  [
13770
13788
  "path",
13771
13789
  {
@@ -13795,9 +13813,9 @@ const __iconNode$a = [
13795
13813
  }
13796
13814
  ]
13797
13815
  ];
13798
- const RefreshCw = createLucideIcon("refresh-cw", __iconNode$a);
13816
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$b);
13799
13817
 
13800
- const __iconNode$9 = [
13818
+ const __iconNode$a = [
13801
13819
  [
13802
13820
  "path",
13803
13821
  {
@@ -13834,9 +13852,9 @@ const __iconNode$9 = [
13834
13852
  }
13835
13853
  ]
13836
13854
  ];
13837
- const Scale = createLucideIcon("scale", __iconNode$9);
13855
+ const Scale = createLucideIcon("scale", __iconNode$a);
13838
13856
 
13839
- const __iconNode$8 = [
13857
+ const __iconNode$9 = [
13840
13858
  [
13841
13859
  "path",
13842
13860
  {
@@ -13870,9 +13888,9 @@ const __iconNode$8 = [
13870
13888
  }
13871
13889
  ]
13872
13890
  ];
13873
- const Settings2 = createLucideIcon("settings-2", __iconNode$8);
13891
+ const Settings2 = createLucideIcon("settings-2", __iconNode$9);
13874
13892
 
13875
- const __iconNode$7 = [
13893
+ const __iconNode$8 = [
13876
13894
  [
13877
13895
  "path",
13878
13896
  {
@@ -13895,9 +13913,9 @@ const __iconNode$7 = [
13895
13913
  }
13896
13914
  ]
13897
13915
  ];
13898
- const Share = createLucideIcon("share", __iconNode$7);
13916
+ const Share = createLucideIcon("share", __iconNode$8);
13899
13917
 
13900
- const __iconNode$6 = [
13918
+ const __iconNode$7 = [
13901
13919
  [
13902
13920
  "path",
13903
13921
  {
@@ -13906,7 +13924,35 @@ const __iconNode$6 = [
13906
13924
  }
13907
13925
  ]
13908
13926
  ];
13909
- const Shield = createLucideIcon("shield", __iconNode$6);
13927
+ const Shield = createLucideIcon("shield", __iconNode$7);
13928
+
13929
+ const __iconNode$6 = [
13930
+ [
13931
+ "path",
13932
+ {
13933
+ d: "M13.172 2a2 2 0 0 1 1.414.586l6.71 6.71a2.4 2.4 0 0 1 0 3.408l-4.592 4.592a2.4 2.4 0 0 1-3.408 0l-6.71-6.71A2 2 0 0 1 6 9.172V3a1 1 0 0 1 1-1z",
13934
+ key: "16rjxf"
13935
+ }
13936
+ ],
13937
+ [
13938
+ "path",
13939
+ {
13940
+ d: "M2 7v6.172a2 2 0 0 0 .586 1.414l6.71 6.71a2.4 2.4 0 0 0 3.191.193",
13941
+ key: "178nd4"
13942
+ }
13943
+ ],
13944
+ [
13945
+ "circle",
13946
+ {
13947
+ cx: "10.5",
13948
+ cy: "6.5",
13949
+ r: ".5",
13950
+ fill: "currentColor",
13951
+ key: "12ikhr"
13952
+ }
13953
+ ]
13954
+ ];
13955
+ const Tags = createLucideIcon("tags", __iconNode$6);
13910
13956
 
13911
13957
  const __iconNode$5 = [
13912
13958
  [
@@ -112625,7 +112671,32 @@ const GuardrailsPopover = ({ guardrails, title = "Guardrails", placement = "righ
112625
112671
  })));
112626
112672
  };
112627
112673
 
112628
- const getNodeLatency = (node)=>node.details?.internals?.latency?.total_time ?? 0;
112674
+ /** Collect start/end instants (unix seconds) for wall-clock span of a single node. */ const getNodeStampTimes = (node)=>{
112675
+ const start = node.stamp?.time;
112676
+ if (start == null) return [];
112677
+ const times = [
112678
+ start
112679
+ ];
112680
+ const latency = node.details?.internals?.latency?.total_time;
112681
+ if (latency != null && latency > 0) times.push(start + latency);
112682
+ return times;
112683
+ };
112684
+ const wallClockSpanSeconds = (times)=>{
112685
+ if (times.length === 0) return 0;
112686
+ const min = Math.min(...times);
112687
+ const max = Math.max(...times);
112688
+ return Math.max(0, max - min);
112689
+ };
112690
+ const collectSubtreeStampTimes = (nodeId, childrenMap, nodeMap)=>{
112691
+ const node = nodeMap.get(nodeId);
112692
+ if (!node) return [];
112693
+ const times = getNodeStampTimes(node);
112694
+ for (const childId of childrenMap.get(nodeId) ?? []){
112695
+ times.push(...collectSubtreeStampTimes(childId, childrenMap, nodeMap));
112696
+ }
112697
+ return times;
112698
+ };
112699
+ /** Wall-clock elapsed time across a node and all descendants (unix stamp times). */ const getSubtreeWallClockSeconds = (nodeId, childrenMap, nodeMap)=>wallClockSpanSeconds(collectSubtreeStampTimes(nodeId, childrenMap, nodeMap));
112629
112700
  const SessionTreeNodeTitle = ({ displayName, subtreeLatency, guardrails })=>{
112630
112701
  return /*#__PURE__*/ React.createElement("span", {
112631
112702
  style: {
@@ -112753,8 +112824,7 @@ const buildNodeTree = (run)=>{
112753
112824
  const nodeKey = `node::${run.run_id}::${node.identifier}`;
112754
112825
  const childIds = childrenMap.get(node.identifier) || [];
112755
112826
  const children = childIds.map((id)=>nodeMap.get(id)).filter((n)=>n != null).sort((a, b)=>(a.stamp?.step ?? 0) - (b.stamp?.step ?? 0)).map(buildTreeNode);
112756
- const childLatency = children.reduce((s, c)=>s + (c.subtreeLatency ?? 0), 0);
112757
- const subtreeLatency = getNodeLatency(node) + childLatency;
112827
+ const subtreeLatency = getSubtreeWallClockSeconds(node.identifier, childrenMap, nodeMap);
112758
112828
  const guardrails = node.details?.internals?.guard_details ?? [];
112759
112829
  const isTool = node.node_type === "Tool";
112760
112830
  const failed = isNodeFailureFromIncomingEdge(run, node.identifier);
@@ -113376,7 +113446,7 @@ const SessionDetails = ({ session, open, onClose, initialNodeId, initialRunId, l
113376
113446
 
113377
113447
  /**
113378
113448
  * DTOs for evaluation data from .railtracks/data/evaluations/*.json
113379
- */ /** Numeric metric definition (LLMMetric or ToolMetric) */ /** Type guard for LLM result */ function isLLMResult(item) {
113449
+ */ /** Numeric metric definition (LLMMetric, ToolMetric, or Numerical for custom evaluators) */ /** Type guard for LLM result */ function isLLMResult(item) {
113380
113450
  return item.type === "LLM";
113381
113451
  }
113382
113452
  /** Type guard for Tool result */ function isToolResult(item) {
@@ -113394,8 +113464,12 @@ const SessionDetails = ({ session, open, onClose, initialNodeId, initialRunId, l
113394
113464
  /** Type guard for CategoricalAggregate */ function isAggregateCategorical(item) {
113395
113465
  return item.type === "CategoricalAggregate";
113396
113466
  }
113397
- /** Type guard for aggregated stats (numeric - LLMInferenceAggregate or ToolAggregate) */ function isAggregatedStats(item) {
113398
- return item.type === "LLMInferenceAggregate" || item.type === "ToolAggregate";
113467
+ /** Type guard for NumericalAggregate (custom evaluator numeric aggregate) */ function isNumericalAggregate(item) {
113468
+ return item.type === "NumericalAggregate";
113469
+ }
113470
+ /** Type guard for aggregated stats (numeric - LLMInferenceAggregate, ToolAggregate, or NumericalAggregate) */ function isAggregatedStats(item) {
113471
+ const type = item.type;
113472
+ return type === "LLMInferenceAggregate" || type === "ToolAggregate" || type === "NumericalAggregate";
113399
113473
  }
113400
113474
 
113401
113475
  function isCategoricalMetric$1(def) {
@@ -113411,7 +113485,8 @@ function isCategoricalMetric$1(def) {
113411
113485
  const aggregateTypes = [
113412
113486
  "ToolAggregate",
113413
113487
  "LLMInferenceAggregate",
113414
- "CategoricalAggregate"
113488
+ "CategoricalAggregate",
113489
+ "NumericalAggregate"
113415
113490
  ];
113416
113491
  const aggregateItems = Object.values(nodes).filter((n)=>n?.type && aggregateTypes.includes(n.type));
113417
113492
  return [
@@ -117077,7 +117152,7 @@ function buildTreeFromProcessedData(latencyByTool, failureRateByTool, usageCount
117077
117152
 
117078
117153
  const JUDGE_RESULT_PREFIX = "JudgeResult/";
117079
117154
  const JUDGE_REASONING_PREFIX = "JudgeReasoning/";
117080
- /** Map agent node id -> session id from the agents array (new format only). */ function buildSessionByNodeId(agents) {
117155
+ /** Map agent node id -> session id from the agents array (new format only). */ function buildSessionByNodeId$1(agents) {
117081
117156
  const map = new Map();
117082
117157
  for (const agent of agents ?? []){
117083
117158
  for (const entry of agent.agent_node_ids ?? []){
@@ -117101,10 +117176,10 @@ const JUDGE_REASONING_PREFIX = "JudgeReasoning/";
117101
117176
  }
117102
117177
  return map;
117103
117178
  }
117104
- function metricNameOf(agg) {
117179
+ function metricNameOf$1(agg) {
117105
117180
  return agg.metric?.name ?? agg.name?.replace(/^Aggregate\//, "") ?? "Unknown";
117106
117181
  }
117107
- /** Collect the JudgeResult leaf nodes (label + node id) grouped by label. */ function groupNodesByLabel(agg, nodes, rawResults, metricName, sessionByNodeId, reasoningByKey) {
117182
+ /** Collect the leaf nodes (label + node id) grouped by label. */ function groupNodesByLabel(agg, nodes, rawResults, metricName, sessionByNodeId, reasoningByKey) {
117108
117183
  const byLabel = new Map();
117109
117184
  const seen = new Set();
117110
117185
  const push = (label, nodeId)=>{
@@ -117142,15 +117217,15 @@ function metricNameOf(agg) {
117142
117217
  }
117143
117218
  return byLabel;
117144
117219
  }
117145
- /** Build the Judge view model: one entry per categorical metric. */ function buildJudgeMetricsFromAggregate(input) {
117220
+ /** Build the categorical view model: one entry per categorical metric. */ function buildCategoricalMetricsFromAggregate(input) {
117146
117221
  const { roots, nodes, agents, rawResults = [] } = input;
117147
- const sessionByNodeId = buildSessionByNodeId(agents);
117222
+ const sessionByNodeId = buildSessionByNodeId$1(agents);
117148
117223
  const reasoningByKey = buildReasoningByKey(rawResults);
117149
117224
  // Prefer roots; fall back to scanning all nodes for categorical aggregates.
117150
117225
  const rootAggregates = roots.map((id)=>nodes[id]).filter((n)=>isAggregateCategorical(n));
117151
117226
  const aggregates = rootAggregates.length > 0 ? rootAggregates : Object.values(nodes).filter((n)=>isAggregateCategorical(n));
117152
117227
  return aggregates.map((agg, index)=>{
117153
- const metricName = metricNameOf(agg);
117228
+ const metricName = metricNameOf$1(agg);
117154
117229
  const counts = agg.counts ?? {};
117155
117230
  const categories = agg.categories ?? agg.metric?.categories ?? Object.keys(counts);
117156
117231
  const byLabel = groupNodesByLabel(agg, nodes, rawResults, metricName, sessionByNodeId, reasoningByKey);
@@ -117182,6 +117257,75 @@ function metricNameOf(agg) {
117182
117257
  });
117183
117258
  }
117184
117259
 
117260
+ /** Map agent node id -> session id from the agents array (new format only). */ function buildSessionByNodeId(agents) {
117261
+ const map = new Map();
117262
+ for (const agent of agents ?? []){
117263
+ for (const entry of agent.agent_node_ids ?? []){
117264
+ if (entry && typeof entry === "object" && "agent_node_id" in entry) {
117265
+ map.set(entry.agent_node_id, entry.session_id);
117266
+ }
117267
+ }
117268
+ }
117269
+ return map;
117270
+ }
117271
+ function metricNameOf(agg) {
117272
+ return agg.metric?.name ?? agg.name?.replace(/^Aggregate\//, "") ?? "Unknown";
117273
+ }
117274
+ /** Collect the per-run leaf values (value + node id) for a numerical aggregate. */ function collectNodes(agg, nodes, rawResults, metricName, sessionByNodeId) {
117275
+ const refs = [];
117276
+ const seen = new Set();
117277
+ const push = (nodeId, value)=>{
117278
+ if (!Number.isFinite(value) || seen.has(nodeId)) return;
117279
+ seen.add(nodeId);
117280
+ refs.push({
117281
+ nodeId,
117282
+ sessionId: sessionByNodeId.get(nodeId),
117283
+ value
117284
+ });
117285
+ };
117286
+ // Preferred: walk the aggregate's children leaf nodes.
117287
+ for (const childId of agg.children ?? []){
117288
+ const child = nodes[childId];
117289
+ if (child && isBaseResult(child)) {
117290
+ const nodeId = child.agent_data_id?.[0];
117291
+ if (nodeId) push(nodeId, Number(child.value));
117292
+ }
117293
+ }
117294
+ // Fallback: derive from raw Base results named after the metric when no children resolve.
117295
+ if (refs.length === 0) {
117296
+ for (const item of rawResults){
117297
+ if (isBaseResult(item) && item.result_name === metricName) {
117298
+ const nodeId = item.agent_data_id?.[0];
117299
+ if (nodeId) push(nodeId, Number(item.value));
117300
+ }
117301
+ }
117302
+ }
117303
+ return refs;
117304
+ }
117305
+ /** Build the custom (numerical) evaluator view model: one entry per numerical metric. */ function buildNumericalMetricsFromAggregate(input) {
117306
+ const { roots, nodes, agents, rawResults = [] } = input;
117307
+ const sessionByNodeId = buildSessionByNodeId(agents);
117308
+ // Prefer roots; fall back to scanning all nodes for numerical aggregates.
117309
+ const rootAggregates = roots.map((id)=>nodes[id]).filter((n)=>isNumericalAggregate(n));
117310
+ const aggregates = rootAggregates.length > 0 ? rootAggregates : Object.values(nodes).filter((n)=>isNumericalAggregate(n));
117311
+ return aggregates.map((agg, index)=>{
117312
+ const metricName = metricNameOf(agg);
117313
+ const nodeRefs = collectNodes(agg, nodes, rawResults, metricName, sessionByNodeId);
117314
+ return {
117315
+ key: agg.identifier ?? `${metricName}-${index}`,
117316
+ metricName,
117317
+ description: agg.metric?.description ?? undefined,
117318
+ mean: agg.mean,
117319
+ minimum: agg.minimum,
117320
+ maximum: agg.maximum,
117321
+ median: agg.median,
117322
+ std: agg.std,
117323
+ count: agg.values?.length ?? nodeRefs.length,
117324
+ nodes: nodeRefs
117325
+ };
117326
+ });
117327
+ }
117328
+
117185
117329
  const NodeActions = ({ sessionId, nodeId, onAgentNodeClick, onOpenVisualizer })=>{
117186
117330
  const { theme } = useTheme$1();
117187
117331
  const baseStyle = {
@@ -117243,7 +117387,7 @@ const NodeActions = ({ sessionId, nodeId, onAgentNodeClick, onOpenVisualizer })=
117243
117387
  }), "Visualizer")));
117244
117388
  };
117245
117389
 
117246
- const NodeRow = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
117390
+ const NodeRow$1 = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
117247
117391
  const { theme } = useTheme$1();
117248
117392
  const [showReasoning, setShowReasoning] = React.useState(false);
117249
117393
  return /*#__PURE__*/ React.createElement("div", {
@@ -117313,7 +117457,7 @@ const NodeRow = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
117313
117457
  marginBottom: 6,
117314
117458
  color: theme.colors.mutedForeground
117315
117459
  }
117316
- }, "Judge reasoning · ", metricName), node.reasoning));
117460
+ }, "Reasoning · ", metricName), node.reasoning));
117317
117461
  };
117318
117462
  const LabelPanelHeader = ({ label })=>{
117319
117463
  const { theme } = useTheme$1();
@@ -117346,7 +117490,7 @@ const LabelPanelHeader = ({ label })=>{
117346
117490
  }
117347
117491
  }, label.count, " ", label.count === 1 ? "node" : "nodes"));
117348
117492
  };
117349
- const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117493
+ const MetricCard$1 = ({ metric, icon: Icon, onAgentNodeClick, onOpenVisualizer })=>{
117350
117494
  const { theme } = useTheme$1();
117351
117495
  const items = metric.labels.map((label)=>({
117352
117496
  key: label.labelName,
@@ -117366,7 +117510,7 @@ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117366
117510
  flexDirection: "column",
117367
117511
  gap: 12
117368
117512
  }
117369
- }, label.nodes.map((node)=>/*#__PURE__*/ React.createElement(NodeRow, {
117513
+ }, label.nodes.map((node)=>/*#__PURE__*/ React.createElement(NodeRow$1, {
117370
117514
  key: node.nodeId,
117371
117515
  node: node,
117372
117516
  metricName: metric.metricName,
@@ -117394,7 +117538,7 @@ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117394
117538
  gap: 12,
117395
117539
  flexWrap: "wrap"
117396
117540
  }
117397
- }, /*#__PURE__*/ React.createElement(Scale, {
117541
+ }, /*#__PURE__*/ React.createElement(Icon, {
117398
117542
  size: 16,
117399
117543
  style: {
117400
117544
  color: theme.colors.primary,
@@ -117435,13 +117579,13 @@ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117435
117579
  marginLeft: "auto",
117436
117580
  flexShrink: 0
117437
117581
  }
117438
- }, /*#__PURE__*/ React.createElement(Meta, {
117582
+ }, /*#__PURE__*/ React.createElement(Meta$1, {
117439
117583
  label: "Most common",
117440
117584
  value: metric.mostCommon
117441
- }), /*#__PURE__*/ React.createElement(Meta, {
117585
+ }), /*#__PURE__*/ React.createElement(Meta$1, {
117442
117586
  label: "Least common",
117443
117587
  value: metric.leastCommon
117444
- }), /*#__PURE__*/ React.createElement(Meta, {
117588
+ }), /*#__PURE__*/ React.createElement(Meta$1, {
117445
117589
  label: "Evaluations",
117446
117590
  value: String(metric.total)
117447
117591
  }))), metric.description && /*#__PURE__*/ React.createElement("div", {
@@ -117458,6 +117602,76 @@ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117458
117602
  }
117459
117603
  }));
117460
117604
  };
117605
+ const Meta$1 = ({ label, value })=>{
117606
+ const { theme } = useTheme$1();
117607
+ return /*#__PURE__*/ React.createElement("span", {
117608
+ style: {
117609
+ display: "flex",
117610
+ flexDirection: "column",
117611
+ alignItems: "flex-end",
117612
+ gap: 1
117613
+ }
117614
+ }, /*#__PURE__*/ React.createElement("span", {
117615
+ style: {
117616
+ fontSize: 10,
117617
+ textTransform: "uppercase",
117618
+ letterSpacing: 0.4,
117619
+ color: theme.colors.mutedForeground
117620
+ }
117621
+ }, label), /*#__PURE__*/ React.createElement("span", {
117622
+ style: {
117623
+ fontSize: 13,
117624
+ fontWeight: 500
117625
+ }
117626
+ }, value ?? "—"));
117627
+ };
117628
+ const CategoricalAggregateView = ({ metrics, title = "Categorical Evaluator - Aggregate View", icon = Tags, emptyLabel = "No categorical metrics available", onAgentNodeClick, onOpenVisualizer })=>{
117629
+ const { theme } = useTheme$1();
117630
+ if (!metrics.length) {
117631
+ return /*#__PURE__*/ React.createElement("div", {
117632
+ style: {
117633
+ padding: 24,
117634
+ textAlign: "center",
117635
+ color: theme.colors.mutedForeground,
117636
+ fontSize: 14
117637
+ }
117638
+ }, emptyLabel);
117639
+ }
117640
+ return /*#__PURE__*/ React.createElement("div", {
117641
+ style: {
117642
+ width: "100%",
117643
+ minWidth: 0
117644
+ }
117645
+ }, /*#__PURE__*/ React.createElement("h3", {
117646
+ style: {
117647
+ margin: "0 0 16px",
117648
+ fontSize: 16,
117649
+ fontWeight: 600
117650
+ }
117651
+ }, title), /*#__PURE__*/ React.createElement("div", {
117652
+ style: {
117653
+ display: "flex",
117654
+ flexDirection: "column",
117655
+ gap: 12
117656
+ }
117657
+ }, metrics.map((metric)=>/*#__PURE__*/ React.createElement(MetricCard$1, {
117658
+ key: metric.key,
117659
+ metric: metric,
117660
+ icon: icon,
117661
+ onAgentNodeClick: onAgentNodeClick,
117662
+ onOpenVisualizer: onOpenVisualizer
117663
+ }))));
117664
+ };
117665
+
117666
+ /**
117667
+ * Format a numerical value for display. Custom metric names are arbitrary, so we
117668
+ * use a light heuristic: latency-like metrics render as durations, integers get
117669
+ * thousands separators, everything else gets two decimals.
117670
+ */ function formatStat(value, metricName) {
117671
+ if (value === undefined || !Number.isFinite(value)) return "—";
117672
+ if (/seconds$/i.test(metricName) || /latency/i.test(metricName)) return formatLatency(value);
117673
+ return Number.isInteger(value) ? formatNumberWithCommas(value) : value.toFixed(2);
117674
+ }
117461
117675
  const Meta = ({ label, value })=>{
117462
117676
  const { theme } = useTheme$1();
117463
117677
  return /*#__PURE__*/ React.createElement("span", {
@@ -117481,7 +117695,149 @@ const Meta = ({ label, value })=>{
117481
117695
  }
117482
117696
  }, value ?? "—"));
117483
117697
  };
117484
- const JudgeAggregateView = ({ metrics, onAgentNodeClick, onOpenVisualizer })=>{
117698
+ const NodeRow = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
117699
+ const { theme } = useTheme$1();
117700
+ return /*#__PURE__*/ React.createElement("div", {
117701
+ style: {
117702
+ display: "flex",
117703
+ alignItems: "center",
117704
+ gap: 10,
117705
+ flexWrap: "wrap"
117706
+ }
117707
+ }, /*#__PURE__*/ React.createElement(Tag, {
117708
+ style: {
117709
+ margin: 0,
117710
+ fontFamily: "monospace",
117711
+ fontWeight: 600,
117712
+ background: theme.colors.tagLlminference?.bg ?? theme.colors.muted,
117713
+ color: theme.colors.tagLlminference?.color ?? theme.colors.foreground,
117714
+ border: `1px solid ${theme.colors.tagLlminference?.border ?? theme.colors.border}`
117715
+ }
117716
+ }, formatStat(node.value, metricName)), /*#__PURE__*/ React.createElement(Tag, {
117717
+ style: {
117718
+ margin: 0,
117719
+ display: "inline-flex",
117720
+ alignItems: "center",
117721
+ gap: 6,
117722
+ background: theme.colors.tagToolLevel2?.bg ?? theme.colors.primary,
117723
+ color: theme.colors.tagToolLevel2?.color ?? theme.colors.primaryForeground,
117724
+ border: "none"
117725
+ }
117726
+ }, /*#__PURE__*/ React.createElement(Bot, {
117727
+ size: 12,
117728
+ style: {
117729
+ flexShrink: 0
117730
+ }
117731
+ }), "Agent Node"), /*#__PURE__*/ React.createElement(NodeActions, {
117732
+ sessionId: node.sessionId,
117733
+ nodeId: node.nodeId,
117734
+ onAgentNodeClick: onAgentNodeClick,
117735
+ onOpenVisualizer: onOpenVisualizer
117736
+ }));
117737
+ };
117738
+ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117739
+ const { theme } = useTheme$1();
117740
+ const items = metric.nodes.length > 0 ? [
117741
+ {
117742
+ key: "per-run",
117743
+ label: /*#__PURE__*/ React.createElement("span", {
117744
+ style: {
117745
+ fontSize: 13,
117746
+ fontWeight: 600
117747
+ }
117748
+ }, "Per-run values", " ", /*#__PURE__*/ React.createElement("span", {
117749
+ style: {
117750
+ color: theme.colors.mutedForeground,
117751
+ fontWeight: 400
117752
+ }
117753
+ }, "(", metric.nodes.length, ")")),
117754
+ children: /*#__PURE__*/ React.createElement("div", {
117755
+ style: {
117756
+ display: "flex",
117757
+ flexDirection: "column",
117758
+ gap: 12
117759
+ }
117760
+ }, metric.nodes.map((node)=>/*#__PURE__*/ React.createElement(NodeRow, {
117761
+ key: node.nodeId,
117762
+ node: node,
117763
+ metricName: metric.metricName,
117764
+ onAgentNodeClick: onAgentNodeClick,
117765
+ onOpenVisualizer: onOpenVisualizer
117766
+ })))
117767
+ }
117768
+ ] : [];
117769
+ return /*#__PURE__*/ React.createElement("div", {
117770
+ style: {
117771
+ background: theme.colors.card,
117772
+ border: `1px solid ${theme.colors.border}`,
117773
+ borderRadius: 8,
117774
+ overflow: "hidden"
117775
+ }
117776
+ }, /*#__PURE__*/ React.createElement("div", {
117777
+ style: {
117778
+ padding: "14px 18px",
117779
+ borderBottom: metric.nodes.length > 0 ? `1px solid ${theme.colors.border}` : "none",
117780
+ background: theme.colors.secondary
117781
+ }
117782
+ }, /*#__PURE__*/ React.createElement("div", {
117783
+ style: {
117784
+ display: "flex",
117785
+ alignItems: "center",
117786
+ gap: 12,
117787
+ flexWrap: "wrap"
117788
+ }
117789
+ }, /*#__PURE__*/ React.createElement(Gauge, {
117790
+ size: 16,
117791
+ style: {
117792
+ color: theme.colors.primary,
117793
+ flexShrink: 0
117794
+ }
117795
+ }), /*#__PURE__*/ React.createElement("span", {
117796
+ style: {
117797
+ fontSize: 15,
117798
+ fontWeight: 600
117799
+ }
117800
+ }, metric.metricName), /*#__PURE__*/ React.createElement("div", {
117801
+ style: {
117802
+ display: "flex",
117803
+ gap: 20,
117804
+ marginLeft: "auto",
117805
+ flexShrink: 0,
117806
+ flexWrap: "wrap"
117807
+ }
117808
+ }, /*#__PURE__*/ React.createElement(Meta, {
117809
+ label: "Mean",
117810
+ value: formatStat(metric.mean, metric.metricName)
117811
+ }), /*#__PURE__*/ React.createElement(Meta, {
117812
+ label: "Min",
117813
+ value: formatStat(metric.minimum, metric.metricName)
117814
+ }), /*#__PURE__*/ React.createElement(Meta, {
117815
+ label: "Max",
117816
+ value: formatStat(metric.maximum, metric.metricName)
117817
+ }), /*#__PURE__*/ React.createElement(Meta, {
117818
+ label: "Median",
117819
+ value: formatStat(metric.median, metric.metricName)
117820
+ }), /*#__PURE__*/ React.createElement(Meta, {
117821
+ label: "Std",
117822
+ value: formatStat(metric.std, metric.metricName)
117823
+ }), /*#__PURE__*/ React.createElement(Meta, {
117824
+ label: "Runs",
117825
+ value: String(metric.count)
117826
+ }))), metric.description && /*#__PURE__*/ React.createElement("div", {
117827
+ style: {
117828
+ marginTop: 6,
117829
+ fontSize: 12,
117830
+ color: theme.colors.mutedForeground
117831
+ }
117832
+ }, metric.description)), metric.nodes.length > 0 && /*#__PURE__*/ React.createElement(Collapse, {
117833
+ items: items,
117834
+ bordered: false,
117835
+ style: {
117836
+ background: theme.colors.card
117837
+ }
117838
+ }));
117839
+ };
117840
+ const NumericalAggregateView = ({ metrics, onAgentNodeClick, onOpenVisualizer })=>{
117485
117841
  const { theme } = useTheme$1();
117486
117842
  if (!metrics.length) {
117487
117843
  return /*#__PURE__*/ React.createElement("div", {
@@ -117491,7 +117847,7 @@ const JudgeAggregateView = ({ metrics, onAgentNodeClick, onOpenVisualizer })=>{
117491
117847
  color: theme.colors.mutedForeground,
117492
117848
  fontSize: 14
117493
117849
  }
117494
- }, "No judge metrics available");
117850
+ }, "No numerical metrics available");
117495
117851
  }
117496
117852
  return /*#__PURE__*/ React.createElement("div", {
117497
117853
  style: {
@@ -117504,7 +117860,7 @@ const JudgeAggregateView = ({ metrics, onAgentNodeClick, onOpenVisualizer })=>{
117504
117860
  fontSize: 16,
117505
117861
  fontWeight: 600
117506
117862
  }
117507
- }, "Judge Evaluator - Aggregate View"), /*#__PURE__*/ React.createElement("div", {
117863
+ }, "Custom Evaluator - Aggregate View"), /*#__PURE__*/ React.createElement("div", {
117508
117864
  style: {
117509
117865
  display: "flex",
117510
117866
  flexDirection: "column",
@@ -117522,7 +117878,10 @@ function detectAggregateType(nodes) {
117522
117878
  const values = Object.values(nodes);
117523
117879
  if (values.some((n)=>n?.type === "ToolAggregate")) return "ToolUse";
117524
117880
  if (values.some((n)=>n?.type === "LLMInferenceAggregate")) return "LLMInference";
117525
- if (values.some((n)=>n?.type === "CategoricalAggregate")) return "Judge";
117881
+ // Categorical covers the built-in JudgeEvaluator and any custom evaluator with categorical metrics.
117882
+ if (values.some((n)=>n?.type === "CategoricalAggregate")) return "Categorical";
117883
+ // Custom numerical evaluators (anything that isn't ToolUse/LLMInference/categorical) emit NumericalAggregate.
117884
+ if (values.some((n)=>n?.type === "NumericalAggregate")) return "Numerical";
117526
117885
  return null;
117527
117886
  }
117528
117887
  function buildLLMInferenceFlatRows(nodes) {
@@ -117564,7 +117923,8 @@ function formatAggregateValue(value, metricName) {
117564
117923
  const DEFAULT_TITLES = {
117565
117924
  ToolUse: "Tool Use Evaluator - Aggregate View",
117566
117925
  LLMInference: "LLM Inference Evaluator - Aggregate View",
117567
- Judge: "Judge Evaluator - Aggregate View"
117926
+ Categorical: "Categorical Evaluator - Aggregate View",
117927
+ Numerical: "Custom Evaluator - Aggregate View"
117568
117928
  };
117569
117929
  const AggregateResultsTable = ({ rawResults = [], aggregateResults, agents, title, evaluatorName, onAgentNodeClick, onOpenVisualizer })=>{
117570
117930
  const { theme } = useTheme$1();
@@ -117606,10 +117966,23 @@ const AggregateResultsTable = ({ rawResults = [], aggregateResults, agents, titl
117606
117966
  llmExpandableKeys
117607
117967
  };
117608
117968
  }
117609
- if (type === "Judge") {
117969
+ if (type === "Categorical") {
117610
117970
  return {
117611
117971
  aggregateType: type,
117612
- dataSource: buildJudgeMetricsFromAggregate({
117972
+ dataSource: buildCategoricalMetricsFromAggregate({
117973
+ roots: aggregateResults.roots,
117974
+ nodes: aggregateResults.nodes,
117975
+ agents,
117976
+ rawResults
117977
+ }),
117978
+ llmIsTree: false,
117979
+ llmExpandableKeys: []
117980
+ };
117981
+ }
117982
+ if (type === "Numerical") {
117983
+ return {
117984
+ aggregateType: type,
117985
+ dataSource: buildNumericalMetricsFromAggregate({
117613
117986
  roots: aggregateResults.roots,
117614
117987
  nodes: aggregateResults.nodes,
117615
117988
  agents,
@@ -117935,8 +118308,21 @@ const AggregateResultsTable = ({ rawResults = [], aggregateResults, agents, titl
117935
118308
  }
117936
118309
  }));
117937
118310
  }
117938
- if (aggregateType === "Judge") {
117939
- return /*#__PURE__*/ React.createElement(JudgeAggregateView, {
118311
+ if (aggregateType === "Categorical") {
118312
+ // JudgeEvaluator keeps its branding; any other (custom) categorical evaluator
118313
+ // renders through the same view with neutral categorical branding.
118314
+ const isJudge = (evaluatorName ?? "").includes("Judge");
118315
+ return /*#__PURE__*/ React.createElement(CategoricalAggregateView, {
118316
+ metrics: dataSource,
118317
+ title: title ?? (isJudge ? "Judge Evaluator - Aggregate View" : "Custom Evaluator - Aggregate View"),
118318
+ icon: isJudge ? Scale : Tags,
118319
+ emptyLabel: isJudge ? "No judge metrics available" : "No categorical metrics available",
118320
+ onAgentNodeClick: onAgentNodeClick,
118321
+ onOpenVisualizer: onOpenVisualizer
118322
+ });
118323
+ }
118324
+ if (aggregateType === "Numerical") {
118325
+ return /*#__PURE__*/ React.createElement(NumericalAggregateView, {
117940
118326
  metrics: dataSource,
117941
118327
  onAgentNodeClick: onAgentNodeClick,
117942
118328
  onOpenVisualizer: onOpenVisualizer
@@ -118203,7 +118589,8 @@ function isCategoricalMetric(def) {
118203
118589
  const aggregateTypes = [
118204
118590
  "ToolAggregate",
118205
118591
  "LLMInferenceAggregate",
118206
- "CategoricalAggregate"
118592
+ "CategoricalAggregate",
118593
+ "NumericalAggregate"
118207
118594
  ];
118208
118595
  const aggregateItems = Object.values(nodes).filter((n)=>n?.type && aggregateTypes.includes(n.type));
118209
118596
  return [