@noodleseed/assistant 1.21.0 → 1.23.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 (44) hide show
  1. package/README.md +47 -9
  2. package/dist/app-view-element-1i_w6FDf.d.cts +40 -0
  3. package/dist/app-view-element-7ZQZLYbL.d.ts +40 -0
  4. package/dist/app-view.cjs +18666 -0
  5. package/dist/app-view.cjs.map +1 -0
  6. package/dist/app-view.d.cts +9 -0
  7. package/dist/app-view.d.ts +9 -0
  8. package/dist/app-view.js +15 -0
  9. package/dist/app-view.js.map +1 -0
  10. package/dist/chunk-5NBHHNI3.js +180 -0
  11. package/dist/chunk-5NBHHNI3.js.map +1 -0
  12. package/dist/{chunk-ZPZHPXIQ.js → chunk-IBDP6PXQ.js} +9 -3882
  13. package/dist/chunk-IBDP6PXQ.js.map +1 -0
  14. package/dist/chunk-P223CYPO.js +3880 -0
  15. package/dist/chunk-P223CYPO.js.map +1 -0
  16. package/dist/{chunk-LEKEIHJV.js → chunk-X7UQDIGS.js} +824 -4049
  17. package/dist/chunk-X7UQDIGS.js.map +1 -0
  18. package/dist/chunk-XKTUXFGX.js +3323 -0
  19. package/dist/chunk-XKTUXFGX.js.map +1 -0
  20. package/dist/{client-BkJlpN5N.d.ts → client-Bp_VKpMg.d.ts} +1 -1
  21. package/dist/{client-BZ7xPwfW.d.cts → client-uo57Swlm.d.cts} +1 -1
  22. package/dist/client.d.cts +1 -1
  23. package/dist/client.d.ts +1 -1
  24. package/dist/client.js +2 -1
  25. package/dist/embed.global.js +90 -75
  26. package/dist/index.cjs +111 -24
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +2 -2
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +4 -2
  31. package/dist/index.js.map +1 -1
  32. package/dist/react/client.d.cts +1 -1
  33. package/dist/react/client.d.ts +1 -1
  34. package/dist/react/client.js +2 -1
  35. package/dist/react/client.js.map +1 -1
  36. package/dist/react.cjs +299 -56
  37. package/dist/react.cjs.map +1 -1
  38. package/dist/react.d.cts +7 -8
  39. package/dist/react.d.ts +7 -8
  40. package/dist/react.js +31 -41
  41. package/dist/react.js.map +1 -1
  42. package/package.json +16 -2
  43. package/dist/chunk-LEKEIHJV.js.map +0 -1
  44. package/dist/chunk-ZPZHPXIQ.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -22112,11 +22112,11 @@ function isAllowedAppLink(value, allowedDomains, baseUrl) {
22112
22112
  return void 0;
22113
22113
  }
22114
22114
  }
