@zero-library/chat-copilot 1.0.0

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.
@@ -0,0 +1,4868 @@
1
+ 'use strict';
2
+
3
+ var icons = require('@ant-design/icons');
4
+ var xV2 = require('@ant-design/x-v2');
5
+ var common = require('@zero-library/common');
6
+ var antd = require('antd');
7
+ var React9 = require('react');
8
+ var valtio = require('valtio');
9
+ var dayjs = require('dayjs');
10
+ var Latex = require('@ant-design/x-markdown/plugins/Latex');
11
+ var jsxRuntime = require('react/jsx-runtime');
12
+ var XMarkdown = require('@ant-design/x-markdown');
13
+ require('@ant-design/x-markdown/themes/light.css');
14
+ var classNames7 = require('classnames');
15
+ var xCard = require('@ant-design/x-card');
16
+ var InfiniteScroll = require('react-infinite-scroll-component');
17
+
18
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
19
+
20
+ var React9__default = /*#__PURE__*/_interopDefault(React9);
21
+ var dayjs__default = /*#__PURE__*/_interopDefault(dayjs);
22
+ var Latex__default = /*#__PURE__*/_interopDefault(Latex);
23
+ var XMarkdown__default = /*#__PURE__*/_interopDefault(XMarkdown);
24
+ var classNames7__default = /*#__PURE__*/_interopDefault(classNames7);
25
+ var InfiniteScroll__default = /*#__PURE__*/_interopDefault(InfiniteScroll);
26
+
27
+ // src/components/ChatSender.tsx
28
+ function getFileExtension(fileName = "") {
29
+ const ext = fileName.split(".").pop();
30
+ return (ext || "").toLowerCase();
31
+ }
32
+ function formatFileSize(size) {
33
+ if (!size) return "0 B";
34
+ if (size < 1024) return `${size} B`;
35
+ if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;
36
+ if (size < 1024 * 1024 * 1024) return `${(size / 1024 / 1024).toFixed(1)} MB`;
37
+ return `${(size / 1024 / 1024 / 1024).toFixed(1)} GB`;
38
+ }
39
+ var getFileIcon = (extension, fontSize = 24) => {
40
+ const baseStyle = { fontSize };
41
+ const createIcon = (Icon, color) => React9__default.default.createElement(Icon, { style: { ...baseStyle, color } });
42
+ if (["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg"].includes(extension)) {
43
+ return createIcon(icons.FileImageOutlined, "#22c55e");
44
+ }
45
+ if (["pdf"].includes(extension)) {
46
+ return createIcon(icons.FilePdfOutlined, "#ef4444");
47
+ }
48
+ if (["doc", "docx"].includes(extension)) {
49
+ return createIcon(icons.FileWordOutlined, "#2563eb");
50
+ }
51
+ if (["xls", "xlsx", "csv"].includes(extension)) {
52
+ return createIcon(icons.FileExcelOutlined, "#16a34a");
53
+ }
54
+ if (["ppt", "pptx"].includes(extension)) {
55
+ return createIcon(icons.FilePptOutlined, "#f59e0b");
56
+ }
57
+ if (["zip", "rar", "7z", "tar", "gz"].includes(extension)) {
58
+ return createIcon(icons.FileZipOutlined, "#8b5cf6");
59
+ }
60
+ if (["txt", "md", "log", "json", "yaml", "yml", "xml", "ini", "conf"].includes(extension)) {
61
+ return createIcon(icons.FileTextOutlined, "#64748b");
62
+ }
63
+ return createIcon(icons.FileUnknownOutlined, "#94a3b8");
64
+ };
65
+ var classifyTime = (timestamp) => {
66
+ const now = dayjs__default.default();
67
+ const target = dayjs__default.default(timestamp);
68
+ if (target.isSame(now, "day")) {
69
+ return "\u4ECA\u5929";
70
+ }
71
+ const diffInDays = now.diff(target, "day");
72
+ if (diffInDays < 7) {
73
+ return "\u6700\u8FD1 7 \u5929";
74
+ } else if (diffInDays < 30) {
75
+ return "\u6700\u8FD1 30 \u5929";
76
+ } else if (diffInDays < 180) {
77
+ return "\u6700\u8FD1\u534A\u5E74";
78
+ } else {
79
+ return "\u66F4\u65E9";
80
+ }
81
+ };
82
+ var variablesToObject = (variables) => {
83
+ if (!common.isArray(variables)) return {};
84
+ const jsonTypes = ["OBJECT", "ARRAY", "ARRAY_STRING", "ARRAY_NUMBER", "ARRAY_DECIMAL", "ARRAY_BOOLEAN", "ARRAY_OBJECT"];
85
+ return variables.reduce(
86
+ (acc, cur) => {
87
+ if (cur.type === "BOOLEAN") {
88
+ if (common.isDef(cur.value) && !common.isNull(cur.value)) {
89
+ acc[cur.name] = cur.value;
90
+ }
91
+ } else if (jsonTypes.includes(cur.type)) {
92
+ if (common.isDef(cur.value) && !common.isNull(cur.value)) {
93
+ if (typeof cur.value === "string") {
94
+ if (cur.value === "") {
95
+ acc[cur.name] = cur.type === "OBJECT" ? {} : [];
96
+ } else {
97
+ try {
98
+ acc[cur.name] = JSON.parse(cur.value);
99
+ } catch (e) {
100
+ acc[cur.name] = cur.type === "OBJECT" ? {} : [];
101
+ }
102
+ }
103
+ } else {
104
+ acc[cur.name] = cur.value;
105
+ }
106
+ }
107
+ } else {
108
+ if (common.isDef(cur.value) && !common.isNull(cur.value) && cur.value !== "") {
109
+ acc[cur.name] = cur.value;
110
+ }
111
+ }
112
+ return acc;
113
+ },
114
+ {}
115
+ );
116
+ };
117
+ var singleTildeExtension = {
118
+ name: "singleTilde",
119
+ level: "inline",
120
+ start(src) {
121
+ return src.match(/(?<!~)~(?!~)/)?.index;
122
+ },
123
+ tokenizer(src) {
124
+ const match = /^(?<!~)~(?!~)/.exec(src);
125
+ if (match) {
126
+ return {
127
+ type: "text",
128
+ raw: match[0],
129
+ text: match[0]
130
+ };
131
+ }
132
+ return void 0;
133
+ }
134
+ };
135
+ var getMarkdownConfig = (options) => {
136
+ const latexExtensions = Latex__default.default();
137
+ const extensions = Array.isArray(latexExtensions) ? [...latexExtensions, singleTildeExtension] : [latexExtensions, singleTildeExtension];
138
+ return {
139
+ extensions,
140
+ breaks: options?.breaks ?? false
141
+ };
142
+ };
143
+ var getChatSocketUrl = (baseURL, params) => {
144
+ return common.buildUrlParams(params, common.getWebSocketUrl(`${baseURL}/ws`), "comma");
145
+ };
146
+ var ChatContext = React9.createContext(null);
147
+ function ChatProvider({ store, children }) {
148
+ return React9__default.default.createElement(ChatContext.Provider, { value: store }, children);
149
+ }
150
+ function useChatStore() {
151
+ const store = React9.useContext(ChatContext);
152
+ if (!store) {
153
+ throw new Error("useChatStore must be used within ChatProvider");
154
+ }
155
+ return store;
156
+ }
157
+
158
+ // src/components/styles.module.less
159
+ var styles_module_default = {
160
+ chatAttachments: "styles_module_chatAttachments",
161
+ chatSender: "styles_module_chatSender"};
162
+ var Attachments_default = React9.forwardRef(({ fileUpload, fileUploadConfig, fileList = [], onChange, extraParams }, ref) => {
163
+ const { message: message3 } = antd.App.useApp();
164
+ const chatStore = useChatStore();
165
+ const agentState = valtio.useSnapshot(chatStore.agent);
166
+ const fileListRef = React9.useRef([]);
167
+ const [attachedFiles, setAttachedFiles, getAttachedFiles] = common.useRefState([]);
168
+ React9.useEffect(() => {
169
+ if (JSON.stringify(fileList) !== JSON.stringify(fileListRef.current)) {
170
+ fileListRef.current = fileList;
171
+ const mapped = fileList.map((file) => ({
172
+ ...file,
173
+ uid: file.id,
174
+ url: file.url || file.id,
175
+ status: "done"
176
+ }));
177
+ setAttachedFiles(mapped);
178
+ }
179
+ }, [fileList]);
180
+ React9.useEffect(() => {
181
+ const files = attachedFiles.filter((file) => file.status === "done").map((file) => {
182
+ const f = { ...file };
183
+ delete f.status;
184
+ delete f.size;
185
+ return f;
186
+ });
187
+ fileListRef.current = files;
188
+ onChange(files);
189
+ }, [attachedFiles]);
190
+ const onErrorTip = common.useDebounce((errorMsg) => {
191
+ message3.error(errorMsg);
192
+ }, 300);
193
+ const findConfig = (file) => {
194
+ return fileUploadConfig?.allowedTypes?.find((type) => type === getFileExtension(file.name)) || "";
195
+ };
196
+ const onBeforeUpload = (files) => {
197
+ for (const file of files) {
198
+ const cfg = findConfig(file);
199
+ if (!cfg) {
200
+ onErrorTip(`\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B\uFF1A${file.name} (${file.type})`);
201
+ return Promise.reject(false);
202
+ }
203
+ if (common.isNumber(fileUploadConfig?.maxCount)) {
204
+ const currentCount = attachedFiles.length;
205
+ if (currentCount + 1 > fileUploadConfig?.maxCount) {
206
+ onErrorTip(`\u3010${file.name}\u3011\u6240\u5C5E\u7C7B\u578B\u6700\u591A\u53EA\u80FD\u4E0A\u4F20 ${fileUploadConfig?.maxCount} \u4E2A\u6587\u4EF6`);
207
+ return Promise.reject(false);
208
+ }
209
+ }
210
+ }
211
+ };
212
+ const onCustomRequest = async ({ file }) => {
213
+ const cfg = findConfig(file);
214
+ if (!cfg) {
215
+ onErrorTip(`\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B\uFF1A${file.name}`);
216
+ return;
217
+ }
218
+ if (fileUploadConfig?.maxSize && file.size > fileUploadConfig?.maxSize * 1024 * 1024) {
219
+ onErrorTip(`\u6587\u4EF6\u5927\u5C0F\u4E0D\u80FD\u8D85\u8FC7 ${fileUploadConfig?.maxSize} MB`);
220
+ return;
221
+ }
222
+ const abortController = new AbortController();
223
+ setAttachedFiles([
224
+ ...getAttachedFiles(),
225
+ {
226
+ uid: file.uid,
227
+ status: "uploading",
228
+ percent: 70,
229
+ size: file.size,
230
+ type: file.type,
231
+ name: file.name,
232
+ url: URL.createObjectURL(file),
233
+ abortController
234
+ }
235
+ ]);
236
+ try {
237
+ const formData = new FormData();
238
+ formData.append("file", file);
239
+ if (common.isObject(extraParams)) {
240
+ Object.keys(extraParams).forEach((key) => {
241
+ if (common.isNullOrUnDef(extraParams[key])) return;
242
+ formData.append(key, extraParams[key]);
243
+ });
244
+ }
245
+ const { data } = await fileUpload(formData, abortController.signal);
246
+ const uploadedFile = data[0];
247
+ let previewUrl = uploadedFile.id;
248
+ if (uploadedFile.conversationId && uploadedFile.path) {
249
+ previewUrl = chatStore.config.services.request.getPreviewUrl(agentState.agentInfo.id, uploadedFile.conversationId, uploadedFile.path);
250
+ }
251
+ setAttachedFiles(
252
+ getAttachedFiles().map((f) => {
253
+ if (f.uid === file.uid) {
254
+ return { ...uploadedFile, uid: file.uid, url: previewUrl, status: "done", size: f.size };
255
+ } else {
256
+ return f;
257
+ }
258
+ })
259
+ );
260
+ } catch (error) {
261
+ if (error?.name === "CanceledError" || error?.message === "canceled") {
262
+ return;
263
+ }
264
+ setAttachedFiles(
265
+ getAttachedFiles().map((f) => {
266
+ if (f.uid === file.uid) {
267
+ return { ...f, status: "error", description: "\u4E0A\u4F20\u5931\u8D25" };
268
+ } else {
269
+ return f;
270
+ }
271
+ })
272
+ );
273
+ }
274
+ };
275
+ const onRemove = (file) => {
276
+ const currentFile = getAttachedFiles().find((f) => f.uid === file.uid);
277
+ if (currentFile?.abortController) {
278
+ currentFile.abortController.abort();
279
+ }
280
+ setAttachedFiles(attachedFiles.filter((f) => f.uid !== file.uid));
281
+ chatStore.config.params.convMeta?.libraryId;
282
+ file.path;
283
+ };
284
+ React9.useImperativeHandle(
285
+ ref,
286
+ () => ({
287
+ validateFile: () => {
288
+ const files = getAttachedFiles();
289
+ const uploadingFiles = files.filter((file) => file.status === "uploading");
290
+ if (uploadingFiles.length > 0) {
291
+ onErrorTip("\u8BF7\u7B49\u5F85\u6240\u6709\u6587\u4EF6\u4E0A\u4F20\u5B8C\u6210");
292
+ return false;
293
+ }
294
+ const errorFiles = files.filter((file) => file.status === "error");
295
+ if (errorFiles.length > 0) {
296
+ onErrorTip("\u8BF7\u68C0\u67E5\u4E0A\u4F20\u5931\u8D25\u7684\u6587\u4EF6");
297
+ return false;
298
+ }
299
+ return true;
300
+ }
301
+ }),
302
+ []
303
+ );
304
+ const acceptStr = React9.useMemo(() => {
305
+ const allTypes = fileUploadConfig?.allowedTypes.map((type) => `.${type}`) || [];
306
+ return allTypes.length ? allTypes.join(",") : void 0;
307
+ }, [fileUploadConfig]);
308
+ return /* @__PURE__ */ jsxRuntime.jsx(
309
+ xV2.Attachments,
310
+ {
311
+ className: styles_module_default.chatAttachments,
312
+ accept: acceptStr,
313
+ multiple: true,
314
+ customRequest: onCustomRequest,
315
+ beforeUpload: (file, files) => onBeforeUpload(files),
316
+ items: attachedFiles,
317
+ onRemove,
318
+ overflow: "wrap",
319
+ placeholder: (type) => type === "drop" ? { title: "\u5C06\u6587\u4EF6\u653E\u5230\u8FD9\u91CC" } : {
320
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CloudUploadOutlined, {}),
321
+ title: "\u63D0\u4EA4\u6587\u4EF6",
322
+ description: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
323
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: "\u5355\u51FB\u6216\u62D6\u52A8\u6587\u4EF6\u5230\u6B64\u533A\u57DF\u8FDB\u884C\u4E0A\u4F20; " }),
324
+ fileUploadConfig?.allowedTypes && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
325
+ "\u652F\u6301\u6269\u5C55\u540D\uFF1A",
326
+ fileUploadConfig?.allowedTypes.join(","),
327
+ "; "
328
+ ] })
329
+ ] })
330
+ }
331
+ }
332
+ );
333
+ });
334
+ var ChatSender_default = React9.forwardRef(
335
+ ({
336
+ placeholder,
337
+ content,
338
+ fileList = [],
339
+ headerOpen = false,
340
+ loading = false,
341
+ onContentChange,
342
+ onFileListChange,
343
+ onHeaderOpenChange,
344
+ onSend,
345
+ onCancel,
346
+ onFocus,
347
+ extraHeader,
348
+ extraFooter,
349
+ extraFooterBelow,
350
+ sendBtnProps,
351
+ fileUpload
352
+ }, ref) => {
353
+ const senderRef = React9.useRef(null);
354
+ const { inputValue, setInputValue } = common.useSyncInput(content || "", onContentChange);
355
+ const attachmentsNode = fileUpload?.config?.enabled && /* @__PURE__ */ jsxRuntime.jsx(antd.Badge, { dot: !!fileList?.length && !headerOpen, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { type: "text", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.PaperClipOutlined, {}), onClick: () => onHeaderOpenChange(!headerOpen) }) });
356
+ const attachmentsRef = React9.useRef();
357
+ const senderHeader = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
358
+ /* @__PURE__ */ jsxRuntime.jsx(xV2.Sender.Header, { title: "\u9009\u62E9\u6587\u4EF6", open: headerOpen, onOpenChange: onHeaderOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(
359
+ Attachments_default,
360
+ {
361
+ ref: attachmentsRef,
362
+ fileList,
363
+ fileUpload: fileUpload.request,
364
+ onChange: onFileListChange,
365
+ fileUploadConfig: fileUpload.config,
366
+ extraParams: fileUpload.params
367
+ }
368
+ ) }),
369
+ extraHeader
370
+ ] });
371
+ const onSubmit = () => {
372
+ if (!attachmentsRef.current?.validateFile || attachmentsRef.current.validateFile()) {
373
+ onSend();
374
+ }
375
+ };
376
+ const isFocusedRef = React9.useRef(false);
377
+ React9.useEffect(() => {
378
+ if (!content) return;
379
+ if (!isFocusedRef.current) {
380
+ senderRef.current?.focus({ cursor: "end" });
381
+ }
382
+ }, [content]);
383
+ React9.useImperativeHandle(
384
+ ref,
385
+ () => ({
386
+ focus: (options) => {
387
+ senderRef.current?.focus(options);
388
+ }
389
+ }),
390
+ []
391
+ );
392
+ return /* @__PURE__ */ jsxRuntime.jsx(xV2.Suggestion, { items: [], onSelect: (itemVal) => setInputValue(`[${itemVal}]:`), children: ({}) => /* @__PURE__ */ jsxRuntime.jsx(
393
+ xV2.Sender,
394
+ {
395
+ className: styles_module_default.chatSender,
396
+ ref: senderRef,
397
+ value: inputValue,
398
+ header: senderHeader,
399
+ onSubmit,
400
+ onChange: setInputValue,
401
+ onFocus: () => {
402
+ isFocusedRef.current = true;
403
+ onFocus?.();
404
+ },
405
+ onBlur: () => {
406
+ isFocusedRef.current = false;
407
+ },
408
+ autoSize: { minRows: 2, maxRows: 6 },
409
+ suffix: false,
410
+ onCancel,
411
+ footer: (_, { components }) => {
412
+ const { SendButton, LoadingButton } = components;
413
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { vertical: true, children: [
414
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { justify: "space-between", align: "center", gap: 12, children: [
415
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { className: "flex-1", gap: 6, align: "center", children: [
416
+ attachmentsNode,
417
+ /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: extraFooter })
418
+ ] }),
419
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Flex, { align: "center", style: { marginLeft: "auto" }, gap: 6, children: loading ? /* @__PURE__ */ jsxRuntime.jsx(LoadingButton, { disabled: false }) : /* @__PURE__ */ jsxRuntime.jsx(SendButton, { ...sendBtnProps }) })
420
+ ] }),
421
+ /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: extraFooterBelow })
422
+ ] });
423
+ },
424
+ placeholder: placeholder || "\u6709\u4EC0\u4E48\u6211\u80FD\u5E2E\u60A8\u7684\u5417\uFF1F"
425
+ }
426
+ ) });
427
+ }
428
+ );
429
+ var XCard = xCard.XCard;
430
+ var { Text: AText } = antd.Typography;
431
+ function getArtifactFallbackTitle(type) {
432
+ const normalizedType = String(type || "").toLowerCase();
433
+ if (normalizedType === "report") return "\u672A\u547D\u540D\u62A5\u544A";
434
+ if (normalizedType === "chart") return "\u672A\u547D\u540D\u56FE\u8868";
435
+ if (normalizedType === "table") return "\u672A\u547D\u540D\u8868\u683C";
436
+ return "\u672A\u547D\u540D\u5185\u5BB9";
437
+ }
438
+ var ArtifactCard = ({ type, title }) => /* @__PURE__ */ jsxRuntime.jsx(antd.Card, { size: "small", style: { borderRadius: 12 }, children: /* @__PURE__ */ jsxRuntime.jsxs(antd.Space, { align: "center", wrap: true, children: [
439
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Tag, { color: "blue", children: type }),
440
+ /* @__PURE__ */ jsxRuntime.jsx(AText, { strong: true, children: title || getArtifactFallbackTitle(type) })
441
+ ] }) });
442
+ function renderMiniChart(spec, opts) {
443
+ const t = String(spec?.type ?? "").toLowerCase();
444
+ if (t !== "line" && t !== "bar" && t !== "pie" && t !== "scatter") return null;
445
+ const xs = Array.isArray(spec?.x) ? spec.x : null;
446
+ const ys = Array.isArray(spec?.y) ? spec.y : null;
447
+ if (!xs || !ys || xs.length === 0 || ys.length === 0) return null;
448
+ const n = Math.min(xs.length, ys.length);
449
+ const pairs = Array.from({ length: n }, (_, i) => ({
450
+ label: String(xs[i]),
451
+ x: xs[i],
452
+ y: typeof ys[i] === "number" ? ys[i] : Number(ys[i])
453
+ })).filter((p) => Number.isFinite(p.y));
454
+ if (pairs.length === 0) return null;
455
+ if (t === "line" && pairs.length < 2) return null;
456
+ const height = 180;
457
+ const left = 44;
458
+ const right = 18;
459
+ const top = 14;
460
+ const bottom = 30;
461
+ const baseWidth = Math.max(520, Math.floor(opts?.containerWidth ?? 0));
462
+ const minBarPx = 22;
463
+ const minPointPx = 32;
464
+ const neededWidth = left + right + Math.max(pairs.length * (t === "bar" ? minBarPx : minPointPx), 320);
465
+ const width = Math.max(baseWidth, neededWidth);
466
+ const colors = [
467
+ "#1677ff",
468
+ "#52c41a",
469
+ "#faad14",
470
+ "#f5222d",
471
+ "#722ed1",
472
+ "#13c2c2",
473
+ "#eb2f96",
474
+ "#fa541c",
475
+ "#a0d911",
476
+ "#2f54eb",
477
+ "#9254de",
478
+ "#08979c",
479
+ "#d46b08",
480
+ "#7cb305",
481
+ "#c41d7f",
482
+ "#ad2102"
483
+ ];
484
+ const formatNumber = (v) => {
485
+ if (Number.isInteger(v)) return String(v);
486
+ const abs = Math.abs(v);
487
+ if (abs < 1) return v.toFixed(2);
488
+ return v.toFixed(1);
489
+ };
490
+ const textColorForHex = (hex) => {
491
+ const m = hex.replace("#", "").trim();
492
+ if (m.length !== 6) return "#fff";
493
+ const r = parseInt(m.slice(0, 2), 16);
494
+ const g = parseInt(m.slice(2, 4), 16);
495
+ const b = parseInt(m.slice(4, 6), 16);
496
+ const luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
497
+ return luminance > 0.6 ? "#111" : "#fff";
498
+ };
499
+ const colorAt = (i) => colors[i] ?? colors[i % colors.length];
500
+ if (t === "pie") {
501
+ const total = pairs.reduce((sum, p) => sum + p.y, 0);
502
+ if (total <= 0) return null;
503
+ let currentAngle = 0;
504
+ const centerX = width / 2 - 80;
505
+ const centerY = height / 2;
506
+ const radius = 60;
507
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "100%", overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width, height, viewBox: `0 0 ${width} ${height}`, children: pairs.map((p, i) => {
508
+ const sliceAngle = p.y / total * 2 * Math.PI;
509
+ const x1 = centerX + radius * Math.cos(currentAngle);
510
+ const y1 = centerY + radius * Math.sin(currentAngle);
511
+ const x2 = centerX + radius * Math.cos(currentAngle + sliceAngle);
512
+ const y2 = centerY + radius * Math.sin(currentAngle + sliceAngle);
513
+ const largeArcFlag = sliceAngle > Math.PI ? 1 : 0;
514
+ const pathData = `M ${centerX} ${centerY} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2} Z`;
515
+ const midAngle = currentAngle + sliceAngle / 2;
516
+ const labelRadius = radius * 0.7;
517
+ const labelX = centerX + labelRadius * Math.cos(midAngle);
518
+ const labelY = centerY + labelRadius * Math.sin(midAngle);
519
+ const ratio = p.y / total;
520
+ const percentText = `${(ratio * 100).toFixed(1)}%`;
521
+ const valueText = formatNumber(p.y);
522
+ const showInner = ratio >= 0.08 && sliceAngle >= 0.35;
523
+ const fill = colorAt(i);
524
+ currentAngle += sliceAngle;
525
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
526
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: pathData, fill, stroke: "#fff", strokeWidth: "1" }),
527
+ showInner ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
528
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: labelX, y: labelY - 2, textAnchor: "middle", style: { fontSize: 11, fill: textColorForHex(fill) }, children: valueText }),
529
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: labelX, y: labelY + 12, textAnchor: "middle", style: { fontSize: 10, fill: textColorForHex(fill) }, children: percentText })
530
+ ] }) : null,
531
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: width - 140, y: 20 + i * 20, width: 12, height: 12, fill, rx: 2 }),
532
+ /* @__PURE__ */ jsxRuntime.jsxs("text", { x: width - 120, y: 30 + i * 20, style: { fontSize: 12, fill: "#666" }, children: [
533
+ p.label,
534
+ ": ",
535
+ valueText,
536
+ " (",
537
+ percentText,
538
+ ")"
539
+ ] })
540
+ ] }, i);
541
+ }) }) });
542
+ }
543
+ if (t === "scatter") {
544
+ const numericPairs = pairs.map((p) => ({
545
+ ...p,
546
+ x: typeof p.x === "number" ? p.x : Number(p.x)
547
+ })).filter((p) => Number.isFinite(p.x) && Number.isFinite(p.y));
548
+ if (numericPairs.length === 0) return null;
549
+ const rawMinX = Math.min(...numericPairs.map((p) => p.x));
550
+ const rawMaxX = Math.max(...numericPairs.map((p) => p.x));
551
+ const rawMinY2 = Math.min(...numericPairs.map((p) => p.y));
552
+ const rawMaxY2 = Math.max(...numericPairs.map((p) => p.y));
553
+ const spanX0 = rawMaxX - rawMinX;
554
+ const spanY0 = rawMaxY2 - rawMinY2;
555
+ const padX = (spanX0 || Math.abs(rawMaxX) || 1) * 0.06;
556
+ const padY = (spanY0 || Math.abs(rawMaxY2) || 1) * 0.08;
557
+ const minX = rawMinX >= 0 ? Math.max(0, rawMinX - padX) : rawMinX - padX;
558
+ const maxX = rawMaxX <= 0 ? Math.min(0, rawMaxX + padX) : rawMaxX + padX;
559
+ const minY2 = rawMinY2 >= 0 ? Math.max(0, rawMinY2 - padY) : rawMinY2 - padY;
560
+ const maxY2 = rawMaxY2 <= 0 ? Math.min(0, rawMaxY2 + padY) : rawMaxY2 + padY;
561
+ const spanX = maxX - minX || 1;
562
+ const spanY2 = maxY2 - minY2 || 1;
563
+ const plotW2 = width - left - right;
564
+ const plotH2 = height - top - bottom;
565
+ const scaleX2 = (x) => left + (x - minX) * plotW2 / spanX;
566
+ const scaleY2 = (y) => top + (maxY2 - y) * plotH2 / spanY2;
567
+ const ticksX = Array.from({ length: 5 }, (_, i) => minX + i * spanX / 4);
568
+ const ticksY = Array.from({ length: 5 }, (_, i) => minY2 + i * spanY2 / 4);
569
+ const x0 = minY2 < 0 && maxY2 > 0 ? scaleY2(0) : null;
570
+ const y02 = minX < 0 && maxX > 0 ? scaleX2(0) : null;
571
+ const formatAxisNumber = (v) => {
572
+ const abs = Math.abs(v);
573
+ if (abs >= 1e3) return String(Math.round(v));
574
+ if (abs >= 10) return String(Math.round(v));
575
+ return formatNumber(v);
576
+ };
577
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "100%", overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width, height, viewBox: `0 0 ${width} ${height}`, children: [
578
+ ticksY.map((value, idx) => {
579
+ const y = scaleY2(value);
580
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
581
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: y, x2: width - right, y2: y, stroke: idx === 0 ? "#eee" : "#f0f0f0" }),
582
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: left - 6, y: y + 4, textAnchor: "end", style: { fontSize: 10, fill: "#999" }, children: formatAxisNumber(value) })
583
+ ] }, `y_${idx}`);
584
+ }),
585
+ ticksX.map((value, idx) => {
586
+ const x = scaleX2(value);
587
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
588
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: x, y1: top, x2: x, y2: height - bottom, stroke: idx === 0 ? "#eee" : "#f0f0f0" }),
589
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x, y: height - 8, textAnchor: "middle", style: { fontSize: 10, fill: "#999" }, children: formatAxisNumber(value) })
590
+ ] }, `x_${idx}`);
591
+ }),
592
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: top, x2: left, y2: height - bottom, stroke: "#eee" }),
593
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: height - bottom, x2: width - right, y2: height - bottom, stroke: "#eee" }),
594
+ typeof x0 === "number" ? /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: x0, x2: width - right, y2: x0, stroke: "#e6f4ff" }) : null,
595
+ typeof y02 === "number" ? /* @__PURE__ */ jsxRuntime.jsx("line", { x1: y02, y1: top, x2: y02, y2: height - bottom, stroke: "#e6f4ff" }) : null,
596
+ numericPairs.map((p, i) => {
597
+ const x = scaleX2(p.x);
598
+ const y = scaleY2(p.y);
599
+ return /* @__PURE__ */ jsxRuntime.jsx("g", { children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: x, cy: y, r: "3", fill: colors[0], opacity: "0.85" }) }, i);
600
+ })
601
+ ] }) });
602
+ }
603
+ const rawMinY = Math.min(...pairs.map((p) => p.y));
604
+ const rawMaxY = Math.max(...pairs.map((p) => p.y));
605
+ const minY = Math.min(0, rawMinY);
606
+ const maxY = Math.max(0, rawMaxY);
607
+ const spanY = maxY - minY || 1;
608
+ const plotW = width - left - right;
609
+ const plotH = height - top - bottom;
610
+ const scaleX = (i) => left + i * plotW / Math.max(1, pairs.length - 1);
611
+ const scaleY = (y) => top + (maxY - y) * plotH / spanY;
612
+ const ticks = Array.from({ length: 5 }, (_, i) => minY + i * spanY / 4);
613
+ const maxLabels = Math.max(2, Math.floor(plotW / 70));
614
+ const labelStep = Math.max(1, Math.ceil(pairs.length / maxLabels));
615
+ if (t === "line") {
616
+ const points = pairs.map((p, i) => `${scaleX(i)},${scaleY(p.y)}`).join(" ");
617
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "100%", overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width, height, viewBox: `0 0 ${width} ${height}`, children: [
618
+ ticks.map((value, idx) => {
619
+ const y = scaleY(value);
620
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
621
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: y, x2: width - right, y2: y, stroke: idx === 0 ? "#eee" : "#f0f0f0" }),
622
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: left - 6, y: y + 4, textAnchor: "end", style: { fontSize: 10, fill: "#999" }, children: formatNumber(value) })
623
+ ] }, idx);
624
+ }),
625
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: top, x2: left, y2: height - bottom, stroke: "#eee" }),
626
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { fill: "none", stroke: "#1677ff", strokeWidth: "2.5", points }),
627
+ pairs.map((p, i) => {
628
+ const x = scaleX(i);
629
+ const y = scaleY(p.y);
630
+ const showLabel = i % labelStep === 0 || i === pairs.length - 1;
631
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
632
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: x, cy: y, r: "3", fill: "#1677ff" }),
633
+ showLabel ? /* @__PURE__ */ jsxRuntime.jsx("text", { x, y: height - 8, textAnchor: "middle", style: { fontSize: 10, fill: "#999" }, children: p.label }) : null
634
+ ] }, i);
635
+ })
636
+ ] }) });
637
+ }
638
+ const barW = plotW / pairs.length;
639
+ const y0 = scaleY(0);
640
+ const showValueLabel = barW >= 18;
641
+ const xAxisY = height - bottom;
642
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { width: "100%", overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width, height, viewBox: `0 0 ${width} ${height}`, children: [
643
+ ticks.map((value, idx) => {
644
+ const y = scaleY(value);
645
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
646
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: y, x2: width - right, y2: y, stroke: idx === 0 ? "#eee" : "#f0f0f0" }),
647
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: left - 6, y: y + 4, textAnchor: "end", style: { fontSize: 10, fill: "#999" }, children: formatNumber(value) })
648
+ ] }, idx);
649
+ }),
650
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: top, x2: left, y2: height - bottom, stroke: "#eee" }),
651
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: xAxisY, x2: width - right, y2: xAxisY, stroke: "#eee" }),
652
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: left, y1: y0, x2: width - right, y2: y0, stroke: "#e6f4ff" }),
653
+ pairs.map((p, i) => {
654
+ const valueY = scaleY(p.y);
655
+ const barH = Math.abs(valueY - y0);
656
+ const x = left + i * barW + 2;
657
+ const cx = left + i * barW + barW / 2;
658
+ const y = Math.min(valueY, y0);
659
+ const labelY = p.y >= 0 ? y - 4 : y + barH + 12;
660
+ const showLabel = i % labelStep === 0 || i === pairs.length - 1;
661
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
662
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x, y, width: Math.max(2, barW - 4), height: barH, fill: colorAt(i), rx: 4 }),
663
+ showValueLabel ? /* @__PURE__ */ jsxRuntime.jsx("text", { x: cx, y: labelY, textAnchor: "middle", style: { fontSize: 10, fill: "#666" }, children: formatNumber(p.y) }) : null,
664
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: cx, y1: xAxisY, x2: cx, y2: xAxisY + 4, stroke: "#e6e6e6" }),
665
+ showLabel ? /* @__PURE__ */ jsxRuntime.jsx("text", { x: cx, y: height - 8, textAnchor: "middle", style: { fontSize: 10, fill: "#999" }, children: p.label }) : null
666
+ ] }, i);
667
+ })
668
+ ] }) });
669
+ }
670
+
671
+ // a2ui-runtime/components/artifacts/export-utils.ts
672
+ function sanitizeFileName(name) {
673
+ return name.replace(/[\\/:*?"<>|\u0000-\u001F]/g, "_").replace(/\s+/g, " ").trim();
674
+ }
675
+ function downloadBlob(blob, fileName) {
676
+ const url = URL.createObjectURL(blob);
677
+ const a = document.createElement("a");
678
+ a.href = url;
679
+ a.download = sanitizeFileName(fileName) || "download";
680
+ document.body.appendChild(a);
681
+ a.click();
682
+ a.remove();
683
+ URL.revokeObjectURL(url);
684
+ }
685
+ function escapeCsvCell(value) {
686
+ const raw = value === null || value === void 0 ? "" : String(value);
687
+ const needsQuote = /[",\n\r]/.test(raw);
688
+ const escaped = raw.replace(/"/g, '""');
689
+ return needsQuote ? `"${escaped}"` : escaped;
690
+ }
691
+ async function exportSvgElementAsPng(svgEl, fileName) {
692
+ const serializer = new XMLSerializer();
693
+ const svgText = serializer.serializeToString(svgEl);
694
+ const blob = new Blob([svgText], { type: "image/svg+xml;charset=utf-8" });
695
+ const url = URL.createObjectURL(blob);
696
+ const wAttr = svgEl.getAttribute("width");
697
+ const hAttr = svgEl.getAttribute("height");
698
+ const width = wAttr ? Number(wAttr) : svgEl.viewBox.baseVal?.width || 520;
699
+ const height = hAttr ? Number(hAttr) : svgEl.viewBox.baseVal?.height || 180;
700
+ const img = new Image();
701
+ img.crossOrigin = "anonymous";
702
+ await new Promise((resolve, reject) => {
703
+ img.onload = () => resolve();
704
+ img.onerror = () => reject(new Error("image load failed"));
705
+ img.src = url;
706
+ });
707
+ const ratio = Math.max(1, Math.min(3, window.devicePixelRatio || 1));
708
+ const canvas = document.createElement("canvas");
709
+ canvas.width = Math.round(width * ratio);
710
+ canvas.height = Math.round(height * ratio);
711
+ const ctx = canvas.getContext("2d");
712
+ if (!ctx) {
713
+ URL.revokeObjectURL(url);
714
+ return;
715
+ }
716
+ ctx.scale(ratio, ratio);
717
+ ctx.drawImage(img, 0, 0, width, height);
718
+ URL.revokeObjectURL(url);
719
+ const pngBlob = await new Promise((resolve) => {
720
+ canvas.toBlob((b) => resolve(b), "image/png");
721
+ });
722
+ if (!pngBlob) return;
723
+ downloadBlob(pngBlob, fileName);
724
+ }
725
+ async function exportCanvasElementAsPng(canvas, fileName) {
726
+ const pngBlob = await new Promise((resolve) => {
727
+ canvas.toBlob((b) => resolve(b), "image/png");
728
+ });
729
+ if (!pngBlob) return;
730
+ downloadBlob(pngBlob, fileName);
731
+ }
732
+ function exportTextFile(text, fileName, mime = "text/plain;charset=utf-8") {
733
+ downloadBlob(new Blob([text], { type: mime }), fileName);
734
+ }
735
+ function exportJsonFile(data, fileName) {
736
+ const json = JSON.stringify(data ?? null, null, 2);
737
+ exportTextFile(json, fileName, "application/json;charset=utf-8");
738
+ }
739
+ var ChartViewer = ({ artifactId, title, payload }) => {
740
+ const containerRef = React9__default.default.useRef(null);
741
+ const [containerWidth, setContainerWidth] = React9__default.default.useState(0);
742
+ const spec = payload?.spec;
743
+ const needsContainerWidth = true;
744
+ React9__default.default.useLayoutEffect(() => {
745
+ const el = containerRef.current;
746
+ if (!el) return;
747
+ let frame = 0;
748
+ const update = () => {
749
+ const nextWidth = el.clientWidth || 0;
750
+ setContainerWidth((prev) => prev === nextWidth ? prev : nextWidth);
751
+ };
752
+ const scheduleUpdate = () => {
753
+ if (frame) window.cancelAnimationFrame(frame);
754
+ frame = window.requestAnimationFrame(update);
755
+ };
756
+ scheduleUpdate();
757
+ const ro = new ResizeObserver(() => scheduleUpdate());
758
+ ro.observe(el);
759
+ return () => {
760
+ ro.disconnect();
761
+ if (frame) window.cancelAnimationFrame(frame);
762
+ };
763
+ }, [needsContainerWidth]);
764
+ if (!spec) {
765
+ return /* @__PURE__ */ jsxRuntime.jsx(ArtifactCard, { type: "chart", artifactId, title, payload });
766
+ }
767
+ const node = renderMiniChart(spec, { containerWidth });
768
+ if (!node) {
769
+ return /* @__PURE__ */ jsxRuntime.jsx(ArtifactCard, { type: "chart", artifactId, title, payload });
770
+ }
771
+ const exportBase = sanitizeFileName(title || artifactId || "chart");
772
+ const exportPng = async () => {
773
+ const svg = containerRef.current?.querySelector("svg");
774
+ if (svg) {
775
+ await exportSvgElementAsPng(svg, `${exportBase}.png`);
776
+ return;
777
+ }
778
+ const canvas = containerRef.current?.querySelector("canvas");
779
+ if (canvas) {
780
+ await exportCanvasElementAsPng(canvas, `${exportBase}.png`);
781
+ }
782
+ };
783
+ return /* @__PURE__ */ jsxRuntime.jsx(
784
+ antd.Card,
785
+ {
786
+ size: "small",
787
+ style: { borderRadius: 12 },
788
+ title: title || "\u56FE\u8868",
789
+ extra: /* @__PURE__ */ jsxRuntime.jsx(antd.Space, { size: 4, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { size: "small", type: "text", onClick: exportPng, children: "\u5BFC\u51FAPNG" }) }),
790
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, children: node })
791
+ }
792
+ );
793
+ };
794
+ var AgentNavigateComponent = React9__default.default.memo((props) => {
795
+ const [content, setContent] = React9.useState(null);
796
+ const { children } = props;
797
+ React9.useEffect(() => {
798
+ if (!children) {
799
+ return;
800
+ }
801
+ console.log(typeof children, children);
802
+ if (typeof children === "string") {
803
+ try {
804
+ setContent(JSON.parse(children));
805
+ } catch (_error) {
806
+ setContent(null);
807
+ }
808
+ } else {
809
+ setContent(children);
810
+ }
811
+ }, [children]);
812
+ const handleClick = () => {
813
+ if (!content?.emit) return;
814
+ };
815
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { onClick: handleClick, style: { padding: 0 }, type: "link", children: content?.name || "\u70B9\u51FB\u6B64\u5904" });
816
+ });
817
+ var agent_navigate_default = AgentNavigateComponent;
818
+ var CodeHighlight = (props) => {
819
+ const { className, children } = props;
820
+ const lang = className?.match(/language-(\w+)/)?.[1] || "";
821
+ if (typeof children !== "string") return null;
822
+ if (!lang) {
823
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { children });
824
+ }
825
+ if (lang === "mermaid") {
826
+ return /* @__PURE__ */ jsxRuntime.jsx(xV2.Mermaid, { children });
827
+ }
828
+ return /* @__PURE__ */ jsxRuntime.jsx(
829
+ "div",
830
+ {
831
+ style: {
832
+ maxHeight: 400,
833
+ overflowY: "auto",
834
+ overflowX: "auto",
835
+ borderRadius: 8
836
+ },
837
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { minWidth: "max-content" }, children: /* @__PURE__ */ jsxRuntime.jsx(xV2.CodeHighlighter, { lang, style: { margin: 0 }, children }) })
838
+ }
839
+ );
840
+ };
841
+ var code_highlight_default = CodeHighlight;
842
+ var TOKEN_KEY = "NS-TOKEN";
843
+ var tokenManager = common.createTokenManager({
844
+ key: TOKEN_KEY
845
+ });
846
+ var redirectUrl = () => {
847
+ const path = localStorage.getItem("SIGNPATH");
848
+ common.emit("jumpLink", { url: `/uc${path || "/sign-in"}` });
849
+ };
850
+ var PreviewLinkComponent = (props) => {
851
+ const chatStore = useChatStore();
852
+ const configState = valtio.useSnapshot(chatStore.config);
853
+ return /* @__PURE__ */ jsxRuntime.jsx(
854
+ "a",
855
+ {
856
+ ...props,
857
+ onClick: (e) => {
858
+ if (props.onClick) {
859
+ props.onClick(e);
860
+ }
861
+ if (!e.defaultPrevented && e.currentTarget.href) {
862
+ e.preventDefault();
863
+ if (props.href && String(props.href).startsWith("/luya") && configState.layout.preview) {
864
+ let fileName = "link";
865
+ let path = e.currentTarget.href;
866
+ const url = new URL(path, window.location.origin);
867
+ const searchParams = new URLSearchParams(url.search);
868
+ if (searchParams.has("path")) {
869
+ path = searchParams.get("path");
870
+ }
871
+ if (path && path.includes("/")) {
872
+ const segments = path.split("/");
873
+ const lastSegment = segments[segments.length - 1];
874
+ if (lastSegment) {
875
+ try {
876
+ fileName = decodeURIComponent(lastSegment);
877
+ } catch (e2) {
878
+ fileName = lastSegment;
879
+ }
880
+ }
881
+ } else if (typeof props.children === "string") {
882
+ fileName = props.children;
883
+ } else if (Array.isArray(props.children) && typeof props.children[0] === "string") {
884
+ fileName = String(props.children[0]);
885
+ }
886
+ chatStore.setPreview({ path, fileName });
887
+ } else if (props.href && !String(props.href).startsWith("/luya")) {
888
+ window.open(props.href || e.currentTarget.href, "_blank");
889
+ } else if (props.href && String(props.href).startsWith("/luya") && !configState.layout.preview) {
890
+ const urlObj = new URL(props.href, window.location.origin);
891
+ urlObj.searchParams.set("NS-TOKEN", tokenManager.get() || "");
892
+ window.open(urlObj.toString(), "_blank");
893
+ }
894
+ }
895
+ }
896
+ }
897
+ );
898
+ };
899
+
900
+ // src/components/custom-components/tool-renders/index.module.less
901
+ var index_module_default = {
902
+ iconContainer: "index_module_iconContainer",
903
+ toolName: "index_module_toolName",
904
+ duration: "index_module_duration",
905
+ statusIcon: "index_module_statusIcon",
906
+ sectionLabel: "index_module_sectionLabel",
907
+ markdownContainer: "index_module_markdownContainer",
908
+ sectionBlock: "index_module_sectionBlock",
909
+ todoList: "index_module_todoList",
910
+ todoItem: "index_module_todoItem",
911
+ statusIconWrapper: "index_module_statusIconWrapper",
912
+ todoContent: "index_module_todoContent",
913
+ todoText: "index_module_todoText",
914
+ completed: "index_module_completed",
915
+ emptyText: "index_module_emptyText"
916
+ };
917
+ var DefaultToolRender = ({ argsContent, resultContent, errorMessage, item }) => {
918
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
919
+ (item.content || item.arguments) && argsContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: index_module_default.sectionBlock, children: [
920
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Typography.Text, { className: index_module_default.sectionLabel, children: "\u8F93\u5165\u53C2\u6570" }),
921
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.markdownContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
922
+ XMarkdown__default.default,
923
+ {
924
+ className: "xMarkdownStyle",
925
+ components: { code: code_highlight_default },
926
+ config: getMarkdownConfig(),
927
+ content: argsContent.isJson ? `\`\`\`json
928
+ ${argsContent.text}
929
+ \`\`\`` : argsContent.text
930
+ }
931
+ ) })
932
+ ] }),
933
+ item.result && resultContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: index_module_default.sectionBlock, children: [
934
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Typography.Text, { className: index_module_default.sectionLabel, children: "\u8FD4\u56DE\u7ED3\u679C" }),
935
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.markdownContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
936
+ XMarkdown__default.default,
937
+ {
938
+ className: "xMarkdownStyle",
939
+ components: { code: code_highlight_default },
940
+ config: getMarkdownConfig(),
941
+ content: resultContent.isJson ? `\`\`\`json
942
+ ${resultContent.text}
943
+ \`\`\`` : resultContent.text
944
+ }
945
+ ) })
946
+ ] }),
947
+ errorMessage && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: index_module_default.sectionBlock, children: [
948
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Typography.Text, { className: index_module_default.sectionLabel, children: "\u9519\u8BEF\u4FE1\u606F" }),
949
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.markdownContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
950
+ XMarkdown__default.default,
951
+ {
952
+ className: "xMarkdownStyle",
953
+ components: { code: code_highlight_default },
954
+ config: getMarkdownConfig(),
955
+ content: `\`\`\`
956
+ ${errorMessage}
957
+ \`\`\``
958
+ }
959
+ ) })
960
+ ] })
961
+ ] });
962
+ };
963
+ var default_render_default = DefaultToolRender;
964
+ var TodoWriteRender = ({ args, result }) => {
965
+ const { token } = antd.theme.useToken();
966
+ const todos = Array.isArray(result) ? result : result?.todos || (Array.isArray(args) ? args : args?.todos) || [];
967
+ const getStatusIcon = (status) => {
968
+ switch (status) {
969
+ case "completed":
970
+ return /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircleOutlined, { style: { color: token.colorSuccess } });
971
+ case "in_progress":
972
+ return /* @__PURE__ */ jsxRuntime.jsx(icons.ClockCircleOutlined, { style: { color: token.colorPrimary } });
973
+ case "pending":
974
+ default:
975
+ return /* @__PURE__ */ jsxRuntime.jsx(icons.ClockCircleOutlined, { style: { color: token.colorTextTertiary } });
976
+ }
977
+ };
978
+ if (!todos || todos.length === 0) {
979
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Typography.Text, { type: "secondary", className: index_module_default.emptyText, children: "\u6682\u65E0\u4EFB\u52A1" });
980
+ }
981
+ return /* @__PURE__ */ jsxRuntime.jsx(
982
+ antd.List,
983
+ {
984
+ size: "small",
985
+ dataSource: todos,
986
+ renderItem: (item) => /* @__PURE__ */ jsxRuntime.jsxs(antd.List.Item, { className: index_module_default.todoItem, children: [
987
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.statusIconWrapper, children: getStatusIcon(item.status) }),
988
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.todoContent, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Typography.Text, { className: `${index_module_default.todoText} ${item.status === "completed" ? index_module_default.completed : ""}`, children: item.title || item.content }) })
989
+ ] }),
990
+ className: index_module_default.todoList
991
+ }
992
+ );
993
+ };
994
+ var todo_write_render_default = TodoWriteRender;
995
+ var toolRenders = {
996
+ todo_write: {
997
+ component: todo_write_render_default,
998
+ defaultExpanded: false,
999
+ alwaysShowContent: (args, result) => {
1000
+ const todos = Array.isArray(result) ? result : result?.todos || (Array.isArray(args) ? args : args?.todos) || [];
1001
+ return todos && todos.length > 0;
1002
+ },
1003
+ hideStatus: true,
1004
+ disableExpandOnError: true
1005
+ }
1006
+ };
1007
+ var getToolRenderConfig = (toolName) => {
1008
+ if (toolName && toolRenders[toolName]) {
1009
+ return toolRenders[toolName];
1010
+ }
1011
+ return {
1012
+ component: default_render_default,
1013
+ defaultExpanded: false,
1014
+ alwaysShowContent: false
1015
+ };
1016
+ };
1017
+ var formatContent = (content) => {
1018
+ try {
1019
+ if (!content) return { text: "", isJson: false, parsed: null };
1020
+ if (typeof content === "object") {
1021
+ return { text: JSON.stringify(content, null, 2), isJson: true, parsed: content };
1022
+ }
1023
+ const parsed = JSON.parse(content);
1024
+ if (typeof parsed === "object" && parsed !== null) {
1025
+ return { text: JSON.stringify(parsed, null, 2), isJson: true, parsed };
1026
+ }
1027
+ return { text: content, isJson: false, parsed: null };
1028
+ } catch {
1029
+ return { text: typeof content === "string" ? content : "", isJson: false, parsed: null };
1030
+ }
1031
+ };
1032
+ var ToolCallItem = ({ item }) => {
1033
+ const { token } = antd.theme.useToken();
1034
+ const renderConfig = getToolRenderConfig(item.toolName);
1035
+ const CustomRender = renderConfig.component;
1036
+ const status = React9.useMemo(() => {
1037
+ if (item.status) return item.status;
1038
+ if (item.errorMessage) return "error";
1039
+ if (item.result) return "success";
1040
+ return "running";
1041
+ }, [item.status, item.errorMessage, item.result]);
1042
+ const argsContent = React9.useMemo(() => formatContent(item.arguments || item.content), [item.arguments, item.content]);
1043
+ const resultContent = React9.useMemo(() => item.result ? formatContent(item.result) : null, [item.result]);
1044
+ const hasContent = React9.useMemo(() => {
1045
+ if (renderConfig.disableExpandOnError && status === "error") return false;
1046
+ let alwaysShow = false;
1047
+ if (typeof renderConfig.alwaysShowContent === "function") {
1048
+ alwaysShow = renderConfig.alwaysShowContent(argsContent.parsed, resultContent?.parsed);
1049
+ } else if (renderConfig.alwaysShowContent) {
1050
+ alwaysShow = renderConfig.alwaysShowContent;
1051
+ }
1052
+ if (alwaysShow) return true;
1053
+ return Boolean(item.errorMessage);
1054
+ }, [renderConfig.disableExpandOnError, renderConfig.alwaysShowContent, item.errorMessage, status, argsContent.parsed, resultContent?.parsed]);
1055
+ const isDefaultExpanded = React9.useMemo(() => {
1056
+ if (typeof renderConfig.defaultExpanded === "function") {
1057
+ return renderConfig.defaultExpanded(argsContent.parsed, resultContent?.parsed);
1058
+ }
1059
+ return renderConfig.defaultExpanded;
1060
+ }, [renderConfig.defaultExpanded, argsContent.parsed, resultContent?.parsed]);
1061
+ const statusConfig = {
1062
+ running: {
1063
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.LoadingOutlined, {}),
1064
+ color: token.colorPrimary
1065
+ },
1066
+ success: {
1067
+ icon: null,
1068
+ color: token.colorSuccess
1069
+ },
1070
+ error: {
1071
+ icon: null,
1072
+ color: token.colorSuccess
1073
+ },
1074
+ pending: {
1075
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.LoadingOutlined, {}),
1076
+ color: token.colorTextSecondary
1077
+ }
1078
+ }[status] || {
1079
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.LoadingOutlined, {}),
1080
+ color: token.colorPrimary
1081
+ };
1082
+ const renderIcon = () => {
1083
+ if (!item.toolIcon) {
1084
+ return /* @__PURE__ */ jsxRuntime.jsx(icons.ToolOutlined, { style: { fontSize: 14, color: token.colorTextSecondary } });
1085
+ }
1086
+ const isUrl = /^(http|\/)/.test(item.toolIcon);
1087
+ if (isUrl) {
1088
+ return /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.toolIcon, alt: "tool-icon", style: { width: "100%", height: "100%", objectFit: "contain" } });
1089
+ }
1090
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 14, lineHeight: 1 }, children: item.toolIcon });
1091
+ };
1092
+ return /* @__PURE__ */ jsxRuntime.jsx(
1093
+ antd.Collapse,
1094
+ {
1095
+ style: { width: "70%" },
1096
+ collapsible: hasContent ? void 0 : "disabled",
1097
+ defaultActiveKey: isDefaultExpanded && hasContent ? [item.toolCallId || "fallback-key"] : void 0,
1098
+ expandIconPlacement: "end",
1099
+ styles: {
1100
+ header: {
1101
+ padding: "6px 10px"
1102
+ }
1103
+ },
1104
+ items: [
1105
+ {
1106
+ key: item.toolCallId || "fallback-key",
1107
+ showArrow: hasContent,
1108
+ label: /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { align: "center", gap: 8, style: { flex: 1, minWidth: 0 }, children: [
1109
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.iconContainer, children: renderIcon() }),
1110
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: index_module_default.toolName, children: item.title || item.toolName || "Unknown Tool" }),
1111
+ (status === "running" || status === "pending") && /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.statusIcon, style: { color: statusConfig.color }, children: statusConfig.icon }),
1112
+ item.duration && /* @__PURE__ */ jsxRuntime.jsxs(antd.Typography.Text, { className: index_module_default.duration, children: [
1113
+ item.duration,
1114
+ "ms"
1115
+ ] })
1116
+ ] }),
1117
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1118
+ CustomRender,
1119
+ {
1120
+ item,
1121
+ args: argsContent.parsed,
1122
+ result: resultContent?.parsed,
1123
+ argsContent,
1124
+ resultContent,
1125
+ errorMessage: item.errorMessage
1126
+ }
1127
+ )
1128
+ }
1129
+ ]
1130
+ }
1131
+ );
1132
+ };
1133
+ var tool_call_item_default = ToolCallItem;
1134
+ function formatMixedContent(content) {
1135
+ return content.replace(/<!DOCTYPE html>[\s\S]*?<\/html>/gi, (match) => `\`\`\`html
1136
+ ${match}
1137
+ \`\`\``);
1138
+ }
1139
+ var ReportViewer = ({ artifactId, title, payload }) => {
1140
+ const markdown = typeof payload?.markdown === "string" ? payload.markdown : null;
1141
+ if (!markdown) {
1142
+ return /* @__PURE__ */ jsxRuntime.jsx(ArtifactCard, { type: "report", artifactId, title, payload });
1143
+ }
1144
+ const exportBase = sanitizeFileName(title || artifactId || "report");
1145
+ const exportMd = () => {
1146
+ exportTextFile(markdown, `${exportBase}.md`, "text/markdown;charset=utf-8");
1147
+ };
1148
+ return /* @__PURE__ */ jsxRuntime.jsx(
1149
+ antd.Card,
1150
+ {
1151
+ size: "small",
1152
+ style: { borderRadius: 12 },
1153
+ title: title || "\u62A5\u544A",
1154
+ extra: /* @__PURE__ */ jsxRuntime.jsx(antd.Space, { size: 4, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { size: "small", type: "text", onClick: exportMd, children: "\u5BFC\u51FAMD" }) }),
1155
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { lineHeight: 1.75 }, children: /* @__PURE__ */ jsxRuntime.jsx(
1156
+ XMarkdown__default.default,
1157
+ {
1158
+ openLinksInNewTab: true,
1159
+ className: classNames7__default.default("x-markdown-light", "xMarkdownStyle"),
1160
+ components: {
1161
+ code: code_highlight_default,
1162
+ agentnavigate: agent_navigate_default,
1163
+ a: PreviewLinkComponent
1164
+ },
1165
+ config: getMarkdownConfig(),
1166
+ content: formatMixedContent(markdown)
1167
+ }
1168
+ ) })
1169
+ }
1170
+ );
1171
+ };
1172
+ var TableViewer = ({ artifactId, title, payload }) => {
1173
+ const columns = Array.isArray(payload?.columns) ? payload.columns : null;
1174
+ const rows = Array.isArray(payload?.rows) ? payload.rows : null;
1175
+ if (!columns || !rows) {
1176
+ return /* @__PURE__ */ jsxRuntime.jsx(ArtifactCard, { type: "table", artifactId, title, payload });
1177
+ }
1178
+ const safeColumns = columns.map((c) => ({
1179
+ title: String(c?.title ?? c?.dataIndex ?? ""),
1180
+ dataIndex: String(c?.dataIndex ?? "")
1181
+ })).filter((c) => c.dataIndex);
1182
+ const dataSource = rows.map((r, i) => ({
1183
+ key: String(r?.id ?? i),
1184
+ ...r && typeof r === "object" ? r : {}
1185
+ }));
1186
+ const exportBase = sanitizeFileName(title || artifactId || "table");
1187
+ const exportCsv = () => {
1188
+ const header = safeColumns.map((c) => escapeCsvCell(c.title)).join(",");
1189
+ const body = rows.map((row) => safeColumns.map((c) => escapeCsvCell(row?.[c.dataIndex])).join(",")).join("\n");
1190
+ exportTextFile(`\uFEFF${header}
1191
+ ${body}
1192
+ `, `${exportBase}.csv`, "text/csv;charset=utf-8");
1193
+ };
1194
+ const exportJson = () => {
1195
+ exportJsonFile({ columns: safeColumns, rows }, `${exportBase}.json`);
1196
+ };
1197
+ return /* @__PURE__ */ jsxRuntime.jsx(
1198
+ antd.Card,
1199
+ {
1200
+ size: "small",
1201
+ style: { borderRadius: 12 },
1202
+ title: title || "\u8868\u683C",
1203
+ extra: /* @__PURE__ */ jsxRuntime.jsxs(antd.Space, { size: 4, children: [
1204
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { size: "small", type: "text", onClick: exportCsv, children: "\u5BFC\u51FACSV" }),
1205
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { size: "small", type: "text", onClick: exportJson, children: "\u5BFC\u51FAJSON" })
1206
+ ] }),
1207
+ children: /* @__PURE__ */ jsxRuntime.jsx(antd.Table, { size: "small", pagination: false, columns: safeColumns, dataSource, scroll: { x: true } })
1208
+ }
1209
+ );
1210
+ };
1211
+ var { Text: AText2, Title } = antd.Typography;
1212
+ var FIELD_LABEL_STYLE = { marginBottom: 6, fontSize: 13, fontWeight: 500, color: "#555" };
1213
+ var INPUT_RADIUS_STYLE = { borderRadius: 8 };
1214
+ var formPathValueStore = /* @__PURE__ */ new Map();
1215
+ function normalizeModelPath(modelPath) {
1216
+ const normalized = typeof modelPath === "string" ? modelPath.trim() : "";
1217
+ if (!normalized.startsWith("/")) return "";
1218
+ return normalized.replace(/\/{2,}/g, "/").replace(/\/$/, "") || "/";
1219
+ }
1220
+ function modelPathPrefix(modelPath) {
1221
+ const normalized = normalizeModelPath(modelPath);
1222
+ if (!normalized || normalized === "/") return normalized;
1223
+ return `${normalized}/`;
1224
+ }
1225
+ function readModelValues(modelPath) {
1226
+ const normalized = normalizeModelPath(modelPath);
1227
+ if (!normalized || normalized === "/") return {};
1228
+ const prefix = modelPathPrefix(normalized);
1229
+ const values = {};
1230
+ for (const [path, value] of formPathValueStore.entries()) {
1231
+ if (typeof path !== "string") continue;
1232
+ if (!path.startsWith(prefix)) continue;
1233
+ const rest = path.slice(prefix.length);
1234
+ if (!rest || rest.includes("/")) continue;
1235
+ values[rest] = value;
1236
+ }
1237
+ return values;
1238
+ }
1239
+ function writeModelValues(modelPath, values) {
1240
+ const normalized = normalizeModelPath(modelPath);
1241
+ if (!normalized || normalized === "/" || !values || typeof values !== "object" || Array.isArray(values)) return;
1242
+ Object.entries(values).forEach(([key, value]) => {
1243
+ if (typeof key !== "string" || !key.trim() || key.includes("/")) return;
1244
+ const fieldPath = `${normalized}/${key}`.replace(/\/{2,}/g, "/");
1245
+ formPathValueStore.set(fieldPath, value === void 0 ? null : value);
1246
+ });
1247
+ }
1248
+ function clearModelValues(modelPath) {
1249
+ const normalized = normalizeModelPath(modelPath);
1250
+ if (!normalized) return;
1251
+ if (normalized === "/") {
1252
+ formPathValueStore.clear();
1253
+ return;
1254
+ }
1255
+ const prefix = modelPathPrefix(normalized);
1256
+ for (const path of Array.from(formPathValueStore.keys())) {
1257
+ if (path === normalized || path.startsWith(prefix)) {
1258
+ formPathValueStore.delete(path);
1259
+ }
1260
+ }
1261
+ }
1262
+ function clearAllModelValues() {
1263
+ formPathValueStore.clear();
1264
+ }
1265
+ function isPathRef(v) {
1266
+ return !!v && typeof v === "object" && typeof v.path === "string";
1267
+ }
1268
+ function isPathString(v) {
1269
+ return typeof v === "string" && v.startsWith("/");
1270
+ }
1271
+ function pathFromValue(v) {
1272
+ if (isPathRef(v)) return v.path;
1273
+ if (isPathString(v)) return v;
1274
+ return null;
1275
+ }
1276
+ function decodeBindPathToken(token) {
1277
+ if (typeof token !== "string") return null;
1278
+ if (!token.startsWith("$bind:")) return null;
1279
+ const path = token.slice("$bind:".length);
1280
+ return path.startsWith("/") ? path : null;
1281
+ }
1282
+ function rememberPathValue(path, value) {
1283
+ if (!path) return;
1284
+ formPathValueStore.set(path, value === void 0 ? null : value);
1285
+ }
1286
+ function readPathValue(path) {
1287
+ if (!path) return void 0;
1288
+ return formPathValueStore.get(path);
1289
+ }
1290
+ function resolveMaybePath(v) {
1291
+ const path = pathFromValue(v);
1292
+ if (!path) return v;
1293
+ const cached = readPathValue(path);
1294
+ return cached === void 0 ? v : cached;
1295
+ }
1296
+ function normalizeActionContext(context) {
1297
+ const next = { ...context };
1298
+ const refs = next.refs && typeof next.refs === "object" && !Array.isArray(next.refs) ? next.refs : null;
1299
+ const values = next.values && typeof next.values === "object" && !Array.isArray(next.values) ? { ...next.values } : {};
1300
+ const candidateKeys = refs ? Object.keys(refs) : Object.keys(next).filter((k) => k !== "form_name" && k !== "refs" && k !== "values");
1301
+ for (const key of candidateKeys) {
1302
+ const source = refs ? refs[key] ?? next[key] : next[key];
1303
+ const resolved = resolveMaybePath(source);
1304
+ if (!pathFromValue(resolved)) {
1305
+ values[key] = resolved;
1306
+ next[key] = resolved;
1307
+ }
1308
+ }
1309
+ if (next.form_name || refs || Object.keys(values).length > 0) {
1310
+ next.values = values;
1311
+ }
1312
+ return next;
1313
+ }
1314
+ function readStringValue(value) {
1315
+ return typeof value === "string" ? value : void 0;
1316
+ }
1317
+ function readBooleanValue(value) {
1318
+ return typeof value === "boolean" ? value : void 0;
1319
+ }
1320
+ function readSelectValue(value) {
1321
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? value : void 0;
1322
+ }
1323
+ function preferCachedStringValue(externalValue, cachedValue, valuePath) {
1324
+ return !!valuePath && externalValue === "" && typeof cachedValue === "string" && cachedValue !== "";
1325
+ }
1326
+ function useBoundFieldState({
1327
+ value,
1328
+ bindPathToken,
1329
+ defaultValue,
1330
+ readExternalValue,
1331
+ readCachedValue,
1332
+ preferCachedValueWhenBound,
1333
+ preferCachedOverExternal
1334
+ }) {
1335
+ const valuePath = decodeBindPathToken(bindPathToken) ?? pathFromValue(value);
1336
+ const cachedValue = readCachedValue(readPathValue(valuePath));
1337
+ const externalValue = readExternalValue(value);
1338
+ const dirtyRef = React9__default.default.useRef(false);
1339
+ const [localValue, setLocalValue] = React9__default.default.useState(() => {
1340
+ if (valuePath && cachedValue !== void 0) {
1341
+ return cachedValue;
1342
+ }
1343
+ if (externalValue !== void 0) {
1344
+ if (preferCachedOverExternal?.(externalValue, cachedValue, valuePath) && cachedValue !== void 0) {
1345
+ return cachedValue;
1346
+ }
1347
+ return externalValue;
1348
+ }
1349
+ if (cachedValue !== void 0) return cachedValue;
1350
+ return defaultValue;
1351
+ });
1352
+ React9__default.default.useEffect(() => {
1353
+ dirtyRef.current = false;
1354
+ }, [valuePath]);
1355
+ React9__default.default.useEffect(() => {
1356
+ if (valuePath && cachedValue !== void 0) {
1357
+ setLocalValue(cachedValue);
1358
+ return;
1359
+ }
1360
+ if (valuePath && cachedValue !== void 0 && dirtyRef.current) {
1361
+ setLocalValue(cachedValue);
1362
+ return;
1363
+ }
1364
+ if (externalValue !== void 0) {
1365
+ if (preferCachedOverExternal?.(externalValue, cachedValue, valuePath) && cachedValue !== void 0) {
1366
+ setLocalValue(cachedValue);
1367
+ return;
1368
+ }
1369
+ if (!dirtyRef.current) {
1370
+ setLocalValue(externalValue);
1371
+ rememberPathValue(valuePath, externalValue);
1372
+ }
1373
+ return;
1374
+ }
1375
+ if (cachedValue !== void 0) {
1376
+ setLocalValue(cachedValue);
1377
+ }
1378
+ }, [cachedValue, externalValue, preferCachedOverExternal, valuePath]);
1379
+ React9__default.default.useEffect(() => {
1380
+ rememberPathValue(valuePath, localValue);
1381
+ }, [valuePath, localValue]);
1382
+ const updateLocalValue = React9__default.default.useCallback(
1383
+ (nextValue) => {
1384
+ dirtyRef.current = true;
1385
+ setLocalValue(nextValue);
1386
+ rememberPathValue(valuePath, nextValue);
1387
+ },
1388
+ [valuePath]
1389
+ );
1390
+ return { localValue, updateLocalValue, valuePath };
1391
+ }
1392
+ var FieldBlock = ({ label, children }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { width: "100%" }, children: [
1393
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: FIELD_LABEL_STYLE, children: label }),
1394
+ children
1395
+ ] });
1396
+ function emitFieldChange(nextValue, valuePath, updateLocalValue, onDataChange, onChange) {
1397
+ updateLocalValue(nextValue);
1398
+ if (valuePath) onDataChange?.(valuePath, nextValue);
1399
+ onChange?.(nextValue);
1400
+ }
1401
+ function useControlId(id) {
1402
+ const autoId = React9__default.default.useId();
1403
+ return id ?? autoId;
1404
+ }
1405
+ function readActionEvent(action) {
1406
+ const name = typeof action?.event?.name === "string" ? action.event.name : "";
1407
+ const context = action?.event?.context ?? {};
1408
+ return { name, context };
1409
+ }
1410
+ var Column = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(antd.Space, { orientation: "vertical", style: { width: "100%" }, size: 14, children });
1411
+ var Row = ({ children, gap = 8 }) => /* @__PURE__ */ jsxRuntime.jsx(antd.Space, { orientation: "horizontal", size: gap, wrap: true, children });
1412
+ var Text = ({ text, variant }) => {
1413
+ if (variant === "h2")
1414
+ return /* @__PURE__ */ jsxRuntime.jsx(Title, { level: 4, style: { margin: 0 }, children: text });
1415
+ if (variant === "h3")
1416
+ return /* @__PURE__ */ jsxRuntime.jsx(Title, { level: 5, style: { margin: 0 }, children: text });
1417
+ if (variant === "caption")
1418
+ return /* @__PURE__ */ jsxRuntime.jsx(AText2, { type: "secondary", style: { fontSize: 12, lineHeight: 1.6 }, children: text });
1419
+ return /* @__PURE__ */ jsxRuntime.jsx(AText2, { style: { lineHeight: 1.7 }, children: text });
1420
+ };
1421
+ var TextField = ({ id, label, placeholder, value, bind_path_token, onChange, onDataChange }) => {
1422
+ const inputId = useControlId(id);
1423
+ const { localValue, updateLocalValue, valuePath } = useBoundFieldState({
1424
+ value,
1425
+ bindPathToken: bind_path_token,
1426
+ defaultValue: "",
1427
+ readExternalValue: readStringValue,
1428
+ readCachedValue: readStringValue,
1429
+ preferCachedValueWhenBound: true,
1430
+ preferCachedOverExternal: preferCachedStringValue
1431
+ });
1432
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldBlock, { label, children: /* @__PURE__ */ jsxRuntime.jsx(
1433
+ antd.Input,
1434
+ {
1435
+ id: inputId,
1436
+ name: inputId,
1437
+ placeholder,
1438
+ value: localValue,
1439
+ onChange: (e) => emitFieldChange(e.target.value, valuePath, updateLocalValue, onDataChange, onChange),
1440
+ style: INPUT_RADIUS_STYLE
1441
+ }
1442
+ ) });
1443
+ };
1444
+ var Select = ({ id, label, placeholder, options, value, bind_path_token, onChange, onDataChange }) => {
1445
+ const inputId = useControlId(id);
1446
+ const { localValue, updateLocalValue, valuePath } = useBoundFieldState({
1447
+ value,
1448
+ bindPathToken: bind_path_token,
1449
+ defaultValue: void 0,
1450
+ readExternalValue: readSelectValue,
1451
+ readCachedValue: readSelectValue,
1452
+ preferCachedValueWhenBound: true,
1453
+ preferCachedOverExternal: (externalValue, cachedValue, valuePath2) => typeof externalValue === "string" ? preferCachedStringValue(externalValue, readStringValue(cachedValue), valuePath2) : false
1454
+ });
1455
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldBlock, { label, children: /* @__PURE__ */ jsxRuntime.jsx(
1456
+ antd.Select,
1457
+ {
1458
+ id: inputId,
1459
+ style: { width: "100%" },
1460
+ options,
1461
+ value: localValue,
1462
+ onChange: (nextValue) => emitFieldChange(nextValue, valuePath, updateLocalValue, onDataChange, onChange),
1463
+ placeholder: placeholder || "\u8BF7\u9009\u62E9..."
1464
+ }
1465
+ ) });
1466
+ };
1467
+ var Switch = ({ id, label, value, bind_path_token, onChange, onDataChange }) => {
1468
+ const inputId = useControlId(id);
1469
+ const { localValue, updateLocalValue, valuePath } = useBoundFieldState({
1470
+ value,
1471
+ bindPathToken: bind_path_token,
1472
+ defaultValue: false,
1473
+ readExternalValue: readBooleanValue,
1474
+ readCachedValue: readBooleanValue,
1475
+ preferCachedValueWhenBound: true
1476
+ });
1477
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Space, { align: "center", children: [
1478
+ /* @__PURE__ */ jsxRuntime.jsx(
1479
+ antd.Switch,
1480
+ {
1481
+ id: inputId,
1482
+ checked: localValue,
1483
+ onChange: (nextValue) => emitFieldChange(nextValue, valuePath, updateLocalValue, onDataChange, onChange)
1484
+ }
1485
+ ),
1486
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13, color: "#555" }, children: label })
1487
+ ] });
1488
+ };
1489
+ var Button3 = ({ label, variant = "default", onClick, action, onAction }) => {
1490
+ const handleClick = () => {
1491
+ if (onClick) {
1492
+ onClick();
1493
+ return;
1494
+ }
1495
+ const { name, context } = readActionEvent(action);
1496
+ if (name && onAction) {
1497
+ onAction(name, context);
1498
+ }
1499
+ };
1500
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { type: variant === "primary" ? "primary" : "default", danger: variant === "danger", onClick: handleClick, style: { borderRadius: 8 }, children: label });
1501
+ };
1502
+ var Divider = () => /* @__PURE__ */ jsxRuntime.jsx(antd.Divider, { style: { margin: "8px 0" } });
1503
+ var Tag = ({ text, color }) => /* @__PURE__ */ jsxRuntime.jsx(antd.Tag, { color, children: text });
1504
+ var Progress = ({
1505
+ percent,
1506
+ status = "normal",
1507
+ text
1508
+ }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { width: "100%" }, children: [
1509
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Progress, { percent: Math.max(0, Math.min(100, Math.round(percent))), status }),
1510
+ text ? /* @__PURE__ */ jsxRuntime.jsx(AText2, { type: "secondary", style: { fontSize: 12 }, children: text }) : null
1511
+ ] });
1512
+ var A2uiComponents = {
1513
+ Column,
1514
+ Row,
1515
+ Text,
1516
+ TextField,
1517
+ Select,
1518
+ Switch,
1519
+ Button: Button3,
1520
+ Divider,
1521
+ Tag,
1522
+ Progress,
1523
+ ArtifactCard,
1524
+ TableViewer,
1525
+ ChartViewer,
1526
+ ReportViewer
1527
+ };
1528
+
1529
+ // a2ui-runtime/controller/meta.ts
1530
+ function readProp(current, props, key) {
1531
+ return current[key] ?? props?.[key];
1532
+ }
1533
+ function readStringProp(current, props, key) {
1534
+ const value = readProp(current, props, key);
1535
+ return typeof value === "string" ? value.trim() : "";
1536
+ }
1537
+ function extractOptionLabels(value) {
1538
+ if (!Array.isArray(value)) return null;
1539
+ const optionLabels = {};
1540
+ value.forEach((item) => {
1541
+ if (!item || typeof item !== "object") return;
1542
+ const option = item;
1543
+ if (typeof option.value !== "string" && typeof option.value !== "number" && typeof option.value !== "boolean") return;
1544
+ if (typeof option.label !== "string" || !option.label.trim()) return;
1545
+ optionLabels[String(option.value)] = option.label.trim();
1546
+ });
1547
+ return Object.keys(optionLabels).length ? optionLabels : null;
1548
+ }
1549
+ function extractPathFromRef(value) {
1550
+ if (typeof value === "string") {
1551
+ if (value.startsWith("$bind:/")) return value.slice("$bind:".length);
1552
+ if (value.startsWith("/")) return value;
1553
+ return null;
1554
+ }
1555
+ if (value && typeof value === "object" && typeof value.path === "string") {
1556
+ return value.path;
1557
+ }
1558
+ return null;
1559
+ }
1560
+ function collectComponentsMeta(node, metaByPath) {
1561
+ if (Array.isArray(node)) {
1562
+ node.forEach((item) => collectComponentsMeta(item, metaByPath));
1563
+ return;
1564
+ }
1565
+ if (!node || typeof node !== "object") return;
1566
+ const current = node;
1567
+ const props = current.props && typeof current.props === "object" ? current.props : null;
1568
+ const label = readStringProp(current, props, "label");
1569
+ const path = extractPathFromRef(readProp(current, props, "bind_path_token")) || extractPathFromRef(readProp(current, props, "value"));
1570
+ if (path) {
1571
+ const nextMeta = metaByPath[path] || {};
1572
+ if (label) {
1573
+ nextMeta.label = label;
1574
+ }
1575
+ const optionLabels = extractOptionLabels(readProp(current, props, "options"));
1576
+ if (optionLabels) {
1577
+ nextMeta.optionLabels = optionLabels;
1578
+ }
1579
+ if (typeof current.component === "string") {
1580
+ nextMeta.component = current.component;
1581
+ }
1582
+ metaByPath[path] = nextMeta;
1583
+ }
1584
+ const children = Array.isArray(current.children) ? current.children : [];
1585
+ children.forEach((child) => collectComponentsMeta(child, metaByPath));
1586
+ }
1587
+ function collectSurfaceMetaByPath(commands, surfaceId) {
1588
+ const metaByPath = {};
1589
+ commands.forEach((cmd) => {
1590
+ const update = cmd?.updateComponents;
1591
+ if (!update || update.surfaceId !== surfaceId) return;
1592
+ collectComponentsMeta(update.components, metaByPath);
1593
+ });
1594
+ return metaByPath;
1595
+ }
1596
+ function resolveDisplayValue(value, meta) {
1597
+ if (value === null || value === void 0 || value === "") return "";
1598
+ if (meta.optionLabels && Object.prototype.hasOwnProperty.call(meta.optionLabels, String(value))) {
1599
+ return meta.optionLabels[String(value)];
1600
+ }
1601
+ if (typeof value === "boolean") {
1602
+ return value ? "\u662F" : "\u5426";
1603
+ }
1604
+ if (Array.isArray(value)) {
1605
+ return value.map((item) => String(item)).join("\u3001");
1606
+ }
1607
+ if (typeof value === "object") {
1608
+ return JSON.stringify(value);
1609
+ }
1610
+ return String(value);
1611
+ }
1612
+ function collectActionDisplayMeta(commands, surfaceId, context) {
1613
+ const refs = context.refs && typeof context.refs === "object" && !Array.isArray(context.refs) ? context.refs : null;
1614
+ if (!surfaceId || !refs) return null;
1615
+ const values = context.values && typeof context.values === "object" && !Array.isArray(context.values) ? context.values : context;
1616
+ const metaByPath = collectSurfaceMetaByPath(commands, surfaceId);
1617
+ if (!Object.keys(metaByPath).length) return null;
1618
+ const labels = {};
1619
+ const valueLabels = {};
1620
+ Object.entries(refs).forEach(([key, ref]) => {
1621
+ const path = extractPathFromRef(ref);
1622
+ const meta = path ? metaByPath[path] : null;
1623
+ if (!meta) return;
1624
+ if (meta.label) {
1625
+ labels[key] = meta.label;
1626
+ }
1627
+ const displayValue = resolveDisplayValue(values[key], meta);
1628
+ if (displayValue) {
1629
+ valueLabels[key] = displayValue;
1630
+ }
1631
+ });
1632
+ return Object.keys(labels).length || Object.keys(valueLabels).length ? { labels, valueLabels } : null;
1633
+ }
1634
+
1635
+ // a2ui-runtime/controller/action.ts
1636
+ function extractPathFromRef2(value) {
1637
+ if (typeof value === "string") {
1638
+ if (value.startsWith("$bind:/")) return value.slice("$bind:".length);
1639
+ if (value.startsWith("/")) return value;
1640
+ return null;
1641
+ }
1642
+ if (value && typeof value === "object" && typeof value.path === "string") {
1643
+ const path = String(value.path || "");
1644
+ return path.startsWith("/") ? path : null;
1645
+ }
1646
+ return null;
1647
+ }
1648
+ function commonParentPath(paths) {
1649
+ const parents = paths.map((p) => {
1650
+ const idx = p.lastIndexOf("/");
1651
+ return idx > 0 ? p.slice(0, idx) : "";
1652
+ }).filter((p) => p.startsWith("/"));
1653
+ if (!parents.length) return "";
1654
+ const split = parents.map((p) => p.split("/").filter(Boolean));
1655
+ let prefix = split[0];
1656
+ for (let i = 1; i < split.length; i++) {
1657
+ const cur = split[i];
1658
+ let j = 0;
1659
+ while (j < prefix.length && j < cur.length && prefix[j] === cur[j]) j++;
1660
+ prefix = prefix.slice(0, j);
1661
+ if (!prefix.length) break;
1662
+ }
1663
+ return prefix.length ? `/${prefix.join("/")}` : "";
1664
+ }
1665
+ function inferModelPathFromContext(context) {
1666
+ const refs = context?.refs && typeof context.refs === "object" && !Array.isArray(context.refs) ? context.refs : null;
1667
+ if (!refs) return "";
1668
+ const paths = Object.values(refs).map((v) => extractPathFromRef2(v)).filter((p) => typeof p === "string" && p.startsWith("/"));
1669
+ return commonParentPath(paths);
1670
+ }
1671
+ function collectBindingPathsFromNode(node, paths) {
1672
+ if (Array.isArray(node)) {
1673
+ node.forEach((item) => collectBindingPathsFromNode(item, paths));
1674
+ return;
1675
+ }
1676
+ if (!node || typeof node !== "object") return;
1677
+ const current = node;
1678
+ const props = current.props && typeof current.props === "object" && !Array.isArray(current.props) ? current.props : null;
1679
+ const bindPath = extractPathFromRef2(current.bind_path_token) || extractPathFromRef2(current.value) || extractPathFromRef2(props?.bind_path_token) || extractPathFromRef2(props?.value);
1680
+ if (bindPath) {
1681
+ paths.push(bindPath);
1682
+ }
1683
+ const children = Array.isArray(current.children) ? current.children : [];
1684
+ children.forEach((child) => collectBindingPathsFromNode(child, paths));
1685
+ }
1686
+ function inferModelPathFromSurfaceCommands(surfaceId, commands) {
1687
+ if (!surfaceId) return "";
1688
+ const paths = [];
1689
+ commands.forEach((cmd) => {
1690
+ const update = cmd?.updateComponents;
1691
+ if (!update || update.surfaceId !== surfaceId) return;
1692
+ collectBindingPathsFromNode(update.components, paths);
1693
+ });
1694
+ return commonParentPath(paths);
1695
+ }
1696
+ function isSubmitLikeActionName(name) {
1697
+ const trimmed = typeof name === "string" ? name.trim() : "";
1698
+ return trimmed === "submit" || trimmed === "confirm" || trimmed.startsWith("submit_") || trimmed.endsWith(".confirm");
1699
+ }
1700
+ function isCancelLikeActionName(name) {
1701
+ const trimmed = typeof name === "string" ? name.trim() : "";
1702
+ return trimmed === "cancel" || trimmed === "qf.cancel" || trimmed.endsWith(".cancel");
1703
+ }
1704
+ function shouldOptimisticallyDismissSurface(actionName, context) {
1705
+ if (isSubmitLikeActionName(actionName) || isCancelLikeActionName(actionName)) return true;
1706
+ if (actionName === "qf.submit" || actionName === "qf.cancel") return true;
1707
+ const submitFlag = context?.submit;
1708
+ return submitFlag === true;
1709
+ }
1710
+ function buildDispatchContext(surfaceId, rawContext, commands) {
1711
+ let normalizedContext = normalizeActionContext(rawContext);
1712
+ let modelPath = normalizedContext?.model && typeof normalizedContext.model === "object" && typeof normalizedContext.model.path === "string" ? String(normalizedContext.model.path).trim() : "";
1713
+ if (!modelPath) {
1714
+ const inferredModelPath = inferModelPathFromContext(normalizedContext);
1715
+ if (inferredModelPath) {
1716
+ modelPath = inferredModelPath;
1717
+ normalizedContext = {
1718
+ ...normalizedContext,
1719
+ model: {
1720
+ ...normalizedContext.model && typeof normalizedContext.model === "object" ? normalizedContext.model : {},
1721
+ path: inferredModelPath
1722
+ }
1723
+ };
1724
+ }
1725
+ }
1726
+ if (!modelPath) {
1727
+ const inferredModelPath = inferModelPathFromSurfaceCommands(surfaceId, commands);
1728
+ if (inferredModelPath) {
1729
+ modelPath = inferredModelPath;
1730
+ normalizedContext = {
1731
+ ...normalizedContext,
1732
+ model: {
1733
+ ...normalizedContext.model && typeof normalizedContext.model === "object" ? normalizedContext.model : {},
1734
+ path: inferredModelPath
1735
+ }
1736
+ };
1737
+ }
1738
+ }
1739
+ if (modelPath) {
1740
+ const valuesFromStore = readModelValues(modelPath);
1741
+ const existingValues = normalizedContext.values && typeof normalizedContext.values === "object" && !Array.isArray(normalizedContext.values) ? normalizedContext.values : {};
1742
+ const mergedValues = { ...valuesFromStore, ...existingValues };
1743
+ if (Object.keys(mergedValues).length > 0) {
1744
+ const existingRefs = normalizedContext.refs && typeof normalizedContext.refs === "object" && !Array.isArray(normalizedContext.refs) ? normalizedContext.refs : {};
1745
+ const refs = { ...existingRefs };
1746
+ for (const key of Object.keys(mergedValues)) {
1747
+ if (refs[key] === void 0) {
1748
+ refs[key] = `$bind:${modelPath}/${key}`.replace(/\/{2,}/g, "/");
1749
+ }
1750
+ }
1751
+ normalizedContext = {
1752
+ ...normalizedContext,
1753
+ refs,
1754
+ values: mergedValues
1755
+ };
1756
+ }
1757
+ }
1758
+ const displayMeta = collectActionDisplayMeta(commands, surfaceId, normalizedContext);
1759
+ if (!displayMeta) return normalizedContext;
1760
+ return {
1761
+ ...normalizedContext,
1762
+ labels: {
1763
+ ...normalizedContext.labels && typeof normalizedContext.labels === "object" ? normalizedContext.labels : {},
1764
+ ...displayMeta.labels
1765
+ },
1766
+ valueLabels: {
1767
+ ...normalizedContext.valueLabels && typeof normalizedContext.valueLabels === "object" ? normalizedContext.valueLabels : {},
1768
+ ...displayMeta.valueLabels
1769
+ }
1770
+ };
1771
+ }
1772
+
1773
+ // a2ui-runtime/controller/visibility.ts
1774
+ function extractSurfaceId(cmd) {
1775
+ if (!cmd || typeof cmd !== "object") return "";
1776
+ return cmd.createSurface?.surfaceId ?? cmd.updateComponents?.surfaceId ?? cmd.updateDataModel?.surfaceId ?? cmd.deleteSurface?.surfaceId ?? "";
1777
+ }
1778
+ function resolveVisibleSurfaceIds(commands, dismissedSurfaceIds = []) {
1779
+ const states = /* @__PURE__ */ new Map();
1780
+ commands.forEach((cmd) => {
1781
+ const sid = extractSurfaceId(cmd);
1782
+ if (!sid) return;
1783
+ const prev = states.get(sid) || { deleted: false };
1784
+ if (cmd?.deleteSurface) {
1785
+ prev.deleted = true;
1786
+ } else if (cmd?.createSurface) {
1787
+ prev.deleted = false;
1788
+ }
1789
+ states.set(sid, prev);
1790
+ });
1791
+ return Array.from(states.entries()).filter(([sid, st]) => !st.deleted && !dismissedSurfaceIds.includes(sid)).map(([sid]) => sid);
1792
+ }
1793
+
1794
+ // a2ui-runtime/controller/wizard.ts
1795
+ function readString(obj, ...keys) {
1796
+ for (const k of keys) {
1797
+ const v = obj?.[k];
1798
+ if (typeof v === "string" && v.trim()) return v.trim();
1799
+ }
1800
+ return "";
1801
+ }
1802
+ function readOptionalString(obj, ...keys) {
1803
+ for (const k of keys) {
1804
+ const v = obj?.[k];
1805
+ if (typeof v === "string") return v;
1806
+ }
1807
+ return null;
1808
+ }
1809
+ function normalizeWizardSchema(schema) {
1810
+ if (!schema || typeof schema !== "object") return null;
1811
+ const raw = schema;
1812
+ const surfaceId = readString(raw, "surfaceId", "surface_id");
1813
+ const modelPath = readString(raw, "modelPath", "model_path");
1814
+ const submitEvent = readString(raw, "submitEvent", "submit_event");
1815
+ const stepsRaw = Array.isArray(raw.steps) ? raw.steps : [];
1816
+ if (!surfaceId || !modelPath || !submitEvent || !stepsRaw.length) return null;
1817
+ const steps = stepsRaw.map((s) => {
1818
+ if (!s || typeof s !== "object") return null;
1819
+ const stepObj = s;
1820
+ const stepId = readString(stepObj, "stepId", "step_id");
1821
+ if (!stepId) return null;
1822
+ const fieldsRaw = Array.isArray(stepObj.fields) ? stepObj.fields : [];
1823
+ const fields = fieldsRaw.map((f) => {
1824
+ if (!f || typeof f !== "object") return null;
1825
+ const fo = f;
1826
+ const key = readString(fo, "key");
1827
+ if (!key) return null;
1828
+ const type = readOptionalString(fo, "type");
1829
+ const label = readOptionalString(fo, "label");
1830
+ const placeholder = readOptionalString(fo, "placeholder");
1831
+ const required = typeof fo.required === "boolean" ? fo.required : fo.required === null || fo.required === void 0 ? null : !!fo.required;
1832
+ const options = Array.isArray(fo.options) ? fo.options : void 0;
1833
+ return {
1834
+ key,
1835
+ type,
1836
+ label,
1837
+ placeholder,
1838
+ required,
1839
+ options,
1840
+ default: fo.default
1841
+ };
1842
+ }).filter(Boolean);
1843
+ return {
1844
+ stepId,
1845
+ title: readOptionalString(stepObj, "title"),
1846
+ description: readOptionalString(stepObj, "description"),
1847
+ fields
1848
+ };
1849
+ }).filter(Boolean);
1850
+ if (!steps.length) return null;
1851
+ const nextEvent = readString(raw, "nextEvent", "next_event") || "wizard.next";
1852
+ const backEvent = readString(raw, "backEvent", "back_event") || "wizard.back";
1853
+ const labels = raw.labels && typeof raw.labels === "object" && !Array.isArray(raw.labels) ? raw.labels : null;
1854
+ return {
1855
+ version: readOptionalString(raw, "version") ?? void 0,
1856
+ surfaceId,
1857
+ modelPath,
1858
+ steps,
1859
+ submitEvent,
1860
+ nextEvent,
1861
+ backEvent,
1862
+ labels,
1863
+ title: readOptionalString(raw, "title"),
1864
+ description: readOptionalString(raw, "description")
1865
+ };
1866
+ }
1867
+ function buildWizardModelSeed(schema) {
1868
+ if (!schema?.modelPath) return null;
1869
+ const values = {};
1870
+ schema.steps.forEach((step) => {
1871
+ const fields = Array.isArray(step?.fields) ? step.fields : [];
1872
+ fields.forEach((field) => {
1873
+ const key = typeof field?.key === "string" ? field.key.trim() : "";
1874
+ if (!key || key in values || field?.default === void 0) return;
1875
+ values[key] = field.default;
1876
+ });
1877
+ });
1878
+ return { modelPath: schema.modelPath, values };
1879
+ }
1880
+ function pickWizardCurrentStepIdFromCommands(surfaceId, commands) {
1881
+ for (let i = commands.length - 1; i >= 0; i--) {
1882
+ const cmd = commands[i];
1883
+ const update = cmd?.updateComponents;
1884
+ if (!update || update.surfaceId !== surfaceId) continue;
1885
+ const components = Array.isArray(update.components) ? update.components : [];
1886
+ for (const c of components) {
1887
+ if (c?.component !== "Button") continue;
1888
+ const stepId = c?.action?.event?.context?.step_id;
1889
+ if (typeof stepId === "string" && stepId.trim()) return stepId.trim();
1890
+ }
1891
+ }
1892
+ return "";
1893
+ }
1894
+ function buildWizardComponents(schema, stepId) {
1895
+ const stepIndex = Math.max(
1896
+ 0,
1897
+ schema.steps.findIndex((s) => s?.stepId === stepId)
1898
+ );
1899
+ const step = schema.steps[stepIndex] || schema.steps[0];
1900
+ const resolvedStepId = typeof step?.stepId === "string" && step.stepId ? step.stepId : schema.steps[0]?.stepId;
1901
+ const fields = Array.isArray(step?.fields) ? step.fields : [];
1902
+ const modelPath = schema.modelPath;
1903
+ const rootChildren = ["title", "desc", "step-indicator", "step-title"];
1904
+ const nodes = [
1905
+ { component: "Column", id: "root", children: rootChildren },
1906
+ { component: "Text", id: "title", text: schema.title || "\u8868\u5355", variant: "h2" },
1907
+ { component: "Text", id: "desc", text: schema.description || "", variant: "caption" },
1908
+ { component: "Text", id: "step-indicator", text: `\u6B65\u9AA4 ${stepIndex + 1}/${schema.steps.length}`, variant: "caption" },
1909
+ { component: "Text", id: "step-title", text: step?.title || "", variant: "h3" }
1910
+ ];
1911
+ for (const f of fields) {
1912
+ if (!f || typeof f !== "object") continue;
1913
+ const key = typeof f.key === "string" ? f.key.trim() : "";
1914
+ if (!key) continue;
1915
+ const id = `f-${key}`;
1916
+ const bindPath = `${modelPath}/${key}`.replace(/\/{2,}/g, "/");
1917
+ rootChildren.push(id);
1918
+ const label = typeof f.label === "string" && f.label.trim() ? f.label.trim() : key;
1919
+ const placeholder = typeof f.placeholder === "string" ? f.placeholder : void 0;
1920
+ const type = typeof f.type === "string" ? f.type.toLowerCase() : "text";
1921
+ if (type === "select") {
1922
+ nodes.push({
1923
+ component: "Select",
1924
+ id,
1925
+ label,
1926
+ placeholder,
1927
+ options: Array.isArray(f.options) ? f.options : [],
1928
+ value: { path: bindPath },
1929
+ bind_path_token: `$bind:${bindPath}`
1930
+ });
1931
+ continue;
1932
+ }
1933
+ if (type === "switch") {
1934
+ nodes.push({
1935
+ component: "Switch",
1936
+ id,
1937
+ label,
1938
+ value: { path: bindPath },
1939
+ bind_path_token: `$bind:${bindPath}`
1940
+ });
1941
+ continue;
1942
+ }
1943
+ nodes.push({
1944
+ component: "TextField",
1945
+ id,
1946
+ label,
1947
+ placeholder,
1948
+ value: { path: bindPath },
1949
+ bind_path_token: `$bind:${bindPath}`
1950
+ });
1951
+ }
1952
+ rootChildren.push("divider", "actions");
1953
+ nodes.push({ component: "Divider", id: "divider" });
1954
+ nodes.push({ component: "Row", id: "actions", gap: 8, children: [] });
1955
+ const actions = nodes.find((n) => n.id === "actions");
1956
+ const actionChildren = [];
1957
+ actions.children = actionChildren;
1958
+ const backLabel = typeof schema.labels?.back === "string" && schema.labels.back.trim() ? schema.labels.back.trim() : "\u4E0A\u4E00\u6B65";
1959
+ const nextLabel = typeof schema.labels?.next === "string" && schema.labels.next.trim() ? schema.labels.next.trim() : "\u4E0B\u4E00\u6B65";
1960
+ const submitLabel = typeof schema.labels?.submit === "string" && schema.labels.submit.trim() ? schema.labels.submit.trim() : "\u63D0\u4EA4";
1961
+ if (stepIndex > 0) {
1962
+ actionChildren.push("btn-prev");
1963
+ nodes.push({
1964
+ component: "Button",
1965
+ id: "btn-prev",
1966
+ label: backLabel,
1967
+ variant: "default",
1968
+ action: { event: { name: schema.backEvent, context: { model: { path: modelPath }, step_id: resolvedStepId } } }
1969
+ });
1970
+ }
1971
+ const isLast = stepIndex >= schema.steps.length - 1;
1972
+ if (isLast) {
1973
+ actionChildren.push("btn-submit");
1974
+ nodes.push({
1975
+ component: "Button",
1976
+ id: "btn-submit",
1977
+ label: submitLabel,
1978
+ variant: "primary",
1979
+ action: { event: { name: schema.submitEvent, context: { model: { path: modelPath }, step_id: resolvedStepId } } }
1980
+ });
1981
+ } else {
1982
+ actionChildren.push("btn-next");
1983
+ nodes.push({
1984
+ component: "Button",
1985
+ id: "btn-next",
1986
+ label: nextLabel,
1987
+ variant: "primary",
1988
+ action: { event: { name: schema.nextEvent, context: { model: { path: modelPath }, step_id: resolvedStepId } } }
1989
+ });
1990
+ }
1991
+ return nodes;
1992
+ }
1993
+ function buildWizardUpdateComponentsCommand(schema, stepId) {
1994
+ return {
1995
+ updateComponents: {
1996
+ surfaceId: schema.surfaceId,
1997
+ components: buildWizardComponents(schema, stepId)
1998
+ },
1999
+ version: "v0.9"
2000
+ };
2001
+ }
2002
+
2003
+ // a2ui-runtime/controller/runtime.ts
2004
+ function createA2uiRuntimeState() {
2005
+ return {
2006
+ processedMessageCursors: [],
2007
+ serverCommands: [],
2008
+ localCommands: [],
2009
+ anchorIndexBySurface: {},
2010
+ wizardSchemaBySurface: {},
2011
+ latestCreateCommandIndexBySurface: {},
2012
+ initializedWizardRevisionBySurface: {},
2013
+ modelPathBySurface: {},
2014
+ wizardStepBySurface: {},
2015
+ optimisticallyDismissedSurfaceIds: [],
2016
+ lastA2uiHost: { id: "", index: -1 }
2017
+ };
2018
+ }
2019
+ function extractSurfaceId2(command) {
2020
+ if (!command || typeof command !== "object") return "";
2021
+ return String(
2022
+ command.createSurface?.surfaceId ?? command.updateComponents?.surfaceId ?? command.updateDataModel?.surfaceId ?? command.deleteSurface?.surfaceId ?? ""
2023
+ ).trim();
2024
+ }
2025
+ function getA2uiRuntimeCommands(state) {
2026
+ return [...state.serverCommands, ...state.localCommands];
2027
+ }
2028
+ function diffConversationMessages(messages, prevCursors) {
2029
+ if (messages.length < prevCursors.length) {
2030
+ return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
2031
+ }
2032
+ const nextCursors = [];
2033
+ const pendingItems = [];
2034
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
2035
+ const message3 = messages[messageIndex];
2036
+ const messageId = String(message3?.messageId ?? messageIndex);
2037
+ const items = Array.isArray(message3?.content) ? message3.content : [];
2038
+ const prevCursor = prevCursors[messageIndex];
2039
+ const startIndex = prevCursor ? prevCursor.contentLength : 0;
2040
+ if (prevCursor && (prevCursor.messageId !== messageId || items.length < prevCursor.contentLength)) {
2041
+ return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
2042
+ }
2043
+ for (let itemIndex = startIndex; itemIndex < items.length; itemIndex += 1) {
2044
+ pendingItems.push({ messageIndex, messageId, item: items[itemIndex] });
2045
+ }
2046
+ nextCursors.push({ messageId, contentLength: items.length });
2047
+ }
2048
+ return { shouldReplayAll: false, nextCursors, pendingItems };
2049
+ }
2050
+ function initializeWizardSurface(state, surfaceId, effects, nextWizardSteps) {
2051
+ const wizard = state.wizardSchemaBySurface[surfaceId];
2052
+ const createCommandIndex = state.latestCreateCommandIndexBySurface[surfaceId];
2053
+ const modelSeed = buildWizardModelSeed(wizard);
2054
+ if (!wizard || modelSeed === null || createCommandIndex === void 0) return;
2055
+ const revision = `${surfaceId}:${createCommandIndex}`;
2056
+ state.modelPathBySurface[surfaceId] = modelSeed.modelPath;
2057
+ if (state.initializedWizardRevisionBySurface[surfaceId] === revision) return;
2058
+ effects.push({ type: "clear-model", modelPath: modelSeed.modelPath });
2059
+ effects.push({ type: "write-model", modelPath: modelSeed.modelPath, values: modelSeed.values });
2060
+ state.initializedWizardRevisionBySurface[surfaceId] = revision;
2061
+ const firstStepId = wizard.steps[0]?.stepId;
2062
+ if (typeof firstStepId === "string" && firstStepId.trim()) {
2063
+ nextWizardSteps[surfaceId] = firstStepId.trim();
2064
+ }
2065
+ }
2066
+ function reduceA2uiRuntimeMessages(state, messages) {
2067
+ const { shouldReplayAll, pendingItems, nextCursors } = diffConversationMessages(messages || [], state.processedMessageCursors);
2068
+ const itemsToProcess = shouldReplayAll ? messages.flatMap((message3, messageIndex) => {
2069
+ const messageId = String(message3?.messageId ?? messageIndex);
2070
+ const items = Array.isArray(message3?.content) ? message3.content : [];
2071
+ return items.map((item) => ({ messageIndex, messageId, item }));
2072
+ }) : pendingItems;
2073
+ if (!shouldReplayAll && itemsToProcess.length === 0) {
2074
+ return { state, effects: [] };
2075
+ }
2076
+ const nextState = shouldReplayAll ? createA2uiRuntimeState() : { ...state };
2077
+ nextState.processedMessageCursors = shouldReplayAll ? [] : [...state.processedMessageCursors];
2078
+ nextState.serverCommands = shouldReplayAll ? [] : [...state.serverCommands];
2079
+ nextState.localCommands = shouldReplayAll ? [] : [...state.localCommands];
2080
+ nextState.anchorIndexBySurface = shouldReplayAll ? {} : { ...state.anchorIndexBySurface };
2081
+ nextState.wizardSchemaBySurface = shouldReplayAll ? {} : { ...state.wizardSchemaBySurface };
2082
+ nextState.latestCreateCommandIndexBySurface = shouldReplayAll ? {} : { ...state.latestCreateCommandIndexBySurface };
2083
+ nextState.initializedWizardRevisionBySurface = shouldReplayAll ? {} : { ...state.initializedWizardRevisionBySurface };
2084
+ nextState.modelPathBySurface = shouldReplayAll ? {} : { ...state.modelPathBySurface };
2085
+ nextState.wizardStepBySurface = shouldReplayAll ? {} : { ...state.wizardStepBySurface };
2086
+ nextState.optimisticallyDismissedSurfaceIds = shouldReplayAll ? [] : [...state.optimisticallyDismissedSurfaceIds];
2087
+ nextState.lastA2uiHost = shouldReplayAll ? { id: "", index: -1 } : { ...state.lastA2uiHost };
2088
+ const effects = shouldReplayAll ? [{ type: "reset-model-store" }] : [];
2089
+ const deletedSurfaceIds = /* @__PURE__ */ new Set();
2090
+ const nextWizardSteps = {};
2091
+ itemsToProcess.forEach(({ item, messageIndex, messageId }) => {
2092
+ if (item?.type === "a2uiSchema") {
2093
+ const schema = normalizeWizardSchema(item.schema);
2094
+ if (schema) {
2095
+ nextState.wizardSchemaBySurface[schema.surfaceId] = schema;
2096
+ initializeWizardSurface(nextState, schema.surfaceId, effects, nextWizardSteps);
2097
+ }
2098
+ return;
2099
+ }
2100
+ if (item?.type !== "a2uiCommand" || !item.command) return;
2101
+ nextState.serverCommands.push(item.command);
2102
+ nextState.lastA2uiHost = { id: messageId, index: messageIndex };
2103
+ const surfaceId = extractSurfaceId2(item.command);
2104
+ if (!surfaceId) return;
2105
+ if (nextState.anchorIndexBySurface[surfaceId] === void 0 && !item.command?.deleteSurface) {
2106
+ nextState.anchorIndexBySurface[surfaceId] = messageIndex;
2107
+ }
2108
+ if (item.command?.createSurface) {
2109
+ nextState.latestCreateCommandIndexBySurface[surfaceId] = nextState.serverCommands.length - 1;
2110
+ initializeWizardSurface(nextState, surfaceId, effects, nextWizardSteps);
2111
+ }
2112
+ if (item.command?.deleteSurface) {
2113
+ deletedSurfaceIds.add(surfaceId);
2114
+ const modelPath = nextState.modelPathBySurface[surfaceId];
2115
+ if (modelPath) effects.push({ type: "clear-model", modelPath });
2116
+ delete nextState.initializedWizardRevisionBySurface[surfaceId];
2117
+ delete nextState.modelPathBySurface[surfaceId];
2118
+ }
2119
+ });
2120
+ nextState.processedMessageCursors = shouldReplayAll ? messages.map((message3, messageIndex) => ({
2121
+ messageId: String(message3?.messageId ?? messageIndex),
2122
+ contentLength: Array.isArray(message3?.content) ? message3.content.length : 0
2123
+ })) : nextCursors;
2124
+ nextState.wizardStepBySurface = { ...nextState.wizardStepBySurface, ...nextWizardSteps };
2125
+ if (deletedSurfaceIds.size) {
2126
+ nextState.optimisticallyDismissedSurfaceIds = nextState.optimisticallyDismissedSurfaceIds.filter((surfaceId) => !deletedSurfaceIds.has(surfaceId));
2127
+ nextState.wizardStepBySurface = Object.fromEntries(
2128
+ Object.entries(nextState.wizardStepBySurface).filter(([surfaceId]) => !deletedSurfaceIds.has(surfaceId))
2129
+ );
2130
+ nextState.localCommands = nextState.localCommands.filter(
2131
+ (cmd) => !deletedSurfaceIds.has(String(cmd?.updateComponents?.surfaceId || cmd?.updateDataModel?.surfaceId || ""))
2132
+ );
2133
+ }
2134
+ return { state: nextState, effects };
2135
+ }
2136
+ function reduceA2uiRuntimeAction(state, input) {
2137
+ const { surfaceId, actionName, rawContext } = input;
2138
+ if (!surfaceId) {
2139
+ return { state, handled: actionName === "wizard.next" || actionName === "wizard.back" };
2140
+ }
2141
+ const wizard = state.wizardSchemaBySurface[surfaceId];
2142
+ if (wizard) {
2143
+ const isNext = actionName === wizard.nextEvent;
2144
+ const isBack = actionName === wizard.backEvent;
2145
+ if (isNext || isBack) {
2146
+ const commands = getA2uiRuntimeCommands(state);
2147
+ const fallbackStepId = pickWizardCurrentStepIdFromCommands(surfaceId, commands) || wizard.steps[0]?.stepId || "";
2148
+ const currentStepId = state.wizardStepBySurface[surfaceId] || fallbackStepId;
2149
+ const currentIndex = wizard.steps.findIndex((step) => step?.stepId === currentStepId);
2150
+ const baseIndex = currentIndex >= 0 ? currentIndex : 0;
2151
+ const nextIndex = isNext ? baseIndex + 1 : baseIndex - 1;
2152
+ const nextStepId = wizard.steps[nextIndex]?.stepId;
2153
+ if (!nextStepId) return { state, handled: true };
2154
+ return {
2155
+ state: {
2156
+ ...state,
2157
+ wizardStepBySurface: { ...state.wizardStepBySurface, [surfaceId]: nextStepId },
2158
+ localCommands: [...state.localCommands, buildWizardUpdateComponentsCommand(wizard, nextStepId)]
2159
+ },
2160
+ handled: true
2161
+ };
2162
+ }
2163
+ }
2164
+ if (actionName === "wizard.next" || actionName === "wizard.back") {
2165
+ return { state, handled: true };
2166
+ }
2167
+ if (!shouldOptimisticallyDismissSurface(actionName, rawContext)) {
2168
+ return { state, handled: false };
2169
+ }
2170
+ if (state.optimisticallyDismissedSurfaceIds.includes(surfaceId)) {
2171
+ return { state, handled: false };
2172
+ }
2173
+ return {
2174
+ state: {
2175
+ ...state,
2176
+ optimisticallyDismissedSurfaceIds: [...state.optimisticallyDismissedSurfaceIds, surfaceId]
2177
+ },
2178
+ handled: false
2179
+ };
2180
+ }
2181
+ function selectA2uiRuntimeView(state, dismissedSurfaceIds) {
2182
+ const mergedDismissedSurfaceIds = Array.from(
2183
+ new Set([...dismissedSurfaceIds || [], ...state.optimisticallyDismissedSurfaceIds].filter((surfaceId) => surfaceId?.trim?.()))
2184
+ );
2185
+ const commands = getA2uiRuntimeCommands(state);
2186
+ const visibleSurfaceIds = resolveVisibleSurfaceIds(commands, mergedDismissedSurfaceIds);
2187
+ const anchoredSurfaceIdsByMessageIndex = {};
2188
+ visibleSurfaceIds.forEach((surfaceId) => {
2189
+ const messageIndex = state.anchorIndexBySurface[surfaceId];
2190
+ if (typeof messageIndex !== "number" || messageIndex < 0) return;
2191
+ if (!anchoredSurfaceIdsByMessageIndex[messageIndex]) anchoredSurfaceIdsByMessageIndex[messageIndex] = [];
2192
+ anchoredSurfaceIdsByMessageIndex[messageIndex].push(surfaceId);
2193
+ });
2194
+ return {
2195
+ commands,
2196
+ visibleSurfaceIds,
2197
+ lastA2uiHostMessageId: state.lastA2uiHost.id,
2198
+ lastA2uiHostMessageIndex: state.lastA2uiHost.index,
2199
+ anchoredSurfaceIdsByMessageIndex
2200
+ };
2201
+ }
2202
+
2203
+ // a2ui-runtime/controller/index.ts
2204
+ function applyA2uiRuntimeEffects(effects) {
2205
+ effects.forEach((effect) => {
2206
+ if (effect.type === "reset-model-store") {
2207
+ clearAllModelValues();
2208
+ return;
2209
+ }
2210
+ if (effect.type === "clear-model") {
2211
+ clearModelValues(effect.modelPath);
2212
+ return;
2213
+ }
2214
+ writeModelValues(effect.modelPath, effect.values);
2215
+ });
2216
+ }
2217
+ function useA2uiController(params) {
2218
+ const { conversationId, conversationMessages, dismissedSurfaceIds } = params;
2219
+ const runtimeRef = React9.useRef(createA2uiRuntimeState());
2220
+ const [runtimeState, setRuntimeState] = React9.useState(() => createA2uiRuntimeState());
2221
+ React9.useEffect(() => {
2222
+ const nextState = createA2uiRuntimeState();
2223
+ runtimeRef.current = nextState;
2224
+ setRuntimeState(nextState);
2225
+ clearAllModelValues();
2226
+ }, [conversationId]);
2227
+ React9.useEffect(() => {
2228
+ const result = reduceA2uiRuntimeMessages(runtimeRef.current, conversationMessages || []);
2229
+ if (result.state === runtimeRef.current && result.effects.length === 0) return;
2230
+ runtimeRef.current = result.state;
2231
+ applyA2uiRuntimeEffects(result.effects);
2232
+ setRuntimeState(result.state);
2233
+ }, [conversationMessages, conversationId]);
2234
+ const view = React9.useMemo(() => selectA2uiRuntimeView(runtimeState, dismissedSurfaceIds), [runtimeState, dismissedSurfaceIds]);
2235
+ const handleRuntimeAction = React9.useCallback((payload) => {
2236
+ const surfaceId = String(payload?.surfaceId || payload?.cardId || "");
2237
+ const name = String(payload?.name || payload?.event?.name || "").trim();
2238
+ const rawContext = payload?.context || payload?.event?.context || {};
2239
+ const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name, rawContext });
2240
+ if (runtimeActionResult.state !== runtimeRef.current) {
2241
+ runtimeRef.current = runtimeActionResult.state;
2242
+ setRuntimeState(runtimeActionResult.state);
2243
+ }
2244
+ return { handled: runtimeActionResult.handled, name, surfaceId, rawContext };
2245
+ }, []);
2246
+ return {
2247
+ runtimeState,
2248
+ commands: view.commands,
2249
+ visibleSurfaceIds: view.visibleSurfaceIds,
2250
+ lastA2uiHostMessageId: view.lastA2uiHostMessageId,
2251
+ lastA2uiHostMessageIndex: view.lastA2uiHostMessageIndex,
2252
+ anchoredSurfaceIdsByMessageIndex: view.anchoredSurfaceIdsByMessageIndex,
2253
+ handleRuntimeAction
2254
+ };
2255
+ }
2256
+ var A2uiRuntimeContext = React9__default.default.createContext({
2257
+ commands: [],
2258
+ onAction: () => void 0,
2259
+ surfaceIdsByMessageIndex: {}
2260
+ });
2261
+
2262
+ // a2ui-runtime/renderer/useA2uiRuntimeView.ts
2263
+ function useA2uiRuntimeView() {
2264
+ return React9__default.default.useContext(A2uiRuntimeContext);
2265
+ }
2266
+ function A2uiMessageCards({ messageIndex }) {
2267
+ const { surfaceIdsByMessageIndex } = useA2uiRuntimeView();
2268
+ const surfaceIds = surfaceIdsByMessageIndex[messageIndex] || [];
2269
+ if (!surfaceIds.length) return null;
2270
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: surfaceIds.map((surfaceId) => /* @__PURE__ */ jsxRuntime.jsx(XCard.Card, { id: surfaceId }, surfaceId)) });
2271
+ }
2272
+
2273
+ // a2ui-runtime/renderer/protocol.ts
2274
+ function isSubmitLikeActionName2(name) {
2275
+ const normalized = String(name || "").trim();
2276
+ return normalized === "submit" || normalized === "confirm" || normalized.startsWith("submit_") || normalized.endsWith(".confirm");
2277
+ }
2278
+ function isCancelLikeActionName2(name) {
2279
+ const normalized = String(name || "").trim();
2280
+ return normalized === "cancel" || normalized === "qf.cancel" || normalized.endsWith(".cancel");
2281
+ }
2282
+ function shouldDismissA2uiSurface(name, context) {
2283
+ if (isSubmitLikeActionName2(name) || isCancelLikeActionName2(name)) return true;
2284
+ if (name === "qf.submit" || name === "qf.cancel") return true;
2285
+ return context?.submit === true;
2286
+ }
2287
+ function normalizeA2uiActionPayload(payload) {
2288
+ return {
2289
+ name: String(payload?.name || "").trim(),
2290
+ surfaceId: String(payload?.surfaceId || "").trim(),
2291
+ context: payload?.context && typeof payload.context === "object" && !Array.isArray(payload.context) ? payload.context : {}
2292
+ };
2293
+ }
2294
+ function formatA2uiActionMessage(payload) {
2295
+ const normalized = normalizeA2uiActionPayload(payload);
2296
+ return JSON.stringify({
2297
+ type: "a2ui_action.v1",
2298
+ name: normalized.name,
2299
+ surfaceId: normalized.surfaceId,
2300
+ context: normalized.context
2301
+ });
2302
+ }
2303
+ function parseA2uiActionMessage(content) {
2304
+ if (typeof content !== "string") return null;
2305
+ const trimmed = content.trim();
2306
+ if (!trimmed.startsWith("{") || !trimmed.includes('"a2ui_action.v1"')) return null;
2307
+ try {
2308
+ const parsed = JSON.parse(trimmed);
2309
+ if (parsed?.type !== "a2ui_action.v1") return null;
2310
+ return normalizeA2uiActionPayload(parsed);
2311
+ } catch {
2312
+ return null;
2313
+ }
2314
+ }
2315
+ function isQuestionActionPayload(payload) {
2316
+ const mode = payload.context?.form_mode;
2317
+ if (payload.name === "qf.submit" || payload.name === "qf.cancel") return true;
2318
+ if (payload.name.startsWith("qf.")) return true;
2319
+ return typeof mode === "string" && mode.toLowerCase() === "ephemeral" ? isSubmitLikeActionName2(payload.name) || isCancelLikeActionName2(payload.name) : false;
2320
+ }
2321
+ function formatActionValue(value, displayOverride) {
2322
+ if (typeof displayOverride === "string" && displayOverride.trim()) return displayOverride.trim();
2323
+ if (typeof value === "boolean") return value ? "\u662F" : "\u5426";
2324
+ if (Array.isArray(value)) return value.map((item) => String(item)).join("\u3001");
2325
+ if (value && typeof value === "object") return JSON.stringify(value);
2326
+ return String(value);
2327
+ }
2328
+ function buildQuestionSummary(payload) {
2329
+ if (isCancelLikeActionName2(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
2330
+ const values = payload.context.values && typeof payload.context.values === "object" && !Array.isArray(payload.context.values) ? payload.context.values : payload.context;
2331
+ const labels = payload.context.labels && typeof payload.context.labels === "object" && !Array.isArray(payload.context.labels) ? payload.context.labels : {};
2332
+ const valueLabels = payload.context.valueLabels && typeof payload.context.valueLabels === "object" && !Array.isArray(payload.context.valueLabels) ? payload.context.valueLabels : {};
2333
+ const details = Object.entries(values).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([key, value]) => {
2334
+ const label = typeof labels[key] === "string" && String(labels[key]).trim() ? String(labels[key]).trim() : key;
2335
+ return `${label}: ${formatActionValue(value, valueLabels[key])}`;
2336
+ });
2337
+ return details.length ? `Question: ${details.join("\uFF1B ")}` : "Question: \u5DF2\u56DE\u7B54";
2338
+ }
2339
+ function formatA2uiActionDisplayText(payload) {
2340
+ if (isQuestionActionPayload(payload)) return buildQuestionSummary(payload);
2341
+ const values = payload.context.values && typeof payload.context.values === "object" && !Array.isArray(payload.context.values) ? payload.context.values : payload.context;
2342
+ const labels = payload.context.labels && typeof payload.context.labels === "object" && !Array.isArray(payload.context.labels) ? payload.context.labels : {};
2343
+ const valueLabels = payload.context.valueLabels && typeof payload.context.valueLabels === "object" && !Array.isArray(payload.context.valueLabels) ? payload.context.valueLabels : {};
2344
+ const actionLabels = {
2345
+ submit_basic: "\u5DF2\u63D0\u4EA4\u57FA\u7840\u4FE1\u606F",
2346
+ submit_params: "\u5DF2\u63D0\u4EA4\u53C2\u6570\u914D\u7F6E",
2347
+ back_to_basic: "\u5DF2\u8FD4\u56DE\u4FEE\u6539\u57FA\u7840\u4FE1\u606F",
2348
+ back_to_params: "\u5DF2\u8FD4\u56DE\u4FEE\u6539\u53C2\u6570",
2349
+ confirm: "\u5DF2\u786E\u8BA4\u521B\u5EFA"
2350
+ };
2351
+ const actionLabel = actionLabels[payload.name] || `\u5DF2\u63D0\u4EA4\u52A8\u4F5C (${payload.name})`;
2352
+ const details = Object.entries(values).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([key, value]) => {
2353
+ const label = typeof labels[key] === "string" && String(labels[key]).trim() ? String(labels[key]).trim() : key;
2354
+ return `${label}: ${formatActionValue(value, valueLabels[key])}`;
2355
+ });
2356
+ return details.length ? `${actionLabel}\uFF1A${details.join("\uFF1B ")}` : actionLabel;
2357
+ }
2358
+ function toA2uiDisplayText(role, content) {
2359
+ if (role !== 1) return content || "";
2360
+ const payload = parseA2uiActionMessage(content);
2361
+ return payload ? formatA2uiActionDisplayText(payload) : content || "";
2362
+ }
2363
+ function shouldHideA2uiPlan(item) {
2364
+ if (!item.plan || typeof item.plan !== "object") return false;
2365
+ const rawPlan = item.plan;
2366
+ const candidates = [rawPlan, rawPlan.plan].filter((plan) => !!plan && typeof plan === "object");
2367
+ return candidates.some((plan) => {
2368
+ const kind = typeof plan.kind === "string" ? plan.kind.toLowerCase() : "";
2369
+ const surfaceId = typeof plan.surface_id === "string" ? plan.surface_id : "";
2370
+ return (kind === "form" || kind === "wizard" || kind === "dashboard") && !!surfaceId;
2371
+ });
2372
+ }
2373
+ function formatMixedContent2(content) {
2374
+ return content.replace(/<!DOCTYPE html>[\s\S]*?<\/html>/gi, (match) => `\`\`\`html
2375
+ ${match}
2376
+ \`\`\``);
2377
+ }
2378
+ function extractPlanPayload(plan) {
2379
+ if (!plan || typeof plan !== "object") return null;
2380
+ const raw = plan;
2381
+ return raw.plan && typeof raw.plan === "object" ? raw.plan : raw;
2382
+ }
2383
+ function normalizeTableColumns(columns) {
2384
+ if (!Array.isArray(columns)) return [];
2385
+ return columns.map((column) => ({
2386
+ title: String(column?.title ?? ""),
2387
+ dataIndex: String(column?.dataIndex ?? column?.data_index ?? "")
2388
+ })).filter((column) => column.dataIndex);
2389
+ }
2390
+ function renderArtifact(artifact, index) {
2391
+ const ReportViewer2 = A2uiComponents.ReportViewer;
2392
+ const ChartViewer2 = A2uiComponents.ChartViewer;
2393
+ const TableViewer2 = A2uiComponents.TableViewer;
2394
+ const ArtifactCard2 = A2uiComponents.ArtifactCard;
2395
+ const type = String(artifact?.type ?? "").toLowerCase();
2396
+ const artifactId = String(artifact?.artifact_id ?? artifact?.artifactId ?? `artifact_${index}`);
2397
+ const title = typeof artifact?.title === "string" ? artifact.title : void 0;
2398
+ if (type === "report") {
2399
+ return /* @__PURE__ */ jsxRuntime.jsx(ReportViewer2, { artifactId, title, payload: { markdown: artifact?.markdown } }, artifactId);
2400
+ }
2401
+ if (type === "chart") {
2402
+ return /* @__PURE__ */ jsxRuntime.jsx(ChartViewer2, { artifactId, title, payload: artifact }, artifactId);
2403
+ }
2404
+ if (type === "table") {
2405
+ return /* @__PURE__ */ jsxRuntime.jsx(
2406
+ TableViewer2,
2407
+ {
2408
+ artifactId,
2409
+ title,
2410
+ payload: { columns: normalizeTableColumns(artifact?.columns), rows: Array.isArray(artifact?.rows) ? artifact.rows : [] }
2411
+ },
2412
+ artifactId
2413
+ );
2414
+ }
2415
+ return /* @__PURE__ */ jsxRuntime.jsx(ArtifactCard2, { type: type || "artifact", artifactId, title, payload: artifact }, artifactId);
2416
+ }
2417
+ function ViewerPlan({ payload }) {
2418
+ const artifacts = Array.isArray(payload.artifacts) ? payload.artifacts : [];
2419
+ if (!artifacts.length) return null;
2420
+ const title = typeof payload.title === "string" ? payload.title.trim() : "";
2421
+ const description = typeof payload.description === "string" ? payload.description.trim() : "";
2422
+ const header = title || description ? `### ${title || "\u62A5\u544A"}
2423
+
2424
+ ${description || ""}`.trim() : "";
2425
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2426
+ header ? /* @__PURE__ */ jsxRuntime.jsx(
2427
+ XMarkdown__default.default,
2428
+ {
2429
+ openLinksInNewTab: true,
2430
+ className: classNames7__default.default("x-markdown-light", "xMarkdownStyle"),
2431
+ components: { code: code_highlight_default, agentnavigate: agent_navigate_default },
2432
+ config: getMarkdownConfig(),
2433
+ content: formatMixedContent2(header)
2434
+ }
2435
+ ) : null,
2436
+ artifacts.map((artifact, index) => renderArtifact(artifact, index))
2437
+ ] });
2438
+ }
2439
+ function A2uiPlanNode({ item }) {
2440
+ if (!item || shouldHideA2uiPlan(item)) return null;
2441
+ const payload = extractPlanPayload(item.plan);
2442
+ const isViewer = typeof payload?.kind === "string" && payload.kind.toLowerCase() === "viewer";
2443
+ if (payload && isViewer) {
2444
+ return /* @__PURE__ */ jsxRuntime.jsx(ViewerPlan, { payload });
2445
+ }
2446
+ const title = item.title ? `### ${item.title}
2447
+
2448
+ ` : "";
2449
+ const content = typeof item.content === "string" ? item.content : item.plan ? `\`\`\`json
2450
+ ${JSON.stringify(item.plan, null, 2)}
2451
+ \`\`\`` : "";
2452
+ if (!title && !content) return null;
2453
+ return /* @__PURE__ */ jsxRuntime.jsx(
2454
+ XMarkdown__default.default,
2455
+ {
2456
+ openLinksInNewTab: true,
2457
+ className: classNames7__default.default("x-markdown-light", "xMarkdownStyle"),
2458
+ components: { code: code_highlight_default, agentnavigate: agent_navigate_default },
2459
+ config: getMarkdownConfig(),
2460
+ content: formatMixedContent2(`${title}${content}`)
2461
+ }
2462
+ );
2463
+ }
2464
+ function extractSurfaceId3(command) {
2465
+ if (!command || typeof command !== "object") return "";
2466
+ const current = command;
2467
+ return String(
2468
+ current.createSurface?.surfaceId ?? current.updateComponents?.surfaceId ?? current.updateDataModel?.surfaceId ?? current.deleteSurface?.surfaceId ?? ""
2469
+ ).trim();
2470
+ }
2471
+ function readContextModelPath(context) {
2472
+ const path = context?.model && typeof context.model === "object" ? context.model.path : "";
2473
+ return typeof path === "string" ? path.trim() : "";
2474
+ }
2475
+ function diffMessages(messages, prevCursors) {
2476
+ if (messages.length < prevCursors.length) {
2477
+ return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
2478
+ }
2479
+ const nextCursors = [];
2480
+ const pendingItems = [];
2481
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
2482
+ const message3 = messages[messageIndex];
2483
+ const messageId = String(message3?.messageId ?? messageIndex);
2484
+ const items = Array.isArray(message3?.content) ? message3.content : [];
2485
+ const prevCursor = prevCursors[messageIndex];
2486
+ const startIndex = prevCursor ? prevCursor.contentLength : 0;
2487
+ if (prevCursor && (prevCursor.messageId !== messageId || items.length < prevCursor.contentLength)) {
2488
+ return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
2489
+ }
2490
+ for (let itemIndex = startIndex; itemIndex < items.length; itemIndex += 1) {
2491
+ pendingItems.push({ item: items[itemIndex] });
2492
+ }
2493
+ nextCursors.push({ messageId, contentLength: items.length });
2494
+ }
2495
+ return { shouldReplayAll: false, nextCursors, pendingItems };
2496
+ }
2497
+ function A2uiRuntimeProvider({ messages, children }) {
2498
+ const chatStore = useChatStore();
2499
+ const conversationState = valtio.useSnapshot(chatStore.conversation);
2500
+ const conversationId = conversationState.active.id;
2501
+ const processedMessageCursorsRef = React9__default.default.useRef([]);
2502
+ const latestCommandIndexBySurfaceRef = React9__default.default.useRef({});
2503
+ const commandIndexRef = React9__default.default.useRef(-1);
2504
+ const [latestCommandIndexBySurface, setLatestCommandIndexBySurface] = React9__default.default.useState({});
2505
+ const [dismissedAtBySurface, setDismissedAtBySurface] = React9__default.default.useState({});
2506
+ React9__default.default.useEffect(() => {
2507
+ processedMessageCursorsRef.current = [];
2508
+ latestCommandIndexBySurfaceRef.current = {};
2509
+ commandIndexRef.current = -1;
2510
+ setLatestCommandIndexBySurface({});
2511
+ setDismissedAtBySurface({});
2512
+ }, [conversationId]);
2513
+ React9__default.default.useEffect(() => {
2514
+ const { shouldReplayAll, nextCursors, pendingItems } = diffMessages(messages, processedMessageCursorsRef.current);
2515
+ const itemsToProcess = shouldReplayAll ? messages.flatMap((message3) => {
2516
+ const items = Array.isArray(message3?.content) ? message3.content : [];
2517
+ return items.map((item) => ({ item }));
2518
+ }) : pendingItems;
2519
+ if (!shouldReplayAll && itemsToProcess.length === 0) return;
2520
+ const nextLatestCommandIndexBySurface = shouldReplayAll ? {} : { ...latestCommandIndexBySurfaceRef.current };
2521
+ let nextCommandIndex = shouldReplayAll ? -1 : commandIndexRef.current;
2522
+ itemsToProcess.forEach(({ item }) => {
2523
+ if (item?.type !== "a2uiCommand" || !item.command) return;
2524
+ nextCommandIndex += 1;
2525
+ const surfaceId = extractSurfaceId3(item.command);
2526
+ if (surfaceId) nextLatestCommandIndexBySurface[surfaceId] = nextCommandIndex;
2527
+ });
2528
+ processedMessageCursorsRef.current = shouldReplayAll ? messages.map((message3, messageIndex) => ({
2529
+ messageId: String(message3?.messageId ?? messageIndex),
2530
+ contentLength: Array.isArray(message3?.content) ? message3.content.length : 0
2531
+ })) : nextCursors;
2532
+ latestCommandIndexBySurfaceRef.current = nextLatestCommandIndexBySurface;
2533
+ commandIndexRef.current = nextCommandIndex;
2534
+ setLatestCommandIndexBySurface(nextLatestCommandIndexBySurface);
2535
+ }, [messages]);
2536
+ const dismissedSurfaceIds = React9__default.default.useMemo(() => {
2537
+ return Object.entries(dismissedAtBySurface).filter(([surfaceId, dismissedAt]) => (latestCommandIndexBySurface[surfaceId] ?? -1) <= dismissedAt).map(([surfaceId]) => surfaceId);
2538
+ }, [dismissedAtBySurface, latestCommandIndexBySurface]);
2539
+ const dispatchA2uiAction = React9__default.default.useCallback(
2540
+ async (payload) => {
2541
+ const actionPayload = normalizeA2uiActionPayload(payload);
2542
+ if (!actionPayload.name) return;
2543
+ if (actionPayload.surfaceId && shouldDismissA2uiSurface(actionPayload.name, actionPayload.context)) {
2544
+ const latestIndex = latestCommandIndexBySurface[actionPayload.surfaceId] ?? Number.MAX_SAFE_INTEGER;
2545
+ setDismissedAtBySurface((prev) => ({ ...prev, [actionPayload.surfaceId]: latestIndex }));
2546
+ }
2547
+ try {
2548
+ await chatStore.config.hooks?.onA2uiAction?.(actionPayload);
2549
+ } catch (error) {
2550
+ console.error("A2UI action hook failed:", error);
2551
+ }
2552
+ try {
2553
+ await chatStore.sendMessage(formatA2uiActionMessage(actionPayload));
2554
+ } catch (error) {
2555
+ console.error("A2UI action send failed:", error);
2556
+ antd.message.error("\u63D0\u4EA4\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
2557
+ }
2558
+ },
2559
+ [chatStore, latestCommandIndexBySurface]
2560
+ );
2561
+ const { runtimeState, commands, anchoredSurfaceIdsByMessageIndex, handleRuntimeAction } = useA2uiController({
2562
+ conversationId,
2563
+ conversationMessages: messages,
2564
+ dismissedSurfaceIds
2565
+ });
2566
+ const onAction = React9__default.default.useCallback(
2567
+ (payload) => {
2568
+ const result = handleRuntimeAction(payload);
2569
+ if (result.handled || !result.name) return;
2570
+ const nextContext = buildDispatchContext(result.surfaceId, result.rawContext, commands);
2571
+ void dispatchA2uiAction({ name: result.name, surfaceId: result.surfaceId, context: nextContext });
2572
+ if (shouldOptimisticallyDismissSurface(result.name, result.rawContext)) {
2573
+ const modelPath = readContextModelPath(nextContext) || readContextModelPath(result.rawContext) || runtimeState.modelPathBySurface[result.surfaceId];
2574
+ if (modelPath) clearModelValues(modelPath);
2575
+ }
2576
+ },
2577
+ [commands, dispatchA2uiAction, handleRuntimeAction, runtimeState.modelPathBySurface]
2578
+ );
2579
+ const contextValue = React9__default.default.useMemo(
2580
+ () => ({ commands, onAction, surfaceIdsByMessageIndex: anchoredSurfaceIdsByMessageIndex }),
2581
+ [anchoredSurfaceIdsByMessageIndex, commands, onAction]
2582
+ );
2583
+ return /* @__PURE__ */ jsxRuntime.jsx(A2uiRuntimeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(XCard.Box, { commands, components: A2uiComponents, onAction, children }) });
2584
+ }
2585
+ function A2uiRenderer(props) {
2586
+ return /* @__PURE__ */ jsxRuntime.jsx(A2uiRuntimeProvider, { ...props });
2587
+ }
2588
+ function formatMixedContent3(content) {
2589
+ return content.replace(/<!DOCTYPE html>[\s\S]*?<\/html>/gi, (match) => `\`\`\`html
2590
+ ${match}
2591
+ \`\`\``);
2592
+ }
2593
+ function QuestionSummary({ content }) {
2594
+ const answer = content.replace(/^Question:\s*/, "").trim() || "\u5DF2\u56DE\u7B54";
2595
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", flexDirection: "column", gap: 4 }, children: [
2596
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "#1677ff", lineHeight: 1.4 }, children: "Question" }),
2597
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13, color: "#262626", lineHeight: 1.6, whiteSpace: "pre-wrap" }, children: answer })
2598
+ ] });
2599
+ }
2600
+ var RunStartedNode = React9__default.default.memo(({ loading }) => {
2601
+ if (!loading) return null;
2602
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Flex, { gap: 8, align: "center", className: styles_module_default.runStartedNode, children: /* @__PURE__ */ jsxRuntime.jsx(icons.LoadingOutlined, { style: { color: "#1677ff" } }) });
2603
+ });
2604
+ var ToolCallNode = React9__default.default.memo(({ item }) => {
2605
+ return /* @__PURE__ */ jsxRuntime.jsx(tool_call_item_default, { item });
2606
+ });
2607
+ var TextNode = React9__default.default.memo(({ item, role, customComponents }) => {
2608
+ const content = toA2uiDisplayText(role, item?.messageContent);
2609
+ if (typeof content === "string" && content.startsWith("Question:")) {
2610
+ return /* @__PURE__ */ jsxRuntime.jsx(QuestionSummary, { content });
2611
+ }
2612
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2613
+ !!item.reasoningContent && /* @__PURE__ */ jsxRuntime.jsx(xV2.Think, { title: "\u6DF1\u5EA6\u601D\u8003", children: item.reasoningContent }),
2614
+ !!content && /* @__PURE__ */ jsxRuntime.jsx(
2615
+ XMarkdown__default.default,
2616
+ {
2617
+ openLinksInNewTab: true,
2618
+ className: classNames7__default.default("x-markdown-light", "xMarkdownStyle"),
2619
+ components: {
2620
+ code: code_highlight_default,
2621
+ agentnavigate: agent_navigate_default,
2622
+ a: PreviewLinkComponent,
2623
+ ...customComponents
2624
+ },
2625
+ config: getMarkdownConfig(),
2626
+ content: formatMixedContent3(content)
2627
+ }
2628
+ )
2629
+ ] });
2630
+ });
2631
+ var StepErrorNode = React9__default.default.memo(({ item, customComponents }) => {
2632
+ if (!item.errorMessage) return null;
2633
+ return /* @__PURE__ */ jsxRuntime.jsx(
2634
+ XMarkdown__default.default,
2635
+ {
2636
+ openLinksInNewTab: true,
2637
+ className: classNames7__default.default("x-markdown-light", "xMarkdownStyle"),
2638
+ components: { code: code_highlight_default, agentnavigate: agent_navigate_default, ...customComponents },
2639
+ config: getMarkdownConfig(),
2640
+ content: item.errorMessage
2641
+ }
2642
+ );
2643
+ });
2644
+ var FilesNode = React9__default.default.memo(({ item }) => {
2645
+ const chatStore = useChatStore();
2646
+ const configState = valtio.useSnapshot(chatStore.config);
2647
+ const agentState = valtio.useSnapshot(chatStore.agent);
2648
+ const conversationState = valtio.useSnapshot(chatStore.conversation);
2649
+ const fileItems = React9.useMemo(() => {
2650
+ return (item.files || []).map((file) => {
2651
+ const previewUrl = configState.services.request.getPreviewUrl(agentState.agentInfo.id, conversationState.active.id, file.path);
2652
+ let fileType = "file";
2653
+ const ext = file.ext?.toLowerCase() || "";
2654
+ if (["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "webp"].includes(ext)) {
2655
+ fileType = "image";
2656
+ } else if (["mp4", "webm", "ogg", "mov"].includes(ext)) {
2657
+ fileType = "video";
2658
+ } else if (["mp3", "wav", "ogg", "m4a"].includes(ext)) {
2659
+ fileType = "audio";
2660
+ }
2661
+ return {
2662
+ ...file,
2663
+ src: fileType === "image" ? previewUrl : file.path,
2664
+ type: fileType,
2665
+ onClick: () => chatStore.setPreview({ path: file.path, fileName: file.name })
2666
+ };
2667
+ });
2668
+ }, [item.files]);
2669
+ return /* @__PURE__ */ jsxRuntime.jsx(xV2.FileCard.List, { style: { width: "70%" }, items: fileItems });
2670
+ });
2671
+ var MessageRender_default = React9__default.default.memo(({ message: message3, messageIndex = -1, loading, containerRef, customComponents }) => {
2672
+ const content = message3.content || [];
2673
+ if (content.length === 0) return null;
2674
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { ref: containerRef, vertical: true, gap: 8, children: [
2675
+ content.filter((item) => item.type !== "a2uiCommand").map((item, index) => {
2676
+ if (item.type === "runStarted") {
2677
+ return /* @__PURE__ */ jsxRuntime.jsx(RunStartedNode, { loading }, `flow-start-${index}`);
2678
+ }
2679
+ if (item.type === "toolCall" || item.type === "toolResult") {
2680
+ return /* @__PURE__ */ jsxRuntime.jsx(ToolCallNode, { item }, `tool-call-${item.toolCallId || index}`);
2681
+ }
2682
+ if (item.type === "text") {
2683
+ return /* @__PURE__ */ jsxRuntime.jsx(TextNode, { item, role: message3.role, customComponents }, `message-${index}`);
2684
+ }
2685
+ if (item.type === "stepError") {
2686
+ return /* @__PURE__ */ jsxRuntime.jsx(StepErrorNode, { item, customComponents }, `step-error-${index}`);
2687
+ }
2688
+ if (item.type === "files") {
2689
+ return /* @__PURE__ */ jsxRuntime.jsx(FilesNode, { item }, `files-${index}`);
2690
+ }
2691
+ if (item.type === "plan") {
2692
+ return /* @__PURE__ */ jsxRuntime.jsx(A2uiPlanNode, { item }, `plan-${index}`);
2693
+ }
2694
+ return null;
2695
+ }),
2696
+ messageIndex >= 0 ? /* @__PURE__ */ jsxRuntime.jsx(A2uiMessageCards, { messageIndex }) : null
2697
+ ] });
2698
+ });
2699
+
2700
+ // src/core/constants.ts
2701
+ var CONV_MODE = {
2702
+ PROD: 1,
2703
+ DEBUG: 2
2704
+ };
2705
+ var flowSpecState = valtio.proxy({
2706
+ nodes: []
2707
+ });
2708
+ function setLogPanelOpen(_open, _executionId) {
2709
+ }
2710
+
2711
+ // src/ui/common/styles.module.less
2712
+ var styles_module_default2 = {
2713
+ chatHeader: "styles_module_chatHeader",
2714
+ chatTitle: "styles_module_chatTitle",
2715
+ popover: "styles_module_popover",
2716
+ conversationListPanel: "styles_module_conversationListPanel",
2717
+ createConversationButton: "styles_module_createConversationButton",
2718
+ conversations: "styles_module_conversations",
2719
+ chatWelcomeWrap: "styles_module_chatWelcomeWrap",
2720
+ chatWelcome: "styles_module_chatWelcome",
2721
+ promptItem: "styles_module_promptItem",
2722
+ bubbleList: "styles_module_bubbleList",
2723
+ messageFooter: "styles_module_messageFooter",
2724
+ resourceBtn: "styles_module_resourceBtn",
2725
+ resourceBtnActive: "styles_module_resourceBtnActive",
2726
+ userInputCollapse: "styles_module_userInputCollapse",
2727
+ logoArea: "styles_module_logoArea",
2728
+ logoContainer: "styles_module_logoContainer",
2729
+ staticHalo: "styles_module_staticHalo",
2730
+ logoHoverWrapper: "styles_module_logoHoverWrapper",
2731
+ logoImage: "styles_module_logoImage",
2732
+ greetingTitle: "styles_module_greetingTitle",
2733
+ gradientText: "styles_module_gradientText",
2734
+ greetingSubtitle: "styles_module_greetingSubtitle",
2735
+ senderReferenceHeaderTitle: "styles_module_senderReferenceHeaderTitle",
2736
+ senderReferenceHeaderContent: "styles_module_senderReferenceHeaderContent"
2737
+ };
2738
+ var WelcomeItem_default = ({ icon = true, title = true, description = true, prompts = true }) => {
2739
+ const chatStore = useChatStore();
2740
+ const agentState = valtio.useSnapshot(chatStore.agent);
2741
+ const recommendQuestions = React9.useMemo(() => {
2742
+ return agentState.agentInfo?.config?.onboarding?.guiding?.map((item, index) => ({
2743
+ key: String(index),
2744
+ description: item
2745
+ }));
2746
+ }, [agentState.agentInfo?.config?.onboarding?.guiding]);
2747
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { vertical: true, justify: "center", className: styles_module_default2.chatWelcomeWrap, children: [
2748
+ /* @__PURE__ */ jsxRuntime.jsx(
2749
+ xV2.Welcome,
2750
+ {
2751
+ className: classNames7__default.default(styles_module_default2.chatWelcome, "p-t-32"),
2752
+ variant: "borderless",
2753
+ icon: /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: icon, DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(antd.Avatar, { shape: "square", size: 58, src: agentState.agentInfo?.iconUrl || "" }) }),
2754
+ title: /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: title, DefaultComponent: `\u4F60\u597D\uFF0C\u6211\u662F${agentState.agentInfo?.name || ""}` }),
2755
+ description: /* @__PURE__ */ jsxRuntime.jsx(
2756
+ common.RenderWrapper,
2757
+ {
2758
+ control: description,
2759
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: agentState.agentInfo?.config?.onboarding?.greeting || "" } })
2760
+ }
2761
+ )
2762
+ }
2763
+ ),
2764
+ (agentState.agentInfo?.config?.onboarding?.guiding?.length ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2765
+ common.RenderWrapper,
2766
+ {
2767
+ control: prompts,
2768
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(
2769
+ xV2.Prompts,
2770
+ {
2771
+ className: classNames7__default.default("m-t-16", styles_module_default2.promptItem),
2772
+ wrap: true,
2773
+ onItemClick: (info) => chatStore.sendMessage(info.data.description),
2774
+ items: recommendQuestions
2775
+ }
2776
+ )
2777
+ }
2778
+ )
2779
+ ] });
2780
+ };
2781
+ var { Text: Text2 } = antd.Typography;
2782
+ function isVisibleContentItem(contentItem, isMessageLoading) {
2783
+ const isRunStarted = contentItem.type === "runStarted";
2784
+ const isFile = contentItem.type === "files";
2785
+ const isTextWithContent = contentItem.type === "text" && (!!contentItem.reasoningContent || !!contentItem.messageContent);
2786
+ const isToolCall = contentItem.type === "toolCall" || contentItem.type === "toolResult";
2787
+ const isStepError = contentItem.type === "stepError" && !!contentItem.errorMessage;
2788
+ const isA2uiCommand = contentItem.type === "a2uiCommand";
2789
+ const isPlan = contentItem.type === "plan";
2790
+ if (!isRunStarted && !isFile && !isTextWithContent && !isToolCall && !isStepError && !isA2uiCommand && !isPlan) {
2791
+ return false;
2792
+ }
2793
+ if (isPlan && shouldHideA2uiPlan(contentItem)) {
2794
+ return false;
2795
+ }
2796
+ if (isRunStarted && !isMessageLoading) {
2797
+ return false;
2798
+ }
2799
+ return true;
2800
+ }
2801
+ function splitRenderableContents(contents, isMessageLoading) {
2802
+ const validContents = [];
2803
+ const nonFileContents = [];
2804
+ const fileContents = [];
2805
+ contents.forEach((contentItem) => {
2806
+ if (!isVisibleContentItem(contentItem, isMessageLoading)) return;
2807
+ validContents.push(contentItem);
2808
+ if (contentItem.type === "files") {
2809
+ fileContents.push(contentItem);
2810
+ } else {
2811
+ nonFileContents.push(contentItem);
2812
+ }
2813
+ });
2814
+ return {
2815
+ validContents,
2816
+ nonFileContents,
2817
+ fileContents,
2818
+ hasFiles: fileContents.length > 0,
2819
+ isAllFiles: validContents.length > 0 && fileContents.length === validContents.length
2820
+ };
2821
+ }
2822
+ function createRenderMessage(message3, content) {
2823
+ return {
2824
+ messageId: message3.messageId,
2825
+ conversationId: message3.conversationId,
2826
+ executionId: message3.executionId,
2827
+ role: message3.role,
2828
+ content: [...content],
2829
+ files: message3.files ? Array.from(message3.files) : void 0,
2830
+ feedback: message3.feedback,
2831
+ params: message3.params,
2832
+ quoteMsg: message3.quoteMsg ? {
2833
+ ...message3.quoteMsg,
2834
+ msgFiles: message3.quoteMsg.msgFiles ? Array.from(message3.quoteMsg.msgFiles) : void 0
2835
+ } : void 0,
2836
+ createdAt: message3.createdAt,
2837
+ stopFlag: message3.stopFlag,
2838
+ generating: message3.generating
2839
+ };
2840
+ }
2841
+ function renderMessageContent(refKey, message3, content, messageIndex, loading, messageRefs, customComponents) {
2842
+ return /* @__PURE__ */ jsxRuntime.jsx(
2843
+ MessageRender_default,
2844
+ {
2845
+ message: createRenderMessage(message3, content),
2846
+ messageIndex,
2847
+ customComponents,
2848
+ loading,
2849
+ containerRef: (node) => {
2850
+ if (node) {
2851
+ messageRefs.current[refKey] = node;
2852
+ } else {
2853
+ delete messageRefs.current[refKey];
2854
+ }
2855
+ }
2856
+ }
2857
+ );
2858
+ }
2859
+ var BubbleListItems_default = ({
2860
+ firstMessages = [],
2861
+ welcomeMessage = true,
2862
+ avatar = { user: false, agent: true },
2863
+ agentActions = false,
2864
+ customComponents = {}
2865
+ }) => {
2866
+ const chatStore = useChatStore();
2867
+ const agentState = valtio.useSnapshot(chatStore.agent);
2868
+ const conversationState = valtio.useSnapshot(chatStore.conversation);
2869
+ const configState = valtio.useSnapshot(chatStore.config);
2870
+ const isDebug = configState.params.convMeta.mode === CONV_MODE.DEBUG;
2871
+ const isWorkFlow = agentState.agentInfo.agentType === 1 /* FLOW */;
2872
+ const conversationRoles = React9.useMemo(() => {
2873
+ const roles = {};
2874
+ if (agentState.agentInfo?.id) {
2875
+ roles.agent = {
2876
+ user: "agent",
2877
+ role: 2,
2878
+ placement: "start"
2879
+ // avatar: (isBoolean(avatar) ? avatar : avatar?.agent) ? { src: agentState.agentInfo.iconUrl, icon: <OpenAIOutlined /> } : null
2880
+ };
2881
+ }
2882
+ roles.user = {
2883
+ user: "user",
2884
+ role: 1,
2885
+ placement: "end",
2886
+ avatar: (common.isBoolean(avatar) ? avatar : avatar?.user) ? /* @__PURE__ */ jsxRuntime.jsx(common.UserAvatar, { size: 30, avatarSrc: "", userName: "" }) : null
2887
+ };
2888
+ return roles;
2889
+ }, [agentState.agentInfo.id]);
2890
+ const chatMessage = React9.useMemo(
2891
+ () => conversationState.messages[conversationState.active.id] || {},
2892
+ [conversationState.messages[conversationState.active.id]]
2893
+ );
2894
+ const conversationMessages = chatMessage?.message || [];
2895
+ const getRole = (role) => {
2896
+ const roleKey = Object.keys(conversationRoles).find((key) => conversationRoles[key].role === role);
2897
+ return conversationRoles[roleKey] || {};
2898
+ };
2899
+ const messageRefs = React9.useRef({});
2900
+ const chatRecords = React9.useMemo(() => {
2901
+ const chatRecords2 = [];
2902
+ conversationMessages.forEach((message3, messageIndex) => {
2903
+ const role = getRole(message3.role);
2904
+ const contents = message3.content || [];
2905
+ const isLeftBubble = role.user === "agent";
2906
+ const isMessageLoading = !!message3.generating;
2907
+ const showLogButton = isDebug && isLeftBubble && !isMessageLoading && isWorkFlow;
2908
+ const baseKey = `${message3.executionId}-${messageIndex}`;
2909
+ const { validContents, nonFileContents, fileContents, hasFiles, isAllFiles } = splitRenderableContents(contents, isMessageLoading);
2910
+ if (validContents.length === 0) return;
2911
+ const footerNode = /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { align: "center", gap: 8, className: styles_module_default2.messageFooter, children: [
2912
+ message3.stopFlag && /* @__PURE__ */ jsxRuntime.jsx(Text2, { type: "secondary", style: { flex: "none" }, children: "\u5DF2\u505C\u6B62" }),
2913
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { align: "center", gap: 4, children: [
2914
+ showLogButton && /* @__PURE__ */ jsxRuntime.jsx(
2915
+ antd.Button,
2916
+ {
2917
+ className: "logBtn",
2918
+ type: "text",
2919
+ size: "small",
2920
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.FileTextOutlined, {}),
2921
+ onClick: () => {
2922
+ setLogPanelOpen(true, message3.executionId);
2923
+ }
2924
+ }
2925
+ ),
2926
+ role.user === "agent" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2927
+ /* @__PURE__ */ jsxRuntime.jsx(
2928
+ antd.Button,
2929
+ {
2930
+ onClick: async () => {
2931
+ const container = messageRefs.current[baseKey];
2932
+ if (!container) return;
2933
+ const markdown = common.htmlToMarkdown(container.innerHTML) || container.innerText || "";
2934
+ common.copyText(markdown);
2935
+ },
2936
+ color: "default",
2937
+ variant: "text",
2938
+ size: "small",
2939
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CopyOutlined, {})
2940
+ }
2941
+ ),
2942
+ /* @__PURE__ */ jsxRuntime.jsx(
2943
+ antd.Button,
2944
+ {
2945
+ color: message3.feedback === 1 ? "primary" : "default",
2946
+ size: "small",
2947
+ variant: "text",
2948
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.LikeOutlined, {}),
2949
+ onClick: () => chatStore.feedback(message3.executionId, 1, messageIndex)
2950
+ }
2951
+ ),
2952
+ /* @__PURE__ */ jsxRuntime.jsx(
2953
+ antd.Button,
2954
+ {
2955
+ color: message3.feedback === 2 ? "primary" : "default",
2956
+ size: "small",
2957
+ variant: "text",
2958
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.DislikeOutlined, {}),
2959
+ onClick: () => chatStore.feedback(message3.executionId, 2, messageIndex)
2960
+ }
2961
+ ),
2962
+ /* @__PURE__ */ jsxRuntime.jsx(
2963
+ common.RenderWrapper,
2964
+ {
2965
+ control: agentActions,
2966
+ ctx: {
2967
+ message: message3,
2968
+ get dom() {
2969
+ return messageRefs.current[baseKey];
2970
+ }
2971
+ }
2972
+ }
2973
+ )
2974
+ ] })
2975
+ ] })
2976
+ ] });
2977
+ if (hasFiles && nonFileContents.length > 0) {
2978
+ chatRecords2.push({
2979
+ key: `${baseKey}-text`,
2980
+ role: String(role.role),
2981
+ placement: role.placement,
2982
+ avatar: role.avatar,
2983
+ content: renderMessageContent(
2984
+ baseKey,
2985
+ message3,
2986
+ nonFileContents,
2987
+ messageIndex,
2988
+ isMessageLoading,
2989
+ messageRefs,
2990
+ customComponents
2991
+ ),
2992
+ footer: footerNode
2993
+ });
2994
+ chatRecords2.push({
2995
+ key: `${baseKey}-files`,
2996
+ role: String(role.role),
2997
+ placement: role.placement,
2998
+ avatar: role.avatar,
2999
+ content: /* @__PURE__ */ jsxRuntime.jsx(
3000
+ MessageRender_default,
3001
+ {
3002
+ message: createRenderMessage(message3, fileContents),
3003
+ messageIndex,
3004
+ customComponents,
3005
+ loading: isMessageLoading
3006
+ }
3007
+ ),
3008
+ variant: "borderless"
3009
+ });
3010
+ return;
3011
+ }
3012
+ chatRecords2.push({
3013
+ key: baseKey,
3014
+ role: String(role.role),
3015
+ placement: role.placement,
3016
+ avatar: role.avatar,
3017
+ content: renderMessageContent(
3018
+ baseKey,
3019
+ message3,
3020
+ validContents,
3021
+ messageIndex,
3022
+ isMessageLoading,
3023
+ messageRefs,
3024
+ customComponents
3025
+ ),
3026
+ footer: footerNode,
3027
+ variant: isAllFiles ? "borderless" : void 0
3028
+ });
3029
+ });
3030
+ return chatRecords2;
3031
+ }, [agentActions, chatStore, conversationMessages, conversationRoles, conversationState.active.id, isDebug, isWorkFlow]);
3032
+ const firstMessagesRecord = React9.useMemo(() => {
3033
+ return (firstMessages || []).map((firstMessage, index) => {
3034
+ const { role, ...args } = firstMessage;
3035
+ const roleObj = getRole(role);
3036
+ return {
3037
+ key: `firstMessage-${index}`,
3038
+ role: roleObj.user,
3039
+ placement: roleObj.placement,
3040
+ avatar: roleObj.avatar,
3041
+ variant: "borderless",
3042
+ ...args
3043
+ };
3044
+ });
3045
+ }, [firstMessages, conversationRoles]);
3046
+ const welcomeMessageRecord = React9.useMemo(() => {
3047
+ if (!welcomeMessage) return [];
3048
+ return [
3049
+ {
3050
+ key: "welcome-message",
3051
+ content: /* @__PURE__ */ jsxRuntime.jsx(WelcomeItem_default, {}),
3052
+ variant: "borderless"
3053
+ }
3054
+ ];
3055
+ }, [welcomeMessage]);
3056
+ const bubbleListItems = React9.useMemo(() => {
3057
+ const list = [];
3058
+ list.push(...firstMessagesRecord);
3059
+ list.push(...chatRecords);
3060
+ if (list.length) {
3061
+ return list;
3062
+ }
3063
+ return [...welcomeMessageRecord];
3064
+ }, [chatRecords, welcomeMessageRecord, firstMessagesRecord]);
3065
+ const listRef = React9.useRef(null);
3066
+ const autoScrollRef = React9.useRef(true);
3067
+ const handleScroll = (el) => {
3068
+ const target = el.target;
3069
+ const distanceToBottom = target.scrollHeight - target.scrollTop - target.clientHeight;
3070
+ autoScrollRef.current = distanceToBottom < 90;
3071
+ };
3072
+ React9.useEffect(() => {
3073
+ const latestMessage = conversationMessages[conversationMessages?.length - 1];
3074
+ if (!latestMessage) return;
3075
+ if (latestMessage.generating) {
3076
+ autoScrollRef.current = true;
3077
+ }
3078
+ }, [conversationMessages?.length]);
3079
+ React9.useEffect(() => {
3080
+ const el = listRef.current?.nativeElement;
3081
+ if (!el || !bubbleListItems.length) return;
3082
+ if (autoScrollRef.current) {
3083
+ setTimeout(() => {
3084
+ if (autoScrollRef.current) {
3085
+ listRef.current?.scrollTo({
3086
+ top: "bottom",
3087
+ behavior: "instant"
3088
+ });
3089
+ }
3090
+ }, 100);
3091
+ }
3092
+ }, [bubbleListItems]);
3093
+ return /* @__PURE__ */ jsxRuntime.jsx(A2uiRenderer, { messages: conversationMessages, children: /* @__PURE__ */ jsxRuntime.jsx(
3094
+ xV2.Bubble.List,
3095
+ {
3096
+ autoScroll: false,
3097
+ ref: listRef,
3098
+ items: bubbleListItems,
3099
+ className: classNames7__default.default(styles_module_default2.bubbleList, "height-full", "scroll-fade-in"),
3100
+ onScroll: handleScroll
3101
+ },
3102
+ conversationState.active.id
3103
+ ) });
3104
+ };
3105
+
3106
+ // src/services/index.ts
3107
+ var createChatService = (request, config) => {
3108
+ const fetchAgentInfo = (agentId) => {
3109
+ return request.get(`/agents/${agentId}`);
3110
+ };
3111
+ const createConversationId = (params) => {
3112
+ return request.post(`/agents/${params.agentId}/conversations`, { convMeta: params.convMeta });
3113
+ };
3114
+ const fetchConversations = (params) => {
3115
+ return request.get(`/agents/${params.agentId}/conversations`, { ...params.convMeta });
3116
+ };
3117
+ const deleteConversation = (id) => {
3118
+ return request.delete(`/agents/conversations/${id}`);
3119
+ };
3120
+ const fetchMessages = (params) => {
3121
+ return request.get(`/agents/conversations/${params.conversationId}/messages`);
3122
+ };
3123
+ const sendMessageStream = (params, agentId) => {
3124
+ return request.post(`/agents/${agentId}/chat`, params);
3125
+ };
3126
+ const cancelMessage = (executionId) => {
3127
+ return request.post(`/agents/executions/${executionId}/cancel`);
3128
+ };
3129
+ const getRecommendQuestions = (params) => {
3130
+ return request.post(`/agents/conversations/${params.conversationId}/messages/recommend`, params);
3131
+ };
3132
+ const getAgentUserInput = (agentId) => {
3133
+ return request.get(`/agents/${agentId}/workflow/params`);
3134
+ };
3135
+ const feedbackUpdate = (params) => {
3136
+ return request.put(`/agents/messages/${params.executionId}/feedback`, params);
3137
+ };
3138
+ const chatUpload = (agentId, data, conversationId, signal) => {
3139
+ return request.post(`/agents/${agentId}/${conversationId}/files`, data, {
3140
+ headers: {
3141
+ "Content-Type": "multipart/form-data"
3142
+ },
3143
+ timeout: 3e5,
3144
+ signal
3145
+ });
3146
+ };
3147
+ const getPreviewUrl = (agentId, conversationId, path) => {
3148
+ return `${config?.baseURL}/agents/${agentId}/${conversationId}/files/download?path=${encodeURIComponent(path)}&${TOKEN_KEY}=${tokenManager.get()}`;
3149
+ };
3150
+ return {
3151
+ fetchAgentInfo,
3152
+ createConversationId,
3153
+ fetchConversations,
3154
+ deleteConversation,
3155
+ fetchMessages,
3156
+ sendMessageStream,
3157
+ cancelMessage,
3158
+ getRecommendQuestions,
3159
+ getAgentUserInput,
3160
+ feedbackUpdate,
3161
+ chatUpload,
3162
+ getPreviewUrl
3163
+ };
3164
+ };
3165
+
3166
+ // src/stores/index.ts
3167
+ var defaultLayout = {
3168
+ globalHeader: true,
3169
+ conversationList: true,
3170
+ preview: true,
3171
+ chatHeader: true,
3172
+ messageList: true,
3173
+ senderHeader: false,
3174
+ sender: true,
3175
+ senderFooter: false,
3176
+ disclaimerNotice: true
3177
+ };
3178
+ function createChatStore() {
3179
+ const config = valtio.proxy({
3180
+ services: {
3181
+ /** WebSocket地址 */
3182
+ websocketUrls: ["", ""],
3183
+ /** HTTP请求实例 */
3184
+ request: {}
3185
+ },
3186
+ hooks: {},
3187
+ layout: {},
3188
+ loading: false,
3189
+ /** 文件预览状态 */
3190
+ preview: {
3191
+ file: {},
3192
+ isEdit: false
3193
+ // 未使用
3194
+ },
3195
+ stream: true,
3196
+ params: {
3197
+ convMeta: {
3198
+ mode: CONV_MODE.DEBUG
3199
+ }
3200
+ }
3201
+ });
3202
+ const setServices = ({ http, websocket } = {}) => {
3203
+ const httpConfig = { baseURL: "/luya/api", headers: { [TOKEN_KEY]: tokenManager.get() }, ...http?.config };
3204
+ const request = common.createRequest(httpConfig);
3205
+ if (config.hooks?.onRequestInterceptor) {
3206
+ request.instance.interceptors.request.use(...config.hooks.onRequestInterceptor);
3207
+ }
3208
+ request.instance.interceptors.response.use(void 0, (err) => {
3209
+ if (err?.response?.status === common.HttpStatus.UNAUTHORIZED) {
3210
+ if (config.hooks.onRedirectLogin) {
3211
+ config.hooks.onRedirectLogin();
3212
+ } else {
3213
+ redirectUrl();
3214
+ }
3215
+ }
3216
+ return Promise.reject(err);
3217
+ });
3218
+ if (config.hooks?.onResponseInterceptor) {
3219
+ request.instance.interceptors.response.use(...config.hooks.onResponseInterceptor);
3220
+ }
3221
+ config.services.request = { ...createChatService(request, httpConfig), ...http?.request };
3222
+ config.services.websocketUrls = ["", ""];
3223
+ if (common.isArray(websocket?.baseURLs)) {
3224
+ websocket.baseURLs.forEach((baseURL, index) => {
3225
+ if (common.isString(baseURL)) {
3226
+ config.services.websocketUrls[index] = getChatSocketUrl(baseURL, websocket?.params || httpConfig.headers);
3227
+ }
3228
+ });
3229
+ } else {
3230
+ const url = getChatSocketUrl(httpConfig.baseURL, websocket?.params || httpConfig.headers);
3231
+ config.services.websocketUrls = [url, ""];
3232
+ }
3233
+ };
3234
+ const setPreview = async (file = {}, isEdit = false) => {
3235
+ const newFile = { ...file, _t: Date.now() };
3236
+ const preview = common.shouldRender(config.layout.preview);
3237
+ const canProceed = await config.hooks?.onBeforeFilePreview?.(file, preview);
3238
+ if (canProceed === false) {
3239
+ return;
3240
+ }
3241
+ if (preview) {
3242
+ config.preview = {
3243
+ file: newFile,
3244
+ isEdit
3245
+ };
3246
+ } else {
3247
+ if (file?.fileUrl) {
3248
+ window.open(file.fileUrl, "_blank");
3249
+ }
3250
+ }
3251
+ config.hooks?.onAfterFilePreview?.(file, preview);
3252
+ };
3253
+ const setParams = (params) => {
3254
+ if (common.isObject(params)) {
3255
+ Object.assign(config.params, params);
3256
+ }
3257
+ };
3258
+ const setLayout = (layout) => {
3259
+ config.layout = common.deepMerge(defaultLayout, layout);
3260
+ };
3261
+ const setHooks = (hooks = {}) => {
3262
+ config.hooks = hooks;
3263
+ };
3264
+ const agent = valtio.proxy({
3265
+ /** 当前智能体 */
3266
+ agentInfo: {},
3267
+ model: {
3268
+ modelName: "qwen3.5-plus",
3269
+ providerName: "\u9AD8\u5C71\u4E91\u57FA",
3270
+ reasoning: true
3271
+ },
3272
+ /** 智能体加载状态 */
3273
+ loading: false
3274
+ });
3275
+ const setAgentModel = (model) => {
3276
+ agent.model = model;
3277
+ };
3278
+ const getUserInput = async (agentId) => {
3279
+ agent.loading = true;
3280
+ try {
3281
+ const res = await config.services.request.getAgentUserInput(agentId);
3282
+ if (res.data?.inputs && agent.agentInfo.userInput?.length === 0) {
3283
+ agent.agentInfo.userInput = res.data.inputs.filter((item) => item.enableEdit);
3284
+ }
3285
+ } finally {
3286
+ agent.loading = false;
3287
+ }
3288
+ };
3289
+ const setAgent = (agentInfo) => {
3290
+ agent.agentInfo = agentInfo;
3291
+ };
3292
+ const setUserInput = (userInput) => {
3293
+ if (config.params?.convMeta?.mode === CONV_MODE.PROD && agent.agentInfo.agentType === 1 /* FLOW */) {
3294
+ getUserInput(agent.agentInfo.id);
3295
+ } else if (agent.agentInfo.userInput) {
3296
+ agent.agentInfo.userInput = userInput;
3297
+ }
3298
+ };
3299
+ const getAgentInfo = async (id) => {
3300
+ config.loading = true;
3301
+ if (agent.agentInfo.id === id) return;
3302
+ try {
3303
+ const { data } = await config.services.request.fetchAgentInfo(id || "");
3304
+ agent.agentInfo = data;
3305
+ } finally {
3306
+ config.loading = false;
3307
+ }
3308
+ };
3309
+ const conversations = valtio.proxy({
3310
+ /** 会话列表数据 */
3311
+ list: {
3312
+ items: []
3313
+ },
3314
+ /** 当前会话索引,创建会话时更新,促使页面更新会话列表 */
3315
+ updateIndex: 0,
3316
+ /** 获取会话列表的加载状态 */
3317
+ loading: false,
3318
+ /** 编辑会话的加载状态 */
3319
+ editLoading: false
3320
+ });
3321
+ const getConversations = async (agentId) => {
3322
+ try {
3323
+ conversations.loading = true;
3324
+ const { data } = await config.services.request.fetchConversations({
3325
+ agentId,
3326
+ convMeta: config.params.convMeta
3327
+ });
3328
+ if (agent.agentInfo.id !== agentId) return;
3329
+ const resultItems = common.transforms(data || [], {
3330
+ key: "id",
3331
+ id: "id",
3332
+ label: "title",
3333
+ spec: "spec",
3334
+ group: (c) => {
3335
+ return classifyTime(c.updatedAt);
3336
+ }
3337
+ });
3338
+ conversations.list.items = resultItems;
3339
+ } finally {
3340
+ conversations.loading = false;
3341
+ }
3342
+ };
3343
+ const delConversation = async (conversationId) => {
3344
+ try {
3345
+ const canProceed = await config.hooks?.onBeforeDelConversation?.(conversationId);
3346
+ if (canProceed === false) return;
3347
+ conversations.editLoading = true;
3348
+ await config.services.request.deleteConversation(conversationId);
3349
+ antd.message.success("\u5220\u9664\u6210\u529F");
3350
+ conversations.list.items = conversations.list.items.filter((item) => item.key !== conversationId);
3351
+ delete conversation.messages[conversationId];
3352
+ if (conversation.active.id === conversationId) {
3353
+ createConversation();
3354
+ }
3355
+ config.hooks?.onAfterDelConversation?.(conversationId, conversation.active.id === conversationId);
3356
+ } finally {
3357
+ conversations.editLoading = false;
3358
+ }
3359
+ };
3360
+ const initConversation = async (config2) => {
3361
+ await getConversations(config2.agent.id);
3362
+ if (config2?.conversationId) {
3363
+ switchConversation(config2.conversationId);
3364
+ } else {
3365
+ if (config2.conversationStrategy === 1) {
3366
+ switchConversation(conversations.list.items[0].key);
3367
+ } else {
3368
+ createConversation();
3369
+ }
3370
+ }
3371
+ };
3372
+ const switchConversation = async (id) => {
3373
+ const conversationId = String(id);
3374
+ config.services.request.getPreviewUrl(agent.agentInfo.id, conversationId, "");
3375
+ if (conversation.active.id === conversationId) return;
3376
+ const canProceed = await config.hooks?.onBeforeSwitchConversation?.(conversationId);
3377
+ if (canProceed === false) {
3378
+ throw new Error("\u64CD\u4F5C\u88AB\u963B\u6B62");
3379
+ }
3380
+ conversation.active.id = conversationId;
3381
+ const targetConversation = conversations.list.items.find((item) => item.key === conversationId);
3382
+ if (targetConversation) {
3383
+ conversation.active.spec = targetConversation.spec;
3384
+ } else {
3385
+ conversation.active.spec = {};
3386
+ }
3387
+ await getMessages(conversationId);
3388
+ await setPreview();
3389
+ config.hooks?.onAfterSwitchConversation?.(conversationId);
3390
+ };
3391
+ const setConversationSpec = (spec) => {
3392
+ if (common.isObject(spec)) {
3393
+ conversation.active.spec = spec;
3394
+ const currentConversation = conversations.list.items.find((item) => item.id === conversation.active.id);
3395
+ if (currentConversation) {
3396
+ currentConversation.spec = spec;
3397
+ }
3398
+ }
3399
+ };
3400
+ const updateConversations = (data) => {
3401
+ const item = common.transform(data, {
3402
+ key: "id",
3403
+ id: "id",
3404
+ label: "title",
3405
+ spec: "spec",
3406
+ group: (c) => {
3407
+ return classifyTime(c.updatedAt);
3408
+ }
3409
+ });
3410
+ conversations.list.items = [item, ...conversations.list.items.filter((i) => i.key !== item.key)];
3411
+ };
3412
+ const createConversation = async () => {
3413
+ if (!agent.agentInfo.id) return;
3414
+ const { data } = await config.services.request.createConversationId({ agentId: agent.agentInfo.id, convMeta: config.params.convMeta });
3415
+ const newSpec = {
3416
+ skills: { items: [] },
3417
+ knowledge: { items: [] }
3418
+ };
3419
+ updateConversations({
3420
+ id: data || "",
3421
+ title: "",
3422
+ agentId: agent.agentInfo?.id || "",
3423
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3424
+ spec: newSpec
3425
+ });
3426
+ await switchConversation(data);
3427
+ config.hooks?.onAfterSwitchConversation?.(data);
3428
+ };
3429
+ const conversation = valtio.proxy({
3430
+ /** 当前激活的会话信息 */
3431
+ active: {
3432
+ id: "",
3433
+ spec: {}
3434
+ },
3435
+ /** 每个会话的消息存储,以会话ID为键 */
3436
+ messages: {},
3437
+ /** 消息反馈状态 */
3438
+ feedback: {
3439
+ /** 反馈操作加载状态 */
3440
+ loading: false
3441
+ }
3442
+ });
3443
+ const setReferences = async (references) => {
3444
+ const canProceed = await config.hooks?.onBeforeSetReferences?.(references);
3445
+ if (canProceed === false) {
3446
+ throw new Error("\u64CD\u4F5C\u88AB\u963B\u6B62");
3447
+ }
3448
+ conversation.messages[conversation.active.id].references = references;
3449
+ config.hooks?.onAfterSetReferences?.(references);
3450
+ };
3451
+ const setContent = (content) => {
3452
+ conversation.messages[conversation.active.id].content = content;
3453
+ };
3454
+ const setContentParams = (params) => {
3455
+ conversation.messages[conversation.active.id].params = params;
3456
+ };
3457
+ const setFileList = (files = []) => {
3458
+ conversation.messages[conversation.active.id].files = files;
3459
+ };
3460
+ const setHeaderOpen = (headerOpen) => {
3461
+ conversation.messages[conversation.active.id].headerOpen = headerOpen;
3462
+ };
3463
+ const feedback = async (executionId, feedback2, index) => {
3464
+ try {
3465
+ conversation.feedback.loading = true;
3466
+ await config.services.request.feedbackUpdate({ executionId, feedback: feedback2 });
3467
+ antd.message.success("\u611F\u8C22\u60A8\u7684\u53CD\u9988");
3468
+ conversation.messages[conversation.active.id].message[index].feedback = feedback2;
3469
+ } finally {
3470
+ conversation.feedback.loading = false;
3471
+ }
3472
+ };
3473
+ const setInitMessage = async (conversationId) => {
3474
+ conversation.messages[conversationId] = {
3475
+ /** 输入框内容 */
3476
+ content: "",
3477
+ /** 上传文件列表 */
3478
+ files: [],
3479
+ /** 头部展开状态 */
3480
+ headerOpen: false,
3481
+ /** 消息发送/接收加载状态 */
3482
+ loading: false,
3483
+ /** 消息列表 */
3484
+ message: []
3485
+ };
3486
+ };
3487
+ const getMessages = async (conversationId) => {
3488
+ const canProceed = await config.hooks?.onBeforeInitMessages?.(conversationId);
3489
+ if (canProceed === false) {
3490
+ throw new Error("\u64CD\u4F5C\u88AB\u963B\u6B62");
3491
+ }
3492
+ if (!conversation.messages[conversationId]) {
3493
+ setInitMessage(conversationId);
3494
+ }
3495
+ if (conversation.messages[conversationId].message.length === 0) {
3496
+ const { data } = await config.services.request.fetchMessages({
3497
+ ...config.params.convMeta,
3498
+ conversationId
3499
+ });
3500
+ conversation.messages[conversationId].message = [];
3501
+ if (data?.length) {
3502
+ data.forEach((msg) => {
3503
+ processMessageContent(msg);
3504
+ });
3505
+ finalizeHistoryMessages(conversationId);
3506
+ normalizeMessagesByExecutionAndRole(conversation.messages[conversationId].message);
3507
+ }
3508
+ }
3509
+ config.hooks?.onAfterInitMessages?.(conversation.messages[conversationId].message);
3510
+ config.hooks?.onAfterInit?.();
3511
+ };
3512
+ function findExecutionMsgIndex(msg, messages) {
3513
+ return (messages || []).findLastIndex((item) => item.executionId === msg.executionId && item.role === msg.role);
3514
+ }
3515
+ function normalizeMessagesByExecutionAndRole(messages) {
3516
+ if (!messages?.length) return;
3517
+ const mergedMessages = [];
3518
+ const groupedMessageIndex = /* @__PURE__ */ new Map();
3519
+ messages.forEach((item) => {
3520
+ const key = `${item.executionId}-${item.role}`;
3521
+ const existedIndex = groupedMessageIndex.get(key);
3522
+ if (common.isNullOrUnDef(existedIndex)) {
3523
+ mergedMessages.push({
3524
+ ...item,
3525
+ content: [...item.content || []],
3526
+ files: item.files ? [...item.files] : item.files
3527
+ });
3528
+ groupedMessageIndex.set(key, mergedMessages.length - 1);
3529
+ return;
3530
+ }
3531
+ const target = mergedMessages[existedIndex];
3532
+ target.content = [...target.content || [], ...item.content || []];
3533
+ if ((!target.files || target.files.length === 0) && item.files?.length) {
3534
+ target.files = [...item.files];
3535
+ }
3536
+ if (item.generating !== void 0) {
3537
+ target.generating = item.generating;
3538
+ }
3539
+ if (item.stopFlag) {
3540
+ target.stopFlag = true;
3541
+ }
3542
+ if (item.feedback !== void 0) {
3543
+ target.feedback = item.feedback;
3544
+ }
3545
+ if (item.params !== void 0) {
3546
+ target.params = item.params;
3547
+ }
3548
+ if (item.quoteMsg !== void 0) {
3549
+ target.quoteMsg = item.quoteMsg;
3550
+ }
3551
+ if (!target.createdAt && item.createdAt) {
3552
+ target.createdAt = item.createdAt;
3553
+ }
3554
+ if (!target.messageId && item.messageId) {
3555
+ target.messageId = item.messageId;
3556
+ }
3557
+ });
3558
+ if (mergedMessages.length !== messages.length) {
3559
+ messages.splice(0, messages.length, ...mergedMessages);
3560
+ }
3561
+ }
3562
+ function finalizeHistoryMessages(conversationId) {
3563
+ const currentConversation = conversation.messages[conversationId];
3564
+ if (!currentConversation?.message) return;
3565
+ currentConversation.loading = false;
3566
+ currentConversation.message.forEach((item) => {
3567
+ item.generating = false;
3568
+ });
3569
+ }
3570
+ function startCallback(msg) {
3571
+ const messages = conversation.messages[msg.conversationId]?.message;
3572
+ if (!messages) return;
3573
+ const idx = findExecutionMsgIndex(msg, messages);
3574
+ const contentItem = msg.content[0];
3575
+ if (contentItem.type !== "runStarted") return;
3576
+ if (idx === -1) {
3577
+ const finalMsg = {
3578
+ ...msg,
3579
+ content: [contentItem],
3580
+ generating: true
3581
+ };
3582
+ messages.push(finalMsg);
3583
+ const targetConversation = conversations.list.items.find((item) => item.id === msg.conversationId);
3584
+ if (targetConversation && msg.createdAt) {
3585
+ updateConversations({
3586
+ ...targetConversation,
3587
+ id: targetConversation.id,
3588
+ title: targetConversation.label,
3589
+ updatedAt: msg.createdAt
3590
+ });
3591
+ }
3592
+ } else {
3593
+ const prevContent = messages[idx]?.content || [];
3594
+ messages[idx].content = [...prevContent, contentItem];
3595
+ }
3596
+ conversation.messages[msg.conversationId].loading = true;
3597
+ }
3598
+ function textCallback(msg) {
3599
+ const messages = conversation.messages[msg.conversationId]?.message;
3600
+ const idx = findExecutionMsgIndex(msg, messages);
3601
+ const contents = idx !== -1 && messages[idx] ? messages[idx].content || [] : [];
3602
+ const nextContent = msg.content[0];
3603
+ if (nextContent.type !== "text") return;
3604
+ const normalizedNextContent = { ...nextContent };
3605
+ if (idx === -1) {
3606
+ const finalMsg = {
3607
+ ...msg,
3608
+ content: [normalizedNextContent],
3609
+ generating: true
3610
+ };
3611
+ messages.push(finalMsg);
3612
+ } else {
3613
+ const lastContent = contents[contents.length - 1];
3614
+ if (lastContent?.type === "text") {
3615
+ const lastTextContent = lastContent;
3616
+ const mergedMessageContent = (lastTextContent.messageContent || "") + (normalizedNextContent.messageContent || "");
3617
+ const mergedReasoningContent = nextContent.reasoningContent ? (lastTextContent.reasoningContent || "") + nextContent.reasoningContent : lastTextContent.reasoningContent;
3618
+ const nextTextContent = {
3619
+ ...lastTextContent,
3620
+ messageContent: mergedMessageContent,
3621
+ reasoningContent: mergedReasoningContent
3622
+ };
3623
+ messages[idx].content = [...contents.slice(0, -1), nextTextContent];
3624
+ } else {
3625
+ messages[idx].content = [...contents, normalizedNextContent];
3626
+ }
3627
+ }
3628
+ conversation.messages[msg.conversationId].loading = true;
3629
+ }
3630
+ function stepStartedCallback(msg) {
3631
+ const messages = conversation.messages[msg.conversationId]?.message;
3632
+ const idx = findExecutionMsgIndex(msg, messages);
3633
+ const contentItem = msg.content[0];
3634
+ conversation.messages[msg.conversationId].loading = true;
3635
+ if (idx !== -1 && messages[idx]) {
3636
+ const contentList = messages[idx].content || [];
3637
+ const runStartedIndex = contentList.findIndex((item) => item.type === "runStarted");
3638
+ const runStartedItem = runStartedIndex !== -1 ? contentList[runStartedIndex] : void 0;
3639
+ if (runStartedItem && contentItem.title) {
3640
+ const nextRunStartedItem = { ...runStartedItem, title: contentItem.title };
3641
+ messages[idx].content = contentList.map((item, i) => i === runStartedIndex ? nextRunStartedItem : item);
3642
+ }
3643
+ }
3644
+ const nodeId = contentItem.stepId;
3645
+ if (nodeId && config.params.convMeta.mode === CONV_MODE.DEBUG && agent.agentInfo.agentType === 1 /* FLOW */) ;
3646
+ }
3647
+ function stepFinishedCallback(msg) {
3648
+ conversation.messages[msg.conversationId].loading = true;
3649
+ const nodeId = msg.content[0].stepId;
3650
+ if (nodeId && config.params.convMeta.mode === CONV_MODE.DEBUG && agent.agentInfo.agentType === 1 /* FLOW */) ;
3651
+ }
3652
+ function stepErrCallback(msg) {
3653
+ conversation.messages[msg.conversationId].loading = false;
3654
+ const messages = conversation.messages[msg.conversationId]?.message;
3655
+ if (messages) {
3656
+ const idx = findExecutionMsgIndex(msg, messages);
3657
+ const contentItem = msg.content[0];
3658
+ messages.forEach((item) => {
3659
+ if (item.executionId === msg.executionId) {
3660
+ item.generating = false;
3661
+ }
3662
+ });
3663
+ if (idx !== -1) {
3664
+ messages[idx].generating = false;
3665
+ }
3666
+ if (idx !== -1) {
3667
+ const prevContent = messages[idx]?.content || [];
3668
+ messages[idx].content = [...prevContent, contentItem];
3669
+ } else {
3670
+ const finalMsg = { ...msg };
3671
+ finalMsg.generating = false;
3672
+ messages.push(finalMsg);
3673
+ }
3674
+ }
3675
+ const nodeId = msg.content[0].stepId;
3676
+ if (nodeId && config.params.convMeta.mode === CONV_MODE.DEBUG && agent.agentInfo.agentType === 1 /* FLOW */) ;
3677
+ }
3678
+ function doneCallback(msg) {
3679
+ conversation.messages[msg.conversationId].loading = false;
3680
+ const messages = conversation.messages[msg.conversationId]?.message;
3681
+ if (messages) {
3682
+ messages.forEach((item) => {
3683
+ if (item.executionId === msg.executionId) {
3684
+ item.generating = false;
3685
+ }
3686
+ });
3687
+ }
3688
+ }
3689
+ function titleCallback(msg) {
3690
+ const content = msg.content[0];
3691
+ if (content.type !== "conversationNewTitle") return;
3692
+ const title = content.title || "";
3693
+ const conversationId = msg.conversationId || "";
3694
+ if (content && conversations.list.items.length) {
3695
+ const idx = conversations.list.items.findIndex((item) => item.id === conversationId);
3696
+ if (idx === -1) return;
3697
+ conversations.list.items[idx].label = title;
3698
+ }
3699
+ }
3700
+ function toolCallCallback(msg) {
3701
+ const messages = conversation.messages[msg.conversationId]?.message;
3702
+ if (!messages) return;
3703
+ let idx = -1;
3704
+ const contentItem = msg.content[0];
3705
+ if (contentItem.type !== "toolCall") return;
3706
+ if (contentItem.toolCallId) {
3707
+ idx = messages.findLastIndex((m) => m.content?.some((c) => c.type === "toolCall" && c.toolCallId === contentItem.toolCallId));
3708
+ }
3709
+ if (idx === -1) {
3710
+ idx = findExecutionMsgIndex(msg, messages);
3711
+ }
3712
+ if (idx === -1) {
3713
+ const finalMsg = { ...msg, generating: true };
3714
+ messages.push(finalMsg);
3715
+ } else {
3716
+ const contents = messages[idx].content;
3717
+ const existingItemIndex = contents.findIndex(
3718
+ (item) => item.type === "toolCall" && item.toolCallId === contentItem.toolCallId
3719
+ );
3720
+ if (existingItemIndex !== -1) {
3721
+ const existingItem = contents[existingItemIndex];
3722
+ const newContent = contentItem.content || contentItem.arguments;
3723
+ const nextItem = { ...existingItem };
3724
+ if (typeof newContent === "string") {
3725
+ nextItem.content = (existingItem.content || "") + newContent;
3726
+ } else if (newContent !== void 0) {
3727
+ nextItem.arguments = newContent;
3728
+ }
3729
+ if (contentItem.toolName) {
3730
+ nextItem.toolName = contentItem.toolName;
3731
+ }
3732
+ if (contentItem.title) {
3733
+ nextItem.title = contentItem.title;
3734
+ }
3735
+ if (contentItem.status) {
3736
+ nextItem.status = contentItem.status;
3737
+ }
3738
+ messages[idx].content = contents.map((item, i) => i === existingItemIndex ? nextItem : item);
3739
+ } else {
3740
+ messages[idx].content = [...contents, contentItem];
3741
+ }
3742
+ }
3743
+ conversation.messages[msg.conversationId].loading = true;
3744
+ }
3745
+ function toolResultCallback(msg) {
3746
+ const messages = conversation.messages[msg.conversationId]?.message;
3747
+ if (!messages) return;
3748
+ const contentItem = msg.content[0];
3749
+ if (contentItem.type !== "toolResult") return;
3750
+ let idx = -1;
3751
+ if (contentItem.toolCallId) {
3752
+ idx = messages.findLastIndex((m) => m.content?.some((c) => c.type === "toolCall" && c.toolCallId === contentItem.toolCallId));
3753
+ }
3754
+ if (idx === -1) {
3755
+ idx = findExecutionMsgIndex(msg, messages);
3756
+ }
3757
+ if (idx === -1) return;
3758
+ const contents = messages[idx].content;
3759
+ const toolCallIndex = contents.findIndex((item) => item.type === "toolCall" && item.toolCallId === contentItem.toolCallId);
3760
+ if (toolCallIndex !== -1) {
3761
+ const toolCallItem = contents[toolCallIndex];
3762
+ const nextToolCallItem = {
3763
+ ...toolCallItem,
3764
+ result: contentItem.result ?? contentItem.content
3765
+ };
3766
+ if (contentItem.status) {
3767
+ nextToolCallItem.status = contentItem.status;
3768
+ }
3769
+ if (contentItem.errorMessage) {
3770
+ nextToolCallItem.errorMessage = contentItem.errorMessage;
3771
+ }
3772
+ if (contentItem.duration) {
3773
+ nextToolCallItem.duration = contentItem.duration;
3774
+ }
3775
+ if (contentItem.title) {
3776
+ nextToolCallItem.title = contentItem.title;
3777
+ }
3778
+ messages[idx].content = contents.map((item, i) => i === toolCallIndex ? nextToolCallItem : item);
3779
+ } else {
3780
+ messages[idx].content = [...contents, contentItem];
3781
+ }
3782
+ conversation.messages[msg.conversationId].loading = true;
3783
+ }
3784
+ function a2uiCommandCallback(msg) {
3785
+ const messages = conversation.messages[msg.conversationId]?.message;
3786
+ if (!messages) return;
3787
+ const idx = findExecutionMsgIndex(msg, messages);
3788
+ const contentItem = msg.content[0];
3789
+ if (contentItem.type !== "a2uiCommand") return;
3790
+ if (idx === -1) {
3791
+ const finalMsg = { ...msg, generating: true };
3792
+ messages.push(finalMsg);
3793
+ } else {
3794
+ const prevContent = messages[idx]?.content || [];
3795
+ messages[idx].content = [...prevContent, contentItem];
3796
+ }
3797
+ conversation.messages[msg.conversationId].loading = true;
3798
+ }
3799
+ function processSingleMessageContent(newMessage) {
3800
+ switch (newMessage.content[0].type) {
3801
+ case "runStarted":
3802
+ startCallback(newMessage);
3803
+ break;
3804
+ case "text":
3805
+ textCallback(newMessage);
3806
+ break;
3807
+ case "stepStarted":
3808
+ stepStartedCallback(newMessage);
3809
+ break;
3810
+ case "stepFinished":
3811
+ stepFinishedCallback(newMessage);
3812
+ break;
3813
+ case "stepError":
3814
+ stepErrCallback(newMessage);
3815
+ break;
3816
+ case "runFinished":
3817
+ case "runStopped":
3818
+ doneCallback(newMessage);
3819
+ break;
3820
+ case "conversationNewTitle":
3821
+ titleCallback(newMessage);
3822
+ break;
3823
+ case "toolCall":
3824
+ toolCallCallback(newMessage);
3825
+ break;
3826
+ case "toolResult":
3827
+ toolResultCallback(newMessage);
3828
+ break;
3829
+ case "a2uiCommand":
3830
+ a2uiCommandCallback(newMessage);
3831
+ break;
3832
+ default: {
3833
+ const messages = conversation.messages[newMessage.conversationId]?.message;
3834
+ if (!messages) return;
3835
+ const idx = findExecutionMsgIndex(newMessage, messages);
3836
+ if (idx === -1) {
3837
+ const finalMsg = { ...newMessage, generating: true };
3838
+ messages.push(finalMsg);
3839
+ } else {
3840
+ const prevContent = messages[idx]?.content || [];
3841
+ messages[idx].content = [...prevContent, newMessage.content[0]];
3842
+ }
3843
+ conversation.messages[newMessage.conversationId].loading = true;
3844
+ break;
3845
+ }
3846
+ }
3847
+ }
3848
+ function processMessageContent(newMessage) {
3849
+ const contentList = Array.isArray(newMessage.content) ? newMessage.content : [];
3850
+ if (contentList.length === 0) {
3851
+ const messages = conversation.messages[newMessage.conversationId]?.message;
3852
+ if (!messages) return;
3853
+ const idx = findExecutionMsgIndex(newMessage, messages);
3854
+ if (idx === -1) {
3855
+ messages.push({ ...newMessage });
3856
+ } else {
3857
+ const prevContent = messages[idx]?.content || [];
3858
+ messages[idx] = {
3859
+ ...messages[idx],
3860
+ ...newMessage,
3861
+ content: prevContent
3862
+ };
3863
+ }
3864
+ normalizeMessagesByExecutionAndRole(messages);
3865
+ return;
3866
+ }
3867
+ contentList.forEach((contentItem) => {
3868
+ processSingleMessageContent({
3869
+ ...newMessage,
3870
+ content: [contentItem]
3871
+ });
3872
+ });
3873
+ normalizeMessagesByExecutionAndRole(conversation.messages[newMessage.conversationId]?.message);
3874
+ }
3875
+ function isStoppedIncomingMessage(newMessage) {
3876
+ const messages = conversation.messages[newMessage.conversationId]?.message;
3877
+ if (!messages) return false;
3878
+ return messages.some((item) => item.stopFlag && item.executionId === newMessage.executionId);
3879
+ }
3880
+ const acceptMessage = async (newMessage) => {
3881
+ const conversationId = newMessage.conversationId;
3882
+ if (!conversation.messages[conversationId]?.message) return;
3883
+ const canProceed = await config.hooks?.onBeforeAcceptMessage?.(newMessage);
3884
+ if (canProceed === false) {
3885
+ throw new Error("\u64CD\u4F5C\u88AB\u963B\u6B62");
3886
+ }
3887
+ if (isStoppedIncomingMessage(newMessage)) {
3888
+ conversation.messages[conversationId].loading = false;
3889
+ return;
3890
+ }
3891
+ processMessageContent(newMessage);
3892
+ };
3893
+ const sendMessage = async (message3, files = [], params) => {
3894
+ const conversationId = conversation.active.id;
3895
+ if (conversation.messages[conversationId].loading) return;
3896
+ let msgContent = "";
3897
+ const references = conversation.messages[conversationId].references;
3898
+ if (message3) {
3899
+ msgContent = message3;
3900
+ } else {
3901
+ if (references?.type === 1 && references?.content?.msgContent) {
3902
+ msgContent = references.content.msgContent + "\n";
3903
+ }
3904
+ msgContent = msgContent + conversation.messages[conversationId].content;
3905
+ }
3906
+ if (!msgContent) return;
3907
+ const canProceed = await config.hooks?.onBeforeSend?.(msgContent, files || []);
3908
+ if (canProceed === false) return;
3909
+ if (agent.agentInfo.userInput?.length) {
3910
+ const invalid = agent.agentInfo.userInput.some((item) => {
3911
+ const isRequired = item.rules?.some((r) => r.type === "required");
3912
+ if (isRequired) {
3913
+ if (item.type === "BOOLEAN") {
3914
+ return common.isNullOrUnDef(item.value);
3915
+ }
3916
+ return common.isNullOrUnDef(item.value) || item.value === "";
3917
+ }
3918
+ return false;
3919
+ });
3920
+ if (invalid) {
3921
+ antd.message.error("\u8BF7\u68C0\u67E5\u8F93\u5165\u53C2\u6570");
3922
+ return;
3923
+ }
3924
+ }
3925
+ conversation.messages[conversationId].loading = true;
3926
+ const idx = conversations.list.items.findIndex((item) => item.id === conversationId);
3927
+ if (idx !== -1 && !conversations.list.items[idx].label) {
3928
+ conversations.list.items[idx].label = "\u65B0\u4F1A\u8BDD";
3929
+ }
3930
+ const sendParams = {
3931
+ conversationId,
3932
+ message: msgContent,
3933
+ convMeta: config.params.convMeta,
3934
+ files: conversation.messages[conversationId].files,
3935
+ params,
3936
+ spec: {
3937
+ ...conversation.active.spec,
3938
+ model: agent.model
3939
+ },
3940
+ stream: true,
3941
+ responseMode: 2
3942
+ };
3943
+ const extraParams = common.deepCopy(config.params?.params || {});
3944
+ const userInputParams = variablesToObject(agent.agentInfo.userInput || []);
3945
+ Object.assign(extraParams, userInputParams);
3946
+ sendParams.params = extraParams;
3947
+ if (!message3) {
3948
+ setContent("");
3949
+ setContentParams();
3950
+ setFileList([]);
3951
+ setReferences();
3952
+ setHeaderOpen(false);
3953
+ }
3954
+ try {
3955
+ await config.services.request.sendMessageStream(sendParams, agent.agentInfo?.id || "");
3956
+ config.hooks?.onAfterSend?.();
3957
+ } finally {
3958
+ }
3959
+ };
3960
+ const cancelReceive = async () => {
3961
+ const messages = conversation.messages[conversation.active.id].message;
3962
+ if (messages.length > 0) {
3963
+ const lastMsg = messages[messages.length - 1];
3964
+ if (lastMsg.executionId) {
3965
+ await config.services.request.cancelMessage(lastMsg.executionId);
3966
+ messages.forEach((item) => {
3967
+ if (item.executionId === lastMsg.executionId) {
3968
+ item.generating = false;
3969
+ item.stopFlag = true;
3970
+ if (item.content && Array.isArray(item.content)) {
3971
+ item.content.forEach((contentItem) => {
3972
+ if (contentItem.type === "toolCall" && contentItem.status !== "success" && contentItem.status !== "error") {
3973
+ contentItem.status = "error";
3974
+ }
3975
+ });
3976
+ }
3977
+ }
3978
+ });
3979
+ } else {
3980
+ lastMsg.stopFlag = true;
3981
+ lastMsg.generating = false;
3982
+ }
3983
+ }
3984
+ conversation.messages[conversation.active.id].loading = false;
3985
+ };
3986
+ return {
3987
+ /** 全局配置对象 */
3988
+ config,
3989
+ /** 设置服务配置 */
3990
+ setServices,
3991
+ /** 智能体状态 */
3992
+ agent,
3993
+ /** 设置智能体模型 */
3994
+ setAgentModel,
3995
+ /** 设置文件预览 */
3996
+ setPreview,
3997
+ /** 设置参数 */
3998
+ setParams,
3999
+ /** 设置布局配置 */
4000
+ setLayout,
4001
+ /** 设置生命周期钩子 */
4002
+ setHooks,
4003
+ /** 获取智能体详情 */
4004
+ getAgentInfo,
4005
+ /** 设置智能体 */
4006
+ setAgent,
4007
+ /** 设置智能体用户输入 */
4008
+ setUserInput,
4009
+ /** 设置会话配置 */
4010
+ setConversationSpec,
4011
+ /** 历史会话状态 */
4012
+ conversations,
4013
+ /** 获取会话列表 */
4014
+ getConversations,
4015
+ /** 删除会话 */
4016
+ delConversation,
4017
+ /** 设置内容参数,透传大模型后清空 */
4018
+ setContentParams,
4019
+ /** 当前会话状态 */
4020
+ conversation,
4021
+ /** 设置引用消息 */
4022
+ setReferences,
4023
+ /** 设置消息内容 */
4024
+ setContent,
4025
+ /** 设置文件列表 */
4026
+ setFileList,
4027
+ /** 设置头部展开状态 */
4028
+ setHeaderOpen,
4029
+ /** 创建新会话 */
4030
+ createConversation,
4031
+ /** 切换会话 */
4032
+ switchConversation,
4033
+ /** 初始化会话 */
4034
+ initConversation,
4035
+ /** 发送消息 */
4036
+ sendMessage,
4037
+ /** 取消接收 */
4038
+ cancelReceive,
4039
+ /** 接收消息 */
4040
+ acceptMessage,
4041
+ /** 获取智能体用户输入 */
4042
+ getUserInput,
4043
+ /** 消息反馈 */
4044
+ feedback
4045
+ };
4046
+ }
4047
+ var ConversationList_default = () => {
4048
+ const chatStore = useChatStore();
4049
+ const conversationsState = valtio.useSnapshot(chatStore.conversations);
4050
+ const conversationState = valtio.useSnapshot(chatStore.conversation);
4051
+ const conversationList = React9.useMemo(() => {
4052
+ return conversationsState.list.items.filter((item) => item.label);
4053
+ }, [conversationsState.list.items]);
4054
+ const menuConfig = (conversation) => ({
4055
+ items: [
4056
+ {
4057
+ label: "\u5220\u9664",
4058
+ key: "deleteChat",
4059
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.DeleteOutlined, {}),
4060
+ danger: true
4061
+ }
4062
+ ],
4063
+ onClick: (itemInfo) => {
4064
+ itemInfo.domEvent.stopPropagation();
4065
+ if (itemInfo.key === "deleteChat") {
4066
+ chatStore.delConversation(conversation.key);
4067
+ }
4068
+ }
4069
+ });
4070
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "height-full scroll-fade-in", id: "scrollableDiv", children: conversationList.length ? /* @__PURE__ */ jsxRuntime.jsx(
4071
+ InfiniteScroll__default.default,
4072
+ {
4073
+ dataLength: conversationList.length,
4074
+ hasMore: false,
4075
+ next: () => {
4076
+ console.log("next");
4077
+ },
4078
+ loader: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center", children: /* @__PURE__ */ jsxRuntime.jsx(antd.Spin, { indicator: /* @__PURE__ */ jsxRuntime.jsx(icons.RedoOutlined, { spin: true }), size: "small" }) }),
4079
+ style: { overflow: "hidden" },
4080
+ scrollableTarget: "scrollableDiv",
4081
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4082
+ xV2.Conversations,
4083
+ {
4084
+ className: styles_module_default2.conversations,
4085
+ items: conversationList,
4086
+ activeKey: conversationState.active.id,
4087
+ onActiveChange: async (id) => chatStore.switchConversation(id),
4088
+ groupable: true,
4089
+ menu: menuConfig
4090
+ }
4091
+ )
4092
+ }
4093
+ ) : /* @__PURE__ */ jsxRuntime.jsx(antd.Empty, { description: "\u6682\u65E0\u4F1A\u8BDD\u8BB0\u5F55", image: antd.Empty.PRESENTED_IMAGE_SIMPLE }) }) });
4094
+ };
4095
+ var ChatHeader_default = ({ title = true, avatar = true, closeBtn = false, newConversationBtn = true, conversationListBtn = true }) => {
4096
+ const chatStore = useChatStore();
4097
+ const agentState = valtio.useSnapshot(chatStore.agent);
4098
+ const configState = valtio.useSnapshot(chatStore.config);
4099
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { justify: "space-between", align: "center", className: classNames7__default.default(styles_module_default2.chatHeader, "zero-chat-header"), children: [
4100
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { gap: 4, align: "center", children: [
4101
+ /* @__PURE__ */ jsxRuntime.jsx(
4102
+ common.RenderWrapper,
4103
+ {
4104
+ control: avatar,
4105
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(antd.Avatar, { size: 22, src: agentState.agentInfo.iconUrl, alt: agentState.agentInfo.name })
4106
+ }
4107
+ ),
4108
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: title, DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles_module_default2.chatTitle, children: agentState.agentInfo.name }) })
4109
+ ] }),
4110
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Space, { size: 2, children: [
4111
+ /* @__PURE__ */ jsxRuntime.jsx(
4112
+ common.RenderWrapper,
4113
+ {
4114
+ control: newConversationBtn,
4115
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { title: "\u65B0\u5EFA\u4F1A\u8BDD", type: "text", size: "large", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.PlusOutlined, {}), onClick: () => chatStore.createConversation() })
4116
+ }
4117
+ ),
4118
+ /* @__PURE__ */ jsxRuntime.jsx(
4119
+ common.RenderWrapper,
4120
+ {
4121
+ control: conversationListBtn,
4122
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(
4123
+ antd.Popover,
4124
+ {
4125
+ getPopupContainer: (e) => e,
4126
+ placement: "bottom",
4127
+ classNames: { container: styles_module_default2.popover },
4128
+ content: /* @__PURE__ */ jsxRuntime.jsx(ConversationList_default, {}),
4129
+ trigger: ["click"],
4130
+ children: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { title: "\u5386\u53F2\u4F1A\u8BDD", type: "text", size: "large", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CommentOutlined, {}) })
4131
+ }
4132
+ )
4133
+ }
4134
+ ),
4135
+ /* @__PURE__ */ jsxRuntime.jsx(
4136
+ common.RenderWrapper,
4137
+ {
4138
+ control: closeBtn,
4139
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { title: "\u5173\u95ED", type: "text", size: "large", onClick: configState.hooks?.onHeaderClose, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CloseOutlined, {}) })
4140
+ }
4141
+ )
4142
+ ] })
4143
+ ] }) });
4144
+ };
4145
+ var { Text: Text3 } = antd.Typography;
4146
+ var ConversationListHeader_default = ({ title = true, avatar = true, newConversationBtn = true }) => {
4147
+ const chatStore = useChatStore();
4148
+ const agentState = valtio.useSnapshot(chatStore.agent);
4149
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { className: "p-24", gap: 16, vertical: true, children: [
4150
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { align: "center", gap: 16, children: [
4151
+ /* @__PURE__ */ jsxRuntime.jsx(
4152
+ common.RenderWrapper,
4153
+ {
4154
+ control: avatar,
4155
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(antd.Avatar, { size: 50, src: agentState.agentInfo?.iconUrl, shape: "square", style: { flexShrink: 0 }, children: (agentState.agentInfo?.name || "AI").slice(0, 1) })
4156
+ }
4157
+ ),
4158
+ /* @__PURE__ */ jsxRuntime.jsx(
4159
+ common.RenderWrapper,
4160
+ {
4161
+ control: title,
4162
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { vertical: true, gap: 4, flex: 1, style: { minWidth: 0 }, children: [
4163
+ /* @__PURE__ */ jsxRuntime.jsx(Text3, { strong: true, className: classNames7__default.default("fz-16"), children: agentState.agentInfo.name }),
4164
+ /* @__PURE__ */ jsxRuntime.jsx(Text3, { type: "secondary", ellipsis: true, className: classNames7__default.default("fz-12"), children: agentState.agentInfo.description })
4165
+ ] }) })
4166
+ }
4167
+ )
4168
+ ] }),
4169
+ /* @__PURE__ */ jsxRuntime.jsx(
4170
+ common.RenderWrapper,
4171
+ {
4172
+ control: newConversationBtn,
4173
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(
4174
+ antd.Button,
4175
+ {
4176
+ block: true,
4177
+ type: "primary",
4178
+ onClick: () => chatStore.createConversation(),
4179
+ className: classNames7__default.default(styles_module_default2.createConversationButton),
4180
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.PlusOutlined, {}),
4181
+ children: "\u65B0\u5EFA\u4F1A\u8BDD"
4182
+ }
4183
+ )
4184
+ }
4185
+ )
4186
+ ] });
4187
+ };
4188
+ var ConversationListPanel = ({ header }) => {
4189
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { vertical: true, className: classNames7__default.default("height-full", "zero-chat-conversations", styles_module_default2.conversationListPanel), children: [
4190
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: header, DefaultComponent: ConversationListHeader_default }),
4191
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "full-scroll", children: /* @__PURE__ */ jsxRuntime.jsx(ConversationList_default, {}) })
4192
+ ] });
4193
+ };
4194
+ var ConversationListPanel_default = ConversationListPanel;
4195
+ var IconFont = icons.createFromIconfontCN({});
4196
+ var icon_font_default = IconFont;
4197
+ var { Text: Text4 } = antd.Typography;
4198
+ var FeaturesRenderer_default = ({ skillsBtn, knowledgeBtn }) => {
4199
+ const chatStore = useChatStore();
4200
+ const agentState = valtio.useSnapshot(chatStore.agent);
4201
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4202
+ /* @__PURE__ */ jsxRuntime.jsxs(
4203
+ antd.Flex,
4204
+ {
4205
+ className: classNames7__default.default(styles_module_default2.resourceBtn, { [styles_module_default2.resourceBtnActive]: agentState.model.reasoning }),
4206
+ onClick: () => chatStore.setAgentModel({ ...agentState.model, reasoning: !agentState.model.reasoning }),
4207
+ children: [
4208
+ /* @__PURE__ */ jsxRuntime.jsx(icon_font_default, { type: "icon-remark" }),
4209
+ /* @__PURE__ */ jsxRuntime.jsx(Text4, { style: { color: agentState.model.reasoning ? "#fff" : "#000" }, children: "\u6DF1\u5EA6\u601D\u8003" })
4210
+ ]
4211
+ }
4212
+ ),
4213
+ /* @__PURE__ */ jsxRuntime.jsx(
4214
+ common.RenderWrapper,
4215
+ {
4216
+ control: skillsBtn,
4217
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsxs(
4218
+ antd.Flex,
4219
+ {
4220
+ className: classNames7__default.default(styles_module_default2.resourceBtn, { [styles_module_default2.resourceBtnActive]: agentState.model.reasoning }),
4221
+ onClick: () => chatStore.setAgentModel({ ...agentState.model, reasoning: !agentState.model.reasoning }),
4222
+ children: [
4223
+ /* @__PURE__ */ jsxRuntime.jsx(icon_font_default, { type: "icon-remark" }),
4224
+ /* @__PURE__ */ jsxRuntime.jsx(Text4, { style: { color: agentState.model.reasoning ? "#fff" : "#000" }, children: "\u6280\u80FD" })
4225
+ ]
4226
+ }
4227
+ )
4228
+ }
4229
+ ),
4230
+ /* @__PURE__ */ jsxRuntime.jsx(
4231
+ common.RenderWrapper,
4232
+ {
4233
+ control: knowledgeBtn,
4234
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsxs(
4235
+ antd.Flex,
4236
+ {
4237
+ className: classNames7__default.default(styles_module_default2.resourceBtn, { [styles_module_default2.resourceBtnActive]: agentState.model.reasoning }),
4238
+ onClick: () => chatStore.setAgentModel({ ...agentState.model, reasoning: !agentState.model.reasoning }),
4239
+ children: [
4240
+ /* @__PURE__ */ jsxRuntime.jsx(icon_font_default, { type: "icon-remark" }),
4241
+ /* @__PURE__ */ jsxRuntime.jsx(Text4, { style: { color: agentState.model.reasoning ? "#fff" : "#000" }, children: "\u77E5\u8BC6\u5E93" })
4242
+ ]
4243
+ }
4244
+ )
4245
+ }
4246
+ )
4247
+ ] });
4248
+ };
4249
+ var ChatSender_default2 = React9.forwardRef(
4250
+ ({ placeholder, extraBtn = false, referencesBtn = false, sendBtnProps, footerBelow = false, skillsBtn = false, knowledgeBtn = false }, ref) => {
4251
+ const chatStore = useChatStore();
4252
+ const configState = valtio.useSnapshot(chatStore.config);
4253
+ const agentState = valtio.useSnapshot(chatStore.agent);
4254
+ const conversationState = valtio.useSnapshot(chatStore.conversation);
4255
+ const fileUploadRequest = (formData, signal) => configState.services.request.chatUpload(agentState.agentInfo.id, formData, conversationState.active.id, signal);
4256
+ const chatMessage = React9.useMemo(
4257
+ () => conversationState.messages[conversationState.active.id] || {},
4258
+ [conversationState.messages[conversationState.active.id]]
4259
+ );
4260
+ const referenceContent = React9.useMemo(() => {
4261
+ const content = chatMessage.references?.content?.name;
4262
+ if (content) {
4263
+ return common.markdownToText(content);
4264
+ }
4265
+ }, [chatMessage.references]);
4266
+ const referenceHandle = (con) => {
4267
+ if (chatMessage?.loading) return;
4268
+ chatStore.setContent(con);
4269
+ chatStore.sendMessage();
4270
+ };
4271
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Flex, { vertical: true, gap: 8, className: "zero-chat-sender", children: /* @__PURE__ */ jsxRuntime.jsx(
4272
+ ChatSender_default,
4273
+ {
4274
+ ref,
4275
+ placeholder,
4276
+ content: chatMessage.content,
4277
+ fileList: chatMessage.files,
4278
+ headerOpen: chatMessage.headerOpen,
4279
+ loading: chatMessage.loading,
4280
+ onContentChange: chatStore.setContent,
4281
+ onFileListChange: chatStore.setFileList,
4282
+ onHeaderOpenChange: chatStore.setHeaderOpen,
4283
+ onSend: () => chatStore.sendMessage(),
4284
+ onCancel: chatStore.cancelReceive,
4285
+ onFocus: chatStore.config.hooks?.onSenderFocus,
4286
+ fileUpload: {
4287
+ request: fileUploadRequest,
4288
+ config: agentState.agentInfo.config?.options?.fileUpload
4289
+ },
4290
+ sendBtnProps: common.isFunction(sendBtnProps) ? sendBtnProps() : {},
4291
+ extraFooterBelow: /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: footerBelow }),
4292
+ extraFooter: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4293
+ /* @__PURE__ */ jsxRuntime.jsx(FeaturesRenderer_default, { skillsBtn, knowledgeBtn }),
4294
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: extraBtn })
4295
+ ] }),
4296
+ extraHeader: /* @__PURE__ */ jsxRuntime.jsx(
4297
+ xV2.Sender.Header,
4298
+ {
4299
+ title: /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { gap: 4, children: [
4300
+ /* @__PURE__ */ jsxRuntime.jsx(icons.EnterOutlined, {}),
4301
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Typography.Text, { type: "secondary", ellipsis: true, children: referenceContent })
4302
+ ] }),
4303
+ open: !!referenceContent,
4304
+ onOpenChange: () => chatStore.setReferences(),
4305
+ classNames: {
4306
+ header: styles_module_default2.senderReferenceHeaderTitle,
4307
+ content: common.shouldRender(referencesBtn) ? "" : styles_module_default2.senderReferenceHeaderContent
4308
+ },
4309
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4310
+ common.RenderWrapper,
4311
+ {
4312
+ control: referencesBtn,
4313
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(antd.Flex, { gap: 8, children: ["\u6DF1\u5EA6\u89E3\u8BFB", "\u6982\u8981\u89E3\u8BFB"].map((con) => /* @__PURE__ */ jsxRuntime.jsxs(antd.Button, { color: "primary", variant: "filled", onClick: () => referenceHandle(con), children: [
4314
+ con,
4315
+ " \u2192"
4316
+ ] }, con)) })
4317
+ }
4318
+ )
4319
+ }
4320
+ )
4321
+ }
4322
+ ) });
4323
+ }
4324
+ );
4325
+
4326
+ // src/assets/images/logo.png
4327
+ var logo_default = "./logo-BX4TAWHK.png";
4328
+ var ChatSenderHeader = () => {
4329
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles_module_default2.logoArea, children: [
4330
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles_module_default2.logoContainer, children: [
4331
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles_module_default2.staticHalo }),
4332
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles_module_default2.logoHoverWrapper, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: logo_default, alt: "LoLR.AI Logo", className: styles_module_default2.logoImage }) })
4333
+ ] }),
4334
+ /* @__PURE__ */ jsxRuntime.jsxs("h1", { className: styles_module_default2.greetingTitle, children: [
4335
+ "\u4F60\u597D\uFF0C\u6211\u662F ",
4336
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles_module_default2.gradientText, children: "LoLR.AI" })
4337
+ ] }),
4338
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles_module_default2.greetingSubtitle, children: "\u4ECA\u5929\u60F3\u63A2\u7D22\u70B9\u4EC0\u4E48\uFF1F" })
4339
+ ] });
4340
+ };
4341
+ var ChatSenderHeader_default = ChatSenderHeader;
4342
+ var MonacoEditor = ({ value = "", onChange, placeholder, height = 200, readOnly = false, style }) => {
4343
+ const handleKeyDownCapture = React9.useCallback((e) => {
4344
+ if (e.key === " " || e.code === "Space") {
4345
+ e.stopPropagation();
4346
+ }
4347
+ }, []);
4348
+ const handleKeyUpCapture = React9.useCallback((e) => {
4349
+ if (e.key === " " || e.code === "Space") {
4350
+ e.stopPropagation();
4351
+ }
4352
+ }, []);
4353
+ const handleScriptChange = React9.useCallback(
4354
+ (event) => {
4355
+ onChange?.(event.target.value || "");
4356
+ },
4357
+ [onChange]
4358
+ );
4359
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style, onKeyDownCapture: handleKeyDownCapture, onKeyUpCapture: handleKeyUpCapture, children: /* @__PURE__ */ jsxRuntime.jsx(
4360
+ antd.Input.TextArea,
4361
+ {
4362
+ value,
4363
+ onChange: handleScriptChange,
4364
+ readOnly,
4365
+ placeholder,
4366
+ autoSize: false,
4367
+ style: {
4368
+ height,
4369
+ resize: "vertical",
4370
+ fontFamily: 'Monaco, Menlo, Consolas, "Courier New", monospace',
4371
+ ...style
4372
+ }
4373
+ }
4374
+ ) });
4375
+ };
4376
+ var monaco_editor_default = MonacoEditor;
4377
+ var { Text: Text5 } = antd.Typography;
4378
+ var START_NODE_TYPE = "start";
4379
+ var FormFileUpload = ({ value, onChange, multiple = false }) => {
4380
+ const { token } = antd.theme.useToken();
4381
+ const fileList = Array.isArray(value) ? value : value ? [value] : [];
4382
+ const chatStore = useChatStore();
4383
+ const configState = valtio.useSnapshot(chatStore.config);
4384
+ const conversationState = valtio.useSnapshot(chatStore.conversation);
4385
+ const customRequest = async (options) => {
4386
+ const { file, onSuccess, onError } = options;
4387
+ try {
4388
+ const formData = new FormData();
4389
+ formData.append("file", file);
4390
+ const res = await configState.services.request.chatUpload(chatStore.agent.agentInfo.id, formData, conversationState.active.id);
4391
+ if (res.code === 200 && res.data?.length) {
4392
+ const uploadedFile = res.data[0];
4393
+ onSuccess(uploadedFile);
4394
+ if (multiple) {
4395
+ onChange?.([...fileList, uploadedFile]);
4396
+ } else {
4397
+ onChange?.([uploadedFile]);
4398
+ }
4399
+ } else {
4400
+ antd.message.error(res.message || "\u4E0A\u4F20\u5931\u8D25");
4401
+ onError(new Error(res.message));
4402
+ }
4403
+ } catch (error) {
4404
+ onError(error);
4405
+ }
4406
+ };
4407
+ const handleRemove = (fileToRemove) => {
4408
+ const newList = fileList.filter((f) => f.id !== fileToRemove.id);
4409
+ onChange?.(newList.length > 0 ? newList : void 0);
4410
+ };
4411
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { vertical: true, gap: 12, style: { width: "100%" }, children: [
4412
+ !multiple && fileList.length >= 1 ? null : /* @__PURE__ */ jsxRuntime.jsx(antd.Upload, { multiple, customRequest, showUploadList: false, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CloudUploadOutlined, {}), children: "\u4ECE\u672C\u5730\u4E0A\u4F20" }) }),
4413
+ fileList.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(antd.Flex, { vertical: true, gap: 8, children: fileList.map((file) => /* @__PURE__ */ jsxRuntime.jsxs(
4414
+ antd.Flex,
4415
+ {
4416
+ align: "center",
4417
+ justify: "space-between",
4418
+ style: {
4419
+ padding: "8px 12px",
4420
+ backgroundColor: token.colorFillAlter,
4421
+ borderRadius: token.borderRadiusLG || 8,
4422
+ border: `1px solid ${token.colorBorderSecondary}`
4423
+ },
4424
+ children: [
4425
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { align: "center", gap: 12, style: { overflow: "hidden", flex: 1 }, children: [
4426
+ /* @__PURE__ */ jsxRuntime.jsx(
4427
+ "div",
4428
+ {
4429
+ style: {
4430
+ width: 40,
4431
+ height: 40,
4432
+ backgroundColor: "#000",
4433
+ borderRadius: token.borderRadiusSM || 4,
4434
+ display: "flex",
4435
+ alignItems: "center",
4436
+ justifyContent: "center",
4437
+ flexShrink: 0
4438
+ },
4439
+ children: getFileIcon(file.extension || getFileExtension(file.name), 20)
4440
+ }
4441
+ ),
4442
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { overflow: "hidden", display: "flex", flexDirection: "column", flex: 1 }, children: [
4443
+ /* @__PURE__ */ jsxRuntime.jsx(Text5, { ellipsis: true, style: { width: "100%", fontSize: 14, fontWeight: 500 }, children: file.name }),
4444
+ /* @__PURE__ */ jsxRuntime.jsxs(Text5, { type: "secondary", style: { fontSize: 12 }, children: [
4445
+ (file.extension || getFileExtension(file.name)).toUpperCase(),
4446
+ " \u2022 ",
4447
+ formatFileSize(file.size)
4448
+ ] })
4449
+ ] })
4450
+ ] }),
4451
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { type: "text", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.DeleteOutlined, {}), onClick: () => handleRemove(file), style: { color: token.colorTextSecondary } })
4452
+ ]
4453
+ },
4454
+ file.id || file.uid
4455
+ )) })
4456
+ ] });
4457
+ };
4458
+ var FormMonacoEditor = ({ value, onChange }) => {
4459
+ const { token } = antd.theme.useToken();
4460
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { backgroundColor: token.colorFillAlter, padding: 8, borderRadius: token.borderRadius }, children: /* @__PURE__ */ jsxRuntime.jsx(monaco_editor_default, { language: "json", placeholder: "\u8BF7\u8F93\u5165\u503C...", height: 80, value, onChange }) });
4461
+ };
4462
+ var UserInputPanel = () => {
4463
+ const chatStore = useChatStore();
4464
+ const agentSnap = valtio.useSnapshot(chatStore.agent);
4465
+ const flowSpecSnap = valtio.useSnapshot(flowSpecState);
4466
+ const [form] = antd.Form.useForm();
4467
+ const [activeKey, setActiveKey] = React9.useState(["1"]);
4468
+ const { layout } = valtio.useSnapshot(chatStore.config);
4469
+ const startNode = React9.useMemo(() => {
4470
+ return flowSpecSnap.nodes.find((n) => String(n.type || "").toLowerCase() === START_NODE_TYPE);
4471
+ }, [flowSpecSnap.nodes]);
4472
+ const inputs = React9.useMemo(() => {
4473
+ if (agentSnap.agentInfo.userInput?.length > 0) {
4474
+ return agentSnap.agentInfo.userInput.filter((i) => i.enableEdit);
4475
+ }
4476
+ return (startNode?.data.input || []).filter((i) => i.enableEdit);
4477
+ }, [startNode, agentSnap.agentInfo.userInput]);
4478
+ React9.useEffect(() => {
4479
+ if (inputs.length > 0) {
4480
+ const initialValues = inputs.reduce((acc, cur) => {
4481
+ const value = cur.value;
4482
+ acc[cur.name] = value;
4483
+ return acc;
4484
+ }, {});
4485
+ form.setFieldsValue(initialValues);
4486
+ }
4487
+ }, [inputs, form]);
4488
+ const handleValuesChange = (changedValues) => {
4489
+ if (agentSnap.agentInfo.userInput?.length > 0) {
4490
+ const newInput = agentSnap.agentInfo.userInput.map((v) => {
4491
+ if (v.name in changedValues) {
4492
+ const newValue = changedValues[v.name];
4493
+ return { ...v, value: newValue };
4494
+ }
4495
+ return v;
4496
+ });
4497
+ chatStore.setAgent({ ...agentSnap.agentInfo, userInput: newInput });
4498
+ return;
4499
+ }
4500
+ const nodeIndex = flowSpecState.nodes.findIndex((n) => n.id === startNode?.id);
4501
+ if (nodeIndex > -1) {
4502
+ const currentInput = flowSpecState.nodes[nodeIndex].data.input;
4503
+ const newInput = currentInput.map((v) => {
4504
+ if (v.name in changedValues) {
4505
+ const newValue = changedValues[v.name];
4506
+ return { ...v, value: newValue };
4507
+ }
4508
+ return v;
4509
+ });
4510
+ flowSpecState.nodes[nodeIndex].data.input = newInput;
4511
+ }
4512
+ };
4513
+ const handleStartChat = () => {
4514
+ form.validateFields().then(() => {
4515
+ setActiveKey([]);
4516
+ }).catch(() => {
4517
+ antd.message.error("\u8BF7\u68C0\u67E5\u8F93\u5165\u53C2\u6570");
4518
+ });
4519
+ };
4520
+ const renderFormItem = (item) => {
4521
+ const itemStyle = { marginBottom: 0 };
4522
+ const commonProps = {
4523
+ label: item.name,
4524
+ name: item.name,
4525
+ style: itemStyle,
4526
+ rules: item.rules?.map((r) => {
4527
+ const valStr = String(r.value || "");
4528
+ if (r.type === "required") return { required: true, message: r.message };
4529
+ if (r.type === "email") return { type: "email", message: r.message };
4530
+ if (r.type === "pattern") return { pattern: new RegExp(valStr), message: r.message };
4531
+ if (r.type === "max" || r.type === "min") {
4532
+ return {
4533
+ validator: (_, val) => {
4534
+ if (val === void 0 || val === null || val === "") return Promise.resolve();
4535
+ const numVal = Number(val);
4536
+ if (isNaN(numVal)) return Promise.resolve();
4537
+ if (r.type === "max" && numVal > Number(valStr)) return Promise.reject(new Error(r.message));
4538
+ if (r.type === "min" && numVal < Number(valStr)) return Promise.reject(new Error(r.message));
4539
+ return Promise.resolve();
4540
+ }
4541
+ };
4542
+ }
4543
+ if (r.type === "length") {
4544
+ const [min, max] = valStr.split(",").map((v) => v ? Number(v) : void 0);
4545
+ return {
4546
+ validator: (_, val) => {
4547
+ if (val === void 0 || val === null || val === "") return Promise.resolve();
4548
+ const strVal = String(val);
4549
+ if (min !== void 0 && strVal.length < min) return Promise.reject(new Error(r.message));
4550
+ if (max !== void 0 && strVal.length > max) return Promise.reject(new Error(r.message));
4551
+ return Promise.resolve();
4552
+ }
4553
+ };
4554
+ }
4555
+ if (r.type === "size") {
4556
+ const [min, max] = valStr.split(",").map((v) => v ? Number(v) : void 0);
4557
+ return {
4558
+ validator: (_, val) => {
4559
+ if (val === void 0 || val === null || val === "") return Promise.resolve();
4560
+ let len = 0;
4561
+ if (Array.isArray(val)) {
4562
+ len = val.length;
4563
+ } else if (typeof val === "string") {
4564
+ try {
4565
+ const parsed = JSON.parse(val);
4566
+ if (Array.isArray(parsed)) len = parsed.length;
4567
+ else return Promise.resolve();
4568
+ } catch (e) {
4569
+ return Promise.resolve();
4570
+ }
4571
+ } else {
4572
+ return Promise.resolve();
4573
+ }
4574
+ if (min !== void 0 && len < min) return Promise.reject(new Error(r.message));
4575
+ if (max !== void 0 && len > max) return Promise.reject(new Error(r.message));
4576
+ return Promise.resolve();
4577
+ }
4578
+ };
4579
+ }
4580
+ if (r.type === "enum") {
4581
+ const options = valStr.split(",").map((s) => s.trim());
4582
+ return {
4583
+ validator: (_, val) => {
4584
+ if (val === void 0 || val === null || val === "") return Promise.resolve();
4585
+ if (options.includes(String(val))) return Promise.resolve();
4586
+ return Promise.reject(new Error(r.message));
4587
+ }
4588
+ };
4589
+ }
4590
+ return {};
4591
+ })
4592
+ };
4593
+ if (["STRING", "LONG"].includes(item.type)) {
4594
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Form.Item, { ...commonProps, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Input, { placeholder: "\u8BF7\u8F93\u5165\u503C" }) });
4595
+ }
4596
+ if (["NUMBER"].includes(item.type)) {
4597
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Form.Item, { ...commonProps, children: /* @__PURE__ */ jsxRuntime.jsx(antd.InputNumber, { style: { width: "100%" }, placeholder: "\u8BF7\u8F93\u5165\u6570\u503C" }) });
4598
+ }
4599
+ if (item.type === "BOOLEAN") {
4600
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Form.Item, { style: itemStyle, name: item.name, valuePropName: "checked", children: /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { justify: "space-between", align: "center", children: [
4601
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: item.name }),
4602
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Switch, { size: "small" })
4603
+ ] }) });
4604
+ }
4605
+ if (item.type === "FILE") {
4606
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Form.Item, { ...commonProps, children: /* @__PURE__ */ jsxRuntime.jsx(FormFileUpload, { multiple: false }) });
4607
+ }
4608
+ if (item.type === "ARRAY_FILE") {
4609
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Form.Item, { ...commonProps, children: /* @__PURE__ */ jsxRuntime.jsx(FormFileUpload, { multiple: true }) });
4610
+ }
4611
+ if (["OBJECT", "ARRAY", "ARRAY_STRING", "ARRAY_NUMBER", "ARRAY_DECIMAL", "ARRAY_BOOLEAN", "ARRAY_OBJECT"].includes(item.type)) {
4612
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Form.Item, { ...commonProps, children: /* @__PURE__ */ jsxRuntime.jsx(FormMonacoEditor, {}) });
4613
+ }
4614
+ return /* @__PURE__ */ jsxRuntime.jsx(antd.Form.Item, { ...commonProps, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Input, { placeholder: "\u8BF7\u8F93\u5165\u503C" }) });
4615
+ };
4616
+ const genExtra = () => {
4617
+ if (activeKey.includes("1")) return null;
4618
+ return /* @__PURE__ */ jsxRuntime.jsx(
4619
+ antd.Button,
4620
+ {
4621
+ type: "text",
4622
+ size: "small",
4623
+ onClick: (e) => {
4624
+ e.stopPropagation();
4625
+ setActiveKey(["1"]);
4626
+ },
4627
+ children: "\u7F16\u8F91"
4628
+ }
4629
+ );
4630
+ };
4631
+ const items = [
4632
+ {
4633
+ key: "1",
4634
+ label: "\u53C2\u6570\u8BBE\u7F6E",
4635
+ extra: genExtra(),
4636
+ children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4637
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Form, { form, layout: "vertical", onValuesChange: handleValuesChange, style: { maxHeight: 500, overflow: "auto", paddingRight: 16 }, children: inputs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(antd.Flex, { vertical: true, gap: 12, children: inputs.map((item) => /* @__PURE__ */ jsxRuntime.jsx(React9__default.default.Fragment, { children: renderFormItem(item) }, item.name)) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "10px", color: "#999", textAlign: "center" }, children: "\u6682\u65E0\u7528\u6237\u8F93\u5165\u5B57\u6BB5" }) }),
4638
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Flex, { align: "center", justify: "center", className: "m-t-16", children: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { type: "primary", onClick: handleStartChat, children: "\u5F00\u59CB\u4F1A\u8BDD" }) })
4639
+ ] })
4640
+ }
4641
+ ];
4642
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles_module_default2.userInputCollapse, children: /* @__PURE__ */ jsxRuntime.jsx(
4643
+ antd.Collapse,
4644
+ {
4645
+ activeKey,
4646
+ onChange: (keys) => {
4647
+ const newKeys = typeof keys === "string" ? [keys] : keys;
4648
+ setActiveKey(newKeys);
4649
+ },
4650
+ items,
4651
+ className: "m-16",
4652
+ styles: {
4653
+ body: {
4654
+ paddingRight: 0,
4655
+ paddingBottom: 10
4656
+ }
4657
+ }
4658
+ }
4659
+ ) });
4660
+ };
4661
+ var UserInputPanel_default = UserInputPanel;
4662
+
4663
+ // src/ui/layouts/components/styles.module.less
4664
+ var styles_module_default3 = {
4665
+ bodyWidth: "styles_module_bodyWidth",
4666
+ inputContainer: "styles_module_inputContainer",
4667
+ disclaimerNotice: "styles_module_disclaimerNotice",
4668
+ previewHeader: "styles_module_previewHeader",
4669
+ previewCloseBtn: "styles_module_previewCloseBtn",
4670
+ closeIcon: "styles_module_closeIcon",
4671
+ rotateIcon: "styles_module_rotateIcon"
4672
+ };
4673
+ var ChatMainPanel = React9.memo(
4674
+ React9.forwardRef((_props, ref) => {
4675
+ const chatStore = useChatStore();
4676
+ const senderRef = React9.useRef(null);
4677
+ React9.useImperativeHandle(
4678
+ ref,
4679
+ () => ({
4680
+ focus: (options) => {
4681
+ senderRef.current?.focus(options);
4682
+ }
4683
+ }),
4684
+ []
4685
+ );
4686
+ const configState = valtio.useSnapshot(chatStore.config);
4687
+ const agentState = valtio.useSnapshot(chatStore.agent);
4688
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { vertical: true, className: classNames7__default.default("height-full"), children: [
4689
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: configState.layout.chatHeader, DefaultComponent: ChatHeader_default }),
4690
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { justify: "center", align: "center", vertical: true, gap: 24, className: classNames7__default.default("height-full", styles_module_default3.bodyWidth), children: [
4691
+ common.shouldRender(agentState.agentInfo.userInput && agentState.agentInfo.userInput.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { DefaultComponent: UserInputPanel_default }),
4692
+ common.shouldRender(configState.layout.messageList) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "full-scroll", style: { width: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: configState.layout.messageList, DefaultComponent: BubbleListItems_default }) }),
4693
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: configState.layout.senderHeader, DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx(ChatSenderHeader_default, {}) }),
4694
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { className: styles_module_default3.inputContainer, vertical: true, gap: 8, children: [
4695
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { ref: senderRef, DefaultComponent: ChatSender_default2 }),
4696
+ /* @__PURE__ */ jsxRuntime.jsx(
4697
+ common.RenderWrapper,
4698
+ {
4699
+ control: configState.layout.disclaimerNotice,
4700
+ DefaultComponent: /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles_module_default3.disclaimerNotice, children: "\u5185\u5BB9\u7531AI\u751F\u6210\uFF0C\u4EC5\u4F9B\u53C2\u8003\uFF0C\u8BF7\u4ED4\u7EC6\u7504\u522B" })
4701
+ }
4702
+ ),
4703
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: configState.layout.senderFooter })
4704
+ ] })
4705
+ ] })
4706
+ ] });
4707
+ })
4708
+ );
4709
+ var ChatMainPanel_default = ChatMainPanel;
4710
+ var ChatPreviewPanel = React9.memo(({ agentId, conversationId, file }) => {
4711
+ const chatStore = useChatStore();
4712
+ const configState = valtio.useSnapshot(chatStore.config);
4713
+ const fileUrl = React9.useMemo(() => {
4714
+ if (file?.fileUrl) return file.fileUrl;
4715
+ if (!file?.path || !agentId || !conversationId) return "";
4716
+ const previewUrl = configState.services.request.getPreviewUrl(agentId, conversationId, file.path);
4717
+ return previewUrl;
4718
+ }, [agentId, conversationId, file]);
4719
+ const suffix = React9.useMemo(() => {
4720
+ const name = file?.fileName || file?.path || "";
4721
+ return name.split(".").pop() || file?.ext || "";
4722
+ }, [file]);
4723
+ const handleDownload = () => {
4724
+ let downloadUrl = file?.path;
4725
+ if (downloadUrl && !downloadUrl.startsWith("http")) {
4726
+ if (!agentId || !conversationId) return;
4727
+ downloadUrl = configState.services.request.getPreviewUrl(agentId, conversationId, downloadUrl);
4728
+ }
4729
+ if (downloadUrl) {
4730
+ const urlObj = new URL(downloadUrl, window.location.origin);
4731
+ urlObj.searchParams.set("NS-TOKEN", tokenManager.get() || "");
4732
+ window.open(urlObj.toString(), "_blank");
4733
+ }
4734
+ };
4735
+ return /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { vertical: true, style: { height: "100%", overflow: "hidden" }, children: [
4736
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { justify: "flex-end", className: styles_module_default3.previewHeader, children: [
4737
+ file?.path && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles_module_default3.previewCloseBtn, onClick: handleDownload, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { type: "text", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.DownloadOutlined, {}), className: styles_module_default3.closeIcon }) }),
4738
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: classNames7__default.default(styles_module_default3.previewCloseBtn, styles_module_default3.rotateIcon), onClick: () => chatStore.setPreview({ path: "", fileName: "" }), children: /* @__PURE__ */ jsxRuntime.jsx(antd.Button, { type: "text", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CloseOutlined, {}), className: styles_module_default3.closeIcon }) })
4739
+ ] }),
4740
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(common.FilePreview, { fileUrl, suffix }) })
4741
+ ] });
4742
+ });
4743
+ var ChatPreviewPanel_default = ChatPreviewPanel;
4744
+
4745
+ // src/ui/layouts/index.module.less
4746
+ var index_module_default2 = {
4747
+ chatLayout: "index_module_chatLayout",
4748
+ spinWrapper: "index_module_spinWrapper",
4749
+ animatedSplitter: "index_module_animatedSplitter",
4750
+ hideSplitterBar: "index_module_hideSplitterBar"
4751
+ };
4752
+ var layouts_default = React9.forwardRef(({ theme: theme4, params, hooks, layout, config, services }, _ref) => {
4753
+ const chatStore = React9.useMemo(() => createChatStore(), []);
4754
+ const senderRef = React9.useRef(null);
4755
+ React9.useImperativeHandle(
4756
+ _ref,
4757
+ () => ({
4758
+ sendMessage: chatStore.sendMessage,
4759
+ switchConversation: chatStore.switchConversation,
4760
+ createConversation: chatStore.createConversation,
4761
+ setReferences: chatStore.setReferences,
4762
+ setMessage: chatStore.setContent,
4763
+ setMessageParams: chatStore.setContentParams,
4764
+ setFiles: chatStore.setFileList,
4765
+ setServices: chatStore.setServices,
4766
+ setParams: chatStore.setParams,
4767
+ senderFocus: (options) => {
4768
+ senderRef.current?.focus(options);
4769
+ }
4770
+ }),
4771
+ []
4772
+ );
4773
+ const configState = valtio.useSnapshot(chatStore.config);
4774
+ const agentState = valtio.useSnapshot(chatStore.agent);
4775
+ const conversationState = valtio.useSnapshot(chatStore.conversation);
4776
+ const containerRef = React9.useRef(null);
4777
+ React9.useEffect(() => {
4778
+ chatStore.setHooks(hooks);
4779
+ }, [hooks]);
4780
+ React9.useEffect(() => {
4781
+ chatStore.setLayout(layout);
4782
+ }, [layout]);
4783
+ React9.useEffect(() => {
4784
+ chatStore.setParams(params);
4785
+ }, [params]);
4786
+ common.useDeepEffect(() => {
4787
+ chatStore.setServices(services);
4788
+ }, [services]);
4789
+ common.useDeepEffect(() => {
4790
+ if (agentState.agentInfo.id && common.isObject(config.agent?.spec)) {
4791
+ chatStore.setAgent({ ...agentState.agentInfo, spec: config.agent.spec || {} });
4792
+ }
4793
+ }, [agentState.agentInfo.id, config.agent?.spec]);
4794
+ common.useDeepEffect(() => {
4795
+ if (agentState.agentInfo.id && common.isObject(config.agent?.config)) {
4796
+ chatStore.setAgent({ ...agentState.agentInfo, config: config.agent.config || {} });
4797
+ }
4798
+ }, [agentState.agentInfo.id, config.agent?.config]);
4799
+ common.useDeepEffect(() => {
4800
+ if (agentState.agentInfo.id) {
4801
+ chatStore.setUserInput(config.agent.userInput);
4802
+ }
4803
+ }, [agentState.agentInfo.id, config.agent?.userInput]);
4804
+ common.useDeepEffect(() => {
4805
+ if (config?.agent?.id) {
4806
+ chatStore.getAgentInfo(config.agent.id);
4807
+ }
4808
+ }, [config.agent?.id]);
4809
+ common.useDeepEffect(() => {
4810
+ if (config?.agent?.id) {
4811
+ chatStore.initConversation(config);
4812
+ }
4813
+ }, [config.agent?.id, config.conversationId]);
4814
+ const hasPreView = React9.useMemo(() => {
4815
+ return common.shouldRender(configState.layout.preview) && !!configState.preview.file.path;
4816
+ }, [configState.layout.preview, configState.preview.file]);
4817
+ const [sizes, setSizes] = React9.useState([0, "100%"]);
4818
+ const setSplitterSizes = (sizes2) => {
4819
+ setSizes(sizes2);
4820
+ };
4821
+ React9.useEffect(() => {
4822
+ if (hasPreView) {
4823
+ setSplitterSizes(["50%", "50%"]);
4824
+ } else {
4825
+ setSplitterSizes([0, "100%"]);
4826
+ }
4827
+ }, [hasPreView]);
4828
+ common.useWebSocket({
4829
+ url: configState.services.websocketUrls?.[0],
4830
+ onMessage: (message3) => chatStore.acceptMessage(message3.payload),
4831
+ clientHeartbeat: false,
4832
+ reconnectInterval: 1e4
4833
+ });
4834
+ common.useWebSocket({
4835
+ url: configState.services.websocketUrls?.[1],
4836
+ onMessage: (message3) => chatStore.acceptMessage(message3.payload),
4837
+ clientHeartbeat: false,
4838
+ reconnectInterval: 1e4
4839
+ });
4840
+ React9.useEffect(() => {
4841
+ hooks?.onBeforeInit?.();
4842
+ }, []);
4843
+ return /* @__PURE__ */ jsxRuntime.jsx(xV2.XProvider, { theme: { cssVar: {}, ...theme4 }, children: /* @__PURE__ */ jsxRuntime.jsx(ChatProvider, { store: chatStore, children: /* @__PURE__ */ jsxRuntime.jsx(antd.Spin, { spinning: configState.loading, classNames: { root: index_module_default2.spinWrapper }, children: /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { vertical: true, className: classNames7__default.default(index_module_default2.chatLayout, "zero-chat-layout", "height-full"), children: [
4844
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: configState.layout.globalHeader, DefaultComponent: ChatHeader_default }),
4845
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Flex, { ref: containerRef, className: "full-scroll", children: [
4846
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: configState.layout.leftPanel }),
4847
+ /* @__PURE__ */ jsxRuntime.jsx(common.RenderWrapper, { control: configState.layout.conversationList, DefaultComponent: ConversationListPanel_default }),
4848
+ /* @__PURE__ */ jsxRuntime.jsxs(antd.Splitter, { className: classNames7__default.default("flex-1", index_module_default2.animatedSplitter, { [index_module_default2.hideSplitterBar]: !hasPreView }), children: [
4849
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Splitter.Panel, { collapsible: false, max: 800, min: 400, size: sizes[1], children: /* @__PURE__ */ jsxRuntime.jsx(ChatMainPanel_default, { ref: senderRef }) }),
4850
+ /* @__PURE__ */ jsxRuntime.jsx(antd.Splitter.Panel, { collapsible: false, min: 600, size: sizes[0], children: /* @__PURE__ */ jsxRuntime.jsx(
4851
+ ChatPreviewPanel_default,
4852
+ {
4853
+ agentId: agentState?.agentInfo?.id,
4854
+ conversationId: conversationState.active.id,
4855
+ file: configState.preview.file
4856
+ }
4857
+ ) })
4858
+ ] })
4859
+ ] })
4860
+ ] }) }) }) });
4861
+ });
4862
+
4863
+ exports.BubbleListItems = BubbleListItems_default;
4864
+ exports.ChatCopilot = layouts_default;
4865
+ exports.ChatSender = ChatSender_default;
4866
+ exports.MessageRender = MessageRender_default;
4867
+ //# sourceMappingURL=index.cjs.js.map
4868
+ //# sourceMappingURL=index.cjs.js.map