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
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ async fn external_agent_config_secondary_source_imports_session_and_plugin_end_t
"message": {
"content": [{
"type": "text",
"text": "<user_query>first request</user_query>"
"text": "<cursor_commands>\n/verify\n</cursor_commands>\n<timestamp>2026-07-26T18:00:00Z</timestamp>\n<user_query>first request</user_query>"
}]
}
})
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/external-agent-migration/src/detect/sessions/cla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::common::SessionFileCandidate;
use super::common::detect_recent_sessions;
use crate::model::ExternalAgentSessionImportLimits;
use crate::sessions::ExternalAgentSessionMigration;
use crate::sessions::SessionRecordFormat;
use std::fs;
use std::io;
use std::path::Path;
Expand Down Expand Up @@ -50,6 +51,7 @@ pub(crate) fn detect_recent_cla_sessions_with_limits(
candidates.push(SessionFileCandidate {
path,
fallback_cwd: None,
record_format: SessionRecordFormat::Cla,
});
}
}
Expand Down
16 changes: 13 additions & 3 deletions codex-rs/external-agent-migration/src/detect/sessions/common.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::model::ExternalAgentSessionImportLimits;
use crate::sessions::ExternalAgentSessionMigration;
use crate::sessions::SessionRecordFormat;
use crate::sessions::ledger::load_import_ledger;
use crate::sessions::ledger::save_import_ledger;
use crate::sessions::now_unix_seconds;
use crate::sessions::records::summarize_session_with_cwd;
use crate::sessions::records_cla;
use crate::sessions::records_cur;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::fs;
Expand All @@ -14,6 +16,7 @@ use std::path::PathBuf;
pub(super) struct SessionFileCandidate {
pub path: PathBuf,
pub fallback_cwd: Option<PathBuf>,
pub record_format: SessionRecordFormat,
}

