@runtypelabs/persona 3.15.1 → 3.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/animations/glyph-cycle.cjs +279 -0
  2. package/dist/animations/glyph-cycle.d.cts +5 -0
  3. package/dist/animations/glyph-cycle.d.ts +5 -0
  4. package/dist/animations/glyph-cycle.js +252 -0
  5. package/dist/animations/types-HPZY7oAI.d.cts +282 -0
  6. package/dist/animations/types-HPZY7oAI.d.ts +282 -0
  7. package/dist/animations/wipe.cjs +107 -0
  8. package/dist/animations/wipe.d.cts +5 -0
  9. package/dist/animations/wipe.d.ts +5 -0
  10. package/dist/animations/wipe.js +80 -0
  11. package/dist/index.cjs +49 -48
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +216 -1
  14. package/dist/index.d.ts +216 -1
  15. package/dist/index.global.js +137 -82
  16. package/dist/index.global.js.map +1 -1
  17. package/dist/index.js +49 -48
  18. package/dist/index.js.map +1 -1
  19. package/dist/testing.cjs +85 -0
  20. package/dist/testing.d.cts +39 -0
  21. package/dist/testing.d.ts +39 -0
  22. package/dist/testing.js +56 -0
  23. package/dist/theme-editor.cjs +847 -127
  24. package/dist/theme-editor.d.cts +225 -2
  25. package/dist/theme-editor.d.ts +225 -2
  26. package/dist/theme-editor.js +845 -127
  27. package/dist/widget.css +133 -0
  28. package/package.json +20 -3
  29. package/src/animations/glyph-cycle.ts +332 -0
  30. package/src/animations/wipe.ts +66 -0
  31. package/src/client.test.ts +141 -0
  32. package/src/client.ts +197 -2
  33. package/src/components/composer-builder.ts +61 -10
  34. package/src/components/header-builder.ts +18 -7
  35. package/src/components/header-layouts.ts +3 -1
  36. package/src/components/message-bubble.test.ts +181 -2
  37. package/src/components/message-bubble.ts +209 -14
  38. package/src/components/panel.ts +4 -1
  39. package/src/defaults.ts +22 -0
  40. package/src/index-global.ts +31 -0
  41. package/src/index.ts +18 -0
  42. package/src/session.test.ts +93 -1
  43. package/src/session.ts +5 -0
  44. package/src/styles/widget.css +133 -0
  45. package/src/testing/index.ts +11 -0
  46. package/src/testing/mock-stream.test.ts +80 -0
  47. package/src/testing/mock-stream.ts +94 -0
  48. package/src/testing.ts +2 -0
  49. package/src/theme-editor/index.ts +4 -0
  50. package/src/theme-editor/preview-utils.test.ts +60 -0
  51. package/src/theme-editor/preview-utils.ts +129 -0
  52. package/src/theme-editor/sections.test.ts +19 -0
  53. package/src/theme-editor/sections.ts +84 -1
  54. package/src/types.ts +221 -0
  55. package/src/ui.stop-button.test.ts +165 -0
  56. package/src/ui.ts +79 -8
  57. package/src/utils/message-fingerprint.ts +2 -0
  58. package/src/utils/morph.ts +7 -0
  59. package/src/utils/stream-animation.test.ts +417 -0
  60. package/src/utils/stream-animation.ts +449 -0
