@noodleseed/assistant 1.0.0 → 1.1.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.
package/README.md CHANGED
@@ -12,22 +12,54 @@ Never pass an embed client secret, model key, MCP token, or raw application sess
12
12
  component. Exchange the already-authenticated user from the customer backend and return only the short-lived
13
13
  assistant session.
14
14
 
15
+ The model configuration and SaaS integration credentials have different owners:
16
+
17
+ | Owner | Configuration | Destination |
18
+ | --- | --- | --- |
19
+ | Noodle deployment | `ASSISTANT_MODEL_BASE_URL`, `ASSISTANT_MODEL`, `ASSISTANT_MODEL_API_KEY` | Managed with `noodle variables set` / `noodle secrets set` |
20
+ | Customer backend | `NOODLE_SERVICE_URL`, `NOODLE_ASSISTANT_CLIENT_ID`, `NOODLE_ASSISTANT_CLIENT_SECRET` | Backend environment or secret manager only |
21
+
22
+ `allowedOrigins` accepts exact origins. Production origins must be HTTPS; plain HTTP is accepted only for
23
+ loopback development origins such as `http://localhost:3000`. Local MCP authoring remains available without
24
+ login, but an external browser embed needs an active deployment before its deployment-bound client can be
25
+ created.
26
+
27
+ Runtime requirements: Node.js 20+ for the server helper; the package ships ESM and CommonJS with full
28
+ export conditions, so bundlers and plain Node resolve it without aliases or type shims.
29
+
30
+ The full, always-current integration guide (access modes, session response contract, framework notes, and
31
+ troubleshooting) lives at <https://docs.noodleseed.dev/guides/embedded-assistant>. Authoring and deploying
32
+ the server itself is `@noodleseed/one` (`npm install -g @noodleseed/one`).
33
+
15
34
  ## Quick start
16
35
 
17
- Install the package in the customer web application:
36
+ Install the package in the customer web application with that application's existing package manager. For
37
+ example:
38
+
39
+ ```bash
40
+ npm install @noodleseed/assistant
41
+ ```
42
+
43
+ Configure the model through Noodle managed config, validate, and deploy the assistant-enabled server before
44
+ creating the embed client:
18
45
 
19
46
  ```bash
20
- pnpm add @noodleseed/assistant
47
+ noodle variables set ASSISTANT_MODEL_BASE_URL --scope env --org acme --app support --env prod --value https://model.example/v1
48
+ noodle variables set ASSISTANT_MODEL --scope env --org acme --app support --env prod --value your-model
49
+ noodle secrets set ASSISTANT_MODEL_API_KEY --scope env --org acme --app support --env prod --from-env ASSISTANT_MODEL_API_KEY
50
+ noodle check --target embedded-assistant
51
+ noodle deploy --org acme --app support --env prod
21
52
  ```
22
53
 
23
- Create an embed client after deploying an assistant-enabled server:
54
+ Then create the deployment-bound client:
24
55
 
25
56
  ```bash
26
57
  noodle assistant clients create --name web --org acme --app support --env prod
27
58
  ```
28
59
 
29
60
  The command saves `{ clientId, clientSecret }` to a mode-`0600` file and prints its path, never the secret.
30
- Load that file only in your backend. A framework route can exchange the current signed-in user like this:
61
+ Move those values to the customer backend's secret manager without printing or committing them. A framework
62
+ route can exchange the current signed-in user like this:
31
63
 
32
64
  ```ts
33
65
  import { createAssistantSession } from '@noodleseed/assistant/server';
@@ -65,6 +97,21 @@ import { NoodleAssistant } from '@noodleseed/assistant/react';
65
97
  <NoodleAssistant sessionEndpoint="/api/assistant/session" theme="auto" />;
66
98
  ```
67
99
 
