@optilogic/chat 1.0.0-beta.10 → 1.0.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -255,7 +255,7 @@ var ThinkingSection = React11__namespace.forwardRef(
255
255
  ref,
256
256
  className: core.cn("px-3 pb-3 border-t border-border", className),
257
257
  ...props,
258
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto", children: isStructured ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0", children: content.map((step) => /* @__PURE__ */ jsxRuntime.jsx(
258
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto scrollbar-thin", children: isStructured ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0", children: content.map((step) => /* @__PURE__ */ jsxRuntime.jsx(
259
259
  ThinkingStepItem,
260
260
  {
261
261
  step,
@@ -431,7 +431,7 @@ var HITLQuestionPanel = React11__namespace.forwardRef(({ question, onSubmit, onS
431
431
  selectedOptions,
432
432
  freeformText
433
433
  );
434
- onSubmit(combined);
434
+ onSubmit(combined, { selectedOptions, freeformText });
435
435
  }, [canSubmit, question.questions, selectedOptions, freeformText, onSubmit]);
436
436
  const handleKeyDown = React11.useCallback(
437
437
  (e) => {
@@ -699,12 +699,152 @@ var initialAgentResponseState = {
699
699
  knowledge: [],
700
700
  memory: [],
701
701
  statusUpdates: [],
702
+ potentialResponses: [],
703
+ customTimelineEntries: [],
702
704
  response: "",
703
705
  thinkingStartTime: null,
704
706
  responseCompleteTime: null,
705
707
  firstMessageTime: null
706
708
  };
707
709
 
710
+ // src/components/agent-timeline/utils.ts
711
+ function buildTimelineEntries(state) {
712
+ const entries = [];
713
+ if (state.thinkingSteps) {
714
+ let idx = 0;
715
+ for (const step of state.thinkingSteps) {
716
+ entries.push({
717
+ id: `tl-think-${idx++}`,
718
+ type: "thinking",
719
+ agentName: step.agentName ?? null,
720
+ parentAgent: step.parentAgent ?? null,
721
+ depth: step.depth ?? 0,
722
+ content: step.content,
723
+ title: step.label,
724
+ timestamp: step.timestamp ?? 0
725
+ });
726
+ }
727
+ } else if (state.thinking) {
728
+ entries.push({
729
+ id: "tl-think-0",
730
+ type: "thinking",
731
+ agentName: null,
732
+ parentAgent: null,
733
+ depth: 0,
734
+ content: state.thinking,
735
+ title: null,
736
+ timestamp: state.thinkingStartTime ?? 0
737
+ });
738
+ }
739
+ let toolIdx = 0;
740
+ for (const tool of state.toolCalls) {
741
+ entries.push({
742
+ id: `tl-tool-${toolIdx++}`,
743
+ type: "tool_call",
744
+ agentName: tool.agentName ?? null,
745
+ parentAgent: tool.parentAgent ?? null,
746
+ depth: tool.depth ?? 0,
747
+ content: tool.name,
748
+ title: null,
749
+ timestamp: tool.timestamp
750
+ });
751
+ }
752
+ let knowIdx = 0;
753
+ for (const item of state.knowledge) {
754
+ entries.push({
755
+ id: `tl-know-${knowIdx++}`,
756
+ type: "knowledge",
757
+ agentName: item.agentName ?? null,
758
+ parentAgent: item.parentAgent ?? null,
759
+ depth: item.depth ?? 0,
760
+ content: item.content,
761
+ title: item.source,
762
+ timestamp: item.timestamp
763
+ });
764
+ }
765
+ let memIdx = 0;
766
+ for (const item of state.memory) {
767
+ entries.push({
768
+ id: `tl-mem-${memIdx++}`,
769
+ type: "memory",
770
+ agentName: item.agentName ?? null,
771
+ parentAgent: item.parentAgent ?? null,
772
+ depth: item.depth ?? 0,
773
+ content: item.content,
774
+ title: item.type,
775
+ timestamp: item.timestamp
776
+ });
777
+ }
778
+ let statIdx = 0;
779
+ for (const item of state.statusUpdates) {
780
+ entries.push({
781
+ id: `tl-stat-${statIdx++}`,
782
+ type: "status_update",
783
+ agentName: item.agentName ?? item.agent ?? null,
784
+ parentAgent: item.parentAgent ?? null,
785
+ depth: item.depth ?? 0,
786
+ content: item.message,
787
+ title: null,
788
+ timestamp: item.timestamp
789
+ });
790
+ }
791
+ if (state.potentialResponses) {
792
+ let respIdx = 0;
793
+ for (const resp of state.potentialResponses) {
794
+ entries.push({
795
+ id: `tl-resp-${respIdx++}`,
796
+ type: "ai_response",
797
+ agentName: resp.agentName ?? null,
798
+ parentAgent: resp.parentAgent ?? null,
799
+ depth: resp.depth ?? 0,
800
+ content: resp.content,
801
+ title: null,
802
+ timestamp: resp.timestamp
803
+ });
804
+ }
805
+ }
806
+ if (state.customTimelineEntries) {
807
+ entries.push(...state.customTimelineEntries);
808
+ }
809
+ entries.sort((a, b) => a.timestamp - b.timestamp);
810
+ return entries;
811
+ }
812
+ function groupIntoAgentRuns(entries) {
813
+ const runs = [];
814
+ let currentRun = null;
815
+ for (const entry of entries) {
816
+ const name = entry.agentName || "Agent";
817
+ if (!currentRun || currentRun.agentName !== name) {
818
+ currentRun = {
819
+ agentName: name,
820
+ parentAgent: entry.parentAgent,
821
+ depth: entry.depth,
822
+ entries: []
823
+ };
824
+ runs.push(currentRun);
825
+ }
826
+ currentRun.entries.push({ entry, count: 1 });
827
+ }
828
+ for (const run of runs) {
829
+ run.entries = deduplicateEntries(run.entries);
830
+ }
831
+ return runs;
832
+ }
833
+ function deduplicateEntries(entries) {
834
+ if (entries.length === 0) return [];
835
+ const result = [entries[0]];
836
+ for (let i = 1; i < entries.length; i++) {
837
+ const prev = result[result.length - 1];
838
+ const curr = entries[i];
839
+ if (prev.entry.type === curr.entry.type && prev.entry.content === curr.entry.content) {
840
+ prev.count += curr.count;
841
+ } else {
842
+ result.push({ ...curr });
843
+ }
844
+ }
845
+ return result;
846
+ }
847
+
708
848
  // src/components/agent-response/hooks/useAgentResponseAccumulator.ts
709
849
  function useAgentResponseAccumulator(options) {
710
850
  const [state, setState] = React11.useState(initialAgentResponseState);
@@ -738,28 +878,44 @@ function useAgentResponseAccumulator(options) {
738
878
  id: payload.thinkingStep.id || `step-${Date.now()}`,
739
879
  label: payload.thinkingStep.label,
740
880
  content: payload.thinkingStep.content,
741
- depth: payload.thinkingStep.depth ?? 0,
742
- isCollapsed: payload.thinkingStep.isCollapsed
881
+ depth: payload.thinkingStep.depth ?? payload.depth ?? 0,
882
+ isCollapsed: payload.thinkingStep.isCollapsed,
883
+ timestamp: Date.now(),
884
+ agentName: payload.agentName,
885
+ parentAgent: payload.parentAgent
743
886
  };
744
887
  const thinkingStartTime2 = prev.thinkingStartTime ?? Date.now();
745
- return {
888
+ const next2 = {
746
889
  ...prev,
747
890
  status: newStatus,
748
891
  thinkingSteps: [...prev.thinkingSteps || [], newStep],
749
892
  thinkingStartTime: thinkingStartTime2,
750
893
  firstMessageTime
751
894
  };
895
+ return { ...next2, timelineEntries: buildTimelineEntries(next2) };
752
896
  }
753
897
  const newThinking = payload.message || payload.content || "";
754
898
  const separator = prev.thinking && newThinking ? "\n\n" : "";
755
899
  const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
756
- return {
900
+ const prevSteps = prev.thinkingSteps || [];
901
+ const plainStep = {
902
+ id: `step-${prevSteps.length}`,
903
+ label: newThinking,
904
+ content: newThinking,
905
+ depth: payload.depth ?? 0,
906
+ timestamp: Date.now(),
907
+ agentName: payload.agentName,
908
+ parentAgent: payload.parentAgent
909
+ };
910
+ const next = {
757
911
  ...prev,
758
912
  status: newStatus,
759
913
  thinking: prev.thinking + separator + newThinking,
914
+ thinkingSteps: [...prevSteps, plainStep],
760
915
  thinkingStartTime,
761
916
  firstMessageTime
762
917
  };
918
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
763
919
  }
764
920
  case "tool_call": {
765
921
  const toolName = payload.message || payload.tool?.name;
@@ -768,14 +924,18 @@ function useAgentResponseAccumulator(options) {
768
924
  id: payload.tool?.id || `tool-${Date.now()}`,
769
925
  name: toolName,
770
926
  arguments: payload.tool?.arguments,
771
- timestamp: Date.now()
927
+ timestamp: Date.now(),
928
+ agentName: payload.agentName,
929
+ parentAgent: payload.parentAgent,
930
+ depth: payload.depth
772
931
  };
773
- return {
932
+ const next = {
774
933
  ...prev,
775
934
  status: newStatus,
776
935
  toolCalls: [...prev.toolCalls, newToolCall],
777
936
  firstMessageTime
778
937
  };
938
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
779
939
  }
780
940
  return { ...prev, status: newStatus, firstMessageTime };
781
941
  }
@@ -786,14 +946,18 @@ function useAgentResponseAccumulator(options) {
786
946
  id: payload.knowledge?.id || `knowledge-${Date.now()}`,
787
947
  source: payload.knowledge?.source || "unknown",
788
948
  content: knowledgeContent,
789
- timestamp: Date.now()
949
+ timestamp: Date.now(),
950
+ agentName: payload.agentName,
951
+ parentAgent: payload.parentAgent,
952
+ depth: payload.depth
790
953
  };
791
- return {
954
+ const next = {
792
955
  ...prev,
793
956
  status: newStatus,
794
957
  knowledge: [...prev.knowledge, newKnowledge],
795
958
  firstMessageTime
796
959
  };
960
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
797
961
  }
798
962
  return { ...prev, status: newStatus, firstMessageTime };
799
963
  }
@@ -804,14 +968,18 @@ function useAgentResponseAccumulator(options) {
804
968
  id: payload.memory?.id || `memory-${Date.now()}`,
805
969
  type: payload.memory?.type || "unknown",
806
970
  content: memoryContent,
807
- timestamp: Date.now()
971
+ timestamp: Date.now(),
972
+ agentName: payload.agentName,
973
+ parentAgent: payload.parentAgent,
974
+ depth: payload.depth
808
975
  };
809
- return {
976
+ const next = {
810
977
  ...prev,
811
978
  status: newStatus,
812
979
  memory: [...prev.memory, newMemory],
813
980
  firstMessageTime
814
981
  };
982
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
815
983
  }
816
984
  return { ...prev, status: newStatus, firstMessageTime };
817
985
  }
@@ -830,14 +998,39 @@ function useAgentResponseAccumulator(options) {
830
998
  id: payload.statusUpdate?.id || `status-${Date.now()}`,
831
999
  message: statusMessage,
832
1000
  agent: payload.statusUpdate?.agent,
833
- timestamp: Date.now()
1001
+ timestamp: Date.now(),
1002
+ agentName: payload.agentName,
1003
+ parentAgent: payload.parentAgent,
1004
+ depth: payload.depth
834
1005
  };
835
- return {
1006
+ const next = {
836
1007
  ...prev,
837
1008
  status: newStatus,
838
1009
  statusUpdates: [...prev.statusUpdates, newStatusItem],
839
1010
  firstMessageTime
840
1011
  };
1012
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
1013
+ }
1014
+ return { ...prev, status: newStatus, firstMessageTime };
1015
+ }
1016
+ case "potential_response": {
1017
+ const respContent = payload.message || payload.content || "";
1018
+ if (respContent) {
1019
+ const newResp = {
1020
+ id: `resp-${Date.now()}`,
1021
+ content: respContent,
1022
+ timestamp: Date.now(),
1023
+ agentName: payload.agentName,
1024
+ parentAgent: payload.parentAgent,
1025
+ depth: payload.depth
1026
+ };
1027
+ const next = {
1028
+ ...prev,
1029
+ status: newStatus,
1030
+ potentialResponses: [...prev.potentialResponses || [], newResp],
1031
+ firstMessageTime
1032
+ };
1033
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
841
1034
  }
842
1035
  return { ...prev, status: newStatus, firstMessageTime };
843
1036
  }
@@ -853,6 +1046,287 @@ function useAgentResponseAccumulator(options) {
853
1046
  }, []);
854
1047
  return { state, handleMessage, reset };
855
1048
  }
1049
+ var ICON_MAP = {
1050
+ thinking: lucideReact.Brain,
1051
+ tool_call: lucideReact.Wrench,
1052
+ knowledge: lucideReact.BookOpen,
1053
+ memory: lucideReact.HardDrive,
1054
+ status_update: lucideReact.Activity,
1055
+ ai_response: lucideReact.MessageSquare,
1056
+ error: lucideReact.AlertCircle
1057
+ };
1058
+ function TimelineItem({
1059
+ displayEntry,
1060
+ renderMarkdown,
1061
+ isExpanded,
1062
+ onToggleExpanded
1063
+ }) {
1064
+ const { entry, count } = displayEntry;
1065
+ const Icon = ICON_MAP[entry.type] ?? lucideReact.Activity;
1066
+ const isLong = entry.content.length > 200 || entry.content.split("\n").length > 3;
1067
+ const canExpand = isLong || entry.type === "ai_response";
1068
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-1 flex items-start gap-2 group", children: [
1069
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0 mt-0.5" }),
1070
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: isExpanded && entry.type === "ai_response" && renderMarkdown ? (
1071
+ // Expanded AI response: rendered markdown
1072
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1073
+ renderMarkdown(entry.content),
1074
+ /* @__PURE__ */ jsxRuntime.jsx(
1075
+ "button",
1076
+ {
1077
+ onClick: onToggleExpanded,
1078
+ className: "text-[10px] text-muted-foreground/70 hover:text-muted-foreground mt-1",
1079
+ children: "Show less"
1080
+ }
1081
+ )
1082
+ ] })
1083
+ ) : isExpanded ? (
1084
+ // Expanded non-AI: plain text
1085
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1086
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: entry.content }),
1087
+ /* @__PURE__ */ jsxRuntime.jsx(
1088
+ "button",
1089
+ {
1090
+ onClick: onToggleExpanded,
1091
+ className: "text-[10px] text-muted-foreground/70 hover:text-muted-foreground mt-1",
1092
+ children: "Show less"
1093
+ }
1094
+ )
1095
+ ] })
1096
+ ) : (
1097
+ // Collapsed: truncated with optional expand
1098
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1.5 min-w-0", children: [
1099
+ /* @__PURE__ */ jsxRuntime.jsx(
1100
+ "div",
1101
+ {
1102
+ className: `text-xs text-muted-foreground min-w-0 ${canExpand ? "line-clamp-2 cursor-pointer hover:text-foreground/80" : ""}`,
1103
+ onClick: canExpand ? onToggleExpanded : void 0,
1104
+ children: entry.content
1105
+ }
1106
+ ),
1107
+ count > 1 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground/60 whitespace-nowrap flex-shrink-0", children: [
1108
+ "(x",
1109
+ count,
1110
+ ")"
1111
+ ] })
1112
+ ] })
1113
+ ) })
1114
+ ] });
1115
+ }
1116
+ function TimelineAgentBlock({
1117
+ block,
1118
+ renderMarkdown,
1119
+ isSingleAgent,
1120
+ isCollapsed,
1121
+ onToggleCollapsed,
1122
+ expandedItems,
1123
+ onToggleItemExpanded
1124
+ }) {
1125
+ const indentPx = block.depth * 16;
1126
+ if (isSingleAgent && block.depth === 0) {
1127
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { paddingLeft: `${indentPx}px` }, children: block.entries.map((displayEntry, i) => /* @__PURE__ */ jsxRuntime.jsx(
1128
+ TimelineItem,
1129
+ {
1130
+ displayEntry,
1131
+ renderMarkdown,
1132
+ isExpanded: expandedItems.has(displayEntry.entry.id),
1133
+ onToggleExpanded: () => onToggleItemExpanded(displayEntry.entry.id)
1134
+ },
1135
+ displayEntry.entry.id + "-" + i
1136
+ )) });
1137
+ }
1138
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { paddingLeft: `${indentPx}px` }, children: [
1139
+ /* @__PURE__ */ jsxRuntime.jsxs(
1140
+ "button",
1141
+ {
1142
+ onClick: onToggleCollapsed,
1143
+ className: "w-full flex items-center gap-1.5 py-1 hover:bg-muted/50 -ml-1 pl-1 pr-2 rounded transition-colors text-left",
1144
+ children: [
1145
+ isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }),
1146
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground/80", children: block.agentName }),
1147
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground/60", children: [
1148
+ "(",
1149
+ block.entries.reduce((sum, e) => sum + e.count, 0),
1150
+ ")"
1151
+ ] })
1152
+ ]
1153
+ }
1154
+ ),
1155
+ !isCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-4", children: block.entries.map((displayEntry, i) => /* @__PURE__ */ jsxRuntime.jsx(
1156
+ TimelineItem,
1157
+ {
1158
+ displayEntry,
1159
+ renderMarkdown,
1160
+ isExpanded: expandedItems.has(displayEntry.entry.id),
1161
+ onToggleExpanded: () => onToggleItemExpanded(displayEntry.entry.id)
1162
+ },
1163
+ displayEntry.entry.id + "-" + i
1164
+ )) })
1165
+ ] });
1166
+ }
1167
+ function createTimelineUIState() {
1168
+ return {
1169
+ expandedItems: /* @__PURE__ */ new Set(),
1170
+ collapsedRuns: /* @__PURE__ */ new Set(),
1171
+ activeFilters: /* @__PURE__ */ new Set()
1172
+ };
1173
+ }
1174
+ var TYPE_CONFIG = [
1175
+ { type: "status_update", icon: lucideReact.Activity, label: "Status" },
1176
+ { type: "thinking", icon: lucideReact.Brain, label: "Thinking" },
1177
+ { type: "tool_call", icon: lucideReact.Wrench, label: "Tools" },
1178
+ { type: "knowledge", icon: lucideReact.BookOpen, label: "Knowledge" },
1179
+ { type: "memory", icon: lucideReact.HardDrive, label: "Memory" },
1180
+ { type: "ai_response", icon: lucideReact.MessageSquare, label: "AI" },
1181
+ { type: "error", icon: lucideReact.AlertCircle, label: "Errors" }
1182
+ ];
1183
+ function AgentTimeline({ entries, renderMarkdown, uiState, maxHeight = "300px" }) {
1184
+ const containerRef = React11.useRef(null);
1185
+ const [renderTick, setRenderTick] = React11.useState(0);
1186
+ const forceRender = React11.useCallback(() => setRenderTick((t) => t + 1), []);
1187
+ const [internalExpandedItems] = React11.useState(() => /* @__PURE__ */ new Set());
1188
+ const [internalCollapsedRuns] = React11.useState(() => /* @__PURE__ */ new Set());
1189
+ const [internalActiveFilters] = React11.useState(() => /* @__PURE__ */ new Set());
1190
+ const expandedItems = uiState?.expandedItems ?? internalExpandedItems;
1191
+ const collapsedRuns = uiState?.collapsedRuns ?? internalCollapsedRuns;
1192
+ const activeFilters = uiState?.activeFilters ?? internalActiveFilters;
1193
+ const availableTypes = React11.useMemo(() => {
1194
+ const types = /* @__PURE__ */ new Set();
1195
+ for (const entry of entries) {
1196
+ types.add(entry.type);
1197
+ }
1198
+ return types;
1199
+ }, [entries]);
1200
+ const filteredEntries = React11.useMemo(
1201
+ () => activeFilters.size === 0 ? entries : entries.filter((e) => activeFilters.has(e.type)),
1202
+ [entries, activeFilters, renderTick]
1203
+ );
1204
+ const agentRuns = React11.useMemo(() => groupIntoAgentRuns(filteredEntries), [filteredEntries, renderTick]);
1205
+ const toggleFilter = React11.useCallback((type) => {
1206
+ if (activeFilters.has(type)) {
1207
+ activeFilters.delete(type);
1208
+ } else {
1209
+ activeFilters.add(type);
1210
+ }
1211
+ forceRender();
1212
+ }, [activeFilters, forceRender]);
1213
+ const clearFilters = React11.useCallback(() => {
1214
+ activeFilters.clear();
1215
+ forceRender();
1216
+ }, [activeFilters, forceRender]);
1217
+ const toggleItemExpanded = React11.useCallback((entryId) => {
1218
+ if (expandedItems.has(entryId)) {
1219
+ expandedItems.delete(entryId);
1220
+ } else {
1221
+ expandedItems.add(entryId);
1222
+ }
1223
+ forceRender();
1224
+ }, [expandedItems, forceRender]);
1225
+ const collapseAll = React11.useCallback(() => {
1226
+ collapsedRuns.clear();
1227
+ agentRuns.forEach((run, i) => {
1228
+ collapsedRuns.add(`${run.agentName}-${i}`);
1229
+ });
1230
+ expandedItems.clear();
1231
+ forceRender();
1232
+ }, [agentRuns, collapsedRuns, expandedItems, forceRender]);
1233
+ const expandAll = React11.useCallback(() => {
1234
+ collapsedRuns.clear();
1235
+ agentRuns.forEach((run, i) => {
1236
+ collapsedRuns.add(`${run.agentName}-${i}:expanded`);
1237
+ });
1238
+ forceRender();
1239
+ }, [agentRuns, collapsedRuns, forceRender]);
1240
+ if (entries.length === 0) return null;
1241
+ const isSingle = agentRuns.length === 1;
1242
+ const hasActiveFilter = activeFilters.size > 0;
1243
+ const scrollStyle = maxHeight !== "none" ? { maxHeight } : void 0;
1244
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1245
+ "div",
1246
+ {
1247
+ ref: containerRef,
1248
+ className: `-mt-1 ${maxHeight !== "none" ? "overflow-y-auto scrollbar-thin" : ""}`,
1249
+ style: scrollStyle,
1250
+ children: [
1251
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-10 bg-background flex items-center gap-1 py-1.5 mb-1 border-b border-border/50 flex-wrap", children: [
1252
+ TYPE_CONFIG.filter((tc) => availableTypes.has(tc.type)).map((tc) => {
1253
+ const isActive = activeFilters.has(tc.type);
1254
+ const count = entries.filter((e) => e.type === tc.type).length;
1255
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1256
+ "button",
1257
+ {
1258
+ onClick: () => toggleFilter(tc.type),
1259
+ className: `inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] transition-colors ${isActive ? "bg-accent text-accent-foreground ring-1 ring-accent-foreground/20" : "text-muted-foreground/60 hover:text-muted-foreground hover:bg-muted/50"}`,
1260
+ title: `${isActive ? "Hide" : "Show only"} ${tc.label}`,
1261
+ children: [
1262
+ /* @__PURE__ */ jsxRuntime.jsx(tc.icon, { className: "w-3 h-3" }),
1263
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: count })
1264
+ ]
1265
+ },
1266
+ tc.type
1267
+ );
1268
+ }),
1269
+ hasActiveFilter && /* @__PURE__ */ jsxRuntime.jsx(
1270
+ "button",
1271
+ {
1272
+ onClick: clearFilters,
1273
+ className: "text-[10px] text-muted-foreground/60 hover:text-muted-foreground px-1",
1274
+ children: "Clear"
1275
+ }
1276
+ ),
1277
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
1278
+ !isSingle && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1279
+ /* @__PURE__ */ jsxRuntime.jsx(
1280
+ "button",
1281
+ {
1282
+ onClick: collapseAll,
1283
+ className: "inline-flex items-center gap-0.5 text-[10px] text-muted-foreground/60 hover:text-muted-foreground px-1 py-0.5 rounded hover:bg-muted/50 transition-colors",
1284
+ title: "Collapse all",
1285
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUp, { className: "w-3 h-3" })
1286
+ }
1287
+ ),
1288
+ /* @__PURE__ */ jsxRuntime.jsx(
1289
+ "button",
1290
+ {
1291
+ onClick: expandAll,
1292
+ className: "inline-flex items-center gap-0.5 text-[10px] text-muted-foreground/60 hover:text-muted-foreground px-1 py-0.5 rounded hover:bg-muted/50 transition-colors",
1293
+ title: "Expand all",
1294
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "w-3 h-3" })
1295
+ }
1296
+ )
1297
+ ] })
1298
+ ] }),
1299
+ filteredEntries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] text-muted-foreground/50 py-2 text-center", children: "No entries match the selected filters" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: agentRuns.map((run, i) => {
1300
+ const runKey = `${run.agentName}-${i}`;
1301
+ const defaultCollapsed = run.depth > 0;
1302
+ const isCollapsed = collapsedRuns.has(runKey) ? true : collapsedRuns.has(`${runKey}:expanded`) ? false : defaultCollapsed;
1303
+ return /* @__PURE__ */ jsxRuntime.jsx(
1304
+ TimelineAgentBlock,
1305
+ {
1306
+ block: run,
1307
+ renderMarkdown,
1308
+ isSingleAgent: isSingle,
1309
+ isCollapsed,
1310
+ onToggleCollapsed: () => {
1311
+ if (isCollapsed) {
1312
+ collapsedRuns.delete(runKey);
1313
+ collapsedRuns.add(`${runKey}:expanded`);
1314
+ } else {
1315
+ collapsedRuns.delete(`${runKey}:expanded`);
1316
+ collapsedRuns.add(runKey);
1317
+ }
1318
+ forceRender();
1319
+ },
1320
+ expandedItems,
1321
+ onToggleItemExpanded: toggleItemExpanded
1322
+ },
1323
+ runKey
1324
+ );
1325
+ }) })
1326
+ ]
1327
+ }
1328
+ );
1329
+ }
856
1330
  var AgentResponse = React11__namespace.forwardRef(
857
1331
  ({
858
1332
  state,
@@ -873,6 +1347,7 @@ var AgentResponse = React11__namespace.forwardRef(
873
1347
  className,
874
1348
  ...props
875
1349
  }, ref) => {
1350
+ const timelineUIStateRef = React11.useRef(createTimelineUIState());
876
1351
  const [uncontrolledExpanded, setUncontrolledExpanded] = React11.useState(defaultThinkingExpanded);
877
1352
  const isThinkingControlled = controlledThinkingExpanded !== void 0;
878
1353
  const thinkingExpanded = isThinkingControlled ? controlledThinkingExpanded : uncontrolledExpanded;
@@ -894,7 +1369,8 @@ var AgentResponse = React11__namespace.forwardRef(
894
1369
  if (!state.firstMessageTime || !state.responseCompleteTime) return 0;
895
1370
  return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
896
1371
  }, [state.firstMessageTime, state.responseCompleteTime]);
897
- const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || false;
1372
+ const hasTimelineEntries = !!(state.timelineEntries && state.timelineEntries.length > 0);
1373
+ const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || hasTimelineEntries || false;
898
1374
  const hasHITLInteractions = hitlInteractions && hitlInteractions.length > 0;
899
1375
  const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || hasHITLInteractions || state.response;
900
1376
  const showMetadataRow = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.status === "processing";
@@ -929,7 +1405,14 @@ var AgentResponse = React11__namespace.forwardRef(
929
1405
  elapsedTime
930
1406
  }
931
1407
  ),
932
- /* @__PURE__ */ jsxRuntime.jsx(
1408
+ hasTimelineEntries ? thinkingExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-3 border-t border-border mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
1409
+ AgentTimeline,
1410
+ {
1411
+ entries: state.timelineEntries,
1412
+ renderMarkdown: renderThinkingMarkdown,
1413
+ uiState: timelineUIStateRef.current
1414
+ }
1415
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(
933
1416
  ThinkingSection,
934
1417
  {
935
1418
  content: state.thinkingSteps && state.thinkingSteps.length > 0 ? state.thinkingSteps : state.thinking,
@@ -1236,21 +1719,138 @@ var UserPromptInput = React11__namespace.forwardRef(
1236
1719
  );
1237
1720
  UserPromptInput.displayName = "UserPromptInput";
1238
1721
 
1722
+ // src/components/inline-actions/parseResponseSegments.ts
1723
+ var ACTION_BLOCK_REGEX = /```json:action\s*\n([\s\S]*?)```/g;
1724
+ function parseResponseSegments(text) {
1725
+ if (!text) return [];
1726
+ const segments = [];
1727
+ let lastIndex = 0;
1728
+ ACTION_BLOCK_REGEX.lastIndex = 0;
1729
+ let match;
1730
+ while ((match = ACTION_BLOCK_REGEX.exec(text)) !== null) {
1731
+ const before = text.slice(lastIndex, match.index);
1732
+ if (before.trim()) {
1733
+ segments.push({ kind: "markdown", content: before });
1734
+ }
1735
+ const jsonContent = match[1].trim();
1736
+ let parsed = null;
1737
+ try {
1738
+ parsed = JSON.parse(jsonContent);
1739
+ } catch {
1740
+ }
1741
+ if (parsed && typeof parsed === "object" && typeof parsed.type === "string") {
1742
+ segments.push({
1743
+ kind: "action",
1744
+ actionType: parsed.type,
1745
+ payload: parsed
1746
+ });
1747
+ } else {
1748
+ const rawBlock = match[0];
1749
+ segments.push({ kind: "markdown", content: rawBlock });
1750
+ }
1751
+ lastIndex = match.index + match[0].length;
1752
+ }
1753
+ const trailing = text.slice(lastIndex);
1754
+ if (trailing.trim()) {
1755
+ segments.push({ kind: "markdown", content: trailing });
1756
+ }
1757
+ return segments;
1758
+ }
1759
+ function ActionMarkdownRenderer({
1760
+ content,
1761
+ registry,
1762
+ renderMarkdown,
1763
+ onAction,
1764
+ isLatest
1765
+ }) {
1766
+ const segments = React11.useMemo(() => parseResponseSegments(content), [content]);
1767
+ if (segments.length === 1 && segments[0].kind === "markdown") {
1768
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderMarkdown(segments[0].content) });
1769
+ }
1770
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: segments.map((segment, index) => {
1771
+ if (segment.kind === "markdown") {
1772
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderMarkdown(segment.content) }, `md-${index}`);
1773
+ }
1774
+ const Component = registry[segment.actionType];
1775
+ if (!Component) {
1776
+ return /* @__PURE__ */ jsxRuntime.jsx(
1777
+ "pre",
1778
+ {
1779
+ className: "my-4 p-4 rounded-lg border border-border bg-muted text-sm font-mono overflow-x-auto",
1780
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: JSON.stringify(segment.payload, null, 2) })
1781
+ },
1782
+ `action-fallback-${index}`
1783
+ );
1784
+ }
1785
+ return /* @__PURE__ */ jsxRuntime.jsx(
1786
+ Component,
1787
+ {
1788
+ payload: segment.payload,
1789
+ onAction,
1790
+ isLatest
1791
+ },
1792
+ `action-${segment.actionType}-${index}`
1793
+ );
1794
+ }) });
1795
+ }
1796
+
1797
+ // src/components/inline-actions/prompts.ts
1798
+ var INLINE_ACTION_PROMPT = `
1799
+ <inline_actions>
1800
+ When your response should include interactive components (like query viewers,
1801
+ data tables, or executable actions), embed them as fenced code blocks using
1802
+ the \`json:action\` language tag:
1803
+
1804
+ \`\`\`json:action
1805
+ {
1806
+ "type": "action-type-here",
1807
+ ...action-specific fields
1808
+ }
1809
+ \`\`\`
1810
+
1811
+ Rules:
1812
+ - Each block must contain valid JSON with a "type" field.
1813
+ - The "type" must match a registered action component on the frontend.
1814
+ - Multiple action blocks per response are allowed.
1815
+ - Surround action blocks with normal markdown text for user context.
1816
+ - The action block is rendered as an interactive component in the chat UI.
1817
+ - SQL strings inside JSON must be properly escaped (newlines as \\n, quotes as \\").
1818
+
1819
+ Available action types:
1820
+
1821
+ - "optimap-query": Displays SQL queries with a button to execute them and
1822
+ update the 3D globe map.
1823
+ Required fields:
1824
+ - type: "optimap-query"
1825
+ - locations_sql: string (the validated locations SQL query)
1826
+ - routes_sql: string (the validated routes SQL query)
1827
+ - database_name: string (the target database name)
1828
+ </inline_actions>
1829
+ `;
1830
+
1239
1831
  exports.ActionBar = ActionBar;
