mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
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:
1 parent
6a225e4005
commit
6d65686313
54 files changed
+313
-237
No files matched your search
@@ -1,7 +1,6 @@
|
||||
use codex_extension_api::ExtensionToolExecutor;
|
||||
use codex_extension_api::ExtensionToolFuture;
|
||||
use codex_extension_api::JsonToolOutput;
|
||||
use codex_extension_api::ToolCall;
|
||||
use codex_extension_api::ToolExecutor;
|
||||
use codex_extension_api::ToolName;
|
||||
use codex_extension_api::ToolSpec;
|
||||
use schemars::JsonSchema;
|
||||
@@ -35,10 +34,13 @@ pub(super) struct ListTool<B> {
|
||||
pub(super) backend: B,
|
||||
}
|
||||
|
||||
impl<B> ExtensionToolExecutor for ListTool<B>
|
||||
#[async_trait::async_trait]
|
||||
impl<B> ToolExecutor<ToolCall> for ListTool<B>
|
||||
where
|
||||
B: MemoriesBackend,
|
||||
{
|
||||
type Output = JsonToolOutput;
|
||||
|
||||
fn tool_name(&self) -> ToolName {
|
||||
memory_tool_name(LIST_TOOL_NAME)
|
||||
}
|
||||
@@ -50,23 +52,24 @@ where
|
||||
))
|
||||
}
|
||||
|
||||
fn handle(&self, call: ToolCall) -> ExtensionToolFuture<'_> {
|
||||
async fn handle(
|
||||
&self,
|
||||
call: ToolCall,
|
||||
) -> Result<Self::Output, codex_extension_api::FunctionCallError> {
|
||||
let backend = self.backend.clone();
|
||||
Box::pin(async move {
|
||||
let args: ListArgs = parse_args(&call)?;
|
||||
let response = backend
|
||||
.list(ListMemoriesRequest {
|
||||
path: args.path,
|
||||
cursor: args.cursor,
|
||||
max_results: clamp_max_results(
|
||||
args.max_results,
|
||||
DEFAULT_LIST_MAX_RESULTS,
|
||||
MAX_LIST_RESULTS,
|
||||
),
|
||||
})
|
||||
.await
|
||||
.map_err(backend_error_to_function_call)?;
|
||||
Ok(JsonToolOutput::new(json!(response)))
|
||||
})
|
||||
let args: ListArgs = parse_args(&call)?;
|
||||
let response = backend
|
||||
.list(ListMemoriesRequest {
|
||||
path: args.path,
|
||||
cursor: args.cursor,
|
||||
max_results: clamp_max_results(
|
||||
args.max_results,
|
||||
DEFAULT_LIST_MAX_RESULTS,
|
||||
MAX_LIST_RESULTS,
|
||||
),
|
||||
})
|
||||
.await
|
||||
.map_err(backend_error_to_function_call)?;
|
||||
Ok(JsonToolOutput::new(json!(response)))
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
use codex_extension_api::ExtensionToolExecutor;
|
||||
use codex_extension_api::ExtensionToolFuture;
|
||||
use codex_extension_api::JsonToolOutput;
|
||||
use codex_extension_api::ToolCall;
|
||||
use codex_extension_api::ToolExecutor;
|
||||
use codex_extension_api::ToolName;
|
||||
use codex_extension_api::ToolSpec;
|
||||
use schemars::JsonSchema;
|
||||
@@ -34,10 +33,13 @@ pub(super) struct ReadTool<B> {
|
||||
pub(super) backend: B,
|
||||
}
|
||||
|
||||
impl<B> ExtensionToolExecutor for ReadTool<B>
|
||||
#[async_trait::async_trait]
|
||||
impl<B> ToolExecutor<ToolCall> for ReadTool<B>
|
||||
where
|
||||
B: MemoriesBackend,
|
||||
{
|
||||
type Output = JsonToolOutput;
|
||||
|
||||
fn tool_name(&self) -> ToolName {
|
||||
memory_tool_name(READ_TOOL_NAME)
|
||||
}
|
||||
@@ -49,20 +51,21 @@ where
|
||||
))
|
||||
}
|
||||
|
||||
fn handle(&self, call: ToolCall) -> ExtensionToolFuture<'_> {
|
||||
async fn handle(
|
||||
&self,
|
||||
call: ToolCall,
|
||||
) -> Result<Self::Output, codex_extension_api::FunctionCallError> {
|
||||
let backend = self.backend.clone();
|
||||
Box::pin(async move {
|
||||
let args: ReadArgs = parse_args(&call)?;
|
||||
let response = backend
|
||||
.read(ReadMemoryRequest {
|
||||
path: args.path,
|
||||
line_offset: args.line_offset.unwrap_or(1),
|
||||
max_lines: args.max_lines,
|
||||
max_tokens: DEFAULT_READ_MAX_TOKENS,
|
||||
})
|
||||
.await
|
||||
.map_err(backend_error_to_function_call)?;
|
||||
Ok(JsonToolOutput::new(json!(response)))
|
||||
})
|
||||
let args: ReadArgs = parse_args(&call)?;
|
||||
let response = backend
|
||||
.read(ReadMemoryRequest {
|
||||
path: args.path,
|
||||
line_offset: args.line_offset.unwrap_or(1),
|
||||
max_lines: args.max_lines,
|
||||
max_tokens: DEFAULT_READ_MAX_TOKENS,
|
||||
})
|
||||
.await
|
||||
.map_err(backend_error_to_function_call)?;
|
||||
Ok(JsonToolOutput::new(json!(response)))
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
use codex_extension_api::ExtensionToolExecutor;
|
||||
use codex_extension_api::ExtensionToolFuture;
|
||||
use codex_extension_api::JsonToolOutput;
|
||||
use codex_extension_api::ToolCall;
|
||||
use codex_extension_api::ToolExecutor;
|
||||
use codex_extension_api::ToolName;
|
||||
use codex_extension_api::ToolSpec;
|
||||
use schemars::JsonSchema;
|
||||
@@ -43,10 +42,13 @@ pub(super) struct SearchTool<B> {
|
||||
pub(super) backend: B,
|
||||
}
|
||||
|
||||
impl<B> ExtensionToolExecutor for SearchTool<B>
|
||||
#[async_trait::async_trait]
|
||||
impl<B> ToolExecutor<ToolCall> for SearchTool<B>
|
||||
where
|
||||
B: MemoriesBackend,
|
||||
{
|
||||
type Output = JsonToolOutput;
|
||||
|
||||
fn tool_name(&self) -> ToolName {
|
||||
memory_tool_name(SEARCH_TOOL_NAME)
|
||||
}
|
||||
@@ -58,16 +60,17 @@ where
|
||||
))
|
||||
}
|
||||
|
||||
fn handle(&self, call: ToolCall) -> ExtensionToolFuture<'_> {
|
||||
async fn handle(
|
||||
&self,
|
||||
call: ToolCall,
|
||||
) -> Result<Self::Output, codex_extension_api::FunctionCallError> {
|
||||
let backend = self.backend.clone();
|
||||
Box::pin(async move {
|
||||
let args: SearchArgs = parse_args(&call)?;
|
||||
let response = backend
|
||||
.search(args.into_request())
|
||||
.await
|
||||
.map_err(backend_error_to_function_call)?;
|
||||
Ok(JsonToolOutput::new(json!(response)))
|
||||
})
|
||||
let args: SearchArgs = parse_args(&call)?;
|
||||
let response = backend
|
||||
.search(args.into_request())
|
||||
.await
|
||||
.map_err(backend_error_to_function_call)?;
|
||||
Ok(JsonToolOutput::new(json!(response)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user