@noodleseed/assistant 1.6.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 (50) hide show
  1. package/README.md +78 -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-ZKXOX67J.js → chunk-JMBUJSFP.js} +233 -87
  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-9kup0-ws.d.cts → client-BxoNZkWp.d.cts} +50 -1
  11. package/dist/{client-BRjZMXlk.d.ts → client-ERQCAH_0.d.ts} +50 -1
  12. package/dist/client.cjs +22983 -94
  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 +10706 -2177
  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 +10706 -2176
  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.cjs.map +1 -1
  35. package/dist/server.d.cts +3 -0
  36. package/dist/server.d.ts +3 -0
  37. package/dist/server.js +1 -1
  38. package/dist/server.js.map +1 -1
  39. package/dist/token-Y6KCR3JT.js +70 -0
  40. package/dist/token-Y6KCR3JT.js.map +1 -0
  41. package/dist/token-util-XFYMRPAB.js +6 -0
  42. package/dist/{v4-2UXPDMWJ.js → v4-KBRL3YLO.js} +3 -3
  43. package/dist/v4-KBRL3YLO.js.map +1 -0
  44. package/package.json +14 -3
  45. package/dist/chunk-GTYYQNGT.js +0 -708
  46. package/dist/chunk-GTYYQNGT.js.map +0 -1
  47. package/dist/chunk-ZKXOX67J.js.map +0 -1
  48. /package/dist/{chunk-UXPKSCID.js.map → chunk-3YYTUJPJ.js.map} +0 -0
  49. /package/dist/{chunk-NSBPE2FW.js.map → chunk-5FUTL2UF.js.map} +0 -0
  50. /package/dist/{v4-2UXPDMWJ.js.map → token-util-XFYMRPAB.js.map} +0 -0
package/README.md CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  Customer-branded embedded assistant surfaces for Noodle Seed deployments.
4
4
 
5
- The package exports the canonical `<noodle-assistant>` Web Component, a React wrapper from
6
- `@noodleseed/assistant/react`, a DOM-free client from `@noodleseed/assistant/client`, and the backend-only
7
- `createAssistantSession` helper from `@noodleseed/assistant/server`. Light, dark, and automatic themes work
8
- without configuration; the component inherits the deployed MCP server's brand kit while slots, methods,
9
- events, and semantic CSS variables let a SaaS developer integrate it without depending on internal DOM
10
- selectors.
5
+ The package exports the canonical `<noodle-assistant>` Web Component, a managed React wrapper from
6
+ `@noodleseed/assistant/react`, a renderer-free React hook from
7
+ `@noodleseed/assistant/react/client`, a DOM-free client from `@noodleseed/assistant/client`, and the
8
+ backend-only `createAssistantSession` helper from `@noodleseed/assistant/server`. Light, dark, and automatic
9
+ themes work without configuration; the component inherits the deployed MCP server's brand kit while slots,
10
+ methods, events, and semantic CSS variables let a SaaS developer integrate it without depending on internal
11
+ DOM selectors.
11
12
 
12
13
  Never pass an embed client secret, model key, MCP token, or raw application session into the browser
13
14
  component. Exchange the already-authenticated user from the customer backend and return only the short-lived
@@ -32,6 +33,11 @@ The full, always-current integration guide (access modes, session response contr
32
33
  troubleshooting) lives at <https://docs.noodleseed.dev/guides/embedded-assistant>. Authoring and deploying
33
34
  the server itself is `@noodleseed/one` (`npm install -g @noodleseed/one`).
34
35
 
36
+ If your page sends a `Content-Security-Policy`, allow the Noodle service origin in `connect-src` (turns and
37
+ event streams) **and** `frame-src` (app widgets render inside a hosted sandbox document served from the
38
+ service origin, `endpoints.sandbox`, so your `script-src` can stay strict). Details are in the guide's
39
+ "Content-Security-Policy on your page" section.
40
+
35
41
  ## Quick start
36
42
 
