feat: make ToolExecutor an async trait (#22560)

## Why

`codex_tools::ToolExecutor` keeps a tool spec attached to its runtime
handler, but extension tools still carried a parallel
`ExtensionToolFuture` / `ExtensionToolExecutor` shape. That made
extension-owned tools look different from host tools even though
routing, registration, and execution need the same abstraction.

This PR makes the shared executor contract directly async and lets
extension tools implement it too, so host tools and extension tools can
move through the same registration path.

## What changed

- Changed `ToolExecutor::handle` to an `async fn` using `async-trait`,
and updated built-in tool handlers to implement the async trait
directly.
- Replaced the bespoke `ExtensionToolFuture` contract with a marker
`ExtensionToolExecutor` over `ToolExecutor<ToolCall, Output =
JsonToolOutput>`, re-exporting `ToolExecutor` from
`codex-extension-api`.
- Updated the memories extension tools to implement the shared executor
trait.
- Split tool-router construction into collected executors plus hosted
model specs, keeping hosted tools like web search and image generation
separate from executable handlers.
- Updated spec/router tests and extension-tool stubs for the new
executor shape.

## Verification

- Not run locally.
This commit is contained in:
jif-oai
2026-05-14 11:23:57 +02:00
committed by GitHub
parent 6a225e4005
commit 6d65686313
54 changed files with 313 additions and 237 deletions
@@ -87,6 +87,7 @@ impl CodeModeExecuteHandler {
}
}
#[async_trait::async_trait]
impl ToolExecutor<ToolInvocation> for CodeModeExecuteHandler {
type Output = FunctionToolOutput;
@@ -41,6 +41,7 @@ where
})
}
#[async_trait::async_trait]
impl ToolExecutor<ToolInvocation> for CodeModeWaitHandler {
type Output = FunctionToolOutput;