agentic-ui-libs 1.2.0-beta.2 → 1.2.0-beta.21

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.
Files changed (76) hide show
  1. package/dist/assets/agentic-ui-libs.css +78 -4
  2. package/dist/features/dashboard/AnalyticsChart.d.ts.map +1 -1
  3. package/dist/features/dashboard/Dashboard.d.ts.map +1 -1
  4. package/dist/features/dashboard/DashboardSection.d.ts.map +1 -1
  5. package/dist/features/dashboard/MetricCard.d.ts.map +1 -1
  6. package/dist/features/dashboard/ModelListView.d.ts +1 -0
  7. package/dist/features/dashboard/ModelListView.d.ts.map +1 -1
  8. package/dist/features/dashboard/ToolListView.d.ts.map +1 -1
  9. package/dist/features/debug-logs/DebugPanel.d.ts.map +1 -1
  10. package/dist/features/debug-logs/components/DebugCard.d.ts.map +1 -1
  11. package/dist/features/debug-logs/index.d.ts +1 -1
  12. package/dist/features/debug-logs/index.d.ts.map +1 -1
  13. package/dist/features/debug-logs/services/ApiService.d.ts.map +1 -1
  14. package/dist/features/debug-logs/services/TreeBuilder.d.ts +3 -3
  15. package/dist/features/debug-logs/services/TreeBuilder.d.ts.map +1 -1
  16. package/dist/features/debug-logs/types.d.ts +13 -2
  17. package/dist/features/debug-logs/types.d.ts.map +1 -1
  18. package/dist/features/md-editor/MDEditor.d.ts.map +1 -1
  19. package/dist/features/md-editor/components/AIDesignPanel.d.ts.map +1 -1
  20. package/dist/features/md-editor/components/EmptyStatePlaceholder.d.ts +21 -0
  21. package/dist/features/md-editor/components/EmptyStatePlaceholder.d.ts.map +1 -0
  22. package/dist/features/md-editor/components/UnifiedToolbar.d.ts +4 -0
  23. package/dist/features/md-editor/components/UnifiedToolbar.d.ts.map +1 -1
  24. package/dist/features/md-editor/components/VariableMenu.d.ts.map +1 -1
  25. package/dist/features/md-editor/components/icons/CategoryIcons.d.ts +1 -0
  26. package/dist/features/md-editor/components/icons/CategoryIcons.d.ts.map +1 -1
  27. package/dist/features/md-editor/components/index.d.ts +2 -0
  28. package/dist/features/md-editor/components/index.d.ts.map +1 -1
  29. package/dist/features/md-editor/hooks/useAIRefinementSession.d.ts +3 -1
  30. package/dist/features/md-editor/hooks/useAIRefinementSession.d.ts.map +1 -1
  31. package/dist/features/md-editor/index.d.ts +1 -1
  32. package/dist/features/md-editor/index.d.ts.map +1 -1
  33. package/dist/features/md-editor/types.d.ts +58 -2
  34. package/dist/features/md-editor/types.d.ts.map +1 -1
  35. package/dist/features/md-editor/utils/index.d.ts +1 -0
  36. package/dist/features/md-editor/utils/index.d.ts.map +1 -1
  37. package/dist/features/md-editor/utils/variableContext.d.ts +38 -0
  38. package/dist/features/md-editor/utils/variableContext.d.ts.map +1 -0
  39. package/dist/features/tracing/components/SessionsList.d.ts.map +1 -1
  40. package/dist/features/tracing/components/TracesList.d.ts.map +1 -1
  41. package/dist/features/tracing/components/detail/DetailPage.d.ts +1 -1
  42. package/dist/features/tracing/components/detail/DetailPage.d.ts.map +1 -1
  43. package/dist/features/tracing/components/detail/NodeDetailPanel.d.ts +1 -1
  44. package/dist/features/tracing/components/detail/NodeDetailPanel.d.ts.map +1 -1
  45. package/dist/features/tracing/components/detail/ObservationNode.d.ts.map +1 -1
  46. package/dist/features/tracing/components/detail/TraceTree.d.ts +1 -1
  47. package/dist/features/tracing/components/detail/TraceTree.d.ts.map +1 -1
  48. package/dist/features/tracing/components/detail/config/observationFilterConfig.d.ts.map +1 -1
  49. package/dist/features/tracing/components/detail/services/DetailPageService.d.ts.map +1 -1
  50. package/dist/features/tracing/components/detail/types.d.ts +22 -0
  51. package/dist/features/tracing/components/detail/types.d.ts.map +1 -1
  52. package/dist/features/tracing/components/shared/CopyableId.d.ts +11 -0
  53. package/dist/features/tracing/components/shared/CopyableId.d.ts.map +1 -0
  54. package/dist/features/tracing/components/shared/TracingListHeader.d.ts +2 -1
  55. package/dist/features/tracing/components/shared/TracingListHeader.d.ts.map +1 -1
  56. package/dist/features/tracing/components/shared/TracingTable.d.ts.map +1 -1
  57. package/dist/features/tracing/components/shared/index.d.ts +1 -0
  58. package/dist/features/tracing/components/shared/index.d.ts.map +1 -1
  59. package/dist/features/tracing/services/TraceTreeService.d.ts +39 -2
  60. package/dist/features/tracing/services/TraceTreeService.d.ts.map +1 -1
  61. package/dist/features/tracing/services/TracingApiService.d.ts +13 -1
  62. package/dist/features/tracing/services/TracingApiService.d.ts.map +1 -1
  63. package/dist/features/tracing/types.d.ts +10 -0
  64. package/dist/features/tracing/types.d.ts.map +1 -1
  65. package/dist/index.angular.d.ts +1 -1
  66. package/dist/index.angular.d.ts.map +1 -1
  67. package/dist/index.d.ts +1 -1
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +2089 -788
  70. package/dist/lib/dashboard-api.service.d.ts +1 -0
  71. package/dist/lib/dashboard-api.service.d.ts.map +1 -1
  72. package/dist/shared/types/index.d.ts +7 -0
  73. package/dist/shared/types/index.d.ts.map +1 -1
  74. package/dist/shared/ui/DataViewer.d.ts.map +1 -1
  75. package/dist/ui-libs.umd.js +2089 -788
  76. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -4291,7 +4291,7 @@ const MetricCard = ({
4291
4291
  onClick,
4292
4292
  isFirst = false
4293
4293
  }) => {
4294
- const { title, value, change, info, highlighted } = data;
4294
+ const { title, value, change, info, highlighted, failedCount } = data;
4295
4295
  const formatValue2 = (val) => {
4296
4296
  if (typeof val === "number") {
4297
4297
  return val.toLocaleString();
@@ -4345,6 +4345,11 @@ const MetricCard = ({
4345
4345
  ] }),
4346
4346
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-3", "data-test-id": `dashboard_metric_card_value_container_${data.metricType || data.title.toLowerCase().replace(/\s+/g, "_")}`, children: [
4347
4347
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl font-semibold text-gray-900", "data-test-id": `dashboard_metric_card_value_${data.metricType || data.title.toLowerCase().replace(/\s+/g, "_")}`, children: formatValue2(value) }),
4348
+ (failedCount ?? 0) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-medium text-red-500", "data-test-id": `dashboard_metric_card_failed_${data.metricType}`, children: [
4349
+ "(",
4350
+ failedCount,
4351
+ " failed)"
4352
+ ] }),
4348
4353
  change && /* @__PURE__ */ jsxRuntimeExports.jsxs(
4349
4354
  "div",
4350
4355
  {
@@ -21355,7 +21360,7 @@ function _toPrimitive$g(t2, r2) {
21355
21360
  if ("object" != _typeof$i(i2)) return i2;
21356
21361
  throw new TypeError("@@toPrimitive must return a primitive value.");
21357
21362
  }
21358
- return ("string" === r2 ? String : Number)(t2);
21363
+ return String(t2);
21359
21364
  }
21360
21365
  var Bar = /* @__PURE__ */ function(_PureComponent) {
21361
21366
  function Bar2() {
@@ -28662,7 +28667,7 @@ const CustomTooltip = ({
28662
28667
  return null;
28663
28668
  }
28664
28669
  const filteredPayload = payload.filter(
28665
- (entry) => entry.name && entry.name !== "" && entry.name !== entry.dataKey
28670
+ (entry) => entry.name && entry.name !== "" && entry.name !== entry.dataKey && entry.value != null && !(typeof entry.value === "number" && Number.isNaN(entry.value)) && !(entry.dataKey === "failedModelRuns" && Number(entry.value) === 0)
28666
28671
  );
28667
28672
  if (filteredPayload.length === 0) {
28668
28673
  return null;
@@ -28762,6 +28767,7 @@ const AnalyticsChart = ({
28762
28767
  agentRuns: 0,
28763
28768
  toolRuns: 0,
28764
28769
  modelRuns: 0,
28770
+ failedModelRuns: null,
28765
28771
  codeTools: 0,
28766
28772
  workflowTools: 0,
28767
28773
  knowledgeTools: 0,
@@ -28864,6 +28870,8 @@ const AnalyticsChart = ({
28864
28870
  label: config2.title,
28865
28871
  strokeWidth: 2
28866
28872
  }];
28873
+ const lineSeries = chartLines.filter((c3) => (c3.seriesType ?? "line") === "line");
28874
+ const barSeries = chartLines.filter((c3) => c3.seriesType === "bar");
28867
28875
  if (isLoading) {
28868
28876
  console.log("AnalyticsChart: Loading state active");
28869
28877
  return /* @__PURE__ */ jsxRuntimeExports.jsx(ChartSkeleton, { className, chartType: config2.type, height });
@@ -28970,7 +28978,7 @@ const AnalyticsChart = ({
28970
28978
  bottom: 20
28971
28979
  },
28972
28980
  children: [
28973
- /* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: chartLines.map((lineConfig, index) => /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: `gradient-${lineConfig.dataKey}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [
28981
+ /* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: lineSeries.map((lineConfig, index) => /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: `gradient-${lineConfig.dataKey}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [
28974
28982
  /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "5%", stopColor: lineConfig.color, stopOpacity: 0.08 }),
28975
28983
  /* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "95%", stopColor: lineConfig.color, stopOpacity: 0.01 })
28976
28984
  ] }, `gradient-${index}`)) }),
@@ -29022,7 +29030,7 @@ const AnalyticsChart = ({
29022
29030
  allowEscapeViewBox: { x: false, y: false }
29023
29031
  }
29024
29032
  ),
29025
- chartLines.map((lineConfig) => /* @__PURE__ */ jsxRuntimeExports.jsx(
29033
+ lineSeries.map((lineConfig) => /* @__PURE__ */ jsxRuntimeExports.jsx(
29026
29034
  Area,
29027
29035
  {
29028
29036
  type: "monotone",
@@ -29030,12 +29038,13 @@ const AnalyticsChart = ({
29030
29038
  stroke: "none",
29031
29039
  fill: `url(#gradient-${lineConfig.dataKey})`,
29032
29040
  fillOpacity: 1,
29041
+ connectNulls: false,
29033
29042
  isAnimationActive: false,
29034
29043
  name: ""
29035
29044
  },
29036
29045
  `area-${lineConfig.dataKey}`
29037
29046
  )),
29038
- chartLines.map((lineConfig) => /* @__PURE__ */ jsxRuntimeExports.jsx(
29047
+ lineSeries.map((lineConfig) => /* @__PURE__ */ jsxRuntimeExports.jsx(
29039
29048
  Line,
29040
29049
  {
29041
29050
  type: "monotone",
@@ -29043,6 +29052,7 @@ const AnalyticsChart = ({
29043
29052
  stroke: lineConfig.color,
29044
29053
  strokeWidth: 2.5,
29045
29054
  strokeDasharray: lineConfig.strokeDasharray,
29055
+ connectNulls: false,
29046
29056
  dot: false,
29047
29057
  activeDot: {
29048
29058
  r: 5,
@@ -29053,6 +29063,19 @@ const AnalyticsChart = ({
29053
29063
  name: lineConfig.label
29054
29064
  },
29055
29065
  lineConfig.dataKey
29066
+ )),
29067
+ barSeries.map((lineConfig) => /* @__PURE__ */ jsxRuntimeExports.jsx(
29068
+ Bar,
29069
+ {
29070
+ dataKey: lineConfig.dataKey,
29071
+ fill: lineConfig.color,
29072
+ fillOpacity: 0.9,
29073
+ name: lineConfig.label,
29074
+ maxBarSize: 14,
29075
+ radius: [3, 3, 0, 0],
29076
+ isAnimationActive: false
29077
+ },
29078
+ `bar-${lineConfig.dataKey}`
29056
29079
  ))
29057
29080
  ]
29058
29081
  }
@@ -29074,8 +29097,15 @@ const AnalyticsChart = ({
29074
29097
  })
29075
29098
  ] })
29076
29099
  ] }) }),
29077
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-4", "data-test-id": "dashboard_analytics_chart_legend", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-4 text-sm text-muted-foreground", "data-test-id": "dashboard_analytics_chart_legend_items", children: chartLines.map((lineConfig) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", "data-test-id": `dashboard_analytics_chart_legend_item_${lineConfig.dataKey}`, children: [
29078
- /* @__PURE__ */ jsxRuntimeExports.jsx(
29100
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-4", "data-test-id": "dashboard_analytics_chart_legend", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-4 text-sm text-muted-foreground", "data-test-id": "dashboard_analytics_chart_legend_items", children: chartLines.filter((lineConfig) => !lineConfig.hideInLegend).map((lineConfig) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", "data-test-id": `dashboard_analytics_chart_legend_item_${lineConfig.dataKey}`, children: [
29101
+ lineConfig.seriesType === "bar" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
29102
+ "div",
29103
+ {
29104
+ className: "w-2 h-2 rounded-[2px]",
29105
+ style: { backgroundColor: lineConfig.color },
29106
+ "data-test-id": `dashboard_analytics_chart_legend_color_${lineConfig.dataKey}`
29107
+ }
29108
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
29079
29109
  "div",
29080
29110
  {
29081
29111
  className: "w-[8px] h-[8px] rounded-full",
@@ -29632,6 +29662,8 @@ function getToolTypeStyle(type) {
29632
29662
  return "bg-green-100 text-green-800 border-green-200";
29633
29663
  if (["knowledge", "KNOWLEDGE", "knowledge tool"].includes(type) || ["knowledge", "knowledge tool"].includes(normalized))
29634
29664
  return "bg-purple-100 text-purple-800 border-purple-200";
29665
+ if (["PRE_PROCESSOR", "POST_PROCESSOR", "INPUT_PROCESSOR", "input_processor", "pre_processor", "post_processor", "processor"].includes(type) || ["pre_processor", "post_processor", "processor", "input_processor"].includes(normalized))
29666
+ return "bg-yellow-100 text-yellow-800 border-yellow-200";
29635
29667
  return "bg-gray-100 text-gray-800 border-gray-200";
29636
29668
  }
29637
29669
  function getToolTypeName(type) {
@@ -29640,6 +29672,8 @@ function getToolTypeName(type) {
29640
29672
  if (["toollibrary", "workflow tool"].includes(normalized)) return "Workflow Tool";
29641
29673
  if (["mcp", "mcptool"].includes(normalized)) return "MCP Tool";
29642
29674
  if (["knowledge", "knowledge tool", "knowledge"].includes(normalized) || type === "KNOWLEDGE") return "Knowledge";
29675
+ if (["pre_processor", "post_processor", "processor", "input_processor"].includes(normalized) || type === "PRE_PROCESSOR" || type === "POST_PROCESSOR" || type === "INPUT_PROCESSOR" || type === "input_processor")
29676
+ return "Processor";
29643
29677
  if (type === "inlineTool") return "Code Tool";
29644
29678
  if (type === "toolLibrary") return "Workflow Tool";
29645
29679
  if (type === "KNOWLEDGE") return "Knowledge";
@@ -29866,7 +29900,14 @@ const ModelListView = ({
29866
29900
  model.provider && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-gray-500 truncate", "data-test-id": `dashboard_model_list_view_row_provider_${index}`, children: getProviderDisplayName(model.provider) })
29867
29901
  ] })
29868
29902
  ] }),
29869
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center font-medium text-xs text-gray-700", "data-test-id": `dashboard_model_list_view_row_runs_${index}`, children: formatValue2(model.runs || 0) }),
29903
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center font-medium text-xs text-gray-700 flex items-center justify-center gap-1", "data-test-id": `dashboard_model_list_view_row_runs_${index}`, children: [
29904
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: formatValue2(model.runs || 0) }),
29905
+ (model.failedRuns ?? 0) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-red-500 text-[10px] font-medium", "data-test-id": `dashboard_model_list_view_row_failed_${index}`, children: [
29906
+ "(",
29907
+ model.failedRuns,
29908
+ " failed)"
29909
+ ] })
29910
+ ] }),
29870
29911
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center font-medium text-xs text-gray-700", "data-test-id": `dashboard_model_list_view_row_tokens_${index}`, children: formatValue2(model.tokens || model.totalTokens || 0) }),
29871
29912
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center font-medium text-xs text-gray-700", "data-test-id": `dashboard_model_list_view_row_response_time_${index}`, children: model.responseTime || (model.avgResponseTime ? `${model.avgResponseTime}ms` : "N/A") })
29872
29913
  ]
@@ -30546,6 +30587,7 @@ class DashboardApiService {
30546
30587
  {
30547
30588
  title: "Model Runs",
30548
30589
  value: data.data.modelRuns,
30590
+ failedCount: data.data.failedModelRuns || 0,
30549
30591
  metricType: "modelRuns",
30550
30592
  icon: "cpu",
30551
30593
  info: "Number of times the AI agents called various language models to generate responses",
@@ -30622,8 +30664,12 @@ class DashboardApiService {
30622
30664
  basePoint.toolRuns = point2.count || 0;
30623
30665
  break;
30624
30666
  case "modelRuns":
30667
+ case "modelruns": {
30668
+ const failed = point2.failedModelRuns;
30625
30669
  basePoint.modelRuns = point2.count || 0;
30670
+ basePoint.failedModelRuns = typeof failed === "number" && failed >= 0 ? failed : 0;
30626
30671
  break;
30672
+ }
30627
30673
  default:
30628
30674
  basePoint.users = point2.count || 0;
30629
30675
  basePoint.sessions = point2.count || 0;
@@ -30632,6 +30678,10 @@ class DashboardApiService {
30632
30678
  basePoint.agentRuns = point2.count || 0;
30633
30679
  basePoint.toolRuns = point2.count || 0;
30634
30680
  basePoint.modelRuns = point2.count || 0;
30681
+ {
30682
+ const failed = point2.failedModelRuns;
30683
+ basePoint.failedModelRuns = typeof failed === "number" && failed >= 0 ? failed : 0;
30684
+ }
30635
30685
  }
30636
30686
  console.log(`Transformed point ${index} for metric ${metricType}:`, basePoint);
30637
30687
  return basePoint;
@@ -30716,22 +30766,16 @@ class DashboardApiService {
30716
30766
  id: `model-${index + 1}`,
30717
30767
  name: item.connectionName ? `${item.modelName} - ${item.connectionName}` : item.modelName || `Model ${index + 1}`,
30718
30768
  modelName: item.modelName,
30719
- // Keep original modelName field
30720
30769
  provider: item.provider,
30721
- // Include provider information
30722
30770
  runs: item.count || 0,
30771
+ failedRuns: item.failedRuns || 0,
30723
30772
  responseTime: item.avgResponseTime ? item.avgResponseTime < 1e3 ? `${Math.round(item.avgResponseTime)}ms` : `${(item.avgResponseTime / 1e3).toFixed(2)}s` : "0ms",
30724
30773
  avgResponseTime: item.avgResponseTime,
30725
- // Keep original avgResponseTime
30726
30774
  tokens: item.tokens || item.totalTokens || Math.floor((item.count || 0) * 300),
30727
- // Use actual token data when available
30728
30775
  totalTokens: item.totalTokens || item.tokens,
30729
- // Include totalTokens field
30730
30776
  successRate: item.successRate ? `${Math.round(item.successRate)}%` : "98%",
30731
- // Default success rate for models
30732
30777
  lastRun: item.lastRun || new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1e3).toLocaleDateString(),
30733
30778
  icon: item.icon
30734
- // Preserve original icon data if available
30735
30779
  }));
30736
30780
  }
30737
30781
  // Extract control options from listView data for agents
@@ -30785,9 +30829,11 @@ class DashboardApiService {
30785
30829
  if (["toollibrary", "workflow tool"].includes(normalized)) return "Workflow Tool";
30786
30830
  if (["mcp", "mcptool"].includes(normalized)) return "MCP Tool";
30787
30831
  if (["knowledge", "knowledge tool"].includes(normalized) || toolType === "KNOWLEDGE") return "Knowledge";
30832
+ if (["pre_processor", "post_processor", "processor", "input_processor"].includes(normalized)) return "Processor";
30788
30833
  if (toolType === "inlineTool") return "Code Tool";
30789
30834
  if (toolType === "toolLibrary") return "Workflow Tool";
30790
30835
  if (toolType === "MCP" || toolType === "mcpTool") return "MCP Tool";
30836
+ if (toolType === "PRE_PROCESSOR" || toolType === "POST_PROCESSOR" || toolType === "INPUT_PROCESSOR" || toolType === "input_processor") return "Processor";
30791
30837
  return "Code Tool";
30792
30838
  };
30793
30839
  options.push({
@@ -30860,7 +30906,7 @@ class DashboardApiService {
30860
30906
  listViewData.forEach((item) => {
30861
30907
  if (item.modelName) {
30862
30908
  options.push({
30863
- label: item.modelName,
30909
+ label: item.connectionName ? `${item.modelName} - ${item.connectionName}` : item.modelName,
30864
30910
  value: item.modelName.replace(/[-\.]/g, ""),
30865
30911
  icon: getModelIconPath2(item.provider),
30866
30912
  // Use actual SVG icon path
@@ -30914,6 +30960,7 @@ class DashboardApiService {
30914
30960
  if (aggregated.has(key)) {
30915
30961
  const existing = aggregated.get(key);
30916
30962
  existing.count = (existing.count || 0) + (item.count || 0);
30963
+ existing.failedRuns = (existing.failedRuns || 0) + (item.failedRuns || 0);
30917
30964
  existing.avgResponseTime = existing.avgResponseTime && item.avgResponseTime ? (existing.avgResponseTime + item.avgResponseTime) / 2 : existing.avgResponseTime || item.avgResponseTime;
30918
30965
  existing.tokens = (existing.tokens || 0) + (item.tokens || 0);
30919
30966
  } else {
@@ -30925,11 +30972,24 @@ class DashboardApiService {
30925
30972
  // Batch fetch enhanced data for all metrics with table and control data
30926
30973
  async fetchEnhancedMetricsData(fromTimestamp, toTimestamp, timeDimension, filters = []) {
30927
30974
  try {
30928
- const [agentsData, toolsData, modelsData] = await Promise.all([
30975
+ const results = await Promise.allSettled([
30929
30976
  this.fetchTimeSeriesDataWithTableData("agent-runs", "runs", fromTimestamp, toTimestamp, timeDimension, filters),
30930
30977
  this.fetchTimeSeriesDataWithTableData("tool-runs", "runs", fromTimestamp, toTimestamp, timeDimension, filters),
30931
30978
  this.fetchTimeSeriesDataWithTableData("model-runs", "runs", fromTimestamp, toTimestamp, timeDimension, filters)
30932
30979
  ]);
30980
+ if (results[0].status === "rejected") {
30981
+ console.error("Error fetching agent runs enhanced data:", results[0].reason);
30982
+ }
30983
+ if (results[1].status === "rejected") {
30984
+ console.error("Error fetching tool runs enhanced data:", results[1].reason);
30985
+ }
30986
+ if (results[2].status === "rejected") {
30987
+ console.error("Error fetching model runs enhanced data:", results[2].reason);
30988
+ }
30989
+ const emptyData = { chartData: [], tableData: [], controlOptions: [] };
30990
+ const agentsData = results[0].status === "fulfilled" ? results[0].value : emptyData;
30991
+ const toolsData = results[1].status === "fulfilled" ? results[1].value : emptyData;
30992
+ const modelsData = results[2].status === "fulfilled" ? results[2].value : emptyData;
30933
30993
  return {
30934
30994
  agents: agentsData,
30935
30995
  tools: toolsData,
@@ -30946,13 +31006,30 @@ class DashboardApiService {
30946
31006
  const getChangeType = (changePercent) => {
30947
31007
  return changePercent > 0 ? "increase" : "decrease";
30948
31008
  };
30949
- const [agentsData, toolsData, modelsData, toolRunsTimeSeriesData] = await Promise.all([
31009
+ const results = await Promise.allSettled([
30950
31010
  this.fetchTimeSeriesDataWithTableData("agent-runs", "runs", fromTimestamp, toTimestamp, timeDimension, filters),
30951
31011
  this.fetchTimeSeriesDataWithTableData("tool-runs", "runs", fromTimestamp, toTimestamp, timeDimension, filters),
30952
31012
  this.fetchTimeSeriesDataWithTableData("model-runs", "runs", fromTimestamp, toTimestamp, timeDimension, filters),
30953
31013
  this.fetchTimeSeriesData("tool-runs", "runs", fromTimestamp, toTimestamp, timeDimension, filters)
30954
31014
  ]);
30955
- const enhancedToolRunsChartData = this.transformTimeSeriesDataForToolRuns(toolRunsTimeSeriesData);
31015
+ if (results[0].status === "rejected") {
31016
+ console.error("Error fetching agent runs data:", results[0].reason);
31017
+ }
31018
+ if (results[1].status === "rejected") {
31019
+ console.error("Error fetching tool runs data:", results[1].reason);
31020
+ }
31021
+ if (results[2].status === "rejected") {
31022
+ console.error("Error fetching model runs data:", results[2].reason);
31023
+ }
31024
+ if (results[3].status === "rejected") {
31025
+ console.error("Error fetching tool runs time series data:", results[3].reason);
31026
+ }
31027
+ const emptyEnhancedData = { chartData: [], tableData: [], controlOptions: [] };
31028
+ const agentsData = results[0].status === "fulfilled" ? results[0].value : emptyEnhancedData;
31029
+ const toolsData = results[1].status === "fulfilled" ? results[1].value : emptyEnhancedData;
31030
+ const modelsData = results[2].status === "fulfilled" ? results[2].value : emptyEnhancedData;
31031
+ const toolRunsTimeSeriesData = results[3].status === "fulfilled" ? results[3].value : void 0;
31032
+ const enhancedToolRunsChartData = toolRunsTimeSeriesData ? this.transformTimeSeriesDataForToolRuns(toolRunsTimeSeriesData) : [];
30956
31033
  return [
30957
31034
  {
30958
31035
  title: "Agent Runs",
@@ -30966,68 +31043,70 @@ class DashboardApiService {
30966
31043
  value: Math.abs(trends.agentRuns.changePercent),
30967
31044
  type: getChangeType(trends.agentRuns.changePercent)
30968
31045
  } : void 0,
30969
- view: {
30970
- type: "chart",
30971
- chart: {
30972
- type: "line",
30973
- title: "Agent Runs",
30974
- data: agentsData.chartData,
30975
- dataKey: "agentRuns",
30976
- color: "#0BA5EC",
30977
- yAxisLabel: "Number of Agent Runs",
30978
- height: 300,
30979
- showGrid: true,
30980
- curve: "monotone",
30981
- tooltip: { show: true, style: "dark" },
30982
- dateRange: {
30983
- start: fromTimestamp.split("T")[0],
30984
- end: toTimestamp.split("T")[0]
30985
- }
30986
- },
30987
- table: {
30988
- title: "Agent Runs",
30989
- data: agentsData.tableData,
30990
- columns: [
30991
- {
30992
- key: "name",
30993
- title: "Name",
30994
- width: 200,
30995
- align: "left"
30996
- },
30997
- {
30998
- key: "runs",
30999
- title: "Runs",
31000
- width: 100,
31001
- align: "right",
31002
- formatter: (value) => `${Math.floor(value / 1e3)}k`
31003
- },
31004
- {
31005
- key: "responseTime",
31006
- title: "Response Time",
31007
- width: 120,
31008
- align: "right"
31009
- },
31010
- {
31011
- key: "tokens",
31012
- title: "Tokens",
31013
- width: 100,
31014
- align: "right",
31015
- formatter: (value) => `${Math.floor(value / 1e3)}k`
31046
+ ...agentsData && {
31047
+ view: {
31048
+ type: "chart",
31049
+ chart: {
31050
+ type: "line",
31051
+ title: "Agent Runs",
31052
+ data: agentsData.chartData,
31053
+ dataKey: "agentRuns",
31054
+ color: "#0BA5EC",
31055
+ yAxisLabel: "Number of Agent Runs",
31056
+ height: 300,
31057
+ showGrid: true,
31058
+ curve: "monotone",
31059
+ tooltip: { show: true, style: "dark" },
31060
+ dateRange: {
31061
+ start: fromTimestamp.split("T")[0],
31062
+ end: toTimestamp.split("T")[0]
31016
31063
  }
31017
- ]
31018
- }
31019
- },
31020
- controls: {
31021
- dropdown: {
31022
- label: "All Agents",
31023
- options: agentsData.controlOptions,
31024
- defaultValue: ["all"],
31025
- multiSelect: true,
31026
- searchable: true
31064
+ },
31065
+ table: {
31066
+ title: "Agent Runs",
31067
+ data: agentsData.tableData,
31068
+ columns: [
31069
+ {
31070
+ key: "name",
31071
+ title: "Name",
31072
+ width: 200,
31073
+ align: "left"
31074
+ },
31075
+ {
31076
+ key: "runs",
31077
+ title: "Runs",
31078
+ width: 100,
31079
+ align: "right",
31080
+ formatter: (value) => `${Math.floor(value / 1e3)}k`
31081
+ },
31082
+ {
31083
+ key: "responseTime",
31084
+ title: "Response Time",
31085
+ width: 120,
31086
+ align: "right"
31087
+ },
31088
+ {
31089
+ key: "tokens",
31090
+ title: "Tokens",
31091
+ width: 100,
31092
+ align: "right",
31093
+ formatter: (value) => `${Math.floor(value / 1e3)}k`
31094
+ }
31095
+ ]
31096
+ }
31027
31097
  },
31028
- toggle: {
31029
- chartView: true,
31030
- tableView: true
31098
+ controls: {
31099
+ dropdown: {
31100
+ label: "All Agents",
31101
+ options: agentsData.controlOptions,
31102
+ defaultValue: ["all"],
31103
+ multiSelect: true,
31104
+ searchable: true
31105
+ },
31106
+ toggle: {
31107
+ chartView: true,
31108
+ tableView: true
31109
+ }
31031
31110
  }
31032
31111
  }
31033
31112
  },
@@ -31042,99 +31121,107 @@ class DashboardApiService {
31042
31121
  value: Math.abs(trends.toolRuns.changePercent.total),
31043
31122
  type: getChangeType(trends.toolRuns.changePercent.total)
31044
31123
  } : void 0,
31045
- view: {
31046
- type: "chart",
31047
- chart: {
31048
- type: "line",
31049
- title: "Tool Runs",
31050
- data: enhancedToolRunsChartData,
31051
- yAxisLabel: "Number of Tool Runs",
31052
- lines: [
31053
- {
31054
- dataKey: "toolRuns",
31055
- color: "#667085",
31056
- label: "Tool Runs"
31057
- },
31058
- {
31059
- dataKey: "codeTools",
31060
- color: "#F38744",
31061
- label: "Code Tools"
31062
- },
31063
- {
31064
- dataKey: "workflowTools",
31065
- color: "#2970FF",
31066
- label: "Workflow Tools"
31067
- },
31068
- {
31069
- dataKey: "knowledgeTools",
31070
- color: "#7A5AF8",
31071
- label: "Knowledge"
31072
- },
31073
- {
31074
- dataKey: "mcpTools",
31075
- color: "#47CD89",
31076
- label: "MCP Tools"
31124
+ ...toolsData && {
31125
+ view: {
31126
+ type: "chart",
31127
+ chart: {
31128
+ type: "line",
31129
+ title: "Tool Runs",
31130
+ data: enhancedToolRunsChartData,
31131
+ yAxisLabel: "Number of Tool Runs",
31132
+ lines: [
31133
+ {
31134
+ dataKey: "toolRuns",
31135
+ color: "#667085",
31136
+ label: "Tool Runs"
31137
+ },
31138
+ {
31139
+ dataKey: "codeTools",
31140
+ color: "#F38744",
31141
+ label: "Code Tools"
31142
+ },
31143
+ {
31144
+ dataKey: "workflowTools",
31145
+ color: "#2970FF",
31146
+ label: "Workflow Tools"
31147
+ },
31148
+ {
31149
+ dataKey: "knowledgeTools",
31150
+ color: "#7A5AF8",
31151
+ label: "Knowledge"
31152
+ },
31153
+ {
31154
+ dataKey: "mcpTools",
31155
+ color: "#47CD89",
31156
+ label: "MCP Tools"
31157
+ },
31158
+ {
31159
+ dataKey: "processors",
31160
+ color: "#EAB308",
31161
+ label: "Processors"
31162
+ }
31163
+ ],
31164
+ height: 300,
31165
+ showGrid: true,
31166
+ showLegend: true,
31167
+ curve: "monotone",
31168
+ tooltip: { show: true, style: "dark" },
31169
+ dateRange: {
31170
+ start: fromTimestamp.split("T")[0],
31171
+ end: toTimestamp.split("T")[0]
31077
31172
  }
31078
- ],
31079
- height: 300,
31080
- showGrid: true,
31081
- showLegend: true,
31082
- curve: "monotone",
31083
- tooltip: { show: true, style: "dark" },
31084
- dateRange: {
31085
- start: fromTimestamp.split("T")[0],
31086
- end: toTimestamp.split("T")[0]
31173
+ },
31174
+ table: {
31175
+ title: "Tool Runs",
31176
+ data: toolsData.tableData,
31177
+ columns: [
31178
+ {
31179
+ key: "name",
31180
+ title: "Name",
31181
+ width: 200,
31182
+ align: "left"
31183
+ },
31184
+ {
31185
+ key: "type",
31186
+ title: "Type",
31187
+ width: 150,
31188
+ align: "left"
31189
+ },
31190
+ {
31191
+ key: "runs",
31192
+ title: "Runs",
31193
+ width: 100,
31194
+ align: "right",
31195
+ formatter: (value) => `${Math.floor(value / 1e3)}k`
31196
+ },
31197
+ {
31198
+ key: "responseTime",
31199
+ title: "Response Time",
31200
+ width: 120,
31201
+ align: "right"
31202
+ }
31203
+ ]
31087
31204
  }
31088
31205
  },
31089
- table: {
31090
- title: "Tool Runs",
31091
- data: toolsData.tableData,
31092
- columns: [
31093
- {
31094
- key: "name",
31095
- title: "Name",
31096
- width: 200,
31097
- align: "left"
31098
- },
31099
- {
31100
- key: "type",
31101
- title: "Type",
31102
- width: 150,
31103
- align: "left"
31104
- },
31105
- {
31106
- key: "runs",
31107
- title: "Runs",
31108
- width: 100,
31109
- align: "right",
31110
- formatter: (value) => `${Math.floor(value / 1e3)}k`
31111
- },
31112
- {
31113
- key: "responseTime",
31114
- title: "Response Time",
31115
- width: 120,
31116
- align: "right"
31117
- }
31118
- ]
31119
- }
31120
- },
31121
- controls: {
31122
- dropdown: {
31123
- label: "All Tools",
31124
- options: toolsData.controlOptions,
31125
- defaultValue: ["all"],
31126
- multiSelect: true,
31127
- searchable: true
31128
- },
31129
- toggle: {
31130
- chartView: true,
31131
- tableView: true
31206
+ controls: {
31207
+ dropdown: {
31208
+ label: "All Tools",
31209
+ options: toolsData.controlOptions,
31210
+ defaultValue: ["all"],
31211
+ multiSelect: true,
31212
+ searchable: true
31213
+ },
31214
+ toggle: {
31215
+ chartView: true,
31216
+ tableView: true
31217
+ }
31132
31218
  }
31133
31219
  }
31134
31220
  },
31135
31221
  {
31136
31222
  title: "Model Runs",
31137
31223
  value: data.data.modelRuns,
31224
+ failedCount: data.data.failedModelRuns || 0,
31138
31225
  metricType: "modelRuns",
31139
31226
  icon: "cpu",
31140
31227
  highlighted: false,
@@ -31143,68 +31230,79 @@ class DashboardApiService {
31143
31230
  value: Math.abs(trends.modelRuns.changePercent),
31144
31231
  type: getChangeType(trends.modelRuns.changePercent)
31145
31232
  } : void 0,
31146
- view: {
31147
- type: "chart",
31148
- chart: {
31149
- type: "line",
31150
- title: "Model Runs",
31151
- data: modelsData.chartData,
31152
- dataKey: "modelRuns",
31153
- color: "#47CD89",
31154
- yAxisLabel: "Number of Model Runs",
31155
- height: 300,
31156
- showGrid: true,
31157
- curve: "monotone",
31158
- tooltip: { show: true, style: "dark" },
31159
- dateRange: {
31160
- start: fromTimestamp.split("T")[0],
31161
- end: toTimestamp.split("T")[0]
31162
- }
31163
- },
31164
- table: {
31165
- title: "Model Runs",
31166
- data: modelsData.tableData,
31167
- columns: [
31168
- {
31169
- key: "name",
31170
- title: "Model Name",
31171
- width: 200,
31172
- align: "left"
31173
- },
31174
- {
31175
- key: "runs",
31176
- title: "Runs",
31177
- width: 100,
31178
- align: "right",
31179
- formatter: (value) => `${Math.floor(value / 1e3)}k`
31180
- },
31181
- {
31182
- key: "tokens",
31183
- title: "Tokens",
31184
- width: 120,
31185
- align: "right",
31186
- formatter: (value) => `${Math.floor(value / 1e3)}k`
31187
- },
31188
- {
31189
- key: "responseTime",
31190
- title: "Response Time",
31191
- width: 120,
31192
- align: "right"
31233
+ ...modelsData && {
31234
+ view: {
31235
+ type: "chart",
31236
+ chart: {
31237
+ type: "line",
31238
+ title: "Model Runs",
31239
+ data: modelsData.chartData,
31240
+ yAxisLabel: "Number of Model Runs",
31241
+ lines: [
31242
+ { dataKey: "modelRuns", color: "#47CD89", label: "Model Runs" },
31243
+ {
31244
+ dataKey: "failedModelRuns",
31245
+ color: "#ef4444",
31246
+ label: "Failed",
31247
+ seriesType: "bar",
31248
+ hideInLegend: true
31249
+ }
31250
+ ],
31251
+ height: 300,
31252
+ showGrid: true,
31253
+ showLegend: true,
31254
+ curve: "monotone",
31255
+ tooltip: { show: true, style: "dark" },
31256
+ dateRange: {
31257
+ start: fromTimestamp.split("T")[0],
31258
+ end: toTimestamp.split("T")[0]
31193
31259
  }
31194
- ]
31195
- }
31196
- },
31197
- controls: {
31198
- dropdown: {
31199
- label: "All Models",
31200
- options: modelsData.controlOptions,
31201
- defaultValue: ["all"],
31202
- multiSelect: true,
31203
- searchable: true
31260
+ },
31261
+ table: {
31262
+ title: "Model Runs",
31263
+ data: modelsData.tableData,
31264
+ columns: [
31265
+ {
31266
+ key: "name",
31267
+ title: "Model Name",
31268
+ width: 200,
31269
+ align: "left"
31270
+ },
31271
+ {
31272
+ key: "runs",
31273
+ title: "Runs",
31274
+ width: 100,
31275
+ align: "right",
31276
+ formatter: (value) => `${Math.floor(value / 1e3)}k`
31277
+ },
31278
+ {
31279
+ key: "tokens",
31280
+ title: "Tokens",
31281
+ width: 120,
31282
+ align: "right",
31283
+ formatter: (value) => `${Math.floor(value / 1e3)}k`
31284
+ },
31285
+ {
31286
+ key: "responseTime",
31287
+ title: "Response Time",
31288
+ width: 120,
31289
+ align: "right"
31290
+ }
31291
+ ]
31292
+ }
31204
31293
  },
31205
- toggle: {
31206
- chartView: true,
31207
- tableView: true
31294
+ controls: {
31295
+ dropdown: {
31296
+ label: "All Models",
31297
+ options: modelsData.controlOptions,
31298
+ defaultValue: ["all"],
31299
+ multiSelect: true,
31300
+ searchable: true
31301
+ },
31302
+ toggle: {
31303
+ chartView: true,
31304
+ tableView: true
31305
+ }
31208
31306
  }
31209
31307
  }
31210
31308
  }
@@ -31216,12 +31314,34 @@ class DashboardApiService {
31216
31314
  const getChangeType = (changePercent) => {
31217
31315
  return changePercent > 0 ? "increase" : "decrease";
31218
31316
  };
31219
- const [usersData, sessionsData, messagesData, tokensData] = await Promise.all([
31317
+ const results = await Promise.allSettled([
31220
31318
  this.fetchTimeSeriesData("users", "usage-analytics", fromTimestamp, toTimestamp, timeDimension, filters),
31221
31319
  this.fetchTimeSeriesData("sessions", "usage-analytics", fromTimestamp, toTimestamp, timeDimension, filters),
31222
31320
  this.fetchTimeSeriesData("messages", "usage-analytics", fromTimestamp, toTimestamp, timeDimension, filters),
31223
31321
  this.fetchTimeSeriesData("tokens", "usage-analytics", fromTimestamp, toTimestamp, timeDimension, filters)
31224
31322
  ]);
31323
+ if (results[0].status === "rejected") {
31324
+ console.error("Error fetching users data:", results[0].reason);
31325
+ }
31326
+ if (results[1].status === "rejected") {
31327
+ console.error("Error fetching sessions data:", results[1].reason);
31328
+ }
31329
+ if (results[2].status === "rejected") {
31330
+ console.error("Error fetching messages data:", results[2].reason);
31331
+ }
31332
+ if (results[3].status === "rejected") {
31333
+ console.error("Error fetching tokens data:", results[3].reason);
31334
+ }
31335
+ const emptyTimeSeries = {
31336
+ type: "time-series",
31337
+ category: "usage-analytics",
31338
+ metric: "",
31339
+ data: []
31340
+ };
31341
+ const usersData = results[0].status === "fulfilled" ? results[0].value : { ...emptyTimeSeries, metric: "users" };
31342
+ const sessionsData = results[1].status === "fulfilled" ? results[1].value : { ...emptyTimeSeries, metric: "sessions" };
31343
+ const messagesData = results[2].status === "fulfilled" ? results[2].value : { ...emptyTimeSeries, metric: "messages" };
31344
+ const tokensData = results[3].status === "fulfilled" ? results[3].value : { ...emptyTimeSeries, metric: "tokens" };
31225
31345
  return [
31226
31346
  {
31227
31347
  title: "Users",
@@ -31235,22 +31355,24 @@ class DashboardApiService {
31235
31355
  value: Math.abs(trends.users.changePercent),
31236
31356
  type: getChangeType(trends.users.changePercent)
31237
31357
  } : void 0,
31238
- view: {
31239
- type: "chart",
31240
- chart: {
31241
- type: "line",
31242
- title: "Total Users",
31243
- data: this.transformTimeSeriesDataForMetric(usersData, "users"),
31244
- dataKey: "users",
31245
- color: "#4E5BA6",
31246
- yAxisLabel: "Number of Users",
31247
- height: 300,
31248
- showGrid: true,
31249
- curve: "monotone",
31250
- tooltip: { show: true, style: "dark" },
31251
- dateRange: {
31252
- start: fromTimestamp.split("T")[0],
31253
- end: toTimestamp.split("T")[0]
31358
+ ...usersData && {
31359
+ view: {
31360
+ type: "chart",
31361
+ chart: {
31362
+ type: "line",
31363
+ title: "Total Users",
31364
+ data: this.transformTimeSeriesDataForMetric(usersData, "users"),
31365
+ dataKey: "users",
31366
+ color: "#4E5BA6",
31367
+ yAxisLabel: "Number of Users",
31368
+ height: 300,
31369
+ showGrid: true,
31370
+ curve: "monotone",
31371
+ tooltip: { show: true, style: "dark" },
31372
+ dateRange: {
31373
+ start: fromTimestamp.split("T")[0],
31374
+ end: toTimestamp.split("T")[0]
31375
+ }
31254
31376
  }
31255
31377
  }
31256
31378
  }
@@ -31266,22 +31388,24 @@ class DashboardApiService {
31266
31388
  value: Math.abs(trends.sessions.changePercent),
31267
31389
  type: getChangeType(trends.sessions.changePercent)
31268
31390
  } : void 0,
31269
- view: {
31270
- type: "chart",
31271
- chart: {
31272
- type: "line",
31273
- title: "Total Sessions",
31274
- data: this.transformTimeSeriesDataForMetric(sessionsData, "sessions"),
31275
- dataKey: "sessions",
31276
- color: "#0BA5EC",
31277
- yAxisLabel: "Number of Sessions",
31278
- height: 300,
31279
- showGrid: true,
31280
- curve: "monotone",
31281
- tooltip: { show: true, style: "dark" },
31282
- dateRange: {
31283
- start: fromTimestamp.split("T")[0],
31284
- end: toTimestamp.split("T")[0]
31391
+ ...sessionsData && {
31392
+ view: {
31393
+ type: "chart",
31394
+ chart: {
31395
+ type: "line",
31396
+ title: "Total Sessions",
31397
+ data: this.transformTimeSeriesDataForMetric(sessionsData, "sessions"),
31398
+ dataKey: "sessions",
31399
+ color: "#0BA5EC",
31400
+ yAxisLabel: "Number of Sessions",
31401
+ height: 300,
31402
+ showGrid: true,
31403
+ curve: "monotone",
31404
+ tooltip: { show: true, style: "dark" },
31405
+ dateRange: {
31406
+ start: fromTimestamp.split("T")[0],
31407
+ end: toTimestamp.split("T")[0]
31408
+ }
31285
31409
  }
31286
31410
  }
31287
31411
  }
@@ -31297,22 +31421,24 @@ class DashboardApiService {
31297
31421
  value: Math.abs(trends.messages.changePercent.total),
31298
31422
  type: getChangeType(trends.messages.changePercent.total)
31299
31423
  } : void 0,
31300
- view: {
31301
- type: "chart",
31302
- chart: {
31303
- type: "line",
31304
- title: "Total Messages",
31305
- data: this.transformTimeSeriesDataForMetric(messagesData, "messages"),
31306
- dataKey: "messages",
31307
- color: "#E478FA",
31308
- yAxisLabel: "Number of Messages",
31309
- height: 300,
31310
- showGrid: true,
31311
- curve: "monotone",
31312
- tooltip: { show: true, style: "dark" },
31313
- dateRange: {
31314
- start: fromTimestamp.split("T")[0],
31315
- end: toTimestamp.split("T")[0]
31424
+ ...messagesData && {
31425
+ view: {
31426
+ type: "chart",
31427
+ chart: {
31428
+ type: "line",
31429
+ title: "Total Messages",
31430
+ data: this.transformTimeSeriesDataForMetric(messagesData, "messages"),
31431
+ dataKey: "messages",
31432
+ color: "#E478FA",
31433
+ yAxisLabel: "Number of Messages",
31434
+ height: 300,
31435
+ showGrid: true,
31436
+ curve: "monotone",
31437
+ tooltip: { show: true, style: "dark" },
31438
+ dateRange: {
31439
+ start: fromTimestamp.split("T")[0],
31440
+ end: toTimestamp.split("T")[0]
31441
+ }
31316
31442
  }
31317
31443
  }
31318
31444
  }
@@ -31328,38 +31454,40 @@ class DashboardApiService {
31328
31454
  value: Math.abs(trends.tokens.changePercent.total),
31329
31455
  type: getChangeType(trends.tokens.changePercent.total)
31330
31456
  } : void 0,
31331
- view: {
31332
- type: "chart",
31333
- chart: {
31334
- type: "line",
31335
- title: "Token Usage Breakdown",
31336
- data: this.transformTimeSeriesDataForMetric(tokensData, "tokens"),
31337
- yAxisLabel: "Number of Tokens",
31338
- lines: [
31339
- {
31340
- dataKey: "totalTokens",
31341
- color: "#FF692E",
31342
- label: "Total Tokens"
31343
- },
31344
- {
31345
- dataKey: "inputTokens",
31346
- color: "#5925DC",
31347
- label: "Input Tokens"
31348
- },
31349
- {
31350
- dataKey: "outputTokens",
31351
- color: "#E478FA",
31352
- label: "Output Tokens"
31457
+ ...tokensData && {
31458
+ view: {
31459
+ type: "chart",
31460
+ chart: {
31461
+ type: "line",
31462
+ title: "Token Usage Breakdown",
31463
+ data: this.transformTimeSeriesDataForMetric(tokensData, "tokens"),
31464
+ yAxisLabel: "Number of Tokens",
31465
+ lines: [
31466
+ {
31467
+ dataKey: "totalTokens",
31468
+ color: "#FF692E",
31469
+ label: "Total Tokens"
31470
+ },
31471
+ {
31472
+ dataKey: "inputTokens",
31473
+ color: "#5925DC",
31474
+ label: "Input Tokens"
31475
+ },
31476
+ {
31477
+ dataKey: "outputTokens",
31478
+ color: "#E478FA",
31479
+ label: "Output Tokens"
31480
+ }
31481
+ ],
31482
+ height: 300,
31483
+ showGrid: true,
31484
+ showLegend: true,
31485
+ curve: "monotone",
31486
+ tooltip: { show: true, style: "dark" },
31487
+ dateRange: {
31488
+ start: fromTimestamp.split("T")[0],
31489
+ end: toTimestamp.split("T")[0]
31353
31490
  }
31354
- ],
31355
- height: 300,
31356
- showGrid: true,
31357
- showLegend: true,
31358
- curve: "monotone",
31359
- tooltip: { show: true, style: "dark" },
31360
- dateRange: {
31361
- start: fromTimestamp.split("T")[0],
31362
- end: toTimestamp.split("T")[0]
31363
31491
  }
31364
31492
  }
31365
31493
  }
@@ -31387,35 +31515,27 @@ class DashboardApiService {
31387
31515
  let workflowTools = 0;
31388
31516
  let knowledgeTools = 0;
31389
31517
  let mcpTools = 0;
31518
+ let processors = 0;
31390
31519
  if (point2.listView && Array.isArray(point2.listView)) {
31391
31520
  point2.listView.forEach((item) => {
31392
31521
  const count = item.count || 0;
31393
- const toolType = (item.toolType || item.tool_type || "").toLowerCase();
31394
- const toolName = (item.toolName || item.tool_name || "").toLowerCase();
31395
- console.log(`Processing listView item:`, { toolType, toolName, count });
31522
+ const toolType = item.toolType || item.tool_type || "";
31396
31523
  const normalizedToolType = toolType.toLowerCase();
31397
- if (["inlinetool", "inlineTool", "tool", "code", "codetool", "event", "EVENT"].includes(toolType) || ["inlinetool", "tool", "code", "codetool", "event"].includes(normalizedToolType)) {
31524
+ if (["inlinetool", "tool", "code", "codetool", "event"].includes(normalizedToolType)) {
31398
31525
  codeTools += count;
31399
- } else if (["toollibrary", "toolLibrary", "workflow", "tool"].includes(toolType) || ["toollibrary", "workflow", "tool"].includes(normalizedToolType)) {
31526
+ } else if (["toollibrary", "workflow"].includes(normalizedToolType)) {
31400
31527
  workflowTools += count;
31401
- } else if (["knowledge", "KNOWLEDGE", "knowledgetool"].includes(toolType) || ["knowledge", "knowledgetool"].includes(normalizedToolType)) {
31528
+ } else if (["knowledge", "knowledgetool"].includes(normalizedToolType) || toolType === "KNOWLEDGE") {
31402
31529
  knowledgeTools += count;
31403
- } else if (["mcp", "MCP", "mcptool", "mcpTool"].includes(toolType) || ["mcp", "mcptool"].includes(normalizedToolType)) {
31530
+ } else if (["mcp", "mcptool"].includes(normalizedToolType)) {
31404
31531
  mcpTools += count;
31532
+ } else if (["pre_processor", "post_processor", "processor", "input_processor"].includes(normalizedToolType) || toolType === "INPUT_PROCESSOR" || toolType === "input_processor") {
31533
+ processors += count;
31405
31534
  } else {
31406
- console.log(`Unknown tool type '${toolType}' for tool '${toolName}', defaulting to code tools`);
31407
31535
  codeTools += count;
31408
31536
  }
31409
31537
  });
31410
- console.log(`Calculated breakdown for point ${index}:`, {
31411
- codeTools,
31412
- workflowTools,
31413
- knowledgeTools,
31414
- mcpTools,
31415
- total: codeTools + workflowTools + knowledgeTools + mcpTools,
31416
- expectedTotal: totalToolRuns
31417
- });
31418
- const calculatedTotal = codeTools + workflowTools + knowledgeTools + mcpTools;
31538
+ const calculatedTotal = codeTools + workflowTools + knowledgeTools + mcpTools + processors;
31419
31539
  if (Math.abs(calculatedTotal - totalToolRuns) > 1) {
31420
31540
  console.warn(`Breakdown total (${calculatedTotal}) doesn't match expected total (${totalToolRuns}) for point ${index}`);
31421
31541
  const difference = totalToolRuns - calculatedTotal;
@@ -31423,7 +31543,6 @@ class DashboardApiService {
31423
31543
  console.log(`Adjusted codeTools by ${difference} to balance total`);
31424
31544
  }
31425
31545
  } else {
31426
- console.log(`No listView data for point ${index}, assigning all ${totalToolRuns} to codeTools`);
31427
31546
  codeTools = totalToolRuns;
31428
31547
  }
31429
31548
  const basePoint = {
@@ -31434,11 +31553,11 @@ class DashboardApiService {
31434
31553
  toolRuns: totalToolRuns,
31435
31554
  value: totalToolRuns,
31436
31555
  count: totalToolRuns,
31437
- // Tool breakdown data for multi-line chart (using actual data)
31438
31556
  codeTools,
31439
31557
  workflowTools,
31440
31558
  knowledgeTools,
31441
31559
  mcpTools,
31560
+ processors,
31442
31561
  // Token data
31443
31562
  input_tokens: point2.input_tokens || 0,
31444
31563
  output_tokens: point2.output_tokens || 0,
@@ -31476,14 +31595,33 @@ class DashboardApiService {
31476
31595
  // Enhanced batch fetch method that returns complete MetricData with embedded view and controls
31477
31596
  async fetchAllCardsDataWithEnhancedViews(fromTimestamp, toTimestamp, timeDimension, filters = []) {
31478
31597
  try {
31479
- const [usageAnalyticsCards, runsCards] = await Promise.all([
31598
+ const cardsResults = await Promise.allSettled([
31480
31599
  this.fetchUsageAnalyticsCards(fromTimestamp, toTimestamp, timeDimension, filters),
31481
31600
  this.fetchRunsCards(fromTimestamp, toTimestamp, timeDimension, filters)
31482
31601
  ]);
31483
- const [enhancedUsageAnalytics, enhancedRuns] = await Promise.all([
31484
- this.transformUsageAnalyticsCardsWithEnhancedData(usageAnalyticsCards, fromTimestamp, toTimestamp, timeDimension, filters),
31485
- this.transformRunsCardsWithEnhancedData(runsCards, fromTimestamp, toTimestamp, timeDimension, filters)
31602
+ if (cardsResults[0].status === "rejected") {
31603
+ console.error("Error fetching usage analytics cards:", cardsResults[0].reason);
31604
+ }
31605
+ if (cardsResults[1].status === "rejected") {
31606
+ console.error("Error fetching runs cards:", cardsResults[1].reason);
31607
+ }
31608
+ if (cardsResults[0].status === "rejected" && cardsResults[1].status === "rejected") {
31609
+ throw new Error("Both usage analytics and runs cards failed to load");
31610
+ }
31611
+ const usageAnalyticsCards = cardsResults[0].status === "fulfilled" ? cardsResults[0].value : void 0;
31612
+ const runsCards = cardsResults[1].status === "fulfilled" ? cardsResults[1].value : void 0;
31613
+ const enhancementResults = await Promise.allSettled([
31614
+ usageAnalyticsCards ? this.transformUsageAnalyticsCardsWithEnhancedData(usageAnalyticsCards, fromTimestamp, toTimestamp, timeDimension, filters) : Promise.resolve([]),
31615
+ runsCards ? this.transformRunsCardsWithEnhancedData(runsCards, fromTimestamp, toTimestamp, timeDimension, filters) : Promise.resolve([])
31486
31616
  ]);
31617
+ if (enhancementResults[0].status === "rejected") {
31618
+ console.error("Error transforming usage analytics cards:", enhancementResults[0].reason);
31619
+ }
31620
+ if (enhancementResults[1].status === "rejected") {
31621
+ console.error("Error transforming runs cards:", enhancementResults[1].reason);
31622
+ }
31623
+ const enhancedUsageAnalytics = enhancementResults[0].status === "fulfilled" ? enhancementResults[0].value : [];
31624
+ const enhancedRuns = enhancementResults[1].status === "fulfilled" ? enhancementResults[1].value : [];
31487
31625
  return {
31488
31626
  usageAnalytics: enhancedUsageAnalytics,
31489
31627
  runs: enhancedRuns
@@ -31496,13 +31634,21 @@ class DashboardApiService {
31496
31634
  // Batch fetch time series data for default selected metrics
31497
31635
  async fetchDefaultTimeSeriesData(fromTimestamp, toTimestamp, timeDimension, filters = []) {
31498
31636
  try {
31499
- const [sessionsData, agentRunsData] = await Promise.all([
31637
+ const results = await Promise.allSettled([
31500
31638
  this.fetchTimeSeriesData("sessions", "usage-analytics", fromTimestamp, toTimestamp, timeDimension, filters),
31501
31639
  this.fetchTimeSeriesData("agent-runs", "runs", fromTimestamp, toTimestamp, timeDimension, filters)
31502
31640
  ]);
31641
+ if (results[0].status === "rejected") {
31642
+ console.error("Error fetching sessions data:", results[0].reason);
31643
+ }
31644
+ if (results[1].status === "rejected") {
31645
+ console.error("Error fetching agent runs data:", results[1].reason);
31646
+ }
31647
+ const sessionsData = results[0].status === "fulfilled" ? results[0].value : void 0;
31648
+ const agentRunsData = results[1].status === "fulfilled" ? results[1].value : void 0;
31503
31649
  return {
31504
- sessions: this.transformTimeSeriesData(sessionsData),
31505
- agentRuns: this.transformTimeSeriesData(agentRunsData)
31650
+ sessions: sessionsData ? this.transformTimeSeriesData(sessionsData) : [],
31651
+ agentRuns: agentRunsData ? this.transformTimeSeriesData(agentRunsData) : []
31506
31652
  };
31507
31653
  } catch (error) {
31508
31654
  console.error("Error fetching default time series data:", error);
@@ -32229,6 +32375,10 @@ const SectionControls = ({
32229
32375
  ] })
32230
32376
  ] });
32231
32377
  };
32378
+ function modelListViewRowLabel(listItem) {
32379
+ if (!listItem.modelName) return "";
32380
+ return listItem.connectionName ? `${listItem.modelName} - ${listItem.connectionName}` : listItem.modelName;
32381
+ }
32232
32382
  const DashboardSection = ({
32233
32383
  section,
32234
32384
  className,
@@ -32326,16 +32476,17 @@ const DashboardSection = ({
32326
32476
  });
32327
32477
  return baseData.map((item) => {
32328
32478
  let filteredValue = 0;
32479
+ let matchingItems = [];
32329
32480
  if (item["listView"] && Array.isArray(item["listView"])) {
32330
- const matchingItems = item["listView"].filter((listItem) => {
32481
+ matchingItems = item["listView"].filter((listItem) => {
32331
32482
  if (metricType === "agentRuns" && listItem.agentName) {
32332
32483
  return listItem.agentName === selectedLabel || listItem.agentName.toLowerCase() === (selectedLabel == null ? void 0 : selectedLabel.toLowerCase());
32333
32484
  }
32334
32485
  if (metricType === "toolRuns" && listItem.toolName) {
32335
32486
  return listItem.toolName === selectedLabel || listItem.toolName.toLowerCase() === (selectedLabel == null ? void 0 : selectedLabel.toLowerCase());
32336
32487
  }
32337
- if (metricType === "modelRuns" && listItem.modelName) {
32338
- return listItem.modelName === selectedLabel || listItem.modelName.toLowerCase() === (selectedLabel == null ? void 0 : selectedLabel.toLowerCase());
32488
+ if (metricType === "modelRuns" && listItem.modelName && selectedLabel) {
32489
+ return modelListViewRowLabel(listItem) === selectedLabel;
32339
32490
  }
32340
32491
  return false;
32341
32492
  });
@@ -32345,10 +32496,17 @@ const DashboardSection = ({
32345
32496
  );
32346
32497
  }
32347
32498
  console.log("📊 Filtered value for", selectedLabel, ":", filteredValue);
32499
+ const failedModelRunsSum = metricType === "modelRuns" ? matchingItems.reduce(
32500
+ (sum2, listItem) => sum2 + (Number(listItem.failedRuns) || 0),
32501
+ 0
32502
+ ) : 0;
32348
32503
  const result = {
32349
32504
  ...item,
32350
32505
  [metricType]: filteredValue
32351
32506
  };
32507
+ if (metricType === "modelRuns") {
32508
+ result.failedModelRuns = failedModelRunsSum;
32509
+ }
32352
32510
  return result;
32353
32511
  });
32354
32512
  }
@@ -32360,8 +32518,9 @@ const DashboardSection = ({
32360
32518
  const selectedLabels = selectedOptions.map((opt) => opt.label);
32361
32519
  return baseData.map((item) => {
32362
32520
  let aggregatedValue = 0;
32521
+ let matchingItems = [];
32363
32522
  if (item["listView"] && Array.isArray(item["listView"])) {
32364
- const matchingItems = item["listView"].filter((listItem) => {
32523
+ matchingItems = item["listView"].filter((listItem) => {
32365
32524
  if (metricType === "agentRuns" && listItem.agentName) {
32366
32525
  return selectedLabels.some(
32367
32526
  (label) => listItem.agentName === label || listItem.agentName.toLowerCase() === (label == null ? void 0 : label.toLowerCase())
@@ -32373,9 +32532,8 @@ const DashboardSection = ({
32373
32532
  );
32374
32533
  }
32375
32534
  if (metricType === "modelRuns" && listItem.modelName) {
32376
- return selectedLabels.some(
32377
- (label) => listItem.modelName === label || listItem.modelName.toLowerCase() === (label == null ? void 0 : label.toLowerCase())
32378
- );
32535
+ const rowLabel = modelListViewRowLabel(listItem);
32536
+ return selectedLabels.some((label) => rowLabel === label);
32379
32537
  }
32380
32538
  return false;
32381
32539
  });
@@ -32384,10 +32542,18 @@ const DashboardSection = ({
32384
32542
  0
32385
32543
  );
32386
32544
  }
32387
- return {
32545
+ const failedModelRunsMulti = metricType === "modelRuns" ? matchingItems.reduce(
32546
+ (sum2, listItem) => sum2 + (Number(listItem.failedRuns) || 0),
32547
+ 0
32548
+ ) : 0;
32549
+ const multiResult = {
32388
32550
  ...item,
32389
32551
  [metricType]: aggregatedValue
32390
32552
  };
32553
+ if (metricType === "modelRuns") {
32554
+ multiResult.failedModelRuns = failedModelRunsMulti;
32555
+ }
32556
+ return multiResult;
32391
32557
  });
32392
32558
  }
32393
32559
  return baseData;
@@ -32619,35 +32785,30 @@ const DashboardSection = ({
32619
32785
  data: filteredData,
32620
32786
  yAxisLabel: "Number of Tool Runs",
32621
32787
  lines: [
32622
- {
32623
- dataKey: "toolRuns",
32624
- color: "#06b6d4",
32625
- // Blue for Tool Runs
32626
- label: "Tool Runs"
32627
- },
32628
32788
  {
32629
32789
  dataKey: "codeTools",
32630
32790
  color: "#f97316",
32631
- // Orange for Code Tools
32632
32791
  label: "Code Tools"
32633
32792
  },
32634
32793
  {
32635
32794
  dataKey: "workflowTools",
32636
32795
  color: "#10b981",
32637
- // Green for Workflow Tools
32638
32796
  label: "Workflow Tools"
32639
32797
  },
32640
32798
  {
32641
32799
  dataKey: "knowledgeTools",
32642
32800
  color: "#8b5cf6",
32643
- // Purple for Knowledge
32644
32801
  label: "Knowledge"
32645
32802
  },
32646
32803
  {
32647
32804
  dataKey: "mcpTools",
32648
32805
  color: "#ef4444",
32649
- // Red for MCP Tools
32650
32806
  label: "MCP Tools"
32807
+ },
32808
+ {
32809
+ dataKey: "processors",
32810
+ color: "#eab308",
32811
+ label: "Processors"
32651
32812
  }
32652
32813
  ],
32653
32814
  height: 300,
@@ -32667,12 +32828,20 @@ const DashboardSection = ({
32667
32828
  type: "line",
32668
32829
  title: getChartTitle("Model Runs"),
32669
32830
  data: getFilteredData(baseData, "modelRuns"),
32670
- dataKey: "modelRuns",
32671
- color: "#10b981",
32672
- // Green as shown in Figma
32673
32831
  yAxisLabel: "Number of Model Runs",
32832
+ lines: [
32833
+ { dataKey: "modelRuns", color: "#10b981", label: "Model Runs" },
32834
+ {
32835
+ dataKey: "failedModelRuns",
32836
+ color: "#ef4444",
32837
+ label: "Failed",
32838
+ seriesType: "bar",
32839
+ hideInLegend: true
32840
+ }
32841
+ ],
32674
32842
  height: 300,
32675
32843
  showGrid: true,
32844
+ showLegend: true,
32676
32845
  curve: "monotone",
32677
32846
  tooltip: { show: true, style: "dark" },
32678
32847
  dateRange: {
@@ -32685,12 +32854,20 @@ const DashboardSection = ({
32685
32854
  type: "line",
32686
32855
  title: getChartTitle("Model Runs"),
32687
32856
  data: filteredData,
32688
- dataKey: "modelRuns",
32689
- color: "#10b981",
32690
- // Green as shown in Figma
32691
32857
  yAxisLabel: "Number of Model Runs",
32858
+ lines: [
32859
+ { dataKey: "modelRuns", color: "#10b981", label: "Model Runs" },
32860
+ {
32861
+ dataKey: "failedModelRuns",
32862
+ color: "#ef4444",
32863
+ label: "Failed",
32864
+ seriesType: "bar",
32865
+ hideInLegend: true
32866
+ }
32867
+ ],
32692
32868
  height: 300,
32693
32869
  showGrid: true,
32870
+ showLegend: true,
32694
32871
  curve: "monotone",
32695
32872
  tooltip: { show: true, style: "dark" },
32696
32873
  dateRange: {
@@ -34942,8 +35119,11 @@ const Dashboard = ({
34942
35119
  if (appConfig) {
34943
35120
  try {
34944
35121
  apiServiceRef.current = new DashboardApiService(appConfig);
34945
- loadEnvironments();
34946
- loadInitialData();
35122
+ const initDashboard = async () => {
35123
+ await loadEnvironments();
35124
+ await loadInitialData();
35125
+ };
35126
+ initDashboard();
34947
35127
  } catch (err) {
34948
35128
  console.error("Failed to initialize API service:", err);
34949
35129
  }
@@ -35509,6 +35689,31 @@ class TracingApiService {
35509
35689
  traces: data.traces || []
35510
35690
  };
35511
35691
  }
35692
+ /**
35693
+ * Get total count of traces matching filters (for pagination)
35694
+ * Endpoint: /tracing/api/trpc/traces.countAll
35695
+ */
35696
+ async fetchTracesCount(projectId, filters, options = {}) {
35697
+ const input = {
35698
+ json: {
35699
+ projectId,
35700
+ filter: filters,
35701
+ searchQuery: options.searchQuery ?? null,
35702
+ searchType: options.searchType ?? ["id"],
35703
+ page: 0,
35704
+ limit: 0,
35705
+ orderBy: options.orderBy ?? null
35706
+ },
35707
+ meta: {
35708
+ values: this.buildMetaValues(filters)
35709
+ }
35710
+ };
35711
+ const url = this.buildTrpcUrl("traces.countAll", input);
35712
+ const data = await this.makeRequest(url);
35713
+ return {
35714
+ totalCount: (data == null ? void 0 : data.totalCount) ?? 0
35715
+ };
35716
+ }
35512
35717
  /**
35513
35718
  * Fetch metrics for multiple traces (latency, tokens, cost)
35514
35719
  * Endpoint: /tracing/api/trpc/traces.metrics
@@ -36582,6 +36787,140 @@ function TokenBreakdownTooltip(props) {
36582
36787
  ] }) })
36583
36788
  ] });
36584
36789
  }
36790
+ const CopyButton$1 = ({
36791
+ text,
36792
+ className = "",
36793
+ iconClassName = "",
36794
+ iconStyle,
36795
+ title = "Copy to clipboard",
36796
+ onCopySuccess,
36797
+ onCopyError,
36798
+ tooltipText = "Copied!",
36799
+ tooltipPosition = "bottom",
36800
+ size = "md"
36801
+ }) => {
36802
+ const [showTooltip, setShowTooltip] = useState(false);
36803
+ const getSizeClasses = () => {
36804
+ switch (size) {
36805
+ case "sm":
36806
+ return {
36807
+ button: "p-1",
36808
+ icon: "w-[12px] h-[12px]",
36809
+ tooltip: "text-xs py-1 px-2"
36810
+ };
36811
+ case "lg":
36812
+ return {
36813
+ button: "p-2",
36814
+ icon: "w-[20px] h-[20px]",
36815
+ tooltip: "text-sm py-2 px-3"
36816
+ };
36817
+ default:
36818
+ return {
36819
+ button: "p-1.5",
36820
+ icon: "w-[16px] h-[16px]",
36821
+ tooltip: "text-xs py-1 px-2"
36822
+ };
36823
+ }
36824
+ };
36825
+ const getTooltipPositionClasses = () => {
36826
+ const baseClasses = "absolute bg-gray-800 text-white rounded whitespace-nowrap z-50";
36827
+ switch (tooltipPosition) {
36828
+ case "bottom":
36829
+ return `${baseClasses} top-full mt-1 left-1/2 -translate-x-1/2`;
36830
+ case "left":
36831
+ return `${baseClasses} right-full mr-1 top-1/2 -translate-y-1/2`;
36832
+ case "right":
36833
+ return `${baseClasses} left-full ml-1 top-1/2 -translate-y-1/2`;
36834
+ default:
36835
+ return `${baseClasses} bottom-full mb-1 left-1/2 -translate-x-1/2`;
36836
+ }
36837
+ };
36838
+ const sizeClasses2 = getSizeClasses();
36839
+ const showCopyTooltip = useCallback(() => {
36840
+ setShowTooltip(true);
36841
+ setTimeout(() => setShowTooltip(false), 1e3);
36842
+ }, []);
36843
+ const copyToClipboard2 = useCallback(async () => {
36844
+ try {
36845
+ if (navigator.clipboard && navigator.clipboard.writeText) {
36846
+ await navigator.clipboard.writeText(text);
36847
+ showCopyTooltip();
36848
+ onCopySuccess == null ? void 0 : onCopySuccess();
36849
+ return;
36850
+ }
36851
+ const textArea = document.createElement("textarea");
36852
+ textArea.value = text;
36853
+ textArea.style.position = "fixed";
36854
+ textArea.style.left = "-999999px";
36855
+ textArea.style.top = "-999999px";
36856
+ document.body.appendChild(textArea);
36857
+ textArea.focus();
36858
+ textArea.select();
36859
+ try {
36860
+ document.execCommand("copy");
36861
+ showCopyTooltip();
36862
+ onCopySuccess == null ? void 0 : onCopySuccess();
36863
+ } catch (err) {
36864
+ const error = err instanceof Error ? err : new Error("Copy failed");
36865
+ console.warn("Copy to clipboard failed:", error);
36866
+ onCopyError == null ? void 0 : onCopyError(error);
36867
+ } finally {
36868
+ document.body.removeChild(textArea);
36869
+ }
36870
+ } catch (err) {
36871
+ const error = err instanceof Error ? err : new Error("Copy failed");
36872
+ console.warn("Copy to clipboard failed:", error);
36873
+ onCopyError == null ? void 0 : onCopyError(error);
36874
+ }
36875
+ }, [text, showCopyTooltip, onCopySuccess, onCopyError]);
36876
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative inline-flex", children: [
36877
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
36878
+ "button",
36879
+ {
36880
+ onClick: copyToClipboard2,
36881
+ className: `${sizeClasses2.button} hover:bg-gray-100 rounded transition-colors ${className}`,
36882
+ title,
36883
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: `${sizeClasses2.icon} text-gray-400 ${iconClassName}`, style: iconStyle })
36884
+ }
36885
+ ),
36886
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
36887
+ "div",
36888
+ {
36889
+ className: `${getTooltipPositionClasses()} ${sizeClasses2.tooltip} transition-opacity duration-150 ${showTooltip ? "opacity-100 animate-fade-in" : "opacity-0 pointer-events-none"}`,
36890
+ style: {
36891
+ visibility: showTooltip ? "visible" : "hidden"
36892
+ },
36893
+ children: tooltipText
36894
+ }
36895
+ )
36896
+ ] });
36897
+ };
36898
+ function CopyableId({ value, truncateLength = 30 }) {
36899
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "copyable-id-wrapper", title: value, children: [
36900
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium text-gray-900 truncate", children: TracingUtils.truncate(value, truncateLength) }),
36901
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
36902
+ "span",
36903
+ {
36904
+ className: "copyable-id-btn",
36905
+ onClick: (e3) => {
36906
+ e3.stopPropagation();
36907
+ e3.preventDefault();
36908
+ },
36909
+ onMouseDown: (e3) => e3.stopPropagation(),
36910
+ onMouseUp: (e3) => e3.stopPropagation(),
36911
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
36912
+ CopyButton$1,
36913
+ {
36914
+ text: value,
36915
+ size: "sm",
36916
+ title: "Copy to clipboard",
36917
+ iconClassName: "text-[#667085]"
36918
+ }
36919
+ )
36920
+ }
36921
+ )
36922
+ ] });
36923
+ }
36585
36924
  function Shimmer$2({ className = "", children }) {
36586
36925
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `animate-pulse bg-[#F2F4F7] rounded ${className}`, children });
36587
36926
  }
@@ -104592,6 +104931,9 @@ function TracingTable(props) {
104592
104931
  }, [columns]);
104593
104932
  const handleRowClick = useCallback(
104594
104933
  (event) => {
104934
+ var _a;
104935
+ const target = (_a = event.event) == null ? void 0 : _a.target;
104936
+ if (target == null ? void 0 : target.closest(".copyable-id-btn")) return;
104595
104937
  if (onRowClick && event.data) {
104596
104938
  onRowClick(event.data);
104597
104939
  }
@@ -104688,9 +105030,10 @@ function TracingTable(props) {
104688
105030
  onClick: goToFirstPage,
104689
105031
  disabled: currentPage === 0,
104690
105032
  className: "p-2 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed",
105033
+ style: { color: "var(--colors-gray-light-mode-700, #344054)" },
104691
105034
  title: "First page",
104692
105035
  "data-test-id": "tracing-table-first-page-btn",
104693
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsLeft, { className: "w-4 h-4" })
105036
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsLeft, { size: 16 })
104694
105037
  }
104695
105038
  ),
104696
105039
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -104699,12 +105042,13 @@ function TracingTable(props) {
104699
105042
  onClick: goToPreviousPage,
104700
105043
  disabled: currentPage === 0,
104701
105044
  className: "p-2 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed",
105045
+ style: { color: "var(--colors-gray-light-mode-700, #344054)" },
104702
105046
  title: "Previous page",
104703
105047
  "data-test-id": "tracing-table-prev-page-btn",
104704
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { className: "w-4 h-4" })
105048
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { size: 16 })
104705
105049
  }
104706
105050
  ),
104707
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-4 py-2 text-sm text-gray-700", "data-test-id": "tracing-table-page-info", children: [
105051
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-4 py-2 text-sm", style: { color: "var(--colors-gray-light-mode-700, #344054)" }, "data-test-id": "tracing-table-page-info", children: [
104708
105052
  "Page ",
104709
105053
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: currentPage + 1 }),
104710
105054
  " of",
@@ -104717,9 +105061,10 @@ function TracingTable(props) {
104717
105061
  onClick: goToNextPage,
104718
105062
  disabled: currentPage >= totalPages - 1,
104719
105063
  className: "p-2 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed",
105064
+ style: { color: "var(--colors-gray-light-mode-700, #344054)" },
104720
105065
  title: "Next page",
104721
105066
  "data-test-id": "tracing-table-next-page-btn",
104722
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "w-4 h-4" })
105067
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 16 })
104723
105068
  }
104724
105069
  ),
104725
105070
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -104728,13 +105073,14 @@ function TracingTable(props) {
104728
105073
  onClick: goToLastPage,
104729
105074
  disabled: currentPage >= totalPages - 1,
104730
105075
  className: "p-2 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed",
105076
+ style: { color: "var(--colors-gray-light-mode-700, #344054)" },
104731
105077
  title: "Last page",
104732
105078
  "data-test-id": "tracing-table-last-page-btn",
104733
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsRight, { className: "w-4 h-4" })
105079
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronsRight, { size: 16 })
104734
105080
  }
104735
105081
  )
104736
105082
  ] }),
104737
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center text-sm text-gray-700 shrink-0 absolute right-[24px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
105083
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center text-sm shrink-0 absolute right-[24px]", style: { color: "var(--colors-gray-light-mode-700, #344054)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
104738
105084
  "Showing ",
104739
105085
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold", children: startRow }),
104740
105086
  " to",
@@ -104762,9 +105108,12 @@ function TracingListHeader(props) {
104762
105108
  timeRangePresetLabel,
104763
105109
  onTimeRangeChange,
104764
105110
  filters,
105111
+ filterColumns: filterColumnsProp,
104765
105112
  onFiltersClick,
104766
105113
  onModifyColumnsClick,
104767
105114
  showModifyColumns = true,
105115
+ onClearFilters,
105116
+ onRemoveFilter,
104768
105117
  onRefresh,
104769
105118
  isRefreshing = false
104770
105119
  } = props;
@@ -104809,6 +105158,50 @@ function TracingListHeader(props) {
104809
105158
  }
104810
105159
  return `Searches in ${fields}.`;
104811
105160
  };
105161
+ const activeFilters = filters.filter(TracingUtils.isFilterActive);
105162
+ const [filtersExpanded, setFiltersExpanded] = useState(false);
105163
+ const [isOverflowing, setIsOverflowing] = useState(false);
105164
+ const chipsContainerRef = useRef(null);
105165
+ const checkOverflow = useCallback(() => {
105166
+ const el = chipsContainerRef.current;
105167
+ if (!el) return;
105168
+ setIsOverflowing(el.scrollHeight > el.clientHeight);
105169
+ }, []);
105170
+ useEffect(() => {
105171
+ checkOverflow();
105172
+ window.addEventListener("resize", checkOverflow);
105173
+ return () => window.removeEventListener("resize", checkOverflow);
105174
+ }, [checkOverflow, activeFilters.length]);
105175
+ const getFilterChipLabel = (filter) => {
105176
+ const col = filterColumnsProp == null ? void 0 : filterColumnsProp.find((c3) => c3.field === filter.column);
105177
+ const label = (col == null ? void 0 : col.label) ?? filter.column;
105178
+ let valueText;
105179
+ if (filter.type === "datetime") {
105180
+ valueText = new Date(filter.value).toLocaleDateString();
105181
+ } else if (filter.type === "number") {
105182
+ valueText = parseFloat(filter.value).toLocaleString();
105183
+ } else if (Array.isArray(filter.value)) {
105184
+ valueText = filter.value.length <= 2 ? filter.value.join(", ") : `${filter.value.length} selected`;
105185
+ } else {
105186
+ valueText = String(filter.value ?? "");
105187
+ }
105188
+ const shortOp = {
105189
+ "=": "",
105190
+ "!=": "≠ ",
105191
+ ">": "> ",
105192
+ ">=": "≥ ",
105193
+ "<": "< ",
105194
+ "<=": "≤ ",
105195
+ "contains": "~ ",
105196
+ "does not contain": "!~ ",
105197
+ "starts with": "starts ",
105198
+ "ends with": "ends ",
105199
+ "any of": "",
105200
+ "none of": "not "
105201
+ };
105202
+ const op = shortOp[filter.operator] ?? `${filter.operator} `;
105203
+ return `${label}: ${op}${valueText}`;
105204
+ };
104812
105205
  const handleDateRangeChange = (dateRange, presetLabel) => {
104813
105206
  if (dateRange && dateRange.from && dateRange.to) {
104814
105207
  const fromDate = dateRange.from;
@@ -104961,7 +105354,66 @@ function TracingListHeader(props) {
104961
105354
  }
104962
105355
  )
104963
105356
  ] })
104964
- ] })
105357
+ ] }),
105358
+ activeFilters.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
105359
+ "div",
105360
+ {
105361
+ className: "flex items-start gap-[8px] border border-gray-200 rounded-[8px] px-[12px] py-[8px]",
105362
+ "data-test-id": "tracing-filter-chips",
105363
+ children: [
105364
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[12px] font-medium leading-[28px] text-gray-500 shrink-0", children: "Filters" }),
105365
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
105366
+ "div",
105367
+ {
105368
+ ref: chipsContainerRef,
105369
+ className: `flex items-center gap-[8px] flex-wrap flex-1 min-w-0 ${!filtersExpanded ? "max-h-[28px] overflow-hidden" : ""}`,
105370
+ children: activeFilters.map((filter, idx) => {
105371
+ const originalIndex = filters.indexOf(filter);
105372
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
105373
+ "div",
105374
+ {
105375
+ className: "inline-flex items-center gap-[4px] h-[28px] px-[10px] py-[4px] bg-blue-50 border border-blue-200 rounded-[6px] text-[12px] leading-[16px] text-blue-800 max-w-[260px]",
105376
+ children: [
105377
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate font-medium", children: getFilterChipLabel(filter) }),
105378
+ onRemoveFilter && /* @__PURE__ */ jsxRuntimeExports.jsx(
105379
+ "button",
105380
+ {
105381
+ onClick: () => onRemoveFilter(originalIndex),
105382
+ className: "flex items-center justify-center shrink-0 text-blue-400 hover:text-blue-700 transition-colors",
105383
+ title: "Remove filter",
105384
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-[14px] h-[14px]", strokeWidth: 2 })
105385
+ }
105386
+ )
105387
+ ]
105388
+ },
105389
+ `chip-${idx}`
105390
+ );
105391
+ })
105392
+ }
105393
+ ),
105394
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[8px] shrink-0 leading-[28px]", children: [
105395
+ (isOverflowing || filtersExpanded) && /* @__PURE__ */ jsxRuntimeExports.jsx(
105396
+ "button",
105397
+ {
105398
+ onClick: () => setFiltersExpanded((prev) => !prev),
105399
+ className: "text-[12px] font-medium text-blue-600 hover:text-blue-800 transition-colors whitespace-nowrap",
105400
+ "data-test-id": "tracing-filter-toggle",
105401
+ children: filtersExpanded ? "View less" : "View all"
105402
+ }
105403
+ ),
105404
+ onClearFilters && /* @__PURE__ */ jsxRuntimeExports.jsx(
105405
+ "button",
105406
+ {
105407
+ onClick: onClearFilters,
105408
+ className: "text-[12px] font-medium text-gray-500 hover:text-gray-700 transition-colors whitespace-nowrap",
105409
+ "data-test-id": "tracing-filter-clear-all",
105410
+ children: "Clear all"
105411
+ }
105412
+ )
105413
+ ] })
105414
+ ]
105415
+ }
105416
+ )
104965
105417
  ] });
104966
105418
  }
104967
105419
  function ColumnCustomization(props) {
@@ -105448,6 +105900,8 @@ function FilterPanel(props) {
105448
105900
  ] })
105449
105901
  ] });
105450
105902
  }
105903
+ const TRACE_PII_DISPLAY_USER_MESSAGE_KEY = "piiDisplayUserMessage";
105904
+ const TRACE_PII_DISPLAY_APP_RESPONSE_KEY = "piiDisplayAppResponse";
105451
105905
  class TraceTreeService {
105452
105906
  /**
105453
105907
  * Build a hierarchical tree from a flat list of observations
@@ -105620,43 +106074,205 @@ class TraceTreeService {
105620
106074
  });
105621
106075
  }
105622
106076
  /**
105623
- * Extract user message from trace input
106077
+ * Extract user message from trace input for display.
106078
+ * Handles string, object with message/content/text/query, and messages array (e.g. voice/chat).
106079
+ */
106080
+ /**
106081
+ * Parse trace metadata from API (string or object) into a plain object.
106082
+ */
106083
+ static parseTraceMetadata(metadata) {
106084
+ if (metadata === null || metadata === void 0) {
106085
+ return {};
106086
+ }
106087
+ if (typeof metadata === "string") {
106088
+ try {
106089
+ return JSON.parse(metadata);
106090
+ } catch {
106091
+ return {};
106092
+ }
106093
+ }
106094
+ if (typeof metadata === "object" && !Array.isArray(metadata)) {
106095
+ return metadata;
106096
+ }
106097
+ return {};
106098
+ }
106099
+ /**
106100
+ * Read PII display strings from Langfuse/Kore trace metadata (if present).
105624
106101
  */
106102
+ static extractPiiDisplayFromTraceMetadata(metadata) {
106103
+ const obj = this.parseTraceMetadata(metadata);
106104
+ const userRaw = obj[TRACE_PII_DISPLAY_USER_MESSAGE_KEY];
106105
+ const appRaw = obj[TRACE_PII_DISPLAY_APP_RESPONSE_KEY];
106106
+ const result = {};
106107
+ if (typeof userRaw === "string" && userRaw.length > 0) {
106108
+ result.displayUserMessage = userRaw;
106109
+ }
106110
+ if (typeof appRaw === "string" && appRaw.length > 0) {
106111
+ result.displayAppResponse = appRaw;
106112
+ }
106113
+ return result;
106114
+ }
106115
+ /**
106116
+ * Some tracing APIs expose custom PII display keys on trace root as well as under metadata.
106117
+ */
106118
+ static extractPiiDisplayFromApiTrace(trace) {
106119
+ const fromMeta = this.extractPiiDisplayFromTraceMetadata(trace.metadata);
106120
+ const userTop = trace[TRACE_PII_DISPLAY_USER_MESSAGE_KEY];
106121
+ const appTop = trace[TRACE_PII_DISPLAY_APP_RESPONSE_KEY];
106122
+ const fromTop = {};
106123
+ if (typeof userTop === "string" && userTop.length > 0) {
106124
+ fromTop.displayUserMessage = userTop;
106125
+ }
106126
+ if (typeof appTop === "string" && appTop.length > 0) {
106127
+ fromTop.displayAppResponse = appTop;
106128
+ }
106129
+ return {
106130
+ displayUserMessage: fromTop.displayUserMessage ?? fromMeta.displayUserMessage,
106131
+ displayAppResponse: fromTop.displayAppResponse ?? fromMeta.displayAppResponse
106132
+ };
106133
+ }
105625
106134
  static extractUserMessage(input) {
105626
106135
  if (!input) return "";
105627
106136
  if (typeof input === "string") {
105628
106137
  try {
105629
106138
  const parsed = JSON.parse(input);
105630
- return (parsed == null ? void 0 : parsed.message) || (parsed == null ? void 0 : parsed.content) || (parsed == null ? void 0 : parsed.text) || (parsed == null ? void 0 : parsed.query) || input;
106139
+ const fromParsed = (parsed == null ? void 0 : parsed.message) ?? (parsed == null ? void 0 : parsed.content) ?? (parsed == null ? void 0 : parsed.text) ?? (parsed == null ? void 0 : parsed.query);
106140
+ if (fromParsed !== void 0 && fromParsed !== null) return String(fromParsed);
106141
+ if (Array.isArray(parsed == null ? void 0 : parsed.messages)) {
106142
+ return this.extractLastUserMessageFromArray(parsed.messages);
106143
+ }
106144
+ return input;
105631
106145
  } catch {
105632
106146
  return input;
105633
106147
  }
105634
106148
  }
105635
106149
  if (typeof input === "object") {
105636
106150
  const obj = input;
105637
- return String((obj == null ? void 0 : obj["message"]) || (obj == null ? void 0 : obj["content"]) || (obj == null ? void 0 : obj["text"]) || (obj == null ? void 0 : obj["query"]) || "");
106151
+ const direct = (obj == null ? void 0 : obj["message"]) ?? (obj == null ? void 0 : obj["content"]) ?? (obj == null ? void 0 : obj["text"]) ?? (obj == null ? void 0 : obj["query"]);
106152
+ if (direct !== void 0 && direct !== null && direct !== "") {
106153
+ return typeof direct === "object" ? JSON.stringify(direct) : String(direct);
106154
+ }
106155
+ if (Array.isArray(obj == null ? void 0 : obj.messages)) {
106156
+ return this.extractLastUserMessageFromArray(obj.messages);
106157
+ }
106158
+ if (Array.isArray(input)) {
106159
+ return this.extractLastUserMessageFromArray(input);
106160
+ }
106161
+ return JSON.stringify(obj);
105638
106162
  }
105639
106163
  return String(input);
105640
106164
  }
105641
106165
  /**
105642
- * Extract app response from trace output
106166
+ * LangChain-serialized messages store role/content under `kwargs` and type in `id`.
106167
+ */
106168
+ static getLangchainMessageContent(msg) {
106169
+ if (msg["content"] !== void 0 && msg["content"] !== null) {
106170
+ return msg["content"];
106171
+ }
106172
+ const kwargs = msg["kwargs"];
106173
+ if (kwargs && typeof kwargs === "object" && !Array.isArray(kwargs)) {
106174
+ const c3 = kwargs["content"];
106175
+ if (c3 !== void 0 && c3 !== null) {
106176
+ return c3;
106177
+ }
106178
+ }
106179
+ return void 0;
106180
+ }
106181
+ static inferLangchainMessageRole(msg) {
106182
+ if (typeof msg["role"] === "string") {
106183
+ return msg["role"];
106184
+ }
106185
+ const kwargs = msg["kwargs"];
106186
+ if (kwargs && typeof kwargs === "object" && !Array.isArray(kwargs)) {
106187
+ const r2 = kwargs["role"];
106188
+ if (typeof r2 === "string") {
106189
+ return r2;
106190
+ }
106191
+ }
106192
+ const id = msg["id"];
106193
+ if (Array.isArray(id)) {
106194
+ const tail = id[id.length - 1];
106195
+ if (tail === "HumanMessage") {
106196
+ return "user";
106197
+ }
106198
+ if (tail === "AIMessage" || tail === "AIMessageChunk") {
106199
+ return "assistant";
106200
+ }
106201
+ if (tail === "SystemMessage") {
106202
+ return "system";
106203
+ }
106204
+ if (tail === "ToolMessage") {
106205
+ return "tool";
106206
+ }
106207
+ }
106208
+ return void 0;
106209
+ }
106210
+ /**
106211
+ * Get last user message content from a messages array (chat/voice format).
106212
+ */
106213
+ static extractLastUserMessageFromArray(messages) {
106214
+ if (!messages.length) return "";
106215
+ for (let i2 = messages.length - 1; i2 >= 0; i2--) {
106216
+ const msg = messages[i2];
106217
+ const role = this.inferLangchainMessageRole(msg);
106218
+ const content2 = this.getLangchainMessageContent(msg);
106219
+ if (role === "user" && content2 != null) {
106220
+ return typeof content2 === "string" ? content2 : JSON.stringify(content2);
106221
+ }
106222
+ }
106223
+ const last2 = messages[messages.length - 1];
106224
+ const content = this.getLangchainMessageContent(last2);
106225
+ if (content != null) {
106226
+ return typeof content === "string" ? content : JSON.stringify(content);
106227
+ }
106228
+ return JSON.stringify(messages[messages.length - 1]);
106229
+ }
106230
+ /**
106231
+ * Extract app response from trace output for display.
106232
+ * Handles string, object with message/content/text/response, and messages array.
105643
106233
  */
105644
106234
  static extractAppResponse(output) {
105645
106235
  if (!output) return "";
105646
106236
  if (typeof output === "string") {
105647
106237
  try {
105648
106238
  const parsed = JSON.parse(output);
105649
- return (parsed == null ? void 0 : parsed.message) || (parsed == null ? void 0 : parsed.content) || (parsed == null ? void 0 : parsed.text) || (parsed == null ? void 0 : parsed.response) || output;
106239
+ const fromParsed = (parsed == null ? void 0 : parsed.message) ?? (parsed == null ? void 0 : parsed.content) ?? (parsed == null ? void 0 : parsed.text) ?? (parsed == null ? void 0 : parsed.response);
106240
+ if (fromParsed !== void 0 && fromParsed !== null) return String(fromParsed);
106241
+ if (Array.isArray(parsed == null ? void 0 : parsed.messages)) {
106242
+ return this.extractLastMessageContentFromArray(parsed.messages);
106243
+ }
106244
+ return output;
105650
106245
  } catch {
105651
106246
  return output;
105652
106247
  }
105653
106248
  }
105654
106249
  if (typeof output === "object") {
105655
106250
  const obj = output;
105656
- return String((obj == null ? void 0 : obj["message"]) || (obj == null ? void 0 : obj["content"]) || (obj == null ? void 0 : obj["text"]) || (obj == null ? void 0 : obj["response"]) || "");
106251
+ const direct = (obj == null ? void 0 : obj["message"]) ?? (obj == null ? void 0 : obj["content"]) ?? (obj == null ? void 0 : obj["text"]) ?? (obj == null ? void 0 : obj["response"]);
106252
+ if (direct !== void 0 && direct !== null && direct !== "") {
106253
+ return typeof direct === "object" ? JSON.stringify(direct) : String(direct);
106254
+ }
106255
+ if (Array.isArray(obj == null ? void 0 : obj.messages)) {
106256
+ return this.extractLastMessageContentFromArray(obj.messages);
106257
+ }
106258
+ if (Array.isArray(output)) {
106259
+ return this.extractLastMessageContentFromArray(output);
106260
+ }
106261
+ return JSON.stringify(obj);
105657
106262
  }
105658
106263
  return String(output);
105659
106264
  }
106265
+ /**
106266
+ * Get last message content from a messages array for output display.
106267
+ */
106268
+ static extractLastMessageContentFromArray(messages) {
106269
+ if (!messages.length) return "";
106270
+ const last2 = messages[messages.length - 1];
106271
+ const fromKwargs = this.getLangchainMessageContent(last2);
106272
+ const content = fromKwargs ?? (last2 == null ? void 0 : last2.message) ?? (last2 == null ? void 0 : last2.text);
106273
+ if (content != null) return typeof content === "string" ? content : JSON.stringify(content);
106274
+ return JSON.stringify(last2);
106275
+ }
105660
106276
  /**
105661
106277
  * Calculate trace metrics from observations
105662
106278
  */
@@ -105666,7 +106282,9 @@ class TraceTreeService {
105666
106282
  let maxEndTime = 0;
105667
106283
  let minStartTime = Infinity;
105668
106284
  observations.forEach((obs) => {
105669
- totalTokens += obs.totalTokens || 0;
106285
+ var _a;
106286
+ const obsTokens = ((_a = obs.usageDetails) == null ? void 0 : _a.total) ?? obs.totalUsage ?? obs.totalTokens;
106287
+ totalTokens += typeof obsTokens === "number" ? obsTokens : parseInt(String(obsTokens || 0), 10) || 0;
105670
106288
  const cost = parseFloat(obs.totalCost || "0");
105671
106289
  if (!isNaN(cost)) totalCost += cost;
105672
106290
  const startMs = new Date(obs.startTime).getTime();
@@ -105689,7 +106307,15 @@ class TraceTreeService {
105689
106307
  );
105690
106308
  const generation = sorted.find((obs) => obs.type === "GENERATION");
105691
106309
  if (!generation) {
105692
- return { observation: null, ancestorIds: [] };
106310
+ const tree = this.buildObservationTree(observations);
106311
+ if (tree.length === 0) return { observation: null, ancestorIds: [] };
106312
+ const findFirstLeaf = (node) => {
106313
+ if (node.children.length === 0) return node;
106314
+ return findFirstLeaf(node.children[0]);
106315
+ };
106316
+ const leafNode = findFirstLeaf(tree[0]);
106317
+ const ancestorIds2 = this.getAncestorIds(observations, leafNode.observation.id);
106318
+ return { observation: leafNode.observation, ancestorIds: ancestorIds2 };
105693
106319
  }
105694
106320
  const ancestorIds = this.getAncestorIds(observations, generation.id);
105695
106321
  return { observation: generation, ancestorIds };
@@ -105836,6 +106462,7 @@ const observationFilterConfig = {
105836
106462
  "toolNode",
105837
106463
  "agent_toolNode",
105838
106464
  "PreProcessor",
106465
+ "PostProcessor",
105839
106466
  "MergerNode"
105840
106467
  ]
105841
106468
  }
@@ -106095,6 +106722,7 @@ class DetailPageService {
106095
106722
  * Transform API trace response to TraceDetailData
106096
106723
  */
106097
106724
  transformToTraceDetailData(trace) {
106725
+ const piiDisplay = TraceTreeService.extractPiiDisplayFromApiTrace(trace);
106098
106726
  return {
106099
106727
  id: trace.id,
106100
106728
  name: trace.name || "",
@@ -106107,6 +106735,8 @@ class DetailPageService {
106107
106735
  input: trace.input,
106108
106736
  output: trace.output,
106109
106737
  metadata: trace.metadata,
106738
+ displayUserMessage: piiDisplay.displayUserMessage,
106739
+ displayAppResponse: piiDisplay.displayAppResponse,
106110
106740
  tags: trace.tags || [],
106111
106741
  bookmarked: trace.bookmarked || false,
106112
106742
  public: trace.public || false,
@@ -106168,6 +106798,8 @@ class DetailPageService {
106168
106798
  timestamp: trace.timestamp,
106169
106799
  input: trace.input,
106170
106800
  output: trace.output,
106801
+ displayUserMessage: trace.displayUserMessage,
106802
+ displayAppResponse: trace.displayAppResponse,
106171
106803
  latency: trace.latency,
106172
106804
  totalTokens: trace.totalTokens,
106173
106805
  totalCost: typeof trace.totalCost === "number" ? String(trace.totalCost) : trace.totalCost,
@@ -106321,6 +106953,19 @@ function getObservationIconProps(observation) {
106321
106953
  name
106322
106954
  };
106323
106955
  }
106956
+ function getObservationTokens(obs) {
106957
+ var _a;
106958
+ const total = ((_a = obs.usageDetails) == null ? void 0 : _a.total) ?? obs.totalUsage ?? obs.totalTokens;
106959
+ if (total === void 0 || total === null) return 0;
106960
+ return typeof total === "number" ? total : parseInt(String(total), 10) || 0;
106961
+ }
106962
+ function getAggregatedTotalTokens(node) {
106963
+ let sum2 = getObservationTokens(node.observation);
106964
+ node.children.forEach((child) => {
106965
+ sum2 += getAggregatedTotalTokens(child);
106966
+ });
106967
+ return sum2;
106968
+ }
106324
106969
  const SuccessIcon = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
106325
106970
  /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "6", cy: "6", r: "5.5", fill: "#17B26A" }),
106326
106971
  /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M4 6L5.5 7.5L8 4.5", stroke: "white", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
@@ -106382,7 +107027,11 @@ function ObservationNode({
106382
107027
  return observation.name || observation.type || "";
106383
107028
  };
106384
107029
  const displayName = getDisplayName3();
106385
- const displayTokens = ((_d = observation.usageDetails) == null ? void 0 : _d.total) || observation.totalUsage || observation.totalTokens;
107030
+ const displayTokens = ((_d = observation.usageDetails) == null ? void 0 : _d.total) ?? observation.totalUsage ?? observation.totalTokens;
107031
+ const aggregatedTotalTokens = useMemo(() => {
107032
+ if (!isSupervisorOrAgent) return 0;
107033
+ return getAggregatedTotalTokens(node);
107034
+ }, [node, isSupervisorOrAgent]);
106386
107035
  const handleRowClick = () => {
106387
107036
  if (hasChildren) {
106388
107037
  onToggle(observation.id);
@@ -106429,34 +107078,43 @@ function ObservationNode({
106429
107078
  className: "w-[24px] h-[24px] rounded-[8px]"
106430
107079
  }
106431
107080
  ) }),
106432
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-[12px] leading-[16px] text-[#101828] truncate flex-1 min-w-0", title: displayName, children: displayName }),
106433
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[8px] flex-shrink-0", children: [
106434
- isSupervisorOrAgent && (modelFromMetadata || observation.model) && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] leading-[12px] text-[#667085] font-normal", children: modelFromMetadata || observation.model }),
106435
- (isGeneration || isSupervisorOrAgent) && displayTokens !== void 0 && displayTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] leading-[12px] text-[#667085] font-normal whitespace-nowrap", children: [
106436
- TraceTreeService.formatTokens(displayTokens),
107081
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-[2px] flex-1 min-w-0", children: [
107082
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-[12px] leading-[16px] text-[#101828] truncate", title: displayName, children: displayName }),
107083
+ isSupervisorOrAgent && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[6px] flex-wrap text-[10px] leading-[12px] text-[#667085] font-normal", children: [
107084
+ modelFromMetadata || observation.model ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: modelFromMetadata || observation.model }) : null,
107085
+ aggregatedTotalTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
107086
+ (modelFromMetadata || observation.model) && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "·" }),
107087
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "whitespace-nowrap", children: [
107088
+ TraceTreeService.formatTokens(aggregatedTotalTokens),
107089
+ " Tokens"
107090
+ ] })
107091
+ ] }),
107092
+ duration > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
107093
+ modelFromMetadata || observation.model || aggregatedTotalTokens > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "·" }) : null,
107094
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "whitespace-nowrap flex items-center gap-[4px]", children: [
107095
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ClockIcon, {}),
107096
+ TraceTreeService.formatDuration(duration)
107097
+ ] })
107098
+ ] })
107099
+ ] })
107100
+ ] }),
107101
+ !isSupervisorOrAgent && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[8px] flex-shrink-0", children: [
107102
+ isGeneration && displayTokens !== void 0 && Number(displayTokens) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] leading-[12px] text-[#667085] font-normal whitespace-nowrap", children: [
107103
+ TraceTreeService.formatTokens(Number(displayTokens)),
106437
107104
  " Tokens"
106438
107105
  ] }),
106439
107106
  duration > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[4px]", children: [
106440
107107
  /* @__PURE__ */ jsxRuntimeExports.jsx(ClockIcon, {}),
106441
107108
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] leading-[12px] text-[#667085] font-normal whitespace-nowrap", children: TraceTreeService.formatDuration(duration) })
106442
107109
  ] }),
106443
- isError && /* @__PURE__ */ jsxRuntimeExports.jsx(
106444
- "div",
106445
- {
106446
- className: "flex-shrink-0 cursor-help",
106447
- title: statusTooltip,
106448
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorIcon, {})
106449
- }
106450
- ),
106451
- isWarning && !isError && /* @__PURE__ */ jsxRuntimeExports.jsx(
106452
- "div",
106453
- {
106454
- className: "flex-shrink-0 cursor-help",
106455
- title: statusTooltip,
106456
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(WarningIcon, {})
106457
- }
106458
- ),
107110
+ isError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0 cursor-help", title: statusTooltip, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorIcon, {}) }),
107111
+ isWarning && !isError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0 cursor-help", title: statusTooltip, children: /* @__PURE__ */ jsxRuntimeExports.jsx(WarningIcon, {}) }),
106459
107112
  isCompleted && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SuccessIcon, {}) })
107113
+ ] }),
107114
+ isSupervisorOrAgent && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-shrink-0 flex items-center", children: [
107115
+ isError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "cursor-help", title: statusTooltip, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorIcon, {}) }),
107116
+ isWarning && !isError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "cursor-help", title: statusTooltip, children: /* @__PURE__ */ jsxRuntimeExports.jsx(WarningIcon, {}) }),
107117
+ isCompleted && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(SuccessIcon, {}) })
106460
107118
  ] })
106461
107119
  ]
106462
107120
  }
@@ -106494,8 +107152,10 @@ function TraceTree({
106494
107152
  onNodeSelect,
106495
107153
  onExpandToggle,
106496
107154
  showTraceId = true,
107155
+ onTraceIdClick,
106497
107156
  isLoading = false,
106498
- defaultExpandedNodeIds
107157
+ defaultExpandedNodeIds,
107158
+ runHeaderInputMode = "display"
106499
107159
  }) {
106500
107160
  const [isExpanded, setIsExpanded] = useState(defaultExpanded);
106501
107161
  const [expandedNodeIds, setExpandedNodeIds] = useState(
@@ -106513,11 +107173,20 @@ function TraceTree({
106513
107173
  return TraceTreeService.buildObservationTree(observations);
106514
107174
  }, [observations]);
106515
107175
  const userMessage = useMemo(() => {
107176
+ if (runHeaderInputMode !== "tokenized" && trace.displayUserMessage !== void 0 && trace.displayUserMessage.length > 0) {
107177
+ return trace.displayUserMessage;
107178
+ }
106516
107179
  return TraceTreeService.extractUserMessage(trace.input);
106517
- }, [trace.input]);
107180
+ }, [trace.input, trace.displayUserMessage, runHeaderInputMode]);
106518
107181
  const appResponse = useMemo(() => {
107182
+ if (runHeaderInputMode !== "tokenized" && trace.displayAppResponse !== void 0 && trace.displayAppResponse.length > 0) {
107183
+ return trace.displayAppResponse;
107184
+ }
106519
107185
  return TraceTreeService.extractAppResponse(trace.output);
106520
- }, [trace.output]);
107186
+ }, [trace.output, trace.displayAppResponse, runHeaderInputMode]);
107187
+ const traceMetrics = useMemo(() => {
107188
+ return TraceTreeService.calculateTraceMetrics(trace, observations);
107189
+ }, [trace, observations]);
106521
107190
  const handleTraceToggle = useCallback(() => {
106522
107191
  setIsExpanded((prev) => !prev);
106523
107192
  onExpandToggle == null ? void 0 : onExpandToggle();
@@ -106544,7 +107213,16 @@ function TraceTree({
106544
107213
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-[4px] w-full mb-[8px]", children: [
106545
107214
  showTraceId && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-[8px] items-center px-0 py-[4px] w-full", children: [
106546
107215
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] leading-[12px] text-[#98A2B3]", children: "Trace ID" }),
106547
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium text-[10px] leading-[12px] text-[#667085]", children: trace.id }),
107216
+ onTraceIdClick ? /* @__PURE__ */ jsxRuntimeExports.jsx(
107217
+ "button",
107218
+ {
107219
+ onClick: () => onTraceIdClick(trace.id),
107220
+ className: "font-medium text-[10px] leading-[12px] text-[#155EEF] hover:underline cursor-pointer bg-transparent border-none p-0",
107221
+ title: "View Trace Details",
107222
+ "data-test-id": `trace-tree-id-link-${trace.id}`,
107223
+ children: trace.id
107224
+ }
107225
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium text-[10px] leading-[12px] text-[#667085]", children: trace.id }),
106548
107226
  /* @__PURE__ */ jsxRuntimeExports.jsx(
106549
107227
  "button",
106550
107228
  {
@@ -106619,10 +107297,18 @@ function TraceTree({
106619
107297
  rootNode.observation.id
106620
107298
  )) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-[16px] text-[12px] text-[#667085] text-center", children: "No observations available" }) }),
106621
107299
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white flex flex-col gap-[8px] p-[12px] border-t border-[#EAECF0]", children: [
106622
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-[8px] items-center w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-[8px] items-center flex-1 min-w-0", children: [
106623
- /* @__PURE__ */ jsxRuntimeExports.jsx(AppResponseIcon, {}),
106624
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-[11px] leading-[14px] text-[#98A2B3] uppercase tracking-[0.02em] flex-1", children: "APP RESPONSE" })
106625
- ] }) }),
107300
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-[8px] items-center w-full", children: [
107301
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-[8px] items-center flex-1 min-w-0", children: [
107302
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AppResponseIcon, {}),
107303
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-[11px] leading-[14px] text-[#98A2B3] uppercase tracking-[0.02em]", children: "APP RESPONSE" })
107304
+ ] }),
107305
+ (traceMetrics.latency > 0 || traceMetrics.totalTokens > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] leading-[12px] text-[#667085] font-normal whitespace-nowrap flex-shrink-0", children: [
107306
+ TraceTreeService.formatDuration(traceMetrics.latency),
107307
+ " · ",
107308
+ TraceTreeService.formatTokens(traceMetrics.totalTokens),
107309
+ " Tokens"
107310
+ ] })
107311
+ ] }),
106626
107312
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium text-[12px] leading-[16px] text-[#101828]", children: appResponse ? appResponse.length > 150 && !isResponseExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
106627
107313
  appResponse.substring(0, 150),
106628
107314
  "...",
@@ -106655,114 +107341,6 @@ function TraceTree({
106655
107341
  ] })
106656
107342
  ] });
106657
107343
  }
106658
- const CopyButton$1 = ({
106659
- text,
106660
- className = "",
106661
- iconClassName = "",
106662
- iconStyle,
106663
- title = "Copy to clipboard",
106664
- onCopySuccess,
106665
- onCopyError,
106666
- tooltipText = "Copied!",
106667
- tooltipPosition = "bottom",
106668
- size = "md"
106669
- }) => {
106670
- const [showTooltip, setShowTooltip] = useState(false);
106671
- const getSizeClasses = () => {
106672
- switch (size) {
106673
- case "sm":
106674
- return {
106675
- button: "p-1",
106676
- icon: "w-[12px] h-[12px]",
106677
- tooltip: "text-xs py-1 px-2"
106678
- };
106679
- case "lg":
106680
- return {
106681
- button: "p-2",
106682
- icon: "w-[20px] h-[20px]",
106683
- tooltip: "text-sm py-2 px-3"
106684
- };
106685
- default:
106686
- return {
106687
- button: "p-1.5",
106688
- icon: "w-[16px] h-[16px]",
106689
- tooltip: "text-xs py-1 px-2"
106690
- };
106691
- }
106692
- };
106693
- const getTooltipPositionClasses = () => {
106694
- const baseClasses = "absolute bg-gray-800 text-white rounded whitespace-nowrap z-50";
106695
- switch (tooltipPosition) {
106696
- case "bottom":
106697
- return `${baseClasses} top-full mt-1 left-1/2 -translate-x-1/2`;
106698
- case "left":
106699
- return `${baseClasses} right-full mr-1 top-1/2 -translate-y-1/2`;
106700
- case "right":
106701
- return `${baseClasses} left-full ml-1 top-1/2 -translate-y-1/2`;
106702
- default:
106703
- return `${baseClasses} bottom-full mb-1 left-1/2 -translate-x-1/2`;
106704
- }
106705
- };
106706
- const sizeClasses2 = getSizeClasses();
106707
- const showCopyTooltip = useCallback(() => {
106708
- setShowTooltip(true);
106709
- setTimeout(() => setShowTooltip(false), 1e3);
106710
- }, []);
106711
- const copyToClipboard2 = useCallback(async () => {
106712
- try {
106713
- if (navigator.clipboard && navigator.clipboard.writeText) {
106714
- await navigator.clipboard.writeText(text);
106715
- showCopyTooltip();
106716
- onCopySuccess == null ? void 0 : onCopySuccess();
106717
- return;
106718
- }
106719
- const textArea = document.createElement("textarea");
106720
- textArea.value = text;
106721
- textArea.style.position = "fixed";
106722
- textArea.style.left = "-999999px";
106723
- textArea.style.top = "-999999px";
106724
- document.body.appendChild(textArea);
106725
- textArea.focus();
106726
- textArea.select();
106727
- try {
106728
- document.execCommand("copy");
106729
- showCopyTooltip();
106730
- onCopySuccess == null ? void 0 : onCopySuccess();
106731
- } catch (err) {
106732
- const error = err instanceof Error ? err : new Error("Copy failed");
106733
- console.warn("Copy to clipboard failed:", error);
106734
- onCopyError == null ? void 0 : onCopyError(error);
106735
- } finally {
106736
- document.body.removeChild(textArea);
106737
- }
106738
- } catch (err) {
106739
- const error = err instanceof Error ? err : new Error("Copy failed");
106740
- console.warn("Copy to clipboard failed:", error);
106741
- onCopyError == null ? void 0 : onCopyError(error);
106742
- }
106743
- }, [text, showCopyTooltip, onCopySuccess, onCopyError]);
106744
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative inline-flex", children: [
106745
- /* @__PURE__ */ jsxRuntimeExports.jsx(
106746
- "button",
106747
- {
106748
- onClick: copyToClipboard2,
106749
- className: `${sizeClasses2.button} hover:bg-gray-100 rounded transition-colors ${className}`,
106750
- title,
106751
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: `${sizeClasses2.icon} text-gray-400 ${iconClassName}`, style: iconStyle })
106752
- }
106753
- ),
106754
- /* @__PURE__ */ jsxRuntimeExports.jsx(
106755
- "div",
106756
- {
106757
- className: `${getTooltipPositionClasses()} ${sizeClasses2.tooltip} transition-opacity duration-150 ${showTooltip ? "opacity-100 animate-fade-in" : "opacity-0 pointer-events-none"}`,
106758
- style: {
106759
- visibility: showTooltip ? "visible" : "hidden"
106760
- },
106761
- children: tooltipText
106762
- }
106763
- )
106764
- ] });
106765
- };
106766
107344
  function __awaiter(thisArg, _arguments, P2, generator) {
106767
107345
  function adopt(value) {
106768
107346
  return value instanceof P2 ? value : new P2(function(resolve) {
@@ -107927,21 +108505,35 @@ const DataModal = ({
107927
108505
  )
107928
108506
  ] })
107929
108507
  ] }),
107930
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-auto bg-gray-800 p-4", children: viewMode === "interactive" && useEnhancedJsonView ? /* @__PURE__ */ jsxRuntimeExports.jsx(
107931
- JsonView,
108508
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
108509
+ "div",
107932
108510
  {
107933
- src: parsedData,
107934
- theme: "github",
107935
- dark: true,
107936
- collapseObjectsAfterLength: 20,
107937
- collapseStringsAfterLength: 500,
107938
- collapseStringMode: "word",
107939
- displaySize: "collapsed",
107940
- matchesURL: true,
107941
- customizeCopy: (node) => stringifyJsonNode(node),
107942
- className: "w-full text-xs"
108511
+ className: "flex-1 overflow-auto bg-gray-800 p-4",
108512
+ style: {
108513
+ "--json-property": "#ffffff",
108514
+ "--json-index": "#e2e8f0",
108515
+ "--json-number": "#e2e8f0",
108516
+ "--json-string": "#e2e8f0",
108517
+ "--json-boolean": "#e2e8f0",
108518
+ "--json-null": "#e2e8f0"
108519
+ },
108520
+ children: viewMode === "interactive" && useEnhancedJsonView ? /* @__PURE__ */ jsxRuntimeExports.jsx(
108521
+ JsonView,
108522
+ {
108523
+ src: parsedData,
108524
+ dark: true,
108525
+ collapseObjectsAfterLength: 20,
108526
+ collapseStringsAfterLength: 500,
108527
+ collapseStringMode: "word",
108528
+ displaySize: "collapsed",
108529
+ matchesURL: true,
108530
+ customizeCopy: (node) => stringifyJsonNode(node),
108531
+ className: "w-full text-xs",
108532
+ style: { color: "#f1f5f9" }
108533
+ }
108534
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs whitespace-pre text-white font-mono", children: stringifyJsonNode(parsedData) })
107943
108535
  }
107944
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs whitespace-pre text-gray-300 font-mono", children: stringifyJsonNode(parsedData) }) })
108536
+ )
107945
108537
  ] }) });
107946
108538
  };
107947
108539
  const JsonViewer = ({
@@ -108309,6 +108901,23 @@ function formatUnknownValue(value) {
108309
108901
  function isObservation(node) {
108310
108902
  return node !== null && "traceId" in node && "type" in node;
108311
108903
  }
108904
+ function metadataForDisplay(metadata) {
108905
+ if (metadata === null || metadata === void 0) return {};
108906
+ let obj;
108907
+ if (typeof metadata === "string") {
108908
+ try {
108909
+ obj = JSON.parse(metadata);
108910
+ } catch {
108911
+ return {};
108912
+ }
108913
+ } else if (typeof metadata === "object") {
108914
+ obj = metadata;
108915
+ } else {
108916
+ return {};
108917
+ }
108918
+ const { tools: _tools, ...rest } = obj;
108919
+ return rest;
108920
+ }
108312
108921
  const defaultMetrics = {
108313
108922
  totalCost: "0",
108314
108923
  totalTokens: 0,
@@ -108357,7 +108966,7 @@ function SectionHeader({ title }) {
108357
108966
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 h-[1px] bg-[#EAECF0]" })
108358
108967
  ] });
108359
108968
  }
108360
- function PreviewContent({ input, output, metadata, statusMessage, isLoading = false, modelParameters }) {
108969
+ function PreviewContent({ input, output, metadata, statusMessage, isLoading = false }) {
108361
108970
  const [showAllMetadata, setShowAllMetadata] = useState(false);
108362
108971
  const messages = useMemo(() => {
108363
108972
  if (!input || typeof input !== "object") return null;
@@ -108389,15 +108998,6 @@ function PreviewContent({ input, output, metadata, statusMessage, isLoading = fa
108389
108998
  }
108390
108999
  return String(output);
108391
109000
  }, [output]);
108392
- const modelName = useMemo(() => {
108393
- if (!input || typeof input !== "object") return null;
108394
- return input["model"] ?? null;
108395
- }, [input]);
108396
- const formatParamValue = (value) => {
108397
- if (value === null || value === void 0) return "";
108398
- if (typeof value === "object") return JSON.stringify(value);
108399
- return String(value);
108400
- };
108401
109001
  if (isLoading) {
108402
109002
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-[16px] p-[16px] overflow-y-auto h-full", children: [
108403
109003
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
@@ -108411,29 +109011,6 @@ function PreviewContent({ input, output, metadata, statusMessage, isLoading = fa
108411
109011
  ] });
108412
109012
  }
108413
109013
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-[20px] p-[16px] overflow-y-auto h-full", children: [
108414
- (modelName || modelParameters && Object.keys(modelParameters).length > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-[6px]", children: [
108415
- modelName && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-[8px] py-[4px] bg-[#F2F4F7] rounded-[4px] text-[11px] font-medium text-[#344054]", children: [
108416
- "Model: ",
108417
- modelName
108418
- ] }),
108419
- modelParameters && typeof modelParameters === "object" && Object.entries(modelParameters).filter(([_2, value]) => value !== null && value !== void 0).map(([key, value]) => {
108420
- const valueString = formatParamValue(value);
108421
- const displayKey = key.replace(/_/g, " ");
108422
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
108423
- "span",
108424
- {
108425
- className: "px-[8px] py-[4px] bg-[#F2F4F7] border border-[#EAECF0] rounded-[4px] text-[11px] font-medium text-[#344054] max-w-[200px] truncate",
108426
- title: `${key}: ${valueString}`,
108427
- children: [
108428
- displayKey,
108429
- ": ",
108430
- valueString
108431
- ]
108432
- },
108433
- key
108434
- );
108435
- })
108436
- ] }),
108437
109014
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
108438
109015
  /* @__PURE__ */ jsxRuntimeExports.jsx(SectionHeader, { title: "Input" }),
108439
109016
  messages ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-[8px]", children: messages.map((msg, index) => /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -108520,14 +109097,21 @@ function CodeEditorSection({
108520
109097
  showHeader: true,
108521
109098
  useEnhancedJsonView: true,
108522
109099
  collapseStringsAfterLength: 500,
108523
- collapseObjectsAfterLength: 20,
109100
+ collapseObjectsAfterLength: selectedTab === "metadata" ? 100 : 20,
109101
+ defaultExpanded: selectedTab === "metadata",
108524
109102
  maxHeight: "100%",
108525
109103
  className: "h-full border-0 rounded-none"
108526
- }
109104
+ },
109105
+ selectedTab
108527
109106
  ) })
108528
109107
  ] });
