@noodleseed/assistant 1.28.0 → 1.29.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 (41) hide show
  1. package/dist/{app-view-element-mXHvcAXc.d.ts → app-view-element-kR8eqhyD.d.cts} +1 -1
  2. package/dist/{app-view-element-BjRkwNN1.d.cts → app-view-element-nY1svwHT.d.ts} +1 -1
  3. package/dist/app-view.d.cts +3 -3
  4. package/dist/app-view.d.ts +3 -3
  5. package/dist/{chunk-WJV4MJUR.js → chunk-3VZ3M5BE.js} +92 -9
  6. package/dist/{chunk-WJV4MJUR.js.map → chunk-3VZ3M5BE.js.map} +1 -1
  7. package/dist/{chunk-QH7PL3GU.js → chunk-DOWFW3KA.js} +259 -54
  8. package/dist/chunk-DOWFW3KA.js.map +1 -0
  9. package/dist/{client-CPFw8tfo.d.ts → client-contract-Bw9dtrhw.d.cts} +26 -35
  10. package/dist/{client-_xivfs4q.d.cts → client-contract-DjU9qsoP.d.ts} +26 -35
  11. package/dist/client.cjs +91 -8
  12. package/dist/client.cjs.map +1 -1
  13. package/dist/client.d.cts +12 -2
  14. package/dist/client.d.ts +12 -2
  15. package/dist/client.js +1 -1
  16. package/dist/embed.global.js +46 -46
  17. package/dist/index.cjs +348 -60
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +3 -3
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +2 -2
  22. package/dist/react/client.cjs +91 -8
  23. package/dist/react/client.cjs.map +1 -1
  24. package/dist/react/client.d.cts +2 -2
  25. package/dist/react/client.d.ts +2 -2
  26. package/dist/react/client.js +1 -1
  27. package/dist/react.cjs +348 -60
  28. package/dist/react.cjs.map +1 -1
  29. package/dist/react.d.cts +3 -3
  30. package/dist/react.d.ts +3 -3
  31. package/dist/react.js +2 -2
  32. package/dist/server-CMqlAnxs.d.cts +270 -0
  33. package/dist/server-CMqlAnxs.d.ts +270 -0
  34. package/dist/server.cjs.map +1 -1
  35. package/dist/server.d.cts +1 -121
  36. package/dist/server.d.ts +1 -121
  37. package/dist/server.js.map +1 -1
  38. package/package.json +1 -1
  39. package/dist/appearance-BpVu3lpk.d.cts +0 -146
  40. package/dist/appearance-BpVu3lpk.d.ts +0 -146
  41. package/dist/chunk-QH7PL3GU.js.map +0 -1
@@ -11,7 +11,7 @@ import {
11
11
  parseAssistantConfiguration,
12
12
  publicConfigurationUrl,
13
13
  sessionSourceKey
14
- } from "./chunk-WJV4MJUR.js";
14
+ } from "./chunk-3VZ3M5BE.js";
15
15
 
16
16
  // src/appearance.ts
17
17
  var common = {
@@ -154,11 +154,8 @@ var DEFAULT_APPEARANCE = {
154
154
  composer: { leadingIcon: "none", sendIcon: "arrow-up", shape: "pill" },
155
155
  messages: { userStyle: "bubble", assistantStyle: "plain" }
156
156
  },
157
- suggestedPrompts: [
158
- "What products do you have?",
159
- "Tell me about your business",
160
- "How can I get in touch?"
161
- ],
157
+ suggestedPrompts: [],
158
+ suggestedPromptsSource: "model",
162
159
  locale: "en",
163
160
  direction: "auto"
164
161
  };
@@ -191,11 +188,8 @@ function resolveAppearance(input = {}) {
191
188
  ...assistant?.labels
192
189
  },
193
190
  presentation: resolvePresentation(assistant?.presentation),
194
- suggestedPrompts: assistant?.suggestedPrompts ?? (branding?.name ? [
195
- "What products do you have?",
196
- `Tell me about ${branding.name}`,
197
- "How can I get in touch?"
198
- ] : DEFAULT_APPEARANCE.suggestedPrompts),
191
+ suggestedPrompts: assistant?.suggestedPrompts ?? [],
192
+ suggestedPromptsSource: assistant?.suggestedPrompts === void 0 ? "model" : "configured",
199
193
  ...assistant?.privacyUrl ? { privacyUrl: assistant.privacyUrl } : {},
