@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.esm.js CHANGED
@@ -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: {},
@@ -3799,6 +3918,57 @@ function initializeWizardSurface(state, surfaceId, effects, nextWizardSteps) {
3799
3918
  nextWizardSteps[surfaceId] = firstStepId.trim();
3800
3919
  }
3801
3920
  }
3921
+ function processA2uiCommand(cmd, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps) {
3922
+ nextState.serverCommands.push(cmd);
3923
+ nextState.lastA2uiHost = { id: messageId, index: messageIndex };
3924
+ const surfaceId = extractSurfaceId2(cmd);
3925
+ if (!surfaceId) return;
3926
+ if (cmd?.createSurface) {
3927
+ nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3928
+ } else if (nextState.anchorIndexBySurface[surfaceId] === void 0 && !cmd?.deleteSurface) {
3929
+ nextState.anchorIndexBySurface[surfaceId] = messageIndex;
3930
+ }
3931
+ if (cmd?.createSurface) {
3932
+ nextState.latestCreateCommandIndexBySurface[surfaceId] = nextState.serverCommands.length - 1;
3933
+ nextState.optimisticallyDismissedSurfaceIds = nextState.optimisticallyDismissedSurfaceIds.filter((id) => id !== surfaceId);
3934
+ initializeWizardSurface(nextState, surfaceId, effects, nextWizardSteps);
3935
+ }
3936
+ if (cmd?.updateDataModel) {
3937
+ const { path, value } = cmd.updateDataModel;
3938
+ if (typeof path === "string" && path.trim() && value && typeof value === "object" && !Array.isArray(value)) {
3939
+ effects.push({ type: "write-model", modelPath: path, values: value });
3940
+ }
3941
+ }
3942
+ if (cmd?.deleteSurface) {
3943
+ deletedSurfaceIds.add(surfaceId);
3944
+ const modelPath = nextState.modelPathBySurface[surfaceId];
3945
+ if (modelPath) effects.push({ type: "clear-model", modelPath });
3946
+ delete nextState.initializedWizardRevisionBySurface[surfaceId];
3947
+ delete nextState.modelPathBySurface[surfaceId];
3948
+ }
3949
+ }
3950
+ function scanA2uiTagsFromMessages(messages, processedTagIds) {
3951
+ const newTags = [];
3952
+ const newTagIds = [];
3953
+ for (let messageIndex = 0; messageIndex < messages.length; messageIndex += 1) {
3954
+ const message2 = messages[messageIndex];
3955
+ const messageId = String(message2?.messageId ?? messageIndex);
3956
+ const items = Array.isArray(message2?.content) ? message2.content : [];
3957
+ for (const item of items) {
3958
+ if (item?.type !== "text") continue;
3959
+ const text = item.messageContent || item.text || "";
3960
+ if (typeof text !== "string" || !text.includes("<A2UI")) continue;
3961
+ const tags = parseA2uiTagsFromText(text);
3962
+ for (const tag of tags) {
3963
+ if (processedTagIds.has(tag.tagId)) continue;
3964
+ processedTagIds.add(tag.tagId);
3965
+ newTagIds.push(tag.tagId);
3966
+ newTags.push({ commands: tag.commands, messageIndex, messageId });
3967
+ }
3968
+ }
3969
+ }
3970
+ return { newTags, newTagIds };
3971
+ }
3802
3972
  function reduceA2uiRuntimeMessages(state, messages) {
3803
3973
  const { shouldReplayAll, pendingItems, nextCursors } = diffConversationMessages(messages || [], state.processedMessageCursors);
3804
3974
  const itemsToProcess = shouldReplayAll ? messages.flatMap((message2, messageIndex) => {
@@ -3806,11 +3976,14 @@ function reduceA2uiRuntimeMessages(state, messages) {
3806
3976
  const items = Array.isArray(message2?.content) ? message2.content : [];
3807
3977
  return items.map((item) => ({ messageIndex, messageId, item }));
3808
3978
  }) : pendingItems;
3809
- if (!shouldReplayAll && itemsToProcess.length === 0) {
3979
+ const tagProcessedSet = new Set(shouldReplayAll ? [] : state.processedTagIds);
3980
+ const { newTags, newTagIds } = scanA2uiTagsFromMessages(messages || [], tagProcessedSet);
3981
+ if (!shouldReplayAll && itemsToProcess.length === 0 && newTags.length === 0) {
3810
3982
  return { state, effects: [] };
3811
3983
  }
3812
3984
  const nextState = shouldReplayAll ? createA2uiRuntimeState() : { ...state };
3813
3985
  nextState.processedMessageCursors = shouldReplayAll ? [] : [...state.processedMessageCursors];
3986
+ nextState.processedTagIds = shouldReplayAll ? [] : [...state.processedTagIds, ...newTagIds];
3814
3987
  nextState.serverCommands = shouldReplayAll ? [] : [...state.serverCommands];
3815
3988
  nextState.localCommands = shouldReplayAll ? [] : [...state.localCommands];
3816
3989
  nextState.anchorIndexBySurface = shouldReplayAll ? {} : { ...state.anchorIndexBySurface };
@@ -3833,24 +4006,13 @@ function reduceA2uiRuntimeMessages(state, messages) {
3833
4006
  }
3834
4007
  return;
3835
4008
  }
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];
4009
+ if (item?.type === "a2uiCommand" && item.command) {
4010
+ processA2uiCommand(item.command, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps);
4011
+ }
4012
+ });
4013
+ newTags.forEach(({ commands, messageIndex, messageId }) => {
4014
+ for (const cmd of commands) {
4015
+ processA2uiCommand(cmd, messageIndex, messageId, nextState, effects, deletedSurfaceIds, nextWizardSteps);
3854
4016
  }
3855
4017
  });