108529
109108
  }
108530
- function NodeDetailPanel({ node, nodeType: _nodeType, apiConfig }) {
109109
+ function NodeDetailPanel({
109110
+ node,
109111
+ nodeType: _nodeType,
109112
+ apiConfig,
109113
+ generationSummaryInputOverride = null
109114
+ }) {
108531
109115
  const [selectedTab, setSelectedTab] = useState("preview");
108532
109116
  const [showTokenTooltip, setShowTokenTooltip] = useState(false);
108533
109117
  const tooltipTimeoutRef = useRef(null);
@@ -108614,6 +109198,7 @@ function NodeDetailPanel({ node, nodeType: _nodeType, apiConfig }) {
108614
109198
  }
108615
109199
  return TraceTreeService.extractUserMessage(displayNode.input);
108616
109200
  }, [displayNode]);
109201
+ const summaryInputLine = generationSummaryInputOverride !== null && generationSummaryInputOverride.length > 0 ? generationSummaryInputOverride : inputText;
108617
109202
  const isGeneration = useMemo(() => {
108618
109203
  return node !== null && isObservation(node) && node.type === "GENERATION";
108619
109204
  }, [node]);
@@ -108697,7 +109282,7 @@ function NodeDetailPanel({ node, nodeType: _nodeType, apiConfig }) {
108697
109282
  case "response":
108698
109283
  return displayNode.output || {};
108699
109284
  case "metadata":
108700
- return isObservation(displayNode) ? displayNode.metadata || {} : {};
109285
+ return isObservation(displayNode) ? metadataForDisplay(displayNode.metadata || {}) : {};
108701
109286
  case "logs":
108702
109287
  return {
108703
109288
  id: isObservation(displayNode) ? displayNode.id : displayNode.id,
@@ -108717,11 +109302,17 @@ function NodeDetailPanel({ node, nodeType: _nodeType, apiConfig }) {
108717
109302
  return {
108718
109303
  input: formattedInput,
108719
109304
  output: displayNode.output || {},
108720
- metadata: isObservation(displayNode) ? displayNode.metadata || {} : {},
109305
+ metadata: isObservation(displayNode) ? metadataForDisplay(displayNode.metadata || {}) : {},
108721
109306
  statusMessage: isObservation(displayNode) ? displayNode.statusMessage : void 0,
108722
109307
  modelParameters: isObservation(displayNode) ? displayNode.modelParameters : void 0
108723
109308
  };
108724
109309
  }, [displayNode, formattedInput]);
109310
+ const summaryModelInfo = useMemo(() => {
109311
+ if (!isGeneration || !displayNode) return { modelName: null, modelParameters: {} };
109312
+ const modelName = typeof formattedInput === "object" && formattedInput !== null && "model" in formattedInput ? formattedInput.model ?? null : null;
109313
+ const modelParameters = isObservation(displayNode) && displayNode.modelParameters && typeof displayNode.modelParameters === "object" ? displayNode.modelParameters : {};
109314
+ return { modelName, modelParameters };
109315
+ }, [isGeneration, displayNode, formattedInput]);
108725
109316
  const tokenTooltipContent = metrics.totalTokens > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
108726
109317
  "div",
108727
109318
  {
@@ -108814,10 +109405,10 @@ function NodeDetailPanel({ node, nodeType: _nodeType, apiConfig }) {
108814
109405
  ] })
