@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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React11 from 'react';
2
2
  import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
3
3
  import { cn, Popover, PopoverTrigger, PopoverContent, Button, Textarea, IconButton, LoadingSpinner } from '@optilogic/core';
4
- import { Activity, Wrench, Book, HardDrive, Check, Copy, ThumbsUp, ThumbsDown, ChevronDown, ChevronRight, MessageCircleQuestion, Square, Loader2, Send, ChevronUp } from 'lucide-react';
4
+ import { Activity, Wrench, Book, HardDrive, Check, Copy, ThumbsUp, ThumbsDown, ChevronDown, ChevronRight, MessageCircleQuestion, Square, Loader2, Send, ChevronUp, Brain, BookOpen, MessageSquare, AlertCircle, ChevronsDownUp, ChevronsUpDown } from 'lucide-react';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
  import { SlateEditor, Text } from '@optilogic/editor';
7
7
 
@@ -234,7 +234,7 @@ var ThinkingSection = React11.forwardRef(
234
234
  ref,
235
235
  className: cn("px-3 pb-3 border-t border-border", className),
236
236
  ...props,
237
- children: /* @__PURE__ */ jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto", children: isStructured ? /* @__PURE__ */ jsx("div", { className: "space-y-0", children: content.map((step) => /* @__PURE__ */ jsx(
237
+ children: /* @__PURE__ */ jsx("div", { className: "mt-2 max-h-[200px] overflow-y-auto scrollbar-thin", children: isStructured ? /* @__PURE__ */ jsx("div", { className: "space-y-0", children: content.map((step) => /* @__PURE__ */ jsx(
238
238
  ThinkingStepItem,
239
239
  {
240
240
  step,
@@ -410,7 +410,7 @@ var HITLQuestionPanel = React11.forwardRef(({ question, onSubmit, onStop, classN
410
410
  selectedOptions,
411
411
  freeformText
412
412
  );
413
- onSubmit(combined);
413
+ onSubmit(combined, { selectedOptions, freeformText });
414
414
  }, [canSubmit, question.questions, selectedOptions, freeformText, onSubmit]);
415
415
  const handleKeyDown = useCallback(
416
416
  (e) => {
@@ -678,12 +678,152 @@ var initialAgentResponseState = {
678
678
  knowledge: [],
679
679
  memory: [],
680
680
  statusUpdates: [],
681
+ potentialResponses: [],
682
+ customTimelineEntries: [],
681
683
  response: "",
682
684
  thinkingStartTime: null,
683
685
  responseCompleteTime: null,
684
686
  firstMessageTime: null
685
687
  };
686
688
 
689
+ // src/components/agent-timeline/utils.ts
690
+ function buildTimelineEntries(state) {
691
+ const entries = [];
692
+ if (state.thinkingSteps) {
693
+ let idx = 0;
694
+ for (const step of state.thinkingSteps) {
695
+ entries.push({
696
+ id: `tl-think-${idx++}`,
697
+ type: "thinking",
698
+ agentName: step.agentName ?? null,
699
+ parentAgent: step.parentAgent ?? null,
700
+ depth: step.depth ?? 0,
701
+ content: step.content,
702
+ title: step.label,
703
+ timestamp: step.timestamp ?? 0
704
+ });
705
+ }
706
+ } else if (state.thinking) {
707
+ entries.push({
708
+ id: "tl-think-0",
709
+ type: "thinking",
710
+ agentName: null,
711
+ parentAgent: null,
712
+ depth: 0,
713
+ content: state.thinking,
714
+ title: null,
715
+ timestamp: state.thinkingStartTime ?? 0
716
+ });
717
+ }
718
+ let toolIdx = 0;
719
+ for (const tool of state.toolCalls) {
720
+ entries.push({
721
+ id: `tl-tool-${toolIdx++}`,
722
+ type: "tool_call",
723
+ agentName: tool.agentName ?? null,
724
+ parentAgent: tool.parentAgent ?? null,
725
+ depth: tool.depth ?? 0,
726
+ content: tool.name,
727
+ title: null,
728
+ timestamp: tool.timestamp
729
+ });
730
+ }
731
+ let knowIdx = 0;
732
+ for (const item of state.knowledge) {
733
+ entries.push({
734
+ id: `tl-know-${knowIdx++}`,
735
+ type: "knowledge",
736
+ agentName: item.agentName ?? null,
737
+ parentAgent: item.parentAgent ?? null,
738
+ depth: item.depth ?? 0,
739
+ content: item.content,
740
+ title: item.source,
741
+ timestamp: item.timestamp
742
+ });
743
+ }
744
+ let memIdx = 0;
745
+ for (const item of state.memory) {
746
+ entries.push({
747
+ id: `tl-mem-${memIdx++}`,
748
+ type: "memory",
749
+ agentName: item.agentName ?? null,
750
+ parentAgent: item.parentAgent ?? null,
751
+ depth: item.depth ?? 0,
752
+ content: item.content,
753
+ title: item.type,
754
+ timestamp: item.timestamp
755
+ });
756
+ }
757
+ let statIdx = 0;
758
+ for (const item of state.statusUpdates) {
759
+ entries.push({
760
+ id: `tl-stat-${statIdx++}`,
761
+ type: "status_update",
762
+ agentName: item.agentName ?? item.agent ?? null,
763
+ parentAgent: item.parentAgent ?? null,
764
+ depth: item.depth ?? 0,
765
+ content: item.message,
766
+ title: null,
767
+ timestamp: item.timestamp
768
+ });
769
+ }
770
+ if (state.potentialResponses) {
771
+ let respIdx = 0;
772
+ for (const resp of state.potentialResponses) {
773
+ entries.push({
774
+ id: `tl-resp-${respIdx++}`,
775
+ type: "ai_response",
776
+ agentName: resp.agentName ?? null,
777
+ parentAgent: resp.parentAgent ?? null,
778
+ depth: resp.depth ?? 0,
779
+ content: resp.content,
780
+ title: null,
781
+ timestamp: resp.timestamp
782
+ });
783
+ }
784
+ }
785
+ if (state.customTimelineEntries) {
786
+ entries.push(...state.customTimelineEntries);
787
+ }
788
+ entries.sort((a, b) => a.timestamp - b.timestamp);
789
+ return entries;
790
+ }
791
+ function groupIntoAgentRuns(entries) {
792
+ const runs = [];
793
+ let currentRun = null;
794
+ for (const entry of entries) {
795
+ const name = entry.agentName || "Agent";
796
+ if (!currentRun || currentRun.agentName !== name) {
797
+ currentRun = {
798
+ agentName: name,
799
+ parentAgent: entry.parentAgent,
800
+ depth: entry.depth,
801
+ entries: []
802
+ };
803
+ runs.push(currentRun);
804
+ }
805
+ currentRun.entries.push({ entry, count: 1 });
806
+ }
807
+ for (const run of runs) {
808
+ run.entries = deduplicateEntries(run.entries);
809
+ }
810
+ return runs;
811
+ }
812
+ function deduplicateEntries(entries) {
813
+ if (entries.length === 0) return [];
814
+ const result = [entries[0]];
815
+ for (let i = 1; i < entries.length; i++) {
816
+ const prev = result[result.length - 1];
817
+ const curr = entries[i];
818
+ if (prev.entry.type === curr.entry.type && prev.entry.content === curr.entry.content) {
819
+ prev.count += curr.count;
820
+ } else {
821
+ result.push({ ...curr });
822
+ }
823
+ }
824
+ return result;
825
+ }
826
+
687
827
  // src/components/agent-response/hooks/useAgentResponseAccumulator.ts
688
828
  function useAgentResponseAccumulator(options) {
689
829
  const [state, setState] = useState(initialAgentResponseState);
@@ -717,28 +857,44 @@ function useAgentResponseAccumulator(options) {
717
857
  id: payload.thinkingStep.id || `step-${Date.now()}`,
718
858
  label: payload.thinkingStep.label,
719
859
  content: payload.thinkingStep.content,
720
- depth: payload.thinkingStep.depth ?? 0,
721
- isCollapsed: payload.thinkingStep.isCollapsed
860
+ depth: payload.thinkingStep.depth ?? payload.depth ?? 0,
861
+ isCollapsed: payload.thinkingStep.isCollapsed,
862
+ timestamp: Date.now(),
863
+ agentName: payload.agentName,
864
+ parentAgent: payload.parentAgent
722
865
  };
723
866
  const thinkingStartTime2 = prev.thinkingStartTime ?? Date.now();
724
- return {
867
+ const next2 = {
725
868
  ...prev,
726
869
  status: newStatus,
727
870
  thinkingSteps: [...prev.thinkingSteps || [], newStep],
728
871
  thinkingStartTime: thinkingStartTime2,
729
872
  firstMessageTime
730
873
  };
874
+ return { ...next2, timelineEntries: buildTimelineEntries(next2) };
731
875
  }
732
876
  const newThinking = payload.message || payload.content || "";
733
877
  const separator = prev.thinking && newThinking ? "\n\n" : "";
734
878
  const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
735
- return {
879
+ const prevSteps = prev.thinkingSteps || [];
880
+ const plainStep = {
881
+ id: `step-${prevSteps.length}`,
882
+ label: newThinking,
883
+ content: newThinking,
884
+ depth: payload.depth ?? 0,
885
+ timestamp: Date.now(),
886
+ agentName: payload.agentName,
887
+ parentAgent: payload.parentAgent
888
+ };
889
+ const next = {
736
890
  ...prev,
737
891
  status: newStatus,
738
892
  thinking: prev.thinking + separator + newThinking,
893
+ thinkingSteps: [...prevSteps, plainStep],
739
894
  thinkingStartTime,
740
895
  firstMessageTime
741
896
  };
897
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
742
898
  }
743
899
  case "tool_call": {
744
900
  const toolName = payload.message || payload.tool?.name;
@@ -747,14 +903,18 @@ function useAgentResponseAccumulator(options) {
747
903
  id: payload.tool?.id || `tool-${Date.now()}`,
748
904
  name: toolName,
749
905
  arguments: payload.tool?.arguments,
750
- timestamp: Date.now()
906
+ timestamp: Date.now(),
907
+ agentName: payload.agentName,
908
+ parentAgent: payload.parentAgent,
909
+ depth: payload.depth
751
910
  };
752
- return {
911
+ const next = {
753
912
  ...prev,
754
913
  status: newStatus,
755
914
  toolCalls: [...prev.toolCalls, newToolCall],
756
915
  firstMessageTime
757
916
  };
917
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
758
918
  }
759
919
  return { ...prev, status: newStatus, firstMessageTime };
760
920
  }
@@ -765,14 +925,18 @@ function useAgentResponseAccumulator(options) {
765
925
  id: payload.knowledge?.id || `knowledge-${Date.now()}`,
766
926
  source: payload.knowledge?.source || "unknown",
767
927
  content: knowledgeContent,
768
- timestamp: Date.now()
928
+ timestamp: Date.now(),
929
+ agentName: payload.agentName,
930
+ parentAgent: payload.parentAgent,
931
+ depth: payload.depth
769
932
  };
770
- return {
933
+ const next = {
771
934
  ...prev,
772
935
  status: newStatus,
773
936
  knowledge: [...prev.knowledge, newKnowledge],
774
937
  firstMessageTime
775
938
  };
939
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
776
940
  }
777
941
  return { ...prev, status: newStatus, firstMessageTime };
778
942
  }
@@ -783,14 +947,18 @@ function useAgentResponseAccumulator(options) {
783
947
  id: payload.memory?.id || `memory-${Date.now()}`,
784
948
  type: payload.memory?.type || "unknown",
785
949
  content: memoryContent,
786
- timestamp: Date.now()
950
+ timestamp: Date.now(),
951
+ agentName: payload.agentName,
952
+ parentAgent: payload.parentAgent,
953
+ depth: payload.depth
787
954
  };
788
- return {
955
+ const next = {
789
956
  ...prev,
790
957
  status: newStatus,
791
958
  memory: [...prev.memory, newMemory],
792
959
  firstMessageTime
793
960
  };
961
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
794
962
  }
795
963
  return { ...prev, status: newStatus, firstMessageTime };
796
964
  }
@@ -809,14 +977,39 @@ function useAgentResponseAccumulator(options) {
809
977
  id: payload.statusUpdate?.id || `status-${Date.now()}`,
810
978
  message: statusMessage,
811
979
  agent: payload.statusUpdate?.agent,
812
- timestamp: Date.now()
980
+ timestamp: Date.now(),
981
+ agentName: payload.agentName,
982
+ parentAgent: payload.parentAgent,
983
+ depth: payload.depth
813
984
  };
814
- return {
985
+ const next = {
815
986
  ...prev,
816
987
  status: newStatus,
817
988
  statusUpdates: [...prev.statusUpdates, newStatusItem],
818
989
  firstMessageTime
819
990
  };
991
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
992
+ }
993
+ return { ...prev, status: newStatus, firstMessageTime };
994
+ }
995
+ case "potential_response": {
996
+ const respContent = payload.message || payload.content || "";
997
+ if (respContent) {
998
+ const newResp = {
999
+ id: `resp-${Date.now()}`,
1000
+ content: respContent,
1001
+ timestamp: Date.now(),
1002
+ agentName: payload.agentName,
1003
+ parentAgent: payload.parentAgent,
1004
+ depth: payload.depth
1005
+ };
1006
+ const next = {
1007
+ ...prev,
1008
+ status: newStatus,
1009
+ potentialResponses: [...prev.potentialResponses || [], newResp],
1010
+ firstMessageTime
1011
+ };
1012
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
820
1013
  }
821
1014
  return { ...prev, status: newStatus, firstMessageTime };
822
1015
  }
@@ -832,6 +1025,287 @@ function useAgentResponseAccumulator(options) {
832
1025
  }, []);
833
1026
  return { state, handleMessage, reset };
834
1027
  }
1028
+ var ICON_MAP = {
1029
+ thinking: Brain,
1030
+ tool_call: Wrench,
1031
+ knowledge: BookOpen,
1032
+ memory: HardDrive,
1033
+ status_update: Activity,
1034
+ ai_response: MessageSquare,
1035
+ error: AlertCircle
1036
+ };
1037
+ function TimelineItem({
1038
+ displayEntry,
1039
+ renderMarkdown,
1040
+ isExpanded,
1041
+ onToggleExpanded
1042
+ }) {
1043
+ const { entry, count } = displayEntry;
1044
+ const Icon = ICON_MAP[entry.type] ?? Activity;
1045
+ const isLong = entry.content.length > 200 || entry.content.split("\n").length > 3;
1046
+ const canExpand = isLong || entry.type === "ai_response";
1047
+ return /* @__PURE__ */ jsxs("div", { className: "py-1 flex items-start gap-2 group", children: [
1048
+ /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0 mt-0.5" }),
1049
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: isExpanded && entry.type === "ai_response" && renderMarkdown ? (
1050
+ // Expanded AI response: rendered markdown
1051
+ /* @__PURE__ */ jsxs("div", { children: [
1052
+ renderMarkdown(entry.content),
1053
+ /* @__PURE__ */ jsx(
1054
+ "button",
1055
+ {
1056
+ onClick: onToggleExpanded,
1057
+ className: "text-[10px] text-muted-foreground/70 hover:text-muted-foreground mt-1",
1058
+ children: "Show less"
1059
+ }
1060
+ )
1061
+ ] })
1062
+ ) : isExpanded ? (
1063
+ // Expanded non-AI: plain text
1064
+ /* @__PURE__ */ jsxs("div", { children: [
1065
+ /* @__PURE__ */ jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: entry.content }),
1066
+ /* @__PURE__ */ jsx(
1067
+ "button",
1068
+ {
1069
+ onClick: onToggleExpanded,
1070
+ className: "text-[10px] text-muted-foreground/70 hover:text-muted-foreground mt-1",
1071
+ children: "Show less"
1072
+ }
1073
+ )
1074
+ ] })
1075
+ ) : (
1076
+ // Collapsed: truncated with optional expand
1077
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1.5 min-w-0", children: [
1078
+ /* @__PURE__ */ jsx(
1079
+ "div",
1080
+ {
1081
+ className: `text-xs text-muted-foreground min-w-0 ${canExpand ? "line-clamp-2 cursor-pointer hover:text-foreground/80" : ""}`,
1082
+ onClick: canExpand ? onToggleExpanded : void 0,
1083
+ children: entry.content
1084
+ }
1085
+ ),
1086
+ count > 1 && /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground/60 whitespace-nowrap flex-shrink-0", children: [
1087
+ "(x",
1088
+ count,
1089
+ ")"
1090
+ ] })
1091
+ ] })
1092
+ ) })
1093
+ ] });
1094
+ }
1095
+ function TimelineAgentBlock({
1096
+ block,
1097
+ renderMarkdown,
1098
+ isSingleAgent,
1099
+ isCollapsed,
1100
+ onToggleCollapsed,
1101
+ expandedItems,
1102
+ onToggleItemExpanded
1103
+ }) {
1104
+ const indentPx = block.depth * 16;
1105
+ if (isSingleAgent && block.depth === 0) {
1106
+ return /* @__PURE__ */ jsx("div", { style: { paddingLeft: `${indentPx}px` }, children: block.entries.map((displayEntry, i) => /* @__PURE__ */ jsx(
1107
+ TimelineItem,
1108
+ {
1109
+ displayEntry,
1110
+ renderMarkdown,
1111
+ isExpanded: expandedItems.has(displayEntry.entry.id),
1112
+ onToggleExpanded: () => onToggleItemExpanded(displayEntry.entry.id)
1113
+ },
1114
+ displayEntry.entry.id + "-" + i
1115
+ )) });
1116
+ }
1117
+ return /* @__PURE__ */ jsxs("div", { style: { paddingLeft: `${indentPx}px` }, children: [
1118
+ /* @__PURE__ */ jsxs(
1119
+ "button",
1120
+ {
1121
+ onClick: onToggleCollapsed,
1122
+ 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",
1123
+ children: [
1124
+ isCollapsed ? /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }),
1125
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground/80", children: block.agentName }),
1126
+ /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground/60", children: [
1127
+ "(",
1128
+ block.entries.reduce((sum, e) => sum + e.count, 0),
1129
+ ")"
1130
+ ] })
1131
+ ]
1132
+ }
1133
+ ),
1134
+ !isCollapsed && /* @__PURE__ */ jsx("div", { className: "ml-4", children: block.entries.map((displayEntry, i) => /* @__PURE__ */ jsx(
1135
+ TimelineItem,
1136
+ {
1137
+ displayEntry,
1138
+ renderMarkdown,
1139
+ isExpanded: expandedItems.has(displayEntry.entry.id),
1140
+ onToggleExpanded: () => onToggleItemExpanded(displayEntry.entry.id)
1141
+ },
1142
+ displayEntry.entry.id + "-" + i
1143
+ )) })
1144
+ ] });
1145
+ }
1146
+ function createTimelineUIState() {
1147
+ return {
1148
+ expandedItems: /* @__PURE__ */ new Set(),
1149
+ collapsedRuns: /* @__PURE__ */ new Set(),
1150
+ activeFilters: /* @__PURE__ */ new Set()
1151
+ };
1152
+ }
1153
+ var TYPE_CONFIG = [
1154
+ { type: "status_update", icon: Activity, label: "Status" },
1155
+ { type: "thinking", icon: Brain, label: "Thinking" },
1156
+ { type: "tool_call", icon: Wrench, label: "Tools" },
1157
+ { type: "knowledge", icon: BookOpen, label: "Knowledge" },
1158
+ { type: "memory", icon: HardDrive, label: "Memory" },
1159
+ { type: "ai_response", icon: MessageSquare, label: "AI" },
1160
+ { type: "error", icon: AlertCircle, label: "Errors" }
1161
+ ];
1162
+ function AgentTimeline({ entries, renderMarkdown, uiState, maxHeight = "300px" }) {
1163
+ const containerRef = useRef(null);
1164
+ const [renderTick, setRenderTick] = useState(0);
1165
+ const forceRender = useCallback(() => setRenderTick((t) => t + 1), []);
1166
+ const [internalExpandedItems] = useState(() => /* @__PURE__ */ new Set());
1167
+ const [internalCollapsedRuns] = useState(() => /* @__PURE__ */ new Set());
1168
+ const [internalActiveFilters] = useState(() => /* @__PURE__ */ new Set());
1169
+ const expandedItems = uiState?.expandedItems ?? internalExpandedItems;
1170
+ const collapsedRuns = uiState?.collapsedRuns ?? internalCollapsedRuns;
1171
+ const activeFilters = uiState?.activeFilters ?? internalActiveFilters;
1172
+ const availableTypes = useMemo(() => {
1173
+ const types = /* @__PURE__ */ new Set();
1174
+ for (const entry of entries) {
1175
+ types.add(entry.type);
1176
+ }
1177
+ return types;
1178
+ }, [entries]);
1179
+ const filteredEntries = useMemo(
1180
+ () => activeFilters.size === 0 ? entries : entries.filter((e) => activeFilters.has(e.type)),
1181
+ [entries, activeFilters, renderTick]
1182
+ );
1183
+ const agentRuns = useMemo(() => groupIntoAgentRuns(filteredEntries), [filteredEntries, renderTick]);
1184
+ const toggleFilter = useCallback((type) => {
1185
+ if (activeFilters.has(type)) {
1186
+ activeFilters.delete(type);
1187
+ } else {
1188
+ activeFilters.add(type);
1189
+ }
1190
+ forceRender();
1191
+ }, [activeFilters, forceRender]);
1192
+ const clearFilters = useCallback(() => {
1193
+ activeFilters.clear();
1194
+ forceRender();
1195
+ }, [activeFilters, forceRender]);
1196
+ const toggleItemExpanded = useCallback((entryId) => {
1197
+ if (expandedItems.has(entryId)) {
1198
+ expandedItems.delete(entryId);
1199
+ } else {
1200
+ expandedItems.add(entryId);
1201
+ }
1202
+ forceRender();
1203
+ }, [expandedItems, forceRender]);
1204
+ const collapseAll = useCallback(() => {
1205
+ collapsedRuns.clear();
1206
+ agentRuns.forEach((run, i) => {
1207
+ collapsedRuns.add(`${run.agentName}-${i}`);
1208
+ });
1209
+ expandedItems.clear();
1210
+ forceRender();
1211
+ }, [agentRuns, collapsedRuns, expandedItems, forceRender]);
1212
+ const expandAll = useCallback(() => {
1213
+ collapsedRuns.clear();
1214
+ agentRuns.forEach((run, i) => {
1215
+ collapsedRuns.add(`${run.agentName}-${i}:expanded`);
1216
+ });
1217
+ forceRender();
1218
+ }, [agentRuns, collapsedRuns, forceRender]);
1219
+ if (entries.length === 0) return null;
1220
+ const isSingle = agentRuns.length === 1;
1221
+ const hasActiveFilter = activeFilters.size > 0;
1222
+ const scrollStyle = maxHeight !== "none" ? { maxHeight } : void 0;
1223
+ return /* @__PURE__ */ jsxs(
1224
+ "div",
1225
+ {
1226
+ ref: containerRef,
1227
+ className: `-mt-1 ${maxHeight !== "none" ? "overflow-y-auto scrollbar-thin" : ""}`,
1228
+ style: scrollStyle,
1229
+ children: [
1230
+ /* @__PURE__ */ 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: [
1231
+ TYPE_CONFIG.filter((tc) => availableTypes.has(tc.type)).map((tc) => {
1232
+ const isActive = activeFilters.has(tc.type);
1233
+ const count = entries.filter((e) => e.type === tc.type).length;
1234
+ return /* @__PURE__ */ jsxs(
1235
+ "button",
1236
+ {
1237
+ onClick: () => toggleFilter(tc.type),
1238
+ 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"}`,
1239
+ title: `${isActive ? "Hide" : "Show only"} ${tc.label}`,
1240
+ children: [
1241
+ /* @__PURE__ */ jsx(tc.icon, { className: "w-3 h-3" }),
1242
+ /* @__PURE__ */ jsx("span", { children: count })
1243
+ ]
1244
+ },
1245
+ tc.type
1246
+ );
1247
+ }),
1248
+ hasActiveFilter && /* @__PURE__ */ jsx(
1249
+ "button",
1250
+ {
1251
+ onClick: clearFilters,
1252
+ className: "text-[10px] text-muted-foreground/60 hover:text-muted-foreground px-1",
1253
+ children: "Clear"
1254
+ }
1255
+ ),
1256
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
1257
+ !isSingle && /* @__PURE__ */ jsxs(Fragment, { children: [
1258
+ /* @__PURE__ */ jsx(
1259
+ "button",
1260
+ {
1261
+ onClick: collapseAll,
1262
+ 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",
1263
+ title: "Collapse all",
1264
+ children: /* @__PURE__ */ jsx(ChevronsDownUp, { className: "w-3 h-3" })
1265
+ }
1266
+ ),
1267
+ /* @__PURE__ */ jsx(
1268
+ "button",
1269
+ {
1270
+ onClick: expandAll,
1271
+ 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",
1272
+ title: "Expand all",
1273
+ children: /* @__PURE__ */ jsx(ChevronsUpDown, { className: "w-3 h-3" })
1274
+ }
1275
+ )
1276
+ ] })
1277
+ ] }),
1278
+ filteredEntries.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-[10px] text-muted-foreground/50 py-2 text-center", children: "No entries match the selected filters" }) : /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: agentRuns.map((run, i) => {
1279
+ const runKey = `${run.agentName}-${i}`;
1280
+ const defaultCollapsed = run.depth > 0;
1281
+ const isCollapsed = collapsedRuns.has(runKey) ? true : collapsedRuns.has(`${runKey}:expanded`) ? false : defaultCollapsed;
1282
+ return /* @__PURE__ */ jsx(
1283
+ TimelineAgentBlock,
1284
+ {
1285
+ block: run,
1286
+ renderMarkdown,
1287
+ isSingleAgent: isSingle,
1288
+ isCollapsed,
1289
+ onToggleCollapsed: () => {
1290
+ if (isCollapsed) {
1291
+ collapsedRuns.delete(runKey);
1292
+ collapsedRuns.add(`${runKey}:expanded`);
1293
+ } else {
1294
+ collapsedRuns.delete(`${runKey}:expanded`);
1295
+ collapsedRuns.add(runKey);
1296
+ }
1297
+ forceRender();
1298
+ },
1299
+ expandedItems,
1300
+ onToggleItemExpanded: toggleItemExpanded
1301
+ },
1302
+ runKey
1303
+ );
1304
+ }) })
1305
+ ]
1306
+ }
1307
+ );
1308
+ }
835
1309
  var AgentResponse = React11.forwardRef(
836
1310
  ({
837
1311
  state,
@@ -852,6 +1326,7 @@ var AgentResponse = React11.forwardRef(
852
1326
  className,
853
1327
  ...props
854
1328
  }, ref) => {
1329
+ const timelineUIStateRef = useRef(createTimelineUIState());
855
1330
  const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultThinkingExpanded);
856
1331
  const isThinkingControlled = controlledThinkingExpanded !== void 0;
857
1332
  const thinkingExpanded = isThinkingControlled ? controlledThinkingExpanded : uncontrolledExpanded;
@@ -873,7 +1348,8 @@ var AgentResponse = React11.forwardRef(
873
1348
  if (!state.firstMessageTime || !state.responseCompleteTime) return 0;
874
1349
  return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
875
1350
  }, [state.firstMessageTime, state.responseCompleteTime]);
876
- const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || false;
1351
+ const hasTimelineEntries = !!(state.timelineEntries && state.timelineEntries.length > 0);
1352
+ const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || hasTimelineEntries || false;
877
1353
  const hasHITLInteractions = hitlInteractions && hitlInteractions.length > 0;
878
1354
  const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || hasHITLInteractions || state.response;
879
1355
  const showMetadataRow = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.status === "processing";
@@ -908,7 +1384,14 @@ var AgentResponse = React11.forwardRef(
908
1384
  elapsedTime
909
1385
  }
910
1386
  ),