200
194
  ...assistant?.termsUrl ? { termsUrl: assistant.termsUrl } : {},
201
195
  locale: assistant?.locale ?? DEFAULT_APPEARANCE.locale,
@@ -438,6 +432,22 @@ function appendConversationRecovery(input) {
438
432
  input.revealLatest();
439
433
  }
440
434
 
435
+ // src/element-error-recovery.ts
436
+ function renderConversationError(options) {
437
+ const { appearance, error } = options;
438
+ const detail = error instanceof AssistantClientError ? error.detail : { code: options.fallbackCode, retryable: false };
439
+ const startNewConversation = detail.serviceCode === "session_turn_budget_exhausted";
440
+ const reconnect = detail.retryable !== false || detail.serviceCode === void 0;
441
+ const recoveryAction = startNewConversation ? { label: appearance.labels.newConversation, run: () => options.startNewConversation() } : reconnect ? { label: appearance.labels.reconnect, run: () => options.reconnect() } : void 0;
442
+ appendConversationRecovery({
443
+ messages: options.messages,
444
+ message: detail.code === "session_expired" ? appearance.labels.sessionExpired : appearance.labels.unavailable,
445
+ ...recoveryAction === void 0 ? {} : { action: recoveryAction },
446
+ revealLatest: () => options.revealLatest()
447
+ });
448
+ return detail;
449
+ }
450
+
441
451
  // src/input-request-card.ts
