@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
@@ -45,6 +45,12 @@ var DEFAULT_WIDGET_CONFIG = {
45
45
  agentIconSize: "40px",
46
46
  headerIconSize: "40px",
47
47
  closeButtonSize: "32px",
48
+ // Zero out browser-default <button> padding so the icon gets the full
49
+ // 32x32 content box, matching clearChat.paddingX/Y below. Without this,
50
+ // UA stylesheets add ~1-2px vertical and ~6px horizontal padding that
51
+ // eats into the border-box width and shrinks the rendered icon.
52
+ closeButtonPaddingX: "0px",
53
+ closeButtonPaddingY: "0px",
48
54
  callToActionIconName: "arrow-up-right",
49
55
  callToActionIconText: "",
50
56
  callToActionIconSize: "32px",
@@ -132,6 +138,12 @@ var DEFAULT_WIDGET_CONFIG = {
132
138
  previewMaxLines: 3,
133
139
  expandable: true,
134
140
  loadingAnimation: "none"
141
+ },
142
+ streamAnimation: {
143
+ type: "none",
144
+ placeholder: "none",
145
+ speed: 120,
146
+ duration: 1800
135
147
  }
136
148
  },
137
149
  suggestionChips: [
@@ -234,11 +246,13 @@ function mergeWithDefaults(config) {
234
246
  ...config.voiceRecognition
235
247
  },
236
248
  features: (() => {
237
- var _a2, _b2, _c2, _d2;
249
+ var _a2, _b2, _c2, _d2, _e2, _f2;
238
250
  const da = (_a2 = DEFAULT_WIDGET_CONFIG.features) == null ? void 0 : _a2.artifacts;
239
251
  const ca = (_b2 = config.features) == null ? void 0 : _b2.artifacts;
240
252
  const dsb = (_c2 = DEFAULT_WIDGET_CONFIG.features) == null ? void 0 : _c2.scrollToBottom;
241
253
  const csb = (_d2 = config.features) == null ? void 0 : _d2.scrollToBottom;
254
+ const dsa = (_e2 = DEFAULT_WIDGET_CONFIG.features) == null ? void 0 : _e2.streamAnimation;
255
+ const csa = (_f2 = config.features) == null ? void 0 : _f2.streamAnimation;
242
256
  const mergedArtifacts = da === void 0 && ca === void 0 ? void 0 : {
243
257
  ...da,
244
258
  ...ca,
@@ -251,11 +265,16 @@ function mergeWithDefaults(config) {
251
265
  ...dsb,
252
266
  ...csb
253
267
  };
268
+ const mergedStreamAnimation = dsa === void 0 && csa === void 0 ? void 0 : {
269
+ ...dsa,
270
+ ...csa
271
+ };
254
272
  return {
255
273
  ...DEFAULT_WIDGET_CONFIG.features,
256
274
  ...config.features,
257
275
  ...mergedScrollToBottom !== void 0 ? { scrollToBottom: mergedScrollToBottom } : {},
258
- ...mergedArtifacts !== void 0 ? { artifacts: mergedArtifacts } : {}
276
+ ...mergedArtifacts !== void 0 ? { artifacts: mergedArtifacts } : {},
277
+ ...mergedStreamAnimation !== void 0 ? { streamAnimation: mergedStreamAnimation } : {}
259
278
  };
260
279
  })(),
261
280
  suggestionChips: (_e = config.suggestionChips) != null ? _e : DEFAULT_WIDGET_CONFIG.suggestionChips,
@@ -2558,6 +2577,91 @@ var featuresSectionDef = {
2558
2577
  { id: "feat-scroll-bottom-label", label: "Scroll To Bottom Label", description: "Leave empty for icon-only mode", type: "text", path: "features.scrollToBottom.label", defaultValue: "" }
2559
2578
  ]
2560
2579
  };
2580
+ var streamAnimationSectionDef = {
2581
+ id: "stream-animation",
2582
+ title: "Stream Animation",
2583
+ description: "Control how assistant text appears while streaming.",
2584
+ collapsed: true,
2585
+ fields: [
2586
+ {
2587
+ id: "stream-anim-type",
2588
+ label: "Animation",
2589
+ description: "Reveal effect applied to each assistant reply as it streams.",
2590
+ type: "select",
2591
+ path: "features.streamAnimation.type",
2592
+ defaultValue: "none",
2593
+ options: [
2594
+ { value: "none", label: "None" },
2595
+ { value: "typewriter", label: "Typewriter" },
2596
+ { value: "word-fade", label: "Word fade" },
2597
+ { value: "letter-rise", label: "Letter rise" },
2598
+ { value: "glyph-cycle", label: "Glyph cycle" },
2599
+ { value: "wipe", label: "Wipe" },
2600
+ { value: "pop-bubble", label: "Pop bubble" }
2601
+ ]
2602
+ },
2603
+ {
2604
+ id: "stream-anim-placeholder",
2605
+ label: "Pre-first-token Placeholder",
2606
+ description: "What to show before the first token arrives.",
2607
+ type: "select",
2608
+ path: "features.streamAnimation.placeholder",
2609
+ defaultValue: "none",
2610
+ options: [
2611
+ { value: "none", label: "Typing indicator (default)" },
2612
+ { value: "skeleton", label: "Skeleton shimmer" }
2613
+ ]
2614
+ },
2615
+ {
2616
+ id: "stream-anim-buffer",
2617
+ label: "Content Buffering",
2618
+ description: "Trim in-progress units so only complete words/lines reveal.",
2619
+ type: "select",
2620
+ path: "features.streamAnimation.buffer",
2621
+ defaultValue: "none",
2622
+ options: [
2623
+ { value: "none", label: "None \u2014 stream every character" },
2624
+ { value: "word", label: "Word \u2014 hold until whitespace" },
2625
+ { value: "line", label: "Line \u2014 hold until newline" }
2626
+ ]
2627
+ },
2628
+ {
2629
+ id: "stream-anim-speed",
2630
+ label: "Per-unit Duration (ms)",
2631
+ description: "Animation length for each character or word.",
2632
+ type: "select",
2633
+ path: "features.streamAnimation.speed",
2634
+ defaultValue: 120,
2635
+ options: [
2636
+ { value: "40", label: "40ms \u2014 snappy" },
2637
+ { value: "80", label: "80ms" },
2638
+ { value: "120", label: "120ms (default)" },
2639
+ { value: "200", label: "200ms" },
2640
+ { value: "320", label: "320ms" },
2641
+ { value: "480", label: "480ms \u2014 slow" }
2642
+ ],
2643
+ formatValue: (v) => String(v != null ? v : 120),
2644
+ parseValue: (v) => Number(v)
2645
+ },
2646
+ {
2647
+ id: "stream-anim-duration",
2648
+ label: "Container Duration (ms)",
2649
+ description: "Length of container-level effects (pop-bubble, custom plugins).",
2650
+ type: "select",
2651
+ path: "features.streamAnimation.duration",
2652
+ defaultValue: 1800,
2653
+ options: [
2654
+ { value: "600", label: "600ms" },
2655
+ { value: "1200", label: "1200ms" },
2656
+ { value: "1800", label: "1800ms (default)" },
2657
+ { value: "2400", label: "2400ms" },
2658
+ { value: "3600", label: "3600ms \u2014 slow" }
2659
+ ],
2660
+ formatValue: (v) => String(v != null ? v : 1800),
2661
+ parseValue: (v) => Number(v)
2662
+ }
2663
+ ]
2664
+ };
2561
2665
  var attachmentsSectionDef = {
2562
2666
  id: "attachments-config",
2563
2667
  title: "Attachments",
@@ -2641,7 +2745,7 @@ var CONFIGURE_SUB_GROUPS = [
2641
2745
  { label: "Content", sections: [copySectionDef, suggestionsSectionDef] },
2642
2746
  { label: "Layout", sections: [generalLayoutSectionDef, headerLayoutSectionDef, messagesLayoutSectionDef, messageActionsSectionDef] },
2643
2747
  { label: "Widget", sections: [launcherBasicsSectionDef, launcherAdvancedSectionDef, sendButtonSectionDef, closeButtonSectionDef, clearChatSectionDef, statusIndicatorSectionDef] },
2644
- { label: "Features", sections: [featuresSectionDef, attachmentsSectionDef, artifactsSectionDef, artifactCustomizationSectionDef] },
2748
+ { label: "Features", sections: [featuresSectionDef, streamAnimationSectionDef, attachmentsSectionDef, artifactsSectionDef, artifactCustomizationSectionDef] },
2645
2749
  { label: "Developer", collapsedByDefault: true, sections: [apiIntegrationSectionDef, debugSectionDef, markdownSectionDef] }
2646
2750
  ];
2647
2751
  var CONFIGURE_SECTIONS = CONFIGURE_SUB_GROUPS.flatMap((g) => g.sections);
@@ -4347,6 +4451,8 @@ var AgentWidgetClient = class {
4347
4451
  let didSplitByPartId = false;
4348
4452
  const reasoningMessages = /* @__PURE__ */ new Map();
4349
4453
  const toolMessages = /* @__PURE__ */ new Map();
4454
+ const nestedStepMessages = /* @__PURE__ */ new Map();
4455
+ const nestedPartIdByStep = /* @__PURE__ */ new Map();
4350
4456
  const reasoningContext = {
4351
4457
  lastId: null,
4352
4458
  byStep: /* @__PURE__ */ new Map()
@@ -4355,6 +4461,31 @@ var AgentWidgetClient = class {
4355
4461
  lastId: null,
4356
4462
  byCall: /* @__PURE__ */ new Map()
4357
4463
  };
4464
+ const getNestedStepKey = (toolId, stepId, partId = "") => `${toolId}::${stepId}::${partId}`;
4465
+ const getNestedStepPrefix = (toolId, stepId) => `${toolId}::${stepId}::`;
4466
+ const ensureNestedStepMessage = (toolId, stepId, partId, executionId) => {
4467
+ const key = getNestedStepKey(toolId, stepId, partId);
4468
+ const existing = nestedStepMessages.get(key);
4469
+ if (existing) return existing;
4470
+ const idSuffix = partId ? `-${partId}` : "";
4471
+ const message = {
4472
+ id: `nested-${toolId}-${stepId}${idSuffix}`,
4473
+ role: "assistant",
4474
+ content: "",
4475
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
4476
+ streaming: true,
4477
+ sequence: nextSequence(),
4478
+ ...partId ? { partId } : {},
4479
+ agentMetadata: {
4480
+ executionId,
4481
+ parentToolId: toolId,
4482
+ parentStepId: stepId
4483
+ }
4484
+ };
4485
+ nestedStepMessages.set(key, message);
4486
+ emitMessage(message);
4487
+ return message;
4488
+ };
4358
4489
  const normalizeKey = (value) => {
4359
4490
  if (value === null || value === void 0) return null;
4360
4491
  try {
@@ -4664,7 +4795,7 @@ var AgentWidgetClient = class {
4664
4795
  const agentIterationMessages = /* @__PURE__ */ new Map();
4665
4796
  const iterationDisplay = (_a = this.config.iterationDisplay) != null ? _a : "separate";
4666
4797
  drainReadyQueue = () => {
4667
- 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;
4798
+ 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;
4668
4799
  for (let i = 0; i < seqReadyQueue.length; i++) {
4669
4800
  const payloadType = seqReadyQueue[i].payloadType;
4670
4801
  const payload = seqReadyQueue[i].payload;
@@ -4837,6 +4968,9 @@ var AgentWidgetClient = class {
4837
4968
  toolContext.byCall.delete(callKey);
4838
4969
  }
4839
4970
  } else if (payloadType === "text_start") {
4971
+ if ((_X = payload.toolContext) == null ? void 0 : _X.toolId) {
4972
+ continue;
4973
+ }
4840
4974
  const incomingPartId = payload.partId;
4841
4975
  if (incomingPartId !== void 0 && partIdState.current !== null && incomingPartId !== partIdState.current) {
4842
4976
  const prev = assistantMessage;
@@ -4852,6 +4986,9 @@ var AgentWidgetClient = class {
4852
4986
  partIdState.current = incomingPartId;
4853
4987
  }
4854
4988
  } else if (payloadType === "text_end") {
4989
+ if ((_Y = payload.toolContext) == null ? void 0 : _Y.toolId) {
4990
+ continue;
4991
+ }
4855
4992
  const prev = assistantMessage;
4856
4993
  if (prev) {
4857
4994
  prev.streaming = false;
@@ -4866,6 +5003,48 @@ var AgentWidgetClient = class {
4866
5003
  if (stepType === "tool" || executionType === "context") {
4867
5004
  continue;
4868
5005
  }
5006
+ const nestedToolCtx = payload.toolContext;
5007
+ if (nestedToolCtx == null ? void 0 : nestedToolCtx.toolId) {
5008
+ const nestedStepId = String(
5009
+ (__ = (_Z = payload.id) != null ? _Z : nestedToolCtx.stepId) != null ? __ : `step-${nextSequence()}`
5010
+ );
5011
+ const incomingPartId2 = payload.partId !== void 0 && payload.partId !== null ? String(payload.partId) : "";
5012
+ const stepScopeKey = `${nestedToolCtx.toolId}::${nestedStepId}`;
5013
+ const prevPartId = nestedPartIdByStep.get(stepScopeKey);
5014
+ if (incomingPartId2 !== "" && prevPartId !== void 0 && prevPartId !== "" && prevPartId !== incomingPartId2) {
5015
+ const prev = nestedStepMessages.get(
5016
+ getNestedStepKey(
5017
+ nestedToolCtx.toolId,
5018
+ nestedStepId,
5019
+ prevPartId
5020
+ )
5021
+ );
5022
+ if (prev && prev.streaming !== false) {
5023
+ prev.streaming = false;
5024
+ emitMessage(prev);
5025
+ }
5026
+ }
5027
+ if (incomingPartId2 !== "") {
5028
+ nestedPartIdByStep.set(stepScopeKey, incomingPartId2);
5029
+ }
5030
+ const nestedMsg = ensureNestedStepMessage(
5031
+ nestedToolCtx.toolId,
5032
+ nestedStepId,
5033
+ incomingPartId2,
5034
+ nestedToolCtx.executionId
5035
+ );
5036
+ const nestedChunk = (_ca = (_ba = (_aa = (_$ = payload.text) != null ? _$ : payload.delta) != null ? _aa : payload.content) != null ? _ba : payload.chunk) != null ? _ca : "";
5037
+ if (nestedChunk) {
5038
+ nestedMsg.content += String(nestedChunk);
5039
+ nestedMsg.streaming = true;
5040
+ emitMessage(nestedMsg);
5041
+ }
5042
+ if (payload.isComplete) {
5043
+ nestedMsg.streaming = false;
5044
+ emitMessage(nestedMsg);
5045
+ }
5046
+ continue;
5047
+ }
4869
5048
  const incomingPartId = payload.partId;
4870
5049
  if (incomingPartId !== void 0 && partIdState.current !== null && incomingPartId !== partIdState.current) {
4871
5050
  const prev = assistantMessage;
@@ -4880,18 +5059,18 @@ var AgentWidgetClient = class {
4880
5059
  if (incomingPartId !== void 0) {
4881
5060
  partIdState.current = incomingPartId;
4882
5061
  }
4883
- const assistant = incomingPartId !== void 0 ? (_X = assistantMessagesByPartId.get(incomingPartId)) != null ? _X : ensureAssistantMessage() : ensureAssistantMessage();
5062
+ const assistant = incomingPartId !== void 0 ? (_da = assistantMessagesByPartId.get(incomingPartId)) != null ? _da : ensureAssistantMessage() : ensureAssistantMessage();
4884
5063
  if (incomingPartId !== void 0) {
4885
5064
  if (!assistant.partId) {
4886
5065
  assistant.partId = incomingPartId;
4887
5066
  }
4888
5067
  assistantMessagesByPartId.set(incomingPartId, assistant);
4889
5068
  }
4890
- const chunk = (_$ = (__ = (_Z = (_Y = payload.text) != null ? _Y : payload.delta) != null ? _Z : payload.content) != null ? __ : payload.chunk) != null ? _$ : "";
5069
+ const chunk = (_ha = (_ga = (_fa = (_ea = payload.text) != null ? _ea : payload.delta) != null ? _fa : payload.content) != null ? _ga : payload.chunk) != null ? _ha : "";
4891
5070
  if (chunk) {
4892
5071
  const chunkSeq = typeof payload.seq === "number" ? payload.seq : void 0;
4893
5072
  const chunkBufferKey = incomingPartId != null ? incomingPartId : assistant.id;
4894
- const accumulatedRaw = chunkSeq !== void 0 ? insertOrderedChunk(chunkBufferKey, chunkSeq, String(chunk)) : ((_aa = rawContentBuffers.get(assistant.id)) != null ? _aa : "") + chunk;
5073
+ const accumulatedRaw = chunkSeq !== void 0 ? insertOrderedChunk(chunkBufferKey, chunkSeq, String(chunk)) : ((_ia = rawContentBuffers.get(assistant.id)) != null ? _ia : "") + chunk;
4895
5074
  assistant.rawContent = accumulatedRaw;
4896
5075
  if (!streamParsers.has(assistant.id)) {
4897
5076
  streamParsers.set(assistant.id, this.createStreamParser());
@@ -4937,7 +5116,7 @@ var AgentWidgetClient = class {
4937
5116
  emitMessage(assistant);
4938
5117
  });
4939
5118
  } else {
4940
- const text = typeof parsedResult === "string" ? parsedResult : (_ba = parsedResult == null ? void 0 : parsedResult.text) != null ? _ba : null;
5119
+ const text = typeof parsedResult === "string" ? parsedResult : (_ja = parsedResult == null ? void 0 : parsedResult.text) != null ? _ja : null;
4941
5120
  if (text !== null && text.trim() !== "") {
4942
5121
  assistant.content = text;
4943
5122
  emitMessage(assistant);
@@ -4951,7 +5130,7 @@ var AgentWidgetClient = class {
4951
5130
  }
4952
5131
  }
4953
5132
  if (payload.isComplete) {
4954
- const finalContent = (_da = (_ca = payload.result) == null ? void 0 : _ca.response) != null ? _da : assistant.content;
5133
+ const finalContent = (_la = (_ka = payload.result) == null ? void 0 : _ka.response) != null ? _la : assistant.content;
4955
5134
  if (finalContent) {
4956
5135
  const rawBuffer = rawContentBuffers.get(assistant.id);
4957
5136
  const contentToProcess = rawBuffer != null ? rawBuffer : ensureStringContent(finalContent);
@@ -4983,7 +5162,7 @@ var AgentWidgetClient = class {
4983
5162
  }
4984
5163
  });
4985
5164
  } else {
4986
- extractedText = typeof parsedResult === "string" ? parsedResult : (_ea = parsedResult == null ? void 0 : parsedResult.text) != null ? _ea : null;
5165
+ extractedText = typeof parsedResult === "string" ? parsedResult : (_ma = parsedResult == null ? void 0 : parsedResult.text) != null ? _ma : null;
4987
5166
  }
4988
5167
  }
4989
5168
  }
@@ -4995,7 +5174,7 @@ var AgentWidgetClient = class {
4995
5174
  }
4996
5175
  const parserToClose = streamParsers.get(assistant.id);
4997
5176
  if (parserToClose) {
4998
- const closeResult = (_fa = parserToClose.close) == null ? void 0 : _fa.call(parserToClose);
5177
+ const closeResult = (_na = parserToClose.close) == null ? void 0 : _na.call(parserToClose);
4999
5178
  if (closeResult instanceof Promise) {
5000
5179
  closeResult.catch(() => {
5001
5180
  });
@@ -5014,9 +5193,33 @@ var AgentWidgetClient = class {
5014
5193
  if (stepType === "tool" || executionType === "context") {
5015
5194
  continue;
5016
5195
  }
5196
+ const nestedCompleteCtx = payload.toolContext;
5197
+ if (nestedCompleteCtx == null ? void 0 : nestedCompleteCtx.toolId) {
5198
+ const nestedStepId = String(
5199
+ (_pa = (_oa = payload.id) != null ? _oa : nestedCompleteCtx.stepId) != null ? _pa : ""
5200
+ );
5201
+ if (nestedStepId) {
5202
+ const prefix = getNestedStepPrefix(
5203
+ nestedCompleteCtx.toolId,
5204
+ nestedStepId
5205
+ );
5206
+ for (const [key, msg] of nestedStepMessages) {
5207
+ if (key.startsWith(prefix) && msg.streaming !== false) {
5208
+ msg.streaming = false;
5209
+ emitMessage(msg);
5210
+ }
5211
+ }
5212
+ nestedPartIdByStep.delete(
5213
+ `${nestedCompleteCtx.toolId}::${nestedStepId}`
5214
+ );
5215
+ }
5216
+ continue;
5217
+ }
5218
+ const stepStopReason = payload.stopReason;
5017
5219
  if (didSplitByPartId) {
5018
5220
  if (assistantMessage !== null) {
5019
5221
  const msg = assistantMessage;
5222
+ if (stepStopReason) msg.stopReason = stepStopReason;
5020
5223
  streamParsers.delete(msg.id);
5021
5224
  rawContentBuffers.delete(msg.id);
5022
5225
  if (msg.streaming !== false) {
@@ -5024,9 +5227,10 @@ var AgentWidgetClient = class {
5024
5227
  emitMessage(msg);
5025
5228
  }
5026
5229
  }
5027
- const splitFinalContent = (_ga = payload.result) == null ? void 0 : _ga.response;
5230
+ const splitFinalContent = (_qa = payload.result) == null ? void 0 : _qa.response;
5028
5231
  const sealedForReconcile = lastSealedTextSegment;
5029
5232
  if (sealedForReconcile) {
5233
+ if (stepStopReason) sealedForReconcile.stopReason = stepStopReason;
5030
5234
  if (splitFinalContent !== void 0 && splitFinalContent !== null) {
5031
5235
  reconcileSealedAssistantWithFinalResponse(sealedForReconcile, splitFinalContent);
5032
5236
  } else {
@@ -5037,8 +5241,9 @@ var AgentWidgetClient = class {
5037
5241
  lastSealedTextSegment = null;
5038
5242
  continue;
5039
5243
  }
5040
- const finalContent = (_ha = payload.result) == null ? void 0 : _ha.response;
5244
+ const finalContent = (_ra = payload.result) == null ? void 0 : _ra.response;
5041
5245
  const assistant = ensureAssistantMessage();
5246
+ if (stepStopReason) assistant.stopReason = stepStopReason;
5042
5247
  if (finalContent !== void 0 && finalContent !== null) {
5043
5248
  const parser = streamParsers.get(assistant.id);
5044
5249
  let hasExtractedText = false;
@@ -5089,7 +5294,7 @@ var AgentWidgetClient = class {
5089
5294
  }
5090
5295
  });
5091
5296
  } else {
5092
- const text = typeof parsedResult === "string" ? parsedResult : (_ia = parsedResult == null ? void 0 : parsedResult.text) != null ? _ia : null;
5297
+ const text = typeof parsedResult === "string" ? parsedResult : (_sa = parsedResult == null ? void 0 : parsedResult.text) != null ? _sa : null;
5093
5298
  if (text !== null && text.trim() !== "") {
5094
5299
  assistant.content = text;
5095
5300
  hasExtractedText = true;
@@ -5113,7 +5318,7 @@ var AgentWidgetClient = class {
5113
5318
  assistant.content = ensureStringContent(finalContent);
5114
5319
  }
5115
5320
  if (parser) {
5116
- const closeResult = (_ja = parser.close) == null ? void 0 : _ja.call(parser);
5321
+ const closeResult = (_ta = parser.close) == null ? void 0 : _ta.call(parser);
5117
5322
  if (closeResult instanceof Promise) {
5118
5323
  closeResult.catch(() => {
5119
5324
  });
@@ -5131,7 +5336,7 @@ var AgentWidgetClient = class {
5131
5336
  emitMessage(assistant);
5132
5337
  }
5133
5338
  } else if (payloadType === "flow_complete") {
5134
- const finalContent = (_ka = payload.result) == null ? void 0 : _ka.response;
5339
+ const finalContent = (_ua = payload.result) == null ? void 0 : _ua.response;
5135
5340
  if (didSplitByPartId) {
5136
5341
  if (assistantMessage !== null) {
5137
5342
  const msg = assistantMessage;
@@ -5198,11 +5403,11 @@ var AgentWidgetClient = class {
5198
5403
  } else if (payloadType === "agent_start") {
5199
5404
  agentExecution = {
5200
5405
  executionId: payload.executionId,
5201
- agentId: (_la = payload.agentId) != null ? _la : "virtual",
5202
- agentName: (_ma = payload.agentName) != null ? _ma : "",
5406
+ agentId: (_va = payload.agentId) != null ? _va : "virtual",
5407
+ agentName: (_wa = payload.agentName) != null ? _wa : "",
5203
5408
  status: "running",
5204
5409
  currentIteration: 0,
5205
- maxTurns: (_na = payload.maxTurns) != null ? _na : 1,
5410
+ maxTurns: (_xa = payload.maxTurns) != null ? _xa : 1,
5206
5411
  startedAt: resolveTimestamp(payload.startedAt)
5207
5412
  };
5208
5413
  } else if (payloadType === "agent_iteration_start") {
@@ -5222,7 +5427,7 @@ var AgentWidgetClient = class {
5222
5427
  } else if (payloadType === "agent_turn_delta") {
5223
5428
  if (payload.contentType === "text") {
5224
5429
  const assistant = ensureAssistantMessage();
5225
- assistant.content += (_oa = payload.delta) != null ? _oa : "";
5430
+ assistant.content += (_ya = payload.delta) != null ? _ya : "";
5226
5431
  assistant.agentMetadata = {
5227
5432
  executionId: payload.executionId,
5228
5433
  iteration: payload.iteration,
@@ -5231,14 +5436,14 @@ var AgentWidgetClient = class {
5231
5436
  };
5232
5437
  emitMessage(assistant);
5233
5438
  } else if (payload.contentType === "thinking") {
5234
- const reasoningId = (_pa = payload.turnId) != null ? _pa : `agent-think-${payload.iteration}`;
5439
+ const reasoningId = (_za = payload.turnId) != null ? _za : `agent-think-${payload.iteration}`;
5235
5440
  const reasoningMessage = ensureReasoningMessage(reasoningId);
5236
- reasoningMessage.reasoning = (_qa = reasoningMessage.reasoning) != null ? _qa : {
5441
+ reasoningMessage.reasoning = (_Aa = reasoningMessage.reasoning) != null ? _Aa : {
5237
5442
  id: reasoningId,
5238
5443
  status: "streaming",
5239
5444
  chunks: []
5240
5445
  };
5241
- reasoningMessage.reasoning.chunks.push((_ra = payload.delta) != null ? _ra : "");
5446
+ reasoningMessage.reasoning.chunks.push((_Ba = payload.delta) != null ? _Ba : "");
5242
5447
  reasoningMessage.agentMetadata = {
5243
5448
  executionId: payload.executionId,
5244
5449
  iteration: payload.iteration,
@@ -5246,12 +5451,12 @@ var AgentWidgetClient = class {
5246
5451
  };
5247
5452
  emitMessage(reasoningMessage);
5248
5453
  } else if (payload.contentType === "tool_input") {
5249
- const toolId = (_sa = payload.toolCallId) != null ? _sa : toolContext.lastId;
5454
+ const toolId = (_Ca = payload.toolCallId) != null ? _Ca : toolContext.lastId;
5250
5455
  if (toolId) {
5251
5456
  const toolMessage = toolMessages.get(toolId);
5252
5457
  if (toolMessage == null ? void 0 : toolMessage.toolCall) {
5253
- toolMessage.toolCall.chunks = (_ta = toolMessage.toolCall.chunks) != null ? _ta : [];
5254
- toolMessage.toolCall.chunks.push((_ua = payload.delta) != null ? _ua : "");
5458
+ toolMessage.toolCall.chunks = (_Da = toolMessage.toolCall.chunks) != null ? _Da : [];
5459
+ toolMessage.toolCall.chunks.push((_Ea = payload.delta) != null ? _Ea : "");
5255
5460
  emitMessage(toolMessage);
5256
5461
  }
5257
5462
  }
@@ -5263,20 +5468,29 @@ var AgentWidgetClient = class {
5263
5468
  if (reasoningMessage == null ? void 0 : reasoningMessage.reasoning) {
5264
5469
  reasoningMessage.reasoning.status = "complete";
5265
5470
  reasoningMessage.reasoning.completedAt = resolveTimestamp(payload.completedAt);
5266
- const start = (_va = reasoningMessage.reasoning.startedAt) != null ? _va : Date.now();
5471
+ const start = (_Fa = reasoningMessage.reasoning.startedAt) != null ? _Fa : Date.now();
5267
5472
  reasoningMessage.reasoning.durationMs = Math.max(
5268
5473
  0,
5269
- ((_wa = reasoningMessage.reasoning.completedAt) != null ? _wa : Date.now()) - start
5474
+ ((_Ga = reasoningMessage.reasoning.completedAt) != null ? _Ga : Date.now()) - start
5270
5475
  );
5271
5476
  reasoningMessage.streaming = false;
5272
5477
  emitMessage(reasoningMessage);
5273
5478
  }
5274
5479
  }
5480
+ const turnStopReason = payload.stopReason;
5481
+ if (turnStopReason && assistantMessage !== null) {
5482
+ const turnId = payload.turnId;
5483
+ const matchesTurn = !turnId || ((_Ha = assistantMessage.agentMetadata) == null ? void 0 : _Ha.turnId) === turnId;
5484
+ if (matchesTurn) {
5485
+ assistantMessage.stopReason = turnStopReason;
5486
+ emitMessage(assistantMessage);
5487
+ }
5488
+ }
5275
5489
  } else if (payloadType === "agent_tool_start") {
5276
- const toolId = (_xa = payload.toolCallId) != null ? _xa : `agent-tool-${nextSequence()}`;
5490
+ const toolId = (_Ia = payload.toolCallId) != null ? _Ia : `agent-tool-${nextSequence()}`;
5277
5491
  trackToolId(getToolCallKey(payload), toolId);
5278
5492
  const toolMessage = ensureToolMessage(toolId);
5279
- const tool = (_ya = toolMessage.toolCall) != null ? _ya : {
5493
+ const tool = (_Ja = toolMessage.toolCall) != null ? _Ja : {
5280
5494
  id: toolId,
5281
5495
  status: "pending",
5282
5496
  name: void 0,
@@ -5288,12 +5502,12 @@ var AgentWidgetClient = class {
5288
5502
  completedAt: void 0,
5289
5503
  durationMs: void 0
5290
5504
  };
5291
- tool.name = (_Aa = (_za = payload.toolName) != null ? _za : payload.name) != null ? _Aa : tool.name;
5505
+ tool.name = (_La = (_Ka = payload.toolName) != null ? _Ka : payload.name) != null ? _La : tool.name;
5292
5506
  tool.status = "running";
5293
5507
  if (payload.parameters !== void 0) {
5294
5508
  tool.args = payload.parameters;
5295
5509
  }
5296
- tool.startedAt = resolveTimestamp((_Ba = payload.startedAt) != null ? _Ba : payload.timestamp);
5510
+ tool.startedAt = resolveTimestamp((_Ma = payload.startedAt) != null ? _Ma : payload.timestamp);
5297
5511
  toolMessage.toolCall = tool;
5298
5512
  toolMessage.streaming = true;
5299
5513
  toolMessage.agentMetadata = {
@@ -5302,21 +5516,21 @@ var AgentWidgetClient = class {
5302
5516
  };
5303
5517
  emitMessage(toolMessage);
5304
5518
  } else if (payloadType === "agent_tool_delta") {
5305
- const toolId = (_Ca = payload.toolCallId) != null ? _Ca : toolContext.lastId;
5519
+ const toolId = (_Na = payload.toolCallId) != null ? _Na : toolContext.lastId;
5306
5520
  if (toolId) {
5307
- const toolMessage = (_Da = toolMessages.get(toolId)) != null ? _Da : ensureToolMessage(toolId);
5521
+ const toolMessage = (_Oa = toolMessages.get(toolId)) != null ? _Oa : ensureToolMessage(toolId);
5308
5522
  if (toolMessage.toolCall) {
5309
- toolMessage.toolCall.chunks = (_Ea = toolMessage.toolCall.chunks) != null ? _Ea : [];
5310
- toolMessage.toolCall.chunks.push((_Fa = payload.delta) != null ? _Fa : "");
5523
+ toolMessage.toolCall.chunks = (_Pa = toolMessage.toolCall.chunks) != null ? _Pa : [];
5524
+ toolMessage.toolCall.chunks.push((_Qa = payload.delta) != null ? _Qa : "");
5311
5525
  toolMessage.toolCall.status = "running";
5312
5526
  toolMessage.streaming = true;
5313
5527
  emitMessage(toolMessage);
5314
5528
  }
5315
5529
  }
5316
5530
  } else if (payloadType === "agent_tool_complete") {
5317
- const toolId = (_Ga = payload.toolCallId) != null ? _Ga : toolContext.lastId;
5531
+ const toolId = (_Ra = payload.toolCallId) != null ? _Ra : toolContext.lastId;
5318
5532
  if (toolId) {
5319
- const toolMessage = (_Ha = toolMessages.get(toolId)) != null ? _Ha : ensureToolMessage(toolId);
5533
+ const toolMessage = (_Sa = toolMessages.get(toolId)) != null ? _Sa : ensureToolMessage(toolId);
5320
5534
  if (toolMessage.toolCall) {
5321
5535
  toolMessage.toolCall.status = "complete";
5322
5536
  if (payload.result !== void 0) {
@@ -5325,7 +5539,7 @@ var AgentWidgetClient = class {
5325
5539
  if (typeof payload.executionTime === "number") {
5326
5540
  toolMessage.toolCall.durationMs = payload.executionTime;
5327
5541
  }
5328
- toolMessage.toolCall.completedAt = resolveTimestamp((_Ia = payload.completedAt) != null ? _Ia : payload.timestamp);
5542
+ toolMessage.toolCall.completedAt = resolveTimestamp((_Ta = payload.completedAt) != null ? _Ta : payload.timestamp);
5329
5543
  toolMessage.streaming = false;
5330
5544
  emitMessage(toolMessage);
5331
5545
  const callKey = getToolCallKey(payload);
@@ -5340,7 +5554,7 @@ var AgentWidgetClient = class {
5340
5554
  const reflectionMessage = {
5341
5555
  id: reflectionId,
5342
5556
  role: "assistant",
5343
- content: (_Ja = payload.reflection) != null ? _Ja : "",
5557
+ content: (_Ua = payload.reflection) != null ? _Ua : "",
5344
5558
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
5345
5559
  streaming: false,
5346
5560
  variant: "reasoning",
@@ -5348,7 +5562,7 @@ var AgentWidgetClient = class {
5348
5562
  reasoning: {
5349
5563
  id: reflectionId,
5350
5564
  status: "complete",
5351
- chunks: [(_Ka = payload.reflection) != null ? _Ka : ""]
5565
+ chunks: [(_Va = payload.reflection) != null ? _Va : ""]
5352
5566
  },
5353
5567
  agentMetadata: {
5354
5568
  executionId: payload.executionId,
@@ -5369,7 +5583,7 @@ var AgentWidgetClient = class {
5369
5583
  }
5370
5584
  onEvent({ type: "status", status: "idle" });
5371
5585
  } else if (payloadType === "agent_error") {
5372
- const errorMessage = typeof payload.error === "string" ? payload.error : (_Ma = (_La = payload.error) == null ? void 0 : _La.message) != null ? _Ma : "Agent execution error";
5586
+ const errorMessage = typeof payload.error === "string" ? payload.error : (_Xa = (_Wa = payload.error) == null ? void 0 : _Wa.message) != null ? _Xa : "Agent execution error";
5373
5587
  if (payload.recoverable) {
5374
5588
  if (typeof console !== "undefined") {
5375
5589
  console.warn("[AgentWidget] Recoverable agent error:", errorMessage);
@@ -5382,7 +5596,7 @@ var AgentWidgetClient = class {
5382
5596
  }
5383
5597
  } else if (payloadType === "agent_ping") {
5384
5598
  } else if (payloadType === "agent_approval_start") {
5385
- const approvalId = (_Na = payload.approvalId) != null ? _Na : `approval-${nextSequence()}`;
5599
+ const approvalId = (_Ya = payload.approvalId) != null ? _Ya : `approval-${nextSequence()}`;
5386
5600
  const approvalMessage = {
5387
5601
  id: `approval-${approvalId}`,
5388
5602
  role: "assistant",
@@ -5394,17 +5608,17 @@ var AgentWidgetClient = class {
5394
5608
  approval: {
5395
5609
  id: approvalId,
5396
5610
  status: "pending",
5397
- agentId: (_Oa = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _Oa : "virtual",
5398
- executionId: (_Qa = (_Pa = payload.executionId) != null ? _Pa : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _Qa : "",
5399
- toolName: (_Ra = payload.toolName) != null ? _Ra : "",
5611
+ agentId: (_Za = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _Za : "virtual",
5612
+ executionId: (_$a = (__a = payload.executionId) != null ? __a : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _$a : "",
5613
+ toolName: (_ab = payload.toolName) != null ? _ab : "",
5400
5614
  toolType: payload.toolType,
5401
- description: (_Ta = payload.description) != null ? _Ta : `Execute ${(_Sa = payload.toolName) != null ? _Sa : "tool"}`,
5615
+ description: (_cb = payload.description) != null ? _cb : `Execute ${(_bb = payload.toolName) != null ? _bb : "tool"}`,
5402
5616
  parameters: payload.parameters
5403
5617
  }
5404
5618
  };
5405
5619
  emitMessage(approvalMessage);
5406
5620
  } else if (payloadType === "step_await" && payload.awaitReason === "approval_required") {
5407
- const approvalId = (_Ua = payload.approvalId) != null ? _Ua : `approval-${nextSequence()}`;
5621
+ const approvalId = (_db = payload.approvalId) != null ? _db : `approval-${nextSequence()}`;
5408
5622
  const approvalMessage = {
5409
5623
  id: `approval-${approvalId}`,
5410
5624
  role: "assistant",
@@ -5416,11 +5630,11 @@ var AgentWidgetClient = class {
5416
5630
  approval: {
5417
5631
  id: approvalId,
5418
5632
  status: "pending",
5419
- agentId: (_Va = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _Va : "virtual",
5420
- executionId: (_Xa = (_Wa = payload.executionId) != null ? _Wa : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _Xa : "",
5421
- toolName: (_Ya = payload.toolName) != null ? _Ya : "",
5633
+ agentId: (_eb = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _eb : "virtual",
5634
+ executionId: (_gb = (_fb = payload.executionId) != null ? _fb : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _gb : "",
5635
+ toolName: (_hb = payload.toolName) != null ? _hb : "",
5422
5636
  toolType: payload.toolType,
5423
- description: (__a = payload.description) != null ? __a : `Execute ${(_Za = payload.toolName) != null ? _Za : "tool"}`,
5637
+ description: (_jb = payload.description) != null ? _jb : `Execute ${(_ib = payload.toolName) != null ? _ib : "tool"}`,
5424
5638
  parameters: payload.parameters
5425
5639
  }
5426
5640
  };
@@ -5439,11 +5653,11 @@ var AgentWidgetClient = class {
5439
5653
  sequence: nextSequence(),
5440
5654
  approval: {
5441
5655
  id: approvalId,
5442
- status: (_$a = payload.decision) != null ? _$a : "approved",
5443
- agentId: (_ab = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _ab : "virtual",
5444
- executionId: (_cb = (_bb = payload.executionId) != null ? _bb : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _cb : "",
5445
- toolName: (_db = payload.toolName) != null ? _db : "",
5446
- description: (_eb = payload.description) != null ? _eb : "",
5656
+ status: (_kb = payload.decision) != null ? _kb : "approved",
5657
+ agentId: (_lb = agentExecution == null ? void 0 : agentExecution.agentId) != null ? _lb : "virtual",
5658
+ executionId: (_nb = (_mb = payload.executionId) != null ? _mb : agentExecution == null ? void 0 : agentExecution.executionId) != null ? _nb : "",
5659
+ toolName: (_ob = payload.toolName) != null ? _ob : "",
5660
+ description: (_pb = payload.description) != null ? _pb : "",
5447
5661
  resolvedAt: Date.now()
5448
5662
  }
5449
5663
  };
@@ -5481,7 +5695,7 @@ var AgentWidgetClient = class {
5481
5695
  }
5482
5696
  } else if (payloadType === "artifact_delta") {
5483
5697
  const deltaId = String(payload.id);
5484
- const deltaText = typeof payload.delta === "string" ? payload.delta : String((_fb = payload.delta) != null ? _fb : "");
5698
+ const deltaText = typeof payload.delta === "string" ? payload.delta : String((_qb = payload.delta) != null ? _qb : "");
5485
5699
  onEvent({
5486
5700
  type: "artifact_delta",
5487
5701
  id: deltaId,
@@ -5504,7 +5718,7 @@ var AgentWidgetClient = class {
5504
5718
  if (refMsg) {
5505
5719
  refMsg.streaming = false;
5506
5720
  try {
5507
- const parsed = JSON.parse((_gb = refMsg.rawContent) != null ? _gb : "{}");
5721
+ const parsed = JSON.parse((_rb = refMsg.rawContent) != null ? _rb : "{}");
5508
5722
  if (parsed.props) {
5509
5723
  parsed.props.status = "complete";
5510
5724
  const acc = artifactContent.get(artCompleteId);
@@ -5525,7 +5739,7 @@ var AgentWidgetClient = class {
5525
5739
  if (!m || typeof m !== "object") {
5526
5740
  continue;
5527
5741
  }
5528
- const id = String((_hb = m.id) != null ? _hb : `msg-${nextSequence()}`);
5742
+ const id = String((_sb = m.id) != null ? _sb : `msg-${nextSequence()}`);
5529
5743
  const roleRaw = m.role;
5530
5744
  const role = roleRaw === "user" ? "user" : roleRaw === "system" ? "system" : "assistant";
5531
5745
  const msg = {
@@ -5544,7 +5758,7 @@ var AgentWidgetClient = class {
5544
5758
  if (msg.rawContent) {
5545
5759
  try {
5546
5760
  const parsed = JSON.parse(msg.rawContent);
5547
- const refArtId = (_ib = parsed == null ? void 0 : parsed.props) == null ? void 0 : _ib.artifactId;
5761
+ const refArtId = (_tb = parsed == null ? void 0 : parsed.props) == null ? void 0 : _tb.artifactId;
5548
5762
  if (typeof refArtId === "string") {
5549
5763
  artifactIdsWithCards.add(refArtId);
5550
5764
  }
@@ -5560,7 +5774,7 @@ var AgentWidgetClient = class {
5560
5774
  if (payload.error instanceof Error) {
5561
5775
  resolvedError = payload.error;
5562
5776
  } else if (payloadType === "dispatch_error") {
5563
- const msg = (_jb = payload.message) != null ? _jb : payload.error;
5777
+ const msg = (_ub = payload.message) != null ? _ub : payload.error;
5564
5778
  if (msg != null && msg !== "") {
5565
5779
  resolvedError = new Error(String(msg));
5566
5780
  }
@@ -5569,7 +5783,7 @@ var AgentWidgetClient = class {
5569
5783
  if (typeof e === "string" && e !== "") {
5570
5784
  resolvedError = new Error(e);
5571
5785
  } else if (e != null && typeof e === "object" && "message" in e) {
5572
- resolvedError = new Error(String((_kb = e.message) != null ? _kb : e));
5786
+ resolvedError = new Error(String((_vb = e.message) != null ? _vb : e));
5573
5787
  }
5574
5788
  } else if (payloadType === "error" && payload.error != null && payload.error !== "") {
5575
5789
  resolvedError = new Error(String(payload.error));
@@ -7414,6 +7628,8 @@ var AgentWidgetSession = class _AgentWidgetSession {
7414
7628
  var _a;
7415
7629
  (_a = this.abortController) == null ? void 0 : _a.abort();
7416
7630
  this.abortController = null;
7631
+ this.stopSpeaking();
7632
+ this.stopVoicePlayback();
7417
7633
  this.setStreaming(false);
7418
7634
  this.setStatus("idle");
7419
7635
  }
@@ -8046,6 +8262,9 @@ var morphMessages = (container, newContent, options = {}) => {
8046
8262
  if (oldNode.classList.contains("persona-animate-typing")) {
8047
8263
  return false;
8048
8264
  }
8265
+ if (oldNode.hasAttribute("data-preserve-runtime")) {
8266
+ return false;
8267
+ }
8049
8268
  if (oldNode.hasAttribute("data-preserve-animation")) {
8050
8269
  if (newNode instanceof HTMLElement && !newNode.hasAttribute("data-preserve-animation")) {
8051
8270
  return;
@@ -8067,7 +8286,7 @@ var morphMessages = (container, newContent, options = {}) => {
8067
8286
 
8068
8287
  // src/utils/message-fingerprint.ts
8069
8288
  function computeMessageFingerprint(message, configVersion) {
8070
- 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;
8289
+ 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;
8071
8290
  return [
8072
8291
  message.id,
8073
8292
  message.role,
@@ -8085,6 +8304,7 @@ function computeMessageFingerprint(message, configVersion) {
8085
8304
  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,
8086
8305
  (_A = (_z = (_y = message.reasoning) == null ? void 0 : _y.chunks) == null ? void 0 : _z.length) != null ? _A : 0,
8087
8306
  (_C = (_B = message.contentParts) == null ? void 0 : _B.length) != null ? _C : 0,
8307
+ (_D = message.stopReason) != null ? _D : "",
8088
8308
  configVersion
8089
8309
  ].join("\0");
8090
8310
  }
@@ -8185,6 +8405,241 @@ var statusCopy = {
8185
8405
  var DEFAULT_OVERLAY_Z_INDEX = 1e5;
8186
8406
  var PORTALED_OVERLAY_Z_INDEX = DEFAULT_OVERLAY_Z_INDEX + 1;
8187
8407
 
8408
+ // src/utils/stream-animation.ts
8409
+ var DEFAULT_STREAM_ANIMATION = {
8410
+ type: "none",
8411
+ placeholder: "none",
8412
+ speed: 120,
8413
+ duration: 1800,
8414
+ buffer: "none"
8415
+ };
8416
+ var DEFAULT_SKIP_TAGS = ["pre", "code", "a", "script", "style"];
8417
+ var resolveStreamAnimation = (feature) => {
8418
+ var _a, _b, _c, _d, _e;
8419
+ return {
8420
+ type: (_a = feature == null ? void 0 : feature.type) != null ? _a : DEFAULT_STREAM_ANIMATION.type,
8421
+ placeholder: (_b = feature == null ? void 0 : feature.placeholder) != null ? _b : DEFAULT_STREAM_ANIMATION.placeholder,
8422
+ speed: (_c = feature == null ? void 0 : feature.speed) != null ? _c : DEFAULT_STREAM_ANIMATION.speed,
8423
+ duration: (_d = feature == null ? void 0 : feature.duration) != null ? _d : DEFAULT_STREAM_ANIMATION.duration,
8424
+ buffer: (_e = feature == null ? void 0 : feature.buffer) != null ? _e : DEFAULT_STREAM_ANIMATION.buffer
8425
+ };
8426
+ };
8427
+ var BUILTIN_PLUGINS = [
8428
+ {
8429
+ name: "typewriter",
8430
+ containerClass: "persona-stream-typewriter",
8431
+ wrap: "char",
8432
+ useCaret: true
8433
+ },
8434
+ {
8435
+ name: "pop-bubble",
8436
+ bubbleClass: "persona-stream-pop",
8437
+ wrap: "none"
8438
+ },
8439
+ {
8440
+ name: "letter-rise",
8441
+ containerClass: "persona-stream-letter-rise",
8442
+ wrap: "char"
8443
+ },
8444
+ {
8445
+ name: "word-fade",
8446
+ containerClass: "persona-stream-word-fade",
8447
+ wrap: "word"
8448
+ }
8449
+ ];
8450
+ var globalRegistry = /* @__PURE__ */ new Map();
8451
+ for (const plugin of BUILTIN_PLUGINS) globalRegistry.set(plugin.name, plugin);
8452
+ var resolveStreamAnimationPlugin = (type, overrides) => {
8453
+ var _a, _b;
8454
+ if (type === "none") return null;
8455
+ if (overrides && Object.prototype.hasOwnProperty.call(overrides, type)) {
8456
+ return (_a = overrides[type]) != null ? _a : null;
8457
+ }
8458
+ return (_b = globalRegistry.get(type)) != null ? _b : null;
8459
+ };
8460
+ var applyStreamBuffer = (content, buffer, plugin, message, streaming) => {
8461
+ if (!streaming) return content;
8462
+ if (plugin == null ? void 0 : plugin.bufferContent) return plugin.bufferContent(content, message);
8463
+ if (!content) return content;
8464
+ if (buffer === "word") {
8465
+ const lastSpace = content.search(/\s(?=\S*$)/);
8466
+ if (lastSpace < 0) return "";
8467
+ return content.slice(0, lastSpace);
8468
+ }
8469
+ if (buffer === "line") {
8470
+ const lastNewline = content.lastIndexOf("\n");
8471
+ if (lastNewline < 0) return "";
8472
+ return content.slice(0, lastNewline);
8473
+ }
8474
+ return content;
8475
+ };
8476
+ var makeCharSpan = (doc, ch, messageId, index) => {
8477
+ const span = doc.createElement("span");
8478
+ span.className = "persona-stream-char";
8479
+ span.id = `stream-c-${messageId}-${index}`;
8480
+ span.style.setProperty("--char-index", String(index));
8481
+ span.textContent = ch;
8482
+ return span;
8483
+ };
8484
+ var makeWordSpan = (doc, word, messageId, index) => {
8485
+ const span = doc.createElement("span");
8486
+ span.className = "persona-stream-word";
8487
+ span.id = `stream-w-${messageId}-${index}`;
8488
+ span.style.setProperty("--word-index", String(index));
8489
+ span.textContent = word;
8490
+ return span;
8491
+ };
8492
+ var WHITESPACE_RE = /\s/;
8493
+ var shouldSkipSubtree = (node, skipTags) => {
8494
+ let current = node.parentNode;
8495
+ while (current) {
8496
+ if (current.nodeType === 1) {
8497
+ const el = current;
8498
+ if (skipTags.has(el.tagName.toLowerCase())) return true;
8499
+ }
8500
+ current = current.parentNode;
8501
+ }
8502
+ return false;
8503
+ };
8504
+ var wrapTextNodeChars = (textNode, messageId, counterRef) => {
8505
+ var _a;
8506
+ const doc = textNode.ownerDocument;
8507
+ const parent = textNode.parentNode;
8508
+ if (!doc || !parent) return;
8509
+ const text = (_a = textNode.nodeValue) != null ? _a : "";
8510
+ if (!text) return;
8511
+ const fragment = doc.createDocumentFragment();
8512
+ let i = 0;
8513
+ while (i < text.length) {
8514
+ if (WHITESPACE_RE.test(text[i])) {
8515
+ let j = i;
8516
+ while (j < text.length && WHITESPACE_RE.test(text[j])) j += 1;
8517
+ fragment.appendChild(doc.createTextNode(text.slice(i, j)));
8518
+ i = j;
8519
+ } else {
8520
+ const group = doc.createElement("span");
8521
+ group.className = "persona-stream-word-group";
8522
+ let j = i;
8523
+ while (j < text.length && !WHITESPACE_RE.test(text[j])) {
8524
+ group.appendChild(makeCharSpan(doc, text[j], messageId, counterRef.value));
8525
+ counterRef.value += 1;
8526
+ j += 1;
8527
+ }
8528
+ fragment.appendChild(group);
8529
+ i = j;
8530
+ }
8531
+ }
8532
+ parent.replaceChild(fragment, textNode);
8533
+ };
8534
+ var wrapTextNodeWords = (textNode, messageId, counterRef) => {
8535
+ var _a;
8536
+ const doc = textNode.ownerDocument;
8537
+ const parent = textNode.parentNode;
8538
+ if (!doc || !parent) return;
8539
+ const text = (_a = textNode.nodeValue) != null ? _a : "";
8540
+ if (!text) return;
8541
+ const fragment = doc.createDocumentFragment();
8542
+ const tokens = text.split(/(\s+)/);
8543
+ for (const token of tokens) {
8544
+ if (!token) continue;
8545
+ if (/^\s+$/.test(token)) {
8546
+ fragment.appendChild(doc.createTextNode(token));
8547
+ } else {
8548
+ fragment.appendChild(makeWordSpan(doc, token, messageId, counterRef.value));
8549
+ counterRef.value += 1;
8550
+ }
8551
+ }
8552
+ parent.replaceChild(fragment, textNode);
8553
+ };
8554
+ var wrapStreamAnimation = (html, mode, messageId, options) => {
8555
+ var _a;
8556
+ if (!html) return html;
8557
+ if (typeof document === "undefined") return html;
8558
+ const scratch = document.createElement("div");
8559
+ scratch.innerHTML = html;
8560
+ const skipTags = new Set(((_a = options == null ? void 0 : options.skipTags) != null ? _a : DEFAULT_SKIP_TAGS).map((t) => t.toLowerCase()));
8561
+ const walker = document.createTreeWalker(scratch, NodeFilter.SHOW_TEXT, null);
8562
+ const textNodes = [];
8563
+ let node = walker.nextNode();
8564
+ while (node) {
8565
+ if (!shouldSkipSubtree(node, skipTags)) {
8566
+ textNodes.push(node);
8567
+ }
8568
+ node = walker.nextNode();
8569
+ }
8570
+ const counterRef = { value: 0 };
8571
+ const wrap = mode === "char" ? wrapTextNodeChars : wrapTextNodeWords;
8572
+ for (const textNode of textNodes) {
8573
+ wrap(textNode, messageId, counterRef);
8574
+ }
8575
+ return scratch.innerHTML;
8576
+ };
8577
+ var createStreamCaret = (doc = document) => {
8578
+ const caret = doc.createElement("span");
8579
+ caret.className = "persona-stream-caret";
8580
+ caret.setAttribute("aria-hidden", "true");
8581
+ caret.setAttribute("data-preserve-animation", "stream-caret");
8582
+ return caret;
8583
+ };
8584
+ var createSkeletonPlaceholder = (doc = document) => {
8585
+ const wrapper = doc.createElement("div");
8586
+ wrapper.className = "persona-stream-skeleton";
8587
+ wrapper.setAttribute("data-preserve-animation", "stream-skeleton");
8588
+ wrapper.setAttribute("aria-hidden", "true");
8589
+ const line = doc.createElement("div");
8590
+ line.className = "persona-stream-skeleton-line";
8591
+ wrapper.appendChild(line);
8592
+ return wrapper;
8593
+ };
8594
+ var injectedStyleRoots = /* @__PURE__ */ new WeakMap();
8595
+ var injectPluginStyles = (plugin, root) => {
8596
+ var _a;
8597
+ if (!plugin.styles) return;
8598
+ let names = injectedStyleRoots.get(root);
8599
+ if (!names) {
8600
+ names = /* @__PURE__ */ new Set();
8601
+ injectedStyleRoots.set(root, names);
8602
+ }
8603
+ if (names.has(plugin.name)) {
8604
+ const escaped = plugin.name.replace(/["\\]/g, "\\$&");
8605
+ const existing = root.querySelector(
8606
+ `style[data-persona-animation="${escaped}"]`
8607
+ );
8608
+ if (existing) return;
8609
+ names.delete(plugin.name);
8610
+ }
8611
+ names.add(plugin.name);
8612
+ const doc = root instanceof ShadowRoot ? root.ownerDocument : (_a = root.ownerDocument) != null ? _a : document;
8613
+ const style = doc.createElement("style");
8614
+ style.setAttribute("data-persona-animation", plugin.name);
8615
+ style.textContent = plugin.styles;
8616
+ root.appendChild(style);
8617
+ };
8618
+ var attachedCleanups = /* @__PURE__ */ new WeakMap();
8619
+ var attachPlugin = (plugin, root) => {
8620
+ if (!plugin.onAttach) return;
8621
+ let cleanups = attachedCleanups.get(root);
8622
+ if (!cleanups) {
8623
+ cleanups = /* @__PURE__ */ new Map();
8624
+ attachedCleanups.set(root, cleanups);
8625
+ }
8626
+ if (cleanups.has(plugin.name)) return;
8627
+ const cleanup = plugin.onAttach(root);
8628
+ cleanups.set(plugin.name, cleanup);
8629
+ };
8630
+ var detachAllPlugins = (root) => {
8631
+ const cleanups = attachedCleanups.get(root);
8632
+ if (!cleanups) return;
8633
+ for (const cleanup of cleanups.values()) {
8634
+ if (typeof cleanup === "function") cleanup();
8635
+ }
8636
+ cleanups.clear();
8637
+ };
8638
+ var ensurePluginActive = (plugin, root) => {
8639
+ injectPluginStyles(plugin, root);
8640
+ attachPlugin(plugin, root);
8641
+ };
8642
+
8188
8643
  // src/utils/overlay-host-stacking.ts
8189
8644
  function syncOverlayHostStacking(host, zIndex = DEFAULT_OVERLAY_Z_INDEX) {
8190
8645
  const originalPosition = host.style.position;
@@ -8545,6 +9000,7 @@ var buildHeader = (context) => {
8545
9000
  clearChatButton.style.color = clearChatIconColor || HEADER_THEME_CSS.actionIconColor;
8546
9001
  const iconSvg = renderLucideIcon(clearChatIconName, "20px", "currentColor", 1);
8547
9002
  if (iconSvg) {
9003
+ iconSvg.style.display = "block";
8548
9004
  clearChatButton.appendChild(iconSvg);
8549
9005
  }
8550
9006
  if (clearChatBgColor) {
@@ -8628,7 +9084,7 @@ var buildHeader = (context) => {
8628
9084
  }
8629
9085
  const closeButtonWrapper = createElement(
8630
9086
  "div",
8631
- closeButtonPlacement === "top-right" ? "persona-absolute persona-top-4 persona-right-4 persona-z-50" : clearChatEnabled && clearChatPlacement === "inline" ? "" : "persona-ml-auto"
9087
+ 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"
8632
9088
  );
8633
9089
  const closeButton = createElement(
8634
9090
  "button",
@@ -8644,8 +9100,9 @@ var buildHeader = (context) => {
8644
9100
  const closeButtonIconName = (_E = launcher.closeButtonIconName) != null ? _E : "x";
8645
9101
  const closeButtonIconText = (_F = launcher.closeButtonIconText) != null ? _F : "\xD7";
8646
9102
  closeButton.style.color = launcher.closeButtonColor || HEADER_THEME_CSS.actionIconColor;
8647
- const closeIconSvg = renderLucideIcon(closeButtonIconName, "20px", "currentColor", 1);
9103
+ const closeIconSvg = renderLucideIcon(closeButtonIconName, "28px", "currentColor", 1);
8648
9104
  if (closeIconSvg) {
9105
+ closeIconSvg.style.display = "block";
8649
9106
  closeButton.appendChild(closeIconSvg);
8650
9107
  } else {
8651
9108
  closeButton.textContent = closeButtonIconText;
@@ -9173,7 +9630,7 @@ var buildMinimalHeader = (context) => {
9173
9630
  closeButton.style.display = showClose ? "" : "none";
9174
9631
  closeButton.style.color = launcher.closeButtonColor || HEADER_THEME_CSS.actionIconColor;
9175
9632
  const closeButtonIconName = (_i = launcher.closeButtonIconName) != null ? _i : "x";
9176
- const closeIconSvg = renderLucideIcon(closeButtonIconName, "20px", "currentColor", 2);
9633
+ const closeIconSvg = renderLucideIcon(closeButtonIconName, "28px", "currentColor", 1);
9177
9634
  if (closeIconSvg) {
9178
9635
  closeButton.appendChild(closeIconSvg);
9179
9636
  } else {
@@ -9268,7 +9725,7 @@ var buildHeaderWithLayout = (config, layoutConfig, context) => {
9268
9725
 
9269
9726
  // src/components/composer-builder.ts
9270
9727
  var buildComposer = (context) => {
9271
- 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;
9728
+ 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;
9272
9729
  const { config } = context;
9273
9730
  const footer = createElement(
9274
9731
  "div",
@@ -9324,9 +9781,13 @@ var buildComposer = (context) => {
9324
9781
  const useIcon = (_d = sendButtonConfig.useIcon) != null ? _d : false;
9325
9782
  const iconText = (_e = sendButtonConfig.iconText) != null ? _e : "\u2191";
9326
9783
  const iconName = sendButtonConfig.iconName;
9327
- const tooltipText = (_f = sendButtonConfig.tooltipText) != null ? _f : "Send message";
9328
- const showTooltip = (_g = sendButtonConfig.showTooltip) != null ? _g : false;
9329
- const buttonSize = (_h = sendButtonConfig.size) != null ? _h : "40px";
9784
+ const stopIconName = (_f = sendButtonConfig.stopIconName) != null ? _f : "square";
9785
+ const tooltipText = (_g = sendButtonConfig.tooltipText) != null ? _g : "Send message";
9786
+ const stopTooltipText = (_h = sendButtonConfig.stopTooltipText) != null ? _h : "Stop generating";
9787
+ const sendLabel = (_j = (_i = config == null ? void 0 : config.copy) == null ? void 0 : _i.sendButtonLabel) != null ? _j : "Send";
9788
+ const stopLabel = (_l = (_k = config == null ? void 0 : config.copy) == null ? void 0 : _k.stopButtonLabel) != null ? _l : "Stop";
9789
+ const showTooltip = (_m = sendButtonConfig.showTooltip) != null ? _m : false;
9790
+ const buttonSize = (_n = sendButtonConfig.size) != null ? _n : "40px";
9330
9791
  const backgroundColor = sendButtonConfig.backgroundColor;
9331
9792
  const textColor = sendButtonConfig.textColor;
9332
9793
  const sendButtonWrapper = createElement("div", "persona-send-button-wrapper");
@@ -9336,6 +9797,8 @@ var buildComposer = (context) => {
9336
9797
  );
9337
9798
  sendButton.type = "submit";
9338
9799
  sendButton.setAttribute("data-persona-composer-submit", "");
9800
+ let sendIcon = null;
9801
+ let stopIcon = null;
9339
9802
  if (useIcon) {
9340
9803
  sendButton.style.width = buttonSize;
9341
9804
  sendButton.style.height = buttonSize;
@@ -9349,25 +9812,26 @@ var buildComposer = (context) => {
9349
9812
  } else {
9350
9813
  sendButton.style.color = "var(--persona-button-primary-fg, #ffffff)";
9351
9814
  }
9815
+ const iconSize = parseFloat(buttonSize) || 24;
9816
+ const iconColor = (textColor == null ? void 0 : textColor.trim()) || "currentColor";
9352
9817
  if (iconName) {
9353
- const iconSize = parseFloat(buttonSize) || 24;
9354
- const iconColor = (textColor == null ? void 0 : textColor.trim()) || "currentColor";
9355
- const iconSvg = renderLucideIcon(iconName, iconSize, iconColor, 2);
9356
- if (iconSvg) {
9357
- sendButton.appendChild(iconSvg);
9818
+ sendIcon = renderLucideIcon(iconName, iconSize, iconColor, 2);
9819
+ if (sendIcon) {
9820
+ sendButton.appendChild(sendIcon);
9358
9821
  } else {
9359
9822
  sendButton.textContent = iconText;
9360
9823
  }
9361
9824
  } else {
9362
9825
  sendButton.textContent = iconText;
9363
9826
  }
9827
+ stopIcon = renderLucideIcon(stopIconName, iconSize, iconColor, 2);
9364
9828
  if (backgroundColor) {
9365
9829
  sendButton.style.backgroundColor = backgroundColor;
9366
9830
  } else {
9367
9831
  sendButton.classList.add("persona-bg-persona-primary");
9368
9832
  }
9369
9833
  } else {
9370
- sendButton.textContent = (_j = (_i = config == null ? void 0 : config.copy) == null ? void 0 : _i.sendButtonLabel) != null ? _j : "Send";
9834
+ sendButton.textContent = sendLabel;
9371
9835
  if (textColor) {
9372
9836
  sendButton.style.color = textColor;
9373
9837
  } else {
@@ -9395,18 +9859,43 @@ var buildComposer = (context) => {
9395
9859
  sendButton.style.paddingTop = "";
9396
9860
  sendButton.style.paddingBottom = "";
9397
9861
  }
9862
+ let sendTooltip = null;
9398
9863
  if (showTooltip && tooltipText) {
9399
- const tooltip = createElement("div", "persona-send-button-tooltip");
9400
- tooltip.textContent = tooltipText;
9401
- sendButtonWrapper.appendChild(tooltip);
9864
+ sendTooltip = createElement("div", "persona-send-button-tooltip");
9865
+ sendTooltip.textContent = tooltipText;
9866
+ sendButtonWrapper.appendChild(sendTooltip);
9402
9867
  }
9868
+ sendButton.setAttribute("aria-label", tooltipText);
9403
9869
  sendButtonWrapper.appendChild(sendButton);
9404
- const voiceRecognitionConfig = (_k = config == null ? void 0 : config.voiceRecognition) != null ? _k : {};
9870
+ let currentMode = "send";
9871
+ const setSendButtonMode = (mode) => {
9872
+ if (mode === currentMode) return;
9873
+ currentMode = mode;
9874
+ const label = mode === "stop" ? stopTooltipText : tooltipText;
9875
+ sendButton.setAttribute("aria-label", label);
9876
+ if (sendTooltip) {
9877
+ sendTooltip.textContent = label;
9878
+ }
9879
+ if (useIcon) {
9880
+ if (sendIcon && stopIcon) {
9881
+ const next = mode === "stop" ? stopIcon : sendIcon;
9882
+ const prev = mode === "stop" ? sendIcon : stopIcon;
9883
+ if (prev.parentNode === sendButton) {
9884
+ sendButton.replaceChild(next, prev);
9885
+ } else {
9886
+ sendButton.appendChild(next);
9887
+ }
9888
+ }
9889
+ } else {
9890
+ sendButton.textContent = mode === "stop" ? stopLabel : sendLabel;
9891
+ }
9892
+ };
9893
+ const voiceRecognitionConfig = (_o = config == null ? void 0 : config.voiceRecognition) != null ? _o : {};
9405
9894
  const voiceRecognitionEnabled = voiceRecognitionConfig.enabled === true;
9406
9895
  let micButton = null;
9407
9896
  let micButtonWrapper = null;
9408
9897
  const hasSpeechRecognition = typeof window !== "undefined" && (typeof window.webkitSpeechRecognition !== "undefined" || typeof window.SpeechRecognition !== "undefined");
9409
- const hasRuntypeProvider = ((_l = voiceRecognitionConfig.provider) == null ? void 0 : _l.type) === "runtype";
9898
+ const hasRuntypeProvider = ((_p = voiceRecognitionConfig.provider) == null ? void 0 : _p.type) === "runtype";
9410
9899
  const hasVoiceInput = hasSpeechRecognition || hasRuntypeProvider;
9411
9900
  if (voiceRecognitionEnabled && hasVoiceInput) {
9412
9901
  micButtonWrapper = createElement("div", "persona-send-button-wrapper");
@@ -9417,11 +9906,11 @@ var buildComposer = (context) => {
9417
9906
  micButton.type = "button";
9418
9907
  micButton.setAttribute("data-persona-composer-mic", "");
9419
9908
  micButton.setAttribute("aria-label", "Start voice recognition");
9420
- const micIconName = (_m = voiceRecognitionConfig.iconName) != null ? _m : "mic";
9421
- const micIconSize = (_n = voiceRecognitionConfig.iconSize) != null ? _n : buttonSize;
9909
+ const micIconName = (_q = voiceRecognitionConfig.iconName) != null ? _q : "mic";
9910
+ const micIconSize = (_r = voiceRecognitionConfig.iconSize) != null ? _r : buttonSize;
9422
9911
  const micIconSizeNum = parseFloat(micIconSize) || 24;
9423
- const micBackgroundColor = (_o = voiceRecognitionConfig.backgroundColor) != null ? _o : backgroundColor;
9424
- const micIconColor = (_p = voiceRecognitionConfig.iconColor) != null ? _p : textColor;
9912
+ const micBackgroundColor = (_s = voiceRecognitionConfig.backgroundColor) != null ? _s : backgroundColor;
9913
+ const micIconColor = (_t = voiceRecognitionConfig.iconColor) != null ? _t : textColor;
9425
9914
  micButton.style.width = micIconSize;
9426
9915
  micButton.style.height = micIconSize;
9427
9916
  micButton.style.minWidth = micIconSize;
@@ -9464,15 +9953,15 @@ var buildComposer = (context) => {
9464
9953
  micButton.style.paddingBottom = voiceRecognitionConfig.paddingY;
9465
9954
  }
9466
9955
  micButtonWrapper.appendChild(micButton);
9467
- const micTooltipText = (_q = voiceRecognitionConfig.tooltipText) != null ? _q : "Start voice recognition";
9468
- const showMicTooltip = (_r = voiceRecognitionConfig.showTooltip) != null ? _r : false;
9956
+ const micTooltipText = (_u = voiceRecognitionConfig.tooltipText) != null ? _u : "Start voice recognition";
9957
+ const showMicTooltip = (_v = voiceRecognitionConfig.showTooltip) != null ? _v : false;
9469
9958
  if (showMicTooltip && micTooltipText) {
9470
9959
  const tooltip = createElement("div", "persona-send-button-tooltip");
9471
9960
  tooltip.textContent = micTooltipText;
9472
9961
  micButtonWrapper.appendChild(tooltip);
9473
9962
  }
9474
9963
  }
9475
- const attachmentsConfig = (_s = config == null ? void 0 : config.attachments) != null ? _s : {};
9964
+ const attachmentsConfig = (_w = config == null ? void 0 : config.attachments) != null ? _w : {};
9476
9965
  const attachmentsEnabled = attachmentsConfig.enabled === true;
9477
9966
  let attachmentButton = null;
9478
9967
  let attachmentButtonWrapper = null;
@@ -9486,8 +9975,8 @@ var buildComposer = (context) => {
9486
9975
  attachmentPreviewsContainer.style.display = "none";
9487
9976
  attachmentInput = createElement("input");
9488
9977
  attachmentInput.type = "file";
9489
- attachmentInput.accept = ((_t = attachmentsConfig.allowedTypes) != null ? _t : ALL_SUPPORTED_MIME_TYPES).join(",");
9490
- attachmentInput.multiple = ((_u = attachmentsConfig.maxFiles) != null ? _u : 4) > 1;
9978
+ attachmentInput.accept = ((_x = attachmentsConfig.allowedTypes) != null ? _x : ALL_SUPPORTED_MIME_TYPES).join(",");
9979
+ attachmentInput.multiple = ((_y = attachmentsConfig.maxFiles) != null ? _y : 4) > 1;
9491
9980
  attachmentInput.style.display = "none";
9492
9981
  attachmentInput.setAttribute("aria-label", "Attach files");
9493
9982
  attachmentButtonWrapper = createElement("div", "persona-send-button-wrapper");
@@ -9496,8 +9985,8 @@ var buildComposer = (context) => {
9496
9985
  "persona-rounded-button persona-flex persona-items-center persona-justify-center disabled:persona-opacity-50 persona-cursor-pointer persona-attachment-button"
9497
9986
  );
9498
9987
  attachmentButton.type = "button";
9499
- attachmentButton.setAttribute("aria-label", (_v = attachmentsConfig.buttonTooltipText) != null ? _v : "Attach file");
9500
- const attachIconName = (_w = attachmentsConfig.buttonIconName) != null ? _w : "paperclip";
9988
+ attachmentButton.setAttribute("aria-label", (_z = attachmentsConfig.buttonTooltipText) != null ? _z : "Attach file");
9989
+ const attachIconName = (_A = attachmentsConfig.buttonIconName) != null ? _A : "paperclip";
9501
9990
  const attachIconSize = buttonSize;
9502
9991
  const buttonSizeNum = parseFloat(attachIconSize) || 40;
9503
9992
  const attachIconSizeNum = Math.round(buttonSizeNum * 0.6);
@@ -9534,7 +10023,7 @@ var buildComposer = (context) => {
9534
10023
  attachmentInput == null ? void 0 : attachmentInput.click();
9535
10024
  });
9536
10025
  attachmentButtonWrapper.appendChild(attachmentButton);
9537
- const attachTooltipText = (_x = attachmentsConfig.buttonTooltipText) != null ? _x : "Attach file";
10026
+ const attachTooltipText = (_B = attachmentsConfig.buttonTooltipText) != null ? _B : "Attach file";
9538
10027
  const tooltip = createElement("div", "persona-send-button-tooltip");
9539
10028
  tooltip.textContent = attachTooltipText;
9540
10029
  attachmentButtonWrapper.appendChild(tooltip);
@@ -9564,16 +10053,16 @@ var buildComposer = (context) => {
9564
10053
  rightActions.append(sendButtonWrapper);
9565
10054
  actionsRow.append(leftActions, rightActions);
9566
10055
  composerForm.append(actionsRow);
9567
- const statusConfig = (_y = config == null ? void 0 : config.statusIndicator) != null ? _y : {};
10056
+ const statusConfig = (_C = config == null ? void 0 : config.statusIndicator) != null ? _C : {};
9568
10057
  const alignClass = statusConfig.align === "left" ? "persona-text-left" : statusConfig.align === "center" ? "persona-text-center" : "persona-text-right";
9569
10058
  const statusText = createElement(
9570
10059
  "div",
9571
10060
  `persona-mt-2 ${alignClass} persona-text-xs persona-text-persona-muted`
9572
10061
  );
9573
10062
  statusText.setAttribute("data-persona-composer-status", "");
9574
- const isVisible = (_z = statusConfig.visible) != null ? _z : true;
10063
+ const isVisible = (_D = statusConfig.visible) != null ? _D : true;
9575
10064
  statusText.style.display = isVisible ? "" : "none";
9576
- const idleLabel = (_A = statusConfig.idleText) != null ? _A : "Online";
10065
+ const idleLabel = (_E = statusConfig.idleText) != null ? _E : "Online";
9577
10066
  if (statusConfig.idleLink) {
9578
10067
  const link = createElement("a");
9579
10068
  link.href = statusConfig.idleLink;
@@ -9605,7 +10094,8 @@ var buildComposer = (context) => {
9605
10094
  // Actions row layout elements
9606
10095
  actionsRow,
9607
10096
  leftActions,
9608
- rightActions
10097
+ rightActions,
10098
+ setSendButtonMode
9609
10099
  };
9610
10100
  };
9611
10101
 
@@ -9753,11 +10243,48 @@ var buildPanel = (config, showClose = true) => {
9753
10243
  // Actions row layout elements
9754
10244
  actionsRow: composerElements.actionsRow,
9755
10245
  leftActions: composerElements.leftActions,
9756
- rightActions: composerElements.rightActions
10246
+ rightActions: composerElements.rightActions,
10247
+ setSendButtonMode: composerElements.setSendButtonMode
9757
10248
  };
9758
10249
  };
9759
10250
 
9760
10251
  // src/components/message-bubble.ts
10252
+ var getDefaultStopReasonNoticeCopy = (stopReason) => {
10253
+ switch (stopReason) {
10254
+ case "max_tool_calls":
10255
+ return "Stopped after calling a tool. Send a follow-up to continue.";
10256
+ case "length":
10257
+ return "Response cut off as max tokens reached. Ask for more to continue.";
10258
+ case "content_filter":
10259
+ return "The provider filtered this response.";
10260
+ case "error":
10261
+ return "Something went wrong generating this response.";
10262
+ case "end_turn":
10263
+ case "unknown":
10264
+ default:
10265
+ return null;
10266
+ }
10267
+ };
10268
+ var resolveStopReasonNoticeText = (stopReason, overrides) => {
10269
+ if (!stopReason) return null;
10270
+ const fallback = getDefaultStopReasonNoticeCopy(stopReason);
10271
+ if (fallback === null) return null;
10272
+ const override = overrides == null ? void 0 : overrides[stopReason];
10273
+ const text = override !== void 0 ? override : fallback;
10274
+ if (!text) return null;
10275
+ return text;
10276
+ };
10277
+ var createStopReasonNotice = (stopReason, text) => {
10278
+ const notice = createElement(
10279
+ "div",
10280
+ "persona-message-stop-reason persona-text-xs persona-mt-2 persona-italic"
10281
+ );
10282
+ notice.setAttribute("data-stop-reason", stopReason);
10283
+ notice.setAttribute("role", "note");
10284
+ notice.style.opacity = "0.75";
10285
+ notice.textContent = text;
10286
+ return notice;
10287
+ };
9761
10288
  var isSafeImageSrc = (src) => {
9762
10289
  const lower = src.toLowerCase();
9763
10290
  if (lower.startsWith("data:image/svg+xml")) return false;
@@ -10060,7 +10587,7 @@ var createMessageActions = (message, actionsConfig, _callbacks) => {
10060
10587
  return container;
10061
10588
  };
10062
10589
  var createStandardBubble = (message, transform, layoutConfig, actionsConfig, actionCallbacks, options) => {
10063
- var _a, _b, _c, _d, _e, _f, _g;
10590
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
10064
10591
  const config = layoutConfig != null ? layoutConfig : {};
10065
10592
  const layout = (_a = config.layout) != null ? _a : "bubble";
10066
10593
  const avatarConfig = config.avatar;
@@ -10085,22 +10612,73 @@ var createStandardBubble = (message, transform, layoutConfig, actionsConfig, act
10085
10612
  const messageContentText = (_g = (_f = message.content) == null ? void 0 : _f.trim()) != null ? _g : "";
10086
10613
  const isImageOnlyFallbackMessage = imageParts.length > 0 && messageContentText === IMAGE_ONLY_MESSAGE_FALLBACK_TEXT;
10087
10614
  const shouldHideTextUntilPreviewFails = isImageOnlyFallbackMessage;
10615
+ const streamAnimation = resolveStreamAnimation(
10616
+ (_i = (_h = options == null ? void 0 : options.widgetConfig) == null ? void 0 : _h.features) == null ? void 0 : _i.streamAnimation
10617
+ );
10618
+ 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;
10619
+ const streamPlugin = message.role === "assistant" && streamAnimation.type !== "none" ? resolveStreamAnimationPlugin(streamAnimation.type, streamPluginOverrides) : null;
10620
+ const pluginStillAnimating = message.role === "assistant" && ((_m = streamPlugin == null ? void 0 : streamPlugin.isAnimating) == null ? void 0 : _m.call(streamPlugin, message)) === true;
10621
+ const streamAnimationActive = message.role === "assistant" && streamPlugin !== null && (Boolean(message.streaming) || pluginStillAnimating);
10622
+ if (streamAnimationActive && (streamPlugin == null ? void 0 : streamPlugin.bubbleClass)) {
10623
+ bubble.classList.add(streamPlugin.bubbleClass);
10624
+ }
10088
10625
  const contentDiv = document.createElement("div");
10089
10626
  contentDiv.classList.add("persona-message-content");
10627
+ if (streamAnimationActive && streamPlugin) {
10628
+ if (streamPlugin.containerClass) {
10629
+ contentDiv.classList.add(streamPlugin.containerClass);
10630
+ }
10631
+ contentDiv.style.setProperty("--persona-stream-step", `${streamAnimation.speed}ms`);
10632
+ contentDiv.style.setProperty("--persona-stream-duration", `${streamAnimation.duration}ms`);
10633
+ }
10634
+ const bufferedContent = streamAnimationActive ? applyStreamBuffer(
10635
+ (_n = message.content) != null ? _n : "",
10636
+ streamAnimation.buffer,
10637
+ streamPlugin,
10638
+ message,
10639
+ Boolean(message.streaming)
10640
+ ) : (_o = message.content) != null ? _o : "";
10090
10641
  const transformedContent = transform({
10091
- text: message.content,
10642
+ text: bufferedContent,
10092
10643
  message,
10093
10644
  streaming: Boolean(message.streaming),
10094
10645
  raw: message.rawContent
10095
10646
  });
10647
+ let animatedContent = transformedContent;
10648
+ if (streamAnimationActive && (streamPlugin == null ? void 0 : streamPlugin.wrap) === "char") {
10649
+ animatedContent = wrapStreamAnimation(transformedContent, "char", message.id, {
10650
+ skipTags: streamPlugin.skipTags
10651
+ });
10652
+ } else if (streamAnimationActive && (streamPlugin == null ? void 0 : streamPlugin.wrap) === "word") {
10653
+ animatedContent = wrapStreamAnimation(transformedContent, "word", message.id, {
10654
+ skipTags: streamPlugin.skipTags
10655
+ });
10656
+ }
10096
10657
  let textContentDiv = null;
10097
10658
  if (shouldHideTextUntilPreviewFails) {
10098
10659
  textContentDiv = document.createElement("div");
10099
- textContentDiv.innerHTML = transformedContent;
10660
+ textContentDiv.innerHTML = animatedContent;
10100
10661
  textContentDiv.style.display = "none";
10101
10662
  contentDiv.appendChild(textContentDiv);
10102
10663
  } else {
10103
- contentDiv.innerHTML = transformedContent;
10664
+ contentDiv.innerHTML = animatedContent;
10665
+ }
10666
+ if (streamAnimationActive && (streamPlugin == null ? void 0 : streamPlugin.useCaret) && !shouldHideTextUntilPreviewFails && messageContentText) {
10667
+ const caret = createStreamCaret();
10668
+ const spans = contentDiv.querySelectorAll(
10669
+ ".persona-stream-char, .persona-stream-word"
10670
+ );
10671
+ const lastSpan = spans[spans.length - 1];
10672
+ if (lastSpan == null ? void 0 : lastSpan.parentNode) {
10673
+ lastSpan.parentNode.insertBefore(caret, lastSpan.nextSibling);
10674
+ } else {
10675
+ const lastChild = contentDiv.lastElementChild;
10676
+ if (lastChild) {
10677
+ lastChild.appendChild(caret);
10678
+ } else {
10679
+ contentDiv.appendChild(caret);
10680
+ }
10681
+ }
10104
10682
  }
10105
10683
  if (showTimestamp && timestampPosition === "inline" && message.createdAt) {
10106
10684
  const timestamp = createTimestamp(message, timestampConfig);
@@ -10129,18 +10707,37 @@ var createStandardBubble = (message, transform, layoutConfig, actionsConfig, act
10129
10707
  timestamp.classList.add("persona-mt-1");
10130
10708
  bubble.appendChild(timestamp);
10131
10709
  }
10710
+ const stopReasonNoticeText = message.role === "assistant" ? resolveStopReasonNoticeText(
10711
+ message.stopReason,
10712
+ (_q = (_p = options == null ? void 0 : options.widgetConfig) == null ? void 0 : _p.copy) == null ? void 0 : _q.stopReasonNotice
10713
+ ) : null;
10132
10714
  if (message.streaming && message.role === "assistant") {
10133
- if (!message.content || !message.content.trim()) {
10134
- const indicator = renderLoadingIndicatorWithFallback(
10135
- "inline",
10136
- options == null ? void 0 : options.loadingIndicatorRenderer,
10137
- options == null ? void 0 : options.widgetConfig
10138
- );
10139
- if (indicator) {
10140
- bubble.appendChild(indicator);
10715
+ const hasVisibleContent = Boolean(bufferedContent && bufferedContent.trim());
10716
+ const skeletonEnabled = streamAnimation.placeholder === "skeleton";
10717
+ const trailSkeleton = skeletonEnabled && streamAnimation.buffer === "line" && hasVisibleContent;
10718
+ if (!hasVisibleContent) {
10719
+ if (skeletonEnabled) {
10720
+ bubble.appendChild(createSkeletonPlaceholder());
10721
+ } else {
10722
+ const indicator = renderLoadingIndicatorWithFallback(
10723
+ "inline",
10724
+ options == null ? void 0 : options.loadingIndicatorRenderer,
10725
+ options == null ? void 0 : options.widgetConfig
10726
+ );
10727
+ if (indicator) {
10728
+ bubble.appendChild(indicator);
10729
+ }
10141
10730
  }
10731
+ } else if (trailSkeleton) {
10732
+ bubble.appendChild(createSkeletonPlaceholder());
10142
10733
  }
10143
10734
  }
10735
+ if (stopReasonNoticeText && message.stopReason && !message.streaming) {
10736
+ if (!messageContentText) {
10737
+ contentDiv.style.display = "none";
10738
+ }
10739
+ bubble.appendChild(createStopReasonNotice(message.stopReason, stopReasonNoticeText));
10740
+ }
10144
10741
  const shouldShowActions = message.role === "assistant" && !message.streaming && message.content && message.content.trim() && (actionsConfig == null ? void 0 : actionsConfig.enabled) !== false;
10145
10742
  if (shouldShowActions && actionsConfig) {
10146
10743
  const actions = createMessageActions(message, actionsConfig, actionCallbacks);
@@ -13811,7 +14408,7 @@ function buildDropOverlay(dropCfg) {
13811
14408
  return overlay;
13812
14409
  }
13813
14410
  var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
13814
- 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;
14411
+ 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;
13815
14412
  if (mount == null) {
13816
14413
  throw new Error(
13817
14414
  'createAgentExperience: mount must be a non-null HTMLElement (e.g. pass document.getElementById("my-root") after the node exists).'
@@ -14023,6 +14620,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14023
14620
  leftActions,
14024
14621
  rightActions
14025
14622
  } = panelElements;
14623
+ let setSendButtonMode = panelElements.setSendButtonMode;
14026
14624
  let micButton = panelElements.micButton;
14027
14625
  let micButtonWrapper = panelElements.micButtonWrapper;
14028
14626
  let attachmentButton = panelElements.attachmentButton;
@@ -14855,12 +15453,24 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14855
15453
  const panelBorder = resolvePanelChrome(panelPartial == null ? void 0 : panelPartial.border, defaultPanelBorder);
14856
15454
  const panelShadow = resolvePanelChrome(panelPartial == null ? void 0 : panelPartial.shadow, defaultPanelShadow);
14857
15455
  const panelBorderRadius = resolvePanelChrome(panelPartial == null ? void 0 : panelPartial.borderRadius, defaultPanelBorderRadius);
15456
+ const prevBodyScrollTop = body.scrollTop;
14858
15457
  mount.style.cssText = "";
14859
15458
  wrapper.style.cssText = "";
14860
15459
  panel.style.cssText = "";
14861
15460
  container.style.cssText = "";
14862
15461
  body.style.cssText = "";
14863
15462
  footer.style.cssText = "";
15463
+ const restoreBodyScrollTop = () => {
15464
+ var _a3;
15465
+ if (prevBodyScrollTop <= 0) return;
15466
+ const ownerWindow3 = (_a3 = body.ownerDocument.defaultView) != null ? _a3 : window;
15467
+ ownerWindow3.requestAnimationFrame(() => {
15468
+ if (body.scrollTop === prevBodyScrollTop) return;
15469
+ const maxScrollTop = body.scrollHeight - body.clientHeight;
15470
+ if (maxScrollTop <= 0) return;
15471
+ body.scrollTop = Math.min(prevBodyScrollTop, maxScrollTop);
15472
+ });
15473
+ };
14864
15474
  if (shouldGoFullscreen) {
14865
15475
  wrapper.classList.remove(
14866
15476
  "persona-bottom-6",
@@ -14916,6 +15526,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
14916
15526
  body.style.overflowY = "auto";
14917
15527
  footer.style.flexShrink = "0";
14918
15528
  wasMobileFullscreen = true;
15529
+ restoreBodyScrollTop();
14919
15530
  return;
14920
15531
  }
14921
15532
  const launcherWidth = (_r2 = (_q2 = config == null ? void 0 : config.launcher) == null ? void 0 : _q2.width) != null ? _r2 : config == null ? void 0 : config.launcherWidth;
@@ -15058,6 +15669,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15058
15669
  const zIndexStyles = !sidebarMode ? `z-index: ${(_w2 = (_v2 = config.launcher) == null ? void 0 : _v2.zIndex) != null ? _w2 : DEFAULT_OVERLAY_Z_INDEX} !important;` : "";
15059
15670
  wrapper.style.cssText += maxHeightStyles + paddingStyles + zIndexStyles;
15060
15671
  }
15672
+ restoreBodyScrollTop();
15061
15673
  };
15062
15674
  applyFullHeightStyles();
15063
15675
  applyThemeVariables(mount, config);
@@ -15121,6 +15733,17 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15121
15733
  cleanupThemeObserver = null;
15122
15734
  }
15123
15735
  });
15736
+ const streamAnimationConfig = (_D = config.features) == null ? void 0 : _D.streamAnimation;
15737
+ if ((streamAnimationConfig == null ? void 0 : streamAnimationConfig.type) && streamAnimationConfig.type !== "none") {
15738
+ const plugin = resolveStreamAnimationPlugin(
15739
+ streamAnimationConfig.type,
15740
+ streamAnimationConfig.plugins
15741
+ );
15742
+ if (plugin) {
15743
+ ensurePluginActive(plugin, mount);
15744
+ destroyCallbacks.push(() => detachAllPlugins(mount));
15745
+ }
15746
+ }
15124
15747
  const suggestionsManager = createSuggestions(suggestions);
15125
15748
  let closeHandler = null;
15126
15749
  let session;
@@ -15142,7 +15765,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15142
15765
  lastUserMessageWasVoice: false,
15143
15766
  lastUserMessageId: null
15144
15767
  };
15145
- const voiceAutoResumeMode = (_E = (_D = config.voiceRecognition) == null ? void 0 : _D.autoResume) != null ? _E : false;
15768
+ const voiceAutoResumeMode = (_F = (_E = config.voiceRecognition) == null ? void 0 : _E.autoResume) != null ? _F : false;
15146
15769
  const emitVoiceState = (source) => {
15147
15770
  eventBus.emit("voice:state", {
15148
15771
  active: voiceState.active,
@@ -15830,7 +16453,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15830
16453
  });
15831
16454
  };
15832
16455
  const setComposerDisabled = (disabled) => {
15833
- sendButton.disabled = disabled;
16456
+ setSendButtonMode(disabled ? "stop" : "send");
15834
16457
  if (micButton) {
15835
16458
  micButton.disabled = disabled;
15836
16459
  }
@@ -15870,7 +16493,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15870
16493
  }
15871
16494
  }
15872
16495
  const useIcon = (_i2 = (_h2 = config.sendButton) == null ? void 0 : _h2.useIcon) != null ? _i2 : false;
15873
- if (!useIcon) {
16496
+ if (!useIcon && !(session == null ? void 0 : session.isStreaming())) {
15874
16497
  sendButton.textContent = (_k2 = (_j2 = config.copy) == null ? void 0 : _j2.sendButtonLabel) != null ? _k2 : "Send";
15875
16498
  }
15876
16499
  textarea.style.fontFamily = 'var(--persona-input-font-family, var(--persona-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif))';
@@ -15989,7 +16612,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
15989
16612
  }
15990
16613
  });
15991
16614
  sessionRef.current = session;
15992
- if (((_G = (_F = config.voiceRecognition) == null ? void 0 : _F.provider) == null ? void 0 : _G.type) === "runtype") {
16615
+ if (((_H = (_G = config.voiceRecognition) == null ? void 0 : _G.provider) == null ? void 0 : _H.type) === "runtype") {
15993
16616
  try {
15994
16617
  session.setupVoice();
15995
16618
  } catch (err) {
@@ -16037,6 +16660,10 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16037
16660
  const handleSubmit = (event) => {
16038
16661
  var _a2;
16039
16662
  event.preventDefault();
16663
+ if (session.isStreaming()) {
16664
+ session.cancel();
16665
+ return;
16666
+ }
16040
16667
  const value = textarea.value.trim();
16041
16668
  const hasAttachments = (_a2 = attachmentManager == null ? void 0 : attachmentManager.hasAttachments()) != null ? _a2 : false;
16042
16669
  if (!value && !hasAttachments) return;
@@ -16591,7 +17218,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16591
17218
  }
16592
17219
  };
16593
17220
  recalcPanelHeight();
16594
- const ownerWindow = (_H = mount.ownerDocument.defaultView) != null ? _H : window;
17221
+ const ownerWindow = (_I = mount.ownerDocument.defaultView) != null ? _I : window;
16595
17222
  ownerWindow.addEventListener("resize", recalcPanelHeight);
16596
17223
  destroyCallbacks.push(() => ownerWindow.removeEventListener("resize", recalcPanelHeight));
16597
17224
  if (typeof ResizeObserver !== "undefined") {
@@ -16602,15 +17229,19 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16602
17229
  destroyCallbacks.push(() => footerResizeObserver.disconnect());
16603
17230
  }
16604
17231
  lastScrollTop = body.scrollTop;
17232
+ let lastScrollHeight = body.scrollHeight;
16605
17233
  const handleScroll = () => {
16606
17234
  const scrollTop = body.scrollTop;
17235
+ const currentScrollHeight = body.scrollHeight;
17236
+ const scrollHeightShrank = currentScrollHeight < lastScrollHeight;
17237
+ lastScrollHeight = currentScrollHeight;
16607
17238
  const { action, nextLastScrollTop } = resolveFollowStateFromScroll({
16608
17239
  following: autoFollow.isFollowing(),
16609
17240
  currentScrollTop: scrollTop,
16610
17241
  lastScrollTop,
16611
17242
  nearBottom: isElementNearBottom(body, BOTTOM_THRESHOLD),
16612
17243
  userScrollThreshold: USER_SCROLL_THRESHOLD,
16613
- isAutoScrolling: isAutoScrolling || hasPendingAutoScroll,
17244
+ isAutoScrolling: isAutoScrolling || hasPendingAutoScroll || scrollHeightShrank,
16614
17245
  pauseOnUpwardScroll: true,
16615
17246
  pauseWhenAwayFromBottom: false,
16616
17247
  resumeRequiresDownwardScroll: true
@@ -16810,7 +17441,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
16810
17441
  }
16811
17442
  const controller = {
16812
17443
  update(nextConfig) {
16813
- 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;
17444
+ 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;
16814
17445
  const previousToolCallConfig = config.toolCall;
16815
17446
  const previousMessageActions = config.messageActions;
16816
17447
  const previousLayoutMessages = (_a2 = config.layout) == null ? void 0 : _a2.messages;
@@ -17021,7 +17652,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17021
17652
  }
17022
17653
  const launcher = (_L2 = config.launcher) != null ? _L2 : {};
17023
17654
  const headerIconHidden = (_M2 = launcher.headerIconHidden) != null ? _M2 : false;
17024
- const layoutShowIcon = (_O = (_N2 = config.layout) == null ? void 0 : _N2.header) == null ? void 0 : _O.showIcon;
17655
+ const layoutShowIcon = (_O2 = (_N2 = config.layout) == null ? void 0 : _N2.header) == null ? void 0 : _O2.showIcon;
17025
17656
  const shouldHideIcon = headerIconHidden || layoutShowIcon === false;
17026
17657
  const headerIconName = launcher.headerIconName;
17027
17658
  const headerIconSize = (_P = launcher.headerIconSize) != null ? _P : "48px";
@@ -17162,7 +17793,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
17162
17793
  const closeButtonIconName = (_ca = launcher.closeButtonIconName) != null ? _ca : "x";
17163
17794
  const closeButtonIconText = (_da = launcher.closeButtonIconText) != null ? _da : "\xD7";
17164
17795
  closeButton.innerHTML = "";
17165
- const iconSvg = renderLucideIcon(closeButtonIconName, "20px", "currentColor", 2);
17796
+ const iconSvg = renderLucideIcon(closeButtonIconName, "28px", "currentColor", 1);
17166
17797
  if (iconSvg) {
17167
17798
  closeButton.appendChild(iconSvg);
17168
17799
  } else {
@@ -18092,7 +18723,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
18092
18723
  }
18093
18724
  }
18094
18725
  };
18095
- const shouldExposeDebugApi = ((_I = runtimeOptions == null ? void 0 : runtimeOptions.debugTools) != null ? _I : false) || Boolean(config.debug);
18726
+ const shouldExposeDebugApi = ((_J = runtimeOptions == null ? void 0 : runtimeOptions.debugTools) != null ? _J : false) || Boolean(config.debug);
18096
18727
  if (shouldExposeDebugApi && typeof window !== "undefined") {
18097
18728
  const previousDebug = window.AgentWidgetBrowser;
18098
18729
  const debugApi = {
@@ -18195,9 +18826,9 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
18195
18826
  const voiceKey = `${persistConfig.keyPrefix}widget-voice`;
18196
18827
  const voiceModeKey = `${persistConfig.keyPrefix}widget-voice-mode`;
18197
18828
  if (storage) {
18198
- const wasOpen = ((_J = persistConfig.persist) == null ? void 0 : _J.openState) && storage.getItem(openKey) === "true";
18199
- const wasVoiceActive = ((_K = persistConfig.persist) == null ? void 0 : _K.voiceState) && storage.getItem(voiceKey) === "true";
18200
- const wasInVoiceMode = ((_L = persistConfig.persist) == null ? void 0 : _L.voiceState) && storage.getItem(voiceModeKey) === "true";
18829
+ const wasOpen = ((_K = persistConfig.persist) == null ? void 0 : _K.openState) && storage.getItem(openKey) === "true";
18830
+ const wasVoiceActive = ((_L = persistConfig.persist) == null ? void 0 : _L.voiceState) && storage.getItem(voiceKey) === "true";
18831
+ const wasInVoiceMode = ((_M = persistConfig.persist) == null ? void 0 : _M.voiceState) && storage.getItem(voiceModeKey) === "true";
18201
18832
  if (wasOpen) {
18202
18833
  setTimeout(() => {
18203
18834
  controller.open();
@@ -18214,7 +18845,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
18214
18845
  }, 100);
18215
18846
  }, 0);
18216
18847
  }
18217
- if ((_M = persistConfig.persist) == null ? void 0 : _M.openState) {
18848
+ if ((_N = persistConfig.persist) == null ? void 0 : _N.openState) {
18218
18849
  eventBus.on("widget:opened", () => {
18219
18850
  storage.setItem(openKey, "true");
18220
18851
  });
@@ -18222,7 +18853,7 @@ var createAgentExperience = (mount, initialConfig, runtimeOptions) => {
18222
18853
  storage.setItem(openKey, "false");
18223
18854
  });
18224
18855
  }
18225
- if ((_N = persistConfig.persist) == null ? void 0 : _N.voiceState) {
18856
+ if ((_O = persistConfig.persist) == null ? void 0 : _O.voiceState) {
18226
18857
  eventBus.on("voice:state", (event) => {
18227
18858
  storage.setItem(voiceKey, event.active ? "true" : "false");
18228
18859
  });
@@ -18796,6 +19427,9 @@ function buildSrcdoc(mountId, shellMode, docked, widgetCssPath) {
18796
19427
  var PREVIEW_TRANSCRIPT_PRESET_LABELS = {
18797
19428
  "user-message": "User message",
18798
19429
  "assistant-message": "Assistant message",
19430
+ "assistant-code-block": "Assistant \u2014 code block",
19431
+ "assistant-markdown-table": "Assistant \u2014 markdown table",
19432
+ "assistant-image": "Assistant \u2014 image",
18799
19433
  "reasoning-streaming": "Reasoning (streaming)",
18800
19434
  "reasoning-complete": "Reasoning (complete)",
18801
19435
  "tool-running": "Tool call (running)",
@@ -18822,6 +19456,56 @@ function createPreviewTranscriptEntry(preset, index = 0) {
18822
19456
  content: "Absolutely. I can keep going and explain what happens next.",
18823
19457
  createdAt
18824
19458
  };
19459
+ case "assistant-code-block":
19460
+ return {
19461
+ id: `preview-seq-assistant-code-${suffix}`,
19462
+ role: "assistant",
19463
+ content: [
19464
+ "Here's how you'd wire up a streaming animation:",
19465
+ "",
19466
+ "```ts",
19467
+ "import { createAgentExperience } from '@runtypelabs/persona';",
19468
+ "",
19469
+ "createAgentExperience(el, {",
19470
+ " features: {",
19471
+ ' streamAnimation: { type: "letter-rise", speed: 120 },',
19472
+ " },",
19473
+ "});",
19474
+ "```",
19475
+ "",
19476
+ "Swap the `type` value to try the other presets."
19477
+ ].join("\n"),
19478
+ createdAt
19479
+ };
19480
+ case "assistant-markdown-table":
19481
+ return {
19482
+ id: `preview-seq-assistant-table-${suffix}`,
19483
+ role: "assistant",
19484
+ content: [
19485
+ "Here are the built-in streaming animations at a glance:",
19486
+ "",
19487
+ "| Preset | Wrap unit | Best for |",
19488
+ "| ------------ | --------- | --------------------------- |",
19489
+ "| Typewriter | Character | Classic terminal feel |",
19490
+ "| Letter rise | Character | Soft, staggered entrance |",
19491
+ "| Word fade | Word | Longer-form assistant replies |",
19492
+ "| Pop bubble | Bubble | Short, punchy affirmations |"
19493
+ ].join("\n"),
19494
+ createdAt
19495
+ };
19496
+ case "assistant-image":
19497
+ return {
19498
+ id: `preview-seq-assistant-image-${suffix}`,
19499
+ role: "assistant",
19500
+ content: [
19501
+ "Here's the reference diagram you asked for \u2014 let me know if you'd like a different view:",
19502
+ "",
19503
+ "![Stream animation reference](https://placehold.co/320x200/png?text=Stream+Animation)",
19504
+ "",
19505
+ "The gradient shows how per-unit delays stagger across the reply."
19506
+ ].join("\n"),
19507
+ createdAt
19508
+ };
18825
19509
  case "reasoning-streaming":
18826
19510
  return {
18827
19511
  id: `preview-seq-reasoning-stream-${suffix}`,
@@ -18889,6 +19573,38 @@ function createPreviewTranscriptEntry(preset, index = 0) {
18889
19573
  function appendPreviewTranscriptEntry(messages, preset) {
18890
19574
  return [...messages, createPreviewTranscriptEntry(preset, messages.length)];
18891
19575
  }
19576
+ function presetStreamsText(preset) {
19577
+ return preset === "assistant-message" || preset === "assistant-code-block" || preset === "assistant-markdown-table" || preset === "assistant-image";
19578
+ }
19579
+ function buildTranscriptStreamFrames(preset, suffix, options) {
19580
+ var _a, _b;
19581
+ const completed = createPreviewTranscriptEntry(preset, suffix);
19582
+ if (!presetStreamsText(preset) || typeof completed.content !== "string") {
19583
+ return [{ message: completed, delayMs: 0, done: true }];
19584
+ }
19585
+ const chunkSize = Math.max(1, (_a = options == null ? void 0 : options.chunkSize) != null ? _a : 24);
19586
+ const delayMs = Math.max(0, (_b = options == null ? void 0 : options.delayMs) != null ? _b : 42);
19587
+ const fullText = completed.content;
19588
+ const frames = [];
19589
+ frames.push({
19590
+ message: { ...completed, content: "", streaming: true },
19591
+ delayMs: 0,
19592
+ done: false
19593
+ });
19594
+ for (let i = chunkSize; i < fullText.length; i += chunkSize) {
19595
+ frames.push({
19596
+ message: { ...completed, content: fullText.slice(0, i), streaming: true },
19597
+ delayMs,
19598
+ done: false
19599
+ });
19600
+ }
19601
+ frames.push({
19602
+ message: { ...completed, content: fullText, streaming: false },
19603
+ delayMs,
19604
+ done: true
19605
+ });
19606
+ return frames;
19607
+ }
18892
19608
  var createAdvancedTranscriptPreviewMessages = () => [
18893
19609
  {
18894
19610
  id: "preview-adv-1",
@@ -19338,6 +20054,7 @@ export {
19338
20054
  buildPreviewConfigWithMessages,
19339
20055
  buildShellCss,
19340
20056
  buildSrcdoc,
20057
+ buildTranscriptStreamFrames,
19341
20058
  convertFromPx,
19342
20059
  convertToPx,
19343
20060
  createPreviewMessages,
@@ -19357,6 +20074,7 @@ export {
19357
20074
  normalizeColorValue,
19358
20075
  paletteColorPath,
19359
20076
  parseCssValue,
20077
+ presetStreamsText,
19360
20078
  resolveRoleAssignment,
19361
20079
  resolveThemeColorPath,
19362
20080
  scopeSection,