100
+ Assistant text renders as provider deltas arrive. If a turn finds an expired session, the component calls
101
+ the same authenticated session endpoint and retries that unprocessed message once. Confirmations never
102
+ replay across sessions. React applications may observe recovery and structured failures:
103
+
104
+ ```tsx
105
+ <NoodleAssistant
106
+ sessionEndpoint="/api/assistant/session"
107
+ onSessionExpired={() => reportAssistantRecovery()}
108
+ onError={({ code, status, retryable }) => reportAssistantError({ code, status, retryable })}
109
+ />;
110
+ ```
111
+
112
+ `createAssistantSession` returns the opaque token, expiry, resolved non-secret configuration, and explicit
113
+ `endpoints.turns` / `endpoints.toolConfirmations` URLs. Forward that response unchanged to the component.
114
+
68
115
  The MCP server's top-level `branding` block provides the shared identity and theme for widgets and the
69
116
  assistant. Set semantic CSS variables only for application-level integration overrides:
70
117
 
@@ -0,0 +1,88 @@
1
+ type AssistantThemeMode = 'auto' | 'light' | 'dark';
2
+ type AssistantLayoutMode = 'floating' | 'inline' | 'drawer';
3
+ type AssistantPosition = 'bottom-left' | 'bottom-right';
4
+ interface AssistantConfiguration {
5
+ readonly branding?: {
6
+ readonly name?: string;
7
+ readonly accent?: string;
8
+ readonly surface?: string;
9
+ readonly surfaceDark?: string;
10
+ readonly logo?: AssistantBrandAsset;
11
+ readonly mark?: AssistantBrandAsset;
12
+ readonly avatar?: AssistantBrandAsset;
13
+ readonly theme?: {
14
+ readonly light?: BrandThemeOverrides;
15
+ readonly dark?: BrandThemeOverrides;
16
+ };
17
+ readonly radius?: 'none' | 'sm' | 'md' | 'lg';
18
+ readonly density?: 'compact' | 'comfortable';
19
+ readonly typography?: 'system' | 'serif' | 'mono';
20
+ readonly colorScheme?: AssistantThemeMode;
21
+ };
22
+ readonly assistant?: AssistantUiConfiguration;
23
+ }
24
+ interface AssistantBrandAsset {
25
+ readonly uri: string;
26
+ readonly darkUri?: string;
27
+ readonly alt: string;
28
+ }
29
+ interface BrandThemeOverrides {
30
+ readonly surface?: string;
31
+ readonly surfaceRaised?: string;
32
+ readonly surfaceMuted?: string;
33
+ readonly text?: string;
34
+ readonly textMuted?: string;
35
+ readonly accent?: string;
36
+ readonly accentText?: string;
37
+ readonly link?: string;
38
+ readonly border?: string;
39
+ readonly borderStrong?: string;
40
+ readonly focus?: string;
41
+ readonly success?: string;
42
+ readonly warning?: string;
43
+ readonly danger?: string;
44
+ readonly code?: string;
45
+ }
46
+ interface AssistantUiConfiguration {
47
+ readonly layout?: {
48
+ readonly mode?: AssistantLayoutMode;
49
+ readonly position?: AssistantPosition;
50
+ readonly panelWidth?: number;
51
+ readonly panelMinHeight?: number;
52
+ readonly panelMaxHeight?: number;
53
+ readonly zIndex?: number;
54
+ readonly density?: 'compact' | 'comfortable';
55
+ readonly mobileFullscreen?: boolean;
56
+ };
57
+ readonly behavior?: {
58
+ readonly startOpen?: boolean;
59
+ readonly closeOnEscape?: boolean;
60
+ readonly closeOnOutsideClick?: boolean;
61
+ readonly showLauncher?: boolean;
62
+ readonly showHeader?: boolean;
63
+ readonly showAvatars?: boolean;
64
+ readonly showTimestamps?: boolean;
65
+ };
66
+ readonly labels?: Partial<AssistantLabels>;
67
+ readonly suggestedPrompts?: readonly string[];
68
+ readonly privacyUrl?: string;
69
+ readonly termsUrl?: string;
70
+ readonly locale?: string;
71
+ readonly direction?: 'ltr' | 'rtl' | 'auto';
72
+ }
73
+ interface AssistantLabels {
74
+ readonly welcomeHeading: string;
75
+ readonly welcomeMessage: string;
76
+ readonly composerPlaceholder: string;
77
+ readonly send: string;
78
+ readonly stop: string;
79
+ readonly close: string;
80
+ readonly open: string;
81
+ readonly confirm: string;
82
+ readonly cancel: string;
83
+ readonly retry: string;
84
+ readonly unavailable: string;
85
+ readonly sessionExpired: string;
86
+ }
87
+
88
+ export type { AssistantThemeMode as A, AssistantConfiguration as a };
@@ -0,0 +1,88 @@
1
+ type AssistantThemeMode = 'auto' | 'light' | 'dark';
2
+ type AssistantLayoutMode = 'floating' | 'inline' | 'drawer';
3
+ type AssistantPosition = 'bottom-left' | 'bottom-right';
4
+ interface AssistantConfiguration {
5
+ readonly branding?: {
6
+ readonly name?: string;
7
+ readonly accent?: string;
8
+ readonly surface?: string;
9
+ readonly surfaceDark?: string;
10
+ readonly logo?: AssistantBrandAsset;
11
+ readonly mark?: AssistantBrandAsset;
12
+ readonly avatar?: AssistantBrandAsset;
13
+ readonly theme?: {
14
+ readonly light?: BrandThemeOverrides;
15
+ readonly dark?: BrandThemeOverrides;
16
+ };
17
+ readonly radius?: 'none' | 'sm' | 'md' | 'lg';
18
+ readonly density?: 'compact' | 'comfortable';
19
+ readonly typography?: 'system' | 'serif' | 'mono';
20
+ readonly colorScheme?: AssistantThemeMode;
21
+ };
22
+ readonly assistant?: AssistantUiConfiguration;
23
+ }
24
+ interface AssistantBrandAsset {
25
+ readonly uri: string;
26
+ readonly darkUri?: string;
27
+ readonly alt: string;
28
+ }
29
+ interface BrandThemeOverrides {
30
+ readonly surface?: string;
31
+ readonly surfaceRaised?: string;
32
+ readonly surfaceMuted?: string;
33
+ readonly text?: string;
34
+ readonly textMuted?: string;
35
+ readonly accent?: string;
36
+ readonly accentText?: string;
37
+ readonly link?: string;
38
+ readonly border?: string;
39
+ readonly borderStrong?: string;
40
+ readonly focus?: string;
41
+ readonly success?: string;
42
+ readonly warning?: string;
43
+ readonly danger?: string;
44
+ readonly code?: string;
45
+ }
46
+ interface AssistantUiConfiguration {
47
+ readonly layout?: {
48
+ readonly mode?: AssistantLayoutMode;
49
+ readonly position?: AssistantPosition;
50
+ readonly panelWidth?: number;
51
+ readonly panelMinHeight?: number;
52
+ readonly panelMaxHeight?: number;
53
+ readonly zIndex?: number;
54
+ readonly density?: 'compact' | 'comfortable';
55
+ readonly mobileFullscreen?: boolean;
56
+ };
57
+ readonly behavior?: {
58
+ readonly startOpen?: boolean;
59
+ readonly closeOnEscape?: boolean;
60
+ readonly closeOnOutsideClick?: boolean;
61
+ readonly showLauncher?: boolean;
62
+ readonly showHeader?: boolean;
63
+ readonly showAvatars?: boolean;
64
+ readonly showTimestamps?: boolean;
65
+ };
66
+ readonly labels?: Partial<AssistantLabels>;
67
+ readonly suggestedPrompts?: readonly string[];
68
+ readonly privacyUrl?: string;
69
+ readonly termsUrl?: string;
70
+ readonly locale?: string;
71
+ readonly direction?: 'ltr' | 'rtl' | 'auto';
72
+ }
73
+ interface AssistantLabels {
74
+ readonly welcomeHeading: string;
75
+ readonly welcomeMessage: string;
76
+ readonly composerPlaceholder: string;
77
+ readonly send: string;
78
+ readonly stop: string;
79
+ readonly close: string;
80
+ readonly open: string;
81
+ readonly confirm: string;
82
+ readonly cancel: string;
83
+ readonly retry: string;
84
+ readonly unavailable: string;
85
+ readonly sessionExpired: string;
86
+ }
87
+
88
+ export type { AssistantThemeMode as A, AssistantConfiguration as a };