@blade-hq/agent-react 2608.0.5-beta.1 → 2608.0.6
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/README.md +1 -1
- package/dist/components/AssistantTurnBlock.d.ts +1 -1
- package/dist/components/ConnectionBanner.d.ts +1 -1
- package/dist/components/FileCard.d.ts +3 -3
- package/dist/components/MarkdownContent.d.ts +2 -2
- package/dist/components/MessageList.d.ts +1 -1
- package/dist/index.js +120 -157
- package/dist/index.js.map +1 -1
- package/dist/lib/media-tags.d.ts +3 -3
- package/dist/style.css +11 -38
- package/dist/style.full.css +12 -39
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ await session?.send("你好")
|
|
|
104
104
|
<MarkdownContent content={markdownText} />
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
传了 `sessionId` 才会把智能体产出文件的 `MEDIA:`
|
|
107
|
+
传了 `sessionId` 才会把智能体产出文件的 `MEDIA:` 行折叠成以文件名为文本的下载链接(下载要用它)。`ChatView` 内部已经传好,只有单独用 `MarkdownContent` 时需要自己给:
|
|
108
108
|
|
|
109
109
|
```tsx
|
|
110
110
|
<MarkdownContent sessionId={sessionId}>{markdownText}</MarkdownContent>
|
|
@@ -7,7 +7,7 @@ interface Props {
|
|
|
7
7
|
onAnswer?: (answer: string, toolCallId: string, answerData: AskUserAnswerData) => void;
|
|
8
8
|
sessionStatus?: string;
|
|
9
9
|
toolCallRenderer?: ToolCallRenderer;
|
|
10
|
-
/** 传给 Markdown 渲染,用于把 MEDIA
|
|
10
|
+
/** 传给 Markdown 渲染,用于把 MEDIA 行折叠成文件下载链接。 */
|
|
11
11
|
sessionId?: string;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
@@ -3,6 +3,6 @@ interface Props {
|
|
|
3
3
|
connection: ConnectionStatus;
|
|
4
4
|
className?: string;
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
6
|
+
/** 连接状态提示条:短暂断线静默,超过容错时间后再逐级提示。 */
|
|
7
7
|
export declare function ConnectionBanner({ connection, className }: Props): import("react/jsx-runtime").JSX.Element | null;
|
|
8
8
|
export {};
|
|
@@ -8,9 +8,9 @@ export type FileCardProps = ComponentPropsWithRef<"span"> & ExtraProps & {
|
|
|
8
8
|
sessionId?: string;
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* 智能体产出文件的下载链接(由 MEDIA 行折叠而来)。
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* href 让 Vue/纯 HTML 宿主看到标准的「文件名→URL」语义;普通点击仍交给
|
|
14
|
+
* downloadFile,避免跨域时 download 属性被忽略,也确保使用点击时的最新 token。
|
|
15
15
|
*/
|
|
16
16
|
export declare function FileCard({ node, "data-path": pathAttribute, "data-name": nameAttribute, dataPath, dataName, sessionId, children, className, ...props }: FileCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -4,13 +4,13 @@ export interface MarkdownContentProps {
|
|
|
4
4
|
/** 流式渲染传 "streaming",历史静态内容默认 "static"。 */
|
|
5
5
|
mode?: "streaming" | "static";
|
|
6
6
|
/**
|
|
7
|
-
* 会话 id。传了才会把 `MEDIA:`
|
|
7
|
+
* 会话 id。传了才会把 `MEDIA:` 行折叠成文件下载链接——下载要用它。
|
|
8
8
|
* 不要给用户消息传:用户自己在输入框打一行 `MEDIA:` 不该被当成平台产物。
|
|
9
9
|
*/
|
|
10
10
|
sessionId?: string;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* SDK 版 Markdown
|
|
13
|
+
* SDK 版 Markdown 渲染:附带代码块复制按钮、智能体产出文件的下载链接;
|
|
14
14
|
* 相比第一方版本去掉了 mermaid、外链确认弹窗与文件预览。
|
|
15
15
|
*/
|
|
16
16
|
export declare function MarkdownContent({ children, className, mode, sessionId }: MarkdownContentProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/index.js
CHANGED
|
@@ -173,13 +173,6 @@ var createLucideIcon = (iconName, iconNode) => {
|
|
|
173
173
|
return Component2;
|
|
174
174
|
};
|
|
175
175
|
|
|
176
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/archive.js
|
|
177
|
-
var Archive = createLucideIcon("Archive", [
|
|
178
|
-
["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
|
|
179
|
-
["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
|
|
180
|
-
["path", { d: "M10 12h4", key: "a56b0p" }]
|
|
181
|
-
]);
|
|
182
|
-
|
|
183
176
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/arrow-up.js
|
|
184
177
|
var ArrowUp = createLucideIcon("ArrowUp", [
|
|
185
178
|
["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
|
|
@@ -247,31 +240,6 @@ var Copy = createLucideIcon("Copy", [
|
|
|
247
240
|
["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
|
|
248
241
|
]);
|
|
249
242
|
|
|
250
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/download.js
|
|
251
|
-
var Download = createLucideIcon("Download", [
|
|
252
|
-
["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
|
|
253
|
-
["polyline", { points: "7 10 12 15 17 10", key: "2ggqvy" }],
|
|
254
|
-
["line", { x1: "12", x2: "12", y1: "15", y2: "3", key: "1vk2je" }]
|
|
255
|
-
]);
|
|
256
|
-
|
|
257
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-code-2.js
|
|
258
|
-
var FileCode2 = createLucideIcon("FileCode2", [
|
|
259
|
-
["path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4", key: "1pf5j1" }],
|
|
260
|
-
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
|
|
261
|
-
["path", { d: "m5 12-3 3 3 3", key: "oke12k" }],
|
|
262
|
-
["path", { d: "m9 18 3-3-3-3", key: "112psh" }]
|
|
263
|
-
]);
|
|
264
|
-
|
|
265
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js
|
|
266
|
-
var FileSpreadsheet = createLucideIcon("FileSpreadsheet", [
|
|
267
|
-
["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
|
|
268
|
-
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
|
|
269
|
-
["path", { d: "M8 13h2", key: "yr2amv" }],
|
|
270
|
-
["path", { d: "M14 13h2", key: "un5t4a" }],
|
|
271
|
-
["path", { d: "M8 17h2", key: "2yhykz" }],
|
|
272
|
-
["path", { d: "M14 17h2", key: "10kma7" }]
|
|
273
|
-
]);
|
|
274
|
-
|
|
275
243
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-text.js
|
|
276
244
|
var FileText = createLucideIcon("FileText", [
|
|
277
245
|
["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
|
|
@@ -281,31 +249,6 @@ var FileText = createLucideIcon("FileText", [
|
|
|
281
249
|
["path", { d: "M16 17H8", key: "z1uh3a" }]
|
|
282
250
|
]);
|
|
283
251
|
|
|
284
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file.js
|
|
285
|
-
var File = createLucideIcon("File", [
|
|
286
|
-
["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
|
|
287
|
-
["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }]
|
|
288
|
-
]);
|
|
289
|
-
|
|
290
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/film.js
|
|
291
|
-
var Film = createLucideIcon("Film", [
|
|
292
|
-
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
|
|
293
|
-
["path", { d: "M7 3v18", key: "bbkbws" }],
|
|
294
|
-
["path", { d: "M3 7.5h4", key: "zfgn84" }],
|
|
295
|
-
["path", { d: "M3 12h18", key: "1i2n21" }],
|
|
296
|
-
["path", { d: "M3 16.5h4", key: "1230mu" }],
|
|
297
|
-
["path", { d: "M17 3v18", key: "in4fa5" }],
|
|
298
|
-
["path", { d: "M17 7.5h4", key: "myr1c1" }],
|
|
299
|
-
["path", { d: "M17 16.5h4", key: "go4c1d" }]
|
|
300
|
-
]);
|
|
301
|
-
|
|
302
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/image.js
|
|
303
|
-
var Image = createLucideIcon("Image", [
|
|
304
|
-
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
|
|
305
|
-
["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
|
|
306
|
-
["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
|
|
307
|
-
]);
|
|
308
|
-
|
|
309
252
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/layers.js
|
|
310
253
|
var Layers = createLucideIcon("Layers", [
|
|
311
254
|
[
|
|
@@ -369,13 +312,6 @@ var MessageSquare = createLucideIcon("MessageSquare", [
|
|
|
369
312
|
["path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z", key: "1lielz" }]
|
|
370
313
|
]);
|
|
371
314
|
|
|
372
|
-
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/music.js
|
|
373
|
-
var Music = createLucideIcon("Music", [
|
|
374
|
-
["path", { d: "M9 18V5l12-2v13", key: "1jmyc2" }],
|
|
375
|
-
["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
|
|
376
|
-
["circle", { cx: "18", cy: "16", r: "3", key: "1hluhg" }]
|
|
377
|
-
]);
|
|
378
|
-
|
|
379
315
|
// ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/square.js
|
|
380
316
|
var Square = createLucideIcon("Square", [
|
|
381
317
|
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }]
|
|
@@ -401,7 +337,7 @@ var X = createLucideIcon("X", [
|
|
|
401
337
|
]);
|
|
402
338
|
|
|
403
339
|
// src/components/ChatView.tsx
|
|
404
|
-
import { useEffect as
|
|
340
|
+
import { useEffect as useEffect7, useState as useState11 } from "react";
|
|
405
341
|
|
|
406
342
|
// src/lib/utils.ts
|
|
407
343
|
function cn(...inputs) {
|
|
@@ -487,24 +423,74 @@ function ChatInput({
|
|
|
487
423
|
}
|
|
488
424
|
|
|
489
425
|
// src/components/ConnectionBanner.tsx
|
|
426
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
490
427
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
428
|
+
var CONNECTION_NOTICE_DELAY_MS = 3e3;
|
|
429
|
+
var CONNECTION_ERROR_DELAY_MS = 15e3;
|
|
430
|
+
function useConnectionNoticePhase(connected) {
|
|
431
|
+
const [phase, setPhase] = useState2("hidden");
|
|
432
|
+
const connectedRef = useRef2(connected);
|
|
433
|
+
const timersRef = useRef2([]);
|
|
434
|
+
connectedRef.current = connected;
|
|
435
|
+
useEffect2(() => {
|
|
436
|
+
const clearTimers = () => {
|
|
437
|
+
for (const timer of timersRef.current) clearTimeout(timer);
|
|
438
|
+
timersRef.current = [];
|
|
439
|
+
};
|
|
440
|
+
const startGracePeriod = () => {
|
|
441
|
+
clearTimers();
|
|
442
|
+
setPhase("hidden");
|
|
443
|
+
timersRef.current = [
|
|
444
|
+
setTimeout(() => setPhase("recovering"), CONNECTION_NOTICE_DELAY_MS),
|
|
445
|
+
setTimeout(() => setPhase("failed"), CONNECTION_ERROR_DELAY_MS)
|
|
446
|
+
];
|
|
447
|
+
};
|
|
448
|
+
if (connected) {
|
|
449
|
+
clearTimers();
|
|
450
|
+
setPhase("hidden");
|
|
451
|
+
} else {
|
|
452
|
+
startGracePeriod();
|
|
453
|
+
}
|
|
454
|
+
const handleForeground = () => {
|
|
455
|
+
if (!connectedRef.current) startGracePeriod();
|
|
456
|
+
};
|
|
457
|
+
const handleVisibilityChange = () => {
|
|
458
|
+
if (document.visibilityState === "visible") handleForeground();
|
|
459
|
+
};
|
|
460
|
+
window.addEventListener("blade:app-active", handleForeground);
|
|
461
|
+
window.addEventListener("focus", handleForeground);
|
|
462
|
+
window.addEventListener("pageshow", handleForeground);
|
|
463
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
464
|
+
return () => {
|
|
465
|
+
clearTimers();
|
|
466
|
+
window.removeEventListener("blade:app-active", handleForeground);
|
|
467
|
+
window.removeEventListener("focus", handleForeground);
|
|
468
|
+
window.removeEventListener("pageshow", handleForeground);
|
|
469
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
470
|
+
};
|
|
471
|
+
}, [connected]);
|
|
472
|
+
return phase;
|
|
473
|
+
}
|
|
491
474
|
function ConnectionBanner({ connection, className }) {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
const
|
|
475
|
+
const hasConnectedRef = useRef2(connection === "connected" || connection === "reconnecting");
|
|
476
|
+
if (connection === "connected") hasConnectedRef.current = true;
|
|
477
|
+
const connected = connection === "connected";
|
|
478
|
+
const phase = useConnectionNoticePhase(connected);
|
|
479
|
+
if (connected || phase === "hidden") return null;
|
|
480
|
+
const recovering = phase === "recovering";
|
|
481
|
+
const firstConnection = !hasConnectedRef.current;
|
|
496
482
|
return /* @__PURE__ */ jsx3("div", { className: cn("blade-chat-banner bg-[hsl(var(--background))] px-5 pt-3", className), children: /* @__PURE__ */ jsxs2(
|
|
497
483
|
"div",
|
|
498
484
|
{
|
|
499
485
|
className: cn(
|
|
500
486
|
"mx-auto flex max-w-3xl items-start gap-3 rounded-2xl border px-4 py-3",
|
|
501
|
-
|
|
487
|
+
recovering ? "border-amber-500/25 bg-amber-500/10 text-amber-100" : "border-rose-500/25 bg-rose-500/10 text-rose-100"
|
|
502
488
|
),
|
|
503
489
|
children: [
|
|
504
|
-
/* @__PURE__ */ jsx3("span", { className: "mt-0.5 shrink-0", children:
|
|
490
|
+
/* @__PURE__ */ jsx3("span", { className: "mt-0.5 shrink-0", children: recovering ? /* @__PURE__ */ jsx3(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx3(TriangleAlert, { size: 14 }) }),
|
|
505
491
|
/* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
|
|
506
|
-
/* @__PURE__ */ jsx3("div", { className: "text-sm font-medium", children:
|
|
507
|
-
/* @__PURE__ */ jsx3("div", { className: "text-xs opacity-80", children: "\
|
|
492
|
+
/* @__PURE__ */ jsx3("div", { className: "text-sm font-medium", children: recovering ? firstConnection ? "\u6B63\u5728\u8FDE\u63A5\u2026" : "\u6B63\u5728\u6062\u590D\u8FDE\u63A5\u2026" : "\u6682\u65F6\u65E0\u6CD5\u8FDE\u63A5" }),
|
|
493
|
+
/* @__PURE__ */ jsx3("div", { className: "text-xs opacity-80", children: recovering ? "\u6062\u590D\u540E\u4F1A\u81EA\u52A8\u540C\u6B65\u6700\u65B0\u6D88\u606F\uFF0C\u8BF7\u7A0D\u5019" : "\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u670D\u52A1\u72B6\u6001\uFF0C\u7CFB\u7EDF\u4F1A\u7EE7\u7EED\u81EA\u52A8\u91CD\u8BD5" })
|
|
508
494
|
] })
|
|
509
495
|
]
|
|
510
496
|
}
|
|
@@ -513,10 +499,10 @@ function ConnectionBanner({ connection, className }) {
|
|
|
513
499
|
|
|
514
500
|
// src/components/MessageList.tsx
|
|
515
501
|
import { isHiddenInternalMessage } from "@blade-hq/agent-client";
|
|
516
|
-
import { useCallback as useCallback3, useEffect as
|
|
502
|
+
import { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo6, useRef as useRef6, useState as useState10 } from "react";
|
|
517
503
|
|
|
518
504
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
|
|
519
|
-
import { useCallback, useMemo as useMemo2, useRef as
|
|
505
|
+
import { useCallback, useMemo as useMemo2, useRef as useRef3, useState as useState3 } from "react";
|
|
520
506
|
var DEFAULT_SPRING_ANIMATION = {
|
|
521
507
|
/**
|
|
522
508
|
* A value from 0 to 1, on how much to damp the animation.
|
|
@@ -553,10 +539,10 @@ globalThis.document?.addEventListener("click", () => {
|
|
|
553
539
|
mouseDown = false;
|
|
554
540
|
});
|
|
555
541
|
var useStickToBottom = (options = {}) => {
|
|
556
|
-
const [escapedFromLock, updateEscapedFromLock] =
|
|
557
|
-
const [isAtBottom, updateIsAtBottom] =
|
|
558
|
-
const [isNearBottom, setIsNearBottom] =
|
|
559
|
-
const optionsRef =
|
|
542
|
+
const [escapedFromLock, updateEscapedFromLock] = useState3(false);
|
|
543
|
+
const [isAtBottom, updateIsAtBottom] = useState3(options.initial !== false);
|
|
544
|
+
const [isNearBottom, setIsNearBottom] = useState3(false);
|
|
545
|
+
const optionsRef = useRef3(null);
|
|
560
546
|
optionsRef.current = options;
|
|
561
547
|
const isSelecting = useCallback(() => {
|
|
562
548
|
if (!mouseDown) {
|
|
@@ -860,11 +846,11 @@ function mergeAnimations(...animations) {
|
|
|
860
846
|
|
|
861
847
|
// ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/StickToBottom.js
|
|
862
848
|
import * as React from "react";
|
|
863
|
-
import { createContext as createContext2, useContext as useContext2, useEffect as
|
|
849
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect3, useImperativeHandle, useLayoutEffect, useMemo as useMemo3, useRef as useRef4 } from "react";
|
|
864
850
|
var StickToBottomContext = createContext2(null);
|
|
865
|
-
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect :
|
|
851
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect3;
|
|
866
852
|
function StickToBottom({ instance, children, resize, initial, mass, damping, stiffness, targetScrollTop: currentTargetScrollTop, contextRef, ...props }) {
|
|
867
|
-
const customTargetScrollTop =
|
|
853
|
+
const customTargetScrollTop = useRef4(null);
|
|
868
854
|
const targetScrollTop = React.useCallback((target, elements) => {
|
|
869
855
|
const get = context?.targetScrollTop ?? currentTargetScrollTop;
|
|
870
856
|
return get?.(target, elements) ?? target;
|
|
@@ -941,10 +927,10 @@ function useStickToBottomContext() {
|
|
|
941
927
|
|
|
942
928
|
// src/components/AssistantTurnBlock.tsx
|
|
943
929
|
import { getTextContent, normalizeMessageContent } from "@blade-hq/agent-client";
|
|
944
|
-
import { useState as
|
|
930
|
+
import { useState as useState9 } from "react";
|
|
945
931
|
|
|
946
932
|
// src/components/AgentLoopBlock.tsx
|
|
947
|
-
import { useState as
|
|
933
|
+
import { useState as useState4 } from "react";
|
|
948
934
|
|
|
949
935
|
// src/components/display-utils.ts
|
|
950
936
|
var TOOL_NAME_ALIASES = {
|
|
@@ -1076,7 +1062,7 @@ function parseAgentDescription(argumentsJson) {
|
|
|
1076
1062
|
}
|
|
1077
1063
|
}
|
|
1078
1064
|
function AgentLoopBlock({ toolCall }) {
|
|
1079
|
-
const [expanded, setExpanded] =
|
|
1065
|
+
const [expanded, setExpanded] = useState4(false);
|
|
1080
1066
|
const description = parseAgentDescription(toolCall.arguments);
|
|
1081
1067
|
const running = toolCall.status === "pending" || toolCall.status === "awaiting_answer";
|
|
1082
1068
|
const failed = toolCall.status === "error" || toolCall.status === "cancelled";
|
|
@@ -1141,10 +1127,10 @@ function AgentLoopBlock({ toolCall }) {
|
|
|
1141
1127
|
|
|
1142
1128
|
// src/components/MarkdownContent.tsx
|
|
1143
1129
|
import {
|
|
1144
|
-
useEffect as
|
|
1130
|
+
useEffect as useEffect4,
|
|
1145
1131
|
useMemo as useMemo4,
|
|
1146
|
-
useRef as
|
|
1147
|
-
useState as
|
|
1132
|
+
useRef as useRef5,
|
|
1133
|
+
useState as useState6
|
|
1148
1134
|
} from "react";
|
|
1149
1135
|
|
|
1150
1136
|
// src/lib/media-tags.ts
|
|
@@ -1191,26 +1177,8 @@ function collapseMediaTags(text, options) {
|
|
|
1191
1177
|
}
|
|
1192
1178
|
|
|
1193
1179
|
// src/components/FileCard.tsx
|
|
1194
|
-
import { useState as
|
|
1180
|
+
import { useState as useState5 } from "react";
|
|
1195
1181
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1196
|
-
var IMAGE_EXTS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "svg", "webp", "ico", "bmp"]);
|
|
1197
|
-
var SHEET_EXTS = /* @__PURE__ */ new Set(["xlsx", "xls", "xlsm", "xlsb", "csv"]);
|
|
1198
|
-
var TEXT_EXTS = /* @__PURE__ */ new Set(["txt", "md", "markdown", "pdf", "doc", "docx", "rtf"]);
|
|
1199
|
-
var CODE_EXTS = /* @__PURE__ */ new Set(["js", "jsx", "ts", "tsx", "py", "go", "json", "yaml", "yml", "html", "css"]);
|
|
1200
|
-
var VIDEO_EXTS = /* @__PURE__ */ new Set(["mp4", "webm", "mov", "mkv", "avi"]);
|
|
1201
|
-
var AUDIO_EXTS = /* @__PURE__ */ new Set(["mp3", "wav", "ogg", "m4a", "flac"]);
|
|
1202
|
-
var ARCHIVE_EXTS = /* @__PURE__ */ new Set(["zip", "tar", "gz", "tgz", "rar", "7z"]);
|
|
1203
|
-
function getFileIcon(name) {
|
|
1204
|
-
const ext = name.split(".").pop()?.toLowerCase() ?? "";
|
|
1205
|
-
if (IMAGE_EXTS.has(ext)) return Image;
|
|
1206
|
-
if (SHEET_EXTS.has(ext)) return FileSpreadsheet;
|
|
1207
|
-
if (TEXT_EXTS.has(ext)) return FileText;
|
|
1208
|
-
if (CODE_EXTS.has(ext)) return FileCode2;
|
|
1209
|
-
if (VIDEO_EXTS.has(ext)) return Film;
|
|
1210
|
-
if (AUDIO_EXTS.has(ext)) return Music;
|
|
1211
|
-
if (ARCHIVE_EXTS.has(ext)) return Archive;
|
|
1212
|
-
return File;
|
|
1213
|
-
}
|
|
1214
1182
|
function stringValue(value) {
|
|
1215
1183
|
return typeof value === "string" ? value : void 0;
|
|
1216
1184
|
}
|
|
@@ -1234,14 +1202,18 @@ function FileCard({
|
|
|
1234
1202
|
...props
|
|
1235
1203
|
}) {
|
|
1236
1204
|
const client = useBladeClient();
|
|
1237
|
-
const [downloading, setDownloading] =
|
|
1238
|
-
const [failed, setFailed] =
|
|
1205
|
+
const [downloading, setDownloading] = useState5(false);
|
|
1206
|
+
const [failed, setFailed] = useState5(false);
|
|
1239
1207
|
const nodeProperties = node && typeof node === "object" && "properties" in node ? node.properties : void 0;
|
|
1240
1208
|
const path = pathAttribute ?? dataPath ?? stringValue(nodeProperties?.["data-path"]) ?? stringValue(nodeProperties?.dataPath) ?? "";
|
|
1241
1209
|
const name = nameAttribute ?? dataName ?? stringValue(nodeProperties?.["data-name"]) ?? stringValue(nodeProperties?.dataName) ?? extractChildrenText(children) ?? "";
|
|
1242
1210
|
const disabled = !sessionId || !isSafeMediaPath(path);
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1211
|
+
const downloadUrl = disabled ? void 0 : client.buildAuthedUrl(
|
|
1212
|
+
`/api/sessions/${encodeURIComponent(sessionId)}/files/${encodeURIComponent(path)}`
|
|
1213
|
+
);
|
|
1214
|
+
const handleDownload = async (event) => {
|
|
1215
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
1216
|
+
event.preventDefault();
|
|
1245
1217
|
if (disabled || downloading || !sessionId) return;
|
|
1246
1218
|
setDownloading(true);
|
|
1247
1219
|
setFailed(false);
|
|
@@ -1254,19 +1226,18 @@ function FileCard({
|
|
|
1254
1226
|
}
|
|
1255
1227
|
};
|
|
1256
1228
|
return /* @__PURE__ */ jsxs4("span", { ...props, className: cn("blade-chat-file-card", className), children: [
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
"
|
|
1229
|
+
/* @__PURE__ */ jsx5(
|
|
1230
|
+
"a",
|
|
1259
1231
|
{
|
|
1260
|
-
|
|
1232
|
+
href: downloadUrl,
|
|
1233
|
+
download: name,
|
|
1261
1234
|
onClick: handleDownload,
|
|
1262
|
-
disabled: disabled ||
|
|
1235
|
+
"aria-disabled": disabled || void 0,
|
|
1236
|
+
"aria-busy": downloading || void 0,
|
|
1263
1237
|
"aria-label": `\u4E0B\u8F7D\u6587\u4EF6\uFF1A${name}`,
|
|
1264
|
-
title: failed ? "\u4E0B\u8F7D\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5" :
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
/* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-name", children: name }),
|
|
1268
|
-
/* @__PURE__ */ jsx5(Download, { size: 13, className: "blade-chat-file-card-action" })
|
|
1269
|
-
]
|
|
1238
|
+
title: failed ? "\u4E0B\u8F7D\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5" : name,
|
|
1239
|
+
className: "blade-chat-file-link",
|
|
1240
|
+
children: name
|
|
1270
1241
|
}
|
|
1271
1242
|
),
|
|
1272
1243
|
failed && /* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-error", children: "\u4E0B\u8F7D\u5931\u8D25" })
|
|
@@ -1277,10 +1248,10 @@ function FileCard({
|
|
|
1277
1248
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1278
1249
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
1279
1250
|
function CodeBlockPre({ children, node: _node, ...props }) {
|
|
1280
|
-
const preRef =
|
|
1281
|
-
const [copied, setCopied] =
|
|
1282
|
-
const [language, setLanguage] =
|
|
1283
|
-
|
|
1251
|
+
const preRef = useRef5(null);
|
|
1252
|
+
const [copied, setCopied] = useState6(false);
|
|
1253
|
+
const [language, setLanguage] = useState6("");
|
|
1254
|
+
useEffect4(() => {
|
|
1284
1255
|
const codeEl = preRef.current?.querySelector("code");
|
|
1285
1256
|
setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
|
|
1286
1257
|
}, []);
|
|
@@ -1365,10 +1336,10 @@ function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
|
1365
1336
|
}
|
|
1366
1337
|
|
|
1367
1338
|
// src/components/ToolCallBlock.tsx
|
|
1368
|
-
import { useState as
|
|
1339
|
+
import { useState as useState8 } from "react";
|
|
1369
1340
|
|
|
1370
1341
|
// src/components/AskUserQuestionBlock.tsx
|
|
1371
|
-
import { useEffect as
|
|
1342
|
+
import { useEffect as useEffect5, useMemo as useMemo5, useState as useState7 } from "react";
|
|
1372
1343
|
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1373
1344
|
function AskUserQuestionBlock({
|
|
1374
1345
|
data,
|
|
@@ -1378,11 +1349,11 @@ function AskUserQuestionBlock({
|
|
|
1378
1349
|
answerData,
|
|
1379
1350
|
onAnswer
|
|
1380
1351
|
}) {
|
|
1381
|
-
const [selections, setSelections] =
|
|
1382
|
-
const [customTexts, setCustomTexts] =
|
|
1383
|
-
const [usingCustom, setUsingCustom] =
|
|
1384
|
-
const [submitted, setSubmitted] =
|
|
1385
|
-
|
|
1352
|
+
const [selections, setSelections] = useState7(/* @__PURE__ */ new Map());
|
|
1353
|
+
const [customTexts, setCustomTexts] = useState7(/* @__PURE__ */ new Map());
|
|
1354
|
+
const [usingCustom, setUsingCustom] = useState7(/* @__PURE__ */ new Set());
|
|
1355
|
+
const [submitted, setSubmitted] = useState7(false);
|
|
1356
|
+
useEffect5(() => {
|
|
1386
1357
|
if (sessionStatus === "failed" || sessionStatus === "interrupted") {
|
|
1387
1358
|
setSubmitted(false);
|
|
1388
1359
|
}
|
|
@@ -1709,7 +1680,7 @@ function ToolCallBlock({
|
|
|
1709
1680
|
sessionStatus,
|
|
1710
1681
|
renderer
|
|
1711
1682
|
}) {
|
|
1712
|
-
const [expanded, setExpanded] =
|
|
1683
|
+
const [expanded, setExpanded] = useState8(false);
|
|
1713
1684
|
const normalizedName = formatToolName(toolCall.name);
|
|
1714
1685
|
if (renderer) {
|
|
1715
1686
|
const custom = renderer(toolCall);
|
|
@@ -1811,7 +1782,7 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
1811
1782
|
// src/components/AssistantTurnBlock.tsx
|
|
1812
1783
|
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1813
1784
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
1814
|
-
const [open, setOpen] =
|
|
1785
|
+
const [open, setOpen] = useState9(false);
|
|
1815
1786
|
return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
|
|
1816
1787
|
/* @__PURE__ */ jsxs8(
|
|
1817
1788
|
"button",
|
|
@@ -2184,8 +2155,8 @@ function MessageList({
|
|
|
2184
2155
|
}
|
|
2185
2156
|
function AutoScrollOnUserSend({ userMessageCount }) {
|
|
2186
2157
|
const { scrollToBottom } = useStickToBottomContext();
|
|
2187
|
-
const previousCountRef =
|
|
2188
|
-
|
|
2158
|
+
const previousCountRef = useRef6(userMessageCount);
|
|
2159
|
+
useEffect6(() => {
|
|
2189
2160
|
if (userMessageCount > previousCountRef.current) {
|
|
2190
2161
|
scrollToBottom("instant");
|
|
2191
2162
|
}
|
|
@@ -2195,9 +2166,9 @@ function AutoScrollOnUserSend({ userMessageCount }) {
|
|
|
2195
2166
|
}
|
|
2196
2167
|
function ScrollToBottomButton() {
|
|
2197
2168
|
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
2198
|
-
const [visible, setVisible] =
|
|
2199
|
-
const hideTimerRef =
|
|
2200
|
-
|
|
2169
|
+
const [visible, setVisible] = useState10(false);
|
|
2170
|
+
const hideTimerRef = useRef6(null);
|
|
2171
|
+
useEffect6(() => {
|
|
2201
2172
|
if (isAtBottom) {
|
|
2202
2173
|
if (!hideTimerRef.current) {
|
|
2203
2174
|
hideTimerRef.current = setTimeout(() => {
|
|
@@ -2262,8 +2233,8 @@ function isUnauthorizedError(error) {
|
|
|
2262
2233
|
return error instanceof BladeApiError && error.status === 401;
|
|
2263
2234
|
}
|
|
2264
2235
|
function LoginCard({ client, onLoggedIn }) {
|
|
2265
|
-
const [loggingIn, setLoggingIn] =
|
|
2266
|
-
const [loginError, setLoginError] =
|
|
2236
|
+
const [loggingIn, setLoggingIn] = useState11(false);
|
|
2237
|
+
const [loginError, setLoginError] = useState11(null);
|
|
2267
2238
|
const handleLogin = async () => {
|
|
2268
2239
|
setLoggingIn(true);
|
|
2269
2240
|
setLoginError(null);
|
|
@@ -2295,8 +2266,8 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
2295
2266
|
}
|
|
2296
2267
|
function ChatView(props) {
|
|
2297
2268
|
const client = useBladeClient();
|
|
2298
|
-
const [attempt, setAttempt] =
|
|
2299
|
-
const [needLogin, setNeedLogin] =
|
|
2269
|
+
const [attempt, setAttempt] = useState11(0);
|
|
2270
|
+
const [needLogin, setNeedLogin] = useState11(() => !client.hasToken());
|
|
2300
2271
|
if (needLogin) {
|
|
2301
2272
|
return /* @__PURE__ */ jsx14(
|
|
2302
2273
|
"div",
|
|
@@ -2335,14 +2306,14 @@ function ChatSessionView({
|
|
|
2335
2306
|
createOptions,
|
|
2336
2307
|
onSessionCreated
|
|
2337
2308
|
});
|
|
2338
|
-
const [stopRequested, setStopRequested] =
|
|
2339
|
-
const [inputText, setInputText] =
|
|
2340
|
-
|
|
2309
|
+
const [stopRequested, setStopRequested] = useState11(false);
|
|
2310
|
+
const [inputText, setInputText] = useState11("");
|
|
2311
|
+
useEffect7(() => {
|
|
2341
2312
|
if (session) {
|
|
2342
2313
|
onSessionReady?.(session);
|
|
2343
2314
|
}
|
|
2344
2315
|
}, [session, onSessionReady]);
|
|
2345
|
-
|
|
2316
|
+
useEffect7(() => {
|
|
2346
2317
|
if (!session) return;
|
|
2347
2318
|
const offAttach = session.on("attachRequested", ({ label, content }) => {
|
|
2348
2319
|
setInputText((prev) => `${prev ? `${prev}
|
|
@@ -2358,12 +2329,12 @@ ${content}`);
|
|
|
2358
2329
|
offInsert();
|
|
2359
2330
|
};
|
|
2360
2331
|
}, [session]);
|
|
2361
|
-
|
|
2332
|
+
useEffect7(() => {
|
|
2362
2333
|
if (isUnauthorizedError(error)) {
|
|
2363
2334
|
onUnauthorized();
|
|
2364
2335
|
}
|
|
2365
2336
|
}, [error, onUnauthorized]);
|
|
2366
|
-
|
|
2337
|
+
useEffect7(() => {
|
|
2367
2338
|
if (!session || !commands) return;
|
|
2368
2339
|
const unsubscribes = Object.entries(commands).map(
|
|
2369
2340
|
([action, handler]) => session.onCommand(action, (payload) => handler(payload))
|
|
@@ -2458,7 +2429,6 @@ lucide-react/dist/esm/shared/src/utils.js:
|
|
|
2458
2429
|
lucide-react/dist/esm/defaultAttributes.js:
|
|
2459
2430
|
lucide-react/dist/esm/Icon.js:
|
|
2460
2431
|
lucide-react/dist/esm/createLucideIcon.js:
|
|
2461
|
-
lucide-react/dist/esm/icons/archive.js:
|
|
2462
2432
|
lucide-react/dist/esm/icons/arrow-up.js:
|
|
2463
2433
|
lucide-react/dist/esm/icons/bot.js:
|
|
2464
2434
|
lucide-react/dist/esm/icons/brain.js:
|
|
@@ -2467,20 +2437,13 @@ lucide-react/dist/esm/icons/chevron-down.js:
|
|
|
2467
2437
|
lucide-react/dist/esm/icons/chevron-right.js:
|
|
2468
2438
|
lucide-react/dist/esm/icons/circle-alert.js:
|
|
2469
2439
|
lucide-react/dist/esm/icons/copy.js:
|
|
2470
|
-
lucide-react/dist/esm/icons/download.js:
|
|
2471
|
-
lucide-react/dist/esm/icons/file-code-2.js:
|
|
2472
|
-
lucide-react/dist/esm/icons/file-spreadsheet.js:
|
|
2473
2440
|
lucide-react/dist/esm/icons/file-text.js:
|
|
2474
|
-
lucide-react/dist/esm/icons/file.js:
|
|
2475
|
-
lucide-react/dist/esm/icons/film.js:
|
|
2476
|
-
lucide-react/dist/esm/icons/image.js:
|
|
2477
2441
|
lucide-react/dist/esm/icons/layers.js:
|
|
2478
2442
|
lucide-react/dist/esm/icons/lightbulb.js:
|
|
2479
2443
|
lucide-react/dist/esm/icons/loader-circle.js:
|
|
2480
2444
|
lucide-react/dist/esm/icons/lock-keyhole.js:
|
|
2481
2445
|
lucide-react/dist/esm/icons/message-square-more.js:
|
|
2482
2446
|
lucide-react/dist/esm/icons/message-square.js:
|
|
2483
|
-
lucide-react/dist/esm/icons/music.js:
|
|
2484
2447
|
lucide-react/dist/esm/icons/square.js:
|
|
2485
2448
|
lucide-react/dist/esm/icons/triangle-alert.js:
|
|
2486
2449
|
lucide-react/dist/esm/icons/x.js:
|