mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] add non-local thread store regression harness (#19266)
- Add an integration test that guarantees nothing gets written to codex home dir or sqlite when running a rollout with a non-local ThreadStore - Add an in-memory "spy" ThreadStore for tests like this Note I could not find a good way to also ensure there were no filesystem _reads_ that didn't go through threadstore. I explored a more elaborate sandboxed-subprocess approach but it isn't platform portable and felt like it wasn't (yet) worth it.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use crate::agents_md::DEFAULT_AGENTS_MD_FILENAME;
|
||||
use crate::agents_md::LOCAL_AGENTS_MD_FILENAME;
|
||||
use crate::config::ThreadStoreConfig;
|
||||
use crate::config::edit::ConfigEdit;
|
||||
use crate::config::edit::ConfigEditsBuilder;
|
||||
use crate::config::edit::apply_blocking;
|
||||
@@ -5294,8 +5295,8 @@ async fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
|
||||
realtime: RealtimeConfig::default(),
|
||||
experimental_realtime_ws_backend_prompt: None,
|
||||
experimental_realtime_ws_startup_context: None,
|
||||
experimental_thread_store_endpoint: None,
|
||||
experimental_thread_config_endpoint: None,
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
guardian_policy_config: None,
|
||||
@@ -5492,8 +5493,8 @@ async fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
realtime: RealtimeConfig::default(),
|
||||
experimental_realtime_ws_backend_prompt: None,
|
||||
experimental_realtime_ws_startup_context: None,
|
||||
experimental_thread_store_endpoint: None,
|
||||
experimental_thread_config_endpoint: None,
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
guardian_policy_config: None,
|
||||
@@ -5644,8 +5645,8 @@ async fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
|
||||
realtime: RealtimeConfig::default(),
|
||||
experimental_realtime_ws_backend_prompt: None,
|
||||
experimental_realtime_ws_startup_context: None,
|
||||
experimental_thread_store_endpoint: None,
|
||||
experimental_thread_config_endpoint: None,
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
guardian_policy_config: None,
|
||||
@@ -5781,8 +5782,8 @@ async fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
|
||||
realtime: RealtimeConfig::default(),
|
||||
experimental_realtime_ws_backend_prompt: None,
|
||||
experimental_realtime_ws_startup_context: None,
|
||||
experimental_thread_store_endpoint: None,
|
||||
experimental_thread_config_endpoint: None,
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
base_instructions: None,
|
||||
developer_instructions: None,
|
||||
guardian_policy_config: None,
|
||||
|
||||
@@ -27,6 +27,7 @@ use codex_config::config_toml::ConfigToml;
|
||||
use codex_config::config_toml::ProjectConfig;
|
||||
use codex_config::config_toml::RealtimeAudioConfig;
|
||||
use codex_config::config_toml::RealtimeConfig;
|
||||
use codex_config::config_toml::ThreadStoreToml;
|
||||
use codex_config::config_toml::validate_model_providers;
|
||||
use codex_config::profile_toml::ConfigProfile;
|
||||
use codex_config::types::ApprovalsReviewer;
|
||||
@@ -230,6 +231,19 @@ impl Permissions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Configured thread persistence backend.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub enum ThreadStoreConfig {
|
||||
/// Persist threads locally using rollout JSONL files and sqlite metadata.
|
||||
#[default]
|
||||
Local,
|
||||
/// Persist threads through the remote thread-store service.
|
||||
Remote { endpoint: String },
|
||||
/// Test-only in-memory thread store.
|
||||
#[cfg(debug_assertions)]
|
||||
InMemory { id: String },
|
||||
}
|
||||
|
||||
/// Application configuration loaded from disk and merged with overrides.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Config {
|
||||
@@ -545,13 +559,12 @@ pub struct Config {
|
||||
/// active.
|
||||
pub experimental_realtime_start_instructions: Option<String>,
|
||||
|
||||
/// Experimental / do not use. When set, app-server uses a remote thread
|
||||
/// store at this endpoint instead of the local filesystem/SQLite store.
|
||||
pub experimental_thread_store_endpoint: Option<String>,
|
||||
|
||||
/// Experimental / do not use. When set, app-server fetches thread-scoped
|
||||
/// config from a remote service at this endpoint.
|
||||
pub experimental_thread_config_endpoint: Option<String>,
|
||||
|
||||
/// Experimental / do not use. Selects the thread persistence backend.
|
||||
pub experimental_thread_store: ThreadStoreConfig,
|
||||
/// When set, restricts ChatGPT login to a specific workspace identifier.
|
||||
pub forced_chatgpt_workspace_id: Option<String>,
|
||||
|
||||
@@ -1297,6 +1310,21 @@ fn resolve_tool_suggest_config(config_toml: &ConfigToml) -> ToolSuggestConfig {
|
||||
ToolSuggestConfig { discoverables }
|
||||
}
|
||||
|
||||
fn thread_store_config(
|
||||
thread_store: Option<ThreadStoreToml>,
|
||||
legacy_remote_endpoint: Option<String>,
|
||||
) -> ThreadStoreConfig {
|
||||
match thread_store {
|
||||
Some(ThreadStoreToml::Local {}) => ThreadStoreConfig::Local,
|
||||
Some(ThreadStoreToml::Remote { endpoint }) => ThreadStoreConfig::Remote { endpoint },
|
||||
#[cfg(debug_assertions)]
|
||||
Some(ThreadStoreToml::InMemory { id }) => ThreadStoreConfig::InMemory { id },
|
||||
None => legacy_remote_endpoint.map_or(ThreadStoreConfig::Local, |endpoint| {
|
||||
ThreadStoreConfig::Remote { endpoint }
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum PermissionConfigSyntax {
|
||||
Legacy,
|
||||
@@ -2434,8 +2462,11 @@ impl Config {
|
||||
experimental_realtime_ws_backend_prompt: cfg.experimental_realtime_ws_backend_prompt,
|
||||
experimental_realtime_ws_startup_context: cfg.experimental_realtime_ws_startup_context,
|
||||
experimental_realtime_start_instructions: cfg.experimental_realtime_start_instructions,
|
||||
experimental_thread_store_endpoint: cfg.experimental_thread_store_endpoint,
|
||||
experimental_thread_config_endpoint: cfg.experimental_thread_config_endpoint,
|
||||
experimental_thread_store: thread_store_config(
|
||||
cfg.experimental_thread_store,
|
||||
cfg.experimental_thread_store_endpoint,
|
||||
),
|
||||
forced_chatgpt_workspace_id,
|
||||
forced_login_method,
|
||||
include_apply_patch_tool: include_apply_patch_tool_flag,
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::SkillsManager;
|
||||
use crate::agent::AgentControl;
|
||||
use crate::codex_thread::CodexThread;
|
||||
use crate::config::Config;
|
||||
use crate::config::ThreadStoreConfig;
|
||||
use crate::environment_selection::default_thread_environment_selections;
|
||||
use crate::environment_selection::selected_primary_environment;
|
||||
use crate::environment_selection::validate_environment_selections;
|
||||
@@ -52,6 +53,8 @@ use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use codex_rollout::RolloutConfig;
|
||||
use codex_state::DirectionalThreadSpawnEdgeStatus;
|
||||
#[cfg(debug_assertions)]
|
||||
use codex_thread_store::InMemoryThreadStore;
|
||||
use codex_thread_store::LocalThreadStore;
|
||||
use codex_thread_store::RemoteThreadStore;
|
||||
use codex_thread_store::ThreadStore;
|
||||
@@ -251,10 +254,14 @@ pub fn build_models_manager(
|
||||
}
|
||||
|
||||
fn configured_thread_store(config: &Config) -> Arc<dyn ThreadStore> {
|
||||
if let Some(endpoint) = config.experimental_thread_store_endpoint.as_deref() {
|
||||
return Arc::new(RemoteThreadStore::new(endpoint));
|
||||
match &config.experimental_thread_store {
|
||||
ThreadStoreConfig::Local => {
|
||||
Arc::new(LocalThreadStore::new(RolloutConfig::from_view(config)))
|
||||
}
|
||||
ThreadStoreConfig::Remote { endpoint } => Arc::new(RemoteThreadStore::new(endpoint)),
|
||||
#[cfg(debug_assertions)]
|
||||
ThreadStoreConfig::InMemory { id } => InMemoryThreadStore::for_id(id),
|
||||
}
|
||||
Arc::new(LocalThreadStore::new(RolloutConfig::from_view(config)))
|
||||
}
|
||||
|
||||
impl ThreadManager {
|
||||
|
||||
Reference in New Issue
Block a user