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
This commit is contained in:
rka-oai
2026-08-27 21:46:20 +00:00
committed by copyberry
parent 34e74fda0e
commit f6494dc8f5
2 changed files with 24 additions and 4 deletions
+8
View File
@@ -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)
@@ -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(());