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:
pakrym-oai
2026-05-06 22:48:29 -07:00
committed by GitHub
parent 5bc33fe31f
commit a8488fec5e
54 changed files with 781 additions and 834 deletions
@@ -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(),
);