Files
codex/codex-rs/app-server/tests/suite/v2/memory_read.rs
jif 553df1c691 Add dedicated memory v2 consolidation and read prompts (#43813)
## What changed

- Consolidate v2 rollout summaries into `memory_summary.md` without generating `raw_memories.md` or requiring `MEMORY.md`. Validate the summary's required sections and size below 10,000 UTF-8 bytes.
- Add v2 read instructions for selective history retrieval, evidence-grounded preferences, citations, and explicit memory edits. Split injected instructions into fragments to preserve the complete summary within fragment byte limits.
- Record memory citation usage in the store selected by `memories.version`.

## Testing

Add coverage for v2 consolidation without a handbook, summary validation, version-isolated memory reads, and resetting both memory versions while preserving threads.

GitOrigin-RevId: 1d895fb4a23a973f1a45ba03be07a1f480c10227
2026-09-08 12:58:11 +00:00

90 lines
3.4 KiB
Rust

//! Exercises version selection through app-server and the model request boundary.
use anyhow::Result;
use app_test_support::MockResponsesConfig;
use app_test_support::TestAppServer;
use codex_app_server_protocol::ThreadStartParams;
use codex_app_server_protocol::ThreadStartResponse;
use codex_app_server_protocol::TurnCompletedNotification;
use codex_app_server_protocol::TurnStartParams;
use codex_app_server_protocol::TurnStatus;
use codex_app_server_protocol::UserInput;
use codex_features::Feature;
use core_test_support::responses::ev_assistant_message;
use core_test_support::responses::ev_completed;
use core_test_support::responses::ev_response_created;
use core_test_support::responses::mount_sse_once;
use core_test_support::responses::sse;
use core_test_support::responses::start_mock_server;
use pretty_assertions::assert_eq;
use serde_json::json;
use tempfile::TempDir;
#[tokio::test]
async fn memory_read_version_selects_only_its_own_context() -> Result<()> {
for (version, expected, excluded) in [
("v1", "legacy-only-marker", "v2-only-marker"),
("v2", "v2-only-marker", "legacy-only-marker"),
] {
let server = start_mock_server().await;
let home = TempDir::new()?;
MockResponsesConfig::new(&server.uri())
.enable_feature(Feature::MemoryTool)
.write(home.path())?;
for (directory, marker) in [
("memories", "legacy-only-marker"),
("memories_v2", "v2-only-marker"),
] {
tokio::fs::create_dir_all(home.path().join(directory)).await?;
tokio::fs::write(
home.path().join(directory).join("memory_summary.md"),
format!("v1\n{marker}\n"),
)
.await?;
}
let mock = mount_sse_once(
&server,
sse(vec![
ev_response_created("response"),
ev_assistant_message("message", "Done"),
ev_completed("response"),
]),
)
.await;
let mut app = TestAppServer::builder()
.with_codex_home(home.path())
.build_initialized()
.await?;
let start = app
.send_thread_start_request_with_auto_env(ThreadStartParams {
// Skip background consolidation so it cannot consume the read test's response.
ephemeral: Some(true),
config: Some(
[
("memories.version".to_string(), json!(version)),
("memories.generate_memories".to_string(), json!(false)),
]
.into(),
),
..Default::default()
})
.await?;
let response: ThreadStartResponse = app.read_response(start).await?;
app.send_turn_start_request(TurnStartParams {
thread_id: response.thread.id,
input: vec![UserInput::Text {
text: "Use my memory preferences".to_string(),
text_elements: Vec::new(),
}],
..Default::default()
})
.await?;
let completed: TurnCompletedNotification = app.read_notification("turn/completed").await?;
assert_eq!(completed.turn.status, TurnStatus::Completed);
let request = mock.single_request();
assert!(request.body_contains_text(expected));
assert!(!request.body_contains_text(excluded));
}
Ok(())
}