@interopio/io-assist-react 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 +467 -0
- package/README.md +503 -0
- package/changelog.md +2 -0
- package/dist/IoAssist.d.ts +12 -0
- package/dist/actions/abortActiveStream.d.ts +2 -0
- package/dist/actions/deleteThread.d.ts +2 -0
- package/dist/actions/elicitation.d.ts +13 -0
- package/dist/actions/initIoAiWeb.d.ts +3 -0
- package/dist/actions/initIoConnect.d.ts +9 -0
- package/dist/actions/mcpAppEvents.d.ts +4 -0
- package/dist/actions/newConversation.d.ts +2 -0
- package/dist/actions/processResponseStream.d.ts +3 -0
- package/dist/actions/renameThread.d.ts +2 -0
- package/dist/actions/sampling.d.ts +5 -0
- package/dist/actions/selectThread.d.ts +2 -0
- package/dist/actions/sendUserMessage.d.ts +3 -0
- package/dist/actions/toggleFavoritePrompt.d.ts +7 -0
- package/dist/actions/toggleTool.d.ts +2 -0
- package/dist/components/chat/ActivePanelModal.d.ts +6 -0
- package/dist/components/chat/AiDisclaimer.d.ts +6 -0
- package/dist/components/chat/Chat.d.ts +2 -0
- package/dist/components/chat/ConfirmModal.d.ts +8 -0
- package/dist/components/chat/WelcomeHeading.d.ts +6 -0
- package/dist/components/header/Header.d.ts +2 -0
- package/dist/components/input-area/InputArea.d.ts +8 -0
- package/dist/components/messages/AssistantMessage.d.ts +10 -0
- package/dist/components/messages/McpAppResource.d.ts +11 -0
- package/dist/components/messages/MdFormatter.d.ts +6 -0
- package/dist/components/messages/MessageArea.d.ts +7 -0
- package/dist/components/messages/ToolMessage.d.ts +9 -0
- package/dist/components/messages/ToolTraceMessage.d.ts +9 -0
- package/dist/components/messages/UserMessage.d.ts +9 -0
- package/dist/components/messages/mdUtils.d.ts +1 -0
- package/dist/components/messages/prismTwilightTheme.d.ts +2 -0
- package/dist/components/prompt/FavoritePromptList.d.ts +2 -0
- package/dist/components/prompt/PromptListItem.d.ts +8 -0
- package/dist/components/prompt/PromptListPanel.d.ts +6 -0
- package/dist/components/scroll-area/ScrollArea.d.ts +33 -0
- package/dist/components/shared/Icon.d.ts +8 -0
- package/dist/components/shared/IconButton.d.ts +11 -0
- package/dist/components/shared/Modal.d.ts +12 -0
- package/dist/components/shared/SearchInput.d.ts +8 -0
- package/dist/components/shared/ToggleInput.d.ts +8 -0
- package/dist/components/shared/Tooltip.d.ts +10 -0
- package/dist/components/shared/icons.d.ts +37 -0
- package/dist/components/threads/ThreadHistory.d.ts +6 -0
- package/dist/components/threads/ThreadHistoryListItem.d.ts +18 -0
- package/dist/components/threads/ThreadHistoryPanel.d.ts +7 -0
- package/dist/components/tool/ToolListItem.d.ts +8 -0
- package/dist/components/tool/ToolListPanel.d.ts +2 -0
- package/dist/components/working-context-panel/WorkingContextPanel.d.ts +2 -0
- package/dist/constants/modalActions.d.ts +11 -0
- package/dist/constants/uiStrings.d.ts +141 -0
- package/dist/context/IoAssistContext.d.ts +14 -0
- package/dist/files/inter-latin-wght-normal.woff2 +0 -0
- package/dist/hooks/useHoverMouseFollow.d.ts +27 -0
- package/dist/hooks/useIoAiWebApi.d.ts +19 -0
- package/dist/hooks/useIoAiWebBootstrap.d.ts +8 -0
- package/dist/hooks/useIoConnectApi.d.ts +12 -0
- package/dist/hooks/useIoConnectBootstrap.d.ts +10 -0
- package/dist/hooks/useIsMobileViewport.d.ts +1 -0
- package/dist/index.cjs +41 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3624 -0
- package/dist/index.js.map +1 -0
- package/dist/stores/agent.d.ts +15 -0
- package/dist/stores/app-lifecycle.d.ts +21 -0
- package/dist/stores/confirm-modal.d.ts +29 -0
- package/dist/stores/index.d.ts +32 -0
- package/dist/stores/mcp-apps.d.ts +13 -0
- package/dist/stores/message.d.ts +33 -0
- package/dist/stores/prompt.d.ts +16 -0
- package/dist/stores/response-stream.d.ts +31 -0
- package/dist/stores/thread.d.ts +17 -0
- package/dist/stores/tool.d.ts +15 -0
- package/dist/stores/working-context.d.ts +16 -0
- package/dist/styles.css +1 -0
- package/dist/types/agent.d.ts +8 -0
- package/dist/types/config.d.ts +40 -0
- package/dist/types/icon.d.ts +5 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/loading.d.ts +38 -0
- package/dist/types/message.d.ts +56 -0
- package/dist/types/panel.d.ts +6 -0
- package/dist/types/prompt.d.ts +17 -0
- package/dist/types/stream.d.ts +22 -0
- package/dist/types/thread.d.ts +15 -0
- package/dist/types/tool.d.ts +15 -0
- package/dist/utils/confirmModal.d.ts +5 -0
- package/dist/utils/ioModals.d.ts +21 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/mcpAppModal.d.ts +3 -0
- package/dist/utils/messageConverter.d.ts +3 -0
- package/dist/utils/messageUtils.d.ts +16 -0
- package/dist/utils/safeStringify.d.ts +1 -0
- package/dist/utils/streamUtils.d.ts +15 -0
- package/dist/utils/threadUtils.d.ts +16 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
# @interopio/io-assist-react
|
|
2
|
+
|
|
3
|
+
A full-featured AI assistant component for React applications. Drop a single `<IoAssist />` component 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
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Conversational AI chat** — Streaming responses, markdown rendering, code highlighting
|
|
11
|
+
- **Persistent conversation threads** — Thread history with resume, rename, and delete
|
|
12
|
+
- **Prompt library** — Categorized pre-written prompts with favorites (persisted via io.Connect preferences)
|
|
13
|
+
- **MCP tool access** — Built-in io.Intelligence MCP server, extensible with remote and third-party servers
|
|
14
|
+
- **MCP Apps** — Custom HTML applications rendered inline in chat or in io.Connect workspace windows
|
|
15
|
+
- **Sampling & elicitation** — Built-in confirmation/input UI for MCP server requests (replaceable with custom handlers)
|
|
16
|
+
- **Working context** — Live data from io.Connect contexts passed to the agent with every message
|
|
17
|
+
- **Theming** — Automatic dark/light mode sync with io.Connect
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
- **React** 18+
|
|
22
|
+
- **Node.js** 20.19+ (< 22)
|
|
23
|
+
- **npm** 10+
|
|
24
|
+
- An **AG-UI Protocol compatible agent server** (e.g. [Mastra](https://mastra.ai/))
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @interopio/io-assist-react
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`react` and `react-dom` are the only **peer dependencies** — your app already provides them:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install react react-dom
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Everything else is declared as a direct dependency and installed automatically, including the io.Connect platform packages (`@interopio/browser`, `@interopio/desktop`), the core intelligence library (`@interopio/ai-web`), working context (`@interopio/working-context`), and the UI runtime (`zustand`, `react-markdown`, `remark-gfm`, `prism-react-renderer`, `@fontsource-variable/inter`). These are resolved from your `node_modules` at runtime, not inlined into the package.
|
|
39
|
+
|
|
40
|
+
You always need to **import a platform factory** and pass it in your `connectConfig` — pick the one that matches your environment:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
// io.Connect Browser (most common)
|
|
44
|
+
import IOBrowser from '@interopio/browser';
|
|
45
|
+
|
|
46
|
+
// io.Connect Desktop
|
|
47
|
+
import IODesktop from '@interopio/desktop';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Agent Server
|
|
53
|
+
|
|
54
|
+
io.Assist requires an **AG-UI Protocol compatible agent server** to handle chat requests. The recommended way to get started is with [Mastra](https://mastra.ai/).
|
|
55
|
+
|
|
56
|
+
### Quick setup with Mastra
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx create-mastra@latest
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This scaffolds a fully working Mastra project. Follow the prompts, then start the server:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm run dev
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
By default the server runs on `http://localhost:4111` — the same URL used in the Quickstart examples below.
|
|
69
|
+
|
|
70
|
+
**Required environment variables:**
|
|
71
|
+
|
|
72
|
+
```env
|
|
73
|
+
# At least one LLM provider key
|
|
74
|
+
OPENAI_API_KEY=your-key
|
|
75
|
+
ANTHROPIC_API_KEY=your-key
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> For full Mastra documentation — including custom agents, tools, memory, and deployment — see [mastra.ai/docs](https://mastra.ai/docs).
|
|
79
|
+
|
|
80
|
+
## Quickstart
|
|
81
|
+
|
|
82
|
+
### 1. Add the stylesheet
|
|
83
|
+
|
|
84
|
+
```css title="src/styles.css"
|
|
85
|
+
@import "@interopio/io-assist-react/styles";
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 2. Render the component
|
|
89
|
+
|
|
90
|
+
`<IoAssist />` takes two props: a `staticConfig` (infrastructure settings, known at bootstrap) and a `dynamicConfig` (the active user's identity and per-request headers, often known only after login).
|
|
91
|
+
|
|
92
|
+
```tsx title="src/App.tsx"
|
|
93
|
+
import { IoAssist, IoAssistStaticConfig, IoAssistDynamicConfig } from '@interopio/io-assist-react';
|
|
94
|
+
import IOBrowser from '@interopio/browser';
|
|
95
|
+
|
|
96
|
+
const staticConfig: IoAssistStaticConfig = {
|
|
97
|
+
connectConfig: {
|
|
98
|
+
browser: {
|
|
99
|
+
factory: IOBrowser,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
aiWebConfig: {
|
|
103
|
+
agentServer: {
|
|
104
|
+
baseUrl: 'http://localhost:4111',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const dynamicConfig: IoAssistDynamicConfig = {
|
|
110
|
+
// id: Your access/auth token of choice — scopes conversation threads
|
|
111
|
+
// name: UI name that will be displayed
|
|
112
|
+
user: { id: 'yourIdOfChoice', name: 'Jane Doe' },
|
|
113
|
+
agentServer: {
|
|
114
|
+
headers: {
|
|
115
|
+
Authorization: `Bearer ${import.meta.env.VITE_AUTH_TOKEN}`,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export function App() {
|
|
121
|
+
return <IoAssist staticConfig={staticConfig} dynamicConfig={dynamicConfig} />;
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 3. Run
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npm run dev
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**io.Assist is live.**
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Quickstart with Login
|
|
136
|
+
|
|
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. Build the `dynamicConfig` from your auth state and render `<IoAssist />` only once a user is present.
|
|
138
|
+
|
|
139
|
+
```tsx title="src/AssistantShell.tsx"
|
|
140
|
+
import { useMemo } from 'react';
|
|
141
|
+
import { Navigate } from 'react-router-dom';
|
|
142
|
+
import { IoAssist, IoAssistDynamicConfig } from '@interopio/io-assist-react';
|
|
143
|
+
import { staticConfig } from './configs';
|
|
144
|
+
import { useAuth } from './auth';
|
|
145
|
+
|
|
146
|
+
export function AssistantShell() {
|
|
147
|
+
const { userId } = useAuth();
|
|
148
|
+
|
|
149
|
+
const dynamicConfig = useMemo<IoAssistDynamicConfig | null>(
|
|
150
|
+
() => (userId ? { user: { id: userId } } : null),
|
|
151
|
+
[userId],
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
if (!dynamicConfig) {
|
|
155
|
+
return <Navigate to="/login" replace />;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return <IoAssist staticConfig={staticConfig} dynamicConfig={dynamicConfig} />;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Once the user logs in, `dynamicConfig` is populated and io.Assist loads threads scoped to that user.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## What you get with the minimal config
|
|
167
|
+
|
|
168
|
+
With just the required fields (`staticConfig.connectConfig`, `staticConfig.aiWebConfig.agentServer.baseUrl`, and `dynamicConfig.user`), io.Assist provides:
|
|
169
|
+
|
|
170
|
+
- Full conversational AI chat with streaming markdown responses
|
|
171
|
+
- Persistent conversation threads (scoped to `user.id`)
|
|
172
|
+
- Automatic agent selection (first available agent from your server)
|
|
173
|
+
- Built-in sampling and elicitation UI (confirmation dialogs when MCP servers request them)
|
|
174
|
+
- Built-in io.Intelligence MCP server connection
|
|
175
|
+
- Dark/light theme sync with io.Connect
|
|
176
|
+
- Auto-injected fonts and syntax highlighting
|
|
177
|
+
|
|
178
|
+
No prompts, no working context, and no MCP Apps — those require additional configuration below.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Configuration
|
|
183
|
+
|
|
184
|
+
io.Assist uses two separate configuration objects, passed as two distinct props:
|
|
185
|
+
|
|
186
|
+
- **`IoAssistStaticConfig`** — infrastructure settings that don't change at runtime (platform factory, agent server, MCP, prompts). Pass it as the `staticConfig` prop.
|
|
187
|
+
- **`IoAssistDynamicConfig`** — the active user's identity and per-request headers, which may only be known after login. Pass it as the `dynamicConfig` prop.
|
|
188
|
+
|
|
189
|
+
### Static configuration (`IoAssistStaticConfig`)
|
|
190
|
+
|
|
191
|
+
Passed as the `staticConfig` prop.
|
|
192
|
+
|
|
193
|
+
**Required fields**
|
|
194
|
+
|
|
195
|
+
| Field | Type | Description |
|
|
196
|
+
|-------|------|-------------|
|
|
197
|
+
| `connectConfig` | `{ browser?, desktop? }` | io.Connect platform settings. Must include a `browser` and/or `desktop` entry, each with a `factory` (and optional `config`). |
|
|
198
|
+
| `aiWebConfig.agentServer.baseUrl` | `string` | Base URL of your AG-UI compatible agent server. |
|
|
199
|
+
|
|
200
|
+
**Optional fields**
|
|
201
|
+
|
|
202
|
+
| Field | Type | Description |
|
|
203
|
+
|-------|------|-------------|
|
|
204
|
+
| `aiWebConfig.agentServer.*` | `IoAiWeb.AgentServerConfig` | Additional agent-server options (retries, backoff, credentials, etc.). |
|
|
205
|
+
| `aiWebConfig.mcp` | `IoAiWeb.MCPConfig` | MCP configuration — remote servers, MCP Apps, sampling/elicitation overrides. |
|
|
206
|
+
| `defaultAgentName` | `string` | Agent to select on startup. Falls back to the first available agent if not found. |
|
|
207
|
+
| `defaultPrompts` | `IoAssistPromptCategory[]` | Categorized prompt library entries. |
|
|
208
|
+
| `workingContext` | `IoAiWeb.WorkingContextConfig` | Live context collection from io.Connect. |
|
|
209
|
+
|
|
210
|
+
### Dynamic configuration (`IoAssistDynamicConfig`)
|
|
211
|
+
|
|
212
|
+
Passed as the `dynamicConfig` prop. Typically derived from your authentication state.
|
|
213
|
+
|
|
214
|
+
| Field | Type | Description |
|
|
215
|
+
|-------|------|-------------|
|
|
216
|
+
| `user.id` | `string` | **Required.** Unique user identifier. Scopes conversation threads — each user sees only their own threads. |
|
|
217
|
+
| `user.name` | `string?` | Display name shown in the chat UI and thread history. |
|
|
218
|
+
| `agentServer.headers` | `Record<string, string>?` | Request headers sent with every agent call. This is the **only** source of request headers — use it for auth tokens or per-user context. |
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Configuration Examples
|
|
223
|
+
|
|
224
|
+
### Standard — with prompts and a named agent
|
|
225
|
+
|
|
226
|
+
```tsx title="src/configs.ts"
|
|
227
|
+
import { IoAssistStaticConfig } from '@interopio/io-assist-react';
|
|
228
|
+
import IOBrowser from '@interopio/browser';
|
|
229
|
+
|
|
230
|
+
export const staticConfig: IoAssistStaticConfig = {
|
|
231
|
+
connectConfig: {
|
|
232
|
+
browser: { factory: IOBrowser },
|
|
233
|
+
},
|
|
234
|
+
aiWebConfig: {
|
|
235
|
+
agentServer: {
|
|
236
|
+
baseUrl: 'http://localhost:4111',
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
defaultAgentName: 'my-agent',
|
|
240
|
+
defaultPrompts: [
|
|
241
|
+
{
|
|
242
|
+
category: 'General',
|
|
243
|
+
prompts: [
|
|
244
|
+
{ name: 'Summarize', prompt: 'Please summarize the following content:' },
|
|
245
|
+
{ name: 'Explain', prompt: 'Please explain this in simple terms:' },
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
category: 'Code',
|
|
250
|
+
prompts: [
|
|
251
|
+
{ name: 'Review Code', prompt: 'Please review this code and suggest improvements:' },
|
|
252
|
+
{
|
|
253
|
+
name: 'Add Comments',
|
|
254
|
+
prompt: 'Annotate this code with detailed comments:',
|
|
255
|
+
iconResource: {
|
|
256
|
+
type: 'svg',
|
|
257
|
+
data: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="..."/></svg>',
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
};
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**What this adds over minimal:**
|
|
267
|
+
|
|
268
|
+
- **Named agent** pre-selected at startup
|
|
269
|
+
- **Prompt library** with two categories — users can browse, search, and favorite prompts
|
|
270
|
+
|
|
271
|
+
### Advanced — custom handlers, MCP Apps, working context
|
|
272
|
+
|
|
273
|
+
```tsx title="src/configs.ts"
|
|
274
|
+
import { IoAssistStaticConfig } from '@interopio/io-assist-react';
|
|
275
|
+
import { IoAiWeb } from '@interopio/ai-web';
|
|
276
|
+
import IOBrowser from '@interopio/browser';
|
|
277
|
+
import { IoIntelWorkingContextFactory, IoIntelWorkingContext } from '@interopio/working-context';
|
|
278
|
+
|
|
279
|
+
export const staticConfig: IoAssistStaticConfig = {
|
|
280
|
+
connectConfig: {
|
|
281
|
+
browser: { factory: IOBrowser },
|
|
282
|
+
},
|
|
283
|
+
aiWebConfig: {
|
|
284
|
+
agentServer: {
|
|
285
|
+
baseUrl: 'http://localhost:4111',
|
|
286
|
+
},
|
|
287
|
+
mcp: {
|
|
288
|
+
// Custom sampling handler — replaces the built-in confirmation dialog
|
|
289
|
+
clientsConfig: {
|
|
290
|
+
enforceStrictCapabilities: false,
|
|
291
|
+
capabilities: {
|
|
292
|
+
sampling: {
|
|
293
|
+
handler: async (
|
|
294
|
+
serverId: string,
|
|
295
|
+
params: IoAiWeb.SamplingRequestParams,
|
|
296
|
+
): Promise<IoAiWeb.SamplingSuccessResponse> => {
|
|
297
|
+
// Your custom logic — show your own UI, call your own APIs, etc.
|
|
298
|
+
return {
|
|
299
|
+
model: 'gpt-4',
|
|
300
|
+
role: 'assistant',
|
|
301
|
+
content: { type: 'text', text: 'Custom sampling response' },
|
|
302
|
+
stopReason: 'endTurn',
|
|
303
|
+
};
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
elicitation: {
|
|
307
|
+
handler: async (
|
|
308
|
+
serverId: string,
|
|
309
|
+
params: IoAiWeb.ElicitationRequestParams,
|
|
310
|
+
): Promise<IoAiWeb.ElicitationResponse> => {
|
|
311
|
+
// Your custom logic — build a form, collect user input, etc.
|
|
312
|
+
return { action: 'accept', content: { confirmed: true } };
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
// Required for MCP Apps
|
|
316
|
+
extensions: {
|
|
317
|
+
'io.modelcontextprotocol/ui': {
|
|
318
|
+
mimeTypes: ['text/html;profile=mcp-app'],
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
// MCP Apps — interactive UI panels in chat or workspace windows
|
|
324
|
+
mcpApps: {
|
|
325
|
+
sandboxProxyUrl: 'http://localhost:6565/index.html',
|
|
326
|
+
displayMode: 'workspace', // or 'inline'
|
|
327
|
+
},
|
|
328
|
+
// Remote MCP servers
|
|
329
|
+
ioIntel: {
|
|
330
|
+
remote: {
|
|
331
|
+
streamableHttp: {
|
|
332
|
+
url: 'http://localhost:8989/mcp',
|
|
333
|
+
name: 'remote-io-mcp-server',
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
remoteServers: [
|
|
338
|
+
{
|
|
339
|
+
streamableHttp: {
|
|
340
|
+
url: 'http://localhost:8081/mcp',
|
|
341
|
+
name: 'third-party-server',
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
defaultAgentName: 'my-agent',
|
|
348
|
+
defaultPrompts: [
|
|
349
|
+
{
|
|
350
|
+
category: 'General',
|
|
351
|
+
prompts: [
|
|
352
|
+
{ name: 'Summarize', prompt: 'Please summarize the following content:' },
|
|
353
|
+
],
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
workingContext: {
|
|
357
|
+
factory: IoIntelWorkingContextFactory,
|
|
358
|
+
config: {
|
|
359
|
+
schema: {
|
|
360
|
+
userId: {
|
|
361
|
+
type: 'string',
|
|
362
|
+
description: "Current user's identifier",
|
|
363
|
+
source: {
|
|
364
|
+
context: {
|
|
365
|
+
location: { global: { names: ['UserSession'] } },
|
|
366
|
+
path: 'user.id',
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
selectedClient: {
|
|
371
|
+
type: 'string',
|
|
372
|
+
description: 'Client currently selected in the workspace',
|
|
373
|
+
source: {
|
|
374
|
+
context: {
|
|
375
|
+
location: { workspace: {} },
|
|
376
|
+
path: 'client.name',
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
} as IoIntelWorkingContext.Config,
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**What this adds over standard:**
|
|
387
|
+
|
|
388
|
+
- **Custom sampling handler** — replaces the built-in confirmation dialog. When an MCP server makes a sampling request, your handler runs instead.
|
|
389
|
+
- **Custom elicitation handler** — replaces the built-in elicitation dialog. When an MCP server requests user input, your handler runs instead.
|
|
390
|
+
- **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.
|
|
391
|
+
- **Remote MCP servers** — switch the io.Intelligence MCP to a remote endpoint and/or add third-party MCP servers.
|
|
392
|
+
- **Working context** — io.Assist reads live data from io.Connect contexts and passes it to the agent with every message.
|
|
393
|
+
|
|
394
|
+
> **Component usage:** In all examples above, pass the config object as the `staticConfig` prop and the user identity as the `dynamicConfig` prop: `<IoAssist staticConfig={staticConfig} dynamicConfig={dynamicConfig} />`. See [Quickstart with Login](#quickstart-with-login) for a full component example.
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## MCP Apps
|
|
399
|
+
|
|
400
|
+
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.
|
|
401
|
+
|
|
402
|
+
**Requirements** — two config sections must both be present under `aiWebConfig.mcp`:
|
|
403
|
+
|
|
404
|
+
1. **`mcpApps`** — enables the MCP Apps runtime:
|
|
405
|
+
```tsx
|
|
406
|
+
mcpApps: {
|
|
407
|
+
sandboxProxyUrl: 'http://localhost:6565/index.html',
|
|
408
|
+
displayMode: 'workspace', // 'workspace' | 'inline' (optional, auto-detects if omitted)
|
|
409
|
+
},
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
2. **`extensions`** — tells MCP servers that this client supports UI:
|
|
413
|
+
```tsx
|
|
414
|
+
capabilities: {
|
|
415
|
+
extensions: {
|
|
416
|
+
'io.modelcontextprotocol/ui': {
|
|
417
|
+
mimeTypes: ['text/html;profile=mcp-app'],
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Without both, MCP servers will not expose UI metadata on tool definitions and no apps will be created.
|
|
424
|
+
|
|
425
|
+
**Display modes:**
|
|
426
|
+
|
|
427
|
+
| Mode | Behavior |
|
|
428
|
+
|------|----------|
|
|
429
|
+
| `'inline'` | App renders inside the chat message flow |
|
|
430
|
+
| `'workspace'` | App opens in a separate io.Connect workspace window (falls back to inline if workspaces are unavailable) |
|
|
431
|
+
|
|
432
|
+
**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.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Sampling & Elicitation
|
|
437
|
+
|
|
438
|
+
When an MCP server sends a sampling or elicitation request:
|
|
439
|
+
|
|
440
|
+
| Scenario | Behavior |
|
|
441
|
+
|----------|----------|
|
|
442
|
+
| **No custom handler** | io.Assist shows a built-in confirmation dialog (uses an io.Connect modal if available, otherwise an in-app overlay) |
|
|
443
|
+
| **Custom handler provided** | Your handler function runs instead — full control over UI and response |
|
|
444
|
+
| **Request from a background thread** | Automatically rejected (the user must be on the active thread the request targets) |
|
|
445
|
+
|
|
446
|
+
**Sampling** — the MCP server asks the client to generate a model response. The built-in handler shows a "Continue / Cancel" dialog. On accept, it calls the selected agent's `generate()` and returns the result as a `SamplingSuccessResponse`. On decline, it returns an error response.
|
|
447
|
+
|
|
448
|
+
**Elicitation** — the MCP server asks the client to collect user input. The built-in handler presents accept/decline/cancel options.
|
|
449
|
+
|
|
450
|
+
Custom handlers are configured under `aiWebConfig.mcp.clientsConfig.capabilities` — see the [advanced configuration example](#advanced--custom-handlers-mcp-apps-working-context) for the handler signatures.
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Prompt Icons
|
|
455
|
+
|
|
456
|
+
Each prompt can have an optional `iconResource`. Three formats are supported:
|
|
457
|
+
|
|
458
|
+
| Type | Example | Notes |
|
|
459
|
+
|------|---------|-------|
|
|
460
|
+
| `'svg'` | `'<svg xmlns="..." viewBox="0 0 24 24">...</svg>'` | Sanitized: `fill`, `width`, `height` stripped; hardcoded colors → `currentColor` |
|
|
461
|
+
| `'url'` | `'/icons/summarize.svg'` | Must be an absolute URL or absolute path from the document root |
|
|
462
|
+
| `'data-url'` | `'data:image/svg+xml;base64,...'` | Base64-encoded SVG, PNG, or JPEG |
|
|
463
|
+
|
|
464
|
+
Prompts without an icon show a default icon.
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
## Public API
|
|
469
|
+
|
|
470
|
+
The package exposes a deliberately small surface — one component and the two config types it consumes:
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
import { IoAssist } from '@interopio/io-assist-react';
|
|
474
|
+
import type { IoAssistStaticConfig, IoAssistDynamicConfig } from '@interopio/io-assist-react';
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
| Export | Kind | Description |
|
|
478
|
+
|--------|------|-------------|
|
|
479
|
+
| `IoAssist` | Component | The root component. Takes `staticConfig` and `dynamicConfig` props. |
|
|
480
|
+
| `IoAssistStaticConfig` | Type | Static configuration shape for the `staticConfig` prop. |
|
|
481
|
+
| `IoAssistDynamicConfig` | Type | Runtime configuration shape for the `dynamicConfig` prop. |
|
|
482
|
+
|
|
483
|
+
The prompt, icon, and working-context shapes referenced in the tables above are structural — TypeScript infers them from the config-object literals you write, so you don't need to import them separately.
|
|
484
|
+
|
|
485
|
+
The stylesheet is exported from the `./styles` subpath:
|
|
486
|
+
|
|
487
|
+
```css
|
|
488
|
+
@import "@interopio/io-assist-react/styles";
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## Related Packages
|
|
494
|
+
|
|
495
|
+
- [@interopio/ai-web](https://www.npmjs.com/package/@interopio/ai-web) — Core intelligence library
|
|
496
|
+
- [@interopio/io-assist-ng](https://www.npmjs.com/package/@interopio/io-assist-ng) — The Angular equivalent of this component
|
|
497
|
+
- [@interopio/browser](https://www.npmjs.com/package/@interopio/browser) — io.Connect Browser platform
|
|
498
|
+
- [@interopio/desktop](https://www.npmjs.com/package/@interopio/desktop) — io.Connect Desktop platform
|
|
499
|
+
- [@interopio/working-context](https://www.npmjs.com/package/@interopio/working-context) — Working context collection
|
|
500
|
+
|
|
501
|
+
## License
|
|
502
|
+
|
|
503
|
+
MIT
|
package/changelog.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { IoAssistStaticConfig, IoAssistDynamicConfig } from './types';
|
|
3
|
+
type Props = {
|
|
4
|
+
staticConfig: IoAssistStaticConfig;
|
|
5
|
+
dynamicConfig: IoAssistDynamicConfig;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Root IoAssist component.
|
|
9
|
+
* Wrap in your own router/auth shell and pass validated configs.
|
|
10
|
+
*/
|
|
11
|
+
export declare function IoAssist({ staticConfig, dynamicConfig }: Props): React.JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IoAiWeb } from '@interopio/ai-web';
|
|
2
|
+
import { ELICITATION_ACTION } from '../constants/modalActions';
|
|
3
|
+
type ElicitationResponse = {
|
|
4
|
+
action: typeof ELICITATION_ACTION.ACCEPT;
|
|
5
|
+
content: Record<string, unknown>;
|
|
6
|
+
} | {
|
|
7
|
+
action: typeof ELICITATION_ACTION.DECLINE;
|
|
8
|
+
} | {
|
|
9
|
+
action: typeof ELICITATION_ACTION.CANCEL;
|
|
10
|
+
};
|
|
11
|
+
export declare function selectElicitation(mcp: IoAiWeb.MCPConfig | undefined): (serverName: string, params: IoAiWeb.ElicitationRequestParams) => Promise<ElicitationResponse>;
|
|
12
|
+
export declare function handleElicitationRequest(serverName: string, request: IoAiWeb.ElicitationRequestParams): Promise<ElicitationResponse>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { IoAssistStoreInstance } from '../stores';
|
|
2
|
+
import { IoAssistDynamicConfig, IoAssistStaticConfig } from '../types';
|
|
3
|
+
export declare function initIoAiWeb(staticConfig: IoAssistStaticConfig, dynamicConfig: IoAssistDynamicConfig, store: IoAssistStoreInstance): Promise<void>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IOConnectBrowser } from '@interopio/browser';
|
|
2
|
+
import { IoAssistStaticConfig } from '../types';
|
|
3
|
+
export type IoConnectStoreSetters = {
|
|
4
|
+
setIoConnectApi: (api: IOConnectBrowser.API) => void;
|
|
5
|
+
setIsIoConnectReady: (ready: boolean) => void;
|
|
6
|
+
setFavoritePromptNames: (names: string[]) => void;
|
|
7
|
+
setIsDarkMode: (dark: boolean) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function initIoConnect(config: IoAssistStaticConfig, store: IoConnectStoreSetters): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { IoAiWeb } from '@interopio/ai-web';
|
|
2
|
+
import { IoAssistStoreInstance } from '../stores';
|
|
3
|
+
import { IoAssistDynamicConfig } from '../types';
|
|
4
|
+
export declare function wireMcpAppEvents(ioIntelWeb: IoAiWeb.API, store: IoAssistStoreInstance, dynamicConfig: IoAssistDynamicConfig): void;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { IoAiWeb } from '@interopio/ai-web';
|
|
2
|
+
import { IoAssistStoreInstance } from '../stores';
|
|
3
|
+
export declare function processResponseStream(runHandle: IoAiWeb.Agents.StreamResponse, threadId: string, store: IoAssistStoreInstance, isActiveThread: () => boolean): Promise<void>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IoAiWeb } from '@interopio/ai-web';
|
|
2
|
+
type SamplingResponse = IoAiWeb.SamplingSuccessResponse | IoAiWeb.SamplingErrorResponse;
|
|
3
|
+
export declare function selectSampling(mcp: IoAiWeb.MCPConfig | undefined): (serverName: string, params: IoAiWeb.SamplingRequestParams) => Promise<SamplingResponse>;
|
|
4
|
+
export declare function handleSamplingRequest(serverName: string, request: IoAiWeb.SamplingRequestParams): Promise<SamplingResponse>;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IoAssistStoreInstance } from '../stores';
|
|
2
|
+
/**
|
|
3
|
+
* Toggle a prompt's favorite status and persist the new list to
|
|
4
|
+
* `io.prefs`. The store mutation is optimistic; if `prefs.update` fails,
|
|
5
|
+
* the previous list is restored.
|
|
6
|
+
*/
|
|
7
|
+
export declare function toggleFavoritePrompt(store: IoAssistStoreInstance, name: string): Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Async question-style dialog backed by `currentConfirmModal` store state:
|
|
4
|
+
* sampling consent, elicitation, mcp-replace. Renders `{heading, text, buttons}`
|
|
5
|
+
* config and resolves the promise returned by `showConfirmModal` with the
|
|
6
|
+
* clicked button id.
|
|
7
|
+
*/
|
|
8
|
+
export declare const ConfirmModal: React.FC;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { UIAssistantMessage } from '../../types';
|
|
3
|
+
type Props = {
|
|
4
|
+
message: UIAssistantMessage;
|
|
5
|
+
isLast?: boolean;
|
|
6
|
+
onReload?: () => void;
|
|
7
|
+
isGenerating?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare const AssistantMessage: React.FC<Props>;
|
|
10
|
+
export {};
|