@noodleseed/assistant 1.7.0 → 1.9.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 +101 -22
  2. package/dist/{appearance-DowzFJjh.d.cts → appearance-Cc-eqSbp.d.cts} +1 -1
  3. package/dist/{appearance-DowzFJjh.d.ts → appearance-Cc-eqSbp.d.ts} +1 -1
  4. package/dist/{chunk-UXPKSCID.js → chunk-3YYTUJPJ.js} +2 -2
  5. package/dist/{chunk-35A7REQX.js → chunk-4B3XXGRP.js} +256 -91
  6. package/dist/chunk-4B3XXGRP.js.map +1 -0
  7. package/dist/{chunk-NSBPE2FW.js → chunk-5FUTL2UF.js} +6 -1
  8. package/dist/chunk-BLMJHF7U.js +544 -0
  9. package/dist/chunk-BLMJHF7U.js.map +1 -0
  10. package/dist/chunk-RYQBXTLR.js +9089 -0
  11. package/dist/chunk-RYQBXTLR.js.map +1 -0
  12. package/dist/{client-D2Y9UFh3.d.cts → client-B803xZVn.d.ts} +44 -2
  13. package/dist/{client-DBuETUVD.d.ts → client-CsmtpD1z.d.cts} +44 -2
  14. package/dist/client.cjs +22976 -92
  15. package/dist/client.cjs.map +1 -1
  16. package/dist/client.d.cts +3 -2
  17. package/dist/client.d.ts +3 -2
  18. package/dist/client.js +3 -2
  19. package/dist/index.cjs +10750 -2212
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +4 -3
  22. package/dist/index.d.ts +4 -3
  23. package/dist/index.js +4 -4
  24. package/dist/react/client.cjs +23688 -0
  25. package/dist/react/client.cjs.map +1 -0
  26. package/dist/react/client.d.cts +24 -0
  27. package/dist/react/client.d.ts +24 -0
  28. package/dist/react/client.js +76 -0
  29. package/dist/react/client.js.map +1 -0
  30. package/dist/react.cjs +10803 -2215
  31. package/dist/react.cjs.map +1 -1
  32. package/dist/react.d.cts +23 -4
  33. package/dist/react.d.ts +23 -4
  34. package/dist/react.js +64 -14
  35. package/dist/react.js.map +1 -1
  36. package/dist/server.d.cts +1 -1
  37. package/dist/server.d.ts +1 -1
  38. package/dist/server.js +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-35A7REQX.js.map +0 -1
  46. package/dist/chunk-7E5HINN4.js +0 -713
  47. package/dist/chunk-7E5HINN4.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 and secure
6
+ `NoodleAppView` MCP App renderer from `@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
@@ -142,10 +143,10 @@ markup-looking text stays text. `presentation.panel.radius` is a bounded panel-s
142
143
  not a second color or identity source. An HTTPS or packaged SVG referenced by `branding.logo`, `branding.mark`, or
143
144
  `branding.avatar` is a bounded asset, not inline renderer markup.
144
145
 
145
- If `presentation` is omitted, the quiet premium baseline remains: solid panel, soft elevation, subtle
146
- border/motion, medium brand-mark launcher without status or effect, undecorated header, pill composer with
147
- no leading icon and an arrow-up send icon, and bubble user/plain assistant messages at comfortable width.
148
- 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.
149
150
 
150
151
  ### Configure and deploy
151
152
 
@@ -210,8 +211,68 @@ import { NoodleAssistant } from "@noodleseed/assistant/react";
210
211
  <NoodleAssistant sessionEndpoint="/api/assistant/session" theme="auto" />;
211
212
  ```
212
213
 
213
- For a customer-owned renderer, subscribe to the same turn and interaction stream without registering a
214
- 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
+ When the customer-owned transcript should render the linked MCP App itself, pass the typed `data-view`
251
+ payload and the same client to the supported host component:
252
+
253
+ ```tsx
254
+ import { NoodleAppView } from "@noodleseed/assistant/react";
255
+
256
+ if (part.type === "data-view") {
257
+ return (
258
+ <NoodleAppView
259
+ key={`${part.data.id}:${part.data.resourceUri}`}
260
+ client={client}
261
+ view={part.data}
262
+ theme="dark"
263
+ onError={(failure) => reportAssistantError(failure)}
264
+ />
265
+ );
266
+ }
267
+ ```
268
+
269
+ `NoodleAppView` owns the double iframe and AppBridge. Its lifecycle identity is the supplied client plus
270
+ `view.id` plus `view.resourceUri`: ordinary parent rerenders and fresh view/callback objects retain the
271
+ iframe, while a semantic view replacement or unmount requests standard App teardown and closes the bridge.
272
+ Do not also key an ancestor by the whole view object or a callback.
273
+
274
+ Outside React, subscribe to the DOM-free AI SDK `UIMessage` state without registering a custom element or
275
+ touching browser storage:
215
276
 