1832
+ exports.ActionMarkdownRenderer = ActionMarkdownRenderer;
1240
1833
  exports.ActivityIndicators = ActivityIndicators;
1241
1834
  exports.AgentResponse = AgentResponse;
1835
+ exports.AgentTimeline = AgentTimeline;
1242
1836
  exports.HITLInteractionRecord = HITLInteractionRecord;
1243
1837
  exports.HITLQuestionPanel = HITLQuestionPanel;
1244
1838
  exports.HITLSection = HITLSection;
1839
+ exports.INLINE_ACTION_PROMPT = INLINE_ACTION_PROMPT;
1245
1840
  exports.MetadataRow = MetadataRow;
1246
1841
  exports.ThinkingSection = ThinkingSection;
1247
1842
  exports.TruncatedMessage = TruncatedMessage;
1248
1843
  exports.UserPrompt = UserPrompt;
1249
1844
  exports.UserPromptInput = UserPromptInput;
1250
1845
  exports.buildResponseString = buildResponseString;
1846
+ exports.buildTimelineEntries = buildTimelineEntries;
1847
+ exports.createTimelineUIState = createTimelineUIState;
1848
+ exports.deduplicateEntries = deduplicateEntries;
1251
1849
  exports.formatTime = formatTime;
1252
1850
  exports.formatTotalTime = formatTotalTime;
1851
+ exports.groupIntoAgentRuns = groupIntoAgentRuns;
1253
1852
  exports.initialAgentResponseState = initialAgentResponseState;
1853
+ exports.parseResponseSegments = parseResponseSegments;
1254
1854
  exports.useAgentResponseAccumulator = useAgentResponseAccumulator;
1255
1855
  exports.useThinkingTimer = useThinkingTimer;
1256
1856
  //# sourceMappingURL=index.cjs.map