Keep the sleep tool outside code mode (#34969)

## What changed

- Mark `clock.sleep` as `DirectModelOnly` so it remains directly callable in
  code-mode-only sessions without appearing in the nested code-mode tool surface.
- Cover both code mode configurations with a tool-plan test that verifies the
  sleep tool's exposure and visibility.

GitOrigin-RevId: 7ef67bea0678f27fdb17d88004368e5f1d475125
This commit is contained in:
rka-oai
2026-07-23 16:20:30 +00:00
committed by copyberry
parent 9e1f43dc2d
commit 205d37a20f
2 changed files with 54 additions and 0 deletions
@@ -13,6 +13,7 @@ use codex_tools::JsonSchema;
use codex_tools::ResponsesApiNamespace;
use codex_tools::ResponsesApiNamespaceTool;
use codex_tools::ResponsesApiTool;
use codex_tools::ToolExposure;
use codex_tools::ToolName;
use codex_tools::ToolSpec;
use serde::Deserialize;
@@ -68,6 +69,10 @@ impl ToolExecutor<ToolInvocation> for SleepHandler {
create_sleep_tool()
}
fn exposure(&self) -> ToolExposure {
ToolExposure::DirectModelOnly
}
fn handle(&self, invocation: ToolInvocation) -> codex_tools::ToolExecutorFuture<'_> {
Box::pin(async move {
let ToolInvocation {
@@ -726,6 +726,55 @@ async fn sleep_tool_follows_current_time_config() {
);
}
#[tokio::test]
async fn sleep_tool_stays_direct_and_outside_code_mode() {
for code_mode_only in [false, true] {
let plan = probe(|turn| {
set_features(
turn,
&[
Feature::CodeMode,
Feature::CurrentTimeReminder,
Feature::MultiAgentV2,
],
);
if code_mode_only {
set_feature(turn, Feature::CodeModeOnly, /*enabled*/ true);
}
update_config(turn, |config| {
config.current_time_reminder = Some(CurrentTimeReminderConfig {
sleep_tool: true,
..CurrentTimeReminderConfig::default()
});
config.multi_agent_v2.wait_agent_enabled = false;
});
})
.await;
assert!(
plan.namespace_function_names("clock")
.iter()
.any(|name| name == "sleep")
);
let sleep_tool_name = ToolName::namespaced("clock", "sleep").to_string();
let wait_agent_tool_name =
ToolName::namespaced(MULTI_AGENT_V2_NAMESPACE, "wait_agent").to_string();
assert_eq!(
plan.exposure(&sleep_tool_name),
ToolExposure::DirectModelOnly
);
plan.assert_registered_lacks(&[wait_agent_tool_name.as_str()]);
let ToolSpec::Freeform(exec) = plan.visible_spec(codex_code_mode::PUBLIC_TOOL_NAME) else {
panic!("expected code mode exec tool");
};
if code_mode_only {
assert!(exec.description.contains("clock__curr_time"));
}
assert!(!exec.description.contains("clock__sleep"));
}
}
#[tokio::test]
async fn mcp_and_tool_search_follow_direct_and_deferred_tool_exposure() {
let direct_mcp = probe_with(