mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
fix: do not apply turn cwd to metadata (#12887)
Details here: https://openai.slack.com/archives/C09NZ54M4KY/p1772056758227339
This commit is contained in:
@@ -326,7 +326,9 @@ impl RolloutRecorder {
|
||||
else {
|
||||
break;
|
||||
};
|
||||
if let Some(path) = select_resume_path_from_db_page(&db_page, filter_cwd) {
|
||||
if let Some(path) =
|
||||
select_resume_path_from_db_page(&db_page, filter_cwd, default_provider).await
|
||||
{
|
||||
return Ok(Some(path));
|
||||
}
|
||||
db_cursor = db_page.next_anchor.map(Into::into);
|
||||
@@ -348,7 +350,7 @@ impl RolloutRecorder {
|
||||
default_provider,
|
||||
)
|
||||
.await?;
|
||||
if let Some(path) = select_resume_path(&page, filter_cwd) {
|
||||
if let Some(path) = select_resume_path(&page, filter_cwd, default_provider).await {
|
||||
return Ok(Some(path));
|
||||
}
|
||||
cursor = page.next_cursor;
|
||||
@@ -961,35 +963,79 @@ impl From<codex_state::ThreadsPage> for ThreadsPage {
|
||||
}
|
||||
}
|
||||
|
||||
fn select_resume_path(page: &ThreadsPage, filter_cwd: Option<&Path>) -> Option<PathBuf> {
|
||||
async fn select_resume_path(
|
||||
page: &ThreadsPage,
|
||||
filter_cwd: Option<&Path>,
|
||||
default_provider: &str,
|
||||
) -> Option<PathBuf> {
|
||||
match filter_cwd {
|
||||
Some(cwd) => page.items.iter().find_map(|item| {
|
||||
if item
|
||||
.cwd
|
||||
.as_ref()
|
||||
.is_some_and(|session_cwd| cwd_matches(session_cwd, cwd))
|
||||
{
|
||||
Some(item.path.clone())
|
||||
} else {
|
||||
None
|
||||
Some(cwd) => {
|
||||
for item in &page.items {
|
||||
if resume_candidate_matches_cwd(
|
||||
item.path.as_path(),
|
||||
item.cwd.as_deref(),
|
||||
cwd,
|
||||
default_provider,
|
||||
)
|
||||
.await
|
||||
{
|
||||
return Some(item.path.clone());
|
||||
}
|
||||
}
|
||||
}),
|
||||
None
|
||||
}
|
||||
None => page.items.first().map(|item| item.path.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn select_resume_path_from_db_page(
|
||||
async fn resume_candidate_matches_cwd(
|
||||
rollout_path: &Path,
|
||||
cached_cwd: Option<&Path>,
|
||||
cwd: &Path,
|
||||
default_provider: &str,
|
||||
) -> bool {
|
||||
if cached_cwd.is_some_and(|session_cwd| cwd_matches(session_cwd, cwd)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Ok((items, _, _)) = RolloutRecorder::load_rollout_items(rollout_path).await
|
||||
&& let Some(latest_turn_context_cwd) = items.iter().rev().find_map(|item| match item {
|
||||
RolloutItem::TurnContext(turn_context) => Some(turn_context.cwd.as_path()),
|
||||
RolloutItem::SessionMeta(_)
|
||||
| RolloutItem::ResponseItem(_)
|
||||
| RolloutItem::Compacted(_)
|
||||
| RolloutItem::EventMsg(_) => None,
|
||||
})
|
||||
{
|
||||
return cwd_matches(latest_turn_context_cwd, cwd);
|
||||
}
|
||||
|
||||
metadata::extract_metadata_from_rollout(rollout_path, default_provider, None)
|
||||
.await
|
||||
.is_ok_and(|outcome| cwd_matches(outcome.metadata.cwd.as_path(), cwd))
|
||||
}
|
||||
|
||||
async fn select_resume_path_from_db_page(
|
||||
page: &codex_state::ThreadsPage,
|
||||
filter_cwd: Option<&Path>,
|
||||
default_provider: &str,
|
||||
) -> Option<PathBuf> {
|
||||
match filter_cwd {
|
||||
Some(cwd) => page.items.iter().find_map(|item| {
|
||||
if cwd_matches(item.cwd.as_path(), cwd) {
|
||||
Some(item.rollout_path.clone())
|
||||
} else {
|
||||
None
|
||||
Some(cwd) => {
|
||||
for item in &page.items {
|
||||
if resume_candidate_matches_cwd(
|
||||
item.rollout_path.as_path(),
|
||||
Some(item.cwd.as_path()),
|
||||
cwd,
|
||||
default_provider,
|
||||
)
|
||||
.await
|
||||
{
|
||||
return Some(item.rollout_path.clone());
|
||||
}
|
||||
}
|
||||
}),
|
||||
None
|
||||
}
|
||||
None => page.items.first().map(|item| item.rollout_path.clone()),
|
||||
}
|
||||
}
|
||||
@@ -1010,8 +1056,12 @@ mod tests {
|
||||
use crate::config::ConfigBuilder;
|
||||
use crate::features::Feature;
|
||||
use chrono::TimeZone;
|
||||
use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig;
|
||||
use codex_protocol::protocol::AgentMessageEvent;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::TurnContextItem;
|
||||
use codex_protocol::protocol::UserMessageEvent;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::fs::File;
|
||||
@@ -1320,4 +1370,47 @@ mod tests {
|
||||
assert_eq!(repaired_path, Some(real_path));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn resume_candidate_matches_cwd_reads_latest_turn_context() -> std::io::Result<()> {
|
||||
let home = TempDir::new().expect("temp dir");
|
||||
let stale_cwd = home.path().join("stale");
|
||||
let latest_cwd = home.path().join("latest");
|
||||
fs::create_dir_all(&stale_cwd)?;
|
||||
fs::create_dir_all(&latest_cwd)?;
|
||||
|
||||
let path = write_session_file(home.path(), "2025-01-03T13-00-00", Uuid::from_u128(9012))?;
|
||||
let mut file = std::fs::OpenOptions::new().append(true).open(&path)?;
|
||||
let turn_context = RolloutLine {
|
||||
timestamp: "2025-01-03T13:00:01Z".to_string(),
|
||||
item: RolloutItem::TurnContext(TurnContextItem {
|
||||
turn_id: Some("turn-1".to_string()),
|
||||
cwd: latest_cwd.clone(),
|
||||
approval_policy: AskForApproval::Never,
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
network: None,
|
||||
model: "test-model".to_string(),
|
||||
personality: None,
|
||||
collaboration_mode: None,
|
||||
effort: None,
|
||||
summary: ReasoningSummaryConfig::Auto,
|
||||
user_instructions: None,
|
||||
developer_instructions: None,
|
||||
final_output_json_schema: None,
|
||||
truncation_policy: None,
|
||||
}),
|
||||
};
|
||||
writeln!(file, "{}", serde_json::to_string(&turn_context)?)?;
|
||||
|
||||
assert!(
|
||||
resume_candidate_matches_cwd(
|
||||
path.as_path(),
|
||||
Some(stale_cwd.as_path()),
|
||||
latest_cwd.as_path(),
|
||||
"test-provider",
|
||||
)
|
||||
.await
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user