mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Revert state DB injection and agent graph store (#21481)
## Why Reverts #20689 to restore the previous optional state DB plumbing. The conflict resolution keeps the newer installation ID and session/thread identity changes that landed after #20689, while removing the mandatory state DB and agent graph store dependency from ThreadManager construction. ## What changed - Restored `Option<StateDbHandle>` through app-server, MCP server, prompt debug, and test entry points. - Removed the `codex-core` dependency on `codex-agent-graph-store` and reverted descendant lookup back to the existing state DB path when available. - Kept newer `installation_id` forwarding by passing it beside the optional DB handle. - Kept local thread-name updates working when the optional state DB handle is absent. ## Validation - `git diff --check` - `cargo test -p codex-thread-store` - `cargo test -p codex-state -p codex-rollout -p codex-app-server-protocol` - Attempted `env CARGO_INCREMENTAL=0 cargo test -p codex-core -p codex-app-server -p codex-app-server-client -p codex-mcp-server -p codex-thread-manager-sample -p codex-tui`; blocked locally by a rustc ICE while compiling `v8 v146.4.0` with `rustc 1.93.0 (254b59607 2026-01-19)` on `aarch64-apple-darwin`.
This commit is contained in:
committed by
GitHub
Unverified
parent
5bc33fe31f
commit
a8488fec5e
@@ -31,6 +31,7 @@ use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::ThreadSource;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_state::DirectionalThreadSpawnEdgeStatus;
|
||||
use codex_thread_store::ReadThreadParams;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
@@ -310,6 +311,7 @@ impl AgentControl {
|
||||
state.notify_thread_created(new_thread.thread_id);
|
||||
|
||||
self.persist_thread_spawn_edge_for_source(
|
||||
new_thread.thread.as_ref(),
|
||||
new_thread.thread_id,
|
||||
notification_source.as_ref(),
|
||||
)
|
||||
@@ -459,14 +461,19 @@ impl AgentControl {
|
||||
))
|
||||
.await?;
|
||||
let state = self.upgrade()?;
|
||||
let agent_graph_store = state.agent_graph_store();
|
||||
let Ok(resumed_thread) = state.get_thread(resumed_thread_id).await else {
|
||||
return Ok(resumed_thread_id);
|
||||
};
|
||||
let Some(state_db_ctx) = resumed_thread.state_db() else {
|
||||
return Ok(resumed_thread_id);
|
||||
};
|
||||
|
||||
let mut resume_queue = VecDeque::from([(thread_id, root_depth)]);
|
||||
while let Some((parent_thread_id, parent_depth)) = resume_queue.pop_front() {
|
||||
let child_ids = match agent_graph_store
|
||||
.list_thread_spawn_children(
|
||||
let child_ids = match state_db_ctx
|
||||
.list_thread_spawn_children_with_status(
|
||||
parent_thread_id,
|
||||
Some(codex_agent_graph_store::ThreadSpawnEdgeStatus::Open),
|
||||
DirectionalThreadSpawnEdgeStatus::Open,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -530,6 +537,7 @@ impl AgentControl {
|
||||
let _ = config.features.disable(Feature::Collab);
|
||||
}
|
||||
let state = self.upgrade()?;
|
||||
let state_db_ctx = state.state_db();
|
||||
let mut reservation = self.state.reserve_spawn_slot(config.agent_max_threads)?;
|
||||
let (session_source, agent_metadata) = match session_source {
|
||||
SessionSource::SubAgent(SubAgentSource::ThreadSpawn {
|
||||
@@ -539,11 +547,14 @@ impl AgentControl {
|
||||
agent_role: _,
|
||||
agent_nickname: _,
|
||||
}) => {
|
||||
let state_db_ctx = state.state_db();
|
||||
let (resumed_agent_nickname, resumed_agent_role) =
|
||||
match state_db_ctx.get_thread(thread_id).await {
|
||||
Ok(Some(metadata)) => (metadata.agent_nickname, metadata.agent_role),
|
||||
Ok(None) | Err(_) => (None, None),
|
||||
if let Some(state_db_ctx) = state_db_ctx.as_ref() {
|
||||
match state_db_ctx.get_thread(thread_id).await {
|
||||
Ok(Some(metadata)) => (metadata.agent_nickname, metadata.agent_role),
|
||||
Ok(None) | Err(_) => (None, None),
|
||||
}
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
self.prepare_thread_spawn(
|
||||
&mut reservation,
|
||||
@@ -610,6 +621,7 @@ impl AgentControl {
|
||||
);
|
||||
}
|
||||
self.persist_thread_spawn_edge_for_source(
|
||||
resumed_thread.thread.as_ref(),
|
||||
resumed_thread.thread_id,
|
||||
Some(¬ification_source),
|
||||
)
|
||||
@@ -722,13 +734,11 @@ impl AgentControl {
|
||||
/// agent and any live descendants reached from the in-memory tree.
|
||||
pub(crate) async fn close_agent(&self, agent_id: ThreadId) -> CodexResult<String> {
|
||||
let state = self.upgrade()?;
|
||||
if let Err(err) = state
|
||||
.agent_graph_store()
|
||||
.set_thread_spawn_edge_status(
|
||||
agent_id,
|
||||
codex_agent_graph_store::ThreadSpawnEdgeStatus::Closed,
|
||||
)
|
||||
.await
|
||||
if let Ok(thread) = state.get_thread(agent_id).await
|
||||
&& let Some(state_db_ctx) = thread.state_db()
|
||||
&& let Err(err) = state_db_ctx
|
||||
.set_thread_spawn_edge_status(agent_id, DirectionalThreadSpawnEdgeStatus::Closed)
|
||||
.await
|
||||
{
|
||||
warn!("failed to persist thread-spawn edge status for {agent_id}: {err}");
|
||||
}
|
||||
@@ -1144,21 +1154,21 @@ impl AgentControl {
|
||||
|
||||
async fn persist_thread_spawn_edge_for_source(
|
||||
&self,
|
||||
thread: &crate::CodexThread,
|
||||
child_thread_id: ThreadId,
|
||||
session_source: Option<&SessionSource>,
|
||||
) {
|
||||
let Some(parent_thread_id) = session_source.and_then(thread_spawn_parent_thread_id) else {
|
||||
return;
|
||||
};
|
||||
let Ok(state) = self.upgrade() else {
|
||||
let Some(state_db_ctx) = thread.state_db() else {
|
||||
return;
|
||||
};
|
||||
if let Err(err) = state
|
||||
.agent_graph_store()
|
||||
if let Err(err) = state_db_ctx
|
||||
.upsert_thread_spawn_edge(
|
||||
parent_thread_id,
|
||||
child_thread_id,
|
||||
codex_agent_graph_store::ThreadSpawnEdgeStatus::Open,
|
||||
DirectionalThreadSpawnEdgeStatus::Open,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
use crate::CodexThread;
|
||||
use crate::StateDbHandle;
|
||||
use crate::ThreadManager;
|
||||
use crate::agent::agent_status_from_event;
|
||||
use crate::config::AgentRoleConfig;
|
||||
@@ -7,6 +8,7 @@ use crate::config::Config;
|
||||
use crate::config::ConfigBuilder;
|
||||
use crate::context::ContextualUserFragment;
|
||||
use crate::context::SubagentNotification;
|
||||
use crate::init_state_db;
|
||||
use assert_matches::assert_matches;
|
||||
use codex_features::Feature;
|
||||
use codex_login::CodexAuth;
|
||||
@@ -84,6 +86,7 @@ fn spawn_agent_call(call_id: &str) -> ResponseItem {
|
||||
struct AgentControlHarness {
|
||||
_home: TempDir,
|
||||
config: Config,
|
||||
state_db: Option<StateDbHandle>,
|
||||
manager: ThreadManager,
|
||||
control: AgentControl,
|
||||
}
|
||||
@@ -91,17 +94,19 @@ struct AgentControlHarness {
|
||||
impl AgentControlHarness {
|
||||
async fn new() -> Self {
|
||||
let (home, config) = test_config().await;
|
||||
let manager = ThreadManager::with_models_provider_and_home_for_tests(
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::with_models_provider_home_and_state_for_tests(
|
||||
CodexAuth::from_api_key("dummy"),
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
std::sync::Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
state_db.clone(),
|
||||
);
|
||||
let control = manager.agent_control();
|
||||
Self {
|
||||
_home: home,
|
||||
config,
|
||||
state_db,
|
||||
manager,
|
||||
control,
|
||||
}
|
||||
@@ -950,8 +955,7 @@ async fn spawn_agent_respects_max_threads_limit() {
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
std::sync::Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
let control = manager.agent_control();
|
||||
|
||||
let _ = manager
|
||||
@@ -1003,8 +1007,7 @@ async fn spawn_agent_releases_slot_after_shutdown() {
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
std::sync::Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
let control = manager.agent_control();
|
||||
|
||||
let first_agent_id = control
|
||||
@@ -1047,8 +1050,7 @@ async fn spawn_agent_limit_shared_across_clones() {
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
std::sync::Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
let control = manager.agent_control();
|
||||
let cloned = control.clone();
|
||||
|
||||
@@ -1093,8 +1095,7 @@ async fn resume_agent_respects_max_threads_limit() {
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
std::sync::Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
let control = manager.agent_control();
|
||||
|
||||
let resumable_id = control
|
||||
@@ -1150,8 +1151,7 @@ async fn resume_agent_releases_slot_after_resume_failure() {
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
std::sync::Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
let control = manager.agent_control();
|
||||
|
||||
let _ = control
|
||||
@@ -1543,17 +1543,19 @@ async fn resume_thread_subagent_restores_stored_nickname_and_role() {
|
||||
.features
|
||||
.enable(Feature::Sqlite)
|
||||
.expect("test config should allow sqlite");
|
||||
let manager = ThreadManager::with_models_provider_and_home_for_tests(
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::with_models_provider_home_and_state_for_tests(
|
||||
CodexAuth::from_api_key("dummy"),
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
std::sync::Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
state_db.clone(),
|
||||
);
|
||||
let control = manager.agent_control();
|
||||
let harness = AgentControlHarness {
|
||||
_home: home,
|
||||
config,
|
||||
state_db,
|
||||
manager,
|
||||
control,
|
||||
};
|
||||
@@ -1704,12 +1706,7 @@ async fn resume_agent_from_rollout_reads_archived_rollout_path() {
|
||||
.expect("child shutdown should succeed");
|
||||
let store = LocalThreadStore::new(
|
||||
LocalThreadStoreConfig::from_config(&harness.config),
|
||||
codex_state::StateRuntime::init(
|
||||
harness.config.sqlite_home.clone(),
|
||||
harness.config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize"),
|
||||
harness.state_db.clone(),
|
||||
);
|
||||
store
|
||||
.archive_thread(ArchiveThreadParams {
|
||||
|
||||
@@ -98,7 +98,6 @@ pub(crate) async fn run_codex_thread_interactive(
|
||||
parent_trace: None,
|
||||
environment_selections: parent_ctx.environments.clone(),
|
||||
analytics_events_client: Some(parent_session.services.analytics_events_client.clone()),
|
||||
state_db: parent_session.services.state_db.clone(),
|
||||
thread_store: Arc::clone(&parent_session.services.thread_store),
|
||||
}))
|
||||
.or_cancel(&cancel_token)
|
||||
|
||||
@@ -30,6 +30,7 @@ use codex_protocol::protocol::TokenUsage;
|
||||
use codex_protocol::protocol::TurnAbortReason;
|
||||
use codex_protocol::protocol::validate_thread_goal_objective;
|
||||
use codex_rollout::state_db::reconcile_rollout;
|
||||
use codex_thread_store::LocalThreadStore;
|
||||
use codex_utils_template::Template;
|
||||
use futures::future::BoxFuture;
|
||||
use std::sync::Arc;
|
||||
@@ -1338,6 +1339,17 @@ impl Session {
|
||||
state_db
|
||||
} else if let Some(state_db) = self.goal_runtime.state_db.lock().await.clone() {
|
||||
state_db
|
||||
} else if let Some(local_store) = self
|
||||
.services
|
||||
.thread_store
|
||||
.as_any()
|
||||
.downcast_ref::<LocalThreadStore>()
|
||||
{
|
||||
local_store.state_db().await.ok_or_else(|| {
|
||||
anyhow::anyhow!(
|
||||
"thread goals require a local persisted thread with a state database"
|
||||
)
|
||||
})?
|
||||
} else {
|
||||
anyhow::bail!("thread goals require a local persisted thread with a state database");
|
||||
};
|
||||
|
||||
@@ -117,9 +117,7 @@ pub use thread_manager::NewThread;
|
||||
pub use thread_manager::StartThreadOptions;
|
||||
pub use thread_manager::ThreadManager;
|
||||
pub use thread_manager::ThreadShutdownReport;
|
||||
pub use thread_manager::agent_graph_store_from_state_db;
|
||||
pub use thread_manager::build_models_manager;
|
||||
pub use thread_manager::init_state_db_from_config;
|
||||
pub use thread_manager::thread_store_from_config;
|
||||
pub use web_search::web_search_action_detail;
|
||||
pub use web_search::web_search_detail;
|
||||
|
||||
@@ -25,7 +25,7 @@ pub enum PersonalityMigrationStatus {
|
||||
pub async fn maybe_migrate_personality(
|
||||
codex_home: &Path,
|
||||
config_toml: &ConfigToml,
|
||||
state_db: StateDbHandle,
|
||||
state_db: Option<StateDbHandle>,
|
||||
) -> io::Result<PersonalityMigrationStatus> {
|
||||
let marker_path = codex_home.join(PERSONALITY_MIGRATION_FILENAME);
|
||||
if tokio::fs::try_exists(&marker_path).await? {
|
||||
@@ -65,13 +65,16 @@ pub async fn maybe_migrate_personality(
|
||||
async fn has_recorded_sessions(
|
||||
codex_home: &Path,
|
||||
default_provider: &str,
|
||||
state_db: StateDbHandle,
|
||||
state_db: Option<StateDbHandle>,
|
||||
) -> io::Result<bool> {
|
||||
let config = LocalThreadStoreConfig {
|
||||
codex_home: codex_home.to_path_buf(),
|
||||
default_model_provider_id: default_provider.to_string(),
|
||||
};
|
||||
let store = LocalThreadStore::new(config, state_db);
|
||||
let store = LocalThreadStore::new(
|
||||
LocalThreadStoreConfig {
|
||||
codex_home: codex_home.to_path_buf(),
|
||||
sqlite_home: codex_home.to_path_buf(),
|
||||
default_model_provider_id: default_provider.to_string(),
|
||||
},
|
||||
state_db,
|
||||
);
|
||||
if has_threads(&store, /*archived*/ false).await? {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ use codex_protocol::protocol::SessionMetaLine;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::UserMessageEvent;
|
||||
use codex_rollout::ARCHIVED_SESSIONS_SUBDIR;
|
||||
use codex_rollout::RolloutConfig;
|
||||
use codex_rollout::SESSIONS_SUBDIR;
|
||||
use codex_rollout::state_db::StateDbHandle;
|
||||
use codex_state::state_db_path;
|
||||
use pretty_assertions::assert_eq;
|
||||
use tempfile::TempDir;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
@@ -23,26 +20,6 @@ async fn read_config_toml(codex_home: &Path) -> io::Result<ConfigToml> {
|
||||
toml::from_str(&contents).map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))
|
||||
}
|
||||
|
||||
async fn state_db_for_test(codex_home: &Path) -> io::Result<StateDbHandle> {
|
||||
state_db_for_test_with_sqlite_home(codex_home, codex_home).await
|
||||
}
|
||||
|
||||
async fn state_db_for_test_with_sqlite_home(
|
||||
codex_home: &Path,
|
||||
sqlite_home: &Path,
|
||||
) -> io::Result<StateDbHandle> {
|
||||
let config = RolloutConfig {
|
||||
codex_home: codex_home.to_path_buf(),
|
||||
sqlite_home: sqlite_home.to_path_buf(),
|
||||
cwd: codex_home.to_path_buf(),
|
||||
model_provider_id: "openai".to_string(),
|
||||
generate_memories: false,
|
||||
};
|
||||
codex_rollout::state_db::try_init(&config)
|
||||
.await
|
||||
.map_err(io::Error::other)
|
||||
}
|
||||
|
||||
async fn write_session_with_user_event(codex_home: &Path) -> io::Result<()> {
|
||||
let thread_id = ThreadId::new();
|
||||
let dir = codex_home
|
||||
@@ -111,8 +88,7 @@ async fn applies_when_sessions_exist_and_no_personality() -> io::Result<()> {
|
||||
write_session_with_user_event(temp.path()).await?;
|
||||
|
||||
let config_toml = ConfigToml::default();
|
||||
let state_db = state_db_for_test(temp.path()).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, state_db).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, /*state_db*/ None).await?;
|
||||
|
||||
assert_eq!(status, PersonalityMigrationStatus::Applied);
|
||||
assert!(temp.path().join(PERSONALITY_MIGRATION_FILENAME).exists());
|
||||
@@ -128,8 +104,7 @@ async fn applies_when_only_archived_sessions_exist_and_no_personality() -> io::R
|
||||
write_archived_session_with_user_event(temp.path()).await?;
|
||||
|
||||
let config_toml = ConfigToml::default();
|
||||
let state_db = state_db_for_test(temp.path()).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, state_db).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, /*state_db*/ None).await?;
|
||||
|
||||
assert_eq!(status, PersonalityMigrationStatus::Applied);
|
||||
assert!(temp.path().join(PERSONALITY_MIGRATION_FILENAME).exists());
|
||||
@@ -145,8 +120,7 @@ async fn skips_when_marker_exists() -> io::Result<()> {
|
||||
create_marker(&temp.path().join(PERSONALITY_MIGRATION_FILENAME)).await?;
|
||||
|
||||
let config_toml = ConfigToml::default();
|
||||
let state_db = state_db_for_test(temp.path()).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, state_db).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, /*state_db*/ None).await?;
|
||||
|
||||
assert_eq!(status, PersonalityMigrationStatus::SkippedMarker);
|
||||
assert!(!temp.path().join("config.toml").exists());
|
||||
@@ -163,8 +137,7 @@ async fn skips_when_personality_explicit() -> io::Result<()> {
|
||||
.map_err(|err| io::Error::other(format!("failed to write config: {err}")))?;
|
||||
|
||||
let config_toml = read_config_toml(temp.path()).await?;
|
||||
let state_db = state_db_for_test(temp.path()).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, state_db).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, /*state_db*/ None).await?;
|
||||
|
||||
assert_eq!(
|
||||
status,
|
||||
@@ -181,37 +154,10 @@ async fn skips_when_personality_explicit() -> io::Result<()> {
|
||||
async fn skips_when_no_sessions() -> io::Result<()> {
|
||||
let temp = TempDir::new()?;
|
||||
let config_toml = ConfigToml::default();
|
||||
let state_db = state_db_for_test(temp.path()).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, state_db).await?;
|
||||
let status = maybe_migrate_personality(temp.path(), &config_toml, /*state_db*/ None).await?;
|
||||
|
||||
assert_eq!(status, PersonalityMigrationStatus::SkippedNoSessions);
|
||||
assert!(temp.path().join(PERSONALITY_MIGRATION_FILENAME).exists());
|
||||
assert!(!temp.path().join("config.toml").exists());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn uses_configured_sqlite_home_when_checking_for_sessions() -> io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let sqlite_home = TempDir::new()?;
|
||||
write_session_with_user_event(codex_home.path()).await?;
|
||||
|
||||
let config_toml = ConfigToml::default();
|
||||
let state_db =
|
||||
state_db_for_test_with_sqlite_home(codex_home.path(), sqlite_home.path()).await?;
|
||||
let status = maybe_migrate_personality(codex_home.path(), &config_toml, state_db).await?;
|
||||
|
||||
assert_eq!(status, PersonalityMigrationStatus::Applied);
|
||||
assert!(
|
||||
codex_home
|
||||
.path()
|
||||
.join(PERSONALITY_MIGRATION_FILENAME)
|
||||
.exists()
|
||||
);
|
||||
|
||||
let persisted = read_config_toml(codex_home.path()).await?;
|
||||
assert_eq!(persisted.personality, Some(Personality::Pragmatic));
|
||||
assert!(!state_db_path(codex_home.path()).exists());
|
||||
assert!(state_db_path(sqlite_home.path()).exists());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -17,9 +17,8 @@ use crate::resolve_installation_id;
|
||||
use crate::session::session::Session;
|
||||
use crate::session::turn::build_prompt;
|
||||
use crate::session::turn::built_tools;
|
||||
use crate::state_db_bridge::StateDbHandle;
|
||||
use crate::thread_manager::ThreadManager;
|
||||
use crate::thread_manager::agent_graph_store_from_state_db;
|
||||
use crate::thread_manager::init_state_db_from_config;
|
||||
use crate::thread_manager::thread_store_from_config;
|
||||
|
||||
/// Build the model-visible `input` list for a single debug turn.
|
||||
@@ -27,6 +26,7 @@ use crate::thread_manager::thread_store_from_config;
|
||||
pub async fn build_prompt_input(
|
||||
mut config: Config,
|
||||
input: Vec<UserInput>,
|
||||
state_db: Option<StateDbHandle>,
|
||||
) -> CodexResult<Vec<ResponseItem>> {
|
||||
config.ephemeral = true;
|
||||
|
||||
@@ -38,11 +38,7 @@ pub async fn build_prompt_input(
|
||||
config.codex_linux_sandbox_exe.clone(),
|
||||
)?;
|
||||
|
||||
let state_db = init_state_db_from_config(&config)
|
||||
.await
|
||||
.ok_or_else(|| std::io::Error::other("prompt debug requires state db"))?;
|
||||
let thread_store = thread_store_from_config(&config, state_db.clone());
|
||||
let agent_graph_store = agent_graph_store_from_state_db(state_db.clone());
|
||||
let installation_id = resolve_installation_id(&config.codex_home).await?;
|
||||
let thread_manager = ThreadManager::new(
|
||||
&config,
|
||||
@@ -50,9 +46,8 @@ pub async fn build_prompt_input(
|
||||
SessionSource::Exec,
|
||||
Arc::new(EnvironmentManager::new(EnvironmentManagerArgs::new(local_runtime_paths)).await),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
state_db.clone(),
|
||||
installation_id,
|
||||
);
|
||||
let thread = thread_manager.start_thread(config).await?;
|
||||
|
||||
@@ -132,6 +132,7 @@ use codex_terminal_detection::user_agent;
|
||||
use codex_thread_store::CreateThreadParams;
|
||||
use codex_thread_store::LiveThread;
|
||||
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;
|
||||
@@ -352,6 +353,7 @@ use codex_protocol::protocol::TokenUsage;
|
||||
use codex_protocol::protocol::TokenUsageInfo;
|
||||
use codex_protocol::protocol::WarningEvent;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_tools::ToolEnvironmentMode;
|
||||
use codex_tools::ToolsConfig;
|
||||
use codex_tools::ToolsConfigParams;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
@@ -409,7 +411,6 @@ pub(crate) struct CodexSpawnArgs {
|
||||
pub(crate) parent_trace: Option<W3cTraceContext>,
|
||||
pub(crate) environment_selections: ResolvedTurnEnvironments,
|
||||
pub(crate) analytics_events_client: Option<AnalyticsEventsClient>,
|
||||
pub(crate) state_db: Option<state_db::StateDbHandle>,
|
||||
pub(crate) thread_store: Arc<dyn ThreadStore>,
|
||||
}
|
||||
|
||||
@@ -469,7 +470,6 @@ impl Codex {
|
||||
parent_trace: _,
|
||||
environment_selections,
|
||||
analytics_events_client,
|
||||
state_db,
|
||||
thread_store,
|
||||
} = args;
|
||||
let (tx_sub, rx_sub) = async_channel::bounded(SUBMISSION_CHANNEL_CAPACITY);
|
||||
@@ -558,7 +558,15 @@ impl Codex {
|
||||
};
|
||||
match thread_id {
|
||||
Some(thread_id) => {
|
||||
let state_db_ctx = state_db.clone();
|
||||
let state_db_ctx = if config.ephemeral {
|
||||
None
|
||||
} else if let Some(local_store) =
|
||||
thread_store.as_any().downcast_ref::<LocalThreadStore>()
|
||||
{
|
||||
local_store.state_db().await
|
||||
} else {
|
||||
None
|
||||
};
|
||||
state_db::get_dynamic_tools(state_db_ctx.as_deref(), thread_id, "codex_spawn")
|
||||
.await
|
||||
}
|
||||
@@ -646,7 +654,6 @@ impl Codex {
|
||||
agent_control,
|
||||
environment_manager,
|
||||
analytics_events_client,
|
||||
state_db,
|
||||
thread_store,
|
||||
parent_rollout_thread_trace,
|
||||
)
|
||||
@@ -1308,7 +1315,7 @@ impl Session {
|
||||
self.services.user_shell.as_ref().clone(),
|
||||
self.services.shell_snapshot_tx.clone(),
|
||||
self.services.session_telemetry.clone(),
|
||||
self.state_db(),
|
||||
self.services.state_db.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -368,7 +368,6 @@ impl Session {
|
||||
agent_control: AgentControl,
|
||||
environment_manager: Arc<EnvironmentManager>,
|
||||
analytics_events_client: Option<AnalyticsEventsClient>,
|
||||
state_db: Option<state_db::StateDbHandle>,
|
||||
thread_store: Arc<dyn ThreadStore>,
|
||||
parent_rollout_thread_trace: ThreadTraceContext,
|
||||
) -> anyhow::Result<Arc<Self>> {
|
||||
@@ -468,7 +467,22 @@ impl Session {
|
||||
otel.name = "session_init.thread_persistence",
|
||||
session_init.ephemeral = config.ephemeral,
|
||||
));
|
||||
let state_db_ctx = if config.ephemeral { None } else { state_db };
|
||||
let state_db_fut = async {
|
||||
if config.ephemeral {
|
||||
None
|
||||
} else if let Some(local_store) =
|
||||
thread_store.as_any().downcast_ref::<LocalThreadStore>()
|
||||
{
|
||||
local_store.state_db().await
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
.instrument(info_span!(
|
||||
"session_init.state_db",
|
||||
otel.name = "session_init.state_db",
|
||||
session_init.ephemeral = config.ephemeral,
|
||||
));
|
||||
|
||||
let auth_manager_clone = Arc::clone(&auth_manager);
|
||||
let config_for_mcp = Arc::clone(&config);
|
||||
@@ -492,8 +506,8 @@ impl Session {
|
||||
));
|
||||
|
||||
// Join all independent futures.
|
||||
let (thread_persistence_result, (auth, mcp_servers, auth_statuses)) =
|
||||
tokio::join!(thread_persistence_fut, auth_and_mcp_fut);
|
||||
let (thread_persistence_result, state_db_ctx, (auth, mcp_servers, auth_statuses)) =
|
||||
tokio::join!(thread_persistence_fut, state_db_fut, auth_and_mcp_fut);
|
||||
|
||||
let mut live_thread_init =
|
||||
LiveThreadInitGuard::new(thread_persistence_result.map_err(|e| {
|
||||
|
||||
@@ -915,7 +915,7 @@ async fn danger_full_access_turns_do_not_expose_managed_network_proxy() -> anyho
|
||||
&permission_profile_for_sandbox_policy(&SandboxPolicy::DangerFullAccess),
|
||||
)?;
|
||||
|
||||
let (session, _codex_home) = make_session_with_config(move |config| {
|
||||
let session = make_session_with_config(move |config| {
|
||||
let cwd = config.cwd.clone();
|
||||
config
|
||||
.permissions
|
||||
@@ -981,7 +981,7 @@ async fn danger_full_access_tool_attempts_do_not_enforce_managed_network() -> an
|
||||
&permission_profile_for_sandbox_policy(&SandboxPolicy::DangerFullAccess),
|
||||
)?;
|
||||
|
||||
let (session, _codex_home) = make_session_with_config(move |config| {
|
||||
let session = make_session_with_config(move |config| {
|
||||
let cwd = config.cwd.clone();
|
||||
config
|
||||
.permissions
|
||||
@@ -1056,7 +1056,7 @@ async fn workspace_write_turns_continue_to_expose_managed_network_proxy() -> any
|
||||
&permission_profile_for_sandbox_policy(&sandbox_policy),
|
||||
)?;
|
||||
|
||||
let (session, _codex_home) = make_session_with_config(move |config| {
|
||||
let session = make_session_with_config(move |config| {
|
||||
let cwd = config.cwd.clone();
|
||||
config
|
||||
.permissions
|
||||
@@ -1083,7 +1083,7 @@ async fn user_shell_commands_do_not_inherit_managed_network_proxy() -> anyhow::R
|
||||
&permission_profile_for_sandbox_policy(&sandbox_policy),
|
||||
)?;
|
||||
|
||||
let (session, rx, _codex_home) = make_session_with_config_and_rx(move |config| {
|
||||
let (session, rx) = make_session_with_config_and_rx(move |config| {
|
||||
let cwd = config.cwd.clone();
|
||||
config
|
||||
.permissions
|
||||
@@ -1213,7 +1213,7 @@ async fn reload_user_config_layer_updates_effective_apps_config() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn reload_user_config_layer_refreshes_hooks() -> anyhow::Result<()> {
|
||||
let (session, _codex_home) = make_session_with_config(|config| {
|
||||
let session = make_session_with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::CodexHooks)
|
||||
@@ -3052,13 +3052,15 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
|
||||
fn turn_environments_for_tests(
|
||||
environment: &Arc<codex_exec_server::Environment>,
|
||||
cwd: &codex_utils_absolute_path::AbsolutePathBuf,
|
||||
) -> Vec<TurnEnvironment> {
|
||||
vec![TurnEnvironment {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
environment: Arc::clone(environment),
|
||||
cwd: cwd.clone(),
|
||||
shell: None,
|
||||
}]
|
||||
) -> crate::environment_selection::ResolvedTurnEnvironments {
|
||||
crate::environment_selection::ResolvedTurnEnvironments {
|
||||
turn_environments: vec![TurnEnvironment {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
environment: Arc::clone(environment),
|
||||
cwd: cwd.clone(),
|
||||
shell: None,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -3598,15 +3600,9 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
|
||||
AgentControl::default(),
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
/*state_db*/ None,
|
||||
Arc::new(codex_thread_store::LocalThreadStore::new(
|
||||
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
|
||||
codex_state::StateRuntime::init(
|
||||
config.sqlite_home.clone(),
|
||||
config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize"),
|
||||
/*state_db*/ None,
|
||||
)),
|
||||
codex_rollout_trace::ThreadTraceContext::disabled(),
|
||||
)
|
||||
@@ -3755,12 +3751,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
live_thread: None,
|
||||
thread_store: Arc::new(codex_thread_store::LocalThreadStore::new(
|
||||
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
|
||||
codex_state::StateRuntime::init(
|
||||
config.sqlite_home.clone(),
|
||||
config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize"),
|
||||
/*state_db*/ None,
|
||||
)),
|
||||
model_client: ModelClient::new(
|
||||
Some(auth_manager.clone()),
|
||||
@@ -3807,7 +3798,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
model_info,
|
||||
&models_manager,
|
||||
/*network*/ None,
|
||||
crate::environment_selection::ResolvedTurnEnvironments { turn_environments },
|
||||
turn_environments,
|
||||
session_configuration.cwd.clone(),
|
||||
"turn_id".to_string(),
|
||||
skills_outcome,
|
||||
@@ -3841,18 +3832,14 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
|
||||
async fn make_session_with_config(
|
||||
mutator: impl FnOnce(&mut Config),
|
||||
) -> anyhow::Result<(Arc<Session>, tempfile::TempDir)> {
|
||||
let (session, _rx_event, codex_home) = make_session_with_config_and_rx(mutator).await?;
|
||||
Ok((session, codex_home))
|
||||
) -> anyhow::Result<Arc<Session>> {
|
||||
let (session, _rx_event) = make_session_with_config_and_rx(mutator).await?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
async fn make_session_with_config_and_rx(
|
||||
mutator: impl FnOnce(&mut Config),
|
||||
) -> anyhow::Result<(
|
||||
Arc<Session>,
|
||||
async_channel::Receiver<Event>,
|
||||
tempfile::TempDir,
|
||||
)> {
|
||||
) -> anyhow::Result<(Arc<Session>, async_channel::Receiver<Event>)> {
|
||||
let codex_home = tempfile::tempdir().expect("create temp dir");
|
||||
let mut config = build_test_config(codex_home.path()).await;
|
||||
mutator(&mut config);
|
||||
@@ -3939,21 +3926,15 @@ async fn make_session_with_config_and_rx(
|
||||
AgentControl::default(),
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
/*state_db*/ None,
|
||||
Arc::new(codex_thread_store::LocalThreadStore::new(
|
||||
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
|
||||
codex_state::StateRuntime::init(
|
||||
config.sqlite_home.clone(),
|
||||
config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize"),
|
||||
/*state_db*/ None,
|
||||
)),
|
||||
codex_rollout_trace::ThreadTraceContext::disabled(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok((session, rx_event, codex_home))
|
||||
Ok((session, rx_event))
|
||||
}
|
||||
|
||||
async fn make_session_with_history_source_and_agent_control_and_rx(
|
||||
@@ -4047,15 +4028,16 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
|
||||
agent_control,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
/*state_db*/ None,
|
||||
Arc::new(codex_thread_store::LocalThreadStore::new(
|
||||
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
|
||||
codex_state::StateRuntime::init(
|
||||
config.sqlite_home.clone(),
|
||||
config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize"),
|
||||
Some(
|
||||
codex_state::StateRuntime::init(
|
||||
config.sqlite_home.clone(),
|
||||
config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize"),
|
||||
),
|
||||
)),
|
||||
codex_rollout_trace::ThreadTraceContext::disabled(),
|
||||
)
|
||||
@@ -4784,7 +4766,7 @@ async fn default_turn_honors_empty_stored_thread_environments() {
|
||||
|
||||
let turn_context = session.new_default_turn().await;
|
||||
|
||||
assert!(turn_context.environments.primary_environment().is_none());
|
||||
assert!(turn_context.environments.primary().is_none());
|
||||
assert!(turn_context.environments.turn_environments.is_empty());
|
||||
assert_eq!(turn_context.cwd, session_cwd);
|
||||
assert_eq!(turn_context.config.cwd, session_cwd);
|
||||
@@ -4846,7 +4828,7 @@ async fn empty_turn_environments_clear_primary_environment() {
|
||||
.await
|
||||
.expect("turn should start");
|
||||
|
||||
assert!(turn_context.environments.primary_environment().is_none());
|
||||
assert!(turn_context.environments.primary().is_none());
|
||||
assert!(turn_context.environments.turn_environments.is_empty());
|
||||
assert_eq!(turn_context.cwd, session.get_config().await.cwd);
|
||||
assert_eq!(turn_context.config.cwd, session.get_config().await.cwd);
|
||||
@@ -5303,13 +5285,47 @@ async fn make_session_and_context_with_auth_and_config_and_rx<F>(
|
||||
Arc<TurnContext>,
|
||||
async_channel::Receiver<Event>,
|
||||
)
|
||||
where
|
||||
F: FnOnce(&mut Config),
|
||||
{
|
||||
let codex_home = tempfile::tempdir().expect("create temp dir");
|
||||
make_session_and_context_with_auth_config_home_and_rx(
|
||||
auth,
|
||||
dynamic_tools,
|
||||
codex_home.path(),
|
||||
configure_config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn make_session_and_context_with_auth_config_home_and_rx<F>(
|
||||
auth: CodexAuth,
|
||||
dynamic_tools: Vec<DynamicToolSpec>,
|
||||
codex_home: &Path,
|
||||
configure_config: F,
|
||||
) -> (
|
||||
Arc<Session>,
|
||||
Arc<TurnContext>,
|
||||
async_channel::Receiver<Event>,
|
||||
)
|
||||
where
|
||||
F: FnOnce(&mut Config),
|
||||
{
|
||||
let (tx_event, rx_event) = async_channel::unbounded();
|
||||
let codex_home = tempfile::tempdir().expect("create temp dir").keep();
|
||||
let mut config = build_test_config(codex_home.as_path()).await;
|
||||
let mut config = build_test_config(codex_home).await;
|
||||
configure_config(&mut config);
|
||||
let state_db = if config.features.enabled(Feature::Goals) {
|
||||
Some(
|
||||
codex_state::StateRuntime::init(
|
||||
config.sqlite_home.clone(),
|
||||
config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("goal tests should initialize sqlite state db"),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let config = Arc::new(config);
|
||||
let thread_id = ThreadId::default();
|
||||
let auth_manager = AuthManager::from_auth_for_testing(auth);
|
||||
@@ -5396,12 +5412,6 @@ where
|
||||
.expect("create environment"),
|
||||
);
|
||||
|
||||
let state_db = codex_state::StateRuntime::init(
|
||||
config.sqlite_home.clone(),
|
||||
config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize");
|
||||
let skills_watcher = Arc::new(SkillsWatcher::noop());
|
||||
let services = SessionServices {
|
||||
mcp_connection_manager: Arc::new(RwLock::new(McpConnectionManager::new_uninitialized(
|
||||
@@ -5442,7 +5452,7 @@ where
|
||||
agent_control,
|
||||
network_proxy: None,
|
||||
network_approval: Arc::clone(&network_approval),
|
||||
state_db: Some(state_db.clone()),
|
||||
state_db: state_db.clone(),
|
||||
live_thread: None,
|
||||
thread_store: Arc::new(codex_thread_store::LocalThreadStore::new(
|
||||
codex_thread_store::LocalThreadStoreConfig::from_config(config.as_ref()),
|
||||
@@ -5493,7 +5503,7 @@ where
|
||||
model_info,
|
||||
&models_manager,
|
||||
/*network*/ None,
|
||||
crate::environment_selection::ResolvedTurnEnvironments { turn_environments },
|
||||
turn_environments,
|
||||
session_configuration.cwd.clone(),
|
||||
"turn_id".to_string(),
|
||||
skills_outcome,
|
||||
@@ -5544,10 +5554,13 @@ async fn make_goal_session_and_context_with_rx() -> (
|
||||
Arc<Session>,
|
||||
Arc<TurnContext>,
|
||||
async_channel::Receiver<Event>,
|
||||
tempfile::TempDir,
|
||||
) {
|
||||
let (session, turn_context, rx) = make_session_and_context_with_auth_and_config_and_rx(
|
||||
let codex_home = tempfile::tempdir().expect("create temp dir");
|
||||
let (session, turn_context, rx) = make_session_and_context_with_auth_config_home_and_rx(
|
||||
CodexAuth::from_api_key("Test API Key"),
|
||||
Vec::new(),
|
||||
codex_home.path(),
|
||||
|config| {
|
||||
config
|
||||
.features
|
||||
@@ -5557,14 +5570,14 @@ async fn make_goal_session_and_context_with_rx() -> (
|
||||
)
|
||||
.await;
|
||||
upsert_goal_test_thread(session.as_ref()).await;
|
||||
(session, turn_context, rx)
|
||||
(session, turn_context, rx, codex_home)
|
||||
}
|
||||
|
||||
async fn upsert_goal_test_thread(session: &Session) {
|
||||
let config = session.get_config().await;
|
||||
let state_db = goal_test_state_db(session)
|
||||
.await
|
||||
.expect("goal test state db should initialize");
|
||||
let state_db = session
|
||||
.state_db()
|
||||
.expect("goal test session should have a state db");
|
||||
let mut builder = codex_state::ThreadMetadataBuilder::new(
|
||||
session.conversation_id,
|
||||
config
|
||||
@@ -7429,7 +7442,7 @@ async fn abort_empty_active_turn_preserves_pending_input() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn interrupt_accounts_active_goal_before_pausing() -> anyhow::Result<()> {
|
||||
let (sess, tc, _rx) = make_goal_session_and_context_with_rx().await;
|
||||
let (sess, tc, _rx, _codex_home) = make_goal_session_and_context_with_rx().await;
|
||||
sess.set_thread_goal(
|
||||
tc.as_ref(),
|
||||
SetGoalRequest {
|
||||
@@ -7693,7 +7706,7 @@ async fn goal_test_state_db(sess: &Session) -> anyhow::Result<crate::StateDbHand
|
||||
|
||||
#[tokio::test]
|
||||
async fn budget_limited_accounting_steers_active_turn_without_aborting() -> anyhow::Result<()> {
|
||||
let (sess, tc, rx) = make_goal_session_and_context_with_rx().await;
|
||||
let (sess, tc, rx, _codex_home) = make_goal_session_and_context_with_rx().await;
|
||||
sess.set_thread_goal(
|
||||
tc.as_ref(),
|
||||
SetGoalRequest {
|
||||
@@ -7793,7 +7806,7 @@ async fn budget_limited_accounting_steers_active_turn_without_aborting() -> anyh
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn external_goal_mutation_accounts_active_turn_before_status_change() -> anyhow::Result<()> {
|
||||
let (sess, tc, _rx) = make_goal_session_and_context_with_rx().await;
|
||||
let (sess, tc, _rx, _codex_home) = make_goal_session_and_context_with_rx().await;
|
||||
sess.set_thread_goal(
|
||||
tc.as_ref(),
|
||||
SetGoalRequest {
|
||||
@@ -7860,7 +7873,7 @@ async fn external_goal_mutation_accounts_active_turn_before_status_change() -> a
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn external_active_goal_set_marks_current_turn_for_accounting() -> anyhow::Result<()> {
|
||||
let (sess, tc, _rx) = make_goal_session_and_context_with_rx().await;
|
||||
let (sess, tc, _rx, _codex_home) = make_goal_session_and_context_with_rx().await;
|
||||
sess.spawn_task(
|
||||
Arc::clone(&tc),
|
||||
Vec::new(),
|
||||
@@ -8527,7 +8540,7 @@ async fn sample_rollout(
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_goal_tool_rejects_existing_goal() {
|
||||
let (session, turn_context, _rx) = make_goal_session_and_context_with_rx().await;
|
||||
let (session, turn_context, _rx, _codex_home) = make_goal_session_and_context_with_rx().await;
|
||||
let tracker = Arc::new(tokio::sync::Mutex::new(TurnDiffTracker::new()));
|
||||
let handler = CreateGoalHandler;
|
||||
|
||||
@@ -8589,7 +8602,7 @@ async fn create_goal_tool_rejects_existing_goal() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_goal_tool_rejects_pausing_goal() {
|
||||
let (session, turn_context, _rx) = make_goal_session_and_context_with_rx().await;
|
||||
let (session, turn_context, _rx, _codex_home) = make_goal_session_and_context_with_rx().await;
|
||||
let tracker = Arc::new(tokio::sync::Mutex::new(TurnDiffTracker::new()));
|
||||
let create_handler = CreateGoalHandler;
|
||||
let update_handler = UpdateGoalHandler;
|
||||
@@ -8650,7 +8663,7 @@ async fn update_goal_tool_rejects_pausing_goal() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_goal_tool_marks_goal_complete() {
|
||||
let (session, turn_context, _rx) = make_goal_session_and_context_with_rx().await;
|
||||
let (session, turn_context, _rx, _codex_home) = make_goal_session_and_context_with_rx().await;
|
||||
let tracker = Arc::new(tokio::sync::Mutex::new(TurnDiffTracker::new()));
|
||||
let create_handler = CreateGoalHandler;
|
||||
let update_handler = UpdateGoalHandler;
|
||||
|
||||
@@ -731,12 +731,7 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() {
|
||||
let skills_watcher = Arc::new(SkillsWatcher::noop());
|
||||
let thread_store = Arc::new(codex_thread_store::LocalThreadStore::new(
|
||||
codex_thread_store::LocalThreadStoreConfig::from_config(&config),
|
||||
codex_state::StateRuntime::init(
|
||||
config.sqlite_home.clone(),
|
||||
config.model_provider_id.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("state db should initialize"),
|
||||
/*state_db*/ None,
|
||||
));
|
||||
|
||||
let CodexSpawnOk { codex, .. } = Codex::spawn(CodexSpawnArgs {
|
||||
@@ -767,7 +762,6 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() {
|
||||
turn_environments: Vec::new(),
|
||||
},
|
||||
analytics_events_client: None,
|
||||
state_db: None,
|
||||
thread_store,
|
||||
})
|
||||
.await
|
||||
|
||||
@@ -11,7 +11,6 @@ use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_sandboxing::compatibility_sandbox_policy_for_permission_profile;
|
||||
use codex_sandboxing::policy_transforms::effective_file_system_sandbox_policy;
|
||||
use codex_sandboxing::policy_transforms::effective_network_sandbox_policy;
|
||||
use codex_tools::ToolEnvironmentMode;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
|
||||
@@ -138,8 +138,11 @@ pub(crate) async fn record_completed_response_item(
|
||||
.await;
|
||||
}
|
||||
mark_thread_memory_mode_polluted_if_external_context(sess, turn_context, item).await;
|
||||
let has_memory_citation =
|
||||
record_stage1_output_usage_and_detect_memory_citation(sess.state_db(), item).await;
|
||||
let has_memory_citation = record_stage1_output_usage_and_detect_memory_citation(
|
||||
sess.services.state_db.as_ref(),
|
||||
item,
|
||||
)
|
||||
.await;
|
||||
if has_memory_citation {
|
||||
sess.record_memory_citation_for_turn(&turn_context.sub_id)
|
||||
.await;
|
||||
@@ -174,7 +177,7 @@ pub(crate) async fn mark_thread_memory_mode_polluted_if_external_context(
|
||||
}
|
||||
|
||||
async fn record_stage1_output_usage_and_detect_memory_citation(
|
||||
state_db_ctx: Option<state_db::StateDbHandle>,
|
||||
state_db_ctx: Option<&state_db::StateDbHandle>,
|
||||
item: &ResponseItem,
|
||||
) -> bool {
|
||||
let Some(raw_text) = raw_assistant_output_text_from_item(item) else {
|
||||
|
||||
@@ -52,14 +52,14 @@ pub fn auth_manager_from_auth_with_home(auth: CodexAuth, codex_home: PathBuf) ->
|
||||
AuthManager::from_auth_for_testing_with_home(auth, codex_home)
|
||||
}
|
||||
|
||||
pub async fn thread_manager_with_models_provider(
|
||||
pub fn thread_manager_with_models_provider(
|
||||
auth: CodexAuth,
|
||||
provider: ModelProviderInfo,
|
||||
) -> ThreadManager {
|
||||
ThreadManager::with_models_provider_for_tests(auth, provider).await
|
||||
ThreadManager::with_models_provider_for_tests(auth, provider)
|
||||
}
|
||||
|
||||
pub async fn thread_manager_with_models_provider_and_home(
|
||||
pub fn thread_manager_with_models_provider_and_home(
|
||||
auth: CodexAuth,
|
||||
provider: ModelProviderInfo,
|
||||
codex_home: PathBuf,
|
||||
@@ -71,7 +71,22 @@ pub async fn thread_manager_with_models_provider_and_home(
|
||||
codex_home,
|
||||
environment_manager,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn thread_manager_with_models_provider_home_and_state(
|
||||
auth: CodexAuth,
|
||||
provider: ModelProviderInfo,
|
||||
codex_home: PathBuf,
|
||||
environment_manager: Arc<EnvironmentManager>,
|
||||
state_db: Option<crate::StateDbHandle>,
|
||||
) -> ThreadManager {
|
||||
ThreadManager::with_models_provider_home_and_state_for_tests(
|
||||
auth,
|
||||
provider,
|
||||
codex_home,
|
||||
environment_manager,
|
||||
state_db,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn start_thread_with_user_shell_override(
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::environment_selection::default_thread_environment_selections;
|
||||
use crate::environment_selection::resolve_environment_selections;
|
||||
use crate::file_watcher::FileWatcher;
|
||||
use crate::mcp::McpManager;
|
||||
use crate::resolve_installation_id;
|
||||
use crate::rollout::RolloutRecorder;
|
||||
use crate::rollout::truncation;
|
||||
use crate::session::Codex;
|
||||
@@ -19,8 +18,6 @@ use crate::skills_watcher::SkillsWatcher;
|
||||
use crate::skills_watcher::SkillsWatcherEvent;
|
||||
use crate::tasks::InterruptedTurnHistoryMarker;
|
||||
use crate::tasks::interrupted_turn_history_marker;
|
||||
use codex_agent_graph_store::AgentGraphStore;
|
||||
use codex_agent_graph_store::LocalAgentGraphStore;
|
||||
use codex_analytics::AnalyticsEventsClient;
|
||||
use codex_app_server_protocol::ThreadHistoryBuilder;
|
||||
use codex_app_server_protocol::TurnStatus;
|
||||
@@ -53,8 +50,8 @@ use codex_protocol::protocol::TurnAbortReason;
|
||||
use codex_protocol::protocol::TurnAbortedEvent;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use codex_rollout::state_db;
|
||||
use codex_rollout::state_db::StateDbHandle;
|
||||
use codex_state::DirectionalThreadSpawnEdgeStatus;
|
||||
use codex_thread_store::InMemoryThreadStore;
|
||||
use codex_thread_store::LocalThreadStore;
|
||||
use codex_thread_store::LocalThreadStoreConfig;
|
||||
@@ -251,11 +248,10 @@ pub(crate) struct ThreadManagerState {
|
||||
mcp_manager: Arc<McpManager>,
|
||||
skills_watcher: Arc<SkillsWatcher>,
|
||||
thread_store: Arc<dyn ThreadStore>,
|
||||
state_db: StateDbHandle,
|
||||
agent_graph_store: Arc<dyn AgentGraphStore>,
|
||||
session_source: SessionSource,
|
||||
installation_id: String,
|
||||
analytics_events_client: Option<AnalyticsEventsClient>,
|
||||
state_db: Option<StateDbHandle>,
|
||||
// Captures submitted ops for testing purpose when test mode is enabled.
|
||||
ops_log: Option<SharedCapturedOps>,
|
||||
}
|
||||
@@ -271,11 +267,10 @@ pub fn build_models_manager(
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn init_state_db_from_config(config: &Config) -> Option<StateDbHandle> {
|
||||
state_db::init(config).await
|
||||
}
|
||||
|
||||
pub fn thread_store_from_config(config: &Config, state_db: StateDbHandle) -> Arc<dyn ThreadStore> {
|
||||
pub fn thread_store_from_config(
|
||||
config: &Config,
|
||||
state_db: Option<StateDbHandle>,
|
||||
) -> Arc<dyn ThreadStore> {
|
||||
match &config.experimental_thread_store {
|
||||
ThreadStoreConfig::Local => Arc::new(LocalThreadStore::new(
|
||||
LocalThreadStoreConfig::from_config(config),
|
||||
@@ -286,27 +281,6 @@ pub fn thread_store_from_config(config: &Config, state_db: StateDbHandle) -> Arc
|
||||
}
|
||||
}
|
||||
|
||||
pub fn agent_graph_store_from_state_db(state_db: StateDbHandle) -> Arc<dyn AgentGraphStore> {
|
||||
Arc::new(LocalAgentGraphStore::new(state_db))
|
||||
}
|
||||
|
||||
async fn state_db_from_roots_for_tests(
|
||||
codex_home: PathBuf,
|
||||
sqlite_home: PathBuf,
|
||||
default_model_provider_id: String,
|
||||
) -> StateDbHandle {
|
||||
let config = codex_rollout::RolloutConfig {
|
||||
codex_home: codex_home.clone(),
|
||||
sqlite_home,
|
||||
cwd: codex_home,
|
||||
model_provider_id: default_model_provider_id,
|
||||
generate_memories: false,
|
||||
};
|
||||
state_db::try_init(&config)
|
||||
.await
|
||||
.unwrap_or_else(|err| panic!("test state db should initialize: {err}"))
|
||||
}
|
||||
|
||||
impl ThreadManager {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
@@ -315,9 +289,8 @@ impl ThreadManager {
|
||||
session_source: SessionSource,
|
||||
environment_manager: Arc<EnvironmentManager>,
|
||||
analytics_events_client: Option<AnalyticsEventsClient>,
|
||||
state_db: StateDbHandle,
|
||||
thread_store: Arc<dyn ThreadStore>,
|
||||
agent_graph_store: Arc<dyn AgentGraphStore>,
|
||||
state_db: Option<StateDbHandle>,
|
||||
installation_id: String,
|
||||
) -> Self {
|
||||
let codex_home = config.codex_home.clone();
|
||||
@@ -345,12 +318,11 @@ impl ThreadManager {
|
||||
mcp_manager,
|
||||
skills_watcher,
|
||||
thread_store,
|
||||
state_db,
|
||||
agent_graph_store,
|
||||
auth_manager,
|
||||
session_source,
|
||||
installation_id,
|
||||
analytics_events_client,
|
||||
state_db,
|
||||
ops_log: should_use_test_thread_manager_behavior()
|
||||
.then(|| Arc::new(std::sync::Mutex::new(Vec::new()))),
|
||||
}),
|
||||
@@ -360,7 +332,7 @@ impl ThreadManager {
|
||||
|
||||
/// Construct with a dummy AuthManager containing the provided CodexAuth.
|
||||
/// Used for integration tests: should not be used by ordinary business logic.
|
||||
pub(crate) async fn with_models_provider_for_tests(
|
||||
pub(crate) fn with_models_provider_for_tests(
|
||||
auth: CodexAuth,
|
||||
provider: ModelProviderInfo,
|
||||
) -> Self {
|
||||
@@ -371,27 +343,11 @@ impl ThreadManager {
|
||||
));
|
||||
std::fs::create_dir_all(&codex_home)
|
||||
.unwrap_or_else(|err| panic!("temp codex home dir create failed: {err}"));
|
||||
let state_db = state_db_from_roots_for_tests(
|
||||
codex_home.clone(),
|
||||
codex_home.clone(),
|
||||
OPENAI_PROVIDER_ID.to_string(),
|
||||
)
|
||||
.await;
|
||||
let skills_codex_home = match AbsolutePathBuf::from_absolute_path_checked(&codex_home) {
|
||||
Ok(codex_home) => codex_home,
|
||||
Err(err) => panic!("test codex_home should be absolute: {err}"),
|
||||
};
|
||||
let installation_id = resolve_installation_id(&skills_codex_home)
|
||||
.await
|
||||
.unwrap_or_else(|err| panic!("resolve test installation id failed: {err}"));
|
||||
let mut manager = Self::with_models_provider_and_home_and_state_db_for_tests(
|
||||
let mut manager = Self::with_models_provider_and_home_for_tests(
|
||||
auth,
|
||||
provider,
|
||||
codex_home.clone(),
|
||||
Arc::new(EnvironmentManager::default_for_tests()),
|
||||
state_db,
|
||||
skills_codex_home,
|
||||
installation_id,
|
||||
);
|
||||
manager._test_codex_home_guard = Some(TempCodexHomeGuard { path: codex_home });
|
||||
manager
|
||||
@@ -399,47 +355,35 @@ impl ThreadManager {
|
||||
|
||||
/// Construct with a dummy AuthManager containing the provided CodexAuth and codex home.
|
||||
/// Used for integration tests: should not be used by ordinary business logic.
|
||||
pub(crate) async fn with_models_provider_and_home_for_tests(
|
||||
pub(crate) fn with_models_provider_and_home_for_tests(
|
||||
auth: CodexAuth,
|
||||
provider: ModelProviderInfo,
|
||||
codex_home: PathBuf,
|
||||
environment_manager: Arc<EnvironmentManager>,
|
||||
) -> Self {
|
||||
let state_db = state_db_from_roots_for_tests(
|
||||
codex_home.clone(),
|
||||
codex_home.clone(),
|
||||
OPENAI_PROVIDER_ID.to_string(),
|
||||
)
|
||||
.await;
|
||||
let skills_codex_home = match AbsolutePathBuf::from_absolute_path_checked(&codex_home) {
|
||||
Ok(codex_home) => codex_home,
|
||||
Err(err) => panic!("test codex_home should be absolute: {err}"),
|
||||
};
|
||||
let installation_id = resolve_installation_id(&skills_codex_home)
|
||||
.await
|
||||
.unwrap_or_else(|err| panic!("resolve test installation id failed: {err}"));
|
||||
Self::with_models_provider_and_home_and_state_db_for_tests(
|
||||
Self::with_models_provider_home_and_state_for_tests(
|
||||
auth,
|
||||
provider,
|
||||
codex_home,
|
||||
environment_manager,
|
||||
state_db,
|
||||
skills_codex_home,
|
||||
installation_id,
|
||||
/*state_db*/ None,
|
||||
)
|
||||
}
|
||||
|
||||
fn with_models_provider_and_home_and_state_db_for_tests(
|
||||
pub(crate) fn with_models_provider_home_and_state_for_tests(
|
||||
auth: CodexAuth,
|
||||
provider: ModelProviderInfo,
|
||||
codex_home: PathBuf,
|
||||
environment_manager: Arc<EnvironmentManager>,
|
||||
state_db: StateDbHandle,
|
||||
skills_codex_home: AbsolutePathBuf,
|
||||
installation_id: String,
|
||||
state_db: Option<StateDbHandle>,
|
||||
) -> Self {
|
||||
set_thread_manager_test_mode_for_tests(/*enabled*/ true);
|
||||
let auth_manager = AuthManager::from_auth_for_testing(auth);
|
||||
let installation_id = uuid::Uuid::new_v4().to_string();
|
||||
let skills_codex_home = match AbsolutePathBuf::from_absolute_path_checked(&codex_home) {
|
||||
Ok(codex_home) => codex_home,
|
||||
Err(err) => panic!("test codex_home should be absolute: {err}"),
|
||||
};
|
||||
let (thread_created_tx, _) = broadcast::channel(THREAD_CREATED_CHANNEL_CAPACITY);
|
||||
let restriction_product = SessionSource::Exec.restriction_product();
|
||||
let plugins_manager = Arc::new(PluginsManager::new_with_restriction_product(
|
||||
@@ -458,11 +402,11 @@ impl ThreadManager {
|
||||
let thread_store: Arc<dyn ThreadStore> = Arc::new(LocalThreadStore::new(
|
||||
LocalThreadStoreConfig {
|
||||
codex_home: codex_home.clone(),
|
||||
sqlite_home: codex_home.clone(),
|
||||
default_model_provider_id: OPENAI_PROVIDER_ID.to_string(),
|
||||
},
|
||||
state_db.clone(),
|
||||
));
|
||||
let agent_graph_store = agent_graph_store_from_state_db(state_db.clone());
|
||||
Self {
|
||||
state: Arc::new(ThreadManagerState {
|
||||
threads: Arc::new(RwLock::new(HashMap::new())),
|
||||
@@ -475,12 +419,11 @@ impl ThreadManager {
|
||||
mcp_manager,
|
||||
skills_watcher,
|
||||
thread_store,
|
||||
state_db,
|
||||
agent_graph_store,
|
||||
auth_manager,
|
||||
session_source: SessionSource::Exec,
|
||||
installation_id,
|
||||
analytics_events_client: None,
|
||||
state_db,
|
||||
ops_log: should_use_test_thread_manager_behavior()
|
||||
.then(|| Arc::new(std::sync::Mutex::new(Vec::new()))),
|
||||
}),
|
||||
@@ -566,17 +509,22 @@ impl ThreadManager {
|
||||
subtree_thread_ids.push(thread_id);
|
||||
seen_thread_ids.insert(thread_id);
|
||||
|
||||
for descendant_id in self
|
||||
.state
|
||||
.agent_graph_store
|
||||
.list_thread_spawn_descendants(thread_id, /*status_filter*/ None)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
CodexErr::Fatal(format!("failed to load thread-spawn descendants: {err}"))
|
||||
})?
|
||||
{
|
||||
if seen_thread_ids.insert(descendant_id) {
|
||||
subtree_thread_ids.push(descendant_id);
|
||||
if let Some(state_db_ctx) = thread.state_db() {
|
||||
for status in [
|
||||
DirectionalThreadSpawnEdgeStatus::Open,
|
||||
DirectionalThreadSpawnEdgeStatus::Closed,
|
||||
] {
|
||||
for descendant_id in state_db_ctx
|
||||
.list_thread_spawn_descendants_with_status(thread_id, status)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
CodexErr::Fatal(format!("failed to load thread-spawn descendants: {err}"))
|
||||
})?
|
||||
{
|
||||
if seen_thread_ids.insert(descendant_id) {
|
||||
subtree_thread_ids.push(descendant_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,14 +866,10 @@ impl ThreadManager {
|
||||
}
|
||||
|
||||
impl ThreadManagerState {
|
||||
pub(crate) fn state_db(&self) -> StateDbHandle {
|
||||
pub(crate) fn state_db(&self) -> Option<StateDbHandle> {
|
||||
self.state_db.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn agent_graph_store(&self) -> Arc<dyn AgentGraphStore> {
|
||||
self.agent_graph_store.clone()
|
||||
}
|
||||
|
||||
pub(crate) async fn list_thread_ids(&self) -> Vec<ThreadId> {
|
||||
self.threads
|
||||
.read()
|
||||
@@ -1242,7 +1186,6 @@ impl ThreadManagerState {
|
||||
parent_trace,
|
||||
environment_selections,
|
||||
analytics_events_client: self.analytics_events_client.clone(),
|
||||
state_db: Some(self.state_db.clone()),
|
||||
thread_store: Arc::clone(&self.thread_store),
|
||||
})
|
||||
.await?;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
use crate::config::test_config;
|
||||
use crate::init_state_db;
|
||||
use crate::installation_id::INSTALLATION_ID_FILENAME;
|
||||
use crate::rollout::RolloutRecorder;
|
||||
use crate::session::session::SessionSettingsUpdate;
|
||||
@@ -50,21 +51,6 @@ fn assistant_msg(text: &str) -> ResponseItem {
|
||||
}
|
||||
}
|
||||
|
||||
async fn state_backed_stores(
|
||||
config: &Config,
|
||||
) -> (
|
||||
StateDbHandle,
|
||||
Arc<dyn ThreadStore>,
|
||||
Arc<dyn AgentGraphStore>,
|
||||
) {
|
||||
let state_db = init_state_db_from_config(config)
|
||||
.await
|
||||
.expect("thread manager test requires state db");
|
||||
let thread_store = thread_store_from_config(config, state_db.clone());
|
||||
let agent_graph_store = agent_graph_store_from_state_db(state_db.clone());
|
||||
(state_db, thread_store, agent_graph_store)
|
||||
}
|
||||
|
||||
fn contextual_user_interrupted_marker() -> ResponseItem {
|
||||
interrupted_turn_history_marker(InterruptedTurnHistoryMarker::ContextualUser)
|
||||
.expect("contextual-user interrupted marker should be enabled")
|
||||
@@ -280,8 +266,7 @@ async fn shutdown_all_threads_bounded_submits_shutdown_to_every_thread() {
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
let thread_1 = manager
|
||||
.start_thread(config.clone())
|
||||
.await
|
||||
@@ -330,8 +315,7 @@ async fn start_thread_accepts_explicit_environment_when_default_environment_is_d
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
environment_manager,
|
||||
)
|
||||
.await;
|
||||
);
|
||||
|
||||
let thread = manager
|
||||
.start_thread_with_options(StartThreadOptions {
|
||||
@@ -367,8 +351,7 @@ async fn start_thread_keeps_internal_threads_hidden_from_normal_lookups() {
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
)
|
||||
.await;
|
||||
);
|
||||
let thread = manager
|
||||
.start_thread_with_options(StartThreadOptions {
|
||||
config,
|
||||
@@ -408,16 +391,14 @@ async fn resume_and_fork_do_not_restore_thread_environments_from_rollout() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
thread_store_from_config(&config, /*state_db*/ None),
|
||||
/*state_db*/ None,
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
let selected_cwd =
|
||||
@@ -524,16 +505,16 @@ async fn explicit_installation_id_skips_codex_home_file() {
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let installation_id = uuid::Uuid::new_v4().to_string();
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let state_db = init_state_db(&config).await;
|
||||
let thread_store = thread_store_from_config(&config, state_db.clone());
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager,
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
state_db.clone(),
|
||||
installation_id.clone(),
|
||||
);
|
||||
|
||||
@@ -563,16 +544,14 @@ async fn resume_active_thread_from_rollout_returns_running_thread() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
thread_store_from_config(&config, /*state_db*/ None),
|
||||
/*state_db*/ None,
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
|
||||
@@ -620,16 +599,14 @@ async fn resume_stopped_thread_from_rollout_spawns_new_thread() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
thread_store_from_config(&config, /*state_db*/ None),
|
||||
/*state_db*/ None,
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
|
||||
@@ -682,16 +659,16 @@ async fn resume_stopped_thread_from_rollout_preserves_thread_source() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let state_db = init_state_db(&config).await;
|
||||
let thread_store = thread_store_from_config(&config, state_db.clone());
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
state_db.clone(),
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
|
||||
@@ -768,16 +745,14 @@ async fn new_uses_active_provider_for_model_refresh() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager,
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
thread_store_from_config(&config, /*state_db*/ None),
|
||||
/*state_db*/ None,
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
|
||||
@@ -983,16 +958,15 @@ async fn interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_histor
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
thread_store_from_config(&config, state_db.clone()),
|
||||
state_db.clone(),
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
|
||||
@@ -1090,16 +1064,15 @@ async fn interrupted_fork_snapshot_preserves_explicit_turn_id() {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
thread_store_from_config(&config, state_db.clone()),
|
||||
state_db.clone(),
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
|
||||
@@ -1186,16 +1159,15 @@ async fn interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
thread_store_from_config(&config, state_db.clone()),
|
||||
state_db.clone(),
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
|
||||
@@ -1328,16 +1300,15 @@ async fn resumed_thread_keeps_paused_goal_paused() -> anyhow::Result<()> {
|
||||
|
||||
let auth_manager =
|
||||
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
|
||||
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
auth_manager.clone(),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db,
|
||||
thread_store,
|
||||
agent_graph_store,
|
||||
thread_store_from_config(&config, state_db.clone()),
|
||||
state_db.clone(),
|
||||
TEST_INSTALLATION_ID.to_string(),
|
||||
);
|
||||
|
||||
@@ -1407,11 +1378,6 @@ async fn resumed_thread_keeps_paused_goal_paused() -> anyhow::Result<()> {
|
||||
.await
|
||||
.is_none()
|
||||
);
|
||||
let goal = state_db
|
||||
.get_thread_goal(resumed.thread_id)
|
||||
.await?
|
||||
.expect("goal should still exist after resume");
|
||||
assert_eq!(codex_state::ThreadGoalStatus::Paused, goal.status);
|
||||
|
||||
resumed.thread.shutdown_and_wait().await?;
|
||||
Ok(())
|
||||
|
||||
@@ -6,7 +6,6 @@ use crate::function_tool::FunctionCallError;
|
||||
use crate::init_state_db;
|
||||
use crate::session::tests::make_session_and_context;
|
||||
use crate::session_prefix::format_subagent_notification_message;
|
||||
use crate::thread_manager::agent_graph_store_from_state_db;
|
||||
use crate::thread_manager::thread_store_from_config;
|
||||
use crate::tools::context::ToolOutput;
|
||||
use crate::tools::handlers::multi_agents_v2::CloseAgentHandler as CloseAgentHandlerV2;
|
||||
@@ -91,12 +90,11 @@ fn parse_agent_id(id: &str) -> ThreadId {
|
||||
ThreadId::from_string(id).expect("agent id should be valid")
|
||||
}
|
||||
|
||||
async fn thread_manager() -> ThreadManager {
|
||||
fn thread_manager() -> ThreadManager {
|
||||
ThreadManager::with_models_provider_for_tests(
|
||||
CodexAuth::from_api_key("dummy"),
|
||||
built_in_model_providers(/* openai_base_url */ /*openai_base_url*/ None)["openai"].clone(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn install_role_with_model_override(turn: &mut TurnContext) -> String {
|
||||
@@ -243,7 +241,7 @@ async fn spawn_agent_uses_explorer_role_and_preserves_approval_policy() {
|
||||
}
|
||||
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let mut config = (*turn.config).clone();
|
||||
let provider_info =
|
||||
@@ -298,7 +296,7 @@ async fn spawn_agent_uses_explorer_role_and_preserves_approval_policy() {
|
||||
async fn spawn_agent_fork_context_rejects_agent_type_override() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let role_name = install_role_with_model_override(&mut turn).await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -330,7 +328,7 @@ async fn spawn_agent_fork_context_rejects_agent_type_override() {
|
||||
#[tokio::test]
|
||||
async fn spawn_agent_fork_context_rejects_child_model_overrides() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -365,7 +363,7 @@ async fn spawn_agent_fork_context_rejects_child_model_overrides() {
|
||||
async fn multi_agent_v2_spawn_fork_turns_all_rejects_agent_type_override() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let role_name = install_role_with_model_override(&mut turn).await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -408,7 +406,7 @@ async fn multi_agent_v2_spawn_fork_turns_all_rejects_agent_type_override() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_spawn_defaults_to_full_fork_and_rejects_child_model_overrides() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -449,7 +447,7 @@ async fn multi_agent_v2_spawn_defaults_to_full_fork_and_rejects_child_model_over
|
||||
async fn multi_agent_v2_spawn_partial_fork_turns_allows_agent_type_override() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let role_name = install_role_with_model_override(&mut turn).await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -505,7 +503,7 @@ async fn multi_agent_v2_spawn_partial_fork_turns_allows_agent_type_override() {
|
||||
#[tokio::test]
|
||||
async fn spawn_agent_returns_agent_id_without_task_name() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
|
||||
let output = SpawnAgentHandler
|
||||
@@ -532,7 +530,7 @@ async fn spawn_agent_returns_agent_id_without_task_name() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_spawn_requires_task_name() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -566,7 +564,7 @@ async fn multi_agent_v2_spawn_requires_task_name() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_spawn_rejects_legacy_items_field() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -626,7 +624,7 @@ async fn multi_agent_v2_spawn_returns_path_and_send_message_accepts_relative_pat
|
||||
}
|
||||
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -723,7 +721,7 @@ async fn multi_agent_v2_spawn_returns_path_and_send_message_accepts_relative_pat
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_spawn_rejects_legacy_fork_context() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -762,7 +760,7 @@ async fn multi_agent_v2_spawn_rejects_legacy_fork_context() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_spawn_rejects_invalid_fork_turns_string() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -801,7 +799,7 @@ async fn multi_agent_v2_spawn_rejects_invalid_fork_turns_string() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_spawn_rejects_zero_fork_turns() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -840,7 +838,7 @@ async fn multi_agent_v2_spawn_rejects_zero_fork_turns() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_send_message_accepts_root_target_from_child() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -916,7 +914,7 @@ async fn multi_agent_v2_send_message_accepts_root_target_from_child() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_followup_task_rejects_root_target_from_child() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -997,7 +995,7 @@ async fn multi_agent_v2_followup_task_rejects_root_target_from_child() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_list_agents_returns_completed_status_and_last_task_message() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1091,7 +1089,7 @@ async fn multi_agent_v2_list_agents_returns_completed_status_and_last_task_messa
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_list_agents_filters_by_relative_path_prefix() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1178,7 +1176,7 @@ async fn multi_agent_v2_list_agents_filters_by_relative_path_prefix() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_list_agents_omits_closed_agents() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1242,7 +1240,7 @@ async fn multi_agent_v2_list_agents_omits_closed_agents() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_send_message_rejects_legacy_items_field() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1298,7 +1296,7 @@ async fn multi_agent_v2_send_message_rejects_legacy_items_field() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_send_message_rejects_interrupt_parameter() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1371,7 +1369,7 @@ async fn multi_agent_v2_send_message_rejects_interrupt_parameter() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1506,7 +1504,7 @@ async fn multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn()
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_followup_task_rejects_legacy_items_field() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1559,7 +1557,7 @@ async fn multi_agent_v2_followup_task_rejects_legacy_items_field() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_interrupted_turn_does_not_notify_parent() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1636,7 +1634,7 @@ async fn multi_agent_v2_interrupted_turn_does_not_notify_parent() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_spawn_omits_agent_id_when_named() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1675,7 +1673,7 @@ async fn multi_agent_v2_spawn_omits_agent_id_when_named() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_spawn_surfaces_task_name_validation_errors() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -1718,7 +1716,7 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
|
||||
}
|
||||
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let expected_sandbox = turn.config.legacy_sandbox_policy();
|
||||
let mut expected_file_system_sandbox_policy =
|
||||
@@ -1799,7 +1797,7 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
|
||||
#[tokio::test]
|
||||
async fn spawn_agent_rejects_when_depth_limit_exceeded() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
|
||||
let max_depth = turn.config.agent_max_depth;
|
||||
@@ -1837,7 +1835,7 @@ async fn spawn_agent_allows_depth_up_to_configured_max_depth() {
|
||||
}
|
||||
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
|
||||
let mut config = (*turn.config).clone();
|
||||
@@ -1883,7 +1881,7 @@ async fn multi_agent_v2_spawn_agent_ignores_configured_max_depth() {
|
||||
}
|
||||
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let mut config = (*turn.config).clone();
|
||||
config.agent_max_depth = 1;
|
||||
config
|
||||
@@ -1991,7 +1989,7 @@ async fn send_input_rejects_invalid_id() {
|
||||
#[tokio::test]
|
||||
async fn send_input_reports_missing_agent() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let agent_id = ThreadId::new();
|
||||
let invocation = invocation(
|
||||
@@ -2012,7 +2010,7 @@ async fn send_input_reports_missing_agent() {
|
||||
#[tokio::test]
|
||||
async fn send_input_interrupts_before_prompt() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let config = turn.config.as_ref().clone();
|
||||
let thread = manager
|
||||
@@ -2054,7 +2052,7 @@ async fn send_input_interrupts_before_prompt() {
|
||||
#[tokio::test]
|
||||
async fn send_input_accepts_structured_items() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let config = turn.config.as_ref().clone();
|
||||
let thread = manager
|
||||
@@ -2128,7 +2126,7 @@ async fn resume_agent_rejects_invalid_id() {
|
||||
#[tokio::test]
|
||||
async fn resume_agent_reports_missing_agent() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let agent_id = ThreadId::new();
|
||||
let invocation = invocation(
|
||||
@@ -2149,7 +2147,7 @@ async fn resume_agent_reports_missing_agent() {
|
||||
#[tokio::test]
|
||||
async fn resume_agent_noops_for_active_agent() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let config = turn.config.as_ref().clone();
|
||||
let thread = manager
|
||||
@@ -2188,7 +2186,7 @@ async fn resume_agent_noops_for_active_agent() {
|
||||
#[tokio::test]
|
||||
async fn resume_agent_restores_closed_agent_and_accepts_send_input() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let config = turn.config.as_ref().clone();
|
||||
let thread = manager
|
||||
@@ -2267,7 +2265,7 @@ async fn resume_agent_restores_closed_agent_and_accepts_send_input() {
|
||||
#[tokio::test]
|
||||
async fn resume_agent_rejects_when_depth_limit_exceeded() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
|
||||
let max_depth = turn.config.agent_max_depth;
|
||||
@@ -2356,7 +2354,7 @@ async fn wait_agent_rejects_empty_targets() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_wait_agent_accepts_timeout_only_argument() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -2495,7 +2493,7 @@ async fn multi_agent_v2_wait_agent_uses_configured_min_timeout() {
|
||||
#[tokio::test]
|
||||
async fn wait_agent_returns_not_found_for_missing_agents() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let id_a = ThreadId::new();
|
||||
let id_b = ThreadId::new();
|
||||
@@ -2531,7 +2529,7 @@ async fn wait_agent_returns_not_found_for_missing_agents() {
|
||||
#[tokio::test]
|
||||
async fn wait_agent_times_out_when_status_is_not_final() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let config = turn.config.as_ref().clone();
|
||||
let thread = manager
|
||||
@@ -2574,7 +2572,7 @@ async fn wait_agent_times_out_when_status_is_not_final() {
|
||||
#[tokio::test]
|
||||
async fn wait_agent_clamps_short_timeouts_to_minimum() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let config = turn.config.as_ref().clone();
|
||||
let thread = manager
|
||||
@@ -2612,7 +2610,7 @@ async fn wait_agent_clamps_short_timeouts_to_minimum() {
|
||||
#[tokio::test]
|
||||
async fn wait_agent_returns_final_status_without_timeout() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let config = turn.config.as_ref().clone();
|
||||
let thread = manager
|
||||
@@ -2664,7 +2662,7 @@ async fn wait_agent_returns_final_status_without_timeout() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_wait_agent_returns_summary_for_mailbox_activity() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -2755,7 +2753,7 @@ async fn multi_agent_v2_wait_agent_returns_summary_for_mailbox_activity() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_wait_agent_returns_for_already_queued_mail() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -2833,7 +2831,7 @@ async fn multi_agent_v2_wait_agent_returns_for_already_queued_mail() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_wait_agent_wakes_on_any_mailbox_notification() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -2921,7 +2919,7 @@ async fn multi_agent_v2_wait_agent_wakes_on_any_mailbox_notification() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_wait_agent_does_not_return_completed_content() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -3007,7 +3005,7 @@ async fn multi_agent_v2_wait_agent_does_not_return_completed_content() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_close_agent_accepts_task_name_target() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -3066,7 +3064,7 @@ async fn multi_agent_v2_close_agent_accepts_task_name_target() {
|
||||
#[tokio::test]
|
||||
async fn multi_agent_v2_close_agent_rejects_root_target_and_id() {
|
||||
let (mut session, mut turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
let root = manager
|
||||
.start_thread((*turn.config).clone())
|
||||
.await
|
||||
@@ -3114,7 +3112,7 @@ async fn multi_agent_v2_close_agent_rejects_root_target_and_id() {
|
||||
#[tokio::test]
|
||||
async fn close_agent_submits_shutdown_and_returns_previous_status() {
|
||||
let (mut session, turn) = make_session_and_context().await;
|
||||
let manager = thread_manager().await;
|
||||
let manager = thread_manager();
|
||||
session.services.agent_control = manager.agent_control();
|
||||
let config = turn.config.as_ref().clone();
|
||||
let thread = manager
|
||||
@@ -3159,18 +3157,15 @@ async fn tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtr
|
||||
.features
|
||||
.enable(Feature::Sqlite)
|
||||
.expect("test config should allow sqlite");
|
||||
let state_db = init_state_db(&config)
|
||||
.await
|
||||
.expect("test config should initialize state db");
|
||||
let state_db = init_state_db(&config).await;
|
||||
let manager = ThreadManager::new(
|
||||
&config,
|
||||
AuthManager::from_auth_for_testing(CodexAuth::from_api_key("dummy")),
|
||||
SessionSource::Exec,
|
||||
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
|
||||
/*analytics_events_client*/ None,
|
||||
state_db.clone(),
|
||||
thread_store_from_config(&config, state_db.clone()),
|
||||
agent_graph_store_from_state_db(state_db.clone()),
|
||||
state_db.clone(),
|
||||
"11111111-1111-4111-8111-111111111111".to_string(),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user