@nextclaw/agent-chat-ui 0.2.19 → 0.2.21
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.d.ts +10 -1
- package/dist/index.js +425 -258
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -166,6 +166,13 @@ type ChatFileOperationBlockViewModel = {
|
|
|
166
166
|
rawText?: string;
|
|
167
167
|
truncated?: boolean;
|
|
168
168
|
};
|
|
169
|
+
type ChatToolActionViewModel = {
|
|
170
|
+
kind: "open-session";
|
|
171
|
+
sessionId: string;
|
|
172
|
+
sessionKind: "child" | "session";
|
|
173
|
+
label?: string;
|
|
174
|
+
parentSessionId?: string;
|
|
175
|
+
};
|
|
169
176
|
type ChatToolPartViewModel = {
|
|
170
177
|
kind: "call" | "result";
|
|
171
178
|
toolName: string;
|
|
@@ -180,6 +187,7 @@ type ChatToolPartViewModel = {
|
|
|
180
187
|
titleLabel: string;
|
|
181
188
|
outputLabel: string;
|
|
182
189
|
emptyLabel: string;
|
|
190
|
+
action?: ChatToolActionViewModel;
|
|
183
191
|
fileOperation?: {
|
|
184
192
|
blocks: ChatFileOperationBlockViewModel[];
|
|
185
193
|
};
|
|
@@ -246,6 +254,7 @@ type ChatMessageListProps = {
|
|
|
246
254
|
hasAssistantDraft: boolean;
|
|
247
255
|
texts: ChatMessageTexts;
|
|
248
256
|
className?: string;
|
|
257
|
+
onToolAction?: (action: ChatToolActionViewModel) => void;
|
|
249
258
|
};
|
|
250
259
|
|
|
251
260
|
type ChatInputBarHandle = {
|
|
@@ -320,4 +329,4 @@ declare function resolveChatComposerSlashTrigger(nodes: ChatComposerNode[], sele
|
|
|
320
329
|
end: number;
|
|
321
330
|
} | null;
|
|
322
331
|
|
|
323
|
-
export { type ChatComposerNode, type ChatComposerSelection, type ChatComposerTextNode, type ChatComposerTokenKind, type ChatComposerTokenNode, type ChatFileOperationBlockViewModel, type ChatFileOperationLineViewModel, type ChatInlineContentSegmentViewModel, type ChatInlineHint, type ChatInlineTokenViewModel, ChatInputBar, type ChatInputBarActionsProps, type ChatInputBarHandle, type ChatInputBarProps, type ChatInputBarToolbarProps, ChatMessageList, type ChatMessageListProps, type ChatMessagePartViewModel, type ChatMessageRole, type ChatMessageTexts, type ChatMessageViewModel, type ChatSelectedItem, type ChatSkillPickerOption, type ChatSkillPickerProps, type ChatSlashItem, type ChatSlashMenuProps, type ChatTexts, type ChatToolPartViewModel, type ChatToolbarAccessory, type ChatToolbarAccessoryIcon, type ChatToolbarIcon, type ChatToolbarSelect, type ChatToolbarSelectGroup, type ChatToolbarSelectOption, copyText, createChatComposerNodesFromText, createChatComposerTextNode, createChatComposerTokenNode, createEmptyChatComposerNodes, extractChatComposerTokenKeys, normalizeChatComposerNodes, removeChatComposerTokenNodes, replaceChatComposerRange, resolveChatComposerSlashTrigger, serializeChatComposerDocument, serializeChatComposerPlainText, useActiveItemScroll, useCopyFeedback, useElementWidth, useStickyBottomScroll };
|
|
332
|
+
export { type ChatComposerNode, type ChatComposerSelection, type ChatComposerTextNode, type ChatComposerTokenKind, type ChatComposerTokenNode, type ChatFileOperationBlockViewModel, type ChatFileOperationLineViewModel, type ChatInlineContentSegmentViewModel, type ChatInlineHint, type ChatInlineTokenViewModel, ChatInputBar, type ChatInputBarActionsProps, type ChatInputBarHandle, type ChatInputBarProps, type ChatInputBarToolbarProps, ChatMessageList, type ChatMessageListProps, type ChatMessagePartViewModel, type ChatMessageRole, type ChatMessageTexts, type ChatMessageViewModel, type ChatSelectedItem, type ChatSkillPickerOption, type ChatSkillPickerProps, type ChatSlashItem, type ChatSlashMenuProps, type ChatTexts, type ChatToolActionViewModel, type ChatToolPartViewModel, type ChatToolbarAccessory, type ChatToolbarAccessoryIcon, type ChatToolbarIcon, type ChatToolbarSelect, type ChatToolbarSelectGroup, type ChatToolbarSelectOption, copyText, createChatComposerNodesFromText, createChatComposerTextNode, createChatComposerTokenNode, createEmptyChatComposerNodes, extractChatComposerTokenKeys, normalizeChatComposerNodes, removeChatComposerTokenNodes, replaceChatComposerRange, resolveChatComposerSlashTrigger, serializeChatComposerDocument, serializeChatComposerPlainText, useActiveItemScroll, useCopyFeedback, useElementWidth, useStickyBottomScroll };
|
package/dist/index.js
CHANGED
|
@@ -290,13 +290,20 @@ function ChatSlashMenu(props) {
|
|
|
290
290
|
] })
|
|
291
291
|
}
|
|
292
292
|
),
|
|
293
|
-
/* @__PURE__ */ jsx5("div", { className: "
|
|
293
|
+
/* @__PURE__ */ jsx5("div", { className: "min-w-0 p-2.5", children: activeItem ? /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
|
|
294
294
|
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
295
295
|
/* @__PURE__ */ jsx5("span", { className: "inline-flex rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-semibold text-primary", children: activeItem.subtitle }),
|
|
296
296
|
/* @__PURE__ */ jsx5("span", { className: "text-sm font-semibold text-gray-900", children: activeItem.title })
|
|
297
297
|
] }),
|
|
298
298
|
/* @__PURE__ */ jsx5("p", { className: "text-xs leading-5 text-gray-600", children: activeItem.description }),
|
|
299
|
-
/* @__PURE__ */ jsx5("div", { className: "space-y-1", children: activeItem.detailLines.map((line) => /* @__PURE__ */ jsx5(
|
|
299
|
+
/* @__PURE__ */ jsx5("div", { className: "space-y-1", children: activeItem.detailLines.map((line) => /* @__PURE__ */ jsx5(
|
|
300
|
+
"div",
|
|
301
|
+
{
|
|
302
|
+
className: "min-w-0 break-all rounded-md bg-gray-50 px-2 py-1 text-[11px] leading-5 text-gray-600",
|
|
303
|
+
children: line
|
|
304
|
+
},
|
|
305
|
+
line
|
|
306
|
+
)) }),
|
|
300
307
|
/* @__PURE__ */ jsx5("div", { className: "pt-1 text-[11px] text-gray-500", children: texts.slashSkillHintLabel })
|
|
301
308
|
] }) : /* @__PURE__ */ jsx5("div", { className: "text-xs text-gray-500", children: texts.slashHintLabel }) })
|
|
302
309
|
] })
|
|
@@ -2752,7 +2759,7 @@ function ChatReasoningBlock({ label, text, isUser, isInProgress }) {
|
|
|
2752
2759
|
|
|
2753
2760
|
// src/components/chat/ui/chat-message-list/tool-card/tool-card-views.tsx
|
|
2754
2761
|
import { Terminal, FileText, Code2, Search as Search2, Globe } from "lucide-react";
|
|
2755
|
-
import { useState as useState7, useEffect as
|
|
2762
|
+
import { useState as useState7, useEffect as useEffect8, useRef as useRef8 } from "react";
|
|
2756
2763
|
|
|
2757
2764
|
// src/components/chat/ui/chat-message-list/tool-card/tool-card-root.tsx
|
|
2758
2765
|
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
@@ -2833,18 +2840,230 @@ function ToolCardHeader({
|
|
|
2833
2840
|
);
|
|
2834
2841
|
}
|
|
2835
2842
|
|
|
2843
|
+
// src/components/chat/hooks/use-sticky-bottom-scroll.ts
|
|
2844
|
+
import { useEffect as useEffect7, useLayoutEffect as useLayoutEffect2, useRef as useRef6 } from "react";
|
|
2845
|
+
var DEFAULT_STICKY_THRESHOLD_PX = 10;
|
|
2846
|
+
function scrollElementToBottom(element) {
|
|
2847
|
+
element.scrollTop = element.scrollHeight;
|
|
2848
|
+
}
|
|
2849
|
+
function queueScrollToBottom(params) {
|
|
2850
|
+
const element = params.scrollRef.current;
|
|
2851
|
+
if (!element) {
|
|
2852
|
+
return;
|
|
2853
|
+
}
|
|
2854
|
+
if (params.scheduledScrollFrameRef.current !== null) {
|
|
2855
|
+
cancelAnimationFrame(params.scheduledScrollFrameRef.current);
|
|
2856
|
+
}
|
|
2857
|
+
params.scheduledScrollFrameRef.current = requestAnimationFrame(() => {
|
|
2858
|
+
params.scheduledScrollFrameRef.current = null;
|
|
2859
|
+
const currentElement = params.scrollRef.current;
|
|
2860
|
+
if (!currentElement) {
|
|
2861
|
+
return;
|
|
2862
|
+
}
|
|
2863
|
+
params.isProgrammaticScrollRef.current = true;
|
|
2864
|
+
scrollElementToBottom(currentElement);
|
|
2865
|
+
});
|
|
2866
|
+
}
|
|
2867
|
+
function useStickyBottomScroll(params) {
|
|
2868
|
+
const isStickyRef = useRef6(true);
|
|
2869
|
+
const isProgrammaticScrollRef = useRef6(false);
|
|
2870
|
+
const previousResetKeyRef = useRef6(null);
|
|
2871
|
+
const pendingInitialScrollRef = useRef6(false);
|
|
2872
|
+
const scheduledScrollFrameRef = useRef6(null);
|
|
2873
|
+
const onScroll = () => {
|
|
2874
|
+
if (isProgrammaticScrollRef.current) {
|
|
2875
|
+
isProgrammaticScrollRef.current = false;
|
|
2876
|
+
return;
|
|
2877
|
+
}
|
|
2878
|
+
const element = params.scrollRef.current;
|
|
2879
|
+
if (!element) {
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
const distanceFromBottom = element.scrollHeight - element.scrollTop - element.clientHeight;
|
|
2883
|
+
isStickyRef.current = distanceFromBottom <= (params.stickyThresholdPx ?? DEFAULT_STICKY_THRESHOLD_PX);
|
|
2884
|
+
};
|
|
2885
|
+
useEffect7(() => {
|
|
2886
|
+
if (previousResetKeyRef.current === params.resetKey) {
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
previousResetKeyRef.current = params.resetKey;
|
|
2890
|
+
isStickyRef.current = true;
|
|
2891
|
+
pendingInitialScrollRef.current = true;
|
|
2892
|
+
}, [params.resetKey]);
|
|
2893
|
+
useEffect7(() => {
|
|
2894
|
+
const scheduledScrollFrame = scheduledScrollFrameRef.current;
|
|
2895
|
+
return () => {
|
|
2896
|
+
if (scheduledScrollFrame !== null) {
|
|
2897
|
+
cancelAnimationFrame(scheduledScrollFrame);
|
|
2898
|
+
}
|
|
2899
|
+
};
|
|
2900
|
+
}, []);
|
|
2901
|
+
useLayoutEffect2(() => {
|
|
2902
|
+
if (!pendingInitialScrollRef.current || params.isLoading || !params.hasContent) {
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2905
|
+
const element = params.scrollRef.current;
|
|
2906
|
+
if (!element) {
|
|
2907
|
+
return;
|
|
2908
|
+
}
|
|
2909
|
+
pendingInitialScrollRef.current = false;
|
|
2910
|
+
queueScrollToBottom({
|
|
2911
|
+
scrollRef: params.scrollRef,
|
|
2912
|
+
scheduledScrollFrameRef,
|
|
2913
|
+
isProgrammaticScrollRef
|
|
2914
|
+
});
|
|
2915
|
+
}, [params.hasContent, params.isLoading, params.scrollRef]);
|
|
2916
|
+
useLayoutEffect2(() => {
|
|
2917
|
+
if (!isStickyRef.current || !params.hasContent) {
|
|
2918
|
+
return;
|
|
2919
|
+
}
|
|
2920
|
+
const element = params.scrollRef.current;
|
|
2921
|
+
if (!element) {
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2924
|
+
queueScrollToBottom({
|
|
2925
|
+
scrollRef: params.scrollRef,
|
|
2926
|
+
scheduledScrollFrameRef,
|
|
2927
|
+
isProgrammaticScrollRef
|
|
2928
|
+
});
|
|
2929
|
+
}, [params.contentVersion, params.hasContent, params.scrollRef]);
|
|
2930
|
+
return { onScroll };
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2836
2933
|
// src/components/chat/ui/chat-message-list/tool-card/tool-card-file-operation.tsx
|
|
2837
|
-
import { Fragment as Fragment4 } from "react";
|
|
2934
|
+
import { Fragment as Fragment4, useRef as useRef7 } from "react";
|
|
2935
|
+
|
|
2936
|
+
// src/components/chat/ui/chat-message-list/tool-card/tool-card-file-operation-lines.tsx
|
|
2838
2937
|
import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2938
|
+
var FILE_ROW_CLASS_NAME = "h-5 font-mono text-[11px] leading-5";
|
|
2939
|
+
var FILE_GUTTER_NUMBER_CELL_CLASS_NAME = "sticky left-0 z-[1] flex h-5 items-center justify-center px-2.5 tabular-nums select-none";
|
|
2839
2940
|
function formatLineNumber(value) {
|
|
2840
2941
|
return typeof value === "number" ? String(value) : "";
|
|
2841
2942
|
}
|
|
2842
2943
|
function readVisibleLineNumber(line) {
|
|
2843
2944
|
return formatLineNumber(line.newLineNumber ?? line.oldLineNumber);
|
|
2844
2945
|
}
|
|
2946
|
+
function readLineKey(prefix, line, index) {
|
|
2947
|
+
return `${prefix}-${index}-${line.oldLineNumber ?? "x"}-${line.newLineNumber ?? "x"}`;
|
|
2948
|
+
}
|
|
2949
|
+
function hasVisibleLineNumber(line) {
|
|
2950
|
+
return typeof line.newLineNumber === "number" || typeof line.oldLineNumber === "number";
|
|
2951
|
+
}
|
|
2952
|
+
function readHasBlockLineNumbers(block) {
|
|
2953
|
+
return block.lines.some(hasVisibleLineNumber);
|
|
2954
|
+
}
|
|
2955
|
+
function readLineNumberColumnWidth(block) {
|
|
2956
|
+
const maxDigits = block.lines.reduce((currentMax, line) => {
|
|
2957
|
+
if (!hasVisibleLineNumber(line)) {
|
|
2958
|
+
return currentMax;
|
|
2959
|
+
}
|
|
2960
|
+
return Math.max(currentMax, readVisibleLineNumber(line).length);
|
|
2961
|
+
}, 0);
|
|
2962
|
+
const width = Math.max(6.5, Math.min(8, maxDigits + 3.5));
|
|
2963
|
+
return `${width}ch`;
|
|
2964
|
+
}
|
|
2965
|
+
function buildRowTemplateColumns(params) {
|
|
2966
|
+
if (!params.showLineNumbers) {
|
|
2967
|
+
return void 0;
|
|
2968
|
+
}
|
|
2969
|
+
return {
|
|
2970
|
+
gridTemplateColumns: `${params.lineNumberColumnWidth} minmax(0, 1fr)`
|
|
2971
|
+
};
|
|
2972
|
+
}
|
|
2973
|
+
function getLineNumberTone(line) {
|
|
2974
|
+
if (line.kind === "remove") {
|
|
2975
|
+
return "border-r border-rose-200 bg-rose-50 text-rose-700";
|
|
2976
|
+
}
|
|
2977
|
+
if (line.kind === "add") {
|
|
2978
|
+
return "border-r border-emerald-200 bg-emerald-50 text-emerald-700";
|
|
2979
|
+
}
|
|
2980
|
+
return "border-r border-stone-200 bg-stone-100 text-stone-500";
|
|
2981
|
+
}
|
|
2982
|
+
function getCodeRowTone(line) {
|
|
2983
|
+
if (line.kind === "remove") {
|
|
2984
|
+
return "bg-rose-50 text-rose-950";
|
|
2985
|
+
}
|
|
2986
|
+
if (line.kind === "add") {
|
|
2987
|
+
return "bg-emerald-50 text-emerald-950";
|
|
2988
|
+
}
|
|
2989
|
+
return "bg-white text-amber-950/80";
|
|
2990
|
+
}
|
|
2991
|
+
function FileOperationLineRow({
|
|
2992
|
+
line,
|
|
2993
|
+
showLineNumbers,
|
|
2994
|
+
lineNumberColumnWidth
|
|
2995
|
+
}) {
|
|
2996
|
+
return /* @__PURE__ */ jsxs13(
|
|
2997
|
+
"div",
|
|
2998
|
+
{
|
|
2999
|
+
"data-file-line-row": "true",
|
|
3000
|
+
className: cn("grid w-max min-w-full", FILE_ROW_CLASS_NAME),
|
|
3001
|
+
style: buildRowTemplateColumns({
|
|
3002
|
+
showLineNumbers,
|
|
3003
|
+
lineNumberColumnWidth
|
|
3004
|
+
}),
|
|
3005
|
+
children: [
|
|
3006
|
+
showLineNumbers ? /* @__PURE__ */ jsx21(
|
|
3007
|
+
"span",
|
|
3008
|
+
{
|
|
3009
|
+
"data-file-line-number-cell": "true",
|
|
3010
|
+
style: { width: lineNumberColumnWidth },
|
|
3011
|
+
className: cn(
|
|
3012
|
+
FILE_GUTTER_NUMBER_CELL_CLASS_NAME,
|
|
3013
|
+
getLineNumberTone(line)
|
|
3014
|
+
),
|
|
3015
|
+
children: readVisibleLineNumber(line)
|
|
3016
|
+
}
|
|
3017
|
+
) : null,
|
|
3018
|
+
/* @__PURE__ */ jsx21(
|
|
3019
|
+
"span",
|
|
3020
|
+
{
|
|
3021
|
+
"data-file-code-row": "true",
|
|
3022
|
+
className: cn(
|
|
3023
|
+
"block min-w-full whitespace-pre px-2.5",
|
|
3024
|
+
getCodeRowTone(line)
|
|
3025
|
+
),
|
|
3026
|
+
children: line.text || " "
|
|
3027
|
+
}
|
|
3028
|
+
)
|
|
3029
|
+
]
|
|
3030
|
+
}
|
|
3031
|
+
);
|
|
3032
|
+
}
|
|
3033
|
+
function FileOperationLinesGrid({
|
|
3034
|
+
block
|
|
3035
|
+
}) {
|
|
3036
|
+
const showLineNumbers = readHasBlockLineNumbers(block);
|
|
3037
|
+
const lineNumberColumnWidth = readLineNumberColumnWidth(block);
|
|
3038
|
+
return /* @__PURE__ */ jsx21("div", { className: "overflow-x-auto custom-scrollbar-amber bg-white", children: block.lines.map((line, index) => /* @__PURE__ */ jsx21(
|
|
3039
|
+
FileOperationLineRow,
|
|
3040
|
+
{
|
|
3041
|
+
line,
|
|
3042
|
+
showLineNumbers,
|
|
3043
|
+
lineNumberColumnWidth
|
|
3044
|
+
},
|
|
3045
|
+
readLineKey("row", line, index)
|
|
3046
|
+
)) });
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3049
|
+
// src/components/chat/ui/chat-message-list/tool-card/tool-card-file-operation.tsx
|
|
3050
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2845
3051
|
function isPreviewBlock(block) {
|
|
2846
3052
|
return block.display === "preview";
|
|
2847
3053
|
}
|
|
3054
|
+
function readFileOperationContentVersion(block) {
|
|
3055
|
+
if (block.rawText) {
|
|
3056
|
+
return block.rawText;
|
|
3057
|
+
}
|
|
3058
|
+
return block.lines.map(
|
|
3059
|
+
(line) => [
|
|
3060
|
+
line.kind,
|
|
3061
|
+
line.oldLineNumber ?? "",
|
|
3062
|
+
line.newLineNumber ?? "",
|
|
3063
|
+
line.text
|
|
3064
|
+
].join(":")
|
|
3065
|
+
).join("\n");
|
|
3066
|
+
}
|
|
2848
3067
|
function getCaptionTone(part) {
|
|
2849
3068
|
if (/^\+\d+$/.test(part)) {
|
|
2850
3069
|
return "text-emerald-700";
|
|
@@ -2859,54 +3078,39 @@ function renderCaption(caption) {
|
|
|
2859
3078
|
if (parts.length === 0) {
|
|
2860
3079
|
return null;
|
|
2861
3080
|
}
|
|
2862
|
-
return /* @__PURE__ */
|
|
2863
|
-
index > 0 ? /* @__PURE__ */
|
|
2864
|
-
/* @__PURE__ */
|
|
3081
|
+
return /* @__PURE__ */ jsx22("div", { className: "flex shrink-0 items-center gap-x-1 whitespace-nowrap text-[10px] font-medium uppercase tracking-[0.08em]", children: parts.map((part, index) => /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
3082
|
+
index > 0 ? /* @__PURE__ */ jsx22("span", { className: "text-stone-300", children: "\xB7" }) : null,
|
|
3083
|
+
/* @__PURE__ */ jsx22("span", { className: cn(getCaptionTone(part)), children: part })
|
|
2865
3084
|
] }, `${part}-${index}`)) });
|
|
2866
3085
|
}
|
|
2867
|
-
function
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
},
|
|
2885
|
-
`preview-gutter-${index}-${line.oldLineNumber ?? "x"}-${line.newLineNumber ?? "x"}`
|
|
2886
|
-
);
|
|
2887
|
-
}
|
|
2888
|
-
function renderDiffCodeRow(line, index) {
|
|
2889
|
-
const rowTone = line.kind === "add" ? "border-l-2 border-emerald-300 bg-emerald-50 text-emerald-950" : line.kind === "remove" ? "border-l-2 border-rose-300 bg-rose-50 text-rose-950" : "border-l-2 border-transparent text-amber-950/80";
|
|
2890
|
-
return /* @__PURE__ */ jsx21(
|
|
3086
|
+
function StickyFileOperationScrollArea({
|
|
3087
|
+
children,
|
|
3088
|
+
contentVersion,
|
|
3089
|
+
resetKey,
|
|
3090
|
+
className,
|
|
3091
|
+
scrollKind
|
|
3092
|
+
}) {
|
|
3093
|
+
const scrollRef = useRef7(null);
|
|
3094
|
+
const { onScroll } = useStickyBottomScroll({
|
|
3095
|
+
scrollRef,
|
|
3096
|
+
resetKey,
|
|
3097
|
+
isLoading: false,
|
|
3098
|
+
hasContent: true,
|
|
3099
|
+
contentVersion,
|
|
3100
|
+
stickyThresholdPx: 20
|
|
3101
|
+
});
|
|
3102
|
+
return /* @__PURE__ */ jsx22(
|
|
2891
3103
|
"div",
|
|
2892
3104
|
{
|
|
3105
|
+
ref: scrollRef,
|
|
3106
|
+
onScroll,
|
|
3107
|
+
"data-file-scroll-kind": scrollKind,
|
|
2893
3108
|
className: cn(
|
|
2894
|
-
"
|
|
2895
|
-
|
|
3109
|
+
"overflow-y-auto overscroll-contain bg-white custom-scrollbar-amber",
|
|
3110
|
+
className
|
|
2896
3111
|
),
|
|
2897
|
-
children
|
|
2898
|
-
}
|
|
2899
|
-
`diff-code-${index}-${line.oldLineNumber ?? "x"}-${line.newLineNumber ?? "x"}`
|
|
2900
|
-
);
|
|
2901
|
-
}
|
|
2902
|
-
function renderPreviewCodeRow(line, index) {
|
|
2903
|
-
return /* @__PURE__ */ jsx21(
|
|
2904
|
-
"div",
|
|
2905
|
-
{
|
|
2906
|
-
className: "min-w-full whitespace-pre px-3 py-1.5 font-mono text-[11px] leading-relaxed text-amber-950/85",
|
|
2907
|
-
children: line.text || " "
|
|
2908
|
-
},
|
|
2909
|
-
`preview-code-${index}-${line.oldLineNumber ?? "x"}-${line.newLineNumber ?? "x"}`
|
|
3112
|
+
children
|
|
3113
|
+
}
|
|
2910
3114
|
);
|
|
2911
3115
|
}
|
|
2912
3116
|
function FileOperationBlock({
|
|
@@ -2917,45 +3121,67 @@ function FileOperationBlock({
|
|
|
2917
3121
|
const { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } = ChatUiPrimitives;
|
|
2918
3122
|
const previewBlock = isPreviewBlock(block);
|
|
2919
3123
|
const showMetaRow = showPathRow || Boolean(block.caption);
|
|
2920
|
-
return /* @__PURE__ */
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
3124
|
+
return /* @__PURE__ */ jsxs14(
|
|
3125
|
+
"section",
|
|
3126
|
+
{
|
|
3127
|
+
className: cn(
|
|
3128
|
+
"overflow-hidden bg-white",
|
|
3129
|
+
!isFirst && "border-t border-stone-200/80"
|
|
3130
|
+
),
|
|
3131
|
+
children: [
|
|
3132
|
+
showMetaRow ? /* @__PURE__ */ jsxs14(
|
|
3133
|
+
"div",
|
|
3134
|
+
{
|
|
3135
|
+
className: cn(
|
|
3136
|
+
"flex items-center justify-between gap-4 border-b border-stone-200/80 px-4 text-stone-700",
|
|
3137
|
+
showPathRow ? "py-2" : "py-1.5"
|
|
3138
|
+
),
|
|
3139
|
+
children: [
|
|
3140
|
+
/* @__PURE__ */ jsx22("div", { className: "min-w-0 flex-1", children: showPathRow ? /* @__PURE__ */ jsx22(TooltipProvider, { delayDuration: 250, children: /* @__PURE__ */ jsxs14(Tooltip, { children: [
|
|
3141
|
+
/* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22(
|
|
3142
|
+
"div",
|
|
3143
|
+
{
|
|
3144
|
+
className: "truncate whitespace-nowrap font-mono text-[12px] font-medium text-stone-700",
|
|
3145
|
+
title: block.path,
|
|
3146
|
+
children: block.path
|
|
3147
|
+
}
|
|
3148
|
+
) }),
|
|
3149
|
+
/* @__PURE__ */ jsx22(
|
|
3150
|
+
TooltipContent,
|
|
3151
|
+
{
|
|
3152
|
+
side: "top",
|
|
3153
|
+
className: "max-w-[420px] text-xs font-mono break-all",
|
|
3154
|
+
children: block.path
|
|
3155
|
+
}
|
|
3156
|
+
)
|
|
3157
|
+
] }) }) : null }),
|
|
3158
|
+
block.caption ? renderCaption(block.caption) : null
|
|
3159
|
+
]
|
|
3160
|
+
}
|
|
3161
|
+
) : null,
|
|
3162
|
+
block.lines.length > 0 ? /* @__PURE__ */ jsx22(
|
|
3163
|
+
StickyFileOperationScrollArea,
|
|
3164
|
+
{
|
|
3165
|
+
resetKey: `block:${block.key}`,
|
|
3166
|
+
contentVersion: readFileOperationContentVersion(block),
|
|
3167
|
+
className: "max-h-72",
|
|
3168
|
+
scrollKind: "block",
|
|
3169
|
+
children: /* @__PURE__ */ jsx22(FileOperationLinesGrid, { block })
|
|
3170
|
+
}
|
|
3171
|
+
) : block.rawText ? /* @__PURE__ */ jsx22(
|
|
3172
|
+
StickyFileOperationScrollArea,
|
|
3173
|
+
{
|
|
3174
|
+
resetKey: `raw:${block.key}`,
|
|
3175
|
+
contentVersion: block.rawText,
|
|
3176
|
+
className: "max-h-72",
|
|
3177
|
+
scrollKind: "raw",
|
|
3178
|
+
children: /* @__PURE__ */ jsx22("div", { className: "overflow-x-auto custom-scrollbar-amber", children: /* @__PURE__ */ jsx22("pre", { className: "min-w-max whitespace-pre bg-white px-4 py-2 font-mono text-[11px] leading-5 text-amber-950/80", children: block.rawText }) })
|
|
3179
|
+
}
|
|
3180
|
+
) : null,
|
|
3181
|
+
block.truncated && !previewBlock ? /* @__PURE__ */ jsx22("div", { className: "border-t border-stone-200/85 bg-stone-50 px-4 py-2 text-[10px] text-stone-500", children: "Showing a shortened diff preview." }) : null
|
|
3182
|
+
]
|
|
3183
|
+
}
|
|
3184
|
+
);
|
|
2959
3185
|
}
|
|
2960
3186
|
function ToolCardFileOperationContent({
|
|
2961
3187
|
card,
|
|
@@ -2966,9 +3192,9 @@ function ToolCardFileOperationContent({
|
|
|
2966
3192
|
if (blocks.length === 0 && !output) {
|
|
2967
3193
|
return null;
|
|
2968
3194
|
}
|
|
2969
|
-
return /* @__PURE__ */
|
|
3195
|
+
return /* @__PURE__ */ jsxs14("div", { className: cn("overflow-hidden bg-white", className), children: [
|
|
2970
3196
|
blocks.map((block, index) => {
|
|
2971
|
-
return /* @__PURE__ */
|
|
3197
|
+
return /* @__PURE__ */ jsx22(
|
|
2972
3198
|
FileOperationBlock,
|
|
2973
3199
|
{
|
|
2974
3200
|
block,
|
|
@@ -2978,15 +3204,24 @@ function ToolCardFileOperationContent({
|
|
|
2978
3204
|
block.key
|
|
2979
3205
|
);
|
|
2980
3206
|
}),
|
|
2981
|
-
output ? /* @__PURE__ */
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
3207
|
+
output ? /* @__PURE__ */ jsx22(
|
|
3208
|
+
StickyFileOperationScrollArea,
|
|
3209
|
+
{
|
|
3210
|
+
resetKey: `output:${card.toolName}:${card.summary ?? "none"}`,
|
|
3211
|
+
contentVersion: output,
|
|
3212
|
+
className: cn(
|
|
3213
|
+
"max-h-56",
|
|
3214
|
+
blocks.length > 0 && "border-t border-stone-200/80"
|
|
3215
|
+
),
|
|
3216
|
+
scrollKind: "output",
|
|
3217
|
+
children: /* @__PURE__ */ jsx22("div", { className: "overflow-x-auto custom-scrollbar-amber", children: /* @__PURE__ */ jsx22("pre", { className: "min-w-max whitespace-pre bg-white px-4 py-2 font-mono text-[11px] leading-5 text-amber-950/80", children: output }) })
|
|
3218
|
+
}
|
|
3219
|
+
) : null
|
|
2985
3220
|
] });
|
|
2986
3221
|
}
|
|
2987
3222
|
|
|
2988
3223
|
// src/components/chat/ui/chat-message-list/tool-card/tool-card-views.tsx
|
|
2989
|
-
import { Fragment as Fragment5, jsx as
|
|
3224
|
+
import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2990
3225
|
var TOOL_CARD_AUTO_EXPAND_DELAY_MS = 200;
|
|
2991
3226
|
var ANSI_ESCAPE_PREFIX = String.fromCharCode(27);
|
|
2992
3227
|
var ANSI_ESCAPE_PATTERN = new RegExp(`${ANSI_ESCAPE_PREFIX}\\[[0-?]*[ -/]*[@-~]`, "g");
|
|
@@ -3060,17 +3295,17 @@ function useToolCardExpandedState({
|
|
|
3060
3295
|
}) {
|
|
3061
3296
|
const [expanded, setExpanded] = useState7(false);
|
|
3062
3297
|
const [hasUserToggled, setHasUserToggled] = useState7(false);
|
|
3063
|
-
const expandTimerRef =
|
|
3064
|
-
const prevRunningRef =
|
|
3065
|
-
const isFirstRenderRef =
|
|
3066
|
-
|
|
3298
|
+
const expandTimerRef = useRef8(null);
|
|
3299
|
+
const prevRunningRef = useRef8(isRunning);
|
|
3300
|
+
const isFirstRenderRef = useRef8(true);
|
|
3301
|
+
useEffect8(() => {
|
|
3067
3302
|
return () => {
|
|
3068
3303
|
if (expandTimerRef.current !== null) {
|
|
3069
3304
|
window.clearTimeout(expandTimerRef.current);
|
|
3070
3305
|
}
|
|
3071
3306
|
};
|
|
3072
3307
|
}, []);
|
|
3073
|
-
|
|
3308
|
+
useEffect8(() => {
|
|
3074
3309
|
if (expandOnError && statusTone === "error" && canExpand && !hasUserToggled) {
|
|
3075
3310
|
if (expandTimerRef.current !== null) {
|
|
3076
3311
|
window.clearTimeout(expandTimerRef.current);
|
|
@@ -3138,7 +3373,7 @@ function GenericToolSection({
|
|
|
3138
3373
|
}
|
|
3139
3374
|
};
|
|
3140
3375
|
const style = tones[tone];
|
|
3141
|
-
return /* @__PURE__ */
|
|
3376
|
+
return /* @__PURE__ */ jsxs15(
|
|
3142
3377
|
"section",
|
|
3143
3378
|
{
|
|
3144
3379
|
className: cn(
|
|
@@ -3146,7 +3381,7 @@ function GenericToolSection({
|
|
|
3146
3381
|
style.shell
|
|
3147
3382
|
),
|
|
3148
3383
|
children: [
|
|
3149
|
-
/* @__PURE__ */
|
|
3384
|
+
/* @__PURE__ */ jsxs15(
|
|
3150
3385
|
"div",
|
|
3151
3386
|
{
|
|
3152
3387
|
className: cn(
|
|
@@ -3154,12 +3389,12 @@ function GenericToolSection({
|
|
|
3154
3389
|
style.header
|
|
3155
3390
|
),
|
|
3156
3391
|
children: [
|
|
3157
|
-
/* @__PURE__ */
|
|
3158
|
-
/* @__PURE__ */
|
|
3392
|
+
/* @__PURE__ */ jsx23("span", { className: cn("h-1.5 w-1.5 rounded-full", style.dot) }),
|
|
3393
|
+
/* @__PURE__ */ jsx23("span", { children: label })
|
|
3159
3394
|
]
|
|
3160
3395
|
}
|
|
3161
3396
|
),
|
|
3162
|
-
/* @__PURE__ */
|
|
3397
|
+
/* @__PURE__ */ jsx23("div", { className: "w-full overflow-hidden", children: /* @__PURE__ */ jsx23(
|
|
3163
3398
|
"pre",
|
|
3164
3399
|
{
|
|
3165
3400
|
className: cn(
|
|
@@ -3184,8 +3419,8 @@ function TerminalExecutionView({ card }) {
|
|
|
3184
3419
|
statusTone: card.statusTone
|
|
3185
3420
|
});
|
|
3186
3421
|
const commandPart = card.summary?.replace(/^(command|path|args|query|input):\s*/i, "");
|
|
3187
|
-
return /* @__PURE__ */
|
|
3188
|
-
/* @__PURE__ */
|
|
3422
|
+
return /* @__PURE__ */ jsxs15(ToolCardRoot, { children: [
|
|
3423
|
+
/* @__PURE__ */ jsx23(
|
|
3189
3424
|
ToolCardHeader,
|
|
3190
3425
|
{
|
|
3191
3426
|
card,
|
|
@@ -3195,17 +3430,17 @@ function TerminalExecutionView({ card }) {
|
|
|
3195
3430
|
onToggle
|
|
3196
3431
|
}
|
|
3197
3432
|
),
|
|
3198
|
-
expanded && /* @__PURE__ */
|
|
3199
|
-
/* @__PURE__ */
|
|
3200
|
-
/* @__PURE__ */
|
|
3201
|
-
/* @__PURE__ */
|
|
3433
|
+
expanded && /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
3434
|
+
/* @__PURE__ */ jsx23("div", { className: "px-3 pb-2 font-mono w-full max-h-48 overflow-y-auto custom-scrollbar-amber min-h-0 text-[12px]", children: /* @__PURE__ */ jsxs15("div", { className: "flex items-start gap-2 leading-relaxed", children: [
|
|
3435
|
+
/* @__PURE__ */ jsx23("span", { className: "text-amber-500/50 font-medium shrink-0 select-none mt-[1px]", children: "$" }),
|
|
3436
|
+
/* @__PURE__ */ jsx23("div", { className: "flex-1 min-w-0", children: commandPart ? /* @__PURE__ */ jsxs15("div", { className: "text-amber-950/80 break-words whitespace-pre-wrap tracking-tight font-medium inline-block", children: [
|
|
3202
3437
|
commandPart,
|
|
3203
|
-
isRunning && !output && /* @__PURE__ */
|
|
3204
|
-
] }) : /* @__PURE__ */
|
|
3438
|
+
isRunning && !output && /* @__PURE__ */ jsx23("span", { className: "inline-block w-1.5 h-3 ml-1 bg-amber-500/60 animate-pulse align-middle" })
|
|
3439
|
+
] }) : /* @__PURE__ */ jsx23("div", { className: "h-3 w-32 bg-amber-200/30 rounded animate-pulse mt-2" }) })
|
|
3205
3440
|
] }) }),
|
|
3206
|
-
output && /* @__PURE__ */
|
|
3441
|
+
output && /* @__PURE__ */ jsx23(ToolCardContent, { children: /* @__PURE__ */ jsxs15("pre", { className: "font-mono text-[12px] text-amber-950/70 whitespace-pre-wrap break-all w-full max-w-full max-h-64 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar-amber leading-relaxed px-0", children: [
|
|
3207
3442
|
output,
|
|
3208
|
-
isRunning && /* @__PURE__ */
|
|
3443
|
+
isRunning && /* @__PURE__ */ jsx23("span", { className: "inline-block w-1.5 h-3 ml-1 bg-amber-500/60 animate-pulse align-middle" })
|
|
3209
3444
|
] }) })
|
|
3210
3445
|
] })
|
|
3211
3446
|
] });
|
|
@@ -3232,8 +3467,8 @@ function FileOperationView({ card }) {
|
|
|
3232
3467
|
statusTone: card.statusTone
|
|
3233
3468
|
});
|
|
3234
3469
|
const isEdit = card.toolName === "edit_file" || card.toolName === "write_file" || card.toolName === "apply_patch" || card.toolName === "file_change";
|
|
3235
|
-
return /* @__PURE__ */
|
|
3236
|
-
/* @__PURE__ */
|
|
3470
|
+
return /* @__PURE__ */ jsxs15(ToolCardRoot, { children: [
|
|
3471
|
+
/* @__PURE__ */ jsx23(
|
|
3237
3472
|
ToolCardHeader,
|
|
3238
3473
|
{
|
|
3239
3474
|
card,
|
|
@@ -3244,7 +3479,7 @@ function FileOperationView({ card }) {
|
|
|
3244
3479
|
onToggle
|
|
3245
3480
|
}
|
|
3246
3481
|
),
|
|
3247
|
-
expanded && hasContent && /* @__PURE__ */
|
|
3482
|
+
expanded && hasContent && /* @__PURE__ */ jsx23(ToolCardContent, { className: "border-t border-amber-200/20 bg-transparent px-0 pt-0 pb-0", children: /* @__PURE__ */ jsx23(ToolCardFileOperationContent, { card }) })
|
|
3248
3483
|
] });
|
|
3249
3484
|
}
|
|
3250
3485
|
function SearchSnippetView({ card }) {
|
|
@@ -3255,8 +3490,8 @@ function SearchSnippetView({ card }) {
|
|
|
3255
3490
|
isRunning,
|
|
3256
3491
|
statusTone: card.statusTone
|
|
3257
3492
|
});
|
|
3258
|
-
return /* @__PURE__ */
|
|
3259
|
-
/* @__PURE__ */
|
|
3493
|
+
return /* @__PURE__ */ jsxs15(ToolCardRoot, { children: [
|
|
3494
|
+
/* @__PURE__ */ jsx23(
|
|
3260
3495
|
ToolCardHeader,
|
|
3261
3496
|
{
|
|
3262
3497
|
card,
|
|
@@ -3266,10 +3501,13 @@ function SearchSnippetView({ card }) {
|
|
|
3266
3501
|
onToggle
|
|
3267
3502
|
}
|
|
3268
3503
|
),
|
|
3269
|
-
expanded && output && /* @__PURE__ */
|
|
3504
|
+
expanded && output && /* @__PURE__ */ jsx23(ToolCardContent, { children: /* @__PURE__ */ jsx23("pre", { className: "font-mono text-[12px] text-amber-950/70 whitespace-pre-wrap break-all w-full max-w-full max-h-64 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar-amber leading-relaxed", children: output }) })
|
|
3270
3505
|
] });
|
|
3271
3506
|
}
|
|
3272
|
-
function GenericToolCard({
|
|
3507
|
+
function GenericToolCard({
|
|
3508
|
+
card,
|
|
3509
|
+
onToolAction
|
|
3510
|
+
}) {
|
|
3273
3511
|
const input = card.input?.trim() ?? "";
|
|
3274
3512
|
const output = card.output?.trim() ?? "";
|
|
3275
3513
|
const isRunning = card.statusTone === "running";
|
|
@@ -3283,8 +3521,8 @@ function GenericToolCard({ card }) {
|
|
|
3283
3521
|
isRunning,
|
|
3284
3522
|
statusTone: card.statusTone
|
|
3285
3523
|
});
|
|
3286
|
-
return /* @__PURE__ */
|
|
3287
|
-
/* @__PURE__ */
|
|
3524
|
+
return /* @__PURE__ */ jsxs15(ToolCardRoot, { children: [
|
|
3525
|
+
/* @__PURE__ */ jsx23(
|
|
3288
3526
|
ToolCardHeader,
|
|
3289
3527
|
{
|
|
3290
3528
|
card,
|
|
@@ -3294,23 +3532,32 @@ function GenericToolCard({ card }) {
|
|
|
3294
3532
|
onToggle
|
|
3295
3533
|
}
|
|
3296
3534
|
),
|
|
3297
|
-
expanded && hasContent && /* @__PURE__ */
|
|
3298
|
-
hasInputSection && /* @__PURE__ */
|
|
3299
|
-
hasInputSection && hasOutputSection && /* @__PURE__ */
|
|
3300
|
-
hasOutputSection && /* @__PURE__ */
|
|
3535
|
+
expanded && hasContent && /* @__PURE__ */ jsxs15(ToolCardContent, { className: "bg-transparent px-2.5 py-2.5", children: [
|
|
3536
|
+
hasInputSection && /* @__PURE__ */ jsx23(GenericToolSection, { label: inputLabel, tone: "input", children: input }),
|
|
3537
|
+
hasInputSection && hasOutputSection && /* @__PURE__ */ jsx23("div", { className: "h-2" }),
|
|
3538
|
+
hasOutputSection && /* @__PURE__ */ jsx23(
|
|
3301
3539
|
GenericToolSection,
|
|
3302
3540
|
{
|
|
3303
3541
|
label: outputLabel,
|
|
3304
3542
|
tone: card.statusTone === "error" ? "error" : "output",
|
|
3305
3543
|
children: output
|
|
3306
3544
|
}
|
|
3307
|
-
)
|
|
3545
|
+
),
|
|
3546
|
+
card.action && onToolAction ? /* @__PURE__ */ jsx23("div", { className: "pt-2", children: /* @__PURE__ */ jsx23(
|
|
3547
|
+
"button",
|
|
3548
|
+
{
|
|
3549
|
+
type: "button",
|
|
3550
|
+
onClick: () => onToolAction(card.action),
|
|
3551
|
+
className: "rounded-md border border-amber-300/70 bg-white/80 px-3 py-1.5 text-[11px] font-semibold text-amber-900 transition-colors hover:bg-amber-100/70",
|
|
3552
|
+
children: card.action.sessionKind === "child" ? "Open child session" : "Open session"
|
|
3553
|
+
}
|
|
3554
|
+
) }) : null
|
|
3308
3555
|
] })
|
|
3309
3556
|
] });
|
|
3310
3557
|
}
|
|
3311
3558
|
|
|
3312
3559
|
// src/components/chat/ui/chat-message-list/chat-tool-card.tsx
|
|
3313
|
-
import { jsx as
|
|
3560
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
3314
3561
|
function isTerminalTool(name) {
|
|
3315
3562
|
const lowered = name.toLowerCase();
|
|
3316
3563
|
return lowered === "exec" || lowered === "exec_command" || lowered === "execute_command" || lowered === "command_execution" || lowered === "bash" || lowered === "shell" || lowered.includes("run_");
|
|
@@ -3323,50 +3570,53 @@ function isSearchTool(name) {
|
|
|
3323
3570
|
const lowered = name.toLowerCase();
|
|
3324
3571
|
return lowered === "grep_search" || lowered === "find_files" || lowered.includes("search");
|
|
3325
3572
|
}
|
|
3326
|
-
function ChatToolCard({
|
|
3573
|
+
function ChatToolCard({
|
|
3574
|
+
card,
|
|
3575
|
+
onToolAction
|
|
3576
|
+
}) {
|
|
3327
3577
|
if (isTerminalTool(card.toolName)) {
|
|
3328
|
-
return /* @__PURE__ */
|
|
3578
|
+
return /* @__PURE__ */ jsx24(TerminalExecutionView, { card });
|
|
3329
3579
|
}
|
|
3330
3580
|
if (isFileEditTool(card.toolName)) {
|
|
3331
|
-
return /* @__PURE__ */
|
|
3581
|
+
return /* @__PURE__ */ jsx24(FileOperationView, { card });
|
|
3332
3582
|
}
|
|
3333
3583
|
if (isSearchTool(card.toolName)) {
|
|
3334
|
-
return /* @__PURE__ */
|
|
3584
|
+
return /* @__PURE__ */ jsx24(SearchSnippetView, { card });
|
|
3335
3585
|
}
|
|
3336
|
-
return /* @__PURE__ */
|
|
3586
|
+
return /* @__PURE__ */ jsx24(GenericToolCard, { card, onToolAction });
|
|
3337
3587
|
}
|
|
3338
3588
|
|
|
3339
3589
|
// src/components/chat/ui/chat-message-list/chat-unknown-part.tsx
|
|
3340
|
-
import { jsx as
|
|
3590
|
+
import { jsx as jsx25, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3341
3591
|
function ChatUnknownPart(props) {
|
|
3342
|
-
return /* @__PURE__ */
|
|
3343
|
-
/* @__PURE__ */
|
|
3592
|
+
return /* @__PURE__ */ jsxs16("div", { className: "rounded-lg border border-gray-200 bg-gray-50 px-2.5 py-2 text-xs text-gray-600", children: [
|
|
3593
|
+
/* @__PURE__ */ jsxs16("div", { className: "font-semibold text-gray-700", children: [
|
|
3344
3594
|
props.label,
|
|
3345
3595
|
": ",
|
|
3346
3596
|
props.rawType
|
|
3347
3597
|
] }),
|
|
3348
|
-
props.text ? /* @__PURE__ */
|
|
3598
|
+
props.text ? /* @__PURE__ */ jsx25("pre", { className: "mt-1 whitespace-pre-wrap break-words text-[11px] text-gray-500", children: props.text }) : null
|
|
3349
3599
|
] });
|
|
3350
3600
|
}
|
|
3351
3601
|
|
|
3352
3602
|
// src/components/chat/ui/chat-message-list/chat-message.tsx
|
|
3353
|
-
import { jsx as
|
|
3603
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
3354
3604
|
var ChatMessage = memo(function ChatMessage2(props) {
|
|
3355
|
-
const { message, texts } = props;
|
|
3605
|
+
const { message, texts, onToolAction } = props;
|
|
3356
3606
|
const { role } = message;
|
|
3357
3607
|
const isUser = role === "user";
|
|
3358
3608
|
const isMessageInProgress = message.status === "pending" || message.status === "streaming";
|
|
3359
|
-
return /* @__PURE__ */
|
|
3609
|
+
return /* @__PURE__ */ jsx26(
|
|
3360
3610
|
"div",
|
|
3361
3611
|
{
|
|
3362
3612
|
className: cn(
|
|
3363
3613
|
"inline-block w-fit max-w-full rounded-2xl border px-4 shadow-sm",
|
|
3364
3614
|
isUser ? "border-primary bg-primary py-3 text-white" : role === "assistant" ? "border-gray-200 bg-white pb-3 pt-4 text-gray-900" : "border-orange-200/80 bg-orange-50/70 py-3 text-gray-900"
|
|
3365
3615
|
),
|
|
3366
|
-
children: /* @__PURE__ */
|
|
3616
|
+
children: /* @__PURE__ */ jsx26("div", { className: "space-y-2", children: message.parts.map((part, index) => {
|
|
3367
3617
|
const { type } = part;
|
|
3368
3618
|
if (type === "markdown") {
|
|
3369
|
-
return /* @__PURE__ */
|
|
3619
|
+
return /* @__PURE__ */ jsx26(
|
|
3370
3620
|
ChatMessageMarkdown,
|
|
3371
3621
|
{
|
|
3372
3622
|
text: part.text,
|
|
@@ -3377,7 +3627,7 @@ var ChatMessage = memo(function ChatMessage2(props) {
|
|
|
3377
3627
|
);
|
|
3378
3628
|
}
|
|
3379
3629
|
if (type === "inline-content") {
|
|
3380
|
-
return /* @__PURE__ */
|
|
3630
|
+
return /* @__PURE__ */ jsx26(
|
|
3381
3631
|
ChatMessageInlineContent,
|
|
3382
3632
|
{
|
|
3383
3633
|
segments: part.segments,
|
|
@@ -3388,7 +3638,7 @@ var ChatMessage = memo(function ChatMessage2(props) {
|
|
|
3388
3638
|
);
|
|
3389
3639
|
}
|
|
3390
3640
|
if (type === "reasoning") {
|
|
3391
|
-
return /* @__PURE__ */
|
|
3641
|
+
return /* @__PURE__ */ jsx26(
|
|
3392
3642
|
ChatReasoningBlock,
|
|
3393
3643
|
{
|
|
3394
3644
|
label: part.label,
|
|
@@ -3400,10 +3650,10 @@ var ChatMessage = memo(function ChatMessage2(props) {
|
|
|
3400
3650
|
);
|
|
3401
3651
|
}
|
|
3402
3652
|
if (type === "tool-card") {
|
|
3403
|
-
return /* @__PURE__ */
|
|
3653
|
+
return /* @__PURE__ */ jsx26("div", { className: "mt-0.5", children: /* @__PURE__ */ jsx26(ChatToolCard, { card: part.card, onToolAction }) }, `tool-${index}`);
|
|
3404
3654
|
}
|
|
3405
3655
|
if (type === "file") {
|
|
3406
|
-
return /* @__PURE__ */
|
|
3656
|
+
return /* @__PURE__ */ jsx26(
|
|
3407
3657
|
ChatMessageFile,
|
|
3408
3658
|
{
|
|
3409
3659
|
file: part.file,
|
|
@@ -3413,7 +3663,7 @@ var ChatMessage = memo(function ChatMessage2(props) {
|
|
|
3413
3663
|
);
|
|
3414
3664
|
}
|
|
3415
3665
|
if (type === "unknown") {
|
|
3416
|
-
return /* @__PURE__ */
|
|
3666
|
+
return /* @__PURE__ */ jsx26(
|
|
3417
3667
|
ChatUnknownPart,
|
|
3418
3668
|
{
|
|
3419
3669
|
label: part.label,
|
|
@@ -3430,9 +3680,9 @@ var ChatMessage = memo(function ChatMessage2(props) {
|
|
|
3430
3680
|
});
|
|
3431
3681
|
|
|
3432
3682
|
// src/components/chat/ui/chat-message-list/chat-message-meta.tsx
|
|
3433
|
-
import { jsxs as
|
|
3683
|
+
import { jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3434
3684
|
function ChatMessageMeta(props) {
|
|
3435
|
-
return /* @__PURE__ */
|
|
3685
|
+
return /* @__PURE__ */ jsxs17(
|
|
3436
3686
|
"div",
|
|
3437
3687
|
{
|
|
3438
3688
|
className: cn(
|
|
@@ -3451,7 +3701,7 @@ function ChatMessageMeta(props) {
|
|
|
3451
3701
|
// src/components/chat/ui/chat-message-list/chat-message-action-copy.tsx
|
|
3452
3702
|
import { useMemo as useMemo6 } from "react";
|
|
3453
3703
|
import { Check as Check5, Copy as Copy2 } from "lucide-react";
|
|
3454
|
-
import { jsx as
|
|
3704
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
3455
3705
|
function ChatMessageActionCopy({
|
|
3456
3706
|
message,
|
|
3457
3707
|
texts
|
|
@@ -3465,7 +3715,7 @@ function ChatMessageActionCopy({
|
|
|
3465
3715
|
}, [message.parts]);
|
|
3466
3716
|
const { copied, copy } = useCopyFeedback({ text: messageText });
|
|
3467
3717
|
if (!messageText) return null;
|
|
3468
|
-
return /* @__PURE__ */
|
|
3718
|
+
return /* @__PURE__ */ jsx27(
|
|
3469
3719
|
"button",
|
|
3470
3720
|
{
|
|
3471
3721
|
type: "button",
|
|
@@ -3473,13 +3723,13 @@ function ChatMessageActionCopy({
|
|
|
3473
3723
|
className: "text-gray-400 hover:text-gray-600 transition-colors p-1 rounded-md hover:bg-gray-100 flex items-center justify-center",
|
|
3474
3724
|
"aria-label": copied ? texts.copiedMessageLabel : texts.copyMessageLabel,
|
|
3475
3725
|
title: copied ? texts.copiedMessageLabel : texts.copyMessageLabel,
|
|
3476
|
-
children: copied ? /* @__PURE__ */
|
|
3726
|
+
children: copied ? /* @__PURE__ */ jsx27(Check5, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx27(Copy2, { className: "h-3.5 w-3.5" })
|
|
3477
3727
|
}
|
|
3478
3728
|
);
|
|
3479
3729
|
}
|
|
3480
3730
|
|
|
3481
3731
|
// src/components/chat/ui/chat-message-list/chat-message-list.tsx
|
|
3482
|
-
import { Fragment as Fragment6, jsx as
|
|
3732
|
+
import { Fragment as Fragment6, jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
3483
3733
|
var INVISIBLE_ONLY_TEXT_PATTERN = /\u200B|\u200C|\u200D|\u2060|\uFEFF/g;
|
|
3484
3734
|
function hasRenderableText(value) {
|
|
3485
3735
|
const trimmed = value.trim();
|
|
@@ -3497,10 +3747,10 @@ function hasRenderableMessageContent(message) {
|
|
|
3497
3747
|
});
|
|
3498
3748
|
}
|
|
3499
3749
|
function ChatMessageTypingFooter() {
|
|
3500
|
-
return /* @__PURE__ */
|
|
3501
|
-
/* @__PURE__ */
|
|
3502
|
-
/* @__PURE__ */
|
|
3503
|
-
/* @__PURE__ */
|
|
3750
|
+
return /* @__PURE__ */ jsx28("div", { className: "flex items-center gap-2 px-1 py-0.5 text-[11px] text-gray-400", children: /* @__PURE__ */ jsxs18("div", { className: "flex space-x-1 items-center h-full", children: [
|
|
3751
|
+
/* @__PURE__ */ jsx28("div", { className: "h-1.5 w-1.5 rounded-full bg-gray-400 animate-pulse" }),
|
|
3752
|
+
/* @__PURE__ */ jsx28("div", { className: "h-1.5 w-1.5 rounded-full bg-gray-400 animate-pulse [animation-delay:200ms]" }),
|
|
3753
|
+
/* @__PURE__ */ jsx28("div", { className: "h-1.5 w-1.5 rounded-full bg-gray-400 animate-pulse [animation-delay:400ms]" })
|
|
3504
3754
|
] }) });
|
|
3505
3755
|
}
|
|
3506
3756
|
function ChatMessageList(props) {
|
|
@@ -3508,118 +3758,35 @@ function ChatMessageList(props) {
|
|
|
3508
3758
|
const hasRenderableAssistantDraft = visibleMessages.some(
|
|
3509
3759
|
(message) => message.role === "assistant" && (message.status === "streaming" || message.status === "pending")
|
|
3510
3760
|
);
|
|
3511
|
-
return /* @__PURE__ */
|
|
3761
|
+
return /* @__PURE__ */ jsxs18("div", { className: cn("space-y-5", props.className), children: [
|
|
3512
3762
|
visibleMessages.map((message) => {
|
|
3513
3763
|
const isUser = message.role === "user";
|
|
3514
3764
|
const isGenerating = !isUser && (message.status === "streaming" || message.status === "pending");
|
|
3515
|
-
return /* @__PURE__ */
|
|
3516
|
-
!isUser ? /* @__PURE__ */
|
|
3517
|
-
/* @__PURE__ */
|
|
3518
|
-
/* @__PURE__ */
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3765
|
+
return /* @__PURE__ */ jsxs18("div", { className: cn("flex gap-3", isUser ? "justify-end" : "justify-start"), children: [
|
|
3766
|
+
!isUser ? /* @__PURE__ */ jsx28(ChatMessageAvatar, { role: message.role }) : null,
|
|
3767
|
+
/* @__PURE__ */ jsxs18("div", { className: cn("w-fit max-w-[92%] space-y-2", isUser && "flex flex-col items-end"), children: [
|
|
3768
|
+
/* @__PURE__ */ jsx28(
|
|
3769
|
+
ChatMessage,
|
|
3770
|
+
{
|
|
3771
|
+
message,
|
|
3772
|
+
texts: props.texts,
|
|
3773
|
+
onToolAction: props.onToolAction
|
|
3774
|
+
}
|
|
3775
|
+
),
|
|
3776
|
+
/* @__PURE__ */ jsx28("div", { className: cn("flex items-center gap-2", isUser && "justify-end"), children: isGenerating ? /* @__PURE__ */ jsx28(ChatMessageTypingFooter, {}) : /* @__PURE__ */ jsxs18(Fragment6, { children: [
|
|
3777
|
+
/* @__PURE__ */ jsx28(ChatMessageMeta, { roleLabel: message.roleLabel, timestampLabel: message.timestampLabel, isUser }),
|
|
3778
|
+
!isUser ? /* @__PURE__ */ jsx28(ChatMessageActionCopy, { message, texts: props.texts }) : null
|
|
3522
3779
|
] }) })
|
|
3523
3780
|
] }),
|
|
3524
|
-
isUser ? /* @__PURE__ */
|
|
3781
|
+
isUser ? /* @__PURE__ */ jsx28(ChatMessageAvatar, { role: message.role }) : null
|
|
3525
3782
|
] }, message.id);
|
|
3526
3783
|
}),
|
|
3527
|
-
props.isSending && !hasRenderableAssistantDraft ? /* @__PURE__ */
|
|
3528
|
-
/* @__PURE__ */
|
|
3529
|
-
/* @__PURE__ */
|
|
3784
|
+
props.isSending && !hasRenderableAssistantDraft ? /* @__PURE__ */ jsxs18("div", { className: "flex justify-start gap-3", children: [
|
|
3785
|
+
/* @__PURE__ */ jsx28(ChatMessageAvatar, { role: "assistant" }),
|
|
3786
|
+
/* @__PURE__ */ jsx28("div", { className: "rounded-2xl border border-gray-200 bg-white px-4 py-3 text-sm text-gray-500 shadow-sm", children: props.texts.typingLabel })
|
|
3530
3787
|
] }) : null
|
|
3531
3788
|
] });
|
|
3532
3789
|
}
|
|
3533
|
-
|
|
3534
|
-
// src/components/chat/hooks/use-sticky-bottom-scroll.ts
|
|
3535
|
-
import { useEffect as useEffect8, useLayoutEffect as useLayoutEffect2, useRef as useRef7 } from "react";
|
|
3536
|
-
var DEFAULT_STICKY_THRESHOLD_PX = 10;
|
|
3537
|
-
function scrollElementToBottom(element) {
|
|
3538
|
-
element.scrollTop = element.scrollHeight;
|
|
3539
|
-
}
|
|
3540
|
-
function queueScrollToBottom(params) {
|
|
3541
|
-
const element = params.scrollRef.current;
|
|
3542
|
-
if (!element) {
|
|
3543
|
-
return;
|
|
3544
|
-
}
|
|
3545
|
-
if (params.scheduledScrollFrameRef.current !== null) {
|
|
3546
|
-
cancelAnimationFrame(params.scheduledScrollFrameRef.current);
|
|
3547
|
-
}
|
|
3548
|
-
params.scheduledScrollFrameRef.current = requestAnimationFrame(() => {
|
|
3549
|
-
params.scheduledScrollFrameRef.current = null;
|
|
3550
|
-
const currentElement = params.scrollRef.current;
|
|
3551
|
-
if (!currentElement) {
|
|
3552
|
-
return;
|
|
3553
|
-
}
|
|
3554
|
-
params.isProgrammaticScrollRef.current = true;
|
|
3555
|
-
scrollElementToBottom(currentElement);
|
|
3556
|
-
});
|
|
3557
|
-
}
|
|
3558
|
-
function useStickyBottomScroll(params) {
|
|
3559
|
-
const isStickyRef = useRef7(true);
|
|
3560
|
-
const isProgrammaticScrollRef = useRef7(false);
|
|
3561
|
-
const previousResetKeyRef = useRef7(null);
|
|
3562
|
-
const pendingInitialScrollRef = useRef7(false);
|
|
3563
|
-
const scheduledScrollFrameRef = useRef7(null);
|
|
3564
|
-
const onScroll = () => {
|
|
3565
|
-
if (isProgrammaticScrollRef.current) {
|
|
3566
|
-
isProgrammaticScrollRef.current = false;
|
|
3567
|
-
return;
|
|
3568
|
-
}
|
|
3569
|
-
const element = params.scrollRef.current;
|
|
3570
|
-
if (!element) {
|
|
3571
|
-
return;
|
|
3572
|
-
}
|
|
3573
|
-
const distanceFromBottom = element.scrollHeight - element.scrollTop - element.clientHeight;
|
|
3574
|
-
isStickyRef.current = distanceFromBottom <= (params.stickyThresholdPx ?? DEFAULT_STICKY_THRESHOLD_PX);
|
|
3575
|
-
};
|
|
3576
|
-
useEffect8(() => {
|
|
3577
|
-
if (previousResetKeyRef.current === params.resetKey) {
|
|
3578
|
-
return;
|
|
3579
|
-
}
|
|
3580
|
-
previousResetKeyRef.current = params.resetKey;
|
|
3581
|
-
isStickyRef.current = true;
|
|
3582
|
-
pendingInitialScrollRef.current = true;
|
|
3583
|
-
}, [params.resetKey]);
|
|
3584
|
-
useEffect8(() => {
|
|
3585
|
-
const scheduledScrollFrame = scheduledScrollFrameRef.current;
|
|
3586
|
-
return () => {
|
|
3587
|
-
if (scheduledScrollFrame !== null) {
|
|
3588
|
-
cancelAnimationFrame(scheduledScrollFrame);
|
|
3589
|
-
}
|
|
3590
|
-
};
|
|
3591
|
-
}, []);
|
|
3592
|
-
useLayoutEffect2(() => {
|
|
3593
|
-
if (!pendingInitialScrollRef.current || params.isLoading || !params.hasContent) {
|
|
3594
|
-
return;
|
|
3595
|
-
}
|
|
3596
|
-
const element = params.scrollRef.current;
|
|
3597
|
-
if (!element) {
|
|
3598
|
-
return;
|
|
3599
|
-
}
|
|
3600
|
-
pendingInitialScrollRef.current = false;
|
|
3601
|
-
queueScrollToBottom({
|
|
3602
|
-
scrollRef: params.scrollRef,
|
|
3603
|
-
scheduledScrollFrameRef,
|
|
3604
|
-
isProgrammaticScrollRef
|
|
3605
|
-
});
|
|
3606
|
-
}, [params.hasContent, params.isLoading, params.scrollRef]);
|
|
3607
|
-
useLayoutEffect2(() => {
|
|
3608
|
-
if (!isStickyRef.current || !params.hasContent) {
|
|
3609
|
-
return;
|
|
3610
|
-
}
|
|
3611
|
-
const element = params.scrollRef.current;
|
|
3612
|
-
if (!element) {
|
|
3613
|
-
return;
|
|
3614
|
-
}
|
|
3615
|
-
queueScrollToBottom({
|
|
3616
|
-
scrollRef: params.scrollRef,
|
|
3617
|
-
scheduledScrollFrameRef,
|
|
3618
|
-
isProgrammaticScrollRef
|
|
3619
|
-
});
|
|
3620
|
-
}, [params.contentVersion, params.hasContent, params.scrollRef]);
|
|
3621
|
-
return { onScroll };
|
|
3622
|
-
}
|
|
3623
3790
|
export {
|
|
3624
3791
|
ChatInputBar,
|
|
3625
3792
|
ChatMessageList,
|