Files
codex/codex-rs/state/src/runtime/memory_versions.rs
T
jif 3f76e88a48 Add configurable memory versions with isolated storage (#43797)
## What changed

- Add `memories.version` with `v1` as the default and `v2` as an opt-in selection.
- Route memory generation, summaries, and retrieval tools through the selected version. Store `v2` artifacts in `memories_v2` and lazily create a separate SQLite database, keeping jobs and outputs isolated while sharing the thread catalog.
- Preserve the initial memory version across extension config updates so summaries and retrieval tools use the same namespace.
- Clear both versions on memory reset and remove thread memory from both stores on thread deletion. Recognize both artifact roots in shell usage telemetry.

## Testing

Add regression coverage for version defaults and validation, independent job claims and outputs, deletion and reset across versions, and shell usage classification for both memory roots.

GitOrigin-RevId: aa799bf87ab6ec10c8f5668213931e57547d080b
2026-09-08 10:55:48 +00:00

57 lines
1.7 KiB
Rust

//! Creates isolated v2 memory state on demand while sharing the source thread catalog.
//! Reset and thread deletion always cover every existing version.
use super::MemoryStore;
use super::StateRuntime;
use codex_protocol::MemoryVersion;
use codex_protocol::ThreadId;
use std::sync::Arc;
impl StateRuntime {
pub async fn memories_for_version(
&self,
version: MemoryVersion,
) -> anyhow::Result<MemoryStore> {
match version {
MemoryVersion::V1 => Ok(self.memories.clone()),
MemoryVersion::V2 => self
.memories_v2
.get_or_try_init(|| async {
let pool = self.sqlite.open_memories_v2_db().await?;
Ok(MemoryStore::new(Arc::new(pool), Arc::clone(&self.pool)))
})
.await
.cloned(),
}
}
pub async fn clear_all_memory_data(&self) -> anyhow::Result<()> {
self.memories.clear_memory_data().await?;
if tokio::fs::try_exists(self.sqlite.memories_v2_db_path()).await? {
self.memories_for_version(MemoryVersion::V2)
.await?
.clear_memory_data()
.await?;
}
Ok(())
}
pub(super) async fn delete_versioned_thread_memory(
&self,
thread_id: ThreadId,
) -> anyhow::Result<()> {
self.memories.delete_thread_memory(thread_id).await?;
if tokio::fs::try_exists(self.sqlite.memories_v2_db_path()).await? {
self.memories_for_version(MemoryVersion::V2)
.await?
.delete_thread_memory(thread_id)
.await?;
}
Ok(())
}
}
#[cfg(test)]
#[path = "memory_versions_tests.rs"]
mod tests;