@zero-library/chat-copilot 3.1.5 → 3.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -158,7 +158,10 @@ var Attachments_default = React10.forwardRef(({ fileUpload, fileUploadConfig, fi
158
158
  const uploadedFile = data[0];
159
159
  let previewUrl = uploadedFile.id;
160
160
  if (uploadedFile.conversationId && uploadedFile.path) {
161
- previewUrl = chatStore.config.services.request.getPreviewUrl(uploadedFile.conversationId, uploadedFile.path);
161
+ previewUrl = chatStore.config.services.request.getPreviewUrl({
162
+ path: uploadedFile.path,
163
+ workspaceId: uploadedFile.conversationId
164
+ });
162
165
  }
163
166
  setAttachedFiles(
164
167
  getAttachedFiles().map((f) => {
@@ -251,8 +254,12 @@ var index_module_default = {
251
254
  promptEditorPlaceholder: "index_module_promptEditorPlaceholder",
252
255
  resourceSelect: "index_module_resourceSelect",
253
256
  fileMenu: "index_module_fileMenu",
257
+ fileMenuGroup: "index_module_fileMenuGroup",
258
+ fileMenuGroupTitle: "index_module_fileMenuGroupTitle",
259
+ fileMenuEmpty: "index_module_fileMenuEmpty",
254
260
  fileMenuItem: "index_module_fileMenuItem",
255
261
  fileMenuItemActive: "index_module_fileMenuItemActive",
262
+ fileIcon: "index_module_fileIcon",
256
263
  fileName: "index_module_fileName",
257
264
  resourceTag: "index_module_resourceTag"
258
265
  };
@@ -260,6 +267,16 @@ var index_module_default = {
260
267
  // src/core/constants.ts
261
268
  var CONV_MODE = {
262
269
  PROD: 1};
270
+ var TOKEN_KEY = "NS-TOKEN";
271
+ var tokenManager = common.createTokenManager({
272
+ key: TOKEN_KEY
273
+ });
274
+ var redirectUrl = () => {
275
+ const path = localStorage.getItem("SIGNPATH");
276
+ common.emit("jumpLink", { url: `/uc${path || "/sign-in"}` });
277
+ };
278
+
279
+ // src/core/utils.ts
263
280
  var classifyTime = (timestamp) => {
264
281
  const now = dayjs__default.default();
265
282
  const target = dayjs__default.default(timestamp);
@@ -306,27 +323,52 @@ var getFileIcon = (extension, fontSize = 24) => {
306
323
  }
307
324
  return createIcon(icons.FileUnknownOutlined, "#94a3b8");
308
325
  };
309
- function FilePickerMenu({
310
- options,
326
+ var getFileUrl = (params, baseUrl, url) => {
327
+ const data = {
328
+ [TOKEN_KEY]: tokenManager.get(),
329
+ workspaceType: "conversation" /* CONVERSATION */,
330
+ ...params
331
+ };
332
+ return common.buildUrlParams(data, url || `${baseUrl}/files/access`);
333
+ };
334
+ function GroupPicker({
335
+ groups,
311
336
  selectedIndex,
312
337
  onSelect,
313
338
  onHover
314
339
  }) {
315
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.fileMenu, role: "listbox", children: options.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs(
316
- "div",
317
- {
318
- role: "option",
319
- "aria-selected": index === selectedIndex,
320
- className: `${index_module_default.fileMenuItem} ${index === selectedIndex ? index_module_default.fileMenuItemActive : ""}`,
321
- onMouseEnter: () => onHover(index),
322
- onClick: () => onSelect(option),
323
- children: [
324
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: getFileIcon(option.ext || common.getFileSuffixName(option.label), 14) }),
325
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: index_module_default.fileName, children: option.label })
326
- ]
327
- },
328
- option.value
329
- )) });
340
+ const itemRefs = React10.useRef([]);
341
+ let currentIndex = -1;
342
+ React10.useEffect(() => {
343
+ itemRefs.current[selectedIndex]?.scrollIntoView({
344
+ block: "nearest"
345
+ });
346
+ }, [groups, selectedIndex]);
347
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.fileMenu, role: "listbox", children: groups.map(({ group, options }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: index_module_default.fileMenuGroup, children: [
348
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.fileMenuGroupTitle, children: group.label }),
349
+ options.length ? options.map((option) => {
350
+ currentIndex += 1;
351
+ const optionIndex = currentIndex;
352
+ return /* @__PURE__ */ jsxRuntime.jsxs(
353
+ "div",
354
+ {
355
+ ref: (element) => {
356
+ itemRefs.current[optionIndex] = element;
357
+ },
358
+ role: "option",
359
+ "aria-selected": optionIndex === selectedIndex,
360
+ className: `${index_module_default.fileMenuItem} ${optionIndex === selectedIndex ? index_module_default.fileMenuItemActive : ""}`,
361
+ onMouseEnter: () => onHover(optionIndex),
362
+ onClick: () => onSelect(group, option),
363
+ children: [
364
+ option.ext && /* @__PURE__ */ jsxRuntime.jsx("span", { className: index_module_default.fileIcon, children: getFileIcon(option.ext, 14) }),
365
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: index_module_default.fileName, children: option.label })
366
+ ]
367
+ },
368
+ `${group.value}-${option.value}`
369
+ );
370
+ }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: index_module_default.fileMenuEmpty, children: "\u6682\u65E0\u6570\u636E" })
371
+ ] }, group.value)) });
330
372
  }
331
373
  function ResourcePickerMenu({
332
374
  anchorElementRef,
@@ -375,7 +417,6 @@ function ResourceTag({ resource }) {
375
417
  formatResourceName(resource.resourceName)
376
418
  ] }) });
377
419
  }
