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
2026-04-30 21:24:59 -07:00
committed by GitHub
Unverified
parent f50c02d7bc
commit fe05acad23
55 changed files with 1076 additions and 514 deletions
+2
View File
@@ -136,6 +136,7 @@ use codex_thread_store::LiveThreadInitGuard;
use codex_thread_store::LocalThreadStore;
use codex_thread_store::ResumeThreadParams;
use codex_thread_store::ThreadEventPersistenceMode;
use codex_thread_store::ThreadPersistenceMetadata;
use codex_thread_store::ThreadStore;
use codex_utils_output_truncation::TruncationPolicy;
use futures::future::BoxFuture;
@@ -347,6 +348,7 @@ use codex_protocol::protocol::SkillMetadata as ProtocolSkillMetadata;
use codex_protocol::protocol::SkillToolDependency as ProtocolSkillToolDependency;
use codex_protocol::protocol::StreamErrorEvent;
use codex_protocol::protocol::Submission;
use codex_protocol::protocol::ThreadMemoryMode;
use codex_protocol::protocol::TokenCountEvent;
use codex_protocol::protocol::TokenUsage;
use codex_protocol::protocol::TokenUsageInfo;
+18
View File
@@ -400,6 +400,15 @@ impl Session {
text: session_configuration.base_instructions.clone(),
},
dynamic_tools: session_configuration.dynamic_tools.clone(),
metadata: ThreadPersistenceMetadata {
cwd: Some(config.cwd.to_path_buf()),
model_provider: config.model_provider_id.clone(),
memory_mode: if config.memories.generate_memories {
ThreadMemoryMode::Enabled
} else {
ThreadMemoryMode::Disabled
},
},
event_persistence_mode,
},
)
@@ -413,6 +422,15 @@ impl Session {
rollout_path: resumed_history.rollout_path.clone(),
history: Some(resumed_history.history.clone()),
include_archived: true,
metadata: ThreadPersistenceMetadata {
cwd: Some(config.cwd.to_path_buf()),
model_provider: config.model_provider_id.clone(),
memory_mode: if config.memories.generate_memories {
ThreadMemoryMode::Enabled
} else {
ThreadMemoryMode::Disabled
},
},
event_persistence_mode,
},
)
+24 -7
View File
@@ -1679,9 +1679,6 @@ async fn fork_startup_context_then_first_turn_diff_snapshot() -> anyhow::Result<
.fork_thread(
usize::MAX,
fork_config.clone(),
std::sync::Arc::new(codex_thread_store::LocalThreadStore::new(
codex_rollout::RolloutConfig::from_view(&fork_config),
)),
rollout_path,
/*persist_extended_history*/ false,
/*parent_trace*/ None,
@@ -2720,6 +2717,7 @@ async fn wait_for_thread_rollback_failed(rx: &async_channel::Receiver<Event>) ->
}
async fn attach_thread_persistence(session: &mut Session) -> PathBuf {
let config = session.get_config().await;
let live_thread = LiveThread::create(
Arc::clone(&session.services.thread_store),
CreateThreadParams {
@@ -2728,6 +2726,15 @@ async fn attach_thread_persistence(session: &mut Session) -> PathBuf {
source: SessionSource::Exec,
base_instructions: BaseInstructions::default(),
dynamic_tools: Vec::new(),
metadata: ThreadPersistenceMetadata {
cwd: Some(config.cwd.to_path_buf()),
model_provider: config.model_provider_id.clone(),
memory_mode: if config.memories.generate_memories {
ThreadMemoryMode::Enabled
} else {
ThreadMemoryMode::Disabled
},
},
event_persistence_mode: ThreadEventPersistenceMode::Limited,
},
)
@@ -3392,7 +3399,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
/*analytics_events_client*/ None,
Arc::new(codex_thread_store::LocalThreadStore::new(
codex_rollout::RolloutConfig::from_view(config.as_ref()),
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
)),
codex_rollout_trace::ThreadTraceContext::disabled(),
)
@@ -3539,7 +3546,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
state_db: None,
live_thread: None,
thread_store: Arc::new(codex_thread_store::LocalThreadStore::new(
codex_rollout::RolloutConfig::from_view(config.as_ref()),
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
)),
model_client: ModelClient::new(
Some(auth_manager.clone()),
@@ -3711,7 +3718,7 @@ async fn make_session_with_config_and_rx(
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
/*analytics_events_client*/ None,
Arc::new(codex_thread_store::LocalThreadStore::new(
codex_rollout::RolloutConfig::from_view(config.as_ref()),
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
)),
codex_rollout_trace::ThreadTraceContext::disabled(),
)
@@ -4574,6 +4581,7 @@ async fn shutdown_complete_does_not_append_to_thread_store_after_shutdown() {
let (mut session, _turn_context) = make_session_and_context().await;
let store = Arc::new(codex_thread_store::InMemoryThreadStore::default());
let thread_store: Arc<dyn codex_thread_store::ThreadStore> = store.clone();
let config = session.get_config().await;
let live_thread = LiveThread::create(
Arc::clone(&thread_store),
CreateThreadParams {
@@ -4582,6 +4590,15 @@ async fn shutdown_complete_does_not_append_to_thread_store_after_shutdown() {
source: SessionSource::Exec,
base_instructions: BaseInstructions::default(),
dynamic_tools: Vec::new(),
metadata: ThreadPersistenceMetadata {
cwd: Some(config.cwd.to_path_buf()),
model_provider: config.model_provider_id.clone(),
memory_mode: if config.memories.generate_memories {
ThreadMemoryMode::Enabled
} else {
ThreadMemoryMode::Disabled
},
},
event_persistence_mode: ThreadEventPersistenceMode::Limited,
},
)
@@ -4968,7 +4985,7 @@ where
state_db: None,
live_thread: None,
thread_store: Arc::new(codex_thread_store::LocalThreadStore::new(
codex_rollout::RolloutConfig::from_view(config.as_ref()),
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
)),
model_client: ModelClient::new(
Some(Arc::clone(&auth_manager)),
@@ -729,7 +729,7 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() {
let mcp_manager = Arc::new(McpManager::new(Arc::clone(&plugins_manager)));
let skills_watcher = Arc::new(SkillsWatcher::noop());
let thread_store = Arc::new(codex_thread_store::LocalThreadStore::new(
codex_rollout::RolloutConfig::from_view(&config),
codex_thread_store::LocalThreadStoreConfig::from_config(&config),
));
let CodexSpawnOk { codex, .. } = Codex::spawn(CodexSpawnArgs {