Assistant Frame API
The Assistant Frame API enables iframes to provide model context (tools and instructions) to a parent window's assistant. This is particularly useful for embedded applications, plugins, or sandboxed components that need to contribute capabilities to the main assistant.
Overview
The Assistant Frame system consists of two main components:
- AssistantFrameProvider: Runs inside the iframe and provides model context
- AssistantFrameHost: Runs in the parent window and consumes context from iframes
Basic Usage
In the iframe (Provider)
The iframe acts as a provider of model context using AssistantFrameProvider
:
// iframe.tsx
import { AssistantFrameProvider } from "@assistant-ui/react";
import { ModelContextRegistry } from "@assistant-ui/react";
import { z } from "zod";
// Create a registry to manage your model context
const registry = new ModelContextRegistry();
// Expose the registry to the parent window
AssistantFrameProvider.addModelContextProvider(registry);
// Add tools that will be available to the parent assistant
registry.addTool({
toolName: "searchProducts",
description: "Search for products in the catalog",
parameters: z.object({
query: z.string(),
category: z.string().optional(),
}),
execute: async ({ query, category }) => {
// Tool implementation runs in the iframe
const results = await searchAPI(query, category);
return { products: results };
},
});
// Add system instructions
const instructionHandle = registry.addInstruction(
"You are a helpful assistant.",
);
// update the instruction
instructionHandle.update("You have access to a product catalog search tool.");
In the parent window (Host)
The parent window consumes the iframe's context using AssistantFrameHost
:
// parent.tsx
import { useAssistantFrameHost } from "@assistant-ui/react";
import { useRef } from "react";
function ParentComponent() {
const iframeRef = useRef<HTMLIFrameElement>(null);
// Connect to the iframe's model context
useAssistantFrameHost({
iframeRef,
targetOrigin: "https://trusted-iframe-domain.com", // optional for increased security
});
return (
<div>
<Thread /> {/* Your assistant UI */}
<iframe
ref={iframeRef}
src="https://trusted-iframe-domain.com/embed"
title="Embedded App"
/>
</div>
);
}
Advanced Usage
ModelContextRegistry
The ModelContextRegistry
provides a flexible way to manage model context dynamically:
const registry = new ModelContextRegistry();
// Add a tool with handle for updates
const toolHandle = registry.addTool({
toolName: "convertCurrency",
description: "Convert between currencies",
parameters: z.object({
amount: z.number(),
from: z.string(),
to: z.string()
}),
execute: async ({ amount, from, to }) => {
const rate = await fetchExchangeRate(from, to);
return { result: amount * rate, currency: to };
},
});
// Update the tool later
toolHandle.update({
toolName: "convertCurrency",
description: "Convert between currencies with live rates", // Updated description
parameters: z.object({
amount: z.number(),
from: z.string(),
to: z.string(),
includesFees: z.boolean().optional()
}),
execute: async ({ amount, from, to, includesFees }) => {
const rate = await fetchExchangeRate(from, to);
const fee = includesFees ? 0.02 : 0; // 2% fee
return {
result: amount * rate * (1 - fee),
currency: to,
fee: includesFees ? amount * rate * fee : 0
};
},
});
// Remove the tool when no longer needed
toolHandle.remove();
// Add multiple instructions
const instruction1 = registry.addInstruction("Be helpful and concise.");
const instruction2 = registry.addInstruction("Use metric units.");
// Remove instructions
instruction1.remove();
Multiple Providers
You can register multiple model context providers in the same iframe:
const catalogRegistry = new ModelContextRegistry();
const analyticsRegistry = new ModelContextRegistry();
// Add different tools to each registry
catalogRegistry.addTool({
/* ... */
});
analyticsRegistry.addTool({
/* ... */
});
// Register both providers
const unsubscribe1 =
AssistantFrameProvider.addModelContextProvider(catalogRegistry);
const unsubscribe2 =
AssistantFrameProvider.addModelContextProvider(analyticsRegistry);
// Later, unsubscribe if needed
unsubscribe1();
unsubscribe2();
Security Considerations
Origin Validation
Both the provider and host can specify allowed origins for security:
// In iframe - only accept messages from specific parent
AssistantFrameProvider.addModelContextProvider(
registry,
"https://parent-app.com",
);
// In parent - only accept messages from specific iframe
useAssistantFrameHost({
iframeRef,
targetOrigin: "https://iframe-app.com",
});
Tool Execution
Tools are executed in the iframe's context, keeping sensitive operations sandboxed:
registry.addTool({
toolName: "accessDatabase",
description: "Query the database",
parameters: z.object({ query: z.string() }),
execute: async ({ query }) => {
// This runs in the iframe with iframe's permissions
// Parent cannot directly access the database
const results = await db.query(query);
return results;
},
});
API Reference
AssistantFrameProvider
Static class that manages model context providers in an iframe.
Methods
addModelContextProvider(provider, targetOrigin?)
Registers a model context provider to share with parent windows.
const unsubscribe = AssistantFrameProvider.addModelContextProvider(
registry,
"https://parent-domain.com", // Optional origin restriction
);
dispose()
Cleans up all resources and removes all providers.
AssistantFrameProvider.dispose();
AssistantFrameHost
Class that connects to an iframe's model context providers.
Constructor
const host = new AssistantFrameHost(
iframeWindow,
targetOrigin? // Optional origin restriction
);
Methods
getModelContext()
Returns the current merged model context from the iframe.
const context = host.getModelContext();
// { system: "...", tools: { ... } }
subscribe(callback)
Subscribes to model context changes.
const unsubscribe = host.subscribe(() => {
console.log("Context updated:", host.getModelContext());
});
dispose()
Cleans up the connection to the iframe.
host.dispose();
useAssistantFrameHost
React hook that manages the lifecycle of an AssistantFrameHost.
useAssistantFrameHost({
iframeRef: RefObject<HTMLIFrameElement>,
targetOrigin?: string,
});
ModelContextRegistry
A flexible registry for managing model context with dynamic updates.
Methods
addTool(tool)
Adds a tool and returns a handle for updates/removal.
const handle = registry.addTool({
toolName: string,
description?: string,
parameters: ZodSchema | JSONSchema,
execute: (args, context) => Promise<any>,
});
handle.update(newTool); // Update the tool
handle.remove(); // Remove the tool
addInstruction(instruction)
Adds a system instruction and returns a handle.
const handle = registry.addInstruction("Be concise.");
handle.update("Be detailed."); // Update instruction
handle.remove(); // Remove instruction
addProvider(provider)
Adds another model context provider.
const handle = registry.addProvider(anotherProvider);
handle.remove(); // Remove provider
Use Cases
Embedded Analytics Dashboard
An analytics iframe can provide data query tools to the parent assistant:
// In analytics iframe
registry.addTool({
toolName: "queryMetrics",
description: "Query analytics data",
parameters: z.object({
metric: z.string(),
timeRange: z.string(),
}),
execute: async ({ metric, timeRange }) => {
const data = await analyticsAPI.query(metric, timeRange);
return { data, visualization: createChart(data) };
},
});
Plugin System
Third-party plugins can extend the assistant's capabilities:
// In plugin iframe
registry.addTool({
toolName: "translateText",
description: "Translate text to another language",
parameters: z.object({
text: z.string(),
targetLanguage: z.string(),
}),
execute: async ({ text, targetLanguage }) => {
return await pluginAPI.translate(text, targetLanguage);
},
});
Data Visualization
Provide data visualization tools in an iframe:
// In visualization iframe
registry.addTool({
toolName: "createChart",
description: "Generate a chart from data",
parameters: z.object({
data: z.array(z.object({
label: z.string(),
value: z.number()
})),
chartType: z.enum(["bar", "line", "pie"]),
title: z.string().optional()
}),
execute: async ({ data, chartType, title }) => {
// Generate chart using a library like Chart.js or D3
const chartUrl = await generateChart(data, chartType, title);
return {
chartUrl,
summary: `Created ${chartType} chart with ${data.length} data points`
};
},
});