22115
- function createAssistantAppHostContext(theme) {
22115
+ function createAssistantAppHostContext(theme, allowFullscreen = false, displayMode = "inline") {
22116
22116
  return {
22117
22117
  theme,
22118
- displayMode: "inline",
22119
- availableDisplayModes: ["inline", "fullscreen"],
22118
+ displayMode: allowFullscreen && displayMode === "fullscreen" ? "fullscreen" : "inline",
22119
+ availableDisplayModes: allowFullscreen ? ["inline", "fullscreen"] : ["inline"],
22120
22120
  platform: "web"
22121
22121
  };
22122
22122
  }
@@ -22142,6 +22142,13 @@ function mountAssistantApp(detail, actions, options = {}) {
22142
22142
  title.textContent = detail.title;
22143
22143
  card.append(title);
22144
22144
  }
22145
+ const exitFullscreen = document.createElement("button");
22146
+ exitFullscreen.className = "noodle-app-fullscreen-exit";
22147
+ exitFullscreen.type = "button";
22148
+ exitFullscreen.setAttribute("aria-label", "Exit fullscreen");
22149
+ exitFullscreen.title = "Exit fullscreen";
22150
+ exitFullscreen.hidden = true;
22151
+ card.append(exitFullscreen);
22145
22152
  const frame = document.createElement("iframe");
22146
22153
  frame.className = "noodle-app-frame";
22147
22154
  frame.title = detail.title ?? detail.tool;
@@ -22155,8 +22162,31 @@ function mountAssistantApp(detail, actions, options = {}) {
22155
22162
  let mountedTransport;
22156
22163
  let destroyed = false;
22157
22164
  let initialized = false;
22158
- let hostContext = createAssistantAppHostContext(actions.theme);
22165
+ let currentTheme = actions.theme;
22166
+ let displayMode = "inline";
22167
+ let hostContext = createAssistantAppHostContext(
22168
+ currentTheme,
22169
+ options.allowFullscreen === true,
22170
+ displayMode
22171
+ );
22159
22172
  let destroyPromise;
22173
+ const applyDisplayMode = (requestedMode) => {
22174
+ displayMode = requestedMode === "fullscreen" && options.allowFullscreen === true ? "fullscreen" : "inline";
22175
+ card.toggleAttribute("data-fullscreen", displayMode === "fullscreen");
22176
+ exitFullscreen.hidden = displayMode !== "fullscreen";
22177
+ hostContext = createAssistantAppHostContext(
22178
+ currentTheme,
22179
+ options.allowFullscreen === true,
22180
+ displayMode
22181
+ );
22182
+ if (initialized) mountedBridge?.setHostContext(hostContext);
22183
+ return displayMode;
22184
+ };
22185
+ exitFullscreen.addEventListener("click", () => {
22186
+ if (destroyed) return;
22187
+ applyDisplayMode("inline");
22188
+ frame.focus();
22189
+ });
22160
22190
  const renderTimer = setTimeout(() => {
22161
22191
  if (initialized || !frame.isConnected) return;
22162
22192
  const note = document.createElement("div");
@@ -22214,6 +22244,11 @@ function mountAssistantApp(detail, actions, options = {}) {
22214
22244
  actions.updateModelContext(update);
22215
22245
  return {};
22216
22246
  };
22247
+ bridge.onrequestteardown = () => {
22248
+ if (destroyed) return;
22249
+ options.onTeardownRequest?.();
22250
+ void destroy();
22251
+ };
22217
22252
  bridge.onopenlink = async ({ url: url2 }) => {
22218
22253
  if (destroyed) return { isError: true };
22219
22254
  const current = options.getDetail?.() ?? detail;
@@ -22227,10 +22262,8 @@ function mountAssistantApp(detail, actions, options = {}) {
22227
22262
  return {};
22228
22263
  };
22229
22264
  bridge.onrequestdisplaymode = async ({ mode }) => {
22230
- const accepted = mode === "fullscreen" ? "fullscreen" : "inline";
22231
- if (destroyed) return { mode: accepted };
22232
- card.toggleAttribute("data-fullscreen", accepted === "fullscreen");
22233
- return { mode: accepted };
22265
+ if (destroyed) return { mode: displayMode };
22266
+ return { mode: applyDisplayMode(mode) };
22234
22267
  };
22235
22268
  bridge.oncalltool = async (params) => {
22236
22269
  if (destroyed) {
@@ -22275,7 +22308,12 @@ function mountAssistantApp(detail, actions, options = {}) {
22275
22308
  );
22276
22309
  const updateTheme = (theme) => {
22277
22310
  if (destroyed) return;
22278
- hostContext = createAssistantAppHostContext(theme);
22311
+ currentTheme = theme;
22312
+ hostContext = createAssistantAppHostContext(
22313
+ currentTheme,
22314
+ options.allowFullscreen === true,
22315
+ displayMode
22316
+ );
22279
22317
  if (initialized) mountedBridge?.setHostContext(hostContext);
22280
22318
  };
22281
22319
  const destroy = () => {
@@ -31596,6 +31634,33 @@ var AssistantElementPageContextController = class {
31596
31634
  }
31597
31635
  };
31598
31636
 
31637
+ // src/element-presentation-gate.ts
31638
+ var AssistantElementPresentationGate = class {
31639
+ #host;
31640
+ #primeSession;
31641
+ #focusComposer;
31642
+ constructor(host, primeSession, focusComposer) {
31643
+ this.#host = host;
31644
+ this.#primeSession = primeSession;
31645
+ this.#focusComposer = focusComposer;
31646
+ }
31647
+ syncOpenState() {
31648
+ const open = this.#host.hasAttribute("open");
31649
+ const presentationReady = this.#host.hasAttribute("data-presentation-ready");
31650
+ const launcher = this.#host.shadowRoot?.querySelector(".launcher");
31651
+ launcher?.setAttribute("aria-expanded", String(open && presentationReady));
31652
+ launcher?.setAttribute("aria-busy", String(open && !presentationReady));
31653
+ if (launcher) launcher.disabled = open && !presentationReady;
31654
+ if (open && this.#host.isConnected) this.#primeSession();
31655
+ }
31656
+ reveal() {
31657
+ if (this.#host.hasAttribute("data-presentation-ready")) return;
31658
+ this.#host.setAttribute("data-presentation-ready", "");
31659
+ this.syncOpenState();
31660
+ if (this.#host.hasAttribute("open")) queueMicrotask(this.#focusComposer);
31661
+ }
31662
+ };
31663
+
31599
31664
  // src/element-scroll-controller.ts
31600
31665
  var AssistantElementScrollController = class {
31601
31666
  #region;
@@ -31697,6 +31762,29 @@ var AssistantElementScrollController = class {
31697
31762
  }
31698
31763
  };
31699
31764
 
31765
+ // src/app-view-styles.ts
31766
+ var ASSISTANT_APP_VIEW_CSS = `
31767
+ .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, var(--ns-app-view-border, #d1d5db)))); border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius, 12px)); background: var(--ns-assistant-app, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated, var(--ns-app-view-surface, #fff)))); }
31768
+ .noodle-app-title { padding: 10px 12px 0; font-size: .86em; font-weight: 650; }
31769
+ .noodle-app-fullscreen-exit { position: absolute; top: max(12px, env(safe-area-inset-top)); right: max(12px, env(safe-area-inset-right)); z-index: 1; display: grid; place-items: center; width: 44px; height: 44px; padding: 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text, var(--ns-app-view-muted, #6b7280))); border: 1px solid var(--ns-assistant-secondary-button-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider, var(--ns-app-view-border, #d1d5db)))); border-radius: 999px; background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated, var(--ns-app-view-surface, #fff)))); box-shadow: 0 6px 20px rgba(0,0,0,.14); cursor: pointer; font: inherit; transition: color .15s ease, background .15s ease, transform .15s ease; }
31770
+ .noodle-app-fullscreen-exit[hidden] { display: none; }
31771
+ .noodle-app-fullscreen-exit::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; }
31772
+ .noodle-app-fullscreen-exit:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text, inherit)); background: var(--ns-assistant-hover, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated, var(--ns-app-view-surface, #fff)))); }
31773
+ .noodle-app-fullscreen-exit:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus, #2563eb)); outline-offset: 2px; }
31774
+ .noodle-app-fullscreen-exit:active { transform: scale(.96); }
31775
+ .noodle-app-frame { display: block; width: 100%; min-height: 120px; border: 0; background: transparent; }
31776
+ .noodle-app-fallback { padding: 14px 16px; font-size: 13px; color: var(--ns-assistant-muted, var(--ns-assistant-default-muted, var(--ns-app-view-muted, #6b7280))); }
31777
+ .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, var(--ns-app-view-surface, #fff))); }
31778
+ .noodle-app-card[data-fullscreen] .noodle-app-frame { height: 100% !important; }
31779
+ `;
31780
+ var ASSISTANT_APP_VIEW_STYLES = `<style>
31781
+ *, *::before, *::after { box-sizing: border-box; }
31782
+ :host { --ns-app-view-surface: #fff; --ns-app-view-border: #d1d5db; --ns-app-view-muted: #6b7280; display: block; min-width: 0; color: #111827; color-scheme: light; font: inherit; }
31783
+ :host([data-theme="dark"]) { --ns-app-view-surface: #17191f; --ns-app-view-border: #343741; --ns-app-view-muted: #a7adb8; color: #f3f4f6; color-scheme: dark; }
31784
+ :host([hidden]) { display: none; }
31785
+ ${ASSISTANT_APP_VIEW_CSS}
31786
+ </style>`;
31787
+
31700
31788
  // src/element-styles.ts
31701
31789
  var ASSISTANT_ELEMENT_STYLES = `<style>
31702
31790
  *, *::before, *::after { box-sizing: border-box; }
@@ -31711,9 +31799,10 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
31711
31799
  .launcher:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 26px rgba(0,0,0,.16); }
31712
31800
  .launcher img { width: 28px; height: 28px; border-radius: 50%; object-fit: contain; }
31713
31801
  .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; }
31714
- :host([open]) .panel { display: flex; }
31802
+ :host([open][data-presentation-ready]) .panel { display: flex; }
31715
31803
  .panel { position: relative; }
31716
- :host([open]) .launcher { display: none; }
31804
+ :host([open][data-presentation-ready]) .launcher { display: none; }
31805
+ :host([open]:not([data-presentation-ready])) .launcher { cursor: progress; opacity: .72; transform: none; }
31717
31806
  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); }
31718
31807
  header strong { flex: 1; font-size: 16px; font-weight: 600; letter-spacing: 0; }
31719
31808
  .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }
@@ -31798,12 +31887,7 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
31798
31887
  .input-request input[type="checkbox"] { width: auto; min-height: auto; justify-self: start; accent-color: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }
31799
31888
  .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)); }
31800
31889
  .input-request .proposal-actions { margin-top: 2px; }
31801
- .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))); }
31802
- .noodle-app-title { padding: 10px 12px 0; font-size: .86em; font-weight: 650; }
31803
- .noodle-app-frame { display: block; width: 100%; min-height: 120px; border: 0; background: transparent; }
31804
- .noodle-app-fallback { padding: 14px 16px; font-size: 13px; color: var(--ns-assistant-muted, var(--ns-assistant-default-muted, #6b7280)); }
31805
- .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)); }
31806
- .noodle-app-card[data-fullscreen] .noodle-app-frame { height: 100% !important; }
31890
+ ${ASSISTANT_APP_VIEW_CSS}
31807
31891
  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; }
31808
31892
  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)); }
31809
31893
  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; }
@@ -32339,6 +32423,11 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32339
32423
  #automaticPageContext = new AssistantElementPageContextController(
32340
32424
  () => !this.#pageContext
32341
32425
  );
32426
+ #presentationGate = new AssistantElementPresentationGate(
32427
+ this,
32428
+ () => this.#primeSession(),
32429
+ () => this.focusComposer()
32430
+ );
32342
32431
  #pendingUserEcho;
32343
32432
  #sessionState = "idle";
32344
32433
  #startOpenApplied = false;
@@ -32409,6 +32498,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32409
32498
  if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute("session-endpoint") ?? "";
32410
32499
  if (!this.embedId) this.embedId = this.getAttribute("embed-id") ?? "";
32411
32500
  if (!this.serviceUrl) this.serviceUrl = this.getAttribute("service-url") ?? "";
32501
+ if (!this.sessionEndpoint && !this.embedId) this.#presentationGate.reveal();
32412
32502
  this.#media = globalThis.matchMedia?.("(prefers-color-scheme: dark)");
32413
32503
  this.#media?.addEventListener("change", this.#handleSystemTheme);
32414
32504
  document.addEventListener("keydown", this.#handleDocumentKeydown);
@@ -32425,7 +32515,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32425
32515
  } else if (!this.embedId) {
32426
32516
  this.#primeSession();
32427
32517
  }
32428
- this.#syncOpenState();
32518
+ this.#presentationGate.syncOpenState();
32429
32519
  }
32430
32520
  disconnectedCallback() {
32431
32521
  this.#conversationGeneration += 1;
@@ -32443,7 +32533,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32443
32533
  }
32444
32534
  attributeChangedCallback(name21) {
32445
32535
  if (name21 === "theme") this.#applyTheme();
32446
- if (name21 === "open") this.#syncOpenState();
32536
+ if (name21 === "open") this.#presentationGate.syncOpenState();
32447
32537
  }
32448
32538
  open() {
32449
32539
  this.setAttribute("open", "");
@@ -32633,6 +32723,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32633
32723
  const bootstrap = client.connect().catch((error51) => {
32634
32724
  if (generation !== this.#conversationGeneration || this.#client !== client) return;
32635
32725
  this.#dispatchClientError(error51, "session_failed");
32726
+ this.#presentationGate.reveal();
32636
32727
  }).finally(() => {
32637
32728
  if (this.#sessionBootstrap === bootstrap) this.#sessionBootstrap = void 0;
32638
32729
  });
@@ -32642,6 +32733,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32642
32733
  this.dispatchEvent(new CustomEvent("assistant-event", { detail: event }));
32643
32734
  this.#events.handle(event);
32644
32735
  if (event.event === "session_started") {
32736
+ this.#presentationGate.reveal();
32645
32737
  this.#setSessionState("ready");
32646
32738
  this.#messages?.querySelector(".conversation-error")?.remove();
32647
32739
  }
@@ -32811,11 +32903,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32811
32903
  this.#sessionState = state;
32812
32904
  syncAssistantSessionVisualState(this, this.shadowRoot, state, this.#appearance);
32813
32905
  }
32814
- #syncOpenState() {
32815
- const open = this.hasAttribute("open");
32816
- this.shadowRoot?.querySelector(".launcher")?.setAttribute("aria-expanded", String(open));
32817
- if (open && this.isConnected) this.#primeSession();
32818
- }
32819
32906
  #closeAndRestoreFocus() {
32820
32907
  this.close();
32821
32908
  this.shadowRoot?.querySelector(".launcher")?.focus();