Preserve selected roots in bounded agent forks

This commit is contained in:
jif-oai
2026-06-25 15:32:30 +01:00
parent 740c8d8fcc
commit 5fdac29fc6
3 changed files with 54 additions and 2 deletions

View File

@@ -1,5 +1,6 @@
use super::residency::is_v2_resident_session_source;
use super::*;
use codex_extension_api::ExtensionDataInit;
const AGENT_NAMES: &str = include_str!("../agent_names.txt");
@@ -433,6 +434,16 @@ impl AgentControl {
))
})?;
let selected_capability_roots = parent_history
.items
.iter()
.find_map(|item| {
let RolloutItem::SessionMeta(meta_line) = item else {
return None;
};
Some(meta_line.meta.selected_capability_roots.clone())
})
.unwrap_or_default();
let mut forked_rollout_items = parent_history.items;
if let SpawnAgentForkMode::LastNTurns(last_n_turns) = fork_mode {
forked_rollout_items =
@@ -504,6 +515,8 @@ impl AgentControl {
{
forked_rollout_items.push(RolloutItem::ResponseItem(subagent_usage_hint_message));
}
let mut thread_extension_init = ExtensionDataInit::new();
thread_extension_init.insert(selected_capability_roots);
state
.fork_thread_with_source(
@@ -517,6 +530,7 @@ impl AgentControl {
inherited_environments,
inherited_exec_policy,
options.environments.clone(),
thread_extension_init,
)
.await
}

View File

@@ -17,6 +17,8 @@ use codex_features::Feature;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_protocol::AgentPath;
use codex_protocol::capabilities::CapabilityRootLocation;
use codex_protocol::capabilities::SelectedCapabilityRoot;
use codex_protocol::config_types::ModeKind;
use codex_protocol::models::ContentItem;
use codex_protocol::models::MessagePhase;
@@ -38,6 +40,7 @@ use codex_thread_store::InMemoryThreadStore;
use codex_thread_store::LocalThreadStore;
use codex_thread_store::LocalThreadStoreConfig;
use codex_thread_store::ThreadStore;
use codex_utils_path_uri::PathUri;
use pretty_assertions::assert_eq;
use tempfile::TempDir;
use tokio::time::Duration;
@@ -1446,7 +1449,33 @@ async fn spawn_agent_fork_last_n_turns_keeps_only_recent_turns() {
#[tokio::test]
async fn spawn_agent_fork_last_n_turns_drops_parent_startup_prefix_when_under_limit() {
let harness = AgentControlHarness::new().await;
let (parent_thread_id, parent_thread) = harness.start_thread().await;
let selected_capability_roots = vec![SelectedCapabilityRoot {
id: "demo@1".to_string(),
location: CapabilityRootLocation::Environment {
environment_id: "build".to_string(),
path: PathUri::parse("file:///plugins/demo").expect("plugin root URI"),
},
}];
let mut thread_extension_init = ExtensionDataInit::new();
thread_extension_init.insert(selected_capability_roots.clone());
let parent = harness
.manager
.start_thread_with_options(StartThreadOptions {
config: harness.config.clone(),
initial_history: InitialHistory::New,
session_source: None,
thread_source: None,
dynamic_tools: Vec::new(),
metrics_service_name: None,
parent_trace: None,
environments: Vec::new(),
thread_extension_init,
supports_openai_form_elicitation: false,
})
.await
.expect("start parent thread");
let parent_thread_id = parent.thread_id;
let parent_thread = parent.thread;
let startup_turn_context = parent_thread.codex.session.new_default_turn().await;
parent_thread
.codex
@@ -1525,6 +1554,14 @@ async fn spawn_agent_fork_last_n_turns_drops_parent_startup_prefix_when_under_li
!history_contains_text(history.raw_items(), "parent startup developer context"),
"bounded fork should drop parent startup context even when fewer turns exist than requested"
);
assert_eq!(
&child_thread
.codex
.session
.services
.selected_capability_roots,
&selected_capability_roots
);
assert!(
child_thread
.codex

View File

@@ -1402,6 +1402,7 @@ impl ThreadManagerState {
inherited_environments: Option<TurnEnvironmentSnapshot>,
inherited_exec_policy: Option<Arc<crate::exec_policy::ExecPolicyManager>>,
environments: Option<Vec<TurnEnvironmentSelection>>,
thread_extension_init: ExtensionDataInit,
) -> CodexResult<NewThread> {
let environments = environments.unwrap_or_else(|| {
default_thread_environment_selections(self.environment_manager.as_ref(), &config.cwd)
@@ -1421,7 +1422,7 @@ impl ThreadManagerState {
inherited_exec_policy,
/*parent_trace*/ None,
environments,
/*thread_extension_init*/ ExtensionDataInit::default(),
thread_extension_init,
/*supports_openai_form_elicitation*/ false,
/*user_shell_override*/ None,
))