@noodleseed/assistant 1.7.0 → 1.8.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 (46) hide show
  1. package/README.md +73 -20
  2. package/dist/{chunk-UXPKSCID.js → chunk-3YYTUJPJ.js} +2 -2
  3. package/dist/{chunk-NSBPE2FW.js → chunk-5FUTL2UF.js} +6 -1
  4. package/dist/chunk-BLMJHF7U.js +544 -0
  5. package/dist/chunk-BLMJHF7U.js.map +1 -0
  6. package/dist/{chunk-35A7REQX.js → chunk-JMBUJSFP.js} +183 -79
  7. package/dist/chunk-JMBUJSFP.js.map +1 -0
  8. package/dist/chunk-RYQBXTLR.js +9089 -0
  9. package/dist/chunk-RYQBXTLR.js.map +1 -0
  10. package/dist/{client-D2Y9UFh3.d.cts → client-BxoNZkWp.d.cts} +43 -1
  11. package/dist/{client-DBuETUVD.d.ts → client-ERQCAH_0.d.ts} +43 -1
  12. package/dist/client.cjs +22976 -92
  13. package/dist/client.cjs.map +1 -1
  14. package/dist/client.d.cts +2 -1
  15. package/dist/client.d.ts +2 -1
  16. package/dist/client.js +3 -2
  17. package/dist/index.cjs +10683 -2201
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +3 -2
  20. package/dist/index.d.ts +3 -2
  21. package/dist/index.js +4 -4
  22. package/dist/react/client.cjs +23688 -0
  23. package/dist/react/client.cjs.map +1 -0
  24. package/dist/react/client.d.cts +24 -0
  25. package/dist/react/client.d.ts +24 -0
  26. package/dist/react/client.js +76 -0
  27. package/dist/react/client.js.map +1 -0
  28. package/dist/react.cjs +10683 -2200
  29. package/dist/react.cjs.map +1 -1
  30. package/dist/react.d.cts +2 -1
  31. package/dist/react.d.ts +2 -1
  32. package/dist/react.js +7 -6
  33. package/dist/react.js.map +1 -1
  34. package/dist/server.js +1 -1
  35. package/dist/token-Y6KCR3JT.js +70 -0
  36. package/dist/token-Y6KCR3JT.js.map +1 -0
  37. package/dist/token-util-XFYMRPAB.js +6 -0
  38. package/dist/{v4-2UXPDMWJ.js → v4-KBRL3YLO.js} +3 -3
  39. package/dist/v4-KBRL3YLO.js.map +1 -0
  40. package/package.json +14 -3
  41. package/dist/chunk-35A7REQX.js.map +0 -1
  42. package/dist/chunk-7E5HINN4.js +0 -713
  43. package/dist/chunk-7E5HINN4.js.map +0 -1
  44. /package/dist/{chunk-UXPKSCID.js.map → chunk-3YYTUJPJ.js.map} +0 -0
  45. /package/dist/{chunk-NSBPE2FW.js.map → chunk-5FUTL2UF.js.map} +0 -0
  46. /package/dist/{v4-2UXPDMWJ.js.map → token-util-XFYMRPAB.js.map} +0 -0
@@ -2,7 +2,7 @@ import {
2
2
  AssistantClientError,
3
3
  copyAssistantModelContext,
4
4
  createAssistantClient
5
- } from "./chunk-7E5HINN4.js";
5
+ } from "./chunk-RYQBXTLR.js";
6
6
  import {
7
7
  _enum,
8
8
  _null,
@@ -24,10 +24,10 @@ import {
24
24
  string,
25
25
  union,
26
26
  unknown
27
- } from "./chunk-UXPKSCID.js";
27
+ } from "./chunk-3YYTUJPJ.js";
28
28
  import {
29
29
  __require
30
- } from "./chunk-NSBPE2FW.js";
30
+ } from "./chunk-5FUTL2UF.js";
31
31
 
32
32
  // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.4.3/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
33
33
  var RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
@@ -3063,6 +3063,14 @@ function isAllowedAppLink(value, allowedDomains, baseUrl) {
3063
3063
  return void 0;
3064
3064
  }
3065
3065
  }
3066
+ function createAssistantAppHostContext(theme) {
3067
+ return {
3068
+ theme,
3069
+ displayMode: "inline",
3070
+ availableDisplayModes: ["inline", "fullscreen"],
3071
+ platform: "web"
3072
+ };
3073
+ }
3066
3074
  var APP_RENDER_TIMEOUT_MS = 1e4;
3067
3075
  function resolveSandboxUrl(value) {
3068
3076
  if (!value) return void 0;
@@ -3117,11 +3125,7 @@ function mountAssistantApp(detail, actions, options = {}) {
3117
3125
  message: { text: {} }
3118
3126
  },
3119
3127
  {
3120
- hostContext: {
3121
- displayMode: "inline",
3122
- availableDisplayModes: ["inline", "fullscreen"],
3123
- platform: "web"
3124
- }
3128
+ hostContext: createAssistantAppHostContext(actions.theme)
3125
3129
  }
3126
3130
  );
