fix(codex): preserve project root on structured resume
Recalcule la policy structured Codex lors des reprises custom/headless afin que le project root et le managed tmp soient transmis en writable_roots. Fail-closed si une session Codex structured est lancée sans policy explicite.
This commit is contained in:
@ -625,6 +625,7 @@ struct FakeStructuredFactory {
|
||||
envs: Arc<Mutex<Vec<Vec<(String, String)>>>>,
|
||||
sandboxes: Arc<Mutex<Vec<Option<domain::sandbox::SandboxPlan>>>>,
|
||||
policies: Arc<Mutex<Vec<Option<domain::ports::StructuredProviderLaunchPolicy>>>>,
|
||||
plans: Arc<Mutex<Vec<SessionPlan>>>,
|
||||
shutdowns: Arc<Mutex<Vec<SessionId>>>,
|
||||
next_session: SessionId,
|
||||
}
|
||||
@ -638,6 +639,7 @@ impl FakeStructuredFactory {
|
||||
envs: Arc::new(Mutex::new(Vec::new())),
|
||||
sandboxes: Arc::new(Mutex::new(Vec::new())),
|
||||
policies: Arc::new(Mutex::new(Vec::new())),
|
||||
plans: Arc::new(Mutex::new(Vec::new())),
|
||||
shutdowns: Arc::new(Mutex::new(Vec::new())),
|
||||
next_session,
|
||||
}
|
||||
@ -662,6 +664,10 @@ impl FakeStructuredFactory {
|
||||
fn policies(&self) -> Vec<Option<domain::ports::StructuredProviderLaunchPolicy>> {
|
||||
self.policies.lock().unwrap().clone()
|
||||
}
|
||||
|
||||
fn plans(&self) -> Vec<SessionPlan> {
|
||||
self.plans.lock().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -675,7 +681,7 @@ impl AgentSessionFactory for FakeStructuredFactory {
|
||||
profile: &AgentProfile,
|
||||
_ctx: &PreparedContext,
|
||||
_cwd: &ProjectPath,
|
||||
_session: &SessionPlan,
|
||||
session: &SessionPlan,
|
||||
_requester: Option<&str>,
|
||||
_env: &[(String, String)],
|
||||
_sandbox: Option<&domain::sandbox::SandboxPlan>,
|
||||
@ -696,6 +702,7 @@ impl AgentSessionFactory for FakeStructuredFactory {
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(structured_policy.cloned());
|
||||
self.plans.lock().unwrap().push(session.clone());
|
||||
Ok(Arc::new(FakeSession {
|
||||
id: self.next_session,
|
||||
conversation_id: Some("engine-session-1".to_owned()),
|
||||
@ -4987,7 +4994,7 @@ async fn launch_structured_non_codex_uses_managed_tmp_for_env_without_os_sandbox
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn launch_structured_codex_uses_managed_tmp_for_env_and_writable_roots_without_os_sandbox() {
|
||||
async fn custom_chat_codex_resume_recomputes_project_and_managed_tmp_writable_roots() {
|
||||
let root = fresh_temp_dir("launch-tmp-structured");
|
||||
let tmp = root.join("managed-tmp-main").to_string_lossy().into_owned();
|
||||
let store = Arc::new(FakeManagedTempStore::default());
|
||||
@ -5011,10 +5018,10 @@ async fn launch_structured_codex_uses_managed_tmp_for_env_and_writable_roots_wit
|
||||
.with_structured_routing_mode(StructuredRoutingMode::RequireStructured)
|
||||
.with_structured(Arc::new(factory.clone()), Arc::clone(&structured));
|
||||
|
||||
launch
|
||||
.execute(launch_input_with_project_root(agent.id, &root))
|
||||
.await
|
||||
.expect("structured launch");
|
||||
let mut input = launch_input_with_project_root(agent.id, &root);
|
||||
input.require_structured = true;
|
||||
input.conversation_id = Some("pair-conversation-306".to_owned());
|
||||
launch.execute(input).await.expect("structured launch");
|
||||
|
||||
assert!(pty.spawns().is_empty());
|
||||
let env = factory.envs().remove(0);
|
||||
@ -5028,7 +5035,15 @@ async fn launch_structured_codex_uses_managed_tmp_for_env_and_writable_roots_wit
|
||||
else {
|
||||
panic!("expected Codex policy");
|
||||
};
|
||||
assert!(writable_roots.contains(&tmp));
|
||||
assert_eq!(
|
||||
writable_roots,
|
||||
vec![root.to_string_lossy().into_owned(), tmp.clone()],
|
||||
"resume/custom chat policy must be rebuilt from the current project root and managed tmp"
|
||||
);
|
||||
assert!(matches!(
|
||||
factory.plans().as_slice(),
|
||||
[SessionPlan::Resume { conversation_id }] if conversation_id == "pair-conversation-306"
|
||||
));
|
||||
assert_eq!(
|
||||
factory.sandboxes(),
|
||||
vec![None],
|
||||
|
||||
Reference in New Issue
Block a user