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`,
};
},
});