mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
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:
committed by
copyberry
parent
eed1dee69e
commit
81e180044d
@@ -43,7 +43,7 @@ use codex_protocol::turn_input::TurnStartOptions;
|
||||
use crate::session::completed_session_loop_termination;
|
||||
|
||||
pub(crate) struct GuardianReadOnlyHistoryTools(
|
||||
pub(crate) Vec<Arc<dyn codex_tools::ToolExecutor<codex_tools::ToolCall>>>,
|
||||
pub(crate) Vec<Arc<dyn for<'call> codex_tools::ToolExecutor<codex_tools::ToolCall<'call>>>>,
|
||||
);
|
||||
|
||||
/// Start an interactive sub-Codex thread and return its runtime and IO channels.
|
||||
|
||||
@@ -25,6 +25,7 @@ use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::TurnAbortReason;
|
||||
use codex_protocol::protocol::WarningEvent;
|
||||
use futures::future::BoxFuture;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::time::Instant;
|
||||
@@ -748,9 +749,8 @@ pub(crate) async fn review_approval_request(
|
||||
request: GuardianApprovalRequest,
|
||||
reasons: ApprovalRequestReasons,
|
||||
) -> ReviewDecision {
|
||||
// Box the delegated review future so callers do not inline the entire
|
||||
// guardian session state machine into their own async stack.
|
||||
Box::pin(run_guardian_review(
|
||||
// Erase the delegated future to bound its async state and the tool handlers' Send checks.
|
||||
let review: BoxFuture<'_, ReviewDecision> = Box::pin(run_guardian_review(
|
||||
Arc::clone(session),
|
||||
context.into(),
|
||||
review_id,
|
||||
@@ -761,8 +761,8 @@ pub(crate) async fn review_approval_request(
|
||||
approval_request_source: GuardianApprovalRequestSource::MainTurn,
|
||||
external_cancel: None,
|
||||
},
|
||||
))
|
||||
.await
|
||||
));
|
||||
review.await
|
||||
}
|
||||
|
||||
pub(crate) async fn review_approval_request_with_cancel(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
@@ -931,6 +932,7 @@ async fn build_extension_turn_input_items(
|
||||
.turn_environments()
|
||||
.enumerate()
|
||||
.map(|(index, environment)| TurnInputEnvironment {
|
||||
_lifetime: PhantomData,
|
||||
environment_id: environment.selection.environment_id.clone(),
|
||||
cwd: environment.cwd().clone(),
|
||||
is_primary: index == 0,
|
||||
|
||||
@@ -146,7 +146,10 @@ impl ToolExecutor<ToolInvocation> for CodeModeExecuteHandler {
|
||||
self.spec.clone()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,10 @@ impl ToolExecutor<ToolInvocation> for CodeModeWaitHandler {
|
||||
create_wait_tool()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +357,10 @@ impl ToolExecutor<ToolInvocation> for ApplyPatchHandler {
|
||||
create_apply_patch_freeform_tool(self.multi_environment)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,10 @@ impl ToolExecutor<ToolInvocation> for CurrentTimeHandler {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
if !matches!(invocation.payload, ToolPayload::Function { .. }) {
|
||||
return Err(FunctionCallError::RespondToModel(format!(
|
||||
|
||||
@@ -105,7 +105,10 @@ impl ToolExecutor<ToolInvocation> for DynamicToolHandler {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Weak;
|
||||
|
||||
@@ -27,10 +28,14 @@ use crate::tools::registry::CoreToolRuntime;
|
||||
use crate::tools::registry::ToolExecutor;
|
||||
use crate::turn_metadata::McpTurnMetadataContext;
|
||||
|
||||
pub(crate) struct ExtensionToolAdapter(Arc<dyn codex_tools::ToolExecutor<ExtensionToolCall>>);
|
||||
pub(crate) struct ExtensionToolAdapter(
|
||||
Arc<dyn for<'call> codex_tools::ToolExecutor<ExtensionToolCall<'call>>>,
|
||||
);
|
||||
|
||||
impl ExtensionToolAdapter {
|
||||
pub(crate) fn new(executor: Arc<dyn codex_tools::ToolExecutor<ExtensionToolCall>>) -> Self {
|
||||
pub(crate) fn new(
|
||||
executor: Arc<dyn for<'call> codex_tools::ToolExecutor<ExtensionToolCall<'call>>>,
|
||||
) -> Self {
|
||||
Self(executor)
|
||||
}
|
||||
}
|
||||
@@ -56,7 +61,10 @@ impl ToolExecutor<ToolInvocation> for ExtensionToolAdapter {
|
||||
self.0.search_info()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move { self.0.handle(to_extension_call(&invocation).await).await })
|
||||
}
|
||||
}
|
||||
@@ -155,7 +163,7 @@ impl TurnItemEmitter for CoreTurnItemEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
async fn to_extension_call(invocation: &ToolInvocation) -> ExtensionToolCall {
|
||||
async fn to_extension_call(invocation: &ToolInvocation) -> ExtensionToolCall<'_> {
|
||||
let conversation_history =
|
||||
ConversationHistory::new(invocation.session.clone_history().await.into_raw_items());
|
||||
let codex_turn_metadata = invocation
|
||||
@@ -185,6 +193,7 @@ async fn to_extension_call(invocation: &ToolInvocation) -> ExtensionToolCall {
|
||||
.additional_permissions;
|
||||
let file_system_sandbox_context = environment.sandbox_context(additional_permissions);
|
||||
environments.push(ToolEnvironment {
|
||||
_lifetime: PhantomData,
|
||||
environment_id: environment.selection.environment_id.clone(),
|
||||
cwd: native_cwd,
|
||||
file_system: environment.environment.get_filesystem(),
|
||||
@@ -226,6 +235,7 @@ mod tests {
|
||||
use codex_tools::ToolCallSource as ExtensionToolCallSource;
|
||||
use codex_utils_absolute_path::test_support::PathExt;
|
||||
use codex_utils_absolute_path::test_support::test_path_buf;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use core_test_support::responses::strip_response_item_id;
|
||||
use core_test_support::responses::strip_response_item_ids;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -246,7 +256,9 @@ mod tests {
|
||||
|
||||
struct StubExtensionExecutor;
|
||||
|
||||
impl codex_extension_api::ToolExecutor<codex_tools::ToolCall> for StubExtensionExecutor {
|
||||
impl<'call> codex_extension_api::ToolExecutor<codex_tools::ToolCall<'call>>
|
||||
for StubExtensionExecutor
|
||||
{
|
||||
fn tool_name(&self) -> codex_tools::ToolName {
|
||||
codex_tools::ToolName::plain("extension_echo")
|
||||
}
|
||||
@@ -270,7 +282,13 @@ mod tests {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, _call: codex_tools::ToolCall) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(
|
||||
&'a self,
|
||||
_call: codex_tools::ToolCall<'call>,
|
||||
) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(async {
|
||||
Ok(
|
||||
Box::new(codex_tools::JsonToolOutput::new(json!({ "ok": true })))
|
||||
@@ -281,10 +299,13 @@ mod tests {
|
||||
}
|
||||
|
||||
struct CapturingExtensionExecutor {
|
||||
captured_call: Arc<Mutex<Option<codex_tools::ToolCall>>>,
|
||||
captured_call: Arc<Mutex<Option<codex_tools::ToolCall<'static>>>>,
|
||||
captured_sandbox_cwds: Arc<Mutex<Vec<Option<PathUri>>>>,
|
||||
}
|
||||
|
||||
impl codex_extension_api::ToolExecutor<codex_tools::ToolCall> for CapturingExtensionExecutor {
|
||||
impl<'call> codex_extension_api::ToolExecutor<codex_tools::ToolCall<'call>>
|
||||
for CapturingExtensionExecutor
|
||||
{
|
||||
fn tool_name(&self) -> codex_tools::ToolName {
|
||||
codex_tools::ToolName::plain("extension_echo")
|
||||
}
|
||||
@@ -300,7 +321,13 @@ mod tests {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, call: codex_tools::ToolCall) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(
|
||||
&'a self,
|
||||
call: codex_tools::ToolCall<'call>,
|
||||
) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(call))
|
||||
}
|
||||
}
|
||||
@@ -308,7 +335,7 @@ mod tests {
|
||||
impl CapturingExtensionExecutor {
|
||||
async fn handle_call(
|
||||
&self,
|
||||
call: codex_tools::ToolCall,
|
||||
call: codex_tools::ToolCall<'_>,
|
||||
) -> Result<Box<dyn codex_tools::ToolOutput>, codex_tools::FunctionCallError> {
|
||||
call.turn_item_emitter
|
||||
.emit_started(ExtensionTurnItem {
|
||||
@@ -321,6 +348,16 @@ mod tests {
|
||||
legacy_events: Vec::new(),
|
||||
})
|
||||
.await;
|
||||
// Record owned metadata only; the invocation lifetime belongs to this callback.
|
||||
*self.captured_sandbox_cwds.lock().await = call
|
||||
.environments
|
||||
.iter()
|
||||
.map(|environment| environment.file_system_sandbox_context.cwd.clone())
|
||||
.collect();
|
||||
let call = codex_tools::ToolCall {
|
||||
environments: Vec::new(),
|
||||
..call
|
||||
};
|
||||
*self.captured_call.lock().await = Some(call);
|
||||
Ok(
|
||||
Box::new(codex_tools::JsonToolOutput::new(json!({ "ok": true })))
|
||||
@@ -382,8 +419,10 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn passes_turn_fields_and_scoped_turn_item_emitter_to_extension_call() {
|
||||
let captured_call = Arc::new(Mutex::new(None));
|
||||
let captured_sandbox_cwds = Arc::new(Mutex::new(Vec::new()));
|
||||
let handler = ExtensionToolAdapter::new(Arc::new(CapturingExtensionExecutor {
|
||||
captured_call: Arc::clone(&captured_call),
|
||||
captured_sandbox_cwds: Arc::clone(&captured_sandbox_cwds),
|
||||
}));
|
||||
let (session, turn, rx) = crate::session::tests::make_session_and_context_with_rx().await;
|
||||
let weak_session = Arc::downgrade(&session);
|
||||
@@ -465,14 +504,7 @@ mod tests {
|
||||
runtime_tool_call_id: "nested-call-1".to_string(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
captured_call
|
||||
.environments
|
||||
.iter()
|
||||
.map(|environment| environment.file_system_sandbox_context.cwd.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
expected_sandbox_cwds
|
||||
);
|
||||
assert_eq!(*captured_sandbox_cwds.lock().await, expected_sandbox_cwds);
|
||||
assert_eq!(
|
||||
strip_response_item_ids(captured_call.conversation_history.items()),
|
||||
vec![expected_history_item]
|
||||
|
||||
@@ -67,7 +67,10 @@ impl ToolExecutor<ToolInvocation> for GetContextRemainingHandler {
|
||||
create_get_context_remaining_tool()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
if !matches!(invocation.payload, ToolPayload::Function { .. }) {
|
||||
return Err(FunctionCallError::RespondToModel(
|
||||
|
||||
@@ -67,7 +67,10 @@ impl ToolExecutor<ToolInvocation> for ListAvailablePluginsToInstallHandler {
|
||||
false
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,10 @@ impl ToolExecutor<ToolInvocation> for McpHandler {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,10 @@ impl ToolExecutor<ToolInvocation> for ListMcpResourceTemplatesHandler {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,10 @@ impl ToolExecutor<ToolInvocation> for ListMcpResourcesHandler {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,10 @@ impl ToolExecutor<ToolInvocation> for ReadMcpResourceHandler {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move { handle_close_agent(invocation).await.map(boxed_tool_output) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move { handle_resume_agent(invocation).await.map(boxed_tool_output) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move { handle_spawn_agent(invocation).await.map(boxed_tool_output) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
create_followup_task_tool()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let mut analytics = ToolCallAnalytics::new(&invocation, CollabAgentTool::FollowupTask);
|
||||
let result = self.handle_call(invocation, &mut analytics).await;
|
||||
|
||||
@@ -15,7 +15,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
create_interrupt_agent_tool_v2()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let mut analytics =
|
||||
ToolCallAnalytics::new(&invocation, CollabAgentTool::InterruptAgent);
|
||||
|
||||
@@ -15,7 +15,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
create_list_agents_tool()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let analytics = ToolCallAnalytics::new(&invocation, CollabAgentTool::ListAgents);
|
||||
let result = self.handle_call(invocation).await;
|
||||
|
||||
@@ -17,7 +17,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
create_send_message_tool()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let mut analytics = ToolCallAnalytics::new(&invocation, CollabAgentTool::SendMessage);
|
||||
let result = self.handle_call(invocation, &mut analytics).await;
|
||||
|
||||
@@ -37,7 +37,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
create_spawn_agent_tool_v2(self.options.clone())
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let analytics = invocation.session.services.analytics_events_client.clone();
|
||||
let sender_thread_id = invocation.session.thread_id;
|
||||
|
||||
@@ -28,7 +28,10 @@ impl ToolExecutor<ToolInvocation> for Handler {
|
||||
create_wait_agent_tool_v2(self.options)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,10 @@ impl ToolExecutor<ToolInvocation> for NewContextWindowHandler {
|
||||
create_new_context_window_tool()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
if !matches!(invocation.payload, ToolPayload::Function { .. }) {
|
||||
return Err(FunctionCallError::RespondToModel(
|
||||
|
||||
@@ -54,7 +54,10 @@ impl ToolExecutor<ToolInvocation> for PlanHandler {
|
||||
create_update_plan_tool()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,10 @@ impl ToolExecutor<ToolInvocation> for RequestPermissionsHandler {
|
||||
create_request_permissions_tool(request_permissions_tool_description())
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,10 @@ impl ToolExecutor<ToolInvocation> for RequestPluginInstallHandler {
|
||||
false
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,10 @@ impl ToolExecutor<ToolInvocation> for RequestUserInputHandler {
|
||||
create_request_user_input_tool(request_user_input_tool_description(&self.available_modes))
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,10 @@ impl ToolExecutor<ToolInvocation> for SendUserMessageAsyncHandler {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let ToolInvocation {
|
||||
session,
|
||||
|
||||
@@ -73,7 +73,10 @@ impl ToolExecutor<ToolInvocation> for SleepHandler {
|
||||
ToolExposure::DirectModelOnly
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let ToolInvocation {
|
||||
session,
|
||||
|
||||
@@ -73,7 +73,10 @@ impl ToolExecutor<ToolInvocation> for TestSyncHandler {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,10 @@ impl ToolExecutor<ToolInvocation> for ToolSearchHandler {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,10 @@ impl ToolExecutor<ToolInvocation> for ExecCommandHandler {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,10 @@ impl ToolExecutor<ToolInvocation> for WriteStdinHandler {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,10 @@ impl ToolExecutor<ToolInvocation> for ViewImageHandler {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(invocation))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,10 @@ impl ToolExecutor<ToolInvocation> for WaitForEnvironmentHandler {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let ToolInvocation {
|
||||
payload,
|
||||
|
||||
@@ -537,7 +537,10 @@ mod tests {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, _invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, _invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async {
|
||||
Ok(
|
||||
Box::new(FunctionToolOutput::from_text("ok".to_string(), Some(true)))
|
||||
|
||||
@@ -20,7 +20,10 @@ impl ToolExecutor<ToolInvocation> for TestHandler {
|
||||
test_spec(&self.tool_name)
|
||||
}
|
||||
|
||||
fn handle(&self, _invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, _invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async {
|
||||
Ok(
|
||||
Box::new(crate::tools::context::FunctionToolOutput::from_text(
|
||||
@@ -48,7 +51,10 @@ impl ToolExecutor<ToolInvocation> for ReadinessTestHandler {
|
||||
self.handler.spec()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
self.handler.handle(invocation)
|
||||
}
|
||||
}
|
||||
@@ -81,7 +87,10 @@ impl ToolExecutor<ToolInvocation> for LifecycleTestHandler {
|
||||
test_spec(&self.tool_name)
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
assert_eq!(
|
||||
invocation.tool_name,
|
||||
self.tool_name.clone().with_default_namespace()
|
||||
|
||||
@@ -65,14 +65,14 @@ impl codex_extension_api::ToolContributor for ExtensionEchoContributor {
|
||||
&self,
|
||||
_session_store: &ExtensionData,
|
||||
_thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ExtensionToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ExtensionToolCall<'call>>>> {
|
||||
vec![Arc::new(ExtensionEchoExecutor)]
|
||||
}
|
||||
}
|
||||
|
||||
struct ExtensionEchoExecutor;
|
||||
|
||||
impl ToolExecutor<ExtensionToolCall> for ExtensionEchoExecutor {
|
||||
impl<'call> ToolExecutor<ExtensionToolCall<'call>> for ExtensionEchoExecutor {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::namespaced("extension/", "echo")
|
||||
}
|
||||
@@ -100,7 +100,10 @@ impl ToolExecutor<ExtensionToolCall> for ExtensionEchoExecutor {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, call: ExtensionToolCall) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, call: ExtensionToolCall<'call>) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(call))
|
||||
}
|
||||
}
|
||||
@@ -108,7 +111,7 @@ impl ToolExecutor<ExtensionToolCall> for ExtensionEchoExecutor {
|
||||
impl ExtensionEchoExecutor {
|
||||
async fn handle_call(
|
||||
&self,
|
||||
call: ExtensionToolCall,
|
||||
call: ExtensionToolCall<'_>,
|
||||
) -> Result<Box<dyn codex_tools::ToolOutput>, codex_tools::FunctionCallError> {
|
||||
let arguments: serde_json::Value =
|
||||
serde_json::from_str(call.function_arguments()?).expect("test arguments should parse");
|
||||
@@ -130,7 +133,9 @@ fn extension_tool_test_registry() -> Arc<ExtensionRegistry<Config>> {
|
||||
fn test_tool_router(
|
||||
step_context: &StepContext,
|
||||
mcp_tools: Vec<RegisteredTool>,
|
||||
extension_tool_executors: impl IntoIterator<Item = Arc<dyn ToolExecutor<ExtensionToolCall>>>,
|
||||
extension_tool_executors: impl IntoIterator<
|
||||
Item = Arc<dyn for<'call> ToolExecutor<ExtensionToolCall<'call>>>,
|
||||
>,
|
||||
dynamic_tools: &[DynamicToolSpec],
|
||||
) -> ToolRouter {
|
||||
let mut registry = build_core_tool_registry(
|
||||
|
||||
@@ -285,7 +285,9 @@ pub(crate) fn append_source_tools(
|
||||
turn_context: &TurnContext,
|
||||
registry: &mut ToolRegistry,
|
||||
mcp_tools: Vec<RegisteredTool>,
|
||||
extension_tool_executors: impl IntoIterator<Item = Arc<dyn ToolExecutor<ExtensionToolCall>>>,
|
||||
extension_tool_executors: impl IntoIterator<
|
||||
Item = Arc<dyn for<'call> ToolExecutor<ExtensionToolCall<'call>>>,
|
||||
>,
|
||||
dynamic_tools: &[DynamicToolSpec],
|
||||
) -> Vec<ToolSpec> {
|
||||
if crate::guardian::is_basic_session_source(&turn_context.session_source) {
|
||||
@@ -305,7 +307,7 @@ pub(crate) fn append_source_tools(
|
||||
pub(crate) fn extension_tool_executors<'a>(
|
||||
session: &'a Session,
|
||||
step_store: &'a ExtensionData,
|
||||
) -> impl Iterator<Item = Arc<dyn ToolExecutor<ExtensionToolCall>>> + 'a {
|
||||
) -> impl Iterator<Item = Arc<dyn for<'call> ToolExecutor<ExtensionToolCall<'call>>>> + 'a {
|
||||
session
|
||||
.services
|
||||
.extensions
|
||||
@@ -1283,7 +1285,7 @@ fn append_tool_search_executor(
|
||||
|
||||
fn append_extension_tool_executors(
|
||||
turn_context: &TurnContext,
|
||||
executors: impl IntoIterator<Item = Arc<dyn ToolExecutor<ExtensionToolCall>>>,
|
||||
executors: impl IntoIterator<Item = Arc<dyn for<'call> ToolExecutor<ExtensionToolCall<'call>>>>,
|
||||
registry: &mut ToolRegistry,
|
||||
) -> Option<ToolName> {
|
||||
let standalone_web_search_enabled = standalone_web_search_enabled(turn_context);
|
||||
@@ -1356,7 +1358,10 @@ impl ToolExecutor<ToolInvocation> for MultiAgentV2NamespaceOverride {
|
||||
self.handler.search_info()
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
self.handler.handle(invocation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ const MULTI_AGENT_V2_NAMESPACE: &str = "collaboration";
|
||||
struct ToolPlanInputs {
|
||||
tool_runtimes: Vec<RegisteredTool>,
|
||||
tool_suggest_candidates: Option<ToolSuggestCandidates>,
|
||||
extension_tool_executors: Vec<Arc<dyn ToolExecutor<ExtensionToolCall>>>,
|
||||
extension_tool_executors: Vec<Arc<dyn for<'call> ToolExecutor<ExtensionToolCall<'call>>>>,
|
||||
wait_for_environment_tool_config: Option<Arc<WaitForEnvironmentToolConfig>>,
|
||||
dynamic_tools: Vec<DynamicToolSpec>,
|
||||
}
|
||||
@@ -310,7 +310,7 @@ struct TestNamespaceExtensionTool {
|
||||
tool_name: &'static str,
|
||||
}
|
||||
|
||||
impl ToolExecutor<ExtensionToolCall> for TestNamespaceExtensionTool {
|
||||
impl<'call> ToolExecutor<ExtensionToolCall<'call>> for TestNamespaceExtensionTool {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::namespaced(self.namespace, self.tool_name)
|
||||
}
|
||||
@@ -330,7 +330,10 @@ impl ToolExecutor<ExtensionToolCall> for TestNamespaceExtensionTool {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, _call: ExtensionToolCall) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, _call: ExtensionToolCall<'call>) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(async {
|
||||
Ok(Box::new(codex_tools::JsonToolOutput::new(json!({}))) as Box<dyn ToolOutput>)
|
||||
})
|
||||
@@ -339,7 +342,7 @@ impl ToolExecutor<ExtensionToolCall> for TestNamespaceExtensionTool {
|
||||
|
||||
struct DeferredExtensionTool;
|
||||
|
||||
impl ToolExecutor<ExtensionToolCall> for DeferredExtensionTool {
|
||||
impl<'call> ToolExecutor<ExtensionToolCall<'call>> for DeferredExtensionTool {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::plain("extension_echo")
|
||||
}
|
||||
@@ -366,7 +369,10 @@ impl ToolExecutor<ExtensionToolCall> for DeferredExtensionTool {
|
||||
ToolExposure::Deferred
|
||||
}
|
||||
|
||||
fn handle(&self, _call: ExtensionToolCall) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, _call: ExtensionToolCall<'call>) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(async { panic!("spec planning should not execute extension tools") })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,10 @@ impl ToolExecutor<ToolInvocation> for TestHandler {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, _invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, _invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'a>
|
||||
where
|
||||
ToolInvocation: 'a,
|
||||
{
|
||||
Box::pin(async {
|
||||
Ok(
|
||||
Box::new(FunctionToolOutput::from_text("ok".to_string(), Some(true)))
|
||||
|
||||
@@ -4748,7 +4748,7 @@ impl ToolContributor for NamespacedCustomTool {
|
||||
&self,
|
||||
_session_store: &ExtensionData,
|
||||
_thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
@@ -4757,7 +4757,7 @@ impl ToolContributor for NamespacedCustomTool {
|
||||
_session_store: &ExtensionData,
|
||||
_thread_store: &ExtensionData,
|
||||
_step_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
vec![Arc::new(Self {
|
||||
generation: self.generations.fetch_add(1, Ordering::Relaxed) + 1,
|
||||
generations: Arc::clone(&self.generations),
|
||||
@@ -4765,7 +4765,7 @@ impl ToolContributor for NamespacedCustomTool {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolExecutor<ToolCall> for NamespacedCustomTool {
|
||||
impl<'call> ToolExecutor<ToolCall<'call>> for NamespacedCustomTool {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::namespaced("editor", "apply_patch")
|
||||
}
|
||||
@@ -4787,7 +4787,10 @@ impl ToolExecutor<ToolCall> for NamespacedCustomTool {
|
||||
})
|
||||
}
|
||||
|
||||
fn handle(&self, call: ToolCall) -> ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, call: ToolCall<'call>) -> ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let ToolPayload::Custom { input } = call.payload else {
|
||||
return Err(FunctionCallError::Fatal(
|
||||
|
||||
@@ -16,7 +16,6 @@ use codex_extension_api::ExtensionRegistry;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::TurnInputContext;
|
||||
use codex_extension_api::TurnInputContributor;
|
||||
use codex_extension_api::TurnInputEnvironment;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
@@ -53,27 +52,38 @@ use serde_json::json;
|
||||
|
||||
const PRETURN_CONTEXT_DIFF_CWD: &str = "PRETURN_CONTEXT_DIFF_CWD";
|
||||
|
||||
struct RecordingTurnInputContributor(Arc<Mutex<Vec<TurnInputEnvironment>>>);
|
||||
struct RecordingTurnInputContributor(Arc<Mutex<Vec<RecordedTurnInputEnvironment>>>);
|
||||
|
||||
impl TurnInputContributor for RecordingTurnInputContributor {
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
input: TurnInputContext,
|
||||
input: TurnInputContext<'a>,
|
||||
_extension_metrics: Option<Arc<dyn ExtensionMetrics>>,
|
||||
_session_store: &'a ExtensionData,
|
||||
_thread_store: &'a ExtensionData,
|
||||
_turn_store: &'a ExtensionData,
|
||||
) -> ExtensionFuture<'a, Vec<Box<dyn ContextualUserFragment + Send>>> {
|
||||
Box::pin(async move {
|
||||
self.0
|
||||
.lock()
|
||||
.expect("recorded environments lock")
|
||||
.extend(input.environments);
|
||||
let mut recorded_environments = self.0.lock().expect("recorded environments lock");
|
||||
for environment in input.environments {
|
||||
recorded_environments.push(RecordedTurnInputEnvironment {
|
||||
environment_id: environment.environment_id,
|
||||
cwd: environment.cwd,
|
||||
is_primary: environment.is_primary,
|
||||
});
|
||||
}
|
||||
Vec::new()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct RecordedTurnInputEnvironment {
|
||||
environment_id: String,
|
||||
cwd: PathUri,
|
||||
is_primary: bool,
|
||||
}
|
||||
|
||||
fn skills_extensions() -> Arc<ExtensionRegistry<Config>> {
|
||||
let mut extensions = ExtensionRegistryBuilder::<Config>::new();
|
||||
install(&mut extensions, |config: &Config| SkillsExtensionConfig {
|
||||
@@ -175,16 +185,15 @@ async fn turn_input_contributors_receive_foreign_environment_cwds() -> Result<()
|
||||
let recorded_environments = recorded_environments
|
||||
.lock()
|
||||
.expect("recorded environments lock")
|
||||
.iter()
|
||||
.map(|environment| {
|
||||
(
|
||||
environment.environment_id.clone(),
|
||||
environment.cwd.clone(),
|
||||
environment.is_primary,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(recorded_environments, vec![(environment_id, cwd, true)]);
|
||||
.clone();
|
||||
assert_eq!(
|
||||
recorded_environments,
|
||||
vec![RecordedTurnInputEnvironment {
|
||||
environment_id,
|
||||
cwd,
|
||||
is_primary: true,
|
||||
}]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -941,12 +941,12 @@ impl ToolContributor for DeferredCustomTool {
|
||||
&self,
|
||||
_session_store: &ExtensionData,
|
||||
_thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
vec![Arc::new(Self)]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolExecutor<ToolCall> for DeferredCustomTool {
|
||||
impl<'call> ToolExecutor<ToolCall<'call>> for DeferredCustomTool {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::plain("custom_echo")
|
||||
}
|
||||
@@ -968,7 +968,10 @@ impl ToolExecutor<ToolCall> for DeferredCustomTool {
|
||||
ToolExposure::Deferred
|
||||
}
|
||||
|
||||
fn handle(&self, call: ToolCall) -> ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, call: ToolCall<'call>) -> ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let ToolPayload::Custom { input } = call.payload else {
|
||||
return Err(FunctionCallError::Fatal(
|
||||
|
||||
@@ -134,7 +134,10 @@ impl SkillProvider for StaticSkillProvider {
|
||||
Box::pin(async move { Ok(catalog) })
|
||||
}
|
||||
|
||||
fn read(&self, request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult> {
|
||||
fn read<'a>(
|
||||
&'a self,
|
||||
request: SkillReadRequest<'a>,
|
||||
) -> SkillProviderFuture<'a, SkillReadResult> {
|
||||
let result = self
|
||||
.main_prompt_contents
|
||||
.clone()
|
||||
@@ -158,7 +161,10 @@ impl SkillProvider for CatalogSkillProvider {
|
||||
Box::pin(async { Ok(self.catalog.clone()) })
|
||||
}
|
||||
|
||||
fn read(&self, _request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult> {
|
||||
fn read<'a>(
|
||||
&'a self,
|
||||
_request: SkillReadRequest<'a>,
|
||||
) -> SkillProviderFuture<'a, SkillReadResult> {
|
||||
Box::pin(async {
|
||||
Err(SkillProviderError::new(
|
||||
"production-flow catalog test does not read skills",
|
||||
|
||||
@@ -227,7 +227,7 @@ pub trait TurnInputContributor: Send + Sync {
|
||||
/// capability is bound to the effective model for that turn.
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
input: TurnInputContext,
|
||||
input: TurnInputContext<'a>,
|
||||
extension_metrics: Option<Arc<dyn ExtensionMetrics>>,
|
||||
session_store: &'a ExtensionData,
|
||||
thread_store: &'a ExtensionData,
|
||||
@@ -303,7 +303,7 @@ pub trait ToolContributor: Send + Sync {
|
||||
&self,
|
||||
session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>>;
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>>;
|
||||
|
||||
/// Returns native tools bound to one sampling step.
|
||||
fn tools_for_step(
|
||||
@@ -311,7 +311,7 @@ pub trait ToolContributor: Send + Sync {
|
||||
session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
_step_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
self.tools(session_store, thread_store)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Host-owned turn environment summary visible to turn-input contributors.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TurnInputEnvironment {
|
||||
pub struct TurnInputEnvironment<'a> {
|
||||
/// Stable host environment id used to route executor-scoped capabilities.
|
||||
pub environment_id: String,
|
||||
/// Effective working directory for this turn in the environment.
|
||||
pub cwd: PathUri,
|
||||
/// Whether this is the primary environment for the turn.
|
||||
pub is_primary: bool,
|
||||
// TODO(anp): Replace the marker with callback-scoped environment access.
|
||||
pub _lifetime: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
/// Turn facts supplied before the host records turn-local model input items.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TurnInputContext {
|
||||
pub struct TurnInputContext<'a> {
|
||||
/// Stable host-owned turn identifier.
|
||||
pub turn_id: String,
|
||||
/// User input submitted for this turn.
|
||||
pub user_input: Vec<UserInput>,
|
||||
/// Resolved turn environments, in host priority order.
|
||||
pub environments: Vec<TurnInputEnvironment>,
|
||||
pub environments: Vec<TurnInputEnvironment<'a>>,
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ fn host_skill_discovery_preserves_legacy_and_host_contributor_behavior() {
|
||||
impl TurnInputContributor for AllContributors {
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
input: TurnInputContext,
|
||||
input: TurnInputContext<'a>,
|
||||
_extension_metrics: Option<Arc<dyn ExtensionMetrics>>,
|
||||
_session_store: &'a ExtensionData,
|
||||
_thread_store: &'a ExtensionData,
|
||||
@@ -144,7 +144,7 @@ impl ToolContributor for AllContributors {
|
||||
&self,
|
||||
_session_store: &ExtensionData,
|
||||
_thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,7 +415,9 @@ where
|
||||
&self,
|
||||
_session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn codex_extension_api::ToolExecutor<codex_extension_api::ToolCall>>> {
|
||||
) -> Vec<
|
||||
Arc<dyn for<'call> codex_extension_api::ToolExecutor<codex_extension_api::ToolCall<'call>>>,
|
||||
> {
|
||||
let Some(runtime) = goal_runtime_handle(thread_store) else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
@@ -136,7 +136,7 @@ impl GoalToolExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolExecutor<ToolCall> for GoalToolExecutor {
|
||||
impl<'call> ToolExecutor<ToolCall<'call>> for GoalToolExecutor {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::plain(match self.kind {
|
||||
GoalToolKind::Get => GET_GOAL_TOOL_NAME,
|
||||
@@ -153,7 +153,13 @@ impl ToolExecutor<ToolCall> for GoalToolExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: ToolCall) -> codex_extension_api::ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(
|
||||
&'a self,
|
||||
invocation: ToolCall<'call>,
|
||||
) -> codex_extension_api::ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
match self.kind {
|
||||
GoalToolKind::Get => self.handle_get(invocation).await,
|
||||
@@ -167,7 +173,7 @@ impl ToolExecutor<ToolCall> for GoalToolExecutor {
|
||||
impl GoalToolExecutor {
|
||||
async fn handle_get(
|
||||
&self,
|
||||
invocation: ToolCall,
|
||||
invocation: ToolCall<'_>,
|
||||
) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
let _ = invocation.function_arguments()?;
|
||||
let goal = self
|
||||
@@ -184,7 +190,7 @@ impl GoalToolExecutor {
|
||||
|
||||
async fn handle_create(
|
||||
&self,
|
||||
invocation: ToolCall,
|
||||
invocation: ToolCall<'_>,
|
||||
) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
let mut request: CreateGoalRequest = parse_arguments(invocation.function_arguments()?)?;
|
||||
request.objective = request.objective.trim().to_string();
|
||||
@@ -227,7 +233,7 @@ impl GoalToolExecutor {
|
||||
|
||||
async fn handle_update(
|
||||
&self,
|
||||
invocation: ToolCall,
|
||||
invocation: ToolCall<'_>,
|
||||
) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
let args: UpdateGoalArgs = parse_arguments(invocation.function_arguments()?)?;
|
||||
if !matches!(
|
||||
@@ -299,7 +305,7 @@ impl GoalToolExecutor {
|
||||
|
||||
fn emit_goal_updated_from_tool_call(
|
||||
&self,
|
||||
invocation: &ToolCall,
|
||||
invocation: &ToolCall<'_>,
|
||||
turn_id: Option<String>,
|
||||
goal: ThreadGoal,
|
||||
) {
|
||||
|
||||
@@ -1229,7 +1229,7 @@ async fn goal_service_enforces_maximum_token_budget_on_creation_and_updates() ->
|
||||
async fn installed_tools(
|
||||
runtime: Arc<codex_state::StateRuntime>,
|
||||
thread_id: ThreadId,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
installed_tools_with_start(
|
||||
runtime,
|
||||
thread_id,
|
||||
@@ -1244,7 +1244,7 @@ async fn installed_tools_with_start(
|
||||
thread_id: ThreadId,
|
||||
session_source: SessionSource,
|
||||
persistent_thread_state_available: bool,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
let mut builder = ExtensionRegistryBuilder::<()>::new();
|
||||
let goal_service = Arc::new(GoalService::new());
|
||||
install_with_backend(
|
||||
@@ -1284,7 +1284,7 @@ async fn installed_tools_with_start(
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn tool_names(tools: &[Arc<dyn ToolExecutor<ToolCall>>]) -> Vec<String> {
|
||||
fn tool_names(tools: &[Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>]) -> Vec<String> {
|
||||
tools.iter().map(|tool| tool.tool_name().name).collect()
|
||||
}
|
||||
|
||||
@@ -1343,7 +1343,7 @@ impl GoalExtensionHarness {
|
||||
})
|
||||
}
|
||||
|
||||
fn tools(&self) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
fn tools(&self) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
self.registry
|
||||
.tool_contributors()
|
||||
.iter()
|
||||
@@ -1470,16 +1470,16 @@ impl GoalExtensionHarness {
|
||||
}
|
||||
|
||||
fn tool_by_name<'a>(
|
||||
tools: &'a [Arc<dyn ToolExecutor<ToolCall>>],
|
||||
tools: &'a [Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>],
|
||||
name: &str,
|
||||
) -> &'a Arc<dyn ToolExecutor<ToolCall>> {
|
||||
) -> &'a Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>> {
|
||||
tools
|
||||
.iter()
|
||||
.find(|tool| tool.tool_name().namespace.is_none() && tool.tool_name().name == name)
|
||||
.expect("requested goal tool should exist")
|
||||
}
|
||||
|
||||
fn tool_call(tool_name: &str, call_id: &str, arguments: serde_json::Value) -> ToolCall {
|
||||
fn tool_call(tool_name: &str, call_id: &str, arguments: serde_json::Value) -> ToolCall<'static> {
|
||||
ToolCall {
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: call_id.to_string(),
|
||||
|
||||
@@ -135,7 +135,7 @@ impl ToolContributor for HistoryNotesExtension {
|
||||
&self,
|
||||
session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
let Some(config) = thread_store.get::<HistoryNotesExtensionConfig>() else {
|
||||
return Vec::new();
|
||||
};
|
||||
@@ -151,7 +151,7 @@ impl ToolContributor for HistoryNotesExtension {
|
||||
config.backend.clone(),
|
||||
session_store.level_id().to_string(),
|
||||
identity.agent_name.clone(),
|
||||
)) as Arc<dyn ToolExecutor<ToolCall>>
|
||||
)) as Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -260,7 +260,10 @@ impl HistoryNotesTool {
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_call(&self, call: ToolCall) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
async fn handle_call(
|
||||
&self,
|
||||
call: ToolCall<'_>,
|
||||
) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
let arguments = call.function_arguments()?;
|
||||
let arguments = if arguments.trim().is_empty() {
|
||||
json!({})
|
||||
@@ -286,7 +289,7 @@ impl HistoryNotesTool {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolExecutor<ToolCall> for HistoryNotesTool {
|
||||
impl<'call> ToolExecutor<ToolCall<'call>> for HistoryNotesTool {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::namespaced(self.action.namespace(), self.action.name())
|
||||
}
|
||||
@@ -316,7 +319,10 @@ impl ToolExecutor<ToolCall> for HistoryNotesTool {
|
||||
self.action.supports_parallel_tool_calls()
|
||||
}
|
||||
|
||||
fn handle(&self, call: ToolCall) -> ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, call: ToolCall<'call>) -> ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(self.handle_call(call))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ fn exposed_tools(
|
||||
registry: &ExtensionRegistry<Config>,
|
||||
session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
registry
|
||||
.tool_contributors()
|
||||
.iter()
|
||||
@@ -358,7 +358,7 @@ fn exposed_tools(
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn tool_call(tool_name: ToolName, arguments: serde_json::Value) -> ToolCall {
|
||||
fn tool_call(tool_name: ToolName, arguments: serde_json::Value) -> ToolCall<'static> {
|
||||
ToolCall {
|
||||
turn_id: "turn-1".to_string(),
|
||||
call_id: "call-read-file".to_string(),
|
||||
|
||||
@@ -86,7 +86,7 @@ impl ToolContributor for ImageGenerationExtension {
|
||||
&self,
|
||||
_session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
let Some(config) = thread_store.get::<ImageGenerationExtensionConfig>() else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
@@ -113,7 +113,7 @@ fn extension_turn_item(item: ImageGenerationItem, legacy_event: EventMsg) -> Ext
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolExecutor<ToolCall> for ImageGenerationTool {
|
||||
impl<'call> ToolExecutor<ToolCall<'call>> for ImageGenerationTool {
|
||||
/// Keeps the tool in the existing image-generation Responses namespace.
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::namespaced(IMAGE_GEN_NAMESPACE, IMAGEGEN_TOOL_NAME)
|
||||
@@ -130,13 +130,19 @@ impl ToolExecutor<ToolCall> for ImageGenerationTool {
|
||||
}
|
||||
|
||||
/// Executes the selected image operation and returns the completed image result.
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
impl ImageGenerationTool {
|
||||
async fn handle_call(&self, call: ToolCall) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
async fn handle_call(
|
||||
&self,
|
||||
call: ToolCall<'_>,
|
||||
) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
let args = parse_args(&call)?;
|
||||
let request =
|
||||
request_for_call_args(&args, call.conversation_history.items(), &call.environments)
|
||||
@@ -263,7 +269,7 @@ fn usage_limit_failure(error: &CodexErr) -> Option<ImageGenerationFailure> {
|
||||
|
||||
async fn save_image_generation_result(
|
||||
save_root: Option<&AbsolutePathBuf>,
|
||||
environment: Option<&ToolEnvironment>,
|
||||
environment: Option<&ToolEnvironment<'_>>,
|
||||
session_id: &str,
|
||||
call_id: &str,
|
||||
result: &str,
|
||||
@@ -403,7 +409,7 @@ enum ImageRequest {
|
||||
async fn request_for_call_args(
|
||||
args: &ImagegenArgs,
|
||||
history: &[ResponseItem],
|
||||
environments: &[ToolEnvironment],
|
||||
environments: &[ToolEnvironment<'_>],
|
||||
) -> Result<ImageRequest, FunctionCallError> {
|
||||
let paths = args.referenced_image_paths.as_deref().unwrap_or_default();
|
||||
if paths.len() > MAX_EDIT_IMAGES {
|
||||
@@ -534,7 +540,7 @@ fn output_image_urls(output: &FunctionCallOutputPayload) -> impl Iterator<Item =
|
||||
|
||||
async fn image_url(
|
||||
path: &AbsolutePathBuf,
|
||||
environment: &ToolEnvironment,
|
||||
environment: &ToolEnvironment<'_>,
|
||||
) -> Result<ImageUrl, FunctionCallError> {
|
||||
let path_uri = PathUri::from_abs_path(path);
|
||||
let sandbox = environment.file_system_sandbox_context.clone();
|
||||
@@ -562,7 +568,7 @@ async fn image_url(
|
||||
}
|
||||
|
||||
/// Parses the strict model-facing arguments for an image-generation call.
|
||||
fn parse_args(call: &ToolCall) -> Result<ImagegenArgs, FunctionCallError> {
|
||||
fn parse_args(call: &ToolCall<'_>) -> Result<ImagegenArgs, FunctionCallError> {
|
||||
serde_json::from_str(call.function_arguments()?)
|
||||
.map_err(|err| FunctionCallError::RespondToModel(err.to_string()))
|
||||
}
|
||||
|
||||
@@ -106,7 +106,9 @@ impl ToolContributor for MemoriesExtension {
|
||||
&self,
|
||||
_session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn codex_extension_api::ToolExecutor<codex_extension_api::ToolCall>>> {
|
||||
) -> Vec<
|
||||
Arc<dyn for<'call> codex_extension_api::ToolExecutor<codex_extension_api::ToolCall<'call>>>,
|
||||
> {
|
||||
let Some(config) = thread_store.get::<MemoriesExtensionConfig>() else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
@@ -580,7 +580,10 @@ async fn search_tool_rejects_legacy_single_query() {
|
||||
assert!(err.to_string().contains("query"));
|
||||
}
|
||||
|
||||
fn memory_tool(memory_root: &Path, tool_name: &str) -> Arc<dyn ToolExecutor<ToolCall>> {
|
||||
fn memory_tool(
|
||||
memory_root: &Path,
|
||||
tool_name: &str,
|
||||
) -> Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>> {
|
||||
let expected_tool_name = memory_tool_name(tool_name);
|
||||
crate::tools::memory_tools(
|
||||
LocalMemoriesBackend::from_memory_root(memory_root),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::HostSkillsSnapshot;
|
||||
@@ -275,7 +276,7 @@ where
|
||||
&self,
|
||||
session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
self.build_skill_tools(
|
||||
session_store,
|
||||
thread_store,
|
||||
@@ -290,7 +291,7 @@ where
|
||||
session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
step_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
let resolved_executor_roots = step_store
|
||||
.get::<Vec<ResolvedSelectedCapabilityRoot>>()
|
||||
.map(|roots| roots.as_slice().to_vec())
|
||||
@@ -357,7 +358,7 @@ where
|
||||
{
|
||||
fn contribute<'a>(
|
||||
&'a self,
|
||||
input: TurnInputContext,
|
||||
input: TurnInputContext<'a>,
|
||||
extension_metrics: Option<Arc<dyn ExtensionMetrics>>,
|
||||
session_store: &'a ExtensionData,
|
||||
thread_store: &'a ExtensionData,
|
||||
@@ -562,7 +563,7 @@ impl<C> SkillsExtension<C> {
|
||||
executor_query: Option<SkillListQuery>,
|
||||
selected_plugins: Option<Arc<SelectedPluginSnapshot>>,
|
||||
sandbox_contexts: Option<Arc<HashMap<String, FileSystemSandboxContext>>>,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
skill_tools(
|
||||
self.providers.clone(),
|
||||
session_store,
|
||||
@@ -606,6 +607,7 @@ impl<C> SkillsExtension<C> {
|
||||
.read_skill(
|
||||
&self.providers,
|
||||
SkillReadRequest {
|
||||
_lifetime: PhantomData,
|
||||
authority: entry.authority.clone(),
|
||||
package: entry.id.clone(),
|
||||
resource: entry.main_prompt.clone(),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -43,7 +44,9 @@ pub struct SkillListQuery {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SkillReadRequest {
|
||||
pub struct SkillReadRequest<'a> {
|
||||
// TODO(anp): Replace the marker with callback-scoped environment access.
|
||||
pub _lifetime: PhantomData<&'a ()>,
|
||||
pub authority: SkillAuthority,
|
||||
pub package: SkillPackageId,
|
||||
pub resource: SkillResourceId,
|
||||
@@ -71,7 +74,10 @@ pub type SkillProviderFuture<'a, T> =
|
||||
pub trait SkillProvider: Send + Sync {
|
||||
fn list(&self, query: SkillListQuery) -> SkillProviderFuture<'_, SkillCatalog>;
|
||||
|
||||
fn read(&self, request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult>;
|
||||
fn read<'a>(
|
||||
&'a self,
|
||||
request: SkillReadRequest<'a>,
|
||||
) -> SkillProviderFuture<'a, SkillReadResult>;
|
||||
|
||||
fn search(&self, request: SkillSearchRequest) -> SkillProviderFuture<'_, SkillSearchResult>;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,10 @@ impl SkillProvider for ExecutorSkillProvider {
|
||||
})
|
||||
}
|
||||
|
||||
fn read(&self, request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult> {
|
||||
fn read<'a>(
|
||||
&'a self,
|
||||
request: SkillReadRequest<'a>,
|
||||
) -> SkillProviderFuture<'a, SkillReadResult> {
|
||||
Box::pin(async move {
|
||||
if request.authority.kind != SkillSourceKind::Executor {
|
||||
return Err(SkillProviderError::new(format!(
|
||||
|
||||
@@ -46,7 +46,10 @@ impl SkillProvider for HostSkillProvider {
|
||||
})
|
||||
}
|
||||
|
||||
fn read(&self, request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult> {
|
||||
fn read<'a>(
|
||||
&'a self,
|
||||
request: SkillReadRequest<'a>,
|
||||
) -> SkillProviderFuture<'a, SkillReadResult> {
|
||||
Box::pin(async move {
|
||||
let Some(host_snapshot) = request.host_snapshot else {
|
||||
return Err(SkillProviderError::new(
|
||||
|
||||
@@ -174,7 +174,10 @@ impl SkillProvider for OrchestratorSkillProvider {
|
||||
})
|
||||
}
|
||||
|
||||
fn read(&self, request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult> {
|
||||
fn read<'a>(
|
||||
&'a self,
|
||||
request: SkillReadRequest<'a>,
|
||||
) -> SkillProviderFuture<'a, SkillReadResult> {
|
||||
Box::pin(async move {
|
||||
if request.authority
|
||||
!= SkillAuthority::new(SkillSourceKind::Orchestrator, CODEX_APPS_MCP_SERVER_NAME)
|
||||
|
||||
@@ -69,7 +69,7 @@ impl ShadowSelectionExperiment {
|
||||
|
||||
pub(crate) fn run(
|
||||
&self,
|
||||
input: &TurnInputContext,
|
||||
input: &TurnInputContext<'_>,
|
||||
catalog: &SkillCatalog,
|
||||
explicitly_selected: &[SkillCatalogEntry],
|
||||
host_snapshot: Option<&HostSkillsSnapshot>,
|
||||
|
||||
@@ -171,7 +171,7 @@ impl SkillProviders {
|
||||
|
||||
pub(crate) async fn read(
|
||||
&self,
|
||||
request: SkillReadRequest,
|
||||
request: SkillReadRequest<'_>,
|
||||
) -> Result<SkillReadResult, SkillProviderError> {
|
||||
let mut last_error = None;
|
||||
for source in self
|
||||
|
||||
@@ -222,7 +222,7 @@ impl SkillsThreadState {
|
||||
pub(crate) async fn read_skill(
|
||||
&self,
|
||||
providers: &SkillProviders,
|
||||
request: SkillReadRequest,
|
||||
request: SkillReadRequest<'_>,
|
||||
) -> SkillProviderResult<SkillReadResult> {
|
||||
if request.authority.kind != SkillSourceKind::Orchestrator {
|
||||
return providers.read(request).await;
|
||||
@@ -349,8 +349,8 @@ struct SkillReadCacheKey {
|
||||
resource: SkillResourceId,
|
||||
}
|
||||
|
||||
impl From<&SkillReadRequest> for SkillReadCacheKey {
|
||||
fn from(request: &SkillReadRequest) -> Self {
|
||||
impl From<&SkillReadRequest<'_>> for SkillReadCacheKey {
|
||||
fn from(request: &SkillReadRequest<'_>) -> Self {
|
||||
Self {
|
||||
authority: request.authority.clone(),
|
||||
package: request.package.clone(),
|
||||
|
||||
@@ -63,7 +63,7 @@ pub(super) struct ListTool {
|
||||
pub(super) context: SkillToolContext,
|
||||
}
|
||||
|
||||
impl ToolExecutor<ToolCall> for ListTool {
|
||||
impl<'call> ToolExecutor<ToolCall<'call>> for ListTool {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
skill_tool_name(TOOL_NAME)
|
||||
}
|
||||
@@ -75,7 +75,10 @@ impl ToolExecutor<ToolCall> for ListTool {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, call: ToolCall) -> ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, call: ToolCall<'call>) -> ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let args: ListArgs = parse_args(&call)?;
|
||||
let response_byte_budget = call.response_byte_budget(MAX_SKILL_RESPONSE_BYTES);
|
||||
|
||||
@@ -63,7 +63,7 @@ pub(crate) fn skill_tools(
|
||||
selected_plugins: Option<Arc<SelectedPluginSnapshot>>,
|
||||
sandbox_contexts: Option<Arc<HashMap<String, FileSystemSandboxContext>>>,
|
||||
shadow_selection: Arc<ShadowSelectionExperiment>,
|
||||
) -> Vec<Arc<dyn ToolExecutor<ToolCall>>> {
|
||||
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
||||
let Some(thread_state) = thread_store.get::<SkillsThreadState>() else {
|
||||
return Vec::new();
|
||||
};
|
||||
@@ -314,7 +314,7 @@ fn skill_function_tool<I: JsonSchema, O: JsonSchema>(name: &str, description: &s
|
||||
})
|
||||
}
|
||||
|
||||
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())
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use codex_analytics::InvocationType;
|
||||
@@ -54,7 +55,7 @@ pub(super) struct ReadTool {
|
||||
pub(super) context: SkillToolContext,
|
||||
}
|
||||
|
||||
impl ToolExecutor<ToolCall> for ReadTool {
|
||||
impl<'call> ToolExecutor<ToolCall<'call>> for ReadTool {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
skill_tool_name(TOOL_NAME)
|
||||
}
|
||||
@@ -66,7 +67,10 @@ impl ToolExecutor<ToolCall> for ReadTool {
|
||||
)
|
||||
}
|
||||
|
||||
fn handle(&self, call: ToolCall) -> ToolExecutorFuture<'_> {
|
||||
fn handle<'a>(&'a self, call: ToolCall<'call>) -> ToolExecutorFuture<'a>
|
||||
where
|
||||
'call: 'a,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let args: ReadArgs = parse_args(&call)?;
|
||||
let response_byte_budget = call.response_byte_budget(MAX_SKILL_RESPONSE_BYTES);
|
||||
@@ -183,6 +187,7 @@ impl ToolExecutor<ToolCall> for ReadTool {
|
||||
.read_skill(
|
||||
&self.context.providers,
|
||||
SkillReadRequest {
|
||||
_lifetime: PhantomData,
|
||||
authority: authority.clone(),
|
||||
package: package.clone(),
|
||||
resource: requested_resource.clone(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
@@ -318,6 +319,7 @@ async fn windows_executor_skill_read_rejects_disabled_sandbox_on_any_orchestrato
|
||||
);
|
||||
let error = provider
|
||||
.read(SkillReadRequest {
|
||||
_lifetime: PhantomData,
|
||||
authority: SkillAuthority::new(SkillSourceKind::Executor, "windows-root"),
|
||||
package: SkillPackageId("skill://windows-root/C:/skill".into()),
|
||||
resource,
|
||||
@@ -876,6 +878,7 @@ async fn high_level_discovery_reuses_materialized_skill_contents_for_reads() {
|
||||
panic!("expected exactly one skill");
|
||||
};
|
||||
let request = SkillReadRequest {
|
||||
_lifetime: PhantomData,
|
||||
authority: entry.authority.clone(),
|
||||
package: entry.id.clone(),
|
||||
resource: entry.main_prompt.clone(),
|
||||
|
||||
@@ -2449,7 +2449,7 @@ async fn prompt_hidden_skill_can_still_be_invoked() -> TestResult {
|
||||
#[derive(Clone)]
|
||||
struct StaticSkillProvider {
|
||||
catalog: SkillCatalog,
|
||||
read_requests: Arc<Mutex<Vec<SkillReadRequest>>>,
|
||||
read_requests: Arc<Mutex<Vec<(SkillAuthority, SkillPackageId, SkillResourceId)>>>,
|
||||
list_calls: Option<Arc<AtomicUsize>>,
|
||||
fail_first_list: bool,
|
||||
}
|
||||
@@ -2565,13 +2565,20 @@ impl SkillProvider for StaticSkillProvider {
|
||||
})
|
||||
}
|
||||
|
||||
fn read(&self, request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult> {
|
||||
fn read<'a>(
|
||||
&'a self,
|
||||
request: SkillReadRequest<'a>,
|
||||
) -> SkillProviderFuture<'a, SkillReadResult> {
|
||||
let read_requests = Arc::clone(&self.read_requests);
|
||||
Box::pin(async move {
|
||||
read_requests
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.push(request.clone());
|
||||
.push((
|
||||
request.authority.clone(),
|
||||
request.package.clone(),
|
||||
request.resource.clone(),
|
||||
));
|
||||
Ok(SkillReadResult {
|
||||
resource: request.resource,
|
||||
contents: "# Lint Fix\n\nRun the formatter.".to_string(),
|
||||
@@ -2637,18 +2644,10 @@ fn test_codex_home() -> PathBuf {
|
||||
}
|
||||
|
||||
fn read_request_keys(
|
||||
requests: &Arc<Mutex<Vec<SkillReadRequest>>>,
|
||||
requests: &Mutex<Vec<(SkillAuthority, SkillPackageId, SkillResourceId)>>,
|
||||
) -> Vec<(SkillAuthority, SkillPackageId, SkillResourceId)> {
|
||||
requests
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.iter()
|
||||
.map(|request| {
|
||||
(
|
||||
request.authority.clone(),
|
||||
request.package.clone(),
|
||||
request.resource.clone(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
.clone()
|
||||
}
|
||||
|
||||
@@ -11,7 +11,10 @@ impl SkillProvider for FailedReads {
|
||||
self.0.list(query)
|
||||
}
|
||||
|
||||
fn read(&self, _request: SkillReadRequest) -> SkillProviderFuture<'_, SkillReadResult> {
|
||||
fn read<'a>(
|
||||
&'a self,
|
||||
_request: SkillReadRequest<'a>,
|
||||
) -> SkillProviderFuture<'a, SkillReadResult> {
|
||||
Box::pin(async { Err(SkillProviderError::new("read unavailable")) })
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,9 @@ impl ToolContributor for WebSearchExtension {
|
||||
&self,
|
||||
session_store: &ExtensionData,
|
||||
thread_store: &ExtensionData,
|
||||
) -> Vec<Arc<dyn codex_extension_api::ToolExecutor<codex_extension_api::ToolCall>>> {
|
||||
) -> Vec<
|
||||
Arc<dyn for<'call> codex_extension_api::ToolExecutor<codex_extension_api::ToolCall<'call>>>,
|
||||
> {
|
||||
let Some(config) = thread_store.get::<WebSearchExtensionConfig>() else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
@@ -49,7 +49,7 @@ pub(crate) struct WebSearchTool {
|
||||
pub(crate) originator: Option<String>,
|
||||
}
|
||||
|
||||
impl ToolExecutor<ToolCall> for WebSearchTool {
|
||||
impl<'call> ToolExecutor<ToolCall<'call>> for WebSearchTool {
|
||||
fn tool_name(&self) -> ToolName {
|
||||
ToolName::namespaced(WEB_NAMESPACE, RUN_TOOL_NAME)
|
||||
}
|
||||
@@ -83,13 +83,19 @@ impl ToolExecutor<ToolCall> for WebSearchTool {
|
||||
true
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
impl WebSearchTool {
|
||||
async fn handle_call(&self, call: ToolCall) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
async fn handle_call(
|
||||
&self,
|
||||
call: ToolCall<'_>,
|
||||
) -> Result<Box<dyn ToolOutput>, FunctionCallError> {
|
||||
let commands = parse_commands(&call)?;
|
||||
let command_action = command_action(&commands);
|
||||
let provider = self
|
||||
@@ -196,7 +202,7 @@ fn search_request_headers(originator: Option<&str>, turn_metadata: Option<&str>)
|
||||
headers
|
||||
}
|
||||
|
||||
fn parse_commands(call: &ToolCall) -> Result<SearchCommands, FunctionCallError> {
|
||||
fn parse_commands(call: &ToolCall<'_>) -> Result<SearchCommands, FunctionCallError> {
|
||||
let arguments = call.function_arguments()?;
|
||||
if arguments.trim().is_empty() {
|
||||
return Ok(SearchCommands::default());
|
||||
|
||||
@@ -9,6 +9,7 @@ use codex_protocol::protocol::EventMsg;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_output_truncation::TruncationPolicy;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -61,7 +62,7 @@ pub trait TurnItemEmitter: Send + Sync {
|
||||
|
||||
/// Host-owned turn environment summary visible to extension tools.
|
||||
#[derive(Clone)]
|
||||
pub struct ToolEnvironment {
|
||||
pub struct ToolEnvironment<'call> {
|
||||
/// Stable host environment id used to route executor-scoped capabilities.
|
||||
pub environment_id: String,
|
||||
/// Effective working directory for this turn in the environment.
|
||||
@@ -70,6 +71,8 @@ pub struct ToolEnvironment {
|
||||
pub file_system: Arc<dyn ExecutorFileSystem>,
|
||||
/// Sandbox context to use for filesystem operations.
|
||||
pub file_system_sandbox_context: FileSystemSandboxContext,
|
||||
// TODO(anp): Replace the marker with callback-scoped environment access.
|
||||
pub _lifetime: PhantomData<&'call ()>,
|
||||
}
|
||||
|
||||
/// Turn-item emitter used when a caller does not expose visible item emission.
|
||||
@@ -101,7 +104,7 @@ pub enum ToolCallSource {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ToolCall {
|
||||
pub struct ToolCall<'call> {
|
||||
pub turn_id: String,
|
||||
pub call_id: String,
|
||||
pub tool_name: ToolName,
|
||||
@@ -111,11 +114,11 @@ pub struct ToolCall {
|
||||
pub source: ToolCallSource,
|
||||
pub conversation_history: ConversationHistory,
|
||||
pub turn_item_emitter: Arc<dyn TurnItemEmitter>,
|
||||
pub environments: Vec<ToolEnvironment>,
|
||||
pub environments: Vec<ToolEnvironment<'call>>,
|
||||
pub payload: ToolPayload,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ToolCall {
|
||||
impl std::fmt::Debug for ToolCall<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ToolCall")
|
||||
.field("turn_id", &self.turn_id)
|
||||
@@ -136,7 +139,7 @@ impl std::fmt::Debug for ToolCall {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToolCall {
|
||||
impl ToolCall<'_> {
|
||||
/// Returns the response-content budget, bounded by the tool's own size limit.
|
||||
///
|
||||
/// Direct calls use the host's effective text-output allowance. Code Mode receives
|
||||
|
||||
@@ -123,5 +123,8 @@ pub trait ToolExecutor<Invocation>: Send + Sync {
|
||||
false
|
||||
}
|
||||
|
||||
fn handle(&self, invocation: Invocation) -> ToolExecutorFuture<'_>;
|
||||
/// Handles one invocation without retaining capabilities borrowed by the host.
|
||||
fn handle<'a>(&'a self, invocation: Invocation) -> ToolExecutorFuture<'a>
|
||||
where
|
||||
Invocation: 'a;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user