@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.internal.md +865 -0
- package/README.md +511 -140
- package/README.user.md +159 -0
- package/dist/README.md +511 -140
- package/dist/fesm2022/interopio-io-assist-ng.mjs +4388 -1942
- package/dist/fesm2022/interopio-io-assist-ng.mjs.map +1 -1
- package/dist/index.d.ts +123 -8
- package/dist/styles.css +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,218 +1,589 @@
|
|
|
1
1
|
# @interopio/io-assist-ng
|
|
2
2
|
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
+
### Existing Angular project
|
|
18
51
|
|
|
19
|
-
|
|
52
|
+
```bash
|
|
53
|
+
npm install @interopio/io-assist-ng @interopio/browser
|
|
54
|
+
```
|
|
20
55
|
|
|
21
|
-
|
|
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
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
###
|
|
98
|
+
### 3. Add the component
|
|
49
99
|
|
|
50
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
The `IoAssist` component accepts a configuration object via the `[config]` input:
|
|
125
|
+
### 4. Run
|
|
74
126
|
|
|
75
|
-
```
|
|
76
|
-
|
|
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
|
-
|
|
131
|
+
Open http://localhost:4200. **io.Assist is live.**
|
|
87
132
|
|
|
88
|
-
|
|
133
|
+
---
|
|
89
134
|
|
|
90
|
-
|
|
135
|
+
### Quickstart with Login
|
|
91
136
|
|
|
92
|
-
|
|
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
|
-
|
|
100
|
-
- `config: IoAssistTempConfig` - Configuration object for the assistant
|
|
139
|
+
Follow steps 1–2 from the basic quickstart, then:
|
|
101
140
|
|
|
102
|
-
|
|
141
|
+
**Login service**
|
|
103
142
|
|
|
104
|
-
|
|
143
|
+
```typescript title="src/app/auth/auth.service.ts"
|
|
144
|
+
import { Injectable, signal } from '@angular/core';
|
|
105
145
|
|
|
106
|
-
|
|
146
|
+
@Injectable({ providedIn: 'root' })
|
|
147
|
+
export class AuthService {
|
|
148
|
+
private readonly _userId = signal<string>('');
|
|
149
|
+
readonly userId = this._userId.asReadonly();
|
|
107
150
|
|
|
108
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
164
|
+
**Login component**
|
|
119
165
|
|
|
120
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
245
|
+
**Required fields**
|
|
161
246
|
|
|
162
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
285
|
+
---
|
|
171
286
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
471
|
+
---
|
|
191
472
|
|
|
192
|
-
|
|
193
|
-
- Angular 20.3
|
|
194
|
-
- TailwindCSS 4.1
|
|
195
|
-
- TypeScript 5.x
|
|
473
|
+
## MCP Apps
|
|
196
474
|
|
|
197
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
498
|
+
Without both, MCP servers will not expose UI metadata on tool definitions and no apps will be created.
|
|
207
499
|
|
|
208
|
-
|
|
500
|
+
**Display modes:**
|
|
209
501
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
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)
|