3856
4018
  nextState.processedMessageCursors = shouldReplayAll ? messages.map((message2, messageIndex) => ({
@@ -3870,7 +4032,7 @@ function reduceA2uiRuntimeMessages(state, messages) {
3870
4032
  return { state: nextState, effects };
3871
4033
  }
3872
4034
  function reduceA2uiRuntimeAction(state, input) {
3873
- const { surfaceId, actionName, rawContext } = input;
4035
+ const { surfaceId, actionName} = input;
3874
4036
  if (!surfaceId) {
3875
4037
  return { state, handled: actionName === "wizard.next" || actionName === "wizard.back" };
3876
4038
  }
@@ -3900,9 +4062,6 @@ function reduceA2uiRuntimeAction(state, input) {
3900
4062
  if (actionName === "wizard.next" || actionName === "wizard.back") {
3901
4063
  return { state, handled: true };
3902
4064
  }
3903
- if (!shouldOptimisticallyDismissSurface(actionName, rawContext)) {
3904
- return { state, handled: false };
3905
- }
3906
4065
  if (state.optimisticallyDismissedSurfaceIds.includes(surfaceId)) {
3907
4066
  return { state, handled: false };
3908
4067
  }
@@ -3967,12 +4126,20 @@ function useA2uiController(params) {
3967
4126
  applyA2uiRuntimeEffects(result.effects);
3968
4127
  setRuntimeState(result.state);
3969
4128
  }, [conversationMessages, conversationId]);
3970
- const view = useMemo(() => selectA2uiRuntimeView(runtimeState, dismissedSurfaceIds), [runtimeState, dismissedSurfaceIds]);
4129
+ const permanentDismissedSurfaceIds = useMemo(
4130
+ () => extractDismissedSurfaceIdsFromMessages(conversationMessages || []),
4131
+ [conversationMessages]
4132
+ );
4133
+ const mergedDismissedSurfaceIds = useMemo(
4134
+ () => Array.from(/* @__PURE__ */ new Set([...dismissedSurfaceIds || [], ...permanentDismissedSurfaceIds])),
4135
+ [dismissedSurfaceIds, permanentDismissedSurfaceIds]
4136
+ );
4137
+ const view = useMemo(() => selectA2uiRuntimeView(runtimeState, mergedDismissedSurfaceIds), [runtimeState, mergedDismissedSurfaceIds]);
3971
4138
  const handleRuntimeAction = useCallback((payload) => {
3972
4139
  const surfaceId = String(payload?.surfaceId || payload?.cardId || "");
3973
4140
  const name = String(payload?.name || payload?.event?.name || "").trim();
3974
4141
  const rawContext = payload?.context || payload?.event?.context || {};
3975
- const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name, rawContext });
4142
+ const runtimeActionResult = reduceA2uiRuntimeAction(runtimeRef.current, { surfaceId, actionName: name});
3976
4143
  if (runtimeActionResult.state !== runtimeRef.current) {
3977
4144
  runtimeRef.current = runtimeActionResult.state;
3978
4145
  setRuntimeState(runtimeActionResult.state);
@@ -3999,26 +4166,26 @@ var A2uiRuntimeContext = React10__default.createContext({
3999
4166
  function useA2uiRuntimeView() {
4000
4167
  return React10__default.useContext(A2uiRuntimeContext);
4001
4168
  }
4002
- function A2uiMessageCards({ messageIndex }) {
4169
+ function A2uiMessageCards({ messageIndex, message: message2 }) {
4003
4170
  const { surfaceIdsByMessageIndex } = useA2uiRuntimeView();
4004
- const surfaceIds = surfaceIdsByMessageIndex[messageIndex] || [];
4171
+ const allSurfaceIds = surfaceIdsByMessageIndex[messageIndex] || [];
4172
+ const inlineSurfaceIds = message2 ? extractInlineSurfaceIdsFromMessage(message2) : /* @__PURE__ */ new Set();
4173
+ const surfaceIds = allSurfaceIds.filter((id) => !inlineSurfaceIds.has(id));
4005
4174
  if (!surfaceIds.length) return null;
4006
4175
  return /* @__PURE__ */ jsx("div", { children: surfaceIds.map((surfaceId) => /* @__PURE__ */ jsx(XCard.Card, { id: surfaceId }, surfaceId)) });
4007
4176
  }
4008
4177
 
4009
4178
  // src/components/CustomComponents/A2uiRuntime/renderer/protocol.ts
4010
- function isSubmitLikeActionName2(name) {
4179
+ function isSubmitLikeActionName(name) {
4011
4180
  const normalized = String(name || "").trim();
4012
4181
  return normalized === "submit" || normalized === "confirm" || normalized.startsWith("submit_") || normalized.endsWith(".confirm");
4013
4182
  }
4014
- function isCancelLikeActionName2(name) {
4183
+ function isCancelLikeActionName(name) {
4015
4184
  const normalized = String(name || "").trim();
4016
4185
  return normalized === "cancel" || normalized === "qf.cancel" || normalized.endsWith(".cancel");
4017
4186
  }
4018
4187
  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;
4188
+ return true;
4022
4189
  }
4023
4190
  function normalizeA2uiActionPayload(payload) {
4024
4191
  return {
@@ -4052,7 +4219,7 @@ function isQuestionActionPayload(payload) {
4052
4219
  const mode = payload.context?.form_mode;
4053
4220
  if (payload.name === "qf.submit" || payload.name === "qf.cancel") return true;
4054
4221
  if (payload.name.startsWith("qf.")) return true;
4055
- return typeof mode === "string" && mode.toLowerCase() === "ephemeral" ? isSubmitLikeActionName2(payload.name) || isCancelLikeActionName2(payload.name) : false;
4222
+ return typeof mode === "string" && mode.toLowerCase() === "ephemeral" ? isSubmitLikeActionName(payload.name) || isCancelLikeActionName(payload.name) : false;
4056
4223
  }
4057
4224
  function formatActionValue(value, displayOverride) {
4058
4225
  if (typeof displayOverride === "string" && displayOverride.trim()) return displayOverride.trim();
@@ -4062,7 +4229,7 @@ function formatActionValue(value, displayOverride) {
4062
4229
  return String(value);
4063
4230
  }
4064
4231
  function buildQuestionSummary(payload) {
4065
- if (isCancelLikeActionName2(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
4232
+ if (isCancelLikeActionName(payload.name)) return "Question: \u5DF2\u53D6\u6D88";
4066
4233
  const values = payload.context.values && typeof payload.context.values === "object" && !Array.isArray(payload.context.values) ? payload.context.values : payload.context;
4067
4234
  const labels = payload.context.labels && typeof payload.context.labels === "object" && !Array.isArray(payload.context.labels) ? payload.context.labels : {};
4068
4235
  const valueLabels = payload.context.valueLabels && typeof payload.context.valueLabels === "object" && !Array.isArray(payload.context.valueLabels) ? payload.context.valueLabels : {};
@@ -4084,10 +4251,22 @@ function formatA2uiActionDisplayText(payload) {
4084
4251
  back_to_params: "\u5DF2\u8FD4\u56DE\u4FEE\u6539\u53C2\u6570",
4085
4252
  confirm: "\u5DF2\u786E\u8BA4\u521B\u5EFA"
4086
4253
  };
4087
- const actionLabel = actionLabels[payload.name] || `\u5DF2\u63D0\u4EA4\u52A8\u4F5C (${payload.name})`;
4254
+ let actionLabel = actionLabels[payload.name];
4255
+ if (!actionLabel) {
4256
+ if (payload.name.startsWith("confirm_")) {
4257
+ actionLabel = "\u5DF2\u9009\u62E9";
4258
+ } else if (payload.name.startsWith("submit_")) {
4259
+ actionLabel = "\u5DF2\u63D0\u4EA4";
4260
+ } else {
4261
+ actionLabel = `\u5DF2\u63D0\u4EA4\u52A8\u4F5C (${payload.name})`;
4262
+ }
4263
+ }
4264
+ const isConfirmLike = payload.name.startsWith("confirm_");
4088
4265
  const details = Object.entries(values).filter(([, value]) => value !== null && value !== void 0 && value !== "").map(([key, value]) => {
4266
+ const formatted = formatActionValue(value, valueLabels[key]);
4267
+ if (isConfirmLike) return formatted;
4089
4268
  const label = typeof labels[key] === "string" && String(labels[key]).trim() ? String(labels[key]).trim() : key;
4090
- return `${label}: ${formatActionValue(value, valueLabels[key])}`;
4269
+ return `${label}: ${formatted}`;
4091
4270
  });
4092
4271
  return details.length ? `${actionLabel}\uFF1A${details.join("\uFF1B ")}` : actionLabel;
4093
4272
  }
@@ -4185,66 +4364,46 @@ function readContextModelPath(context) {
4185
4364
  const path = context?.model && typeof context.model === "object" ? context.model.path : "";
4186
4365
  return typeof path === "string" ? path.trim() : "";
4187
4366
  }
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);
4367
+ function buildLatestCommandIndexBySurface(messages) {
4368
+ const indexBySurface = {};
4369
+ let commandIndex = -1;
4370
+ for (const message2 of messages) {
4197
4371
  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] });
4372
+ for (const item of items) {
4373
+ if (item?.type === "a2uiCommand" && item.command) {
4374
+ commandIndex += 1;
4375
+ const surfaceId = extractSurfaceId3(item.command);
4376
+ if (surfaceId) indexBySurface[surfaceId] = commandIndex;
4377
+ continue;
4378
+ }
4379
+ if (item?.type === "text") {
4380
+ const text = item.messageContent || item.text || "";
4381
+ if (typeof text !== "string" || !text.includes("<A2UI")) continue;
4382
+ const tags = parseA2uiTagsFromText(text);
4383
+ for (const tag of tags) {
4384
+ for (const cmd of tag.commands) {
4385
+ commandIndex += 1;
4386
+ const surfaceId = extractSurfaceId3(cmd);
4387
+ if (surfaceId) indexBySurface[surfaceId] = commandIndex;
4388
+ }
4389
+ }
4390
+ }
4205
4391
  }
4206
- nextCursors.push({ messageId, contentLength: items.length });
4207
4392
  }
4208
- return { shouldReplayAll: false, nextCursors, pendingItems };
4393
+ return indexBySurface;
4209
4394
  }
4210
4395
  function A2uiRuntimeProvider({ messages, children }) {
4211
4396
  const chatStore = useChatStore();
4212
4397
  const conversationState = useSnapshot(chatStore.conversation);
4213
4398
  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
4399
  const [latestCommandIndexBySurface, setLatestCommandIndexBySurface] = React10__default.useState({});
4218
4400
  const [dismissedAtBySurface, setDismissedAtBySurface] = React10__default.useState({});
4219
4401
  React10__default.useEffect(() => {
4220
- processedMessageCursorsRef.current = [];
4221
- latestCommandIndexBySurfaceRef.current = {};
4222
- commandIndexRef.current = -1;
4223
4402
  setLatestCommandIndexBySurface({});
4224
4403
  setDismissedAtBySurface({});
4225
4404
  }, [conversationId]);
4226
4405
  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);
4406
+ setLatestCommandIndexBySurface(buildLatestCommandIndexBySurface(messages));
4248
4407
  }, [messages]);
4249
4408
  const dismissedSurfaceIds = React10__default.useMemo(() => {
4250
4409
  return Object.entries(dismissedAtBySurface).filter(([surfaceId, dismissedAt]) => (latestCommandIndexBySurface[surfaceId] ?? -1) <= dismissedAt).map(([surfaceId]) => surfaceId);
@@ -4373,14 +4532,37 @@ function QuestionSummary({ content }) {
4373
4532
  ] });
4374
4533
  }
4375
4534
  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 });
4535
+ ({
4536
+ item,
4537
+ role,
4538
+ customComponents,
4539
+ message: message2,
4540
+ messageIndex = -1
4541
+ }) => {
4542
+ const { surfaceIdsByMessageIndex } = useA2uiRuntimeView();
4543
+ const rawContent = toA2uiDisplayText(role, item?.messageContent);
4544
+ const segments = splitA2uiTextSegments(rawContent);
4545
+ const visibleSurfaceIds = messageIndex >= 0 ? new Set(surfaceIdsByMessageIndex[messageIndex] || []) : null;
4546
+ const firstSeg = segments[0];
4547
+ const isPureText = segments.length === 0 || segments.length === 1 && firstSeg.type === "text";
4548
+ if (isPureText) {
4549
+ const content = firstSeg && firstSeg.type === "text" ? firstSeg.content : "";
4550
+ if (typeof content === "string" && content.startsWith("Question:")) {
4551
+ return /* @__PURE__ */ jsx(QuestionSummary, { content });
4552
+ }
4553
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4554
+ !!item.reasoningContent && /* @__PURE__ */ jsx(Think, { title: "\u6DF1\u5EA6\u601D\u8003", children: item.reasoningContent }),
4555
+ !!content && /* @__PURE__ */ jsx(XMarkdown_default, { message: message2, components: customComponents, content })
4556
+ ] });
4380
4557
  }
4381
4558
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4382
4559
  !!item.reasoningContent && /* @__PURE__ */ jsx(Think, { title: "\u6DF1\u5EA6\u601D\u8003", children: item.reasoningContent }),
4383
- !!content && /* @__PURE__ */ jsx(XMarkdown_default, { message: message2, components: customComponents, content })
4560
+ segments.map((seg, i) => {
4561
+ if (seg.type === "text") {
4562
+ return seg.content.trim() ? /* @__PURE__ */ jsx(XMarkdown_default, { message: message2, components: customComponents, content: seg.content }, `text-${i}`) : null;
4563
+ }
4564
+ return seg.surfaceIds.filter((sid) => !visibleSurfaceIds || visibleSurfaceIds.has(sid)).map((sid) => /* @__PURE__ */ jsx(XCard.Card, { id: sid }, `a2ui-${i}-${sid}`));
4565
+ })
4384
4566
  ] });
