@optilogic/chat 1.0.0-beta.9 → 1.0.0

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 (31) hide show
  1. package/README.md +43 -0
  2. package/dist/index.cjs +709 -79
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +283 -4
  5. package/dist/index.d.ts +283 -4
  6. package/dist/index.js +674 -53
  7. package/dist/index.js.map +1 -1
  8. package/package.json +3 -3
  9. package/src/components/agent-response/AgentResponse.tsx +59 -13
  10. package/src/components/agent-response/components/MetadataRow.tsx +15 -4
  11. package/src/components/agent-response/components/TruncatedMessage.tsx +52 -0
  12. package/src/components/agent-response/components/index.ts +3 -0
  13. package/src/components/agent-response/hooks/useAgentResponseAccumulator.ts +65 -8
  14. package/src/components/agent-response/index.ts +19 -0
  15. package/src/components/agent-response/types.ts +61 -1
  16. package/src/components/agent-timeline/AgentTimeline.tsx +256 -0
  17. package/src/components/agent-timeline/TimelineAgentBlock.tsx +84 -0
  18. package/src/components/agent-timeline/TimelineItem.tsx +97 -0
  19. package/src/components/agent-timeline/index.ts +14 -0
  20. package/src/components/agent-timeline/types.ts +49 -0
  21. package/src/components/agent-timeline/utils.ts +189 -0
  22. package/src/components/hitl-interactions/HITLQuestionPanel.tsx +35 -21
  23. package/src/components/hitl-interactions/index.ts +1 -1
  24. package/src/components/inline-actions/ActionMarkdownRenderer.tsx +60 -0
  25. package/src/components/inline-actions/index.ts +18 -0
  26. package/src/components/inline-actions/parseResponseSegments.ts +66 -0
  27. package/src/components/inline-actions/prompts.ts +41 -0
  28. package/src/components/inline-actions/types.ts +57 -0
  29. package/src/components/user-prompt-input/UserPromptInput.tsx +13 -8
  30. package/src/components/user-prompt-input/types.ts +4 -0
  31. package/src/index.ts +29 -0
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- import * as React10 from 'react';
1
+ import * as React11 from 'react';
2
2
  import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
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';
3
+ import { cn, Popover, PopoverTrigger, PopoverContent, Button, Textarea, Tooltip, IconButton, LoadingSpinner } from '@optilogic/core';
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
 
8
8
  // src/components/agent-response/AgentResponse.tsx
