npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@interopio/io-assist-react

v1.0.1

Published

io.Intelligence React client library

Downloads

231

Readme

@interopio/io-assist-react

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 compatible agent server — with streaming responses, persistent threads, a prompt library, MCP tool access, working context awareness, and built-in sampling/elicitation handling.

Built on io.Connect and @interopio/ai-web.

Features

  • Conversational AI chat — Streaming responses, markdown rendering, code highlighting
  • Persistent conversation threads — Thread history with resume, rename, and delete
  • Prompt library — Categorized pre-written prompts with favorites (persisted via io.Connect preferences)
  • MCP tool access — Built-in io.Intelligence MCP server, extensible with remote and third-party servers
  • MCP Apps — Custom HTML applications rendered inline in chat or in io.Connect workspace windows
  • Sampling & elicitation — Built-in confirmation/input UI for MCP server requests (replaceable with custom handlers)
  • Working context — Live data from io.Connect contexts passed to the agent with every message
  • Theming — Automatic dark/light mode sync with io.Connect

Prerequisites

  • React 18+
  • Node.js 20.19+ (< 22)
  • npm 10+
  • An AG-UI Protocol compatible agent server (e.g. Mastra)

Installation

npm install @interopio/io-assist-react

react and react-dom are the only peer dependencies — your app already provides them:

npm install react react-dom

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.

You always need to import a platform factory and pass it in your connectConfig — pick the one that matches your environment:

// io.Connect Browser (most common)
import IOBrowser from '@interopio/browser';

// io.Connect Desktop
import IODesktop from '@interopio/desktop';

Agent Server

io.Assist requires an AG-UI Protocol compatible agent server to handle chat requests. The recommended way to get started is with Mastra.

Quick setup with Mastra

npx create-mastra@latest

This scaffolds a fully working Mastra project. Follow the prompts, then start the server:

npm run dev

By default the server runs on http://localhost:4111 — the same URL used in the Quickstart examples below.

Required environment variables:

# At least one LLM provider key
OPENAI_API_KEY=your-key
ANTHROPIC_API_KEY=your-key

For full Mastra documentation — including custom agents, tools, memory, and deployment — see mastra.ai/docs.

Quickstart

1. Add the stylesheet

@import "@interopio/io-assist-react/styles";

2. Render the component

<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).

import { IoAssist, IoAssistStaticConfig, IoAssistDynamicConfig } from '@interopio/io-assist-react';
import IOBrowser from '@interopio/browser';

const staticConfig: IoAssistStaticConfig = {
    connectConfig: {
        browser: {
            factory: IOBrowser,
        },
    },
    aiWebConfig: {
        agentServer: {
            baseUrl: 'http://localhost:4111',
        },
    },
};

const dynamicConfig: IoAssistDynamicConfig = {
    // id: Your access/auth token of choice — scopes conversation threads
    // name: UI name that will be displayed
    user: { id: 'yourIdOfChoice', name: 'Jane Doe' },
    agentServer: {
        headers: {
            Authorization: `Bearer ${import.meta.env.VITE_AUTH_TOKEN}`,
        },
    },
};

export function App() {
    return <IoAssist staticConfig={staticConfig} dynamicConfig={dynamicConfig} />;
}

3. Run

npm run dev

io.Assist is live.


Quickstart with Login

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.

import { useMemo } from 'react';
import { Navigate } from 'react-router-dom';
import { IoAssist, IoAssistDynamicConfig } from '@interopio/io-assist-react';
import { staticConfig } from './configs';
import { useAuth } from './auth';

export function AssistantShell() {
    const { userId } = useAuth();

    const dynamicConfig = useMemo<IoAssistDynamicConfig | null>(
        () => (userId ? { user: { id: userId } } : null),
        [userId],
    );

    if (!dynamicConfig) {
        return <Navigate to="/login" replace />;
    }

    return <IoAssist staticConfig={staticConfig} dynamicConfig={dynamicConfig} />;
}

Once the user logs in, dynamicConfig is populated and io.Assist loads threads scoped to that user.


What you get with the minimal config

With just the required fields (staticConfig.connectConfig, staticConfig.aiWebConfig.agentServer.baseUrl, and dynamicConfig.user), io.Assist provides:

  • Full conversational AI chat with streaming markdown responses
  • Persistent conversation threads (scoped to user.id)
  • Automatic agent selection (first available agent from your server)
  • Built-in sampling and elicitation UI (confirmation dialogs when MCP servers request them)
  • Built-in io.Intelligence MCP server connection
  • Dark/light theme sync with io.Connect
  • Auto-injected fonts and syntax highlighting

No prompts, no working context, and no MCP Apps — those require additional configuration below.


Configuration

