@blade-hq/agent-kit 0.5.1 → 0.5.3
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/{AskUserQuestionBlock-CjvG_pUY.d.ts → AskUserQuestionBlock---kOTouk.d.ts} +2 -2
- package/dist/{SkillStatusBar-B7-EU8A4.d.ts → SkillStatusBar-BKAGU9tr.d.ts} +7 -5
- package/dist/{blade-client-BKiP6U73.d.ts → blade-client-R3cLVOYs.d.ts} +31 -5
- package/dist/{chunk-L2KVYOQP.js → chunk-BFF6D2XV.js} +2 -2
- package/dist/{chunk-UPHYN7CQ.js → chunk-IRCXJHXT.js} +2 -2
- package/dist/{chunk-ROGNJYST.js → chunk-Q6CSM5DE.js} +63 -5
- package/dist/chunk-Q6CSM5DE.js.map +1 -0
- package/dist/{chunk-75BPCDBW.js → chunk-RTBAPZIO.js} +277 -216
- package/dist/chunk-RTBAPZIO.js.map +1 -0
- package/dist/{chunk-DSBIKYKQ.js → chunk-UQEXX57F.js} +16 -10
- package/dist/chunk-UQEXX57F.js.map +1 -0
- package/dist/{chunk-DAFIIANJ.js → chunk-ZQQNSKQS.js} +2 -11
- package/dist/chunk-ZQQNSKQS.js.map +1 -0
- package/dist/client/index.d.ts +11 -7
- package/dist/client/index.js +1 -1
- package/dist/{projection-DIfyh6RK.d.ts → projection-BWYEFYNn.d.ts} +1 -1
- package/dist/react/api/vibe-coding.d.ts +3 -3
- package/dist/react/api/vibe-coding.js +2 -2
- package/dist/react/components/chat/index.d.ts +6 -6
- package/dist/react/components/chat/index.js +5 -5
- package/dist/react/components/plan/index.d.ts +3 -3
- package/dist/react/components/plan/index.js +3 -3
- package/dist/react/components/session/index.js +3 -3
- package/dist/react/components/workspace/index.js +32 -4
- package/dist/react/components/workspace/index.js.map +1 -1
- package/dist/react/index.d.ts +15 -11
- package/dist/react/index.js +6 -6
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/dist/chunk-75BPCDBW.js.map +0 -1
- package/dist/chunk-DAFIIANJ.js.map +0 -1
- package/dist/chunk-DSBIKYKQ.js.map +0 -1
- package/dist/chunk-ROGNJYST.js.map +0 -1
- /package/dist/{chunk-L2KVYOQP.js.map → chunk-BFF6D2XV.js.map} +0 -0
- /package/dist/{chunk-UPHYN7CQ.js.map → chunk-IRCXJHXT.js.map} +0 -0
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
getCodeLanguageFromFilename,
|
|
9
9
|
parseAskUserQuestion,
|
|
10
10
|
useHighlightedCodeHtml
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ZQQNSKQS.js";
|
|
12
12
|
import {
|
|
13
13
|
Collapsible,
|
|
14
14
|
CollapsibleContent,
|
|
15
15
|
CollapsibleTrigger,
|
|
16
16
|
resolveSessionFilePreviewTarget
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-IRCXJHXT.js";
|
|
18
18
|
import {
|
|
19
19
|
buildMessageContent,
|
|
20
20
|
buildToolPreviewKey,
|
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
useUiBridgeStore,
|
|
58
58
|
useUiStore,
|
|
59
59
|
writeFile
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-UQEXX57F.js";
|
|
61
61
|
import {
|
|
62
62
|
registerBridgeIframe,
|
|
63
63
|
tapBridgeEvent
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
ModelOption,
|
|
67
67
|
ModelsConfig,
|
|
68
68
|
ModelsResource
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-Q6CSM5DE.js";
|
|
70
70
|
import {
|
|
71
71
|
cn,
|
|
72
72
|
copyToClipboard
|
|
@@ -80,13 +80,15 @@ import { Eye } from "lucide-react";
|
|
|
80
80
|
import { useCallback as useCallback13 } from "react";
|
|
81
81
|
|
|
82
82
|
// src/react/hooks/use-chat.ts
|
|
83
|
-
import { useCallback, useEffect } from "react";
|
|
83
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
84
84
|
var EMPTY_MESSAGES = [];
|
|
85
85
|
function useChat(sessionId) {
|
|
86
86
|
const messages = useChatStore((s) => s.messages[sessionId] ?? EMPTY_MESSAGES);
|
|
87
87
|
const isStreaming = useChatStore((s) => s.isStreaming[sessionId] ?? false);
|
|
88
88
|
const mode = useSessionStore((s) => s.modes[sessionId] ?? "executing");
|
|
89
89
|
const setAnswerCallback = useAnswerCallbackStore((s) => s.setAnswerCallback);
|
|
90
|
+
const [isStopping, setIsStopping] = useState(false);
|
|
91
|
+
const previousSessionIdRef = useRef(sessionId);
|
|
90
92
|
const send = useCallback(
|
|
91
93
|
(msg, mode2, askuserAnswer, options) => {
|
|
92
94
|
const synthesizedAnswer = askuserAnswer ?? buildPendingAskUserAnswer(sessionId, msg);
|
|
@@ -94,9 +96,27 @@ function useChat(sessionId) {
|
|
|
94
96
|
},
|
|
95
97
|
[sessionId]
|
|
96
98
|
);
|
|
97
|
-
const stop = useCallback(() => {
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
const stop = useCallback(async () => {
|
|
100
|
+
if (isStopping) return;
|
|
101
|
+
setIsStopping(true);
|
|
102
|
+
try {
|
|
103
|
+
await getSocket().stop(sessionId);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error("[chat] stop request failed", error);
|
|
106
|
+
} finally {
|
|
107
|
+
setIsStopping(false);
|
|
108
|
+
}
|
|
109
|
+
}, [isStopping, sessionId]);
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (previousSessionIdRef.current !== sessionId) {
|
|
112
|
+
previousSessionIdRef.current = sessionId;
|
|
113
|
+
setIsStopping(false);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!isStreaming) {
|
|
117
|
+
setIsStopping(false);
|
|
118
|
+
}
|
|
119
|
+
}, [isStreaming, sessionId]);
|
|
100
120
|
const answer = useCallback(
|
|
101
121
|
(msg, toolCallId, answerData) => {
|
|
102
122
|
send(msg, mode, { tool_call_id: toolCallId, ...answerData });
|
|
@@ -107,7 +127,7 @@ function useChat(sessionId) {
|
|
|
107
127
|
setAnswerCallback(sessionId, answer);
|
|
108
128
|
return () => setAnswerCallback(sessionId, void 0);
|
|
109
129
|
}, [answer, sessionId, setAnswerCallback]);
|
|
110
|
-
return { messages, isStreaming, send, stop };
|
|
130
|
+
return { messages, isStreaming, isStopping, send, stop };
|
|
111
131
|
}
|
|
112
132
|
function buildPendingAskUserAnswer(sessionId, message) {
|
|
113
133
|
const session = useSessionStore.getState().sessions.find((item) => item.id === sessionId);
|
|
@@ -180,17 +200,17 @@ import {
|
|
|
180
200
|
useEffect as useEffect7,
|
|
181
201
|
useEffectEvent as useEffectEvent2,
|
|
182
202
|
useMemo as useMemo7,
|
|
183
|
-
useRef as
|
|
184
|
-
useState as
|
|
203
|
+
useRef as useRef5,
|
|
204
|
+
useState as useState8
|
|
185
205
|
} from "react";
|
|
186
206
|
import { createRoot } from "react-dom/client";
|
|
187
207
|
import { toast } from "sonner";
|
|
188
208
|
|
|
189
209
|
// src/react/asr/use-tiptap-voice-input.ts
|
|
190
|
-
import { useCallback as useCallback3, useEffect as useEffect3, useEffectEvent, useRef as
|
|
210
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useEffectEvent, useRef as useRef3 } from "react";
|
|
191
211
|
|
|
192
212
|
// src/react/asr/use-voice-input.ts
|
|
193
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useRef, useState } from "react";
|
|
213
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
194
214
|
|
|
195
215
|
// src/react/asr/voice-input-support.ts
|
|
196
216
|
function isIpHost(hostname) {
|
|
@@ -237,14 +257,14 @@ function matchesRequest(data, requestId) {
|
|
|
237
257
|
return !rid || rid === requestId;
|
|
238
258
|
}
|
|
239
259
|
function useVoiceInput(options) {
|
|
240
|
-
const [status, setStatus] =
|
|
241
|
-
const [error, setError] =
|
|
242
|
-
const [level, setLevel] =
|
|
243
|
-
const sessionRef =
|
|
244
|
-
const startingRef =
|
|
245
|
-
const stoppingRef =
|
|
246
|
-
const unmountedRef =
|
|
247
|
-
const optionsRef =
|
|
260
|
+
const [status, setStatus] = useState2("idle");
|
|
261
|
+
const [error, setError] = useState2(null);
|
|
262
|
+
const [level, setLevel] = useState2(0);
|
|
263
|
+
const sessionRef = useRef2(null);
|
|
264
|
+
const startingRef = useRef2(false);
|
|
265
|
+
const stoppingRef = useRef2(false);
|
|
266
|
+
const unmountedRef = useRef2(false);
|
|
267
|
+
const optionsRef = useRef2(options);
|
|
248
268
|
optionsRef.current = options;
|
|
249
269
|
const reportError = useCallback2((err) => {
|
|
250
270
|
const payload = typeof err === "string" ? { title: err } : err;
|
|
@@ -499,8 +519,8 @@ function useVoiceInput(options) {
|
|
|
499
519
|
// src/react/asr/use-tiptap-voice-input.ts
|
|
500
520
|
function useTiptapVoiceInput(options) {
|
|
501
521
|
const { editorRef, workletUrl, onError } = options;
|
|
502
|
-
const partialRangeRef =
|
|
503
|
-
const lastPartialLenRef =
|
|
522
|
+
const partialRangeRef = useRef3(null);
|
|
523
|
+
const lastPartialLenRef = useRef3(0);
|
|
504
524
|
const handlePartial = useEffectEvent((text) => {
|
|
505
525
|
const ed = editorRef.current;
|
|
506
526
|
if (!ed) return;
|
|
@@ -619,7 +639,7 @@ function VoiceWaveform({ level, color = "currentColor", size = 16 }) {
|
|
|
619
639
|
|
|
620
640
|
// src/react/components/model/ModelSelector.tsx
|
|
621
641
|
import { Loader2, Sparkles } from "lucide-react";
|
|
622
|
-
import { useEffect as useEffect4, useMemo, useRef as
|
|
642
|
+
import { useEffect as useEffect4, useMemo, useRef as useRef4, useState as useState3 } from "react";
|
|
623
643
|
|
|
624
644
|
// src/react/hooks/use-model-preferences.ts
|
|
625
645
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
@@ -704,6 +724,21 @@ function usePreferredModel() {
|
|
|
704
724
|
|
|
705
725
|
// src/react/components/model/ModelSelector.tsx
|
|
706
726
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
727
|
+
var inputModalityLabels = {
|
|
728
|
+
text: "\u6587\u672C",
|
|
729
|
+
image: "\u56FE\u7247",
|
|
730
|
+
file: "\u6587\u4EF6",
|
|
731
|
+
audio: "\u97F3\u9891",
|
|
732
|
+
video: "\u89C6\u9891"
|
|
733
|
+
};
|
|
734
|
+
function getInputModalities(model) {
|
|
735
|
+
const values = model.inputModalities && model.inputModalities.length > 0 ? model.inputModalities : model.supportsImage ? ["text", "image"] : ["text"];
|
|
736
|
+
const normalized = values.map((value) => value.trim().toLowerCase()).filter((value) => value.length > 0);
|
|
737
|
+
return normalized.length > 0 ? Array.from(new Set(normalized)) : ["text"];
|
|
738
|
+
}
|
|
739
|
+
function formatInputModalities(model) {
|
|
740
|
+
return getInputModalities(model).map((value) => inputModalityLabels[value] ?? value).join("\u3001");
|
|
741
|
+
}
|
|
707
742
|
function ModelSelector({
|
|
708
743
|
value,
|
|
709
744
|
onValueChange,
|
|
@@ -712,9 +747,9 @@ function ModelSelector({
|
|
|
712
747
|
placement = "bottom"
|
|
713
748
|
}) {
|
|
714
749
|
const { models, defaultModel, isLoading } = useModelConfig();
|
|
715
|
-
const [isOpen, setIsOpen] =
|
|
716
|
-
const [query, setQuery] =
|
|
717
|
-
const rootRef =
|
|
750
|
+
const [isOpen, setIsOpen] = useState3(false);
|
|
751
|
+
const [query, setQuery] = useState3("");
|
|
752
|
+
const rootRef = useRef4(null);
|
|
718
753
|
useEffect4(() => {
|
|
719
754
|
if (!isOpen) return;
|
|
720
755
|
const closeOnPointerDown = (event) => {
|
|
@@ -729,13 +764,21 @@ function ModelSelector({
|
|
|
729
764
|
const normalized = query.trim().toLowerCase();
|
|
730
765
|
if (!normalized) return models;
|
|
731
766
|
return models.filter(
|
|
732
|
-
(model) =>
|
|
767
|
+
(model) => {
|
|
768
|
+
const inputLabel = formatInputModalities(model).toLowerCase();
|
|
769
|
+
return model.id.toLowerCase().includes(normalized) || model.label.toLowerCase().includes(normalized) || inputLabel.includes(normalized);
|
|
770
|
+
}
|
|
733
771
|
);
|
|
734
772
|
}, [models, query]);
|
|
735
773
|
const canSelect = models.length > 0;
|
|
736
|
-
const
|
|
737
|
-
const
|
|
774
|
+
const selectedModel = models.find((model) => model.id === value);
|
|
775
|
+
const defaultModelOption = models.find((model) => model.id === defaultModel);
|
|
776
|
+
const selectedLabel = selectedModel?.label;
|
|
777
|
+
const defaultLabel = defaultModelOption?.label;
|
|
738
778
|
const label = isLoading ? "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B..." : models.length === 0 ? "\u65E0\u53EF\u7528\u6A21\u578B" : selectedLabel || defaultLabel || value.trim() || "\u672A\u8FDE\u63A5\u5230\u6A21\u578B";
|
|
779
|
+
const activeModel = selectedModel ?? defaultModelOption;
|
|
780
|
+
const activeInputLabel = activeModel ? formatInputModalities(activeModel) : "";
|
|
781
|
+
const selectorTitle = activeInputLabel ? `${label}\uFF0C\u652F\u6301\u8F93\u5165\uFF1A${activeInputLabel}` : label;
|
|
739
782
|
const dropdownPosition = placement === "top" ? "bottom-[calc(100%+8px)]" : "top-[calc(100%+8px)]";
|
|
740
783
|
if (!canSelect) {
|
|
741
784
|
return /* @__PURE__ */ jsxs(
|
|
@@ -758,17 +801,24 @@ function ModelSelector({
|
|
|
758
801
|
disabled,
|
|
759
802
|
onClick: () => setIsOpen((current) => !current),
|
|
760
803
|
className: "flex min-w-0 items-center gap-1 rounded-lg px-2.5 py-[5px] text-[hsl(var(--muted-foreground))] transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] disabled:cursor-not-allowed disabled:opacity-50",
|
|
761
|
-
title:
|
|
804
|
+
title: selectorTitle,
|
|
762
805
|
children: [
|
|
763
806
|
/* @__PURE__ */ jsx2(Sparkles, { size: 14, "aria-hidden": "true" }),
|
|
764
|
-
/* @__PURE__ */ jsx2(
|
|
807
|
+
/* @__PURE__ */ jsx2(
|
|
808
|
+
"span",
|
|
809
|
+
{
|
|
810
|
+
className: `min-w-0 truncate whitespace-nowrap text-xs ${compact ? "max-w-[120px]" : "max-w-[180px]"}`,
|
|
811
|
+
children: label
|
|
812
|
+
}
|
|
813
|
+
),
|
|
814
|
+
activeInputLabel ? /* @__PURE__ */ jsx2("span", { className: "shrink-0 rounded border border-[hsl(var(--border))] px-1 py-0 text-[10px] leading-4 text-[hsl(var(--muted-foreground))]", children: activeInputLabel }) : null
|
|
765
815
|
]
|
|
766
816
|
}
|
|
767
817
|
),
|
|
768
818
|
isOpen && /* @__PURE__ */ jsxs(
|
|
769
819
|
"div",
|
|
770
820
|
{
|
|
771
|
-
className: `absolute left-0 z-50 w-[
|
|
821
|
+
className: `absolute left-0 z-50 w-[320px] overflow-hidden rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--popover))] shadow-xl ${dropdownPosition}`,
|
|
772
822
|
children: [
|
|
773
823
|
/* @__PURE__ */ jsx2("div", { className: "border-b border-[hsl(var(--border))] p-2", children: /* @__PURE__ */ jsx2(
|
|
774
824
|
"input",
|
|
@@ -779,21 +829,28 @@ function ModelSelector({
|
|
|
779
829
|
className: "h-8 w-full rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--background))] px-2.5 text-xs text-[hsl(var(--foreground))] outline-none placeholder:text-[hsl(var(--muted-foreground))] focus:border-[hsl(var(--ring))]"
|
|
780
830
|
}
|
|
781
831
|
) }),
|
|
782
|
-
/* @__PURE__ */ jsx2("div", { className: "max-h-[220px] overflow-y-auto p-1", children: filteredModels.length === 0 ? /* @__PURE__ */ jsx2("div", { className: "px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: "\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B" }) : filteredModels.map((model) =>
|
|
783
|
-
|
|
784
|
-
{
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
832
|
+
/* @__PURE__ */ jsx2("div", { className: "max-h-[220px] overflow-y-auto p-1", children: filteredModels.length === 0 ? /* @__PURE__ */ jsx2("div", { className: "px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: "\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B" }) : filteredModels.map((model) => {
|
|
833
|
+
const inputLabel = formatInputModalities(model);
|
|
834
|
+
const title = model.id === model.label ? `${model.id}\uFF0C\u652F\u6301\u8F93\u5165\uFF1A${inputLabel}` : `${model.label} (${model.id})\uFF0C\u652F\u6301\u8F93\u5165\uFF1A${inputLabel}`;
|
|
835
|
+
return /* @__PURE__ */ jsxs(
|
|
836
|
+
"button",
|
|
837
|
+
{
|
|
838
|
+
type: "button",
|
|
839
|
+
onClick: () => {
|
|
840
|
+
onValueChange(model.id);
|
|
841
|
+
setIsOpen(false);
|
|
842
|
+
setQuery("");
|
|
843
|
+
},
|
|
844
|
+
className: `flex w-full items-center justify-between gap-3 rounded-lg px-3 py-2 text-left text-xs transition-colors ${model.id === value ? "bg-[hsl(var(--accent))] text-[hsl(var(--foreground))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"}`,
|
|
845
|
+
title,
|
|
846
|
+
children: [
|
|
847
|
+
/* @__PURE__ */ jsx2("span", { className: "min-w-0 truncate", children: model.label }),
|
|
848
|
+
/* @__PURE__ */ jsx2("span", { className: "shrink-0 text-[11px] text-[hsl(var(--muted-foreground))]", children: inputLabel })
|
|
849
|
+
]
|
|
790
850
|
},
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
},
|
|
795
|
-
model.id
|
|
796
|
-
)) })
|
|
851
|
+
model.id
|
|
852
|
+
);
|
|
853
|
+
}) })
|
|
797
854
|
]
|
|
798
855
|
}
|
|
799
856
|
)
|
|
@@ -801,7 +858,7 @@ function ModelSelector({
|
|
|
801
858
|
}
|
|
802
859
|
|
|
803
860
|
// src/react/hooks/use-input-history.ts
|
|
804
|
-
import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo2, useState as
|
|
861
|
+
import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo2, useState as useState4 } from "react";
|
|
805
862
|
var MAX_HISTORY_ENTRIES = 50;
|
|
806
863
|
function getStorageKey(sessionId) {
|
|
807
864
|
return sessionId ? `input-history:${sessionId}` : null;
|
|
@@ -826,9 +883,9 @@ function readEntries(storageKey) {
|
|
|
826
883
|
}
|
|
827
884
|
function useInputHistory(sessionId) {
|
|
828
885
|
const storageKey = useMemo2(() => getStorageKey(sessionId), [sessionId]);
|
|
829
|
-
const [entries, setEntries] =
|
|
830
|
-
const [cursor, setCursor] =
|
|
831
|
-
const [draft, setDraft] =
|
|
886
|
+
const [entries, setEntries] = useState4([]);
|
|
887
|
+
const [cursor, setCursor] = useState4(null);
|
|
888
|
+
const [draft, setDraft] = useState4("");
|
|
832
889
|
useEffect5(() => {
|
|
833
890
|
setEntries(readEntries(storageKey));
|
|
834
891
|
setCursor(null);
|
|
@@ -967,7 +1024,7 @@ function skillDisplayName(skill) {
|
|
|
967
1024
|
|
|
968
1025
|
// src/react/components/chat/FileCompletionMenu.tsx
|
|
969
1026
|
import { ChevronRight, File, Folder } from "lucide-react";
|
|
970
|
-
import { forwardRef, useCallback as useCallback5, useImperativeHandle, useMemo as useMemo4, useState as
|
|
1027
|
+
import { forwardRef, useCallback as useCallback5, useImperativeHandle, useMemo as useMemo4, useState as useState5 } from "react";
|
|
971
1028
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
972
1029
|
var ROOT_DIR = ".";
|
|
973
1030
|
function isVisibleEntry(entry) {
|
|
@@ -1071,7 +1128,7 @@ var FileCompletionMenu = forwardRef(
|
|
|
1071
1128
|
}
|
|
1072
1129
|
);
|
|
1073
1130
|
var FileCompletionMenuContent = forwardRef(function FileCompletionMenuContent2({ command, editor, filterQuery, items, onExit, range, sessionId }, ref) {
|
|
1074
|
-
const [rawSelectedIndex, setRawSelectedIndex] =
|
|
1131
|
+
const [rawSelectedIndex, setRawSelectedIndex] = useState5(0);
|
|
1075
1132
|
const filteredEntries = useMemo4(() => filterEntries(items, filterQuery), [filterQuery, items]);
|
|
1076
1133
|
const selectedIndex = filteredEntries.length === 0 ? 0 : Math.min(rawSelectedIndex, filteredEntries.length - 1);
|
|
1077
1134
|
const handleSelect = useCallback5(
|
|
@@ -1152,11 +1209,11 @@ var FileCompletionMenuContent = forwardRef(function FileCompletionMenuContent2({
|
|
|
1152
1209
|
});
|
|
1153
1210
|
|
|
1154
1211
|
// src/react/components/chat/SkillCompletionMenu.tsx
|
|
1155
|
-
import { forwardRef as forwardRef2, useCallback as useCallback6, useImperativeHandle as useImperativeHandle2, useState as
|
|
1212
|
+
import { forwardRef as forwardRef2, useCallback as useCallback6, useImperativeHandle as useImperativeHandle2, useState as useState6 } from "react";
|
|
1156
1213
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1157
1214
|
var SkillCompletionMenu = forwardRef2(
|
|
1158
1215
|
function SkillCompletionMenu2({ command, items }, ref) {
|
|
1159
|
-
const [rawSelectedIndex, setRawSelectedIndex] =
|
|
1216
|
+
const [rawSelectedIndex, setRawSelectedIndex] = useState6(0);
|
|
1160
1217
|
const selectedIndex = items.length === 0 ? 0 : Math.min(rawSelectedIndex, items.length - 1);
|
|
1161
1218
|
const handleSelect = useCallback6(
|
|
1162
1219
|
(item) => {
|
|
@@ -1261,7 +1318,7 @@ var SkillCompletionMenu = forwardRef2(
|
|
|
1261
1318
|
|
|
1262
1319
|
// src/react/components/chat/BackgroundTasksPill.tsx
|
|
1263
1320
|
import { FileText, Square, Terminal } from "lucide-react";
|
|
1264
|
-
import { useState as
|
|
1321
|
+
import { useState as useState7 } from "react";
|
|
1265
1322
|
|
|
1266
1323
|
// src/react/hooks/use-background-tasks.ts
|
|
1267
1324
|
import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
@@ -1310,8 +1367,8 @@ function statusClass(status) {
|
|
|
1310
1367
|
}
|
|
1311
1368
|
function BackgroundTasksPill({ sessionId }) {
|
|
1312
1369
|
const { data: tasks } = useBackgroundTasks(sessionId);
|
|
1313
|
-
const [open, setOpen] =
|
|
1314
|
-
const [logTask, setLogTask] =
|
|
1370
|
+
const [open, setOpen] = useState7(false);
|
|
1371
|
+
const [logTask, setLogTask] = useState7(null);
|
|
1315
1372
|
if (tasks.length === 0) return null;
|
|
1316
1373
|
const runningCount = tasks.filter((task) => task.status === "running").length;
|
|
1317
1374
|
const openTaskLog = async (task) => {
|
|
@@ -2094,20 +2151,38 @@ function ComposerFilePill({
|
|
|
2094
2151
|
const isFile = attachment.kind === "file";
|
|
2095
2152
|
const isFailed = isFile && attachment.status === "failed";
|
|
2096
2153
|
const isUploading = isFile && attachment.status === "uploading";
|
|
2154
|
+
const uploadPercent = isUploading && typeof attachment.uploadProgress === "number" ? Math.max(0, Math.min(100, Math.round(attachment.uploadProgress * 100))) : null;
|
|
2097
2155
|
return /* @__PURE__ */ jsxs8(
|
|
2098
2156
|
"div",
|
|
2099
2157
|
{
|
|
2100
|
-
className: `flex shrink-0 items-center gap-1.5 rounded-full border px-2.5 py-1 text-[11px] ${isFailed ? "border-red-500/30 bg-red-500/5 text-red-400" : "border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--foreground))]"}`,
|
|
2158
|
+
className: `relative flex shrink-0 items-center gap-1.5 overflow-hidden rounded-full border px-2.5 py-1 text-[11px] ${isFailed ? "border-red-500/30 bg-red-500/5 text-red-400" : "border-[hsl(var(--border))] bg-[hsl(var(--card))] text-[hsl(var(--foreground))]"}`,
|
|
2101
2159
|
children: [
|
|
2102
|
-
|
|
2103
|
-
|
|
2160
|
+
uploadPercent !== null ? /* @__PURE__ */ jsx9(
|
|
2161
|
+
"span",
|
|
2162
|
+
{
|
|
2163
|
+
className: "absolute inset-y-0 left-0 bg-[hsl(var(--primary))]/10 transition-[width]",
|
|
2164
|
+
style: { width: `${uploadPercent}%` }
|
|
2165
|
+
}
|
|
2166
|
+
) : null,
|
|
2167
|
+
isUploading ? /* @__PURE__ */ jsx9(
|
|
2168
|
+
Loader22,
|
|
2169
|
+
{
|
|
2170
|
+
size: 12,
|
|
2171
|
+
className: "relative z-10 shrink-0 animate-spin text-[hsl(var(--muted-foreground))]"
|
|
2172
|
+
}
|
|
2173
|
+
) : /* @__PURE__ */ jsx9(Icon, { size: 12, className: "relative z-10 shrink-0 text-[hsl(var(--muted-foreground))]" }),
|
|
2174
|
+
/* @__PURE__ */ jsx9("span", { className: "relative z-10 max-w-32 truncate", children: attachment.name }),
|
|
2175
|
+
uploadPercent !== null ? /* @__PURE__ */ jsxs8("span", { className: "relative z-10 font-mono text-[10px] tabular-nums text-[hsl(var(--muted-foreground))]", children: [
|
|
2176
|
+
uploadPercent,
|
|
2177
|
+
"%"
|
|
2178
|
+
] }) : null,
|
|
2104
2179
|
/* @__PURE__ */ jsx9(
|
|
2105
2180
|
"button",
|
|
2106
2181
|
{
|
|
2107
2182
|
type: "button",
|
|
2108
2183
|
onClick: () => onRemove(attachment.id),
|
|
2109
2184
|
"aria-label": `\u79FB\u9664 ${attachment.name}`,
|
|
2110
|
-
className: "ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full text-[hsl(var(--muted-foreground))] transition hover:text-rose-400",
|
|
2185
|
+
className: "relative z-10 ml-0.5 inline-flex shrink-0 items-center justify-center rounded-full text-[hsl(var(--muted-foreground))] transition hover:text-rose-400",
|
|
2111
2186
|
children: /* @__PURE__ */ jsx9(X2, { size: 10 })
|
|
2112
2187
|
}
|
|
2113
2188
|
)
|
|
@@ -2121,13 +2196,13 @@ function AddContextDialog({
|
|
|
2121
2196
|
onAdd
|
|
2122
2197
|
}) {
|
|
2123
2198
|
const CONTEXT_INLINE_THRESHOLD = 200;
|
|
2124
|
-
const [label, setLabel] =
|
|
2125
|
-
const [content, setContent] =
|
|
2126
|
-
const [showSessionPicker, setShowSessionPicker] =
|
|
2127
|
-
const [sessions, setSessions] =
|
|
2128
|
-
const [loadingSessions, setLoadingSessions] =
|
|
2129
|
-
const [importingId, setImportingId] =
|
|
2130
|
-
const [isImportProcessing, setIsImportProcessing] =
|
|
2199
|
+
const [label, setLabel] = useState8("");
|
|
2200
|
+
const [content, setContent] = useState8("");
|
|
2201
|
+
const [showSessionPicker, setShowSessionPicker] = useState8(false);
|
|
2202
|
+
const [sessions, setSessions] = useState8([]);
|
|
2203
|
+
const [loadingSessions, setLoadingSessions] = useState8(false);
|
|
2204
|
+
const [importingId, setImportingId] = useState8(null);
|
|
2205
|
+
const [isImportProcessing, setIsImportProcessing] = useState8(false);
|
|
2131
2206
|
const sanitizeContextFolderName = (raw) => {
|
|
2132
2207
|
const normalized = raw.trim().toLowerCase();
|
|
2133
2208
|
const safe = normalized.replace(/[^\w\-.\u4e00-\u9fa5]+/g, "_").replace(/^_+|_+$/g, "");
|
|
@@ -2357,7 +2432,7 @@ function ComposerContextPill({
|
|
|
2357
2432
|
content,
|
|
2358
2433
|
onRemove
|
|
2359
2434
|
}) {
|
|
2360
|
-
const [showDetail, setShowDetail] =
|
|
2435
|
+
const [showDetail, setShowDetail] = useState8(false);
|
|
2361
2436
|
const tokenK = formatTokenK(content);
|
|
2362
2437
|
return /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
2363
2438
|
/* @__PURE__ */ jsxs8("div", { className: "flex shrink-0 items-center gap-1.5 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--accent))] px-2.5 py-1 text-[11px] text-[hsl(var(--foreground))]", children: [
|
|
@@ -2552,6 +2627,7 @@ function ChatInput({
|
|
|
2552
2627
|
onSend,
|
|
2553
2628
|
onStop,
|
|
2554
2629
|
isStreaming,
|
|
2630
|
+
isStopping = false,
|
|
2555
2631
|
mode = "executing",
|
|
2556
2632
|
onToggleMode,
|
|
2557
2633
|
renderAttachments,
|
|
@@ -2571,13 +2647,13 @@ function ChatInput({
|
|
|
2571
2647
|
onResyncSkills,
|
|
2572
2648
|
isResyncingSkills = false
|
|
2573
2649
|
}) {
|
|
2574
|
-
const [input, setInputInternal] =
|
|
2650
|
+
const [input, setInputInternal] = useState8(externalDraft?.value ?? "");
|
|
2575
2651
|
const setInput = useEffectEvent2((value) => {
|
|
2576
2652
|
setInputInternal(value);
|
|
2577
2653
|
externalDraft?.setValue(value);
|
|
2578
2654
|
});
|
|
2579
2655
|
const externalDraftValue = externalDraft?.value;
|
|
2580
|
-
const inputRef =
|
|
2656
|
+
const inputRef = useRef5(input);
|
|
2581
2657
|
inputRef.current = input;
|
|
2582
2658
|
useEffect7(() => {
|
|
2583
2659
|
if (externalDraftValue == null) return;
|
|
@@ -2587,7 +2663,7 @@ function ChatInput({
|
|
|
2587
2663
|
}
|
|
2588
2664
|
setInputInternal(externalDraftValue);
|
|
2589
2665
|
}, [externalDraftValue]);
|
|
2590
|
-
const [composerAttachments, setComposerAttachmentsInternal] =
|
|
2666
|
+
const [composerAttachments, setComposerAttachmentsInternal] = useState8(
|
|
2591
2667
|
externalAttachments?.value ?? []
|
|
2592
2668
|
);
|
|
2593
2669
|
const setComposerAttachments = useEffectEvent2(
|
|
@@ -2600,24 +2676,24 @@ function ChatInput({
|
|
|
2600
2676
|
}
|
|
2601
2677
|
);
|
|
2602
2678
|
const externalAttachmentsValue = externalAttachments?.value;
|
|
2603
|
-
const composerAttachmentsRef =
|
|
2679
|
+
const composerAttachmentsRef = useRef5(composerAttachments);
|
|
2604
2680
|
composerAttachmentsRef.current = composerAttachments;
|
|
2605
2681
|
useEffect7(() => {
|
|
2606
2682
|
if (externalAttachmentsValue == null) return;
|
|
2607
2683
|
if (composerAttachmentsRef.current === externalAttachmentsValue) return;
|
|
2608
2684
|
setComposerAttachmentsInternal(externalAttachmentsValue);
|
|
2609
2685
|
}, [externalAttachmentsValue]);
|
|
2610
|
-
const [dragging, setDragging] =
|
|
2611
|
-
const [isEditorFocused, setIsEditorFocused] =
|
|
2612
|
-
const [oversizedFiles, setOversizedFiles] =
|
|
2613
|
-
const [selectedModel, setSelectedModel] =
|
|
2686
|
+
const [dragging, setDragging] = useState8(false);
|
|
2687
|
+
const [isEditorFocused, setIsEditorFocused] = useState8(false);
|
|
2688
|
+
const [oversizedFiles, setOversizedFiles] = useState8([]);
|
|
2689
|
+
const [selectedModel, setSelectedModel] = useState8("");
|
|
2614
2690
|
const { setPreferredModel } = usePreferredModel();
|
|
2615
2691
|
const queryClient = useQueryClient2();
|
|
2616
|
-
const actionMenuRef =
|
|
2617
|
-
const fileInputRef =
|
|
2618
|
-
const folderInputRef =
|
|
2619
|
-
const editorRef =
|
|
2620
|
-
const localImageUrlsRef =
|
|
2692
|
+
const actionMenuRef = useRef5(null);
|
|
2693
|
+
const fileInputRef = useRef5(null);
|
|
2694
|
+
const folderInputRef = useRef5(null);
|
|
2695
|
+
const editorRef = useRef5(null);
|
|
2696
|
+
const localImageUrlsRef = useRef5(/* @__PURE__ */ new Map());
|
|
2621
2697
|
const activeSessionId = useSessionStore((state) => state.activeSessionId);
|
|
2622
2698
|
const sessions = useSessionStore((state) => state.sessions);
|
|
2623
2699
|
const activeSessionModel = useMemo7(
|
|
@@ -2650,7 +2726,7 @@ function ChatInput({
|
|
|
2650
2726
|
const inputHistory = useInputHistory(activeSessionId);
|
|
2651
2727
|
const getSessionId = useEffectEvent2(() => activeSessionId);
|
|
2652
2728
|
const handleSlashCommand = useEffectEvent2((commandId) => onCommand?.(commandId));
|
|
2653
|
-
const [localImageUrls, setLocalImageUrls] =
|
|
2729
|
+
const [localImageUrls, setLocalImageUrls] = useState8({});
|
|
2654
2730
|
useEffect7(() => {
|
|
2655
2731
|
const closeActionMenu = (event) => {
|
|
2656
2732
|
const menu = actionMenuRef.current;
|
|
@@ -2979,7 +3055,7 @@ function ChatInput({
|
|
|
2979
3055
|
editor.commands.focus("end");
|
|
2980
3056
|
setRewindDraft(activeSessionId, null);
|
|
2981
3057
|
}, [activeSessionId, editor, rewindDraft, setRewindDraft]);
|
|
2982
|
-
const submittingRef =
|
|
3058
|
+
const submittingRef = useRef5(false);
|
|
2983
3059
|
useEffect7(() => {
|
|
2984
3060
|
let changed = false;
|
|
2985
3061
|
const nextLocalIds = /* @__PURE__ */ new Set();
|
|
@@ -3058,14 +3134,14 @@ function ChatInput({
|
|
|
3058
3134
|
});
|
|
3059
3135
|
const { isRecording, level: voiceLevel } = voice;
|
|
3060
3136
|
const handleMicDisabledClick = () => toast.info("\u8BED\u97F3\u8F93\u5165\u529F\u80FD\u672A\u5F00\u542F\uFF0C\u8BF7\u5728\u540E\u7AEF .env \u914D\u7F6E ASR_API_KEY");
|
|
3061
|
-
const voiceStopRef =
|
|
3137
|
+
const voiceStopRef = useRef5(voice.stop);
|
|
3062
3138
|
voiceStopRef.current = voice.stop;
|
|
3063
3139
|
useEffect7(() => {
|
|
3064
3140
|
if (isStreaming && isRecording) {
|
|
3065
3141
|
void voiceStopRef.current();
|
|
3066
3142
|
}
|
|
3067
3143
|
}, [isStreaming, isRecording]);
|
|
3068
|
-
const prevSessionIdRef =
|
|
3144
|
+
const prevSessionIdRef = useRef5(activeSessionId);
|
|
3069
3145
|
useEffect7(() => {
|
|
3070
3146
|
if (prevSessionIdRef.current !== activeSessionId) {
|
|
3071
3147
|
prevSessionIdRef.current = activeSessionId;
|
|
@@ -3116,14 +3192,24 @@ function ChatInput({
|
|
|
3116
3192
|
if (pendingFiles.length > 0) {
|
|
3117
3193
|
setComposerAttachments(
|
|
3118
3194
|
(prev) => prev.map(
|
|
3119
|
-
(a) => a.kind === "file" && a.status === "pending" ? { ...a, status: "uploading" } : a
|
|
3195
|
+
(a) => a.kind === "file" && a.status === "pending" ? { ...a, status: "uploading", uploadProgress: 0 } : a
|
|
3120
3196
|
)
|
|
3121
3197
|
);
|
|
3122
3198
|
try {
|
|
3123
3199
|
const result = await uploadFiles(
|
|
3124
3200
|
uploadSessionId,
|
|
3125
3201
|
".",
|
|
3126
|
-
pendingFiles.map((a) => ({ file: a.file, name: a.name }))
|
|
3202
|
+
pendingFiles.map((a) => ({ file: a.file, name: a.name })),
|
|
3203
|
+
{
|
|
3204
|
+
onProgress: (progress) => {
|
|
3205
|
+
if (typeof progress.percent !== "number") return;
|
|
3206
|
+
setComposerAttachments(
|
|
3207
|
+
(prev) => prev.map(
|
|
3208
|
+
(a) => pendingFiles.some((pending) => pending.id === a.id) && a.kind === "file" && a.status === "uploading" ? { ...a, uploadProgress: progress.percent } : a
|
|
3209
|
+
)
|
|
3210
|
+
);
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3127
3213
|
);
|
|
3128
3214
|
const uploadResultById = /* @__PURE__ */ new Map();
|
|
3129
3215
|
const failedSet = new Set(result.failed);
|
|
@@ -3139,9 +3225,15 @@ function ChatInput({
|
|
|
3139
3225
|
updatedAttachments = composerAttachments.map((a) => {
|
|
3140
3226
|
if (!uploadResultById.has(a.id)) return a;
|
|
3141
3227
|
const uploadedPath = uploadResultById.get(a.id);
|
|
3142
|
-
if (!uploadedPath) return { ...a, status: "failed" };
|
|
3228
|
+
if (!uploadedPath) return { ...a, status: "failed", uploadProgress: null };
|
|
3143
3229
|
const actualName = uploadedPath.split("/").pop() || a.name;
|
|
3144
|
-
return {
|
|
3230
|
+
return {
|
|
3231
|
+
...a,
|
|
3232
|
+
name: actualName,
|
|
3233
|
+
status: "uploaded",
|
|
3234
|
+
uploadedPath,
|
|
3235
|
+
uploadProgress: null
|
|
3236
|
+
};
|
|
3145
3237
|
});
|
|
3146
3238
|
setComposerAttachments(updatedAttachments);
|
|
3147
3239
|
if (result.uploaded.length > 0) {
|
|
@@ -3183,7 +3275,7 @@ function ChatInput({
|
|
|
3183
3275
|
const removeAttachment = (id) => {
|
|
3184
3276
|
setComposerAttachments((prev) => prev.filter((attachment) => attachment.id !== id));
|
|
3185
3277
|
};
|
|
3186
|
-
const [showAddContext, setShowAddContext] =
|
|
3278
|
+
const [showAddContext, setShowAddContext] = useState8(false);
|
|
3187
3279
|
const isPlanning = mode === "planning";
|
|
3188
3280
|
const placeholder = isPlanning ? "\u89C4\u5212\u8FDB\u884C\u4E2D\u2026 \u53EF\u8F93\u5165\u8865\u5145\u9700\u6C42\u6216\u7B49\u5F85\u5B8C\u6210" : "\u8F93\u5165\u6D88\u606F\u2026";
|
|
3189
3281
|
const attachments = renderAttachments?.() ?? null;
|
|
@@ -3559,10 +3651,11 @@ function ChatInput({
|
|
|
3559
3651
|
"button",
|
|
3560
3652
|
{
|
|
3561
3653
|
type: "button",
|
|
3562
|
-
onClick: onStop,
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3654
|
+
onClick: () => void onStop(),
|
|
3655
|
+
disabled: isStopping,
|
|
3656
|
+
"aria-label": isStopping ? "\u6B63\u5728\u505C\u6B62" : "\u505C\u6B62\u751F\u6210",
|
|
3657
|
+
className: "flex h-7 w-7 items-center justify-center rounded-lg bg-[hsl(var(--destructive))] text-[hsl(var(--destructive-foreground))] transition-opacity hover:opacity-80 disabled:cursor-wait disabled:opacity-70",
|
|
3658
|
+
children: isStopping ? /* @__PURE__ */ jsx9(Loader22, { size: 13, className: "animate-spin" }) : /* @__PURE__ */ jsx9(Square2, { size: 13 })
|
|
3566
3659
|
}
|
|
3567
3660
|
) : /* @__PURE__ */ jsx9(
|
|
3568
3661
|
"button",
|
|
@@ -3652,12 +3745,12 @@ import {
|
|
|
3652
3745
|
useEffect as useEffect16,
|
|
3653
3746
|
useEffectEvent as useEffectEvent4,
|
|
3654
3747
|
useMemo as useMemo17,
|
|
3655
|
-
useRef as
|
|
3656
|
-
useState as
|
|
3748
|
+
useRef as useRef12,
|
|
3749
|
+
useState as useState21
|
|
3657
3750
|
} from "react";
|
|
3658
3751
|
|
|
3659
3752
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
|
|
3660
|
-
import { useCallback as useCallback7, useMemo as useMemo8, useRef as
|
|
3753
|
+
import { useCallback as useCallback7, useMemo as useMemo8, useRef as useRef6, useState as useState9 } from "react";
|
|
3661
3754
|
var DEFAULT_SPRING_ANIMATION = {
|
|
3662
3755
|
/**
|
|
3663
3756
|
* A value from 0 to 1, on how much to damp the animation.
|
|
@@ -3694,10 +3787,10 @@ globalThis.document?.addEventListener("click", () => {
|
|
|
3694
3787
|
mouseDown = false;
|
|
3695
3788
|
});
|
|
3696
3789
|
var useStickToBottom = (options = {}) => {
|
|
3697
|
-
const [escapedFromLock, updateEscapedFromLock] =
|
|
3698
|
-
const [isAtBottom, updateIsAtBottom] =
|
|
3699
|
-
const [isNearBottom, setIsNearBottom] =
|
|
3700
|
-
const optionsRef =
|
|
3790
|
+
const [escapedFromLock, updateEscapedFromLock] = useState9(false);
|
|
3791
|
+
const [isAtBottom, updateIsAtBottom] = useState9(options.initial !== false);
|
|
3792
|
+
const [isNearBottom, setIsNearBottom] = useState9(false);
|
|
3793
|
+
const optionsRef = useRef6(null);
|
|
3701
3794
|
optionsRef.current = options;
|
|
3702
3795
|
const isSelecting = useCallback7(() => {
|
|
3703
3796
|
if (!mouseDown) {
|
|
@@ -4001,11 +4094,11 @@ function mergeAnimations(...animations) {
|
|
|
4001
4094
|
|
|
4002
4095
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js
|
|
4003
4096
|
import * as React from "react";
|
|
4004
|
-
import { createContext, useContext, useEffect as useEffect8, useImperativeHandle as useImperativeHandle3, useLayoutEffect, useMemo as useMemo9, useRef as
|
|
4097
|
+
import { createContext, useContext, useEffect as useEffect8, useImperativeHandle as useImperativeHandle3, useLayoutEffect, useMemo as useMemo9, useRef as useRef7 } from "react";
|
|
4005
4098
|
var StickToBottomContext = createContext(null);
|
|
4006
4099
|
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect8;
|
|
4007
4100
|
function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {
|
|
4008
|
-
const customTargetScrollTop =
|
|
4101
|
+
const customTargetScrollTop = useRef7(null);
|
|
4009
4102
|
const targetScrollTop = React.useCallback((target, elements) => {
|
|
4010
4103
|
const get = context?.targetScrollTop ?? currentTargetScrollTop;
|
|
4011
4104
|
return get?.(target, elements) ?? target;
|
|
@@ -4082,7 +4175,7 @@ function useStickToBottomContext() {
|
|
|
4082
4175
|
|
|
4083
4176
|
// src/react/components/chat/AssistantTurnBlock.tsx
|
|
4084
4177
|
import { AlertCircle, BookOpen, Check as Check4, ChevronRight as ChevronRight5 } from "lucide-react";
|
|
4085
|
-
import { useCallback as useCallback11, useEffect as useEffect14, useMemo as useMemo15, useRef as
|
|
4178
|
+
import { useCallback as useCallback11, useEffect as useEffect14, useMemo as useMemo15, useRef as useRef11, useState as useState18 } from "react";
|
|
4086
4179
|
|
|
4087
4180
|
// src/react/routes.ts
|
|
4088
4181
|
var MEMORIES_ROUTE = "/memories";
|
|
@@ -4100,8 +4193,8 @@ import {
|
|
|
4100
4193
|
useContext as useContext2,
|
|
4101
4194
|
useEffect as useEffect9,
|
|
4102
4195
|
useMemo as useMemo11,
|
|
4103
|
-
useRef as
|
|
4104
|
-
useState as
|
|
4196
|
+
useRef as useRef8,
|
|
4197
|
+
useState as useState10
|
|
4105
4198
|
} from "react";
|
|
4106
4199
|
import { createPortal as createPortal2 } from "react-dom";
|
|
4107
4200
|
import { Streamdown } from "streamdown";
|
|
@@ -4168,7 +4261,6 @@ var useReasoning = () => {
|
|
|
4168
4261
|
}
|
|
4169
4262
|
return context;
|
|
4170
4263
|
};
|
|
4171
|
-
var AUTO_CLOSE_DELAY = 3e3;
|
|
4172
4264
|
var MS_IN_S = 1e3;
|
|
4173
4265
|
var Reasoning = memo2(
|
|
4174
4266
|
({
|
|
@@ -4181,10 +4273,8 @@ var Reasoning = memo2(
|
|
|
4181
4273
|
children,
|
|
4182
4274
|
...props
|
|
4183
4275
|
}) => {
|
|
4184
|
-
const resolvedDefaultOpen = defaultOpen ?? isStreaming;
|
|
4185
|
-
const isExplicitlyClosed = defaultOpen === false;
|
|
4186
4276
|
const [isOpen, setIsOpen] = useControllableState({
|
|
4187
|
-
defaultProp:
|
|
4277
|
+
defaultProp: defaultOpen ?? false,
|
|
4188
4278
|
onChange: onOpenChange,
|
|
4189
4279
|
prop: open
|
|
4190
4280
|
});
|
|
@@ -4192,12 +4282,9 @@ var Reasoning = memo2(
|
|
|
4192
4282
|
defaultProp: void 0,
|
|
4193
4283
|
prop: durationProp
|
|
4194
4284
|
});
|
|
4195
|
-
const
|
|
4196
|
-
const [hasAutoClosed, setHasAutoClosed] = useState9(false);
|
|
4197
|
-
const startTimeRef = useRef7(null);
|
|
4285
|
+
const startTimeRef = useRef8(null);
|
|
4198
4286
|
useEffect9(() => {
|
|
4199
4287
|
if (isStreaming) {
|
|
4200
|
-
hasEverStreamedRef.current = true;
|
|
4201
4288
|
if (startTimeRef.current === null) {
|
|
4202
4289
|
startTimeRef.current = Date.now();
|
|
4203
4290
|
}
|
|
@@ -4206,20 +4293,6 @@ var Reasoning = memo2(
|
|
|
4206
4293
|
startTimeRef.current = null;
|
|
4207
4294
|
}
|
|
4208
4295
|
}, [isStreaming, setDuration]);
|
|
4209
|
-
useEffect9(() => {
|
|
4210
|
-
if (isStreaming && !isOpen && !isExplicitlyClosed) {
|
|
4211
|
-
setIsOpen(true);
|
|
4212
|
-
}
|
|
4213
|
-
}, [isStreaming, isOpen, setIsOpen, isExplicitlyClosed]);
|
|
4214
|
-
useEffect9(() => {
|
|
4215
|
-
if (hasEverStreamedRef.current && !isStreaming && isOpen && !hasAutoClosed) {
|
|
4216
|
-
const timer = setTimeout(() => {
|
|
4217
|
-
setIsOpen(false);
|
|
4218
|
-
setHasAutoClosed(true);
|
|
4219
|
-
}, AUTO_CLOSE_DELAY);
|
|
4220
|
-
return () => clearTimeout(timer);
|
|
4221
|
-
}
|
|
4222
|
-
}, [isStreaming, isOpen, setIsOpen, hasAutoClosed]);
|
|
4223
4296
|
const handleOpenChange = useCallback9(
|
|
4224
4297
|
(newOpen) => {
|
|
4225
4298
|
setIsOpen(newOpen);
|
|
@@ -4233,7 +4306,7 @@ var Reasoning = memo2(
|
|
|
4233
4306
|
return /* @__PURE__ */ jsx12(ReasoningContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx12(
|
|
4234
4307
|
Collapsible,
|
|
4235
4308
|
{
|
|
4236
|
-
className: cn("not-prose
|
|
4309
|
+
className: cn("not-prose", className),
|
|
4237
4310
|
onOpenChange: handleOpenChange,
|
|
4238
4311
|
open: isOpen,
|
|
4239
4312
|
...props,
|
|
@@ -4242,38 +4315,36 @@ var Reasoning = memo2(
|
|
|
4242
4315
|
) });
|
|
4243
4316
|
}
|
|
4244
4317
|
);
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
}
|
|
4249
|
-
if (duration === void 0) {
|
|
4250
|
-
return /* @__PURE__ */ jsx12("p", { children: "\u5DF2\u6DF1\u5EA6\u601D\u8003" });
|
|
4251
|
-
}
|
|
4252
|
-
return /* @__PURE__ */ jsxs10("p", { children: [
|
|
4253
|
-
"\u5DF2\u6DF1\u5EA6\u601D\u8003 ",
|
|
4254
|
-
duration,
|
|
4255
|
-
" \u79D2"
|
|
4256
|
-
] });
|
|
4257
|
-
};
|
|
4318
|
+
function formatWordCount(value) {
|
|
4319
|
+
return new Intl.NumberFormat("zh-CN").format(value);
|
|
4320
|
+
}
|
|
4258
4321
|
var ReasoningTrigger = memo2(
|
|
4259
4322
|
({
|
|
4260
4323
|
className,
|
|
4261
4324
|
children,
|
|
4262
|
-
|
|
4325
|
+
wordCount,
|
|
4263
4326
|
...props
|
|
4264
4327
|
}) => {
|
|
4265
4328
|
const { isStreaming, isOpen, duration } = useReasoning();
|
|
4329
|
+
const status = isStreaming || duration === 0 ? "\u6B63\u5728\u601D\u8003" : "\u5DF2\u601D\u8003";
|
|
4330
|
+
const detail = `${formatWordCount(wordCount)} \u5B57`;
|
|
4266
4331
|
return /* @__PURE__ */ jsx12(
|
|
4267
4332
|
CollapsibleTrigger,
|
|
4268
4333
|
{
|
|
4269
4334
|
className: cn(
|
|
4270
|
-
"flex w-
|
|
4335
|
+
"flex w-fit items-center gap-2 rounded-full px-1 py-0.5 text-muted-foreground text-sm transition-colors hover:text-foreground",
|
|
4271
4336
|
className
|
|
4272
4337
|
),
|
|
4273
4338
|
...props,
|
|
4274
4339
|
children: children ?? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
4275
4340
|
/* @__PURE__ */ jsx12(BrainIcon, { className: "size-4" }),
|
|
4276
|
-
|
|
4341
|
+
/* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
4342
|
+
isStreaming || duration === 0 ? /* @__PURE__ */ jsx12(Shimmer, { duration: 1, children: status }) : /* @__PURE__ */ jsx12("span", { children: status }),
|
|
4343
|
+
/* @__PURE__ */ jsxs10("span", { className: "text-[hsl(var(--muted-foreground))]/70", children: [
|
|
4344
|
+
"\xB7 ",
|
|
4345
|
+
detail
|
|
4346
|
+
] })
|
|
4347
|
+
] }),
|
|
4277
4348
|
/* @__PURE__ */ jsx12(
|
|
4278
4349
|
ChevronDownIcon,
|
|
4279
4350
|
{
|
|
@@ -4295,7 +4366,7 @@ var ReasoningContent = memo2(
|
|
|
4295
4366
|
CollapsibleContent,
|
|
4296
4367
|
{
|
|
4297
4368
|
className: cn(
|
|
4298
|
-
"mt-
|
|
4369
|
+
"mt-2 max-h-60 overflow-auto rounded-lg border border-[hsl(var(--border))] bg-[hsl(var(--muted))]/20 px-3 py-2 text-sm",
|
|
4299
4370
|
"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
4300
4371
|
className
|
|
4301
4372
|
),
|
|
@@ -4309,7 +4380,7 @@ function compactReasoningText(text) {
|
|
|
4309
4380
|
}
|
|
4310
4381
|
function ThinkingBadge({ reasoning, variant = "inline", onClick }) {
|
|
4311
4382
|
const compactReasoning = compactReasoningText(reasoning);
|
|
4312
|
-
const [open, setOpen] =
|
|
4383
|
+
const [open, setOpen] = useState10(false);
|
|
4313
4384
|
return /* @__PURE__ */ jsxs10(
|
|
4314
4385
|
"span",
|
|
4315
4386
|
{
|
|
@@ -4386,10 +4457,10 @@ ReasoningContent.displayName = "ReasoningContent";
|
|
|
4386
4457
|
|
|
4387
4458
|
// src/react/components/chat/AgentLoopBlock.tsx
|
|
4388
4459
|
import { Bot, Check as Check3, ChevronRight as ChevronRight4, FileText as FileText6, Loader2 as Loader24, MessageSquareMore as MessageSquareMore2 } from "lucide-react";
|
|
4389
|
-
import { useEffect as useEffect13, useMemo as useMemo14, useState as
|
|
4460
|
+
import { useEffect as useEffect13, useMemo as useMemo14, useState as useState17 } from "react";
|
|
4390
4461
|
|
|
4391
4462
|
// src/react/components/chat/ResourceIframe.tsx
|
|
4392
|
-
import { useEffect as useEffect10, useEffectEvent as useEffectEvent3, useRef as
|
|
4463
|
+
import { useEffect as useEffect10, useEffectEvent as useEffectEvent3, useRef as useRef9, useState as useState11 } from "react";
|
|
4393
4464
|
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
4394
4465
|
function isResourceBridgeMessage(value) {
|
|
4395
4466
|
return typeof value === "object" && value !== null && value.__resourceBridge === true && typeof value.action === "string";
|
|
@@ -4398,8 +4469,8 @@ var INLINE_HEIGHT_MIN = 80;
|
|
|
4398
4469
|
var INLINE_HEIGHT_MAX = 6e3;
|
|
4399
4470
|
var INLINE_HEIGHT_PADDING = 8;
|
|
4400
4471
|
function ResourceIframe({ ui, sessionId }) {
|
|
4401
|
-
const iframeRef =
|
|
4402
|
-
const iframeKeyRef =
|
|
4472
|
+
const iframeRef = useRef9(null);
|
|
4473
|
+
const iframeKeyRef = useRef9(
|
|
4403
4474
|
`iframe-${Math.random().toString(36).slice(2, 10)}`
|
|
4404
4475
|
);
|
|
4405
4476
|
const activeSessionId = useSessionStore((state) => state.activeSessionId);
|
|
@@ -4407,7 +4478,7 @@ function ResourceIframe({ ui, sessionId }) {
|
|
|
4407
4478
|
const theme = useUiStore((state) => state.theme);
|
|
4408
4479
|
const resourceUri = ui.resourceUri ?? ui.resourceURI;
|
|
4409
4480
|
const iframeLabel = ui.title ?? resourceUri ?? "\u5DE5\u5177\u754C\u9762";
|
|
4410
|
-
const [autoHeight, setAutoHeight] =
|
|
4481
|
+
const [autoHeight, setAutoHeight] = useState11(null);
|
|
4411
4482
|
useEffect10(() => {
|
|
4412
4483
|
setAutoHeight(null);
|
|
4413
4484
|
}, [ui.resourceHTML, resourceUri]);
|
|
@@ -4518,7 +4589,7 @@ function ResourceIframe({ ui, sessionId }) {
|
|
|
4518
4589
|
|
|
4519
4590
|
// src/react/components/chat/ToolCallBlock.tsx
|
|
4520
4591
|
import { Check, ChevronRight as ChevronRight3, Loader2 as Loader23, MessageSquareMore, PanelRightOpen, X as X4 } from "lucide-react";
|
|
4521
|
-
import { useMemo as useMemo12, useState as
|
|
4592
|
+
import { useMemo as useMemo12, useState as useState14 } from "react";
|
|
4522
4593
|
|
|
4523
4594
|
// src/react/components/chat/tool-renderers/shared.tsx
|
|
4524
4595
|
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
@@ -4845,21 +4916,21 @@ function FileEditRenderer({ toolCall }) {
|
|
|
4845
4916
|
}
|
|
4846
4917
|
|
|
4847
4918
|
// src/react/components/chat/tool-renderers/FileReadRenderer.tsx
|
|
4848
|
-
import { useState as
|
|
4919
|
+
import { useState as useState13 } from "react";
|
|
4849
4920
|
|
|
4850
4921
|
// src/react/components/chat/ImageLightbox.tsx
|
|
4851
4922
|
import { ChevronLeft, ChevronRight as ChevronRight2, Download as Download2, ExternalLink, Minus, Plus as Plus2, RotateCcw, X as X3 } from "lucide-react";
|
|
4852
|
-
import { useCallback as useCallback10, useEffect as useEffect11, useRef as
|
|
4923
|
+
import { useCallback as useCallback10, useEffect as useEffect11, useRef as useRef10, useState as useState12 } from "react";
|
|
4853
4924
|
import { createPortal as createPortal3 } from "react-dom";
|
|
4854
4925
|
import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
4855
4926
|
function ImageLightbox({ open, onOpenChange, images, initialIndex = 0 }) {
|
|
4856
|
-
const [currentIndex, setCurrentIndex] =
|
|
4857
|
-
const [scale, setScale] =
|
|
4858
|
-
const [translate, setTranslate] =
|
|
4859
|
-
const dragging =
|
|
4860
|
-
const dragStart =
|
|
4861
|
-
const translateStart =
|
|
4862
|
-
const imgRef =
|
|
4927
|
+
const [currentIndex, setCurrentIndex] = useState12(initialIndex);
|
|
4928
|
+
const [scale, setScale] = useState12(1);
|
|
4929
|
+
const [translate, setTranslate] = useState12({ x: 0, y: 0 });
|
|
4930
|
+
const dragging = useRef10(false);
|
|
4931
|
+
const dragStart = useRef10({ x: 0, y: 0 });
|
|
4932
|
+
const translateStart = useRef10({ x: 0, y: 0 });
|
|
4933
|
+
const imgRef = useRef10(null);
|
|
4863
4934
|
const reset = useCallback10(() => {
|
|
4864
4935
|
setScale(1);
|
|
4865
4936
|
setTranslate({ x: 0, y: 0 });
|
|
@@ -4878,7 +4949,7 @@ function ImageLightbox({ open, onOpenChange, images, initialIndex = 0 }) {
|
|
|
4878
4949
|
setCurrentIndex((i) => Math.min(images.length - 1, i + 1));
|
|
4879
4950
|
reset();
|
|
4880
4951
|
}, [images.length, reset]);
|
|
4881
|
-
const prevOpenRef =
|
|
4952
|
+
const prevOpenRef = useRef10(false);
|
|
4882
4953
|
useEffect11(() => {
|
|
4883
4954
|
if (open && !prevOpenRef.current) {
|
|
4884
4955
|
setCurrentIndex(initialIndex);
|
|
@@ -5168,7 +5239,7 @@ function formatLineRange(startLine, endLine) {
|
|
|
5168
5239
|
return startLine === endLine ? `\u7B2C ${startLine} \u884C` : `\u7B2C ${startLine}-${endLine} \u884C`;
|
|
5169
5240
|
}
|
|
5170
5241
|
function FileReadRenderer({ toolCall }) {
|
|
5171
|
-
const [lightboxIndex, setLightboxIndex] =
|
|
5242
|
+
const [lightboxIndex, setLightboxIndex] = useState13(null);
|
|
5172
5243
|
const argsValue = parseJsonValue(toolCall.arguments);
|
|
5173
5244
|
const args = isPlainObject(argsValue) ? argsValue : null;
|
|
5174
5245
|
const filePath = extractToolFilePath(toolCall);
|
|
@@ -5466,7 +5537,7 @@ function ToolCallBlock({
|
|
|
5466
5537
|
reasoning,
|
|
5467
5538
|
customization
|
|
5468
5539
|
}) {
|
|
5469
|
-
const [expanded, setExpanded] =
|
|
5540
|
+
const [expanded, setExpanded] = useState14(false);
|
|
5470
5541
|
const activeSessionId = useSessionStore((s) => s.activeSessionId);
|
|
5471
5542
|
const sessions = useSessionStore((s) => s.sessions);
|
|
5472
5543
|
const pushArtifact = useUiStore((s) => s.pushArtifact);
|
|
@@ -5670,7 +5741,7 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
5670
5741
|
}
|
|
5671
5742
|
|
|
5672
5743
|
// src/react/components/chat/UserMessageBubble.tsx
|
|
5673
|
-
import { useState as
|
|
5744
|
+
import { useState as useState16 } from "react";
|
|
5674
5745
|
|
|
5675
5746
|
// src/react/lib/preview-dispatch.ts
|
|
5676
5747
|
var IMAGE_EXTS = [
|
|
@@ -6003,10 +6074,10 @@ function MessageFileAttachmentList({
|
|
|
6003
6074
|
|
|
6004
6075
|
// src/react/components/chat/MessageActions.tsx
|
|
6005
6076
|
import { Check as Check2, Copy } from "lucide-react";
|
|
6006
|
-
import { useState as
|
|
6077
|
+
import { useState as useState15 } from "react";
|
|
6007
6078
|
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
6008
6079
|
function MessageActions({ content, className }) {
|
|
6009
|
-
const [copied, setCopied] =
|
|
6080
|
+
const [copied, setCopied] = useState15(false);
|
|
6010
6081
|
const handleCopy = async () => {
|
|
6011
6082
|
const ok = await copyToClipboard(content);
|
|
6012
6083
|
if (ok) {
|
|
@@ -6196,8 +6267,8 @@ function UserMessageBubble({ message, className }) {
|
|
|
6196
6267
|
alt: attachment.name || "\u7528\u6237\u4E0A\u4F20\u7684\u56FE\u7247"
|
|
6197
6268
|
}))
|
|
6198
6269
|
];
|
|
6199
|
-
const [lightboxIndex, setLightboxIndex] =
|
|
6200
|
-
const [preview, setPreview] =
|
|
6270
|
+
const [lightboxIndex, setLightboxIndex] = useState16(null);
|
|
6271
|
+
const [preview, setPreview] = useState16(null);
|
|
6201
6272
|
const handleTextAttachmentPreview = (attachment) => {
|
|
6202
6273
|
if (!activeSessionId) return;
|
|
6203
6274
|
const pathForUrl = attachment.uploadedPath ?? attachment.name;
|
|
@@ -6364,7 +6435,7 @@ function AgentLoopBlock({ toolCall, sessionId, reasoning }) {
|
|
|
6364
6435
|
() => visibleLoopToolCalls.some((childToolCall) => childToolCall.status === "awaiting_answer"),
|
|
6365
6436
|
[visibleLoopToolCalls]
|
|
6366
6437
|
);
|
|
6367
|
-
const [expanded, setExpanded] =
|
|
6438
|
+
const [expanded, setExpanded] = useState17(hasAwaitingAnswer);
|
|
6368
6439
|
const completedToolLabels = useMemo14(
|
|
6369
6440
|
() => visibleLoopToolCalls.flatMap((childToolCall) => {
|
|
6370
6441
|
const isCompleted = childToolCall.status === "done" || childToolCall.status !== "pending" && childToolCall.status !== "awaiting_answer" && childToolCall.status !== "error" && childToolCall.status !== "cancelled";
|
|
@@ -6616,12 +6687,9 @@ function ExpandedChildAssistantMessage({
|
|
|
6616
6687
|
const text = typeof message.content === "string" ? message.content.trim() : message.content.filter((part) => part.type === "text").map((part) => part.text).join("").trim();
|
|
6617
6688
|
const toolCalls = message.tool_calls ?? [];
|
|
6618
6689
|
const hasToolCalls = toolCalls.length > 0;
|
|
6619
|
-
const firstToolCallId = toolCalls[0]?.id;
|
|
6620
|
-
const toolReasoning = !isStreaming && !text && hasToolCalls ? message.reasoning : void 0;
|
|
6621
|
-
const standaloneReasoning = !isStreaming && !text && !hasToolCalls ? message.reasoning : void 0;
|
|
6622
6690
|
return /* @__PURE__ */ jsxs24("div", { className: "flex flex-col gap-2", children: [
|
|
6623
|
-
message.reasoning &&
|
|
6624
|
-
/* @__PURE__ */ jsx29(ReasoningTrigger, {}),
|
|
6691
|
+
message.reasoning && /* @__PURE__ */ jsxs24(Reasoning, { isStreaming, children: [
|
|
6692
|
+
/* @__PURE__ */ jsx29(ReasoningTrigger, { wordCount: message.reasoning.length }),
|
|
6625
6693
|
/* @__PURE__ */ jsx29(ReasoningContent, { children: message.reasoning })
|
|
6626
6694
|
] }),
|
|
6627
6695
|
text ? /* @__PURE__ */ jsx29(
|
|
@@ -6630,18 +6698,17 @@ function ExpandedChildAssistantMessage({
|
|
|
6630
6698
|
text,
|
|
6631
6699
|
isStreaming,
|
|
6632
6700
|
sessionId,
|
|
6633
|
-
reasoning:
|
|
6701
|
+
reasoning: void 0
|
|
6634
6702
|
}
|
|
6635
6703
|
) : null,
|
|
6636
6704
|
!text && isStreaming && /* @__PURE__ */ jsx29("span", { className: "pl-8 text-[12px] text-[hsl(var(--muted-foreground))]", children: "\u6B63\u5728\u751F\u6210..." }),
|
|
6637
|
-
standaloneReasoning ? /* @__PURE__ */ jsx29("div", { className: "pl-8", children: /* @__PURE__ */ jsx29(ThinkingBadge, { reasoning: standaloneReasoning, variant: "block" }) }) : null,
|
|
6638
6705
|
hasToolCalls && /* @__PURE__ */ jsx29("div", { className: "flex flex-col gap-2", children: toolCalls.map(
|
|
6639
|
-
(toolCall
|
|
6706
|
+
(toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx29(
|
|
6640
6707
|
AgentLoopBlock,
|
|
6641
6708
|
{
|
|
6642
6709
|
toolCall,
|
|
6643
6710
|
sessionId,
|
|
6644
|
-
reasoning:
|
|
6711
|
+
reasoning: void 0
|
|
6645
6712
|
},
|
|
6646
6713
|
toolCall.id
|
|
6647
6714
|
) : /* @__PURE__ */ jsx29(
|
|
@@ -6651,7 +6718,7 @@ function ExpandedChildAssistantMessage({
|
|
|
6651
6718
|
sessionId,
|
|
6652
6719
|
level: 2,
|
|
6653
6720
|
turnBlocks: message.blocks,
|
|
6654
|
-
reasoning:
|
|
6721
|
+
reasoning: void 0
|
|
6655
6722
|
},
|
|
6656
6723
|
toolCall.id
|
|
6657
6724
|
)
|
|
@@ -6873,10 +6940,10 @@ function AssistantTurnBlock({
|
|
|
6873
6940
|
),
|
|
6874
6941
|
[allToolCalls]
|
|
6875
6942
|
);
|
|
6876
|
-
const [displayMode, setDisplayMode] =
|
|
6943
|
+
const [displayMode, setDisplayMode] = useState18(
|
|
6877
6944
|
defaultTurnDisplayMode({ forceExpanded, hasActionableToolCall })
|
|
6878
6945
|
);
|
|
6879
|
-
const wasStreamingRef =
|
|
6946
|
+
const wasStreamingRef = useRef11(isStreaming);
|
|
6880
6947
|
useEffect14(() => {
|
|
6881
6948
|
if (wasStreamingRef.current && !isStreaming && !forceExpanded) {
|
|
6882
6949
|
setDisplayMode(defaultTurnDisplayMode({ forceExpanded, hasActionableToolCall }));
|
|
@@ -6975,23 +7042,18 @@ function AssistantMessages({
|
|
|
6975
7042
|
return messages.map(
|
|
6976
7043
|
(message, index) => isRenderableAssistantMessage(message, isStreaming && index === messages.length - 1) ? (() => {
|
|
6977
7044
|
const isStreamingLastMessage = isStreaming && index === messages.length - 1;
|
|
6978
|
-
const hasText = !!getMessageText(message);
|
|
6979
7045
|
const reasoning = message.reasoning;
|
|
6980
7046
|
const hasReasoning = !!reasoning;
|
|
6981
|
-
const hasAttachments = getImageParts(message.content).length > 0 || getFileParts(message.content).length > 0;
|
|
6982
7047
|
const toolCalls = message.tool_calls ?? [];
|
|
6983
7048
|
const hasToolCalls = toolCalls.length > 0;
|
|
6984
|
-
const firstToolCallId = toolCalls[0]?.id;
|
|
6985
7049
|
const toolRenderItems = groupDetailedToolCalls(toolCalls);
|
|
6986
|
-
const toolReasoning = hasReasoning && !hasText && !hasAttachments && hasToolCalls && !isStreamingLastMessage ? reasoning : void 0;
|
|
6987
|
-
const contentReasoning = hasReasoning && !isStreamingLastMessage && (hasText || hasAttachments || !hasToolCalls) ? reasoning : void 0;
|
|
6988
7050
|
return /* @__PURE__ */ jsxs25(
|
|
6989
7051
|
"div",
|
|
6990
7052
|
{
|
|
6991
7053
|
className: "flex flex-col gap-3",
|
|
6992
7054
|
children: [
|
|
6993
|
-
hasReasoning &&
|
|
6994
|
-
/* @__PURE__ */ jsx30(ReasoningTrigger, {}),
|
|
7055
|
+
hasReasoning && /* @__PURE__ */ jsxs25(Reasoning, { isStreaming: isStreamingLastMessage, children: [
|
|
7056
|
+
/* @__PURE__ */ jsx30(ReasoningTrigger, { wordCount: reasoning.length }),
|
|
6995
7057
|
/* @__PURE__ */ jsx30(ReasoningContent, { children: reasoning })
|
|
6996
7058
|
] }),
|
|
6997
7059
|
/* @__PURE__ */ jsx30(
|
|
@@ -7000,7 +7062,7 @@ function AssistantMessages({
|
|
|
7000
7062
|
message,
|
|
7001
7063
|
isStreaming: isStreamingLastMessage,
|
|
7002
7064
|
sessionId,
|
|
7003
|
-
reasoning:
|
|
7065
|
+
reasoning: void 0,
|
|
7004
7066
|
className: customization?.classNames?.assistantText
|
|
7005
7067
|
}
|
|
7006
7068
|
),
|
|
@@ -7011,7 +7073,7 @@ function AssistantMessages({
|
|
|
7011
7073
|
{
|
|
7012
7074
|
toolCalls: item.toolCalls,
|
|
7013
7075
|
kind: item.kind,
|
|
7014
|
-
reasoning:
|
|
7076
|
+
reasoning: void 0,
|
|
7015
7077
|
sessionId,
|
|
7016
7078
|
sessionStatus,
|
|
7017
7079
|
askAnswers,
|
|
@@ -7029,7 +7091,7 @@ function AssistantMessages({
|
|
|
7029
7091
|
{
|
|
7030
7092
|
toolCall,
|
|
7031
7093
|
sessionId,
|
|
7032
|
-
reasoning:
|
|
7094
|
+
reasoning: void 0
|
|
7033
7095
|
},
|
|
7034
7096
|
toolCall.id
|
|
7035
7097
|
) : customization?.components?.ToolCall ? /* @__PURE__ */ jsx30(
|
|
@@ -7043,7 +7105,7 @@ function AssistantMessages({
|
|
|
7043
7105
|
sessionStatus,
|
|
7044
7106
|
level,
|
|
7045
7107
|
turnBlocks: message.blocks,
|
|
7046
|
-
reasoning:
|
|
7108
|
+
reasoning: void 0,
|
|
7047
7109
|
customization
|
|
7048
7110
|
},
|
|
7049
7111
|
toolCall.id
|
|
@@ -7058,7 +7120,7 @@ function AssistantMessages({
|
|
|
7058
7120
|
sessionStatus,
|
|
7059
7121
|
level,
|
|
7060
7122
|
turnBlocks: message.blocks,
|
|
7061
|
-
reasoning:
|
|
7123
|
+
reasoning: void 0,
|
|
7062
7124
|
customization
|
|
7063
7125
|
},
|
|
7064
7126
|
toolCall.id
|
|
@@ -7100,7 +7162,7 @@ function CompactToolGroupBlock({
|
|
|
7100
7162
|
level,
|
|
7101
7163
|
customization
|
|
7102
7164
|
}) {
|
|
7103
|
-
const [expanded, setExpanded] =
|
|
7165
|
+
const [expanded, setExpanded] = useState18(false);
|
|
7104
7166
|
const indentClass = level === 2 ? "ml-3" : "ml-4";
|
|
7105
7167
|
const hasError = toolCalls.some(
|
|
7106
7168
|
(tc) => tc.status === "error" || tc.status === "cancelled"
|
|
@@ -7266,7 +7328,7 @@ function AssistantText({
|
|
|
7266
7328
|
}
|
|
7267
7329
|
function MemoryRefsHint({ refs: rawRefs }) {
|
|
7268
7330
|
const refs = Array.isArray(rawRefs) ? rawRefs : [];
|
|
7269
|
-
const [expanded, setExpanded] =
|
|
7331
|
+
const [expanded, setExpanded] = useState18(false);
|
|
7270
7332
|
const hasSkill = refs.some((r3) => r3.skill_name);
|
|
7271
7333
|
const label = hasSkill ? "\u53C2\u8003\u4E86\u8BE5\u6280\u80FD\u7684\u5386\u53F2\u7ECF\u9A8C" : "\u53C2\u8003\u4E86\u5386\u53F2\u7ECF\u9A8C";
|
|
7272
7334
|
return /* @__PURE__ */ jsxs25("div", { className: "ml-4", children: [
|
|
@@ -7314,7 +7376,7 @@ function MemoryRefsHint({ refs: rawRefs }) {
|
|
|
7314
7376
|
|
|
7315
7377
|
// src/react/components/chat/CompactionCard.tsx
|
|
7316
7378
|
import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight6, Loader2 as Loader25, Square as Square3, XCircle } from "lucide-react";
|
|
7317
|
-
import { useState as
|
|
7379
|
+
import { useState as useState19 } from "react";
|
|
7318
7380
|
import { jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
7319
7381
|
var PERCENT_FORMATTER = new Intl.NumberFormat("zh-CN", {
|
|
7320
7382
|
style: "percent",
|
|
@@ -7374,7 +7436,7 @@ function CompactionCard({
|
|
|
7374
7436
|
...compaction,
|
|
7375
7437
|
status: status ?? "completed"
|
|
7376
7438
|
} : activeCompaction;
|
|
7377
|
-
const [expanded, setExpanded] =
|
|
7439
|
+
const [expanded, setExpanded] = useState19(false);
|
|
7378
7440
|
if (!source || !source.compaction_id) {
|
|
7379
7441
|
return null;
|
|
7380
7442
|
}
|
|
@@ -7416,7 +7478,7 @@ function CompactionCard({
|
|
|
7416
7478
|
"button",
|
|
7417
7479
|
{
|
|
7418
7480
|
type: "button",
|
|
7419
|
-
onClick: () => getSocket().stop(sessionId),
|
|
7481
|
+
onClick: () => void getSocket().stop(sessionId),
|
|
7420
7482
|
className: "shrink-0 rounded-md border border-current/15 px-2 py-0.5 text-[11px] transition-opacity hover:opacity-80",
|
|
7421
7483
|
children: "\u53D6\u6D88\u6574\u7406"
|
|
7422
7484
|
}
|
|
@@ -7535,7 +7597,7 @@ import {
|
|
|
7535
7597
|
TerminalSquare,
|
|
7536
7598
|
WandSparkles
|
|
7537
7599
|
} from "lucide-react";
|
|
7538
|
-
import { useEffect as useEffect15, useMemo as useMemo16, useState as
|
|
7600
|
+
import { useEffect as useEffect15, useMemo as useMemo16, useState as useState20 } from "react";
|
|
7539
7601
|
import { jsx as jsx33, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
7540
7602
|
var EMPTY_EVENTS = [];
|
|
7541
7603
|
function formatElapsedDuration(durationMs) {
|
|
@@ -7614,7 +7676,7 @@ function getTurnStartedAt(events) {
|
|
|
7614
7676
|
return null;
|
|
7615
7677
|
}
|
|
7616
7678
|
function useElapsedDuration(startedAt, active) {
|
|
7617
|
-
const [now, setNow] =
|
|
7679
|
+
const [now, setNow] = useState20(() => Date.now());
|
|
7618
7680
|
useEffect15(() => {
|
|
7619
7681
|
if (!active || startedAt == null) {
|
|
7620
7682
|
return;
|
|
@@ -7729,15 +7791,12 @@ function parseModeChange(message) {
|
|
|
7729
7791
|
return null;
|
|
7730
7792
|
}
|
|
7731
7793
|
function getPlanningDividerKind(message) {
|
|
7732
|
-
if (message.kind === "planning_enter" || message.kind === "planning_exit") {
|
|
7733
|
-
return message.kind;
|
|
7734
|
-
}
|
|
7735
7794
|
const modeChange = parseModeChange(message);
|
|
7736
7795
|
if (modeChange?.to === "planning") {
|
|
7737
|
-
return "
|
|
7796
|
+
return "enter";
|
|
7738
7797
|
}
|
|
7739
7798
|
if (modeChange?.from === "planning") {
|
|
7740
|
-
return "
|
|
7799
|
+
return "exit";
|
|
7741
7800
|
}
|
|
7742
7801
|
return null;
|
|
7743
7802
|
}
|
|
@@ -7909,10 +7968,10 @@ function MessageList({
|
|
|
7909
7968
|
) ?? null,
|
|
7910
7969
|
[lastTurnId, renderBlocks]
|
|
7911
7970
|
);
|
|
7912
|
-
const containerRef =
|
|
7913
|
-
const scrollContainerRef =
|
|
7914
|
-
const frameRef =
|
|
7915
|
-
const [activeTurnId, setActiveTurnId] =
|
|
7971
|
+
const containerRef = useRef12(null);
|
|
7972
|
+
const scrollContainerRef = useRef12(null);
|
|
7973
|
+
const frameRef = useRef12(null);
|
|
7974
|
+
const [activeTurnId, setActiveTurnId] = useState21(lastTurnId);
|
|
7916
7975
|
const layoutSignature = useMemo17(
|
|
7917
7976
|
() => getMessagesMeasureSignature(messages),
|
|
7918
7977
|
[messages]
|
|
@@ -8085,7 +8144,7 @@ function MessageListContent({
|
|
|
8085
8144
|
(toolCall) => formatToolName(toolCall.name) === "ExitPlanMode" && toolCall.status !== "error" && toolCall.status !== "cancelled"
|
|
8086
8145
|
)
|
|
8087
8146
|
);
|
|
8088
|
-
const isFollowedByPlanningExit = nextBlock?.type === "planning_divider" && nextBlock.kind === "
|
|
8147
|
+
const isFollowedByPlanningExit = nextBlock?.type === "planning_divider" && nextBlock.kind === "exit";
|
|
8089
8148
|
const showPlanCard = (hasExitPlan || isFollowedByPlanningExit) && onConfirmPlan && sessionStatus === "waiting_for_input";
|
|
8090
8149
|
return /* @__PURE__ */ jsxs30(
|
|
8091
8150
|
"div",
|
|
@@ -8182,7 +8241,7 @@ function ScrollToBottomButton() {
|
|
|
8182
8241
|
);
|
|
8183
8242
|
}
|
|
8184
8243
|
function PlanningDivider({ kind }) {
|
|
8185
|
-
const isEnter = kind === "
|
|
8244
|
+
const isEnter = kind === "enter";
|
|
8186
8245
|
return /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-3 py-1", children: [
|
|
8187
8246
|
/* @__PURE__ */ jsx35("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
|
|
8188
8247
|
/* @__PURE__ */ jsxs30("div", { className: "inline-flex items-center gap-1.5 rounded-full border border-amber-500/30 bg-amber-500/10 px-3 py-1 text-[11px] text-amber-300", children: [
|
|
@@ -8210,6 +8269,7 @@ function ChatView({
|
|
|
8210
8269
|
const {
|
|
8211
8270
|
messages,
|
|
8212
8271
|
isStreaming,
|
|
8272
|
+
isStopping,
|
|
8213
8273
|
send,
|
|
8214
8274
|
stop
|
|
8215
8275
|
} = useChat(sessionId);
|
|
@@ -8257,6 +8317,7 @@ function ChatView({
|
|
|
8257
8317
|
onSend: (msg, _targetSessionId, model) => send(msg, mode, void 0, { model: model || void 0 }),
|
|
8258
8318
|
onStop: stop,
|
|
8259
8319
|
isStreaming,
|
|
8320
|
+
isStopping,
|
|
8260
8321
|
mode,
|
|
8261
8322
|
onToggleMode: toggleMode,
|
|
8262
8323
|
renderAttachments,
|
|
@@ -8326,4 +8387,4 @@ use-stick-to-bottom/dist/StickToBottom.js:
|
|
|
8326
8387
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
8327
8388
|
*--------------------------------------------------------------------------------------------*)
|
|
8328
8389
|
*/
|
|
8329
|
-
//# sourceMappingURL=chunk-
|
|
8390
|
+
//# sourceMappingURL=chunk-RTBAPZIO.js.map
|