9
- var ActivityIndicators = React10.forwardRef(
9
+ var ActivityIndicators = React11.forwardRef(
10
10
  ({ toolCalls, knowledge, memory, statusUpdates = [], className, ...props }, ref) => {
11
11
  const hasAnyActivity = toolCalls.length > 0 || knowledge.length > 0 || memory.length > 0 || statusUpdates.length > 0;
12
12
  if (!hasAnyActivity) return null;
@@ -125,7 +125,7 @@ function formatTotalTime(seconds) {
125
125
  const minutes = seconds / 60;
126
126
  return `${minutes.toFixed(1)}m`;
127
127
  }
128
- var MetadataRow = React10.forwardRef(
128
+ var MetadataRow = React11.forwardRef(
129
129
  ({
130
130
  hasThinking,
131
131
  isExpanded,
@@ -134,6 +134,7 @@ var MetadataRow = React10.forwardRef(
134
134
  knowledge,
135
135
  memory,
136
136
  statusUpdates = [],
137
+ statusContent,
137
138
  status,
138
139
  elapsedTime,
139
140
  className,
@@ -158,7 +159,7 @@ var MetadataRow = React10.forwardRef(
158
159
  return null;
159
160
  };
160
161
  const leftContent = renderLeftContent();
161
- if (!leftContent && !hasActivity) {
162
+ if (!leftContent && !hasActivity && !statusContent) {
162
163
  return null;
163
164
  }
164
165
  return /* @__PURE__ */ jsxs(
@@ -172,10 +173,11 @@ var MetadataRow = React10.forwardRef(
172
173
  "button",
173
174
  {
174
175
  onClick: onToggle,
175
- className: "flex items-center gap-1.5 hover:bg-muted/50 -ml-1.5 pl-1.5 pr-2 py-0.5 rounded transition-colors",
176
+ className: "flex items-center gap-1.5 hover:bg-muted/50 -ml-1.5 pl-1.5 pr-2 py-0.5 rounded transition-colors shrink-0",
176
177
  children: leftContent
177
178
  }
178
- ) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: leftContent }),
179
+ ) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 shrink-0", children: leftContent }),
180
+ statusContent && /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0 mx-2", children: statusContent }),
179
181
  /* @__PURE__ */ jsx(
180
182
  ActivityIndicators,
181
183
  {
@@ -220,7 +222,7 @@ var ThinkingStepItem = ({ step, renderMarkdown }) => {
220
222
  )
221
223
  ] });
222
224
  };
223
- var ThinkingSection = React10.forwardRef(
225
+ var ThinkingSection = React11.forwardRef(
224
226
  ({ content, isExpanded, renderMarkdown, className, ...props }, ref) => {
225
227
  if (!isExpanded || !content || Array.isArray(content) && content.length === 0) {
226
228
  return null;
@@ -245,7 +247,7 @@ var ThinkingSection = React10.forwardRef(
245
247
  }
246
248
  );
247
249
  ThinkingSection.displayName = "ThinkingSection";
248
- var ActionBar = React10.forwardRef(
250
+ var ActionBar = React11.forwardRef(
249
251
  ({
250
252
  response,
251
253
  isVisible,
@@ -349,22 +351,24 @@ A: ${answer}`);
349
351
  }
350
352
  return parts.join("\n\n");
351
353
  }
352
- var HITLQuestionPanel = React10.forwardRef(({ question, onSubmit, onStop, className, ...props }, ref) => {
354
+ var HITLQuestionPanel = React11.forwardRef(({ question, onSubmit, onStop, className, ...props }, ref) => {
353
355
  const [freeformText, setFreeformText] = useState("");
354
356
  const [selectedOptions, setSelectedOptions] = useState({});
357
+ const hasTimeout = question.timeoutSeconds != null;
355
358
  const [secondsLeft, setSecondsLeft] = useState(
356
- () => Math.max(
359
+ () => hasTimeout ? Math.max(
357
360
  0,
358
361
  Math.round(
359
362
  question.timeoutSeconds - (Date.now() - question.receivedAt) / 1e3
360
363
  )
361
- )
364
+ ) : Infinity
362
365
  );
363
366
  const textareaRef = useRef(null);
364
367
  useEffect(() => {
365
368
  textareaRef.current?.focus();
366
369
  }, []);
367
370
  useEffect(() => {
371
+ if (!hasTimeout) return;
368
372
  const interval = setInterval(() => {
369
373
  const remaining = Math.max(
370
374
  0,
@@ -376,8 +380,8 @@ var HITLQuestionPanel = React10.forwardRef(({ question, onSubmit, onStop, classN
376
380
  if (remaining <= 0) clearInterval(interval);
377
381
  }, 1e3);
378
382
  return () => clearInterval(interval);
379
- }, [question.timeoutSeconds, question.receivedAt]);
380
- const timedOut = secondsLeft <= 0;
383
+ }, [hasTimeout, question.timeoutSeconds, question.receivedAt]);
384
+ const timedOut = hasTimeout && secondsLeft <= 0;
381
385
  const questionsWithOptions = useMemo(
382
386
  () => question.questions.filter((q) => question.options?.[q]?.length),
383
387
  [question.questions, question.options]
@@ -406,7 +410,7 @@ var HITLQuestionPanel = React10.forwardRef(({ question, onSubmit, onStop, classN
406
410
  selectedOptions,
407
411
  freeformText
408
412
  );
409
- onSubmit(combined);
413
+ onSubmit(combined, { selectedOptions, freeformText });
410
414
  }, [canSubmit, question.questions, selectedOptions, freeformText, onSubmit]);
411
415
  const handleKeyDown = useCallback(
412
416
  (e) => {
@@ -434,7 +438,7 @@ var HITLQuestionPanel = React10.forwardRef(({ question, onSubmit, onStop, classN
434
438
  children: [
435
439
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
436
440
  /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: question.reason }) }),
437
- /* @__PURE__ */ jsx(
441
+ hasTimeout && /* @__PURE__ */ jsx(
438
442
  "span",
439
443
  {
440
444
  className: cn(
@@ -517,7 +521,7 @@ function parseResponse(response) {
517
521
  }
518
522
  return { answers, additionalContext };
519
523
  }
520
- var HITLInteractionRecord = React10.forwardRef(({ interaction, className, ...props }, ref) => {
524
+ var HITLInteractionRecord = React11.forwardRef(({ interaction, className, ...props }, ref) => {
521
525
  const { question, response, respondedAt } = interaction;
522
526
  const timestamp = new Date(respondedAt).toLocaleTimeString([], {
523
527
  hour: "2-digit",
@@ -568,7 +572,7 @@ var HITLInteractionRecord = React10.forwardRef(({ interaction, className, ...pro
568
572
  );
569
573
  });
570
574
  HITLInteractionRecord.displayName = "HITLInteractionRecord";
571
- var HITLSection = React10.forwardRef(
575
+ var HITLSection = React11.forwardRef(
572
576
  ({
573
577
  interactions,
574
578
  defaultExpanded = false,
@@ -621,6 +625,24 @@ var HITLSection = React10.forwardRef(
621
625
  }
622
626
  );
623
627
  HITLSection.displayName = "HITLSection";
628
+ var TruncatedMessage = React11.forwardRef(
629
+ ({ message, className, ...props }, ref) => {
630
+ return /* @__PURE__ */ jsx(
631
+ "div",
632
+ {
633
+ ref,
634
+ className: cn(
635
+ "text-xs text-muted-foreground truncate min-w-0",
636
+ className
637
+ ),
638
+ title: message,
639
+ ...props,
640
+ children: message
641
+ }
642
+ );
643
+ }
644
+ );
645
+ TruncatedMessage.displayName = "TruncatedMessage";
624
646
  function useThinkingTimer({
625
647
  startTime,
626
648
  endTime,
@@ -656,12 +678,152 @@ var initialAgentResponseState = {
656
678
  knowledge: [],
657
679
  memory: [],
658
680
  statusUpdates: [],
681
+ potentialResponses: [],
682
+ customTimelineEntries: [],
659
683
  response: "",
660
684
  thinkingStartTime: null,
661
685
  responseCompleteTime: null,
662
686
  firstMessageTime: null
663
687
  };
664
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
+
665
827
  // src/components/agent-response/hooks/useAgentResponseAccumulator.ts
666
828
  function useAgentResponseAccumulator(options) {
667
829
  const [state, setState] = useState(initialAgentResponseState);
@@ -695,28 +857,44 @@ function useAgentResponseAccumulator(options) {
695
857
  id: payload.thinkingStep.id || `step-${Date.now()}`,
696
858
  label: payload.thinkingStep.label,
697
859
  content: payload.thinkingStep.content,
698
- depth: payload.thinkingStep.depth ?? 0,
699
- 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
700
865
  };
701
866
  const thinkingStartTime2 = prev.thinkingStartTime ?? Date.now();
702
- return {
867
+ const next2 = {
703
868
  ...prev,
704
869
  status: newStatus,
705
870
  thinkingSteps: [...prev.thinkingSteps || [], newStep],
706
871
  thinkingStartTime: thinkingStartTime2,
707
872
  firstMessageTime
708
873
  };
874
+ return { ...next2, timelineEntries: buildTimelineEntries(next2) };
709
875
  }
710
876
  const newThinking = payload.message || payload.content || "";
711
877
  const separator = prev.thinking && newThinking ? "\n\n" : "";
712
878
  const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
713
- 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 = {
714
890
  ...prev,
715
891
  status: newStatus,
716
892
  thinking: prev.thinking + separator + newThinking,
893
+ thinkingSteps: [...prevSteps, plainStep],
717
894
  thinkingStartTime,
718
895
  firstMessageTime
719
896
  };
897
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
720
898
  }
721
899
  case "tool_call": {
722
900
  const toolName = payload.message || payload.tool?.name;
@@ -725,14 +903,18 @@ function useAgentResponseAccumulator(options) {
725
903
  id: payload.tool?.id || `tool-${Date.now()}`,
726
904
  name: toolName,
727
905
  arguments: payload.tool?.arguments,
728
- timestamp: Date.now()
906
+ timestamp: Date.now(),
907
+ agentName: payload.agentName,
908
+ parentAgent: payload.parentAgent,
909
+ depth: payload.depth
729
910
  };
730
- return {
911
+ const next = {
731
912
  ...prev,
732
913
  status: newStatus,
733
914
  toolCalls: [...prev.toolCalls, newToolCall],
734
915
  firstMessageTime
735
916
  };
917
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
736
918
  }
737
919
  return { ...prev, status: newStatus, firstMessageTime };
738
920
  }
@@ -743,14 +925,18 @@ function useAgentResponseAccumulator(options) {
743
925
  id: payload.knowledge?.id || `knowledge-${Date.now()}`,
744
926
  source: payload.knowledge?.source || "unknown",
745
927
  content: knowledgeContent,
746
- timestamp: Date.now()
928
+ timestamp: Date.now(),
929
+ agentName: payload.agentName,
930
+ parentAgent: payload.parentAgent,
931
+ depth: payload.depth
747
932
  };
748
- return {
933
+ const next = {
749
934
  ...prev,
750
935
  status: newStatus,
751
936
  knowledge: [...prev.knowledge, newKnowledge],
752
937
  firstMessageTime
753
938
  };
939
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
754
940
  }
755
941
  return { ...prev, status: newStatus, firstMessageTime };
756
942
  }
@@ -761,14 +947,18 @@ function useAgentResponseAccumulator(options) {
761
947
  id: payload.memory?.id || `memory-${Date.now()}`,
762
948
  type: payload.memory?.type || "unknown",
763
949
  content: memoryContent,
764
- timestamp: Date.now()
950
+ timestamp: Date.now(),
951
+ agentName: payload.agentName,
952
+ parentAgent: payload.parentAgent,
953
+ depth: payload.depth
765
954
  };
766
- return {
955
+ const next = {
767
956
  ...prev,
768
957
  status: newStatus,
769
958
  memory: [...prev.memory, newMemory],
770
959
  firstMessageTime
771
960
  };
961
+ return { ...next, timelineEntries: buildTimelineEntries(next) };
772
962
  }
773
963
  return { ...prev, status: newStatus, firstMessageTime };
774
964
  }
@@ -787,14 +977,39 @@ function useAgentResponseAccumulator(options) {
787
977
  id: payload.statusUpdate?.id || `status-${Date.now()}`,
788
978
  message: statusMessage,
789
979
  agent: payload.statusUpdate?.agent,
790
- timestamp: Date.now()
980
+ timestamp: Date.now(),
981
+ agentName: payload.agentName,
982
+ parentAgent: payload.parentAgent,
983
+ depth: payload.depth
791
984
  };
792
- return {
985
+ const next = {
793
986
  ...prev,
794
987
  status: newStatus,
795
988
  statusUpdates: [...prev.statusUpdates, newStatusItem],
796
989
  firstMessageTime
797
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) };
798
1013
  }
799
1014
  return { ...prev, status: newStatus, firstMessageTime };
800
1015
  }
@@ -810,7 +1025,288 @@ function useAgentResponseAccumulator(options) {
810
1025
  }, []);
811
1026
  return { state, handleMessage, reset };
812
1027
  }
813
- var AgentResponse = React10.forwardRef(
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: maxHeight !== "none" ? "overflow-y-auto" : "",
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 pl-2", 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
+ }
1309
+ var AgentResponse = React11.forwardRef(
814
1310
  ({
815
1311
  state,
816
1312
  id,
@@ -824,11 +1320,14 @@ var AgentResponse = React10.forwardRef(
824
1320
  actionsVisible = "hover",
825
1321
  hitlInteractions,
826
1322
  defaultHITLExpanded = false,
1323
+ statusContent,
827
1324
  renderMarkdown,
828
1325
  renderThinkingMarkdown,
1326
+ timelineMaxHeight,
829
1327
  className,
830
1328
  ...props
831
1329
  }, ref) => {
1330
+ const timelineUIStateRef = useRef(createTimelineUIState());
832
1331
  const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultThinkingExpanded);
833
1332
  const isThinkingControlled = controlledThinkingExpanded !== void 0;
834
1333
  const thinkingExpanded = isThinkingControlled ? controlledThinkingExpanded : uncontrolledExpanded;
@@ -850,7 +1349,8 @@ var AgentResponse = React10.forwardRef(
850
1349
  if (!state.firstMessageTime || !state.responseCompleteTime) return 0;
851
1350
  return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
852
1351
  }, [state.firstMessageTime, state.responseCompleteTime]);
853
- const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || false;
1352
+ const hasTimelineEntries = !!(state.timelineEntries && state.timelineEntries.length > 0);
1353
+ const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || hasTimelineEntries || false;
854
1354
  const hasHITLInteractions = hitlInteractions && hitlInteractions.length > 0;
855
1355
  const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || hasHITLInteractions || state.response;
856
1356
  const showMetadataRow = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.status === "processing";
@@ -880,11 +1380,20 @@ var AgentResponse = React10.forwardRef(
880
1380
  knowledge: state.knowledge,
881
1381
  memory: state.memory,
882
1382
  statusUpdates: state.statusUpdates,
1383
+ statusContent,
883
1384
  status: state.status,
884
1385
  elapsedTime
885
1386
  }
886
1387
  ),
887
- /* @__PURE__ */ jsx(
1388
+ hasTimelineEntries ? thinkingExpanded && /* @__PURE__ */ jsx("div", { className: "pb-3 border-t border-border", children: /* @__PURE__ */ jsx(
1389
+ AgentTimeline,
1390
+ {
1391
+ entries: state.timelineEntries,
1392
+ renderMarkdown: renderThinkingMarkdown,
1393
+ uiState: timelineUIStateRef.current,
1394
+ maxHeight: timelineMaxHeight
1395
+ }
1396
+ ) }) : /* @__PURE__ */ jsx(
888
1397
  ThinkingSection,
889
1398
  {
890
1399
  content: state.thinkingSteps && state.thinkingSteps.length > 0 ? state.thinkingSteps : state.thinking,
@@ -928,7 +1437,7 @@ var AgentResponse = React10.forwardRef(
928
1437
  }
929
1438
  );
930
1439
  AgentResponse.displayName = "AgentResponse";
931
- var UserPrompt = React10.forwardRef(
1440
+ var UserPrompt = React11.forwardRef(
932
1441
  ({ content, timestamp, className, ...props }, ref) => {
933
1442
  return /* @__PURE__ */ jsxs(
934
1443
  "div",
@@ -1027,7 +1536,7 @@ function CodeBlockLeaf({ attributes, children, leaf }) {
1027
1536
  }
1028
1537
  return /* @__PURE__ */ jsx("span", { ...attributes, children });
1029
1538
  }
1030
- var UserPromptInput = React10.forwardRef(
1539
+ var UserPromptInput = React11.forwardRef(
1031
1540
  ({
1032
1541
  value = "",
1033
1542
  onChange,
@@ -1037,6 +1546,8 @@ var UserPromptInput = React10.forwardRef(
1037
1546
  disabled = false,
1038
1547
  isSubmitting = false,
1039
1548
  onStop,
1549
+ stopTooltip,
1550
+ stopClassName,
1040
1551
  disableWhileSubmitting = true,
1041
1552
  autoFocus = false,
1042
1553
  refocusAfterSubmit = false,
@@ -1050,14 +1561,14 @@ var UserPromptInput = React10.forwardRef(
1050
1561
  className,
1051
1562
  ...props
1052
1563
  }, ref) => {
1053
- const editorRef = React10.useRef(null);
1054
- const [internalValue, setInternalValue] = React10.useState(value);
1055
- const prevIsSubmitting = React10.useRef(isSubmitting);
1056
- const hasEmittedReady = React10.useRef(false);
1057
- React10.useEffect(() => {
1564
+ const editorRef = React11.useRef(null);
1565
+ const [internalValue, setInternalValue] = React11.useState(value);
1566
+ const prevIsSubmitting = React11.useRef(isSubmitting);
1567
+ const hasEmittedReady = React11.useRef(false);
1568
+ React11.useEffect(() => {
1058
1569
  setInternalValue(value);
1059
1570
  }, [value]);
1060
- React10.useEffect(() => {
1571
+ React11.useEffect(() => {
1061
1572
  if (autoFocus) {
1062
1573
  requestAnimationFrame(() => {
1063
1574
  requestAnimationFrame(() => {
@@ -1066,7 +1577,7 @@ var UserPromptInput = React10.forwardRef(
1066
1577
  });
1067
1578
  }
1068
1579
  }, [autoFocus]);
1069
- React10.useEffect(() => {
1580
+ React11.useEffect(() => {
1070
1581
  if (!hasEmittedReady.current && onReady) {
1071
1582
  requestAnimationFrame(() => {
1072
1583
  requestAnimationFrame(() => {
@@ -1076,7 +1587,7 @@ var UserPromptInput = React10.forwardRef(
1076
1587
  });
1077
1588
  }
1078
1589
  }, [onReady]);
1079
- React10.useEffect(() => {
1590
+ React11.useEffect(() => {
1080
1591
  if (refocusAfterSubmit && prevIsSubmitting.current && !isSubmitting) {
1081
1592
  requestAnimationFrame(() => {
1082
1593
  editorRef.current?.focus();
@@ -1084,7 +1595,7 @@ var UserPromptInput = React10.forwardRef(
1084
1595
  }
1085
1596
  prevIsSubmitting.current = isSubmitting;
1086
1597
  }, [isSubmitting, refocusAfterSubmit]);
1087
- React10.useImperativeHandle(
1598
+ React11.useImperativeHandle(
1088
1599
  ref,
1089
1600
  () => ({
1090
1601
  focus: () => {
@@ -1107,14 +1618,14 @@ var UserPromptInput = React10.forwardRef(
1107
1618
  }),
1108
1619
  []
1109
1620
  );
1110
- const handleChange = React10.useCallback(
1621
+ const handleChange = React11.useCallback(
1111
1622
  (newValue) => {
1112
1623
  setInternalValue(newValue);
1113
1624
  onChange?.(newValue);
1114
1625
  },
1115
1626
  [onChange]
1116
1627
  );
1117
- const handleSubmit = React10.useCallback(
1628
+ const handleSubmit = React11.useCallback(
1118
1629
  (text) => {
1119
1630
  if (disabled || isSubmitting) return;
1120
1631
  if (!text.trim()) return;
@@ -1126,7 +1637,7 @@ var UserPromptInput = React10.forwardRef(
1126
1637
  },
1127
1638
  [disabled, isSubmitting, onSubmit, clearOnSubmit]
1128
1639
  );
1129
- const handleSendClick = React10.useCallback(() => {
1640
+ const handleSendClick = React11.useCallback(() => {
1130
1641
  const text = editorRef.current?.getText() ?? "";
1131
1642
  handleSubmit(text);
1132
1643
  }, [handleSubmit]);
@@ -1163,16 +1674,17 @@ var UserPromptInput = React10.forwardRef(
1163
1674
  ) }),
1164
1675
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pl-2 pr-1 pb-1 pt-1", children: [
1165
1676
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: renderActions?.() }),
1166
- isSubmitting && onStop ? /* @__PURE__ */ jsx(
1677
+ isSubmitting && onStop ? /* @__PURE__ */ jsx(Tooltip, { content: stopTooltip, disabled: !stopTooltip, children: /* @__PURE__ */ jsx(
1167
1678
  IconButton,
1168
1679
  {
1169
1680
  icon: /* @__PURE__ */ jsx(Square, {}),
1170
1681
  variant: "filled",
1171
1682
  size: "sm",
1172
- "aria-label": "Stop",
1173
- onClick: onStop
1683
+ "aria-label": stopTooltip || "Stop",
1684
+ onClick: onStop,
1685
+ className: stopClassName
1174
1686
  }
1175
- ) : /* @__PURE__ */ jsx(
1687
+ ) }) : /* @__PURE__ */ jsx(
1176
1688
  IconButton,
1177
1689
  {
1178
1690
  icon: isSubmitting ? /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" }) : /* @__PURE__ */ jsx(Send, {}),
@@ -1191,6 +1703,115 @@ var UserPromptInput = React10.forwardRef(
1191
1703
  );
1192
1704
  UserPromptInput.displayName = "UserPromptInput";
1193
1705
 
1194
- export { ActionBar, ActivityIndicators, AgentResponse, HITLInteractionRecord, HITLQuestionPanel, HITLSection, MetadataRow, ThinkingSection, UserPrompt, UserPromptInput, buildResponseString, formatTime, formatTotalTime, initialAgentResponseState, useAgentResponseAccumulator, useThinkingTimer };
1706
+ // src/components/inline-actions/parseResponseSegments.ts
1707
+ var ACTION_BLOCK_REGEX = /```json:action\s*\n([\s\S]*?)```/g;
1708
+ function parseResponseSegments(text) {
1709
+ if (!text) return [];
1710
+ const segments = [];
1711
+ let lastIndex = 0;
1712
+ ACTION_BLOCK_REGEX.lastIndex = 0;
1713
+ let match;
1714
+ while ((match = ACTION_BLOCK_REGEX.exec(text)) !== null) {
1715
+ const before = text.slice(lastIndex, match.index);
1716
+ if (before.trim()) {
1717
+ segments.push({ kind: "markdown", content: before });
1718
+ }
1719
+ const jsonContent = match[1].trim();
1720
+ let parsed = null;
1721
+ try {
1722
+ parsed = JSON.parse(jsonContent);
1723
+ } catch {
1724
+ }
1725
+ if (parsed && typeof parsed === "object" && typeof parsed.type === "string") {
1726
+ segments.push({
1727
+ kind: "action",
1728
+ actionType: parsed.type,
1729
+ payload: parsed
1730
+ });
1731
+ } else {
1732
+ const rawBlock = match[0];
1733
+ segments.push({ kind: "markdown", content: rawBlock });
1734
+ }
1735
+ lastIndex = match.index + match[0].length;
1736
+ }
1737
+ const trailing = text.slice(lastIndex);
1738
+ if (trailing.trim()) {
1739
+ segments.push({ kind: "markdown", content: trailing });
1740
+ }
1741
+ return segments;
1742
+ }
1743
+ function ActionMarkdownRenderer({
1744
+ content,
1745
+ registry,
1746
+ renderMarkdown,
1747
+ onAction,
1748
+ isLatest
1749
+ }) {
1750
+ const segments = useMemo(() => parseResponseSegments(content), [content]);
1751
+ if (segments.length === 1 && segments[0].kind === "markdown") {
1752
+ return /* @__PURE__ */ jsx(Fragment, { children: renderMarkdown(segments[0].content) });
1753
+ }
1754
+ return /* @__PURE__ */ jsx(Fragment, { children: segments.map((segment, index) => {
1755
+ if (segment.kind === "markdown") {
1756
+ return /* @__PURE__ */ jsx("div", { children: renderMarkdown(segment.content) }, `md-${index}`);
1757
+ }
1758
+ const Component = registry[segment.actionType];
1759
+ if (!Component) {
1760
+ return /* @__PURE__ */ jsx(
1761
+ "pre",
1762
+ {
1763
+ className: "my-4 p-4 rounded-lg border border-border bg-muted text-sm font-mono overflow-x-auto",
1764
+ children: /* @__PURE__ */ jsx("code", { children: JSON.stringify(segment.payload, null, 2) })
1765
+ },
1766
+ `action-fallback-${index}`
1767
+ );
1768
+ }
1769
+ return /* @__PURE__ */ jsx(
1770
+ Component,
1771
+ {
1772
+ payload: segment.payload,
1773
+ onAction,
1774
+ isLatest
1775
+ },
1776
+ `action-${segment.actionType}-${index}`
1777
+ );
1778
+ }) });
1779
+ }
1780
+
1781
+ // src/components/inline-actions/prompts.ts
1782
+ var INLINE_ACTION_PROMPT = `
1783
+ <inline_actions>
1784
+ When your response should include interactive components (like query viewers,
1785
+ data tables, or executable actions), embed them as fenced code blocks using
1786
+ the \`json:action\` language tag:
1787
+
1788
+ \`\`\`json:action
1789
+ {
1790
+ "type": "action-type-here",
1791
+ ...action-specific fields
1792
+ }
1793
+ \`\`\`
1794
+
1795
+ Rules:
1796
+ - Each block must contain valid JSON with a "type" field.
1797
+ - The "type" must match a registered action component on the frontend.
1798
+ - Multiple action blocks per response are allowed.
1799
+ - Surround action blocks with normal markdown text for user context.
1800
+ - The action block is rendered as an interactive component in the chat UI.
1801
+ - SQL strings inside JSON must be properly escaped (newlines as \\n, quotes as \\").
1802
+
1803
+ Available action types:
1804
+
1805
+ - "optimap-query": Displays SQL queries with a button to execute them and
1806
+ update the 3D globe map.
1807
+ Required fields:
1808
+ - type: "optimap-query"
1809
+ - locations_sql: string (the validated locations SQL query)
1810
+ - routes_sql: string (the validated routes SQL query)
1811
+ - database_name: string (the target database name)
1812
+ </inline_actions>
1813
+ `;
1814
+
1815
+ 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 };
1195
1816
  //# sourceMappingURL=index.js.map
1196
1817
  //# sourceMappingURL=index.js.map