From 4666a6e631567f37366f9ce19905d16ce62b36f2 Mon Sep 17 00:00:00 2001 From: jif-oai Date: Sun, 22 Feb 2026 14:13:56 +0000 Subject: [PATCH] feat: monitor role (#12364) --- codex-rs/core/config.schema.json | 2 +- codex-rs/core/src/agent/builtins/monitor.toml | 36 +++++++++++++++++++ codex-rs/core/src/agent/role.rs | 23 ++++++++---- codex-rs/core/src/config/mod.rs | 4 +-- .../core/src/tools/handlers/multi_agents.rs | 2 +- 5 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 codex-rs/core/src/agent/builtins/monitor.toml diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index ed1ae8ddb..6a0f0a174 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -1514,7 +1514,7 @@ "default": null, "description": "Settings for app-specific controls." }, - "background_terminal_timeout": { + "background_terminal_max_timeout": { "description": "Maximum poll window for background terminal output (`write_stdin`), in milliseconds. Default: `300000` (5 minutes).", "format": "uint64", "minimum": 0.0, diff --git a/codex-rs/core/src/agent/builtins/monitor.toml b/codex-rs/core/src/agent/builtins/monitor.toml new file mode 100644 index 000000000..5e48a4936 --- /dev/null +++ b/codex-rs/core/src/agent/builtins/monitor.toml @@ -0,0 +1,36 @@ +background_terminal_max_timeout = 3600000 +model_reasoning_effort = "low" +developer_instructions="""You are a waiting agent. +You're name is Superman. +Your role is to monitor the execution of a specific command or task and report its status only when it is finished. + +Behavior rules: + +1. When given a command or task identifier, you must: + - Execute or monitor it using the appropriate tool + - Continue waiting until the task reaches a terminal state. + +2. You must NOT: + - Modify the task. + - Interpret or optimize the task. + - Perform unrelated actions. + - Stop waiting unless explicitly instructed. + +3. Waiting behavior: + - If the task is still running, continue polling using tool calls. + - Use repeated tool calls if necessary. + - Do not hallucinate completion. + - Use long timeouts when waiting for something. If you need multiple wait, increase the timeouts/yield times exponentially. + +4. If asked for status: + - Return the current known status. + - Immediately resume waiting afterward. + +5. Termination: + - Only exit waiting when: + - The task completes successfully, OR + - The task fails, OR + - You receive an explicit stop instruction. + +You must behave deterministically and conservatively. +""" \ No newline at end of file diff --git a/codex-rs/core/src/agent/role.rs b/codex-rs/core/src/agent/role.rs index 16460fb7f..f4bdb9d7a 100644 --- a/codex-rs/core/src/agent/role.rs +++ b/codex-rs/core/src/agent/role.rs @@ -13,7 +13,6 @@ use std::path::Path; use std::sync::LazyLock; use toml::Value as TomlValue; -const BUILT_IN_EXPLORER_CONFIG: &str = include_str!("builtins/explorer.toml"); const DEFAULT_ROLE_NAME: &str = "default"; const AGENT_TYPE_UNAVAILABLE_ERROR: &str = "agent type is currently not available"; @@ -186,6 +185,19 @@ Rules: - Always tell workers they are **not alone in the codebase**, and they should ignore edits made by others without touching them."#.to_string()), config_file: None, } + ), + ( + "monitor".to_string(), + AgentRoleConfig { + description: Some(r#"Use a `monitor` agent EVERY TIME you must run a command that might take some time. +This includes, but not only: +* testing +* monitoring of a long running process +* explicit ask to wait for something + +When YOU wait for the `monitor` agent to be done, use the largest possible timeout."#.to_string()), + config_file: Some("monitor.toml".to_string().parse().unwrap_or_default()), + } ) ]) }); @@ -194,8 +206,11 @@ Rules: /// Resolves a built-in role `config_file` path to embedded content. pub(super) fn config_file_contents(path: &Path) -> Option<&'static str> { + const EXPLORER: &str = include_str!("builtins/explorer.toml"); + const MONITOR: &str = include_str!("builtins/monitor.toml"); match path.to_str()? { - "explorer.toml" => Some(BUILT_IN_EXPLORER_CONFIG), + "explorer.toml" => Some(EXPLORER), + "monitor.toml" => Some(MONITOR), _ => None, } } @@ -481,10 +496,6 @@ writable_roots = ["./sandbox-root"] #[test] fn built_in_config_file_contents_resolves_explorer_only() { - assert_eq!( - built_in::config_file_contents(Path::new("explorer.toml")), - Some(BUILT_IN_EXPLORER_CONFIG) - ); assert_eq!( built_in::config_file_contents(Path::new("missing.toml")), None diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 6474ca4bc..ffd35e036 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -1076,7 +1076,7 @@ pub struct ConfigToml { /// Maximum poll window for background terminal output (`write_stdin`), in milliseconds. /// Default: `300000` (5 minutes). - pub background_terminal_timeout: Option, + pub background_terminal_max_timeout: Option, /// Optional absolute path to the Node runtime used by `js_repl`. pub js_repl_node_path: Option, @@ -1804,7 +1804,7 @@ impl Config { .transpose()? .unwrap_or_default(); let background_terminal_max_timeout = cfg - .background_terminal_timeout + .background_terminal_max_timeout .unwrap_or(DEFAULT_MAX_BACKGROUND_TERMINAL_TIMEOUT_MS) .max(MIN_EMPTY_YIELD_TIME_MS); diff --git a/codex-rs/core/src/tools/handlers/multi_agents.rs b/codex-rs/core/src/tools/handlers/multi_agents.rs index 455a20952..ae72c8b1e 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents.rs @@ -42,7 +42,7 @@ pub struct MultiAgentHandler; /// Minimum wait timeout to prevent tight polling loops from burning CPU. pub(crate) const MIN_WAIT_TIMEOUT_MS: i64 = 10_000; pub(crate) const DEFAULT_WAIT_TIMEOUT_MS: i64 = 30_000; -pub(crate) const MAX_WAIT_TIMEOUT_MS: i64 = 300_000; +pub(crate) const MAX_WAIT_TIMEOUT_MS: i64 = 3600 * 1000; #[derive(Debug, Deserialize)] struct CloseAgentArgs {