Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions codex-rs/core/src/memories/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ async fn write_rollout_summary_for_thread(
writeln!(body, "rollout_path: {}", memory.rollout_path.display())
.map_err(rollout_summary_format_error)?;
writeln!(body, "cwd: {}", memory.cwd.display()).map_err(rollout_summary_format_error)?;
if let Some(git_branch) = memory.git_branch.as_deref() {
writeln!(body, "git_branch: {git_branch}").map_err(rollout_summary_format_error)?;
}
writeln!(body).map_err(rollout_summary_format_error)?;
body.push_str(&memory.rollout_summary);
body.push('\n');
Expand Down Expand Up @@ -273,6 +276,7 @@ mod tests {
rollout_slug: rollout_slug.map(ToString::to_string),
rollout_path: PathBuf::from("/tmp/rollout.jsonl"),
cwd: PathBuf::from("/tmp/workspace"),
git_branch: None,
generated_at: Utc.timestamp_opt(124, 0).single().expect("timestamp"),
}
}
Expand Down
5 changes: 5 additions & 0 deletions codex-rs/core/src/memories/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ async fn sync_rollout_summaries_and_raw_memories_file_keeps_latest_memories_only
rollout_slug: None,
rollout_path: PathBuf::from("/tmp/rollout-100.jsonl"),
cwd: PathBuf::from("/tmp/workspace"),
git_branch: None,
generated_at: Utc.timestamp_opt(101, 0).single().expect("timestamp"),
}];

Expand Down Expand Up @@ -193,6 +194,7 @@ async fn sync_rollout_summaries_uses_timestamp_hash_and_sanitized_slug_filename(
rollout_slug: Some("Unsafe Slug/With Spaces & Symbols + EXTRA_LONG_12345".to_string()),
rollout_path: PathBuf::from("/tmp/rollout-200.jsonl"),
cwd: PathBuf::from("/tmp/workspace"),
git_branch: Some("feature/memory-branch".to_string()),
generated_at: Utc.timestamp_opt(201, 0).single().expect("timestamp"),
}];

Expand Down Expand Up @@ -248,6 +250,7 @@ async fn sync_rollout_summaries_uses_timestamp_hash_and_sanitized_slug_filename(
.expect("read rollout summary");
assert!(summary.contains(&format!("thread_id: {thread_id}")));
assert!(summary.contains("rollout_path: /tmp/rollout-200.jsonl"));
assert!(summary.contains("git_branch: feature/memory-branch"));
assert!(
!tokio::fs::try_exists(&stale_unslugged_path)
.await
Expand Down Expand Up @@ -294,6 +297,7 @@ task_outcome: success
rollout_slug: Some("Unsafe Slug/With Spaces & Symbols + EXTRA_LONG_12345".to_string()),
rollout_path: PathBuf::from("/tmp/rollout-200.jsonl"),
cwd: PathBuf::from("/tmp/workspace"),
git_branch: None,
generated_at: Utc.timestamp_opt(201, 0).single().expect("timestamp"),
}];

Expand Down Expand Up @@ -378,6 +382,7 @@ mod phase2 {
rollout_slug: None,
rollout_path: PathBuf::from("/tmp/rollout-summary.jsonl"),
cwd: PathBuf::from("/tmp/workspace"),
git_branch: None,
generated_at: chrono::DateTime::<Utc>::from_timestamp(source_updated_at + 1, 0)
.expect("valid generated_at timestamp"),
}
Expand Down
7 changes: 7 additions & 0 deletions codex-rs/core/tests/suite/memories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ async fn memories_startup_phase2_tracks_added_and_removed_inputs_across_runs() -
let rollout_summaries = read_rollout_summary_bodies(&memory_root).await?;
assert_eq!(rollout_summaries.len(), 1);
assert!(rollout_summaries[0].contains("rollout summary A"));
assert!(rollout_summaries[0].contains("git_branch: branch-rollout-a"));

shutdown_test_codex(&first).await?;