3127
3131
  bridge.onsandboxready = () => {
@@ -3191,10 +3195,10 @@ var common = {
3191
3195
  baseFontSize: 15,
3192
3196
  messageFontSize: 15,
3193
3197
  lineHeight: 1.5,
3194
- panelRadius: 20,
3195
- cardRadius: 14,
3196
- inputRadius: 14,
3197
- buttonRadius: 12,
3198
+ panelRadius: 24,
3199
+ cardRadius: 16,
3200
+ inputRadius: 999,
3201
+ buttonRadius: 999,
3198
3202
  launcherRadius: 999,
3199
3203
  spacing: 8,
3200
3204
  backdropBlur: 18,
@@ -3301,7 +3305,7 @@ var DEFAULT_APPEARANCE = {
3301
3305
  },
3302
3306
  presentation: {
3303
3307
  panel: {
3304
- surface: "solid",
3308
+ surface: "glass",
3305
3309
  elevation: "soft",
3306
3310
  border: "subtle"
3307
3311
  },
@@ -6608,8 +6612,7 @@ var AssistantElementEventController = class {
6608
6612
  if (name === "message_started") {
6609
6613
  this.#startStream("message");
6610
6614
  const body = this.#host.appendMessage("user", String(data.message ?? ""));
6611
- const messages = this.#host.messages();
6612
- if (body && messages) this.#revealLatestMessage(messages);
6615
+ if (body) this.#host.revealLatest();
6613
6616
  this.#host.element.dispatchEvent(new CustomEvent("assistant-message-started"));
6614
6617
  return;
6615
6618
  }
@@ -6675,6 +6678,7 @@ var AssistantElementEventController = class {
6675
6678
  this.#clearStream();
6676
6679
  this.#completedTool = void 0;
6677
6680
  this.#host.element.removeAttribute("has-messages");
6681
+ this.#host.revealLatest();
6678
6682
  this.#host.element.dispatchEvent(new CustomEvent("assistant-session-reset"));
6679
6683
  }
6680
6684
  #finishInteraction(id, action) {
@@ -6685,6 +6689,7 @@ var AssistantElementEventController = class {
6685
6689
  messages.append(
6686
6690
  createResultCard(this.#completedTool.result, labels.completed, labels.redacted)
6687
6691
  );
6692
+ this.#host.revealLatest();
6688
6693
  }
6689
6694
  }
6690
6695
  this.#proposalCards.get(id)?.remove();
@@ -6722,7 +6727,7 @@ var AssistantElementEventController = class {
6722
6727
  });
6723
6728
  messages.append(card);
6724
6729
  this.#proposalCards.set(id, card);
6725
- this.#revealLatestMessage(messages);
6730
+ this.#host.revealLatest();
6726
6731
  this.#host.element.dispatchEvent(
6727
6732
  new CustomEvent("assistant-tool-proposed", {
6728
6733
  detail: { id, tool, title, description, arguments: arguments_, reviewSchema }
@@ -6746,7 +6751,7 @@ var AssistantElementEventController = class {
6746
6751
  });
6747
6752
  messages.append(card);
6748
6753
  this.#proposalCards.set(id, card);
6749
- this.#revealLatestMessage(messages);
6754
+ this.#host.revealLatest();
6750
6755
  this.#host.element.dispatchEvent(
6751
6756
  new CustomEvent("assistant-input-requested", {
6752
6757
  detail: { id, message, requestedSchema }
@@ -6759,6 +6764,7 @@ var AssistantElementEventController = class {
6759
6764
  this.#streamKind = kind;
6760
6765
  }
6761
6766
  #clearStream() {
6767
+ this.#assistantBody?.parentElement?.classList.remove("streaming");
6762
6768
  this.#assistantBody = void 0;
6763
6769
  this.#assistantText = "";
6764
6770
  this.#streamKind = void 0;
@@ -6771,20 +6777,10 @@ var AssistantElementEventController = class {
6771
6777
  const body = this.#assistantBody ?? this.#host.appendMessage("assistant", "");
6772
6778
  this.#assistantBody = body;
6773
6779
  if (!body) return;
6780
+ body.parentElement?.classList.add("streaming");
6774
6781
  body.innerHTML = html2;
6775
- const messages = this.#host.messages();
6776
- if (messages) this.#revealLatestMessage(messages);
6777
- }
6778
- #revealLatestMessage(messages) {
6779
6782
  this.#host.element.setAttribute("has-messages", "");
6780
- const distance = messages.scrollHeight - messages.scrollTop - messages.clientHeight;
6781
- const control = this.#host.element.shadowRoot?.querySelector(".new-messages");
6782
- if (distance <= 160) {
6783
- messages.scrollTop = messages.scrollHeight;
6784
- if (control) control.hidden = true;
6785
- } else if (control) {
6786
- control.hidden = false;
6787
- }
6783
+ this.#host.revealLatest();
6788
6784
  }
6789
6785
  };
6790
6786
  function isRecord(value) {
@@ -6809,6 +6805,107 @@ function queryRequired(root, selector) {
6809
6805
  return element;
6810
6806
  }
6811
6807
 
6808
+ // src/element-scroll-controller.ts
6809
+ var AssistantElementScrollController = class {
6810
+ #region;
6811
+ #messages;
6812
+ #control;
6813
+ #mutationObserver;
6814
+ #resizeObserver;
6815
+ #syncScheduled = false;
6816
+ #followingLatest = true;
6817
+ #lastScrollTop = 0;
6818
+ connect(elements) {
6819
+ this.disconnect();
6820
+ this.#region = elements.region;
6821
+ this.#messages = elements.messages;
6822
+ this.#control = elements.control;
6823
+ this.#lastScrollTop = elements.messages.scrollTop;
6824
+ this.#followingLatest = this.#distanceFromBottom() <= 30;
6825
+ elements.messages.addEventListener("scroll", this.#handleScroll, { passive: true });
6826
+ elements.control.addEventListener("click", this.#handleControlClick);
6827
+ if (globalThis.MutationObserver) {
6828
+ this.#mutationObserver = new MutationObserver(() => this.#scheduleContentSync());
6829
+ this.#mutationObserver.observe(elements.messages, {
6830
+ childList: true,
6831
+ subtree: true,
6832
+ attributes: true,
6833
+ attributeFilter: ["style"]
6834
+ });
6835
+ }
6836
+ if (globalThis.ResizeObserver) {
6837
+ this.#resizeObserver = new ResizeObserver(() => this.#scheduleContentSync());
6838
+ this.#resizeObserver.observe(elements.messages);
6839
+ }
6840
+ this.sync();
6841
+ }
6842
+ disconnect() {
6843
+ this.#messages?.removeEventListener("scroll", this.#handleScroll);
6844
+ this.#control?.removeEventListener("click", this.#handleControlClick);
6845
+ this.#mutationObserver?.disconnect();
6846
+ this.#resizeObserver?.disconnect();
6847
+ this.#region?.removeAttribute("data-can-scroll-up");
6848
+ this.#region?.removeAttribute("data-can-scroll-down");
6849
+ this.#region = void 0;
6850
+ this.#messages = void 0;
6851
+ this.#control = void 0;
6852
+ this.#mutationObserver = void 0;
6853
+ this.#resizeObserver = void 0;
6854
+ this.#syncScheduled = false;
6855
+ this.#followingLatest = true;
6856
+ this.#lastScrollTop = 0;
6857
+ }
6858
+ revealLatest() {
6859
+ if (!this.#messages) return;
6860
+ if (this.#followingLatest || this.#distanceFromBottom() <= 160) {
6861
+ this.scrollToBottom();
6862
+ return;
6863
+ }
6864
+ this.sync();
6865
+ }
6866
+ scrollToBottom() {
6867
+ if (!this.#messages) return;
6868
+ this.#followingLatest = true;
6869
+ this.#messages.scrollTop = this.#messages.scrollHeight;
6870
+ this.sync();
6871
+ }
6872
+ sync() {
6873
+ if (!this.#messages || !this.#region || !this.#control) return;
6874
+ const distance = this.#distanceFromBottom();
6875
+ this.#region.toggleAttribute("data-can-scroll-up", this.#messages.scrollTop > 20);
6876
+ this.#region.toggleAttribute("data-can-scroll-down", distance > 20);
6877
+ this.#control.hidden = distance <= 100;
6878
+ }
6879
+ #handleScroll = () => {
6880
+ if (!this.#messages) return;
6881
+ const distance = this.#distanceFromBottom();
6882
+ const movedUp = this.#messages.scrollTop < this.#lastScrollTop - 5;
6883
+ this.#lastScrollTop = this.#messages.scrollTop;
6884
+ if (movedUp && distance > 50) this.#followingLatest = false;
6885
+ if (distance < 30) this.#followingLatest = true;
6886
+ this.sync();
6887
+ };
6888
+ #handleControlClick = () => {
6889
+ this.scrollToBottom();
6890
+ };
6891
+ #distanceFromBottom() {
6892
+ if (!this.#messages) return 0;
6893
+ return this.#messages.scrollHeight - this.#messages.scrollTop - this.#messages.clientHeight;
6894
+ }
6895
+ #scheduleContentSync() {
6896
+ if (this.#syncScheduled) return;
6897
+ this.#syncScheduled = true;
6898
+ queueMicrotask(() => {
6899
+ this.#syncScheduled = false;
6900
+ if (this.#followingLatest) {
6901
+ this.scrollToBottom();
6902
+ } else {
6903
+ this.sync();
6904
+ }
6905
+ });
6906
+ }
6907
+ };
6908
+
6812
6909
  // src/element-styles.ts
6813
6910
  var ASSISTANT_ELEMENT_STYLES = `<style>
6814
6911
  *, *::before, *::after { box-sizing: border-box; }
@@ -6822,40 +6919,48 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
6822
6919
  .launcher { display: grid; place-items: center; width: 48px; height: 48px; border: 1px solid var(--ns-assistant-launcher-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 999px; color: var(--ns-assistant-launcher-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-launcher, var(--ns-assistant-panel, var(--ns-assistant-default-panel))); box-shadow: 0 8px 28px rgba(0,0,0,.14); cursor: pointer; transition: transform .24s cubic-bezier(.25,1,.5,1), box-shadow .2s ease; }
6823
6920
  .launcher:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 26px rgba(0,0,0,.16); }
6824
6921
  .launcher img { width: 28px; height: 28px; border-radius: 50%; object-fit: contain; }
6825
- .panel { display: none; flex-direction: column; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 40px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 40px)); overflow: hidden; color: var(--ns-assistant-panel-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border: 1px solid var(--ns-assistant-panel-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); transform-origin: bottom right; animation: halo-panel-in .28s cubic-bezier(.23,1,.32,1) both; }
6922
+ .panel { display: none; flex-direction: column; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 40px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 40px)); overflow: hidden; color: var(--ns-assistant-panel-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border: 1px solid var(--ns-assistant-panel-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); transform-origin: bottom right; isolation: isolate; animation: halo-panel-in .28s cubic-bezier(.23,1,.32,1) both; }
6826
6923
  :host([open]) .panel { display: flex; }
6827
6924
  .panel { position: relative; }
6828
6925
  :host([open]) .launcher { display: none; }
6829
- header { display: flex; flex: 0 0 auto; gap: 10px; align-items: center; min-height: 64px; padding: 12px 18px; color: var(--ns-assistant-header-text, inherit); background: var(--ns-assistant-header, transparent); border-bottom: 1px solid var(--ns-assistant-header-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); }
6830
- header strong { flex: 1; font-size: 16px; font-weight: 600; letter-spacing: -.01em; }
6926
+ header { display: flex; flex: 0 0 auto; gap: 10px; align-items: center; min-height: 64px; padding: 12px 18px; color: var(--ns-assistant-header-text, inherit); background: var(--ns-assistant-header, transparent); border-bottom: 1px solid color-mix(in srgb, var(--ns-assistant-header-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))) 78%, transparent); }
6927
+ header strong { flex: 1; font-size: 16px; font-weight: 600; letter-spacing: 0; }
6831
6928
  .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }
6832
- .close, .send { display: grid; place-items: center; border: 0; border-radius: 999px; cursor: pointer; }
6833
- .close { width: 44px; height: 44px; padding: 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; font-size: 24px; font-weight: 300; line-height: 1; transition: background .15s ease, color .15s ease; }
6929
+ .close, .send { display: grid; place-items: center; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; }
6930
+ .close { position: relative; width: 44px; height: 44px; padding: 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; transition: background .15s ease, color .15s ease, transform .15s ease; }
6931
+ .close::before { content: ''; width: 18px; height: 18px; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 6 12 12M18 6 6 18' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 6 12 12M18 6 6 18' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; }
6834
6932
  .close:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }
6933
+ .close:active { transform: scale(.96); }
6835
6934
  .welcome { flex: 0 0 auto; padding: 30px 22px 18px; }
6836
- .welcome h2 { margin: 0; font-size: 1.42em; line-height: 1.25; letter-spacing: -.025em; }
6935
+ .welcome h2 { margin: 0; font-size: 1.35em; line-height: 1.25; letter-spacing: 0; }
6837
6936
  .welcome p { max-width: 42ch; margin: 7px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
6838
6937
  :host([has-messages]) .welcome, :host([has-messages]) .suggested-prompts { display: none; }
6839
6938
  .suggested-prompts { display: flex; flex: 0 0 auto; flex-wrap: wrap; gap: 8px; padding: 0 20px 16px; }
6840
6939
  .suggested-prompts:empty { display: none; }
6841
- .suggested-prompts button { min-height: 44px; padding: 9px 14px; color: var(--ns-assistant-suggestion-text, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text))); background: var(--ns-assistant-suggestion, transparent); border: 1px solid var(--ns-assistant-suggestion-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 12px; cursor: pointer; transition: background .2s ease, color .2s ease, transform .2s ease; }
6940
+ .suggested-prompts button { min-height: 44px; padding: 8px 14px; color: var(--ns-assistant-suggestion-text, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text))); background: var(--ns-assistant-suggestion, color-mix(in srgb, var(--ns-assistant-input, var(--ns-assistant-default-input)) 58%, transparent)); border: 1px solid var(--ns-assistant-suggestion-border, color-mix(in srgb, var(--ns-assistant-divider, var(--ns-assistant-default-divider)) 82%, transparent)); border-radius: 999px; cursor: pointer; font-size: .86em; transition: background .2s ease, color .2s ease, border-color .2s ease, transform .2s ease; }
6842
6941
  .suggested-prompts button:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); transform: translateY(-1px); }
6843
- .messages { flex: 1 1 auto; min-height: 0; padding: 18px 20px; overflow-y: auto; background: var(--ns-assistant-canvas, transparent); overscroll-behavior: contain; scroll-behavior: smooth; }
6942
+ .messages-region { position: relative; display: flex; flex: 1 1 auto; min-height: 0; overflow: hidden; }
6943
+ .messages-region::before, .messages-region::after { content: ''; position: absolute; right: 0; left: 0; z-index: 1; height: 18px; pointer-events: none; opacity: 0; transition: opacity .18s ease; }
6944
+ .messages-region::before { top: 0; background: linear-gradient(to bottom, color-mix(in srgb, var(--ns-assistant-panel, var(--ns-assistant-default-panel)) 92%, transparent), transparent); }
6945
+ .messages-region::after { bottom: 0; background: linear-gradient(to top, color-mix(in srgb, var(--ns-assistant-panel, var(--ns-assistant-default-panel)) 92%, transparent), transparent); }
6946
+ .messages-region[data-can-scroll-up]::before, .messages-region[data-can-scroll-down]::after { opacity: 1; }
6947
+ .messages { flex: 1 1 auto; width: 100%; min-height: 0; padding: 18px 20px 24px; overflow-y: auto; background: var(--ns-assistant-canvas, transparent); overscroll-behavior: contain; scroll-behavior: smooth; }
6844
6948
  .messages::-webkit-scrollbar { width: 6px; }
6845
6949
  .messages::-webkit-scrollbar-thumb { background: var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; }
6846
6950
  .message { width: fit-content; max-width: 88%; margin: 0 0 14px; padding: 0; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: transparent; white-space: pre-wrap; animation: halo-message-in .2s ease both; }
6847
6951
  .message > span, .message > .markdown { overflow-wrap: anywhere; }
6848
6952
  .message .avatar { float: left; width: 24px; height: 24px; margin-right: 9px; border-radius: 50%; object-fit: cover; }
6849
6953
  .message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; line-height: 1.2; }
6850
- .message-copy { min-width: 44px; min-height: 32px; margin-top: 6px; padding: 4px 8px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; border: 0; border-radius: 8px; cursor: pointer; font-size: .78em; opacity: 0; transition: opacity .15s ease, background .15s ease; }
6954
+ .message-copy { min-width: 44px; min-height: 32px; margin-top: 6px; padding: 4px 10px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; border: 0; border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; font-size: .78em; opacity: 0; transition: opacity .15s ease, background .15s ease; }
6851
6955
  .message:hover .message-copy, .message:focus-within .message-copy { opacity: 1; }
6852
6956
  .conversation-status { margin: 4px auto 14px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .82em; text-align: center; }
6853
- .conversation-error { display: flex; gap: 12px; align-items: center; justify-content: space-between; margin: 8px 0 16px; padding: 12px 14px; color: var(--ns-assistant-danger, var(--ns-assistant-default-danger)); border: 1px solid color-mix(in srgb, var(--ns-assistant-danger, var(--ns-assistant-default-danger)) 28%, transparent); border-radius: 12px; background: color-mix(in srgb, var(--ns-assistant-danger, var(--ns-assistant-default-danger)) 7%, transparent); }
6957
+ .conversation-error { display: flex; gap: 12px; align-items: center; justify-content: space-between; margin: 8px 0 16px; padding: 12px 14px; color: var(--ns-assistant-danger, var(--ns-assistant-default-danger)); border: 1px solid color-mix(in srgb, var(--ns-assistant-danger, var(--ns-assistant-default-danger)) 28%, transparent); border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: color-mix(in srgb, var(--ns-assistant-danger, var(--ns-assistant-default-danger)) 7%, transparent); }
6854
6958
  .conversation-error p { margin: 0; }
6855
- .conversation-error button { min-height: 44px; padding: 8px 12px; color: var(--ns-assistant-secondary-button-text, inherit); background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-secondary-button-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 10px; cursor: pointer; font-weight: 600; }
6856
- .new-messages { position: absolute; left: 50%; bottom: 82px; z-index: 1; min-height: 36px; padding: 7px 12px; color: var(--ns-assistant-secondary-button-text, inherit); background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-secondary-button-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 999px; box-shadow: 0 4px 18px rgba(0,0,0,.12); transform: translateX(-50%); cursor: pointer; }
6857
- .message.assistant { color: var(--ns-assistant-assistant-message-text, inherit); background: var(--ns-assistant-assistant-message, transparent); border: 1px solid var(--ns-assistant-assistant-message-border, transparent); }
6858
- .message.user { display: grid; justify-items: start; gap: 3px; margin-left: auto; padding: 10px 16px 8px; color: var(--ns-assistant-user-message-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-user-message, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-user-message-border, transparent); font-size: .94em; }
6959
+ .conversation-error button { min-height: 44px; padding: 8px 14px; color: var(--ns-assistant-secondary-button-text, inherit); background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-secondary-button-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); cursor: pointer; font-weight: 600; }
6960
+ .new-messages { position: absolute; left: 50%; bottom: 14px; z-index: 2; width: 44px; height: 44px; padding: 0; color: var(--ns-assistant-secondary-button-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-secondary-button, color-mix(in srgb, var(--ns-assistant-input, var(--ns-assistant-default-input)) 92%, transparent)); border: 1px solid var(--ns-assistant-secondary-button-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); box-shadow: 0 8px 24px rgba(0,0,0,.12); transform: translateX(-50%); cursor: pointer; }
6961
+ .new-messages::before { content: ''; display: block; width: 18px; height: 18px; margin: auto; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 9 6 6 6-6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m6 9 6 6 6-6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; }
6962
+ .message.assistant { max-width: 100%; color: var(--ns-assistant-assistant-message-text, inherit); background: var(--ns-assistant-assistant-message, transparent); border: 1px solid var(--ns-assistant-assistant-message-border, transparent); }
6963
+ .message.user { display: grid; max-width: 85%; justify-items: start; gap: 3px; margin-left: auto; padding: 10px 16px 8px; color: var(--ns-assistant-user-message-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-user-message, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-user-message-border, transparent); border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); font-size: .94em; }
6859
6964
  .message.user time { margin-top: 0; }
6860
6965
  .markdown { white-space: normal; }
6861
6966
  .markdown p { margin: 0 0 8px; }
@@ -6870,13 +6975,14 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
6870
6975
  .markdown ul, .markdown ol { margin: 8px 0; padding-left: 22px; }
6871
6976
  .markdown li { margin: 3px 0; }
6872
6977
  .markdown blockquote { margin: 10px 0; padding-left: 12px; border-left: 3px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
6873
- .markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown h6 { margin: 14px 0 7px; line-height: 1.25; letter-spacing: -.015em; }
6978
+ .markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown h6 { margin: 14px 0 7px; line-height: 1.25; letter-spacing: 0; }
6874
6979
  .markdown h1:first-child, .markdown h2:first-child, .markdown h3:first-child { margin-top: 0; }
6875
6980
  .markdown h1 { font-size: 1.3em; } .markdown h2 { font-size: 1.18em; } .markdown h3 { font-size: 1.08em; }
6981
+ .message.assistant.streaming .markdown::after { content: ''; display: inline-block; width: 2px; height: 1em; margin-left: 3px; border-radius: 999px; background: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); vertical-align: -.14em; animation: halo-caret-blink 1s steps(2, start) infinite; }
6876
6982
  .message.thinking > span { display: inline-block; color: transparent; background: linear-gradient(90deg, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)) 25%, var(--ns-assistant-text, var(--ns-assistant-default-text)) 50%, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)) 75%); background-size: 300% 100%; background-clip: text; -webkit-background-clip: text; font-style: italic; font-weight: 500; animation: halo-shimmer 2s linear infinite; }
6877
6983
  .tool-proposal { display: grid; gap: 12px; align-items: start; margin: 8px 0 16px; padding: 18px; color: var(--ns-assistant-confirmation-text, inherit); border: 1px solid var(--ns-assistant-confirmation-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-card-radius, 14px); background: var(--ns-assistant-confirmation, var(--ns-assistant-input, var(--ns-assistant-default-input))); animation: halo-message-in .2s ease both; }
6878
6984
  .proposal-eyebrow { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
6879
- .tool-proposal h3 { margin: -4px 0 0; font-size: 1.08em; line-height: 1.3; letter-spacing: -.01em; }
6985
+ .tool-proposal h3 { margin: -4px 0 0; font-size: 1.08em; line-height: 1.3; letter-spacing: 0; }
6880
6986
  .proposal-description { margin: -4px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
6881
6987
  .proposal-arguments { display: grid; grid-template-columns: minmax(100px, .7fr) minmax(0, 1.3fr); gap: 8px 14px; margin: 0; padding: 12px 0; border-block: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); font-size: .9em; }
6882
6988
  .proposal-arguments .proposal-arguments { grid-column: 1 / -1; padding: 4px 0 0; border: 0; }
@@ -6887,7 +6993,7 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
6887
6993
  .proposal-details summary { min-height: 36px; padding: 8px 0; cursor: pointer; font-weight: 600; }
6888
6994
  .proposal-details .proposal-arguments { margin-top: 4px; }
6889
6995
  .proposal-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: end; }
6890
- .tool-proposal button { min-height: 44px; padding: 9px 14px; border: 1px solid var(--ns-assistant-secondary-button-border, transparent); border-radius: var(--ns-assistant-button-radius, 12px); color: var(--ns-assistant-secondary-button-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); cursor: pointer; font-weight: 600; }
6996
+ .tool-proposal button { min-height: 44px; padding: 9px 16px; border: 1px solid var(--ns-assistant-secondary-button-border, transparent); border-radius: var(--ns-assistant-button-radius, var(--ns-assistant-default-button-radius)); color: var(--ns-assistant-secondary-button-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); cursor: pointer; font-weight: 600; }
6891
6997
  .tool-proposal .proposal-accept { color: var(--ns-assistant-primary-button-text, var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text))); background: var(--ns-assistant-primary-button, var(--ns-assistant-accent, var(--ns-assistant-default-accent))); border-color: var(--ns-assistant-primary-button-border, transparent); }
6892
6998
  .tool-proposal button:disabled { opacity: .55; cursor: not-allowed; }
6893
6999
  .tool-proposal button { min-height: 45px; }
@@ -6896,9 +7002,9 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
6896
7002
  .input-request form { display: grid; gap: 10px; align-items: stretch; min-height: 0; margin: 0; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
6897
7003
  .input-request form:focus-within { box-shadow: none; }
6898
7004
  .input-request label { display: grid; gap: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .9em; }
6899
- .input-request input, .input-request select { width: 100%; padding: 8px 10px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); outline: 0; font: inherit; }
6900
- .input-request select[multiple] { min-height: 88px; }
6901
- .input-request input[type="checkbox"] { width: auto; justify-self: start; accent-color: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }
7005
+ .input-request input, .input-request select { width: 100%; min-height: 44px; padding: 8px 14px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-input, var(--ns-assistant-default-input)); border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); outline: 0; font: inherit; }
7006
+ .input-request select[multiple] { min-height: 88px; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); }
7007
+ .input-request input[type="checkbox"] { width: auto; min-height: auto; justify-self: start; accent-color: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }
6902
7008
  .input-request input:focus-visible, .input-request select:focus-visible { border-color: var(--ns-assistant-focus, var(--ns-assistant-default-focus)); box-shadow: 0 0 0 2px var(--ns-assistant-focus, var(--ns-assistant-default-focus)); }
6903
7009
  .input-request .proposal-actions { margin-top: 2px; }
6904
7010
  .noodle-app-card { position: relative; display: grid; gap: 8px; width: 100%; margin: 4px 0 16px; overflow: hidden; color: var(--ns-assistant-app-text, inherit); border: 1px solid var(--ns-assistant-app-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-app, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); }
@@ -6907,15 +7013,15 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
6907
7013
  .noodle-app-fallback { padding: 14px 16px; font-size: 13px; color: var(--ns-assistant-muted, var(--ns-assistant-default-muted, #6b7280)); }
6908
7014
  .noodle-app-card[data-fullscreen] { position: fixed; inset: 0; z-index: 2; margin: 0; border-radius: 0; background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); }
6909
7015
  .noodle-app-card[data-fullscreen] .noodle-app-frame { height: 100% !important; }
6910
- form { display: flex; flex: 0 0 auto; gap: 8px; align-items: center; min-height: 56px; margin: 8px 16px 16px; padding: 6px 6px 6px 16px; color: var(--ns-assistant-composer-text, inherit); border: 1px solid var(--ns-assistant-composer-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-input-radius, 14px); background: var(--ns-assistant-composer, var(--ns-assistant-input, var(--ns-assistant-default-input))); box-shadow: 0 1px 2px rgba(0,0,0,.04); transition: border-color .15s ease, box-shadow .15s ease; }
7016
+ form { display: flex; flex: 0 0 auto; gap: 8px; align-items: center; min-height: 56px; margin: 8px 16px 16px; padding: 6px 6px 6px 16px; color: var(--ns-assistant-composer-text, inherit); border: 1px solid var(--ns-assistant-composer-border, color-mix(in srgb, var(--ns-assistant-divider, var(--ns-assistant-default-divider)) 86%, transparent)); border-radius: var(--ns-assistant-input-radius, var(--ns-assistant-default-input-radius)); background: var(--ns-assistant-composer, color-mix(in srgb, var(--ns-assistant-input, var(--ns-assistant-default-input)) 92%, transparent)); box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.035); transition: border-color .15s ease, box-shadow .15s ease; }
6911
7017
  form:focus-within { box-shadow: inset 0 0 0 1px var(--ns-assistant-focus, var(--ns-assistant-default-focus)), 0 0 0 2px var(--ns-assistant-focus, var(--ns-assistant-default-focus)); }
6912
7018
  textarea { flex: 1; min-height: 24px; max-height: 120px; resize: none; padding: 0; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 0; border-radius: 0; outline: 0; box-shadow: none; appearance: none; -webkit-appearance: none; font: inherit; font-size: 16px; line-height: 24px; }
6913
7019
  textarea::placeholder { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
6914
7020
  textarea:focus, textarea:focus-visible { outline: none; box-shadow: none; }
6915
7021
  button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }
6916
- .send { position: relative; display: block; width: 44px; height: 44px; flex: 0 0 44px; padding: 0; overflow: hidden; color: transparent; background: var(--ns-assistant-primary-button, var(--ns-assistant-accent, var(--ns-assistant-default-accent))); font-size: 0; line-height: 0; transition: transform .15s ease, background .15s ease; }
7022
+ .send { position: relative; display: block; width: 44px; height: 44px; flex: 0 0 44px; padding: 0; overflow: hidden; color: transparent; border-radius: 999px; background: var(--ns-assistant-primary-button, var(--ns-assistant-accent, var(--ns-assistant-default-accent))); font-size: 0; line-height: 0; transition: transform .15s ease, background .15s ease; }
6917
7023
  .send::before { content: ''; position: absolute; top: 50%; left: 50%; width: 17px; height: 17px; background: var(--ns-assistant-primary-button-text, var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text))); transform: translate(-50%, -50%); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; }
6918
- .send:hover { transform: scale(1.05); background: var(--ns-assistant-hover, var(--ns-assistant-default-hover)); }
7024
+ .send:hover { transform: scale(1.05); background: var(--ns-assistant-hover, color-mix(in srgb, var(--ns-assistant-primary-button, var(--ns-assistant-accent, var(--ns-assistant-default-accent))) 88%, var(--ns-assistant-primary-button-text, var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text))) 12%)); }
6919
7025
  :host([busy]) .send::before { width: 13px; height: 13px; border-radius: 3px; -webkit-mask: none; mask: none; }
6920
7026
  .send:disabled, textarea:disabled { opacity: .55; cursor: not-allowed; }
6921
7027
  .legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 9px; font-size: .75em; }
@@ -6925,9 +7031,10 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
6925
7031
  @keyframes halo-panel-in { from { opacity: 0; transform: translateY(14px) scale(.985); } to { opacity: 1; transform: none; } }
6926
7032
  @keyframes halo-message-in { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
6927
7033
  @keyframes halo-shimmer { from { background-position: 100% center; } to { background-position: 0 center; } }
7034
+ @keyframes halo-caret-blink { 50% { opacity: 0; } }
6928
7035
  :host([data-density="compact"]) .welcome { padding: 20px 18px 12px; }
6929
- @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border: 0; border-radius: 0; } }
6930
- @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; } .messages { scroll-behavior: auto; } }
7036
+ @media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border: 0; border-radius: 0; } :host([mobile-fullscreen]) header { padding-top: max(12px, env(safe-area-inset-top)); padding-right: max(18px, env(safe-area-inset-right)); padding-left: max(18px, env(safe-area-inset-left)); } :host([mobile-fullscreen]) form { margin-right: max(16px, env(safe-area-inset-right)); margin-bottom: max(16px, env(safe-area-inset-bottom)); margin-left: max(16px, env(safe-area-inset-left)); } :host([mobile-fullscreen]) .legal, :host([mobile-fullscreen]) ::slotted([slot="conversation-footer"]) { padding-bottom: max(10px, env(safe-area-inset-bottom)); } }
7037
+ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; } .messages { scroll-behavior: auto; } .message.assistant.streaming .markdown::after { animation: none; } }
6931
7038
  @media (forced-colors: active) { .message.thinking > span { color: CanvasText; background: none; } }
6932
7039
  @media (hover: none) { .message-copy { opacity: 1; } }
6933
7040
  @media (max-width: 560px) { :host([data-mode="floating"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }
@@ -7246,6 +7353,8 @@ var presentationStyles = `<style>
7246
7353
  border: var(--ns-assistant-panel-border, var(--ns-assistant-presentation-border));
7247
7354
  border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-presentation-panel-radius, var(--ns-assistant-default-panel-radius)));
7248
7355
  box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-presentation-shadow));
7356
+ backdrop-filter: blur(var(--ns-assistant-backdrop-blur, var(--ns-assistant-default-backdrop-blur)));
7357
+ -webkit-backdrop-filter: blur(var(--ns-assistant-backdrop-blur, var(--ns-assistant-default-backdrop-blur)));
7249
7358
  }
7250
7359
  :host([data-panel-surface="solid"]) .panel {
7251
7360
  backdrop-filter: none;
@@ -7439,6 +7548,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7439
7548
  #hostAppearance;
7440
7549
  #appearanceWarningKeys = /* @__PURE__ */ new Set();
7441
7550
  #appearanceStyleSnapshot = /* @__PURE__ */ new Map();
7551
+ #scroll = new AssistantElementScrollController();
7442
7552
  sessionEndpoint = "";
7443
7553
  get appearance() {
7444
7554
  return this.#hostAppearance;
@@ -7466,6 +7576,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7466
7576
  labels: () => this.#appearance.labels,
7467
7577
  respond: (id, response) => this.respond(id, response),
7468
7578
  dispatchError: (detail) => this.#dispatchError(detail),
7579
+ revealLatest: () => this.#revealLatest(),
7469
7580
  renderView: (detail) => {
7470
7581
  const messages = this.#messages;
7471
7582
  const client = this.#client;
@@ -7476,7 +7587,8 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7476
7587
  {
7477
7588
  client,
7478
7589
  sendMessage: (message) => this.sendMessage(message),
7479
- updateModelContext: (update) => this.updateModelContext(update)
7590
+ updateModelContext: (update) => this.updateModelContext(update),
7591
+ theme: this.#resolvedMode()
7480
7592
  },
7481
7593
  {
7482
7594
  ...sandboxUrl === void 0 ? {} : { sandboxUrl },
@@ -7486,7 +7598,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7486
7598
  if (!view) return;
7487
7599
  messages.append(view);
7488
7600
  this.setAttribute("has-messages", "");
7489
- messages.scrollTop = messages.scrollHeight;
7601
+ this.#revealLatest();
7490
7602
  }
7491
7603
  });
7492
7604
  connectedCallback() {
@@ -7509,6 +7621,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7509
7621
  this.#clientEndpoint = "";
7510
7622
  this.#unsubscribeClient = void 0;
7511
7623
  this.#sessionBootstrap = void 0;
7624
+ this.#scroll.disconnect();
7512
7625
  this.#setBusy(false);
7513
7626
  this.#media?.removeEventListener("change", this.#handleSystemTheme);
7514
7627
  document.removeEventListener("keydown", this.#handleDocumentKeydown);
@@ -7791,18 +7904,10 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7791
7904
  this.#messages.append(status);
7792
7905
  }
7793
7906
  #scrollToBottom() {
7794
- if (this.#messages) this.#messages.scrollTop = this.#messages.scrollHeight;
7907
+ this.#scroll.scrollToBottom();
7795
7908
  }
7796
7909
  #revealLatest() {
7797
- if (!this.#messages) return;
7798
- const distance = this.#messages.scrollHeight - this.#messages.scrollTop - this.#messages.clientHeight;
7799
- const control = this.shadowRoot?.querySelector(".new-messages");
7800
- if (distance <= 160) {
7801
- this.#scrollToBottom();
7802
- if (control) control.hidden = true;
7803
- } else if (control) {
7804
- control.hidden = false;
7805
- }
7910
+ this.#scroll.revealLatest();
7806
7911
  }
7807
7912
  #dispatchError(detail) {
7808
7913
  this.dispatchEvent(new CustomEvent("assistant-error", { detail }));
@@ -7919,6 +8024,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7919
8024
  }
7920
8025
  #render() {
7921
8026
  if (!this.shadowRoot) return;
8027
+ this.#scroll.disconnect();
7922
8028
  const conversation = this.#messages ? [...this.#messages.childNodes] : [];
7923
8029
  const appearance = this.#appearance;
7924
8030
  this.setAttribute("role", "complementary");
@@ -7932,11 +8038,13 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7932
8038
  this.shadowRoot.innerHTML = `${ASSISTANT_ELEMENT_STYLES}${presentationStyles}
7933
8039
  <button class="launcher" type="button" aria-label="${escapeAttribute(appearance.labels.open)}" aria-controls="assistant-panel" aria-expanded="${String(this.hasAttribute("open"))}"><slot name="launcher-icon"></slot><span class="visually-hidden" data-session-status aria-live="polite" hidden></span></button>
7934
8040
  <section class="panel" id="assistant-panel" role="dialog" aria-label="${escapeAttribute(appearance.brand.name)}">
7935
- <header><slot name="header-leading"></slot><img class="brand-logo" alt=""><strong></strong><slot name="header-actions"></slot><button class="close" type="button" aria-label="${escapeAttribute(appearance.labels.close)}">\xD7</button></header>
8041
+ <header><slot name="header-leading"></slot><img class="brand-logo" alt=""><strong></strong><slot name="header-actions"></slot><button class="close" type="button" aria-label="${escapeAttribute(appearance.labels.close)}"></button></header>
7936
8042
  <div class="welcome"><slot name="empty-state"></slot></div>
7937
8043
  <div class="suggested-prompts"></div>
7938
- <div class="messages" aria-live="polite"></div>
7939
- <button class="new-messages" type="button" hidden></button>
8044
+ <div class="messages-region">
8045
+ <div class="messages" aria-live="polite"></div>
8046
+ <button class="new-messages" type="button" aria-label="${escapeAttribute(appearance.labels.newMessages)}" hidden></button>
8047
+ </div>
7940
8048
  <form><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
7941
8049
  <nav class="legal" aria-label="Legal"></nav>
7942
8050
  <slot name="conversation-footer"></slot>
@@ -7998,15 +8106,11 @@ var NoodleAssistantElement = class extends HTMLElementBase {
7998
8106
  form.requestSubmit();
7999
8107
  });
8000
8108
  const newMessages = queryRequired(this.shadowRoot, ".new-messages");
8001
- newMessages.textContent = appearance.labels.newMessages;
8002
- newMessages.addEventListener("click", () => {
8003
- this.#scrollToBottom();
8004
- newMessages.hidden = true;
8005
- });
8006
- this.#messages?.addEventListener("scroll", () => {
8007
- if (this.#messages && this.#messages.scrollHeight - this.#messages.scrollTop - this.#messages.clientHeight < 48) {
8008
- newMessages.hidden = true;
8009
- }
8109
+ newMessages.setAttribute("aria-label", appearance.labels.newMessages);
8110
+ this.#scroll.connect({
8111
+ region: queryRequired(this.shadowRoot, ".messages-region"),
8112
+ messages: queryRequired(this.shadowRoot, ".messages"),
8113
+ control: newMessages
8010
8114
  });
8011
8115
  this.#applyTheme();
8012
8116
  }
@@ -8041,4 +8145,4 @@ export {
8041
8145
  dompurify/dist/purify.es.mjs:
8042
8146
  (*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE *)
8043
8147
  */
8044
- //# sourceMappingURL=chunk-35A7REQX.js.map
8148
+ //# sourceMappingURL=chunk-JMBUJSFP.js.map