@zero-library/chat-copilot 3.1.6 → 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
@@ -3291,6 +3291,135 @@ var A2uiComponents = {
3291
3291
  ReportViewer
3292
3292
  };
3293
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
+
3294
3423
  // src/components/CustomComponents/A2uiRuntime/controller/meta.ts
3295
3424
  function readProp(current, props, key) {
3296
3425
  return current[key] ?? props?.[key];
@@ -3458,19 +3587,8 @@ function inferModelPathFromSurfaceCommands(surfaceId, commands) {
3458
3587
  });
3459
3588
  return commonParentPath(paths);
3460
3589
  }
3461
- function isSubmitLikeActionName(name) {
3462
- const trimmed = typeof name === "string" ? name.trim() : "";
3463
- return trimmed === "submit" || trimmed === "confirm" || trimmed.startsWith("submit_") || trimmed.endsWith(".confirm");
3464
- }
3465
- function isCancelLikeActionName(name) {
3466
- const trimmed = typeof name === "string" ? name.trim() : "";
3467
- return trimmed === "cancel" || trimmed === "qf.cancel" || trimmed.endsWith(".cancel");
3468
- }
3469
3590
  function shouldOptimisticallyDismissSurface(actionName, context) {
3470
- if (isSubmitLikeActionName(actionName) || isCancelLikeActionName(actionName)) return true;
3471
- if (actionName === "qf.submit" || actionName === "qf.cancel") return true;
3472
- const submitFlag = context?.submit;
3473
- return submitFlag === true;
3591
+ return true;
3474
3592
  }
3475
3593
  function buildDispatchContext(surfaceId, rawContext, commands) {
3476
3594
  let normalizedContext = normalizeActionContext(rawContext);
@@ -3769,6 +3887,7 @@ function buildWizardUpdateComponentsCommand(schema, stepId) {
3769
3887
  function createA2uiRuntimeState() {
3770
3888
  return {
3771
3889
  processedMessageCursors: [],
3890
+ processedTagIds: [],
3772
3891
  serverCommands: [],
3773
3892
  localCommands: [],
3774
3893
  anchorIndexBySurface: {},
@@ -3828,6 +3947,57 @@ function initializeWizardSurface(state, surfaceId, effects, nextWizardSteps) {
3828
3947
  nextWizardSteps[surfaceId] = firstStepId.trim();
3829
3948
  }
3830
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
+ }
3831
4001
  function reduceA2uiRuntimeMessages(state, messages) {
3832
4002
  const { shouldReplayAll, pendingItems, nextCursors } = diffConversationMessages(messages || [], state.processedMessageCursors);
3833
4003
  const itemsToProcess = shouldReplayAll ? messages.flatMap((message2, messageIndex) => {
@@ -3835,11 +4005,14 @@ function reduceA2uiRuntimeMessages(state, messages) {
3835
4005
  const items = Array.isArray(message2?.content) ? message2.content : [];
3836
4006
  return items.map((item) => ({ messageIndex, messageId, item }));
3837
4007
  }) : pendingItems;
3838
- 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) {
3839
4011
  return { state, effects: [] };
3840
4012
  }
3841
4013
  const nextState = shouldReplayAll ? createA2uiRuntimeState() : { ...state };
3842
4014
  nextState.processedMessageCursors = shouldReplayAll ? [] : [...state.processedMessageCursors];
4015
+ nextState.processedTagIds = shouldReplayAll ? [] : [...state.processedTagIds, ...newTagIds];
3843
4016
  nextState.serverCommands = shouldReplayAll ? [] : [...state.serverCommands];
3844
4017
  nextState.localCommands = shouldReplayAll ? [] : [...state.localCommands];
3845
4018
  nextState.anchorIndexBySurface = shouldReplayAll ? {} : { ...state.anchorIndexBySurface };
@@ -3862,24 +4035,13 @@ function reduceA2uiRuntimeMessages(state, messages) {
3862
4035
  }
3863
4036
  return;
3864
4037
  }
3865
- if (item?.type !== "a2uiCommand" || !item.command) return;
3866
- nextState.serverCommands.push(item.command);
3867
- nextState.lastA2uiHost = { id: messageId, index: messageIndex };
3868
- const surfaceId = extractSurfaceId2(item.command);
3869
- if (!surfaceId) return;
3870
- if (nextState.anchorIndexBySurface[surfaceId] === void 0 && !item.command?.deleteSurface) {
3871
- nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3872
- }
3873
- if (item.command?.createSurface) {
3874
- nextState.latestCreateCommandIndexBySurface[surfaceId] = nextState.serverCommands.length - 1;
3875
- initializeWizardSurface(nextState, surfaceId, effects, nextWizardSteps);
3876
- }
3877
- if (item.command?.deleteSurface) {
3878
- deletedSurfaceIds.add(surfaceId);
3879
- const modelPath = nextState.modelPathBySurface[surfaceId];
3880
- if (modelPath) effects.push({ type: "clear-model", modelPath });
3881
- delete nextState.initializedWizardRevisionBySurface[surfaceId];
3882
- 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);
3883
4045
  }
3884
4046
  });