108815
109406
  ),
108816
109407
  /* @__PURE__ */ jsxRuntimeExports.jsx(ContentDivider, {}),
108817
- isGeneration && inputText.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
109408
+ isGeneration && summaryInputLine.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
108818
109409
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-[8px]", children: [
108819
109410
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[12px] font-medium leading-[16px] text-[#98A2B3]", children: "Input" }),
108820
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[12px] font-medium leading-[16px] text-[#101828] truncate", children: inputText })
109411
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[12px] font-medium leading-[16px] text-[#101828] truncate", children: summaryInputLine })
108821
109412
  ] }),
108822
109413
  /* @__PURE__ */ jsxRuntimeExports.jsx(ContentDivider, {})
108823
109414
  ] }),
@@ -108833,6 +109424,37 @@ function NodeDetailPanel({ node, nodeType: _nodeType, apiConfig }) {
108833
109424
  ] })
108834
109425
  ] }),
108835
109426
  /* @__PURE__ */ jsxRuntimeExports.jsx(ContentDivider, {})
109427
+ ] }),
109428
+ isGeneration && (summaryModelInfo.modelName || Object.keys(summaryModelInfo.modelParameters).length > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
109429
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-[8px]", children: [
109430
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[12px] font-medium leading-[16px] text-[#98A2B3]", children: "Model parameters" }),
109431
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-[6px]", children: [
109432
+ summaryModelInfo.modelName && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-[8px] py-[4px] bg-[#F2F4F7] rounded-[4px] text-[11px] font-medium text-[#344054]", children: [
109433
+ "Model: ",
109434
+ summaryModelInfo.modelName
109435
+ ] }),
109436
+ Object.entries(summaryModelInfo.modelParameters).filter(
109437
+ ([_2, value]) => value !== null && value !== void 0
109438
+ ).map(([key, value]) => {
109439
+ const valueStr = typeof value === "object" ? JSON.stringify(value) : String(value);
109440
+ const displayKey = key.replace(/_/g, " ");
109441
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
109442
+ "span",
109443
+ {
109444
+ className: "px-[8px] py-[4px] bg-[#F2F4F7] border border-[#EAECF0] rounded-[4px] text-[11px] font-medium text-[#344054] max-w-[200px] truncate",
109445
+ title: `${key}: ${valueStr}`,
109446
+ children: [
109447
+ displayKey,
109448
+ ": ",
109449
+ valueStr
109450
+ ]
109451
+ },
109452
+ key
109453
+ );
109454
+ })
109455
+ ] })
109456
+ ] }),
109457
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ContentDivider, {})
108836
109458
  ] })
