mirror of
https://github.com/openai/codex.git
synced 2026-10-28 08:04:55 +00:00
Unify multi-agent settings under agents (#33550)
## What changed - Add `agents.enabled` as a user override for multi-agent tools while keeping an enabled `features.multi_agent_v2` authoritative. - Rename the shared spawned-thread limit to `agents.max_concurrent_threads_per_session`, retain `agents.max_threads` as an alias, and apply the setting to both multi-agent backends. - Add reserved subagent model, reasoning effort, and agent-type settings to the config surface and persist all resolved agent settings in config locks. - Show the resolved `[agents]` values in TUI debug-config output. ## Testing - Cover config loading, legacy alias normalization across merged layers, backend-selection precedence, V2 concurrency, and debug output. GitOrigin-RevId: 2957c954a2e1aef51592768dbbccd56c4bf8f118
This commit is contained in:
@@ -1953,7 +1953,7 @@ async fn spawn_agent_fork_last_n_turns_strips_parent_usage_hints() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn spawn_agent_respects_max_threads_limit() {
|
||||
async fn spawn_agent_respects_legacy_max_threads_alias() {
|
||||
let max_threads = 1usize;
|
||||
let (_home, config) = test_config_with_cli_overrides(vec![(
|
||||
"agents.max_threads".to_string(),
|
||||
@@ -2008,7 +2008,7 @@ async fn spawn_agent_respects_max_threads_limit() {
|
||||
async fn spawn_agent_releases_slot_after_shutdown() {
|
||||
let max_threads = 1usize;
|
||||
let (_home, config) = test_config_with_cli_overrides(vec![(
|
||||
"agents.max_threads".to_string(),
|
||||
"agents.max_concurrent_threads_per_session".to_string(),
|
||||
TomlValue::Integer(max_threads as i64),
|
||||
)])
|
||||
.await;
|
||||
@@ -2051,7 +2051,7 @@ async fn spawn_agent_releases_slot_after_shutdown() {
|
||||
async fn spawn_agent_limit_shared_across_clones() {
|
||||
let max_threads = 1usize;
|
||||
let (_home, config) = test_config_with_cli_overrides(vec![(
|
||||
"agents.max_threads".to_string(),
|
||||
"agents.max_concurrent_threads_per_session".to_string(),
|
||||
TomlValue::Integer(max_threads as i64),
|
||||
)])
|
||||
.await;
|
||||
@@ -2096,7 +2096,7 @@ async fn spawn_agent_limit_shared_across_clones() {
|
||||
async fn resume_agent_respects_max_threads_limit() {
|
||||
let max_threads = 1usize;
|
||||
let (_home, config) = test_config_with_cli_overrides(vec![(
|
||||
"agents.max_threads".to_string(),
|
||||
"agents.max_concurrent_threads_per_session".to_string(),
|
||||
TomlValue::Integer(max_threads as i64),
|
||||
)])
|
||||
.await;
|
||||
@@ -2152,7 +2152,7 @@ async fn resume_agent_respects_max_threads_limit() {
|
||||
async fn resume_agent_releases_slot_after_resume_failure() {
|
||||
let max_threads = 1usize;
|
||||
let (_home, config) = test_config_with_cli_overrides(vec![(
|
||||
"agents.max_threads".to_string(),
|
||||
"agents.max_concurrent_threads_per_session".to_string(),
|
||||
TomlValue::Integer(max_threads as i64),
|
||||
)])
|
||||
.await;
|
||||
|
||||
@@ -7348,8 +7348,12 @@ async fn load_config_rejects_missing_agent_role_config_file() -> std::io::Result
|
||||
let missing_path = codex_home.path().join("agents").join("researcher.toml");
|
||||
let cfg = ConfigToml {
|
||||
agents: Some(AgentsToml {
|
||||
max_threads: None,
|
||||
enabled: None,
|
||||
max_concurrent_threads_per_session: None,
|
||||
max_depth: None,
|
||||
support_agent_type: None,
|
||||
default_subagent_model: None,
|
||||
default_subagent_reasoning_effort: None,
|
||||
job_max_runtime_seconds: None,
|
||||
interrupt_message: None,
|
||||
roles: BTreeMap::from([(
|
||||
@@ -8269,10 +8273,15 @@ model = "gpt-5-mini"
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn load_config_resolves_agent_interrupt_message() -> std::io::Result<()> {
|
||||
async fn load_config_resolves_agent_controls() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let cfg = ConfigToml {
|
||||
agents: Some(AgentsToml {
|
||||
enabled: Some(false),
|
||||
max_depth: Some(2),
|
||||
support_agent_type: Some(true),
|
||||
default_subagent_model: Some("gpt-5.6-terra".to_string()),
|
||||
default_subagent_reasoning_effort: Some(ReasoningEffort::High),
|
||||
interrupt_message: Some(false),
|
||||
..Default::default()
|
||||
}),
|
||||
@@ -8286,18 +8295,60 @@ async fn load_config_resolves_agent_interrupt_message() -> std::io::Result<()> {
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert!(!config.agent_interrupt_message_enabled);
|
||||
assert_eq!(
|
||||
(
|
||||
config.agents_enabled,
|
||||
config.agent_max_depth,
|
||||
config.agent_support_agent_type,
|
||||
config.agent_default_subagent_model.as_deref(),
|
||||
config.agent_default_subagent_reasoning_effort,
|
||||
config.agent_interrupt_message_enabled,
|
||||
),
|
||||
(
|
||||
false,
|
||||
2,
|
||||
Some(true),
|
||||
Some("gpt-5.6-terra"),
|
||||
Some(ReasoningEffort::High),
|
||||
false,
|
||||
)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn agents_max_threads_alias_matches_canonical_config() {
|
||||
let canonical: ConfigToml = toml::from_str(
|
||||
r#"[agents]
|
||||
max_concurrent_threads_per_session = 7
|
||||
"#,
|
||||
)
|
||||
.expect("canonical agents thread limit should parse");
|
||||
let legacy: ConfigToml = toml::from_str(
|
||||
r#"[agents]
|
||||
max_threads = 7
|
||||
"#,
|
||||
)
|
||||
.expect("legacy agents thread limit should parse");
|
||||
|
||||
assert_eq!(legacy, canonical);
|
||||
let serialized = toml::to_string(&legacy).expect("agents config should serialize");
|
||||
assert!(serialized.contains("max_concurrent_threads_per_session = 7"));
|
||||
assert!(!serialized.contains("max_threads"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn load_config_normalizes_agent_role_nickname_candidates() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let cfg = ConfigToml {
|
||||
agents: Some(AgentsToml {
|
||||
max_threads: None,
|
||||
enabled: None,
|
||||
max_concurrent_threads_per_session: None,
|
||||
max_depth: None,
|
||||
support_agent_type: None,
|
||||
default_subagent_model: None,
|
||||
default_subagent_reasoning_effort: None,
|
||||
job_max_runtime_seconds: None,
|
||||
interrupt_message: None,
|
||||
roles: BTreeMap::from([(
|
||||
@@ -8339,8 +8390,12 @@ async fn load_config_rejects_empty_agent_role_nickname_candidates() -> std::io::
|
||||
let codex_home = TempDir::new()?;
|
||||
let cfg = ConfigToml {
|
||||
agents: Some(AgentsToml {
|
||||
max_threads: None,
|
||||
enabled: None,
|
||||
max_concurrent_threads_per_session: None,
|
||||
max_depth: None,
|
||||
support_agent_type: None,
|
||||
default_subagent_model: None,
|
||||
default_subagent_reasoning_effort: None,
|
||||
job_max_runtime_seconds: None,
|
||||
interrupt_message: None,
|
||||
roles: BTreeMap::from([(
|
||||
@@ -8376,8 +8431,12 @@ async fn load_config_rejects_duplicate_agent_role_nickname_candidates() -> std::
|
||||
let codex_home = TempDir::new()?;
|
||||
let cfg = ConfigToml {
|
||||
agents: Some(AgentsToml {
|
||||
max_threads: None,
|
||||
enabled: None,
|
||||
max_concurrent_threads_per_session: None,
|
||||
max_depth: None,
|
||||
support_agent_type: None,
|
||||
default_subagent_model: None,
|
||||
default_subagent_reasoning_effort: None,
|
||||
job_max_runtime_seconds: None,
|
||||
interrupt_message: None,
|
||||
roles: BTreeMap::from([(
|
||||
@@ -8413,8 +8472,12 @@ async fn load_config_rejects_unsafe_agent_role_nickname_candidates() -> std::io:
|
||||
let codex_home = TempDir::new()?;
|
||||
let cfg = ConfigToml {
|
||||
agents: Some(AgentsToml {
|
||||
max_threads: None,
|
||||
enabled: None,
|
||||
max_concurrent_threads_per_session: None,
|
||||
max_depth: None,
|
||||
support_agent_type: None,
|
||||
default_subagent_model: None,
|
||||
default_subagent_reasoning_effort: None,
|
||||
job_max_runtime_seconds: None,
|
||||
interrupt_message: None,
|
||||
roles: BTreeMap::from([(
|
||||
@@ -10389,6 +10452,9 @@ tool_namespace = "agents"
|
||||
hide_spawn_agent_metadata = true
|
||||
expose_spawn_agent_model_overrides = false
|
||||
non_code_mode_only = true
|
||||
|
||||
[agents]
|
||||
max_concurrent_threads_per_session = 9
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -10408,7 +10474,7 @@ non_code_mode_only = true
|
||||
config.agent_max_threads,
|
||||
config.effective_agent_max_threads(MultiAgentVersion::V2)
|
||||
),
|
||||
(None, Some(4))
|
||||
(Some(9), Some(4))
|
||||
);
|
||||
assert_eq!(
|
||||
config.multi_agent_v2.usage_hint_text.as_deref(),
|
||||
@@ -10576,7 +10642,7 @@ subagent_usage_hint_text = ""
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_feature_rejects_agents_max_threads() -> std::io::Result<()> {
|
||||
async fn multi_agent_v2_uses_agents_max_concurrent_threads_per_session() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
std::fs::write(
|
||||
codex_home.path().join(CONFIG_TOML_FILE),
|
||||
@@ -10584,7 +10650,7 @@ async fn multi_agent_v2_feature_rejects_agents_max_threads() -> std::io::Result<
|
||||
enabled = true
|
||||
|
||||
[agents]
|
||||
max_threads = 3
|
||||
max_concurrent_threads_per_session = 7
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -10593,25 +10659,19 @@ max_threads = 3
|
||||
.fallback_cwd(Some(codex_home.path().to_path_buf()))
|
||||
.build()
|
||||
.await?;
|
||||
let err = config
|
||||
.validate_multi_agent_v2_config()
|
||||
.expect_err("agents.max_threads should conflict with multi_agent_v2");
|
||||
|
||||
assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput);
|
||||
assert_eq!(
|
||||
err.to_string(),
|
||||
"agents.max_threads cannot be set when features.multi_agent_v2 is enabled"
|
||||
);
|
||||
assert_eq!(
|
||||
config.effective_agent_max_threads(MultiAgentVersion::V2),
|
||||
Some(3)
|
||||
(
|
||||
config.multi_agent_v2.max_concurrent_threads_per_session,
|
||||
config.effective_agent_max_threads(MultiAgentVersion::V2),
|
||||
),
|
||||
(8, Some(7))
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn catalog_v2_allows_agents_max_threads_when_feature_disabled() -> std::io::Result<()> {
|
||||
async fn catalog_v2_allows_agents_thread_limit_when_feature_disabled() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
std::fs::write(
|
||||
codex_home.path().join(CONFIG_TOML_FILE),
|
||||
@@ -10619,7 +10679,7 @@ async fn catalog_v2_allows_agents_max_threads_when_feature_disabled() -> std::io
|
||||
enabled = false
|
||||
|
||||
[agents]
|
||||
max_threads = 3
|
||||
max_concurrent_threads_per_session = 3
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -10629,10 +10689,12 @@ max_threads = 3
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
config.validate_multi_agent_v2_config()?;
|
||||
assert_eq!(
|
||||
config.effective_agent_max_threads(MultiAgentVersion::V2),
|
||||
Some(3)
|
||||
(
|
||||
config.multi_agent_v2.max_concurrent_threads_per_session,
|
||||
config.effective_agent_max_threads(MultiAgentVersion::V2),
|
||||
),
|
||||
(4, Some(3))
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -857,15 +857,28 @@ pub struct Config {
|
||||
/// Token budget applied when storing tool/function outputs in the context manager.
|
||||
pub tool_output_token_limit: Option<usize>,
|
||||
|
||||
/// User-configured maximum number of agent threads that can be open concurrently.
|
||||
/// Whether multi-agent tools are enabled through `[agents]`.
|
||||
pub agents_enabled: bool,
|
||||
|
||||
/// User-configured maximum number of spawned agent threads per session.
|
||||
pub agent_max_threads: Option<usize>,
|
||||
|
||||
/// Reserved setting for whether the spawn tool supports agent types.
|
||||
pub agent_support_agent_type: Option<bool>,
|
||||
|
||||
/// Reserved default model for spawned subagents.
|
||||
pub agent_default_subagent_model: Option<String>,
|
||||
|
||||
/// Reserved default reasoning effort for spawned subagents.
|
||||
pub agent_default_subagent_reasoning_effort: Option<ReasoningEffort>,
|
||||
|
||||
/// Maximum runtime in seconds for agent job workers before they are failed.
|
||||
pub agent_job_max_runtime_seconds: Option<u64>,
|
||||
|
||||
/// Whether to record a model-visible message when an agent turn is interrupted.
|
||||
pub agent_interrupt_message_enabled: bool,
|
||||
|
||||
/// Maximum nesting depth allowed for spawned agent threads.
|
||||
/// Maximum nesting depth for V1 agent threads. Ignored by V2.
|
||||
pub agent_max_depth: i32,
|
||||
|
||||
/// User-defined role declarations keyed by role name.
|
||||
@@ -1420,25 +1433,33 @@ impl ConfigBuilder {
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub(crate) fn multi_agent_version_from_features(&self) -> MultiAgentVersion {
|
||||
pub(crate) fn multi_agent_version_override(&self) -> Option<MultiAgentVersion> {
|
||||
if self.features.enabled(Feature::MultiAgentV2) {
|
||||
MultiAgentVersion::V2
|
||||
} else if self.features.enabled(Feature::Collab) {
|
||||
MultiAgentVersion::V1
|
||||
Some(MultiAgentVersion::V2)
|
||||
} else if !self.agents_enabled {
|
||||
Some(MultiAgentVersion::Disabled)
|
||||
} else {
|
||||
MultiAgentVersion::Disabled
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn validate_multi_agent_v2_config(&self) -> std::io::Result<()> {
|
||||
if self.features.enabled(Feature::MultiAgentV2) && self.agent_max_threads.is_some() {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"agents.max_threads cannot be set when features.multi_agent_v2 is enabled",
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
pub(crate) fn multi_agent_version_from_features(&self) -> MultiAgentVersion {
|
||||
self.multi_agent_version_override().unwrap_or_else(|| {
|
||||
if self.features.enabled(Feature::Collab) {
|
||||
MultiAgentVersion::V1
|
||||
} else {
|
||||
MultiAgentVersion::Disabled
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn multi_agent_version_for_model(
|
||||
&self,
|
||||
model_multi_agent_version: Option<MultiAgentVersion>,
|
||||
) -> MultiAgentVersion {
|
||||
self.multi_agent_version_override()
|
||||
.or(model_multi_agent_version)
|
||||
.unwrap_or_else(|| self.multi_agent_version_from_features())
|
||||
}
|
||||
|
||||
pub(crate) fn effective_agent_max_threads(
|
||||
@@ -2516,6 +2537,13 @@ fn resolve_multi_agent_v2_config(config_toml: &ConfigToml) -> MultiAgentV2Config
|
||||
let base = multi_agent_v2_toml_config(config_toml.features.as_ref());
|
||||
let max_concurrent_threads_per_session = base
|
||||
.and_then(|config| config.max_concurrent_threads_per_session)
|
||||
.or_else(|| {
|
||||
config_toml
|
||||
.agents
|
||||
.as_ref()
|
||||
.and_then(|agents| agents.max_concurrent_threads_per_session)
|
||||
.map(|max_threads| max_threads.saturating_add(1))
|
||||
})
|
||||
.unwrap_or(DEFAULT_MULTI_AGENT_V2_MAX_CONCURRENT_THREADS_PER_SESSION);
|
||||
let default =
|
||||
MultiAgentV2Config::defaults_for_max_concurrency(max_concurrent_threads_per_session);
|
||||
@@ -3558,11 +3586,19 @@ impl Config {
|
||||
));
|
||||
}
|
||||
validate_multi_agent_v2_tool_namespace(multi_agent_v2.tool_namespace.as_deref())?;
|
||||
let agent_max_threads = cfg.agents.as_ref().and_then(|agents| agents.max_threads);
|
||||
let agents_enabled = cfg
|
||||
.agents
|
||||
.as_ref()
|
||||
.and_then(|agents| agents.enabled)
|
||||
.unwrap_or(true);
|
||||
let agent_max_threads = cfg
|
||||
.agents
|
||||
.as_ref()
|
||||
.and_then(|agents| agents.max_concurrent_threads_per_session);
|
||||
if agent_max_threads == Some(0) {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"agents.max_threads must be at least 1",
|
||||
"agents.max_concurrent_threads_per_session must be at least 1",
|
||||
));
|
||||
}
|
||||
let agent_max_depth = cfg
|
||||
@@ -3570,12 +3606,18 @@ impl Config {
|
||||
.as_ref()
|
||||
.and_then(|agents| agents.max_depth)
|
||||
.unwrap_or(DEFAULT_AGENT_MAX_DEPTH);
|
||||
if agent_max_depth < 1 {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
"agents.max_depth must be at least 1",
|
||||
));
|
||||
}
|
||||
let agent_support_agent_type = cfg
|
||||
.agents
|
||||
.as_ref()
|
||||
.and_then(|agents| agents.support_agent_type);
|
||||
let agent_default_subagent_model = cfg
|
||||
.agents
|
||||
.as_ref()
|
||||
.and_then(|agents| agents.default_subagent_model.clone());
|
||||
let agent_default_subagent_reasoning_effort = cfg
|
||||
.agents
|
||||
.as_ref()
|
||||
.and_then(|agents| agents.default_subagent_reasoning_effort.clone());
|
||||
let agent_job_max_runtime_seconds = cfg
|
||||
.agents
|
||||
.as_ref()
|
||||
@@ -3926,7 +3968,11 @@ impl Config {
|
||||
})
|
||||
.collect(),
|
||||
tool_output_token_limit: cfg.tool_output_token_limit,
|
||||
agents_enabled,
|
||||
agent_max_threads,
|
||||
agent_support_agent_type,
|
||||
agent_default_subagent_model,
|
||||
agent_default_subagent_reasoning_effort,
|
||||
agent_max_depth,
|
||||
agent_roles,
|
||||
memories: memories_config,
|
||||
|
||||
@@ -177,14 +177,13 @@ fn save_config_resolved_fields(
|
||||
)?);
|
||||
|
||||
let agents = lock_config.agents.get_or_insert_with(Default::default);
|
||||
// Multi-agent v2 owns thread fanout through its feature config. Preserve
|
||||
// the legacy agents.max_threads setting only when v2 is disabled.
|
||||
agents.max_threads = if config.features.enabled(Feature::MultiAgentV2) {
|
||||
None
|
||||
} else {
|
||||
config.agent_max_threads
|
||||
};
|
||||
agents.enabled = Some(config.agents_enabled);
|
||||
agents.max_concurrent_threads_per_session = config.agent_max_threads;
|
||||
agents.max_depth = Some(config.agent_max_depth);
|
||||
agents.support_agent_type = config.agent_support_agent_type;
|
||||
agents.default_subagent_model = config.agent_default_subagent_model.clone();
|
||||
agents.default_subagent_reasoning_effort =
|
||||
config.agent_default_subagent_reasoning_effort.clone();
|
||||
agents.job_max_runtime_seconds = config.agent_job_max_runtime_seconds;
|
||||
agents.interrupt_message = Some(config.agent_interrupt_message_enabled);
|
||||
|
||||
@@ -295,7 +294,6 @@ mod tests {
|
||||
.is_none_or(|debug| debug.config_lockfile.is_none())
|
||||
);
|
||||
assert!(lock.memories.is_some());
|
||||
|
||||
let features = lock
|
||||
.features
|
||||
.as_ref()
|
||||
|
||||
@@ -599,14 +599,12 @@ impl Session {
|
||||
let model_info = models_manager
|
||||
.get_model_info(model.as_str(), &config.to_models_manager_config())
|
||||
.await;
|
||||
let multi_agent_version =
|
||||
resolve_multi_agent_version(&conversation_history, inherited_multi_agent_version);
|
||||
let multi_agent_version = config.multi_agent_version_override().or_else(|| {
|
||||
resolve_multi_agent_version(&conversation_history, inherited_multi_agent_version)
|
||||
});
|
||||
let history_mode = conversation_history.get_history_mode(
|
||||
requested_history_mode.unwrap_or_else(|| thread_store.default_history_mode()),
|
||||
);
|
||||
config
|
||||
.validate_multi_agent_v2_config()
|
||||
.map_err(|err| CodexErr::InvalidRequest(err.to_string()))?;
|
||||
let base_instructions = config
|
||||
.base_instructions
|
||||
.clone()
|
||||
@@ -3074,12 +3072,10 @@ impl Session {
|
||||
config: &Config,
|
||||
) -> MultiAgentVersion {
|
||||
if let Some(multi_agent_version) = self.multi_agent_version() {
|
||||
return multi_agent_version;
|
||||
return config.multi_agent_version_for_model(Some(multi_agent_version));
|
||||
}
|
||||
|
||||
let selected = model_info
|
||||
.multi_agent_version
|
||||
.unwrap_or_else(|| config.multi_agent_version_from_features());
|
||||
let selected = config.multi_agent_version_for_model(model_info.multi_agent_version);
|
||||
|
||||
self.set_multi_agent_version_if_unset(selected)
|
||||
}
|
||||
|
||||
@@ -737,10 +737,10 @@ impl Session {
|
||||
TurnMultiAgentRuntime::ResolveAndStore => {
|
||||
self.resolve_multi_agent_version_for_model(&model_info, &per_turn_config)
|
||||
}
|
||||
TurnMultiAgentRuntime::Preview => self
|
||||
.multi_agent_version()
|
||||
.or(model_info.multi_agent_version)
|
||||
.unwrap_or_else(|| per_turn_config.multi_agent_version_from_features()),
|
||||
TurnMultiAgentRuntime::Preview => per_turn_config.multi_agent_version_for_model(
|
||||
self.multi_agent_version()
|
||||
.or(model_info.multi_agent_version),
|
||||
),
|
||||
};
|
||||
let plugins_input = per_turn_config.plugins_config_input();
|
||||
let plugin_outcome = self
|
||||
|
||||
@@ -1224,6 +1224,9 @@ impl ThreadManagerState {
|
||||
forked_from_thread_id: Option<ThreadId>,
|
||||
config: &Config,
|
||||
) -> MultiAgentVersion {
|
||||
if let Some(multi_agent_version) = config.multi_agent_version_override() {
|
||||
return multi_agent_version;
|
||||
}
|
||||
self.initial_multi_agent_version_for_spawn(
|
||||
initial_history,
|
||||
session_source,
|
||||
|
||||
@@ -61,6 +61,8 @@ async fn handle_spawn_agent(
|
||||
let child_depth = next_thread_spawn_depth(&session_source);
|
||||
let mut config =
|
||||
build_agent_spawn_config(&session.get_base_instructions().await, turn.as_ref())?;
|
||||
// TODO(jif): Apply `agents.default_subagent_model` as the default model here.
|
||||
// TODO(jif): Apply `agents.default_subagent_reasoning_effort` as the default effort here.
|
||||
if let Some(service_tier) = args.service_tier.as_ref() {
|
||||
config.service_tier = Some(service_tier.clone());
|
||||
}
|
||||
|
||||
@@ -798,6 +798,7 @@ fn add_collaboration_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mu
|
||||
.flatten();
|
||||
let agent_type_description =
|
||||
agent_type_description(turn_context, context.default_agent_type_description);
|
||||
// TODO(jif): Wire `agents.support_agent_type` into the V2 spawn tool surface.
|
||||
planned_tools.add_arc(override_tool_exposure(
|
||||
multi_agent_v2_handler(
|
||||
SpawnAgentHandlerV2::new(SpawnAgentToolOptions {
|
||||
|
||||
Reference in New Issue
Block a user