From f6494dc8f5969e8576a8a0945a674f2a15ac4de6 Mon Sep 17 00:00:00 2001 From: rka-oai Date: Thu, 27 Aug 2026 21:37:01 +0000 Subject: [PATCH] Enable clock tools from model metadata (#41210) ## What changed - Register both `clock.curr_time` and `clock.sleep` when a model lists `clock` in `experimental_supported_tools`. - Keep current-time reminder injection controlled separately by the `current_time_reminder` feature. ## Testing - Cover a model-advertised clock with reminders disabled, verifying that both tools are available and no reminder is added. GitOrigin-RevId: c39b5cb6e2da397daaaa4e0ad81f0763b8dd91e9 --- codex-rs/core/src/tools/spec_plan.rs | 8 ++++++++ .../core/tests/suite/current_time_reminder.rs | 20 +++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/codex-rs/core/src/tools/spec_plan.rs b/codex-rs/core/src/tools/spec_plan.rs index 9d789113ad..5d5d0c7bc9 100644 --- a/codex-rs/core/src/tools/spec_plan.rs +++ b/codex-rs/core/src/tools/spec_plan.rs @@ -1163,6 +1163,14 @@ fn add_core_utility_tools(context: &CoreToolPlanContext<'_>, registry: &mut Tool { registry.add(SleepHandler); } + } else if context + .model_info + .experimental_supported_tools + .iter() + .any(|tool| tool == "clock") + { + registry.add(CurrentTimeHandler); + registry.add(SleepHandler); } if tool_suggest_enabled(turn_context) diff --git a/codex-rs/core/tests/suite/current_time_reminder.rs b/codex-rs/core/tests/suite/current_time_reminder.rs index fa06d98192..400adc0500 100644 --- a/codex-rs/core/tests/suite/current_time_reminder.rs +++ b/codex-rs/core/tests/suite/current_time_reminder.rs @@ -59,6 +59,7 @@ enum ClockSetup { Configured, Persistent, OrdinaryEffort, + ModelTools, ExplicitlyDisabled, RequiredOff, } @@ -338,6 +339,7 @@ async fn current_time_reminders_can_follow_only_user_or_tool_outputs() -> Result #[test_case(ClockSetup::Configured; "configured")] #[test_case(ClockSetup::Persistent; "persistent")] #[test_case(ClockSetup::OrdinaryEffort; "ordinary_effort")] +#[test_case(ClockSetup::ModelTools; "model_tools_without_reminders")] #[test_case(ClockSetup::ExplicitlyDisabled; "explicitly_disabled")] #[test_case(ClockSetup::RequiredOff; "required_off")] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] @@ -351,10 +353,17 @@ async fn system_time_source_adds_current_time_reminder(clock_setup: ClockSetup) ) .await; let mut builder = test_codex() + .with_model_info_override("gpt-5.5", move |model_info| { + if matches!(clock_setup, ClockSetup::Configured | ClockSetup::ModelTools) { + model_info + .experimental_supported_tools + .push("clock".to_string()); + } + }) .with_pre_build_hook(move |home| { let config = match clock_setup { ClockSetup::Configured => Some("[features]\ncurrent_time_reminder = true\n"), - ClockSetup::ExplicitlyDisabled => { + ClockSetup::ModelTools | ClockSetup::ExplicitlyDisabled => { Some("[features]\ncurrent_time_reminder = false\n") } ClockSetup::Persistent | ClockSetup::OrdinaryEffort | ClockSetup::RequiredOff => { @@ -369,7 +378,7 @@ async fn system_time_source_adds_current_time_reminder(clock_setup: ClockSetup) .with_config(move |config| { config.include_environment_context = false; config.model_reasoning_effort = Some(match clock_setup { - ClockSetup::OrdinaryEffort => ReasoningEffort::High, + ClockSetup::OrdinaryEffort | ClockSetup::ModelTools => ReasoningEffort::High, ClockSetup::Configured | ClockSetup::Persistent | ClockSetup::ExplicitlyDisabled @@ -392,7 +401,7 @@ async fn system_time_source_adds_current_time_reminder(clock_setup: ClockSetup) ["curr_time", "sleep"].map(|name| request.tool_by_name("clock", name).is_some()), match clock_setup { ClockSetup::Configured => [true, false], - ClockSetup::Persistent => [true, true], + ClockSetup::Persistent | ClockSetup::ModelTools => [true, true], ClockSetup::OrdinaryEffort | ClockSetup::ExplicitlyDisabled | ClockSetup::RequiredOff => [false, false], @@ -400,7 +409,10 @@ async fn system_time_source_adds_current_time_reminder(clock_setup: ClockSetup) ); if matches!( clock_setup, - ClockSetup::OrdinaryEffort | ClockSetup::ExplicitlyDisabled | ClockSetup::RequiredOff + ClockSetup::OrdinaryEffort + | ClockSetup::ModelTools + | ClockSetup::ExplicitlyDisabled + | ClockSetup::RequiredOff ) { assert!(current_time_reminders(&request).is_empty()); return Ok(());