mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Add TUI tools for managing Codex tasks (#40308)
## Why The TUI rejected app-server dynamic tool calls as unsupported, so agents could not inspect or manage other Codex tasks through a TUI session. ## What changed - Add the `codex_tui` tool namespace for listing, reading, waiting on, creating, forking, messaging, renaming, archiving, and restoring tasks. - Handle tool calls through existing app-server thread operations, with bounded inputs and responses and cleanup when calls complete or the TUI disconnects. - Route delegation tools through an authenticated local MCP server with explicit approval prompts, while respecting configured and managed MCP policies. - Fall back to starting threads without dynamic tools when connected to an older app server that does not support them. ## Testing Add coverage for tool schemas and response bounds, task lifecycle operations, approval-gated MCP transport, namespace dispatch, cancellation, and legacy app-server fallback behavior. GitOrigin-RevId: c782c11f0a3edceb3fa6909a4b92d6ce01a6eed3
This commit is contained in:
1 parent
fb0781b9ee
commit
a8468330bb
18 files changed
+3722
-62
No files matched your search
@@ -100,6 +100,35 @@ impl App {
|
||||
self.handle_startup_thread_started(app_server, result)
|
||||
.await?;
|
||||
}
|
||||
AppEvent::DynamicToolThreadStarted {
|
||||
thread_id,
|
||||
registered,
|
||||
} => {
|
||||
self.agents_overview
|
||||
.dispatched_requests
|
||||
.entry(thread_id)
|
||||
.or_default();
|
||||
let _ = registered.send(());
|
||||
}
|
||||
AppEvent::DynamicToolCallCompleted {
|
||||
request_id,
|
||||
response,
|
||||
} => {
|
||||
self.dynamic_tool_tasks.remove(&request_id);
|
||||
match serde_json::to_value(response) {
|
||||
Ok(result) => {
|
||||
if let Err(error) = app_server
|
||||
.resolve_server_request(request_id.clone(), result)
|
||||
.await
|
||||
{
|
||||
tracing::warn!(?request_id, %error, "failed to resolve dynamic tool call");
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!(?request_id, %error, "failed to serialize dynamic tool response");
|
||||
}
|
||||
}
|
||||
}
|
||||
AppEvent::RequestOlderScrollbackHistory { thread_id } => {
|
||||
if self.chat_widget.thread_id() == Some(thread_id)
|
||||
&& self.overlay.is_none()
|
||||
@@ -2903,6 +2932,25 @@ impl App {
|
||||
app_server: &mut AppServerSession,
|
||||
mode: ExitMode,
|
||||
) -> AppRunControl {
|
||||
for (request_id, (_, task)) in self.dynamic_tool_tasks.drain() {
|
||||
task.abort();
|
||||
let response = crate::dynamic_tools::failure_response(
|
||||
"TUI disconnected while handling a dynamic tool call",
|
||||
);
|
||||
match serde_json::to_value(response) {
|
||||
Ok(result) => {
|
||||
if let Err(error) = app_server
|
||||
.resolve_server_request(request_id.clone(), result)
|
||||
.await
|
||||
{
|
||||
tracing::warn!(?request_id, %error, "failed to cancel dynamic tool call");
|
||||
}
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::warn!(?request_id, %error, "failed to serialize dynamic tool response")
|
||||
}
|
||||
}
|
||||
}
|
||||
match mode {
|
||||
ExitMode::ShutdownFirst => {
|
||||
// Mark the thread we are explicitly shutting down for exit so
|
||||
|
||||
Reference in new issue
Block a user