@assistant-ui/react
Version:
TypeScript/React library for AI Chat
105 lines (72 loc) • 3.67 kB
Markdown
## Assistant Frames
Assistant frames allow an iframe to provide model context (tools, instructions) to a parent window's assistant.
### Scope
Supported features are:
- ModelContextProvider API
- support for tools (defining tool name, description, parameters, execute)
- support for instructions (system instructions)
Out of scope for now:
- model configuration (temperature, etc.)
- ToolCallReader API (incremental reading support)
### API design
[SPEC_ModelContextRegistry](../registry/SPEC_ModelContextRegistry.md)
### Inside the iframe (provides context)
```typescript
// Add model context providers
const registry = new ModelContextRegistry();
AssistantFrameProvider.addModelContextProvider(registry);
// Add tools/instructions to registry
registry.addTool({
toolName: "search",
description: "Search the web",
parameters: z.object({ query: z.string() }),
execute: async (args) => {
// Tool implementation runs in iframe
return { results: ["..."] };
},
});
```
### In the parent window (consumes context)
```typescript
// The parent window hosts the assistant that needs the context
const frameHost = new AssistantFrameHost(iframeWindow);
// Register with assistant runtime
const runtime = useAssistantRuntime();
runtime.registerModelContextProvider(frameHost);
// The assistant now has access to tools from the iframe
```
### Communication Channel Design
The communication between `AssistantFrameProvider` (iframe) and `AssistantFrameHost` (parent window) uses the `window.postMessage` API with a structured protocol. The iframe provides model context to the parent window's assistant.
#### ModelContextProvider API
AssistantFrameHost implements the ModelContextProvider API. It immediately subscribes to the iframe for updates. This is necessary because ModelContextProvider.getModelContext() is synchronous.
#### Message Channel
All messages are wrapped with a channel identifier to avoid conflicts with other postMessage usage:
```typescript
{
channel: "assistant-ui-frame",
message: FrameMessage
}
```
#### Message Types
1. **Context Discovery**
- `model-context-request`: Parent (Host) requests current context from iframe (Provider)
- `model-context-update`: Iframe pushes context changes to parent
2. **Tool Execution**
- `tool-call`: Parent requests tool execution in iframe (where tools are defined)
- `tool-result`: Iframe returns execution result or error to parent
#### Serialization
- **Tools**: Zod schemas are converted to JSON Schema format using `z.toJSONSchema()`
- **Parameters**: Tool parameters are serialized as JSON
- **System messages**: Passed as strings
- **Unsupported features**: Model config, call settings, and priority are not transmitted
#### Security Considerations
1. **Origin Validation**: Both sides can specify `targetOrigin` to restrict message sources
2. **Window Reference**: Host (parent) only accepts messages from the specific iframe window it's connected to
3. **Message Channel**: Using a unique channel identifier prevents cross-talk with other postMessage users
#### Connection Lifecycle
1. **Initialization**: Parent (Host) sends `model-context-request` to iframe on creation
2. **Updates**: Iframe (Provider) notifies parent whenever any registered ModelContextProvider changes
#### Error Handling
- Tool execution errors are serialized and sent back as error messages
- Connection failures (timeout, no response) are silently handled - the Host continues to work as an empty ModelContextProvider
- If the iframe doesn't register any providers, the AssistantFrameHost acts as a no-op empty ModelContextProvider returning `{}` from `getModelContext()`