Make thread store process-scoped (#19474)

- Build one app-server process ThreadStore from startup config and share
it with ThreadManager and CodexMessageProcessor.
- Remove per-thread/fork store reconstruction so effective thread config
cannot switch the persistence backend.
- Add params to ThreadStore create/resume for specifying thread
metadata, since otherwise the metadata from store creation would be used
(incorrectly).
This commit is contained in:
Tom authored and GitHub committed 2026-04-30 21:24:59 -07:00
1 parent f50c02d7bc
commit fe05acad23
55 files changed
+1076 -514

No files matched your search

@@ -58,7 +58,7 @@ pub(super) async fn update_thread_metadata(
codex_rollout::state_db::reconcile_rollout(
state_db_ctx.as_deref(),
resolved_rollout_path.path.as_path(),
store.config.model_provider_id.as_str(),
store.config.default_model_provider_id.as_str(),
/*builder*/ None,
&[],
/*archived_only*/ resolved_rollout_path.archived.then_some(true),
@@ -203,6 +203,7 @@ mod tests {
use crate::ResumeThreadParams;
use crate::ThreadEventPersistenceMode;
use crate::ThreadMetadataPatch;
use crate::ThreadPersistenceMetadata;
use crate::ThreadStore;
use crate::local::LocalThreadStore;
use crate::local::test_support::test_config;
@@ -254,7 +255,7 @@ mod tests {
write_session_file(home.path(), "2025-01-03T14-30-00", uuid).expect("session file");
let runtime = codex_state::StateRuntime::init(
home.path().to_path_buf(),
config.model_provider_id.clone(),
config.default_model_provider_id.clone(),
)
.await
.expect("state db should initialize");
@@ -299,6 +300,7 @@ mod tests {
rollout_path: Some(path.clone()),
history: None,
include_archived: true,
metadata: test_thread_metadata(),
event_persistence_mode: ThreadEventPersistenceMode::Limited,
})
.await
@@ -400,7 +402,7 @@ mod tests {
.expect("archived session file");
let runtime = codex_state::StateRuntime::init(
home.path().to_path_buf(),
config.model_provider_id.clone(),
config.default_model_provider_id.clone(),
)
.await
.expect("state db should initialize");
@@ -411,7 +413,7 @@ mod tests {
codex_rollout::state_db::reconcile_rollout(
Some(runtime.as_ref()),
archived_path.as_path(),
config.model_provider_id.as_str(),
config.default_model_provider_id.as_str(),
/*builder*/ None,
&[],
/*archived_only*/ Some(true),
@@ -463,7 +465,7 @@ mod tests {
.expect("archived session file");
let runtime = codex_state::StateRuntime::init(
home.path().to_path_buf(),
config.model_provider_id.clone(),
config.default_model_provider_id.clone(),
)
.await
.expect("state db should initialize");
@@ -474,7 +476,7 @@ mod tests {
codex_rollout::state_db::reconcile_rollout(
Some(runtime.as_ref()),
archived_path.as_path(),
config.model_provider_id.as_str(),
config.default_model_provider_id.as_str(),
/*builder*/ None,
&[],
/*archived_only*/ Some(true),
@@ -487,6 +489,7 @@ mod tests {
rollout_path: Some(archived_path.clone()),
history: None,
include_archived: true,
metadata: test_thread_metadata(),
event_persistence_mode: ThreadEventPersistenceMode::Limited,
})
.await
@@ -516,6 +519,14 @@ mod tests {
);
}
fn test_thread_metadata() -> ThreadPersistenceMetadata {
ThreadPersistenceMetadata {
cwd: Some(std::env::current_dir().expect("cwd")),
model_provider: "test-provider".to_string(),
memory_mode: ThreadMemoryMode::Enabled,
}
}
fn last_rollout_item(path: &std::path::Path) -> Value {
let last_line = std::fs::read_to_string(path)
.expect("read rollout")