442
452
  function createInputRequestCard(options) {
443
453
  const card = document.createElement("section");
@@ -4588,6 +4598,59 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
4588
4598
  @media (max-width: 560px) { :host([data-mode="floating"]:not([open])) { bottom: 20px; } :host([open]:not([mobile-fullscreen])) .panel { width: calc(100vw - 40px); max-height: calc(100dvh - 40px); } }
4589
4599
  </style>`;
4590
4600
 
4601
+ // src/element-suggestions-controller.ts
4602
+ var AssistantElementSuggestionsController = class {
4603
+ #host;
4604
+ #initialRequested = false;
4605
+ #dynamic;
4606
+ constructor(host) {
4607
+ this.#host = host;
4608
+ }
4609
+ reset() {
4610
+ this.#initialRequested = false;
4611
+ this.clear();
4612
+ }
4613
+ clear() {
4614
+ this.#dynamic = void 0;
4615
+ this.render();
4616
+ }
4617
+ handle(event) {
4618
+ if (event.event === "message_started" || event.event === "interaction_started") {
4619
+ this.clear();
4620
+ return;
4621
+ }
4622
+ if (event.event !== "suggested_prompts") return;
4623
+ this.#dynamic = event.data;
4624
+ this.render();
4625
+ }
4626
+ maybeLoadInitial() {
4627
+ const appearance = this.#host.appearance();
4628
+ if (this.#initialRequested || appearance.suggestedPromptsSource !== "model" || this.#host.hasMessages() || !this.#host.isOpen()) {
4629
+ return;
4630
+ }
4631
+ const client = this.#host.client();
4632
+ if (!client?.loadInitialSuggestions) return;
4633
+ this.#initialRequested = true;
4634
+ void client.loadInitialSuggestions().catch(() => {
4635
+ });
4636
+ }
4637
+ render() {
4638
+ const container = this.#host.root()?.querySelector(".suggested-prompts");
4639
+ if (!container) return;
4640
+ const appearance = this.#host.appearance();
4641
+ const hasMessages = this.#host.hasMessages();
4642
+ const prompts = (this.#dynamic?.phase === "follow_up" || !hasMessages ? this.#dynamic?.prompts : void 0) ?? (!hasMessages && appearance.suggestedPromptsSource === "configured" ? appearance.suggestedPrompts : []);
4643
+ container.replaceChildren();
4644
+ for (const prompt of prompts) {
4645
+ const button2 = document.createElement("button");
4646
+ button2.type = "button";
4647
+ button2.textContent = prompt;
4648
+ button2.addEventListener("click", () => this.#host.send(prompt));
4649
+ container.append(button2);
4650
+ }
4651
+ }
4652
+ };
4653
+
4591
4654
  // src/host-appearance.ts
4592
4655
  var ROLE_VARIABLES = {
4593
4656
  canvas: "--ns-assistant-canvas",
@@ -4896,6 +4959,147 @@ function applyAssistantElementTheme(input) {
4896
4959
  return warnings;
4897
4960
  }
4898
4961
 
4962
+ // src/webmcp-bridge.ts
4963
+ var INERT = { registeredToolNames: [], stop: () => {
4964
+ } };
4965
+ async function startWebMcpBridge(ports) {
4966
+ const { client, modelContext, enabled } = ports;
4967
+ if (!enabled || !modelContext) return INERT;
4968
+ let listed;
4969
+ try {
4970
+ listed = await client.requestApp("tools/list", {});
4971
+ } catch {
4972
+ return INERT;
4973
+ }
4974
+ const registrations = [];
4975
+ for (const tool of projectableTools(listed)) {
4976
+ registrations.push({
4977
+ name: tool.name,
4978
+ handle: modelContext.registerTool({
4979
+ name: tool.name,
4980
+ ...tool.description === void 0 ? {} : { description: tool.description },
4981
+ ...tool.inputSchema === void 0 ? {} : { inputSchema: tool.inputSchema },
4982
+ // Passed through, never inferred: an agent may use `readOnlyHint` to decide it can call
4983
+ // without asking, so a hint this bridge invented would be a hint nobody authored.
4984
+ ...tool.annotations === void 0 ? {} : { annotations: tool.annotations },
4985
+ execute: (args) => executeThroughAssistant(client, tool.name, args)
4986
+ })
4987
+ });
4988
+ }
4989
+ let stopped = false;
4990
+ return {
4991
+ get registeredToolNames() {
4992
+ return stopped ? [] : registrations.map((entry) => entry.name);
4993
+ },
4994
+ stop() {
4995
+ if (stopped) return;
4996
+ stopped = true;
4997
+ for (const entry of registrations) entry.handle?.unregister?.();
4998
+ }
4999
+ };
5000
+ }
5001
+ function projectableTools(listed) {
5002
+ const tools = isRecord3(listed) && Array.isArray(listed.tools) ? listed.tools : [];
5003
+ const projectable = [];
5004
+ for (const tool of tools) {
5005
+ if (!isRecord3(tool) || typeof tool.name !== "string" || tool.name.length === 0) continue;
5006
+ const visibility = readVisibility(tool);
5007
+ if (visibility !== void 0 && !(visibility.includes("app") && visibility.includes("model"))) {
5008
+ continue;
5009
+ }
5010
+ projectable.push({
5011
+ name: tool.name,
5012
+ description: typeof tool.description === "string" ? tool.description : void 0,
5013
+ inputSchema: isRecord3(tool.inputSchema) ? tool.inputSchema : void 0,
5014
+ annotations: isRecord3(tool.annotations) ? tool.annotations : void 0
5015
+ });
5016
+ }
5017
+ return projectable;
5018
+ }
5019
+ function readVisibility(tool) {
5020
+ const meta = isRecord3(tool._meta) ? tool._meta : void 0;
5021
+ const ui = meta && isRecord3(meta.ui) ? meta.ui : void 0;
5022
+ const visibility = ui?.visibility;
5023
+ return Array.isArray(visibility) ? visibility.filter((entry) => typeof entry === "string") : void 0;
5024
+ }
5025
+ async function executeThroughAssistant(client, name, args) {
5026
+ let suspend;
5027
+ const suspended = new Promise((resolve) => {
5028
+ suspend = resolve;
5029
+ });
5030
+ try {
5031
+ const call = client.requestApp(
5032
+ "tools/call",
5033
+ { name, arguments: args },
5034
+ // Attribution only: anyone holding the session token could send this, and it selects a
5035
+ // *narrower* budget than the unmarked path, so declaring it can only cost the declarer.
5036
+ { bridge: "webmcp", onSuspended: suspend }
5037
+ );
5038
+ void call.catch(() => {
5039
+ });
5040
+ const outcome = await Promise.race([
5041
+ call.then((value) => ({ kind: "result", value })),
5042
+ suspended.then(() => ({ kind: "confirmation" }))
5043
+ ]);
5044
+ return outcome.kind === "confirmation" ? CONFIRMATION_REQUIRED : toToolResult(outcome.value);
5045
+ } catch (error) {
5046
+ return textResult(error instanceof Error ? error.message : "tool call failed", true);
5047
+ }
5048
+ }
5049
+ var CONFIRMATION_REQUIRED = {
5050
+ content: [
5051
+ {
5052
+ type: "text",
5053
+ text: "confirmation required: open the assistant panel on this page to approve this action"
5054
+ }
5055
+ ],
5056
+ isError: true
5057
+ };
5058
+ function toToolResult(value) {
5059
+ if (isRecord3(value) && Array.isArray(value.content)) return value;
5060
+ return textResult(JSON.stringify(value ?? null), false);
5061
+ }
5062
+ function textResult(text2, isError) {
5063
+ return { content: [{ type: "text", text: text2 }], isError };
5064
+ }
5065
+ function isRecord3(value) {
5066
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5067
+ }
5068
+
5069
+ // src/element-webmcp-controller.ts
5070
+ var AssistantElementWebMcpController = class {
5071
+ #enabled = false;
5072
+ #bridge;
5073
+ /** Guards against a late `startWebMcpBridge` resolving after the session it belonged to is gone. */
5074
+ #generation = 0;
5075
+ /** Called when resolved configuration arrives; the deployment's opt-in is the only source. */
5076
+ configure(enabled) {
5077
+ this.#enabled = enabled;
5078
+ if (!enabled) this.stop();
5079
+ }
5080
+ start(client) {
5081
+ if (!this.#enabled || !client) return;
5082
+ const modelContext = browserModelContext();
5083
+ if (!modelContext) return;
5084
+ this.stop();
5085
+ const generation = ++this.#generation;
5086
+ void startWebMcpBridge({ client, modelContext, enabled: true }).then((bridge) => {
5087
+ if (generation === this.#generation) this.#bridge = bridge;
5088
+ else bridge.stop();
5089
+ });
5090
+ }
5091
+ stop() {
5092
+ this.#generation += 1;
5093
+ this.#bridge?.stop();
5094
+ this.#bridge = void 0;
5095
+ }
5096
+ };
5097
+ function browserModelContext() {
5098
+ if (typeof document === "undefined") return void 0;
5099
+ const host = document;
5100
+ return typeof host.modelContext?.registerTool === "function" ? host.modelContext : void 0;
5101
+ }
5102
+
4899
5103
  // src/presentation-styles.ts
4900
5104
  var presentationStyles = `<style>
4901
5105
  :host([data-mode="floating"]) {
@@ -5139,9 +5343,18 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5139
5343
  #turnInFlight = false;
5140
5344
  #fetch;
5141
5345
  #hostAppearance;
5346
+ #webmcp = new AssistantElementWebMcpController();
5142
5347
  #appearanceWarningKeys = /* @__PURE__ */ new Set();
5143
5348
  #appearanceStyleSnapshot = /* @__PURE__ */ new Map();
5144
5349
  #scroll = new AssistantElementScrollController();
5350
+ #suggestions = new AssistantElementSuggestionsController({
5351
+ root: () => this.shadowRoot,
5352
+ appearance: () => this.#appearance,
5353
+ client: () => this.#client,
5354
+ hasMessages: () => this.hasAttribute("has-messages"),
5355
+ isOpen: () => this.hasAttribute("open"),
5356
+ send: (prompt) => this.#sendGuarded(prompt)
5357
+ });
5145
5358
  sessionEndpoint = "";
