mirror of
https://github.com/openai/codex.git
synced 2026-10-18 17:18:52 +00:00
Configure the default code-mode exec yield timeout (#37352)
## What changed - Add `features.code_mode.default_exec_yield_time_ms`, defaulting to 30 seconds. - Apply the configured default to code-mode `exec` calls that omit `yield_time_ms` and reflect it in the tool description. - Remove the `code_mode_buffered_exec` compatibility feature flag. ## Testing - Cover config loading and tool descriptions for both default and custom yield timeouts. GitOrigin-RevId: 581ffc737b04721c7b5fc81260b1da1cf7d87523
This commit is contained in:
@@ -365,6 +365,12 @@
|
||||
"CodeModeConfigToml": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"default_exec_yield_time_ms": {
|
||||
"description": "Default yield timeout for code-mode exec calls, in milliseconds.",
|
||||
"format": "uint64",
|
||||
"minimum": 0.0,
|
||||
"type": "integer"
|
||||
},
|
||||
"direct_only_tool_namespaces": {
|
||||
"description": "Exact tool namespaces to expose only as direct model tools. These tools bypass deferral, remain top-level in code-mode-only sessions, and are omitted from the nested code-mode tool surface.",
|
||||
"items": {
|
||||
|
||||
@@ -538,6 +538,7 @@ async fn load_config_resolves_code_mode_config() -> std::io::Result<()> {
|
||||
r#"
|
||||
[features.code_mode]
|
||||
enabled = true
|
||||
default_exec_yield_time_ms = 10000
|
||||
excluded_tool_namespaces = ["mcp__codex_apps", "multi_agent_v1"]
|
||||
direct_only_tool_namespaces = ["mcp__history", "mcp__notes"]
|
||||
|
||||
@@ -554,6 +555,7 @@ disable_in_process_fallback = true
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert_eq!(config.code_mode.default_exec_yield_time_ms, 10_000);
|
||||
assert_eq!(
|
||||
config.code_mode.excluded_tool_namespaces,
|
||||
vec!["mcp__codex_apps".to_string(), "multi_agent_v1".to_string()]
|
||||
|
||||
@@ -1117,14 +1117,28 @@ pub struct ToolRegistryConfig {
|
||||
pub error_on_tool_collisions: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
|
||||
const DEFAULT_CODE_MODE_EXEC_YIELD_TIME_MS: u64 = 30_000;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct CodeModeConfig {
|
||||
pub default_exec_yield_time_ms: u64,
|
||||
pub excluded_tool_namespaces: Vec<String>,
|
||||
pub direct_only_tool_namespaces: Vec<String>,
|
||||
/// Keep code mode fail-closed when the standalone host is unavailable.
|
||||
pub disable_in_process_fallback: bool,
|
||||
}
|
||||
|
||||
impl Default for CodeModeConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
default_exec_yield_time_ms: DEFAULT_CODE_MODE_EXEC_YIELD_TIME_MS,
|
||||
excluded_tool_namespaces: Vec::new(),
|
||||
direct_only_tool_namespaces: Vec::new(),
|
||||
disable_in_process_fallback: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const DEFAULT_TOKEN_BUDGET_REMINDER_MESSAGE_TEMPLATE: &str = concat!(
|
||||
"Your context window is nearly exhausted (only {n_remaining} tokens remaining) and will be automatically reset for you soon. ",
|
||||
"Once reset, message items in current context window will be cleared in the new window, but notes and history items will be persistent across windows."
|
||||
@@ -2685,6 +2699,9 @@ fn resolve_code_mode_config(config_toml: &ConfigToml) -> CodeModeConfig {
|
||||
});
|
||||
|
||||
CodeModeConfig {
|
||||
default_exec_yield_time_ms: base
|
||||
.and_then(|config| config.default_exec_yield_time_ms)
|
||||
.unwrap_or(DEFAULT_CODE_MODE_EXEC_YIELD_TIME_MS),
|
||||
excluded_tool_namespaces: base
|
||||
.and_then(|config| config.excluded_tool_namespaces.as_ref())
|
||||
.cloned()
|
||||
|
||||
@@ -1204,7 +1204,7 @@ impl Session {
|
||||
executed_tool_calls,
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(
|
||||
Arc::clone(&code_mode_session_provider),
|
||||
&config.features,
|
||||
&config.code_mode,
|
||||
),
|
||||
tool_search_handler_cache: Default::default(),
|
||||
turn_environments: Arc::clone(&turn_environments),
|
||||
|
||||
@@ -5827,7 +5827,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
executed_tool_calls,
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(
|
||||
Arc::new(codex_code_mode::DisabledCodeModeSessionProvider),
|
||||
&config.features,
|
||||
&config.code_mode,
|
||||
),
|
||||
tool_search_handler_cache: Default::default(),
|
||||
turn_environments: Arc::clone(&turn_environments),
|
||||
@@ -8046,7 +8046,7 @@ where
|
||||
executed_tool_calls,
|
||||
code_mode_service: crate::tools::code_mode::CodeModeService::new(
|
||||
Arc::new(codex_code_mode::DisabledCodeModeSessionProvider),
|
||||
&config.features,
|
||||
&config.code_mode,
|
||||
),
|
||||
tool_search_handler_cache: Default::default(),
|
||||
turn_environments: Arc::clone(&turn_environments),
|
||||
|
||||
@@ -17,13 +17,12 @@ use codex_code_mode::CodeModeSession;
|
||||
use codex_code_mode::CodeModeSessionProvider;
|
||||
use codex_code_mode::CodeModeToolKind;
|
||||
use codex_code_mode::RuntimeResponse;
|
||||
use codex_features::Feature;
|
||||
use codex_features::Features;
|
||||
use codex_protocol::models::FunctionCallOutputContentItem;
|
||||
use serde_json::Value as JsonValue;
|
||||
use tokio::sync::OnceCell;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use crate::config::CodeModeConfig;
|
||||
use crate::function_tool::FunctionCallError;
|
||||
use crate::original_image_detail::can_request_original_image_detail;
|
||||
use crate::original_image_detail::sanitize_original_image_detail as sanitize_image_detail_items;
|
||||
@@ -54,13 +53,6 @@ pub(crate) use wait_handler::CodeModeWaitHandler;
|
||||
pub(crate) const PUBLIC_TOOL_NAME: &str = codex_code_mode::PUBLIC_TOOL_NAME;
|
||||
pub(crate) const WAIT_TOOL_NAME: &str = codex_code_mode::WAIT_TOOL_NAME;
|
||||
pub(crate) const DEFAULT_WAIT_YIELD_TIME_MS: u64 = codex_code_mode::DEFAULT_WAIT_YIELD_TIME_MS;
|
||||
const BUFFERED_EXEC_YIELD_TIME_MS: u64 = 30_000;
|
||||
|
||||
pub(crate) fn default_exec_yield_time_override_ms(features: &Features) -> Option<u64> {
|
||||
features
|
||||
.enabled(Feature::CodeModeBufferedExec)
|
||||
.then_some(BUFFERED_EXEC_YIELD_TIME_MS)
|
||||
}
|
||||
|
||||
/// Returns true for the code-mode `exec` tool in the default namespace.
|
||||
pub(crate) fn is_exec_tool_name(tool_name: &ToolName) -> bool {
|
||||
@@ -78,7 +70,7 @@ pub(crate) struct CodeModeService {
|
||||
session_provider: Arc<dyn CodeModeSessionProvider>,
|
||||
availability: Result<(), String>,
|
||||
dispatch_broker: Arc<CodeModeDispatchBroker>,
|
||||
default_exec_yield_time_override_ms: Option<u64>,
|
||||
default_exec_yield_time_ms: u64,
|
||||
shutting_down: AtomicBool,
|
||||
unavailable_warning_emitted: AtomicBool,
|
||||
}
|
||||
@@ -86,7 +78,7 @@ pub(crate) struct CodeModeService {
|
||||
impl CodeModeService {
|
||||
pub(crate) fn new(
|
||||
session_provider: Arc<dyn CodeModeSessionProvider>,
|
||||
features: &Features,
|
||||
config: &CodeModeConfig,
|
||||
) -> Self {
|
||||
let dispatch_broker = Arc::new(CodeModeDispatchBroker::new());
|
||||
let availability = session_provider.availability();
|
||||
@@ -95,7 +87,7 @@ impl CodeModeService {
|
||||
session_provider,
|
||||
availability,
|
||||
dispatch_broker,
|
||||
default_exec_yield_time_override_ms: default_exec_yield_time_override_ms(features),
|
||||
default_exec_yield_time_ms: config.default_exec_yield_time_ms,
|
||||
shutting_down: AtomicBool::new(false),
|
||||
unavailable_warning_emitted: AtomicBool::new(false),
|
||||
}
|
||||
@@ -129,9 +121,9 @@ impl CodeModeService {
|
||||
&self,
|
||||
mut request: codex_code_mode::ExecuteRequest,
|
||||
) -> Result<codex_code_mode::StartedCell, String> {
|
||||
if request.yield_time_ms.is_none() {
|
||||
request.yield_time_ms = self.default_exec_yield_time_override_ms;
|
||||
}
|
||||
request
|
||||
.yield_time_ms
|
||||
.get_or_insert(self.default_exec_yield_time_ms);
|
||||
self.session().await?.execute(request).await
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::environment_selection::TurnEnvironmentSnapshot;
|
||||
use crate::image_preparation::unified_image_budget_enabled;
|
||||
use crate::session::session::Session;
|
||||
use crate::session::turn_context::TurnContext;
|
||||
use crate::tools::code_mode::default_exec_yield_time_override_ms;
|
||||
use crate::tools::code_mode::execute_spec::create_code_mode_tool;
|
||||
use crate::tools::context::ToolInvocation;
|
||||
use crate::tools::effective_tool_mode;
|
||||
@@ -758,16 +757,12 @@ fn register_code_mode_executors(
|
||||
);
|
||||
enabled_tools
|
||||
.sort_by(|left, right| compare_code_mode_tools(left, right, &namespace_descriptions));
|
||||
let default_exec_yield_time_ms =
|
||||
default_exec_yield_time_override_ms(&turn_context.config.features)
|
||||
.unwrap_or(codex_code_mode::DEFAULT_EXEC_YIELD_TIME_MS);
|
||||
|
||||
let execute_handler = CodeModeExecuteHandler::new(
|
||||
create_code_mode_tool(
|
||||
&enabled_tools,
|
||||
&deferred_tools,
|
||||
&namespace_descriptions,
|
||||
default_exec_yield_time_ms,
|
||||
turn_context.config.code_mode.default_exec_yield_time_ms,
|
||||
tool_mode == ToolMode::CodeModeOnly,
|
||||
if unified_image_budget_enabled(&turn_context.config.features, &turn_context.model_info)
|
||||
{
|
||||
|
||||
@@ -1948,17 +1948,28 @@ async fn code_mode_only_exposes_code_executor_and_hides_nested_tools() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn code_mode_buffered_exec_updates_exec_description() {
|
||||
let plan = probe(|turn| {
|
||||
set_features(turn, &[Feature::CodeMode, Feature::CodeModeBufferedExec]);
|
||||
})
|
||||
.await;
|
||||
async fn code_mode_config_updates_exec_description() {
|
||||
for (configured_yield_time_ms, expected_yield_time_ms) in
|
||||
[(None, 30_000), (Some(10_000), 10_000)]
|
||||
{
|
||||
let plan = probe(|turn| {
|
||||
set_features(turn, &[Feature::CodeMode]);
|
||||
if let Some(yield_time_ms) = configured_yield_time_ms {
|
||||
update_config(turn, |config| {
|
||||
config.code_mode.default_exec_yield_time_ms = yield_time_ms;
|
||||
});
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
let ToolSpec::Freeform(exec) = plan.visible_spec(codex_code_mode::PUBLIC_TOOL_NAME) else {
|
||||
panic!("expected code mode exec tool");
|
||||
};
|
||||
assert!(exec.description.contains("Defaults to 30000 ms."));
|
||||
assert!(!exec.description.contains("Defaults to 10000 ms."));
|
||||
let ToolSpec::Freeform(exec) = plan.visible_spec(codex_code_mode::PUBLIC_TOOL_NAME) else {
|
||||
panic!("expected code mode exec tool");
|
||||
};
|
||||
assert!(
|
||||
exec.description
|
||||
.contains(&format!("Defaults to {expected_yield_time_ms} ms."))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -279,7 +279,7 @@ async fn missing_code_mode_wait_traces_only_the_wait_tool_call() -> anyhow::Resu
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
session.services.code_mode_service = CodeModeService::new(
|
||||
Arc::new(MissingCellCodeModeSessionProvider),
|
||||
&turn.config.features,
|
||||
&turn.config.code_mode,
|
||||
);
|
||||
attach_test_trace(&mut session, &turn, temp.path())?;
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ pub struct ToolRegistryConfigToml {
|
||||
pub struct CodeModeConfigToml {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enabled: Option<bool>,
|
||||
/// Default yield timeout for code-mode exec calls, in milliseconds.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub default_exec_yield_time_ms: Option<u64>,
|
||||
/// Exact tool namespaces to omit from the code-mode nested tool surface.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub excluded_tool_namespaces: Option<Vec<String>>,
|
||||
|
||||
@@ -99,7 +99,7 @@ pub enum Feature {
|
||||
ExecutedToolCallMetadata,
|
||||
/// Enable JavaScript code mode backed by the standalone host process.
|
||||
CodeMode,
|
||||
/// Use a 30-second default yield timeout for code mode exec calls.
|
||||
/// Removed compatibility flag for the configurable code-mode exec yield timeout.
|
||||
CodeModeBufferedExec,
|
||||
/// Run JavaScript code mode in the standalone host process.
|
||||
CodeModeHost,
|
||||
@@ -924,7 +924,7 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
FeatureSpec {
|
||||
id: Feature::CodeModeBufferedExec,
|
||||
key: "code_mode_buffered_exec",
|
||||
stage: Stage::UnderDevelopment,
|
||||
stage: Stage::Removed,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
|
||||
Reference in New Issue
Block a user