@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/README.md +20 -7
- package/dist/components/AssistantTurnBlock.d.ts +3 -1
- package/dist/components/ChatView.d.ts +2 -0
- package/dist/components/FileCard.d.ts +16 -0
- package/dist/components/MarkdownContent.d.ts +8 -4
- package/dist/components/MessageList.d.ts +3 -1
- package/dist/components/ToolCallBlock.d.ts +17 -0
- package/dist/embed/blade-chat-element.d.ts +1 -1
- package/dist/index.js +459 -176
- package/dist/index.js.map +1 -1
- package/dist/lib/media-tags.d.ts +24 -0
- package/dist/style.css +148 -4
- package/dist/style.full.css +675 -0
- package/package.json +4 -3
- package/public-api.md +3 -1
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
|
|
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))]
|
|
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
|
|
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
|
|
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, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
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] =
|
|
1090
|
-
const [language, setLanguage] =
|
|
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__ */
|
|
1103
|
-
/* @__PURE__ */
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1116
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
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
|
|
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
|
|
1362
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1154
1363
|
function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
1155
|
-
return /* @__PURE__ */
|
|
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
|
|
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
|
|
1163
|
-
import { jsx as
|
|
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] =
|
|
1173
|
-
const [customTexts, setCustomTexts] =
|
|
1174
|
-
const [usingCustom, setUsingCustom] =
|
|
1175
|
-
const [submitted, setSubmitted] =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1333
|
-
/* @__PURE__ */
|
|
1334
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1557
|
+
children: /* @__PURE__ */ jsx8(MarkdownContent, { className: "blade-chat-prose", children: question.question })
|
|
1349
1558
|
}
|
|
1350
1559
|
)
|
|
1351
1560
|
] }),
|
|
1352
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1386
|
-
/* @__PURE__ */
|
|
1387
|
-
opt.description && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
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
|
|
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] =
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1729
|
+
return /* @__PURE__ */ jsx9(
|
|
1505
1730
|
AskUserQuestionBlock,
|
|
1506
1731
|
{
|
|
1507
1732
|
data: askData,
|
|
1508
|
-
answered:
|
|
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__ */
|
|
1518
|
-
/* @__PURE__ */
|
|
1519
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1523
|
-
/* @__PURE__ */
|
|
1524
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1533
|
-
/* @__PURE__ */
|
|
1534
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1777
|
+
/* @__PURE__ */ jsxs7("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
|
|
1553
1778
|
statusIcon,
|
|
1554
|
-
/* @__PURE__ */
|
|
1779
|
+
/* @__PURE__ */ jsx9("span", { children: getToolStatusLabel(toolCall.status) })
|
|
1555
1780
|
] }),
|
|
1556
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1563
|
-
/* @__PURE__ */
|
|
1564
|
-
/* @__PURE__ */
|
|
1565
|
-
/* @__PURE__ */
|
|
1566
|
-
/* @__PURE__ */
|
|
1567
|
-
toolCall.result != null && /* @__PURE__ */
|
|
1568
|
-
/* @__PURE__ */
|
|
1569
|
-
/* @__PURE__ */
|
|
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
|
|
1812
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1588
1813
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
1589
|
-
const [open, setOpen] =
|
|
1590
|
-
return /* @__PURE__ */
|
|
1591
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1600
|
-
isStreaming ? /* @__PURE__ */
|
|
1601
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1642
|
-
hasInterrupted && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1655
|
-
text && /* @__PURE__ */
|
|
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__ */
|
|
1664
|
-
(toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1722
|
-
/* @__PURE__ */
|
|
1723
|
-
/* @__PURE__ */
|
|
1724
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1753
|
-
imageParts.length > 0 && /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1768
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1774
|
-
text && isSending(message) && /* @__PURE__ */
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1905
|
-
/* @__PURE__ */
|
|
1906
|
-
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */
|
|
1907
|
-
/* @__PURE__ */
|
|
1908
|
-
/* @__PURE__ */
|
|
1909
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1942
|
-
/* @__PURE__ */
|
|
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__ */
|
|
2177
|
+
return /* @__PURE__ */ jsx13(PlanningDivider, { kind: block.kind }, block.key);
|
|
1949
2178
|
}),
|
|
1950
|
-
sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */
|
|
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__ */
|
|
1953
|
-
/* @__PURE__ */
|
|
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
|
-
|
|
1970
|
-
|
|
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:
|
|
1975
|
-
|
|
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__ */
|
|
1978
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1985
|
-
/* @__PURE__ */
|
|
1986
|
-
/* @__PURE__ */
|
|
1987
|
-
/* @__PURE__ */
|
|
1988
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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] =
|
|
2001
|
-
const [loginError, setLoginError] =
|
|
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__ */
|
|
2015
|
-
/* @__PURE__ */
|
|
2016
|
-
/* @__PURE__ */
|
|
2017
|
-
/* @__PURE__ */
|
|
2018
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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] =
|
|
2034
|
-
const [needLogin, setNeedLogin] =
|
|
2298
|
+
const [attempt, setAttempt] = useState10(0);
|
|
2299
|
+
const [needLogin, setNeedLogin] = useState10(() => !client.hasToken());
|
|
2035
2300
|
if (needLogin) {
|
|
2036
|
-
return /* @__PURE__ */
|
|
2037
|
-
|
|
2301
|
+
return /* @__PURE__ */ jsx14(
|
|
2302
|
+
"div",
|
|
2038
2303
|
{
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
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__ */
|
|
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] =
|
|
2066
|
-
const [inputText, setInputText] =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2130
|
-
/* @__PURE__ */
|
|
2131
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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:
|