@zero-library/chat-copilot 3.1.6 → 3.1.8

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.esm.js CHANGED
@@ -3,7 +3,7 @@ import { Attachments, Sender, FileCard, Bubble, Think, XProvider, Mermaid, CodeH
3
3
  import { useRefState, useDebounce, createTokenManager, useSyncInput, isEmptyObj, markdownToText, RenderWrapper, shouldRender, isFunction, downloadFile, LuyaFilePreview, MarkdownEditor, useDeepEffect, isObject, useWebSocket, isNullOrUnDef, isNumber, getFileSuffixName, FileIcon, copyText, LazyComponent, isBoolean, UserAvatar, htmlToMarkdown, buildUrlParams, isExternal, deepCopy, transforms, deepMerge, createRequest, HttpStatus, isArray, isString, transform, emit, getWebSocketUrl, safeParseJson } from '@zero-library/common';
4
4
  import { App, Badge, Button, Flex, Typography, Tooltip, Layout, Tag, Spin, Splitter, Image as Image$1, Popover, Skeleton, Alert, theme, Collapse, Divider as Divider$1, Select as Select$1, Avatar, Space, Drawer, Empty, Modal, Checkbox, Input, message, List, Card, Table, Progress as Progress$1, Switch as Switch$1 } from 'antd';
5
5
  import * as React10 from 'react';
6
- import React10__default, { createContext, forwardRef, useRef, useEffect, useImperativeHandle, useMemo, useCallback, memo, useState, useContext, useLayoutEffect } from 'react';
6
+ import React10__default, { createContext, forwardRef, useRef, useEffect, useImperativeHandle, useMemo, memo, useState, useContext, useCallback, useLayoutEffect } from 'react';
7
7
  import { useSnapshot, proxy } from 'valtio';
8
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
9
  import { LexicalComposer } from '@lexical/react/LexicalComposer';
@@ -825,8 +825,8 @@ var ChatSender_default = forwardRef(
825
825
  const isFocusedRef = useRef(false);
826
826
  const commandConfigRef = useRef(commandConfig);
827
827
  commandConfigRef.current = commandConfig;
828
- const inputComponent = useCallback(
829
- (inputProps) => /* @__PURE__ */ jsx(ChatInput_default, { ...inputProps, commandConfig: commandConfigRef.current }),
828
+ const inputComponent = useMemo(
829
+ () => forwardRef((inputProps, ref2) => /* @__PURE__ */ jsx(ChatInput_default, { ...inputProps, ref: ref2, commandConfig: commandConfigRef.current })),
830
830
  []
831
831
  );
832
832
  useEffect(() => {
@@ -3262,6 +3262,135 @@ var A2uiComponents = {
3262
3262
  ReportViewer
3263
3263
  };
3264
3264
 
3265
+ // src/components/CustomComponents/A2uiRuntime/controller/extract.ts
3266
+ var A2UI_TAG_REGEX = /<A2UI\s+id="([^"]*)"\s*>([\s\S]*?)<\/A2UI>/g;
3267
+ function hasA2uiTag(text) {
3268
+ return typeof text === "string" && text.includes("<A2UI");
3269
+ }
3270
+ function parseA2uiTagsFromText(text) {
3271
+ if (!hasA2uiTag(text)) return [];
3272
+ const tags = [];
3273
+ const regex = new RegExp(A2UI_TAG_REGEX);
3274
+ let match;
3275
+ while ((match = regex.exec(text)) !== null) {
3276
+ const tagId = match[1];
3277
+ const json = match[2].trim();
3278
+ if (!json) continue;
3279
+ try {
3280
+ const parsed = JSON.parse(json);
3281
+ const commands = Array.isArray(parsed) ? parsed : [parsed];
3282
+ if (commands.length) tags.push({ tagId, commands });
3283
+ } catch {
3284
+ }
3285
+ }
3286
+ return tags;
3287
+ }
3288
+ function stripA2uiTags(text) {
3289
+ if (!hasA2uiTag(text)) return text;
3290
+ let result = text.replace(A2UI_TAG_REGEX, "");
3291
+ result = result.replace(/<A2UI\b[\s\S]*$/, "");
3292
+ return result.trim();
3293
+ }
3294
+ function splitA2uiTextSegments(text) {
3295
+ if (typeof text !== "string" || !text.includes("<A2UI")) {
3296
+ return text ? [{ type: "text", content: text }] : [];
3297
+ }
3298
+ const segments = [];
3299
+ const regex = new RegExp(A2UI_TAG_REGEX);
3300
+ let lastIndex = 0;
3301
+ let match;
3302
+ while ((match = regex.exec(text)) !== null) {
3303
+ if (match.index > lastIndex) {
3304
+ const before = text.slice(lastIndex, match.index);
3305
+ if (before) segments.push({ type: "text", content: before });
3306
+ }
3307
+ const json = match[2].trim();
3308
+ if (json) {
3309
+ try {
3310
+ const parsed = JSON.parse(json);
3311
+ const commands = Array.isArray(parsed) ? parsed : [parsed];
3312
+ const surfaceIds = commands.map((cmd) => String(cmd?.createSurface?.surfaceId || "").trim()).filter(Boolean);
3313
+ if (surfaceIds.length) {
3314
+ segments.push({ type: "a2ui", surfaceIds });
3315
+ }
3316
+ } catch {
3317
+ }
3318
+ }
3319
+ lastIndex = regex.lastIndex;
3320
+ }
3321
+ if (lastIndex < text.length) {
3322
+ let remaining = text.slice(lastIndex);
3323
+ remaining = remaining.replace(/<A2UI\b[\s\S]*$/, "");
3324
+ if (remaining) segments.push({ type: "text", content: remaining });
3325
+ }
3326
+ return segments.length ? segments : [];
3327
+ }
3328
+ function extractInlineSurfaceIdsFromMessage(message2) {
3329
+ const surfaceIds = /* @__PURE__ */ new Set();
3330
+ const items = Array.isArray(message2?.content) ? message2.content : [];
3331
+ for (const item of items) {
3332
+ if (item?.type !== "text") continue;
3333
+ const text = item.messageContent || item.text || "";
3334
+ if (typeof text !== "string" || !text.includes("<A2UI")) continue;
3335
+ const tags = parseA2uiTagsFromText(text);
3336
+ for (const tag of tags) {
3337
+ for (const cmd of tag.commands) {
3338
+ const sid = String(cmd?.createSurface?.surfaceId || "").trim();
3339
+ if (sid) surfaceIds.add(sid);
3340
+ }
3341
+ }
3342
+ }
3343
+ return surfaceIds;
3344
+ }
3345
+ function extractDismissedSurfaceIdsFromMessages(messages) {
3346
+ const lastCreateIndexBySurface = /* @__PURE__ */ new Map();
3347
+ const lastActionIndexBySurface = /* @__PURE__ */ new Map();
3348
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {
3349
+ const message2 = messages[messageIndex];
3350
+ const items = Array.isArray(message2?.content) ? message2.content : [];
3351
+ for (const item of items) {
3352
+ if (message2?.role !== 1) {
3353
+ if (item?.type === "a2uiCommand" && item.command) {
3354
+ const surfaceId = String(item.command?.createSurface?.surfaceId || "").trim();
3355
+ if (surfaceId) lastCreateIndexBySurface.set(surfaceId, messageIndex);
3356
+ }
3357
+ if (item?.type === "text") {
3358
+ const text = item.messageContent || item.text || "";
3359
+ if (typeof text === "string" && text.includes("<A2UI")) {
3360
+ const tags = parseA2uiTagsFromText(text);
3361
+ for (const tag of tags) {
3362
+ for (const cmd of tag.commands) {
3363
+ const surfaceId = String(cmd?.createSurface?.surfaceId || "").trim();
3364
+ if (surfaceId) lastCreateIndexBySurface.set(surfaceId, messageIndex);
3365
+ }
3366
+ }
3367
+ }
3368
+ }
3369
+ }
3370
+ if (message2?.role === 1 && item?.type === "text") {
3371
+ const text = item.messageContent || item.text || "";
3372
+ if (typeof text !== "string" || !text.includes("a2ui_action.v1")) continue;
3373
+ try {
3374
+ const parsed = JSON.parse(text.trim());
3375
+ if (parsed?.type !== "a2ui_action.v1") continue;
3376
+ const surfaceId = String(parsed.surfaceId || "").trim();
3377
+ if (!surfaceId) continue;
3378
+ lastActionIndexBySurface.set(surfaceId, messageIndex);
3379
+ } catch {
3380
+ }
3381
+ }
3382
+ }
3383
+ }
3384
+ const dismissed = [];
3385
+ for (const [surfaceId, actionIndex] of lastActionIndexBySurface) {
3386
+ const createIndex = lastCreateIndexBySurface.get(surfaceId);
3387
+ if (createIndex === void 0 || actionIndex > createIndex) {
3388
+ dismissed.push(surfaceId);
3389
+ }
3390
+ }
3391
+ return dismissed;
3392
+ }
3393
+
3265
3394
  // src/components/CustomComponents/A2uiRuntime/controller/meta.ts
3266
3395
  function readProp(current, props, key) {
3267
3396
  return current[key] ?? props?.[key];
@@ -3429,19 +3558,8 @@ function inferModelPathFromSurfaceCommands(surfaceId, commands) {
3429
3558
  });
3430
3559
  return commonParentPath(paths);
3431
3560
  }
3432
- function isSubmitLikeActionName(name) {
3433
- const trimmed = typeof name === "string" ? name.trim() : "";
3434
- return trimmed === "submit" || trimmed === "confirm" || trimmed.startsWith("submit_") || trimmed.endsWith(".confirm");
3435
- }
3436
- function isCancelLikeActionName(name) {
3437
- const trimmed = typeof name === "string" ? name.trim() : "";
3438
- return trimmed === "cancel" || trimmed === "qf.cancel" || trimmed.endsWith(".cancel");
3439
- }
3440
3561
  function shouldOptimisticallyDismissSurface(actionName, context) {
3441
- if (isSubmitLikeActionName(actionName) || isCancelLikeActionName(actionName)) return true;
3442
- if (actionName === "qf.submit" || actionName === "qf.cancel") return true;
3443
- const submitFlag = context?.submit;
3444
- return submitFlag === true;
3562
+ return true;
3445
3563
  }
3446
3564
  function buildDispatchContext(surfaceId, rawContext, commands) {
3447
3565
  let normalizedContext = normalizeActionContext(rawContext);
@@ -3740,6 +3858,7 @@ function buildWizardUpdateComponentsCommand(schema, stepId) {
3740
3858
  function createA2uiRuntimeState() {
3741
3859
  return {
3742
3860
  processedMessageCursors: [],
3861
+ processedTagIds: [],
3743
3862
  serverCommands: [],
3744
3863
  localCommands: [],
3745
3864
  anchorIndexBySurface: {},
@@ -3761,6 +3880,15 @@ function extractSurfaceId2(command) {
3761
3880
  function getA2uiRuntimeCommands(state) {
3762
3881
  return [...state.serverCommands, ...state.localCommands];
3763
3882
  }
3883
+ function sanitizeA2uiCommands(commands) {
3884
+ return commands.map((cmd) => {
3885
+ if (!cmd || typeof cmd !== "object" || !cmd.updateDataModel) return cmd;
3886
+ const { path } = cmd.updateDataModel;
3887
+ if (typeof path === "string" && path.trim()) return cmd;
3888
+ const { updateDataModel: _, ...rest } = cmd;
3889
+ return rest;
3890
+ });
3891
+ }
3764
3892
  function diffConversationMessages(messages, prevCursors) {
3765
3893
  if (messages.length < prevCursors.length) {
3766
3894
  return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
@@ -3799,6 +3927,57 @@ function initializeWizardSurface(state, surfaceId, effects, nextWizardSteps) {
3799
3927
  nextWizardSteps[surfaceId] = firstStepId.trim();
3800
3928
  }
3801
3929
  }
3930
+ function processA2uiCommand(cmd, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps) {
3931
+ nextState.serverCommands.push(cmd);
3932
+ nextState.lastA2uiHost = { id: messageId, index: messageIndex };
3933
+ const surfaceId = extractSurfaceId2(cmd);
3934
+ if (!surfaceId) return;
3935
+ if (cmd?.createSurface) {
3936
+ nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3937
+ } else if (nextState.anchorIndexBySurface[surfaceId] === void 0 && !cmd?.deleteSurface) {
3938
+ nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3939
+ }
3940
+ if (cmd?.createSurface) {
3941
+ nextState.latestCreateCommandIndexBySurface[surfaceId] = nextState.serverCommands.length - 1;
3942
+ nextState.optimisticallyDismissedSurfaceIds = nextState.optimisticallyDismissedSurfaceIds.filter((id) => id !== surfaceId);
3943
+ initializeWizardSurface(nextState, surfaceId, effects, nextWizardSteps);
3944
+ }
3945
+ if (cmd?.updateDataModel) {
3946
+ const { path, value } = cmd.updateDataModel;
3947
+ if (typeof path === "string" && path.trim() && value && typeof value === "object" && !Array.isArray(value)) {
3948
+ effects.push({ type: "write-model", modelPath: path, values: value });
3949
+ }
3950
+ }
3951
+ if (cmd?.deleteSurface) {
3952
+ deletedSurfaceIds.add(surfaceId);
3953
+ const modelPath = nextState.modelPathBySurface[surfaceId];
3954
+ if (modelPath) effects.push({ type: "clear-model", modelPath });
3955
+ delete nextState.initializedWizardRevisionBySurface[surfaceId];
3956
+ delete nextState.modelPathBySurface[surfaceId];
3957
+ }
3958
+ }
3959
+ function scanA2uiTagsFromMessages(messages, processedTagIds) {
3960
+ const newTags = [];
3961
+ const newTagIds = [];
3962
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
3963
+ const message2 = messages[messageIndex];
3964
+ const messageId = String(message2?.messageId ?? messageIndex);
3965
+ const items = Array.isArray(message2?.content) ? message2.content : [];
3966
+ for (const item of items) {
3967
+ if (item?.type !== "text") continue;
3968
+ const text = item.messageContent || item.text || "";
3969
+ if (typeof text !== "string" || !text.includes("<A2UI")) continue;
3970
+ const tags = parseA2uiTagsFromText(text);
3971
+ for (const tag of tags) {
3972
+ if (processedTagIds.has(tag.tagId)) continue;
3973
+ processedTagIds.add(tag.tagId);
3974
+ newTagIds.push(tag.tagId);
3975
+ newTags.push({ commands: tag.commands, messageIndex, messageId });
3976
+ }
3977
+ }
3978
+ }
3979
+ return { newTags, newTagIds };
3980
+ }
3802
3981
  function reduceA2uiRuntimeMessages(state, messages) {
3803
3982
  const { shouldReplayAll, pendingItems, nextCursors } = diffConversationMessages(messages || [], state.processedMessageCursors);
3804
3983
  const itemsToProcess = shouldReplayAll ? messages.flatMap((message2, messageIndex) => {
@@ -3806,11 +3985,14 @@ function reduceA2uiRuntimeMessages(state, messages) {
3806
3985
  const items = Array.isArray(message2?.content) ? message2.content : [];
3807
3986
  return items.map((item) => ({ messageIndex, messageId, item }));
3808
3987
  }) : pendingItems;
3809
- if (!shouldReplayAll && itemsToProcess.length === 0) {
3988
+ const tagProcessedSet = new Set(shouldReplayAll ? [] : state.processedTagIds);
3989
+ const { newTags, newTagIds } = scanA2uiTagsFromMessages(messages || [], tagProcessedSet);
3990
+ if (!shouldReplayAll && itemsToProcess.length === 0 && newTags.length === 0) {
3810
3991
  return { state, effects: [] };
3811
3992
  }
3812
3993
  const nextState = shouldReplayAll ? createA2uiRuntimeState() : { ...state };
3813
3994
  nextState.processedMessageCursors = shouldReplayAll ? [] : [...state.processedMessageCursors];
3995
+ nextState.processedTagIds = shouldReplayAll ? [] : [...state.processedTagIds, ...newTagIds];
3814
3996
  nextState.serverCommands = shouldReplayAll ? [] : [...state.serverCommands];
3815
3997
  nextState.localCommands = shouldReplayAll ? [] : [...state.localCommands];
3816
3998
  nextState.anchorIndexBySurface = shouldReplayAll ? {} : { ...state.anchorIndexBySurface };
@@ -3833,24 +4015,13 @@ function reduceA2uiRuntimeMessages(state, messages) {
3833
4015
  }
3834
4016
  return;
3835
4017
  }
3836
- if (item?.type !== "a2uiCommand" || !item.command) return;
3837
- nextState.serverCommands.push(item.command);
3838
- nextState.lastA2uiHost = { id: messageId, index: messageIndex };
3839
- const surfaceId = extractSurfaceId2(item.command);
3840
- if (!surfaceId) return;
3841
- if (nextState.anchorIndexBySurface[surfaceId] === void 0 && !item.command?.deleteSurface) {
3842
- nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3843
- }
3844
- if (item.command?.createSurface) {
3845
- nextState.latestCreateCommandIndexBySurface[surfaceId] = nextState.serverCommands.length - 1;
3846
- initializeWizardSurface(nextState, surfaceId, effects, nextWizardSteps);
3847
- }
3848
- if (item.command?.deleteSurface) {
3849
- deletedSurfaceIds.add(surfaceId);
3850
- const modelPath = nextState.modelPathBySurface[surfaceId];
3851
- if (modelPath) effects.push({ type: "clear-model", modelPath });
3852
- delete nextState.initializedWizardRevisionBySurface[surfaceId];
3853
- delete nextState.modelPathBySurface[surfaceId];
4018
+ if (item?.type === "a2uiCommand" && item.command) {
4019
+ processA2uiCommand(item.command, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps);
4020
+ }
4021
+ });
4022
+ newTags.forEach(({ commands, messageIndex, messageId }) => {
4023
+ for (const cmd of commands) {
4024
+ processA2uiCommand(cmd, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps);
3854
4025
  }
3855
4026
  });
3856
4027
  nextState.processedMessageCursors = shouldReplayAll ? messages.map((message2, messageIndex) => ({
@@ -3870,7 +4041,7 @@ function reduceA2uiRuntimeMessages(state, messages) {
3870
4041
  return { state: nextState, effects };
3871
4042
  }
3872
4043
  function reduceA2uiRuntimeAction(state, input) {
3873
- const { surfaceId, actionName, rawContext } = input;
4044
+ const { surfaceId, actionName} = input;
3874
4045
  if (!surfaceId) {
3875
4046
  return { state, handled: actionName === "wizard.next" || actionName === "wizard.back" };
3876
4047
  }
@@ -3900,9 +4071,6 @@ function reduceA2uiRuntimeAction(state, input) {
3900
4071
  if (actionName === "wizard.next" || actionName === "wizard.back") {
3901
4072
  return { state, handled: true };
3902
4073
  }
3903
- if (!shouldOptimisticallyDismissSurface(actionName, rawContext)) {
3904
- return { state, handled: false };
3905
- }
3906
4074
  if (state.optimisticallyDismissedSurfaceIds.includes(surfaceId)) {
3907
4075
  return { state, handled: false };
3908
4076
  }
@@ -3918,7 +4086,7 @@ function selectA2uiRuntimeView(state, dismissedSurfaceIds) {
3918
4086
  const mergedDismissedSurfaceIds = Array.from(
3919
4087
  new Set([...dismissedSurfaceIds || [], ...state.optimisticallyDismissedSurfaceIds].filter((surfaceId) => surfaceId?.trim?.()))
3920
4088
  );
3921
- const commands = getA2uiRuntimeCommands(state);
4089
+ const commands = sanitizeA2uiCommands(getA2uiRuntimeCommands(state));
3922
4090
  const visibleSurfaceIds = resolveVisibleSurfaceIds(commands, mergedDismissedSurfaceIds);
3923
4091
  const anchoredSurfaceIdsByMessageIndex = {};
3924
4092
  visibleSurfaceIds.forEach((surfaceId) => {
@@ -3967,12 +4135,20 @@ function useA2uiController(params) {
3967
4135
  applyA2uiRuntimeEffects(result.effects);
3968
4136
  setRuntimeState(result.state);
3969
4137
  }, [conversationMessages, conversationId]);
3970
- const view = useMemo(() => selectA2uiRuntimeView(runtimeState, dismissedSurfaceIds), [runtimeState, dismissedSurfaceIds]);
4138
+ const permanentDismissedSurfaceIds = useMemo(
4139
+ () => extractDismissedSurfaceIdsFromMessages(conversationMessages || []),
4140
+ [conversationMessages]
4141
+ );
4142
+ const mergedDismissedSurfaceIds = useMemo(
4143
+ () => Array.from(/* @__PURE__ */ new Set([...dismissedSurfaceIds || [], ...permanentDismissedSurfaceIds])),
4144
+ [dismissedSurfaceIds, permanentDismissedSurfaceIds]
4145
+ );
4146
+ const view = useMemo(() => selectA2uiRuntimeView(runtimeState, mergedDismissedSurfaceIds), [runtimeState, mergedDismissedSurfaceIds]);
3971
4147
  const handleRuntimeAction = useCallback((payload) => {
3972
4148
  const surfaceId = String(payload?.surfaceId || payload?.cardId || "");
3973
4149
  const name = String(payload?.name || payload?.event?.name || "").trim();
3974
4150
  const rawContext = payload?.context || payload?.event?.context || {};
3975
- const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name, rawContext });
4151
+ const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name});
3976
4152
  if (runtimeActionResult.state !== runtimeRef.current) {
3977
4153
  runtimeRef.current = runtimeActionResult.state;
3978
4154
  setRuntimeState(runtimeActionResult.state);
@@ -3999,26 +4175,26 @@ var A2uiRuntimeContext = React10__default.createContext({
3999
4175
  function useA2uiRuntimeView() {
4000
4176
  return React10__default.useContext(A2uiRuntimeContext);
4001
4177
  }
4002
- function A2uiMessageCards({ messageIndex }) {
4178
+ function A2uiMessageCards({ messageIndex, message: message2 }) {
4003
4179
  const { surfaceIdsByMessageIndex } = useA2uiRuntimeView();
4004
- const surfaceIds = surfaceIdsByMessageIndex[messageIndex] || [];
4180
+ const allSurfaceIds = surfaceIdsByMessageIndex[messageIndex] || [];
4181
+ const inlineSurfaceIds = message2 ? extractInlineSurfaceIdsFromMessage(message2) : /* @__PURE__ */ new Set();
4182
+ const surfaceIds = allSurfaceIds.filter((id) => !inlineSurfaceIds.has(id));
4005
4183
  if (!surfaceIds.length) return null;
4006
4184
  return /* @__PURE__ */ jsx("div", { children: surfaceIds.map((surfaceId) => /* @__PURE__ */ jsx(XCard.Card, { id: surfaceId }, surfaceId)) });
4007
4185
  }
4008
4186
 
4009
4187
  // src/components/CustomComponents/A2uiRuntime/renderer/protocol.ts
4010
- function isSubmitLikeActionName2(name) {
4188
+ function isSubmitLikeActionName(name) {
4011
4189
  const normalized = String(name || "").trim();
4012
4190
  return normalized === "submit" || normalized === "confirm" || normalized.startsWith("submit_") || normalized.endsWith(".confirm");
4013
4191
  }
4014
- function isCancelLikeActionName2(name) {
4192
+ function isCancelLikeActionName(name) {
4015
4193
  const normalized = String(name || "").trim();
4016
4194
  return normalized === "cancel" || normalized === "qf.cancel" || normalized.endsWith(".cancel");
4017
4195
  }
4018
4196
  function shouldDismissA2uiSurface(name, context) {
4019
- if (isSubmitLikeActionName2(name) || isCancelLikeActionName2(name)) return true;
4020
- if (name === "qf.submit" || name === "qf.cancel") return true;
4021
- return context?.submit === true;
4197
+ return true;
4022
4198
  }
4023
4199
  function normalizeA2uiActionPayload(payload) {
4024
4200
  return {
@@ -4052,7 +4228,7 @@ function isQuestionActionPayload(payload) {
4052
4228
  const mode = payload.context?.form_mode;
4053
4229
  if (payload.name === "qf.submit" || payload.name === "qf.cancel") return true;
4054
4230
  if (payload.name.startsWith("qf.")) return true;
4055
- return typeof mode === "string" && mode.toLowerCase() === "ephemeral" ? isSubmitLikeActionName2(payload.name) || isCancelLikeActionName2(payload.name) : false;
4231
+ return typeof mode === "string" && mode.toLowerCase() === "ephemeral" ? isSubmitLikeActionName(payload.name) || isCancelLikeActionName(payload.name) : false;
4056
4232
  }
4057
4233
  function formatActionValue(value, displayOverride) {
4058
4234
  if (typeof displayOverride === "string" && displayOverride.trim()) return displayOverride.trim();
@@ -4062,7 +4238,7 @@ function formatActionValue(value, displayOverride) {
4062
4238
  return String(value);
4063
4239
  }
4064
4240
  function buildQuestionSummary(payload) {
4065
- if (isCancelLikeActionName2(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
4241
+ if (isCancelLikeActionName(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
4066
4242
  const values = payload.context.values && typeof payload.context.values === "object" && !Array.isArray(payload.context.values) ? payload.context.values : payload.context;
4067
4243
  const labels = payload.context.labels && typeof payload.context.labels === "object" && !Array.isArray(payload.context.labels) ? payload.context.labels : {};
4068
4244
  const valueLabels = payload.context.valueLabels && typeof payload.context.valueLabels === "object" && !Array.isArray(payload.context.valueLabels) ? payload.context.valueLabels : {};
@@ -4084,10 +4260,22 @@ function formatA2uiActionDisplayText(payload) {
4084
4260
  back_to_params: "\u5DF2\u8FD4\u56DE\u4FEE\u6539\u53C2\u6570",
4085
4261
  confirm: "\u5DF2\u786E\u8BA4\u521B\u5EFA"
4086
4262
  };
4087
- const actionLabel = actionLabels[payload.name] || `\u5DF2\u63D0\u4EA4\u52A8\u4F5C (${payload.name})`;
4263
+ let actionLabel = actionLabels[payload.name];
4264
+ if (!actionLabel) {
4265
+ if (payload.name.startsWith("confirm_")) {
4266
+ actionLabel = "\u5DF2\u9009\u62E9";
4267
+ } else if (payload.name.startsWith("submit_")) {
4268
+ actionLabel = "\u5DF2\u63D0\u4EA4";
4269
+ } else {
4270
+ actionLabel = `\u5DF2\u63D0\u4EA4\u52A8\u4F5C (${payload.name})`;
4271
+ }
4272
+ }
4273
+ const isConfirmLike = payload.name.startsWith("confirm_");
4088
4274
  const details = Object.entries(values).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([key, value]) => {
4275
+ const formatted = formatActionValue(value, valueLabels[key]);
4276
+ if (isConfirmLike) return formatted;
4089
4277
  const label = typeof labels[key] === "string" && String(labels[key]).trim() ? String(labels[key]).trim() : key;
4090
- return `${label}: ${formatActionValue(value, valueLabels[key])}`;
4278
+ return `${label}: ${formatted}`;
4091
4279
  });
4092
4280
  return details.length ? `${actionLabel}\uFF1A${details.join("\uFF1B ")}` : actionLabel;
4093
4281
  }
@@ -4185,66 +4373,46 @@ function readContextModelPath(context) {
4185
4373
  const path = context?.model && typeof context.model === "object" ? context.model.path : "";
4186
4374
  return typeof path === "string" ? path.trim() : "";
4187
4375
  }
4188
- function diffMessages(messages, prevCursors) {
4189
- if (messages.length < prevCursors.length) {
4190
- return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
4191
- }
4192
- const nextCursors = [];
4193
- const pendingItems = [];
4194
- for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
4195
- const message2 = messages[messageIndex];
4196
- const messageId = String(message2?.messageId ?? messageIndex);
4376
+ function buildLatestCommandIndexBySurface(messages) {
4377
+ const indexBySurface = {};
4378
+ let commandIndex = -1;
4379
+ for (const message2 of messages) {
4197
4380
  const items = Array.isArray(message2?.content) ? message2.content : [];
4198
- const prevCursor = prevCursors[messageIndex];
4199
- const startIndex = prevCursor ? prevCursor.contentLength : 0;
4200
- if (prevCursor && (prevCursor.messageId !== messageId || items.length < prevCursor.contentLength)) {
4201
- return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
4202
- }
4203
- for (let itemIndex = startIndex; itemIndex < items.length; itemIndex += 1) {
4204
- pendingItems.push({ item: items[itemIndex] });
4381
+ for (const item of items) {
4382
+ if (item?.type === "a2uiCommand" && item.command) {
4383
+ commandIndex += 1;
4384
+ const surfaceId = extractSurfaceId3(item.command);
4385
+ if (surfaceId) indexBySurface[surfaceId] = commandIndex;
4386
+ continue;
4387
+ }
4388
+ if (item?.type === "text") {
4389
+ const text = item.messageContent || item.text || "";
4390
+ if (typeof text !== "string" || !text.includes("<A2UI")) continue;
4391
+ const tags = parseA2uiTagsFromText(text);
4392
+ for (const tag of tags) {
4393
+ for (const cmd of tag.commands) {
4394
+ commandIndex += 1;
4395
+ const surfaceId = extractSurfaceId3(cmd);
4396
+ if (surfaceId) indexBySurface[surfaceId] = commandIndex;
4397
+ }
4398
+ }
4399
+ }
4205
4400
  }
4206
- nextCursors.push({ messageId, contentLength: items.length });
4207
4401
  }
4208
- return { shouldReplayAll: false, nextCursors, pendingItems };
4402
+ return indexBySurface;
4209
4403
  }
4210
4404
  function A2uiRuntimeProvider({ messages, children }) {
4211
4405
  const chatStore = useChatStore();
4212
4406
  const conversationState = useSnapshot(chatStore.conversation);
4213
4407
  const conversationId = conversationState.active.id;
4214
- const processedMessageCursorsRef = React10__default.useRef([]);
4215
- const latestCommandIndexBySurfaceRef = React10__default.useRef({});
4216
- const commandIndexRef = React10__default.useRef(-1);
4217
4408
  const [latestCommandIndexBySurface, setLatestCommandIndexBySurface] = React10__default.useState({});
4218
4409
  const [dismissedAtBySurface, setDismissedAtBySurface] = React10__default.useState({});
4219
4410
  React10__default.useEffect(() => {
4220
- processedMessageCursorsRef.current = [];
4221
- latestCommandIndexBySurfaceRef.current = {};
4222
- commandIndexRef.current = -1;
4223
4411
  setLatestCommandIndexBySurface({});
4224
4412
  setDismissedAtBySurface({});
4225
4413
  }, [conversationId]);
4226
4414
  React10__default.useEffect(() => {
4227
- const { shouldReplayAll, nextCursors, pendingItems } = diffMessages(messages, processedMessageCursorsRef.current);
4228
- const itemsToProcess = shouldReplayAll ? messages.flatMap((message2) => {
4229
- const items = Array.isArray(message2?.content) ? message2.content : [];
4230
- return items.map((item) => ({ item }));
4231
- }) : pendingItems;
4232
- if (!shouldReplayAll && itemsToProcess.length === 0) return;
4233
- const nextLatestCommandIndexBySurface = shouldReplayAll ? {} : { ...latestCommandIndexBySurfaceRef.current };
4234
- let nextCommandIndex = shouldReplayAll ? -1 : commandIndexRef.current;
4235
- itemsToProcess.forEach(({ item }) => {
4236
- if (item?.type !== "a2uiCommand" || !item.command) return;
4237
- nextCommandIndex += 1;
4238
- const surfaceId = extractSurfaceId3(item.command);
4239
- if (surfaceId) nextLatestCommandIndexBySurface[surfaceId] = nextCommandIndex;
4240
- });
4241
- processedMessageCursorsRef.current = shouldReplayAll ? messages.map((message2, messageIndex) => ({
4242
- messageId: String(message2?.messageId ?? messageIndex),
4243
- contentLength: Array.isArray(message2?.content) ? message2.content.length : 0
4244
- })) : nextCursors;
4245
- latestCommandIndexBySurfaceRef.current = nextLatestCommandIndexBySurface;
4246
- commandIndexRef.current = nextCommandIndex;
4247
- setLatestCommandIndexBySurface(nextLatestCommandIndexBySurface);
4415
+ setLatestCommandIndexBySurface(buildLatestCommandIndexBySurface(messages));
4248
4416
  }, [messages]);
4249
4417
  const dismissedSurfaceIds = React10__default.useMemo(() => {
4250
4418
  return Object.entries(dismissedAtBySurface).filter(([surfaceId, dismissedAt]) => (latestCommandIndexBySurface[surfaceId] ?? -1) <= dismissedAt).map(([surfaceId]) => surfaceId);
@@ -4373,14 +4541,37 @@ function QuestionSummary({ content }) {
4373
4541
  ] });
4374
4542
  }
4375
4543
  var TextNode2 = React10__default.memo(
4376
- ({ item, role, customComponents, message: message2 }) => {
4377
- const content = toA2uiDisplayText(role, item?.messageContent);
4378
- if (typeof content === "string" && content.startsWith("Question:")) {
4379
- return /* @__PURE__ */ jsx(QuestionSummary, { content });
4544
+ ({
4545
+ item,
4546
+ role,
4547
+ customComponents,
4548
+ message: message2,
4549
+ messageIndex = -1
4550
+ }) => {
4551
+ const { surfaceIdsByMessageIndex } = useA2uiRuntimeView();
4552
+ const rawContent = toA2uiDisplayText(role, item?.messageContent);
4553
+ const segments = splitA2uiTextSegments(rawContent);
4554
+ const visibleSurfaceIds = messageIndex >= 0 ? new Set(surfaceIdsByMessageIndex[messageIndex] || []) : null;
4555
+ const firstSeg = segments[0];
4556
+ const isPureText = segments.length === 0 || segments.length === 1 && firstSeg.type === "text";
4557
+ if (isPureText) {
4558
+ const content = firstSeg && firstSeg.type === "text" ? firstSeg.content : "";
4559
+ if (typeof content === "string" && content.startsWith("Question:")) {
4560
+ return /* @__PURE__ */ jsx(QuestionSummary, { content });
4561
+ }
4562
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4563
+ !!item.reasoningContent && /* @__PURE__ */ jsx(Think, { title: "\u6DF1\u5EA6\u601D\u8003", children: item.reasoningContent }),
4564
+ !!content && /* @__PURE__ */ jsx(XMarkdown_default, { message: message2, components: customComponents, content })
4565
+ ] });
4380
4566
  }
4381
4567
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4382
4568
  !!item.reasoningContent && /* @__PURE__ */ jsx(Think, { title: "\u6DF1\u5EA6\u601D\u8003", children: item.reasoningContent }),
4383
- !!content && /* @__PURE__ */ jsx(XMarkdown_default, { message: message2, components: customComponents, content })
4569
+ segments.map((seg, i) => {
4570
+ if (seg.type === "text") {
4571
+ return seg.content.trim() ? /* @__PURE__ */ jsx(XMarkdown_default, { message: message2, components: customComponents, content: seg.content }, `text-${i}`) : null;
4572
+ }
4573
+ return seg.surfaceIds.filter((sid) => !visibleSurfaceIds || visibleSurfaceIds.has(sid)).map((sid) => /* @__PURE__ */ jsx(XCard.Card, { id: sid }, `a2ui-${i}-${sid}`));
4574
+ })
4384
4575
  ] });
4385
4576
  }
4386
4577
  );
@@ -4608,6 +4799,12 @@ var MessageRender_default = React10__default.memo(({ role, message: message2, me
4608
4799
  if (item.type === "plan") {
4609
4800
  return !shouldHideA2uiPlan(item);
4610
4801
  }
4802
+ if (item.type === "text") {
4803
+ const rawText = item.messageContent || item.text || "";
4804
+ const visibleText = stripA2uiTags(rawText);
4805
+ const hasA2uiTag2 = typeof rawText === "string" && rawText.includes("<A2UI");
4806
+ return !!visibleText.trim() || !!item.reasoningContent || hasA2uiTag2;
4807
+ }
4611
4808
  return true;
4612
4809
  });
4613
4810
  }, [loading, message2.content]);
@@ -4636,7 +4833,7 @@ var MessageRender_default = React10__default.memo(({ role, message: message2, me
4636
4833
  content: /* @__PURE__ */ jsxs(Fragment, { children: [
4637
4834
  item.type === "runStarted" && /* @__PURE__ */ jsx(RunStartedNode, { loading }, `flow-start-${index}`),
4638
4835
  (item.type === "toolCall" || item.type === "toolResult") && /* @__PURE__ */ jsx(tool_call_item_default, { item }, `tool-call-${item.toolCallId || index}`),
4639
- item.type === "text" && /* @__PURE__ */ jsx(TextNode2, { item, role: message2.role, customComponents, message: message2 }, `message-${index}`),
4836
+ item.type === "text" && /* @__PURE__ */ jsx(TextNode2, { item, role: message2.role, customComponents, message: message2, messageIndex }, `message-${index}`),
4640
4837
  item.type === "stepError" && (item.errorMessage ? /* @__PURE__ */ jsx(XMarkdown_default, { message: message2, components: customComponents, content: item.errorMessage }) : null),
4641
4838
  item.type === "files" && /* @__PURE__ */ jsx(FilesNode, { item }, `files-${index}`),
4642
4839
  item.type === "plan" && /* @__PURE__ */ jsx(A2uiPlanNode, { item }, `plan-${index}`)
@@ -4646,7 +4843,7 @@ var MessageRender_default = React10__default.memo(({ role, message: message2, me
4646
4843
  );
4647
4844
  }),
4648
4845
  quoteMsg && /* @__PURE__ */ jsx(QuoteMsgNode, { quoteMsg, role }),
4649
- messageIndex >= 0 ? /* @__PURE__ */ jsx(A2uiMessageCards, { messageIndex }) : null
4846
+ messageIndex >= 0 ? /* @__PURE__ */ jsx(A2uiMessageCards, { messageIndex, message: message2 }) : null
4650
4847
  ] });
4651
4848
  });
4652
4849
  var WelcomeItem_default = ({ icon = true, title = true, description = true, prompts = true }) => {