feat(core): remove spawn_mode from agent roles

This commit is contained in:
Friel
2026-04-01 03:06:22 +00:00
parent e07c0a963d
commit a2ebccc904
11 changed files with 12 additions and 64 deletions
@@ -2527,7 +2527,6 @@ mod tests {
prompt: "inspect the repo".into(),
model: "gpt-5.4-mini".into(),
reasoning_effort: codex_protocol::openai_models::ReasoningEffort::Medium,
spawn_mode: codex_protocol::protocol::AgentSpawnMode::Spawn,
status: AgentStatus::Running,
}),
];
+1 -16
View File
@@ -6,13 +6,6 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"AgentRoleSpawnMode": {
"enum": [
"spawn",
"fork"
],
"type": "string"
},
"AgentRoleToml": {
"additionalProperties": false,
"properties": {
@@ -43,14 +36,6 @@
},
"type": "array"
},
"spawn_mode": {
"allOf": [
{
"$ref": "#/definitions/AgentRoleSpawnMode"
}
],
"description": "Optional default spawn mode when `spawn_agent` omits `spawn_mode`."
},
"watchdog_interval_s": {
"description": "Optional watchdog interval in seconds for roles that should behave as watchdogs.",
"format": "int64",
@@ -2625,4 +2610,4 @@
},
"title": "ConfigToml",
"type": "object"
}
}
+9 -9
View File
@@ -1,6 +1,6 @@
# You are the Root Agent
You are the **root agent** in a multi-agent Codex session. Until you see `# You are a Subagent`, these instructions define your role. If this thread was created from the root thread with `spawn_mode = "fork"` (a forked child), you may see both sets of instructions; apply subagent instructions as local role guidance while root instructions remain governing system-level rules.
You are the **root agent** in a multi-agent Codex session. Until you see `# You are a Subagent`, these instructions define your role. If this thread was created from the root thread with `fork_context = true` (a forked child), you may see both sets of instructions; apply subagent instructions as local role guidance while root instructions remain governing system-level rules.
## Root Agent Responsibilities
@@ -36,23 +36,23 @@ Create a subagent and give it an initial task.
Parameters:
- `message` (required): the task description.
- `agent_type` (optional): the role to assign (`default`, `explorer`, `fast-worker`, or `worker`).
- `spawn_mode` (optional): one of `spawn` or `fork`.
- `fork_context` (optional): when `true`, the child receives the current thread history.
Guidance:
- When `spawn_mode` is omitted, the default is `fork` unless the selected role overrides it.
- When `fork_context` is omitted, the default comes from the selected role and otherwise falls back to `true`.
- Use `agent_type = "explorer"` for specific codebase questions; it defaults to context-free `spawn`.
- Use `agent_type = "fast-worker"` for tightly constrained execution work that can run from a self-contained prompt; it also defaults to context-free `spawn`.
- Use `agent_type = "worker"` for broader implementation work that should inherit current-thread context; it defaults to `fork`.
- Choose `fork` vs `spawn` by context requirements first (not by task shape).
- Use `spawn_mode = "fork"` when the child should preserve your current conversation history and rely on current-thread context, including:
- Choose `fork_context = true` vs `false` by context requirements first (not by task shape).
- Use `fork_context = true` when the child should preserve your current conversation history and rely on current-thread context, including:
- current debugging-thread relevance (for example, "summarize only failures relevant to this investigation")
- active plan / ExecPlan branch continuation
- recent user decisions, tradeoffs, or rejected approaches
- parallel review work that should inherit the same context automatically
- Use `spawn_mode = "spawn"` only when the child can do the task correctly from a fresh prompt you provide now, without needing current-thread context.
- For `spawn`, make the task, inputs, and expected output explicit (especially for independent, output-heavy work where you want the child to distill results and keep the root thread context clean).
- Needle-in-a-haystack searches are strong `spawn` candidates when the child can search from a precise prompt without current-thread context.
- Do not choose `spawn` solely because work is output-heavy or command-heavy if it still depends on current-thread context.
- Use `fork_context = false` only when the child can do the task correctly from a fresh prompt you provide now, without needing current-thread context.
- For `fork_context = false`, make the task, inputs, and expected output explicit (especially for independent, output-heavy work where you want the child to distill results and keep the root thread context clean).
- Needle-in-a-haystack searches are strong `fork_context = false` candidates when the child can search from a precise prompt without current-thread context.
- Do not choose `fork_context = false` solely because work is output-heavy or command-heavy if it still depends on current-thread context.
### 2) `send_input`
@@ -11,7 +11,6 @@ use crate::agent::role::default_fork_context_for_role;
use crate::agent::role::watchdog_interval_for_role;
use crate::config::Config;
use codex_features::Feature;
use codex_protocol::protocol::AgentSpawnMode;
use codex_protocol::protocol::SessionSource;
use std::collections::HashSet;
@@ -198,13 +197,6 @@ impl ToolHandler for Handler {
prompt,
model: effective_model,
reasoning_effort: effective_reasoning_effort,
spawn_mode: if is_watchdog {
AgentSpawnMode::Watchdog
} else if fork_context {
AgentSpawnMode::Fork
} else {
AgentSpawnMode::Spawn
},
status,
}
.into(),
@@ -449,7 +449,7 @@ async fn multi_agent_v2_spawn_fork_context_ignores_child_model_overrides() {
}
#[tokio::test]
async fn spawn_agent_watchdog_role_returns_handle_without_spawn_mode() {
async fn spawn_agent_watchdog_role_returns_handle_with_role_defaults() {
let (mut session, mut turn) = make_session_and_context().await;
let manager = thread_manager();
session.services.agent_control = manager.agent_control();
@@ -6,7 +6,6 @@ use crate::agent::role::DEFAULT_ROLE_NAME;
use crate::agent::role::apply_role_to_config;
use crate::agent::role::default_fork_context_for_role;
use codex_protocol::AgentPath;
use codex_protocol::protocol::AgentSpawnMode;
use codex_protocol::protocol::InterAgentCommunication;
use codex_protocol::protocol::Op;
@@ -178,11 +177,6 @@ impl ToolHandler for Handler {
prompt,
model: effective_model,
reasoning_effort: effective_reasoning_effort,
spawn_mode: if fork_context {
AgentSpawnMode::Fork
} else {
AgentSpawnMode::Spawn
},
status,
}
.into(),
+1 -1
View File
@@ -52,7 +52,7 @@ When you detect these, prescribe the corrective action explicitly.
Use only the multi-agent tools that exist here:
- `spawn_agent` (prefer `spawn_mode = "fork"` when shared context matters).
- `spawn_agent` (prefer `fork_context = true` when shared context matters).
- `send_input`.
- `compact_parent_context` (watchdog-only recovery tool; see below).
- `watchdog_self_close` (watchdog-only immediate exit tool; see below).
-13
View File
@@ -3420,16 +3420,6 @@ pub struct CollabAgentSpawnBeginEvent {
pub reasoning_effort: ReasoningEffortConfig,
}
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS, Default)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case")]
pub enum AgentSpawnMode {
#[default]
Spawn,
Fork,
Watchdog,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
pub struct CollabAgentRef {
/// Thread ID of the receiver/new agent.
@@ -3477,9 +3467,6 @@ pub struct CollabAgentSpawnEndEvent {
pub model: String,
/// Effective reasoning effort used by the spawned agent after inheritance and role overrides.
pub reasoning_effort: ReasoningEffortConfig,
/// Spawn mode used for this agent.
#[serde(default)]
pub spawn_mode: AgentSpawnMode,
/// Last known status of the new agent reported to the sender agent.
pub status: AgentStatus,
}
-5
View File
@@ -139,7 +139,6 @@ use codex_protocol::protocol::AgentReasoningEvent;
use codex_protocol::protocol::AgentReasoningRawContentDeltaEvent;
#[cfg(test)]
use codex_protocol::protocol::AgentReasoningRawContentEvent;
use codex_protocol::protocol::AgentSpawnMode;
use codex_protocol::protocol::AgentStatus;
use codex_protocol::protocol::ApplyPatchApprovalRequestEvent;
#[cfg(test)]
@@ -3666,10 +3665,6 @@ impl ChatWidget {
prompt: prompt.unwrap_or_default(),
model: String::new(),
reasoning_effort: ReasoningEffortConfig::Medium,
// Thread history items do not carry spawn_mode yet, so the
// replay path must choose an explicit fallback for reconstructed
// spawn rows. Plain spawn is the least surprising default.
spawn_mode: AgentSpawnMode::Spawn,
status: first_receiver
.as_ref()
.and_then(|thread_id| agents_states.get(&thread_id.to_string()))
-1
View File
@@ -2341,7 +2341,6 @@ async fn collab_spawn_end_shows_requested_model_and_effort() {
new_agent_nickname: Some("Robie".to_string()),
new_agent_role: Some("explorer".to_string()),
prompt: "Explore the repo".to_string(),
spawn_mode: codex_protocol::protocol::AgentSpawnMode::Spawn,
model: "gpt-5".to_string(),
reasoning_effort: ReasoningEffortConfig::High,
status: AgentStatus::PendingInit,
-3
View File
@@ -583,7 +583,6 @@ fn status_summary_spans(status: &AgentStatus) -> Vec<Span<'static>> {
mod tests {
use super::*;
use crate::history_cell::HistoryCell;
use codex_protocol::protocol::AgentSpawnMode;
#[cfg(target_os = "macos")]
use crossterm::event::KeyEvent;
#[cfg(target_os = "macos")]
@@ -610,7 +609,6 @@ mod tests {
new_agent_nickname: Some("Robie".to_string()),
new_agent_role: Some("explorer".to_string()),
prompt: "Compute 11! and reply with just the integer result.".to_string(),
spawn_mode: AgentSpawnMode::Spawn,
model: "gpt-5".to_string(),
reasoning_effort: ReasoningEffortConfig::High,
status: AgentStatus::PendingInit,
@@ -749,7 +747,6 @@ mod tests {
new_agent_nickname: Some("Robie".to_string()),
new_agent_role: Some("explorer".to_string()),
prompt: String::new(),
spawn_mode: AgentSpawnMode::Spawn,
model: "gpt-5".to_string(),
reasoning_effort: ReasoningEffortConfig::High,
status: AgentStatus::PendingInit,