onToolResult Callback
The onToolResult prop lets your website receive completed tool outputs from an assistant response. Use it when a tool result should update your page UI, populate a custom panel, or trigger application logic outside the chat transcript. To render a card inside the conversation as soon as output arrives, use uiRenderers instead.
onToolResult only runs after an assistant response has finished. It fires once for each completed tool invocation and includes both successful and failed tool calls.
Result Shape
Successful tool calls return:
{
toolName: string;
status: 'success';
output: unknown;
}
Failed tool calls return:
{
toolName: string;
status: 'error';
error: string;
}
The callback does not expose tool call IDs, tool inputs, provider metadata, HTTP status, timing, raw AI SDK parts, or internal execution fields.
Basic Usage
Agent.initStandard({
agentName: 'your-agent-name',
onToolResult: (result) => {
console.log('Tool completed:', result);
},
});
The same prop works with bubble and popup widgets:
Agent.initBubble({
agentName: 'your-agent-name',
onToolResult: (result) => {
console.log(result);
},
});
Agent.initPopup({
agentName: 'your-agent-name',
onToolResult: (result) => {
console.log(result);
},
});
Update Your Page UI
You can use tool outputs to keep application UI in sync with the assistant. For example, if a tool named get_order_status returns order data, render it into a page panel:
<div id="order-status"></div>
<script type="module">
import Agent from 'https://cdn.jsdelivr.net/npm/@agent-embed/js@latest/dist/web.js';
Agent.initStandard({
agentName: 'support-agent',
onToolResult: (result) => {
if (result.toolName !== 'get_order_status') return;
const panel = document.getElementById('order-status');
if (!panel) return;
if (result.status === 'error') {
panel.textContent = `Could not load order status: ${result.error}`;
return;
}
const order =
result.output && typeof result.output === 'object'
? result.output
: {};
const heading = document.createElement('h2');
heading.textContent = 'Order Status';
const status = document.createElement('p');
status.textContent = `Status: ${order.status ?? 'Unknown'}`;
const delivery = document.createElement('p');
delivery.textContent = `Estimated delivery: ${
order.estimatedDelivery ?? 'Not available'
}`;
panel.replaceChildren(heading, status, delivery);
},
});
</script>
<agent-standard style="width: 100%; height: 600px;"></agent-standard>
Generate Custom UI From Tool Outputs
Tool results are useful when your webapp needs more than a chat bubble. You can let the assistant call tools, then use the structured output to render a product card, account summary, itinerary, dashboard widget, or any other application UI.
Agent.initStandard({
agentName: 'shopping-agent',
onToolResult: (result) => {
if (result.toolName !== 'recommend_products') return;
const container = document.querySelector('[data-product-results]');
if (!container) return;
if (result.status === 'error') {
container.replaceChildren('Recommendations are unavailable right now.');
return;
}
const output =
result.output && typeof result.output === 'object'
? result.output
: {};
const products = Array.isArray(output.products)
? output.products
: [];
container.replaceChildren(
...products.map((product) => {
const card = document.createElement('article');
const title = document.createElement('h3');
const summary = document.createElement('p');
const link = document.createElement('a');
card.className = 'product-card';
title.textContent = product.name;
summary.textContent = product.summary;
link.href = product.url;
link.textContent = 'View product';
card.replaceChildren(title, summary, link);
return card;
})
);
},
});
This example keeps its UI outside the chatbot messages. You can also register a uiRenderers function for the same tool to display its output inside the conversation. Rendering does not depend on onToolResult.
Handle visitor interactions with event listeners in your renderer. Input renderers provide their own controls and use context.requestSubmit() or context.requestCancel() to resolve a pending form. Those methods are separate from onToolResult.
Behavior Notes
- The callback fires after the assistant response completes, not while intermediate tool states are streaming.
- One assistant response can produce multiple callback calls if it used multiple tools.
- Existing or restored conversation history does not trigger the callback.
- Tool results are emitted once per completed tool invocation in the current browser session.