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