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:
@ -1100,6 +1100,28 @@ fn self_restart_launch_input(
|
||||
}
|
||||
}
|
||||
|
||||
fn automatic_resume_launch_input(
|
||||
context: ResumeContext,
|
||||
agent_id: AgentId,
|
||||
node_id: domain::NodeId,
|
||||
conversation_id: Option<String>,
|
||||
mcp_runtime: Option<McpRuntime>,
|
||||
) -> LaunchAgentInput {
|
||||
LaunchAgentInput {
|
||||
project: context.project,
|
||||
agent_id,
|
||||
rows: context.rows,
|
||||
cols: context.cols,
|
||||
node_id: Some(node_id),
|
||||
conversation_id,
|
||||
mcp_runtime,
|
||||
allow_structured_alongside_pty: false,
|
||||
require_structured: context.require_structured,
|
||||
fresh_start: false,
|
||||
managed_temp_exposure: application::ManagedTempExposureRequest::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod self_restart_contract_tests {
|
||||
use super::*;
|
||||
@ -1137,6 +1159,42 @@ mod self_restart_contract_tests {
|
||||
assert!(!input.fresh_start);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn automatic_resume_preserves_custom_chat_structured_routing() {
|
||||
let project = Project::new(
|
||||
ProjectId::from_uuid(Uuid::from_u128(306)),
|
||||
"resume",
|
||||
domain::project::ProjectPath::new("/external/project-root").unwrap(),
|
||||
domain::remote::RemoteRef::local(),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
let agent = AgentId::from_uuid(Uuid::from_u128(1));
|
||||
let node = domain::NodeId::from_uuid(Uuid::from_u128(2));
|
||||
let input = automatic_resume_launch_input(
|
||||
ResumeContext {
|
||||
project,
|
||||
rows: 24,
|
||||
cols: 80,
|
||||
node_id: Some(node),
|
||||
conversation_id: Some("old-conversation".to_owned()),
|
||||
require_structured: true,
|
||||
},
|
||||
agent,
|
||||
node,
|
||||
Some("current-conversation".to_owned()),
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(input.require_structured);
|
||||
assert_eq!(input.node_id, Some(node));
|
||||
assert_eq!(
|
||||
input.conversation_id.as_deref(),
|
||||
Some("current-conversation")
|
||||
);
|
||||
assert!(!input.fresh_start);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn human_turn_ignores_old_terminal_and_accepts_replacement() {
|
||||
let mailbox = Arc::new(InMemoryMailbox::new());
|
||||
@ -1682,19 +1740,13 @@ impl AgentResumer for AppAgentResumer {
|
||||
|
||||
let project_id = ctx.project.id;
|
||||
self.launch_agent
|
||||
.execute(LaunchAgentInput {
|
||||
project: ctx.project,
|
||||
.execute(automatic_resume_launch_input(
|
||||
ctx,
|
||||
agent_id,
|
||||
rows: ctx.rows,
|
||||
cols: ctx.cols,
|
||||
node_id: Some(node_id),
|
||||
node_id,
|
||||
conversation_id,
|
||||
mcp_runtime,
|
||||
allow_structured_alongside_pty: false,
|
||||
require_structured: false,
|
||||
fresh_start: false,
|
||||
managed_temp_exposure: application::ManagedTempExposureRequest::default(),
|
||||
})
|
||||
))
|
||||
.await?;
|
||||
|
||||
// Premier tour de reprise par le **portail d'entrée** (pas de write brut, §20) :
|
||||
|
||||
Reference in New Issue
Block a user