911
- /* @__PURE__ */ jsx(
1387
+ hasTimelineEntries ? thinkingExpanded && /* @__PURE__ */ jsx("div", { className: "px-3 pb-3 border-t border-border mt-2", children: /* @__PURE__ */ jsx(
1388
+ AgentTimeline,
1389
+ {
1390
+ entries: state.timelineEntries,
1391
+ renderMarkdown: renderThinkingMarkdown,
1392
+ uiState: timelineUIStateRef.current
1393
+ }
1394
+ ) }) : /* @__PURE__ */ jsx(
912
1395
  ThinkingSection,
913
1396
  {
914
1397
  content: state.thinkingSteps && state.thinkingSteps.length > 0 ? state.thinkingSteps : state.thinking,
@@ -1215,6 +1698,115 @@ var UserPromptInput = React11.forwardRef(
1215
1698
  );
1216
1699
  UserPromptInput.displayName = "UserPromptInput";
1217
1700
 
1218
- export { ActionBar, ActivityIndicators, AgentResponse, HITLInteractionRecord, HITLQuestionPanel, HITLSection, MetadataRow, ThinkingSection, TruncatedMessage, UserPrompt, UserPromptInput, buildResponseString, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
1701
+ // src/components/inline-actions/parseResponseSegments.ts
1702
+ var ACTION_BLOCK_REGEX = /```json:action\s*\n([\s\S]*?)```/g;
1703
+ function parseResponseSegments(text) {
1704
+ if (!text) return [];
1705
+ const segments = [];
1706
+ let lastIndex = 0;
1707
+ ACTION_BLOCK_REGEX.lastIndex = 0;
1708
+ let match;
1709
+ while ((match = ACTION_BLOCK_REGEX.exec(text)) !== null) {
1710
+ const before = text.slice(lastIndex, match.index);
1711
+ if (before.trim()) {
1712
+ segments.push({ kind: "markdown", content: before });
1713
+ }
1714
+ const jsonContent = match[1].trim();
1715
+ let parsed = null;
1716
+ try {
1717
+ parsed = JSON.parse(jsonContent);
1718
+ } catch {
1719
+ }
1720
+ if (parsed && typeof parsed === "object" && typeof parsed.type === "string") {
1721
+ segments.push({
1722
+ kind: "action",
1723
+ actionType: parsed.type,
1724
+ payload: parsed
1725
+ });
1726
+ } else {
1727
+ const rawBlock = match[0];
1728
+ segments.push({ kind: "markdown", content: rawBlock });
1729
+ }
1730
+ lastIndex = match.index + match[0].length;
1731
+ }
1732
+ const trailing = text.slice(lastIndex);
1733
+ if (trailing.trim()) {
1734
+ segments.push({ kind: "markdown", content: trailing });
1735
+ }
1736
+ return segments;
1737
+ }
1738
+ function ActionMarkdownRenderer({
1739
+ content,
1740
+ registry,
1741
+ renderMarkdown,
1742
+ onAction,
1743
+ isLatest
1744
+ }) {
1745
+ const segments = useMemo(() => parseResponseSegments(content), [content]);
1746
+ if (segments.length === 1 && segments[0].kind === "markdown") {
1747
+ return /* @__PURE__ */ jsx(Fragment, { children: renderMarkdown(segments[0].content) });
1748
+ }
1749
+ return /* @__PURE__ */ jsx(Fragment, { children: segments.map((segment, index) => {
1750
+ if (segment.kind === "markdown") {
1751
+ return /* @__PURE__ */ jsx("div", { children: renderMarkdown(segment.content) }, `md-${index}`);
1752
+ }
1753
+ const Component = registry[segment.actionType];
1754
+ if (!Component) {
1755
+ return /* @__PURE__ */ jsx(
1756
+ "pre",
1757
+ {
1758
+ className: "my-4 p-4 rounded-lg border border-border bg-muted text-sm font-mono overflow-x-auto",
1759
+ children: /* @__PURE__ */ jsx("code", { children: JSON.stringify(segment.payload, null, 2) })
1760
+ },
1761
+ `action-fallback-${index}`
1762
+ );
1763
+ }
1764
+ return /* @__PURE__ */ jsx(
1765
+ Component,
1766
+ {
1767
+ payload: segment.payload,
1768
+ onAction,
1769
+ isLatest
1770
+ },
1771
+ `action-${segment.actionType}-${index}`
1772
+ );
1773
+ }) });
1774
+ }
1775
+
1776
+ // src/components/inline-actions/prompts.ts
1777
+ var INLINE_ACTION_PROMPT = `
1778
+ <inline_actions>
1779
+ When your response should include interactive components (like query viewers,
1780
+ data tables, or executable actions), embed them as fenced code blocks using
1781
+ the \`json:action\` language tag:
1782
+
1783
+ \`\`\`json:action
1784
+ {
1785
+ "type": "action-type-here",
1786
+ ...action-specific fields
1787
+ }
1788
+ \`\`\`
1789
+
1790
+ Rules:
1791
+ - Each block must contain valid JSON with a "type" field.
1792
+ - The "type" must match a registered action component on the frontend.
1793
+ - Multiple action blocks per response are allowed.
1794
+ - Surround action blocks with normal markdown text for user context.
1795
+ - The action block is rendered as an interactive component in the chat UI.
1796
+ - SQL strings inside JSON must be properly escaped (newlines as \\n, quotes as \\").
1797
+
1798
+ Available action types:
1799
+
1800
+ - "optimap-query": Displays SQL queries with a button to execute them and
1801
+ update the 3D globe map.
1802
+ Required fields:
1803
+ - type: "optimap-query"
1804
+ - locations_sql: string (the validated locations SQL query)
1805
+ - routes_sql: string (the validated routes SQL query)
1806
+ - database_name: string (the target database name)
1807
+ </inline_actions>
1808
+ `;
1809
+
1810
+ export { ActionBar, ActionMarkdownRenderer, ActivityIndicators, AgentResponse, AgentTimeline, HITLInteractionRecord, HITLQuestionPanel, HITLSection, INLINE_ACTION_PROMPT, MetadataRow, ThinkingSection, TruncatedMessage, UserPrompt, UserPromptInput, buildResponseString, buildTimelineEntries, createTimelineUIState, deduplicateEntries, formatTime, formatTotalTime, groupIntoAgentRuns, initialAgentResponseState, parseResponseSegments, useAgentResponseAccumulator, useThinkingTimer };
1219
1811
  //# sourceMappingURL=index.js.map
1220
1812
  //# sourceMappingURL=index.js.map