3885
4047
  nextState.processedMessageCursors = shouldReplayAll ? messages.map((message2, messageIndex) => ({
@@ -3899,7 +4061,7 @@ function reduceA2uiRuntimeMessages(state, messages) {
3899
4061
  return { state: nextState, effects };
3900
4062
  }
3901
4063
  function reduceA2uiRuntimeAction(state, input) {
3902
- const { surfaceId, actionName, rawContext } = input;
4064
+ const { surfaceId, actionName} = input;
3903
4065
  if (!surfaceId) {
3904
4066
  return { state, handled: actionName === "wizard.next" || actionName === "wizard.back" };
3905
4067
  }
@@ -3929,9 +4091,6 @@ function reduceA2uiRuntimeAction(state, input) {
3929
4091
  if (actionName === "wizard.next" || actionName === "wizard.back") {
3930
4092
  return { state, handled: true };
3931
4093
  }
3932
- if (!shouldOptimisticallyDismissSurface(actionName, rawContext)) {
3933
- return { state, handled: false };
3934
- }
3935
4094
  if (state.optimisticallyDismissedSurfaceIds.includes(surfaceId)) {
3936
4095
  return { state, handled: false };
3937
4096
  }
@@ -3996,12 +4155,20 @@ function useA2uiController(params) {
3996
4155
  applyA2uiRuntimeEffects(result.effects);
3997
4156
  setRuntimeState(result.state);
3998
4157
  }, [conversationMessages, conversationId]);
3999
- 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]);
4000
4167
  const handleRuntimeAction = React10.useCallback((payload) => {
4001
4168
  const surfaceId = String(payload?.surfaceId || payload?.cardId || "");
4002
4169
  const name = String(payload?.name || payload?.event?.name || "").trim();
4003
4170
  const rawContext = payload?.context || payload?.event?.context || {};
4004
- const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name, rawContext });
4171
+ const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name});
4005
4172
  if (runtimeActionResult.state !== runtimeRef.current) {
4006
4173
  runtimeRef.current = runtimeActionResult.state;
4007
4174
  setRuntimeState(runtimeActionResult.state);
@@ -4028,26 +4195,26 @@ var A2uiRuntimeContext = React10__namespace.default.createContext({
4028
4195
  function useA2uiRuntimeView() {
4029
4196
  return React10__namespace.default.useContext(A2uiRuntimeContext);
4030
4197
  }
4031
- function A2uiMessageCards({ messageIndex }) {
4198
+ function A2uiMessageCards({ messageIndex, message: message2 }) {
4032
4199
  const { surfaceIdsByMessageIndex } = useA2uiRuntimeView();
4033
- 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));
4034
4203
  if (!surfaceIds.length) return null;
4035
4204
  return /* @__PURE__ */ jsxRuntime.jsx("div", { children: surfaceIds.map((surfaceId) => /* @__PURE__ */ jsxRuntime.jsx(XCard.Card, { id: surfaceId }, surfaceId)) });
4036
4205
  }
4037
4206
 
4038
4207
  // src/components/CustomComponents/A2uiRuntime/renderer/protocol.ts
4039
- function isSubmitLikeActionName2(name) {
4208
+ function isSubmitLikeActionName(name) {
4040
4209
  const normalized = String(name || "").trim();
4041
4210
  return normalized === "submit" || normalized === "confirm" || normalized.startsWith("submit_") || normalized.endsWith(".confirm");
4042
4211
  }
4043
- function isCancelLikeActionName2(name) {
4212
+ function isCancelLikeActionName(name) {
4044
4213
  const normalized = String(name || "").trim();
4045
4214
  return normalized === "cancel" || normalized === "qf.cancel" || normalized.endsWith(".cancel");
4046
4215
  }
4047
4216
  function shouldDismissA2uiSurface(name, context) {
4048
- if (isSubmitLikeActionName2(name) || isCancelLikeActionName2(name)) return true;
4049
- if (name === "qf.submit" || name === "qf.cancel") return true;
4050
- return context?.submit === true;
4217
+ return true;
4051
4218
  }
4052
4219
  function normalizeA2uiActionPayload(payload) {
4053
4220
  return {
@@ -4081,7 +4248,7 @@ function isQuestionActionPayload(payload) {
4081
4248
  const mode = payload.context?.form_mode;
4082
4249
  if (payload.name === "qf.submit" || payload.name === "qf.cancel") return true;
4083
4250
  if (payload.name.startsWith("qf.")) return true;
4084
- 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;
4085
4252
  }
4086
4253
  function formatActionValue(value, displayOverride) {
4087
4254
  if (typeof displayOverride === "string" && displayOverride.trim()) return displayOverride.trim();
@@ -4091,7 +4258,7 @@ function formatActionValue(value, displayOverride) {
4091
4258
  return String(value);
4092
4259
  }
4093
4260
  function buildQuestionSummary(payload) {
4094
- if (isCancelLikeActionName2(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
4261
+ if (isCancelLikeActionName(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
4095
4262
  const values = payload.context.values && typeof payload.context.values === "object" && !Array.isArray(payload.context.values) ? payload.context.values : payload.context;
4096
4263
  const labels = payload.context.labels && typeof payload.context.labels === "object" && !Array.isArray(payload.context.labels) ? payload.context.labels : {};
4097
4264
  const valueLabels = payload.context.valueLabels && typeof payload.context.valueLabels === "object" && !Array.isArray(payload.context.valueLabels) ? payload.context.valueLabels : {};
@@ -4113,10 +4280,22 @@ function formatA2uiActionDisplayText(payload) {
4113
4280
  back_to_params: "\u5DF2\u8FD4\u56DE\u4FEE\u6539\u53C2\u6570",
4114
4281
  confirm: "\u5DF2\u786E\u8BA4\u521B\u5EFA"
4115
4282
  };
4116
- 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_");
4117
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;
4118
4297
  const label = typeof labels[key] === "string" && String(labels[key]).trim() ? String(labels[key]).trim() : key;
4119
- return `${label}: ${formatActionValue(value, valueLabels[key])}`;
4298
+ return `${label}: ${formatted}`;
4120
4299
  });
4121
4300
  return details.length ? `${actionLabel}\uFF1A${details.join("\uFF1B ")}` : actionLabel;
4122
4301
  }
@@ -4214,66 +4393,46 @@ function readContextModelPath(context) {
4214
4393
  const path = context?.model && typeof context.model === "object" ? context.model.path : "";
4215
4394
  return typeof path === "string" ? path.trim() : "";
4216
4395
  }
4217
- function diffMessages(messages, prevCursors) {
4218
- if (messages.length < prevCursors.length) {
4219
- return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
4220
- }
4221
- const nextCursors = [];
4222
- const pendingItems = [];
4223
- for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
4224
- const message2 = messages[messageIndex];
4225
- const messageId = String(message2?.messageId ?? messageIndex);
4396
+ function buildLatestCommandIndexBySurface(messages) {
4397
+ const indexBySurface = {};
4398
+ let commandIndex = -1;
4399
+ for (const message2 of messages) {
4226
4400
  const items = Array.isArray(message2?.content) ? message2.content : [];
4227
- const prevCursor = prevCursors[messageIndex];
4228
- const startIndex = prevCursor ? prevCursor.contentLength : 0;
4229
- if (prevCursor && (prevCursor.messageId !== messageId || items.length < prevCursor.contentLength)) {
4230
- return { shouldReplayAll: true, nextCursors: [], pendingItems: [] };
4231
- }
4232
- for (let itemIndex = startIndex; itemIndex < items.length; itemIndex += 1) {
4233
- 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
+ }
4234
4420
  }
4235
- nextCursors.push({ messageId, contentLength: items.length });
4236
4421
  }
4237
- return { shouldReplayAll: false, nextCursors, pendingItems };
4422
+ return indexBySurface;
4238
4423
  }
4239
4424
  function A2uiRuntimeProvider({ messages, children }) {
4240
4425
  const chatStore = useChatStore();
4241
4426
  const conversationState = valtio.useSnapshot(chatStore.conversation);
4242
4427
  const conversationId = conversationState.active.id;
4243
- const processedMessageCursorsRef = React10__namespace.default.useRef([]);
4244
- const latestCommandIndexBySurfaceRef = React10__namespace.default.useRef({});
4245
- const commandIndexRef = React10__namespace.default.useRef(-1);
4246
4428
  const [latestCommandIndexBySurface, setLatestCommandIndexBySurface] = React10__namespace.default.useState({});
4247
4429
  const [dismissedAtBySurface, setDismissedAtBySurface] = React10__namespace.default.useState({});
4248
4430
  React10__namespace.default.useEffect(() => {
4249
- processedMessageCursorsRef.current = [];
4250
- latestCommandIndexBySurfaceRef.current = {};
4251
- commandIndexRef.current = -1;
4252
4431
  setLatestCommandIndexBySurface({});
4253
4432
  setDismissedAtBySurface({});
4254
4433
  }, [conversationId]);
4255
4434
  React10__namespace.default.useEffect(() => {
4256
- const { shouldReplayAll, nextCursors, pendingItems } = diffMessages(messages, processedMessageCursorsRef.current);
4257
- const itemsToProcess = shouldReplayAll ? messages.flatMap((message2) => {
4258
- const items = Array.isArray(message2?.content) ? message2.content : [];
4259
- return items.map((item) => ({ item }));
4260
- }) : pendingItems;
4261
- if (!shouldReplayAll && itemsToProcess.length === 0) return;
4262
- const nextLatestCommandIndexBySurface = shouldReplayAll ? {} : { ...latestCommandIndexBySurfaceRef.current };
4263
- let nextCommandIndex = shouldReplayAll ? -1 : commandIndexRef.current;
4264
- itemsToProcess.forEach(({ item }) => {
4265
- if (item?.type !== "a2uiCommand" || !item.command) return;
4266
- nextCommandIndex += 1;
4267
- const surfaceId = extractSurfaceId3(item.command);
4268
- if (surfaceId) nextLatestCommandIndexBySurface[surfaceId] = nextCommandIndex;
4269
- });
4270
- processedMessageCursorsRef.current = shouldReplayAll ? messages.map((message2, messageIndex) => ({
4271
- messageId: String(message2?.messageId ?? messageIndex),
4272
- contentLength: Array.isArray(message2?.content) ? message2.content.length : 0
4273
- })) : nextCursors;
4274
- latestCommandIndexBySurfaceRef.current = nextLatestCommandIndexBySurface;
4275
- commandIndexRef.current = nextCommandIndex;
4276
- setLatestCommandIndexBySurface(nextLatestCommandIndexBySurface);
4435
+ setLatestCommandIndexBySurface(buildLatestCommandIndexBySurface(messages));
4277
4436
  }, [messages]);
4278
4437
  const dismissedSurfaceIds = React10__namespace.default.useMemo(() => {
4279
4438
  return Object.entries(dismissedAtBySurface).filter(([surfaceId, dismissedAt]) => (latestCommandIndexBySurface[surfaceId] ?? -1) <= dismissedAt).map(([surfaceId]) => surfaceId);
@@ -4402,14 +4561,37 @@ function QuestionSummary({ content }) {
4402
4561
  ] });
4403
4562
  }
4404
4563
  var TextNode2 = React10__namespace.default.memo(
4405
- ({ item, role, customComponents, message: message2 }) => {
4406
- const content = toA2uiDisplayText(role, item?.messageContent);
4407
- if (typeof content === "string" && content.startsWith("Question:")) {
4408
- 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
+ ] });
4409
4586
  }
4410
4587
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4411
4588
  !!item.reasoningContent && /* @__PURE__ */ jsxRuntime.jsx(xV2.Think, { title: "\u6DF1\u5EA6\u601D\u8003", children: item.reasoningContent }),
4412
- !!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
+ })
4413
4595
  ] });
4414
4596
  }
4415
4597
  );
@@ -4637,6 +4819,12 @@ var MessageRender_default = React10__namespace.default.memo(({ role, message: me
4637
4819
  if (item.type === "plan") {
4638
4820
  return !shouldHideA2uiPlan(item);
4639
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
+ }
4640
4828
  return true;
4641
4829
  });
4642
4830
  }, [loading, message2.content]);
