@blade-hq/agent-react 1.2.1-beta.9 → 2608.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -173,6 +173,13 @@ 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
+
176
183
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/arrow-up.js
177
184
  var ArrowUp = createLucideIcon("ArrowUp", [
178
185
  ["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
@@ -240,6 +247,31 @@ var Copy = createLucideIcon("Copy", [
240
247
  ["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" }]
241
248
  ]);
242
249
 
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
+
243
275
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/file-text.js
244
276
  var FileText = createLucideIcon("FileText", [
245
277
  ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
@@ -249,6 +281,31 @@ var FileText = createLucideIcon("FileText", [
249
281
  ["path", { d: "M16 17H8", key: "z1uh3a" }]
250
282
  ]);
251
283
 
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
+
252
309
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/layers.js
253
310
  var Layers = createLucideIcon("Layers", [
254
311
  [
@@ -312,6 +369,13 @@ var MessageSquare = createLucideIcon("MessageSquare", [
312
369
  ["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" }]
313
370
  ]);
314
371
 
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
+
315
379
  // ../../node_modules/.pnpm/lucide-react@0.468.0_react@19.2.4/node_modules/lucide-react/dist/esm/icons/square.js
316
380
  var Square = createLucideIcon("Square", [
317
381
  ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }]
@@ -337,7 +401,7 @@ var X = createLucideIcon("X", [
337
401
  ]);
338
402
 
339
403
  // src/components/ChatView.tsx
340
- import { useEffect as useEffect6, useState as useState8 } from "react";
404
+ import { useEffect as useEffect6, useState as useState10 } from "react";
341
405
 
342
406
  // src/lib/utils.ts
343
407
  function cn(...inputs) {
@@ -378,7 +442,7 @@ function ChatInput({
378
442
  void handleSend();
379
443
  }
380
444
  };
381
- return /* @__PURE__ */ jsx2("div", { className: cn("blade-chat-input border-t border-[hsl(var(--border))] px-4 py-3", className), children: /* @__PURE__ */ jsxs("div", { className: "blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2", children: [
445
+ return /* @__PURE__ */ jsx2("div", { className: cn("blade-chat-input border-t border-[hsl(var(--border))] py-3", className), children: /* @__PURE__ */ jsxs("div", { className: "blade-chat-input-inner mx-auto flex max-w-[748px] items-end gap-2 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-2", children: [
382
446
  /* @__PURE__ */ jsx2(
383
447
  "textarea",
384
448
  {
@@ -449,7 +513,7 @@ function ConnectionBanner({ connection, className }) {
449
513
 
450
514
  // src/components/MessageList.tsx
451
515
  import { isHiddenInternalMessage } from "@blade-hq/agent-client";
452
- import { useEffect as useEffect5, useMemo as useMemo6, useRef as useRef5 } from "react";
516
+ import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo6, useRef as useRef5, useState as useState9 } from "react";
453
517
 
454
518
  // ../../node_modules/.pnpm/use-stick-to-bottom@1.1.3_react@19.2.4/node_modules/use-stick-to-bottom/dist/useStickToBottom.js
455
519
  import { useCallback, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
@@ -877,7 +941,7 @@ function useStickToBottomContext() {
877
941
 
878
942
  // src/components/AssistantTurnBlock.tsx
879
943
  import { getTextContent, normalizeMessageContent } from "@blade-hq/agent-client";
880
- import { useState as useState7 } from "react";
944
+ import { useState as useState8 } from "react";
881
945
 
882
946
  // src/components/AgentLoopBlock.tsx
883
947
  import { useState as useState3 } from "react";
@@ -1080,14 +1144,142 @@ import {
1080
1144
  useEffect as useEffect3,
1081
1145
  useMemo as useMemo4,
1082
1146
  useRef as useRef4,
1083
- useState as useState4
1147
+ useState as useState5
1084
1148
  } from "react";
1149
+
1150
+ // src/lib/media-tags.ts
1151
+ var FILE_CARD_TAG = "blade-file-card";
1152
+ var MEDIA_LINE_RE = /^[ \t]*(?:[-*+][ \t]+|\d+\.[ \t]+)?(?<wrap>[`"'*_]*)MEDIA:[ \t]*(?<path>.+?)\k<wrap>[ \t]*[。,、;;,]?[ \t]*\r?$/gm;
1153
+ var MEDIA_LINE_START_RE = /^[ \t]*(?:[-*+][ \t]+|\d+\.[ \t]+)?[`"'*_]*MEDIA:/;
1154
+ function basename(path) {
1155
+ return path.split(/[/\\]/).filter(Boolean).pop() || path;
1156
+ }
1157
+ function unwrapMediaPath(path) {
1158
+ if (!path.startsWith("<")) return path;
1159
+ const closingBracket = path.indexOf(">");
1160
+ if (closingBracket < 0) return null;
1161
+ return `${path.slice(1, closingBracket)}${path.slice(closingBracket + 1)}`;
1162
+ }
1163
+ function isSafeMediaPath(path) {
1164
+ if (!path) return false;
1165
+ return !path.split(/[/\\]/).includes("..");
1166
+ }
1167
+ function escapeAttribute(value) {
1168
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1169
+ }
1170
+ function foldMediaLines(text) {
1171
+ return text.replace(MEDIA_LINE_RE, (match, _wrap, rawPath) => {
1172
+ const path = unwrapMediaPath(rawPath);
1173
+ if (path === null) return match;
1174
+ const name = basename(path);
1175
+ if (!isSafeMediaPath(path)) {
1176
+ return `\`${name}\``;
1177
+ }
1178
+ return `<${FILE_CARD_TAG} data-path="${escapeAttribute(path)}" data-name="${escapeAttribute(name)}">${escapeAttribute(name)}</${FILE_CARD_TAG}>`;
1179
+ });
1180
+ }
1181
+ function collapseMediaTags(text, options) {
1182
+ if (!text.includes("MEDIA:")) return text;
1183
+ if (!options?.streaming) return foldMediaLines(text);
1184
+ const newlineIndex = text.lastIndexOf("\n");
1185
+ const head = newlineIndex < 0 ? "" : text.slice(0, newlineIndex + 1);
1186
+ const lastLine = newlineIndex < 0 ? text : text.slice(newlineIndex + 1);
1187
+ if (MEDIA_LINE_START_RE.test(lastLine)) {
1188
+ return foldMediaLines(head);
1189
+ }
1190
+ return foldMediaLines(head) + lastLine;
1191
+ }
1192
+
1193
+ // src/components/FileCard.tsx
1194
+ import { useState as useState4 } from "react";
1085
1195
  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
+ function stringValue(value) {
1215
+ return typeof value === "string" ? value : void 0;
1216
+ }
1217
+ function extractChildrenText(children) {
1218
+ if (typeof children === "string") return children;
1219
+ if (Array.isArray(children)) return children.map(extractChildrenText).join("");
1220
+ if (children && typeof children === "object" && "props" in children) {
1221
+ return extractChildrenText(children.props?.children);
1222
+ }
1223
+ return "";
1224
+ }
1225
+ function FileCard({
1226
+ node,
1227
+ "data-path": pathAttribute,
1228
+ "data-name": nameAttribute,
1229
+ dataPath,
1230
+ dataName,
1231
+ sessionId,
1232
+ children,
1233
+ className,
1234
+ ...props
1235
+ }) {
1236
+ const client = useBladeClient();
1237
+ const [downloading, setDownloading] = useState4(false);
1238
+ const [failed, setFailed] = useState4(false);
1239
+ const nodeProperties = node && typeof node === "object" && "properties" in node ? node.properties : void 0;
1240
+ const path = pathAttribute ?? dataPath ?? stringValue(nodeProperties?.["data-path"]) ?? stringValue(nodeProperties?.dataPath) ?? "";
1241
+ const name = nameAttribute ?? dataName ?? stringValue(nodeProperties?.["data-name"]) ?? stringValue(nodeProperties?.dataName) ?? extractChildrenText(children) ?? "";
1242
+ const disabled = !sessionId || !isSafeMediaPath(path);
1243
+ const Icon2 = getFileIcon(name);
1244
+ const handleDownload = async () => {
1245
+ if (disabled || downloading || !sessionId) return;
1246
+ setDownloading(true);
1247
+ setFailed(false);
1248
+ try {
1249
+ await client.sessions.downloadFile(sessionId, path, name);
1250
+ } catch {
1251
+ setFailed(true);
1252
+ } finally {
1253
+ setDownloading(false);
1254
+ }
1255
+ };
1256
+ return /* @__PURE__ */ jsxs4("span", { ...props, className: cn("blade-chat-file-card", className), children: [
1257
+ /* @__PURE__ */ jsxs4(
1258
+ "button",
1259
+ {
1260
+ type: "button",
1261
+ onClick: handleDownload,
1262
+ disabled: disabled || downloading,
1263
+ "aria-label": `\u4E0B\u8F7D\u6587\u4EF6\uFF1A${name}`,
1264
+ title: failed ? "\u4E0B\u8F7D\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5" : `\u4E0B\u8F7D ${name}`,
1265
+ children: [
1266
+ /* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-icon", children: downloading ? /* @__PURE__ */ jsx5(LoaderCircle, { size: 15, className: "animate-spin" }) : /* @__PURE__ */ jsx5(Icon2, { size: 15 }) }),
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
+ ]
1270
+ }
1271
+ ),
1272
+ failed && /* @__PURE__ */ jsx5("span", { className: "blade-chat-file-card-error", children: "\u4E0B\u8F7D\u5931\u8D25" })
1273
+ ] });
1274
+ }
1275
+
1276
+ // src/components/MarkdownContent.tsx
1277
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1086
1278
  var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
1087
1279
  function CodeBlockPre({ children, node: _node, ...props }) {
1088
1280
  const preRef = useRef4(null);
1089
- const [copied, setCopied] = useState4(false);
1090
- const [language, setLanguage] = useState4("");
1281
+ const [copied, setCopied] = useState5(false);
1282
+ const [language, setLanguage] = useState5("");
1091
1283
  useEffect3(() => {
1092
1284
  const codeEl = preRef.current?.querySelector("code");
1093
1285
  setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
@@ -1099,10 +1291,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1099
1291
  setTimeout(() => setCopied(false), 2e3);
1100
1292
  }
1101
1293
  };
1102
- return /* @__PURE__ */ jsxs4("div", { className: "blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]", children: [
1103
- /* @__PURE__ */ jsxs4("div", { className: "blade-chat-codeblock-header flex h-[34px] items-center justify-between border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))/0.5] pl-3.5 pr-1.5", children: [
1104
- /* @__PURE__ */ jsx5("span", { className: "font-mono text-[12px] text-[hsl(var(--muted-foreground))]", children: language || "code" }),
1105
- /* @__PURE__ */ jsxs4(
1294
+ return /* @__PURE__ */ jsxs5("div", { className: "blade-chat-codeblock not-prose my-3 overflow-hidden rounded-xl border border-[hsl(var(--border))]", children: [
1295
+ /* @__PURE__ */ jsxs5("div", { className: "blade-chat-codeblock-header flex h-[34px] items-center justify-between border-b border-[hsl(var(--border))] bg-[hsl(var(--muted))/0.5] pl-3.5 pr-1.5", children: [
1296
+ /* @__PURE__ */ jsx6("span", { className: "font-mono text-[12px] text-[hsl(var(--muted-foreground))]", children: language || "code" }),
1297
+ /* @__PURE__ */ jsxs5(
1106
1298
  "button",
1107
1299
  {
1108
1300
  type: "button",
@@ -1112,13 +1304,13 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1112
1304
  copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
1113
1305
  ),
1114
1306
  children: [
1115
- copied ? /* @__PURE__ */ jsx5(Check, { size: 12 }) : /* @__PURE__ */ jsx5(Copy, { size: 12 }),
1116
- /* @__PURE__ */ jsx5("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
1307
+ copied ? /* @__PURE__ */ jsx6(Check, { size: 12 }) : /* @__PURE__ */ jsx6(Copy, { size: 12 }),
1308
+ /* @__PURE__ */ jsx6("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
1117
1309
  ]
1118
1310
  }
1119
1311
  )
1120
1312
  ] }),
1121
- /* @__PURE__ */ jsx5(
1313
+ /* @__PURE__ */ jsx6(
1122
1314
  "pre",
1123
1315
  {
1124
1316
  ref: preRef,
@@ -1130,37 +1322,54 @@ function CodeBlockPre({ children, node: _node, ...props }) {
1130
1322
  ] });
1131
1323
  }
1132
1324
  function ExternalAnchor({ node: _node, children, ...props }) {
1133
- return /* @__PURE__ */ jsx5("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
1325
+ return /* @__PURE__ */ jsx6("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
1134
1326
  }
1135
1327
  var MARKDOWN_COMPONENTS = {
1136
1328
  pre: CodeBlockPre,
1137
1329
  a: ExternalAnchor
1138
1330
  };
1139
- function MarkdownContent({ children, className, mode }) {
1140
- const resolvedChildren = useMemo4(() => children.replace(SYSTEM_REMINDER_RE, ""), [children]);
1141
- return /* @__PURE__ */ jsx5(
1331
+ var CUSTOM_ALLOWED_TAGS = {
1332
+ [FILE_CARD_TAG]: ["dataPath", "dataName", "data-path", "data-name"]
1333
+ };
1334
+ function MarkdownContent({ children, className, mode, sessionId }) {
1335
+ const streaming = mode === "streaming";
1336
+ const resolvedChildren = useMemo4(() => {
1337
+ const withoutReminders = children.replace(SYSTEM_REMINDER_RE, "");
1338
+ if (!sessionId) return withoutReminders;
1339
+ return collapseMediaTags(withoutReminders, { streaming });
1340
+ }, [children, sessionId, streaming]);
1341
+ const components = useMemo4(
1342
+ () => ({
1343
+ ...MARKDOWN_COMPONENTS,
1344
+ [FILE_CARD_TAG]: (fileCardProps) => /* @__PURE__ */ jsx6(FileCard, { ...fileCardProps, sessionId })
1345
+ }),
1346
+ [sessionId]
1347
+ );
1348
+ return /* @__PURE__ */ jsx6(
1142
1349
  _r,
1143
1350
  {
1144
1351
  className: cn("blade-chat-markdown break-words", className),
1145
1352
  mode: mode ?? "static",
1146
- components: MARKDOWN_COMPONENTS,
1353
+ components,
1354
+ allowedTags: CUSTOM_ALLOWED_TAGS,
1147
1355
  children: resolvedChildren
1148
- }
1356
+ },
1357
+ sessionId ?? "no-session"
1149
1358
  );
1150
1359
  }
1151
1360
 
1152
1361
  // src/components/Shimmer.tsx
1153
- import { jsx as jsx6 } from "react/jsx-runtime";
1362
+ import { jsx as jsx7 } from "react/jsx-runtime";
1154
1363
  function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
1155
- return /* @__PURE__ */ jsx6("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
1364
+ return /* @__PURE__ */ jsx7("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
1156
1365
  }
1157
1366
 
1158
1367
  // src/components/ToolCallBlock.tsx
1159
- import { useState as useState6 } from "react";
1368
+ import { useState as useState7 } from "react";
1160
1369
 
1161
1370
  // src/components/AskUserQuestionBlock.tsx
1162
- import { useEffect as useEffect4, useMemo as useMemo5, useState as useState5 } from "react";
1163
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1371
+ import { useEffect as useEffect4, useMemo as useMemo5, useState as useState6 } from "react";
1372
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1164
1373
  function AskUserQuestionBlock({
1165
1374
  data,
1166
1375
  answered,
@@ -1169,10 +1378,10 @@ function AskUserQuestionBlock({
1169
1378
  answerData,
1170
1379
  onAnswer
1171
1380
  }) {
1172
- const [selections, setSelections] = useState5(/* @__PURE__ */ new Map());
1173
- const [customTexts, setCustomTexts] = useState5(/* @__PURE__ */ new Map());
1174
- const [usingCustom, setUsingCustom] = useState5(/* @__PURE__ */ new Set());
1175
- const [submitted, setSubmitted] = useState5(false);
1381
+ const [selections, setSelections] = useState6(/* @__PURE__ */ new Map());
1382
+ const [customTexts, setCustomTexts] = useState6(/* @__PURE__ */ new Map());
1383
+ const [usingCustom, setUsingCustom] = useState6(/* @__PURE__ */ new Set());
1384
+ const [submitted, setSubmitted] = useState6(false);
1176
1385
  useEffect4(() => {
1177
1386
  if (sessionStatus === "failed" || sessionStatus === "interrupted") {
1178
1387
  setSubmitted(false);
@@ -1263,7 +1472,7 @@ ${parts.join("\n")}`;
1263
1472
  setSubmitted(true);
1264
1473
  onAnswer(text, toolCallId, nextAnswerData);
1265
1474
  };
1266
- return /* @__PURE__ */ jsxs5(
1475
+ return /* @__PURE__ */ jsxs6(
1267
1476
  "div",
1268
1477
  {
1269
1478
  className: cn(
@@ -1271,12 +1480,12 @@ ${parts.join("\n")}`;
1271
1480
  answered ? "max-w-2xl space-y-3 p-3 text-xs text-[hsl(var(--muted-foreground))] opacity-80" : "max-w-lg space-y-5 p-4 text-sm"
1272
1481
  ),
1273
1482
  children: [
1274
- data.source_loop?.description && /* @__PURE__ */ jsxs5("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1483
+ data.source_loop?.description && /* @__PURE__ */ jsxs6("div", { className: "rounded-lg bg-[hsl(var(--muted)/0.35)] px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]", children: [
1275
1484
  "\u5B50\u667A\u80FD\u4F53\u300C",
1276
1485
  data.source_loop.description,
1277
1486
  "\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
1278
1487
  ] }),
1279
- data.questions.map((q, qIdx) => /* @__PURE__ */ jsx7(
1488
+ data.questions.map((q, qIdx) => /* @__PURE__ */ jsx8(
1280
1489
  QuestionCard,
1281
1490
  {
1282
1491
  question: q,
@@ -1291,7 +1500,7 @@ ${parts.join("\n")}`;
1291
1500
  },
1292
1501
  q.question
1293
1502
  )),
1294
- !answered && !submitted && onAnswer && /* @__PURE__ */ jsx7(
1503
+ !answered && !submitted && onAnswer && /* @__PURE__ */ jsx8(
1295
1504
  "button",
1296
1505
  {
1297
1506
  type: "button",
@@ -1301,14 +1510,14 @@ ${parts.join("\n")}`;
1301
1510
  children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
1302
1511
  }
1303
1512
  ),
1304
- submitted && !answered && /* @__PURE__ */ jsxs5(
1513
+ submitted && !answered && /* @__PURE__ */ jsxs6(
1305
1514
  "button",
1306
1515
  {
1307
1516
  type: "button",
1308
1517
  disabled: true,
1309
1518
  className: "flex w-full items-center justify-center gap-2 rounded-lg bg-[hsl(var(--primary))] px-4 py-2 text-xs font-semibold text-[hsl(var(--primary-foreground))] opacity-80",
1310
1519
  children: [
1311
- /* @__PURE__ */ jsx7(LoaderCircle, { size: 14, className: "animate-spin" }),
1520
+ /* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
1312
1521
  "\u786E\u8BA4\u4E2D"
1313
1522
  ]
1314
1523
  }
@@ -1329,30 +1538,30 @@ function QuestionCard({
1329
1538
  onCustomChange
1330
1539
  }) {
1331
1540
  const multi = question.multiSelect ?? false;
1332
- return /* @__PURE__ */ jsxs5("div", { children: [
1333
- /* @__PURE__ */ jsxs5("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
1334
- /* @__PURE__ */ jsx7(
1541
+ return /* @__PURE__ */ jsxs6("div", { children: [
1542
+ /* @__PURE__ */ jsxs6("div", { className: cn("flex items-start gap-2", answered ? "mb-2" : "mb-3"), children: [
1543
+ /* @__PURE__ */ jsx8(
1335
1544
  MessageSquareMore,
1336
1545
  {
1337
1546
  size: answered ? 12 : 13,
1338
1547
  className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
1339
1548
  }
1340
1549
  ),
1341
- /* @__PURE__ */ jsx7(
1550
+ /* @__PURE__ */ jsx8(
1342
1551
  "div",
1343
1552
  {
1344
1553
  className: cn(
1345
1554
  "min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
1346
1555
  answered ? "text-xs" : "text-sm"
1347
1556
  ),
1348
- children: /* @__PURE__ */ jsx7(MarkdownContent, { className: "blade-chat-prose", children: question.question })
1557
+ children: /* @__PURE__ */ jsx8(MarkdownContent, { className: "blade-chat-prose", children: question.question })
1349
1558
  }
1350
1559
  )
1351
1560
  ] }),
1352
- /* @__PURE__ */ jsxs5("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
1561
+ /* @__PURE__ */ jsxs6("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
1353
1562
  question.options.map((opt, optIdx) => {
1354
1563
  const isSel = selected.has(optIdx);
1355
- return /* @__PURE__ */ jsxs5(
1564
+ return /* @__PURE__ */ jsxs6(
1356
1565
  "button",
1357
1566
  {
1358
1567
  type: "button",
@@ -1366,14 +1575,14 @@ function QuestionCard({
1366
1575
  answered && "cursor-default opacity-70"
1367
1576
  ),
1368
1577
  children: [
1369
- multi && /* @__PURE__ */ jsx7(
1578
+ multi && /* @__PURE__ */ jsx8(
1370
1579
  "div",
1371
1580
  {
1372
1581
  className: cn(
1373
1582
  "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
1374
1583
  isSel && !answered ? "border-[hsl(var(--primary-foreground)/0.6)] bg-[hsl(var(--primary-foreground)/0.2)]" : isSel ? "border-[hsl(var(--primary)/0.45)] bg-[hsl(var(--primary)/0.12)]" : "border-[hsl(var(--border))]"
1375
1584
  ),
1376
- children: isSel && /* @__PURE__ */ jsx7(
1585
+ children: isSel && /* @__PURE__ */ jsx8(
1377
1586
  Check,
1378
1587
  {
1379
1588
  size: 9,
@@ -1382,9 +1591,9 @@ function QuestionCard({
1382
1591
  )
1383
1592
  }
1384
1593
  ),
1385
- /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
1386
- /* @__PURE__ */ jsx7("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
1387
- opt.description && /* @__PURE__ */ jsx7(
1594
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0", children: [
1595
+ /* @__PURE__ */ jsx8("div", { className: cn("font-medium", answered ? "text-xs" : "text-[13px]"), children: opt.label }),
1596
+ opt.description && /* @__PURE__ */ jsx8(
1388
1597
  "div",
1389
1598
  {
1390
1599
  className: cn(
@@ -1401,7 +1610,7 @@ function QuestionCard({
1401
1610
  opt.label
1402
1611
  );
1403
1612
  }),
1404
- answered && !isCustom ? null : /* @__PURE__ */ jsxs5(
1613
+ answered && !isCustom ? null : /* @__PURE__ */ jsxs6(
1405
1614
  "div",
1406
1615
  {
1407
1616
  className: cn(
@@ -1411,8 +1620,8 @@ function QuestionCard({
1411
1620
  answered && "cursor-default opacity-70"
1412
1621
  ),
1413
1622
  children: [
1414
- /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
1415
- /* @__PURE__ */ jsx7(
1623
+ /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
1624
+ /* @__PURE__ */ jsx8(
1416
1625
  "input",
1417
1626
  {
1418
1627
  type: "text",
@@ -1480,7 +1689,18 @@ function normalizeOptionItem(value) {
1480
1689
  }
1481
1690
 
1482
1691
  // src/components/ToolCallBlock.tsx
1483
- import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1692
+ import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1693
+ function resolveAskQuestionState({
1694
+ toolStatus,
1695
+ hasAnswerData,
1696
+ fallbackAnswered
1697
+ }) {
1698
+ const awaitingAnswer = !hasAnswerData && toolStatus === "awaiting_answer";
1699
+ return {
1700
+ awaitingAnswer,
1701
+ answered: hasAnswerData || !awaitingAnswer && (Boolean(fallbackAnswered) || toolStatus === "done" || toolStatus === "cancelled" || toolStatus === "error")
1702
+ };
1703
+ }
1484
1704
  function ToolCallBlock({
1485
1705
  toolCall,
1486
1706
  onAnswer,
@@ -1489,23 +1709,28 @@ function ToolCallBlock({
1489
1709
  sessionStatus,
1490
1710
  renderer
1491
1711
  }) {
1492
- const [expanded, setExpanded] = useState6(false);
1712
+ const [expanded, setExpanded] = useState7(false);
1493
1713
  const normalizedName = formatToolName(toolCall.name);
1494
1714
  if (renderer) {
1495
1715
  const custom = renderer(toolCall);
1496
1716
  if (custom !== null && custom !== void 0) {
1497
- return /* @__PURE__ */ jsx8(Fragment, { children: custom });
1717
+ return /* @__PURE__ */ jsx9(Fragment, { children: custom });
1498
1718
  }
1499
1719
  }
1500
1720
  if (normalizedName === "AskUserQuestion") {
1501
1721
  const askData = parseAskUserQuestion(typeof toolCall.result === "string" ? toolCall.result : null) ?? parseAskUserQuestion(buildAskUserPayload(toolCall.arguments));
1502
- const canAnswer = toolCall.status === "awaiting_answer" && Boolean(onAnswer);
1722
+ const questionState = resolveAskQuestionState({
1723
+ toolStatus: toolCall.status,
1724
+ hasAnswerData: Boolean(answerData),
1725
+ fallbackAnswered: answered
1726
+ });
1727
+ const canAnswer = questionState.awaitingAnswer && Boolean(onAnswer);
1503
1728
  if (askData) {
1504
- return /* @__PURE__ */ jsx8(
1729
+ return /* @__PURE__ */ jsx9(
1505
1730
  AskUserQuestionBlock,
1506
1731
  {
1507
1732
  data: askData,
1508
- answered: toolCall.status === "awaiting_answer" ? false : Boolean(answered) || toolCall.status === "done",
1733
+ answered: questionState.answered,
1509
1734
  toolCallId: toolCall.id,
1510
1735
  sessionStatus: sessionStatus ?? "",
1511
1736
  answerData,
@@ -1514,24 +1739,24 @@ function ToolCallBlock({
1514
1739
  );
1515
1740
  }
1516
1741
  if (toolCall.status === "pending") {
1517
- return /* @__PURE__ */ jsxs6("div", { className: "ml-4 flex max-w-lg items-center gap-2 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-4 text-sm text-[hsl(var(--muted-foreground))]", children: [
1518
- /* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
1519
- /* @__PURE__ */ jsx8("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
1742
+ return /* @__PURE__ */ jsxs7("div", { className: "ml-4 flex max-w-lg items-center gap-2 rounded-xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-4 text-sm text-[hsl(var(--muted-foreground))]", children: [
1743
+ /* @__PURE__ */ jsx9(LoaderCircle, { size: 14, className: "animate-spin" }),
1744
+ /* @__PURE__ */ jsx9("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
1520
1745
  ] });
1521
1746
  }
1522
- return /* @__PURE__ */ jsxs6("div", { className: "ml-4 max-w-lg rounded-xl border border-amber-500/35 bg-amber-500/10 p-4 text-sm text-[hsl(var(--foreground))]", children: [
1523
- /* @__PURE__ */ jsx8("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
1524
- /* @__PURE__ */ jsx8("div", { className: "mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: "\u6536\u5230\u7684\u4EA4\u4E92\u6570\u636E\u4E0D\u5B8C\u6574\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002" })
1747
+ return /* @__PURE__ */ jsxs7("div", { className: "ml-4 max-w-lg rounded-xl border border-amber-500/35 bg-amber-500/10 p-4 text-sm text-[hsl(var(--foreground))]", children: [
1748
+ /* @__PURE__ */ jsx9("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
1749
+ /* @__PURE__ */ jsx9("div", { className: "mt-1 text-xs leading-5 text-[hsl(var(--muted-foreground))]", children: "\u6536\u5230\u7684\u4EA4\u4E92\u6570\u636E\u4E0D\u5B8C\u6574\u3002\u8BF7\u8BA9\u667A\u80FD\u4F53\u91CD\u65B0\u63D0\u95EE\u3002" })
1525
1750
  ] });
1526
1751
  }
1527
1752
  const tone = getToolTone(toolCall.status);
1528
1753
  const displayName = getToolDisplayLabel(toolCall);
1529
1754
  const toneClass = tone === "red" ? "border-l-[hsl(var(--muted-foreground)/0.5)]" : tone === "amber" ? "border-l-amber-400" : tone === "blue" ? "border-l-blue-500" : "border-l-[hsl(var(--primary))]";
1530
- const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */ jsx8(LoaderCircle, { size: 11, className: "animate-spin" }) : toolCall.status === "awaiting_answer" ? /* @__PURE__ */ jsx8(MessageSquareMore, { size: 11 }) : toolCall.status === "cancelled" || toolCall.status === "error" ? /* @__PURE__ */ jsx8(X, { size: 11 }) : /* @__PURE__ */ jsx8(Check, { size: 11 });
1755
+ const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */ jsx9(LoaderCircle, { size: 11, className: "animate-spin" }) : toolCall.status === "awaiting_answer" ? /* @__PURE__ */ jsx9(MessageSquareMore, { size: 11 }) : toolCall.status === "cancelled" || toolCall.status === "error" ? /* @__PURE__ */ jsx9(X, { size: 11 }) : /* @__PURE__ */ jsx9(Check, { size: 11 });
1531
1756
  const statusTextClass = tone === "red" ? "text-[hsl(var(--muted-foreground))]" : tone === "amber" ? "text-amber-300" : tone === "blue" ? "text-blue-300" : "text-[hsl(var(--primary))]";
1532
- return /* @__PURE__ */ jsxs6("div", { className: "blade-chat-tool ml-4 text-xs", children: [
1533
- /* @__PURE__ */ jsxs6("div", { className: cn("border-l-[3px] flex items-center gap-2 px-3 py-2", toneClass), children: [
1534
- /* @__PURE__ */ jsxs6(
1757
+ return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-tool ml-4 text-xs", children: [
1758
+ /* @__PURE__ */ jsxs7("div", { className: cn("border-l-[3px] flex items-center gap-2 px-3 py-2", toneClass), children: [
1759
+ /* @__PURE__ */ jsxs7(
1535
1760
  "button",
1536
1761
  {
1537
1762
  type: "button",
@@ -1539,7 +1764,7 @@ function ToolCallBlock({
1539
1764
  className: "flex min-w-0 flex-1 items-center gap-2 text-left transition-colors hover:bg-white/3 focus-visible:ring-1 focus-visible:ring-[hsl(var(--ring))] focus:outline-none",
1540
1765
  "aria-expanded": expanded,
1541
1766
  children: [
1542
- /* @__PURE__ */ jsx8(
1767
+ /* @__PURE__ */ jsx9(
1543
1768
  ChevronRight,
1544
1769
  {
1545
1770
  size: 11,
@@ -1549,24 +1774,24 @@ function ToolCallBlock({
1549
1774
  )
1550
1775
  }
1551
1776
  ),
1552
- /* @__PURE__ */ jsxs6("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
1777
+ /* @__PURE__ */ jsxs7("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
1553
1778
  statusIcon,
1554
- /* @__PURE__ */ jsx8("span", { children: getToolStatusLabel(toolCall.status) })
1779
+ /* @__PURE__ */ jsx9("span", { children: getToolStatusLabel(toolCall.status) })
1555
1780
  ] }),
1556
- /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
1781
+ /* @__PURE__ */ jsx9("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
1557
1782
  ]
1558
1783
  }
1559
1784
  ),
1560
- typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */ jsx8("span", { className: "shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]", children: formatToolDuration(toolCall.duration_ms) })
1785
+ typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */ jsx9("span", { className: "shrink-0 font-mono text-[10px] text-[hsl(var(--muted-foreground))]", children: formatToolDuration(toolCall.duration_ms) })
1561
1786
  ] }),
1562
- expanded && /* @__PURE__ */ jsxs6("div", { className: "blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
1563
- /* @__PURE__ */ jsx8("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u5177" }),
1564
- /* @__PURE__ */ jsx8("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
1565
- /* @__PURE__ */ jsx8("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
1566
- /* @__PURE__ */ jsx8("pre", { className: "overflow-x-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolArgs(toolCall.arguments) }),
1567
- toolCall.result != null && /* @__PURE__ */ jsxs6(Fragment, { children: [
1568
- /* @__PURE__ */ jsx8("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
1569
- /* @__PURE__ */ jsx8("pre", { className: "max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolResult(toolCall.result) })
1787
+ expanded && /* @__PURE__ */ jsxs7("div", { className: "blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
1788
+ /* @__PURE__ */ jsx9("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u5177" }),
1789
+ /* @__PURE__ */ jsx9("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
1790
+ /* @__PURE__ */ jsx9("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
1791
+ /* @__PURE__ */ jsx9("pre", { className: "overflow-x-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolArgs(toolCall.arguments) }),
1792
+ toolCall.result != null && /* @__PURE__ */ jsxs7(Fragment, { children: [
1793
+ /* @__PURE__ */ jsx9("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
1794
+ /* @__PURE__ */ jsx9("pre", { className: "max-h-[400px] overflow-auto whitespace-pre-wrap rounded-md bg-[hsl(var(--muted))] p-2 font-mono text-[11px] text-[hsl(var(--foreground))]", children: formatToolResult(toolCall.result) })
1570
1795
  ] })
1571
1796
  ] })
1572
1797
  ] });
@@ -1584,11 +1809,11 @@ function buildAskUserPayload(argumentsJson) {
1584
1809
  }
1585
1810
 
1586
1811
  // src/components/AssistantTurnBlock.tsx
1587
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1812
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1588
1813
  function ThinkingBlock({ reasoning, isStreaming }) {
1589
- const [open, setOpen] = useState7(false);
1590
- return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
1591
- /* @__PURE__ */ jsxs7(
1814
+ const [open, setOpen] = useState8(false);
1815
+ return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
1816
+ /* @__PURE__ */ jsxs8(
1592
1817
  "button",
1593
1818
  {
1594
1819
  type: "button",
@@ -1596,14 +1821,14 @@ function ThinkingBlock({ reasoning, isStreaming }) {
1596
1821
  "aria-expanded": open,
1597
1822
  className: "inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
1598
1823
  children: [
1599
- /* @__PURE__ */ jsx9(Brain, { size: 12, className: "shrink-0" }),
1600
- isStreaming ? /* @__PURE__ */ jsx9(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }) : /* @__PURE__ */ jsx9("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
1601
- /* @__PURE__ */ jsxs7("span", { className: "text-[hsl(var(--muted-foreground))]/70", children: [
1824
+ /* @__PURE__ */ jsx10(Brain, { size: 12, className: "shrink-0" }),
1825
+ isStreaming ? /* @__PURE__ */ jsx10(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }) : /* @__PURE__ */ jsx10("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
1826
+ /* @__PURE__ */ jsxs8("span", { className: "text-[hsl(var(--muted-foreground))]/70", children: [
1602
1827
  "\xB7 ",
1603
1828
  new Intl.NumberFormat("zh-CN").format(reasoning.length),
1604
1829
  " \u5B57"
1605
1830
  ] }),
1606
- /* @__PURE__ */ jsx9(
1831
+ /* @__PURE__ */ jsx10(
1607
1832
  ChevronDown,
1608
1833
  {
1609
1834
  size: 12,
@@ -1613,7 +1838,7 @@ function ThinkingBlock({ reasoning, isStreaming }) {
1613
1838
  ]
1614
1839
  }
1615
1840
  ),
1616
- open && /* @__PURE__ */ jsx9("div", { className: "mt-1.5 whitespace-pre-wrap border-l-2 border-[hsl(var(--border))] pl-3 text-[11px] leading-5 text-[hsl(var(--muted-foreground))]", children: reasoning })
1841
+ open && /* @__PURE__ */ jsx10("div", { className: "mt-1.5 whitespace-pre-wrap border-l-2 border-[hsl(var(--border))] pl-3 text-[11px] leading-5 text-[hsl(var(--muted-foreground))]", children: reasoning })
1617
1842
  ] });
1618
1843
  }
1619
1844
  function getMessageText(message) {
@@ -1631,37 +1856,39 @@ function AssistantTurnBlock({
1631
1856
  askAnswers,
1632
1857
  onAnswer,
1633
1858
  sessionStatus,
1634
- toolCallRenderer
1859
+ toolCallRenderer,
1860
+ sessionId
1635
1861
  }) {
1636
1862
  const hasInterrupted = messages.some((message) => message.status === "interrupted");
1637
1863
  const hasAnyContent = messages.some(
1638
1864
  (message) => getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0
1639
1865
  );
1640
1866
  const latestReasoningIndex = isStreaming ? findLatestReasoningMessageIndex(messages) : -1;
1641
- return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
1642
- hasInterrupted && /* @__PURE__ */ jsx9("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
1867
+ return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
1868
+ hasInterrupted && /* @__PURE__ */ jsx10("div", { className: "ml-4 w-fit rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }),
1643
1869
  messages.map((message, index) => {
1644
1870
  const isLast = index === messages.length - 1;
1645
1871
  const streamingThis = isStreaming && isLast;
1646
1872
  const text = getMessageText(message);
1647
1873
  const toolCalls = message.tool_calls ?? [];
1648
1874
  const showReasoning = !!message.reasoning && (!isStreaming || index === latestReasoningIndex);
1649
- return /* @__PURE__ */ jsxs7(
1875
+ return /* @__PURE__ */ jsxs8(
1650
1876
  "div",
1651
1877
  {
1652
1878
  className: "flex flex-col gap-3",
1653
1879
  children: [
1654
- showReasoning && message.reasoning && /* @__PURE__ */ jsx9(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
1655
- text && /* @__PURE__ */ jsx9("div", { className: "blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]", children: /* @__PURE__ */ jsx9(
1880
+ showReasoning && message.reasoning && /* @__PURE__ */ jsx10(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
1881
+ text && /* @__PURE__ */ jsx10("div", { className: "blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]", children: /* @__PURE__ */ jsx10(
1656
1882
  MarkdownContent,
1657
1883
  {
1658
1884
  mode: streamingThis ? "streaming" : "static",
1659
1885
  className: "blade-chat-prose",
1886
+ sessionId,
1660
1887
  children: text
1661
1888
  }
1662
1889
  ) }),
1663
- toolCalls.length > 0 && /* @__PURE__ */ jsx9("div", { className: "flex flex-col gap-2", children: toolCalls.map(
1664
- (toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx9(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx9(
1890
+ toolCalls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "flex flex-col gap-2", children: toolCalls.map(
1891
+ (toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx10(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx10(
1665
1892
  ToolCallBlock,
1666
1893
  {
1667
1894
  toolCall,
@@ -1679,13 +1906,13 @@ function AssistantTurnBlock({
1679
1906
  message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
1680
1907
  );
1681
1908
  }),
1682
- isStreaming && !hasAnyContent && /* @__PURE__ */ jsx9(Shimmer, { className: "ml-4", children: "\u6B63\u5728\u751F\u6210..." })
1909
+ isStreaming && !hasAnyContent && /* @__PURE__ */ jsx10(Shimmer, { className: "ml-4", children: "\u6B63\u5728\u751F\u6210..." })
1683
1910
  ] });
1684
1911
  }
1685
1912
 
1686
1913
  // src/components/RenderErrorBoundary.tsx
1687
1914
  import { Component } from "react";
1688
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1915
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1689
1916
  function getFirstComponentName(componentStack) {
1690
1917
  const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
1691
1918
  return match?.[1] ?? null;
@@ -1718,18 +1945,18 @@ var RenderErrorBoundary = class extends Component {
1718
1945
  return children;
1719
1946
  }
1720
1947
  const componentName = getFirstComponentName(componentStack);
1721
- return /* @__PURE__ */ jsx10("div", { className: "blade-chat-render-error rounded-xl border border-amber-500/30 bg-amber-500/8 px-4 py-3 text-sm text-amber-100", children: /* @__PURE__ */ jsxs8("div", { className: "flex items-start gap-2", children: [
1722
- /* @__PURE__ */ jsx10(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
1723
- /* @__PURE__ */ jsxs8("div", { className: "min-w-0 flex-1", children: [
1724
- /* @__PURE__ */ jsxs8("div", { className: "font-medium", children: [
1948
+ return /* @__PURE__ */ jsx11("div", { className: "blade-chat-render-error rounded-xl border border-amber-500/30 bg-amber-500/8 px-4 py-3 text-sm text-amber-100", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-2", children: [
1949
+ /* @__PURE__ */ jsx11(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
1950
+ /* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
1951
+ /* @__PURE__ */ jsxs9("div", { className: "font-medium", children: [
1725
1952
  label,
1726
1953
  "\u6E32\u67D3\u5931\u8D25"
1727
1954
  ] }),
1728
- /* @__PURE__ */ jsxs8("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
1955
+ /* @__PURE__ */ jsxs9("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
1729
1956
  componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
1730
1957
  error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
1731
1958
  ] }),
1732
- details ? /* @__PURE__ */ jsx10("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
1959
+ details ? /* @__PURE__ */ jsx11("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
1733
1960
  ] })
1734
1961
  ] }) });
1735
1962
  }
@@ -1737,7 +1964,7 @@ var RenderErrorBoundary = class extends Component {
1737
1964
 
1738
1965
  // src/components/UserMessageBubble.tsx
1739
1966
  import { getFileParts, getImageParts, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
1740
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1967
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1741
1968
  function isUserMessage(message) {
1742
1969
  return message.role === "user";
1743
1970
  }
@@ -1749,8 +1976,8 @@ function UserMessageBubble({ message, className }) {
1749
1976
  const text = getTextContent2(message.content).trim();
1750
1977
  const fileParts = getFileParts(message.content);
1751
1978
  const imageParts = getImageParts(message.content);
1752
- return /* @__PURE__ */ jsx11("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs9("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
1753
- imageParts.length > 0 && /* @__PURE__ */ jsx11("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx11(
1979
+ return /* @__PURE__ */ jsx12("div", { className: cn("blade-chat-user-row flex justify-end", className), children: /* @__PURE__ */ jsxs10("div", { className: "blade-chat-user-col flex max-w-[72%] flex-col items-end gap-3", children: [
1980
+ imageParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx12(
1754
1981
  "img",
1755
1982
  {
1756
1983
  src: part.image_url.url,
@@ -1759,21 +1986,21 @@ function UserMessageBubble({ message, className }) {
1759
1986
  },
1760
1987
  part.image_url.url
1761
1988
  )) }),
1762
- fileParts.length > 0 && /* @__PURE__ */ jsx11("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs9(
1989
+ fileParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs10(
1763
1990
  "div",
1764
1991
  {
1765
1992
  className: "flex items-center gap-1.5 rounded-lg border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--muted)/0.3)] px-2.5 py-1.5 text-xs text-[hsl(var(--muted-foreground))]",
1766
1993
  children: [
1767
- /* @__PURE__ */ jsx11(FileText, { size: 12, className: "shrink-0" }),
1768
- /* @__PURE__ */ jsx11("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
1994
+ /* @__PURE__ */ jsx12(FileText, { size: 12, className: "shrink-0" }),
1995
+ /* @__PURE__ */ jsx12("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
1769
1996
  ]
1770
1997
  },
1771
1998
  `${part.name}-${part.data.length}`
1772
1999
  )) }),
1773
- text && /* @__PURE__ */ jsx11("div", { className: "blade-chat-user-bubble max-w-full rounded-[20px] rounded-br-[6px] border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-[18px] py-[13px] text-sm leading-[1.65] text-[hsl(var(--user-msg-fg))]", children: /* @__PURE__ */ jsx11(MarkdownContent, { className: "blade-chat-prose", children: text }) }),
1774
- text && isSending(message) && /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
1775
- /* @__PURE__ */ jsx11(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
1776
- /* @__PURE__ */ jsx11("span", { children: "\u53D1\u9001\u4E2D" })
2000
+ text && /* @__PURE__ */ jsx12("div", { className: "blade-chat-user-bubble max-w-full rounded-[20px] rounded-br-[6px] border border-[hsl(var(--user-msg-border))] bg-[hsl(var(--user-msg-bg))] px-[18px] py-[13px] text-sm leading-[1.65] text-[hsl(var(--user-msg-fg))]", children: /* @__PURE__ */ jsx12(MarkdownContent, { className: "blade-chat-prose", children: text }) }),
2001
+ text && isSending(message) && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 pr-1 text-[11px] font-medium text-[hsl(var(--muted-foreground))/0.85]", children: [
2002
+ /* @__PURE__ */ jsx12(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
2003
+ /* @__PURE__ */ jsx12("span", { children: "\u53D1\u9001\u4E2D" })
1777
2004
  ] })
1778
2005
  ] }) });
1779
2006
  }
@@ -1782,11 +2009,11 @@ function ErrorMessageBlock({
1782
2009
  className
1783
2010
  }) {
1784
2011
  const text = getTextContent2(message.content);
1785
- return /* @__PURE__ */ jsx11("div", { className: cn("blade-chat-error-row flex justify-center", className), children: /* @__PURE__ */ jsx11("div", { className: "blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--destructive))] px-4 py-1 text-sm leading-7 text-[hsl(var(--destructive))]", children: text }) });
2012
+ return /* @__PURE__ */ jsx12("div", { className: cn("blade-chat-error-row flex justify-center", className), children: /* @__PURE__ */ jsx12("div", { className: "blade-chat-error-block max-w-[85%] border-l-[3px] border-[hsl(var(--border))] px-4 py-1 text-sm leading-7 text-[hsl(var(--muted-foreground))]", children: text }) });
1786
2013
  }
1787
2014
 
1788
2015
  // src/components/MessageList.tsx
1789
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2016
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1790
2017
  function parseModeChange(message) {
1791
2018
  if (message.kind !== "mode_change" || typeof message.content !== "string") {
1792
2019
  return null;
@@ -1826,7 +2053,8 @@ function MessageList({
1826
2053
  onAnswer,
1827
2054
  toolCallRenderer,
1828
2055
  emptyState,
1829
- className
2056
+ className,
2057
+ sessionId
1830
2058
  }) {
1831
2059
  const renderBlocks = useMemo6(() => {
1832
2060
  const visible = messages.filter((message) => {
@@ -1901,24 +2129,24 @@ function MessageList({
1901
2129
  }
1902
2130
  return blocks;
1903
2131
  }, [messages, isStreaming]);
1904
- return /* @__PURE__ */ jsx12("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: /* @__PURE__ */ jsxs10(StickToBottom, { className: "h-full overflow-y-hidden", initial: "instant", resize: "instant", children: [
1905
- /* @__PURE__ */ jsx12(StickToBottom.Content, { className: "px-5 pb-7 pt-8 sm:px-10 sm:pt-10", children: /* @__PURE__ */ jsx12("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: /* @__PURE__ */ jsxs10("div", { className: "flex min-w-0 flex-col gap-9", children: [
1906
- renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs10("div", { className: "flex flex-col items-center justify-center gap-3 py-24 text-[hsl(var(--muted-foreground))]", children: [
1907
- /* @__PURE__ */ jsx12(MessageSquare, { size: 40, strokeWidth: 1.5 }),
1908
- /* @__PURE__ */ jsx12("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
1909
- /* @__PURE__ */ jsx12("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
2132
+ return /* @__PURE__ */ jsx13("div", { className: cn("blade-chat-messages relative min-h-0 flex-1", className), children: /* @__PURE__ */ jsxs11(StickToBottom, { className: "h-full overflow-y-hidden", initial: "instant", resize: "instant", children: [
2133
+ /* @__PURE__ */ jsx13(StickToBottom.Content, { className: "blade-chat-messages-scroll", children: /* @__PURE__ */ jsx13("div", { className: "blade-chat-messages-content mx-auto max-w-[748px]", children: /* @__PURE__ */ jsxs11("div", { className: "flex min-w-0 flex-col", children: [
2134
+ renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs11("div", { className: "blade-chat-empty", children: [
2135
+ /* @__PURE__ */ jsx13(MessageSquare, { size: 40, strokeWidth: 1.5 }),
2136
+ /* @__PURE__ */ jsx13("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
2137
+ /* @__PURE__ */ jsx13("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
1910
2138
  ] }) : renderBlocks.map((block) => {
1911
2139
  if (block.type === "message") {
1912
- return /* @__PURE__ */ jsx12("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx12(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx12(ErrorMessageBlock, { message: block.message }) : null }, block.key);
2140
+ return /* @__PURE__ */ jsx13("div", { "data-entry-id": block.message.entry_id, children: isUserMessage(block.message) ? /* @__PURE__ */ jsx13(UserMessageBubble, { message: block.message }) : isErrorMessage(block.message) ? /* @__PURE__ */ jsx13(ErrorMessageBlock, { message: block.message }) : null }, block.key);
1913
2141
  }
1914
2142
  if (block.type === "assistant_turn") {
1915
- return /* @__PURE__ */ jsx12("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsx12(
2143
+ return /* @__PURE__ */ jsx13("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsx13(
1916
2144
  RenderErrorBoundary,
1917
2145
  {
1918
2146
  label: "\u52A9\u624B\u6D88\u606F",
1919
2147
  details: block.key,
1920
2148
  resetKey: getMessageResetSignature(block.messages),
1921
- children: /* @__PURE__ */ jsx12(
2149
+ children: /* @__PURE__ */ jsx13(
1922
2150
  AssistantTurnBlock,
1923
2151
  {
1924
2152
  messages: block.messages,
@@ -1926,31 +2154,32 @@ function MessageList({
1926
2154
  askAnswers,
1927
2155
  onAnswer,
1928
2156
  sessionStatus,
1929
- toolCallRenderer
2157
+ toolCallRenderer,
2158
+ sessionId
1930
2159
  }
1931
2160
  )
1932
2161
  }
1933
2162
  ) }, block.key);
1934
2163
  }
1935
2164
  if (block.type === "compaction") {
1936
- return /* @__PURE__ */ jsxs10(
2165
+ return /* @__PURE__ */ jsxs11(
1937
2166
  "div",
1938
2167
  {
1939
2168
  className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
1940
2169
  children: [
1941
- /* @__PURE__ */ jsx12(Layers, { size: 12 }),
1942
- /* @__PURE__ */ jsx12("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
2170
+ /* @__PURE__ */ jsx13(Layers, { size: 12 }),
2171
+ /* @__PURE__ */ jsx13("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
1943
2172
  ]
1944
2173
  },
1945
2174
  block.key
1946
2175
  );
1947
2176
  }
1948
- return /* @__PURE__ */ jsx12(PlanningDivider, { kind: block.kind }, block.key);
2177
+ return /* @__PURE__ */ jsx13(PlanningDivider, { kind: block.kind }, block.key);
1949
2178
  }),
1950
- sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx12("div", { className: "flex", children: /* @__PURE__ */ jsx12("div", { className: "rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }) }) : null
2179
+ sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */ jsx13("div", { className: "flex", children: /* @__PURE__ */ jsx13("div", { className: "rounded-full border border-amber-500/30 bg-amber-500/10 px-2.5 py-1 text-[10px] font-medium uppercase tracking-[0.12em] text-amber-300", children: "\u5DF2\u4E2D\u65AD" }) }) : null
1951
2180
  ] }) }) }),
1952
- /* @__PURE__ */ jsx12(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
1953
- /* @__PURE__ */ jsx12(ScrollToBottomButton, {})
2181
+ /* @__PURE__ */ jsx13(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
2182
+ /* @__PURE__ */ jsx13(ScrollToBottomButton, {})
1954
2183
  ] }) });
1955
2184
  }
1956
2185
  function AutoScrollOnUserSend({ userMessageCount }) {
@@ -1966,39 +2195,75 @@ function AutoScrollOnUserSend({ userMessageCount }) {
1966
2195
  }
1967
2196
  function ScrollToBottomButton() {
1968
2197
  const { isAtBottom, scrollToBottom } = useStickToBottomContext();
1969
- if (isAtBottom) return null;
1970
- return /* @__PURE__ */ jsxs10(
2198
+ const [visible, setVisible] = useState9(false);
2199
+ const hideTimerRef = useRef5(null);
2200
+ useEffect5(() => {
2201
+ if (isAtBottom) {
2202
+ if (!hideTimerRef.current) {
2203
+ hideTimerRef.current = setTimeout(() => {
2204
+ setVisible(false);
2205
+ hideTimerRef.current = null;
2206
+ }, 300);
2207
+ }
2208
+ } else {
2209
+ if (hideTimerRef.current) {
2210
+ clearTimeout(hideTimerRef.current);
2211
+ hideTimerRef.current = null;
2212
+ }
2213
+ setVisible(true);
2214
+ }
2215
+ return () => {
2216
+ if (hideTimerRef.current) {
2217
+ clearTimeout(hideTimerRef.current);
2218
+ hideTimerRef.current = null;
2219
+ }
2220
+ };
2221
+ }, [isAtBottom]);
2222
+ const handleClick = useCallback3(() => {
2223
+ if (hideTimerRef.current) {
2224
+ clearTimeout(hideTimerRef.current);
2225
+ hideTimerRef.current = null;
2226
+ }
2227
+ setVisible(false);
2228
+ scrollToBottom();
2229
+ }, [scrollToBottom]);
2230
+ if (!visible) return null;
2231
+ return /* @__PURE__ */ jsxs11(
1971
2232
  "button",
1972
2233
  {
1973
2234
  type: "button",
1974
- onClick: () => scrollToBottom(),
1975
- className: "absolute bottom-4 right-4 flex items-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-1.5 text-xs text-[hsl(var(--muted-foreground))] shadow-lg transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
2235
+ onClick: handleClick,
2236
+ "aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
2237
+ className: "blade-chat-scroll-bottom absolute bottom-4 right-4 flex items-center gap-1 rounded-full border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-3 py-1.5 text-xs text-[hsl(var(--muted-foreground))] shadow-lg transition-colors hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]",
1976
2238
  children: [
1977
- /* @__PURE__ */ jsx12(ChevronDown, { size: 14 }),
1978
- /* @__PURE__ */ jsx12("span", { children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
2239
+ /* @__PURE__ */ jsx13(ChevronDown, { size: 14 }),
2240
+ /* @__PURE__ */ jsx13("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
1979
2241
  ]
1980
2242
  }
1981
2243
  );
1982
2244
  }
1983
2245
  function PlanningDivider({ kind }) {
1984
- return /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3 py-1", children: [
1985
- /* @__PURE__ */ jsx12("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
1986
- /* @__PURE__ */ jsxs10("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: [
1987
- /* @__PURE__ */ jsx12(Lightbulb, { size: 12 }),
1988
- /* @__PURE__ */ jsx12("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
2246
+ return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3 py-1", children: [
2247
+ /* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
2248
+ /* @__PURE__ */ jsxs11("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: [
2249
+ /* @__PURE__ */ jsx13(Lightbulb, { size: 12 }),
2250
+ /* @__PURE__ */ jsx13("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
1989
2251
  ] }),
1990
- /* @__PURE__ */ jsx12("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
2252
+ /* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
1991
2253
  ] });
1992
2254
  }
1993
2255
 
1994
2256
  // src/components/ChatView.tsx
1995
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2257
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2258
+ function themeAttr(theme) {
2259
+ return theme === "dark" ? "dark" : void 0;
2260
+ }
1996
2261
  function isUnauthorizedError(error) {
1997
2262
  return error instanceof BladeApiError && error.status === 401;
1998
2263
  }
1999
2264
  function LoginCard({ client, onLoggedIn }) {
2000
- const [loggingIn, setLoggingIn] = useState8(false);
2001
- const [loginError, setLoginError] = useState8(null);
2265
+ const [loggingIn, setLoggingIn] = useState10(false);
2266
+ const [loginError, setLoginError] = useState10(null);
2002
2267
  const handleLogin = async () => {
2003
2268
  setLoggingIn(true);
2004
2269
  setLoginError(null);
@@ -2011,11 +2276,11 @@ function LoginCard({ client, onLoggedIn }) {
2011
2276
  setLoggingIn(false);
2012
2277
  }
2013
2278
  };
2014
- return /* @__PURE__ */ jsx13("div", { className: "blade-chat-login flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs11("div", { className: "flex w-full max-w-sm flex-col items-center gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-6 py-8 text-center", children: [
2015
- /* @__PURE__ */ jsx13(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
2016
- /* @__PURE__ */ jsx13("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
2017
- /* @__PURE__ */ jsx13("div", { className: "text-sm text-[hsl(var(--muted-foreground))]", children: "\u767B\u5F55\u540E\u5373\u53EF\u4E0E\u667A\u80FD\u4F53\u5BF9\u8BDD\uFF0C\u4F60\u7684\u4F1A\u8BDD\u5185\u5BB9\u4EC5\u81EA\u5DF1\u53EF\u89C1\u3002" }),
2018
- /* @__PURE__ */ jsx13(
2279
+ return /* @__PURE__ */ jsx14("div", { className: "blade-chat-login flex flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsxs12("div", { className: "flex w-full max-w-sm flex-col items-center gap-4 rounded-2xl border border-[hsl(var(--border))] bg-[hsl(var(--card))] px-6 py-8 text-center", children: [
2280
+ /* @__PURE__ */ jsx14(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
2281
+ /* @__PURE__ */ jsx14("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
2282
+ /* @__PURE__ */ jsx14("div", { className: "text-sm text-[hsl(var(--muted-foreground))]", children: "\u767B\u5F55\u540E\u5373\u53EF\u4E0E\u667A\u80FD\u4F53\u5BF9\u8BDD\uFF0C\u4F60\u7684\u4F1A\u8BDD\u5185\u5BB9\u4EC5\u81EA\u5DF1\u53EF\u89C1\u3002" }),
2283
+ /* @__PURE__ */ jsx14(
2019
2284
  "button",
2020
2285
  {
2021
2286
  type: "button",
@@ -2025,26 +2290,33 @@ function LoginCard({ client, onLoggedIn }) {
2025
2290
  children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
2026
2291
  }
2027
2292
  ),
2028
- loginError && /* @__PURE__ */ jsx13("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
2293
+ loginError && /* @__PURE__ */ jsx14("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
2029
2294
  ] }) });
2030
2295
  }
2031
2296
  function ChatView(props) {
2032
2297
  const client = useBladeClient();
2033
- const [attempt, setAttempt] = useState8(0);
2034
- const [needLogin, setNeedLogin] = useState8(() => !client.hasToken());
2298
+ const [attempt, setAttempt] = useState10(0);
2299
+ const [needLogin, setNeedLogin] = useState10(() => !client.hasToken());
2035
2300
  if (needLogin) {
2036
- return /* @__PURE__ */ jsx13("div", { className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root), children: /* @__PURE__ */ jsx13(
2037
- LoginCard,
2301
+ return /* @__PURE__ */ jsx14(
2302
+ "div",
2038
2303
  {
2039
- client,
2040
- onLoggedIn: () => {
2041
- setNeedLogin(false);
2042
- setAttempt((value) => value + 1);
2043
- }
2304
+ "data-theme": themeAttr(props.theme),
2305
+ className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root),
2306
+ children: /* @__PURE__ */ jsx14(
2307
+ LoginCard,
2308
+ {
2309
+ client,
2310
+ onLoggedIn: () => {
2311
+ setNeedLogin(false);
2312
+ setAttempt((value) => value + 1);
2313
+ }
2314
+ }
2315
+ )
2044
2316
  }
2045
- ) });
2317
+ );
2046
2318
  }
2047
- return /* @__PURE__ */ jsx13(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
2319
+ return /* @__PURE__ */ jsx14(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
2048
2320
  }
2049
2321
  function ChatSessionView({
2050
2322
  sessionId,
@@ -2056,14 +2328,15 @@ function ChatSessionView({
2056
2328
  renderers,
2057
2329
  slots,
2058
2330
  placeholder,
2331
+ theme,
2059
2332
  onUnauthorized
2060
2333
  }) {
2061
2334
  const { session, state, error } = useAgentSession(sessionId, {
2062
2335
  createOptions,
2063
2336
  onSessionCreated
2064
2337
  });
2065
- const [stopRequested, setStopRequested] = useState8(false);
2066
- const [inputText, setInputText] = useState8("");
2338
+ const [stopRequested, setStopRequested] = useState10(false);
2339
+ const [inputText, setInputText] = useState10("");
2067
2340
  useEffect6(() => {
2068
2341
  if (session) {
2069
2342
  onSessionReady?.(session);
@@ -2111,27 +2384,28 @@ ${content}`);
2111
2384
  setStopRequested(true);
2112
2385
  void session?.stop();
2113
2386
  };
2114
- return /* @__PURE__ */ jsxs11(
2387
+ return /* @__PURE__ */ jsxs12(
2115
2388
  "div",
2116
2389
  {
2390
+ "data-theme": themeAttr(theme),
2117
2391
  className: cn(
2118
2392
  "blade-chat flex min-h-0 flex-1 flex-col overflow-hidden",
2119
2393
  classNames?.root
2120
2394
  ),
2121
2395
  children: [
2122
- /* @__PURE__ */ jsx13(
2396
+ /* @__PURE__ */ jsx14(
2123
2397
  ConnectionBanner,
2124
2398
  {
2125
2399
  connection: state?.connection ?? "connecting",
2126
2400
  className: classNames?.banner
2127
2401
  }
2128
2402
  ),
2129
- errorMessage && /* @__PURE__ */ jsxs11("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800 dark:border-red-800/30 dark:bg-red-950/30 dark:text-red-300", children: [
2130
- /* @__PURE__ */ jsx13(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
2131
- /* @__PURE__ */ jsx13("span", { children: errorMessage })
2403
+ errorMessage && /* @__PURE__ */ jsxs12("div", { className: "blade-chat-error-bar flex items-start gap-2 border-b px-4 py-3 text-sm", children: [
2404
+ /* @__PURE__ */ jsx14(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
2405
+ /* @__PURE__ */ jsx14("span", { children: errorMessage })
2132
2406
  ] }),
2133
2407
  slots?.header,
2134
- /* @__PURE__ */ jsx13(
2408
+ /* @__PURE__ */ jsx14(
2135
2409
  MessageList,
2136
2410
  {
2137
2411
  messages: state?.messages ?? [],
@@ -2146,10 +2420,11 @@ ${content}`);
2146
2420
  },
2147
2421
  toolCallRenderer: renderers?.toolCall,
2148
2422
  emptyState: slots?.emptyState,
2149
- className: classNames?.messageList
2423
+ className: classNames?.messageList,
2424
+ sessionId: session?.sessionId
2150
2425
  }
2151
2426
  ),
2152
- /* @__PURE__ */ jsx13(
2427
+ /* @__PURE__ */ jsx14(
2153
2428
  ChatInput,
2154
2429
  {
2155
2430
  value: inputText,
@@ -2183,6 +2458,7 @@ lucide-react/dist/esm/shared/src/utils.js:
2183
2458
  lucide-react/dist/esm/defaultAttributes.js:
2184
2459
  lucide-react/dist/esm/Icon.js:
2185
2460
  lucide-react/dist/esm/createLucideIcon.js:
2461
+ lucide-react/dist/esm/icons/archive.js:
2186
2462
  lucide-react/dist/esm/icons/arrow-up.js:
2187
2463
  lucide-react/dist/esm/icons/bot.js:
2188
2464
  lucide-react/dist/esm/icons/brain.js:
@@ -2191,13 +2467,20 @@ lucide-react/dist/esm/icons/chevron-down.js:
2191
2467
  lucide-react/dist/esm/icons/chevron-right.js:
2192
2468
  lucide-react/dist/esm/icons/circle-alert.js:
2193
2469
  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:
2194
2473
  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:
2195
2477
  lucide-react/dist/esm/icons/layers.js:
2196
2478
  lucide-react/dist/esm/icons/lightbulb.js:
2197
2479
  lucide-react/dist/esm/icons/loader-circle.js:
2198
2480
  lucide-react/dist/esm/icons/lock-keyhole.js:
2199
2481
  lucide-react/dist/esm/icons/message-square-more.js:
2200
2482
  lucide-react/dist/esm/icons/message-square.js:
2483
+ lucide-react/dist/esm/icons/music.js:
2201
2484
  lucide-react/dist/esm/icons/square.js:
2202
2485
  lucide-react/dist/esm/icons/triangle-alert.js:
2203
2486
  lucide-react/dist/esm/icons/x.js: