Scope extension capabilities to invocation lifetimes (#41020)

## What changed

- Add callback lifetimes to extension `ToolCall`, `ToolEnvironment`, turn-input context, and skill-read request types.
- Require extension tool executors to handle calls for any invocation lifetime and tie their returned futures to that lifetime.
- Update built-in extensions, adapters, and tests to use the lifetime-scoped APIs without retaining host-owned environment capabilities.

GitOrigin-RevId: aca9ce3a1b6870df550bc84ec9308cc65533f161
This commit is contained in:
Adam Perry @ OpenAI authored and copyberry committed 2026-08-27 02:00:31 +00:00
1 parent eed1dee69e
commit 81e180044d
85 files changed
+477 -202

No files matched your search

@@ -41,7 +41,7 @@ pub(super) struct AddAdHocNoteTool<B> {
pub(super) metrics_client: Option<MetricsClient>,
}
impl<B> ToolExecutor<ToolCall> for AddAdHocNoteTool<B>
impl<'call, B> ToolExecutor<ToolCall<'call>> for AddAdHocNoteTool<B>
where
B: MemoriesBackend,
{
@@ -56,7 +56,10 @@ where
)
}
fn handle(&self, call: ToolCall) -> codex_extension_api::ToolExecutorFuture<'_> {
fn handle<'a>(&'a self, call: ToolCall<'call>) -> codex_extension_api::ToolExecutorFuture<'a>
where
'call: 'a,
{
Box::pin(self.handle_call(call))
}
}
@@ -67,7 +70,7 @@ where
{
async fn handle_call(
&self,
call: ToolCall,
call: ToolCall<'_>,
) -> Result<Box<dyn codex_extension_api::ToolOutput>, codex_extension_api::FunctionCallError>
{
let backend = self.backend.clone();
+6 -3
View File
@@ -39,7 +39,7 @@ pub(super) struct ListTool<B> {
pub(super) metrics_client: Option<MetricsClient>,
}
impl<B> ToolExecutor<ToolCall> for ListTool<B>
impl<'call, B> ToolExecutor<ToolCall<'call>> for ListTool<B>
where
B: MemoriesBackend,
{
@@ -54,7 +54,10 @@ where
)
}
fn handle(&self, call: ToolCall) -> codex_extension_api::ToolExecutorFuture<'_> {
fn handle<'a>(&'a self, call: ToolCall<'call>) -> codex_extension_api::ToolExecutorFuture<'a>
where
'call: 'a,
{
Box::pin(self.handle_call(call))
}
}
@@ -65,7 +68,7 @@ where
{
async fn handle_call(
&self,
call: ToolCall,
call: ToolCall<'_>,
) -> Result<Box<dyn codex_extension_api::ToolOutput>, codex_extension_api::FunctionCallError>
{
let backend = self.backend.clone();
+2 -2
View File
@@ -28,7 +28,7 @@ mod search;
pub(crate) fn memory_tools<B>(
backend: B,
metrics_client: Option<MetricsClient>,
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>>
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>>
where
B: MemoriesBackend,
{
@@ -77,7 +77,7 @@ pub(super) fn memory_function_tool<I: JsonSchema, O: JsonSchema>(
})
}
fn parse_args<T: for<'de> Deserialize<'de>>(call: &ToolCall) -> Result<T, FunctionCallError> {
fn parse_args<T: for<'de> Deserialize<'de>>(call: &ToolCall<'_>) -> Result<T, FunctionCallError> {
let arguments = call.function_arguments()?;
let value = if arguments.trim().is_empty() {
Value::Object(serde_json::Map::new())
+6 -3
View File
@@ -38,7 +38,7 @@ pub(super) struct ReadTool<B> {
pub(super) metrics_client: Option<MetricsClient>,
}
impl<B> ToolExecutor<ToolCall> for ReadTool<B>
impl<'call, B> ToolExecutor<ToolCall<'call>> for ReadTool<B>
where
B: MemoriesBackend,
{
@@ -53,7 +53,10 @@ where
)
}
fn handle(&self, call: ToolCall) -> codex_extension_api::ToolExecutorFuture<'_> {
fn handle<'a>(&'a self, call: ToolCall<'call>) -> codex_extension_api::ToolExecutorFuture<'a>
where
'call: 'a,
{
Box::pin(self.handle_call(call))
}
}
@@ -64,7 +67,7 @@ where
{
async fn handle_call(
&self,
call: ToolCall,
call: ToolCall<'_>,
) -> Result<Box<dyn codex_extension_api::ToolOutput>, codex_extension_api::FunctionCallError>
{
let backend = self.backend.clone();
+6 -3
View File
@@ -47,7 +47,7 @@ pub(super) struct SearchTool<B> {
pub(super) metrics_client: Option<MetricsClient>,
}
impl<B> ToolExecutor<ToolCall> for SearchTool<B>
impl<'call, B> ToolExecutor<ToolCall<'call>> for SearchTool<B>
where
B: MemoriesBackend,
{
@@ -62,7 +62,10 @@ where
)
}
fn handle(&self, call: ToolCall) -> codex_extension_api::ToolExecutorFuture<'_> {
fn handle<'a>(&'a self, call: ToolCall<'call>) -> codex_extension_api::ToolExecutorFuture<'a>
where
'call: 'a,
{
Box::pin(self.handle_call(call))
}
}
@@ -73,7 +76,7 @@ where
{
async fn handle_call(
&self,
call: ToolCall,
call: ToolCall<'_>,
) -> Result<Box<dyn codex_extension_api::ToolOutput>, codex_extension_api::FunctionCallError>
{
let backend = self.backend.clone();