From 6666a89354aa46f262f4a27dd6268c4e24097060 Mon Sep 17 00:00:00 2001 From: jif-oai Date: Mon, 1 Jun 2026 23:53:45 +0100 Subject: [PATCH] simplify --- .../src/context/environment_context_tests.rs | 1 + .../core/src/context_manager/history_tests.rs | 1 + codex-rs/core/src/session/mod.rs | 30 +------ codex-rs/core/src/session/multi_agents.rs | 2 +- .../session/rollout_reconstruction_tests.rs | 8 ++ codex-rs/core/src/session/tests.rs | 5 +- codex-rs/core/src/session/turn_context.rs | 22 ++--- codex-rs/core/src/tasks/mod.rs | 4 +- codex-rs/core/src/thread_manager.rs | 5 +- .../core/src/tools/handlers/agent_jobs.rs | 6 +- .../src/tools/handlers/multi_agents/spawn.rs | 4 +- .../src/tools/handlers/multi_agents_tests.rs | 2 +- .../tools/handlers/multi_agents_v2/spawn.rs | 4 +- codex-rs/core/src/tools/spec_plan.rs | 8 +- codex-rs/core/src/tools/spec_plan_tests.rs | 2 +- codex-rs/core/tests/suite/resume_warning.rs | 1 + codex-rs/protocol/src/protocol.rs | 18 +++- codex-rs/rollout/src/recorder.rs | 10 +++ codex-rs/rollout/src/recorder_tests.rs | 1 + codex-rs/state/src/extract.rs | 4 + codex-rs/thread-store/src/in_memory.rs | 35 -------- codex-rs/thread-store/src/lib.rs | 1 - codex-rs/thread-store/src/local/mod.rs | 73 --------------- .../local/set_multi_agent_version_if_unset.rs | 88 ------------------- codex-rs/thread-store/src/store.rs | 8 -- codex-rs/thread-store/src/types.rs | 9 -- 26 files changed, 75 insertions(+), 277 deletions(-) delete mode 100644 codex-rs/thread-store/src/local/set_multi_agent_version_if_unset.rs diff --git a/codex-rs/core/src/context/environment_context_tests.rs b/codex-rs/core/src/context/environment_context_tests.rs index 875ce20c09..49c3fc0c58 100644 --- a/codex-rs/core/src/context/environment_context_tests.rs +++ b/codex-rs/core/src/context/environment_context_tests.rs @@ -180,6 +180,7 @@ fn turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd() { model: "gpt-5".to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: None, effort: None, summary: codex_protocol::config_types::ReasoningSummary::Auto, diff --git a/codex-rs/core/src/context_manager/history_tests.rs b/codex-rs/core/src/context_manager/history_tests.rs index 42179c42b5..7ee22be44a 100644 --- a/codex-rs/core/src/context_manager/history_tests.rs +++ b/codex-rs/core/src/context_manager/history_tests.rs @@ -132,6 +132,7 @@ fn reference_context_item() -> TurnContextItem { model: "gpt-test".to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: Some(false), effort: None, summary: codex_protocol::config_types::ReasoningSummary::Auto, diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index 5babd5e64b..40aebd70e0 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -138,7 +138,6 @@ use codex_thread_store::LiveThreadInitGuard; use codex_thread_store::LocalThreadStore; use codex_thread_store::ReadThreadParams; use codex_thread_store::ResumeThreadParams; -use codex_thread_store::SetMultiAgentVersionIfUnsetParams; use codex_thread_store::ThreadEventPersistenceMode; use codex_thread_store::ThreadPersistenceMetadata; use codex_thread_store::ThreadStore; @@ -1670,7 +1669,7 @@ impl Session { turn_context: &TurnContext, msg: &EventMsg, ) { - if turn_context.multi_agent_version != Some(MultiAgentVersion::V2) { + if turn_context.multi_agent_version != MultiAgentVersion::V2 { return; } @@ -2652,7 +2651,7 @@ impl Session { *self.multi_agent_version.get_or_init(|| multi_agent_version) } - pub(crate) async fn resolve_multi_agent_version_for_model( + pub(crate) fn resolve_multi_agent_version_for_model( &self, model_info: &ModelInfo, config: &Config, @@ -2665,30 +2664,7 @@ impl Session { .multi_agent_version .unwrap_or_else(|| config.multi_agent_version_from_features()); - let stored = if config.ephemeral { - selected - } else { - match self - .services - .thread_store - .set_multi_agent_version_if_unset(SetMultiAgentVersionIfUnsetParams { - thread_id: self.thread_id(), - multi_agent_version: selected, - }) - .await - { - Ok(multi_agent_version) => multi_agent_version, - Err(err) => { - warn!( - "failed to set multi-agent version for thread {}: {err}", - self.thread_id() - ); - selected - } - } - }; - - self.set_multi_agent_version_if_unset(stored) + self.set_multi_agent_version_if_unset(selected) } async fn send_raw_response_items(&self, turn_context: &TurnContext, items: &[ResponseItem]) { diff --git a/codex-rs/core/src/session/multi_agents.rs b/codex-rs/core/src/session/multi_agents.rs index e4423b29ed..a78a9c938e 100644 --- a/codex-rs/core/src/session/multi_agents.rs +++ b/codex-rs/core/src/session/multi_agents.rs @@ -7,7 +7,7 @@ pub(super) fn usage_hint_text<'a>( turn_context: &'a TurnContext, session_source: &SessionSource, ) -> Option<&'a str> { - if turn_context.multi_agent_version != Some(MultiAgentVersion::V2) { + if turn_context.multi_agent_version != MultiAgentVersion::V2 { return None; } diff --git a/codex-rs/core/src/session/rollout_reconstruction_tests.rs b/codex-rs/core/src/session/rollout_reconstruction_tests.rs index 05be3e8967..0ca54e55e0 100644 --- a/codex-rs/core/src/session/rollout_reconstruction_tests.rs +++ b/codex-rs/core/src/session/rollout_reconstruction_tests.rs @@ -72,6 +72,7 @@ async fn record_initial_history_resumed_bare_turn_context_does_not_hydrate_previ model: previous_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -110,6 +111,7 @@ async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lif model: previous_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -959,6 +961,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis model: previous_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -1037,6 +1040,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis model: previous_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -1065,6 +1069,7 @@ async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_tu model: previous_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -1183,6 +1188,7 @@ async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_fo model: current_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -1300,6 +1306,7 @@ async fn record_initial_history_resumed_trailing_incomplete_turn_compaction_clea model: previous_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -1458,6 +1465,7 @@ async fn record_initial_history_resumed_replaced_incomplete_compacted_turn_clear model: previous_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 2d5db9f23e..d001951bfc 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -2540,6 +2540,7 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() { model: previous_model.to_string(), personality: turn_context.personality, collaboration_mode: Some(turn_context.collaboration_mode.clone()), + multi_agent_version: None, realtime_active: Some(turn_context.realtime_active), effort: turn_context.reasoning_effort, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -4787,7 +4788,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) { &session_telemetry, session_configuration.provider.clone(), &session_configuration, - Some(config.multi_agent_version_from_features()), + config.multi_agent_version_from_features(), services.user_shell.as_ref(), services.shell_zsh_path.as_ref(), services.main_execve_wrapper_exe.as_ref(), @@ -6640,7 +6641,7 @@ where &session_telemetry, session_configuration.provider.clone(), &session_configuration, - Some(config.multi_agent_version_from_features()), + config.multi_agent_version_from_features(), services.user_shell.as_ref(), services.shell_zsh_path.as_ref(), services.main_execve_wrapper_exe.as_ref(), diff --git a/codex-rs/core/src/session/turn_context.rs b/codex-rs/core/src/session/turn_context.rs index 0ab40b05e4..9593984301 100644 --- a/codex-rs/core/src/session/turn_context.rs +++ b/codex-rs/core/src/session/turn_context.rs @@ -80,7 +80,7 @@ pub struct TurnContext { pub(crate) compact_prompt: Option, pub(crate) user_instructions: Option, pub(crate) collaboration_mode: CollaborationMode, - pub(crate) multi_agent_version: Option, + pub(crate) multi_agent_version: MultiAgentVersion, pub(crate) personality: Option, pub(crate) approval_policy: Constrained, pub(crate) permission_profile: PermissionProfile, @@ -106,8 +106,8 @@ pub struct TurnContext { } enum TurnMultiAgentRuntime { - Resolve, - Unset, + ResolveAndStore, + Preview, } impl TurnContext { @@ -363,6 +363,7 @@ impl TurnContext { model: self.model_info.slug.clone(), personality: self.personality, collaboration_mode: Some(self.collaboration_mode.clone()), + multi_agent_version: Some(self.multi_agent_version), realtime_active: Some(self.realtime_active), effort: self.reasoning_effort, summary: ReasoningSummaryConfig::Auto, @@ -464,7 +465,7 @@ impl Session { session_telemetry: &SessionTelemetry, provider: ModelProviderInfo, session_configuration: &SessionConfiguration, - multi_agent_version: Option, + multi_agent_version: MultiAgentVersion, user_shell: &shell::Shell, shell_zsh_path: Option<&PathBuf>, main_execve_wrapper_exe: Option<&PathBuf>, @@ -701,7 +702,7 @@ impl Session { session_configuration, final_output_json_schema, turn_environments, - TurnMultiAgentRuntime::Resolve, + TurnMultiAgentRuntime::ResolveAndStore, ) .await } @@ -717,7 +718,7 @@ impl Session { session_configuration, /*final_output_json_schema*/ None, turn_environments, - TurnMultiAgentRuntime::Unset, + TurnMultiAgentRuntime::Preview, ) .await } @@ -753,11 +754,12 @@ impl Session { .await; let multi_agent_version = match multi_agent_runtime { - TurnMultiAgentRuntime::Resolve => Some( + TurnMultiAgentRuntime::ResolveAndStore => { self.resolve_multi_agent_version_for_model(&model_info, &per_turn_config) - .await, - ), - TurnMultiAgentRuntime::Unset => None, + } + TurnMultiAgentRuntime::Preview => model_info + .multi_agent_version + .unwrap_or_else(|| per_turn_config.multi_agent_version_from_features()), }; let plugin_outcome = self .services diff --git a/codex-rs/core/src/tasks/mod.rs b/codex-rs/core/src/tasks/mod.rs index a3cd10cf82..76d5e6478e 100644 --- a/codex-rs/core/src/tasks/mod.rs +++ b/codex-rs/core/src/tasks/mod.rs @@ -73,12 +73,12 @@ pub(crate) enum InterruptedTurnHistoryMarker { impl InterruptedTurnHistoryMarker { pub(crate) fn from_config_and_version( config: &Config, - multi_agent_version: Option, + multi_agent_version: MultiAgentVersion, ) -> Self { if !config.agent_interrupt_message_enabled { return Self::Disabled; } - if multi_agent_version == Some(MultiAgentVersion::V2) { + if multi_agent_version == MultiAgentVersion::V2 { Self::Developer } else { Self::ContextualUser diff --git a/codex-rs/core/src/thread_manager.rs b/codex-rs/core/src/thread_manager.rs index f41c8907f9..5c5e1ea22b 100644 --- a/codex-rs/core/src/thread_manager.rs +++ b/codex-rs/core/src/thread_manager.rs @@ -664,7 +664,7 @@ impl ThreadManager { history, InterruptedTurnHistoryMarker::from_config_and_version( &options.config, - Some(inherited_multi_agent_version), + inherited_multi_agent_version, ), ); self.start_thread_with_options_and_fork_source( @@ -942,7 +942,8 @@ impl ThreadManager { }; let interrupted_marker = InterruptedTurnHistoryMarker::from_config_and_version( &config, - resolve_multi_agent_version(&history, /*inherited_multi_agent_version*/ None), + resolve_multi_agent_version(&history, /*inherited_multi_agent_version*/ None) + .unwrap_or(MultiAgentVersion::V1), ); let history = fork_history_from_snapshot(snapshot, history, interrupted_marker); let environments = default_thread_environment_selections( diff --git a/codex-rs/core/src/tools/handlers/agent_jobs.rs b/codex-rs/core/src/tools/handlers/agent_jobs.rs index 138a45e137..c9366bb822 100644 --- a/codex-rs/core/src/tools/handlers/agent_jobs.rs +++ b/codex-rs/core/src/tools/handlers/agent_jobs.rs @@ -111,11 +111,7 @@ async fn build_runner_options( turn: &Arc, requested_concurrency: Option, ) -> Result { - let multi_agent_version = turn.multi_agent_version.ok_or_else(|| { - FunctionCallError::RespondToModel( - "multi-agent version is unresolved; this session cannot spawn workers".to_string(), - ) - })?; + let multi_agent_version = turn.multi_agent_version; if multi_agent_version == MultiAgentVersion::Disabled { return Err(FunctionCallError::RespondToModel( "multi-agent runtime is disabled; this session cannot spawn workers".to_string(), diff --git a/codex-rs/core/src/tools/handlers/multi_agents/spawn.rs b/codex-rs/core/src/tools/handlers/multi_agents/spawn.rs index c099412987..561bda2ae3 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents/spawn.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents/spawn.rs @@ -109,9 +109,7 @@ async fn handle_spawn_agent( ) .await?; apply_spawn_agent_runtime_overrides(&mut config, turn.as_ref())?; - let multi_agent_version = turn - .multi_agent_version - .ok_or_else(|| FunctionCallError::Fatal("multi-agent version is unresolved".to_string()))?; + let multi_agent_version = turn.multi_agent_version; let result = Box::pin(session.services.agent_control.spawn_agent_with_metadata( config, diff --git a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs index 4c33ecad1b..cf8025db31 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs @@ -135,7 +135,7 @@ model_reasoning_effort = "minimal" } fn set_turn_config(turn: &mut TurnContext, config: crate::config::Config) { - turn.multi_agent_version = Some(config.multi_agent_version_from_features()); + turn.multi_agent_version = config.multi_agent_version_from_features(); turn.config = Arc::new(config); } diff --git a/codex-rs/core/src/tools/handlers/multi_agents_v2/spawn.rs b/codex-rs/core/src/tools/handlers/multi_agents_v2/spawn.rs index 5d3a5f550c..a8b79c373e 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_v2/spawn.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_v2/spawn.rs @@ -108,9 +108,7 @@ async fn handle_spawn_agent( ) .await?; apply_spawn_agent_runtime_overrides(&mut config, turn.as_ref())?; - let multi_agent_version = turn - .multi_agent_version - .ok_or_else(|| FunctionCallError::Fatal("multi-agent version is unresolved".to_string()))?; + let multi_agent_version = turn.multi_agent_version; let spawn_source = thread_spawn_source( session.conversation_id, diff --git a/codex-rs/core/src/tools/spec_plan.rs b/codex-rs/core/src/tools/spec_plan.rs index 4924b9509c..8c21fbfc6b 100644 --- a/codex-rs/core/src/tools/spec_plan.rs +++ b/codex-rs/core/src/tools/spec_plan.rs @@ -290,17 +290,17 @@ fn namespace_tools_enabled(turn_context: &TurnContext) -> bool { } fn multi_agent_v2_enabled(turn_context: &TurnContext) -> bool { - turn_context.multi_agent_version == Some(MultiAgentVersion::V2) + turn_context.multi_agent_version == MultiAgentVersion::V2 } fn collab_tools_enabled(turn_context: &TurnContext) -> bool { match turn_context.multi_agent_version { - None | Some(MultiAgentVersion::Disabled) => false, - Some(MultiAgentVersion::V1) => !exceeds_thread_spawn_depth_limit( + MultiAgentVersion::Disabled => false, + MultiAgentVersion::V1 => !exceeds_thread_spawn_depth_limit( next_thread_spawn_depth(&turn_context.session_source), turn_context.config.agent_max_depth, ), - Some(MultiAgentVersion::V2) => true, + MultiAgentVersion::V2 => true, } } diff --git a/codex-rs/core/src/tools/spec_plan_tests.rs b/codex-rs/core/src/tools/spec_plan_tests.rs index dc93846609..7037bd7ec1 100644 --- a/codex-rs/core/src/tools/spec_plan_tests.rs +++ b/codex-rs/core/src/tools/spec_plan_tests.rs @@ -215,7 +215,7 @@ fn set_feature(turn: &mut TurnContext, feature: Feature, enabled: bool) { .disable(feature) .expect("test feature should be disableable in config"); } - turn.multi_agent_version = Some(config.multi_agent_version_from_features()); + turn.multi_agent_version = config.multi_agent_version_from_features(); turn.config = Arc::new(config); turn.tool_mode = turn.model_info.tool_mode.unwrap_or_else(|| { if turn.config.features.enabled(Feature::CodeModeOnly) { diff --git a/codex-rs/core/tests/suite/resume_warning.rs b/codex-rs/core/tests/suite/resume_warning.rs index 9cb2980725..86c59826bb 100644 --- a/codex-rs/core/tests/suite/resume_warning.rs +++ b/codex-rs/core/tests/suite/resume_warning.rs @@ -39,6 +39,7 @@ fn resume_history( model: previous_model.to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: None, effort: config.model_reasoning_effort, summary: config diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 4619ed3eb5..f9da57df92 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -2727,7 +2727,7 @@ fn multi_agent_version_from_items( items: &[RolloutItem], thread_id: Option, ) -> Option { - items + let session_meta_version = items .iter() .rev() .find_map(|item| match item { @@ -2738,11 +2738,22 @@ fn multi_agent_version_from_items( } _ => None, }) - .and_then(|meta_line| meta_line.meta.multi_agent_version) + .and_then(|meta_line| meta_line.meta.multi_agent_version); + + session_meta_version.or_else(|| { + items.iter().rev().find_map(|item| match item { + RolloutItem::TurnContext(turn_context) => turn_context.multi_agent_version, + RolloutItem::SessionMeta(_) + | RolloutItem::ResponseItem(_) + | RolloutItem::Compacted(_) + | RolloutItem::EventMsg(_) => None, + }) + }) } #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] +#[ts(rename_all = "snake_case")] pub enum MultiAgentVersion { Disabled, V1, @@ -2891,6 +2902,8 @@ pub struct TurnContextItem { #[serde(default, skip_serializing_if = "Option::is_none")] pub collaboration_mode: Option, #[serde(default, skip_serializing_if = "Option::is_none")] + pub multi_agent_version: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] pub realtime_active: Option, #[serde(skip_serializing_if = "Option::is_none")] pub effort: Option, @@ -5338,6 +5351,7 @@ mod tests { model: "gpt-5".to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: None, effort: None, summary: ReasoningSummaryConfig::Auto, diff --git a/codex-rs/rollout/src/recorder.rs b/codex-rs/rollout/src/recorder.rs index d102d5c540..afebc0a0d8 100644 --- a/codex-rs/rollout/src/recorder.rs +++ b/codex-rs/rollout/src/recorder.rs @@ -1534,6 +1534,16 @@ impl RolloutWriterState { } async fn write_session_meta_if_needed(&mut self) -> std::io::Result<()> { + if let Some(session_meta) = self.meta.as_mut() + && session_meta.multi_agent_version.is_none() + { + session_meta.multi_agent_version = self.pending_items.iter().find_map(|item| { + let RolloutItem::TurnContext(turn_context) = item else { + return None; + }; + turn_context.multi_agent_version + }); + } let Some(session_meta) = self.meta.as_ref().cloned() else { return Ok(()); }; diff --git a/codex-rs/rollout/src/recorder_tests.rs b/codex-rs/rollout/src/recorder_tests.rs index 4da081eff5..07029abe37 100644 --- a/codex-rs/rollout/src/recorder_tests.rs +++ b/codex-rs/rollout/src/recorder_tests.rs @@ -1146,6 +1146,7 @@ async fn resume_candidate_matches_cwd_reads_latest_turn_context() -> std::io::Re model: "test-model".to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: None, effort: None, summary: codex_protocol::config_types::ReasoningSummary::Auto, diff --git a/codex-rs/state/src/extract.rs b/codex-rs/state/src/extract.rs index 0d15d46a52..1bba63fbf3 100644 --- a/codex-rs/state/src/extract.rs +++ b/codex-rs/state/src/extract.rs @@ -358,6 +358,7 @@ mod tests { model: "gpt-5".to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: None, effort: None, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -395,6 +396,7 @@ mod tests { model: "gpt-5".to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: None, effort: None, summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -429,6 +431,7 @@ mod tests { model: "gpt-5".to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: None, effort: Some(ReasoningEffort::High), summary: codex_protocol::config_types::ReasoningSummary::Auto, @@ -459,6 +462,7 @@ mod tests { model: "gpt-5".to_string(), personality: None, collaboration_mode: None, + multi_agent_version: None, realtime_active: None, effort: Some(ReasoningEffort::High), summary: codex_protocol::config_types::ReasoningSummary::Auto, diff --git a/codex-rs/thread-store/src/in_memory.rs b/codex-rs/thread-store/src/in_memory.rs index 4ae629d79c..317e561a3f 100644 --- a/codex-rs/thread-store/src/in_memory.rs +++ b/codex-rs/thread-store/src/in_memory.rs @@ -10,7 +10,6 @@ use chrono::Utc; use codex_protocol::ThreadId; use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; -use codex_protocol::protocol::MultiAgentVersion; use codex_protocol::protocol::RolloutItem; use codex_protocol::protocol::SessionMeta; use codex_protocol::protocol::SessionMetaLine; @@ -24,7 +23,6 @@ use crate::LoadThreadHistoryParams; use crate::ReadThreadByRolloutPathParams; use crate::ReadThreadParams; use crate::ResumeThreadParams; -use crate::SetMultiAgentVersionIfUnsetParams; use crate::StoredThread; use crate::StoredThreadHistory; use crate::ThreadMetadataPatch; @@ -212,39 +210,6 @@ impl ThreadStore for InMemoryThreadStore { Ok(()) } - async fn set_multi_agent_version_if_unset( - &self, - params: SetMultiAgentVersionIfUnsetParams, - ) -> ThreadStoreResult { - let mut state = self.state.lock().await; - let history = - state - .histories - .get_mut(¶ms.thread_id) - .ok_or(ThreadStoreError::ThreadNotFound { - thread_id: params.thread_id, - })?; - let mut session_meta = history - .iter() - .rev() - .find_map(|item| match item { - RolloutItem::SessionMeta(meta_line) if meta_line.meta.id == params.thread_id => { - Some(meta_line.clone()) - } - _ => None, - }) - .ok_or_else(|| ThreadStoreError::InvalidRequest { - message: format!("thread {} does not have session metadata", params.thread_id), - })?; - if let Some(multi_agent_version) = session_meta.meta.multi_agent_version { - return Ok(multi_agent_version); - } - session_meta.git = None; - session_meta.meta.multi_agent_version = Some(params.multi_agent_version); - history.push(RolloutItem::SessionMeta(session_meta)); - Ok(params.multi_agent_version) - } - async fn append_items(&self, params: AppendThreadItemsParams) -> ThreadStoreResult<()> { let mut state = self.state.lock().await; state.calls.append_items += 1; diff --git a/codex-rs/thread-store/src/lib.rs b/codex-rs/thread-store/src/lib.rs index 53cde2715d..aec8270a53 100644 --- a/codex-rs/thread-store/src/lib.rs +++ b/codex-rs/thread-store/src/lib.rs @@ -35,7 +35,6 @@ pub use types::ReadThreadByRolloutPathParams; pub use types::ReadThreadParams; pub use types::ResumeThreadParams; pub use types::SearchThreadsParams; -pub use types::SetMultiAgentVersionIfUnsetParams; pub use types::SortDirection; pub use types::StoredThread; pub use types::StoredThreadHistory; diff --git a/codex-rs/thread-store/src/local/mod.rs b/codex-rs/thread-store/src/local/mod.rs index 234c98dcd2..4b74dd12ca 100644 --- a/codex-rs/thread-store/src/local/mod.rs +++ b/codex-rs/thread-store/src/local/mod.rs @@ -5,7 +5,6 @@ mod list_threads; mod live_writer; mod read_thread; mod search_threads; -mod set_multi_agent_version_if_unset; mod unarchive_thread; mod update_thread_metadata; @@ -21,7 +20,6 @@ use std::collections::hash_map::Entry; use std::path::PathBuf; use std::sync::Arc; use tokio::sync::Mutex; -use tokio::sync::Semaphore; use crate::AppendThreadItemsParams; use crate::ArchiveThreadParams; @@ -32,7 +30,6 @@ use crate::ReadThreadByRolloutPathParams; use crate::ReadThreadParams; use crate::ResumeThreadParams; use crate::SearchThreadsParams; -use crate::SetMultiAgentVersionIfUnsetParams; use crate::StoredThread; use crate::StoredThreadHistory; use crate::ThreadPage; @@ -41,7 +38,6 @@ use crate::ThreadStore; use crate::ThreadStoreError; use crate::ThreadStoreResult; use crate::UpdateThreadMetadataParams; -use codex_protocol::protocol::MultiAgentVersion; /// Local filesystem/SQLite-backed implementation of [`ThreadStore`]. /// @@ -60,7 +56,6 @@ use codex_protocol::protocol::MultiAgentVersion; pub struct LocalThreadStore { pub(super) config: LocalThreadStoreConfig, live_recorders: Arc>>, - multi_agent_version_update_gate: Arc, state_db: Option, } @@ -100,7 +95,6 @@ impl LocalThreadStore { Self { config, live_recorders: Arc::new(Mutex::new(HashMap::new())), - multi_agent_version_update_gate: Arc::new(Semaphore::new(1)), state_db, } } @@ -186,13 +180,6 @@ impl ThreadStore for LocalThreadStore { live_writer::resume_thread(self, params).await } - async fn set_multi_agent_version_if_unset( - &self, - params: SetMultiAgentVersionIfUnsetParams, - ) -> ThreadStoreResult { - set_multi_agent_version_if_unset::set_multi_agent_version_if_unset(self, params).await - } - async fn append_items(&self, params: AppendThreadItemsParams) -> ThreadStoreResult<()> { live_writer::append_items(self, params).await } @@ -773,44 +760,6 @@ mod tests { assert!(err.to_string().contains("already has a live local writer")); } - #[tokio::test] - async fn set_multi_agent_version_if_unset_appends_once_and_returns_existing_value() { - let home = TempDir::new().expect("temp dir"); - let store = LocalThreadStore::new(test_config(home.path()), /*state_db*/ None); - let thread_id = ThreadId::default(); - - store - .create_thread(create_thread_params(thread_id)) - .await - .expect("create thread"); - - let first = store - .set_multi_agent_version_if_unset(SetMultiAgentVersionIfUnsetParams { - thread_id, - multi_agent_version: MultiAgentVersion::V2, - }) - .await - .expect("set missing runtime"); - assert_eq!(first, MultiAgentVersion::V2); - assert_eq!( - session_meta_versions(&store, thread_id).await, - vec![None, Some(MultiAgentVersion::V2)] - ); - - let second = store - .set_multi_agent_version_if_unset(SetMultiAgentVersionIfUnsetParams { - thread_id, - multi_agent_version: MultiAgentVersion::V1, - }) - .await - .expect("return existing runtime"); - assert_eq!(second, MultiAgentVersion::V2); - assert_eq!( - session_meta_versions(&store, thread_id).await, - vec![None, Some(MultiAgentVersion::V2)] - ); - } - #[tokio::test] async fn resume_thread_rejects_duplicate_live_writer() { let home = TempDir::new().expect("temp dir"); @@ -1104,28 +1053,6 @@ mod tests { })) } - async fn session_meta_versions( - store: &LocalThreadStore, - thread_id: ThreadId, - ) -> Vec> { - store - .load_history(LoadThreadHistoryParams { - thread_id, - include_archived: true, - }) - .await - .expect("load history") - .items - .into_iter() - .filter_map(|item| match item { - RolloutItem::SessionMeta(meta_line) if meta_line.meta.id == thread_id => { - Some(meta_line.meta.multi_agent_version) - } - _ => None, - }) - .collect() - } - async fn assert_rollout_contains_message(path: &std::path::Path, expected: &str) { let (items, _, _) = RolloutRecorder::load_rollout_items(path) .await diff --git a/codex-rs/thread-store/src/local/set_multi_agent_version_if_unset.rs b/codex-rs/thread-store/src/local/set_multi_agent_version_if_unset.rs deleted file mode 100644 index aadc5e3f69..0000000000 --- a/codex-rs/thread-store/src/local/set_multi_agent_version_if_unset.rs +++ /dev/null @@ -1,88 +0,0 @@ -use codex_protocol::protocol::MultiAgentVersion; -use codex_protocol::protocol::RolloutItem; -use codex_rollout::append_rollout_item_to_path; - -use super::LocalThreadStore; -use super::live_writer; -use super::read_thread; -use crate::AppendThreadItemsParams; -use crate::ReadThreadParams; -use crate::SetMultiAgentVersionIfUnsetParams; -use crate::ThreadStoreError; -use crate::ThreadStoreResult; - -pub(super) async fn set_multi_agent_version_if_unset( - store: &LocalThreadStore, - params: SetMultiAgentVersionIfUnsetParams, -) -> ThreadStoreResult { - let _permit = store - .multi_agent_version_update_gate - .acquire() - .await - .map_err(|err| ThreadStoreError::Internal { - message: format!("failed to set thread multi-agent version: {err}"), - })?; - let has_live_writer = live_writer::rollout_path(store, params.thread_id) - .await - .is_ok(); - if has_live_writer { - live_writer::persist_thread(store, params.thread_id).await?; - live_writer::flush_thread(store, params.thread_id).await?; - } - - let thread = read_thread::read_thread( - store, - ReadThreadParams { - thread_id: params.thread_id, - include_archived: true, - include_history: true, - }, - ) - .await?; - let rollout_path = thread - .rollout_path - .ok_or_else(|| ThreadStoreError::Internal { - message: format!("thread {} does not have a rollout path", params.thread_id), - })?; - let history = thread.history.ok_or_else(|| ThreadStoreError::Internal { - message: format!("failed to load history for thread {}", params.thread_id), - })?; - let mut session_meta = history - .items - .iter() - .rev() - .find_map(|item| match item { - RolloutItem::SessionMeta(meta_line) if meta_line.meta.id == params.thread_id => { - Some(meta_line.clone()) - } - _ => None, - }) - .ok_or_else(|| ThreadStoreError::InvalidRequest { - message: format!("thread {} does not have session metadata", params.thread_id), - })?; - if let Some(multi_agent_version) = session_meta.meta.multi_agent_version { - return Ok(multi_agent_version); - } - - session_meta.git = None; - session_meta.meta.multi_agent_version = Some(params.multi_agent_version); - let item = RolloutItem::SessionMeta(session_meta); - if has_live_writer { - live_writer::append_items( - store, - AppendThreadItemsParams { - thread_id: params.thread_id, - items: vec![item], - }, - ) - .await?; - } else { - append_rollout_item_to_path(&rollout_path, &item) - .await - .map_err(|err| ThreadStoreError::Internal { - message: format!("failed to set thread multi-agent version: {err}"), - })?; - } - - Ok(params.multi_agent_version) -} diff --git a/codex-rs/thread-store/src/store.rs b/codex-rs/thread-store/src/store.rs index ef6fc18285..7276a980da 100644 --- a/codex-rs/thread-store/src/store.rs +++ b/codex-rs/thread-store/src/store.rs @@ -14,7 +14,6 @@ use crate::ReadThreadByRolloutPathParams; use crate::ReadThreadParams; use crate::ResumeThreadParams; use crate::SearchThreadsParams; -use crate::SetMultiAgentVersionIfUnsetParams; use crate::StoredThread; use crate::StoredThreadHistory; use crate::ThreadPage; @@ -23,7 +22,6 @@ use crate::ThreadStoreError; use crate::ThreadStoreResult; use crate::TurnPage; use crate::UpdateThreadMetadataParams; -use codex_protocol::protocol::MultiAgentVersion; /// Storage-neutral thread persistence boundary. #[async_trait] @@ -37,12 +35,6 @@ pub trait ThreadStore: Any + Send + Sync { /// Reopens an existing thread for live appends. async fn resume_thread(&self, params: ResumeThreadParams) -> ThreadStoreResult<()>; - /// Sets a thread's multi-agent runtime if it is unset, returning the stored value. - async fn set_multi_agent_version_if_unset( - &self, - params: SetMultiAgentVersionIfUnsetParams, - ) -> ThreadStoreResult; - /// Appends canonical rollout items to a live thread. /// /// This is the raw history API. It does not infer metadata from item contents. Callers that diff --git a/codex-rs/thread-store/src/types.rs b/codex-rs/thread-store/src/types.rs index 1f4fc39a01..e6c46f7b34 100644 --- a/codex-rs/thread-store/src/types.rs +++ b/codex-rs/thread-store/src/types.rs @@ -66,15 +66,6 @@ pub struct ThreadPersistenceMetadata { pub memory_mode: MemoryMode, } -/// Parameters for setting a thread's multi-agent runtime when it has not been recorded yet. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct SetMultiAgentVersionIfUnsetParams { - /// Thread id whose metadata should be initialized. - pub thread_id: ThreadId, - /// Version to persist if the thread does not already have one. - pub multi_agent_version: MultiAgentVersion, -} - /// Parameters required to create a persisted thread. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CreateThreadParams {