2025-10-05 17:10:49 +01:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
2025-10-07 10:12:38 -07:00
|
|
|
use tokio::sync::RwLock;
|
|
|
|
|
use tokio_util::either::Either;
|
|
|
|
|
use tokio_util::task::AbortOnDropHandle;
|
2025-10-05 17:10:49 +01:00
|
|
|
|
|
|
|
|
use crate::codex::Session;
|
|
|
|
|
use crate::codex::TurnContext;
|
|
|
|
|
use crate::error::CodexErr;
|
|
|
|
|
use crate::function_tool::FunctionCallError;
|
|
|
|
|
use crate::tools::context::SharedTurnDiffTracker;
|
|
|
|
|
use crate::tools::router::ToolCall;
|
|
|
|
|
use crate::tools::router::ToolRouter;
|
|
|
|
|
use codex_protocol::models::ResponseInputItem;
|
|
|
|
|
|
|
|
|
|
pub(crate) struct ToolCallRuntime {
|
|
|
|
|
router: Arc<ToolRouter>,
|
|
|
|
|
session: Arc<Session>,
|
|
|
|
|
turn_context: Arc<TurnContext>,
|
|
|
|
|
tracker: SharedTurnDiffTracker,
|
2025-10-07 10:12:38 -07:00
|
|
|
parallel_execution: Arc<RwLock<()>>,
|
2025-10-05 17:10:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ToolCallRuntime {
|
|
|
|
|
pub(crate) fn new(
|
|
|
|
|
router: Arc<ToolRouter>,
|
|
|
|
|
session: Arc<Session>,
|
|
|
|
|
turn_context: Arc<TurnContext>,
|
|
|
|
|
tracker: SharedTurnDiffTracker,
|
|
|
|
|
) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
router,
|
|
|
|
|
session,
|
|
|
|
|
turn_context,
|
|
|
|
|
tracker,
|
2025-10-07 10:12:38 -07:00
|
|
|
parallel_execution: Arc::new(RwLock::new(())),
|
2025-10-05 17:10:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-07 10:12:38 -07:00
|
|
|
pub(crate) fn handle_tool_call(
|
|
|
|
|
&self,
|
2025-10-05 17:10:49 +01:00
|
|
|
call: ToolCall,
|
2025-10-07 10:12:38 -07:00
|
|
|
) -> impl std::future::Future<Output = Result<ResponseInputItem, CodexErr>> {
|
2025-10-05 17:10:49 +01:00
|
|
|
let supports_parallel = self.router.tool_supports_parallel(&call.tool_name);
|
|
|
|
|
|
|
|
|
|
let router = Arc::clone(&self.router);
|
|
|
|
|
let session = Arc::clone(&self.session);
|
|
|
|
|
let turn = Arc::clone(&self.turn_context);
|
|
|
|
|
let tracker = Arc::clone(&self.tracker);
|
2025-10-07 10:12:38 -07:00
|
|
|
let lock = Arc::clone(&self.parallel_execution);
|
|
|
|
|
|
|
|
|
|
let handle: AbortOnDropHandle<Result<ResponseInputItem, FunctionCallError>> =
|
|
|
|
|
AbortOnDropHandle::new(tokio::spawn(async move {
|
|
|
|
|
let _guard = if supports_parallel {
|
|
|
|
|
Either::Left(lock.read().await)
|
|
|
|
|
} else {
|
|
|
|
|
Either::Right(lock.write().await)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
router
|
2025-10-21 08:04:16 -07:00
|
|
|
.dispatch_tool_call(session, turn, tracker, call)
|
2025-10-07 10:12:38 -07:00
|
|
|
.await
|
|
|
|
|
}));
|
2025-10-05 17:10:49 +01:00
|
|
|
|
2025-10-07 10:12:38 -07:00
|
|
|
async move {
|
|
|
|
|
match handle.await {
|
|
|
|
|
Ok(Ok(response)) => Ok(response),
|
|
|
|
|
Ok(Err(FunctionCallError::Fatal(message))) => Err(CodexErr::Fatal(message)),
|
|
|
|
|
Ok(Err(other)) => Err(CodexErr::Fatal(other.to_string())),
|
|
|
|
|
Err(err) => Err(CodexErr::Fatal(format!(
|
|
|
|
|
"tool task failed to receive: {err:?}"
|
|
|
|
|
))),
|
|
|
|
|
}
|
2025-10-05 17:10:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|