5146
5359
  /** Public mount: the non-secret embed id `noodle deploy` printed. Mutually exclusive with the above. */
5147
5360
  embedId = "";
@@ -5253,6 +5466,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5253
5466
  this.#launcher.disconnect();
5254
5467
  this.#setBusy(false);
5255
5468
  this.#environment.disconnect();
5469
+ this.#webmcp.stop();
5256
5470
  }
5257
5471
  attributeChangedCallback(name) {
5258
5472
  if (name === "theme") this.#applyTheme();
@@ -5286,6 +5500,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5286
5500
  }
5287
5501
  resetSession() {
5288
5502
  this.#conversationGeneration += 1;
5503
+ this.#webmcp.stop();
5289
5504
  this.#client?.abort();
5290
5505
  this.#unsubscribeClient?.();
5291
5506
  this.#client = void 0;
@@ -5295,12 +5510,14 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5295
5510
  this.#events.resetConversation();
5296
5511
  this.#pendingUserEcho = void 0;
5297
5512
  this.removeAttribute("has-messages");
5513
+ this.#suggestions.reset();
5298
5514
  this.#setBusy(false);
5299
5515
  this.#setSessionState("idle");
5300
5516
  }
5301
5517
  /** Re-establish the session without replaying a message or interaction decision. */