108837
109459
  ] })
108838
109460
  ] }),
@@ -108860,7 +109482,8 @@ function DetailPage({
108860
109482
  selectedObservationId,
108861
109483
  batchSize = DEFAULT_BATCH_SIZE,
108862
109484
  initialTraceCount,
108863
- initialSessionData
109485
+ initialSessionData,
109486
+ runHeaderInputMode = "display"
108864
109487
  }) {
108865
109488
  const [currentMode, setCurrentMode] = useState(initialMode);
108866
109489
  const [currentSessionId, setCurrentSessionId] = useState(initialSessionId);
@@ -109101,12 +109724,52 @@ function DetailPage({
109101
109724
  }, [mode, sessionData, traceData, sessionId, traceId, initialSessionData]);
109102
109725
  const traces = useMemo(() => {
109103
109726
  if (mode === "session" && sessionData) {
109104
- return sessionData.traces.map((t2) => service.transformToTraceData(t2));
109727
+ const sorted = [...sessionData.traces].sort((a4, b2) => {
109728
+ const tA = a4.timestamp ? new Date(a4.timestamp).getTime() : 0;
109729
+ const tB = b2.timestamp ? new Date(b2.timestamp).getTime() : 0;
109730
+ return tA - tB;
109731
+ });
109732
+ return sorted.map((t2) => service.transformToTraceData(t2));
109105
109733
  } else if (mode === "trace" && traceData) {
109106
109734
  return [service.transformToTraceData(traceData)];
109107
109735
  }
109108
109736
  return [];
109109
109737
  }, [mode, sessionData, traceData, service]);
109738
+ const generationSummaryInputOverride = useMemo(() => {
109739
+ var _a;
109740
+ if (runHeaderInputMode === "tokenized") {
109741
+ return null;
109742
+ }
109743
+ if (!selectedNode || !("traceId" in selectedNode) || !("type" in selectedNode)) {
109744
+ return null;
109745
+ }
109746
+ const obs = selectedNode;
109747
+ if (obs.type !== "GENERATION") {
109748
+ return null;
109749
+ }
109750
+ const traceRow = traces.find((t2) => t2.id === obs.traceId);
109751
+ if (!traceRow) {
109752
+ return null;
109753
+ }
109754
+ const displayUser = traceRow.displayUserMessage && traceRow.displayUserMessage.length > 0 ? traceRow.displayUserMessage : TraceTreeService.extractUserMessage(traceRow.input);
109755
+ if (!displayUser || displayUser.length === 0) {
109756
+ return null;
109757
+ }
109758
+ const fromState = (_a = traceObservations[obs.traceId]) == null ? void 0 : _a.observations;
109759
+ const observations = fromState && fromState.length > 0 ? fromState : mode === "trace" && (traceData == null ? void 0 : traceData.id) === obs.traceId && traceData.observations.length > 0 ? traceData.observations : [];
109760
+ const { observation: firstGen } = TraceTreeService.findFirstGeneration(observations);
109761
+ if (!firstGen || firstGen.id !== obs.id) {
109762
+ return null;
109763
+ }
109764
+ return displayUser;
109765
+ }, [
109766
+ runHeaderInputMode,
109767
+ selectedNode,
109768
+ traces,
109769
+ traceObservations,
109770
+ mode,
109771
+ traceData
109772
+ ]);
109110
109773
  const handleNodeSelect = useCallback((node) => {
109111
109774
  setSelectedNode(node);
109112
109775
  }, []);
@@ -109155,6 +109818,23 @@ function DetailPage({
109155
109818
  firstTraceId: null
109156
109819
  });
109157
109820
  }, []);
