@blade-hq/agent-react 1.2.1-alpha.4 → 1.2.1-beta.10
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 +10 -1
- package/dist/components/AssistantTurnBlock.d.ts +3 -1
- package/dist/components/ChatInput.d.ts +1 -1
- 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/index.js +404 -167
- package/dist/index.js.map +1 -1
- package/dist/lib/media-tags.d.ts +24 -0
- package/dist/style.css +146 -2
- package/package.json +2 -2
- package/public-api.md +17 -8
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 useState9 } from "react";
|
|
341
405
|
|
|
342
406
|
// src/lib/utils.ts
|
|
343
407
|
function cn(...inputs) {
|
|
@@ -366,18 +430,19 @@ function ChatInput({
|
|
|
366
430
|
}) {
|
|
367
431
|
const trimmed = value.trim();
|
|
368
432
|
const canSend = trimmed.length > 0 && !isStreaming;
|
|
369
|
-
const handleSend = () => {
|
|
433
|
+
const handleSend = async () => {
|
|
370
434
|
if (!canSend) return;
|
|
371
|
-
onSend(trimmed);
|
|
435
|
+
const accepted = await onSend(trimmed);
|
|
436
|
+
if (!accepted) return;
|
|
372
437
|
onValueChange("");
|
|
373
438
|
};
|
|
374
439
|
const handleKeyDown = (event) => {
|
|
375
440
|
if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
|
|
376
441
|
event.preventDefault();
|
|
377
|
-
handleSend();
|
|
442
|
+
void handleSend();
|
|
378
443
|
}
|
|
379
444
|
};
|
|
380
|
-
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: [
|
|
381
446
|
/* @__PURE__ */ jsx2(
|
|
382
447
|
"textarea",
|
|
383
448
|
{
|
|
@@ -876,7 +941,7 @@ function useStickToBottomContext() {
|
|
|
876
941
|
|
|
877
942
|
// src/components/AssistantTurnBlock.tsx
|
|
878
943
|
import { getTextContent, normalizeMessageContent } from "@blade-hq/agent-client";
|
|
879
|
-
import { useState as
|
|
944
|
+
import { useState as useState8 } from "react";
|
|
880
945
|
|
|
881
946
|
// src/components/AgentLoopBlock.tsx
|
|
882
947
|
import { useState as useState3 } from "react";
|
|
@@ -1079,14 +1144,142 @@ import {
|
|
|
1079
1144
|
useEffect as useEffect3,
|
|
1080
1145
|
useMemo as useMemo4,
|
|
1081
1146
|
useRef as useRef4,
|
|
1082
|
-
useState as
|
|
1147
|
+
useState as useState5
|
|
1083
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";
|
|
1084
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";
|
|
1085
1278
|
var SYSTEM_REMINDER_RE = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
1086
1279
|
function CodeBlockPre({ children, node: _node, ...props }) {
|
|
1087
1280
|
const preRef = useRef4(null);
|
|
1088
|
-
const [copied, setCopied] =
|
|
1089
|
-
const [language, setLanguage] =
|
|
1281
|
+
const [copied, setCopied] = useState5(false);
|
|
1282
|
+
const [language, setLanguage] = useState5("");
|
|
1090
1283
|
useEffect3(() => {
|
|
1091
1284
|
const codeEl = preRef.current?.querySelector("code");
|
|
1092
1285
|
setLanguage(codeEl?.className.match(/language-(\S+)/)?.[1] ?? "");
|
|
@@ -1098,10 +1291,10 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1098
1291
|
setTimeout(() => setCopied(false), 2e3);
|
|
1099
1292
|
}
|
|
1100
1293
|
};
|
|
1101
|
-
return /* @__PURE__ */
|
|
1102
|
-
/* @__PURE__ */
|
|
1103
|
-
/* @__PURE__ */
|
|
1104
|
-
/* @__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(
|
|
1105
1298
|
"button",
|
|
1106
1299
|
{
|
|
1107
1300
|
type: "button",
|
|
@@ -1111,13 +1304,13 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1111
1304
|
copied ? "text-[hsl(var(--primary))]" : "text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))]"
|
|
1112
1305
|
),
|
|
1113
1306
|
children: [
|
|
1114
|
-
copied ? /* @__PURE__ */
|
|
1115
|
-
/* @__PURE__ */
|
|
1307
|
+
copied ? /* @__PURE__ */ jsx6(Check, { size: 12 }) : /* @__PURE__ */ jsx6(Copy, { size: 12 }),
|
|
1308
|
+
/* @__PURE__ */ jsx6("span", { children: copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236" })
|
|
1116
1309
|
]
|
|
1117
1310
|
}
|
|
1118
1311
|
)
|
|
1119
1312
|
] }),
|
|
1120
|
-
/* @__PURE__ */
|
|
1313
|
+
/* @__PURE__ */ jsx6(
|
|
1121
1314
|
"pre",
|
|
1122
1315
|
{
|
|
1123
1316
|
ref: preRef,
|
|
@@ -1129,37 +1322,54 @@ function CodeBlockPre({ children, node: _node, ...props }) {
|
|
|
1129
1322
|
] });
|
|
1130
1323
|
}
|
|
1131
1324
|
function ExternalAnchor({ node: _node, children, ...props }) {
|
|
1132
|
-
return /* @__PURE__ */
|
|
1325
|
+
return /* @__PURE__ */ jsx6("a", { ...props, target: "_blank", rel: "noopener noreferrer", children });
|
|
1133
1326
|
}
|
|
1134
1327
|
var MARKDOWN_COMPONENTS = {
|
|
1135
1328
|
pre: CodeBlockPre,
|
|
1136
1329
|
a: ExternalAnchor
|
|
1137
1330
|
};
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
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(
|
|
1141
1349
|
_r,
|
|
1142
1350
|
{
|
|
1143
1351
|
className: cn("blade-chat-markdown break-words", className),
|
|
1144
1352
|
mode: mode ?? "static",
|
|
1145
|
-
components
|
|
1353
|
+
components,
|
|
1354
|
+
allowedTags: CUSTOM_ALLOWED_TAGS,
|
|
1146
1355
|
children: resolvedChildren
|
|
1147
|
-
}
|
|
1356
|
+
},
|
|
1357
|
+
sessionId ?? "no-session"
|
|
1148
1358
|
);
|
|
1149
1359
|
}
|
|
1150
1360
|
|
|
1151
1361
|
// src/components/Shimmer.tsx
|
|
1152
|
-
import { jsx as
|
|
1362
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1153
1363
|
function Shimmer({ children = "\u6B63\u5728\u601D\u8003...", className }) {
|
|
1154
|
-
return /* @__PURE__ */
|
|
1364
|
+
return /* @__PURE__ */ jsx7("span", { className: cn("blade-shimmer-text text-sm font-medium", className), children });
|
|
1155
1365
|
}
|
|
1156
1366
|
|
|
1157
1367
|
// src/components/ToolCallBlock.tsx
|
|
1158
|
-
import { useState as
|
|
1368
|
+
import { useState as useState7 } from "react";
|
|
1159
1369
|
|
|
1160
1370
|
// src/components/AskUserQuestionBlock.tsx
|
|
1161
|
-
import { useEffect as useEffect4, useMemo as useMemo5, useState as
|
|
1162
|
-
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";
|
|
1163
1373
|
function AskUserQuestionBlock({
|
|
1164
1374
|
data,
|
|
1165
1375
|
answered,
|
|
@@ -1168,10 +1378,10 @@ function AskUserQuestionBlock({
|
|
|
1168
1378
|
answerData,
|
|
1169
1379
|
onAnswer
|
|
1170
1380
|
}) {
|
|
1171
|
-
const [selections, setSelections] =
|
|
1172
|
-
const [customTexts, setCustomTexts] =
|
|
1173
|
-
const [usingCustom, setUsingCustom] =
|
|
1174
|
-
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);
|
|
1175
1385
|
useEffect4(() => {
|
|
1176
1386
|
if (sessionStatus === "failed" || sessionStatus === "interrupted") {
|
|
1177
1387
|
setSubmitted(false);
|
|
@@ -1262,7 +1472,7 @@ ${parts.join("\n")}`;
|
|
|
1262
1472
|
setSubmitted(true);
|
|
1263
1473
|
onAnswer(text, toolCallId, nextAnswerData);
|
|
1264
1474
|
};
|
|
1265
|
-
return /* @__PURE__ */
|
|
1475
|
+
return /* @__PURE__ */ jsxs6(
|
|
1266
1476
|
"div",
|
|
1267
1477
|
{
|
|
1268
1478
|
className: cn(
|
|
@@ -1270,12 +1480,12 @@ ${parts.join("\n")}`;
|
|
|
1270
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"
|
|
1271
1481
|
),
|
|
1272
1482
|
children: [
|
|
1273
|
-
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: [
|
|
1274
1484
|
"\u5B50\u667A\u80FD\u4F53\u300C",
|
|
1275
1485
|
data.source_loop.description,
|
|
1276
1486
|
"\u300D\u5728\u7B49\u5F85\u4F60\u7684\u56DE\u7B54"
|
|
1277
1487
|
] }),
|
|
1278
|
-
data.questions.map((q, qIdx) => /* @__PURE__ */
|
|
1488
|
+
data.questions.map((q, qIdx) => /* @__PURE__ */ jsx8(
|
|
1279
1489
|
QuestionCard,
|
|
1280
1490
|
{
|
|
1281
1491
|
question: q,
|
|
@@ -1290,7 +1500,7 @@ ${parts.join("\n")}`;
|
|
|
1290
1500
|
},
|
|
1291
1501
|
q.question
|
|
1292
1502
|
)),
|
|
1293
|
-
!answered && !submitted && onAnswer && /* @__PURE__ */
|
|
1503
|
+
!answered && !submitted && onAnswer && /* @__PURE__ */ jsx8(
|
|
1294
1504
|
"button",
|
|
1295
1505
|
{
|
|
1296
1506
|
type: "button",
|
|
@@ -1300,14 +1510,14 @@ ${parts.join("\n")}`;
|
|
|
1300
1510
|
children: allAnswered ? "\u786E\u8BA4" : "\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u9009\u9879"
|
|
1301
1511
|
}
|
|
1302
1512
|
),
|
|
1303
|
-
submitted && !answered && /* @__PURE__ */
|
|
1513
|
+
submitted && !answered && /* @__PURE__ */ jsxs6(
|
|
1304
1514
|
"button",
|
|
1305
1515
|
{
|
|
1306
1516
|
type: "button",
|
|
1307
1517
|
disabled: true,
|
|
1308
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",
|
|
1309
1519
|
children: [
|
|
1310
|
-
/* @__PURE__ */
|
|
1520
|
+
/* @__PURE__ */ jsx8(LoaderCircle, { size: 14, className: "animate-spin" }),
|
|
1311
1521
|
"\u786E\u8BA4\u4E2D"
|
|
1312
1522
|
]
|
|
1313
1523
|
}
|
|
@@ -1328,30 +1538,30 @@ function QuestionCard({
|
|
|
1328
1538
|
onCustomChange
|
|
1329
1539
|
}) {
|
|
1330
1540
|
const multi = question.multiSelect ?? false;
|
|
1331
|
-
return /* @__PURE__ */
|
|
1332
|
-
/* @__PURE__ */
|
|
1333
|
-
/* @__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(
|
|
1334
1544
|
MessageSquareMore,
|
|
1335
1545
|
{
|
|
1336
1546
|
size: answered ? 12 : 13,
|
|
1337
1547
|
className: "mt-0.5 shrink-0 text-[hsl(var(--primary))]"
|
|
1338
1548
|
}
|
|
1339
1549
|
),
|
|
1340
|
-
/* @__PURE__ */
|
|
1550
|
+
/* @__PURE__ */ jsx8(
|
|
1341
1551
|
"div",
|
|
1342
1552
|
{
|
|
1343
1553
|
className: cn(
|
|
1344
1554
|
"min-w-0 flex-1 font-medium text-[hsl(var(--foreground))]",
|
|
1345
1555
|
answered ? "text-xs" : "text-sm"
|
|
1346
1556
|
),
|
|
1347
|
-
children: /* @__PURE__ */
|
|
1557
|
+
children: /* @__PURE__ */ jsx8(MarkdownContent, { className: "blade-chat-prose", children: question.question })
|
|
1348
1558
|
}
|
|
1349
1559
|
)
|
|
1350
1560
|
] }),
|
|
1351
|
-
/* @__PURE__ */
|
|
1561
|
+
/* @__PURE__ */ jsxs6("div", { className: cn("flex flex-col pl-5", answered ? "gap-1" : "gap-1.5"), children: [
|
|
1352
1562
|
question.options.map((opt, optIdx) => {
|
|
1353
1563
|
const isSel = selected.has(optIdx);
|
|
1354
|
-
return /* @__PURE__ */
|
|
1564
|
+
return /* @__PURE__ */ jsxs6(
|
|
1355
1565
|
"button",
|
|
1356
1566
|
{
|
|
1357
1567
|
type: "button",
|
|
@@ -1365,14 +1575,14 @@ function QuestionCard({
|
|
|
1365
1575
|
answered && "cursor-default opacity-70"
|
|
1366
1576
|
),
|
|
1367
1577
|
children: [
|
|
1368
|
-
multi && /* @__PURE__ */
|
|
1578
|
+
multi && /* @__PURE__ */ jsx8(
|
|
1369
1579
|
"div",
|
|
1370
1580
|
{
|
|
1371
1581
|
className: cn(
|
|
1372
1582
|
"mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors",
|
|
1373
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))]"
|
|
1374
1584
|
),
|
|
1375
|
-
children: isSel && /* @__PURE__ */
|
|
1585
|
+
children: isSel && /* @__PURE__ */ jsx8(
|
|
1376
1586
|
Check,
|
|
1377
1587
|
{
|
|
1378
1588
|
size: 9,
|
|
@@ -1381,9 +1591,9 @@ function QuestionCard({
|
|
|
1381
1591
|
)
|
|
1382
1592
|
}
|
|
1383
1593
|
),
|
|
1384
|
-
/* @__PURE__ */
|
|
1385
|
-
/* @__PURE__ */
|
|
1386
|
-
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(
|
|
1387
1597
|
"div",
|
|
1388
1598
|
{
|
|
1389
1599
|
className: cn(
|
|
@@ -1400,7 +1610,7 @@ function QuestionCard({
|
|
|
1400
1610
|
opt.label
|
|
1401
1611
|
);
|
|
1402
1612
|
}),
|
|
1403
|
-
answered && !isCustom ? null : /* @__PURE__ */
|
|
1613
|
+
answered && !isCustom ? null : /* @__PURE__ */ jsxs6(
|
|
1404
1614
|
"div",
|
|
1405
1615
|
{
|
|
1406
1616
|
className: cn(
|
|
@@ -1410,8 +1620,8 @@ function QuestionCard({
|
|
|
1410
1620
|
answered && "cursor-default opacity-70"
|
|
1411
1621
|
),
|
|
1412
1622
|
children: [
|
|
1413
|
-
/* @__PURE__ */
|
|
1414
|
-
/* @__PURE__ */
|
|
1623
|
+
/* @__PURE__ */ jsx8("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: "\u5176\u4ED6\uFF1A" }),
|
|
1624
|
+
/* @__PURE__ */ jsx8(
|
|
1415
1625
|
"input",
|
|
1416
1626
|
{
|
|
1417
1627
|
type: "text",
|
|
@@ -1479,7 +1689,7 @@ function normalizeOptionItem(value) {
|
|
|
1479
1689
|
}
|
|
1480
1690
|
|
|
1481
1691
|
// src/components/ToolCallBlock.tsx
|
|
1482
|
-
import { Fragment, jsx as
|
|
1692
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1483
1693
|
function ToolCallBlock({
|
|
1484
1694
|
toolCall,
|
|
1485
1695
|
onAnswer,
|
|
@@ -1488,19 +1698,19 @@ function ToolCallBlock({
|
|
|
1488
1698
|
sessionStatus,
|
|
1489
1699
|
renderer
|
|
1490
1700
|
}) {
|
|
1491
|
-
const [expanded, setExpanded] =
|
|
1701
|
+
const [expanded, setExpanded] = useState7(false);
|
|
1492
1702
|
const normalizedName = formatToolName(toolCall.name);
|
|
1493
1703
|
if (renderer) {
|
|
1494
1704
|
const custom = renderer(toolCall);
|
|
1495
1705
|
if (custom !== null && custom !== void 0) {
|
|
1496
|
-
return /* @__PURE__ */
|
|
1706
|
+
return /* @__PURE__ */ jsx9(Fragment, { children: custom });
|
|
1497
1707
|
}
|
|
1498
1708
|
}
|
|
1499
1709
|
if (normalizedName === "AskUserQuestion") {
|
|
1500
1710
|
const askData = parseAskUserQuestion(typeof toolCall.result === "string" ? toolCall.result : null) ?? parseAskUserQuestion(buildAskUserPayload(toolCall.arguments));
|
|
1501
1711
|
const canAnswer = toolCall.status === "awaiting_answer" && Boolean(onAnswer);
|
|
1502
1712
|
if (askData) {
|
|
1503
|
-
return /* @__PURE__ */
|
|
1713
|
+
return /* @__PURE__ */ jsx9(
|
|
1504
1714
|
AskUserQuestionBlock,
|
|
1505
1715
|
{
|
|
1506
1716
|
data: askData,
|
|
@@ -1513,24 +1723,24 @@ function ToolCallBlock({
|
|
|
1513
1723
|
);
|
|
1514
1724
|
}
|
|
1515
1725
|
if (toolCall.status === "pending") {
|
|
1516
|
-
return /* @__PURE__ */
|
|
1517
|
-
/* @__PURE__ */
|
|
1518
|
-
/* @__PURE__ */
|
|
1726
|
+
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: [
|
|
1727
|
+
/* @__PURE__ */ jsx9(LoaderCircle, { size: 14, className: "animate-spin" }),
|
|
1728
|
+
/* @__PURE__ */ jsx9("span", { children: "\u6B63\u5728\u51C6\u5907\u95EE\u9898\u2026" })
|
|
1519
1729
|
] });
|
|
1520
1730
|
}
|
|
1521
|
-
return /* @__PURE__ */
|
|
1522
|
-
/* @__PURE__ */
|
|
1523
|
-
/* @__PURE__ */
|
|
1731
|
+
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: [
|
|
1732
|
+
/* @__PURE__ */ jsx9("div", { className: "font-semibold", children: "\u9009\u62E9\u9898\u5185\u5BB9\u6682\u65F6\u65E0\u6CD5\u663E\u793A" }),
|
|
1733
|
+
/* @__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" })
|
|
1524
1734
|
] });
|
|
1525
1735
|
}
|
|
1526
1736
|
const tone = getToolTone(toolCall.status);
|
|
1527
1737
|
const displayName = getToolDisplayLabel(toolCall);
|
|
1528
1738
|
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))]";
|
|
1529
|
-
const statusIcon = toolCall.status === "pending" ? /* @__PURE__ */
|
|
1739
|
+
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 });
|
|
1530
1740
|
const statusTextClass = tone === "red" ? "text-[hsl(var(--muted-foreground))]" : tone === "amber" ? "text-amber-300" : tone === "blue" ? "text-blue-300" : "text-[hsl(var(--primary))]";
|
|
1531
|
-
return /* @__PURE__ */
|
|
1532
|
-
/* @__PURE__ */
|
|
1533
|
-
/* @__PURE__ */
|
|
1741
|
+
return /* @__PURE__ */ jsxs7("div", { className: "blade-chat-tool ml-4 text-xs", children: [
|
|
1742
|
+
/* @__PURE__ */ jsxs7("div", { className: cn("border-l-[3px] flex items-center gap-2 px-3 py-2", toneClass), children: [
|
|
1743
|
+
/* @__PURE__ */ jsxs7(
|
|
1534
1744
|
"button",
|
|
1535
1745
|
{
|
|
1536
1746
|
type: "button",
|
|
@@ -1538,7 +1748,7 @@ function ToolCallBlock({
|
|
|
1538
1748
|
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",
|
|
1539
1749
|
"aria-expanded": expanded,
|
|
1540
1750
|
children: [
|
|
1541
|
-
/* @__PURE__ */
|
|
1751
|
+
/* @__PURE__ */ jsx9(
|
|
1542
1752
|
ChevronRight,
|
|
1543
1753
|
{
|
|
1544
1754
|
size: 11,
|
|
@@ -1548,24 +1758,24 @@ function ToolCallBlock({
|
|
|
1548
1758
|
)
|
|
1549
1759
|
}
|
|
1550
1760
|
),
|
|
1551
|
-
/* @__PURE__ */
|
|
1761
|
+
/* @__PURE__ */ jsxs7("span", { className: cn("flex shrink-0 items-center gap-1 text-[10px]", statusTextClass), children: [
|
|
1552
1762
|
statusIcon,
|
|
1553
|
-
/* @__PURE__ */
|
|
1763
|
+
/* @__PURE__ */ jsx9("span", { children: getToolStatusLabel(toolCall.status) })
|
|
1554
1764
|
] }),
|
|
1555
|
-
/* @__PURE__ */
|
|
1765
|
+
/* @__PURE__ */ jsx9("span", { className: "min-w-0 flex-1 truncate font-medium text-[hsl(var(--foreground))]", children: displayName })
|
|
1556
1766
|
]
|
|
1557
1767
|
}
|
|
1558
1768
|
),
|
|
1559
|
-
typeof toolCall.duration_ms === "number" && toolCall.duration_ms > 0 && /* @__PURE__ */
|
|
1769
|
+
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) })
|
|
1560
1770
|
] }),
|
|
1561
|
-
expanded && /* @__PURE__ */
|
|
1562
|
-
/* @__PURE__ */
|
|
1563
|
-
/* @__PURE__ */
|
|
1564
|
-
/* @__PURE__ */
|
|
1565
|
-
/* @__PURE__ */
|
|
1566
|
-
toolCall.result != null && /* @__PURE__ */
|
|
1567
|
-
/* @__PURE__ */
|
|
1568
|
-
/* @__PURE__ */
|
|
1771
|
+
expanded && /* @__PURE__ */ jsxs7("div", { className: "blade-chat-tool-detail ml-4 mt-1 rounded-xl bg-[hsl(var(--card))] px-3 py-3", children: [
|
|
1772
|
+
/* @__PURE__ */ jsx9("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u5DE5\u5177" }),
|
|
1773
|
+
/* @__PURE__ */ jsx9("div", { className: "mb-3 font-mono text-[11px] text-[hsl(var(--foreground))]", children: normalizedName }),
|
|
1774
|
+
/* @__PURE__ */ jsx9("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u53C2\u6570" }),
|
|
1775
|
+
/* @__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) }),
|
|
1776
|
+
toolCall.result != null && /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
1777
|
+
/* @__PURE__ */ jsx9("div", { className: "mb-1 mt-3 text-[10px] uppercase tracking-wider text-[hsl(var(--muted-foreground))]", children: "\u7ED3\u679C" }),
|
|
1778
|
+
/* @__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) })
|
|
1569
1779
|
] })
|
|
1570
1780
|
] })
|
|
1571
1781
|
] });
|
|
@@ -1583,11 +1793,11 @@ function buildAskUserPayload(argumentsJson) {
|
|
|
1583
1793
|
}
|
|
1584
1794
|
|
|
1585
1795
|
// src/components/AssistantTurnBlock.tsx
|
|
1586
|
-
import { jsx as
|
|
1796
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1587
1797
|
function ThinkingBlock({ reasoning, isStreaming }) {
|
|
1588
|
-
const [open, setOpen] =
|
|
1589
|
-
return /* @__PURE__ */
|
|
1590
|
-
/* @__PURE__ */
|
|
1798
|
+
const [open, setOpen] = useState8(false);
|
|
1799
|
+
return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-thinking ml-4 text-sm", children: [
|
|
1800
|
+
/* @__PURE__ */ jsxs8(
|
|
1591
1801
|
"button",
|
|
1592
1802
|
{
|
|
1593
1803
|
type: "button",
|
|
@@ -1595,9 +1805,14 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
1595
1805
|
"aria-expanded": open,
|
|
1596
1806
|
className: "inline-flex items-center gap-1.5 text-[hsl(var(--muted-foreground))] transition-colors hover:text-[hsl(var(--foreground))]",
|
|
1597
1807
|
children: [
|
|
1598
|
-
/* @__PURE__ */
|
|
1599
|
-
isStreaming ? /* @__PURE__ */
|
|
1600
|
-
/* @__PURE__ */
|
|
1808
|
+
/* @__PURE__ */ jsx10(Brain, { size: 12, className: "shrink-0" }),
|
|
1809
|
+
isStreaming ? /* @__PURE__ */ jsx10(Shimmer, { className: "text-xs", children: "\u6B63\u5728\u601D\u8003" }) : /* @__PURE__ */ jsx10("span", { children: "\u601D\u8003\u8FC7\u7A0B" }),
|
|
1810
|
+
/* @__PURE__ */ jsxs8("span", { className: "text-[hsl(var(--muted-foreground))]/70", children: [
|
|
1811
|
+
"\xB7 ",
|
|
1812
|
+
new Intl.NumberFormat("zh-CN").format(reasoning.length),
|
|
1813
|
+
" \u5B57"
|
|
1814
|
+
] }),
|
|
1815
|
+
/* @__PURE__ */ jsx10(
|
|
1601
1816
|
ChevronDown,
|
|
1602
1817
|
{
|
|
1603
1818
|
size: 12,
|
|
@@ -1607,47 +1822,57 @@ function ThinkingBlock({ reasoning, isStreaming }) {
|
|
|
1607
1822
|
]
|
|
1608
1823
|
}
|
|
1609
1824
|
),
|
|
1610
|
-
open && /* @__PURE__ */
|
|
1825
|
+
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 })
|
|
1611
1826
|
] });
|
|
1612
1827
|
}
|
|
1613
1828
|
function getMessageText(message) {
|
|
1614
1829
|
return getTextContent(normalizeMessageContent(message.content)).trim();
|
|
1615
1830
|
}
|
|
1831
|
+
function findLatestReasoningMessageIndex(messages) {
|
|
1832
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
1833
|
+
if (messages[index].reasoning) return index;
|
|
1834
|
+
}
|
|
1835
|
+
return -1;
|
|
1836
|
+
}
|
|
1616
1837
|
function AssistantTurnBlock({
|
|
1617
1838
|
messages,
|
|
1618
1839
|
isStreaming = false,
|
|
1619
1840
|
askAnswers,
|
|
1620
1841
|
onAnswer,
|
|
1621
1842
|
sessionStatus,
|
|
1622
|
-
toolCallRenderer
|
|
1843
|
+
toolCallRenderer,
|
|
1844
|
+
sessionId
|
|
1623
1845
|
}) {
|
|
1624
1846
|
const hasInterrupted = messages.some((message) => message.status === "interrupted");
|
|
1625
1847
|
const hasAnyContent = messages.some(
|
|
1626
1848
|
(message) => getMessageText(message) || message.reasoning || (message.tool_calls?.length ?? 0) > 0
|
|
1627
1849
|
);
|
|
1628
|
-
|
|
1629
|
-
|
|
1850
|
+
const latestReasoningIndex = isStreaming ? findLatestReasoningMessageIndex(messages) : -1;
|
|
1851
|
+
return /* @__PURE__ */ jsxs8("div", { className: "blade-chat-assistant-turn flex flex-col gap-3", children: [
|
|
1852
|
+
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" }),
|
|
1630
1853
|
messages.map((message, index) => {
|
|
1631
1854
|
const isLast = index === messages.length - 1;
|
|
1632
1855
|
const streamingThis = isStreaming && isLast;
|
|
1633
1856
|
const text = getMessageText(message);
|
|
1634
1857
|
const toolCalls = message.tool_calls ?? [];
|
|
1635
|
-
|
|
1858
|
+
const showReasoning = !!message.reasoning && (!isStreaming || index === latestReasoningIndex);
|
|
1859
|
+
return /* @__PURE__ */ jsxs8(
|
|
1636
1860
|
"div",
|
|
1637
1861
|
{
|
|
1638
1862
|
className: "flex flex-col gap-3",
|
|
1639
1863
|
children: [
|
|
1640
|
-
message.reasoning && /* @__PURE__ */
|
|
1641
|
-
text && /* @__PURE__ */
|
|
1864
|
+
showReasoning && message.reasoning && /* @__PURE__ */ jsx10(ThinkingBlock, { reasoning: message.reasoning, isStreaming: streamingThis && !text }),
|
|
1865
|
+
text && /* @__PURE__ */ jsx10("div", { className: "blade-chat-assistant-text text-[15px] leading-8 text-[hsl(var(--foreground))]", children: /* @__PURE__ */ jsx10(
|
|
1642
1866
|
MarkdownContent,
|
|
1643
1867
|
{
|
|
1644
1868
|
mode: streamingThis ? "streaming" : "static",
|
|
1645
1869
|
className: "blade-chat-prose",
|
|
1870
|
+
sessionId,
|
|
1646
1871
|
children: text
|
|
1647
1872
|
}
|
|
1648
1873
|
) }),
|
|
1649
|
-
toolCalls.length > 0 && /* @__PURE__ */
|
|
1650
|
-
(toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */
|
|
1874
|
+
toolCalls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "flex flex-col gap-2", children: toolCalls.map(
|
|
1875
|
+
(toolCall) => formatToolName(toolCall.name) === "Agent" ? /* @__PURE__ */ jsx10(AgentLoopBlock, { toolCall }, toolCall.id) : /* @__PURE__ */ jsx10(
|
|
1651
1876
|
ToolCallBlock,
|
|
1652
1877
|
{
|
|
1653
1878
|
toolCall,
|
|
@@ -1665,13 +1890,13 @@ function AssistantTurnBlock({
|
|
|
1665
1890
|
message.entry_id ?? `${message.timestamp ?? "assistant"}-${index}`
|
|
1666
1891
|
);
|
|
1667
1892
|
}),
|
|
1668
|
-
isStreaming && !hasAnyContent && /* @__PURE__ */
|
|
1893
|
+
isStreaming && !hasAnyContent && /* @__PURE__ */ jsx10(Shimmer, { className: "ml-4", children: "\u6B63\u5728\u751F\u6210..." })
|
|
1669
1894
|
] });
|
|
1670
1895
|
}
|
|
1671
1896
|
|
|
1672
1897
|
// src/components/RenderErrorBoundary.tsx
|
|
1673
1898
|
import { Component } from "react";
|
|
1674
|
-
import { jsx as
|
|
1899
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1675
1900
|
function getFirstComponentName(componentStack) {
|
|
1676
1901
|
const match = componentStack.match(/\n\s+at\s+([^\s(]+)/);
|
|
1677
1902
|
return match?.[1] ?? null;
|
|
@@ -1704,18 +1929,18 @@ var RenderErrorBoundary = class extends Component {
|
|
|
1704
1929
|
return children;
|
|
1705
1930
|
}
|
|
1706
1931
|
const componentName = getFirstComponentName(componentStack);
|
|
1707
|
-
return /* @__PURE__ */
|
|
1708
|
-
/* @__PURE__ */
|
|
1709
|
-
/* @__PURE__ */
|
|
1710
|
-
/* @__PURE__ */
|
|
1932
|
+
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: [
|
|
1933
|
+
/* @__PURE__ */ jsx11(TriangleAlert, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-300" }),
|
|
1934
|
+
/* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
|
|
1935
|
+
/* @__PURE__ */ jsxs9("div", { className: "font-medium", children: [
|
|
1711
1936
|
label,
|
|
1712
1937
|
"\u6E32\u67D3\u5931\u8D25"
|
|
1713
1938
|
] }),
|
|
1714
|
-
/* @__PURE__ */
|
|
1939
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-1 break-words text-xs leading-5 text-amber-100/75", children: [
|
|
1715
1940
|
componentName ? `\u7EC4\u4EF6\uFF1A${componentName}\u3002` : null,
|
|
1716
1941
|
error.message || "\u53D1\u751F\u4E86\u672A\u9884\u671F\u7684\u6E32\u67D3\u9519\u8BEF\u3002"
|
|
1717
1942
|
] }),
|
|
1718
|
-
details ? /* @__PURE__ */
|
|
1943
|
+
details ? /* @__PURE__ */ jsx11("div", { className: "mt-1 truncate text-xs text-amber-100/55", children: details }) : null
|
|
1719
1944
|
] })
|
|
1720
1945
|
] }) });
|
|
1721
1946
|
}
|
|
@@ -1723,7 +1948,7 @@ var RenderErrorBoundary = class extends Component {
|
|
|
1723
1948
|
|
|
1724
1949
|
// src/components/UserMessageBubble.tsx
|
|
1725
1950
|
import { getFileParts, getImageParts, getTextContent as getTextContent2 } from "@blade-hq/agent-client";
|
|
1726
|
-
import { jsx as
|
|
1951
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1727
1952
|
function isUserMessage(message) {
|
|
1728
1953
|
return message.role === "user";
|
|
1729
1954
|
}
|
|
@@ -1735,8 +1960,8 @@ function UserMessageBubble({ message, className }) {
|
|
|
1735
1960
|
const text = getTextContent2(message.content).trim();
|
|
1736
1961
|
const fileParts = getFileParts(message.content);
|
|
1737
1962
|
const imageParts = getImageParts(message.content);
|
|
1738
|
-
return /* @__PURE__ */
|
|
1739
|
-
imageParts.length > 0 && /* @__PURE__ */
|
|
1963
|
+
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: [
|
|
1964
|
+
imageParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "grid gap-2", children: imageParts.map((part) => /* @__PURE__ */ jsx12(
|
|
1740
1965
|
"img",
|
|
1741
1966
|
{
|
|
1742
1967
|
src: part.image_url.url,
|
|
@@ -1745,21 +1970,21 @@ function UserMessageBubble({ message, className }) {
|
|
|
1745
1970
|
},
|
|
1746
1971
|
part.image_url.url
|
|
1747
1972
|
)) }),
|
|
1748
|
-
fileParts.length > 0 && /* @__PURE__ */
|
|
1973
|
+
fileParts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "flex flex-col items-end gap-1.5", children: fileParts.map((part) => /* @__PURE__ */ jsxs10(
|
|
1749
1974
|
"div",
|
|
1750
1975
|
{
|
|
1751
1976
|
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))]",
|
|
1752
1977
|
children: [
|
|
1753
|
-
/* @__PURE__ */
|
|
1754
|
-
/* @__PURE__ */
|
|
1978
|
+
/* @__PURE__ */ jsx12(FileText, { size: 12, className: "shrink-0" }),
|
|
1979
|
+
/* @__PURE__ */ jsx12("span", { className: "max-w-56 truncate", title: part.name, children: part.name })
|
|
1755
1980
|
]
|
|
1756
1981
|
},
|
|
1757
1982
|
`${part.name}-${part.data.length}`
|
|
1758
1983
|
)) }),
|
|
1759
|
-
text && /* @__PURE__ */
|
|
1760
|
-
text && isSending(message) && /* @__PURE__ */
|
|
1761
|
-
/* @__PURE__ */
|
|
1762
|
-
/* @__PURE__ */
|
|
1984
|
+
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 }) }),
|
|
1985
|
+
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: [
|
|
1986
|
+
/* @__PURE__ */ jsx12(LoaderCircle, { size: 11, className: "animate-spin", "aria-hidden": "true" }),
|
|
1987
|
+
/* @__PURE__ */ jsx12("span", { children: "\u53D1\u9001\u4E2D" })
|
|
1763
1988
|
] })
|
|
1764
1989
|
] }) });
|
|
1765
1990
|
}
|
|
@@ -1768,11 +1993,11 @@ function ErrorMessageBlock({
|
|
|
1768
1993
|
className
|
|
1769
1994
|
}) {
|
|
1770
1995
|
const text = getTextContent2(message.content);
|
|
1771
|
-
return /* @__PURE__ */
|
|
1996
|
+
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(--destructive))] px-4 py-1 text-sm leading-7 text-[hsl(var(--destructive))]", children: text }) });
|
|
1772
1997
|
}
|
|
1773
1998
|
|
|
1774
1999
|
// src/components/MessageList.tsx
|
|
1775
|
-
import { jsx as
|
|
2000
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1776
2001
|
function parseModeChange(message) {
|
|
1777
2002
|
if (message.kind !== "mode_change" || typeof message.content !== "string") {
|
|
1778
2003
|
return null;
|
|
@@ -1812,7 +2037,8 @@ function MessageList({
|
|
|
1812
2037
|
onAnswer,
|
|
1813
2038
|
toolCallRenderer,
|
|
1814
2039
|
emptyState,
|
|
1815
|
-
className
|
|
2040
|
+
className,
|
|
2041
|
+
sessionId
|
|
1816
2042
|
}) {
|
|
1817
2043
|
const renderBlocks = useMemo6(() => {
|
|
1818
2044
|
const visible = messages.filter((message) => {
|
|
@@ -1887,24 +2113,24 @@ function MessageList({
|
|
|
1887
2113
|
}
|
|
1888
2114
|
return blocks;
|
|
1889
2115
|
}, [messages, isStreaming]);
|
|
1890
|
-
return /* @__PURE__ */
|
|
1891
|
-
/* @__PURE__ */
|
|
1892
|
-
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */
|
|
1893
|
-
/* @__PURE__ */
|
|
1894
|
-
/* @__PURE__ */
|
|
1895
|
-
/* @__PURE__ */
|
|
2116
|
+
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: [
|
|
2117
|
+
/* @__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: [
|
|
2118
|
+
renderBlocks.length === 0 ? emptyState ?? /* @__PURE__ */ jsxs11("div", { className: "blade-chat-empty", children: [
|
|
2119
|
+
/* @__PURE__ */ jsx13(MessageSquare, { size: 40, strokeWidth: 1.5 }),
|
|
2120
|
+
/* @__PURE__ */ jsx13("span", { className: "text-base font-medium", children: "\u5F00\u59CB\u5BF9\u8BDD" }),
|
|
2121
|
+
/* @__PURE__ */ jsx13("span", { className: "text-sm opacity-60", children: "\u5728\u4E0B\u65B9\u8F93\u5165\u6D88\u606F\u5F00\u59CB\u804A\u5929" })
|
|
1896
2122
|
] }) : renderBlocks.map((block) => {
|
|
1897
2123
|
if (block.type === "message") {
|
|
1898
|
-
return /* @__PURE__ */
|
|
2124
|
+
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);
|
|
1899
2125
|
}
|
|
1900
2126
|
if (block.type === "assistant_turn") {
|
|
1901
|
-
return /* @__PURE__ */
|
|
2127
|
+
return /* @__PURE__ */ jsx13("div", { "data-entry-id": block.messages[0]?.entry_id, children: /* @__PURE__ */ jsx13(
|
|
1902
2128
|
RenderErrorBoundary,
|
|
1903
2129
|
{
|
|
1904
2130
|
label: "\u52A9\u624B\u6D88\u606F",
|
|
1905
2131
|
details: block.key,
|
|
1906
2132
|
resetKey: getMessageResetSignature(block.messages),
|
|
1907
|
-
children: /* @__PURE__ */
|
|
2133
|
+
children: /* @__PURE__ */ jsx13(
|
|
1908
2134
|
AssistantTurnBlock,
|
|
1909
2135
|
{
|
|
1910
2136
|
messages: block.messages,
|
|
@@ -1912,31 +2138,32 @@ function MessageList({
|
|
|
1912
2138
|
askAnswers,
|
|
1913
2139
|
onAnswer,
|
|
1914
2140
|
sessionStatus,
|
|
1915
|
-
toolCallRenderer
|
|
2141
|
+
toolCallRenderer,
|
|
2142
|
+
sessionId
|
|
1916
2143
|
}
|
|
1917
2144
|
)
|
|
1918
2145
|
}
|
|
1919
2146
|
) }, block.key);
|
|
1920
2147
|
}
|
|
1921
2148
|
if (block.type === "compaction") {
|
|
1922
|
-
return /* @__PURE__ */
|
|
2149
|
+
return /* @__PURE__ */ jsxs11(
|
|
1923
2150
|
"div",
|
|
1924
2151
|
{
|
|
1925
2152
|
className: "flex items-center gap-2 text-xs text-[hsl(var(--muted-foreground))]",
|
|
1926
2153
|
children: [
|
|
1927
|
-
/* @__PURE__ */
|
|
1928
|
-
/* @__PURE__ */
|
|
2154
|
+
/* @__PURE__ */ jsx13(Layers, { size: 12 }),
|
|
2155
|
+
/* @__PURE__ */ jsx13("span", { children: "\u4E0A\u4E0B\u6587\u5DF2\u538B\u7F29" })
|
|
1929
2156
|
]
|
|
1930
2157
|
},
|
|
1931
2158
|
block.key
|
|
1932
2159
|
);
|
|
1933
2160
|
}
|
|
1934
|
-
return /* @__PURE__ */
|
|
2161
|
+
return /* @__PURE__ */ jsx13(PlanningDivider, { kind: block.kind }, block.key);
|
|
1935
2162
|
}),
|
|
1936
|
-
sessionStatus === "interrupted" && !isStreaming ? /* @__PURE__ */
|
|
2163
|
+
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
|
|
1937
2164
|
] }) }) }),
|
|
1938
|
-
/* @__PURE__ */
|
|
1939
|
-
/* @__PURE__ */
|
|
2165
|
+
/* @__PURE__ */ jsx13(AutoScrollOnUserSend, { userMessageCount: messages.filter((m) => isUserMessage(m)).length }),
|
|
2166
|
+
/* @__PURE__ */ jsx13(ScrollToBottomButton, {})
|
|
1940
2167
|
] }) });
|
|
1941
2168
|
}
|
|
1942
2169
|
function AutoScrollOnUserSend({ userMessageCount }) {
|
|
@@ -1953,38 +2180,39 @@ function AutoScrollOnUserSend({ userMessageCount }) {
|
|
|
1953
2180
|
function ScrollToBottomButton() {
|
|
1954
2181
|
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
1955
2182
|
if (isAtBottom) return null;
|
|
1956
|
-
return /* @__PURE__ */
|
|
2183
|
+
return /* @__PURE__ */ jsxs11(
|
|
1957
2184
|
"button",
|
|
1958
2185
|
{
|
|
1959
2186
|
type: "button",
|
|
1960
2187
|
onClick: () => scrollToBottom(),
|
|
1961
|
-
|
|
2188
|
+
"aria-label": "\u6EDA\u52A8\u5230\u5E95\u90E8",
|
|
2189
|
+
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))]",
|
|
1962
2190
|
children: [
|
|
1963
|
-
/* @__PURE__ */
|
|
1964
|
-
/* @__PURE__ */
|
|
2191
|
+
/* @__PURE__ */ jsx13(ChevronDown, { size: 14 }),
|
|
2192
|
+
/* @__PURE__ */ jsx13("span", { className: "blade-chat-scroll-bottom-label", children: "\u6EDA\u52A8\u5230\u5E95\u90E8" })
|
|
1965
2193
|
]
|
|
1966
2194
|
}
|
|
1967
2195
|
);
|
|
1968
2196
|
}
|
|
1969
2197
|
function PlanningDivider({ kind }) {
|
|
1970
|
-
return /* @__PURE__ */
|
|
1971
|
-
/* @__PURE__ */
|
|
1972
|
-
/* @__PURE__ */
|
|
1973
|
-
/* @__PURE__ */
|
|
1974
|
-
/* @__PURE__ */
|
|
2198
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3 py-1", children: [
|
|
2199
|
+
/* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" }),
|
|
2200
|
+
/* @__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: [
|
|
2201
|
+
/* @__PURE__ */ jsx13(Lightbulb, { size: 12 }),
|
|
2202
|
+
/* @__PURE__ */ jsx13("span", { children: kind === "enter" ? "\u8FDB\u5165\u89C4\u5212\u6A21\u5F0F" : "\u89C4\u5212\u5B8C\u6210" })
|
|
1975
2203
|
] }),
|
|
1976
|
-
/* @__PURE__ */
|
|
2204
|
+
/* @__PURE__ */ jsx13("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent via-amber-400/40 to-transparent" })
|
|
1977
2205
|
] });
|
|
1978
2206
|
}
|
|
1979
2207
|
|
|
1980
2208
|
// src/components/ChatView.tsx
|
|
1981
|
-
import { jsx as
|
|
2209
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1982
2210
|
function isUnauthorizedError(error) {
|
|
1983
2211
|
return error instanceof BladeApiError && error.status === 401;
|
|
1984
2212
|
}
|
|
1985
2213
|
function LoginCard({ client, onLoggedIn }) {
|
|
1986
|
-
const [loggingIn, setLoggingIn] =
|
|
1987
|
-
const [loginError, setLoginError] =
|
|
2214
|
+
const [loggingIn, setLoggingIn] = useState9(false);
|
|
2215
|
+
const [loginError, setLoginError] = useState9(null);
|
|
1988
2216
|
const handleLogin = async () => {
|
|
1989
2217
|
setLoggingIn(true);
|
|
1990
2218
|
setLoginError(null);
|
|
@@ -1997,11 +2225,11 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
1997
2225
|
setLoggingIn(false);
|
|
1998
2226
|
}
|
|
1999
2227
|
};
|
|
2000
|
-
return /* @__PURE__ */
|
|
2001
|
-
/* @__PURE__ */
|
|
2002
|
-
/* @__PURE__ */
|
|
2003
|
-
/* @__PURE__ */
|
|
2004
|
-
/* @__PURE__ */
|
|
2228
|
+
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: [
|
|
2229
|
+
/* @__PURE__ */ jsx14(LockKeyhole, { size: 28, className: "text-[hsl(var(--muted-foreground))]" }),
|
|
2230
|
+
/* @__PURE__ */ jsx14("div", { className: "text-base font-medium text-[hsl(var(--foreground))]", children: "\u9700\u8981\u767B\u5F55\u540E\u4F7F\u7528" }),
|
|
2231
|
+
/* @__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" }),
|
|
2232
|
+
/* @__PURE__ */ jsx14(
|
|
2005
2233
|
"button",
|
|
2006
2234
|
{
|
|
2007
2235
|
type: "button",
|
|
@@ -2011,15 +2239,15 @@ function LoginCard({ client, onLoggedIn }) {
|
|
|
2011
2239
|
children: loggingIn ? "\u767B\u5F55\u4E2D\u2026" : "\u767B\u5F55"
|
|
2012
2240
|
}
|
|
2013
2241
|
),
|
|
2014
|
-
loginError && /* @__PURE__ */
|
|
2242
|
+
loginError && /* @__PURE__ */ jsx14("div", { className: "text-xs text-[hsl(var(--destructive))]", children: loginError })
|
|
2015
2243
|
] }) });
|
|
2016
2244
|
}
|
|
2017
2245
|
function ChatView(props) {
|
|
2018
2246
|
const client = useBladeClient();
|
|
2019
|
-
const [attempt, setAttempt] =
|
|
2020
|
-
const [needLogin, setNeedLogin] =
|
|
2247
|
+
const [attempt, setAttempt] = useState9(0);
|
|
2248
|
+
const [needLogin, setNeedLogin] = useState9(() => !client.hasToken());
|
|
2021
2249
|
if (needLogin) {
|
|
2022
|
-
return /* @__PURE__ */
|
|
2250
|
+
return /* @__PURE__ */ jsx14("div", { className: cn("blade-chat flex min-h-0 flex-1 flex-col", props.classNames?.root), children: /* @__PURE__ */ jsx14(
|
|
2023
2251
|
LoginCard,
|
|
2024
2252
|
{
|
|
2025
2253
|
client,
|
|
@@ -2030,7 +2258,7 @@ function ChatView(props) {
|
|
|
2030
2258
|
}
|
|
2031
2259
|
) });
|
|
2032
2260
|
}
|
|
2033
|
-
return /* @__PURE__ */
|
|
2261
|
+
return /* @__PURE__ */ jsx14(ChatSessionView, { ...props, onUnauthorized: () => setNeedLogin(true) }, attempt);
|
|
2034
2262
|
}
|
|
2035
2263
|
function ChatSessionView({
|
|
2036
2264
|
sessionId,
|
|
@@ -2048,8 +2276,8 @@ function ChatSessionView({
|
|
|
2048
2276
|
createOptions,
|
|
2049
2277
|
onSessionCreated
|
|
2050
2278
|
});
|
|
2051
|
-
const [stopRequested, setStopRequested] =
|
|
2052
|
-
const [inputText, setInputText] =
|
|
2279
|
+
const [stopRequested, setStopRequested] = useState9(false);
|
|
2280
|
+
const [inputText, setInputText] = useState9("");
|
|
2053
2281
|
useEffect6(() => {
|
|
2054
2282
|
if (session) {
|
|
2055
2283
|
onSessionReady?.(session);
|
|
@@ -2091,13 +2319,13 @@ ${content}`);
|
|
|
2091
2319
|
const errorMessage = connectError ?? state?.errorMessage ?? null;
|
|
2092
2320
|
const handleSend = (text) => {
|
|
2093
2321
|
setStopRequested(false);
|
|
2094
|
-
|
|
2322
|
+
return session?.send(text, { mode: state?.mode ?? void 0 }) ?? Promise.resolve(false);
|
|
2095
2323
|
};
|
|
2096
2324
|
const handleStop = () => {
|
|
2097
2325
|
setStopRequested(true);
|
|
2098
2326
|
void session?.stop();
|
|
2099
2327
|
};
|
|
2100
|
-
return /* @__PURE__ */
|
|
2328
|
+
return /* @__PURE__ */ jsxs12(
|
|
2101
2329
|
"div",
|
|
2102
2330
|
{
|
|
2103
2331
|
className: cn(
|
|
@@ -2105,19 +2333,19 @@ ${content}`);
|
|
|
2105
2333
|
classNames?.root
|
|
2106
2334
|
),
|
|
2107
2335
|
children: [
|
|
2108
|
-
/* @__PURE__ */
|
|
2336
|
+
/* @__PURE__ */ jsx14(
|
|
2109
2337
|
ConnectionBanner,
|
|
2110
2338
|
{
|
|
2111
2339
|
connection: state?.connection ?? "connecting",
|
|
2112
2340
|
className: classNames?.banner
|
|
2113
2341
|
}
|
|
2114
2342
|
),
|
|
2115
|
-
errorMessage && /* @__PURE__ */
|
|
2116
|
-
/* @__PURE__ */
|
|
2117
|
-
/* @__PURE__ */
|
|
2343
|
+
errorMessage && /* @__PURE__ */ jsxs12("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: [
|
|
2344
|
+
/* @__PURE__ */ jsx14(CircleAlert, { size: 16, className: "mt-0.5 shrink-0" }),
|
|
2345
|
+
/* @__PURE__ */ jsx14("span", { children: errorMessage })
|
|
2118
2346
|
] }),
|
|
2119
2347
|
slots?.header,
|
|
2120
|
-
/* @__PURE__ */
|
|
2348
|
+
/* @__PURE__ */ jsx14(
|
|
2121
2349
|
MessageList,
|
|
2122
2350
|
{
|
|
2123
2351
|
messages: state?.messages ?? [],
|
|
@@ -2132,10 +2360,11 @@ ${content}`);
|
|
|
2132
2360
|
},
|
|
2133
2361
|
toolCallRenderer: renderers?.toolCall,
|
|
2134
2362
|
emptyState: slots?.emptyState,
|
|
2135
|
-
className: classNames?.messageList
|
|
2363
|
+
className: classNames?.messageList,
|
|
2364
|
+
sessionId: session?.sessionId
|
|
2136
2365
|
}
|
|
2137
2366
|
),
|
|
2138
|
-
/* @__PURE__ */
|
|
2367
|
+
/* @__PURE__ */ jsx14(
|
|
2139
2368
|
ChatInput,
|
|
2140
2369
|
{
|
|
2141
2370
|
value: inputText,
|
|
@@ -2169,6 +2398,7 @@ lucide-react/dist/esm/shared/src/utils.js:
|
|
|
2169
2398
|
lucide-react/dist/esm/defaultAttributes.js:
|
|
2170
2399
|
lucide-react/dist/esm/Icon.js:
|
|
2171
2400
|
lucide-react/dist/esm/createLucideIcon.js:
|
|
2401
|
+
lucide-react/dist/esm/icons/archive.js:
|
|
2172
2402
|
lucide-react/dist/esm/icons/arrow-up.js:
|
|
2173
2403
|
lucide-react/dist/esm/icons/bot.js:
|
|
2174
2404
|
lucide-react/dist/esm/icons/brain.js:
|
|
@@ -2177,13 +2407,20 @@ lucide-react/dist/esm/icons/chevron-down.js:
|
|
|
2177
2407
|
lucide-react/dist/esm/icons/chevron-right.js:
|
|
2178
2408
|
lucide-react/dist/esm/icons/circle-alert.js:
|
|
2179
2409
|
lucide-react/dist/esm/icons/copy.js:
|
|
2410
|
+
lucide-react/dist/esm/icons/download.js:
|
|
2411
|
+
lucide-react/dist/esm/icons/file-code-2.js:
|
|
2412
|
+
lucide-react/dist/esm/icons/file-spreadsheet.js:
|
|
2180
2413
|
lucide-react/dist/esm/icons/file-text.js:
|
|
2414
|
+
lucide-react/dist/esm/icons/file.js:
|
|
2415
|
+
lucide-react/dist/esm/icons/film.js:
|
|
2416
|
+
lucide-react/dist/esm/icons/image.js:
|
|
2181
2417
|
lucide-react/dist/esm/icons/layers.js:
|
|
2182
2418
|
lucide-react/dist/esm/icons/lightbulb.js:
|
|
2183
2419
|
lucide-react/dist/esm/icons/loader-circle.js:
|
|
2184
2420
|
lucide-react/dist/esm/icons/lock-keyhole.js:
|
|
2185
2421
|
lucide-react/dist/esm/icons/message-square-more.js:
|
|
2186
2422
|
lucide-react/dist/esm/icons/message-square.js:
|
|
2423
|
+
lucide-react/dist/esm/icons/music.js:
|
|
2187
2424
|
lucide-react/dist/esm/icons/square.js:
|
|
2188
2425
|
lucide-react/dist/esm/icons/triangle-alert.js:
|
|
2189
2426
|
lucide-react/dist/esm/icons/x.js:
|