37
43
  Install the package in the customer web application with that application's existing package manager. For
@@ -137,10 +143,10 @@ markup-looking text stays text. `presentation.panel.radius` is a bounded panel-s
137
143
  not a second color or identity source. An HTTPS or packaged SVG referenced by `branding.logo`, `branding.mark`, or
138
144
  `branding.avatar` is a bounded asset, not inline renderer markup.
139
145
 
140
- If `presentation` is omitted, the quiet premium baseline remains: solid panel, soft elevation, subtle
141
- border/motion, medium brand-mark launcher without status or effect, undecorated header, pill composer with
142
- no leading icon and an arrow-up send icon, and bubble user/plain assistant messages at comfortable width.
143
- Partial objects merge with those defaults.
146
+ If `presentation` is omitted, the rounded Halo-inspired baseline remains: a frosted glass panel with a 24px
147
+ radius, soft elevation, subtle border/motion, medium brand-mark launcher without status or effect,
148
+ undecorated header, pill composer and action controls, and rounded user bubbles with plain assistant messages
149
+ at comfortable width. Partial objects merge with those defaults.
144
150
 
145
151
  ### Configure and deploy
146
152
 
@@ -205,8 +211,44 @@ import { NoodleAssistant } from "@noodleseed/assistant/react";
205
211
  <NoodleAssistant sessionEndpoint="/api/assistant/session" theme="auto" />;
206
212
  ```
207
213
 
208
- For a customer-owned renderer, subscribe to the same turn and interaction stream without registering a
209
- custom element or touching browser storage:
214
+ Or keep the Noodle backend and own every rendered element in React:
215
+
216
+ ```tsx
217
+ "use client";
218
+
219
+ import { useNoodleAssistant } from "@noodleseed/assistant/react/client";
220
+ import { YourChatUI } from "./your-chat-ui";
221
+
222
+ export function CustomAssistant({ principalKey }: { principalKey: string }) {
223
+ const { client, messages, status, error } = useNoodleAssistant({
224
+ sessionEndpoint: "/api/assistant/session",
225
+ principalKey,
226
+ });
227
+
228
+ return (
229
+ <YourChatUI
230
+ messages={messages}
231
+ status={status}
232
+ error={error}
233
+ onSend={(text) => client.sendMessage(text)}
234
+ onStop={() => client.abort()}
235
+ onRespond={(id, response) => client.respond(id, response)}
236
+ />
237
+ );
238
+ }
239
+ ```
240
+
241
+ `useNoodleAssistant` owns client lifetime and React subscription only. It renders no Noodle markup,
242
+ registers no custom element, and returns `{ client, messages, status, error }`. `client` remains the one
243
+ command surface for messages, interactions, context, Apps requests, session resets, and aborts. A
244
+ customer-owned renderer must present every interaction it supports, await or catch command promises, and
245
+ preserve the typed part semantics; it must not invent user messages when an accepted, declined, or cancelled
246
+ interaction streams a continuation. `principalKey` is browser-local and never sent to Noodle. Change it
247
+ whenever the authenticated user or tenant changes so the hook aborts and clears the previous session and
248
+ transcript.
249
+
250
+ Outside React, subscribe to the DOM-free AI SDK `UIMessage` state without registering a custom element or
251
+ touching browser storage:
210
252
 
211
253
  ```ts
212
254
  import { createAssistantClient } from "@noodleseed/assistant/client";
@@ -224,19 +266,34 @@ assistant.updateModelContext({
224
266
  structuredContent: { widget: { name: "time-off", lifecycle: "mounted" } },
225
267
  });
226
268
 