io.Assist uses two separate configuration objects, passed as two distinct props:

  • IoAssistStaticConfig — infrastructure settings that don't change at runtime (platform factory, agent server, MCP, prompts). Pass it as the staticConfig prop.
  • IoAssistDynamicConfig — the active user's identity and per-request headers, which may only be known after login. Pass it as the dynamicConfig prop.

Static configuration (IoAssistStaticConfig)

Passed as the staticConfig prop.

Required fields

| Field | Type | Description | |-------|------|-------------| | connectConfig | { browser?, desktop? } | io.Connect platform settings. Must include a browser and/or desktop entry, each with a factory (and optional config). | | aiWebConfig.agentServer.baseUrl | string | Base URL of your AG-UI compatible agent server. |

Optional fields

| Field | Type | Description | |-------|------|-------------| | aiWebConfig.agentServer.* | IoAiWeb.AgentServerConfig | Additional agent-server options (retries, backoff, credentials, etc.). | | aiWebConfig.mcp | IoAiWeb.MCPConfig | MCP configuration — remote servers, MCP Apps, sampling/elicitation overrides. | | defaultAgentName | string | Agent to select on startup. Falls back to the first available agent if not found. | | defaultPrompts | IoAssistPromptCategory[] | Categorized prompt library entries. | | workingContext | IoAiWeb.WorkingContextConfig | Live context collection from io.Connect. |

Dynamic configuration (IoAssistDynamicConfig)

Passed as the dynamicConfig prop. Typically derived from your authentication state.

| Field | Type | Description | |-------|------|-------------| | user.id | string | Required. Unique user identifier. Scopes conversation threads — each user sees only their own threads. | | user.name | string? | Display name shown in the chat UI and thread history. | | 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. |


Configuration Examples

Standard — with prompts and a named agent

import { IoAssistStaticConfig } from '@interopio/io-assist-react';
import IOBrowser from '@interopio/browser';

export const staticConfig: IoAssistStaticConfig = {
    connectConfig: {
        browser: { factory: IOBrowser },
    },
    aiWebConfig: {
        agentServer: {
            baseUrl: 'http://localhost:4111',
        },
    },
    defaultAgentName: 'my-agent',
    defaultPrompts: [
        {
            category: 'General',
            prompts: [
                { name: 'Summarize', prompt: 'Please summarize the following content:' },
                { name: 'Explain', prompt: 'Please explain this in simple terms:' },
            ],
        },
        {
            category: 'Code',
            prompts: [
                { name: 'Review Code', prompt: 'Please review this code and suggest improvements:' },
                {
                    name: 'Add Comments',
                    prompt: 'Annotate this code with detailed comments:',
                    iconResource: {
                        type: 'svg',
                        data: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="..."/></svg>',
                    },
                },
            ],
        },
    ],
};

What this adds over minimal:

  • Named agent pre-selected at startup
  • Prompt library with two categories — users can browse, search, and favorite prompts

Advanced — custom handlers, MCP Apps, working context

import { IoAssistStaticConfig } from '@interopio/io-assist-react';
import { IoAiWeb } from '@interopio/ai-web';
import IOBrowser from '@interopio/browser';
import { IoIntelWorkingContextFactory, IoIntelWorkingContext } from '@interopio/working-context';

export const staticConfig: IoAssistStaticConfig = {
    connectConfig: {
        browser: { factory: IOBrowser },
    },
    aiWebConfig: {
        agentServer: {
            baseUrl: 'http://localhost:4111',
        },
        mcp: {
            // Custom sampling handler — replaces the built-in confirmation dialog
            clientsConfig: {
                enforceStrictCapabilities: false,
                capabilities: {
                    sampling: {
                        handler: async (
                            serverId: string,
                            params: IoAiWeb.SamplingRequestParams,
                        ): Promise<IoAiWeb.SamplingSuccessResponse> => {
                            // Your custom logic — show your own UI, call your own APIs, etc.
                            return {
                                model: 'gpt-4',
                                role: 'assistant',
                                content: { type: 'text', text: 'Custom sampling response' },
                                stopReason: 'endTurn',
                            };
                        },
                    },
                    elicitation: {
                        handler: async (
                            serverId: string,
                            params: IoAiWeb.ElicitationRequestParams,
                        ): Promise<IoAiWeb.ElicitationResponse> => {
                            // Your custom logic — build a form, collect user input, etc.
                            return { action: 'accept', content: { confirmed: true } };
                        },
                    },
                    // Required for MCP Apps
                    extensions: {
                        'io.modelcontextprotocol/ui': {
                            mimeTypes: ['text/html;profile=mcp-app'],
                        },
                    },
                },
            },
            // MCP Apps — interactive UI panels in chat or workspace windows
            mcpApps: {
                sandboxProxyUrl: 'http://localhost:6565/index.html',
                displayMode: 'workspace', // or 'inline'
            },
            // Remote MCP servers
            ioIntel: {
                remote: {
                    streamableHttp: {
                        url: 'http://localhost:8989/mcp',
                        name: 'remote-io-mcp-server',
                    },
                },
            },
            remoteServers: [
                {
                    streamableHttp: {
                        url: 'http://localhost:8081/mcp',
                        name: 'third-party-server',
                    },
                },
            ],
        },
    },
    defaultAgentName: 'my-agent',
    defaultPrompts: [
        {
            category: 'General',
            prompts: [
                { name: 'Summarize', prompt: 'Please summarize the following content:' },
            ],
        },
    ],
    workingContext: {
        factory: IoIntelWorkingContextFactory,
        config: {
            schema: {
                userId: {
                    type: 'string',
                    description: "Current user's identifier",
                    source: {
                        context: {
                            location: { global: { names: ['UserSession'] } },
                            path: 'user.id',
                        },
                    },
                },
                selectedClient: {
                    type: 'string',
                    description: 'Client currently selected in the workspace',
                    source: {
                        context: {
                            location: { workspace: {} },
                            path: 'client.name',
                        },
                    },
                },
            },
        } as IoIntelWorkingContext.Config,
    },
};