216
277
  ```ts
217
278
  import { createAssistantClient } from "@noodleseed/assistant/client";
@@ -229,19 +290,34 @@ assistant.updateModelContext({
229
290
  structuredContent: { widget: { name: "time-off", lifecycle: "mounted" } },
230
291
  });
231
292
 
232
- const unsubscribe = assistant.subscribe((event) => {
233
- renderAssistantEvent(event);
234
- if (event.event === "view_available") {
235
- renderRegisteredView(event.data.resourceUri, event.data.result);
293
+ const unsubscribe = assistant.subscribeChat((state) => {
294
+ renderUIMessageState(state);
295
+ for (const message of state.messages) {
296
+ for (const part of message.parts) {
297
+ if (part.type === "data-confirmation" && part.data.status === "pending") {
298
+ renderConfirmation(part.data, (response) =>
299
+ assistant.respond(part.data.id, response),
300
+ );
301
+ }
302
+ if (part.type === "data-view") {
303
+ renderRegisteredView(part.data.resourceUri, part.data.result);
304
+ }
305
+ }
236
306
  }
237
307
  });
238
308
  await assistant.sendMessage("Book next Thursday and Friday off");
239
- await assistant.respond("interaction_123", { action: "accept" });
240
- // Resolve one interaction once; alternatives are { action: 'decline' } or { action: 'cancel' }.
241
309
 
242
310
  unsubscribe();
243
311
  ```
244
312
 
313
+ `subscribeChat` immediately emits a detached `{ messages, status, error? }` snapshot and then emits as the
314
+ AI SDK `UIMessage.parts` change. Assistant text uses `text`; confirmations, structured input requests, tool
315
+ results, and linked MCP Apps use `data-confirmation`, `data-input-request`, `data-tool-result`, and
316
+ `data-view`. Interaction data moves through `pending`, `submitting`, `accepted`, `declined`, or `cancelled`.
317
+ Use the lower-level `subscribe(...)` event stream only for transport and session lifecycle observations that
318
+ do not belong in the transcript. The package uses the headless `ai` runtime only; React remains an optional
319
+ peer isolated to the `/react` and `/react/client` entries.
320
+
245
321
  `clientContext` contains untrusted locale/timezone presentation hints and is evaluated for every turn.
246
322
  The client resolves a turn or interaction only after exactly one valid terminal `done` event followed by
247
323
  stream EOF. A truncated or malformed stream, duplicate `done`, or any frame after `done` is
@@ -279,10 +355,13 @@ leaves the same input interaction pending so the renderer can submit a corrected
279
355
  flow collects all elicited input before its first connector operation.
280
356
 
281
357
  A completed widget-linked tool emits typed `view_available` data with its call/interaction id, tool,
282
- `ui://` resource identity, optional title, and bounded/redacted public result. This is an availability
283
- signal, not proof of rendering. Map the identity to a component already trusted by your application; never
284
- fetch the `ui://` URI or inject its resource HTML into your page. The standard element does not render it,
285
- but forwards the same detail as a DOM event:
358
+ `ui://` resource identity, optional title, bounded/redacted public result, and—on current services—the
359
+ self-contained App document. This is an availability signal, not proof of rendering. A customer-owned React
360
+ renderer either mounts the actual App with `NoodleAppView` or deliberately substitutes a component already
361
+ trusted by the application and selected by `resourceUri`/tool. The JSON `result` is data for a native
362
+ component; serializing it is not a rendering of the linked App. Never fetch the `ui://` URI, inject
363
+ `part.data.html`, or assign it to `srcdoc` yourself. The standard element also forwards the same detail as a
364
+ DOM event:
286
365
 
287
366
  ```ts
288
367
  element.addEventListener("assistant-view-available", (event) => {
@@ -133,4 +133,4 @@ interface AssistantLabels {
133
133
  readonly sessionError: string;
134
134
  }
135
135
 
136
- export type { AssistantThemeMode as A, AssistantConfiguration as a };
136
+ export type { AssistantConfiguration as A, AssistantThemeMode as a };
@@ -133,4 +133,4 @@ interface AssistantLabels {
133
133
  readonly sessionError: string;
134
134
  }
135
135
 
136
- export type { AssistantThemeMode as A, AssistantConfiguration as a };
136
+ export type { AssistantConfiguration as A, AssistantThemeMode as a };
@@ -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