109821
+ const handleNavigateToTrace = useCallback((targetTraceId) => {
109822
+ setSelectedNode(null);
109823
+ setSessionData(null);
109824
+ setTraceData(null);
109825
+ setTraceObservations({});
109826
+ setLoadingState("idle");
109827
+ setError(null);
109828
+ setHasAutoSelected(false);
109829
+ setCurrentMode("trace");
109830
+ setCurrentTraceId(targetTraceId);
109831
+ setProgressiveState({
109832
+ traceCount: 0,
109833
+ pendingTraceIds: [],
109834
+ firstTraceLoaded: false,
109835
+ firstTraceId: null
109836
+ });
109837
+ }, []);
109158
109838
  if (loadingState === "loading") {
109159
109839
  const canShowHeader = mode === "session" && initialSessionData;
109160
109840
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `h-full flex flex-col bg-white ${className}`, children: [
@@ -109323,8 +110003,10 @@ function DetailPage({
109323
110003
  onNodeSelect: handleNodeSelect,
109324
110004
  onExpandToggle: () => handleTraceExpand(trace.id, trace.timestamp),
109325
110005
  showTraceId: mode === "session",
110006
+ onTraceIdClick: mode === "session" ? handleNavigateToTrace : void 0,
109326
110007
  isLoading: isLoadingObservations,
109327
- defaultExpandedNodeIds: autoExpandIds
110008
+ defaultExpandedNodeIds: autoExpandIds,
110009
+ runHeaderInputMode
109328
110010
  },
109329
110011
  trace.id
109330
110012
  );
@@ -109344,7 +110026,15 @@ function DetailPage({
109344
110026
  );
109345
110027
  }) })
109346
110028
  ] }) }),
109347
- !selectedNode && !hasAutoSelected ? /* @__PURE__ */ jsxRuntimeExports.jsx(NodeDetailSkeleton, { showFullSummary: true }) : /* @__PURE__ */ jsxRuntimeExports.jsx(NodeDetailPanel, { node: selectedNode, nodeType, apiConfig })
110029
+ !selectedNode && !hasAutoSelected ? /* @__PURE__ */ jsxRuntimeExports.jsx(NodeDetailSkeleton, { showFullSummary: true }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
110030
+ NodeDetailPanel,
110031
+ {
110032
+ node: selectedNode,
110033
+ nodeType,
110034
+ apiConfig,
110035
+ generationSummaryInputOverride
110036
+ }
110037
+ )
109348
110038
  ] })
109349
110039
  ] });
109350
110040
  }
@@ -109759,22 +110449,25 @@ function EnvironmentNameCell$1({ envId }) {
109759
110449
  return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-600", title: envId || "-", children: displayName });
109760
110450
  }
109761
110451
  function SessionsListContent(props) {
109762
- const { apiConfig, onSessionClick, className = "", defaultFilters = [], defaultTimeRange = "24 hours" } = props;
109763
- const { environments } = useEnvironment();
109764
- const [selectedSessionId, setSelectedSessionId] = useState(null);
110452
+ const { apiConfig, onSessionClick, className = "", defaultFilters = [], defaultTimeRange = "24 hours", initialSessionId } = props;
110453
+ const { environments, resolveEnvironmentName } = useEnvironment();
110454
+ const [selectedSessionId, setSelectedSessionId] = useState(() => initialSessionId ?? null);
109765
110455
  const [selectedSessionData, setSelectedSessionData] = useState(null);
109766
- const [isModalOpen, setIsModalOpen] = useState(false);
110456
+ const [isModalOpen, setIsModalOpen] = useState(() => !!initialSessionId);
109767
110457
  const [sessions, setSessions] = useState([]);
109768
110458
  const [totalCount, setTotalCount] = useState(0);
109769
110459
  const [loading, setLoading] = useState(true);
109770
110460
  const [hasInitiallyLoaded, setHasInitiallyLoaded] = useState(false);
110461
+ const [appVersionOptions, setAppVersionOptions] = useState([]);
110462
+ const [searchTerm, setSearchTerm] = useState("");
109771
110463
  const initialFilters = useMemo(() => {
109772
110464
  const hasEnvFilter = defaultFilters.some((f) => f.column === "envId");
109773
- if (hasEnvFilter) {
109774
- return defaultFilters;
110465
+ const base2 = hasEnvFilter ? defaultFilters : [createDraftEnvironmentFilter$1(), ...defaultFilters];
110466
+ if (initialSessionId) {
110467
+ return [...base2, { column: "id", type: "string", operator: "=", value: initialSessionId }];
109775
110468
  }
109776
- return [createDraftEnvironmentFilter$1(), ...defaultFilters];
109777
- }, [defaultFilters]);
110469
+ return base2;
110470
+ }, [defaultFilters, initialSessionId]);
109778
110471
  const [filters, setFilters] = useState(initialFilters);
109779
110472
  const [showFilterPanel, setShowFilterPanel] = useState(false);
109780
110473
  const [showColumnCustomization, setShowColumnCustomization] = useState(false);
@@ -109783,6 +110476,32 @@ function SessionsListContent(props) {
109783
110476
  const [pagination, setPagination] = useState({ page: 0, limit: 50 });
109784
110477
  const [orderBy, setOrderBy] = useState({ column: "createdAt", order: "DESC" });
109785
110478
  const apiService = useMemo(() => new TracingApiService(apiConfig), [apiConfig]);
110479
+ useEffect(() => {
110480
+ if (initialSessionId) {
110481
+ setSelectedSessionId(initialSessionId);
110482
+ setIsModalOpen(true);
110483
+ }
110484
+ }, [initialSessionId]);
110485
+ useEffect(() => {
110486
+ const fetchAppVersions = async () => {
110487
+ try {
110488
+ const filterOptionsData = await apiService.fetchFilterOptions({
110489
+ projectId: apiConfig.projectId
110490
+ });
110491
+ if ((filterOptionsData == null ? void 0 : filterOptionsData.appvIds) && Array.isArray(filterOptionsData.appvIds)) {
110492
+ setAppVersionOptions(
110493
+ filterOptionsData.appvIds.map((item) => ({
110494
+ value: item.value,
110495
+ label: item.value
110496
+ }))
110497
+ );
110498
+ }
110499
+ } catch (error) {
110500
+ console.warn("Failed to fetch app version filter options:", error);
110501
+ }
110502
+ };
110503
+ fetchAppVersions();
110504
+ }, [apiService, apiConfig.projectId]);
109786
110505
  const convertPresetToDateRange = (preset) => {
109787
110506
  const now2 = /* @__PURE__ */ new Date();
109788
110507
  let pastDate;
@@ -109844,7 +110563,6 @@ function SessionsListContent(props) {
109844
110563
  });
109845
110564
  }
109846
110565
  const allFilters = [...timeFilters, ...filters];
109847
- if (apiConfig.projectId) ;
109848
110566
  return allFilters;
109849
110567
  }, [timeRange, filters]);
