@optilogic/chat 1.0.0-beta.10 → 1.0.0-beta.11
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 +575 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +207 -2
- package/dist/index.d.ts +207 -2
- package/dist/index.js +569 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/agent-response/AgentResponse.tsx +31 -13
- package/src/components/agent-response/components/ThinkingSection.tsx +1 -1
- package/src/components/agent-response/hooks/useAgentResponseAccumulator.ts +42 -8
- package/src/components/agent-response/index.ts +16 -0
- package/src/components/agent-response/types.ts +42 -0
- package/src/components/agent-timeline/AgentTimeline.tsx +256 -0
- package/src/components/agent-timeline/TimelineAgentBlock.tsx +84 -0
- package/src/components/agent-timeline/TimelineItem.tsx +97 -0
- package/src/components/agent-timeline/index.ts +14 -0
- package/src/components/agent-timeline/types.ts +49 -0
- package/src/components/agent-timeline/utils.ts +167 -0
- package/src/components/hitl-interactions/HITLQuestionPanel.tsx +9 -2
- package/src/components/hitl-interactions/index.ts +1 -1
- package/src/components/inline-actions/ActionMarkdownRenderer.tsx +60 -0
- package/src/components/inline-actions/index.ts +18 -0
- package/src/components/inline-actions/parseResponseSegments.ts +66 -0
- package/src/components/inline-actions/prompts.ts +41 -0
- package/src/components/inline-actions/types.ts +57 -0
- package/src/index.ts +26 -0
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) => {
|
|
@@ -684,6 +684,126 @@ var initialAgentResponseState = {
|
|
|
684
684
|
firstMessageTime: null
|
|
685
685
|
};
|
|
686
686
|
|
|
687
|
+
// src/components/agent-timeline/utils.ts
|
|
688
|
+
function buildTimelineEntries(state) {
|
|
689
|
+
const entries = [];
|
|
690
|
+
if (state.thinkingSteps) {
|
|
691
|
+
let idx = 0;
|
|
692
|
+
for (const step of state.thinkingSteps) {
|
|
693
|
+
entries.push({
|
|
694
|
+
id: `tl-think-${idx++}`,
|
|
695
|
+
type: "thinking",
|
|
696
|
+
agentName: step.agentName ?? null,
|
|
697
|
+
parentAgent: step.parentAgent ?? null,
|
|
698
|
+
depth: step.depth ?? 0,
|
|
699
|
+
content: step.content,
|
|
700
|
+
title: step.label,
|
|
701
|
+
timestamp: step.timestamp ?? 0
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
} else if (state.thinking) {
|
|
705
|
+
entries.push({
|
|
706
|
+
id: "tl-think-0",
|
|
707
|
+
type: "thinking",
|
|
708
|
+
agentName: null,
|
|
709
|
+
parentAgent: null,
|
|
710
|
+
depth: 0,
|
|
711
|
+
content: state.thinking,
|
|
712
|
+
title: null,
|
|
713
|
+
timestamp: state.thinkingStartTime ?? 0
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
let toolIdx = 0;
|
|
717
|
+
for (const tool of state.toolCalls) {
|
|
718
|
+
entries.push({
|
|
719
|
+
id: `tl-tool-${toolIdx++}`,
|
|
720
|
+
type: "tool_call",
|
|
721
|
+
agentName: tool.agentName ?? null,
|
|
722
|
+
parentAgent: tool.parentAgent ?? null,
|
|
723
|
+
depth: tool.depth ?? 0,
|
|
724
|
+
content: tool.name,
|
|
725
|
+
title: null,
|
|
726
|
+
timestamp: tool.timestamp
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
let knowIdx = 0;
|
|
730
|
+
for (const item of state.knowledge) {
|
|
731
|
+
entries.push({
|
|
732
|
+
id: `tl-know-${knowIdx++}`,
|
|
733
|
+
type: "knowledge",
|
|
734
|
+
agentName: item.agentName ?? null,
|
|
735
|
+
parentAgent: item.parentAgent ?? null,
|
|
736
|
+
depth: item.depth ?? 0,
|
|
737
|
+
content: item.content,
|
|
738
|
+
title: item.source,
|
|
739
|
+
timestamp: item.timestamp
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
let memIdx = 0;
|
|
743
|
+
for (const item of state.memory) {
|
|
744
|
+
entries.push({
|
|
745
|
+
id: `tl-mem-${memIdx++}`,
|
|
746
|
+
type: "memory",
|
|
747
|
+
agentName: item.agentName ?? null,
|
|
748
|
+
parentAgent: item.parentAgent ?? null,
|
|
749
|
+
depth: item.depth ?? 0,
|
|
750
|
+
content: item.content,
|
|
751
|
+
title: item.type,
|
|
752
|
+
timestamp: item.timestamp
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
let statIdx = 0;
|
|
756
|
+
for (const item of state.statusUpdates) {
|
|
757
|
+
entries.push({
|
|
758
|
+
id: `tl-stat-${statIdx++}`,
|
|
759
|
+
type: "status_update",
|
|
760
|
+
agentName: item.agentName ?? item.agent ?? null,
|
|
761
|
+
parentAgent: item.parentAgent ?? null,
|
|
762
|
+
depth: item.depth ?? 0,
|
|
763
|
+
content: item.message,
|
|
764
|
+
title: null,
|
|
765
|
+
timestamp: item.timestamp
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
entries.sort((a, b) => a.timestamp - b.timestamp);
|
|
769
|
+
return entries;
|
|
770
|
+
}
|
|
771
|
+
function groupIntoAgentRuns(entries) {
|
|
772
|
+
const runs = [];
|
|
773
|
+
let currentRun = null;
|
|
774
|
+
for (const entry of entries) {
|
|
775
|
+
const name = entry.agentName || "Agent";
|
|
776
|
+
if (!currentRun || currentRun.agentName !== name) {
|
|
777
|
+
currentRun = {
|
|
778
|
+
agentName: name,
|
|
779
|
+
parentAgent: entry.parentAgent,
|
|
780
|
+
depth: entry.depth,
|
|
781
|
+
entries: []
|
|
782
|
+
};
|
|
783
|
+
runs.push(currentRun);
|
|
784
|
+
}
|
|
785
|
+
currentRun.entries.push({ entry, count: 1 });
|
|
786
|
+
}
|
|
787
|
+
for (const run of runs) {
|
|
788
|
+
run.entries = deduplicateEntries(run.entries);
|
|
789
|
+
}
|
|
790
|
+
return runs;
|
|
791
|
+
}
|
|
792
|
+
function deduplicateEntries(entries) {
|
|
793
|
+
if (entries.length === 0) return [];
|
|
794
|
+
const result = [entries[0]];
|
|
795
|
+
for (let i = 1; i < entries.length; i++) {
|
|
796
|
+
const prev = result[result.length - 1];
|
|
797
|
+
const curr = entries[i];
|
|
798
|
+
if (prev.entry.type === curr.entry.type && prev.entry.content === curr.entry.content) {
|
|
799
|
+
prev.count += curr.count;
|
|
800
|
+
} else {
|
|
801
|
+
result.push({ ...curr });
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return result;
|
|
805
|
+
}
|
|
806
|
+
|
|
687
807
|
// src/components/agent-response/hooks/useAgentResponseAccumulator.ts
|
|
688
808
|
function useAgentResponseAccumulator(options) {
|
|
689
809
|
const [state, setState] = useState(initialAgentResponseState);
|
|
@@ -717,28 +837,44 @@ function useAgentResponseAccumulator(options) {
|
|
|
717
837
|
id: payload.thinkingStep.id || `step-${Date.now()}`,
|
|
718
838
|
label: payload.thinkingStep.label,
|
|
719
839
|
content: payload.thinkingStep.content,
|
|
720
|
-
depth: payload.thinkingStep.depth ?? 0,
|
|
721
|
-
isCollapsed: payload.thinkingStep.isCollapsed
|
|
840
|
+
depth: payload.thinkingStep.depth ?? payload.depth ?? 0,
|
|
841
|
+
isCollapsed: payload.thinkingStep.isCollapsed,
|
|
842
|
+
timestamp: Date.now(),
|
|
843
|
+
agentName: payload.agentName,
|
|
844
|
+
parentAgent: payload.parentAgent
|
|
722
845
|
};
|
|
723
846
|
const thinkingStartTime2 = prev.thinkingStartTime ?? Date.now();
|
|
724
|
-
|
|
847
|
+
const next2 = {
|
|
725
848
|
...prev,
|
|
726
849
|
status: newStatus,
|
|
727
850
|
thinkingSteps: [...prev.thinkingSteps || [], newStep],
|
|
728
851
|
thinkingStartTime: thinkingStartTime2,
|
|
729
852
|
firstMessageTime
|
|
730
853
|
};
|
|
854
|
+
return { ...next2, timelineEntries: buildTimelineEntries(next2) };
|
|
731
855
|
}
|
|
732
856
|
const newThinking = payload.message || payload.content || "";
|
|
733
857
|
const separator = prev.thinking && newThinking ? "\n\n" : "";
|
|
734
858
|
const thinkingStartTime = prev.thinkingStartTime ?? (newThinking ? Date.now() : null);
|
|
735
|
-
|
|
859
|
+
const prevSteps = prev.thinkingSteps || [];
|
|
860
|
+
const plainStep = {
|
|
861
|
+
id: `step-${prevSteps.length}`,
|
|
862
|
+
label: newThinking,
|
|
863
|
+
content: newThinking,
|
|
864
|
+
depth: payload.depth ?? 0,
|
|
865
|
+
timestamp: Date.now(),
|
|
866
|
+
agentName: payload.agentName,
|
|
867
|
+
parentAgent: payload.parentAgent
|
|
868
|
+
};
|
|
869
|
+
const next = {
|
|
736
870
|
...prev,
|
|
737
871
|
status: newStatus,
|
|
738
872
|
thinking: prev.thinking + separator + newThinking,
|
|
873
|
+
thinkingSteps: [...prevSteps, plainStep],
|
|
739
874
|
thinkingStartTime,
|
|
740
875
|
firstMessageTime
|
|
741
876
|
};
|
|
877
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
742
878
|
}
|
|
743
879
|
case "tool_call": {
|
|
744
880
|
const toolName = payload.message || payload.tool?.name;
|
|
@@ -747,14 +883,18 @@ function useAgentResponseAccumulator(options) {
|
|
|
747
883
|
id: payload.tool?.id || `tool-${Date.now()}`,
|
|
748
884
|
name: toolName,
|
|
749
885
|
arguments: payload.tool?.arguments,
|
|
750
|
-
timestamp: Date.now()
|
|
886
|
+
timestamp: Date.now(),
|
|
887
|
+
agentName: payload.agentName,
|
|
888
|
+
parentAgent: payload.parentAgent,
|
|
889
|
+
depth: payload.depth
|
|
751
890
|
};
|
|
752
|
-
|
|
891
|
+
const next = {
|
|
753
892
|
...prev,
|
|
754
893
|
status: newStatus,
|
|
755
894
|
toolCalls: [...prev.toolCalls, newToolCall],
|
|
756
895
|
firstMessageTime
|
|
757
896
|
};
|
|
897
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
758
898
|
}
|
|
759
899
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
760
900
|
}
|
|
@@ -765,14 +905,18 @@ function useAgentResponseAccumulator(options) {
|
|
|
765
905
|
id: payload.knowledge?.id || `knowledge-${Date.now()}`,
|
|
766
906
|
source: payload.knowledge?.source || "unknown",
|
|
767
907
|
content: knowledgeContent,
|
|
768
|
-
timestamp: Date.now()
|
|
908
|
+
timestamp: Date.now(),
|
|
909
|
+
agentName: payload.agentName,
|
|
910
|
+
parentAgent: payload.parentAgent,
|
|
911
|
+
depth: payload.depth
|
|
769
912
|
};
|
|
770
|
-
|
|
913
|
+
const next = {
|
|
771
914
|
...prev,
|
|
772
915
|
status: newStatus,
|
|
773
916
|
knowledge: [...prev.knowledge, newKnowledge],
|
|
774
917
|
firstMessageTime
|
|
775
918
|
};
|
|
919
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
776
920
|
}
|
|
777
921
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
778
922
|
}
|
|
@@ -783,14 +927,18 @@ function useAgentResponseAccumulator(options) {
|
|
|
783
927
|
id: payload.memory?.id || `memory-${Date.now()}`,
|
|
784
928
|
type: payload.memory?.type || "unknown",
|
|
785
929
|
content: memoryContent,
|
|
786
|
-
timestamp: Date.now()
|
|
930
|
+
timestamp: Date.now(),
|
|
931
|
+
agentName: payload.agentName,
|
|
932
|
+
parentAgent: payload.parentAgent,
|
|
933
|
+
depth: payload.depth
|
|
787
934
|
};
|
|
788
|
-
|
|
935
|
+
const next = {
|
|
789
936
|
...prev,
|
|
790
937
|
status: newStatus,
|
|
791
938
|
memory: [...prev.memory, newMemory],
|
|
792
939
|
firstMessageTime
|
|
793
940
|
};
|
|
941
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
794
942
|
}
|
|
795
943
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
796
944
|
}
|
|
@@ -809,14 +957,18 @@ function useAgentResponseAccumulator(options) {
|
|
|
809
957
|
id: payload.statusUpdate?.id || `status-${Date.now()}`,
|
|
810
958
|
message: statusMessage,
|
|
811
959
|
agent: payload.statusUpdate?.agent,
|
|
812
|
-
timestamp: Date.now()
|
|
960
|
+
timestamp: Date.now(),
|
|
961
|
+
agentName: payload.agentName,
|
|
962
|
+
parentAgent: payload.parentAgent,
|
|
963
|
+
depth: payload.depth
|
|
813
964
|
};
|
|
814
|
-
|
|
965
|
+
const next = {
|
|
815
966
|
...prev,
|
|
816
967
|
status: newStatus,
|
|
817
968
|
statusUpdates: [...prev.statusUpdates, newStatusItem],
|
|
818
969
|
firstMessageTime
|
|
819
970
|
};
|
|
971
|
+
return { ...next, timelineEntries: buildTimelineEntries(next) };
|
|
820
972
|
}
|
|
821
973
|
return { ...prev, status: newStatus, firstMessageTime };
|
|
822
974
|
}
|
|
@@ -832,6 +984,287 @@ function useAgentResponseAccumulator(options) {
|
|
|
832
984
|
}, []);
|
|
833
985
|
return { state, handleMessage, reset };
|
|
834
986
|
}
|
|
987
|
+
var ICON_MAP = {
|
|
988
|
+
thinking: Brain,
|
|
989
|
+
tool_call: Wrench,
|
|
990
|
+
knowledge: BookOpen,
|
|
991
|
+
memory: HardDrive,
|
|
992
|
+
status_update: Activity,
|
|
993
|
+
ai_response: MessageSquare,
|
|
994
|
+
error: AlertCircle
|
|
995
|
+
};
|
|
996
|
+
function TimelineItem({
|
|
997
|
+
displayEntry,
|
|
998
|
+
renderMarkdown,
|
|
999
|
+
isExpanded,
|
|
1000
|
+
onToggleExpanded
|
|
1001
|
+
}) {
|
|
1002
|
+
const { entry, count } = displayEntry;
|
|
1003
|
+
const Icon = ICON_MAP[entry.type] ?? Activity;
|
|
1004
|
+
const isLong = entry.content.length > 200 || entry.content.split("\n").length > 3;
|
|
1005
|
+
const canExpand = isLong || entry.type === "ai_response";
|
|
1006
|
+
return /* @__PURE__ */ jsxs("div", { className: "py-1 flex items-start gap-2 group", children: [
|
|
1007
|
+
/* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5 text-muted-foreground flex-shrink-0 mt-0.5" }),
|
|
1008
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: isExpanded && entry.type === "ai_response" && renderMarkdown ? (
|
|
1009
|
+
// Expanded AI response: rendered markdown
|
|
1010
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1011
|
+
renderMarkdown(entry.content),
|
|
1012
|
+
/* @__PURE__ */ jsx(
|
|
1013
|
+
"button",
|
|
1014
|
+
{
|
|
1015
|
+
onClick: onToggleExpanded,
|
|
1016
|
+
className: "text-[10px] text-muted-foreground/70 hover:text-muted-foreground mt-1",
|
|
1017
|
+
children: "Show less"
|
|
1018
|
+
}
|
|
1019
|
+
)
|
|
1020
|
+
] })
|
|
1021
|
+
) : isExpanded ? (
|
|
1022
|
+
// Expanded non-AI: plain text
|
|
1023
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1024
|
+
/* @__PURE__ */ jsx("pre", { className: "text-xs text-muted-foreground whitespace-pre-wrap font-mono", children: entry.content }),
|
|
1025
|
+
/* @__PURE__ */ jsx(
|
|
1026
|
+
"button",
|
|
1027
|
+
{
|
|
1028
|
+
onClick: onToggleExpanded,
|
|
1029
|
+
className: "text-[10px] text-muted-foreground/70 hover:text-muted-foreground mt-1",
|
|
1030
|
+
children: "Show less"
|
|
1031
|
+
}
|
|
1032
|
+
)
|
|
1033
|
+
] })
|
|
1034
|
+
) : (
|
|
1035
|
+
// Collapsed: truncated with optional expand
|
|
1036
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1.5 min-w-0", children: [
|
|
1037
|
+
/* @__PURE__ */ jsx(
|
|
1038
|
+
"div",
|
|
1039
|
+
{
|
|
1040
|
+
className: `text-xs text-muted-foreground min-w-0 ${canExpand ? "line-clamp-2 cursor-pointer hover:text-foreground/80" : ""}`,
|
|
1041
|
+
onClick: canExpand ? onToggleExpanded : void 0,
|
|
1042
|
+
children: entry.content
|
|
1043
|
+
}
|
|
1044
|
+
),
|
|
1045
|
+
count > 1 && /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground/60 whitespace-nowrap flex-shrink-0", children: [
|
|
1046
|
+
"(x",
|
|
1047
|
+
count,
|
|
1048
|
+
")"
|
|
1049
|
+
] })
|
|
1050
|
+
] })
|
|
1051
|
+
) })
|
|
1052
|
+
] });
|
|
1053
|
+
}
|
|
1054
|
+
function TimelineAgentBlock({
|
|
1055
|
+
block,
|
|
1056
|
+
renderMarkdown,
|
|
1057
|
+
isSingleAgent,
|
|
1058
|
+
isCollapsed,
|
|
1059
|
+
onToggleCollapsed,
|
|
1060
|
+
expandedItems,
|
|
1061
|
+
onToggleItemExpanded
|
|
1062
|
+
}) {
|
|
1063
|
+
const indentPx = block.depth * 16;
|
|
1064
|
+
if (isSingleAgent && block.depth === 0) {
|
|
1065
|
+
return /* @__PURE__ */ jsx("div", { style: { paddingLeft: `${indentPx}px` }, children: block.entries.map((displayEntry, i) => /* @__PURE__ */ jsx(
|
|
1066
|
+
TimelineItem,
|
|
1067
|
+
{
|
|
1068
|
+
displayEntry,
|
|
1069
|
+
renderMarkdown,
|
|
1070
|
+
isExpanded: expandedItems.has(displayEntry.entry.id),
|
|
1071
|
+
onToggleExpanded: () => onToggleItemExpanded(displayEntry.entry.id)
|
|
1072
|
+
},
|
|
1073
|
+
displayEntry.entry.id + "-" + i
|
|
1074
|
+
)) });
|
|
1075
|
+
}
|
|
1076
|
+
return /* @__PURE__ */ jsxs("div", { style: { paddingLeft: `${indentPx}px` }, children: [
|
|
1077
|
+
/* @__PURE__ */ jsxs(
|
|
1078
|
+
"button",
|
|
1079
|
+
{
|
|
1080
|
+
onClick: onToggleCollapsed,
|
|
1081
|
+
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",
|
|
1082
|
+
children: [
|
|
1083
|
+
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" }),
|
|
1084
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-foreground/80", children: block.agentName }),
|
|
1085
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground/60", children: [
|
|
1086
|
+
"(",
|
|
1087
|
+
block.entries.reduce((sum, e) => sum + e.count, 0),
|
|
1088
|
+
")"
|
|
1089
|
+
] })
|
|
1090
|
+
]
|
|
1091
|
+
}
|
|
1092
|
+
),
|
|
1093
|
+
!isCollapsed && /* @__PURE__ */ jsx("div", { className: "ml-4", children: block.entries.map((displayEntry, i) => /* @__PURE__ */ jsx(
|
|
1094
|
+
TimelineItem,
|
|
1095
|
+
{
|
|
1096
|
+
displayEntry,
|
|
1097
|
+
renderMarkdown,
|
|
1098
|
+
isExpanded: expandedItems.has(displayEntry.entry.id),
|
|
1099
|
+
onToggleExpanded: () => onToggleItemExpanded(displayEntry.entry.id)
|
|
1100
|
+
},
|
|
1101
|
+
displayEntry.entry.id + "-" + i
|
|
1102
|
+
)) })
|
|
1103
|
+
] });
|
|
1104
|
+
}
|
|
1105
|
+
function createTimelineUIState() {
|
|
1106
|
+
return {
|
|
1107
|
+
expandedItems: /* @__PURE__ */ new Set(),
|
|
1108
|
+
collapsedRuns: /* @__PURE__ */ new Set(),
|
|
1109
|
+
activeFilters: /* @__PURE__ */ new Set()
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
var TYPE_CONFIG = [
|
|
1113
|
+
{ type: "status_update", icon: Activity, label: "Status" },
|
|
1114
|
+
{ type: "thinking", icon: Brain, label: "Thinking" },
|
|
1115
|
+
{ type: "tool_call", icon: Wrench, label: "Tools" },
|
|
1116
|
+
{ type: "knowledge", icon: BookOpen, label: "Knowledge" },
|
|
1117
|
+
{ type: "memory", icon: HardDrive, label: "Memory" },
|
|
1118
|
+
{ type: "ai_response", icon: MessageSquare, label: "AI" },
|
|
1119
|
+
{ type: "error", icon: AlertCircle, label: "Errors" }
|
|
1120
|
+
];
|
|
1121
|
+
function AgentTimeline({ entries, renderMarkdown, uiState, maxHeight = "300px" }) {
|
|
1122
|
+
const containerRef = useRef(null);
|
|
1123
|
+
const [renderTick, setRenderTick] = useState(0);
|
|
1124
|
+
const forceRender = useCallback(() => setRenderTick((t) => t + 1), []);
|
|
1125
|
+
const [internalExpandedItems] = useState(() => /* @__PURE__ */ new Set());
|
|
1126
|
+
const [internalCollapsedRuns] = useState(() => /* @__PURE__ */ new Set());
|
|
1127
|
+
const [internalActiveFilters] = useState(() => /* @__PURE__ */ new Set());
|
|
1128
|
+
const expandedItems = uiState?.expandedItems ?? internalExpandedItems;
|
|
1129
|
+
const collapsedRuns = uiState?.collapsedRuns ?? internalCollapsedRuns;
|
|
1130
|
+
const activeFilters = uiState?.activeFilters ?? internalActiveFilters;
|
|
1131
|
+
const availableTypes = useMemo(() => {
|
|
1132
|
+
const types = /* @__PURE__ */ new Set();
|
|
1133
|
+
for (const entry of entries) {
|
|
1134
|
+
types.add(entry.type);
|
|
1135
|
+
}
|
|
1136
|
+
return types;
|
|
1137
|
+
}, [entries]);
|
|
1138
|
+
const filteredEntries = useMemo(
|
|
1139
|
+
() => activeFilters.size === 0 ? entries : entries.filter((e) => activeFilters.has(e.type)),
|
|
1140
|
+
[entries, activeFilters, renderTick]
|
|
1141
|
+
);
|
|
1142
|
+
const agentRuns = useMemo(() => groupIntoAgentRuns(filteredEntries), [filteredEntries, renderTick]);
|
|
1143
|
+
const toggleFilter = useCallback((type) => {
|
|
1144
|
+
if (activeFilters.has(type)) {
|
|
1145
|
+
activeFilters.delete(type);
|
|
1146
|
+
} else {
|
|
1147
|
+
activeFilters.add(type);
|
|
1148
|
+
}
|
|
1149
|
+
forceRender();
|
|
1150
|
+
}, [activeFilters, forceRender]);
|
|
1151
|
+
const clearFilters = useCallback(() => {
|
|
1152
|
+
activeFilters.clear();
|
|
1153
|
+
forceRender();
|
|
1154
|
+
}, [activeFilters, forceRender]);
|
|
1155
|
+
const toggleItemExpanded = useCallback((entryId) => {
|
|
1156
|
+
if (expandedItems.has(entryId)) {
|
|
1157
|
+
expandedItems.delete(entryId);
|
|
1158
|
+
} else {
|
|
1159
|
+
expandedItems.add(entryId);
|
|
1160
|
+
}
|
|
1161
|
+
forceRender();
|
|
1162
|
+
}, [expandedItems, forceRender]);
|
|
1163
|
+
const collapseAll = useCallback(() => {
|
|
1164
|
+
collapsedRuns.clear();
|
|
1165
|
+
agentRuns.forEach((run, i) => {
|
|
1166
|
+
collapsedRuns.add(`${run.agentName}-${i}`);
|
|
1167
|
+
});
|
|
1168
|
+
expandedItems.clear();
|
|
1169
|
+
forceRender();
|
|
1170
|
+
}, [agentRuns, collapsedRuns, expandedItems, forceRender]);
|
|
1171
|
+
const expandAll = useCallback(() => {
|
|
1172
|
+
collapsedRuns.clear();
|
|
1173
|
+
agentRuns.forEach((run, i) => {
|
|
1174
|
+
collapsedRuns.add(`${run.agentName}-${i}:expanded`);
|
|
1175
|
+
});
|
|
1176
|
+
forceRender();
|
|
1177
|
+
}, [agentRuns, collapsedRuns, forceRender]);
|
|
1178
|
+
if (entries.length === 0) return null;
|
|
1179
|
+
const isSingle = agentRuns.length === 1;
|
|
1180
|
+
const hasActiveFilter = activeFilters.size > 0;
|
|
1181
|
+
const scrollStyle = maxHeight !== "none" ? { maxHeight } : void 0;
|
|
1182
|
+
return /* @__PURE__ */ jsxs(
|
|
1183
|
+
"div",
|
|
1184
|
+
{
|
|
1185
|
+
ref: containerRef,
|
|
1186
|
+
className: `-mt-1 ${maxHeight !== "none" ? "overflow-y-auto scrollbar-thin" : ""}`,
|
|
1187
|
+
style: scrollStyle,
|
|
1188
|
+
children: [
|
|
1189
|
+
/* @__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: [
|
|
1190
|
+
TYPE_CONFIG.filter((tc) => availableTypes.has(tc.type)).map((tc) => {
|
|
1191
|
+
const isActive = activeFilters.has(tc.type);
|
|
1192
|
+
const count = entries.filter((e) => e.type === tc.type).length;
|
|
1193
|
+
return /* @__PURE__ */ jsxs(
|
|
1194
|
+
"button",
|
|
1195
|
+
{
|
|
1196
|
+
onClick: () => toggleFilter(tc.type),
|
|
1197
|
+
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"}`,
|
|
1198
|
+
title: `${isActive ? "Hide" : "Show only"} ${tc.label}`,
|
|
1199
|
+
children: [
|
|
1200
|
+
/* @__PURE__ */ jsx(tc.icon, { className: "w-3 h-3" }),
|
|
1201
|
+
/* @__PURE__ */ jsx("span", { children: count })
|
|
1202
|
+
]
|
|
1203
|
+
},
|
|
1204
|
+
tc.type
|
|
1205
|
+
);
|
|
1206
|
+
}),
|
|
1207
|
+
hasActiveFilter && /* @__PURE__ */ jsx(
|
|
1208
|
+
"button",
|
|
1209
|
+
{
|
|
1210
|
+
onClick: clearFilters,
|
|
1211
|
+
className: "text-[10px] text-muted-foreground/60 hover:text-muted-foreground px-1",
|
|
1212
|
+
children: "Clear"
|
|
1213
|
+
}
|
|
1214
|
+
),
|
|
1215
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
1216
|
+
!isSingle && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1217
|
+
/* @__PURE__ */ jsx(
|
|
1218
|
+
"button",
|
|
1219
|
+
{
|
|
1220
|
+
onClick: collapseAll,
|
|
1221
|
+
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",
|
|
1222
|
+
title: "Collapse all",
|
|
1223
|
+
children: /* @__PURE__ */ jsx(ChevronsDownUp, { className: "w-3 h-3" })
|
|
1224
|
+
}
|
|
1225
|
+
),
|
|
1226
|
+
/* @__PURE__ */ jsx(
|
|
1227
|
+
"button",
|
|
1228
|
+
{
|
|
1229
|
+
onClick: expandAll,
|
|
1230
|
+
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",
|
|
1231
|
+
title: "Expand all",
|
|
1232
|
+
children: /* @__PURE__ */ jsx(ChevronsUpDown, { className: "w-3 h-3" })
|
|
1233
|
+
}
|
|
1234
|
+
)
|
|
1235
|
+
] })
|
|
1236
|
+
] }),
|
|
1237
|
+
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) => {
|
|
1238
|
+
const runKey = `${run.agentName}-${i}`;
|
|
1239
|
+
const defaultCollapsed = run.depth > 0;
|
|
1240
|
+
const isCollapsed = collapsedRuns.has(runKey) ? true : collapsedRuns.has(`${runKey}:expanded`) ? false : defaultCollapsed;
|
|
1241
|
+
return /* @__PURE__ */ jsx(
|
|
1242
|
+
TimelineAgentBlock,
|
|
1243
|
+
{
|
|
1244
|
+
block: run,
|
|
1245
|
+
renderMarkdown,
|
|
1246
|
+
isSingleAgent: isSingle,
|
|
1247
|
+
isCollapsed,
|
|
1248
|
+
onToggleCollapsed: () => {
|
|
1249
|
+
if (isCollapsed) {
|
|
1250
|
+
collapsedRuns.delete(runKey);
|
|
1251
|
+
collapsedRuns.add(`${runKey}:expanded`);
|
|
1252
|
+
} else {
|
|
1253
|
+
collapsedRuns.delete(`${runKey}:expanded`);
|
|
1254
|
+
collapsedRuns.add(runKey);
|
|
1255
|
+
}
|
|
1256
|
+
forceRender();
|
|
1257
|
+
},
|
|
1258
|
+
expandedItems,
|
|
1259
|
+
onToggleItemExpanded: toggleItemExpanded
|
|
1260
|
+
},
|
|
1261
|
+
runKey
|
|
1262
|
+
);
|
|
1263
|
+
}) })
|
|
1264
|
+
]
|
|
1265
|
+
}
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
835
1268
|
var AgentResponse = React11.forwardRef(
|
|
836
1269
|
({
|
|
837
1270
|
state,
|
|
@@ -852,6 +1285,7 @@ var AgentResponse = React11.forwardRef(
|
|
|
852
1285
|
className,
|
|
853
1286
|
...props
|
|
854
1287
|
}, ref) => {
|
|
1288
|
+
const timelineUIStateRef = useRef(createTimelineUIState());
|
|
855
1289
|
const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultThinkingExpanded);
|
|
856
1290
|
const isThinkingControlled = controlledThinkingExpanded !== void 0;
|
|
857
1291
|
const thinkingExpanded = isThinkingControlled ? controlledThinkingExpanded : uncontrolledExpanded;
|
|
@@ -873,7 +1307,8 @@ var AgentResponse = React11.forwardRef(
|
|
|
873
1307
|
if (!state.firstMessageTime || !state.responseCompleteTime) return 0;
|
|
874
1308
|
return (state.responseCompleteTime - state.firstMessageTime) / 1e3;
|
|
875
1309
|
}, [state.firstMessageTime, state.responseCompleteTime]);
|
|
876
|
-
const
|
|
1310
|
+
const hasTimelineEntries = !!(state.timelineEntries && state.timelineEntries.length > 0);
|
|
1311
|
+
const hasThinkingContent = !!state.thinking || state.thinkingSteps && state.thinkingSteps.length > 0 || hasTimelineEntries || false;
|
|
877
1312
|
const hasHITLInteractions = hitlInteractions && hitlInteractions.length > 0;
|
|
878
1313
|
const hasAnyContent = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || hasHITLInteractions || state.response;
|
|
879
1314
|
const showMetadataRow = hasThinkingContent || state.toolCalls.length > 0 || state.knowledge.length > 0 || state.memory.length > 0 || state.statusUpdates.length > 0 || state.status === "processing";
|
|
@@ -908,7 +1343,14 @@ var AgentResponse = React11.forwardRef(
|
|
|
908
1343
|
elapsedTime
|
|
909
1344
|
}
|
|
910
1345
|
),
|
|
911
|
-
/* @__PURE__ */ jsx(
|
|
1346
|
+
hasTimelineEntries ? thinkingExpanded && /* @__PURE__ */ jsx("div", { className: "px-3 pb-3 border-t border-border mt-2", children: /* @__PURE__ */ jsx(
|
|
1347
|
+
AgentTimeline,
|
|
1348
|
+
{
|
|
1349
|
+
entries: state.timelineEntries,
|
|
1350
|
+
renderMarkdown: renderThinkingMarkdown,
|
|
1351
|
+
uiState: timelineUIStateRef.current
|
|
1352
|
+
}
|
|
1353
|
+
) }) : /* @__PURE__ */ jsx(
|
|
912
1354
|
ThinkingSection,
|
|
913
1355
|
{
|
|
914
1356
|
content: state.thinkingSteps && state.thinkingSteps.length > 0 ? state.thinkingSteps : state.thinking,
|
|
@@ -1215,6 +1657,115 @@ var UserPromptInput = React11.forwardRef(
|
|
|
1215
1657
|
);
|
|
1216
1658
|
UserPromptInput.displayName = "UserPromptInput";
|
|
1217
1659
|
|
|
1218
|
-
|
|
1660
|
+
// src/components/inline-actions/parseResponseSegments.ts
|
|
1661
|
+
var ACTION_BLOCK_REGEX = /```json:action\s*\n([\s\S]*?)```/g;
|
|
1662
|
+
function parseResponseSegments(text) {
|
|
1663
|
+
if (!text) return [];
|
|
1664
|
+
const segments = [];
|
|
1665
|
+
let lastIndex = 0;
|
|
1666
|
+
ACTION_BLOCK_REGEX.lastIndex = 0;
|
|
1667
|
+
let match;
|
|
1668
|
+
while ((match = ACTION_BLOCK_REGEX.exec(text)) !== null) {
|
|
1669
|
+
const before = text.slice(lastIndex, match.index);
|
|
1670
|
+
if (before.trim()) {
|
|
1671
|
+
segments.push({ kind: "markdown", content: before });
|
|
1672
|
+
}
|
|
1673
|
+
const jsonContent = match[1].trim();
|
|
1674
|
+
let parsed = null;
|
|
1675
|
+
try {
|
|
1676
|
+
parsed = JSON.parse(jsonContent);
|
|
1677
|
+
} catch {
|
|
1678
|
+
}
|
|
1679
|
+
if (parsed && typeof parsed === "object" && typeof parsed.type === "string") {
|
|
1680
|
+
segments.push({
|
|
1681
|
+
kind: "action",
|
|
1682
|
+
actionType: parsed.type,
|
|
1683
|
+
payload: parsed
|
|
1684
|
+
});
|
|
1685
|
+
} else {
|
|
1686
|
+
const rawBlock = match[0];
|
|
1687
|
+
segments.push({ kind: "markdown", content: rawBlock });
|
|
1688
|
+
}
|
|
1689
|
+
lastIndex = match.index + match[0].length;
|
|
1690
|
+
}
|
|
1691
|
+
const trailing = text.slice(lastIndex);
|
|
1692
|
+
if (trailing.trim()) {
|
|
1693
|
+
segments.push({ kind: "markdown", content: trailing });
|
|
1694
|
+
}
|
|
1695
|
+
return segments;
|
|
1696
|
+
}
|
|
1697
|
+
function ActionMarkdownRenderer({
|
|
1698
|
+
content,
|
|
1699
|
+
registry,
|
|
1700
|
+
renderMarkdown,
|
|
1701
|
+
onAction,
|
|
1702
|
+
isLatest
|
|
1703
|
+
}) {
|
|
1704
|
+
const segments = useMemo(() => parseResponseSegments(content), [content]);
|
|
1705
|
+
if (segments.length === 1 && segments[0].kind === "markdown") {
|
|
1706
|
+
return /* @__PURE__ */ jsx(Fragment, { children: renderMarkdown(segments[0].content) });
|
|
1707
|
+
}
|
|
1708
|
+
return /* @__PURE__ */ jsx(Fragment, { children: segments.map((segment, index) => {
|
|
1709
|
+
if (segment.kind === "markdown") {
|
|
1710
|
+
return /* @__PURE__ */ jsx("div", { children: renderMarkdown(segment.content) }, `md-${index}`);
|
|
1711
|
+
}
|
|
1712
|
+
const Component = registry[segment.actionType];
|
|
1713
|
+
if (!Component) {
|
|
1714
|
+
return /* @__PURE__ */ jsx(
|
|
1715
|
+
"pre",
|
|
1716
|
+
{
|
|
1717
|
+
className: "my-4 p-4 rounded-lg border border-border bg-muted text-sm font-mono overflow-x-auto",
|
|
1718
|
+
children: /* @__PURE__ */ jsx("code", { children: JSON.stringify(segment.payload, null, 2) })
|
|
1719
|
+
},
|
|
1720
|
+
`action-fallback-${index}`
|
|
1721
|
+
);
|
|
1722
|
+
}
|
|
1723
|
+
return /* @__PURE__ */ jsx(
|
|
1724
|
+
Component,
|
|
1725
|
+
{
|
|
1726
|
+
payload: segment.payload,
|
|
1727
|
+
onAction,
|
|
1728
|
+
isLatest
|
|
1729
|
+
},
|
|
1730
|
+
`action-${segment.actionType}-${index}`
|
|
1731
|
+
);
|
|
1732
|
+
}) });
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
// src/components/inline-actions/prompts.ts
|
|
1736
|
+
var INLINE_ACTION_PROMPT = `
|
|
1737
|
+
<inline_actions>
|
|
1738
|
+
When your response should include interactive components (like query viewers,
|
|
1739
|
+
data tables, or executable actions), embed them as fenced code blocks using
|
|
1740
|
+
the \`json:action\` language tag:
|
|
1741
|
+
|
|
1742
|
+
\`\`\`json:action
|
|
1743
|
+
{
|
|
1744
|
+
"type": "action-type-here",
|
|
1745
|
+
...action-specific fields
|
|
1746
|
+
}
|
|
1747
|
+
\`\`\`
|
|
1748
|
+
|
|
1749
|
+
Rules:
|
|
1750
|
+
- Each block must contain valid JSON with a "type" field.
|
|
1751
|
+
- The "type" must match a registered action component on the frontend.
|
|
1752
|
+
- Multiple action blocks per response are allowed.
|
|
1753
|
+
- Surround action blocks with normal markdown text for user context.
|
|
1754
|
+
- The action block is rendered as an interactive component in the chat UI.
|
|
1755
|
+
- SQL strings inside JSON must be properly escaped (newlines as \\n, quotes as \\").
|
|
1756
|
+
|
|
1757
|
+
Available action types:
|
|
1758
|
+
|
|
1759
|
+
- "optimap-query": Displays SQL queries with a button to execute them and
|
|
1760
|
+
update the 3D globe map.
|
|
1761
|
+
Required fields:
|
|
1762
|
+
- type: "optimap-query"
|
|
1763
|
+
- locations_sql: string (the validated locations SQL query)
|
|
1764
|
+
- routes_sql: string (the validated routes SQL query)
|
|
1765
|
+
- database_name: string (the target database name)
|
|
1766
|
+
</inline_actions>
|
|
1767
|
+
`;
|
|
1768
|
+
|
|
1769
|
+
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
1770
|
//# sourceMappingURL=index.js.map
|
|
1220
1771
|
//# sourceMappingURL=index.js.map
|