@interopio/io-assist-ng 0.0.1 → 1.0.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
@@ -1,218 +1,589 @@
1
1
  # @interopio/io-assist-ng
2
2
 
3
- Angular library for integrating io.Intelligence AI assistance capabilities into Angular applications (Angular 20.3+).
3
+ A full-featured AI assistant component for Angular applications. Drop a single `<io-assist>` tag into your app and get a conversational AI chat interface backed by any [AG-UI Protocol](https://docs.ag-ui.com) compatible agent server — with streaming responses, persistent threads, a prompt library, MCP tool access, working context awareness, and built-in sampling/elicitation handling.
4
+
5
+ Built on [io.Connect](https://interop.io/) and [@interopio/ai-web](https://www.npmjs.com/package/@interopio/ai-web).
6
+
7
+ ## Features
8
+
9
+ - **Conversational AI chat** — Streaming responses, markdown rendering, code highlighting
10
+ - **Persistent conversation threads** — Thread history with resume, rename, and delete
11
+ - **Prompt library** — Categorized pre-written prompts with favorites (persisted via IO Preferences)
12
+ - **MCP tool access** — Built-in io.Intelligence MCP server, extensible with remote and third-party servers
13
+ - **MCP Apps** — Custom HTML applications rendered inline in chat or in io.Connect workspace windows
14
+ - **Sampling & elicitation** — Built-in confirmation/input UI for MCP server requests (replaceable with custom handlers)
15
+ - **Working context** — Live data from io.Connect contexts passed to the agent with every message
16
+ - **Theming** — Automatic dark/light mode sync with io.Connect
17
+
18
+ ## Prerequisites
19
+
20
+ - **Angular** 20.3+
21
+ - **Node.js** 20.19+ (< 22)
22
+ - **npm** 10+
23
+ - An **AG-UI Protocol compatible agent server** (e.g. [Mastra](https://mastra.ai/))
4
24
 
5
25
  ## Installation
6
26
 
7
27
  ```bash
8
- npm install @interopio/io-assist-ng
28
+ npm install @interopio/io-assist-ng @interopio/browser
9
29
  ```
10
30
 
11
- ## Prerequisites
31
+ Peer dependencies (`@interopio/ai-web`, `@interopio/ng`, `@interopio/working-context`, `@angular/cdk`, `@ngrx/store`, `@ngrx/effects`, `@ngrx/store-devtools`, `zod`, and others) are installed automatically.
32
+
33
+ > Replace `@interopio/browser` with `@interopio/desktop` if targeting io.Connect Desktop.
34
+
35
+ ## Quickstart
36
+
37
+ ### New Angular project
38
+
39
+ If you don't have an Angular project yet, create one first:
40
+
41
+ ```bash
42
+ npm install -g @angular/cli
43
+ ng new my-app
44
+ cd my-app
45
+ npm install @interopio/io-assist-ng @interopio/browser
46
+ ```
12
47
 
13
- - Angular 20.3 or higher
14
- - Node.js 20.19+ (< 22)
15
- - npm 10.0.0 or higher
48
+ > See the full Angular setup guide at [angular.dev/installation](https://angular.dev/installation).
16
49
 
17
- ## Setup
50
+ ### Existing Angular project
18
51
 
19
- ### 1. Import Styles
52
+ ```bash
53
+ npm install @interopio/io-assist-ng @interopio/browser
54
+ ```
20
55
 
21
- Add the library styles to your Angular application:
56
+ ---
57
+
58
+ ### 1. Add the stylesheet
59
+
60
+ ```css title="src/styles.css"
61
+ @import "@interopio/io-assist-ng/styles.css";
62
+ ```
63
+
64
+ Or in `angular.json`:
22
65
 
23
- **Option A: In `angular.json`**
24
66
  ```json
25
- {
26
- "projects": {
27
- "your-app": {
28
- "architect": {
29
- "build": {
30
- "options": {
31
- "styles": [
32
- "node_modules/@interopio/io-assist-ng/styles.css",
33
- "src/styles.css"
34
- ]
35
- }
36
- }
37
- }
38
- }
39
- }
40
- }
67
+ "styles": [
68
+ "node_modules/@interopio/io-assist-ng/styles.css",
69
+ "src/styles.css"
70
+ ]
41
71
  ```
42
72
 
43
- **Option B: In `styles.css`/`styles.scss`**
44
- ```css
45
- @import '@interopio/io-assist-ng/styles.css';
73
+ ### 2. Configure providers
74
+
75
+ ```typescript title="src/app/app.config.ts"
76
+ import { ApplicationConfig } from '@angular/core';
77
+ import { provideIoAssist } from '@interopio/io-assist-ng';
78
+ import IOBrowser from '@interopio/browser';
79
+
80
+ export const appConfig: ApplicationConfig = {
81
+ providers: [
82
+ provideIoAssist({
83
+ connectConfig: {
84
+ browser: {
85
+ factory: IOBrowser,
86
+ },
87
+ },
88
+ aiWebConfig: {
89
+ agentServer: {
90
+ baseUrl: 'http://localhost:4111',
91
+ },
92
+ },
93
+ }),
94
+ ],
95
+ };
46
96
  ```
47
97
 
48
- ### 2. Import Components
98
+ ### 3. Add the component
49
99
 
50
- Import the components you need in your Angular component:
100
+ The component requires a `[config]` input with the current user's identity. Pass a signal so the assistant can react to auth state changes:
51
101
 
52
- ```typescript
53
- import { Component } from '@angular/core';
54
- import { IoAssist } from '@interopio/io-assist-ng';
102
+ ```typescript title="src/app/app.component.ts"
103
+ import { Component, signal } from '@angular/core';
104
+ import { IoAssist, IoAssistDynamicConfig } from '@interopio/io-assist-ng';
55
105
 
56
106
  @Component({
57
- selector: 'app-root',
58
- standalone: true,
59
- imports: [IoAssist],
60
- template: `
61
- <io-assist [config]="assistConfig"></io-assist>
62
- `
107
+ selector: 'app-root',
108
+ imports: [IoAssist],
109
+ template: `<io-assist [config]="dynamicConfig()" />`,
63
110
  })
64
111
  export class AppComponent {
65
- assistConfig = {
66
- // Your configuration here
67
- };
112
+ readonly dynamicConfig = signal<IoAssistDynamicConfig>({
113
+ // id: Your access/auth token of choice
114
+ // name: UI name tha will be displayed
115
+ user: { id: 'yourIdOfChoice', name: 'Jane Doe' },
116
+ agentServer: {
117
+ headers: {
118
+ Authorization: `Bearer ${import.meta.env.VITE_AUTH_TOKEN}`,
119
+ }
120
+ },
121
+ });
68
122
  }
69
123
  ```
70
124
 
71
- ## Configuration
72
-
73
- The `IoAssist` component accepts a configuration object via the `[config]` input:
125
+ ### 4. Run
74
126
 
75
- ```typescript
76
- import { IoAssistTempConfig } from '@interopio/io-assist-ng';
77
-
78
- const assistConfig: IoAssistTempConfig = {
79
- // Configuration options
80
- apiEndpoint: 'https://your-api-endpoint.com',
81
- theme: 'light', // or 'dark'
82
- // Add other configuration options as needed
83
- };
127
+ ```bash
128
+ ng serve
84
129
  ```
85
130
 
86
- ## Components
131
+ Open http://localhost:4200. **io.Assist is live.**
87
132
 
88
- ### IoAssist
133
+ ---
89
134
 
90
- Main component for AI assistance functionality.
135
+ ### Quickstart with Login
91
136
 
92
- **Usage:**
93
- ```html
94
- <io-assist
95
- [config]="assistConfig"
96
- ></io-assist>
97
- ```
137
+ This pattern shows how to pair io.Assist with a login flow — the user's identity is only passed to the assistant after authentication.
98
138
 
99
- **Inputs:**
100
- - `config: IoAssistTempConfig` - Configuration object for the assistant
139
+ Follow steps 1–2 from the basic quickstart, then:
101
140
 
102
- ## Styling
141
+ **Login service**
103
142
 
104
- The library uses TailwindCSS for styling. The styles are pre-compiled and included in the distribution.
143
+ ```typescript title="src/app/auth/auth.service.ts"
144
+ import { Injectable, signal } from '@angular/core';
105
145
 
106
- ### Custom Theming
146
+ @Injectable({ providedIn: 'root' })
147
+ export class AuthService {
148
+ private readonly _userId = signal<string>('');
149
+ readonly userId = this._userId.asReadonly();
107
150
 
108
- To customize the appearance, override CSS variables in your application:
151
+ login(userId: string, password: string): boolean {
152
+ // Replace with your own authentication logic
153
+ const isValid = password === 'secret';
154
+ if (isValid) this._userId.set(userId);
155
+ return isValid;
156
+ }
109
157
 
110
- ```css
111
- :root {
112
- --io-assist-primary-color: #your-color;
113
- --io-assist-background: #your-background;
114
- /* Add other custom variables */
158
+ logout(): void {
159
+ this._userId.set('');
160
+ }
115
161
  }
116
162
  ```
117
163
 
118
- ## Examples
164
+ **Login component**
119
165
 
120
- ### Basic Integration
166
+ ```typescript title="src/app/login/login.component.ts"
167
+ import { Component, inject, signal } from '@angular/core';
168
+ import { Router } from '@angular/router';
169
+ import { AuthService } from '../auth/auth.service';
121
170
 
122
- ```typescript
123
- import { Component } from '@angular/core';
124
- import { IoAssist, IoAssistTempConfig } from '@interopio/io-assist-ng';
171
+ @Component({
172
+ selector: 'app-login',
173
+ template: `
174
+ <input [value]="username()" (input)="username.set($any($event.target).value)" placeholder="Username" />
175
+ <input [value]="password()" (input)="password.set($any($event.target).value)" type="password" placeholder="Password" />
176
+ <button (click)="submit()">Sign in</button>
177
+ `,
178
+ })
179
+ export class LoginComponent {
180
+ private readonly _auth = inject(AuthService);
181
+ private readonly _router = inject(Router);
182
+
183
+ protected readonly username = signal('');
184
+ protected readonly password = signal('');
185
+
186
+ protected submit(): void {
187
+ const success = this._auth.login(this.username(), this.password());
188
+ if (success) this._router.navigate(['/assistant']);
189
+ }
190
+ }
191
+ ```
192
+
193
+ **Assistant component** — pass the user identity as `[config]`
194
+
195
+ ```typescript title="src/app/assistant/assistant.component.ts"
196
+ import { Component, computed, inject } from '@angular/core';
197
+ import { IoAssist, IoAssistDynamicConfig } from '@interopio/io-assist-ng';
198
+ import { AuthService } from '../auth/auth.service';
125
199
 
126
200
  @Component({
127
- selector: 'app-dashboard',
128
- standalone: true,
129
- imports: [IoAssist],
130
- template: `
131
- <div class="dashboard">
132
- <h1>My Dashboard</h1>
133
- <io-assist [config]="config"></io-assist>
134
- </div>
135
- `
201
+ selector: 'app-assistant',
202
+ imports: [IoAssist],
203
+ template: `<io-assist [config]="dynamicConfig()" />`,
136
204
  })
137
- export class DashboardComponent {
138
- config: IoAssistTempConfig = {
139
- apiEndpoint: 'https://api.example.com/assist',
140
- theme: 'light'
141
- };
205
+ export class AssistantComponent {
206
+ private readonly _auth = inject(AuthService);
207
+
208
+ protected readonly dynamicConfig = computed<IoAssistDynamicConfig>(() => ({
209
+ user: { id: this._auth.userId() },
210
+ }));
142
211
  }
143
212
  ```
144
213
 
145
- ## Browser Support
214
+ Once the user logs in, `dynamicConfig` updates and io.Assist loads threads scoped to that user.
215
+
216
+ ---
217
+
218
+ ### What you get with the minimal config
146
219
 
147
- - Chrome/Edge (latest 2 versions)
148
- - Firefox (latest 2 versions)
149
- - Safari (latest 2 versions)
220
+ With just the three required fields (`user`, `connectConfig`, `aiWebConfig.agentServer`), io.Assist provides:
150
221
 
151
- ## Dependencies
222
+ - Full conversational AI chat with streaming markdown responses
223
+ - Persistent conversation threads (scoped to `user.id`)
224
+ - Automatic agent selection (first available agent from your server)
225
+ - Built-in sampling and elicitation UI panels (confirmation dialogs when MCP servers request them)
226
+ - Built-in io.Intelligence MCP server connection (local mode)
227
+ - Dark/light theme sync with io.Connect
228
+ - Auto-injected fonts and syntax highlighting
152
229
 
153
- This library has peer dependencies on:
154
- - `@angular/core`: ^20.3.0
155
- - `@angular/common`: ^20.3.0
156
- - `@interopio/intel-web`: Latest
230
+ No prompts, no working context, and no MCP Apps — those require additional configuration below.
157
231
 
158
- These will be automatically installed with npm 7+.
232
+ ---
233
+
234
+ ## Configuration
235
+
236
+ io.Assist uses two separate configuration objects:
237
+
238
+ - **`IoAssistStaticConfig`** — passed to `provideIoAssist()` at application bootstrap. Contains infrastructure settings that don't change at runtime.
239
+ - **`IoAssistDynamicConfig`** — passed as `[config]` input to `<io-assist>` in your template. Contains the active user's identity, which may only be known after login.
240
+
241
+ ### Static configuration (`IoAssistStaticConfig`)
242
+
243
+ Passed to `provideIoAssist()`. Validated at bootstrap with Zod — throws if invalid.
159
244
 
160
- ## TypeScript Support
245
+ **Required fields**
161
246
 
162
- Full TypeScript support with type definitions included.
247
+ | Field | Type | Description |
248
+ |-------|------|-------------|
249
+ | `connectConfig` | `IOConnectNgSettings` | io.Connect platform settings. Must include `browser` or `desktop`. |
250
+ | `aiWebConfig.agentServer.baseUrl` | `string` | Base URL of your AG-UI compatible agent server. |
251
+
252
+ **Optional fields**
253
+
254
+ | Field | Type | Description |
255
+ |-------|------|-------------|
256
+ | `aiWebConfig.agentServer.retries` | `number` | Number of retry attempts on failure. |
257
+ | `aiWebConfig.agentServer.backoffMs` | `number` | Initial backoff delay in milliseconds. |
258
+ | `aiWebConfig.agentServer.maxBackoffMs` | `number` | Maximum backoff delay. |
259
+ | `aiWebConfig.agentServer.credentials` | `'omit' \| 'same-origin' \| 'include'` | Fetch credentials mode. |
260
+ | `aiWebConfig.mcp` | `object` | MCP configuration — remote servers, MCP Apps, sampling/elicitation overrides. |
261
+ | `defaultAgentName` | `string` | Agent to select on startup. Falls back to first available if not found. |
262
+ | `defaultPrompts` | `IoAssistPromptCategory[]` | Categorized prompt library entries. |
263
+ | `workingContext` | `object` | Live context collection from io.Connect. |
264
+
265
+ ### Dynamic configuration (`IoAssistDynamicConfig`)
266
+
267
+ Passed as `[config]` input to `<io-assist>` in your template. Validated in `ngOnInit` with Zod — throws `ZodError` if invalid. Typically computed from your authentication state:
163
268
 
164
269
  ```typescript
165
- import type { IoAssistTempConfig, IoAssistResponse } from '@interopio/io-assist-ng';
270
+ protected readonly dynamicConfig = computed<IoAssistDynamicConfig>(() => ({
271
+ user: { id: this._auth.userId(), name: this._auth.displayName() },
272
+ }));
273
+ ```
274
+
275
+ ```html
276
+ <io-assist [config]="dynamicConfig()" />
166
277
  ```
167
278
 
168
- ## Troubleshooting
279
+ | Field | Type | Description |
280
+ |-------|------|-------------|
281
+ | `user.id` | `string` | **Required.** Unique user identifier. Scopes conversation threads — each user sees only their own threads. |
282
+ | `user.name` | `string?` | Display name shown in the chat UI and thread history. |
283
+ | `agentServer.headers` | `Record<string, string>?` | Request headers sent with every agent call. Use for auth tokens or per-user context. |
169
284
 
170
- ### Styles Not Loading
285
+ ---
171
286
 
172
- Ensure you've imported the styles in `angular.json` or your main stylesheet:
173
- ```json
174
- "styles": [
175
- "node_modules/@interopio/io-assist-ng/styles.css"
176
- ]
287
+ ## Configuration Examples
288
+
289
+ ### Standard — with prompts and named agent
290
+
291
+ ```typescript title="app.config.ts"
292
+ import { ApplicationConfig } from '@angular/core';
293
+ import { provideIoAssist } from '@interopio/io-assist-ng';
294
+ import IOBrowser from '@interopio/browser';
295
+
296
+ export const appConfig: ApplicationConfig = {
297
+ providers: [
298
+ provideIoAssist({
299
+ connectConfig: {
300
+ browser: { factory: IOBrowser },
301
+ },
302
+ aiWebConfig: {
303
+ agentServer: {
304
+ baseUrl: 'http://localhost:4111',
305
+ },
306
+ },
307
+ defaultAgentName: 'my-agent',
308
+ defaultPrompts: [
309
+ {
310
+ category: 'General',
311
+ prompts: [
312
+ { name: 'Summarize', prompt: 'Please summarize the following content:' },
313
+ { name: 'Explain', prompt: 'Please explain this in simple terms:' },
314
+ ],
315
+ },
316
+ {
317
+ category: 'Code',
318
+ prompts: [
319
+ { name: 'Review Code', prompt: 'Please review this code and suggest improvements:' },
320
+ {
321
+ name: 'Add Comments',
322
+ prompt: 'Annotate this code with detailed comments:',
323
+ iconResource: {
324
+ type: 'svg',
325
+ data: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="..."/></svg>',
326
+ },
327
+ },
328
+ ],
329
+ },
330
+ ],
331
+ }),
332
+ ],
333
+ };
177
334
  ```
178
335
 
179
- ### Component Not Found
180
-
181
- Make sure you've imported the component in your standalone component or module:
182
- ```typescript
183
- imports: [IoAssist]
336
+ **What this adds over minimal:**
337
+
338
+ - **Named agent** pre-selected at startup
339
+ - **Prompt library** with two categories — users can browse, search, and favorite prompts
340
+
341
+ ### Advanced — custom handlers, MCP Apps, working context
342
+
343
+ ```typescript title="app.config.ts"
344
+ import { ApplicationConfig } from '@angular/core';
345
+ import { provideIoAssist } from '@interopio/io-assist-ng';
346
+ import { IoAiWeb } from '@interopio/ai-web';
347
+ import IOBrowser from '@interopio/browser';
348
+ import { IoIntelWorkingContextFactory, IoIntelWorkingContext } from '@interopio/working-context';
349
+
350
+ export const appConfig: ApplicationConfig = {
351
+ providers: [
352
+ provideIoAssist({
353
+ connectConfig: {
354
+ browser: { factory: IOBrowser },
355
+ },
356
+ aiWebConfig: {
357
+ agentServer: {
358
+ baseUrl: 'http://localhost:4111',
359
+ },
360
+ mcp: {
361
+ // Custom sampling handler — replaces the built-in confirmation panel
362
+ clientsConfig: {
363
+ enforceStrictCapabilities: false,
364
+ capabilities: {
365
+ sampling: {
366
+ handler: async (
367
+ serverId: string,
368
+ params: IoAiWeb.SamplingRequestParams,
369
+ ): Promise<IoAiWeb.SamplingSuccessResponse> => {
370
+ // Your custom logic — show your own UI, call your own APIs, etc.
371
+ return {
372
+ model: 'gpt-4',
373
+ role: 'assistant',
374
+ content: { type: 'text', text: 'Custom sampling response' },
375
+ stopReason: 'endTurn',
376
+ };
377
+ },
378
+ },
379
+ elicitation: {
380
+ handler: async (
381
+ serverId: string,
382
+ params: IoAiWeb.ElicitationRequestParams,
383
+ ): Promise<IoAiWeb.ElicitationResponse> => {
384
+ // Your custom logic — build a form, collect user input, etc.
385
+ return { action: 'accept', content: { confirmed: true } };
386
+ },
387
+ },
388
+ // Required for MCP Apps
389
+ extensions: {
390
+ 'io.modelcontextprotocol/ui': {
391
+ mimeTypes: ['text/html;profile=mcp-app'],
392
+ },
393
+ },
394
+ },
395
+ },
396
+ // MCP Apps — interactive UI panels in chat or workspace windows
397
+ mcpApps: {
398
+ sandboxProxyUrl: 'http://localhost:6565/index.html',
399
+ displayMode: 'workspace', // or 'inline'
400
+ },
401
+ // Remote MCP servers
402
+ ioIntel: {
403
+ remote: {
404
+ streamableHttp: {
405
+ url: 'http://localhost:8989/mcp',
406
+ name: 'remote-io-mcp-server',
407
+ },
408
+ },
409
+ },
410
+ remoteServers: [
411
+ {
412
+ streamableHttp: {
413
+ url: 'http://localhost:8081/mcp',
414
+ name: 'third-party-server',
415
+ },
416
+ },
417
+ ],
418
+ },
419
+ },
420
+ defaultAgentName: 'my-agent',
421
+ defaultPrompts: [
422
+ {
423
+ category: 'General',
424
+ prompts: [
425
+ { name: 'Summarize', prompt: 'Please summarize the following content:' },
426
+ ],
427
+ },
428
+ ],
429
+ workingContext: {
430
+ factory: IoIntelWorkingContextFactory,
431
+ config: {
432
+ schema: {
433
+ userId: {
434
+ type: 'string',
435
+ description: "Current user's identifier",
436
+ source: {
437
+ context: {
438
+ location: { global: { names: ['UserSession'] } },
439
+ path: 'user.id',
440
+ },
441
+ },
442
+ },
443
+ selectedClient: {
444
+ type: 'string',
445
+ description: 'Client currently selected in the workspace',
446
+ source: {
447
+ context: {
448
+ location: { workspace: {} },
449
+ path: 'client.name',
450
+ },
451
+ },
452
+ },
453
+ },
454
+ } as IoIntelWorkingContext.Config,
455
+ },
456
+ }),
457
+ ],
458
+ };
184
459
  ```
185
460
 
186
- ### Type Errors
461
+ **What this adds over standard:**
462
+
463
+ - **Custom sampling handler** — replaces the built-in confirmation panel. When an MCP server makes a sampling request, your handler runs instead.
464
+ - **Custom elicitation handler** — replaces the built-in elicitation panel. When an MCP server requests user input, your handler runs instead.
465
+ - **MCP Apps** — interactive HTML panels that MCP tools can render inline in chat or in io.Connect workspace windows. Requires both `mcpApps` config and the `io.modelcontextprotocol/ui` extension.
466
+ - **Remote MCP servers** — switch io.Intelligence MCP to a remote endpoint and/or add third-party MCP servers.
467
+ - **Working context** — io.Assist reads live data from io.Connect contexts and passes it to the agent with every message.
187
468
 
188
- Ensure your TypeScript version is 5.0 or higher and `strict` mode is enabled in `tsconfig.json`.
469
+ > **Component usage:** In all examples above, pair `provideIoAssist()` with `<io-assist [config]="dynamicConfig()" />` in your template. Refer to the [Quickstart with Login](#quickstart-with-login) section for a full component example.
189
470
 
190
- ## Development
471
+ ---
191
472
 
192
- This library is built with:
193
- - Angular 20.3
194
- - TailwindCSS 4.1
195
- - TypeScript 5.x
473
+ ## MCP Apps
196
474
 
197
- ## Support
475
+ MCP Apps are fully interactive UI applications that MCP tools can display directly inside the assistant. Instead of returning only text, a tool can ship a complete HTML application that the user interacts with in context.
198
476
 
199
- For issues, questions, or contributions, please visit:
200
- - GitHub: [io.Intelligence JS Repository]
201
- - Documentation: [Coming Soon]
202
- - Issues: [GitHub Issues]
477
+ **Requirements** two config sections must both be present:
203
478
 
204
- ## License
479
+ 1. **`mcpApps`** — enables the MCP Apps runtime:
480
+ ```typescript
481
+ mcpApps: {
482
+ sandboxProxyUrl: 'http://localhost:6565/index.html',
483
+ displayMode: 'workspace', // 'workspace' | 'inline' (optional, auto-detects if omitted)
484
+ },
485
+ ```
486
+
487
+ 2. **`extensions`** — tells MCP servers that this client supports UI:
488
+ ```typescript
489
+ capabilities: {
490
+ extensions: {
491
+ 'io.modelcontextprotocol/ui': {
492
+ mimeTypes: ['text/html;profile=mcp-app'],
493
+ },
494
+ },
495
+ },
496
+ ```
205
497
 
206
- ISC License
498
+ Without both, MCP servers will not expose UI metadata on tool definitions and no apps will be created.
207
499
 
208
- ## Changelog
500
+ **Display modes:**
209
501
 
210
- ### 0.0.0 (Initial Release)
211
- - Initial release with core `IoAssist` component
212
- - TailwindCSS styling support
213
- - TypeScript type definitions
214
- - Angular 20.3 compatibility
502
+ | Mode | Behavior |
503
+ |------|----------|
504
+ | `'inline'` | App renders inside the chat message flow |
505
+ | `'workspace'` | App opens in a separate io.Connect workspace window (falls back to inline if workspaces unavailable) |
506
+
507
+ **Sandbox proxy** — MCP Apps run inside a sandboxed iframe. The `sandboxProxyUrl` points to an HTML file that bridges communication between the host and the app. This proxy page must be served alongside your application.
508
+
509
+ ---
510
+
511
+ ## Sampling & Elicitation
512
+
513
+ When an MCP server sends a sampling or elicitation request:
514
+
515
+ | Scenario | Behavior |
516
+ |----------|----------|
517
+ | **No custom handler** | io.Assist shows a built-in confirmation panel (uses io.Connect modal if available, otherwise an overlay panel) |
518
+ | **Custom handler provided** | Your handler function runs instead — full control over UI and response |
519
+ | **Request from background thread** | Automatically rejected (user must be on the active thread) |
520
+
521
+ **Sampling** — the MCP server asks the client to generate a model response. The built-in handler shows a "Permission to proceed" dialog. On accept, it calls your agent server and returns the result.
522
+
523
+ **Elicitation** — the MCP server asks the client to collect user input via a form schema. The built-in handler presents accept/decline options.
524
+
525
+ See the advanced configuration example above for custom handler signatures.
526
+
527
+ ---
528
+
529
+ ## Public API
530
+
531
+ ```typescript
532
+ import { IoAssist, provideIoAssist } from '@interopio/io-assist-ng';
533
+ import type {
534
+ IoAssistStaticConfig,
535
+ IoAssistDynamicConfig,
536
+ AIWebConfig,
537
+ IoAssistUserConfig,
538
+ IO_ASSIST_CONFIG,
539
+ IO_ASSIST_DYNAMIC_CONFIG,
540
+ IoAssistPrompt,
541
+ IoAssistPromptCategory,
542
+ IconResource,
543
+ IconType,
544
+ } from '@interopio/io-assist-ng';
545
+ ```
546
+
547
+ | Export | Kind | Description |
548
+ |--------|------|-------------|
549
+ | `IoAssist` | Component | The `<io-assist>` root component. Requires `[config]` input. |
550
+ | `provideIoAssist(config)` | Function | Registers all providers — call once in `app.config.ts` |
551
+ | `IoAssistStaticConfig` | Type | Static configuration shape passed to `provideIoAssist()` |
552
+ | `IoAssistDynamicConfig` | Type | Runtime configuration shape passed as `[config]` to `<io-assist>` |
553
+ | `AIWebConfig` | Type | Agent server + MCP config shape |
554
+ | `IoAssistUserConfig` | Type | `{ id: string; name?: string }` |
555
+ | `IO_ASSIST_CONFIG` | InjectionToken | DI token for the validated static config |
556
+ | `IO_ASSIST_DYNAMIC_CONFIG` | InjectionToken | DI token for the `WritableSignal<IoAssistDynamicConfig>` (internal use) |
557
+ | `IoAssistPrompt` | Type | Single prompt definition |
558
+ | `IoAssistPromptCategory` | Type | Category with array of prompts |
559
+ | `IconResource` | Type | `{ type: IconType; data: string }` |
560
+ | `IconType` | Type | `'svg' \| 'url' \| 'data-url'` |
215
561
 
216
562
  ---
217
563
 
218
- **Note:** This library is currently in development. API and features may change before the stable 1.0.0 release.
564
+ ## Prompt Icons
565
+
566
+ Each prompt can have an optional `iconResource`. Three formats are supported:
567
+
568
+ | Type | Example | Notes |
569
+ |------|---------|-------|
570
+ | `'svg'` | `'<svg xmlns="..." viewBox="0 0 24 24">...</svg>'` | Auto-sanitized: `fill`, `width`, `height` stripped; hardcoded colors → `currentColor` |
571
+ | `'url'` | `'/icons/summarize.svg'` | Must be an absolute URL or absolute path from document root |
572
+ | `'data-url'` | `'data:image/svg+xml;base64,...'` | Base64-encoded SVG, PNG, or JPEG |
573
+
574
+ Prompts without an icon show a default icon.
575
+
576
+ ---
577
+
578
+ ## Related Packages
579
+
580
+ - [@interopio/ai-web](https://www.npmjs.com/package/@interopio/ai-web) — Core intelligence library
581
+ - [@interopio/ng](https://www.npmjs.com/package/@interopio/ng) — io.Connect Angular integration
582
+ - [@interopio/browser](https://www.npmjs.com/package/@interopio/browser) — io.Connect Browser platform
583
+ - [@interopio/desktop](https://www.npmjs.com/package/@interopio/desktop) — io.Connect Desktop platform
584
+ - [@interopio/working-context](https://www.npmjs.com/package/@interopio/working-context) — Working context collection
585
+ - [@interopio/modals-api](https://www.npmjs.com/package/@interopio/modals-api) — io.Connect Modals API
586
+
587
+ ## License
588
+
589
+ [MIT](./LICENSE)