378
- var EMPTY_CASCADE_OPTION_VALUE = "__empty__";
379
420
  var VariableNode = class _VariableNode extends lexical.DecoratorNode {
380
421
  __resourceLabel;
381
422
  __resourceType;
@@ -466,34 +507,25 @@ var VariableNode = class _VariableNode extends lexical.DecoratorNode {
466
507
  function $createVariableNode(resourceLabel, resourceName, resourceType, resourceId) {
467
508
  return new VariableNode(resourceLabel, resourceName, resourceType, resourceId);
468
509
  }
469
- var CascadeOption = class extends LexicalTypeaheadMenuPlugin.MenuOption {
470
- category;
510
+ var ResourceOption = class extends LexicalTypeaheadMenuPlugin.MenuOption {
511
+ group;
471
512
  item;
472
513
  /**
473
- * 将级联菜单中的父子节点包装成 Lexical 菜单选项对象。
514
+ * 将分组列表中的资源节点包装成 Lexical 菜单选项对象。
474
515
  */
475
- constructor(category, item) {
476
- super(`${category.value}:${item.value}`);
477
- this.category = category;
516
+ constructor(group, item) {
517
+ super(`${group.value}:${item.value}`);
518
+ this.group = group;
478
519
  this.item = item;
479
520
  }
480
521
  };
481
- var FileOption = class extends LexicalTypeaheadMenuPlugin.MenuOption {
482
- file;
483
- /**
484
- * 将文件列表项包装成 Lexical 菜单选项对象。
485
- */
486
- constructor(file) {
487
- super(file.value);
488
- this.file = file;
489
- }
490
- };
491
522
  function VariablePickerPlugin({ commandConfig = {} }) {
492
523
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
493
524
  const chatStore = useChatStore();
494
525
  const [commandDataSource, setCommandDataSource] = React10.useState(commandConfig);
495
526
  const [queryString, setQueryString] = React10.useState(null);
496
527
  const [isEditorFocused, setIsEditorFocused] = React10.useState(false);
528
+ const [menuResetKey, setMenuResetKey] = React10.useState(0);
497
529
  const blurTimerRef = React10.useRef(null);
498
530
  React10.useEffect(() => {
499
531
  const unregister = utils.mergeRegister(
@@ -510,6 +542,7 @@ function VariablePickerPlugin({ commandConfig = {} }) {
510
542
  lexical.BLUR_COMMAND,
511
543
  () => {
512
544
  setIsEditorFocused(false);
545
+ setMenuResetKey((current) => current + 1);
513
546
  return false;
514
547
  },
515
548
  lexical.COMMAND_PRIORITY_LOW
@@ -524,6 +557,7 @@ function VariablePickerPlugin({ commandConfig = {} }) {
524
557
  setCommandDataSource(commandConfig);
525
558
  }, [commandConfig]);
526
559
  const commandKey = queryString?.[0] || "";
560
+ const searchKeyword = queryString?.slice(commandKey.length).trim().toLocaleLowerCase() || "";
527
561
  const categoryConfig = React10.useMemo(
528
562
  () => ({
529
563
  skill: {
@@ -541,58 +575,82 @@ function VariablePickerPlugin({ commandConfig = {} }) {
541
575
  }),
542
576
  [chatStore]
543
577
  );
544
- const commandOptions = React10.useMemo(() => {
545
- if (!isEditorFocused) return [];
546
- return (commandDataSource[commandKey]?.dataSource || []).flatMap(
547
- (category) => category.children?.filter((item) => !item.disabled).map((item) => new CascadeOption(category, item)) || []
548
- );
549
- }, [commandDataSource, commandKey, isEditorFocused]);
550
578
  const formatDataSource = React10.useCallback(
551
579
  (items, category) => {
552
580
  const currentCategoryConfig = categoryConfig[category.value];
553
- if (!items.length) {
554
- return [
555
- {
556
- value: EMPTY_CASCADE_OPTION_VALUE,
557
- label: "\u6682\u65E0\u6570\u636E",
558
- isLeaf: true,
559
- disabled: true
560
- }
561
- ];
562
- }
581
+ if (!items.length) return [];
563
582
  return items.map((item) => ({
564
583
  value: item.id,
565
- label: currentCategoryConfig?.getLabel(item) || item.name
584
+ label: currentCategoryConfig?.getLabel(item) || item.name,
585
+ children: []
566
586
  }));
567
587
  },
568
588
  [categoryConfig]
569
589
  );
570
- const loadData = React10.useCallback(
571
- (selectedOptions) => {
572
- const category = selectedOptions[selectedOptions.length - 1];
573
- if (!category || category.children?.length || category.isLeaf) return;
574
- const currentCategoryConfig = categoryConfig[category.value];
575
- if (!currentCategoryConfig) return;
576
- currentCategoryConfig.load().then((response) => {
577
- const items = response.data || [];
578
- setCommandDataSource((current) => ({
579
- ...current,
580
- [commandKey]: {
581
- ...current[commandKey],
582
- dataSource: current[commandKey]?.dataSource?.map(
583
- (item) => item.value === category.value ? { ...item, children: formatDataSource(items, category) } : item
584
- ) || []
585
- }
586
- }));
587
- });
588
- },
589
- [categoryConfig, commandKey, formatDataSource]
590
+ React10.useEffect(() => {
591
+ let isUnmounted = false;
592
+ const initializeCommandDataSource = async () => {
593
+ const nextEntries = await Promise.all(
594
+ Object.entries(commandConfig).map(async ([trigger, currentCommandConfig]) => {
595
+ const nextDataSource = await Promise.all(
596
+ (currentCommandConfig.dataSource || []).map(async (category) => {
597
+ const normalizedChildren = category.children || [];
598
+ const nextCategory = {
599
+ ...category,
600
+ children: normalizedChildren
601
+ };
602
+ const currentCategoryConfig = categoryConfig[category.value];
603
+ if (!currentCategoryConfig) {
604
+ return nextCategory;
605
+ }
606
+ if (normalizedChildren.length) {
607
+ return nextCategory;
608
+ }
609
+ const response = await currentCategoryConfig.load();
610
+ const items = response.data || [];
611
+ return {
612
+ ...nextCategory,
613
+ children: formatDataSource(items, category)
614
+ };
615
+ })
616
+ );
617
+ return [
618
+ trigger,
619
+ {
620
+ ...currentCommandConfig,
621
+ dataSource: nextDataSource
622
+ }
623
+ ];
624
+ })
625
+ );
626
+ if (isUnmounted) return;
627
+ setCommandDataSource(Object.fromEntries(nextEntries));
628
+ };
629
+ initializeCommandDataSource();
630
+ return () => {
631
+ isUnmounted = true;
632
+ };
633
+ }, [categoryConfig, commandConfig, formatDataSource]);
634
+ const commandGroups = React10.useMemo(() => {
635
+ if (!isEditorFocused) return [];
636
+ return (commandDataSource[commandKey]?.dataSource || []).map((group) => {
637
+ const options = group.children || [];
638
+ if (!searchKeyword) return { group, options };
639
+ return {
640
+ group,
641
+ options: options.filter((option) => option.label.toLocaleLowerCase().includes(searchKeyword))
642
+ };
643
+ }).filter(({ options }) => !searchKeyword || options.length);
644
+ }, [commandDataSource, commandKey, isEditorFocused, searchKeyword]);
645
+ const commandOptions = React10.useMemo(
646
+ () => commandGroups.flatMap(({ group, options }) => options.map((item) => new ResourceOption(group, item))),
647
+ [commandGroups]
590
648
  );
591
649
  const onSelectOption = React10.useCallback(
592
650
  (selectedOption, nodeToReplace, closeMenu, matchingString) => {
593
- const resource = selectedOption instanceof FileOption ? selectedOption.file : selectedOption.item;
594
- const resourceLabel = selectedOption instanceof FileOption ? "\u6587\u4EF6" : selectedOption.category.label;
595
- const resourceType = selectedOption instanceof FileOption ? "file" : selectedOption.category.value;
651
+ const resource = selectedOption.item;
652
+ const resourceLabel = selectedOption.group.label;
653
+ const resourceType = selectedOption.group.value;
596
654
  editor.update(() => {
597
655
  const variableNode = $createVariableNode(resourceLabel, resource.label, resourceType, resource.value);
598
656
  if (nodeToReplace) {
@@ -602,7 +660,7 @@ function VariablePickerPlugin({ commandConfig = {} }) {
602
660
  });
603
661
  closeMenu();
604
662
  },
605
- [commandDataSource, editor]
663
+ [editor]
606
664
  );
607
665
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
608
666
  LexicalTypeaheadMenuPlugin.LexicalTypeaheadMenuPlugin,
@@ -616,40 +674,24 @@ function VariablePickerPlugin({ commandConfig = {} }) {
616
674
  if (!match) return null;
617
675
  return { leadOffset: match.index, matchingString: match[0], replaceableString: match[0] };
618
676
  },
619
- options: commandOptions.map((option) => new CascadeOption(option.category, option.item)),
620
- menuRenderFn: (anchorElementRef, { selectedIndex, setHighlightedIndex, selectOptionAndCleanUp }, matchingString) => {
621
- if (!anchorElementRef.current) return null;
677
+ options: commandOptions,
678
+ menuRenderFn: (anchorElementRef, { selectedIndex, setHighlightedIndex, selectOptionAndCleanUp }) => {
679
+ if (!isEditorFocused || !anchorElementRef.current || searchKeyword && !commandGroups.length) return null;
622
680
  return ReactDOM__namespace.createPortal(
623
- /* @__PURE__ */ jsxRuntime.jsxs(ResourcePickerMenu, { anchorElementRef, children: [
624
- commandDataSource[matchingString]?.component === "cascade" && /* @__PURE__ */ jsxRuntime.jsx(
625
- antd.Cascader.Panel,
626
- {
627
- options: commandDataSource[matchingString]?.dataSource,
628
- expandTrigger: "hover",
629
- loadData,
630
- onChange: (value) => {
631
- const [categoryValue, itemValue] = value;
632
- const option = commandOptions.find(
633
- (currentOption) => currentOption.category.value === categoryValue && currentOption.item.value === itemValue
634
- );
635
- if (option) selectOptionAndCleanUp(option);
636
- }
637
- }
638
- ),
639
- commandDataSource[matchingString]?.component === "list" && /* @__PURE__ */ jsxRuntime.jsx(
640
- FilePickerMenu,
641
- {
642
- options: commandDataSource[matchingString]?.dataSource || [],
643
- selectedIndex: selectedIndex ?? 0,
644
- onHover: setHighlightedIndex,
645
- onSelect: (option) => selectOptionAndCleanUp(new FileOption(option))
646
- }
647
- )
648
- ] }),
681
+ /* @__PURE__ */ jsxRuntime.jsx(ResourcePickerMenu, { anchorElementRef, children: /* @__PURE__ */ jsxRuntime.jsx(
682
+ GroupPicker,
683
+ {
684
+ groups: commandGroups,
685
+ selectedIndex: selectedIndex ?? 0,
686
+ onHover: setHighlightedIndex,
687
+ onSelect: (group, option) => selectOptionAndCleanUp(new ResourceOption(group, option))
688
+ }
689
+ ) }),
649
690
  anchorElementRef.current
650
691
  );
651
692
  }
652
- }
693
+ },
694
+ menuResetKey
653
695
  ) });
654
696
  }
655
697
  function InitialStatePlugin({ value }) {
@@ -872,14 +914,6 @@ var ChatSender_default = React10.forwardRef(
872
914
  );
873
915
  }
874
916
  );
875
- var TOKEN_KEY = "NS-TOKEN";
876
- var tokenManager = common.createTokenManager({
877
- key: TOKEN_KEY
878
- });
879
- var redirectUrl = () => {
880
- const path = localStorage.getItem("SIGNPATH");
881
- common.emit("jumpLink", { url: `/uc${path || "/sign-in"}` });
882
- };
883
917
  var createChatService = (request, config) => {
884
918
  const fetchModelList = () => {
885
919
  return request.get(`/providers/models/type/llm`);
@@ -920,14 +954,8 @@ var createChatService = (request, config) => {
920
954
  signal
921
955
  });
922
956
  };
923
- const getPreviewUrl = (conversationId, path) => {
924
- const params = {
925
- path,
926
- [TOKEN_KEY]: tokenManager.get(),
927
- workspaceId: conversationId,
928
- workspaceType: "conversation" /* CONVERSATION */
929
- };
930
- return common.buildUrlParams(params, `${config?.baseURL}/files/access`);
957
+ const getPreviewUrl = (params) => {
958
+ return getFileUrl(params, config?.baseURL);
931
959
  };
932
960
  const docQuery = (params) => {
933
961
  return request.get(`/library/cloud/document?${params}`);
@@ -2736,7 +2764,10 @@ var PreviewLink_default = ({ data, loading, message: message2, ...rest }) => {
2736
2764
  const fileName = getLinkFileName(href);
2737
2765
  const suffix = common.getFileSuffixName(fileName);
2738
2766
  chatStore.setPreview({
2739
- fileUrl: chatStore.config.services.request.getPreviewUrl(message2.conversationId, href),
2767
+ fileUrl: chatStore.config.services.request.getPreviewUrl({
2768
+ path: href,
2769
+ workspaceId: message2.conversationId
2770
+ }),
2740
2771
  fileName,
2741
2772
  suffix
2742
2773
  });
@@ -3260,6 +3291,135 @@ var A2uiComponents = {
3260
3291
  ReportViewer
3261
3292
  };
3262
3293
 
3294
+ // src/components/CustomComponents/A2uiRuntime/controller/extract.ts
3295
+ var A2UI_TAG_REGEX = /<A2UI\s+id="([^"]*)"\s*>([\s\S]*?)<\/A2UI>/g;
3296
+ function hasA2uiTag(text) {
3297
+ return typeof text === "string" && text.includes("<A2UI");
3298
+ }
3299
+ function parseA2uiTagsFromText(text) {
3300
+ if (!hasA2uiTag(text)) return [];
3301
+ const tags = [];
3302
+ const regex = new RegExp(A2UI_TAG_REGEX);
3303
+ let match;
3304
+ while ((match = regex.exec(text)) !== null) {
3305
+ const tagId = match[1];
3306
+ const json = match[2].trim();
3307
+ if (!json) continue;
3308
+ try {
3309
+ const parsed = JSON.parse(json);
3310
+ const commands = Array.isArray(parsed) ? parsed : [parsed];
3311
+ if (commands.length) tags.push({ tagId, commands });
3312
+ } catch {
3313
+ }
3314
+ }
3315
+ return tags;
3316
+ }
3317
+ function stripA2uiTags(text) {
3318
+ if (!hasA2uiTag(text)) return text;
3319
+ let result = text.replace(A2UI_TAG_REGEX, "");
3320
+ result = result.replace(/<A2UI\b[\s\S]*$/, "");
3321
+ return result.trim();
3322
+ }
3323
+ function splitA2uiTextSegments(text) {
3324
+ if (typeof text !== "string" || !text.includes("<A2UI")) {
3325
+ return text ? [{ type: "text", content: text }] : [];
3326
+ }
3327
+ const segments = [];
3328
+ const regex = new RegExp(A2UI_TAG_REGEX);
3329
+ let lastIndex = 0;
3330
+ let match;
3331
+ while ((match = regex.exec(text)) !== null) {
3332
+ if (match.index > lastIndex) {
3333
+ const before = text.slice(lastIndex, match.index);
3334
+ if (before) segments.push({ type: "text", content: before });
3335
+ }
3336
+ const json = match[2].trim();
3337
+ if (json) {
3338
+ try {
3339
+ const parsed = JSON.parse(json);
3340
+ const commands = Array.isArray(parsed) ? parsed : [parsed];
3341
+ const surfaceIds = commands.map((cmd) => String(cmd?.createSurface?.surfaceId || "").trim()).filter(Boolean);
3342
+ if (surfaceIds.length) {
3343
+ segments.push({ type: "a2ui", surfaceIds });
3344
+ }
3345
+ } catch {
3346
+ }
3347
+ }
3348
+ lastIndex = regex.lastIndex;
3349
+ }
3350
+ if (lastIndex < text.length) {
3351
+ let remaining = text.slice(lastIndex);
3352
+ remaining = remaining.replace(/<A2UI\b[\s\S]*$/, "");
3353
+ if (remaining) segments.push({ type: "text", content: remaining });
3354
+ }
3355
+ return segments.length ? segments : [];
3356
+ }
3357
+ function extractInlineSurfaceIdsFromMessage(message2) {
3358
+ const surfaceIds = /* @__PURE__ */ new Set();
3359
+ const items = Array.isArray(message2?.content) ? message2.content : [];
3360
+ for (const item of items) {
3361
+ if (item?.type !== "text") continue;
3362
+ const text = item.messageContent || item.text || "";
3363
+ if (typeof text !== "string" || !text.includes("<A2UI")) continue;
3364
+ const tags = parseA2uiTagsFromText(text);
3365
+ for (const tag of tags) {
3366
+ for (const cmd of tag.commands) {
3367
+ const sid = String(cmd?.createSurface?.surfaceId || "").trim();
3368
+ if (sid) surfaceIds.add(sid);
3369
+ }
3370
+ }
3371
+ }
3372
+ return surfaceIds;
3373
+ }
3374
+ function extractDismissedSurfaceIdsFromMessages(messages) {
3375
+ const lastCreateIndexBySurface = /* @__PURE__ */ new Map();
3376
+ const lastActionIndexBySurface = /* @__PURE__ */ new Map();
3377
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {
3378
+ const message2 = messages[messageIndex];
3379
+ const items = Array.isArray(message2?.content) ? message2.content : [];
3380
+ for (const item of items) {
3381
+ if (message2?.role !== 1) {
3382
+ if (item?.type === "a2uiCommand" && item.command) {
3383
+ const surfaceId = String(item.command?.createSurface?.surfaceId || "").trim();
3384
+ if (surfaceId) lastCreateIndexBySurface.set(surfaceId, messageIndex);
3385
+ }
3386
+ if (item?.type === "text") {
3387
+ const text = item.messageContent || item.text || "";
3388
+ if (typeof text === "string" && text.includes("<A2UI")) {
3389
+ const tags = parseA2uiTagsFromText(text);
3390
+ for (const tag of tags) {
3391
+ for (const cmd of tag.commands) {
3392
+ const surfaceId = String(cmd?.createSurface?.surfaceId || "").trim();
3393
+ if (surfaceId) lastCreateIndexBySurface.set(surfaceId, messageIndex);
3394
+ }
3395
+ }
3396
+ }
3397
+ }
3398
+ }
3399
+ if (message2?.role === 1 && item?.type === "text") {
3400
+ const text = item.messageContent || item.text || "";
3401
+ if (typeof text !== "string" || !text.includes("a2ui_action.v1")) continue;
3402
+ try {
3403
+ const parsed = JSON.parse(text.trim());
3404
+ if (parsed?.type !== "a2ui_action.v1") continue;
3405
+ const surfaceId = String(parsed.surfaceId || "").trim();
3406
+ if (!surfaceId) continue;
3407
+ lastActionIndexBySurface.set(surfaceId, messageIndex);
3408
+ } catch {
3409
+ }
3410
+ }
3411
+ }
3412
+ }
3413
+ const dismissed = [];
3414
+ for (const [surfaceId, actionIndex] of lastActionIndexBySurface) {
3415
+ const createIndex = lastCreateIndexBySurface.get(surfaceId);
3416
+ if (createIndex === void 0 || actionIndex > createIndex) {
3417
+ dismissed.push(surfaceId);
3418
+ }
3419
+ }
3420
+ return dismissed;
3421
+ }
3422
+
3263
3423
  // src/components/CustomComponents/A2uiRuntime/controller/meta.ts
3264
3424
  function readProp(current, props, key) {
3265
3425
  return current[key] ?? props?.[key];
@@ -3427,19 +3587,8 @@ function inferModelPathFromSurfaceCommands(surfaceId, commands) {
3427
3587
  });
3428
3588
  return commonParentPath(paths);
3429
3589
  }
3430
- function isSubmitLikeActionName(name) {
3431
- const trimmed = typeof name === "string" ? name.trim() : "";
3432
- return trimmed === "submit" || trimmed === "confirm" || trimmed.startsWith("submit_") || trimmed.endsWith(".confirm");
3433
- }
3434
- function isCancelLikeActionName(name) {
3435
- const trimmed = typeof name === "string" ? name.trim() : "";
3436
- return trimmed === "cancel" || trimmed === "qf.cancel" || trimmed.endsWith(".cancel");
3437
- }
3438
3590
  function shouldOptimisticallyDismissSurface(actionName, context) {
3439
- if (isSubmitLikeActionName(actionName) || isCancelLikeActionName(actionName)) return true;
3440
- if (actionName === "qf.submit" || actionName === "qf.cancel") return true;
3441
- const submitFlag = context?.submit;
3442
- return submitFlag === true;
3591
+ return true;
3443
3592
  }
3444
3593
  function buildDispatchContext(surfaceId, rawContext, commands) {
3445
3594
  let normalizedContext = normalizeActionContext(rawContext);
@@ -3738,6 +3887,7 @@ function buildWizardUpdateComponentsCommand(schema, stepId) {
3738
3887
  function createA2uiRuntimeState() {
3739
3888
  return {
3740
3889
  processedMessageCursors: [],
3890
+ processedTagIds: [],
3741
3891
  serverCommands: [],
3742
3892
  localCommands: [],
3743
3893
  anchorIndexBySurface: {},
@@ -3797,6 +3947,57 @@ function initializeWizardSurface(state, surfaceId, effects, nextWizardSteps) {
3797
3947
  nextWizardSteps[surfaceId] = firstStepId.trim();
3798
3948
  }
3799
3949
  }
3950
+ function processA2uiCommand(cmd, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps) {
3951
+ nextState.serverCommands.push(cmd);
3952
+ nextState.lastA2uiHost = { id: messageId, index: messageIndex };
3953
+ const surfaceId = extractSurfaceId2(cmd);
3954
+ if (!surfaceId) return;
3955
+ if (cmd?.createSurface) {
3956
+ nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3957
+ } else if (nextState.anchorIndexBySurface[surfaceId] === void 0 && !cmd?.deleteSurface) {
3958
+ nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3959
+ }
3960
+ if (cmd?.createSurface) {
3961
+ nextState.latestCreateCommandIndexBySurface[surfaceId] = nextState.serverCommands.length - 1;
3962
+ nextState.optimisticallyDismissedSurfaceIds = nextState.optimisticallyDismissedSurfaceIds.filter((id) => id !== surfaceId);
3963
+ initializeWizardSurface(nextState, surfaceId, effects, nextWizardSteps);
3964
+ }
3965
+ if (cmd?.updateDataModel) {
3966
+ const { path, value } = cmd.updateDataModel;
3967
+ if (typeof path === "string" && path.trim() && value && typeof value === "object" && !Array.isArray(value)) {
3968
+ effects.push({ type: "write-model", modelPath: path, values: value });
3969
+ }
3970
+ }
3971
+ if (cmd?.deleteSurface) {
3972
+ deletedSurfaceIds.add(surfaceId);
3973
+ const modelPath = nextState.modelPathBySurface[surfaceId];
3974
+ if (modelPath) effects.push({ type: "clear-model", modelPath });
3975
+ delete nextState.initializedWizardRevisionBySurface[surfaceId];
3976
+ delete nextState.modelPathBySurface[surfaceId];
3977
+ }
3978
+ }
3979
+ function scanA2uiTagsFromMessages(messages, processedTagIds) {
3980
+ const newTags = [];
3981
+ const newTagIds = [];
3982
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
3983
+ const message2 = messages[messageIndex];
3984
+ const messageId = String(message2?.messageId ?? messageIndex);
3985
+ const items = Array.isArray(message2?.content) ? message2.content : [];
3986
+ for (const item of items) {
3987
+ if (item?.type !== "text") continue;
3988
+ const text = item.messageContent || item.text || "";
3989
+ if (typeof text !== "string" || !text.includes("<A2UI")) continue;
3990
+ const tags = parseA2uiTagsFromText(text);
3991
+ for (const tag of tags) {
3992
+ if (processedTagIds.has(tag.tagId)) continue;
3993
+ processedTagIds.add(tag.tagId);
3994
+ newTagIds.push(tag.tagId);
3995
+ newTags.push({ commands: tag.commands, messageIndex, messageId });
3996
+ }
3997
+ }
3998
+ }
3999
+ return { newTags, newTagIds };
4000
+ }
3800
4001
  function reduceA2uiRuntimeMessages(state, messages) {
3801
4002
  const { shouldReplayAll, pendingItems, nextCursors } = diffConversationMessages(messages || [], state.processedMessageCursors);
3802
4003
  const itemsToProcess = shouldReplayAll ? messages.flatMap((message2, messageIndex) => {
@@ -3804,11 +4005,14 @@ function reduceA2uiRuntimeMessages(state, messages) {
3804
4005
  const items = Array.isArray(message2?.content) ? message2.content : [];
3805
4006
  return items.map((item) => ({ messageIndex, messageId, item }));
3806
4007
  }) : pendingItems;
3807
- if (!shouldReplayAll && itemsToProcess.length === 0) {
4008
+ const tagProcessedSet = new Set(shouldReplayAll ? [] : state.processedTagIds);
4009
+ const { newTags, newTagIds } = scanA2uiTagsFromMessages(messages || [], tagProcessedSet);
4010
+ if (!shouldReplayAll && itemsToProcess.length === 0 && newTags.length === 0) {
3808
4011
  return { state, effects: [] };
3809
4012
  }
3810
4013
  const nextState = shouldReplayAll ? createA2uiRuntimeState() : { ...state };
3811
4014
  nextState.processedMessageCursors = shouldReplayAll ? [] : [...state.processedMessageCursors];
4015
+ nextState.processedTagIds = shouldReplayAll ? [] : [...state.processedTagIds, ...newTagIds];
3812
4016
  nextState.serverCommands = shouldReplayAll ? [] : [...state.serverCommands];
3813
4017
  nextState.localCommands = shouldReplayAll ? [] : [...state.localCommands];
3814
4018
  nextState.anchorIndexBySurface = shouldReplayAll ? {} : { ...state.anchorIndexBySurface };
@@ -3831,24 +4035,13 @@ function reduceA2uiRuntimeMessages(state, messages) {
3831
4035
  }
3832
4036
  return;
3833
4037
  }
3834
- if (item?.type !== "a2uiCommand" || !item.command) return;
3835
- nextState.serverCommands.push(item.command);
3836
- nextState.lastA2uiHost = { id: messageId, index: messageIndex };
3837
- const surfaceId = extractSurfaceId2(item.command);
3838
- if (!surfaceId) return;
3839
- if (nextState.anchorIndexBySurface[surfaceId] === void 0 && !item.command?.deleteSurface) {
3840
- nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3841
- }
3842
- if (item.command?.createSurface) {
3843
- nextState.latestCreateCommandIndexBySurface[surfaceId] = nextState.serverCommands.length - 1;
3844
- initializeWizardSurface(nextState, surfaceId, effects, nextWizardSteps);
3845
- }
3846
- if (item.command?.deleteSurface) {
3847
- deletedSurfaceIds.add(surfaceId);
3848
- const modelPath = nextState.modelPathBySurface[surfaceId];
3849
- if (modelPath) effects.push({ type: "clear-model", modelPath });
3850
- delete nextState.initializedWizardRevisionBySurface[surfaceId];
3851
- delete nextState.modelPathBySurface[surfaceId];
4038
+ if (item?.type === "a2uiCommand" && item.command) {
4039
+ processA2uiCommand(item.command, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps);
4040
+ }
4041
+ });
4042
+ newTags.forEach(({ commands, messageIndex, messageId }) => {
4043
+ for (const cmd of commands) {
4044
+ processA2uiCommand(cmd, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps);
3852
4045
  }
3853
4046
  });
3854
4047
  nextState.processedMessageCursors = shouldReplayAll ? messages.map((message2, messageIndex) => ({
@@ -3868,7 +4061,7 @@ function reduceA2uiRuntimeMessages(state, messages) {
3868
4061
  return { state: nextState, effects };
3869
4062
  }
3870
4063
  function reduceA2uiRuntimeAction(state, input) {
3871
- const { surfaceId, actionName, rawContext } = input;
4064
+ const { surfaceId, actionName} = input;
3872
4065
  if (!surfaceId) {
3873
4066
  return { state, handled: actionName === "wizard.next" || actionName === "wizard.back" };
3874
4067
  }
@@ -3898,9 +4091,6 @@ function reduceA2uiRuntimeAction(state, input) {
3898
4091
  if (actionName === "wizard.next" || actionName === "wizard.back") {
3899
4092
  return { state, handled: true };
3900
4093
  }
3901
- if (!shouldOptimisticallyDismissSurface(actionName, rawContext)) {
3902
- return { state, handled: false };
3903
- }
3904
4094
  if (state.optimisticallyDismissedSurfaceIds.includes(surfaceId)) {
3905
4095
  return { state, handled: false };
3906
4096
  }
@@ -3965,12 +4155,20 @@ function useA2uiController(params) {
3965
4155
  applyA2uiRuntimeEffects(result.effects);
3966
4156
  setRuntimeState(result.state);
3967
4157
  }, [conversationMessages, conversationId]);
3968
- const view = React10.useMemo(() => selectA2uiRuntimeView(runtimeState, dismissedSurfaceIds), [runtimeState, dismissedSurfaceIds]);
4158
+ const permanentDismissedSurfaceIds = React10.useMemo(
4159
+ () => extractDismissedSurfaceIdsFromMessages(conversationMessages || []),
4160
+ [conversationMessages]
4161
+ );
4162
+ const mergedDismissedSurfaceIds = React10.useMemo(
4163
+ () => Array.from(/* @__PURE__ */ new Set([...dismissedSurfaceIds || [], ...permanentDismissedSurfaceIds])),
4164
+ [dismissedSurfaceIds, permanentDismissedSurfaceIds]
4165
+ );
4166
+ const view = React10.useMemo(() => selectA2uiRuntimeView(runtimeState, mergedDismissedSurfaceIds), [runtimeState, mergedDismissedSurfaceIds]);
3969
4167
  const handleRuntimeAction = React10.useCallback((payload) => {
3970
4168
  const surfaceId = String(payload?.surfaceId || payload?.cardId || "");
3971
4169
  const name = String(payload?.name || payload?.event?.name || "").trim();
3972
4170
  const rawContext = payload?.context || payload?.event?.context || {};
3973
- const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name, rawContext });
4171
+ const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name});
3974
4172
  if (runtimeActionResult.state !== runtimeRef.current) {
3975
4173
  runtimeRef.current = runtimeActionResult.state;
3976
4174
  setRuntimeState(runtimeActionResult.state);
@@ -3997,26 +4195,26 @@ var A2uiRuntimeContext = React10__namespace.default.createContext({
3997
4195
  function useA2uiRuntimeView() {
3998
4196
  return React10__namespace.default.useContext(A2uiRuntimeContext);
3999
4197
  }
4000
- function A2uiMessageCards({ messageIndex }) {
4198
+ function A2uiMessageCards({ messageIndex, message: message2 }) {
4001
4199
  const { surfaceIdsByMessageIndex } = useA2uiRuntimeView();
4002
- const surfaceIds = surfaceIdsByMessageIndex[messageIndex] || [];
4200
+ const allSurfaceIds = surfaceIdsByMessageIndex[messageIndex] || [];
4201
+ const inlineSurfaceIds = message2 ? extractInlineSurfaceIdsFromMessage(message2) : /* @__PURE__ */ new Set();
4202
+ const surfaceIds = allSurfaceIds.filter((id) => !inlineSurfaceIds.has(id));
4003
4203
  if (!surfaceIds.length) return null;
4004
4204
  return /* @__PURE__ */ jsxRuntime.jsx("div", { children: surfaceIds.map((surfaceId) => /* @__PURE__ */ jsxRuntime.jsx(XCard.Card, { id: surfaceId }, surfaceId)) });
4005
4205
  }
4006
4206
 
4007
4207
  // src/components/CustomComponents/A2uiRuntime/renderer/protocol.ts
4008
- function isSubmitLikeActionName2(name) {
4208
+ function isSubmitLikeActionName(name) {
4009
4209
  const normalized = String(name || "").trim();
4010
4210
  return normalized === "submit" || normalized === "confirm" || normalized.startsWith("submit_") || normalized.endsWith(".confirm");
4011
4211
  }
4012
- function isCancelLikeActionName2(name) {
4212
+ function isCancelLikeActionName(name) {
4013
4213
  const normalized = String(name || "").trim();
4014
4214
  return normalized === "cancel" || normalized === "qf.cancel" || normalized.endsWith(".cancel");
4015
4215
  }
4016
4216
  function shouldDismissA2uiSurface(name, context) {
4017
- if (isSubmitLikeActionName2(name) || isCancelLikeActionName2(name)) return true;
4018
- if (name === "qf.submit" || name === "qf.cancel") return true;
4019
- return context?.submit === true;
4217
+ return true;
4020
4218
  }
4021
4219
  function normalizeA2uiActionPayload(payload) {
4022
4220
  return {
@@ -4050,7 +4248,7 @@ function isQuestionActionPayload(payload) {
4050
4248
  const mode = payload.context?.form_mode;
4051
4249
  if (payload.name === "qf.submit" || payload.name === "qf.cancel") return true;
4052
4250
  if (payload.name.startsWith("qf.")) return true;
4053
- return typeof mode === "string" && mode.toLowerCase() === "ephemeral" ? isSubmitLikeActionName2(payload.name) || isCancelLikeActionName2(payload.name) : false;
4251
+ return typeof mode === "string" && mode.toLowerCase() === "ephemeral" ? isSubmitLikeActionName(payload.name) || isCancelLikeActionName(payload.name) : false;
4054
4252
  }
4055
4253
  function formatActionValue(value, displayOverride) {
4056
4254
  if (typeof displayOverride === "string" && displayOverride.trim()) return displayOverride.trim();
@@ -4060,7 +4258,7 @@ function formatActionValue(value, displayOverride) {
4060
4258
  return String(value);
4061
4259
  }
4062
4260
  function buildQuestionSummary(payload) {
4063
- if (isCancelLikeActionName2(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
4261
+ if (isCancelLikeActionName(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
4064
4262
  const values = payload.context.values && typeof payload.context.values === "object" && !Array.isArray(payload.context.values) ? payload.context.values : payload.context;
4065
4263
  const labels = payload.context.labels && typeof payload.context.labels === "object" && !Array.isArray(payload.context.labels) ? payload.context.labels : {};
4066
4264
  const valueLabels = payload.context.valueLabels && typeof payload.context.valueLabels === "object" && !Array.isArray(payload.context.valueLabels) ? payload.context.valueLabels : {};
@@ -4082,10 +4280,22 @@ function formatA2uiActionDisplayText(payload) {
4082
4280
  back_to_params: "\u5DF2\u8FD4\u56DE\u4FEE\u6539\u53C2\u6570",
4083
4281
  confirm: "\u5DF2\u786E\u8BA4\u521B\u5EFA"
4084
4282
  };
4085
- const actionLabel = actionLabels[payload.name] || `\u5DF2\u63D0\u4EA4\u52A8\u4F5C (${payload.name})`;
4283
+ let actionLabel = actionLabels[payload.name];
4284
+ if (!actionLabel) {
4285
+ if (payload.name.startsWith("confirm_")) {
4286
+ actionLabel = "\u5DF2\u9009\u62E9";
4287
+ } else if (payload.name.startsWith("submit_")) {
4288
+ actionLabel = "\u5DF2\u63D0\u4EA4";
4289
+ } else {
4290
+ actionLabel = `\u5DF2\u63D0\u4EA4\u52A8\u4F5C (${payload.name})`;
4291
+ }
4292
+ }
4293
+ const isConfirmLike = payload.name.startsWith("confirm_");
4086
4294
  const details = Object.entries(values).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([key, value]) => {
4295
+ const formatted = formatActionValue(value, valueLabels[key]);
4296
+ if (isConfirmLike) return formatted;
4087
4297
  const label = typeof labels[key] === "string" && String(labels[key]).trim() ? String(labels[key]).trim() : key;
4088
- return `${label}: ${formatActionValue(value, valueLabels[key])}`;
4298
+ return `${label}: ${formatted}`;
4089
4299
  });
4090
4300
  return details.length ? `${actionLabel}\uFF1A${details.join("\uFF1B ")}` : actionLabel;
4091
4301
  }
@@ -4183,66 +4393,46 @@ function readContextModelPath(context) {
4183
4393
  const path = context?.model && typeof context.model === "object" ? context.model.path : "";
4184
4394
  return typeof path === "string" ? path.trim() : "";
4185
4395
  }
4186
- function diffMessages(messages, prevCursors) {
4187
- if (messages.length < prevCursors.length) {
4188
- return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
4189
- }
4190
- const nextCursors = [];
4191
- const pendingItems = [];
4192
- for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
4193
- const message2 = messages[messageIndex];
4194
- const messageId = String(message2?.messageId ?? messageIndex);
4396
+ function buildLatestCommandIndexBySurface(messages) {
4397
+ const indexBySurface = {};
4398
+ let commandIndex = -1;
4399
+ for (const message2 of messages) {
4195
4400
  const items = Array.isArray(message2?.content) ? message2.content : [];
4196
- const prevCursor = prevCursors[messageIndex];
4197
- const startIndex = prevCursor ? prevCursor.contentLength : 0;
4198
- if (prevCursor && (prevCursor.messageId !== messageId || items.length < prevCursor.contentLength)) {
4199
- return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
4200
- }
4201
- for (let itemIndex = startIndex; itemIndex < items.length; itemIndex += 1) {
4202
- pendingItems.push({ item: items[itemIndex] });
4401
+ for (const item of items) {
4402
+ if (item?.type === "a2uiCommand" && item.command) {
4403
+ commandIndex += 1;
4404
+ const surfaceId = extractSurfaceId3(item.command);
4405
+ if (surfaceId) indexBySurface[surfaceId] = commandIndex;
4406
+ continue;
4407
+ }
4408
+ if (item?.type === "text") {
4409
+ const text = item.messageContent || item.text || "";
4410
+ if (typeof text !== "string" || !text.includes("<A2UI")) continue;
4411
+ const tags = parseA2uiTagsFromText(text);
4412
+ for (const tag of tags) {
4413
+ for (const cmd of tag.commands) {
4414
+ commandIndex += 1;
4415
+ const surfaceId = extractSurfaceId3(cmd);
4416
+ if (surfaceId) indexBySurface[surfaceId] = commandIndex;
4417
+ }
4418
+ }
4419
+ }
4203
4420
  }
4204
- nextCursors.push({ messageId, contentLength: items.length });
4205
4421
  }
4206
- return { shouldReplayAll: false, nextCursors, pendingItems };
4422
+ return indexBySurface;
4207
4423
  }
4208
4424
  function A2uiRuntimeProvider({ messages, children }) {
4209
4425
  const chatStore = useChatStore();
4210
4426
  const conversationState = valtio.useSnapshot(chatStore.conversation);
4211
4427
  const conversationId = conversationState.active.id;
4212
- const processedMessageCursorsRef = React10__namespace.default.useRef([]);
4213
- const latestCommandIndexBySurfaceRef = React10__namespace.default.useRef({});
4214
- const commandIndexRef = React10__namespace.default.useRef(-1);
4215
4428
  const [latestCommandIndexBySurface, setLatestCommandIndexBySurface] = React10__namespace.default.useState({});
4216
4429
  const [dismissedAtBySurface, setDismissedAtBySurface] = React10__namespace.default.useState({});
4217
4430
  React10__namespace.default.useEffect(() => {
4218
- processedMessageCursorsRef.current = [];
4219
- latestCommandIndexBySurfaceRef.current = {};
4220
- commandIndexRef.current = -1;
4221
4431
  setLatestCommandIndexBySurface({});
4222
4432
  setDismissedAtBySurface({});
4223
4433
  }, [conversationId]);
4224
4434
  React10__namespace.default.useEffect(() => {
4225
- const { shouldReplayAll, nextCursors, pendingItems } = diffMessages(messages, processedMessageCursorsRef.current);
4226
- const itemsToProcess = shouldReplayAll ? messages.flatMap((message2) => {
4227
- const items = Array.isArray(message2?.content) ? message2.content : [];
4228
- return items.map((item) => ({ item }));
4229
- }) : pendingItems;
4230
- if (!shouldReplayAll && itemsToProcess.length === 0) return;
4231
- const nextLatestCommandIndexBySurface = shouldReplayAll ? {} : { ...latestCommandIndexBySurfaceRef.current };
4232
- let nextCommandIndex = shouldReplayAll ? -1 : commandIndexRef.current;
4233
- itemsToProcess.forEach(({ item }) => {
4234
- if (item?.type !== "a2uiCommand" || !item.command) return;
4235
- nextCommandIndex += 1;
4236
- const surfaceId = extractSurfaceId3(item.command);
4237
- if (surfaceId) nextLatestCommandIndexBySurface[surfaceId] = nextCommandIndex;
4238
- });
4239
- processedMessageCursorsRef.current = shouldReplayAll ? messages.map((message2, messageIndex) => ({
4240
- messageId: String(message2?.messageId ?? messageIndex),
4241
- contentLength: Array.isArray(message2?.content) ? message2.content.length : 0
4242
- })) : nextCursors;
4243
- latestCommandIndexBySurfaceRef.current = nextLatestCommandIndexBySurface;
4244
- commandIndexRef.current = nextCommandIndex;
4245
- setLatestCommandIndexBySurface(nextLatestCommandIndexBySurface);
4435
+ setLatestCommandIndexBySurface(buildLatestCommandIndexBySurface(messages));
4246
4436
  }, [messages]);
4247
4437
  const dismissedSurfaceIds = React10__namespace.default.useMemo(() => {
4248
4438
  return Object.entries(dismissedAtBySurface).filter(([surfaceId, dismissedAt]) => (latestCommandIndexBySurface[surfaceId] ?? -1) <= dismissedAt).map(([surfaceId]) => surfaceId);
@@ -4299,11 +4489,13 @@ function A2uiRenderer(props) {
4299
4489
  var FilesNode = React10__namespace.default.memo(({ item }) => {
4300
4490
  const chatStore = useChatStore();
4301
4491
  const configState = valtio.useSnapshot(chatStore.config);
4302
- valtio.useSnapshot(chatStore.agent);
4303
4492
  const conversationState = valtio.useSnapshot(chatStore.conversation);
4304
4493
  const fileItems = React10.useMemo(() => {
4305
4494
  return (item.files || []).map((file) => {
4306
- const previewUrl = configState.services.request.getPreviewUrl(conversationState.active.id, file.path);
4495
+ const previewUrl = configState.services.request.getPreviewUrl({
4496
+ path: file.path,
4497
+ workspaceId: conversationState.active.id
4498
+ });
4307
4499
  let fileType = "file";
4308
4500
  const ext = file.ext?.toLowerCase() || "";
4309
4501
  if (["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "webp"].includes(ext)) {
@@ -4369,14 +4561,37 @@ function QuestionSummary({ content }) {
4369
4561
  ] });
4370
4562
  }
4371
4563
  var TextNode2 = React10__namespace.default.memo(
4372
- ({ item, role, customComponents, message: message2 }) => {
4373
- const content = toA2uiDisplayText(role, item?.messageContent);
4374
- if (typeof content === "string" && content.startsWith("Question:")) {
4375
- return /* @__PURE__ */ jsxRuntime.jsx(QuestionSummary, { content });
4564
+ ({
4565
+ item,
4566
+ role,
4567
+ customComponents,
4568
+ message: message2,
4569
+ messageIndex = -1
4570
+ }) => {
4571
+ const { surfaceIdsByMessageIndex } = useA2uiRuntimeView();
4572
+ const rawContent = toA2uiDisplayText(role, item?.messageContent);
4573
+ const segments = splitA2uiTextSegments(rawContent);
4574
+ const visibleSurfaceIds = messageIndex >= 0 ? new Set(surfaceIdsByMessageIndex[messageIndex] || []) : null;
4575
+ const firstSeg = segments[0];
4576
+ const isPureText = segments.length === 0 || segments.length === 1 && firstSeg.type === "text";
4577
+ if (isPureText) {
4578
+ const content = firstSeg && firstSeg.type === "text" ? firstSeg.content : "";
4579
+ if (typeof content === "string" && content.startsWith("Question:")) {
4580
+ return /* @__PURE__ */ jsxRuntime.jsx(QuestionSummary, { content });
4581
+ }
4582
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4583
+ !!item.reasoningContent && /* @__PURE__ */ jsxRuntime.jsx(xV2.Think, { title: "\u6DF1\u5EA6\u601D\u8003", children: item.reasoningContent }),
4584
+ !!content && /* @__PURE__ */ jsxRuntime.jsx(XMarkdown_default, { message: message2, components: customComponents, content })
4585
+ ] });
4376
4586
  }
4377
4587
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4378
4588
  !!item.reasoningContent && /* @__PURE__ */ jsxRuntime.jsx(xV2.Think, { title: "\u6DF1\u5EA6\u601D\u8003", children: item.reasoningContent }),
4379
- !!content && /* @__PURE__ */ jsxRuntime.jsx(XMarkdown_default, { message: message2, components: customComponents, content })
4589
+ segments.map((seg, i) => {
4590
+ if (seg.type === "text") {
4591
+ return seg.content.trim() ? /* @__PURE__ */ jsxRuntime.jsx(XMarkdown_default, { message: message2, components: customComponents, content: seg.content }, `text-${i}`) : null;
4592
+ }
4593
+ return seg.surfaceIds.filter((sid) => !visibleSurfaceIds || visibleSurfaceIds.has(sid)).map((sid) => /* @__PURE__ */ jsxRuntime.jsx(XCard.Card, { id: sid }, `a2ui-${i}-${sid}`));
4594
+ })
4380
4595
  ] });
4381
4596
  }
4382
4597
  );
@@ -4604,6 +4819,12 @@ var MessageRender_default = React10__namespace.default.memo(({ role, message: me
4604
4819
  if (item.type === "plan") {
4605
4820
  return !shouldHideA2uiPlan(item);
4606
4821
  }
4822
+ if (item.type === "text") {
4823
+ const rawText = item.messageContent || item.text || "";
4824
+ const visibleText = stripA2uiTags(rawText);
4825
+ const hasA2uiTag2 = typeof rawText === "string" && rawText.includes("<A2UI");
4826
+ return !!visibleText.trim() || !!item.reasoningContent || hasA2uiTag2;
4827
+ }
4607
4828
  return true;
4608
4829
  });
4609
4830
  }, [loading, message2.content]);
@@ -4632,7 +4853,7 @@ var MessageRender_default = React10__namespace.default.memo(({ role, message: me
4632
4853
  content: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4633
4854
  item.type === "runStarted" && /* @__PURE__ */ jsxRuntime.jsx(RunStartedNode, { loading }, `flow-start-${index}`),
4634
4855
  (item.type === "toolCall" || item.type === "toolResult") && /* @__PURE__ */ jsxRuntime.jsx(tool_call_item_default, { item }, `tool-call-${item.toolCallId || index}`),
4635
- item.type === "text" && /* @__PURE__ */ jsxRuntime.jsx(TextNode2, { item, role: message2.role, customComponents, message: message2 }, `message-${index}`),
4856
+ item.type === "text" && /* @__PURE__ */ jsxRuntime.jsx(TextNode2, { item, role: message2.role, customComponents, message: message2, messageIndex }, `message-${index}`),
4636
4857
  item.type === "stepError" && (item.errorMessage ? /* @__PURE__ */ jsxRuntime.jsx(XMarkdown_default, { message: message2, components: customComponents, content: item.errorMessage }) : null),
4637
4858
  item.type === "files" && /* @__PURE__ */ jsxRuntime.jsx(FilesNode, { item }, `files-${index}`),
4638
4859
  item.type === "plan" && /* @__PURE__ */ jsxRuntime.jsx(A2uiPlanNode, { item }, `plan-${index}`)
@@ -4642,7 +4863,7 @@ var MessageRender_default = React10__namespace.default.memo(({ role, message: me
4642
4863
  );
4643
4864
  }),
4644
4865
  quoteMsg && /* @__PURE__ */ jsxRuntime.jsx(QuoteMsgNode, { quoteMsg, role }),
4645
- messageIndex >= 0 ? /* @__PURE__ */ jsxRuntime.jsx(A2uiMessageCards, { messageIndex }) : null
4866
+ messageIndex >= 0 ? /* @__PURE__ */ jsxRuntime.jsx(A2uiMessageCards, { messageIndex, message: message2 }) : null
4646
4867
  ] });
4647
4868
  });
4648
4869
  var WelcomeItem_default = ({ icon = true, title = true, description = true, prompts = true }) => {
@@ -5587,5 +5808,7 @@ var layouts_default = React10.forwardRef(({ theme: theme4, params, hooks, layout
5587
5808
  exports.Attachments = Attachments_default;
5588
5809
  exports.ChatCopilot = layouts_default;
5589
5810
  exports.ChatSender = ChatSender_default;
5811
+ exports.getFileIcon = getFileIcon;
5812
+ exports.getFileUrl = getFileUrl;
5590
5813
  //# sourceMappingURL=index.cjs.js.map
5591
5814
  //# sourceMappingURL=index.cjs.js.map