feat: show MCP tool calls in TUI (#836)

Adds logic for the `McpToolCallBegin` and `McpToolCallEnd` events in
`codex-rs/tui/src/chatwidget.rs` so they get entries in the conversation
history in the TUI.

Building on top of https://github.com/openai/codex/pull/829, here is the
result of running:

```
cargo run --bin codex -- 'what is the weather in san francisco tomorrow'
```


![image](https://github.com/user-attachments/assets/db4a79bb-4988-46cb-acb2-446d5ba9e058)
This commit is contained in:
Michael Bolin
2025-05-06 16:12:15 -07:00
committed by GitHub
parent 147a940449
commit 88e7ca5f2b
5 changed files with 172 additions and 3 deletions

View File

@@ -8,6 +8,7 @@ use crossterm::event::KeyEvent;
use ratatui::prelude::*;
use ratatui::style::Style;
use ratatui::widgets::*;
use serde_json::Value as JsonValue;
use std::cell::Cell as StdCell;
use std::collections::HashMap;
use std::path::PathBuf;
@@ -192,6 +193,18 @@ impl ConversationHistoryWidget {
self.add_to_history(HistoryCell::new_active_exec_command(call_id, command));
}
pub fn add_active_mcp_tool_call(
&mut self,
call_id: String,
server: String,
tool: String,
arguments: Option<JsonValue>,
) {
self.add_to_history(HistoryCell::new_active_mcp_tool_call(
call_id, server, tool, arguments,
));
}
fn add_to_history(&mut self, cell: HistoryCell) {
self.history.push(cell);
}
@@ -232,6 +245,43 @@ impl ConversationHistoryWidget {
}
}
}
pub fn record_completed_mcp_tool_call(
&mut self,
call_id: String,
success: bool,
result: Option<mcp_types::CallToolResult>,
) {
// Convert result into serde_json::Value early so we don't have to
// worry about lifetimes inside the match arm.
let result_val = result.map(|r| {
serde_json::to_value(r)
.unwrap_or_else(|_| serde_json::Value::String("<serialization error>".into()))
});
for cell in self.history.iter_mut() {
if let HistoryCell::ActiveMcpToolCall {
call_id: history_id,
fq_tool_name,
invocation,
start,
..
} = cell
{
if &call_id == history_id {
let completed = HistoryCell::new_completed_mcp_tool_call(
fq_tool_name.clone(),
invocation.clone(),
*start,
success,
result_val,
);
*cell = completed;
break;
}
}
}
}
}
impl WidgetRef for ConversationHistoryWidget {