227
- const unsubscribe = assistant.subscribe((event) => {
228
- renderAssistantEvent(event);
229
- if (event.event === "view_available") {
230
- renderRegisteredView(event.data.resourceUri, event.data.result);
269
+ const unsubscribe = assistant.subscribeChat((state) => {
270
+ renderUIMessageState(state);
271
+ for (const message of state.messages) {
272
+ for (const part of message.parts) {
273
+ if (part.type === "data-confirmation" && part.data.status === "pending") {
274
+ renderConfirmation(part.data, (response) =>
275
+ assistant.respond(part.data.id, response),
276
+ );
277
+ }
278
+ if (part.type === "data-view") {
279
+ renderRegisteredView(part.data.resourceUri, part.data.result);
280
+ }
281
+ }
231
282
  }
232
283
  });
233
284
  await assistant.sendMessage("Book next Thursday and Friday off");
234
- await assistant.respond("interaction_123", { action: "accept" });
235
- // Resolve one interaction once; alternatives are { action: 'decline' } or { action: 'cancel' }.
236
285
 
237
286
  unsubscribe();
238
287
  ```
239
288
 
289
+ `subscribeChat` immediately emits a detached `{ messages, status, error? }` snapshot and then emits as the
290
+ AI SDK `UIMessage.parts` change. Assistant text uses `text`; confirmations, structured input requests, tool
291
+ results, and linked MCP Apps use `data-confirmation`, `data-input-request`, `data-tool-result`, and
292
+ `data-view`. Interaction data moves through `pending`, `submitting`, `accepted`, `declined`, or `cancelled`.
293
+ Use the lower-level `subscribe(...)` event stream only for transport and session lifecycle observations that
294
+ do not belong in the transcript. The package uses the headless `ai` runtime only; React remains an optional
295
+ peer isolated to the `/react` and `/react/client` entries.
296
+
240
297
  `clientContext` contains untrusted locale/timezone presentation hints and is evaluated for every turn.
241
298
  The client resolves a turn or interaction only after exactly one valid terminal `done` event followed by
242
299
  stream EOF. A truncated or malformed stream, duplicate `done`, or any frame after `done` is
@@ -276,8 +333,9 @@ flow collects all elicited input before its first connector operation.
276
333
  A completed widget-linked tool emits typed `view_available` data with its call/interaction id, tool,
277
334
  `ui://` resource identity, optional title, and bounded/redacted public result. This is an availability
278
335
  signal, not proof of rendering. Map the identity to a component already trusted by your application; never
279
- fetch the `ui://` URI or inject its resource HTML into your page. The standard element does not render it,
280
- but forwards the same detail as a DOM event:
336
+ fetch the `ui://` URI, inject `part.data.html`, or assign it to `srcdoc`. The standard element alone mounts
337
+ the service-supplied document through its double-iframe MCP Apps host, and it also forwards the same detail
338
+ as a DOM event:
281
339
 
282
340
  ```ts
283
341
  element.addEventListener("assistant-view-available", (event) => {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __export
3
- } from "./chunk-NSBPE2FW.js";
3
+ } from "./chunk-5FUTL2UF.js";
4
4
 
5
5
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
6
6
  var external_exports = {};
@@ -14764,4 +14764,4 @@ export {
14764
14764
  external_exports,
14765
14765
  v4_default
14766
14766
  };
14767
- //# sourceMappingURL=chunk-UXPKSCID.js.map
14767
+ //# sourceMappingURL=chunk-3YYTUJPJ.js.map
@@ -1,10 +1,14 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
3
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
4
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
5
  }) : x)(function(x) {
5
6
  if (typeof require !== "undefined") return require.apply(this, arguments);
6
7
  throw Error('Dynamic require of "' + x + '" is not supported');
7
8
  });
9
+ var __commonJS = (cb, mod) => function __require2() {
10
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
+ };
8
12
  var __export = (target, all) => {
9
13
  for (var name in all)
10
14
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -12,6 +16,7 @@ var __export = (target, all) => {
12
16
 
13
17
  export {
14
18
  __require,
19
+ __commonJS,
15
20
  __export
16
21
  };
17
- //# sourceMappingURL=chunk-NSBPE2FW.js.map
22
+ //# sourceMappingURL=chunk-5FUTL2UF.js.map