mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Add external agent memory migration (#33444)
## What changed - Add a feature-gated `MEMORY` migration item to the app-server protocol and TUI. - Discover project memory Markdown files, preserve their project scope, and copy selected projects into the Codex memory extension workspace. - Detect changed, renamed, and removed source projects, report per-project import failures, and enqueue memory consolidation after workspace changes. ## Testing - Cover memory discovery, selection, synchronization, scope validation, feature gating, protocol results, and TUI rendering. GitOrigin-RevId: 9b17b2e9a639a064dba8aaffbec6345ae419018e
This commit is contained in:
1 parent
08924bca00
commit
7d1218a997
35 files changed
+1750
-23
No files matched your search
@@ -0,0 +1,118 @@
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn discovers_arbitrary_project_markdown() {
|
||||
let root = TempDir::new().expect("create tempdir");
|
||||
let external_agent_home = root.path().join(".external-agent");
|
||||
let project_root = external_agent_home.join("projects/opaque-project-key");
|
||||
let project_memory = project_root.join("memory");
|
||||
let project_cwd = root.path().join("project");
|
||||
fs::create_dir_all(project_memory.join("topics")).expect("create memory directories");
|
||||
fs::create_dir_all(&project_cwd).expect("create project cwd");
|
||||
fs::write(
|
||||
project_root.join("session.jsonl"),
|
||||
serde_json::json!({
|
||||
"type": "user",
|
||||
"cwd": &project_cwd,
|
||||
"timestamp": "2026-07-13T00:00:00Z",
|
||||
"message": { "content": "remember this" },
|
||||
})
|
||||
.to_string(),
|
||||
)
|
||||
.expect("write session");
|
||||
fs::write(project_memory.join("MEMORY.md"), "index").expect("write index");
|
||||
fs::write(project_memory.join("release-process.md"), "release notes")
|
||||
.expect("write arbitrary topic");
|
||||
fs::write(project_memory.join("topics/database.md"), "database notes")
|
||||
.expect("write nested topic");
|
||||
fs::write(project_memory.join("ignored.txt"), "not markdown").expect("write ignored file");
|
||||
let discovered =
|
||||
discover_external_memory_files(&external_agent_home).expect("discover memories");
|
||||
let project_cwd = fs::canonicalize(project_cwd).expect("canonicalize project cwd");
|
||||
|
||||
assert_eq!(
|
||||
discovered
|
||||
.iter()
|
||||
.map(|memory| {
|
||||
(
|
||||
memory.project_key.as_str(),
|
||||
memory.project_cwd.as_deref(),
|
||||
memory.relative_path.as_path(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
(
|
||||
"opaque-project-key",
|
||||
Some(project_cwd.as_path()),
|
||||
Path::new("MEMORY.md")
|
||||
),
|
||||
(
|
||||
"opaque-project-key",
|
||||
Some(project_cwd.as_path()),
|
||||
Path::new("release-process.md")
|
||||
),
|
||||
(
|
||||
"opaque-project-key",
|
||||
Some(project_cwd.as_path()),
|
||||
Path::new("topics/database.md")
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leaves_project_unscoped_without_an_existing_absolute_cwd() {
|
||||
let root = TempDir::new().expect("create tempdir");
|
||||
let external_agent_home = root.path().join(".external-agent");
|
||||
let project_root = external_agent_home.join("projects/opaque-project-key");
|
||||
let project_memory = project_root.join("memory");
|
||||
fs::create_dir_all(&project_memory).expect("create memory directory");
|
||||
fs::write(
|
||||
project_root.join("session.jsonl"),
|
||||
serde_json::json!({
|
||||
"type": "user",
|
||||
"cwd": root.path().join("missing-project"),
|
||||
"timestamp": "2026-07-13T00:00:00Z",
|
||||
"message": { "content": "remember this" },
|
||||
})
|
||||
.to_string(),
|
||||
)
|
||||
.expect("write session");
|
||||
fs::write(project_memory.join("MEMORY.md"), "index").expect("write index");
|
||||
|
||||
let discovered =
|
||||
discover_external_memory_files(&external_agent_home).expect("discover memories");
|
||||
|
||||
assert_eq!(
|
||||
discovered,
|
||||
vec![ExternalMemoryFile {
|
||||
project_key: "opaque-project-key".to_string(),
|
||||
project_cwd: None,
|
||||
source_path: project_memory.join("MEMORY.md"),
|
||||
relative_path: PathBuf::from("MEMORY.md"),
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn skips_symlinked_memory_directory() {
|
||||
use std::os::unix::fs::symlink;
|
||||
|
||||
let root = TempDir::new().expect("create tempdir");
|
||||
let external_agent_home = root.path().join(".external-agent");
|
||||
let project_root = external_agent_home.join("projects/project");
|
||||
let outside_memory = root.path().join("outside-memory");
|
||||
fs::create_dir_all(&project_root).expect("create project");
|
||||
fs::create_dir_all(&outside_memory).expect("create outside memory");
|
||||
fs::write(outside_memory.join("secret.md"), "secret").expect("write outside memory");
|
||||
symlink(&outside_memory, project_root.join("memory")).expect("symlink memory directory");
|
||||
|
||||
assert_eq!(
|
||||
discover_external_memory_files(&external_agent_home).expect("discover memories"),
|
||||
Vec::new()
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user