@@ -4665,7 +4853,7 @@ var MessageRender_default = React10__namespace.default.memo(({ role, message: me
4665
4853
  content: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4666
4854
  item.type === "runStarted" && /* @__PURE__ */ jsxRuntime.jsx(RunStartedNode, { loading }, `flow-start-${index}`),
4667
4855
  (item.type === "toolCall" || item.type === "toolResult") && /* @__PURE__ */ jsxRuntime.jsx(tool_call_item_default, { item }, `tool-call-${item.toolCallId || index}`),
4668
- 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}`),
4669
4857
  item.type === "stepError" && (item.errorMessage ? /* @__PURE__ */ jsxRuntime.jsx(XMarkdown_default, { message: message2, components: customComponents, content: item.errorMessage }) : null),
4670
4858
  item.type === "files" && /* @__PURE__ */ jsxRuntime.jsx(FilesNode, { item }, `files-${index}`),
4671
4859
  item.type === "plan" && /* @__PURE__ */ jsxRuntime.jsx(A2uiPlanNode, { item }, `plan-${index}`)
@@ -4675,7 +4863,7 @@ var MessageRender_default = React10__namespace.default.memo(({ role, message: me
4675
4863
  );
4676
4864
  }),
4677
4865
  quoteMsg && /* @__PURE__ */ jsxRuntime.jsx(QuoteMsgNode, { quoteMsg, role }),
4678
- messageIndex >= 0 ? /* @__PURE__ */ jsxRuntime.jsx(A2uiMessageCards, { messageIndex }) : null
4866
+ messageIndex >= 0 ? /* @__PURE__ */ jsxRuntime.jsx(A2uiMessageCards, { messageIndex, message: message2 }) : null
4679
4867
  ] });
4680
4868
  });
4681
4869
  var WelcomeItem_default = ({ icon = true, title = true, description = true, prompts = true }) => {