@railtownai/railtracks-visualizer 0.0.69 → 0.0.71

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$D = [
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$D);
12959
12959
 
12960
- const __iconNode$z = [
12960
+ const __iconNode$C = [
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$C);
12977
12977
 
12978
- const __iconNode$y = [
12978
+ const __iconNode$B = [
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$B);
13027
13027
 
13028
- const __iconNode$x = [
13028
+ const __iconNode$A = [
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$A);
13063
13063
 
13064
- const __iconNode$w = [
13064
+ const __iconNode$z = [
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$z);
13122
13122
 
13123
- const __iconNode$v = [
13123
+ const __iconNode$y = [
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$y);
13133
13133
 
13134
- const __iconNode$u = [
13134
+ const __iconNode$x = [
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$x);
13144
13144
 
13145
- const __iconNode$t = [
13145
+ const __iconNode$w = [
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$w);
13162
13162
 
13163
- const __iconNode$s = [
13163
+ const __iconNode$v = [
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$v);
13180
13180
 
13181
- const __iconNode$r = [
13181
+ const __iconNode$u = [
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$u);
13213
13213
 
13214
- const __iconNode$q = [
13214
+ const __iconNode$t = [
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$t);
13231
13231
 
13232
- const __iconNode$p = [
13232
+ const __iconNode$s = [
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$s);
13258
13258
 
13259
- const __iconNode$o = [
13259
+ const __iconNode$r = [
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$r);
13278
13278
 
13279
- const __iconNode$n = [
13279
+ const __iconNode$q = [
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$q);
13301
13301
 
13302
- const __iconNode$m = [
13302
+ const __iconNode$p = [
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$p);
13411
13411
 
13412
- const __iconNode$l = [
13412
+ const __iconNode$o = [
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$o);
13432
13432
 
13433
- const __iconNode$k = [
13433
+ const __iconNode$n = [
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$n);
13464
13464
 
13465
- const __iconNode$j = [
13465
+ const __iconNode$m = [
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$m);
13496
13496
 
13497
- const __iconNode$i = [
13497
+ const __iconNode$l = [
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$l);
13556
13556
 
13557
- const __iconNode$h = [
13557
+ const __iconNode$k = [
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$k);
13574
+
13575
+ const __iconNode$j = [
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$j);
13600
13618
 
13601
- const __iconNode$g = [
13619
+ const __iconNode$i = [
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$i);
13627
13645
 
13628
- const __iconNode$f = [
13646
+ const __iconNode$h = [
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$h);
13666
13684
 
13667
- const __iconNode$e = [
13685
+ const __iconNode$g = [
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$g);
13698
13716
 
13699
- const __iconNode$d = [
13717
+ const __iconNode$f = [
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$f);
13716
13734
 
13717
- const __iconNode$c = [
13735
+ const __iconNode$e = [
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$e);
13738
13756
 
13739
- const __iconNode$b = [
13757
+ const __iconNode$d = [
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$d);
13767
13785
 
13768
- const __iconNode$a = [
13786
+ const __iconNode$c = [
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$c);
13799
13817
 
13800
- const __iconNode$9 = [
13818
+ const __iconNode$b = [
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$b);
13838
13856
 
13839
- const __iconNode$8 = [
13857
+ const __iconNode$a = [
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$a);
13874
13892
 
13875
- const __iconNode$7 = [
13893
+ const __iconNode$9 = [
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$9);
13899
13917
 
13900
- const __iconNode$6 = [
13918
+ const __iconNode$8 = [
13901
13919
  [
13902
13920
  "path",
13903
13921
  {
@@ -13906,9 +13924,37 @@ const __iconNode$6 = [
13906
13924
  }
13907
13925
  ]
13908
13926
  ];
13909
- const Shield = createLucideIcon("shield", __iconNode$6);
13927
+ const Shield = createLucideIcon("shield", __iconNode$8);
13910
13928
 
13911
- const __iconNode$5 = [
13929
+ const __iconNode$7 = [
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$7);
13956
+
13957
+ const __iconNode$6 = [
13912
13958
  [
13913
13959
  "circle",
13914
13960
  {
@@ -13937,9 +13983,9 @@ const __iconNode$5 = [
13937
13983
  }
13938
13984
  ]
13939
13985
  ];
13940
- const Target = createLucideIcon("target", __iconNode$5);
13986
+ const Target = createLucideIcon("target", __iconNode$6);
13941
13987
 
13942
- const __iconNode$4 = [
13988
+ const __iconNode$5 = [
13943
13989
  [
13944
13990
  "line",
13945
13991
  {
@@ -13970,7 +14016,32 @@ const __iconNode$4 = [
13970
14016
  }
13971
14017
  ]
13972
14018
  ];
13973
- const Timer = createLucideIcon("timer", __iconNode$4);
14019
+ const Timer = createLucideIcon("timer", __iconNode$5);
14020
+
14021
+ const __iconNode$4 = [
14022
+ [
14023
+ "path",
14024
+ {
14025
+ d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",
14026
+ key: "wmoenq"
14027
+ }
14028
+ ],
14029
+ [
14030
+ "path",
14031
+ {
14032
+ d: "M12 9v4",
14033
+ key: "juzpu7"
14034
+ }
14035
+ ],
14036
+ [
14037
+ "path",
14038
+ {
14039
+ d: "M12 17h.01",
14040
+ key: "p32p05"
14041
+ }
14042
+ ]
14043
+ ];
14044
+ const TriangleAlert = createLucideIcon("triangle-alert", __iconNode$4);
13974
14045
 
13975
14046
  const __iconNode$3 = [
13976
14047
  [
@@ -47792,7 +47863,7 @@ const Paragraph = /*#__PURE__*/ React__namespace.forwardRef((props, ref)=>{
47792
47863
  }, children);
47793
47864
  });
47794
47865
 
47795
- const Text$2 = /*#__PURE__*/ React__namespace.forwardRef((props, ref)=>{
47866
+ const Text$3 = /*#__PURE__*/ React__namespace.forwardRef((props, ref)=>{
47796
47867
  const { ellipsis, children, ...restProps } = props;
47797
47868
  const mergedEllipsis = React__namespace.useMemo(()=>{
47798
47869
  if (ellipsis && typeof ellipsis === 'object') {
@@ -47839,7 +47910,7 @@ const Title$1 = /*#__PURE__*/ React__namespace.forwardRef((props, ref)=>{
47839
47910
  });
47840
47911
 
47841
47912
  const Typography = Typography$1;
47842
- Typography.Text = Text$2;
47913
+ Typography.Text = Text$3;
47843
47914
  Typography.Link = Link$1;
47844
47915
  Typography.Title = Title$1;
47845
47916
  Typography.Paragraph = Paragraph;
@@ -48160,6 +48231,130 @@ function valueToTreeNodes(value, path) {
48160
48231
  return valueToTreeNodes(data, "$root");
48161
48232
  }
48162
48233
 
48234
+ const { Text: Text$2 } = Typography;
48235
+ /**
48236
+ * Detect whether a tool/node output is an error envelope rather than a regular
48237
+ * return value. Failed nodes serialize as `{ type, message, traceback }`; a
48238
+ * traceback alone, or a `type` + `message` pair, is enough to treat it as an
48239
+ * error. Returns the parsed error (with only string fields kept) or null.
48240
+ */ function parseErrorOutput(output) {
48241
+ if (output === null || typeof output !== "object" || Array.isArray(output)) {
48242
+ return null;
48243
+ }
48244
+ const obj = output;
48245
+ const type = typeof obj.type === "string" ? obj.type : undefined;
48246
+ const message = typeof obj.message === "string" ? obj.message : undefined;
48247
+ const traceback = typeof obj.traceback === "string" ? obj.traceback : undefined;
48248
+ const looksLikeError = traceback !== undefined || type !== undefined && message !== undefined;
48249
+ return looksLikeError ? {
48250
+ type,
48251
+ message,
48252
+ traceback
48253
+ } : null;
48254
+ }
48255
+ /**
48256
+ * Renders a failed node/tool output distinctly from a regular returned object:
48257
+ * a destructive-tinted surface with the exception type, message, and a
48258
+ * collapsible traceback.
48259
+ */ const ErrorOutput = ({ error })=>{
48260
+ const { theme } = useTheme$1();
48261
+ const [showTraceback, setShowTraceback] = React.useState(false);
48262
+ const destructive = theme?.colors?.destructive ?? "hsl(0 84.2% 60.2%)";
48263
+ const foreground = theme?.colors?.foreground ?? "inherit";
48264
+ const mutedForeground = theme?.colors?.mutedForeground ?? "inherit";
48265
+ const radius = theme?.borderRadius?.md ?? "0.375rem";
48266
+ const xs = theme?.spacing?.xs ?? "0.25rem";
48267
+ const sm = theme?.spacing?.sm ?? "0.5rem";
48268
+ const md = theme?.spacing?.md ?? "1rem";
48269
+ const fontXs = theme?.fontSize?.xs ?? "0.75rem";
48270
+ const fontSm = theme?.fontSize?.sm ?? "0.875rem";
48271
+ const { type, message, traceback } = error;
48272
+ return /*#__PURE__*/ React.createElement("div", {
48273
+ "data-testid": "error-output",
48274
+ style: {
48275
+ border: `1px solid color-mix(in srgb, ${destructive} 45%, transparent)`,
48276
+ background: `color-mix(in srgb, ${destructive} 8%, transparent)`,
48277
+ borderRadius: radius,
48278
+ padding: md,
48279
+ display: "flex",
48280
+ flexDirection: "column",
48281
+ gap: sm
48282
+ }
48283
+ }, /*#__PURE__*/ React.createElement("div", {
48284
+ style: {
48285
+ display: "flex",
48286
+ alignItems: "center",
48287
+ gap: sm,
48288
+ flexWrap: "wrap"
48289
+ }
48290
+ }, /*#__PURE__*/ React.createElement(TriangleAlert, {
48291
+ size: 16,
48292
+ color: destructive,
48293
+ strokeWidth: 2,
48294
+ "aria-hidden": true
48295
+ }), /*#__PURE__*/ React.createElement(Tag, {
48296
+ color: "red",
48297
+ style: {
48298
+ margin: 0
48299
+ }
48300
+ }, type || "Error")), message && /*#__PURE__*/ React.createElement(Text$2, {
48301
+ strong: true,
48302
+ style: {
48303
+ color: foreground,
48304
+ fontSize: fontSm,
48305
+ wordBreak: "break-word"
48306
+ }
48307
+ }, message), traceback && /*#__PURE__*/ React.createElement("div", {
48308
+ style: {
48309
+ display: "flex",
48310
+ flexDirection: "column",
48311
+ gap: xs
48312
+ }
48313
+ }, /*#__PURE__*/ React.createElement("button", {
48314
+ type: "button",
48315
+ onClick: ()=>setShowTraceback((prev)=>!prev),
48316
+ "aria-expanded": showTraceback,
48317
+ style: {
48318
+ display: "inline-flex",
48319
+ alignItems: "center",
48320
+ gap: xs,
48321
+ alignSelf: "flex-start",
48322
+ padding: 0,
48323
+ border: "none",
48324
+ background: "transparent",
48325
+ cursor: "pointer",
48326
+ color: destructive,
48327
+ fontSize: fontXs,
48328
+ fontWeight: 500
48329
+ }
48330
+ }, showTraceback ? /*#__PURE__*/ React.createElement(ChevronDown, {
48331
+ size: 14,
48332
+ strokeWidth: 2,
48333
+ "aria-hidden": true
48334
+ }) : /*#__PURE__*/ React.createElement(ChevronRight, {
48335
+ size: 14,
48336
+ strokeWidth: 2,
48337
+ "aria-hidden": true
48338
+ }), showTraceback ? "Hide traceback" : "Show traceback"), showTraceback && /*#__PURE__*/ React.createElement("pre", {
48339
+ "data-testid": "error-output-traceback",
48340
+ style: {
48341
+ margin: 0,
48342
+ padding: sm,
48343
+ borderRadius: radius,
48344
+ background: `color-mix(in srgb, ${destructive} 6%, transparent)`,
48345
+ border: `1px solid color-mix(in srgb, ${destructive} 25%, transparent)`,
48346
+ color: mutedForeground,
48347
+ fontFamily: "monospace",
48348
+ fontSize: fontXs,
48349
+ lineHeight: 1.5,
48350
+ whiteSpace: "pre-wrap",
48351
+ wordBreak: "break-word",
48352
+ maxHeight: "300px",
48353
+ overflow: "auto"
48354
+ }
48355
+ }, traceback)));
48356
+ };
48357
+
48163
48358
  const { Text: Text$1 } = Typography;
48164
48359
  function themedCodeSurface(theme) {
48165
48360
  return {
@@ -48338,8 +48533,9 @@ const InputsOutputsCollapse = ({ inputs, output, toolOutput, modelProvider, mode
48338
48533
  const { theme } = useTheme$1();
48339
48534
  const hasInputs = hasInputsProp ?? inputs.length > 0;
48340
48535
  const hasOutputs = output !== null || toolOutput !== null;
48536
+ const errorOutput = parseErrorOutput(toolOutput);
48341
48537
  const outputsText = hasOutputs ? formatOutputAsText(output, toolOutput) : "";
48342
- const isToolOutputTabular = toolOutput !== null && toolOutput !== undefined && isTabularData(toolOutput);
48538
+ const isToolOutputTabular = !errorOutput && toolOutput !== null && toolOutput !== undefined && isTabularData(toolOutput);
48343
48539
  const toolInputText = getToolInputText(inputs);
48344
48540
  const inputsLabel = largeInputsTitle ? /*#__PURE__*/ React.createElement("div", {
48345
48541
  style: {
@@ -48424,13 +48620,26 @@ const InputsOutputsCollapse = ({ inputs, output, toolOutput, modelProvider, mode
48424
48620
  },
48425
48621
  {
48426
48622
  key: "outputs",
48427
- label: /*#__PURE__*/ React.createElement(Text$1, {
48623
+ label: /*#__PURE__*/ React.createElement("div", {
48624
+ style: {
48625
+ display: "flex",
48626
+ alignItems: "center",
48627
+ gap: theme.spacing.sm
48628
+ }
48629
+ }, /*#__PURE__*/ React.createElement(Text$1, {
48428
48630
  strong: true,
48429
48631
  style: {
48430
48632
  color: theme.colors.foreground
48431
48633
  }
48432
- }, "Outputs"),
48433
- children: hasOutputs ? isToolOutputTabular ? /*#__PURE__*/ React.createElement(JsonValueTree, {
48634
+ }, "Outputs"), errorOutput && /*#__PURE__*/ React.createElement(Tag, {
48635
+ color: "red",
48636
+ style: {
48637
+ margin: 0
48638
+ }
48639
+ }, "Failed")),
48640
+ children: hasOutputs ? errorOutput ? /*#__PURE__*/ React.createElement(ErrorOutput, {
48641
+ error: errorOutput
48642
+ }) : isToolOutputTabular ? /*#__PURE__*/ React.createElement(JsonValueTree, {
48434
48643
  data: toolOutput
48435
48644
  }) : /*#__PURE__*/ React.createElement("pre", {
48436
48645
  style: outputPreStyle
@@ -112625,7 +112834,32 @@ const GuardrailsPopover = ({ guardrails, title = "Guardrails", placement = "righ
112625
112834
  })));
112626
112835
  };
112627
112836
 
112628
- const getNodeLatency = (node)=>node.details?.internals?.latency?.total_time ?? 0;
112837
+ /** Collect start/end instants (unix seconds) for wall-clock span of a single node. */ const getNodeStampTimes = (node)=>{
112838
+ const start = node.stamp?.time;
112839
+ if (start == null) return [];
112840
+ const times = [
112841
+ start
112842
+ ];
112843
+ const latency = node.details?.internals?.latency?.total_time;
112844
+ if (latency != null && latency > 0) times.push(start + latency);
112845
+ return times;
112846
+ };
112847
+ const wallClockSpanSeconds = (times)=>{
112848
+ if (times.length === 0) return 0;
112849
+ const min = Math.min(...times);
112850
+ const max = Math.max(...times);
112851
+ return Math.max(0, max - min);
112852
+ };
112853
+ const collectSubtreeStampTimes = (nodeId, childrenMap, nodeMap)=>{
112854
+ const node = nodeMap.get(nodeId);
112855
+ if (!node) return [];
112856
+ const times = getNodeStampTimes(node);
112857
+ for (const childId of childrenMap.get(nodeId) ?? []){
112858
+ times.push(...collectSubtreeStampTimes(childId, childrenMap, nodeMap));
112859
+ }
112860
+ return times;
112861
+ };
112862
+ /** Wall-clock elapsed time across a node and all descendants (unix stamp times). */ const getSubtreeWallClockSeconds = (nodeId, childrenMap, nodeMap)=>wallClockSpanSeconds(collectSubtreeStampTimes(nodeId, childrenMap, nodeMap));
112629
112863
  const SessionTreeNodeTitle = ({ displayName, subtreeLatency, guardrails })=>{
112630
112864
  return /*#__PURE__*/ React.createElement("span", {
112631
112865
  style: {
@@ -112753,8 +112987,7 @@ const buildNodeTree = (run)=>{
112753
112987
  const nodeKey = `node::${run.run_id}::${node.identifier}`;
112754
112988
  const childIds = childrenMap.get(node.identifier) || [];
112755
112989
  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;
112990
+ const subtreeLatency = getSubtreeWallClockSeconds(node.identifier, childrenMap, nodeMap);
112758
112991
  const guardrails = node.details?.internals?.guard_details ?? [];
112759
112992
  const isTool = node.node_type === "Tool";
112760
112993
  const failed = isNodeFailureFromIncomingEdge(run, node.identifier);
@@ -113376,7 +113609,7 @@ const SessionDetails = ({ session, open, onClose, initialNodeId, initialRunId, l
113376
113609
 
113377
113610
  /**
113378
113611
  * DTOs for evaluation data from .railtracks/data/evaluations/*.json
113379
- */ /** Numeric metric definition (LLMMetric or ToolMetric) */ /** Type guard for LLM result */ function isLLMResult(item) {
113612
+ */ /** Numeric metric definition (LLMMetric, ToolMetric, or Numerical for custom evaluators) */ /** Type guard for LLM result */ function isLLMResult(item) {
113380
113613
  return item.type === "LLM";
113381
113614
  }
113382
113615
  /** Type guard for Tool result */ function isToolResult(item) {
@@ -113394,8 +113627,12 @@ const SessionDetails = ({ session, open, onClose, initialNodeId, initialRunId, l
113394
113627
  /** Type guard for CategoricalAggregate */ function isAggregateCategorical(item) {
113395
113628
  return item.type === "CategoricalAggregate";
113396
113629
  }
113397
- /** Type guard for aggregated stats (numeric - LLMInferenceAggregate or ToolAggregate) */ function isAggregatedStats(item) {
113398
- return item.type === "LLMInferenceAggregate" || item.type === "ToolAggregate";
113630
+ /** Type guard for NumericalAggregate (custom evaluator numeric aggregate) */ function isNumericalAggregate(item) {
113631
+ return item.type === "NumericalAggregate";
113632
+ }
113633
+ /** Type guard for aggregated stats (numeric - LLMInferenceAggregate, ToolAggregate, or NumericalAggregate) */ function isAggregatedStats(item) {
113634
+ const type = item.type;
113635
+ return type === "LLMInferenceAggregate" || type === "ToolAggregate" || type === "NumericalAggregate";
113399
113636
  }
113400
113637
 
113401
113638
  function isCategoricalMetric$1(def) {
@@ -113411,7 +113648,8 @@ function isCategoricalMetric$1(def) {
113411
113648
  const aggregateTypes = [
113412
113649
  "ToolAggregate",
113413
113650
  "LLMInferenceAggregate",
113414
- "CategoricalAggregate"
113651
+ "CategoricalAggregate",
113652
+ "NumericalAggregate"
113415
113653
  ];
113416
113654
  const aggregateItems = Object.values(nodes).filter((n)=>n?.type && aggregateTypes.includes(n.type));
113417
113655
  return [
@@ -117077,7 +117315,7 @@ function buildTreeFromProcessedData(latencyByTool, failureRateByTool, usageCount
117077
117315
 
117078
117316
  const JUDGE_RESULT_PREFIX = "JudgeResult/";
117079
117317
  const JUDGE_REASONING_PREFIX = "JudgeReasoning/";
117080
- /** Map agent node id -> session id from the agents array (new format only). */ function buildSessionByNodeId(agents) {
117318
+ /** Map agent node id -> session id from the agents array (new format only). */ function buildSessionByNodeId$1(agents) {
117081
117319
  const map = new Map();
117082
117320
  for (const agent of agents ?? []){
117083
117321
  for (const entry of agent.agent_node_ids ?? []){
@@ -117101,10 +117339,10 @@ const JUDGE_REASONING_PREFIX = "JudgeReasoning/";
117101
117339
  }
117102
117340
  return map;
117103
117341
  }
117104
- function metricNameOf(agg) {
117342
+ function metricNameOf$1(agg) {
117105
117343
  return agg.metric?.name ?? agg.name?.replace(/^Aggregate\//, "") ?? "Unknown";
117106
117344
  }
117107
- /** Collect the JudgeResult leaf nodes (label + node id) grouped by label. */ function groupNodesByLabel(agg, nodes, rawResults, metricName, sessionByNodeId, reasoningByKey) {
117345
+ /** Collect the leaf nodes (label + node id) grouped by label. */ function groupNodesByLabel(agg, nodes, rawResults, metricName, sessionByNodeId, reasoningByKey) {
117108
117346
  const byLabel = new Map();
117109
117347
  const seen = new Set();
117110
117348
  const push = (label, nodeId)=>{
@@ -117142,15 +117380,15 @@ function metricNameOf(agg) {
117142
117380
  }
117143
117381
  return byLabel;
117144
117382
  }
117145
- /** Build the Judge view model: one entry per categorical metric. */ function buildJudgeMetricsFromAggregate(input) {
117383
+ /** Build the categorical view model: one entry per categorical metric. */ function buildCategoricalMetricsFromAggregate(input) {
117146
117384
  const { roots, nodes, agents, rawResults = [] } = input;
117147
- const sessionByNodeId = buildSessionByNodeId(agents);
117385
+ const sessionByNodeId = buildSessionByNodeId$1(agents);
117148
117386
  const reasoningByKey = buildReasoningByKey(rawResults);
117149
117387
  // Prefer roots; fall back to scanning all nodes for categorical aggregates.
117150
117388
  const rootAggregates = roots.map((id)=>nodes[id]).filter((n)=>isAggregateCategorical(n));
117151
117389
  const aggregates = rootAggregates.length > 0 ? rootAggregates : Object.values(nodes).filter((n)=>isAggregateCategorical(n));
117152
117390
  return aggregates.map((agg, index)=>{
117153
- const metricName = metricNameOf(agg);
117391
+ const metricName = metricNameOf$1(agg);
117154
117392
  const counts = agg.counts ?? {};
117155
117393
  const categories = agg.categories ?? agg.metric?.categories ?? Object.keys(counts);
117156
117394
  const byLabel = groupNodesByLabel(agg, nodes, rawResults, metricName, sessionByNodeId, reasoningByKey);
@@ -117182,6 +117420,75 @@ function metricNameOf(agg) {
117182
117420
  });
117183
117421
  }
117184
117422
 
117423
+ /** Map agent node id -> session id from the agents array (new format only). */ function buildSessionByNodeId(agents) {
117424
+ const map = new Map();
117425
+ for (const agent of agents ?? []){
117426
+ for (const entry of agent.agent_node_ids ?? []){
117427
+ if (entry && typeof entry === "object" && "agent_node_id" in entry) {
117428
+ map.set(entry.agent_node_id, entry.session_id);
117429
+ }
117430
+ }
117431
+ }
117432
+ return map;
117433
+ }
117434
+ function metricNameOf(agg) {
117435
+ return agg.metric?.name ?? agg.name?.replace(/^Aggregate\//, "") ?? "Unknown";
117436
+ }
117437
+ /** Collect the per-run leaf values (value + node id) for a numerical aggregate. */ function collectNodes(agg, nodes, rawResults, metricName, sessionByNodeId) {
117438
+ const refs = [];
117439
+ const seen = new Set();
117440
+ const push = (nodeId, value)=>{
117441
+ if (!Number.isFinite(value) || seen.has(nodeId)) return;
117442
+ seen.add(nodeId);
117443
+ refs.push({
117444
+ nodeId,
117445
+ sessionId: sessionByNodeId.get(nodeId),
117446
+ value
117447
+ });
117448
+ };
117449
+ // Preferred: walk the aggregate's children leaf nodes.
117450
+ for (const childId of agg.children ?? []){
117451
+ const child = nodes[childId];
117452
+ if (child && isBaseResult(child)) {
117453
+ const nodeId = child.agent_data_id?.[0];
117454
+ if (nodeId) push(nodeId, Number(child.value));
117455
+ }
117456
+ }
117457
+ // Fallback: derive from raw Base results named after the metric when no children resolve.
117458
+ if (refs.length === 0) {
117459
+ for (const item of rawResults){
117460
+ if (isBaseResult(item) && item.result_name === metricName) {
117461
+ const nodeId = item.agent_data_id?.[0];
117462
+ if (nodeId) push(nodeId, Number(item.value));
117463
+ }
117464
+ }
117465
+ }
117466
+ return refs;
117467
+ }
117468
+ /** Build the custom (numerical) evaluator view model: one entry per numerical metric. */ function buildNumericalMetricsFromAggregate(input) {
117469
+ const { roots, nodes, agents, rawResults = [] } = input;
117470
+ const sessionByNodeId = buildSessionByNodeId(agents);
117471
+ // Prefer roots; fall back to scanning all nodes for numerical aggregates.
117472
+ const rootAggregates = roots.map((id)=>nodes[id]).filter((n)=>isNumericalAggregate(n));
117473
+ const aggregates = rootAggregates.length > 0 ? rootAggregates : Object.values(nodes).filter((n)=>isNumericalAggregate(n));
117474
+ return aggregates.map((agg, index)=>{
117475
+ const metricName = metricNameOf(agg);
117476
+ const nodeRefs = collectNodes(agg, nodes, rawResults, metricName, sessionByNodeId);
117477
+ return {
117478
+ key: agg.identifier ?? `${metricName}-${index}`,
117479
+ metricName,
117480
+ description: agg.metric?.description ?? undefined,
117481
+ mean: agg.mean,
117482
+ minimum: agg.minimum,
117483
+ maximum: agg.maximum,
117484
+ median: agg.median,
117485
+ std: agg.std,
117486
+ count: agg.values?.length ?? nodeRefs.length,
117487
+ nodes: nodeRefs
117488
+ };
117489
+ });
117490
+ }
117491
+
117185
117492
  const NodeActions = ({ sessionId, nodeId, onAgentNodeClick, onOpenVisualizer })=>{
117186
117493
  const { theme } = useTheme$1();
117187
117494
  const baseStyle = {
@@ -117243,7 +117550,7 @@ const NodeActions = ({ sessionId, nodeId, onAgentNodeClick, onOpenVisualizer })=
117243
117550
  }), "Visualizer")));
117244
117551
  };
117245
117552
 
117246
- const NodeRow = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
117553
+ const NodeRow$1 = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
117247
117554
  const { theme } = useTheme$1();
117248
117555
  const [showReasoning, setShowReasoning] = React.useState(false);
117249
117556
  return /*#__PURE__*/ React.createElement("div", {
@@ -117313,7 +117620,7 @@ const NodeRow = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
117313
117620
  marginBottom: 6,
117314
117621
  color: theme.colors.mutedForeground
117315
117622
  }
117316
- }, "Judge reasoning · ", metricName), node.reasoning));
117623
+ }, "Reasoning · ", metricName), node.reasoning));
117317
117624
  };
117318
117625
  const LabelPanelHeader = ({ label })=>{
117319
117626
  const { theme } = useTheme$1();
@@ -117346,7 +117653,7 @@ const LabelPanelHeader = ({ label })=>{
117346
117653
  }
117347
117654
  }, label.count, " ", label.count === 1 ? "node" : "nodes"));
117348
117655
  };
117349
- const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117656
+ const MetricCard$1 = ({ metric, icon: Icon, onAgentNodeClick, onOpenVisualizer })=>{
117350
117657
  const { theme } = useTheme$1();
117351
117658
  const items = metric.labels.map((label)=>({
117352
117659
  key: label.labelName,
@@ -117366,7 +117673,7 @@ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117366
117673
  flexDirection: "column",
117367
117674
  gap: 12
117368
117675
  }
117369
- }, label.nodes.map((node)=>/*#__PURE__*/ React.createElement(NodeRow, {
117676
+ }, label.nodes.map((node)=>/*#__PURE__*/ React.createElement(NodeRow$1, {
117370
117677
  key: node.nodeId,
117371
117678
  node: node,
117372
117679
  metricName: metric.metricName,
@@ -117394,7 +117701,7 @@ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117394
117701
  gap: 12,
117395
117702
  flexWrap: "wrap"
117396
117703
  }
117397
- }, /*#__PURE__*/ React.createElement(Scale, {
117704
+ }, /*#__PURE__*/ React.createElement(Icon, {
117398
117705
  size: 16,
117399
117706
  style: {
117400
117707
  color: theme.colors.primary,
@@ -117435,13 +117742,13 @@ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117435
117742
  marginLeft: "auto",
117436
117743
  flexShrink: 0
117437
117744
  }
117438
- }, /*#__PURE__*/ React.createElement(Meta, {
117745
+ }, /*#__PURE__*/ React.createElement(Meta$1, {
117439
117746
  label: "Most common",
117440
117747
  value: metric.mostCommon
117441
- }), /*#__PURE__*/ React.createElement(Meta, {
117748
+ }), /*#__PURE__*/ React.createElement(Meta$1, {
117442
117749
  label: "Least common",
117443
117750
  value: metric.leastCommon
117444
- }), /*#__PURE__*/ React.createElement(Meta, {
117751
+ }), /*#__PURE__*/ React.createElement(Meta$1, {
117445
117752
  label: "Evaluations",
117446
117753
  value: String(metric.total)
117447
117754
  }))), metric.description && /*#__PURE__*/ React.createElement("div", {
@@ -117458,6 +117765,76 @@ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117458
117765
  }
117459
117766
  }));
117460
117767
  };
117768
+ const Meta$1 = ({ label, value })=>{
117769
+ const { theme } = useTheme$1();
117770
+ return /*#__PURE__*/ React.createElement("span", {
117771
+ style: {
117772
+ display: "flex",
117773
+ flexDirection: "column",
117774
+ alignItems: "flex-end",
117775
+ gap: 1
117776
+ }
117777
+ }, /*#__PURE__*/ React.createElement("span", {
117778
+ style: {
117779
+ fontSize: 10,
117780
+ textTransform: "uppercase",
117781
+ letterSpacing: 0.4,
117782
+ color: theme.colors.mutedForeground
117783
+ }
117784
+ }, label), /*#__PURE__*/ React.createElement("span", {
117785
+ style: {
117786
+ fontSize: 13,
117787
+ fontWeight: 500
117788
+ }
117789
+ }, value ?? "—"));
117790
+ };
117791
+ const CategoricalAggregateView = ({ metrics, title = "Categorical Evaluator - Aggregate View", icon = Tags, emptyLabel = "No categorical metrics available", onAgentNodeClick, onOpenVisualizer })=>{
117792
+ const { theme } = useTheme$1();
117793
+ if (!metrics.length) {
117794
+ return /*#__PURE__*/ React.createElement("div", {
117795
+ style: {
117796
+ padding: 24,
117797
+ textAlign: "center",
117798
+ color: theme.colors.mutedForeground,
117799
+ fontSize: 14
117800
+ }
117801
+ }, emptyLabel);
117802
+ }
117803
+ return /*#__PURE__*/ React.createElement("div", {
117804
+ style: {
117805
+ width: "100%",
117806
+ minWidth: 0
117807
+ }
117808
+ }, /*#__PURE__*/ React.createElement("h3", {
117809
+ style: {
117810
+ margin: "0 0 16px",
117811
+ fontSize: 16,
117812
+ fontWeight: 600
117813
+ }
117814
+ }, title), /*#__PURE__*/ React.createElement("div", {
117815
+ style: {
117816
+ display: "flex",
117817
+ flexDirection: "column",
117818
+ gap: 12
117819
+ }
117820
+ }, metrics.map((metric)=>/*#__PURE__*/ React.createElement(MetricCard$1, {
117821
+ key: metric.key,
117822
+ metric: metric,
117823
+ icon: icon,
117824
+ onAgentNodeClick: onAgentNodeClick,
117825
+ onOpenVisualizer: onOpenVisualizer
117826
+ }))));
117827
+ };
117828
+
117829
+ /**
117830
+ * Format a numerical value for display. Custom metric names are arbitrary, so we
117831
+ * use a light heuristic: latency-like metrics render as durations, integers get
117832
+ * thousands separators, everything else gets two decimals.
117833
+ */ function formatStat(value, metricName) {
117834
+ if (value === undefined || !Number.isFinite(value)) return "—";
117835
+ if (/seconds$/i.test(metricName) || /latency/i.test(metricName)) return formatLatency(value);
117836
+ return Number.isInteger(value) ? formatNumberWithCommas(value) : value.toFixed(2);
117837
+ }
117461
117838
  const Meta = ({ label, value })=>{
117462
117839
  const { theme } = useTheme$1();
117463
117840
  return /*#__PURE__*/ React.createElement("span", {
@@ -117481,7 +117858,149 @@ const Meta = ({ label, value })=>{
117481
117858
  }
117482
117859
  }, value ?? "—"));
117483
117860
  };
117484
- const JudgeAggregateView = ({ metrics, onAgentNodeClick, onOpenVisualizer })=>{
117861
+ const NodeRow = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
117862
+ const { theme } = useTheme$1();
117863
+ return /*#__PURE__*/ React.createElement("div", {
117864
+ style: {
117865
+ display: "flex",
117866
+ alignItems: "center",
117867
+ gap: 10,
117868
+ flexWrap: "wrap"
117869
+ }
117870
+ }, /*#__PURE__*/ React.createElement(Tag, {
117871
+ style: {
117872
+ margin: 0,
117873
+ fontFamily: "monospace",
117874
+ fontWeight: 600,
117875
+ background: theme.colors.tagLlminference?.bg ?? theme.colors.muted,
117876
+ color: theme.colors.tagLlminference?.color ?? theme.colors.foreground,
117877
+ border: `1px solid ${theme.colors.tagLlminference?.border ?? theme.colors.border}`
117878
+ }
117879
+ }, formatStat(node.value, metricName)), /*#__PURE__*/ React.createElement(Tag, {
117880
+ style: {
117881
+ margin: 0,
117882
+ display: "inline-flex",
117883
+ alignItems: "center",
117884
+ gap: 6,
117885
+ background: theme.colors.tagToolLevel2?.bg ?? theme.colors.primary,
117886
+ color: theme.colors.tagToolLevel2?.color ?? theme.colors.primaryForeground,
117887
+ border: "none"
117888
+ }
117889
+ }, /*#__PURE__*/ React.createElement(Bot, {
117890
+ size: 12,
117891
+ style: {
117892
+ flexShrink: 0
117893
+ }
117894
+ }), "Agent Node"), /*#__PURE__*/ React.createElement(NodeActions, {
117895
+ sessionId: node.sessionId,
117896
+ nodeId: node.nodeId,
117897
+ onAgentNodeClick: onAgentNodeClick,
117898
+ onOpenVisualizer: onOpenVisualizer
117899
+ }));
117900
+ };
117901
+ const MetricCard = ({ metric, onAgentNodeClick, onOpenVisualizer })=>{
117902
+ const { theme } = useTheme$1();
117903
+ const items = metric.nodes.length > 0 ? [
117904
+ {
117905
+ key: "per-run",
117906
+ label: /*#__PURE__*/ React.createElement("span", {
117907
+ style: {
117908
+ fontSize: 13,
117909
+ fontWeight: 600
117910
+ }
117911
+ }, "Per-run values", " ", /*#__PURE__*/ React.createElement("span", {
117912
+ style: {
117913
+ color: theme.colors.mutedForeground,
117914
+ fontWeight: 400
117915
+ }
117916
+ }, "(", metric.nodes.length, ")")),
117917
+ children: /*#__PURE__*/ React.createElement("div", {
117918
+ style: {
117919
+ display: "flex",
117920
+ flexDirection: "column",
117921
+ gap: 12
117922
+ }
117923
+ }, metric.nodes.map((node)=>/*#__PURE__*/ React.createElement(NodeRow, {
117924
+ key: node.nodeId,
117925
+ node: node,
117926
+ metricName: metric.metricName,
117927
+ onAgentNodeClick: onAgentNodeClick,
117928
+ onOpenVisualizer: onOpenVisualizer
117929
+ })))
117930
+ }
117931
+ ] : [];
117932
+ return /*#__PURE__*/ React.createElement("div", {
117933
+ style: {
117934
+ background: theme.colors.card,
117935
+ border: `1px solid ${theme.colors.border}`,
117936
+ borderRadius: 8,
117937
+ overflow: "hidden"
117938
+ }
117939
+ }, /*#__PURE__*/ React.createElement("div", {
117940
+ style: {
117941
+ padding: "14px 18px",
117942
+ borderBottom: metric.nodes.length > 0 ? `1px solid ${theme.colors.border}` : "none",
117943
+ background: theme.colors.secondary
117944
+ }
117945
+ }, /*#__PURE__*/ React.createElement("div", {
117946
+ style: {
117947
+ display: "flex",
117948
+ alignItems: "center",
117949
+ gap: 12,
117950
+ flexWrap: "wrap"
117951
+ }
117952
+ }, /*#__PURE__*/ React.createElement(Gauge, {
117953
+ size: 16,
117954
+ style: {
117955
+ color: theme.colors.primary,
117956
+ flexShrink: 0
117957
+ }
117958
+ }), /*#__PURE__*/ React.createElement("span", {
117959
+ style: {
117960
+ fontSize: 15,
117961
+ fontWeight: 600
117962
+ }
117963
+ }, metric.metricName), /*#__PURE__*/ React.createElement("div", {
117964
+ style: {
117965
+ display: "flex",
117966
+ gap: 20,
117967
+ marginLeft: "auto",
117968
+ flexShrink: 0,
117969
+ flexWrap: "wrap"
117970
+ }
117971
+ }, /*#__PURE__*/ React.createElement(Meta, {
117972
+ label: "Mean",
117973
+ value: formatStat(metric.mean, metric.metricName)
117974
+ }), /*#__PURE__*/ React.createElement(Meta, {
117975
+ label: "Min",
117976
+ value: formatStat(metric.minimum, metric.metricName)
117977
+ }), /*#__PURE__*/ React.createElement(Meta, {
117978
+ label: "Max",
117979
+ value: formatStat(metric.maximum, metric.metricName)
117980
+ }), /*#__PURE__*/ React.createElement(Meta, {
117981
+ label: "Median",
117982
+ value: formatStat(metric.median, metric.metricName)
117983
+ }), /*#__PURE__*/ React.createElement(Meta, {
117984
+ label: "Std",
117985
+ value: formatStat(metric.std, metric.metricName)
117986
+ }), /*#__PURE__*/ React.createElement(Meta, {
117987
+ label: "Runs",
117988
+ value: String(metric.count)
117989
+ }))), metric.description && /*#__PURE__*/ React.createElement("div", {
117990
+ style: {
117991
+ marginTop: 6,
117992
+ fontSize: 12,
117993
+ color: theme.colors.mutedForeground
117994
+ }
117995
+ }, metric.description)), metric.nodes.length > 0 && /*#__PURE__*/ React.createElement(Collapse, {
117996
+ items: items,
117997
+ bordered: false,
117998
+ style: {
117999
+ background: theme.colors.card
118000
+ }
118001
+ }));
118002
+ };
118003
+ const NumericalAggregateView = ({ metrics, onAgentNodeClick, onOpenVisualizer })=>{
117485
118004
  const { theme } = useTheme$1();
117486
118005
  if (!metrics.length) {
117487
118006
  return /*#__PURE__*/ React.createElement("div", {
@@ -117491,7 +118010,7 @@ const JudgeAggregateView = ({ metrics, onAgentNodeClick, onOpenVisualizer })=>{
117491
118010
  color: theme.colors.mutedForeground,
117492
118011
  fontSize: 14
117493
118012
  }
117494
- }, "No judge metrics available");
118013
+ }, "No numerical metrics available");
117495
118014
  }
117496
118015
  return /*#__PURE__*/ React.createElement("div", {
117497
118016
  style: {
@@ -117504,7 +118023,7 @@ const JudgeAggregateView = ({ metrics, onAgentNodeClick, onOpenVisualizer })=>{
117504
118023
  fontSize: 16,
117505
118024
  fontWeight: 600
117506
118025
  }
117507
- }, "Judge Evaluator - Aggregate View"), /*#__PURE__*/ React.createElement("div", {
118026
+ }, "Custom Evaluator - Aggregate View"), /*#__PURE__*/ React.createElement("div", {
117508
118027
  style: {
117509
118028
  display: "flex",
117510
118029
  flexDirection: "column",
@@ -117522,7 +118041,10 @@ function detectAggregateType(nodes) {
117522
118041
  const values = Object.values(nodes);
117523
118042
  if (values.some((n)=>n?.type === "ToolAggregate")) return "ToolUse";
117524
118043
  if (values.some((n)=>n?.type === "LLMInferenceAggregate")) return "LLMInference";
117525
- if (values.some((n)=>n?.type === "CategoricalAggregate")) return "Judge";
118044
+ // Categorical covers the built-in JudgeEvaluator and any custom evaluator with categorical metrics.
118045
+ if (values.some((n)=>n?.type === "CategoricalAggregate")) return "Categorical";
118046
+ // Custom numerical evaluators (anything that isn't ToolUse/LLMInference/categorical) emit NumericalAggregate.
118047
+ if (values.some((n)=>n?.type === "NumericalAggregate")) return "Numerical";
117526
118048
  return null;
117527
118049
  }
117528
118050
  function buildLLMInferenceFlatRows(nodes) {
@@ -117564,7 +118086,8 @@ function formatAggregateValue(value, metricName) {
117564
118086
  const DEFAULT_TITLES = {
117565
118087
  ToolUse: "Tool Use Evaluator - Aggregate View",
117566
118088
  LLMInference: "LLM Inference Evaluator - Aggregate View",
117567
- Judge: "Judge Evaluator - Aggregate View"
118089
+ Categorical: "Categorical Evaluator - Aggregate View",
118090
+ Numerical: "Custom Evaluator - Aggregate View"
117568
118091
  };
117569
118092
  const AggregateResultsTable = ({ rawResults = [], aggregateResults, agents, title, evaluatorName, onAgentNodeClick, onOpenVisualizer })=>{
117570
118093
  const { theme } = useTheme$1();
@@ -117606,10 +118129,23 @@ const AggregateResultsTable = ({ rawResults = [], aggregateResults, agents, titl
117606
118129
  llmExpandableKeys
117607
118130
  };
117608
118131
  }
117609
- if (type === "Judge") {
118132
+ if (type === "Categorical") {
117610
118133
  return {
117611
118134
  aggregateType: type,
117612
- dataSource: buildJudgeMetricsFromAggregate({
118135
+ dataSource: buildCategoricalMetricsFromAggregate({
118136
+ roots: aggregateResults.roots,
118137
+ nodes: aggregateResults.nodes,
118138
+ agents,
118139
+ rawResults
118140
+ }),
118141
+ llmIsTree: false,
118142
+ llmExpandableKeys: []
118143
+ };
118144
+ }
118145
+ if (type === "Numerical") {
118146
+ return {
118147
+ aggregateType: type,
118148
+ dataSource: buildNumericalMetricsFromAggregate({
117613
118149
  roots: aggregateResults.roots,
117614
118150
  nodes: aggregateResults.nodes,
117615
118151
  agents,
@@ -117935,8 +118471,21 @@ const AggregateResultsTable = ({ rawResults = [], aggregateResults, agents, titl
117935
118471
  }
117936
118472
  }));
117937
118473
  }
117938
- if (aggregateType === "Judge") {
117939
- return /*#__PURE__*/ React.createElement(JudgeAggregateView, {
118474
+ if (aggregateType === "Categorical") {
118475
+ // JudgeEvaluator keeps its branding; any other (custom) categorical evaluator
118476
+ // renders through the same view with neutral categorical branding.
118477
+ const isJudge = (evaluatorName ?? "").includes("Judge");
118478
+ return /*#__PURE__*/ React.createElement(CategoricalAggregateView, {
118479
+ metrics: dataSource,
118480
+ title: title ?? (isJudge ? "Judge Evaluator - Aggregate View" : "Custom Evaluator - Aggregate View"),
118481
+ icon: isJudge ? Scale : Tags,
118482
+ emptyLabel: isJudge ? "No judge metrics available" : "No categorical metrics available",
118483
+ onAgentNodeClick: onAgentNodeClick,
118484
+ onOpenVisualizer: onOpenVisualizer
118485
+ });
118486
+ }
118487
+ if (aggregateType === "Numerical") {
118488
+ return /*#__PURE__*/ React.createElement(NumericalAggregateView, {
117940
118489
  metrics: dataSource,
117941
118490
  onAgentNodeClick: onAgentNodeClick,
117942
118491
  onOpenVisualizer: onOpenVisualizer
@@ -118203,7 +118752,8 @@ function isCategoricalMetric(def) {
118203
118752
  const aggregateTypes = [
118204
118753
  "ToolAggregate",
118205
118754
  "LLMInferenceAggregate",
118206
- "CategoricalAggregate"
118755
+ "CategoricalAggregate",
118756
+ "NumericalAggregate"
118207
118757
  ];
118208
118758
  const aggregateItems = Object.values(nodes).filter((n)=>n?.type && aggregateTypes.includes(n.type));
118209
118759
  return [