Expand Down Expand Up @@ -141,6 +142,11 @@ async fn memories_startup_phase2_tracks_added_and_removed_inputs_across_runs() -
.iter()
.any(|summary| summary.contains("rollout summary B"))
);
assert!(
rollout_summaries
.iter()
.any(|summary| summary.contains("git_branch: branch-rollout-b"))
);
assert!(
rollout_summaries
.iter()
Expand Down Expand Up @@ -185,6 +191,7 @@ async fn seed_stage1_output(
);
metadata_builder.cwd = codex_home.join(format!("workspace-{rollout_slug}"));
metadata_builder.model_provider = Some("test-provider".to_string());
metadata_builder.git_branch = Some(format!("branch-{rollout_slug}"));
let metadata = metadata_builder.build("test-provider");
db.upsert_thread(&metadata).await?;

Expand Down
4 changes: 4 additions & 0 deletions codex-rs/state/src/model/memories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub struct Stage1Output {
pub rollout_summary: String,
pub rollout_slug: Option<String>,
pub cwd: PathBuf,
pub git_branch: Option<String>,
pub generated_at: DateTime<Utc>,
}

Expand Down Expand Up @@ -45,6 +46,7 @@ pub(crate) struct Stage1OutputRow {
rollout_summary: String,
rollout_slug: Option<String>,
cwd: String,
git_branch: Option<String>,
generated_at: i64,
}

Expand All @@ -58,6 +60,7 @@ impl Stage1OutputRow {
rollout_summary: row.try_get("rollout_summary")?,
rollout_slug: row.try_get("rollout_slug")?,
cwd: row.try_get("cwd")?,
git_branch: row.try_get("git_branch")?,
generated_at: row.try_get("generated_at")?,
})
}
Expand All @@ -75,6 +78,7 @@ impl TryFrom<Stage1OutputRow> for Stage1Output {
rollout_summary: row.rollout_summary,
rollout_slug: row.rollout_slug,
cwd: PathBuf::from(row.cwd),
git_branch: row.git_branch,
generated_at: epoch_seconds_to_datetime(row.generated_at)?,
})
}
Expand Down
30 changes: 17 additions & 13 deletions codex-rs/state/src/runtime/memories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ LEFT JOIN jobs
///
/// Query behavior:
/// - filters out rows where both `raw_memory` and `rollout_summary` are blank
/// - joins `threads` to include thread `cwd` and `rollout_path`
/// - joins `threads` to include thread `cwd`, `rollout_path`, and `git_branch`
/// - orders by `source_updated_at DESC, thread_id DESC`
/// - applies `LIMIT n`
pub async fn list_stage1_outputs_for_global(
Expand All @@ -244,8 +244,9 @@ SELECT
so.raw_memory,
so.rollout_summary,
so.rollout_slug,
so.generated_at
, COALESCE(t.cwd, '') AS cwd
so.generated_at,
COALESCE(t.cwd, '') AS cwd,
t.git_branch AS git_branch
FROM stage1_outputs AS so
LEFT JOIN threads AS t
ON t.id = so.thread_id
Expand Down Expand Up @@ -301,9 +302,10 @@ SELECT
so.rollout_summary,
so.rollout_slug,
so.generated_at,
COALESCE(t.cwd, '') AS cwd,
t.git_branch AS git_branch,
so.selected_for_phase2,
so.selected_for_phase2_source_updated_at,
COALESCE(t.cwd, '') AS cwd
so.selected_for_phase2_source_updated_at
FROM stage1_outputs AS so
LEFT JOIN threads AS t
ON t.id = so.thread_id
Expand Down Expand Up @@ -352,9 +354,10 @@ SELECT
so.source_updated_at,
so.raw_memory,
so.rollout_summary,
so.rollout_slug
, so.generated_at
, COALESCE(t.cwd, '') AS cwd
so.rollout_slug,
so.generated_at,
COALESCE(t.cwd, '') AS cwd,
t.git_branch AS git_branch
FROM stage1_outputs AS so
LEFT JOIN threads AS t
ON t.id = so.thread_id
Expand Down Expand Up @@ -2215,12 +2218,11 @@ WHERE kind = 'memory_stage1'
))
.await
.expect("upsert thread a");
let mut metadata_b =
test_thread_metadata(&codex_home, thread_id_b, codex_home.join("workspace-b"));
metadata_b.git_branch = Some("feature/stage1-b".to_string());
runtime
.upsert_thread(&test_thread_metadata(
&codex_home,
thread_id_b,
codex_home.join("workspace-b"),
))
.upsert_thread(&metadata_b)
.await
.expect("upsert thread b");

Expand Down Expand Up @@ -2279,10 +2281,12 @@ WHERE kind = 'memory_stage1'
assert_eq!(outputs[0].rollout_summary, "summary b");
assert_eq!(outputs[0].rollout_slug.as_deref(), Some("rollout-b"));
assert_eq!(outputs[0].cwd, codex_home.join("workspace-b"));
assert_eq!(outputs[0].git_branch.as_deref(), Some("feature/stage1-b"));
assert_eq!(outputs[1].thread_id, thread_id_a);
assert_eq!(outputs[1].rollout_summary, "summary a");
assert_eq!(outputs[1].rollout_slug, None);
assert_eq!(outputs[1].cwd, codex_home.join("workspace-a"));
assert_eq!(outputs[1].git_branch, None);

let _ = tokio::fs::remove_dir_all(codex_home).await;
}
Expand Down
Loading