@@ -80,6 +80,7 @@ __export(theme_editor_exports, {
80
80
  buildPreviewConfigWithMessages: () => buildPreviewConfigWithMessages,
81
81
  buildShellCss: () => buildShellCss,
82
82
  buildSrcdoc: () => buildSrcdoc,
83
+ buildTranscriptStreamFrames: () => buildTranscriptStreamFrames,
83
84
  convertFromPx: () => convertFromPx,
84
85
  convertToPx: () => convertToPx,
85
86
  createPreviewMessages: () => createPreviewMessages,
@@ -99,6 +100,7 @@ __export(theme_editor_exports, {
99
100
  normalizeColorValue: () => normalizeColorValue,
100
101
  paletteColorPath: () => paletteColorPath,
101
102
  parseCssValue: () => parseCssValue,
103
+ presetStreamsText: () => presetStreamsText,
102
104
  resolveRoleAssignment: () => resolveRoleAssignment,
103
105
  resolveThemeColorPath: () => resolveThemeColorPath,
104
106
  scopeSection: () => scopeSection,
@@ -154,6 +156,12 @@ var DEFAULT_WIDGET_CONFIG = {
154
156
  agentIconSize: "40px",
155
157
  headerIconSize: "40px",
156
158
  closeButtonSize: "32px",
159
+ // Zero out browser-default <button> padding so the icon gets the full
160
+ // 32x32 content box, matching clearChat.paddingX/Y below. Without this,
161
+ // UA stylesheets add ~1-2px vertical and ~6px horizontal padding that
162
+ // eats into the border-box width and shrinks the rendered icon.
163
+ closeButtonPaddingX: "0px",
164
+ closeButtonPaddingY: "0px",
157
165
  callToActionIconName: "arrow-up-right",
158
166
  callToActionIconText: "",
159
167
  callToActionIconSize: "32px",
@@ -241,6 +249,12 @@ var DEFAULT_WIDGET_CONFIG = {
241
249
  previewMaxLines: 3,
242
250
  expandable: true,
243
251
  loadingAnimation: "none"
252
+ },
253
+ streamAnimation: {
254
+ type: "none",
255
+ placeholder: "none",
256
+ speed: 120,
257
+ duration: 1800
244
258
  }
245
259
  },
246
260
  suggestionChips: [
@@ -343,11 +357,13 @@ function mergeWithDefaults(config) {
343
357
  ...config.voiceRecognition
344
358
  },
345
359
  features: (() => {
346
- var _a2, _b2, _c2, _d2;
360
+ var _a2, _b2, _c2, _d2, _e2, _f2;
347
361
  const da = (_a2 = DEFAULT_WIDGET_CONFIG.features) == null ? void 0 : _a2.artifacts;
348
362
  const ca = (_b2 = config.features) == null ? void 0 : _b2.artifacts;
349
363
  const dsb = (_c2 = DEFAULT_WIDGET_CONFIG.features) == null ? void 0 : _c2.scrollToBottom;
350
364
  const csb = (_d2 = config.features) == null ? void 0 : _d2.scrollToBottom;
365
+ const dsa = (_e2 = DEFAULT_WIDGET_CONFIG.features) == null ? void 0 : _e2.streamAnimation;
366
+ const csa = (_f2 = config.features) == null ? void 0 : _f2.streamAnimation;
351
367
  const mergedArtifacts = da === void 0 && ca === void 0 ? void 0 : {
352
368
  ...da,
353
369
  ...ca,
@@ -360,11 +376,16 @@ function mergeWithDefaults(config) {
360
376
  ...dsb,
361
377
  ...csb
362
378
  };
379
+ const mergedStreamAnimation = dsa === void 0 && csa === void 0 ? void 0 : {
380
+ ...dsa,
381
+ ...csa
382
+ };
363
383
  return {
364
384
  ...DEFAULT_WIDGET_CONFIG.features,
365
385
  ...config.features,
366
386
  ...mergedScrollToBottom !== void 0 ? { scrollToBottom: mergedScrollToBottom } : {},
367
- ...mergedArtifacts !== void 0 ? { artifacts: mergedArtifacts } : {}
387
+ ...mergedArtifacts !== void 0 ? { artifacts: mergedArtifacts } : {},
388
+ ...mergedStreamAnimation !== void 0 ? { streamAnimation: mergedStreamAnimation } : {}
368
389
  };
369
390
  })(),
370
391
  suggestionChips: (_e = config.suggestionChips) != null ? _e : DEFAULT_WIDGET_CONFIG.suggestionChips,
@@ -2667,6 +2688,91 @@ var featuresSectionDef = {
2667
2688
  { id: "feat-scroll-bottom-label", label: "Scroll To Bottom Label", description: "Leave empty for icon-only mode", type: "text", path: "features.scrollToBottom.label", defaultValue: "" }
2668
2689
  ]
2669
2690
  };
2691
+ var streamAnimationSectionDef = {
2692
+ id: "stream-animation",
2693
+ title: "Stream Animation",
2694
+ description: "Control how assistant text appears while streaming.",
2695
+ collapsed: true,
2696
+ fields: [
2697
+ {
2698
+ id: "stream-anim-type",
2699
+ label: "Animation",
2700
+ description: "Reveal effect applied to each assistant reply as it streams.",
2701
+ type: "select",
2702
+ path: "features.streamAnimation.type",
2703
+ defaultValue: "none",
2704
+ options: [
2705
+ { value: "none", label: "None" },
2706
+ { value: "typewriter", label: "Typewriter" },
2707
+ { value: "word-fade", label: "Word fade" },
2708
+ { value: "letter-rise", label: "Letter rise" },
2709
+ { value: "glyph-cycle", label: "Glyph cycle" },
2710
+ { value: "wipe", label: "Wipe" },
2711
+ { value: "pop-bubble", label: "Pop bubble" }
2712
+ ]
2713
+ },
2714
+ {
2715
+ id: "stream-anim-placeholder",
2716
+ label: "Pre-first-token Placeholder",
2717
+ description: "What to show before the first token arrives.",
2718
+ type: "select",
2719
+ path: "features.streamAnimation.placeholder",
2720
+ defaultValue: "none",
2721
+ options: [
2722
+ { value: "none", label: "Typing indicator (default)" },
2723
+ { value: "skeleton", label: "Skeleton shimmer" }
2724
+ ]
2725
+ },
2726
+ {
2727
+ id: "stream-anim-buffer",
2728
+ label: "Content Buffering",
2729
+ description: "Trim in-progress units so only complete words/lines reveal.",
2730
+ type: "select",
2731
+ path: "features.streamAnimation.buffer",
2732
+ defaultValue: "none",
2733
+ options: [
2734
+ { value: "none", label: "None \u2014 stream every character" },
2735
+ { value: "word", label: "Word \u2014 hold until whitespace" },
2736
+ { value: "line", label: "Line \u2014 hold until newline" }
2737
+ ]
2738
+ },
2739
+ {
2740
+ id: "stream-anim-speed",
2741
+ label: "Per-unit Duration (ms)",
2742
+ description: "Animation length for each character or word.",
2743
+ type: "select",
2744
+ path: "features.streamAnimation.speed",
2745
+ defaultValue: 120,
2746
+ options: [
2747
+ { value: "40", label: "40ms \u2014 snappy" },
2748
+ { value: "80", label: "80ms" },
2749
+ { value: "120", label: "120ms (default)" },
2750
+ { value: "200", label: "200ms" },
2751
+ { value: "320", label: "320ms" },
2752
+ { value: "480", label: "480ms \u2014 slow" }
2753
+ ],
2754
+ formatValue: (v) => String(v != null ? v : 120),
2755
+ parseValue: (v) => Number(v)
2756
+ },
2757
+ {
2758
+ id: "stream-anim-duration",
2759
+ label: "Container Duration (ms)",
2760
+ description: "Length of container-level effects (pop-bubble, custom plugins).",
2761
+ type: "select",
2762
+ path: "features.streamAnimation.duration",
2763
+ defaultValue: 1800,
2764
+ options: [
2765
+ { value: "600", label: "600ms" },
2766
+ { value: "1200", label: "1200ms" },
2767
+ { value: "1800", label: "1800ms (default)" },
2768
+ { value: "2400", label: "2400ms" },
2769
+ { value: "3600", label: "3600ms \u2014 slow" }
2770
+ ],
2771
+ formatValue: (v) => String(v != null ? v : 1800),
2772
+ parseValue: (v) => Number(v)
2773
+ }
2774
+ ]
2775
+ };
2670
2776
  var attachmentsSectionDef = {
2671
2777
  id: "attachments-config",
2672
2778
  title: "Attachments",
@@ -2750,7 +2856,7 @@ var CONFIGURE_SUB_GROUPS = [
2750
2856
  { label: "Content", sections: [copySectionDef, suggestionsSectionDef] },
2751
2857
  { label: "Layout", sections: [generalLayoutSectionDef, headerLayoutSectionDef, messagesLayoutSectionDef, messageActionsSectionDef] },
2752
2858
  { label: "Widget", sections: [launcherBasicsSectionDef, launcherAdvancedSectionDef, sendButtonSectionDef, closeButtonSectionDef, clearChatSectionDef, statusIndicatorSectionDef] },
2753
- { label: "Features", sections: [featuresSectionDef, attachmentsSectionDef, artifactsSectionDef, artifactCustomizationSectionDef] },
2859
+ { label: "Features", sections: [featuresSectionDef, streamAnimationSectionDef, attachmentsSectionDef, artifactsSectionDef, artifactCustomizationSectionDef] },
2754
2860
  { label: "Developer", collapsedByDefault: true, sections: [apiIntegrationSectionDef, debugSectionDef, markdownSectionDef] }
2755
2861
  ];
2756
2862
  var CONFIGURE_SECTIONS = CONFIGURE_SUB_GROUPS.flatMap((g) => g.sections);
@@ -4456,6 +4562,8 @@ var AgentWidgetClient = class {
4456
4562
  let didSplitByPartId = false;
4457
4563
  const reasoningMessages = /* @__PURE__ */ new Map();
4458
4564
  const toolMessages = /* @__PURE__ */ new Map();
4565
+ const nestedStepMessages = /* @__PURE__ */ new Map();
4566
+ const nestedPartIdByStep = /* @__PURE__ */ new Map();
4459
4567
  const reasoningContext = {
4460
4568
  lastId: null,
4461
4569
  byStep: /* @__PURE__ */ new Map()
@@ -4464,6 +4572,31 @@ var AgentWidgetClient = class {
4464
4572
  lastId: null,
4465
4573
  byCall: /* @__PURE__ */ new Map()
4466
4574
  };
4575
+ const getNestedStepKey = (toolId, stepId, partId = "") => `${toolId}::${stepId}::${partId}`;
4576
+ const getNestedStepPrefix = (toolId, stepId) => `${toolId}::${stepId}::`;
4577
+ const ensureNestedStepMessage = (toolId, stepId, partId, executionId) => {
4578
+ const key = getNestedStepKey(toolId, stepId, partId);
4579
+ const existing = nestedStepMessages.get(key);
4580
+ if (existing) return existing;
4581
+ const idSuffix = partId ? `-${partId}` : "";
4582
+ const message = {
4583
+ id: `nested-${toolId}-${stepId}${idSuffix}`,
4584
+ role: "assistant",
4585
+ content: "",
4586
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
4587
+ streaming: true,
4588
+ sequence: nextSequence(),
4589
+ ...partId ? { partId } : {},
4590
+ agentMetadata: {
4591
+ executionId,
4592
+ parentToolId: toolId,
4593
+ parentStepId: stepId
4594
+ }
4595
+ };
4596
+ nestedStepMessages.set(key, message);
4597
+ emitMessage(message);
4598
+ return message;
4599
+ };
4467
4600
  const normalizeKey = (value) => {
4468
4601
  if (value === null || value === void 0) return null;
4469
4602
  try {
@@ -4773,7 +4906,7 @@ var AgentWidgetClient = class {
4773
4906
  const agentIterationMessages = /* @__PURE__ */ new Map();
4774
4907
  const iterationDisplay = (_a = this.config.iterationDisplay) != null ? _a : "separate";
4775
4908
  drainReadyQueue = () => {
4776
- var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab, _bb, _cb, _db, _eb, _fb, _gb, _hb, _ib, _jb, _kb;
4909
+ var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab, _bb, _cb, _db, _eb, _fb, _gb, _hb, _ib, _jb, _kb, _lb, _mb, _nb, _ob, _pb, _qb, _rb, _sb, _tb, _ub, _vb;
4777
4910
  for (let i = 0; i < seqReadyQueue.length; i++) {
4778
4911
  const payloadType = seqReadyQueue[i].payloadType;
4779
4912
  const payload = seqReadyQueue[i].payload;
@@ -4946,6 +5079,9 @@ var AgentWidgetClient = class {
4946
5079
  toolContext.byCall.delete(callKey);
4947
5080
  }
4948
5081
  } else if (payloadType === "text_start") {
5082
+ if ((_X = payload.toolContext) == null ? void 0 : _X.toolId) {
5083
+ continue;
5084
+ }
4949
5085
  const incomingPartId = payload.partId;
4950
5086
  if (incomingPartId !== void 0 && partIdState.current !== null && incomingPartId !== partIdState.current) {
4951
5087
  const prev = assistantMessage;
@@ -4961,6 +5097,9 @@ var AgentWidgetClient = class {
4961
5097
  partIdState.current = incomingPartId;
4962
5098
  }
4963
5099
  } else if (payloadType === "text_end") {
5100
+ if ((_Y = payload.toolContext) == null ? void 0 : _Y.toolId) {
5101
+ continue;
5102
+ }
4964
5103
  const prev = assistantMessage;
4965
5104
  if (prev) {
4966
5105
  prev.streaming = false;
@@ -4975,6 +5114,48 @@ var AgentWidgetClient = class {
4975
5114
  if (stepType === "tool" || executionType === "context") {
4976
5115
  continue;
4977
5116
  }
5117
+ const nestedToolCtx = payload.toolContext;
5118
+ if (nestedToolCtx == null ? void 0 : nestedToolCtx.toolId) {
5119
+ const nestedStepId = String(
5120
+ (__ = (_Z = payload.id) != null ? _Z : nestedToolCtx.stepId) != null ? __ : `step-${nextSequence()}`
5121
+ );
5122
+ const incomingPartId2 = payload.partId !== void 0 && payload.partId !== null ? String(payload.partId) : "";
5123
+ const stepScopeKey = `${nestedToolCtx.toolId}::${nestedStepId}`;
5124
+ const prevPartId = nestedPartIdByStep.get(stepScopeKey);
5125
+ if (incomingPartId2 !== "" && prevPartId !== void 0 && prevPartId !== "" && prevPartId !== incomingPartId2) {
5126
+ const prev = nestedStepMessages.get(
5127
+ getNestedStepKey(
5128
+ nestedToolCtx.toolId,
5129
+ nestedStepId,
5130
+ prevPartId
5131
+ )
5132
+ );
5133
+ if (prev && prev.streaming !== false) {
5134
+ prev.streaming = false;
5135
+ emitMessage(prev);
5136
+ }
5137
+ }
5138
+ if (incomingPartId2 !== "") {
5139
+ nestedPartIdByStep.set(stepScopeKey, incomingPartId2);
5140
+ }
5141
+ const nestedMsg = ensureNestedStepMessage(
5142
+ nestedToolCtx.toolId,
5143
+ nestedStepId,
5144
+ incomingPartId2,
5145
+ nestedToolCtx.executionId
5146
+ );
5147
+ const nestedChunk = (_ca = (_ba = (_aa = (_$ = payload.text) != null ? _$ : payload.delta) != null ? _aa : payload.content) != null ? _ba : payload.chunk) != null ? _ca : "";
5148
+ if (nestedChunk) {
5149
+ nestedMsg.content += String(nestedChunk);
5150
+ nestedMsg.streaming = true;
5151
+ emitMessage(nestedMsg);
5152
+ }
5153
+ if (payload.isComplete) {
5154
+ nestedMsg.streaming = false;
5155
+ emitMessage(nestedMsg);
5156
+ }
5157
+ continue;
5158
+ }
4978
5159
  const incomingPartId = payload.partId;
4979
5160
  if (incomingPartId !== void 0 && partIdState.current !== null && incomingPartId !== partIdState.current) {
4980
5161
  const prev = assistantMessage;
@@ -4989,18 +5170,18 @@ var AgentWidgetClient = class {
4989
5170
  if (incomingPartId !== void 0) {
4990
5171
  partIdState.current = incomingPartId;
4991
5172
  }
4992
- const assistant = incomingPartId !== void 0 ? (_X = assistantMessagesByPartId.get(incomingPartId)) != null ? _X : ensureAssistantMessage() : ensureAssistantMessage();
5173
+ const assistant = incomingPartId !== void 0 ? (_da = assistantMessagesByPartId.get(incomingPartId)) != null ? _da : ensureAssistantMessage() : ensureAssistantMessage();
4993
5174
  if (incomingPartId !== void 0) {
4994
5175
  if (!assistant.partId) {
4995
5176
  assistant.partId = incomingPartId;
4996
5177
  }
4997
5178
  assistantMessagesByPartId.set(incomingPartId, assistant);
4998
5179
  }
4999
- const chunk = (_$ = (__ = (_Z = (_Y = payload.text) != null ? _Y : payload.delta) != null ? _Z : payload.content) != null ? __ : payload.chunk) != null ? _$ : "";
5180
+ const chunk = (_ha = (_ga = (_fa = (_ea = payload.text) != null ? _ea : payload.delta) != null ? _fa : payload.content) != null ? _ga : payload.chunk) != null ? _ha : "";
5000
5181
  if (chunk) {
5001
5182
  const chunkSeq = typeof payload.seq === "number" ? payload.seq : void 0;
5002
5183
  const chunkBufferKey = incomingPartId != null ? incomingPartId : assistant.id;
5003
- const accumulatedRaw = chunkSeq !== void 0 ? insertOrderedChunk(chunkBufferKey, chunkSeq, String(chunk)) : ((_aa = rawContentBuffers.get(assistant.id)) != null ? _aa : "") + chunk;
5184
+ const accumulatedRaw = chunkSeq !== void 0 ? insertOrderedChunk(chunkBufferKey, chunkSeq, String(chunk)) : ((_ia = rawContentBuffers.get(assistant.id)) != null ? _ia : "") + chunk;
5004
5185
  assistant.rawContent = accumulatedRaw;
5005
5186
  if (!streamParsers.has(assistant.id)) {
5006
5187
  streamParsers.set(assistant.id, this.createStreamParser());
@@ -5046,7 +5227,7 @@ var AgentWidgetClient = class {
5046
5227
  emitMessage(assistant);
5047
5228
  });
5048
5229
  } else {
5049
- const text = typeof parsedResult === "string" ? parsedResult : (_ba = parsedResult == null ? void 0 : parsedResult.text) != null ? _ba : null;
5230
+ const text = typeof parsedResult === "string" ? parsedResult : (_ja = parsedResult == null ? void 0 : parsedResult.text) != null ? _ja : null;
5050
5231
  if (text !== null && text.trim() !== "") {
5051
5232
  assistant.content = text;
5052
5233
  emitMessage(assistant);
@@ -5060,7 +5241,7 @@ var AgentWidgetClient = class {
5060
5241
  }
5061
5242
  }
5062
5243
  if (payload.isComplete) {
5063
- const finalContent = (_da = (_ca = payload.result) == null ? void 0 : _ca.response) != null ? _da : assistant.content;
5244
+ const finalContent = (_la = (_ka = payload.result) == null ? void 0 : _ka.response) != null ? _la : assistant.content;
5064
5245
  if (finalContent) {
5065
5246
  const rawBuffer = rawContentBuffers.get(assistant.id);
5066
5247
  const contentToProcess = rawBuffer != null ? rawBuffer : ensureStringContent(finalContent);
@@ -5092,7 +5273,7 @@ var AgentWidgetClient = class {
5092
5273
  }
5093
5274
  });
5094
5275
  } else {
5095
- extractedText = typeof parsedResult === "string" ? parsedResult : (_ea = parsedResult == null ? void 0 : parsedResult.text) != null ? _ea : null;
5276
+ extractedText = typeof parsedResult === "string" ? parsedResult : (_ma = parsedResult == null ? void 0 : parsedResult.text) != null ? _ma : null;
5096
5277
  }
5097
5278
  }
5098
5279
  }
@@ -5104,7 +5285,7 @@ var AgentWidgetClient = class {
5104
5285
  }
5105
5286
  const parserToClose = streamParsers.get(assistant.id);
5106
5287
  if (parserToClose) {
5107
- const closeResult = (_fa = parserToClose.close) == null ? void 0 : _fa.call(parserToClose);
5288
+ const closeResult = (_na = parserToClose.close) == null ? void 0 : _na.call(parserToClose);
5108
5289
  if (closeResult instanceof Promise) {
5109
5290
  closeResult.catch(() => {
5110
5291
  });
@@ -5123,9 +5304,33 @@ var AgentWidgetClient = class {
5123
5304
  if (stepType === "tool" || executionType === "context") {
5124
5305
  continue;
5125
5306
  }
5307
+ const nestedCompleteCtx = payload.toolContext;
5308
+ if (nestedCompleteCtx == null ? void 0 : nestedCompleteCtx.toolId) {
5309
+ const nestedStepId = String(
5310
+ (_pa = (_oa = payload.id) != null ? _oa : nestedCompleteCtx.stepId) != null ? _pa : ""
5311
+ );
5312
+ if (nestedStepId) {
5313
+ const prefix = getNestedStepPrefix(
5314
+ nestedCompleteCtx.toolId,
5315
+ nestedStepId
5316
+ );
5317
+ for (const [key, msg] of nestedStepMessages) {
5318
+ if (key.startsWith(prefix) && msg.streaming !== false) {
5319
+ msg.streaming = false;
5320
+ emitMessage(msg);
5321
+ }
5322
+ }
5323
+ nestedPartIdByStep.delete(
5324
+ `${nestedCompleteCtx.toolId}::${nestedStepId}`
5325
+ );
5326
+ }
5327
+ continue;
5328
+ }
5329
+ const stepStopReason = payload.stopReason;
5126
5330
  if (didSplitByPartId) {
5127
5331
  if (assistantMessage !== null) {
5128
5332
  const msg = assistantMessage;
5333
+ if (stepStopReason) msg.stopReason = stepStopReason;
5129
5334
  streamParsers.delete(msg.id);
5130
5335
  rawContentBuffers.delete(msg.id);
5131
5336
  if (msg.streaming !== false) {
@@ -5133,9 +5338,10 @@ var AgentWidgetClient = class {
5133
5338
  emitMessage(msg);
5134
5339
  }
5135
5340
  }
5136
- const splitFinalContent = (_ga = payload.result) == null ? void 0 : _ga.response;
5341
+ const splitFinalContent = (_qa = payload.result) == null ? void 0 : _qa.response;
5137
5342
  const sealedForReconcile = lastSealedTextSegment;
5138
5343
  if (sealedForReconcile) {
5344
+ if (stepStopReason) sealedForReconcile.stopReason = stepStopReason;
5139
5345
  if (splitFinalContent !== void 0 && splitFinalContent !== null) {
5140
5346
  reconcileSealedAssistantWithFinalResponse(sealedForReconcile, splitFinalContent);
5141
5347
  } else {
@@ -5146,8 +5352,9 @@ var AgentWidgetClient = class {
5146
5352
  lastSealedTextSegment = null;
5147
5353
  continue;
5148
5354
  }
5149
- const finalContent = (_ha = payload.result) == null ? void 0 : _ha.response;
5355
+ const finalContent = (_ra = payload.result) == null ? void 0 : _ra.response;
5150
5356
  const assistant = ensureAssistantMessage();
5357
+ if (stepStopReason) assistant.stopReason = stepStopReason;
5151
5358
  if (finalContent !== void 0 && finalContent !== null) {
5152
5359
  const parser = streamParsers.get(assistant.id);
5153
5360
  let hasExtractedText = false;
@@ -5198,7 +5405,7 @@ var AgentWidgetClient = class {
5198
5405
  }
5199
5406
  });
5200
5407
  } else {
5201
- const text = typeof parsedResult === "string" ? parsedResult : (_ia = parsedResult == null ? void 0 : parsedResult.text) != null ? _ia : null;
5408
+ const text = typeof parsedResult === "string" ? parsedResult : (_sa = parsedResult == null ? void 0 : parsedResult.text) != null ? _sa : null;
5202
5409
  if (text !== null && text.trim() !== "") {
5203
5410
  assistant.content = text;
5204
5411
  hasExtractedText = true;
@@ -5222,7 +5429,7 @@ var AgentWidgetClient = class {
5222
5429
  assistant.content = ensureStringContent(finalContent);
5223
5430
  }
5224
5431
  if (parser) {
5225
- const closeResult = (_ja = parser.close) == null ? void 0 : _ja.call(parser);
5432
+ const closeResult = (_ta = parser.close) == null ? void 0 : _ta.call(parser);
5226
5433
  if (closeResult instanceof Promise) {
5227
5434
  closeResult.catch(() => {
5228
5435
  });
@@ -5240,7 +5447,7 @@ var AgentWidgetClient = class {
5240
5447
  emitMessage(assistant);
5241
5448
  }
5242
5449
  } else if (payloadType === "flow_complete") {
5243
- const finalContent = (_ka = payload.result) == null ? void 0 : _ka.response;
5450
+ const finalContent = (_ua = payload.result) == null ? void 0 : _ua.response;
5244
5451
  if (didSplitByPartId) {
5245
5452
  if (assistantMessage !== null) {
5246
5453
  const msg = assistantMessage;
@@ -5307,11 +5514,11 @@ var AgentWidgetClient = class {
5307
5514
  } else if (payloadType === "agent_start") {
5308
5515
  agentExecution = {
5309
5516
  executionId: payload.executionId,
5310
- agentId: (_la = payload.agentId) != null ? _la : "virtual",
5311
- agentName: (_ma = payload.agentName) != null ? _ma : "",
5517
+ agentId: (_va = payload.agentId) != null ? _va : "virtual",
5518
+ agentName: (_wa = payload.agentName) != null ? _wa : "",
5312
5519
  status: "running",
5313
5520
  currentIteration: 0,
5314
- maxTurns: (_na = payload.maxTurns) != null ? _na : 1,
5521
+ maxTurns: (_xa = payload.maxTurns) != null ? _xa : 1,
5315
5522
  startedAt: resolveTimestamp(payload.startedAt)
5316
5523
  };
5317
5524
  } else if (payloadType === "agent_iteration_start") {
@@ -5331,7 +5538,7 @@ var AgentWidgetClient = class {
5331
5538
  } else if (payloadType === "agent_turn_delta") {
5332
5539
  if (payload.contentType === "text") {
5333
5540
  const assistant = ensureAssistantMessage();
5334
- assistant.content += (_oa = payload.delta) != null ? _oa : "";
5541
+ assistant.content += (_ya = payload.delta) != null ? _ya : "";
5335
5542
  assistant.agentMetadata = {
5336
5543
  executionId: payload.executionId,
5337
5544
  iteration: payload.iteration,
@@ -5340,14 +5547,14 @@ var AgentWidgetClient = class {
5340
5547
  };
5341
5548
  emitMessage(assistant);
5342
5549
  } else if (payload.contentType === "thinking") {
5343
- const reasoningId = (_pa = payload.turnId) != null ? _pa : `agent-think-${payload.iteration}`;
5550
+ const reasoningId = (_za = payload.turnId) != null ? _za : `agent-think-${payload.iteration}`;
5344
5551
  const reasoningMessage = ensureReasoningMessage(reasoningId);
5345
- reasoningMessage.reasoning = (_qa = reasoningMessage.reasoning) != null ? _qa : {
5552
+ reasoningMessage.reasoning = (_Aa = reasoningMessage.reasoning) != null ? _Aa : {
5346
5553
  id: reasoningId,
5347
5554
  status: "streaming",
5348
5555
  chunks: []
5349
5556
  };
5350
- reasoningMessage.reasoning.chunks.push((_ra = payload.delta) != null ? _ra : "");
5557
+ reasoningMessage.reasoning.chunks.push((_Ba = payload.delta) != null ? _Ba : "");
5351
5558
  reasoningMessage.agentMetadata = {
5352
5559
  executionId: payload.executionId,
5353
5560
  iteration: payload.iteration,
@@ -5355,12 +5562,12 @@ var AgentWidgetClient = class {
5355
5562
  };
5356
5563
  emitMessage(reasoningMessage);
5357
5564
  } else if (payload.contentType === "tool_input") {
5358
- const toolId = (_sa = payload.toolCallId) != null ? _sa : toolContext.lastId;
5565
+ const toolId = (_Ca = payload.toolCallId) != null ? _Ca : toolContext.lastId;
5359
5566
  if (toolId) {
5360
5567
  const toolMessage = toolMessages.get(toolId);
5361
5568
  if (toolMessage == null ? void 0 : toolMessage.toolCall) {
5362
- toolMessage.toolCall.chunks = (_ta = toolMessage.toolCall.chunks) != null ? _ta : [];
5363
- toolMessage.toolCall.chunks.push((_ua = payload.delta) != null ? _ua : "");
5569
+ toolMessage.toolCall.chunks = (_Da = toolMessage.toolCall.chunks) != null ? _Da : [];
5570
+ toolMessage.toolCall.chunks.push((_Ea = payload.delta) != null ? _Ea : "");
5364
5571
  emitMessage(toolMessage);
5365
5572
  }
5366
5573
  }
@@ -5372,20 +5579,29 @@ var AgentWidgetClient = class {
5372
5579
  if (reasoningMessage == null ? void 0 : reasoningMessage.reasoning) {
5373
5580
  reasoningMessage.reasoning.status = "complete";
5374
5581
  reasoningMessage.reasoning.completedAt = resolveTimestamp(payload.completedAt);
5375
- const start = (_va = reasoningMessage.reasoning.startedAt) != null ? _va : Date.now();
5582
+ const start = (_Fa = reasoningMessage.reasoning.startedAt) != null ? _Fa : Date.now();
5376
5583
  reasoningMessage.reasoning.durationMs = Math.max(
5377
5584
  0,
5378
- ((_wa = reasoningMessage.reasoning.completedAt) != null ? _wa : Date.now()) - start
5585
+ ((_Ga = reasoningMessage.reasoning.completedAt) != null ? _Ga : Date.now()) - start
5379
5586
  );
5380
5587
  reasoningMessage.streaming = false;
5381
5588
  emitMessage(reasoningMessage);
5382
5589
  }
5383
5590
  }
5591
+ const turnStopReason = payload.stopReason;
5592
+ if (turnStopReason && assistantMessage !== null) {
5593
+ const turnId = payload.turnId;
5594
+ const matchesTurn = !turnId || ((_Ha = assistantMessage.agentMetadata) == null ? void 0 : _Ha.turnId) === turnId;
5595
+ if (matchesTurn) {
5596
+ assistantMessage.stopReason = turnStopReason;
5597
+ emitMessage(assistantMessage);
5598
+ }
5599
+ }
5384
5600
  } else if (payloadType === "agent_tool_start") {
5385
- const toolId = (_xa = payload.toolCallId) != null ? _xa : `agent-tool-${nextSequence()}`;
5601
+ const toolId = (_Ia = payload.toolCallId) != null ? _Ia : `agent-tool-${nextSequence()}`;
5386
5602
  trackToolId(getToolCallKey(payload), toolId);
5387
5603
  const toolMessage = ensureToolMessage(toolId);
5388
- const tool = (_ya = toolMessage.toolCall) != null ? _ya : {
5604
+ const tool = (_Ja = toolMessage.toolCall) != null ? _Ja : {
5389
5605
  id: toolId,
5390
5606
  status: "pending",
5391
5607
  name: void 0,
@@ -5397,12 +5613,12 @@ var AgentWidgetClient = class {
5397
5613
  completedAt: void 0,
5398
5614
  durationMs: void 0
5399
5615
  };
5400
- tool.name = (_Aa = (_za = payload.toolName) != null ? _za : payload.name) != null ? _Aa : tool.name;
5616
+ tool.name = (_La = (_Ka = payload.toolName) != null ? _Ka : payload.name) != null ? _La : tool.name;
5401
5617
  tool.status = "running";
5402
5618
  if (payload.parameters !== void 0) {
5403
5619
  tool.args = payload.parameters;
5404
5620
  }
5405
- tool.startedAt = resolveTimestamp((_Ba = payload.startedAt) != null ? _Ba : payload.timestamp);
5621
+ tool.startedAt = resolveTimestamp((_Ma = payload.startedAt) != null ? _Ma : payload.timestamp);
5406
5622
  toolMessage.toolCall = tool;
5407
5623
  toolMessage.streaming = true;
5408
5624
  toolMessage.agentMetadata = {
@@ -5411,21 +5627,21 @@ var AgentWidgetClient = class {
5411
5627
  };
5412
5628
  emitMessage(toolMessage);
5413
5629
  } else if (payloadType === "agent_tool_delta") {
5414
- const toolId = (_Ca = payload.toolCallId) != null ? _Ca : toolContext.lastId;
5630
+ const toolId = (_Na = payload.toolCallId) != null ? _Na : toolContext.lastId;
5415
5631
  if (toolId) {
5416
- const toolMessage = (_Da = toolMessages.get(toolId)) != null ? _Da : ensureToolMessage(toolId);
5632
+ const toolMessage = (_Oa = toolMessages.get(toolId)) != null ? _Oa : ensureToolMessage(toolId);
5417
5633
  if (toolMessage.toolCall) {
5418
- toolMessage.toolCall.chunks = (_Ea = toolMessage.toolCall.chunks) != null ? _Ea : [];
5419
- toolMessage.toolCall.chunks.push((_Fa = payload.delta) != null ? _Fa : "");
5634
+ toolMessage.toolCall.chunks = (_Pa = toolMessage.toolCall.chunks) != null ? _Pa : [];
5635
+ toolMessage.toolCall.chunks.push((_Qa = payload.delta) != null ? _Qa : "");
5420
5636
  toolMessage.toolCall.status = "running";
5421
5637
  toolMessage.streaming = true;
5422
5638
  emitMessage(toolMessage);
5423
5639
  }
5424
5640
  }
5425
5641
  } else if (payloadType === "agent_tool_complete") {
5426
- const toolId = (_Ga = payload.toolCallId) != null ? _Ga : toolContext.lastId;
5642
+ const toolId = (_Ra = payload.toolCallId) != null ? _Ra : toolContext.lastId;
5427
5643
  if (toolId) {
5428
- const toolMessage = (_Ha = toolMessages.get(toolId)) != null ? _Ha : ensureToolMessage(toolId);
5644
+ const toolMessage = (_Sa = toolMessages.get(toolId)) != null ? _Sa : ensureToolMessage(toolId);
5429
5645
  if (toolMessage.toolCall) {
5430
5646
  toolMessage.toolCall.status = "complete";
5431
5647
  if (payload.result !== void 0) {
@@ -5434,7 +5650,7 @@ var AgentWidgetClient = class {
5434
5650
  if (typeof payload.executionTime === "number") {
5435
5651
  toolMessage.toolCall.durationMs = payload.executionTime;
5436
5652
  }
5437
- toolMessage.toolCall.completedAt = resolveTimestamp((_Ia = payload.completedAt) != null ? _Ia : payload.timestamp);
5653
+ toolMessage.toolCall.completedAt = resolveTimestamp((_Ta = payload.completedAt) != null ? _Ta : payload.timestamp);
5438
5654
  toolMessage.streaming = false;
5439
5655
  emitMessage(toolMessage);
5440
5656
  const callKey = getToolCallKey(payload);
@@ -5449,7 +5665,7 @@ var AgentWidgetClient = class {
5449
5665
  const reflectionMessage = {
5450
5666
  id: reflectionId,
5451
5667
  role: "assistant",
5452
- content: (_Ja = payload.reflection) != null ? _Ja : "",
5668
+ content: (_Ua = payload.reflection) != null ? _Ua : "",
5453
5669
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5454
5670
  streaming: false,
5455
5671
  variant: "reasoning",
@@ -5457,7 +5673,7 @@ var AgentWidgetClient = class {
5457
5673
  reasoning: {
5458
5674
  id: reflectionId,
5459
5675
  status: "complete",
5460
- chunks: [(_Ka = payload.reflection) != null ? _Ka : ""]
5676
+ chunks: [(_Va = payload.reflection) != null ? _Va : ""]
5461
5677
  },
5462
5678
  agentMetadata: {
5463
5679
  executionId: payload.executionId,
@@ -5478,7 +5694,7 @@ var AgentWidgetClient = class {
5478
5694
  }
5479
5695
  onEvent({ type: "status", status: "idle" });
5480
5696
  } else if (payloadType === "agent_error") {
5481
- const errorMessage = typeof payload.error === "string" ? payload.error : (_Ma = (_La = payload.error) == null ? void 0 : _La.message) != null ? _Ma : "Agent execution error";
5697
+ const errorMessage = typeof payload.error === "string" ? payload.error : (_Xa = (_Wa = payload.error) == null ? void 0 : _Wa.message) != null ? _Xa : "Agent execution error";
5482
5698
  if (payload.recoverable) {
5483
5699
  if (typeof console !== "undefined") {
5484
5700
  console.warn("[AgentWidget] Recoverable agent error:", errorMessage);
@@ -5491,7 +5707,7 @@ var AgentWidgetClient = class {
5491
5707
  }
5492
5708
  } else if (payloadType === "agent_ping") {
5493
5709
  } else if (payloadType === "agent_approval_start") {
5494
- const approvalId = (_Na = payload.approvalId) != null ? _Na : `approval-${nextSequence()}`;
5710
+ const approvalId = (_Ya = payload.approvalId) != null ? _Ya : `approval-${nextSequence()}`;
5495
5711
  const approvalMessage = {
5496
5712
  id: `approval-${approvalId}`,
5497
5713
  role: "assistant",
@@ -5503,17 +5719,17 @@ var AgentWidgetClient = class {
5503
5719
  approval: {
5504
5720
  id: approvalId,
5505
5721
  status: "pending",
5506
- agentId: (_Oa = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _Oa : "virtual",
5507
- executionId: (_Qa = (_Pa = payload.executionId) != null ? _Pa : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _Qa : "",
5508
- toolName: (_Ra = payload.toolName) != null ? _Ra : "",
5722
+ agentId: (_Za = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _Za : "virtual",
5723
+ executionId: (_$a = (__a = payload.executionId) != null ? __a : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _$a : "",
5724
+ toolName: (_ab = payload.toolName) != null ? _ab : "",
5509
5725
  toolType: payload.toolType,
5510
- description: (_Ta = payload.description) != null ? _Ta : `Execute ${(_Sa = payload.toolName) != null ? _Sa : "tool"}`,
5726
+ description: (_cb = payload.description) != null ? _cb : `Execute ${(_bb = payload.toolName) != null ? _bb : "tool"}`,
5511
5727
  parameters: payload.parameters
5512
5728
  }
5513
5729
  };
5514
5730
  emitMessage(approvalMessage);
5515
5731
  } else if (payloadType === "step_await" && payload.awaitReason === "approval_required") {
5516
- const approvalId = (_Ua = payload.approvalId) != null ? _Ua : `approval-${nextSequence()}`;
5732
+ const approvalId = (_db = payload.approvalId) != null ? _db : `approval-${nextSequence()}`;
5517
5733
  const approvalMessage = {
5518
5734
  id: `approval-${approvalId}`,
5519
5735
  role: "assistant",
@@ -5525,11 +5741,11 @@ var AgentWidgetClient = class {
5525
5741
  approval: {
5526
5742
  id: approvalId,
5527
5743
  status: "pending",
5528
- agentId: (_Va = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _Va : "virtual",
5529
- executionId: (_Xa = (_Wa = payload.executionId) != null ? _Wa : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _Xa : "",
5530
- toolName: (_Ya = payload.toolName) != null ? _Ya : "",
5744
+ agentId: (_eb = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _eb : "virtual",
5745
+ executionId: (_gb = (_fb = payload.executionId) != null ? _fb : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _gb : "",
5746
+ toolName: (_hb = payload.toolName) != null ? _hb : "",
5531
5747
  toolType: payload.toolType,
5532
- description: (__a = payload.description) != null ? __a : `Execute ${(_Za = payload.toolName) != null ? _Za : "tool"}`,
5748
+ description: (_jb = payload.description) != null ? _jb : `Execute ${(_ib = payload.toolName) != null ? _ib : "tool"}`,
5533
5749
  parameters: payload.parameters
5534
5750
  }
5535
5751
  };
@@ -5548,11 +5764,11 @@ var AgentWidgetClient = class {
5548
5764
  sequence: nextSequence(),
5549
5765
  approval: {
5550
5766
  id: approvalId,
5551
- status: (_$a = payload.decision) != null ? _$a : "approved",
5552
- agentId: (_ab = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _ab : "virtual",
5553
- executionId: (_cb = (_bb = payload.executionId) != null ? _bb : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _cb : "",
5554
- toolName: (_db = payload.toolName) != null ? _db : "",
5555
- description: (_eb = payload.description) != null ? _eb : "",
5767
+ status: (_kb = payload.decision) != null ? _kb : "approved",
5768
+ agentId: (_lb = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _lb : "virtual",
5769
+ executionId: (_nb = (_mb = payload.executionId) != null ? _mb : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _nb : "",
5770
+ toolName: (_ob = payload.toolName) != null ? _ob : "",
5771
+ description: (_pb = payload.description) != null ? _pb : "",
5556
5772
  resolvedAt: Date.now()
5557
5773
  }
5558
5774
  };
@@ -5590,7 +5806,7 @@ var AgentWidgetClient = class {
5590
5806
  }
5591
5807
  } else if (payloadType === "artifact_delta") {
5592
5808
  const deltaId = String(payload.id);
5593
- const deltaText = typeof payload.delta === "string" ? payload.delta : String((_fb = payload.delta) != null ? _fb : "");
5809
+ const deltaText = typeof payload.delta === "string" ? payload.delta : String((_qb = payload.delta) != null ? _qb : "");
5594
5810
  onEvent({
5595
5811
  type: "artifact_delta",
5596
5812
  id: deltaId,
@@ -5613,7 +5829,7 @@ var AgentWidgetClient = class {
5613
5829
  if (refMsg) {
5614
5830
  refMsg.streaming = false;
5615
5831
  try {
5616
- const parsed = JSON.parse((_gb = refMsg.rawContent) != null ? _gb : "{}");
5832
+ const parsed = JSON.parse((_rb = refMsg.rawContent) != null ? _rb : "{}");
5617
5833
  if (parsed.props) {
5618
5834
  parsed.props.status = "complete";
5619
5835
  const acc = artifactContent.get(artCompleteId);
@@ -5634,7 +5850,7 @@ var AgentWidgetClient = class {
5634
5850
  if (!m || typeof m !== "object") {
5635
5851
  continue;
5636
5852
  }
5637
- const id = String((_hb = m.id) != null ? _hb : `msg-${nextSequence()}`);
5853
+ const id = String((_sb = m.id) != null ? _sb : `msg-${nextSequence()}`);
5638
5854
  const roleRaw = m.role;
5639
5855
  const role = roleRaw === "user" ? "user" : roleRaw === "system" ? "system" : "assistant";
5640
5856
  const msg = {
@@ -5653,7 +5869,7 @@ var AgentWidgetClient = class {
5653
5869
  if (msg.rawContent) {
5654
5870
  try {
5655
5871
  const parsed = JSON.parse(msg.rawContent);
5656
- const refArtId = (_ib = parsed == null ? void 0 : parsed.props) == null ? void 0 : _ib.artifactId;
5872
+ const refArtId = (_tb = parsed == null ? void 0 : parsed.props) == null ? void 0 : _tb.artifactId;
5657
5873
  if (typeof refArtId === "string") {
5658
5874
  artifactIdsWithCards.add(refArtId);
5659
5875
  }
@@ -5669,7 +5885,7 @@ var AgentWidgetClient = class {
5669
5885
  if (payload.error instanceof Error) {
5670
5886
  resolvedError = payload.error;
5671
5887
  } else if (payloadType === "dispatch_error") {
5672
- const msg = (_jb = payload.message) != null ? _jb : payload.error;
5888
+ const msg = (_ub = payload.message) != null ? _ub : payload.error;
5673
5889
  if (msg != null && msg !== "") {
5674
5890
  resolvedError = new Error(String(msg));
5675
5891
  }
@@ -5678,7 +5894,7 @@ var AgentWidgetClient = class {
5678
5894
  if (typeof e === "string" && e !== "") {
5679
5895
  resolvedError = new Error(e);
5680
5896
  } else if (e != null && typeof e === "object" && "message" in e) {
5681
- resolvedError = new Error(String((_kb = e.message) != null ? _kb : e));
5897
+ resolvedError = new Error(String((_vb = e.message) != null ? _vb : e));
5682
5898
  }
5683
5899
  } else if (payloadType === "error" && payload.error != null && payload.error !== "") {
5684
5900
  resolvedError = new Error(String(payload.error));
@@ -7523,6 +7739,8 @@ var AgentWidgetSession = class _AgentWidgetSession {
7523
7739
  var _a;
7524
7740
  (_a = this.abortController) == null ? void 0 : _a.abort();
7525
7741
  this.abortController = null;
7742
+ this.stopSpeaking();
7743
+ this.stopVoicePlayback();
7526
7744
  this.setStreaming(false);
7527
7745
  this.setStatus("idle");
7528
7746
  }
@@ -8155,6 +8373,9 @@ var morphMessages = (container, newContent, options = {}) => {
8155
8373
  if (oldNode.classList.contains("persona-animate-typing")) {
8156
8374
  return false;
8157
8375
  }
8376
+ if (oldNode.hasAttribute("data-preserve-runtime")) {
8377
+ return false;
8378
+ }
8158
8379
  if (oldNode.hasAttribute("data-preserve-animation")) {
8159
8380
  if (newNode instanceof HTMLElement && !newNode.hasAttribute("data-preserve-animation")) {
8160
8381
  return;
@@ -8176,7 +8397,7 @@ var morphMessages = (container, newContent, options = {}) => {
8176
8397
 
8177
8398
  // src/utils/message-fingerprint.ts
8178
8399
  function computeMessageFingerprint(message, configVersion) {
8179
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
8400
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D;
8180
8401
  return [
8181
8402
  message.id,
8182
8403
  message.role,
@@ -8194,6 +8415,7 @@ function computeMessageFingerprint(message, configVersion) {
8194
8415
  typeof ((_w = message.toolCall) == null ? void 0 : _w.args) === "string" ? message.toolCall.args.length : ((_x = message.toolCall) == null ? void 0 : _x.args) ? JSON.stringify(message.toolCall.args).length : 0,
8195
8416
  (_A = (_z = (_y = message.reasoning) == null ? void 0 : _y.chunks) == null ? void 0 : _z.length) != null ? _A : 0,
8196
8417
  (_C = (_B = message.contentParts) == null ? void 0 : _B.length) != null ? _C : 0,
8418
+ (_D = message.stopReason) != null ? _D : "",
8197
8419
  configVersion
8198
8420
  ].join("\0");
8199
8421
  }
@@ -8294,6 +8516,241 @@ var statusCopy = {
8294
8516
  var DEFAULT_OVERLAY_Z_INDEX = 1e5;
8295
8517
  var PORTALED_OVERLAY_Z_INDEX = DEFAULT_OVERLAY_Z_INDEX + 1;
8296
8518
 
8519
+ // src/utils/stream-animation.ts
8520
+ var DEFAULT_STREAM_ANIMATION = {
8521
+ type: "none",
8522
+ placeholder: "none",
8523
+ speed: 120,
8524
+ duration: 1800,
8525
+ buffer: "none"
8526
+ };
8527
+ var DEFAULT_SKIP_TAGS = ["pre", "code", "a", "script", "style"];
8528
+ var resolveStreamAnimation = (feature) => {
8529
+ var _a, _b, _c, _d, _e;
8530
+ return {
8531
+ type: (_a = feature == null ? void 0 : feature.type) != null ? _a : DEFAULT_STREAM_ANIMATION.type,
8532
+ placeholder: (_b = feature == null ? void 0 : feature.placeholder) != null ? _b : DEFAULT_STREAM_ANIMATION.placeholder,
8533
+ speed: (_c = feature == null ? void 0 : feature.speed) != null ? _c : DEFAULT_STREAM_ANIMATION.speed,
8534
+ duration: (_d = feature == null ? void 0 : feature.duration) != null ? _d : DEFAULT_STREAM_ANIMATION.duration,
8535
+ buffer: (_e = feature == null ? void 0 : feature.buffer) != null ? _e : DEFAULT_STREAM_ANIMATION.buffer
8536
+ };
8537
+ };
8538
+ var BUILTIN_PLUGINS = [
8539
+ {
8540
+ name: "typewriter",
8541
+ containerClass: "persona-stream-typewriter",
8542
+ wrap: "char",
8543
+ useCaret: true
8544
+ },
8545
+ {
8546
+ name: "pop-bubble",
8547
+ bubbleClass: "persona-stream-pop",
8548
+ wrap: "none"
8549
+ },
8550
+ {
8551
+ name: "letter-rise",
8552
+ containerClass: "persona-stream-letter-rise",
8553
+ wrap: "char"
8554
+ },
8555
+ {
8556
+ name: "word-fade",
8557
+ containerClass: "persona-stream-word-fade",
8558
+ wrap: "word"
8559
+ }
8560
+ ];
8561
+ var globalRegistry = /* @__PURE__ */ new Map();
8562
+ for (const plugin of BUILTIN_PLUGINS) globalRegistry.set(plugin.name, plugin);
8563
+ var resolveStreamAnimationPlugin = (type, overrides) => {
8564
+ var _a, _b;
8565
+ if (type === "none") return null;
8566
+ if (overrides && Object.prototype.hasOwnProperty.call(overrides, type)) {
8567
+ return (_a = overrides[type]) != null ? _a : null;
8568
+ }
8569
+ return (_b = globalRegistry.get(type)) != null ? _b : null;
8570
+ };
8571
+ var applyStreamBuffer = (content, buffer, plugin, message, streaming) => {
8572
+ if (!streaming) return content;
8573
+ if (plugin == null ? void 0 : plugin.bufferContent) return plugin.bufferContent(content, message);
8574
+ if (!content) return content;
8575
+ if (buffer === "word") {
8576
+ const lastSpace = content.search(/\s(?=\S*$)/);
8577
+ if (lastSpace < 0) return "";
8578
+ return content.slice(0, lastSpace);
8579
+ }
8580
+ if (buffer === "line") {
8581
+ const lastNewline = content.lastIndexOf("\n");
8582
+ if (lastNewline < 0) return "";
8583
+ return content.slice(0, lastNewline);
8584
+ }
8585
+ return content;
8586
+ };
8587
+ var makeCharSpan = (doc, ch, messageId, index) => {
8588
+ const span = doc.createElement("span");
8589
+ span.className = "persona-stream-char";
8590
+ span.id = `stream-c-${messageId}-${index}`;
8591
+ span.style.setProperty("--char-index", String(index));
8592
+ span.textContent = ch;
8593
+ return span;
8594
+ };
8595
+ var makeWordSpan = (doc, word, messageId, index) => {
8596
+ const span = doc.createElement("span");
8597
+ span.className = "persona-stream-word";
8598
+ span.id = `stream-w-${messageId}-${index}`;
8599
+ span.style.setProperty("--word-index", String(index));
8600
+ span.textContent = word;
8601
+ return span;
8602
+ };
8603
+ var WHITESPACE_RE = /\s/;
8604
+ var shouldSkipSubtree = (node, skipTags) => {
8605
+ let current = node.parentNode;
8606
+ while (current) {
8607
+ if (current.nodeType === 1) {
8608
+ const el = current;
8609
+ if (skipTags.has(el.tagName.toLowerCase())) return true;
8610
+ }
8611
+ current = current.parentNode;
8612
+ }
8613
+ return false;
8614
+ };
8615
+ var wrapTextNodeChars = (textNode, messageId, counterRef) => {
8616
+ var _a;
8617
+ const doc = textNode.ownerDocument;
8618
+ const parent = textNode.parentNode;
8619
+ if (!doc || !parent) return;
8620
+ const text = (_a = textNode.nodeValue) != null ? _a : "";
8621
+ if (!text) return;
8622
+ const fragment = doc.createDocumentFragment();
8623
+ let i = 0;
8624
+ while (i < text.length) {
8625
+ if (WHITESPACE_RE.test(text[i])) {
8626
+ let j = i;
8627
+ while (j < text.length && WHITESPACE_RE.test(text[j])) j += 1;
8628
+ fragment.appendChild(doc.createTextNode(text.slice(i, j)));
8629
+ i = j;
8630
+ } else {
8631
+ const group = doc.createElement("span");
8632
+ group.className = "persona-stream-word-group";
8633
+ let j = i;
8634
+ while (j < text.length && !WHITESPACE_RE.test(text[j])) {
8635
+ group.appendChild(makeCharSpan(doc, text[j], messageId, counterRef.value));
8636
+ counterRef.value += 1;
8637
+ j += 1;
8638
+ }
8639
+ fragment.appendChild(group);
8640
+ i = j;
8641
+ }
8642
+ }
8643
+ parent.replaceChild(fragment, textNode);
8644
+ };
8645
+ var wrapTextNodeWords = (textNode, messageId, counterRef) => {
8646
+ var _a;
8647
+ const doc = textNode.ownerDocument;
8648
+ const parent = textNode.parentNode;
8649
+ if (!doc || !parent) return;
8650
+ const text = (_a = textNode.nodeValue) != null ? _a : "";
8651
+ if (!text) return;
8652
+ const fragment = doc.createDocumentFragment();
8653
+ const tokens = text.split(/(\s+)/);
8654
+ for (const token of tokens) {
8655
+ if (!token) continue;
8656
+ if (/^\s+$/.test(token)) {
8657
+ fragment.appendChild(doc.createTextNode(token));
8658
+ } else {
8659
+ fragment.appendChild(makeWordSpan(doc, token, messageId, counterRef.value));
8660
+ counterRef.value += 1;
8661
+ }
8662
+ }
8663
+ parent.replaceChild(fragment, textNode);
8664
+ };
8665
+ var wrapStreamAnimation = (html, mode, messageId, options) => {
8666
+ var _a;
8667
+ if (!html) return html;
8668
+ if (typeof document === "undefined") return html;
8669
+ const scratch = document.createElement("div");
8670
+ scratch.innerHTML = html;
8671
+ const skipTags = new Set(((_a = options == null ? void 0 : options.skipTags) != null ? _a : DEFAULT_SKIP_TAGS).map((t) => t.toLowerCase()));
8672
+ const walker = document.createTreeWalker(scratch, NodeFilter.SHOW_TEXT, null);
8673
+ const textNodes = [];
8674
+ let node = walker.nextNode();
8675
+ while (node) {
8676
+ if (!shouldSkipSubtree(node, skipTags)) {
8677
+ textNodes.push(node);
8678
+ }
8679
+ node = walker.nextNode();
8680
+ }
8681
+ const counterRef = { value: 0 };
8682
+ const wrap = mode === "char" ? wrapTextNodeChars : wrapTextNodeWords;
8683
+ for (const textNode of textNodes) {
8684
+ wrap(textNode, messageId, counterRef);
8685
+ }
8686
+ return scratch.innerHTML;
8687
+ };
8688
+ var createStreamCaret = (doc = document) => {
8689
+ const caret = doc.createElement("span");
8690
+ caret.className = "persona-stream-caret";
8691
+ caret.setAttribute("aria-hidden", "true");
8692
+ caret.setAttribute("data-preserve-animation", "stream-caret");
8693
+ return caret;
8694
+ };
8695
+ var createSkeletonPlaceholder = (doc = document) => {
8696
+ const wrapper = doc.createElement("div");
8697
+ wrapper.className = "persona-stream-skeleton";
8698
+ wrapper.setAttribute("data-preserve-animation", "stream-skeleton");
8699
+ wrapper.setAttribute("aria-hidden", "true");
8700
+ const line = doc.createElement("div");
8701
+ line.className = "persona-stream-skeleton-line";
8702
+ wrapper.appendChild(line);
8703
+ return wrapper;
8704
+ };
8705
+ var injectedStyleRoots = /* @__PURE__ */ new WeakMap();
8706
+ var injectPluginStyles = (plugin, root) => {
8707
+ var _a;
8708
+ if (!plugin.styles) return;
8709
+ let names = injectedStyleRoots.get(root);
8710
+ if (!names) {
8711
+ names = /* @__PURE__ */ new Set();
8712
+ injectedStyleRoots.set(root, names);
8713
+ }
8714
+ if (names.has(plugin.name)) {
8715
+ const escaped = plugin.name.replace(/["\\]/g, "\\$&");
8716
+ const existing = root.querySelector(
8717
+ `style[data-persona-animation="${escaped}"]`
8718
+ );
8719
+ if (existing) return;
8720
+ names.delete(plugin.name);
8721
+ }
8722
+ names.add(plugin.name);
8723
+ const doc = root instanceof ShadowRoot ? root.ownerDocument : (_a = root.ownerDocument) != null ? _a : document;
8724
+ const style = doc.createElement("style");
8725
+ style.setAttribute("data-persona-animation", plugin.name);
8726
+ style.textContent = plugin.styles;
8727
+ root.appendChild(style);
8728
+ };
8729
+ var attachedCleanups = /* @__PURE__ */ new WeakMap();
8730
+ var attachPlugin = (plugin, root) => {
8731
+ if (!plugin.onAttach) return;
8732
+ let cleanups = attachedCleanups.get(root);
8733
+ if (!cleanups) {
8734
+ cleanups = /* @__PURE__ */ new Map();
8735
+ attachedCleanups.set(root, cleanups);
8736
+ }
8737
+ if (cleanups.has(plugin.name)) return;
8738
+ const cleanup = plugin.onAttach(root);
8739
+ cleanups.set(plugin.name, cleanup);
8740
+ };
8741
+ var detachAllPlugins = (root) => {
8742
+ const cleanups = attachedCleanups.get(root);
8743
+ if (!cleanups) return;
8744
+ for (const cleanup of cleanups.values()) {
8745
+ if (typeof cleanup === "function") cleanup();
8746
+ }
8747
+ cleanups.clear();
8748
+ };
8749
+ var ensurePluginActive = (plugin, root) => {
8750
+ injectPluginStyles(plugin, root);
8751
+ attachPlugin(plugin, root);
8752
+ };
8753
+
8297
8754
  // src/utils/overlay-host-stacking.ts
8298
8755
  function syncOverlayHostStacking(host, zIndex = DEFAULT_OVERLAY_Z_INDEX) {
8299
8756
  const originalPosition = host.style.position;
@@ -8654,6 +9111,7 @@ var buildHeader = (context) => {
8654
9111
  clearChatButton.style.color = clearChatIconColor || HEADER_THEME_CSS.actionIconColor;
8655
9112
  const iconSvg = renderLucideIcon(clearChatIconName, "20px", "currentColor", 1);
8656
9113
  if (iconSvg) {
9114
+ iconSvg.style.display = "block";
8657
9115
  clearChatButton.appendChild(iconSvg);
8658
9116
  }
8659
9117
  if (clearChatBgColor) {
@@ -8737,7 +9195,7 @@ var buildHeader = (context) => {
8737
9195
  }
8738
9196
  const closeButtonWrapper = createElement(
8739
9197
  "div",
8740
- closeButtonPlacement === "top-right" ? "persona-absolute persona-top-4 persona-right-4 persona-z-50" : clearChatEnabled && clearChatPlacement === "inline" ? "" : "persona-ml-auto"
9198
+ closeButtonPlacement === "top-right" ? "persona-absolute persona-top-4 persona-right-4 persona-z-50" : clearChatEnabled && clearChatPlacement === "inline" ? "persona-relative persona-inline-flex persona-items-center persona-justify-center" : "persona-relative persona-ml-auto persona-inline-flex persona-items-center persona-justify-center"
8741
9199
  );
8742
9200
  const closeButton = createElement(
8743
9201
  "button",
@@ -8753,8 +9211,9 @@ var buildHeader = (context) => {
8753
9211
  const closeButtonIconName = (_E = launcher.closeButtonIconName) != null ? _E : "x";
8754
9212
  const closeButtonIconText = (_F = launcher.closeButtonIconText) != null ? _F : "\xD7";
8755
9213
  closeButton.style.color = launcher.closeButtonColor || HEADER_THEME_CSS.actionIconColor;
8756
- const closeIconSvg = renderLucideIcon(closeButtonIconName, "20px", "currentColor", 1);
9214
+ const closeIconSvg = renderLucideIcon(closeButtonIconName, "28px", "currentColor", 1);
8757
9215
  if (closeIconSvg) {
9216
+ closeIconSvg.style.display = "block";
8758
9217
  closeButton.appendChild(closeIconSvg);
8759
9218
  } else {
8760
9219
  closeButton.textContent = closeButtonIconText;
@@ -9282,7 +9741,7 @@ var buildMinimalHeader = (context) => {
9282
9741
  closeButton.style.display = showClose ? "" : "none";
9283
9742
  closeButton.style.color = launcher.closeButtonColor || HEADER_THEME_CSS.actionIconColor;
9284
9743
  const closeButtonIconName = (_i = launcher.closeButtonIconName) != null ? _i : "x";
9285
- const closeIconSvg = renderLucideIcon(closeButtonIconName, "20px", "currentColor", 2);
9744
+ const closeIconSvg = renderLucideIcon(closeButtonIconName, "28px", "currentColor", 1);
9286
9745
  if (closeIconSvg) {
9287
9746
  closeButton.appendChild(closeIconSvg);
9288
9747
  } else {
@@ -9377,7 +9836,7 @@ var buildHeaderWithLayout = (config, layoutConfig, context) => {
9377
9836
 
9378
9837
  // src/components/composer-builder.ts
9379
9838
  var buildComposer = (context) => {
9380
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A;
9839
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E;
9381
9840
  const { config } = context;
9382
9841
  const footer = createElement(
9383
9842
  "div",
@@ -9433,9 +9892,13 @@ var buildComposer = (context) => {
9433
9892
  const useIcon = (_d = sendButtonConfig.useIcon) != null ? _d : false;
9434
9893
  const iconText = (_e = sendButtonConfig.iconText) != null ? _e : "\u2191";
9435
9894
  const iconName = sendButtonConfig.iconName;
9436
- const tooltipText = (_f = sendButtonConfig.tooltipText) != null ? _f : "Send message";
9437
- const showTooltip = (_g = sendButtonConfig.showTooltip) != null ? _g : false;
9438
- const buttonSize = (_h = sendButtonConfig.size) != null ? _h : "40px";
9895
+ const stopIconName = (_f = sendButtonConfig.stopIconName) != null ? _f : "square";
9896
+ const tooltipText = (_g = sendButtonConfig.tooltipText) != null ? _g : "Send message";
9897
+ const stopTooltipText = (_h = sendButtonConfig.stopTooltipText) != null ? _h : "Stop generating";
9898
+ const sendLabel = (_j = (_i = config == null ? void 0 : config.copy) == null ? void 0 : _i.sendButtonLabel) != null ? _j : "Send";
9899
+ const stopLabel = (_l = (_k = config == null ? void 0 : config.copy) == null ? void 0 : _k.stopButtonLabel) != null ? _l : "Stop";
9900
+ const showTooltip = (_m = sendButtonConfig.showTooltip) != null ? _m : false;
9901
+ const buttonSize = (_n = sendButtonConfig.size) != null ? _n : "40px";
9439
9902
  const backgroundColor = sendButtonConfig.backgroundColor;
9440
9903
  const textColor = sendButtonConfig.textColor;
9441
9904
  const sendButtonWrapper = createElement("div", "persona-send-button-wrapper");
@@ -9445,6 +9908,8 @@ var buildComposer = (context) => {
9445
9908
  );
9446
9909
  sendButton.type = "submit";
9447
9910
  sendButton.setAttribute("data-persona-composer-submit", "");
9911
+ let sendIcon = null;
9912
+ let stopIcon = null;
9448
9913
  if (useIcon) {
9449
9914
  sendButton.style.width = buttonSize;
9450
9915
  sendButton.style.height = buttonSize;
@@ -9458,25 +9923,26 @@ var buildComposer = (context) => {
9458
9923
  } else {
9459
9924
  sendButton.style.color = "var(--persona-button-primary-fg, #ffffff)";
9460
9925
  }
9926
+ const iconSize = parseFloat(buttonSize) || 24;
9927
+ const iconColor = (textColor == null ? void 0 : textColor.trim()) || "currentColor";
9461
9928
  if (iconName) {
9462
- const iconSize = parseFloat(buttonSize) || 24;
9463
- const iconColor = (textColor == null ? void 0 : textColor.trim()) || "currentColor";
9464
- const iconSvg = renderLucideIcon(iconName, iconSize, iconColor, 2);
9465
- if (iconSvg) {
9466
- sendButton.appendChild(iconSvg);
9929
+ sendIcon = renderLucideIcon(iconName, iconSize, iconColor, 2);
9930
+ if (sendIcon) {
9931
+ sendButton.appendChild(sendIcon);
9467
9932
  } else {
9468
9933
  sendButton.textContent = iconText;
9469
9934
  }
9470
9935
  } else {
9471
9936
  sendButton.textContent = iconText;
9472
9937
  }
9938
+ stopIcon = renderLucideIcon(stopIconName, iconSize, iconColor, 2);
9473
9939
  if (backgroundColor) {
9474
9940
  sendButton.style.backgroundColor = backgroundColor;
9475
9941
  } else {
9476
9942
  sendButton.classList.add("persona-bg-persona-primary");
9477
9943
  }
9478
9944
  } else {
9479
- sendButton.textContent = (_j = (_i = config == null ? void 0 : config.copy) == null ? void 0 : _i.sendButtonLabel) != null ? _j : "Send";
9945
+ sendButton.textContent = sendLabel;
9480
9946
  if (textColor) {
9481
9947
  sendButton.style.color = textColor;
9482
9948
  } else {
@@ -9504,18 +9970,43 @@ var buildComposer = (context) => {
9504
9970
  sendButton.style.paddingTop = "";
9505
9971
  sendButton.style.paddingBottom = "";
9506
9972
  }
9973
+ let sendTooltip = null;
9507
9974
  if (showTooltip && tooltipText) {
9508
- const tooltip = createElement("div", "persona-send-button-tooltip");
9509
- tooltip.textContent = tooltipText;
9510
- sendButtonWrapper.appendChild(tooltip);
9975
+ sendTooltip = createElement("div", "persona-send-button-tooltip");
9976
+ sendTooltip.textContent = tooltipText;
9977
+ sendButtonWrapper.appendChild(sendTooltip);
9511
9978
  }
9979
+ sendButton.setAttribute("aria-label", tooltipText);
9512
9980
  sendButtonWrapper.appendChild(sendButton);
9513
- const voiceRecognitionConfig = (_k = config == null ? void 0 : config.voiceRecognition) != null ? _k : {};
9981
+ let currentMode = "send";
9982
+ const setSendButtonMode = (mode) => {
9983
+ if (mode === currentMode) return;
9984
+ currentMode = mode;
9985
+ const label = mode === "stop" ? stopTooltipText : tooltipText;
9986
+ sendButton.setAttribute("aria-label", label);
9987
+ if (sendTooltip) {
9988
+ sendTooltip.textContent = label;
9989
+ }
9990
+ if (useIcon) {
9991
+ if (sendIcon && stopIcon) {
9992
+ const next = mode === "stop" ? stopIcon : sendIcon;
9993
+ const prev = mode === "stop" ? sendIcon : stopIcon;
9994
+ if (prev.parentNode === sendButton) {
9995
+ sendButton.replaceChild(next, prev);
9996
+ } else {
9997
+ sendButton.appendChild(next);
9998
+ }
9999
+ }
10000
+ } else {
10001
+ sendButton.textContent = mode === "stop" ? stopLabel : sendLabel;
10002
+ }
10003
+ };
10004
+ const voiceRecognitionConfig = (_o = config == null ? void 0 : config.voiceRecognition) != null ? _o : {};
9514
10005
  const voiceRecognitionEnabled = voiceRecognitionConfig.enabled === true;
9515
10006
  let micButton = null;
9516
10007
  let micButtonWrapper = null;
9517
10008
  const hasSpeechRecognition = typeof window !== "undefined" && (typeof window.webkitSpeechRecognition !== "undefined" || typeof window.SpeechRecognition !== "undefined");
9518
- const hasRuntypeProvider = ((_l = voiceRecognitionConfig.provider) == null ? void 0 : _l.type) === "runtype";
10009
+ const hasRuntypeProvider = ((_p = voiceRecognitionConfig.provider) == null ? void 0 : _p.type) === "runtype";
9519
10010
  const hasVoiceInput = hasSpeechRecognition || hasRuntypeProvider;
9520
10011
  if (voiceRecognitionEnabled && hasVoiceInput) {
9521
10012
  micButtonWrapper = createElement("div", "persona-send-button-wrapper");
@@ -9526,11 +10017,11 @@ var buildComposer = (context) => {
9526
10017
  micButton.type = "button";
9527
10018
  micButton.setAttribute("data-persona-composer-mic", "");
9528
10019
  micButton.setAttribute("aria-label", "Start voice recognition");
9529
- const micIconName = (_m = voiceRecognitionConfig.iconName) != null ? _m : "mic";
9530
- const micIconSize = (_n = voiceRecognitionConfig.iconSize) != null ? _n : buttonSize;
10020
+ const micIconName = (_q = voiceRecognitionConfig.iconName) != null ? _q : "mic";
10021
+ const micIconSize = (_r = voiceRecognitionConfig.iconSize) != null ? _r : buttonSize;
9531
10022
  const micIconSizeNum = parseFloat(micIconSize) || 24;
9532
- const micBackgroundColor = (_o = voiceRecognitionConfig.backgroundColor) != null ? _o : backgroundColor;
9533
- const micIconColor = (_p = voiceRecognitionConfig.iconColor) != null ? _p : textColor;
10023
+ const micBackgroundColor = (_s = voiceRecognitionConfig.backgroundColor) != null ? _s : backgroundColor;
10024
+ const micIconColor = (_t = voiceRecognitionConfig.iconColor) != null ? _t : textColor;
9534
10025
  micButton.style.width = micIconSize;
9535
10026
  micButton.style.height = micIconSize;
9536
10027
  micButton.style.minWidth = micIconSize;
@@ -9573,15 +10064,15 @@ var buildComposer = (context) => {
9573
10064
  micButton.style.paddingBottom = voiceRecognitionConfig.paddingY;
9574
10065
  }
9575
10066
  micButtonWrapper.appendChild(micButton);
9576
- const micTooltipText = (_q = voiceRecognitionConfig.tooltipText) != null ? _q : "Start voice recognition";
9577
- const showMicTooltip = (_r = voiceRecognitionConfig.showTooltip) != null ? _r : false;
10067
+ const micTooltipText = (_u = voiceRecognitionConfig.tooltipText) != null ? _u : "Start voice recognition";
10068
+ const showMicTooltip = (_v = voiceRecognitionConfig.showTooltip) != null ? _v : false;
9578
10069
  if (showMicTooltip && micTooltipText) {
9579
10070
  const tooltip = createElement("div", "persona-send-button-tooltip");
9580
10071
  tooltip.textContent = micTooltipText;
9581
10072
  micButtonWrapper.appendChild(tooltip);
9582
10073
  }
9583
10074
  }
9584
- const attachmentsConfig = (_s = config == null ? void 0 : config.attachments) != null ? _s : {};
10075
+ const attachmentsConfig = (_w = config == null ? void 0 : config.attachments) != null ? _w : {};
9585
10076
  const attachmentsEnabled = attachmentsConfig.enabled === true;
9586
10077
  let attachmentButton = null;
9587
10078
  let attachmentButtonWrapper = null;
@@ -9595,8 +10086,8 @@ var buildComposer = (context) => {
9595
10086
  attachmentPreviewsContainer.style.display = "none";
9596
10087
  attachmentInput = createElement("input");
9597
10088
  attachmentInput.type = "file";
9598
- attachmentInput.accept = ((_t = attachmentsConfig.allowedTypes) != null ? _t : ALL_SUPPORTED_MIME_TYPES).join(",");
9599
- attachmentInput.multiple = ((_u = attachmentsConfig.maxFiles) != null ? _u : 4) > 1;
10089
+ attachmentInput.accept = ((_x = attachmentsConfig.allowedTypes) != null ? _x : ALL_SUPPORTED_MIME_TYPES).join(",");
10090
+ attachmentInput.multiple = ((_y = attachmentsConfig.maxFiles) != null ? _y : 4) > 1;
9600
10091
  attachmentInput.style.display = "none";
9601
10092
  attachmentInput.setAttribute("aria-label", "Attach files");
9602
10093
  attachmentButtonWrapper = createElement("div", "persona-send-button-wrapper");
@@ -9605,8 +10096,8 @@ var buildComposer = (context) => {
9605
10096
  "persona-rounded-button persona-flex persona-items-center persona-justify-center disabled:persona-opacity-50 persona-cursor-pointer persona-attachment-button"
9606
10097
  );
9607
10098
  attachmentButton.type = "button";
9608
- attachmentButton.setAttribute("aria-label", (_v = attachmentsConfig.buttonTooltipText) != null ? _v : "Attach file");
9609
- const attachIconName = (_w = attachmentsConfig.buttonIconName) != null ? _w : "paperclip";
10099
+ attachmentButton.setAttribute("aria-label", (_z = attachmentsConfig.buttonTooltipText) != null ? _z : "Attach file");
10100
+ const attachIconName = (_A = attachmentsConfig.buttonIconName) != null ? _A : "paperclip";
9610
10101
  const attachIconSize = buttonSize;
9611
10102
  const buttonSizeNum = parseFloat(attachIconSize) || 40;
9612
10103
  const attachIconSizeNum = Math.round(buttonSizeNum * 0.6);
@@ -9643,7 +10134,7 @@ var buildComposer = (context) => {
9643
10134
  attachmentInput == null ? void 0 : attachmentInput.click();
9644
10135
  });
9645
10136
  attachmentButtonWrapper.appendChild(attachmentButton);
9646
- const attachTooltipText = (_x = attachmentsConfig.buttonTooltipText) != null ? _x : "Attach file";
10137
+ const attachTooltipText = (_B = attachmentsConfig.buttonTooltipText) != null ? _B : "Attach file";
9647
10138
  const tooltip = createElement("div", "persona-send-button-tooltip");
9648
10139
  tooltip.textContent = attachTooltipText;
9649
10140
  attachmentButtonWrapper.appendChild(tooltip);
@@ -9673,16 +10164,16 @@ var buildComposer = (context) => {
9673
10164
  rightActions.append(sendButtonWrapper);
9674
10165
  actionsRow.append(leftActions, rightActions);
9675
10166
  composerForm.append(actionsRow);
9676
- const statusConfig = (_y = config == null ? void 0 : config.statusIndicator) != null ? _y : {};
10167
+ const statusConfig = (_C = config == null ? void 0 : config.statusIndicator) != null ? _C : {};
9677
10168
  const alignClass = statusConfig.align === "left" ? "persona-text-left" : statusConfig.align === "center" ? "persona-text-center" : "persona-text-right";
9678
10169
  const statusText = createElement(
9679
10170
  "div",
9680
10171
  `persona-mt-2 ${alignClass} persona-text-xs persona-text-persona-muted`
9681
10172
  );
9682
10173
  statusText.setAttribute("data-persona-composer-status", "");
9683
- const isVisible = (_z = statusConfig.visible) != null ? _z : true;
10174
+ const isVisible = (_D = statusConfig.visible) != null ? _D : true;
9684
10175
  statusText.style.display = isVisible ? "" : "none";
9685
- const idleLabel = (_A = statusConfig.idleText) != null ? _A : "Online";
10176
+ const idleLabel = (_E = statusConfig.idleText) != null ? _E : "Online";
9686
10177
  if (statusConfig.idleLink) {
9687
10178
  const link = createElement("a");
9688
10179
  link.href = statusConfig.idleLink;
@@ -9714,7 +10205,8 @@ var buildComposer = (context) => {
9714
10205
  // Actions row layout elements
9715
10206
  actionsRow,
9716
10207
  leftActions,
9717
- rightActions
10208
+ rightActions,
10209
+ setSendButtonMode
9718
10210
  };
9719
10211
  };
9720
10212
 
@@ -9862,11 +10354,48 @@ var buildPanel = (config, showClose = true) => {
9862
10354
  // Actions row layout elements
9863
10355
  actionsRow: composerElements.actionsRow,
9864
10356
  leftActions: composerElements.leftActions,
9865
- rightActions: composerElements.rightActions
10357
+ rightActions: composerElements.rightActions,
10358
+ setSendButtonMode: composerElements.setSendButtonMode
9866
10359
  };
9867
10360
  };
9868
10361
 
9869
10362
  // src/components/message-bubble.ts
10363
+ var getDefaultStopReasonNoticeCopy = (stopReason) => {
10364
+ switch (stopReason) {
10365
+ case "max_tool_calls":
10366
+ return "Stopped after calling a tool. Send a follow-up to continue.";
10367
+ case "length":
10368
+ return "Response cut off as max tokens reached. Ask for more to continue.";
10369
+ case "content_filter":
10370
+ return "The provider filtered this response.";
10371
+ case "error":
10372
+ return "Something went wrong generating this response.";
10373
+ case "end_turn":
10374
+ case "unknown":
10375
+ default:
10376
+ return null;
10377
+ }
10378
+ };
10379
+ var resolveStopReasonNoticeText = (stopReason, overrides) => {
10380
+ if (!stopReason) return null;
10381
+ const fallback = getDefaultStopReasonNoticeCopy(stopReason);
10382
+ if (fallback === null) return null;
10383
+ const override = overrides == null ? void 0 : overrides[stopReason];
10384
+ const text = override !== void 0 ? override : fallback;
10385
+ if (!text) return null;
10386
+ return text;
10387
+ };
10388
+ var createStopReasonNotice = (stopReason, text) => {
10389
+ const notice = createElement(
10390
+ "div",
10391
+ "persona-message-stop-reason persona-text-xs persona-mt-2 persona-italic"
10392
+ );
10393
+ notice.setAttribute("data-stop-reason", stopReason);
10394
+ notice.setAttribute("role", "note");
10395
+ notice.style.opacity = "0.75";
10396
+ notice.textContent = text;
10397
+ return notice;
10398
+ };
9870
10399
  var isSafeImageSrc = (src) => {
9871
10400
  const lower = src.toLowerCase();
9872
10401
  if (lower.startsWith("data:image/svg+xml")) return false;
@@ -10169,7 +10698,7 @@ var createMessageActions = (message, actionsConfig, _callbacks) => {
10169
10698
  return container;
10170
10699
  };
10171
10700
  var createStandardBubble = (message, transform, layoutConfig, actionsConfig, actionCallbacks, options) => {
10172
- var _a, _b, _c, _d, _e, _f, _g;
10701
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
10173
10702
  const config = layoutConfig != null ? layoutConfig : {};
10174
10703
  const layout = (_a = config.layout) != null ? _a : "bubble";
10175
10704
  const avatarConfig = config.avatar;
@@ -10194,22 +10723,73 @@ var createStandardBubble = (message, transform, layoutConfig, actionsConfig, act
10194
10723
  const messageContentText = (_g = (_f = message.content) == null ? void 0 : _f.trim()) != null ? _g : "";
10195
10724
  const isImageOnlyFallbackMessage = imageParts.length > 0 && messageContentText === IMAGE_ONLY_MESSAGE_FALLBACK_TEXT;
10196
10725
  const shouldHideTextUntilPreviewFails = isImageOnlyFallbackMessage;
10726
+ const streamAnimation = resolveStreamAnimation(
10727
+ (_i = (_h = options == null ? void 0 : options.widgetConfig) == null ? void 0 : _h.features) == null ? void 0 : _i.streamAnimation
10728
+ );
10729
+ const streamPluginOverrides = (_l = (_k = (_j = options == null ? void 0 : options.widgetConfig) == null ? void 0 : _j.features) == null ? void 0 : _k.streamAnimation) == null ? void 0 : _l.plugins;
10730
+ const streamPlugin = message.role === "assistant" && streamAnimation.type !== "none" ? resolveStreamAnimationPlugin(streamAnimation.type, streamPluginOverrides) : null;
10731
+ const pluginStillAnimating = message.role === "assistant" && ((_m = streamPlugin == null ? void 0 : streamPlugin.isAnimating) == null ? void 0 : _m.call(streamPlugin, message)) === true;
10732
+ const streamAnimationActive = message.role === "assistant" && streamPlugin !== null && (Boolean(message.streaming) || pluginStillAnimating);
10733
+ if (streamAnimationActive && (streamPlugin == null ? void 0 : streamPlugin.bubbleClass)) {
10734
+ bubble.classList.add(streamPlugin.bubbleClass);
10735
+ }
10197
10736
  const contentDiv = document.createElement("div");
10198
10737
  contentDiv.classList.add("persona-message-content");
10738
+ if (streamAnimationActive && streamPlugin) {
10739
+ if (streamPlugin.containerClass) {
10740
+ contentDiv.classList.add(streamPlugin.containerClass);
10741
+ }
10742
+ contentDiv.style.setProperty("--persona-stream-step", `${streamAnimation.speed}ms`);
10743
+ contentDiv.style.setProperty("--persona-stream-duration", `${streamAnimation.duration}ms`);
10744
+ }
10745
+ const bufferedContent = streamAnimationActive ? applyStreamBuffer(
10746
+ (_n = message.content) != null ? _n : "",
10747
+ streamAnimation.buffer,
10748
+ streamPlugin,
10749
+ message,
10750
+ Boolean(message.streaming)
10751
+ ) : (_o = message.content) != null ? _o : "";
10199
10752
  const transformedContent = transform({
10200
- text: message.content,
10753
+ text: bufferedContent,
10201
10754
  message,
10202
10755
  streaming: Boolean(message.streaming),
10203
10756
  raw: message.rawContent
10204
10757
  });
10758
+ let animatedContent = transformedContent;
10759
+ if (streamAnimationActive && (streamPlugin == null ? void 0 : streamPlugin.wrap) === "char") {
10760
+ animatedContent = wrapStreamAnimation(transformedContent, "char", message.id, {
10761
+ skipTags: streamPlugin.skipTags
10762
+ });
10763
+ } else if (streamAnimationActive && (streamPlugin == null ? void 0 : streamPlugin.wrap) === "word") {
10764
+ animatedContent = wrapStreamAnimation(transformedContent, "word", message.id, {
10765
+ skipTags: streamPlugin.skipTags
10766
+ });
10767
+ }
10205
10768
  let textContentDiv = null;
10206
10769
  if (shouldHideTextUntilPreviewFails) {
10207
10770
  textContentDiv = document.createElement("div");
10208
- textContentDiv.innerHTML = transformedContent;
10771
+ textContentDiv.innerHTML = animatedContent;
10209
10772
  textContentDiv.style.display = "none";
10210
10773
  contentDiv.appendChild(textContentDiv);
10211
10774
  } else {
10212
- contentDiv.innerHTML = transformedContent;
10775
+ contentDiv.innerHTML = animatedContent;
10776
+ }
10777
+ if (streamAnimationActive && (streamPlugin == null ? void 0 : streamPlugin.useCaret) && !shouldHideTextUntilPreviewFails && messageContentText) {
10778
+ const caret = createStreamCaret();
10779
+ const spans = contentDiv.querySelectorAll(
10780
+ ".persona-stream-char, .persona-stream-word"
10781
+ );
10782
+ const lastSpan = spans[spans.length - 1];
10783
+ if (lastSpan == null ? void 0 : lastSpan.parentNode) {
10784
+ lastSpan.parentNode.insertBefore(caret, lastSpan.nextSibling);
10785
+ } else {
10786
+ const lastChild = contentDiv.lastElementChild;
10787
+ if (lastChild) {
10788
+ lastChild.appendChild(caret);
10789
+ } else {
10790
+ contentDiv.appendChild(caret);
10791
+ }
10792
+ }
10213
10793
  }
10214
10794
  if (showTimestamp && timestampPosition === "inline" && message.createdAt) {
10215
10795
  const timestamp = createTimestamp(message, timestampConfig);
@@ -10238,18 +10818,37 @@ var createStandardBubble = (message, transform, layoutConfig, actionsConfig, act
10238
10818
  timestamp.classList.add("persona-mt-1");
10239
10819
  bubble.appendChild(timestamp);
10240
10820
  }
10821
+ const stopReasonNoticeText = message.role === "assistant" ? resolveStopReasonNoticeText(
10822
+ message.stopReason,
10823
+ (_q = (_p = options == null ? void 0 : options.widgetConfig) == null ? void 0 : _p.copy) == null ? void 0 : _q.stopReasonNotice
10824
+ ) : null;
10241
10825
  if (message.streaming && message.role === "assistant") {
10242
- if (!message.content || !message.content.trim()) {
10243
- const indicator = renderLoadingIndicatorWithFallback(
10244
- "inline",
10245
- options == null ? void 0 : options.loadingIndicatorRenderer,
10246
- options == null ? void 0 : options.widgetConfig
10247
- );
10248
- if (indicator) {
10249
- bubble.appendChild(indicator);
10826
+ const hasVisibleContent = Boolean(bufferedContent && bufferedContent.trim());
10827
+ const skeletonEnabled = streamAnimation.placeholder === "skeleton";
10828
+ const trailSkeleton = skeletonEnabled && streamAnimation.buffer === "line" && hasVisibleContent;
10829
+ if (!hasVisibleContent) {
10830
+ if (skeletonEnabled) {
10831
+ bubble.appendChild(createSkeletonPlaceholder());
10832
+ } else {
10833
+ const indicator = renderLoadingIndicatorWithFallback(
10834
+ "inline",
10835
+ options == null ? void 0 : options.loadingIndicatorRenderer,
10836
+ options == null ? void 0 : options.widgetConfig
10837
+ );
10838
+ if (indicator) {
10839
+ bubble.appendChild(indicator);
10840
+ }
10250
10841
  }
10842
+ } else if (trailSkeleton) {
10843
+ bubble.appendChild(createSkeletonPlaceholder());
10251
10844
  }
10252
10845
  }
10846
+ if (stopReasonNoticeText && message.stopReason && !message.streaming) {
10847
+ if (!messageContentText) {
10848
+ contentDiv.style.display = "none";
10849
+ }
10850
+ bubble.appendChild(createStopReasonNotice(message.stopReason, stopReasonNoticeText));
10851
+ }
10253
10852
  const shouldShowActions = message.role === "assistant" && !message.streaming && message.content && message.content.trim() && (actionsConfig == null ? void 0 : actionsConfig.enabled) !== false;
10254
10853
  if (shouldShowActions && actionsConfig) {
10255
10854
  const actions = createMessageActions(message, actionsConfig, actionCallbacks);
@@ -13920,7 +14519,7 @@ function buildDropOverlay(dropCfg) {
13920
14519
  return overlay;
13921
14520
  }
13922
14521
  var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
13923
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N;
14522
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O;
13924
14523
  if (mount == null) {
13925
14524
  throw new Error(
13926
14525
  'createAgentExperience: mount must be a non-null HTMLElement (e.g. pass document.getElementById("my-root") after the node exists).'
@@ -14132,6 +14731,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14132
14731
  leftActions,
14133
14732
  rightActions
14134
14733
  } = panelElements;
14734
+ let setSendButtonMode = panelElements.setSendButtonMode;
14135
14735
  let micButton = panelElements.micButton;
14136
14736
  let micButtonWrapper = panelElements.micButtonWrapper;
14137
14737
  let attachmentButton = panelElements.attachmentButton;
@@ -14964,12 +15564,24 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14964
15564
  const panelBorder = resolvePanelChrome(panelPartial == null ? void 0 : panelPartial.border, defaultPanelBorder);
14965
15565
  const panelShadow = resolvePanelChrome(panelPartial == null ? void 0 : panelPartial.shadow, defaultPanelShadow);
14966
15566
  const panelBorderRadius = resolvePanelChrome(panelPartial == null ? void 0 : panelPartial.borderRadius, defaultPanelBorderRadius);
15567
+ const prevBodyScrollTop = body.scrollTop;
14967
15568
  mount.style.cssText = "";
14968
15569
  wrapper.style.cssText = "";
14969
15570
  panel.style.cssText = "";
14970
15571
  container.style.cssText = "";
14971
15572
  body.style.cssText = "";
14972
15573
  footer.style.cssText = "";
15574
+ const restoreBodyScrollTop = () => {
15575
+ var _a3;
15576
+ if (prevBodyScrollTop <= 0) return;
15577
+ const ownerWindow3 = (_a3 = body.ownerDocument.defaultView) != null ? _a3 : window;
15578
+ ownerWindow3.requestAnimationFrame(() => {
15579
+ if (body.scrollTop === prevBodyScrollTop) return;
15580
+ const maxScrollTop = body.scrollHeight - body.clientHeight;
15581
+ if (maxScrollTop <= 0) return;
15582
+ body.scrollTop = Math.min(prevBodyScrollTop, maxScrollTop);
15583
+ });
15584
+ };
14973
15585
  if (shouldGoFullscreen) {
14974
15586
  wrapper.classList.remove(
14975
15587
  "persona-bottom-6",
@@ -15025,6 +15637,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15025
15637
  body.style.overflowY = "auto";
15026
15638
  footer.style.flexShrink = "0";
15027
15639
  wasMobileFullscreen = true;
15640
+ restoreBodyScrollTop();
15028
15641
  return;
15029
15642
  }
15030
15643
  const launcherWidth = (_r2 = (_q2 = config == null ? void 0 : config.launcher) == null ? void 0 : _q2.width) != null ? _r2 : config == null ? void 0 : config.launcherWidth;
@@ -15167,6 +15780,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15167
15780
  const zIndexStyles = !sidebarMode ? `z-index: ${(_w2 = (_v2 = config.launcher) == null ? void 0 : _v2.zIndex) != null ? _w2 : DEFAULT_OVERLAY_Z_INDEX} !important;` : "";
15168
15781
  wrapper.style.cssText += maxHeightStyles + paddingStyles + zIndexStyles;
15169
15782
  }
15783
+ restoreBodyScrollTop();
15170
15784
  };
15171
15785
  applyFullHeightStyles();
15172
15786
  applyThemeVariables(mount, config);
@@ -15230,6 +15844,17 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15230
15844
  cleanupThemeObserver = null;
15231
15845
  }
15232
15846
  });
15847
+ const streamAnimationConfig = (_D = config.features) == null ? void 0 : _D.streamAnimation;
15848
+ if ((streamAnimationConfig == null ? void 0 : streamAnimationConfig.type) && streamAnimationConfig.type !== "none") {
15849
+ const plugin = resolveStreamAnimationPlugin(
15850
+ streamAnimationConfig.type,
15851
+ streamAnimationConfig.plugins
15852
+ );
15853
+ if (plugin) {
15854
+ ensurePluginActive(plugin, mount);
15855
+ destroyCallbacks.push(() => detachAllPlugins(mount));
15856
+ }
15857
+ }
15233
15858
  const suggestionsManager = createSuggestions(suggestions);
15234
15859
  let closeHandler = null;
15235
15860
  let session;
@@ -15251,7 +15876,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15251
15876
  lastUserMessageWasVoice: false,
15252
15877
  lastUserMessageId: null
15253
15878
  };
15254
- const voiceAutoResumeMode = (_E = (_D = config.voiceRecognition) == null ? void 0 : _D.autoResume) != null ? _E : false;
15879
+ const voiceAutoResumeMode = (_F = (_E = config.voiceRecognition) == null ? void 0 : _E.autoResume) != null ? _F : false;
15255
15880
  const emitVoiceState = (source) => {
15256
15881
  eventBus.emit("voice:state", {
15257
15882
  active: voiceState.active,
@@ -15939,7 +16564,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15939
16564
  });
15940
16565
  };
15941
16566
  const setComposerDisabled = (disabled) => {
15942
- sendButton.disabled = disabled;
16567
+ setSendButtonMode(disabled ? "stop" : "send");
15943
16568
  if (micButton) {
15944
16569
  micButton.disabled = disabled;
15945
16570
  }
@@ -15979,7 +16604,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15979
16604
  }
15980
16605
  }
15981
16606
  const useIcon = (_i2 = (_h2 = config.sendButton) == null ? void 0 : _h2.useIcon) != null ? _i2 : false;
15982
- if (!useIcon) {
16607
+ if (!useIcon && !(session == null ? void 0 : session.isStreaming())) {
15983
16608
  sendButton.textContent = (_k2 = (_j2 = config.copy) == null ? void 0 : _j2.sendButtonLabel) != null ? _k2 : "Send";
15984
16609
  }
15985
16610
  textarea.style.fontFamily = 'var(--persona-input-font-family, var(--persona-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif))';
@@ -16098,7 +16723,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16098
16723
  }
16099
16724
  });
16100
16725
  sessionRef.current = session;
16101
- if (((_G = (_F = config.voiceRecognition) == null ? void 0 : _F.provider) == null ? void 0 : _G.type) === "runtype") {
16726
+ if (((_H = (_G = config.voiceRecognition) == null ? void 0 : _G.provider) == null ? void 0 : _H.type) === "runtype") {
16102
16727
  try {
16103
16728
  session.setupVoice();
16104
16729
  } catch (err) {
@@ -16146,6 +16771,10 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16146
16771
  const handleSubmit = (event) => {
16147
16772
  var _a2;
16148
16773
  event.preventDefault();
16774
+ if (session.isStreaming()) {
16775
+ session.cancel();
16776
+ return;
16777
+ }
16149
16778
  const value = textarea.value.trim();
16150
16779
  const hasAttachments = (_a2 = attachmentManager == null ? void 0 : attachmentManager.hasAttachments()) != null ? _a2 : false;
16151
16780
  if (!value && !hasAttachments) return;
@@ -16700,7 +17329,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16700
17329
  }
16701
17330
  };
16702
17331
  recalcPanelHeight();
16703
- const ownerWindow = (_H = mount.ownerDocument.defaultView) != null ? _H : window;
17332
+ const ownerWindow = (_I = mount.ownerDocument.defaultView) != null ? _I : window;
16704
17333
  ownerWindow.addEventListener("resize", recalcPanelHeight);
16705
17334
  destroyCallbacks.push(() => ownerWindow.removeEventListener("resize", recalcPanelHeight));
16706
17335
  if (typeof ResizeObserver !== "undefined") {
@@ -16711,15 +17340,19 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16711
17340
  destroyCallbacks.push(() => footerResizeObserver.disconnect());
16712
17341
  }
16713
17342
  lastScrollTop = body.scrollTop;
17343
+ let lastScrollHeight = body.scrollHeight;
16714
17344
  const handleScroll = () => {
16715
17345
  const scrollTop = body.scrollTop;
17346
+ const currentScrollHeight = body.scrollHeight;
17347
+ const scrollHeightShrank = currentScrollHeight < lastScrollHeight;
17348
+ lastScrollHeight = currentScrollHeight;
16716
17349
  const { action, nextLastScrollTop } = resolveFollowStateFromScroll({
16717
17350
  following: autoFollow.isFollowing(),
16718
17351
  currentScrollTop: scrollTop,
16719
17352
  lastScrollTop,
16720
17353
  nearBottom: isElementNearBottom(body, BOTTOM_THRESHOLD),
16721
17354
  userScrollThreshold: USER_SCROLL_THRESHOLD,
16722
- isAutoScrolling: isAutoScrolling || hasPendingAutoScroll,
17355
+ isAutoScrolling: isAutoScrolling || hasPendingAutoScroll || scrollHeightShrank,
16723
17356
  pauseOnUpwardScroll: true,
16724
17357
  pauseWhenAwayFromBottom: false,
16725
17358
  resumeRequiresDownwardScroll: true
@@ -16919,7 +17552,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16919
17552
  }
16920
17553
  const controller = {
16921
17554
  update(nextConfig) {
16922
- var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o2, _p2, _q2, _r2, _s2, _t2, _u2, _v2, _w2, _x2, _y2, _z2, _A2, _B2, _C2, _D2, _E2, _F2, _G2, _H2, _I2, _J2, _K2, _L2, _M2, _N2, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab;
17555
+ var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2, _m2, _n2, _o2, _p2, _q2, _r2, _s2, _t2, _u2, _v2, _w2, _x2, _y2, _z2, _A2, _B2, _C2, _D2, _E2, _F2, _G2, _H2, _I2, _J2, _K2, _L2, _M2, _N2, _O2, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab;
16923
17556
  const previousToolCallConfig = config.toolCall;
16924
17557
  const previousMessageActions = config.messageActions;
16925
17558
  const previousLayoutMessages = (_a2 = config.layout) == null ? void 0 : _a2.messages;
@@ -17130,7 +17763,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17130
17763
  }
17131
17764
  const launcher = (_L2 = config.launcher) != null ? _L2 : {};
17132
17765
  const headerIconHidden = (_M2 = launcher.headerIconHidden) != null ? _M2 : false;
17133
- const layoutShowIcon = (_O = (_N2 = config.layout) == null ? void 0 : _N2.header) == null ? void 0 : _O.showIcon;
17766
+ const layoutShowIcon = (_O2 = (_N2 = config.layout) == null ? void 0 : _N2.header) == null ? void 0 : _O2.showIcon;
17134
17767
  const shouldHideIcon = headerIconHidden || layoutShowIcon === false;
17135
17768
  const headerIconName = launcher.headerIconName;
17136
17769
  const headerIconSize = (_P = launcher.headerIconSize) != null ? _P : "48px";
@@ -17271,7 +17904,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17271
17904
  const closeButtonIconName = (_ca = launcher.closeButtonIconName) != null ? _ca : "x";
17272
17905
  const closeButtonIconText = (_da = launcher.closeButtonIconText) != null ? _da : "\xD7";
17273
17906
  closeButton.innerHTML = "";
17274
- const iconSvg = renderLucideIcon(closeButtonIconName, "20px", "currentColor", 2);
17907
+ const iconSvg = renderLucideIcon(closeButtonIconName, "28px", "currentColor", 1);
17275
17908
  if (iconSvg) {
17276
17909
  closeButton.appendChild(iconSvg);
17277
17910
  } else {
@@ -18201,7 +18834,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
18201
18834
  }
18202
18835
  }
18203
18836
  };
18204
- const shouldExposeDebugApi = ((_I = runtimeOptions == null ? void 0 : runtimeOptions.debugTools) != null ? _I : false) || Boolean(config.debug);
18837
+ const shouldExposeDebugApi = ((_J = runtimeOptions == null ? void 0 : runtimeOptions.debugTools) != null ? _J : false) || Boolean(config.debug);
18205
18838
  if (shouldExposeDebugApi && typeof window !== "undefined") {
18206
18839
  const previousDebug = window.AgentWidgetBrowser;
18207
18840
  const debugApi = {
@@ -18304,9 +18937,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
18304
18937
  const voiceKey = `${persistConfig.keyPrefix}widget-voice`;
18305
18938
  const voiceModeKey = `${persistConfig.keyPrefix}widget-voice-mode`;
18306
18939
  if (storage) {
18307
- const wasOpen = ((_J = persistConfig.persist) == null ? void 0 : _J.openState) && storage.getItem(openKey) === "true";
18308
- const wasVoiceActive = ((_K = persistConfig.persist) == null ? void 0 : _K.voiceState) && storage.getItem(voiceKey) === "true";
18309
- const wasInVoiceMode = ((_L = persistConfig.persist) == null ? void 0 : _L.voiceState) && storage.getItem(voiceModeKey) === "true";
18940
+ const wasOpen = ((_K = persistConfig.persist) == null ? void 0 : _K.openState) && storage.getItem(openKey) === "true";
18941
+ const wasVoiceActive = ((_L = persistConfig.persist) == null ? void 0 : _L.voiceState) && storage.getItem(voiceKey) === "true";
18942
+ const wasInVoiceMode = ((_M = persistConfig.persist) == null ? void 0 : _M.voiceState) && storage.getItem(voiceModeKey) === "true";
18310
18943
  if (wasOpen) {
18311
18944
  setTimeout(() => {
18312
18945
  controller.open();
@@ -18323,7 +18956,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
18323
18956
  }, 100);
18324
18957
  }, 0);
18325
18958
  }
18326
- if ((_M = persistConfig.persist) == null ? void 0 : _M.openState) {
18959
+ if ((_N = persistConfig.persist) == null ? void 0 : _N.openState) {
18327
18960
  eventBus.on("widget:opened", () => {
18328
18961
  storage.setItem(openKey, "true");
18329
18962
  });
@@ -18331,7 +18964,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
18331
18964
  storage.setItem(openKey, "false");
18332
18965
  });
18333
18966
  }
18334
- if ((_N = persistConfig.persist) == null ? void 0 : _N.voiceState) {
18967
+ if ((_O = persistConfig.persist) == null ? void 0 : _O.voiceState) {
18335
18968
  eventBus.on("voice:state", (event) => {
18336
18969
  storage.setItem(voiceKey, event.active ? "true" : "false");
18337
18970
  });
@@ -18905,6 +19538,9 @@ function buildSrcdoc(mountId, shellMode, docked, widgetCssPath) {
18905
19538
  var PREVIEW_TRANSCRIPT_PRESET_LABELS = {
18906
19539
  "user-message": "User message",
18907
19540
  "assistant-message": "Assistant message",
19541
+ "assistant-code-block": "Assistant \u2014 code block",
19542
+ "assistant-markdown-table": "Assistant \u2014 markdown table",
19543
+ "assistant-image": "Assistant \u2014 image",
18908
19544
  "reasoning-streaming": "Reasoning (streaming)",
18909
19545
  "reasoning-complete": "Reasoning (complete)",
18910
19546
  "tool-running": "Tool call (running)",
@@ -18931,6 +19567,56 @@ function createPreviewTranscriptEntry(preset, index = 0) {
18931
19567
  content: "Absolutely. I can keep going and explain what happens next.",
18932
19568
  createdAt
18933
19569
  };
19570
+ case "assistant-code-block":
19571
+ return {
19572
+ id: `preview-seq-assistant-code-${suffix}`,
19573
+ role: "assistant",
19574
+ content: [
19575
+ "Here's how you'd wire up a streaming animation:",
19576
+ "",
19577
+ "```ts",
19578
+ "import { createAgentExperience } from '@runtypelabs/persona';",
19579
+ "",
19580
+ "createAgentExperience(el, {",
19581
+ " features: {",
19582
+ ' streamAnimation: { type: "letter-rise", speed: 120 },',
19583
+ " },",
19584
+ "});",
19585
+ "```",
19586
+ "",
19587
+ "Swap the `type` value to try the other presets."
19588
+ ].join("\n"),
19589
+ createdAt
19590
+ };
19591
+ case "assistant-markdown-table":
19592
+ return {
19593
+ id: `preview-seq-assistant-table-${suffix}`,
19594
+ role: "assistant",
19595
+ content: [
19596
+ "Here are the built-in streaming animations at a glance:",
19597
+ "",
19598
+ "| Preset | Wrap unit | Best for |",
19599
+ "| ------------ | --------- | --------------------------- |",
19600
+ "| Typewriter | Character | Classic terminal feel |",
19601
+ "| Letter rise | Character | Soft, staggered entrance |",
19602
+ "| Word fade | Word | Longer-form assistant replies |",
19603
+ "| Pop bubble | Bubble | Short, punchy affirmations |"
19604
+ ].join("\n"),
19605
+ createdAt
19606
+ };
19607
+ case "assistant-image":
19608
+ return {
19609
+ id: `preview-seq-assistant-image-${suffix}`,
19610
+ role: "assistant",
19611
+ content: [
19612
+ "Here's the reference diagram you asked for \u2014 let me know if you'd like a different view:",
19613
+ "",
19614
+ "![Stream animation reference](https://placehold.co/320x200/png?text=Stream+Animation)",
19615
+ "",
19616
+ "The gradient shows how per-unit delays stagger across the reply."
19617
+ ].join("\n"),
19618
+ createdAt
19619
+ };
18934
19620
  case "reasoning-streaming":
18935
19621
  return {
18936
19622
  id: `preview-seq-reasoning-stream-${suffix}`,
@@ -18998,6 +19684,38 @@ function createPreviewTranscriptEntry(preset, index = 0) {
18998
19684
  function appendPreviewTranscriptEntry(messages, preset) {
18999
19685
  return [...messages, createPreviewTranscriptEntry(preset, messages.length)];
19000
19686
  }
19687
+ function presetStreamsText(preset) {
19688
+ return preset === "assistant-message" || preset === "assistant-code-block" || preset === "assistant-markdown-table" || preset === "assistant-image";
19689
+ }
19690
+ function buildTranscriptStreamFrames(preset, suffix, options) {
19691
+ var _a, _b;
19692
+ const completed = createPreviewTranscriptEntry(preset, suffix);
19693
+ if (!presetStreamsText(preset) || typeof completed.content !== "string") {
19694
+ return [{ message: completed, delayMs: 0, done: true }];
19695
+ }
19696
+ const chunkSize = Math.max(1, (_a = options == null ? void 0 : options.chunkSize) != null ? _a : 24);
19697
+ const delayMs = Math.max(0, (_b = options == null ? void 0 : options.delayMs) != null ? _b : 42);
19698
+ const fullText = completed.content;
19699
+ const frames = [];
19700
+ frames.push({
19701
+ message: { ...completed, content: "", streaming: true },
19702
+ delayMs: 0,
19703
+ done: false
19704
+ });
19705
+ for (let i = chunkSize; i < fullText.length; i += chunkSize) {
19706
+ frames.push({
19707
+ message: { ...completed, content: fullText.slice(0, i), streaming: true },
19708
+ delayMs,
19709
+ done: false
19710
+ });
19711
+ }
19712
+ frames.push({
19713
+ message: { ...completed, content: fullText, streaming: false },
19714
+ delayMs,
19715
+ done: true
19716
+ });
19717
+ return frames;
19718
+ }
19001
19719
  var createAdvancedTranscriptPreviewMessages = () => [
19002
19720
  {
19003
19721
  id: "preview-adv-1",
@@ -19448,6 +20166,7 @@ function createThemePreview(container, initialOptions) {
19448
20166
  buildPreviewConfigWithMessages,
19449
20167
  buildShellCss,
19450
20168
  buildSrcdoc,
20169
+ buildTranscriptStreamFrames,
19451
20170
  convertFromPx,
19452
20171
  convertToPx,
19453
20172
  createPreviewMessages,
@@ -19467,6 +20186,7 @@ function createThemePreview(container, initialOptions) {
19467
20186
  normalizeColorValue,
19468
20187
  paletteColorPath,
19469
20188
  parseCssValue,
20189
+ presetStreamsText,
19470
20190
  resolveRoleAssignment,
19471
20191
  resolveThemeColorPath,
19472
20192
  scopeSection,