Rename exec_wait tool to wait (#14983)

Summary
- document that code mode only exposes `exec` and the renamed `wait`
tool
- update code mode tool spec and descriptions to match the new tool name
- rename tests and helper references from `exec_wait` to `wait`

Testing
- Not run (not requested)
This commit is contained in:
pakrym-oai 2026-03-17 14:22:26 -07:00 committed by GitHub
parent 2cc4ee413f
commit ee756eb80f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 31 additions and 30 deletions

View file

@ -87,7 +87,7 @@ pub enum Feature {
JsRepl,
/// Enable a minimal JavaScript mode backed by Node's built-in vm runtime.
CodeMode,
/// Restrict model-visible tools to code mode entrypoints (`exec`, `exec_wait`).
/// Restrict model-visible tools to code mode entrypoints (`exec`, `wait`).
CodeModeOnly,
/// Only expose js_repl tools directly to the model.
JsReplToolsOnly,

View file

@ -34,10 +34,11 @@ const CODE_MODE_BRIDGE_SOURCE: &str = include_str!("bridge.js");
const CODE_MODE_DESCRIPTION_TEMPLATE: &str = include_str!("description.md");
const CODE_MODE_WAIT_DESCRIPTION_TEMPLATE: &str = include_str!("wait_description.md");
const CODE_MODE_PRAGMA_PREFIX: &str = "// @exec:";
const CODE_MODE_ONLY_PREFACE: &str = "Use `exec/exec_wait` tool to run all other tools, do not attempt to use any other tools directly";
const CODE_MODE_ONLY_PREFACE: &str =
"Use `exec/wait` tool to run all other tools, do not attempt to use any other tools directly";
pub(crate) const PUBLIC_TOOL_NAME: &str = "exec";
pub(crate) const WAIT_TOOL_NAME: &str = "exec_wait";
pub(crate) const WAIT_TOOL_NAME: &str = "wait";
pub(crate) fn is_code_mode_nested_tool(tool_name: &str) -> bool {
tool_name != PUBLIC_TOOL_NAME && tool_name != WAIT_TOOL_NAME

View file

@ -1,8 +1,8 @@
- Use `exec_wait` only after `exec` returns `Script running with cell ID ...`.
- Use `wait` only after `exec` returns `Script running with cell ID ...`.
- `cell_id` identifies the running `exec` cell to resume.
- `yield_time_ms` controls how long to wait for more output before yielding again. If omitted, `exec_wait` uses its default wait timeout.
- `yield_time_ms` controls how long to wait for more output before yielding again. If omitted, `wait` uses its default wait timeout.
- `max_tokens` limits how much new output this wait call returns.
- `terminate: true` stops the running cell instead of waiting for more output.
- `exec_wait` returns only the new output since the last yield, or the final completion or termination result for that cell.
- If the cell is still running, `exec_wait` may yield again with the same `cell_id`.
- If the cell has already finished, `exec_wait` returns the completed result and closes the cell.
- `wait` returns only the new output since the last yield, or the final completion or termination result for that cell.
- If the cell is still running, `wait` may yield again with the same `cell_id`.
- If the cell has already finished, `wait` returns the completed result and closes the cell.

View file

@ -772,7 +772,7 @@ fn create_write_stdin_tool() -> ToolSpec {
})
}
fn create_exec_wait_tool() -> ToolSpec {
fn create_wait_tool() -> ToolSpec {
let properties = BTreeMap::from([
(
"cell_id".to_string(),
@ -2597,7 +2597,7 @@ pub(crate) fn build_specs_with_discoverable_tools(
builder.register_handler(PUBLIC_TOOL_NAME, code_mode_handler);
push_tool_spec(
&mut builder,
create_exec_wait_tool(),
create_wait_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);

View file

@ -2693,7 +2693,7 @@ fn code_mode_only_restricts_model_tools_to_exec_tools() {
"gpt-5.1-codex",
&features,
Some(WebSearchMode::Live),
&["exec", "exec_wait"],
&["exec", "wait"],
);
}
@ -2724,7 +2724,7 @@ fn code_mode_only_exec_description_includes_full_nested_tool_details() {
assert!(!description.contains("Enabled nested tools:"));
assert!(!description.contains("Nested tool reference:"));
assert!(description.starts_with(
"Use `exec/exec_wait` tool to run all other tools, do not attempt to use any other tools directly"
"Use `exec/wait` tool to run all other tools, do not attempt to use any other tools directly"
));
assert!(description.contains("### `update_plan` (`update_plan`)"));
assert!(description.contains("### `view_image` (`view_image`)"));
@ -2754,7 +2754,7 @@ fn code_mode_exec_description_omits_nested_tool_details_when_not_code_mode_only(
};
assert!(!description.starts_with(
"Use `exec/exec_wait` tool to run all other tools, do not attempt to use any other tools directly"
"Use `exec/wait` tool to run all other tools, do not attempt to use any other tools directly"
));
assert!(!description.contains("### `update_plan` (`update_plan`)"));
assert!(!description.contains("### `view_image` (`view_image`)"));

View file

@ -305,7 +305,7 @@ async fn code_mode_only_restricts_prompt_tools() -> Result<()> {
let first_body = resp_mock.single_request().body_json();
assert_eq!(
tool_names(&first_body),
vec!["exec".to_string(), "exec_wait".to_string()]
vec!["exec".to_string(), "wait".to_string()]
);
Ok(())
@ -539,7 +539,7 @@ Error:\ boom\n
#[cfg_attr(windows, ignore = "no exec_command on Windows")]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_can_yield_and_resume_with_exec_wait() -> Result<()> {
async fn code_mode_can_yield_and_resume_with_wait() -> Result<()> {
skip_if_no_network!(Ok(()));
let server = responses::start_mock_server().await;
@ -602,7 +602,7 @@ text("phase 3");
ev_response_created("resp-3"),
responses::ev_function_call(
"call-2",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": cell_id.clone(),
"yield_time_ms": 1_000,
@ -646,7 +646,7 @@ text("phase 3");
ev_response_created("resp-5"),
responses::ev_function_call(
"call-3",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": cell_id.clone(),
"yield_time_ms": 1_000,
@ -742,7 +742,7 @@ while (true) {}
ev_response_created("resp-3"),
responses::ev_function_call(
"call-2",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": cell_id.clone(),
"terminate": true,
@ -869,7 +869,7 @@ text("session b done");
ev_response_created("resp-5"),
responses::ev_function_call(
"call-3",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": session_a_id.clone(),
"yield_time_ms": 1_000,
@ -909,7 +909,7 @@ text("session b done");
ev_response_created("resp-7"),
responses::ev_function_call(
"call-4",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": session_b_id.clone(),
"yield_time_ms": 1_000,
@ -947,7 +947,7 @@ text("session b done");
#[cfg_attr(windows, ignore = "no exec_command on Windows")]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_exec_wait_can_terminate_and_continue() -> Result<()> {
async fn code_mode_wait_can_terminate_and_continue() -> Result<()> {
skip_if_no_network!(Ok(()));
let server = responses::start_mock_server().await;
@ -999,7 +999,7 @@ text("phase 2");
ev_response_created("resp-3"),
responses::ev_function_call(
"call-2",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": cell_id.clone(),
"terminate": true,
@ -1073,7 +1073,7 @@ text("after terminate");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_exec_wait_returns_error_for_unknown_session() -> Result<()> {
async fn code_mode_wait_returns_error_for_unknown_session() -> Result<()> {
skip_if_no_network!(Ok(()));
let server = responses::start_mock_server().await;
@ -1088,7 +1088,7 @@ async fn code_mode_exec_wait_returns_error_for_unknown_session() -> Result<()> {
ev_response_created("resp-1"),
responses::ev_function_call(
"call-1",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": "999999",
"yield_time_ms": 1_000,
@ -1134,7 +1134,7 @@ async fn code_mode_exec_wait_returns_error_for_unknown_session() -> Result<()> {
#[cfg_attr(windows, ignore = "no exec_command on Windows")]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_exec_wait_terminate_returns_completed_session_if_it_finished_after_yield_control()
async fn code_mode_wait_terminate_returns_completed_session_if_it_finished_after_yield_control()
-> Result<()> {
skip_if_no_network!(Ok(()));
@ -1229,7 +1229,7 @@ text("session b done");
ev_response_created("resp-5"),
responses::ev_function_call(
"call-3",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": session_b_id.clone(),
"yield_time_ms": 1_000,
@ -1279,7 +1279,7 @@ text("session b done");
ev_response_created("resp-7"),
responses::ev_function_call(
"call-4",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": session_a_id.clone(),
"terminate": true,
@ -1330,7 +1330,7 @@ text("session b done");
#[cfg_attr(windows, ignore = "no exec_command on Windows")]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_background_keeps_running_on_later_turn_without_exec_wait() -> Result<()> {
async fn code_mode_background_keeps_running_on_later_turn_without_wait() -> Result<()> {
skip_if_no_network!(Ok(()));
let server = responses::start_mock_server().await;
@ -1423,7 +1423,7 @@ text("after yield");
#[cfg_attr(windows, ignore = "no exec_command on Windows")]
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn code_mode_exec_wait_uses_its_own_max_tokens_budget() -> Result<()> {
async fn code_mode_wait_uses_its_own_max_tokens_budget() -> Result<()> {
skip_if_no_network!(Ok(()));
let server = responses::start_mock_server().await;
@ -1476,7 +1476,7 @@ text("token one token two token three token four token five token six token seve
ev_response_created("resp-3"),
responses::ev_function_call(
"call-2",
"exec_wait",
"wait",
&serde_json::to_string(&serde_json::json!({
"cell_id": cell_id.clone(),
"yield_time_ms": 1_000,