diff --git a/codex-rs/core/src/client_common.rs b/codex-rs/core/src/client_common.rs index 54ad70daaa..1e98b25d11 100644 --- a/codex-rs/core/src/client_common.rs +++ b/codex-rs/core/src/client_common.rs @@ -8,6 +8,7 @@ use codex_tools::ToolSpec; use futures::Stream; use serde_json::Value; use std::pin::Pin; +use std::sync::Arc; use std::task::Context; use std::task::Poll; use tokio::sync::mpsc; @@ -21,7 +22,7 @@ pub struct Prompt { /// Tools available to the model, including additional tools sourced from /// external MCP servers. - pub(crate) tools: Vec, + pub(crate) tools: Arc<[ToolSpec]>, /// Whether parallel tool calls are permitted for this prompt. pub(crate) parallel_tool_calls: bool, @@ -39,7 +40,7 @@ impl Default for Prompt { fn default() -> Self { Self { input: Vec::new(), - tools: Vec::new(), + tools: Arc::default(), parallel_tool_calls: false, base_instructions: BaseInstructions::default(), output_schema: None, diff --git a/codex-rs/core/src/tools/router.rs b/codex-rs/core/src/tools/router.rs index 83edd0463a..b3e60a5986 100644 --- a/codex-rs/core/src/tools/router.rs +++ b/codex-rs/core/src/tools/router.rs @@ -67,7 +67,7 @@ pub(crate) fn tool_log_payload<'a>( pub struct ToolRouter { registry: ToolRegistry, - model_visible_specs: Vec, + model_visible_specs: Arc<[ToolSpec]>, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -102,12 +102,12 @@ impl ToolRouter { pub(crate) fn from_parts(registry: ToolRegistry, model_visible_specs: Vec) -> Self { Self { registry, - model_visible_specs, + model_visible_specs: model_visible_specs.into(), } } - pub(crate) fn model_visible_specs(&self) -> Vec { - self.model_visible_specs.clone() + pub(crate) fn model_visible_specs(&self) -> Arc<[ToolSpec]> { + Arc::clone(&self.model_visible_specs) } pub(crate) fn deferred_tool_namespaces(&self) -> BTreeMap { diff --git a/codex-rs/core/src/tools/router_tests.rs b/codex-rs/core/src/tools/router_tests.rs index 690fb9ca2b..f354c75475 100644 --- a/codex-rs/core/src/tools/router_tests.rs +++ b/codex-rs/core/src/tools/router_tests.rs @@ -471,9 +471,11 @@ async fn specs_filter_deferred_dynamic_tools() -> anyhow::Result<()> { Vec::new(), &dynamic_tools, ); + let visible_specs = router.model_visible_specs(); + assert!(Arc::ptr_eq(&visible_specs, &router.model_visible_specs())); assert_eq!( - namespace_function_names(&router.model_visible_specs(), "codex_app"), + namespace_function_names(&visible_specs, "codex_app"), vec![visible_tool.to_string()] ); assert_eq!( @@ -481,6 +483,11 @@ async fn specs_filter_deferred_dynamic_tools() -> anyhow::Result<()> { BTreeMap::from([("codex_app".to_string(), "Codex app tools.".to_string())]) ); + let updated_router = test_tool_router(step_context.as_ref(), Vec::new(), Vec::new(), &[]); + let updated_specs = updated_router.model_visible_specs(); + assert!(!Arc::ptr_eq(&visible_specs, &updated_specs)); + assert!(namespace_function_names(&updated_specs, "codex_app").is_empty()); + Ok(()) } diff --git a/codex-rs/core/src/tools/spec_plan_tests.rs b/codex-rs/core/src/tools/spec_plan_tests.rs index c144b6da30..3b225ac4b0 100644 --- a/codex-rs/core/src/tools/spec_plan_tests.rs +++ b/codex-rs/core/src/tools/spec_plan_tests.rs @@ -80,7 +80,7 @@ struct ToolPlanProbe { impl ToolPlanProbe { fn from_router(router: ToolRouter) -> Self { - let visible_specs = router.model_visible_specs(); + let visible_specs = router.model_visible_specs().to_vec(); let visible_names = visible_specs .iter() .map(|spec| spec.name().to_string())