When a tool completes its execution, it returns a ToolResult. This result contains the data intended for the LLM and, optionally, instructions on how to display that data in the UI.
ToolResult
The ToolResult struct captures the output of a single tool execution.
pub struct ToolResult {
/// The actual data to return to the LLM (usually JSON)
pub output: String,
/// Optional configuration for how to display this result in the UI
pub display: Option<DisplayConfig>,
/// Whether the execution was successful
pub is_error: bool,
}
DisplayConfig
DisplayConfig allows a tool to control its visual representation without being coupled to a specific UI implementation (like the TUI or a web interface).
pub struct DisplayConfig {
pub title: String,
pub content_type: ContentType,
pub collapsed: bool,
}
pub enum ContentType {
Text,
Markdown,
Json,
Code(String), // Language tag
}
By providing a DisplayConfig, a tool can ensure that its output is rendered as a formatted code block, a markdown table, or a simple text summary.
ToolBatchResult
Since tools can be executed in batches, the system uses ToolBatchResult to aggregate the results of multiple calls.
pub struct ToolBatchResult {
pub results: Vec<ToolCallResult>,
}
pub struct ToolCallResult {
pub call_id: String,
pub result: ToolResult,
}
From ToolResult to UI Message
The conversion from a raw ToolResult to a UI element follows this path:
- Tool Execution: Returns
ToolResult. - Controller: Receives
ToolBatchResult. - Event Conversion: The controller emits a
ControllerEvent::ToolResult. - UI Adapter: The UI (e.g., the TUI) receives the event and uses the
DisplayConfigto create aDisplayResultwidget.
Error Results
If a tool encounters an error, it should still return a ToolResult with is_error: true. This allows the LLM to see the error message and potentially try a different approach or correct its input.
// Example of an error result
ToolResult {
output: "Permission denied: Cannot write to /etc/shadow".to_string(),
display: Some(DisplayConfig {
title: "File Write Error".to_string(),
content_type: ContentType::Text,
collapsed: false,
}),
is_error: true,
} 