4385
4567
  }
4386
4568
  );
@@ -4608,6 +4790,12 @@ var MessageRender_default = React10__default.memo(({ role, message: message2, me
4608
4790
  if (item.type === "plan") {
4609
4791
  return !shouldHideA2uiPlan(item);
4610
4792
  }
4793
+ if (item.type === "text") {
4794
+ const rawText = item.messageContent || item.text || "";
4795
+ const visibleText = stripA2uiTags(rawText);
4796
+ const hasA2uiTag2 = typeof rawText === "string" && rawText.includes("<A2UI");
4797
+ return !!visibleText.trim() || !!item.reasoningContent || hasA2uiTag2;
4798
+ }
4611
4799
  return true;
4612
4800
  });
4613
4801
  }, [loading, message2.content]);
@@ -4636,7 +4824,7 @@ var MessageRender_default = React10__default.memo(({ role, message: message2, me
4636
4824
  content: /* @__PURE__ */ jsxs(Fragment, { children: [
4637
4825
  item.type === "runStarted" && /* @__PURE__ */ jsx(RunStartedNode, { loading }, `flow-start-${index}`),
4638
4826
  (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}`),
4827
+ item.type === "text" && /* @__PURE__ */ jsx(TextNode2, { item, role: message2.role, customComponents, message: message2, messageIndex }, `message-${index}`),
4640
4828
  item.type === "stepError" && (item.errorMessage ? /* @__PURE__ */ jsx(XMarkdown_default, { message: message2, components: customComponents, content: item.errorMessage }) : null),
4641
4829
  item.type === "files" && /* @__PURE__ */ jsx(FilesNode, { item }, `files-${index}`),
4642
4830
  item.type === "plan" && /* @__PURE__ */ jsx(A2uiPlanNode, { item }, `plan-${index}`)
@@ -4646,7 +4834,7 @@ var MessageRender_default = React10__default.memo(({ role, message: message2, me
4646
4834
  );
4647
4835
  }),
4648
4836
  quoteMsg && /* @__PURE__ */ jsx(QuoteMsgNode, { quoteMsg, role }),
4649
- messageIndex >= 0 ? /* @__PURE__ */ jsx(A2uiMessageCards, { messageIndex }) : null
4837
+ messageIndex >= 0 ? /* @__PURE__ */ jsx(A2uiMessageCards, { messageIndex, message: message2 }) : null
4650
4838
  ] });
4651
4839
  });
4652
4840
  var WelcomeItem_default = ({ icon = true, title = true, description = true, prompts = true }) => {