5302
5518
  reconnect() {
5303
5519
  this.#conversationGeneration += 1;
5520
+ this.#webmcp.stop();
5304
5521
  this.#client?.abort();
5305
5522
  this.#unsubscribeClient?.();
5306
5523
  this.#client = void 0;
@@ -5358,6 +5575,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5358
5575
  this.#turnInFlight = true;
5359
5576
  this.#pendingUserEcho = message;
5360
5577
  this.#appendMessage("user", message);
5578
+ this.#suggestions.clear();
5361
5579
  this.#setBusy(true);
5362
5580
  if (this.#sessionState !== "ready") this.#setSessionState("loading");
5363
5581
  try {
@@ -5377,12 +5595,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5377
5595
  if (generation === this.#conversationGeneration) this.#setBusy(false);
5378
5596
  }
5379
5597
  }
5380
- /**
5381
- * Every listener the element attaches to its own DOM must go through this guard: internal UI
5382
- * failures surface as `assistant-error` events (already dispatched by the failing path) and must
5383
- * never escape as unhandled rejections into the embedding page. Programmatic callers use
5384
- * `sendMessage`/`confirmTool` directly and keep the rejection.
5385
- */
5598
+ /** DOM listeners swallow after the failing path dispatches its typed assistant-error event. */
5386
5599
  #sendGuarded(text2) {
5387
5600
  void this.sendMessage(text2).catch(() => {
5388
5601
  });
@@ -5434,13 +5647,21 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5434
5647
  }
5435
5648
  #primeSession() {
5436
5649
  if (!this.sessionEndpoint && !this.embedId) return;
5437
- if (this.#sessionBootstrap || this.#client?.hasSession()) return;
5650
+ if (this.#sessionBootstrap) return;
5651
+ if (this.#client?.hasSession()) {
5652
+ this.#suggestions.maybeLoadInitial();
5653
+ return;
5654
+ }
5438
5655
  if (this.#client?.isBusy?.() === true) return;
5439
5656
  if (this.embedId && !this.#pageContext) void this.#automaticPageContext.refresh();
5440
5657
  const client = this.#ensureClient();
5441
5658
  const generation = this.#conversationGeneration;
5442
5659
  this.#setSessionState("loading");
5443
- const bootstrap = client.connect().catch((error) => {
5660
+ const bootstrap = client.connect().then(() => {
5661
+ if (generation === this.#conversationGeneration && this.#client === client) {
5662
+ this.#suggestions.maybeLoadInitial();
5663
+ }
5664
+ }).catch((error) => {
5444
5665
  if (generation !== this.#conversationGeneration || this.#client !== client) return;
5445
5666
  this.#dispatchClientError(error, "session_failed");
5446
5667
  this.#presentationGate.reveal();
@@ -5452,15 +5673,18 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5452
5673
  #handleClientEvent(event) {
5453
5674
  this.dispatchEvent(new CustomEvent("assistant-event", { detail: event }));
5454
5675
  this.#events.handle(event);
5676
+ this.#suggestions.handle(event);
5455
5677
  if (event.event === "session_started") {
5456
5678
  this.#publicConfiguration.disconnect();
5457
5679
  this.removeAttribute("data-public-configuration-loading");
5458
5680
  this.#presentationGate.reveal();
5459
5681
  this.#setSessionState("ready");
5460
5682
  this.#messages?.querySelector(".conversation-error")?.remove();
5683
+ this.#webmcp.start(this.#client);
5461
5684
  }
5462
5685
  if (event.event === "session_expired" || event.event === "session_reset") {
5463
5686
  this.#setSessionState("idle");
5687
+ this.#webmcp.stop();
5464
5688
  }
5465
5689
  if (event.event === "tool_proposed" || event.event === "interaction_proposed" || event.event === "input_requested") {
5466
5690
  this.#removeThinking();
@@ -5564,23 +5788,17 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5564
5788
  if (error instanceof AssistantClientError && error.detail.code === "session_failed") {
5565
5789
  this.#setSessionState("error");
5566
5790
  }
5567
- const detail = error instanceof AssistantClientError ? error.detail : { code: fallbackCode, retryable: false };
5568
- const startNewConversation = detail.serviceCode === "session_turn_budget_exhausted";
5569
- const reconnect = detail.retryable !== false || detail.serviceCode === void 0;
5570
- const recoveryAction = startNewConversation ? {
5571
- label: this.#appearance.labels.newConversation,
5572
- run: () => this.#startNewConversation()
5573
- } : reconnect ? { label: this.#appearance.labels.reconnect, run: () => this.reconnect() } : void 0;
5574
- appendConversationRecovery({
5575
- messages: this.#messages,
5576
- message: detail.code === "session_expired" ? this.#appearance.labels.sessionExpired : this.#appearance.labels.unavailable,
5577
- // A spent or switched-off daily budget offers no retry. Reconnecting cannot succeed, and every
5578
- // open tab trying is exactly the load the cap was set to refuse — so the button goes, not just
5579
- // the alarming words. A spent *session* keeps it: reconnect mints a fresh one, which is the fix.
5580
- ...recoveryAction === void 0 ? {} : { action: recoveryAction },
5581
- revealLatest: () => this.#revealLatest()
5582
- });
5583
- this.#dispatchError(detail);
5791
+ this.#dispatchError(
5792
+ renderConversationError({
5793
+ messages: this.#messages,
5794
+ appearance: this.#appearance,
5795
+ error,
5796
+ fallbackCode,
5797
+ startNewConversation: () => this.#startNewConversation(),
5798
+ reconnect: () => this.reconnect(),
5799
+ revealLatest: () => this.#revealLatest()
5800
+ })
5801
+ );
5584
5802
  }
5585
5803
  #startNewConversation() {
5586
5804
  this.resetSession();
@@ -5613,7 +5831,9 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5613
5831
  }
5614
5832
  }
5615
5833
  #applyConfiguration(configuration) {
5834
+ this.#webmcp.configure(configuration.assistant?.webmcp?.enabled === true);
5616
5835
  this.#appearance = resolveAppearance(configuration);
5836
+ this.#suggestions.render();
5617
5837
  this.#syncAppearance();
5618
5838
  this.#applyStartOpenPolicy();
5619
5839
  }
@@ -5658,15 +5878,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5658
5878
  "aria-label",
5659
5879
  appearance.labels.close
5660
5880
  );
5661
- const prompts = queryRequired(this.shadowRoot, ".suggested-prompts");
5662
- prompts.replaceChildren();
5663
- for (const prompt of appearance.suggestedPrompts) {
5664
- const button2 = document.createElement("button");
5665
- button2.type = "button";
5666
- button2.textContent = prompt;
5667
- button2.addEventListener("click", () => this.#sendGuarded(prompt));
5668
- prompts.append(button2);
5669
- }
5881
+ this.#suggestions.render();
5670
5882
  queryRequired(this.shadowRoot, "header").hidden = !appearance.behavior.showHeader;
5671
5883
  const legal = queryRequired(this.shadowRoot, ".legal");
5672
5884
  legal.replaceChildren();
@@ -5704,14 +5916,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
5704
5916
  textarea.placeholder = appearance.labels.composerPlaceholder;
5705
5917
  textarea.setAttribute("aria-label", appearance.labels.composerPlaceholder);
5706
5918
  queryRequired(this.shadowRoot, ".send").textContent = appearance.labels.send;
5707
- const prompts = queryRequired(this.shadowRoot, ".suggested-prompts");
5708
- for (const prompt of appearance.suggestedPrompts) {
5709
- const button2 = document.createElement("button");
5710
- button2.type = "button";
5711
- button2.textContent = prompt;
5712
- button2.addEventListener("click", () => this.#sendGuarded(prompt));
5713
- prompts.append(button2);
5714
- }
5919
+ this.#suggestions.render();
5715
5920
  if (!appearance.behavior.showLauncher)
5716
5921
  queryRequired(this.shadowRoot, ".launcher").hidden = true;
5717
5922
  if (!appearance.behavior.showHeader)
@@ -5770,4 +5975,4 @@ export {
5770
5975
  dompurify/dist/purify.es.mjs:
5771
5976
  (*! @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 *)
5772
5977
  */
5773
- //# sourceMappingURL=chunk-QH7PL3GU.js.map
5978
+ //# sourceMappingURL=chunk-DOWFW3KA.js.map