109850
110568
  const fetchSessions = useCallback(async () => {
@@ -109904,6 +110622,28 @@ function SessionsListContent(props) {
109904
110622
  useEffect(() => {
109905
110623
  fetchSessions();
109906
110624
  }, [fetchSessions]);
110625
+ const filteredSessions = useMemo(() => {
110626
+ const term = searchTerm.trim().toLowerCase();
110627
+ if (!term) return sessions;
110628
+ return sessions.filter((session) => {
110629
+ var _a;
110630
+ const envName = ((_a = resolveEnvironmentName(session.envId)) == null ? void 0 : _a.toLowerCase()) || "";
110631
+ const searchableFields = [
110632
+ session.id,
110633
+ envName,
110634
+ session.envId,
110635
+ session.appvId,
110636
+ session.source,
110637
+ session.environment,
110638
+ session.sessionReference,
110639
+ session.userReference,
110640
+ ...session.userIds || []
110641
+ ];
110642
+ return searchableFields.some(
110643
+ (field) => field && String(field).toLowerCase().includes(term)
110644
+ );
110645
+ });
110646
+ }, [sessions, searchTerm, resolveEnvironmentName]);
109907
110647
  const defaultColumns = useMemo(
109908
110648
  () => [
109909
110649
  {
@@ -109912,8 +110652,7 @@ function SessionsListContent(props) {
109912
110652
  width: 320,
109913
110653
  pinned: "left",
109914
110654
  hide: false,
109915
- // Pinned columns should always be visible
109916
- cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium text-gray-900", title: params.value, children: TracingUtils.truncate(params.value, 30) })
110655
+ cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableId, { value: params.value, truncateLength: 30 })
109917
110656
  },
109918
110657
  {
109919
110658
  field: "envId",
@@ -110040,6 +110779,20 @@ function SessionsListContent(props) {
110040
110779
  disabled: true,
110041
110780
  valueFormatter: (params) => TracingUtils.formatTokens(params.value),
110042
110781
  cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", children: TracingUtils.formatTokens(params.value) })
110782
+ },
110783
+ {
110784
+ field: "sessionReference",
110785
+ headerName: "Session Reference",
110786
+ width: 180,
110787
+ hide: true,
110788
+ cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", title: params.value || "-", children: params.value || "-" })
110789
+ },
110790
+ {
110791
+ field: "identity",
110792
+ headerName: "User Reference",
110793
+ width: 180,
110794
+ hide: true,
110795
+ cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", title: params.value || "-", children: params.value || "-" })
110043
110796
  }
110044
110797
  // {
110045
110798
  // field: 'traceTags',
@@ -110159,8 +110912,9 @@ function SessionsListContent(props) {
110159
110912
  // User-friendly label
110160
110913
  apiColumnName: "App Version ID",
110161
110914
  // API expects "App Version ID" (koretracing uiTableName)
110162
- type: "string",
110163
- operators: ["=", "!=", "contains"]
110915
+ type: "stringOptions",
110916
+ operators: ["any of", "none of"],
110917
+ options: appVersionOptions
110164
110918
  },
110165
110919
  {
110166
110920
  field: "source",
@@ -110212,10 +110966,27 @@ function SessionsListContent(props) {
110212
110966
  // API expects "Output Tokens" (koretracing uiTableName)
110213
110967
  type: "number",
110214
110968
  operators: ["=", ">", ">=", "<", "<="]
110969
+ },
110970
+ {
110971
+ field: "sessionReference",
110972
+ label: "Session Reference",
110973
+ apiColumnName: "Session Reference",
110974
+ type: "string",
110975
+ operators: ["=", "!=", "contains"]
110976
+ },
110977
+ {
110978
+ field: "identity",
110979
+ label: "User Reference",
110980
+ apiColumnName: "User Reference",
110981
+ type: "string",
110982
+ operators: ["=", "!=", "contains"]
110215
110983
  }
110216
110984
  ],
110217
- [environments]
110985
+ [environments, appVersionOptions]
110218
110986
  );
110987
+ const handleSearch = useCallback((term) => {
110988
+ setSearchTerm(term);
110989
+ }, []);
110219
110990
  const handleTimeRangeChange = (value, presetLabel) => {
110220
110991
  console.log("🗓️ SessionsList: Time range change requested:", value, presetLabel);
110221
110992
  setTimeRange(value);
@@ -110257,6 +111028,7 @@ function SessionsListContent(props) {
110257
111028
  };
110258
111029
  const handleClearFilters = () => {
110259
111030
  setFilters([]);
111031
+ setSearchTerm("");
110260
111032
  setTimeRange("24 hours");
110261
111033
  };
110262
111034
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `h-full flex flex-col w-full ${className}`, children: [
@@ -110265,11 +111037,19 @@ function SessionsListContent(props) {
110265
111037
  {
110266
111038
  title: "Sessions",
110267
111039
  description: "Review session logs and trace details to analyze conversation logs and app behavior.",
110268
- showSearch: false,
111040
+ searchPlaceholder: "Search sessions...",
111041
+ showSearch: true,
111042
+ searchConfig: {
111043
+ metadataSearchFields: ["Session ID", "Environment", "App Version", "User ID", "Source"],
111044
+ updateQuery: handleSearch,
111045
+ currentQuery: searchTerm,
111046
+ tableAllowsFullTextSearch: false
111047
+ },
110269
111048
  timeRange,
110270
111049
  timeRangePresetLabel,
110271
111050
  onTimeRangeChange: handleTimeRangeChange,
110272
111051
  filters,
111052
+ filterColumns,
110273
111053
  onFiltersClick: () => setShowFilterPanel(!showFilterPanel),
110274
111054
  onModifyColumnsClick: () => setShowColumnCustomization(true),
110275
111055
  onExportClick: handleExport,
@@ -110320,10 +111100,10 @@ function SessionsListContent(props) {
110320
111100
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-auto p-[24px] pt-[8px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
110321
111101
  TracingTable,
110322
111102
  {
110323
- data: sessions,
111103
+ data: filteredSessions,
110324
111104
  columns,
110325
111105
  loading,
110326
- totalCount,
111106
+ totalCount: searchTerm.trim() ? filteredSessions.length : totalCount,
110327
111107
  pagination,
110328
111108
  onPaginationChange: setPagination,
110329
111109
  onRowClick: handleRowClick,
@@ -110370,24 +111150,26 @@ function TracesListContent(props) {
110370
111150
  onTraceClick,
110371
111151
  className = "",
110372
111152
  defaultFilters = [],
110373
- sessionId
111153
+ sessionId,
111154
+ initialTraceId
110374
111155
  } = props;
110375
111156
  const { environments } = useEnvironment();
110376
- const [selectedTraceId, setSelectedTraceId] = useState(null);
110377
- const [isModalOpen, setIsModalOpen] = useState(false);
111157
+ const [selectedTraceId, setSelectedTraceId] = useState(() => initialTraceId ?? null);
111158
+ const [isModalOpen, setIsModalOpen] = useState(() => !!initialTraceId);
110378
111159
  const [traces, setTraces] = useState([]);
110379
111160
  const [totalCount, setTotalCount] = useState(0);
110380
111161
  const [loading, setLoading] = useState(true);
110381
111162
  const [hasInitiallyLoaded, setHasInitiallyLoaded] = useState(false);
110382
111163
  const [searchTerm, setSearchTerm] = useState("");
110383
- const [searchType, setSearchType] = useState(["id"]);
111164
+ const [searchType, setSearchType] = useState(["id", "content"]);
110384
111165
  const initialFilters = useMemo(() => {
110385
111166
  const hasEnvFilter = defaultFilters.some((f) => f.column === "envId");
110386
- if (hasEnvFilter) {
110387
- return defaultFilters;
111167
+ const base2 = hasEnvFilter ? defaultFilters : [createDraftEnvironmentFilter(), ...defaultFilters];
111168
+ if (initialTraceId) {
111169
+ return [...base2, { column: "id", type: "string", operator: "=", value: initialTraceId }];
110388
111170
  }
110389
- return [createDraftEnvironmentFilter(), ...defaultFilters];
110390
- }, [defaultFilters]);
111171
+ return base2;
111172
+ }, [defaultFilters, initialTraceId]);
110391
111173
  const [filters, setFilters] = useState(initialFilters);
110392
111174
  const [showFilterPanel, setShowFilterPanel] = useState(false);
110393
111175
  const [showColumnCustomization, setShowColumnCustomization] = useState(false);
@@ -110396,6 +111178,12 @@ function TracesListContent(props) {
110396
111178
  const [pagination, setPagination] = useState({ page: 0, limit: 50 });
110397
111179
  const [orderBy, setOrderBy] = useState({ column: "timestamp", order: "DESC" });
110398
111180
  const [detailedTraceData, setDetailedTraceData] = useState(/* @__PURE__ */ new Map());
111181
+ useEffect(() => {
111182
+ if (initialTraceId) {
111183
+ setSelectedTraceId(initialTraceId);
111184
+ setIsModalOpen(true);
111185
+ }
111186
+ }, [initialTraceId]);
110399
111187
  const apiService = useMemo(() => new TracingApiService(apiConfig), [apiConfig]);
110400
111188
  const convertPresetToDateRange = (preset) => {
110401
111189
  const now2 = /* @__PURE__ */ new Date();
@@ -110481,18 +111269,24 @@ function TracesListContent(props) {
110481
111269
  orderBy
110482
111270
  });
110483
111271
  const apiFilters = TracingUtils.convertFiltersToApiFormat(effectiveFilters, filterColumns);
110484
- const tracesResponse = await apiService.fetchTraces({
110485
- projectId: apiConfig.projectId,
110486
- filter: apiFilters,
110487
- orderBy,
110488
- page: pagination.page,
110489
- limit: pagination.limit,
110490
- searchQuery: searchTerm || null,
110491
- searchType
110492
- // 'id' for IDs/Names, ['id', 'content'] for Full Text
110493
- });
111272
+ const [tracesResponse, countResponse] = await Promise.all([
111273
+ apiService.fetchTraces({
111274
+ projectId: apiConfig.projectId,
111275
+ filter: apiFilters,
111276
+ orderBy,
111277
+ page: pagination.page,
111278
+ limit: pagination.limit,
111279
+ searchQuery: searchTerm || null,
111280
+ searchType
111281
+ }),
111282
+ apiService.fetchTracesCount(apiConfig.projectId, apiFilters, {
111283
+ searchQuery: searchTerm || null,
111284
+ searchType,
111285
+ orderBy
111286
+ })
111287
+ ]);
110494
111288
  const basicTraces = tracesResponse.traces || [];
110495
- console.log("✅ Basic traces loaded:", { count: basicTraces.length });
111289
+ console.log("✅ Basic traces loaded:", { count: basicTraces.length, total: countResponse.totalCount });
110496
111290
  if (basicTraces.length > 0) {
110497
111291
  const traceIds = basicTraces.map((t2) => t2.id);
110498
111292
  try {
@@ -110527,7 +111321,7 @@ function TracesListContent(props) {
110527
111321
  } else {
110528
111322
  setTraces([]);
110529
111323
  }
110530
- setTotalCount(basicTraces.length);
111324
+ setTotalCount(countResponse.totalCount);
110531
111325
  } catch (error) {
110532
111326
  console.error("❌ Error fetching traces:", error);
110533
111327
  setTraces([]);
@@ -110556,11 +111350,13 @@ function TracesListContent(props) {
110556
111350
  projectId: apiConfig.projectId,
110557
111351
  timestamp: trace.timestamp
110558
111352
  });
111353
+ const inputDisplay = TraceTreeService.extractUserMessage(detail["input"]);
111354
+ const outputDisplay = TraceTreeService.extractAppResponse(detail["output"]);
110559
111355
  setDetailedTraceData((prev) => {
110560
111356
  const newMap = new Map(prev);
110561
111357
  newMap.set(traceId, {
110562
- input: detail["input"],
110563
- output: detail["output"],
111358
+ input: inputDisplay,
111359
+ output: outputDisplay,
110564
111360
  totalCost: detail["totalCost"],
110565
111361
  envId: detail["envId"],
110566
111362
  source: detail["source"]
@@ -110597,8 +111393,7 @@ function TracesListContent(props) {
110597
111393
  width: 320,
110598
111394
  pinned: "left",
110599
111395
  hide: false,
110600
- // Pinned columns should always be visible
110601
- cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium text-gray-900", title: params.value, children: TracingUtils.truncate(params.value, 30) })
111396
+ cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx(CopyableId, { value: params.value, truncateLength: 30 })
110602
111397
  }
110603
111398
  ];
110604
111399
  {
@@ -110609,11 +111404,13 @@ function TracesListContent(props) {
110609
111404
  hide: false,
110610
111405
  cellRenderer: (params) => {
110611
111406
  const detailData = detailedTraceData.get(params.data.id);
110612
- const inputText = detailData == null ? void 0 : detailData.input;
110613
- if (inputText === void 0) {
111407
+ const rawInput = detailData == null ? void 0 : detailData.input;
111408
+ if (rawInput === void 0) {
110614
111409
  return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-400 italic", children: "Loading..." });
110615
111410
  }
110616
- return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", title: inputText, children: TracingUtils.truncate(inputText || "-", 50) });
111411
+ const inputText = typeof rawInput === "string" ? rawInput : TraceTreeService.extractUserMessage(rawInput);
111412
+ const displayText = TracingUtils.truncate(inputText || "-", 50);
111413
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", title: inputText || void 0, children: displayText });
110617
111414
  }
110618
111415
  });
110619
111416
  }
@@ -110642,11 +111439,13 @@ function TracesListContent(props) {
110642
111439
  hide: false,
110643
111440
  cellRenderer: (params) => {
110644
111441
  const detailData = detailedTraceData.get(params.data.id);
110645
- const outputText = detailData == null ? void 0 : detailData.output;
110646
- if (outputText === void 0) {
111442
+ const rawOutput = detailData == null ? void 0 : detailData.output;
111443
+ if (rawOutput === void 0) {
110647
111444
  return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-400 italic", children: "Loading..." });
110648
111445
  }
110649
- return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", title: outputText, children: TracingUtils.truncate(outputText || "-", 50) });
111446
+ const outputText = typeof rawOutput === "string" ? rawOutput : TraceTreeService.extractAppResponse(rawOutput);
111447
+ const displayText = TracingUtils.truncate(outputText || "-", 50);
111448
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", title: outputText || void 0, children: displayText });
110650
111449
  }
110651
111450
  });
110652
111451
  }
@@ -110709,11 +111508,9 @@ function TracesListContent(props) {
110709
111508
  // },
110710
111509
  {
110711
111510
  field: "timestamp",
110712
- headerName: "Timestamp",
111511
+ headerName: "Created At",
110713
111512
  width: 180,
110714
- hide: true,
110715
- // DISABLED - This is the main sort column for traces
110716
- disabled: true,
111513
+ hide: false,
110717
111514
  cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-500", children: params.value ? new Date(params.value).toLocaleString() : "-" })
110718
111515
  },
110719
111516
  {
@@ -110788,6 +111585,20 @@ function TracesListContent(props) {
110788
111585
  return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-600", children: source || "-" });
110789
111586
  }
110790
111587
  },
111588
+ {
111589
+ field: "sessionReference",
111590
+ headerName: "Session Reference",
111591
+ width: 180,
111592
+ hide: true,
111593
+ cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", title: params.value || "-", children: params.value || "-" })
111594
+ },
111595
+ {
111596
+ field: "identity",
111597
+ headerName: "User Reference",
111598
+ width: 180,
111599
+ hide: true,
111600
+ cellRenderer: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-gray-700", title: params.value || "-", children: params.value || "-" })
111601
+ },
110791
111602
  {
110792
111603
  field: "promptTokens",
110793
111604
  headerName: "Input Tokens",
@@ -110964,10 +111775,9 @@ function TracesListContent(props) {
110964
111775
  },
110965
111776
  {
110966
111777
  field: "timestamp",
110967
- label: "Timestamp",
110968
- // Same as API
111778
+ label: "Created At",
110969
111779
  apiColumnName: "Timestamp",
110970
- // API expects "Timestamp" (koretracing uiTableName)
111780
+ // Backend payload: keep "Timestamp" for API
110971
111781
  type: "datetime",
110972
111782
  operators: [">=", "<=", "="]
110973
111783
  },
@@ -111058,6 +111868,20 @@ function TracesListContent(props) {
111058
111868
  label: "Output Tokens",
111059
111869
  type: "number",
111060
111870
  operators: ["=", ">", ">=", "<", "<="]
111871
+ },
111872
+ {
111873
+ field: "sessionReference",
111874
+ label: "Session Reference",
111875
+ apiColumnName: "Session Reference",
111876
+ type: "string",
111877
+ operators: ["=", "!=", "contains"]
111878
+ },
111879
+ {
111880
+ field: "identity",
111881
+ label: "User Reference",
111882
+ apiColumnName: "User Reference",
111883
+ type: "string",
111884
+ operators: ["=", "!=", "contains"]
111061
111885
  }
111062
111886
  );
111063
111887
  return baseColumns;
@@ -111124,6 +111948,7 @@ function TracesListContent(props) {
111124
111948
  timeRangePresetLabel,
111125
111949
  onTimeRangeChange: handleTimeRangeChange,
111126
111950
  filters,
111951
+ filterColumns,
111127
111952
  onFiltersClick: () => setShowFilterPanel(!showFilterPanel),
111128
111953
  onModifyColumnsClick: () => setShowColumnCustomization(true),
111129
111954
  onExportClick: handleExport,
@@ -112175,12 +113000,12 @@ class TreeBuilder {
112175
113000
  * Process execution events and build a hierarchical tree structure
112176
113001
  * Session > Run > Node Tree
112177
113002
  */
112178
- static buildSessionTree(events, sessionId) {
113003
+ static buildSessionTree(events, sessionId, options) {
112179
113004
  var _a;
112180
113005
  const runGroups = this.groupEventsByRun(events);
112181
113006
  const runs = [];
112182
113007
  for (const [runId, runEvents] of runGroups.entries()) {
112183
- const runTree = this.buildRunTree(runId, runEvents);
113008
+ const runTree = this.buildRunTree(runId, runEvents, options);
112184
113009
  runs.push(runTree);
112185
113010
  }
112186
113011
  runs.sort((a4, b2) => new Date(a4.startTime).getTime() - new Date(b2.startTime).getTime());
@@ -112206,11 +113031,11 @@ class TreeBuilder {
112206
113031
  /**
112207
113032
  * Build tree for a single run
112208
113033
  */
112209
- static buildRunTree(runId, events) {
113034
+ static buildRunTree(runId, events, options) {
112210
113035
  var _a;
112211
113036
  const nodeEventMap = /* @__PURE__ */ new Map();
112212
113037
  events.forEach((event) => {
112213
- const nodeKey = `${event.data.id}|${event.data.name}|${event.data.toolName}`;
113038
+ const nodeKey = event.data.id;
112214
113039
  if (!nodeEventMap.has(nodeKey)) {
112215
113040
  nodeEventMap.set(nodeKey, {});
112216
113041
  }
@@ -112237,7 +113062,7 @@ class TreeBuilder {
112237
113062
  const status = this.calculateRunStatus(runEvents);
112238
113063
  const duration = endTime && startTime ? endTime - startTime : void 0;
112239
113064
  const totalTokens = this.calculateRunTokens(runEvents);
112240
- const userInput = this.extractUserInput(runEvents);
113065
+ const userInput = this.extractUserInput(runEvents, options);
112241
113066
  const finalOutput = this.extractFinalOutput(runEvents);
112242
113067
  return {
112243
113068
  runId,
@@ -112256,11 +113081,12 @@ class TreeBuilder {
112256
113081
  * Create TreeNode from paired started/completed events
112257
113082
  */
112258
113083
  static createTreeNodeFromEvents(startedEvent, completedEvent, runId) {
113084
+ var _a;
112259
113085
  const startTime = startedEvent.data.timestamp;
112260
113086
  const endTime = completedEvent == null ? void 0 : completedEvent.data.timestamp;
112261
113087
  const duration = endTime && startTime ? new Date(endTime).getTime() - new Date(startTime).getTime() : void 0;
112262
113088
  const primaryEvent = completedEvent || startedEvent;
112263
- const hasInputOutput = primaryEvent.data.type === "llm" || primaryEvent.data.type === "tool" || primaryEvent.data.type === "GuardrailsInputScan" || primaryEvent.data.type === "GuardrailsOutputScan" || primaryEvent.data.type === "Agent" || primaryEvent.data.type === "External Orchestrator" || primaryEvent.data.type === "ProxyWorker" || primaryEvent.data.type === "event";
113089
+ const hasInputOutput = primaryEvent.data.type === "llm" || primaryEvent.data.type === "tool" || primaryEvent.data.type === "GuardrailsInputScan" || primaryEvent.data.type === "GuardrailsOutputScan" || primaryEvent.data.type === "Agent" || primaryEvent.data.type === "External Orchestrator" || primaryEvent.data.type === "ProxyWorker" || primaryEvent.data.type === "PostProcessor" || primaryEvent.data.type === "event";
112264
113090
  const input = hasInputOutput ? startedEvent.data.input : void 0;
112265
113091
  let output = void 0;
112266
113092
  let error = void 0;
@@ -112274,7 +113100,8 @@ class TreeBuilder {
112274
113100
  const { toolInvocations, isResponse } = this.extractToolInvocations(output);
112275
113101
  console.log("toolInvocations", toolInvocations);
112276
113102
  console.log("isResponse", isResponse);
112277
- const provider = primaryEvent.data.type === "llm" ? this.extractProvider(primaryEvent.data.name || primaryEvent.data.toolName) : void 0;
113103
+ const extractedProvider = primaryEvent.data.type === "llm" ? this.extractProvider(primaryEvent.data.name || primaryEvent.data.toolName) : void 0;
113104
+ const provider = ((_a = primaryEvent.data.metadata) == null ? void 0 : _a.provider) || extractedProvider;
112278
113105
  return {
112279
113106
  id: primaryEvent.data.id,
112280
113107
  parentId: primaryEvent.data.parentId,
@@ -112433,12 +113260,22 @@ class TreeBuilder {
112433
113260
  /**
112434
113261
  * Extract initial user input from the first LLM node's input
112435
113262
  */
112436
- static extractUserInput(events) {
113263
+ static extractUserInput(events, options) {
113264
+ const preferDisplay = ((options == null ? void 0 : options.runHeaderInputMode) ?? "display") === "display";
112437
113265
  const llmEvents = events.filter(
112438
113266
  (e3) => e3.type === "node_started" && e3.data.type === "llm"
112439
113267
  ).sort((a4, b2) => new Date(a4.data.timestamp).getTime() - new Date(b2.data.timestamp).getTime());
112440
113268
  if (llmEvents.length > 0) {
112441
113269
  const firstLlmEvent = llmEvents[0];
113270
+ if (preferDisplay && firstLlmEvent.data.displayInput !== void 0 && firstLlmEvent.data.displayInput !== null) {
113271
+ const d3 = firstLlmEvent.data.displayInput;
113272
+ if (typeof d3 === "string") {
113273
+ return d3;
113274
+ }
113275
+ if (typeof d3 === "object") {
113276
+ return JSON.stringify(d3);
113277
+ }
113278
+ }
112442
113279
  if (firstLlmEvent.data.input) {
112443
113280
  if (typeof firstLlmEvent.data.input === "string") {
112444
113281
  return firstLlmEvent.data.input;
@@ -112506,6 +113343,22 @@ class TreeBuilder {
112506
113343
  */
112507
113344
  static extractFinalOutput(events) {
112508
113345
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
113346
+ const postProcessorEvents = events.filter(
113347
+ (e3) => {
113348
+ var _a2;
113349
+ return e3.type === "node_completed" && e3.data.type === "tool" && ((_a2 = e3.data.metadata) == null ? void 0 : _a2.type) === "PostProcessor" && e3.data.output;
113350
+ }
113351
+ );
113352
+ if (postProcessorEvents.length > 0) {
113353
+ const lastPP = postProcessorEvents[postProcessorEvents.length - 1];
113354
+ const ppOutput = lastPP.data.output;
113355
+ if (typeof ppOutput === "object" && ppOutput.output) {
113356
+ return typeof ppOutput.output === "string" ? ppOutput.output : JSON.stringify(ppOutput.output);
113357
+ }
113358
+ if (typeof ppOutput === "string") {
113359
+ return ppOutput;
113360
+ }
113361
+ }
112509
113362
  const errorEvents = events.filter(
112510
113363
  (e3) => e3.type === "node_completed" && e3.data.error && (e3.data.status === "errored" || e3.data.status === "failed")
112511
113364
  );
@@ -112632,8 +113485,8 @@ class TreeBuilder {
112632
113485
  /**
112633
113486
  * Update tree with new events (optimized for real-time updates)
112634
113487
  */
112635
- static updateTree(existingTree, _newEvents, allEvents) {
112636
- return this.buildSessionTree(allEvents, existingTree.sessionId);
113488
+ static updateTree(existingTree, _newEvents, allEvents, options) {
113489
+ return this.buildSessionTree(allEvents, existingTree.sessionId, options);
112637
113490
  }
112638
113491
  /**
112639
113492
  * Merge new events into existing events efficiently
@@ -112985,7 +113838,7 @@ class ApiService {
112985
113838
  nodeId,
112986
113839
  totalObservations: observations.length
112987
113840
  });
112988
- const matchedObservation = observations.find((obs) => {
113841
+ const matchingObservations = observations.filter((obs) => {
112989
113842
  let metadata = obs.metadata;
112990
113843
  if (typeof metadata === "string") {
112991
113844
  try {
@@ -113006,6 +113859,7 @@ class ApiService {
113006
113859
  });
113007
113860
  return nodeId === observationNodeId;
113008
113861
  });
113862
+ const matchedObservation = matchingObservations.find((obs) => obs.type === "GENERATION") || matchingObservations[0] || null;
113009
113863
  if (!matchedObservation) {
113010
113864
  const parts = nodeId.split("_");
113011
113865
  if (parts.length === 2) {
@@ -113147,6 +114001,36 @@ class ApiService {
113147
114001
  return this.config;
113148
114002
  }
113149
114003
  }
114004
+ function sanitizeForTestId(value) {
114005
+ return value.trim().toLowerCase().replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "") || "node";
114006
+ }
114007
+ function getDebuggerCallTypeTestId(node) {
114008
+ const name = (node.name ?? "unknown").toString();
114009
+ let slug = sanitizeForTestId(name);
114010
+ switch (node.type) {
114011
+ case "event":
114012
+ slug = slug.replace(/-event$/, "") || "event";
114013
+ return `debugger-event-${slug}`;
114014
+ case "Agent":
114015
+ return `debugger-${slug}-call`;
114016
+ case "tool":
114017
+ return `debugger-${slug}-call`;
114018
+ case "llm":
114019
+ return `debugger-llm-${slug}`;
114020
+ case "GuardrailsInputScan":
114021
+ return `debugger-guardrails-input-${slug}`;
114022
+ case "GuardrailsOutputScan":
114023
+ return `debugger-guardrails-output-${slug}`;
114024
+ case "External Orchestrator":
114025
+ return `debugger-orchestrator-${slug}`;
114026
+ case "ProxyWorker":
114027
+ return `debugger-proxy-${slug}`;
114028
+ case "PostProcessor":
114029
+ return `debugger-postprocessor-${slug}`;
114030
+ default:
114031
+ return `debugger-${String(node.type).toLowerCase().replace(/\s+/g, "-")}-${slug}`;
114032
+ }
114033
+ }
113150
114034
  function DebugCard({
113151
114035
  node,
113152
114036
  onToggle,
@@ -113158,9 +114042,12 @@ function DebugCard({
113158
114042
  projectId,
113159
114043
  nodeIndex = 0
113160
114044
  }) {
114045
+ var _a;
114046
+ const callTypeTestId = useMemo(() => getDebuggerCallTypeTestId(node), [node.type, node.name]);
114047
+ const cardTestId = useMemo(() => `${callTypeTestId}_${node.id}`, [callTypeTestId, node.id]);
113161
114048
  const isGuardrailsNode = useMemo(() => {
113162
- var _a;
113163
- return node.type === "GuardrailsInputScan" || node.type === "GuardrailsOutputScan" || ((_a = node.name) == null ? void 0 : _a.toLowerCase().includes("guardrail"));
114049
+ var _a2;
114050
+ return node.type === "GuardrailsInputScan" || node.type === "GuardrailsOutputScan" || ((_a2 = node.name) == null ? void 0 : _a2.toLowerCase().includes("guardrail"));
113164
114051
  }, [node.type, node.name]);
113165
114052
  const availableTabs = useMemo(() => {
113166
114053
  switch (node.type) {
@@ -113337,7 +114224,7 @@ function DebugCard({
113337
114224
  }
113338
114225
  };
113339
114226
  const getNodeIcon = () => {
113340
- var _a, _b;
114227
+ var _a2, _b;
113341
114228
  if (isGuardrailsNode) {
113342
114229
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0 relative w-[24px] h-[24px] bg-gray-200 rounded-[8px] flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "17", height: "21", viewBox: "0 0 17 21", fill: "none", className: "w-[16px] h-[16px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
113343
114230
  "path",
@@ -113372,7 +114259,7 @@ function DebugCard({
113372
114259
  size: "small",
113373
114260
  name: node.name,
113374
114261
  className: "w-[24px] h-[24px]",
113375
- toolType: node.type === "tool" ? (_a = node.metadata) == null ? void 0 : _a.type : void 0,
114262
+ toolType: node.type === "tool" ? (_a2 = node.metadata) == null ? void 0 : _a2.type : void 0,
113376
114263
  provider: node.type === "llm" ? (_b = node.metadata) == null ? void 0 : _b.provider : void 0,
113377
114264
  modelName: node.type === "llm" ? node.name : void 0
113378
114265
  }
@@ -113396,7 +114283,7 @@ function DebugCard({
113396
114283
  return availableTabs;
113397
114284
  };
113398
114285
  const renderActionContent = () => {
113399
- var _a, _b;
114286
+ var _a2, _b;
113400
114287
  let toolInvocations = node.toolInvocations || [];
113401
114288
  if (node.type === "llm" && Array.isArray(node.output)) {
113402
114289
  toolInvocations = node.output.filter(
@@ -113418,7 +114305,7 @@ function DebugCard({
113418
114305
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-600 truncate", children: child.name || "Unknown" })
113419
114306
  ] }, child.id || index))
113420
114307
  ] }),
113421
- toolInvocations.length > 0 && ((_b = (_a = toolInvocations[0]) == null ? void 0 : _a.args) == null ? void 0 : _b.reason) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
114308
+ toolInvocations.length > 0 && ((_b = (_a2 = toolInvocations[0]) == null ? void 0 : _a2.args) == null ? void 0 : _b.reason) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
113422
114309
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-medium text-gray-400 mb-[4px]", children: "Reason" }),
113423
114310
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-gray-600", children: toolInvocations[0].args.reason })
113424
114311
  ] })
@@ -113445,14 +114332,14 @@ function DebugCard({
113445
114332
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-gray-500 italic", children: "No actions taken" });
113446
114333
  };
113447
114334
  const extractOutputMessage = (output) => {
113448
- var _a, _b, _c, _d;
114335
+ var _a2, _b, _c, _d;
113449
114336
  if (!output || typeof output !== "object") return void 0;
113450
114337
  if (Array.isArray(output)) {
113451
114338
  const routeToUserTool = output.find(
113452
114339
  (item) => item && typeof item === "object" && (item.name === "route_to_user" || item.toolName === "route_to_user")
113453
114340
  );
113454
114341
  if (routeToUserTool) {
113455
- return ((_a = routeToUserTool.args) == null ? void 0 : _a.message) || routeToUserTool.message || ((_b = routeToUserTool.output) == null ? void 0 : _b.message);
114342
+ return ((_a2 = routeToUserTool.args) == null ? void 0 : _a2.message) || routeToUserTool.message || ((_b = routeToUserTool.output) == null ? void 0 : _b.message);
113456
114343
  }
113457
114344
  } else if (output.name === "route_to_user" || output.toolName === "route_to_user") {
113458
114345
  return ((_c = output.args) == null ? void 0 : _c.message) || output.message || ((_d = output.output) == null ? void 0 : _d.message);
@@ -113549,7 +114436,7 @@ function DebugCard({
113549
114436
  ] });
113550
114437
  };
113551
114438
  const renderTabContent = () => {
113552
- var _a;
114439
+ var _a2;
113553
114440
  switch (activeTab) {
113554
114441
  case "summary":
113555
114442
  if (isGuardrailsNode) {
@@ -113740,7 +114627,7 @@ function DebugCard({
113740
114627
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
113741
114628
  DataViewer,
113742
114629
  {
113743
- data: ((_a = node.metadata) == null ? void 0 : _a["logs"]) || {},
114630
+ data: ((_a2 = node.metadata) == null ? void 0 : _a2["logs"]) || {},
113744
114631
  title: "Execution Logs",
113745
114632
  maxHeight: "250px",
113746
114633
  defaultExpanded: true,
@@ -113753,15 +114640,15 @@ function DebugCard({
113753
114640
  };
113754
114641
  return (
113755
114642
  // bg-white w-full border-t border-gray-200
113756
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white w-full", "data-test-id": `debug_card_${node.id}`, children: [
114643
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white w-full", "data-test-id": cardTestId, "data-call-type-test-id": callTypeTestId, children: [
113757
114644
  /* @__PURE__ */ jsxRuntimeExports.jsx(
113758
114645
  "div",
113759
114646
  {
113760
114647
  className: `flex items-center pl-[8px] pr-[8px] relative transition-colors cursor-pointer w-full
113761
114648
  ${isSelected ? "" : ""}`,
113762
114649
  onClick: handleNodeClick,
113763
- "data-test-id": `debug_card_header_${node.id}`,
113764
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[10px] w-full", "data-test-id": `debug_card_header_content_${node.id}`, children: [
114650
+ "data-test-id": `${callTypeTestId}_header`,
114651
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[10px] w-full", "data-test-id": `${callTypeTestId}_header_content`, children: [
113765
114652
  /* @__PURE__ */ jsxRuntimeExports.jsx(
113766
114653
  "div",
113767
114654
  {
@@ -113775,7 +114662,7 @@ function DebugCard({
113775
114662
  }
113776
114663
  },
113777
114664
  title: hasChildren ? isExpanded ? "Collapse" : "Expand" : "Show details",
113778
- "data-test-id": `debug_card_toggle_${node.id}`,
114665
+ "data-test-id": `${callTypeTestId}_toggle`,
113779
114666
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(
113780
114667
  ChevronRight,
113781
114668
  {
@@ -113784,28 +114671,28 @@ function DebugCard({
113784
114671
  )
113785
114672
  }
113786
114673
  ),
113787
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[8px] w-full py-[8px] border-b border-gray-200", "data-test-id": `debug_card_node_info_${node.id}`, children: [
113788
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0 rounded-[8px] bg-[#B2DDFF]", "data-test-id": `debug_card_node_icon_${node.id}`, children: getNodeIcon() }),
114674
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[8px] w-full py-[8px] border-b border-gray-200", "data-test-id": `${callTypeTestId}_node_info`, children: [
114675
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0 rounded-[8px] bg-[#B2DDFF]", "data-test-id": `${callTypeTestId}_node_icon`, children: getNodeIcon() }),
113789
114676
  /* @__PURE__ */ jsxRuntimeExports.jsx(
113790
114677
  "span",
113791
114678
  {
113792
114679
  className: "font-semibold text-gray-900 text-xs truncate w-full",
113793
114680
  title: node.type === "llm" ? node.name : void 0,
113794
- "data-test-id": `debug_card_node_name_${node.id}`,
113795
- children: isGuardrailsNode ? node.type === "GuardrailsInputScan" ? "Input Guardrails Scanner" : "Output Guardrails Scanner" : node.type === "llm" ? "AI Model Call" : node.type === "tool" ? formatToolName(node.name) : node.name
114681
+ "data-test-id": `${callTypeTestId}_node_name`,
114682
+ children: isGuardrailsNode ? node.type === "GuardrailsInputScan" ? "Input Guardrails Scanner" : "Output Guardrails Scanner" : node.type === "llm" ? ((_a = node == null ? void 0 : node.metadata) == null ? void 0 : _a.isRoutedModel) ? `AI Model Call (${node.name})` : "AI Model Call" : node.type === "PostProcessor" ? "Response Processor" : node.type === "tool" ? formatToolName(node.name) : node.name
113796
114683
  }
113797
114684
  ),
113798
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[12px] text-[10px] text-gray-500", "data-test-id": `debug_card_node_metadata_${node.id}`, children: [
114685
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[12px] text-[10px] text-gray-500", "data-test-id": `${callTypeTestId}_node_metadata`, children: [
113799
114686
  node.type === "Agent" && (() => {
113800
- var _a;
113801
- const llmChild = (_a = node.children) == null ? void 0 : _a.find((child) => child.type === "llm");
114687
+ var _a2;
114688
+ const llmChild = (_a2 = node.children) == null ? void 0 : _a2.find((child) => child.type === "llm");
113802
114689
  if (llmChild == null ? void 0 : llmChild.name) {
113803
114690
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
113804
114691
  "span",
113805
114692
  {
113806
114693
  className: "text-[10px] text-gray-500 truncate max-w-[100px]",
113807
114694
  title: llmChild.name,
113808
- "data-test-id": `debug_card_node_model_name_${node.id}`,
114695
+ "data-test-id": `${callTypeTestId}_node_model_name`,
113809
114696
  children: llmChild.name
113810
114697
  }
113811
114698
  );
@@ -113813,7 +114700,7 @@ function DebugCard({
113813
114700
  return null;
113814
114701
  })(),
113815
114702
  (node.type === "Agent" || node.type === "llm" || isGuardrailsNode) && (() => {
113816
- var _a, _b, _c;
114703
+ var _a2, _b, _c;
113817
114704
  let llmUsage = node.llmUsage;
113818
114705
  if (node.type === "Agent" && node.children) {
113819
114706
  const llmChildren = node.children.filter((child) => child.type === "llm");
@@ -113835,10 +114722,10 @@ function DebugCard({
113835
114722
  "span",
113836
114723
  {
113837
114724
  className: "text-[10px] text-gray-500 whitespace-nowrap cursor-help",
113838
- title: `Input: ${((_a = llmUsage.input_tokens) == null ? void 0 : _a.toLocaleString()) || 0} tokens
114725
+ title: `Input: ${((_a2 = llmUsage.input_tokens) == null ? void 0 : _a2.toLocaleString()) || 0} tokens
113839
114726
  Output: ${((_b = llmUsage.output_tokens) == null ? void 0 : _b.toLocaleString()) || 0} tokens
113840
114727
  Total: ${((_c = llmUsage.total_tokens) == null ? void 0 : _c.toLocaleString()) || 0} tokens`,
113841
- "data-test-id": `debug_card_node_tokens_${node.id}`,
114728
+ "data-test-id": `${callTypeTestId}_node_tokens`,
113842
114729
  children: [
113843
114730
  llmUsage.total_tokens.toLocaleString(),
113844
114731
  " Tokens"
@@ -113848,34 +114735,34 @@ Total: ${((_c = llmUsage.total_tokens) == null ? void 0 : _c.toLocaleString()) |
113848
114735
  }
113849
114736
  return null;
113850
114737
  })(),
113851
- node.duration && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[4px]", "data-test-id": `debug_card_node_duration_${node.id}`, children: [
114738
+ node.duration && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-[4px]", "data-test-id": `${callTypeTestId}_node_duration`, children: [
113852
114739
  /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "w-[12px] h-[12px]" }),
113853
114740
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-gray-500 whitespace-nowrap", children: formatDuration(node.duration) })
113854
114741
  ] })
113855
114742
  ] }),
113856
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", "data-test-id": `debug_card_node_status_${node.id}`, children: getStatusIcon() })
114743
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-shrink-0", "data-test-id": `${callTypeTestId}_node_status`, children: getStatusIcon() })
113857
114744
  ] })
113858
114745
  ] })
113859
114746
  }
113860
114747
  ),
113861
- isSelected && availableTabs.length > 0 && showDetailView && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full pl-[32px] relative", "data-test-id": `debug_card_detail_panel_${node.id}`, children: [
113862
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-[-40px] left-[16px] w-[1px] border-l border-dashed border-gray-200 h-[calc(100%+40px)] z-[1]", "data-test-id": `debug_card_detail_panel_connector_${node.id}` }),
113863
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-[4px] py-[8px] w-full", "data-test-id": `debug_card_detail_panel_content_${node.id}`, children: [
113864
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-gray-50 rounded-[4px] p-[4px] inline-flex gap-[4px] mb-[8px] border border-gray-200", "data-test-id": `debug_card_detail_panel_tabs_${node.id}`, children: getTabsForNodeType().map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
114748
+ isSelected && availableTabs.length > 0 && showDetailView && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full pl-[32px] relative", "data-test-id": `${callTypeTestId}_detail_panel`, children: [
114749
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-[-40px] left-[16px] w-[1px] border-l border-dashed border-gray-200 h-[calc(100%+40px)] z-[1]", "data-test-id": `${callTypeTestId}_detail_panel_connector` }),
114750
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-[4px] py-[8px] w-full", "data-test-id": `${callTypeTestId}_detail_panel_content`, children: [
114751
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-gray-50 rounded-[4px] p-[4px] inline-flex gap-[4px] mb-[8px] border border-gray-200", "data-test-id": `${callTypeTestId}_detail_panel_tabs`, children: getTabsForNodeType().map((tab) => /* @__PURE__ */ jsxRuntimeExports.jsx(
113865
114752
  "button",
113866
114753
  {
113867
114754
  onClick: () => handleTabClick(tab),
113868
114755
  className: `px-[8px] py-[4px] text-xs font-medium rounded-[4px] text-gray-500 hover:text-gray-700 hover:shadow-tab hover:bg-white transition-colors ${activeTab === tab ? "bg-white text-gray-900 shadow-tab" : "text-gray-500 hover:text-gray-700 hover:bg-white"}`,
113869
- "data-test-id": `debug_card_detail_panel_tab_${node.id}_${tab}`,
114756
+ "data-test-id": `${callTypeTestId}_detail_panel_tab_${tab}`,
113870
114757
  children: tab.charAt(0).toUpperCase() + tab.slice(1)
113871
114758
  },
113872
114759
  tab
113873
114760
  )) }),
113874
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-[4px]", "data-test-id": `debug_card_detail_panel_tab_content_${node.id}`, children: renderTabContent() })
114761
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-[4px]", "data-test-id": `${callTypeTestId}_detail_panel_tab_content`, children: renderTabContent() })
113875
114762
  ] })
113876
114763
  ] }),
113877
- isExpanded && hasChildren && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full pl-[32px] relative", "data-test-id": `debug_card_children_${node.id}`, children: [
113878
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-[-40px] left-[16px] w-[1px] border-l border-dashed border-gray-200 h-[calc(100%+40px)] z-[1]", "data-test-id": `debug_card_children_connector_${node.id}` }),
114764
+ isExpanded && hasChildren && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full pl-[32px] relative", "data-test-id": `${callTypeTestId}_children`, children: [
114765
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-[-40px] left-[16px] w-[1px] border-l border-dashed border-gray-200 h-[calc(100%+40px)] z-[1]", "data-test-id": `${callTypeTestId}_children_connector` }),
113879
114766
  node.children.map((child, index) => /* @__PURE__ */ jsxRuntimeExports.jsx(
113880
114767
  DebugCard,
113881
114768
  {
@@ -113911,6 +114798,7 @@ const DebugPanel = forwardRef(({
113911
114798
  expansionMode = "none",
113912
114799
  showExpansionControls = false,
113913
114800
  defaultDetailView = true,
114801
+ runHeaderInputMode = "display",
113914
114802
  apiConfig
113915
114803
  } = config2;
113916
114804
  console.log("🔧 DebugPanel - Config received:", {
@@ -113971,10 +114859,12 @@ const DebugPanel = forwardRef(({
113971
114859
  }
113972
114860
  }), []);
113973
114861
  const sessionTree = useMemo(() => {
113974
- const tree = TreeBuilder.buildSessionTree(executionEvents, sessionId);
114862
+ const tree = TreeBuilder.buildSessionTree(executionEvents, sessionId, {
114863
+ runHeaderInputMode
114864
+ });
113975
114865
  prevSessionTreeRef.current = tree;
113976
114866
  return tree;
113977
- }, [executionEvents, sessionId]);
114867
+ }, [executionEvents, sessionId, runHeaderInputMode]);
113978
114868
  const getAllNodeIds = (tree) => {
113979
114869
  const nodeIds = [];
113980
114870
  const collectIds = (node) => {
@@ -114382,16 +115272,25 @@ const DebugPanel = forwardRef(({
114382
115272
  const findFinalOutput = (nodes) => {
114383
115273
  let lastOutput = void 0;
114384
115274
  let routeToUserOutput = void 0;
115275
+ let postProcessorOutput = void 0;
114385
115276
  const traverse = (nodeList) => {
114386
- var _a, _b, _c, _d, _e;
115277
+ var _a, _b, _c, _d, _e, _f;
114387
115278
  for (const node of nodeList) {
115279
+ if (node.type === "tool" && ((_a = node.metadata) == null ? void 0 : _a.type) === "PostProcessor" && node.output) {
115280
+ const ppOut = node.output;
115281
+ if (typeof ppOut === "object" && ppOut.output) {
115282
+ postProcessorOutput = typeof ppOut.output === "string" ? ppOut.output : JSON.stringify(ppOut.output);
115283
+ } else if (typeof ppOut === "string") {
115284
+ postProcessorOutput = ppOut;
115285
+ }
115286
+ }
114388
115287
  if (node.type === "tool" && (node.name === "route_to_user" || node.name === "route_to_user")) {
114389
115288
  if (node.output) {
114390
115289
  if (typeof node.output === "string") {
114391
115290
  routeToUserOutput = node.output;
114392
- } else if ((_a = node.output) == null ? void 0 : _a.message) {
115291
+ } else if ((_b = node.output) == null ? void 0 : _b.message) {
114393
115292
  routeToUserOutput = node.output.message;
114394
- } else if ((_b = node.output) == null ? void 0 : _b.result) {
115293
+ } else if ((_c = node.output) == null ? void 0 : _c.result) {
114395
115294
  routeToUserOutput = node.output.result;
114396
115295
  }
114397
115296
  }
@@ -114401,7 +115300,7 @@ const DebugPanel = forwardRef(({
114401
115300
  (item) => (item == null ? void 0 : item.name) === "route_to_user" || (item == null ? void 0 : item.toolName) === "route_to_user"
114402
115301
  );
114403
115302
  if (routeItem) {
114404
- if ((_c = routeItem.args) == null ? void 0 : _c.message) {
115303
+ if ((_d = routeItem.args) == null ? void 0 : _d.message) {
114405
115304
  routeToUserOutput = routeItem.args.message;
114406
115305
  } else if (routeItem.message) {
114407
115306
  routeToUserOutput = routeItem.message;
@@ -114412,9 +115311,9 @@ const DebugPanel = forwardRef(({
114412
115311
  if (typeof node.output === "string") {
114413
115312
  lastOutput = node.output;
114414
115313
  } else if (!Array.isArray(node.output)) {
114415
- if ((_d = node.output) == null ? void 0 : _d.message) {
115314
+ if ((_e = node.output) == null ? void 0 : _e.message) {
114416
115315
  lastOutput = node.output.message;
114417
- } else if ((_e = node.output) == null ? void 0 : _e.result) {
115316
+ } else if ((_f = node.output) == null ? void 0 : _f.result) {
114418
115317
  lastOutput = node.output.result;
114419
115318
  } else if (typeof node.output === "object") {
114420
115319
  if (!node.output.name && !node.output.toolName) {
@@ -114429,7 +115328,7 @@ const DebugPanel = forwardRef(({
114429
115328
  }
114430
115329
  };
114431
115330
  traverse(nodes);
114432
- return routeToUserOutput || lastOutput;
115331
+ return postProcessorOutput || routeToUserOutput || lastOutput;
114433
115332
  };
114434
115333
  const outputFromNodes = run2.rootNodes ? findFinalOutput(run2.rootNodes) : void 0;
114435
115334
  const finalOutput = outputFromNodes || run2.finalOutput;
@@ -141250,6 +142149,57 @@ function nodeContentToInline(content) {
141250
142149
  };
141251
142150
  });
141252
142151
  }
142152
+ function getVariableContextAtPosition(editor, pos) {
142153
+ const { doc: doc2 } = editor.state;
142154
+ if (pos < 2 || pos > doc2.content.size) {
142155
+ return null;
142156
+ }
142157
+ const $pos = doc2.resolve(pos);
142158
+ const parent = $pos.parent;
142159
+ if (!parent.isTextblock) {
142160
+ return null;
142161
+ }
142162
+ const contentStart = $pos.start();
142163
+ let text = "";
142164
+ const posMap = [];
142165
+ parent.forEach((node, offset2) => {
142166
+ const nodeDocStart = contentStart + offset2;
142167
+ if (nodeDocStart >= pos) return;
142168
+ if (node.isText && node.text) {
142169
+ const charsToTake = Math.min(node.text.length, pos - nodeDocStart);
142170
+ for (let i2 = 0; i2 < charsToTake; i2++) {
142171
+ posMap.push(nodeDocStart + i2);
142172
+ text += node.text[i2];
142173
+ }
142174
+ }
142175
+ });
142176
+ const lastOpen = text.lastIndexOf("{{");
142177
+ if (lastOpen === -1) {
142178
+ return null;
142179
+ }
142180
+ const queryText = text.substring(lastOpen + 2);
142181
+ if (queryText.includes("}}")) {
142182
+ return null;
142183
+ }
142184
+ const triggerFrom = posMap[lastOpen];
142185
+ if (triggerFrom === void 0) {
142186
+ return null;
142187
+ }
142188
+ const trimmedQuery = /^\}*$/.test(queryText) ? "" : queryText;
142189
+ return { triggerFrom, query: trimmedQuery };
142190
+ }
142191
+ const TYPE_PREFIXES = ["env", "memory", "system", "content"];
142192
+ function inferVariableType(path) {
142193
+ const firstDot = path.indexOf(".");
142194
+ if (firstDot === -1) return "custom";
142195
+ const prefix2 = path.substring(0, firstDot).toLowerCase();
142196
+ return TYPE_PREFIXES.includes(prefix2) ? prefix2 : "custom";
142197
+ }
142198
+ function removeTypePrefix(path) {
142199
+ const type = inferVariableType(path);
142200
+ if (type === "custom") return path;
142201
+ return path.substring(type.length + 1);
142202
+ }
141253
142203
  const buildVariableSyntax = (variableType, path) => {
141254
142204
  if (variableType === "system" || variableType === "custom") {
141255
142205
  return `{{${path}}}`;
@@ -141968,6 +142918,27 @@ const ChevronRightIcon = ({ size = 16, className }) => /* @__PURE__ */ jsxRuntim
141968
142918
  )
141969
142919
  }
141970
142920
  );
142921
+ const AIStarIcon = ({ size = 14, className }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
142922
+ "svg",
142923
+ {
142924
+ width: size,
142925
+ height: size,
142926
+ viewBox: "0 0 14 14",
142927
+ fill: "none",
142928
+ xmlns: "http://www.w3.org/2000/svg",
142929
+ className,
142930
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
142931
+ "path",
142932
+ {
142933
+ d: "M2.10833 12.3167V9.4M2.10833 3.56667V0.65M0.65 2.10833H3.56667M0.65 10.8583H3.56667M7.06667 1.23333L6.05506 3.8635C5.89056 4.29122 5.8083 4.50508 5.68039 4.68497C5.56703 4.8444 5.42773 4.98369 5.2683 5.09706C5.08841 5.22497 4.87455 5.30722 4.44684 5.47173L1.81667 6.48333L4.44684 7.49494C4.87455 7.65944 5.08841 7.7417 5.2683 7.86961C5.42773 7.98297 5.56703 8.12227 5.68039 8.2817C5.8083 8.46159 5.89056 8.67545 6.05506 9.10316L7.06667 11.7333L8.07827 9.10316C8.24278 8.67545 8.32503 8.46159 8.45294 8.2817C8.56631 8.12227 8.7056 7.98297 8.86503 7.86961C9.04492 7.7417 9.25878 7.65944 9.6865 7.49494L12.3167 6.48333L9.6865 5.47173C9.25878 5.30722 9.04492 5.22497 8.86503 5.09706C8.7056 4.98369 8.56631 4.8444 8.45294 4.68497C8.32503 4.50508 8.24278 4.29122 8.07827 3.8635L7.06667 1.23333Z",
142934
+ stroke: "currentColor",
142935
+ strokeWidth: "1.3",
142936
+ strokeLinecap: "round",
142937
+ strokeLinejoin: "round"
142938
+ }
142939
+ )
142940
+ }
142941
+ );
141971
142942
  const CATEGORY_ICON_MAP = {
141972
142943
  agents: AgentsIcon,
141973
142944
  tools: ToolsIcon,
@@ -142844,7 +143815,7 @@ const VariableMenu = ({
142844
143815
  setCurrentPath(parsedQuery.path);
142845
143816
  }
142846
143817
  }, [parsedQuery.category, parsedQuery.path, activeCategory]);
142847
- useEffect(() => {
143818
+ useLayoutEffect(() => {
142848
143819
  if (!menuRef.current) return;
142849
143820
  const menuRect = menuRef.current.getBoundingClientRect();
142850
143821
  const viewportWidth = window.innerWidth;
@@ -142865,7 +143836,7 @@ const VariableMenu = ({
142865
143836
  newTop = padding;
142866
143837
  }
142867
143838
  setAdjustedPosition({ top: newTop, left: newLeft });
142868
- }, [position]);
143839
+ }, [position, activeCategory, currentPath.length, query]);
142869
143840
  const categories = [
142870
143841
  { id: "env", label: "Environment Variables", icon: VariableIcon, variables: envVariables },
142871
143842
  { id: "memory", label: "Memory", icon: MemoryIcon, variables: memoryVariables },
@@ -142940,13 +143911,21 @@ const VariableMenu = ({
142940
143911
  }
142941
143912
  }, [editorControlled]);
142942
143913
  useEffect(() => {
143914
+ const isEventInsideMenu = (event) => {
143915
+ if (!menuRef.current) return false;
143916
+ const path = typeof event.composedPath === "function" ? event.composedPath() : [];
143917
+ if (path.length > 0) {
143918
+ return path.includes(menuRef.current);
143919
+ }
143920
+ return menuRef.current.contains(event.target);
143921
+ };
142943
143922
  const handleClickOutside = (e3) => {
142944
- if (menuRef.current && !menuRef.current.contains(e3.target)) {
143923
+ if (!isEventInsideMenu(e3)) {
142945
143924
  onClose();
142946
143925
  }
142947
143926
  };
142948
- document.addEventListener("mousedown", handleClickOutside);
142949
- return () => document.removeEventListener("mousedown", handleClickOutside);
143927
+ document.addEventListener("mousedown", handleClickOutside, true);
143928
+ return () => document.removeEventListener("mousedown", handleClickOutside, true);
142950
143929
  }, [onClose]);
142951
143930
  useEffect(() => {
142952
143931
  const handleKeyDown2 = (e3) => {
@@ -143033,6 +144012,10 @@ const VariableMenu = ({
143033
144012
  "button",
143034
144013
  {
143035
144014
  type: "button",
144015
+ onMouseDown: (e3) => {
144016
+ e3.preventDefault();
144017
+ e3.stopPropagation();
144018
+ },
143036
144019
  onClick: handleBack,
143037
144020
  className: "flex items-center justify-center w-[24px] h-[24px] p-0 border-0 bg-[#F9FAFB] rounded-[4px] cursor-pointer text-[#667085] hover:bg-[#F2F4F7]",
143038
144021
  "aria-label": "Go back",
@@ -143058,7 +144041,7 @@ const VariableMenu = ({
143058
144041
  )
143059
144042
  ] }) }),
143060
144043
  !activeCategory && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pt-[8px] pb-[4px] px-[12px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[12px] leading-[16px] font-normal text-[#667085]", children: "Type to search or choose from:" }) }),
143061
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children: items.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-[16px] text-center text-[#667085] text-[14px]", children: "No items found" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: items.map((item, index) => {
144044
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: items.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-[16px] text-center text-[#667085] text-[14px]", children: "No items found" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: items.map((item, index) => {
143062
144045
  var _a;
143063
144046
  const isCategory = "variables" in item;
143064
144047
  const Icon = isCategory ? item.icon : getIconForType(item.type);
@@ -143067,7 +144050,11 @@ const VariableMenu = ({
143067
144050
  "button",
143068
144051
  {
143069
144052
  type: "button",
143070
- onClick: () => handleItemClick(item),
144053
+ onMouseDown: (e3) => {
144054
+ e3.preventDefault();
144055
+ e3.stopPropagation();
144056
+ handleItemClick(item);
144057
+ },
143071
144058
  className: `flex items-center gap-[8px] w-full px-[12px] py-[8px] border-0 rounded-[4px] text-left cursor-pointer transition-colors duration-100 ${index === selectedIndex ? "bg-[#F9FAFB]" : "bg-transparent hover:bg-[#F9FAFB]"}`,
143072
144059
  onMouseEnter: () => setSelectedIndex(index),
143073
144060
  "data-test-id": `md-editor-variable-item-${isCategory ? item.id : item.id}`,
@@ -143643,7 +144630,9 @@ const UnifiedToolbar = ({
143643
144630
  theme = "light",
143644
144631
  disabled = false,
143645
144632
  containerRef,
143646
- followSelection = false
144633
+ followSelection = false,
144634
+ showDesignWithAI = false,
144635
+ onDesignWithAI
143647
144636
  }) => {
143648
144637
  const [position, setPosition] = useState(null);
143649
144638
  const [isAtSelection, setIsAtSelection] = useState(false);
@@ -144001,7 +144990,30 @@ const UnifiedToolbar = ({
144001
144990
  )
144002
144991
  ] }),
144003
144992
  /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarDivider$2, {}),
144004
- showAIButton && onAIAction && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: aiDropdownRef, className: "relative shrink-0", children: [
144993
+ showDesignWithAI && onDesignWithAI && /* @__PURE__ */ jsxRuntimeExports.jsxs(
144994
+ "button",
144995
+ {
144996
+ type: "button",
144997
+ onClick: (e3) => {
144998
+ e3.preventDefault();
144999
+ e3.stopPropagation();
145000
+ onDesignWithAI();
145001
+ },
145002
+ disabled,
145003
+ className: `
145004
+ flex items-center justify-center gap-1 px-3 py-1 rounded-[4px]
145005
+ text-[12px] leading-[16px] font-medium transition-colors duration-150 whitespace-nowrap
145006
+ border border-[#6A11CB] text-[#004EEB] hover:bg-[#EFF4FF]
145007
+ ${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
145008
+ `,
145009
+ "data-id": "toolbar-design-with-ai",
145010
+ children: [
145011
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AIStarIcon, { size: 14, className: "text-[#155EEF]" }),
145012
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Design with AI" })
145013
+ ]
145014
+ }
145015
+ ),
145016
+ showAIButton && onAIAction && !showDesignWithAI && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: aiDropdownRef, className: "relative shrink-0", children: [
144005
145017
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
144006
145018
  "button",
144007
145019
  {
@@ -144116,7 +145128,8 @@ const ACTION_LABELS = {
144116
145128
  "make-shorter": "Make Shorter",
144117
145129
  "make-longer": "Make Longer",
144118
145130
  "convert-to-yaml": "Convert to YAML",
144119
- "custom": "Custom Modify"
145131
+ "custom": "Custom Modify",
145132
+ "generate": "Generate"
144120
145133
  };
144121
145134
  function calculateTextSimilarity(text1, text2) {
144122
145135
  if (text1 === text2) return 1;
@@ -144150,7 +145163,7 @@ const AIDesignPanel = ({
144150
145163
  sessionState,
144151
145164
  sessionActions
144152
145165
  }) => {
144153
- var _a, _b;
145166
+ var _a, _b, _c;
144154
145167
  const useSessionMode = !!sessionState && !!sessionActions;
144155
145168
  const [messages, setMessages] = useState([]);
144156
145169
  const [inputValue, setInputValue] = useState("");
@@ -144166,6 +145179,36 @@ const AIDesignPanel = ({
144166
145179
  const modificationReason = useSessionMode ? sessionState.modificationReason : selectionModifiedReason;
144167
145180
  const currentGeneratedContent = useSessionMode ? (_b = sessionState.session) == null ? void 0 : _b.lastGeneratedContent : generatedContent;
144168
145181
  const displayMessages = useSessionMode ? convertSessionHistoryToMessages(sessionState) : messages;
145182
+ const [appliedFeedback, setAppliedFeedback] = useState(null);
145183
+ const [copiedFeedback, setCopiedFeedback] = useState(false);
145184
+ const [pendingApplyMode, setPendingApplyMode] = useState(null);
145185
+ const [autocopiedOnFail, setAutocopiedOnFail] = useState(false);
145186
+ const appliedTimerRef = useRef(null);
145187
+ const copiedTimerRef = useRef(null);
145188
+ const lastAssistantMsgId = useMemo(() => {
145189
+ const assistantMsgs = displayMessages.filter(
145190
+ (m3) => m3.type === "assistant" && !m3.isGenerating && !m3.isError
145191
+ );
145192
+ return assistantMsgs.length > 0 ? assistantMsgs[assistantMsgs.length - 1].id : null;
145193
+ }, [displayMessages]);
145194
+ const showInsertButton = isSelectionMode;
145195
+ const cursorInsertActive = useSessionMode && sessionState.cursorInsertPosition !== null;
145196
+ const replaceTooltip = isSelectionMode ? "Replace selection" : "Replace all";
145197
+ const insertTooltip = cursorInsertActive ? "Insert at cursor" : "Insert below selection";
145198
+ useEffect(() => {
145199
+ return () => {
145200
+ if (appliedTimerRef.current) clearTimeout(appliedTimerRef.current);
145201
+ if (copiedTimerRef.current) clearTimeout(copiedTimerRef.current);
145202
+ };
145203
+ }, []);
145204
+ useEffect(() => {
145205
+ if (isCurrentlyGenerating) {
145206
+ setAppliedFeedback(null);
145207
+ setCopiedFeedback(false);
145208
+ setPendingApplyMode(null);
145209
+ setAutocopiedOnFail(false);
145210
+ }
145211
+ }, [isCurrentlyGenerating]);
144169
145212
  useEffect(() => {
144170
145213
  var _a2;
144171
145214
  (_a2 = messagesEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
@@ -144269,8 +145312,9 @@ const AIDesignPanel = ({
144269
145312
  setGeneratedContent(response.refinedText);
144270
145313
  onContentGenerated == null ? void 0 : onContentGenerated(true);
144271
145314
  } catch (error) {
145315
+ const errorMsg = error instanceof Error ? error.message : "Failed to generate. Please try again.";
144272
145316
  setMessages((prev) => prev.map(
144273
- (msg) => msg.id === aiMsgId ? { ...msg, content: "Failed to generate. Please try again.", isGenerating: false, isError: true } : msg
145317
+ (msg) => msg.id === aiMsgId ? { ...msg, content: errorMsg, isGenerating: false, isError: true } : msg
144274
145318
  ));
144275
145319
  } finally {
144276
145320
  setIsGenerating(false);
@@ -144312,8 +145356,9 @@ const AIDesignPanel = ({
144312
145356
  setGeneratedContent(response.refinedText);
144313
145357
  onContentGenerated == null ? void 0 : onContentGenerated(true);
144314
145358
  } catch (error) {
145359
+ const errorMsg = error instanceof Error ? error.message : "Failed to generate. Please try again.";
144315
145360
  setMessages((prev) => prev.map(
144316
- (msg) => msg.id === aiMsgId ? { ...msg, content: "Failed to generate. Please try again.", isGenerating: false, isError: true } : msg
145361
+ (msg) => msg.id === aiMsgId ? { ...msg, content: errorMsg, isGenerating: false, isError: true } : msg
144317
145362
  ));
144318
145363
  } finally {
144319
145364
  setIsGenerating(false);
@@ -144348,6 +145393,52 @@ const AIDesignPanel = ({
144348
145393
  };
144349
145394
  }
144350
145395
  }, [useSessionMode, sessionActions, generatedContent, onReplace, isSelectionMode]);
145396
+ const handleCopy = useCallback(async () => {
145397
+ var _a2;
145398
+ const content = useSessionMode ? (_a2 = sessionState == null ? void 0 : sessionState.session) == null ? void 0 : _a2.lastGeneratedContent : generatedContent;
145399
+ if (content) {
145400
+ await navigator.clipboard.writeText(content);
145401
+ setCopiedFeedback(true);
145402
+ if (copiedTimerRef.current) clearTimeout(copiedTimerRef.current);
145403
+ copiedTimerRef.current = setTimeout(() => setCopiedFeedback(false), 2e3);
145404
+ }
145405
+ }, [useSessionMode, sessionState, generatedContent]);
145406
+ const handleInsertWithFeedback = useCallback(() => {
145407
+ setPendingApplyMode("insert");
145408
+ setAutocopiedOnFail(false);
145409
+ handleInsert();
145410
+ }, [handleInsert]);
145411
+ const handleReplaceWithFeedback = useCallback(() => {
145412
+ setPendingApplyMode("replace");
145413
+ setAutocopiedOnFail(false);
145414
+ handleReplace();
145415
+ }, [handleReplace]);
145416
+ useEffect(() => {
145417
+ var _a2;
145418
+ if (!pendingApplyMode) return;
145419
+ if (useSessionMode) {
145420
+ if (sessionState.status === "applied") {
145421
+ setAppliedFeedback(pendingApplyMode);
145422
+ setPendingApplyMode(null);
145423
+ if (appliedTimerRef.current) clearTimeout(appliedTimerRef.current);
145424
+ appliedTimerRef.current = setTimeout(() => setAppliedFeedback(null), 2500);
145425
+ } else if (sessionState.isOriginalModified) {
145426
+ const content = (_a2 = sessionState.session) == null ? void 0 : _a2.lastGeneratedContent;
145427
+ if (content) {
145428
+ navigator.clipboard.writeText(content).catch(() => {
145429
+ });
145430
+ setAutocopiedOnFail(true);
145431
+ }
145432
+ setAppliedFeedback(null);
145433
+ setPendingApplyMode(null);
145434
+ }
145435
+ } else {
145436
+ setAppliedFeedback(pendingApplyMode);
145437
+ setPendingApplyMode(null);
145438
+ if (appliedTimerRef.current) clearTimeout(appliedTimerRef.current);
145439
+ appliedTimerRef.current = setTimeout(() => setAppliedFeedback(null), 2500);
145440
+ }
145441
+ }, [pendingApplyMode, useSessionMode, sessionState == null ? void 0 : sessionState.status, sessionState == null ? void 0 : sessionState.isOriginalModified, (_c = sessionState == null ? void 0 : sessionState.session) == null ? void 0 : _c.lastGeneratedContent]);
144351
145442
  const handleStop = useCallback(() => {
144352
145443
  if (useSessionMode) {
144353
145444
  return;
@@ -144447,34 +145538,71 @@ const AIDesignPanel = ({
144447
145538
  // Result - gray background bubble
144448
145539
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full", children: [
144449
145540
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-[#F2F4F7] rounded-xl p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-[#101828] leading-relaxed whitespace-pre-wrap", children: message.content }) }),
144450
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
144451
- /* @__PURE__ */ jsxRuntimeExports.jsx(
144452
- "button",
144453
- {
144454
- type: "button",
144455
- onClick: handleInsert,
144456
- disabled: isModified,
144457
- title: isModified ? modificationReason || "Selected text has been modified" : void 0,
144458
- className: `px-2.5 py-0.5 text-sm font-medium rounded-full border transition-colors ${isModified ? "text-[#98A2B3] bg-[#F9FAFB] border-[#EAECF0] cursor-not-allowed" : "text-[#344054] bg-white border-[#EAECF0] hover:bg-gray-50 cursor-pointer"}`,
144459
- children: "Insert"
144460
- }
144461
- ),
144462
- (onReplace || useSessionMode) && /* @__PURE__ */ jsxRuntimeExports.jsx(
144463
- "button",
144464
- {
144465
- type: "button",
144466
- onClick: handleReplace,
144467
- disabled: isModified,
144468
- title: isModified ? modificationReason || "Selected text has been modified" : void 0,
144469
- className: `px-2.5 py-0.5 text-sm font-medium rounded-full border transition-colors ${isModified ? "text-[#98A2B3] bg-[#F9FAFB] border-[#EAECF0] cursor-not-allowed" : "text-[#344054] bg-white border-[#EAECF0] hover:bg-gray-50 cursor-pointer"}`,
144470
- children: "Replace"
144471
- }
144472
- )
144473
- ] }),
144474
- isModified && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-[#F79009] mt-1.5 flex items-center gap-1", children: [
144475
- /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M6 4V6M6 8H6.005M10.5 6C10.5 8.48528 8.48528 10.5 6 10.5C3.51472 10.5 1.5 8.48528 1.5 6C1.5 3.51472 3.51472 1.5 6 1.5C8.48528 1.5 10.5 3.51472 10.5 6Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
144476
- modificationReason || "Original text was modified"
144477
- ] })
145541
+ message.id === lastAssistantMsgId && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: appliedFeedback ? (
145542
+ /* Success feedback */
145543
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 mt-2 text-[#12B76A] animate-[fadeIn_0.2s_ease-out]", children: [
145544
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 14, strokeWidth: 2.5 }),
145545
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: appliedFeedback === "replace" ? "Replaced" : "Inserted" }),
145546
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-[#667085] ml-1", children: [
145547
+ navigator.platform.includes("Mac") ? "⌘Z" : "Ctrl+Z",
145548
+ " to undo"
145549
+ ] })
145550
+ ] })
145551
+ ) : isModified ? (
145552
+ /* Recovery UI -- original text was modified, apply would fail */
145553
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 animate-[fadeIn_0.2s_ease-out]", children: [
145554
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
145555
+ "button",
145556
+ {
145557
+ type: "button",
145558
+ onClick: handleCopy,
145559
+ className: "px-2.5 py-0.5 text-sm font-medium rounded-full border transition-colors text-[#344054] bg-white border-[#EAECF0] hover:bg-gray-50 cursor-pointer flex items-center gap-1.5",
145560
+ children: copiedFeedback || autocopiedOnFail ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
145561
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 12, className: "text-[#12B76A]" }),
145562
+ " Copied"
145563
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
145564
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 12 }),
145565
+ " Copy content"
145566
+ ] })
145567
+ }
145568
+ ) }),
145569
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-[#667085] mt-1.5", children: autocopiedOnFail ? "Content saved to clipboard. Paste manually or re-select text to try again." : `${modificationReason || "Original text changed"}. Copy content and paste manually, or re-select text.` })
145570
+ ] })
145571
+ ) : (
145572
+ /* Normal action buttons */
145573
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mt-2", children: [
145574
+ (onReplace || useSessionMode) && /* @__PURE__ */ jsxRuntimeExports.jsx(
145575
+ "button",
145576
+ {
145577
+ type: "button",
145578
+ onClick: handleReplaceWithFeedback,
145579
+ title: replaceTooltip,
145580
+ className: "px-2.5 py-0.5 text-sm font-medium rounded-full border transition-colors text-white bg-[#155EEF] border-[#155EEF] hover:bg-[#1849D6] cursor-pointer",
145581
+ children: "Replace"
145582
+ }
145583
+ ),
145584
+ showInsertButton && /* @__PURE__ */ jsxRuntimeExports.jsx(
145585
+ "button",
145586
+ {
145587
+ type: "button",
145588
+ onClick: handleInsertWithFeedback,
145589
+ title: insertTooltip,
145590
+ className: "px-2.5 py-0.5 text-sm font-medium rounded-full border transition-colors text-[#344054] bg-white border-[#EAECF0] hover:bg-gray-50 cursor-pointer",
145591
+ children: "Insert"
145592
+ }
145593
+ ),
145594
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
145595
+ "button",
145596
+ {
145597
+ type: "button",
145598
+ onClick: handleCopy,
145599
+ title: copiedFeedback ? "Copied!" : "Copy to clipboard",
145600
+ className: "p-1 text-[#667085] hover:text-[#344054] hover:bg-gray-100 rounded transition-colors cursor-pointer",
145601
+ children: copiedFeedback ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 14, className: "text-[#12B76A]" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 14 })
145602
+ }
145603
+ )
145604
+ ] })
145605
+ ) })
144478
145606
  ] })
144479
145607
  ) })
144480
145608
  ) }, message.id)),
@@ -144557,6 +145685,32 @@ function convertSessionHistoryToMessages(sessionState) {
144557
145685
  }
144558
145686
  return messages;
144559
145687
  }
145688
+ const EmptyStatePlaceholder = ({
145689
+ placeholder = "Write your agent definition here or type '/' to insert variables, agents, tools, memory & more",
145690
+ example,
145691
+ isFocused = false
145692
+ }) => {
145693
+ if (isFocused) return null;
145694
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
145695
+ "div",
145696
+ {
145697
+ className: "absolute inset-0 pointer-events-none px-[32px] py-[24px] overflow-hidden",
145698
+ "data-id": "md-editor-empty-state",
145699
+ children: [
145700
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[14px] leading-[20px] text-[#98A2B3] mb-[8px]", children: placeholder }),
145701
+ example && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[14px] leading-[20px] text-[#98A2B3]", children: example })
145702
+ ]
145703
+ }
145704
+ );
145705
+ };
145706
+ const AgentDefinitionExample = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
145707
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mb-[14px]", children: "e.g., You are a meeting scheduler agent who coordinate sales meetings by checking team availability, matching prospect needs with appropriate sales specialists, and sending prep materials." }),
145708
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "list-disc ml-[21px]", children: [
145709
+ /* @__PURE__ */ jsxRuntimeExports.jsx("li", { className: "mb-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "leading-[20px]", children: "Match prospect needs with sales expertise" }) }),
145710
+ /* @__PURE__ */ jsxRuntimeExports.jsx("li", { className: "mb-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "leading-[20px]", children: "Find optimal meeting times across calendars" }) }),
145711
+ /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "leading-[20px]", children: "Distribute meeting agenda and materials" }) })
145712
+ ] })
145713
+ ] });
144560
145714
  function hashString(str) {
144561
145715
  let hash2 = 5381;
144562
145716
  for (let i2 = 0; i2 < str.length; i2++) {
@@ -144766,7 +145920,8 @@ const initialState = {
144766
145920
  modificationReason: "",
144767
145921
  pendingSelection: null,
144768
145922
  showSwitchBanner: false,
144769
- error: null
145923
+ error: null,
145924
+ cursorInsertPosition: null
144770
145925
  };
144771
145926
  function refinementReducer(state, action) {
144772
145927
  switch (action.type) {
@@ -144877,7 +146032,7 @@ function refinementReducer(state, action) {
144877
146032
  }
144878
146033
  case "APPLY_CONTENT": {
144879
146034
  if (!state.session) return state;
144880
- const { appliedContent } = action.payload;
146035
+ const { appliedContent, newFingerprint } = action.payload;
144881
146036
  return {
144882
146037
  ...state,
144883
146038
  status: "applied",
@@ -144885,8 +146040,11 @@ function refinementReducer(state, action) {
144885
146040
  ...state.session,
144886
146041
  appliedContent,
144887
146042
  applyCount: state.session.applyCount + 1,
144888
- workingContent: appliedContent
146043
+ workingContent: appliedContent,
144889
146044
  // For subsequent refinements
146045
+ // Update fingerprint to track the newly applied content's position
146046
+ // This enables subsequent iterations to work on the replaced content
146047
+ fingerprint: newFingerprint || state.session.fingerprint
144890
146048
  },
144891
146049
  isOriginalModified: false,
144892
146050
  modificationReason: ""
@@ -144894,9 +146052,9 @@ function refinementReducer(state, action) {
144894
146052
  }
144895
146053
  case "SELECTION_CHANGED": {
144896
146054
  if (!state.session) return state;
144897
- const { fingerprint } = action.payload;
144898
- const isFullDocument = fingerprint.contextBefore === "" && fingerprint.contextAfter === "";
144899
- const newMode = isFullDocument ? "full-document" : "selection";
146055
+ const { fingerprint, explicitMode } = action.payload;
146056
+ const inferredMode = fingerprint.contextBefore === "" && fingerprint.contextAfter === "" ? "full-document" : "selection";
146057
+ const newMode = explicitMode ?? inferredMode;
144900
146058
  return {
144901
146059
  ...state,
144902
146060
  session: {
@@ -144904,8 +146062,10 @@ function refinementReducer(state, action) {
144904
146062
  mode: newMode,
144905
146063
  fingerprint,
144906
146064
  workingContent: fingerprint.selectedMarkdown,
144907
- // Reset applied content since selection changed
144908
- appliedContent: null
146065
+ // Reset apply state since selection changed -- previous apply context is irrelevant
146066
+ appliedContent: null,
146067
+ applyCount: 0,
146068
+ lastGeneratedContent: null
144909
146069
  },
144910
146070
  // Clear modification state since we have a fresh selection
144911
146071
  isOriginalModified: false,
@@ -144913,7 +146073,8 @@ function refinementReducer(state, action) {
144913
146073
  // Only show switch banner if there was content and this is user-initiated selection change
144914
146074
  // For now, keep it simple - don't show banner, just update context
144915
146075
  pendingSelection: null,
144916
- showSwitchBanner: false
146076
+ showSwitchBanner: false,
146077
+ cursorInsertPosition: null
144917
146078
  };
144918
146079
  }
144919
146080
  case "CONFIRM_SWITCH": {
@@ -144982,6 +146143,11 @@ function refinementReducer(state, action) {
144982
146143
  }
144983
146144
  };
144984
146145
  }
146146
+ case "SET_CURSOR_INSERT_POSITION":
146147
+ return {
146148
+ ...state,
146149
+ cursorInsertPosition: action.payload.position
146150
+ };
144985
146151
  default:
144986
146152
  return state;
144987
146153
  }
@@ -144991,7 +146157,8 @@ function useAIRefinementSession({
144991
146157
  onRefine,
144992
146158
  editorContent,
144993
146159
  promptType,
144994
- agentContext
146160
+ agentContext,
146161
+ onContentApplied
144995
146162
  }) {
144996
146163
  const [state, dispatch] = useReducer(refinementReducer, initialState);
144997
146164
  const hasGeneratedContentRef = useRef(false);
@@ -145010,14 +146177,18 @@ function useAIRefinementSession({
145010
146177
  });
145011
146178
  if (editor) {
145012
146179
  let fingerprint;
145013
- if (range3 && range3.from !== range3.to) {
146180
+ const isSelection = !!range3 && range3.from !== range3.to;
146181
+ if (isSelection) {
145014
146182
  fingerprint = createSelectionFingerprint(editor, range3.from, range3.to);
145015
146183
  } else {
145016
146184
  fingerprint = createFullDocumentFingerprint(editor);
145017
146185
  }
145018
146186
  dispatch({
145019
146187
  type: "SELECTION_CHANGED",
145020
- payload: { fingerprint }
146188
+ payload: {
146189
+ fingerprint,
146190
+ explicitMode: isSelection ? "selection" : "full-document"
146191
+ }
145021
146192
  });
145022
146193
  }
145023
146194
  }, [editor]);
@@ -145027,13 +146198,24 @@ function useAIRefinementSession({
145027
146198
  }, []);
145028
146199
  const startGeneration = useCallback(async (action, instruction) => {
145029
146200
  if (!onRefine || !state.session) return;
145030
- const contextText = state.session.applyCount > 0 ? state.session.appliedContent || state.session.workingContent : state.session.lastGeneratedContent || state.session.workingContent;
146201
+ let contextText;
146202
+ if (state.session.mode === "full-document" && state.session.applyCount > 0) {
146203
+ contextText = editorContent || state.session.appliedContent || state.session.workingContent;
146204
+ } else if (state.session.applyCount > 0) {
146205
+ contextText = state.session.appliedContent || state.session.workingContent;
146206
+ } else {
146207
+ contextText = state.session.lastGeneratedContent || state.session.workingContent;
146208
+ }
146209
+ if (!contextText) {
146210
+ contextText = editorContent;
146211
+ }
145031
146212
  const actionLabels = {
145032
146213
  "improve": "Improve",
145033
146214
  "make-shorter": "Make Shorter",
145034
146215
  "make-longer": "Make Longer",
145035
146216
  "convert-to-yaml": "Convert to YAML",
145036
- "custom": instruction || "Custom"
146217
+ "custom": instruction || "Custom",
146218
+ "generate": "Generate new content"
145037
146219
  };
145038
146220
  const displayMessage = instruction || actionLabels[action] || action;
145039
146221
  const isFirstMessage = state.session.conversationHistory.length === 0;
@@ -145093,7 +146275,7 @@ function useAIRefinementSession({
145093
146275
  "custom": instruction || "Custom"
145094
146276
  };
145095
146277
  const displayMessage = instruction || actionLabels[action] || action;
145096
- const contentForAI = ((_a = state.session.fingerprint) == null ? void 0 : _a.selectedMarkdown) || state.session.workingContent;
146278
+ const contentForAI = ((_a = state.session.fingerprint) == null ? void 0 : _a.selectedMarkdown) || state.session.workingContent || editorContent;
145097
146279
  const quotedText = contentForAI.length > 100 ? `${contentForAI.substring(0, 100)}...` : contentForAI;
145098
146280
  dispatch({
145099
146281
  type: "START_GENERATION",
@@ -145137,11 +146319,13 @@ function useAIRefinementSession({
145137
146319
  if (!editor || !state.session || !state.session.lastGeneratedContent) return;
145138
146320
  const refinedText = state.session.lastGeneratedContent;
145139
146321
  let result;
146322
+ let newFingerprint;
145140
146323
  if (state.session.mode === "full-document") {
145141
146324
  try {
145142
146325
  const parsed = markdownToEditorJson(refinedText);
145143
146326
  editor.commands.setContent(parsed);
145144
146327
  result = { success: true };
146328
+ newFingerprint = createFullDocumentFingerprint(editor);
145145
146329
  } catch (error) {
145146
146330
  result = {
145147
146331
  success: false,
@@ -145161,10 +146345,17 @@ function useAIRefinementSession({
145161
146345
  } else {
145162
146346
  try {
145163
146347
  const parsedContent = markdownToEditorJson(refinedText);
146348
+ const insertionStart = matchedRange.from;
145164
146349
  if (mode === "replace") {
145165
146350
  editor.chain().focus().setTextSelection(matchedRange).deleteSelection().insertContent(parsedContent).run();
146351
+ const newEndPos = editor.state.selection.to;
146352
+ newFingerprint = createSelectionFingerprint(editor, insertionStart, newEndPos);
145166
146353
  } else {
145167
- editor.chain().focus().setTextSelection({ from: matchedRange.to, to: matchedRange.to }).insertContent("\n\n").insertContent(parsedContent).run();
146354
+ const useCursorPos = state.cursorInsertPosition !== null && state.cursorInsertPosition !== matchedRange.to;
146355
+ const insertPos = useCursorPos ? state.cursorInsertPosition : matchedRange.to;
146356
+ editor.chain().focus().setTextSelection({ from: insertPos, to: insertPos }).insertContent("\n\n").insertContent(parsedContent).run();
146357
+ const newEndPos = editor.state.selection.to;
146358
+ newFingerprint = createSelectionFingerprint(editor, insertPos + 2, newEndPos);
145168
146359
  }
145169
146360
  result = { success: true };
145170
146361
  } catch (error) {
@@ -145179,8 +146370,12 @@ function useAIRefinementSession({
145179
146370
  if (result.success) {
145180
146371
  dispatch({
145181
146372
  type: "APPLY_CONTENT",
145182
- payload: { mode, appliedContent: refinedText }
146373
+ payload: { mode, appliedContent: refinedText, newFingerprint }
145183
146374
  });
146375
+ if (onContentApplied && editor) {
146376
+ const fullMarkdown = state.session.mode === "full-document" ? refinedText : editorJsonToMarkdown(editor.getJSON());
146377
+ onContentApplied(fullMarkdown);
146378
+ }
145184
146379
  } else {
145185
146380
  dispatch({
145186
146381
  type: "SET_MODIFIED",
@@ -145190,7 +146385,7 @@ function useAIRefinementSession({
145190
146385
  }
145191
146386
  });
145192
146387
  }
145193
- }, [editor, state.session]);
146388
+ }, [editor, state.session, state.cursorInsertPosition, onContentApplied]);
145194
146389
  const handleSelectionChange = useCallback((from2, to, _text) => {
145195
146390
  if (!editor || !state.session) return;
145196
146391
  if (from2 === to) return;
@@ -145202,7 +146397,7 @@ function useAIRefinementSession({
145202
146397
  }
145203
146398
  dispatch({
145204
146399
  type: "SELECTION_CHANGED",
145205
- payload: { fingerprint: newFingerprint }
146400
+ payload: { fingerprint: newFingerprint, explicitMode: "selection" }
145206
146401
  });
145207
146402
  }, [editor, state.session]);
145208
146403
  const confirmSwitch = useCallback(() => {
@@ -145241,19 +146436,31 @@ function useAIRefinementSession({
145241
146436
  useEffect(() => {
145242
146437
  if (!editor || state.status === "idle") return;
145243
146438
  const handleSelectionUpdate = () => {
146439
+ var _a, _b;
145244
146440
  const { from: from2, to } = editor.state.selection;
145245
146441
  const hasSelection2 = from2 !== to;
145246
- if (!hasSelection2 || !hasGeneratedContentRef.current) {
145247
- return;
146442
+ if (hasSelection2) {
146443
+ if (hasGeneratedContentRef.current) {
146444
+ const selectedText = editor.state.doc.textBetween(from2, to, " ", "\n");
146445
+ handleSelectionChange(from2, to, selectedText);
146446
+ }
146447
+ if (state.cursorInsertPosition !== null) {
146448
+ dispatch({ type: "SET_CURSOR_INSERT_POSITION", payload: { position: null } });
146449
+ }
146450
+ } else if (((_a = state.session) == null ? void 0 : _a.mode) === "selection" && ((_b = state.session) == null ? void 0 : _b.fingerprint) && hasGeneratedContentRef.current) {
146451
+ const fp = state.session.fingerprint;
146452
+ const isOutside = from2 < fp.originalRange.from || from2 > fp.originalRange.to;
146453
+ const newPos = isOutside ? from2 : null;
146454
+ if (newPos !== state.cursorInsertPosition) {
146455
+ dispatch({ type: "SET_CURSOR_INSERT_POSITION", payload: { position: newPos } });
146456
+ }
145248
146457
  }
145249
- const selectedText = editor.state.doc.textBetween(from2, to, " ", "\n");
145250
- handleSelectionChange(from2, to, selectedText);
145251
146458
  };
145252
146459
  editor.on("selectionUpdate", handleSelectionUpdate);
145253
146460
  return () => {
145254
146461
  editor.off("selectionUpdate", handleSelectionUpdate);
145255
146462
  };
145256
- }, [editor, state.status, handleSelectionChange]);
146463
+ }, [editor, state.status, state.session, state.cursorInsertPosition, handleSelectionChange]);
145257
146464
  const actions = {
145258
146465
  openPanel,
145259
146466
  closePanel,
@@ -145320,7 +146527,12 @@ const MDEditor = forwardRef(
145320
146527
  onFocus,
145321
146528
  onBlur,
145322
146529
  onLoadSuggestions,
145323
- suggestionsLoading: propSuggestionsLoading = false
146530
+ suggestionsLoading: propSuggestionsLoading = false,
146531
+ // Empty state props
146532
+ emptyStatePlaceholder,
146533
+ emptyStateExample,
146534
+ showDesignWithAI = false,
146535
+ onDesignWithAI
145324
146536
  } = props;
145325
146537
  const mergedSlashConfig = { ...DEFAULT_SLASH_COMMAND_CONFIG, ...slashCommandConfig };
145326
146538
  const mergedAIConfig = { ...DEFAULT_AI_CONFIG, ...aiConfig };
@@ -145328,13 +146540,16 @@ const MDEditor = forwardRef(
145328
146540
  const lastEmittedMarkdownRef = useRef("");
145329
146541
  const isInternalUpdateRef = useRef(false);
145330
146542
  const editorContainerRef = useRef(null);
146543
+ const skipRawSyncRef = useRef(false);
146544
+ const skipEditorSyncRef = useRef(false);
145331
146545
  const [asyncSuggestions, setAsyncSuggestions] = useState(null);
145332
146546
  const [suggestionsLoading, setSuggestionsLoading] = useState(false);
145333
146547
  const [variableMenuOpen, setVariableMenuOpen] = useState(false);
145334
146548
  const [variableMenuPosition, setVariableMenuPosition] = useState({ top: 0, left: 0 });
145335
146549
  const [variableMenuQuery, setVariableMenuQuery] = useState("");
145336
- const [editingVariableChip, setEditingVariableChip] = useState(null);
145337
146550
  const variableTriggerPosRef = useRef(null);
146551
+ const hasVariableSuggestionsRef = useRef(false);
146552
+ const variableMenuOpenRef = useRef(false);
145338
146553
  const [editorMode, setEditorMode] = useState("editor");
145339
146554
  const [rawMarkdown, setRawMarkdown] = useState("");
145340
146555
  const isRawMode = editorMode === "preview";
@@ -145378,12 +146593,7 @@ const MDEditor = forwardRef(
145378
146593
  contentVariables: mergedContentVariables,
145379
146594
  loading: finalSuggestionsLoading
145380
146595
  };
145381
- console.log("MDEditor render: suggestionsRef updated with:", {
145382
- agentsCount: mergedAgents.length,
145383
- toolsCount: mergedTools.length,
145384
- knowledgeCount: mergedKnowledge.length,
145385
- hasAsyncSuggestions: !!asyncSuggestions
145386
- });
146596
+ hasVariableSuggestionsRef.current = mergedEnvVariables.length > 0 || mergedMemoryVariables.length > 0 || mergedSystemVariables.length > 0 || mergedContentVariables.length > 0;
145387
146597
  const defaultCategories = useMemo(() => {
145388
146598
  const categories = [];
145389
146599
  if (mergedAgents.length > 0) {
@@ -145448,21 +146658,6 @@ const MDEditor = forwardRef(
145448
146658
  (variable, triggerPos) => {
145449
146659
  if (!editorRef.current) return;
145450
146660
  const editor2 = editorRef.current;
145451
- if (editingVariableChip) {
145452
- const { position, nodeSize: nodeSize2 } = editingVariableChip;
145453
- editor2.chain().focus().deleteRange({ from: position, to: position + nodeSize2 }).insertContentAt(position, {
145454
- type: "variableChip",
145455
- attrs: {
145456
- variableType: variable.type,
145457
- path: variable.path,
145458
- displayName: variable.name
145459
- }
145460
- }).run();
145461
- setEditingVariableChip(null);
145462
- setVariableMenuOpen(false);
145463
- setVariableMenuQuery("");
145464
- return;
145465
- }
145466
146661
  const deleteFrom = triggerPos ?? variableTriggerPosRef.current;
145467
146662
  if (deleteFrom !== null) {
145468
146663
  const { from: from2 } = editor2.state.selection;
@@ -145475,6 +146670,10 @@ const MDEditor = forwardRef(
145475
146670
  displayName: variable.name
145476
146671
  }
145477
146672
  }).insertContent(" ").run();
146673
+ const posAfter = editor2.state.selection.from;
146674
+ if (posAfter + 2 <= editor2.state.doc.content.size && editor2.state.doc.textBetween(posAfter, posAfter + 2) === "}}") {
146675
+ editor2.chain().focus().deleteRange({ from: posAfter, to: posAfter + 2 }).run();
146676
+ }
145478
146677
  } else {
145479
146678
  editor2.chain().focus().insertContent({
145480
146679
  type: "variableChip",
@@ -145489,7 +146688,19 @@ const MDEditor = forwardRef(
145489
146688
  setVariableMenuQuery("");
145490
146689
  variableTriggerPosRef.current = null;
145491
146690
  },
145492
- [editingVariableChip]
146691
+ []
146692
+ );
146693
+ const handleVariableQueryChange = useCallback(
146694
+ (newQuery) => {
146695
+ setVariableMenuQuery(newQuery);
146696
+ if (!editorRef.current || variableTriggerPosRef.current === null) return;
146697
+ const editor2 = editorRef.current;
146698
+ const triggerPos = variableTriggerPosRef.current;
146699
+ const insertFrom = triggerPos + 2;
146700
+ const { from: from2 } = editor2.state.selection;
146701
+ editor2.chain().focus().deleteRange({ from: insertFrom, to: from2 }).insertContentAt(insertFrom, newQuery).run();
146702
+ },
146703
+ []
145493
146704
  );
145494
146705
  const insertMention = useCallback(
145495
146706
  (mention) => {
@@ -145524,14 +146735,23 @@ const MDEditor = forwardRef(
145524
146735
  const json = editorRef.current.getJSON();
145525
146736
  const markdown = editorJsonToMarkdown(json);
145526
146737
  setRawMarkdown(markdown);
146738
+ lastEmittedMarkdownRef.current = markdown;
146739
+ skipRawSyncRef.current = true;
145527
146740
  }
145528
146741
  if (currentMode === "preview" && newMode === "editor") {
145529
146742
  const parsedContent = markdownToEditorJson(rawMarkdown);
146743
+ isInternalUpdateRef.current = true;
145530
146744
  editorRef.current.commands.setContent(parsedContent);
145531
146745
  lastEmittedMarkdownRef.current = rawMarkdown;
146746
+ skipEditorSyncRef.current = true;
146747
+ onMarkdownChange == null ? void 0 : onMarkdownChange(rawMarkdown);
146748
+ if (onChange) {
146749
+ const doc2 = editorJsonToDocument(parsedContent);
146750
+ onChange(doc2, rawMarkdown);
146751
+ }
145532
146752
  }
145533
146753
  setEditorMode(newMode);
145534
- }, [editorMode, rawMarkdown]);
146754
+ }, [editorMode, rawMarkdown, onChange, onMarkdownChange]);
145535
146755
  const toggleRawMode = useCallback(() => {
145536
146756
  handleModeChange(isRawMode ? "editor" : "preview");
145537
146757
  }, [handleModeChange, isRawMode]);
@@ -145546,13 +146766,17 @@ const MDEditor = forwardRef(
145546
146766
  dropcursor: false
145547
146767
  }),
145548
146768
  Placeholder.configure({
145549
- placeholder: ({ node }) => {
146769
+ placeholder: ({ node, editor: placeholderEditor }) => {
146770
+ if (emptyStatePlaceholder && placeholderEditor.isEmpty) {
146771
+ return "";
146772
+ }
145550
146773
  if (node.type.name === "heading") {
145551
146774
  const level = node.attrs["level"];
145552
146775
  return `Heading ${level}`;
145553
146776
  }
145554
146777
  if (node.type.name === "paragraph") {
145555
- return placeholder;
146778
+ const focusPlaceholder = "Type here or '/' to insert variables, agents, tools, memory & more";
146779
+ return placeholderEditor.isEmpty ? placeholder : focusPlaceholder;
145556
146780
  }
145557
146781
  return "";
145558
146782
  },
@@ -145622,7 +146846,7 @@ const MDEditor = forwardRef(
145622
146846
  );
145623
146847
  }
145624
146848
  return exts;
145625
- }, [mergedFeatures, placeholder, defaultCategories, handleSlashCommandSelect, mergedSlashConfig.highlightMentions]);
146849
+ }, [mergedFeatures, placeholder, emptyStatePlaceholder, defaultCategories, handleSlashCommandSelect, mergedSlashConfig.highlightMentions]);
145626
146850
  const editorRef = useRef(null);
145627
146851
  const editor = useEditor({
145628
146852
  extensions,
@@ -145656,12 +146880,24 @@ const MDEditor = forwardRef(
145656
146880
  editorRef.current = editor;
145657
146881
  }, [editor]);
145658
146882
  const editorContent = editor ? editorJsonToMarkdown(editor.getJSON()) : "";
146883
+ const handleAIContentApplied = useCallback((markdown) => {
146884
+ lastEmittedMarkdownRef.current = markdown;
146885
+ if (onMarkdownChange) {
146886
+ onMarkdownChange(markdown);
146887
+ }
146888
+ if (onChange) {
146889
+ const json = markdownToEditorJson(markdown);
146890
+ const doc2 = editorJsonToDocument(json);
146891
+ onChange(doc2, markdown);
146892
+ }
146893
+ }, [onMarkdownChange, onChange]);
145659
146894
  const { state: aiSessionState, actions: aiSessionActions, isOpen: aiPanelOpen } = useAIRefinementSession({
145660
146895
  editor,
145661
146896
  onRefine: onAIRefine,
145662
146897
  editorContent,
145663
146898
  promptType: props.promptType,
145664
- agentContext: props.agentContext
146899
+ agentContext: props.agentContext,
146900
+ onContentApplied: handleAIContentApplied
145665
146901
  });
145666
146902
  const openAIRefine = useCallback(
145667
146903
  (_type = "selection") => {
@@ -145688,6 +146924,22 @@ const MDEditor = forwardRef(
145688
146924
  // autoGenerate
145689
146925
  );
145690
146926
  }, [aiSessionActions]);
146927
+ const handleDesignWithAI = useCallback(() => {
146928
+ aiSessionActions.openPanel(
146929
+ "generate",
146930
+ "",
146931
+ // Empty text since we're generating from scratch
146932
+ void 0,
146933
+ // No selection range
146934
+ void 0,
146935
+ // No custom prompt - AI will use context
146936
+ true
146937
+ // autoGenerate - start generation immediately
146938
+ );
146939
+ if (onDesignWithAI) {
146940
+ onDesignWithAI();
146941
+ }
146942
+ }, [aiSessionActions, onDesignWithAI]);
145691
146943
  const handleCloseAIPanel = useCallback(() => {
145692
146944
  if (editorRef.current) {
145693
146945
  editorRef.current.setEditable(!readOnly);
@@ -145722,11 +146974,27 @@ const MDEditor = forwardRef(
145722
146974
  from2
145723
146975
  );
145724
146976
  if (textAfterTrigger.includes("}}")) {
146977
+ const pathRaw = textAfterTrigger.split("}}")[0].trim();
146978
+ if (pathRaw) {
146979
+ const varType = inferVariableType(pathRaw);
146980
+ const cleanPath = removeTypePrefix(pathRaw);
146981
+ const displayName = cleanPath.split(".").pop() || cleanPath;
146982
+ editor.chain().focus().deleteRange({ from: triggerPos, to: from2 }).insertContent({
146983
+ type: "variableChip",
146984
+ attrs: {
146985
+ variableType: varType,
146986
+ path: cleanPath,
146987
+ displayName
146988
+ }
146989
+ }).insertContent(" ").run();
146990
+ }
145725
146991
  setVariableMenuOpen(false);
145726
146992
  variableTriggerPosRef.current = null;
145727
146993
  return;
145728
146994
  }
145729
146995
  setVariableMenuQuery(textAfterTrigger);
146996
+ const coords = editor.view.coordsAtPos(from2);
146997
+ setVariableMenuPosition({ top: coords.bottom + 8, left: coords.left });
145730
146998
  };
145731
146999
  const editorElement = editor.view.dom;
145732
147000
  editorElement.addEventListener("keydown", handleKeyDown2);
@@ -145736,12 +147004,36 @@ const MDEditor = forwardRef(
145736
147004
  editorElement.removeEventListener("input", handleInput);
145737
147005
  };
145738
147006
  }, [editor, mergedFeatures.variableChips, variableMenuOpen]);
147007
+ useEffect(() => {
147008
+ variableMenuOpenRef.current = variableMenuOpen;
147009
+ }, [variableMenuOpen]);
147010
+ useEffect(() => {
147011
+ if (!editor || !mergedFeatures.variableChips) return;
147012
+ const detectVariableContext = () => {
147013
+ if (variableMenuOpenRef.current) return;
147014
+ if (!hasVariableSuggestionsRef.current) return;
147015
+ const { from: from2 } = editor.state.selection;
147016
+ const context = getVariableContextAtPosition(editor, from2);
147017
+ if (context) {
147018
+ variableTriggerPosRef.current = context.triggerFrom;
147019
+ setVariableMenuQuery(context.query);
147020
+ const coords = editor.view.coordsAtPos(from2);
147021
+ setVariableMenuPosition({ top: coords.bottom + 8, left: coords.left });
147022
+ setVariableMenuOpen(true);
147023
+ }
147024
+ };
147025
+ editor.on("focus", detectVariableContext);
147026
+ editor.on("selectionUpdate", detectVariableContext);
147027
+ return () => {
147028
+ editor.off("focus", detectVariableContext);
147029
+ editor.off("selectionUpdate", detectVariableContext);
147030
+ };
147031
+ }, [editor, mergedFeatures.variableChips]);
145739
147032
  useEffect(() => {
145740
147033
  if (!variableMenuOpen) return;
145741
147034
  const handleKeyDown2 = (event) => {
145742
147035
  if (event.key === "Escape") {
145743
147036
  setVariableMenuOpen(false);
145744
- setEditingVariableChip(null);
145745
147037
  variableTriggerPosRef.current = null;
145746
147038
  editor == null ? void 0 : editor.chain().focus().run();
145747
147039
  }
@@ -145754,19 +147046,11 @@ const MDEditor = forwardRef(
145754
147046
  const handleVariableChipEdit = (event) => {
145755
147047
  const customEvent = event;
145756
147048
  const { variableType, path, position, nodeSize: nodeSize2 } = customEvent.detail;
145757
- const coords = editor.view.coordsAtPos(position);
145758
- setEditingVariableChip({
145759
- position,
145760
- nodeSize: nodeSize2,
145761
- variableType,
145762
- path
145763
- });
145764
- setVariableMenuPosition({
145765
- top: coords.bottom + 8,
145766
- left: coords.left
145767
- });
145768
- setVariableMenuQuery("");
145769
- setVariableMenuOpen(true);
147049
+ const innerPath = variableType === "system" || variableType === "custom" ? path : `${variableType}.${path}`;
147050
+ const fullText = `{{${innerPath}}}`;
147051
+ editor.chain().focus().deleteRange({ from: position, to: position + nodeSize2 }).insertContentAt(position, fullText).run();
147052
+ const cursorPos = position + 2 + innerPath.length;
147053
+ editor.chain().focus().setTextSelection(cursorPos).run();
145770
147054
  };
145771
147055
  const editorElement = editor.view.dom;
145772
147056
  editorElement.addEventListener("variable-chip-edit", handleVariableChipEdit);
@@ -145775,6 +147059,10 @@ const MDEditor = forwardRef(
145775
147059
  };
145776
147060
  }, [editor]);
145777
147061
  useEffect(() => {
147062
+ if (skipEditorSyncRef.current) {
147063
+ skipEditorSyncRef.current = false;
147064
+ return;
147065
+ }
145778
147066
  if (!editor || isInternalUpdateRef.current) {
145779
147067
  isInternalUpdateRef.current = false;
145780
147068
  return;
@@ -145806,6 +147094,10 @@ const MDEditor = forwardRef(
145806
147094
  return () => clearTimeout(timer);
145807
147095
  }, [rawMarkdown, isRawMode, onMarkdownChange, onChange]);
145808
147096
  useEffect(() => {
147097
+ if (skipRawSyncRef.current) {
147098
+ skipRawSyncRef.current = false;
147099
+ return;
147100
+ }
145809
147101
  if (isRawMode && markdownValue !== void 0 && markdownValue !== lastEmittedMarkdownRef.current) {
145810
147102
  setRawMarkdown(markdownValue);
145811
147103
  }
@@ -145946,6 +147238,13 @@ const MDEditor = forwardRef(
145946
147238
  editor,
145947
147239
  className: "k-md-editor__content w-full h-full"
145948
147240
  }
147241
+ ),
147242
+ (editor == null ? void 0 : editor.isEmpty) && emptyStatePlaceholder && /* @__PURE__ */ jsxRuntimeExports.jsx(
147243
+ EmptyStatePlaceholder,
147244
+ {
147245
+ placeholder: emptyStatePlaceholder,
147246
+ example: emptyStateExample
147247
+ }
145949
147248
  )
145950
147249
  ] })
145951
147250
  ) }),
@@ -145954,20 +147253,18 @@ const MDEditor = forwardRef(
145954
147253
  {
145955
147254
  position: variableMenuPosition,
145956
147255
  query: variableMenuQuery,
145957
- onQueryChange: setVariableMenuQuery,
147256
+ onQueryChange: handleVariableQueryChange,
145958
147257
  onSelect: (variable) => insertVariable(variable),
145959
147258
  onClose: () => {
145960
147259
  setVariableMenuOpen(false);
145961
147260
  setVariableMenuQuery("");
145962
- setEditingVariableChip(null);
145963
147261
  variableTriggerPosRef.current = null;
145964
147262
  },
145965
147263
  envVariables: mergedEnvVariables,
145966
147264
  memoryVariables: mergedMemoryVariables,
145967
147265
  systemVariables: mergedSystemVariables,
145968
147266
  contentVariables: mergedContentVariables,
145969
- editorControlled: !editingVariableChip,
145970
- isEditMode: !!editingVariableChip
147267
+ editorControlled: true
145971
147268
  }
145972
147269
  )
145973
147270
  ] }),
@@ -145981,7 +147278,9 @@ const MDEditor = forwardRef(
145981
147278
  onAIAction: isAIEnabled ? handleAIToolbarAction : void 0,
145982
147279
  theme: theme === "dark" || theme.includes("dark") ? "dark" : "light",
145983
147280
  disabled: readOnly,
145984
- containerRef: editorContainerRef
147281
+ containerRef: editorContainerRef,
147282
+ showDesignWithAI: showDesignWithAI && (editor == null ? void 0 : editor.isEmpty),
147283
+ onDesignWithAI: isAIEnabled ? handleDesignWithAI : onDesignWithAI
145985
147284
  }
145986
147285
  )
145987
147286
  ] }),
@@ -149524,6 +150823,7 @@ export {
149524
150823
  AIRefineDropdown,
149525
150824
  AIRefineExtension,
149526
150825
  AIRefinePanel,
150826
+ AgentDefinitionExample,
149527
150827
  AgentListView,
149528
150828
  AnalyticsChart,
149529
150829
  AnalyticsTable,
@@ -149549,6 +150849,7 @@ export {
149549
150849
  DetailPage,
149550
150850
  DetailPageService,
149551
150851
  EmptyState,
150852
+ EmptyStatePlaceholder,
149552
150853
  EndpointsConfigService,
149553
150854
  EnvironmentContext,
149554
150855
  EnvironmentProvider,