What this adds over standard:

  • Custom sampling handler — replaces the built-in confirmation dialog. When an MCP server makes a sampling request, your handler runs instead.
  • Custom elicitation handler — replaces the built-in elicitation dialog. When an MCP server requests user input, your handler runs instead.
  • 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.
  • Remote MCP servers — switch the io.Intelligence MCP to a remote endpoint and/or add third-party MCP servers.
  • Working context — io.Assist reads live data from io.Connect contexts and passes it to the agent with every message.

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 for a full component example.


MCP Apps

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.

Requirements — two config sections must both be present under aiWebConfig.mcp:

  1. mcpApps — enables the MCP Apps runtime:

    mcpApps: {
        sandboxProxyUrl: 'http://localhost:6565/index.html',
        displayMode: 'workspace', // 'workspace' | 'inline' (optional, auto-detects if omitted)
    },
  2. extensions — tells MCP servers that this client supports UI:

    capabilities: {
        extensions: {
            'io.modelcontextprotocol/ui': {
                mimeTypes: ['text/html;profile=mcp-app'],
            },
        },
    },

Without both, MCP servers will not expose UI metadata on tool definitions and no apps will be created.

Display modes:

| Mode | Behavior | |------|----------| | 'inline' | App renders inside the chat message flow | | 'workspace' | App opens in a separate io.Connect workspace window (falls back to inline if workspaces are unavailable) |

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.


Sampling & Elicitation

When an MCP server sends a sampling or elicitation request:

| Scenario | Behavior | |----------|----------| | No custom handler | io.Assist shows a built-in confirmation dialog (uses an io.Connect modal if available, otherwise an in-app overlay) | | Custom handler provided | Your handler function runs instead — full control over UI and response | | Request from a background thread | Automatically rejected (the user must be on the active thread the request targets) |

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.

Elicitation — the MCP server asks the client to collect user input. The built-in handler presents accept/decline/cancel options.

Custom handlers are configured under aiWebConfig.mcp.clientsConfig.capabilities — see the advanced configuration example for the handler signatures.


Prompt Icons

Each prompt can have an optional iconResource. Three formats are supported:

| Type | Example | Notes | |------|---------|-------| | 'svg' | '<svg xmlns="..." viewBox="0 0 24 24">...</svg>' | Sanitized: fill, width, height stripped; hardcoded colors → currentColor | | 'url' | '/icons/summarize.svg' | Must be an absolute URL or absolute path from the document root | | 'data-url' | 'data:image/svg+xml;base64,...' | Base64-encoded SVG, PNG, or JPEG |

Prompts without an icon show a default icon.


Public API

The package exposes a deliberately small surface — one component and the two config types it consumes:

import { IoAssist } from '@interopio/io-assist-react';
import type { IoAssistStaticConfig, IoAssistDynamicConfig } from '@interopio/io-assist-react';

| Export | Kind | Description | |--------|------|-------------| | IoAssist | Component | The root component. Takes staticConfig and dynamicConfig props. | | IoAssistStaticConfig | Type | Static configuration shape for the staticConfig prop. | | IoAssistDynamicConfig | Type | Runtime configuration shape for the dynamicConfig prop. |

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.

The stylesheet is exported from the ./styles subpath:

@import "@interopio/io-assist-react/styles";

Related Packages

License

MIT