pub(super) fn detect_recent_sessions(
Expand Down Expand Up @@ -57,6 +60,7 @@ pub(super) fn detect_recent_sessions(
Reverse(modified_at_nanos),
candidate.path,
candidate.fallback_cwd,
candidate.record_format,
));
if recent.len() > limits.max_sessions {
recent.pop();
Expand All @@ -66,7 +70,7 @@ pub(super) fn detect_recent_sessions(
drop(source_states);
let mut migrations = Vec::new();
let mut ledger_changed = false;
for (modified_at, path, fallback_cwd) in recent.into_sorted_vec() {
for (modified_at, path, fallback_cwd, record_format) in recent.into_sorted_vec() {
match ledger.refresh_current_source(&path, modified_at.0) {
Ok(false) => {}
Ok(true) => {
Expand All @@ -75,7 +79,13 @@ pub(super) fn detect_recent_sessions(
}
Err(_) => continue,
}
let Ok(Some(summary)) = summarize_session_with_cwd(&path, fallback_cwd.as_deref()) else {
let summary = match record_format {
SessionRecordFormat::Cla => records_cla::summarize_session(&path),
SessionRecordFormat::Cur => {
records_cur::summarize_session(&path, fallback_cwd.as_deref())
}
};
let Ok(Some(summary)) = summary else {
continue;
};
if require_existing_cwd && !summary.migration.cwd.is_dir() {
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/external-agent-migration/src/detect/sessions/cur.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::common::SessionFileCandidate;
use super::common::detect_recent_sessions;
use crate::model::ExternalAgentSessionImportLimits;
use crate::sessions::ExternalAgentSessionMigration;
use crate::sessions::SessionRecordFormat;
use std::fs;
use std::io;
use std::path::Path;
Expand Down Expand Up @@ -42,6 +43,7 @@ pub(crate) fn detect_recent_cur_sessions_with_limits(
candidates.push(SessionFileCandidate {
path,
fallback_cwd: fallback_cwd.clone(),
record_format: SessionRecordFormat::Cur,
});
}
}
Expand Down
20 changes: 14 additions & 6 deletions codex-rs/external-agent-migration/src/sessions/export.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::ConversationMessage;
use super::ImportedExternalAgentSession;
use super::MessageRole;
use super::records::read_session_import_with_cwd;
use super::SessionRecordFormat;
use super::records_cla;
use super::records_cur;
use super::summarize_for_label;
use super::title::IMPORTED_SESSION_FALLBACK_TITLE;
use super::title::SessionTitleCandidates;
Expand All @@ -26,17 +28,23 @@ const EXTERNAL_SESSION_IMPORTED_MARKER: &str = "<EXTERNAL SESSION IMPORTED>";

#[cfg(test)]
fn load_session_for_import(path: &Path) -> io::Result<Option<ImportedExternalAgentSession>> {
Ok(
load_session_for_import_with_content_sha256(path, /*fallback_cwd*/ None)?
.map(|(session, _content_sha256, _attributed_mcp_server_ids)| session),
)
Ok(load_session_for_import_with_content_sha256(
path,
SessionRecordFormat::Cla,
/*fallback_cwd*/ None,
)?
.map(|(session, _content_sha256, _attributed_mcp_server_ids)| session))
}

pub(crate) fn load_session_for_import_with_content_sha256(
path: &Path,
record_format: SessionRecordFormat,
fallback_cwd: Option<&Path>,
) -> io::Result<Option<(ImportedExternalAgentSession, String, BTreeSet<String>)>> {
let parsed = read_session_import_with_cwd(path, fallback_cwd)?;
let parsed = match record_format {
SessionRecordFormat::Cla => records_cla::read_session_import(path)?,
SessionRecordFormat::Cur => records_cur::read_session_import(path, fallback_cwd)?,
};
let Some(cwd) = parsed.cwd else {
return Ok(None);
};
Expand Down
35 changes: 28 additions & 7 deletions codex-rs/external-agent-migration/src/sessions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

mod export;
pub(crate) mod ledger;
pub(crate) mod records;
pub(crate) mod records_cla;
mod records_common;
pub(crate) mod records_cur;
mod title;

use codex_protocol::protocol::RolloutItem;
Expand All @@ -21,11 +23,30 @@ pub use ledger::ImportedConnectorCandidate;
pub use ledger::has_current_session_been_imported;
pub use ledger::read_imported_connector_candidates;
pub use ledger::record_completed_session_imports;
pub use records::SessionSummary;
pub use records::summarize_session;
pub use records_cla::summarize_session;

const SESSION_TITLE_MAX_LEN: usize = 120;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum SessionRecordFormat {
Cla,
Cur,
}

pub struct SessionSummary {
pub latest_timestamp: i64,
pub migration: ExternalAgentSessionMigration,
}

struct ParsedSessionImport {
cwd: Option<PathBuf>,
custom_title: Option<String>,
ai_title: Option<String>,
messages: Vec<ConversationMessage>,
content_sha256: String,
attributed_mcp_server_ids: BTreeSet<String>,
}

pub(crate) fn normalized_connector_display_name(name: Option<&str>) -> Option<String> {
name.map(str::trim)
.filter(|name| !name.is_empty())
Expand Down Expand Up @@ -93,12 +114,12 @@ fn load_importable_session(
metadata_mode: SessionMetadataMode,
) -> io::Result<Option<PendingSessionImport>> {
let source_path = std::fs::canonicalize(path)?;
let fallback_cwd = match metadata_mode {
SessionMetadataMode::Embedded => None,
SessionMetadataMode::MigrationFallback => Some(fallback_cwd),
let (record_format, fallback_cwd) = match metadata_mode {
SessionMetadataMode::Embedded => (SessionRecordFormat::Cla, None),
SessionMetadataMode::MigrationFallback => (SessionRecordFormat::Cur, Some(fallback_cwd)),
};
let Some((imported_session, source_content_sha256, attributed_mcp_server_ids)) =
load_session_for_import_with_content_sha256(&source_path, fallback_cwd)?
load_session_for_import_with_content_sha256(&source_path, record_format, fallback_cwd)?
else {
return Ok(None);
};
Expand Down
Loading
Loading