diff --git a/codex-rs/app-server/tests/suite/conversation_summary.rs b/codex-rs/app-server/tests/suite/conversation_summary.rs index 109999d90..d54f5edc5 100644 --- a/codex-rs/app-server/tests/suite/conversation_summary.rs +++ b/codex-rs/app-server/tests/suite/conversation_summary.rs @@ -128,6 +128,7 @@ async fn get_conversation_summary_by_thread_id_reads_pathless_store_thread() -> thread_source: None, base_instructions: BaseInstructions::default(), dynamic_tools: Vec::new(), + multi_agent_version: None, metadata: ThreadPersistenceMetadata { cwd: None, model_provider: "test-provider".to_string(), diff --git a/codex-rs/app-server/tests/suite/v2/thread_read.rs b/codex-rs/app-server/tests/suite/v2/thread_read.rs index 1540a84b5..17c55a74a 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_read.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_read.rs @@ -1362,6 +1362,7 @@ async fn seed_pathless_store_thread( thread_source: None, base_instructions: BaseInstructions::default(), dynamic_tools: Vec::new(), + multi_agent_version: None, metadata: ThreadPersistenceMetadata { cwd: None, model_provider: "test-provider".to_string(), diff --git a/codex-rs/app-server/tests/suite/v2/thread_unarchive.rs b/codex-rs/app-server/tests/suite/v2/thread_unarchive.rs index 70a9ff23d..09c17bb79 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_unarchive.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_unarchive.rs @@ -215,6 +215,7 @@ async fn thread_unarchive_preserves_pathless_store_metadata() -> Result<()> { thread_source: None, base_instructions: BaseInstructions::default(), dynamic_tools: Vec::new(), + multi_agent_version: None, metadata: ThreadPersistenceMetadata { cwd: None, model_provider: "test-provider".to_string(), diff --git a/codex-rs/core/src/session/session.rs b/codex-rs/core/src/session/session.rs index cdc92d3b4..966c96332 100644 --- a/codex-rs/core/src/session/session.rs +++ b/codex-rs/core/src/session/session.rs @@ -558,6 +558,7 @@ impl Session { text: session_configuration.base_instructions.clone(), }, dynamic_tools: session_configuration.dynamic_tools.clone(), + multi_agent_version: None, metadata: ThreadPersistenceMetadata { cwd: Some(config.cwd.to_path_buf()), model_provider: config.model_provider_id.clone(), diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 47b764725..28fa0ed27 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -3461,6 +3461,7 @@ async fn attach_thread_persistence(session: &mut Session) -> PathBuf { thread_source: None, base_instructions: BaseInstructions::default(), dynamic_tools: Vec::new(), + multi_agent_version: None, metadata: ThreadPersistenceMetadata { cwd: Some(config.cwd.to_path_buf()), model_provider: config.model_provider_id.clone(), @@ -5957,6 +5958,7 @@ async fn shutdown_complete_does_not_append_to_thread_store_after_shutdown() { thread_source: None, base_instructions: BaseInstructions::default(), dynamic_tools: Vec::new(), + multi_agent_version: None, metadata: ThreadPersistenceMetadata { cwd: Some(config.cwd.to_path_buf()), model_provider: config.model_provider_id.clone(), diff --git a/codex-rs/rollout/src/recorder.rs b/codex-rs/rollout/src/recorder.rs index 8f13d1844..d102d5c54 100644 --- a/codex-rs/rollout/src/recorder.rs +++ b/codex-rs/rollout/src/recorder.rs @@ -52,6 +52,7 @@ use codex_git_utils::collect_git_info; use codex_git_utils::get_git_repo_root; use codex_protocol::protocol::GitInfo as ProtocolGitInfo; use codex_protocol::protocol::InitialHistory; +use codex_protocol::protocol::MultiAgentVersion; use codex_protocol::protocol::ResumedHistory; use codex_protocol::protocol::RolloutItem; use codex_protocol::protocol::RolloutLine; @@ -87,6 +88,7 @@ pub enum RolloutRecorderParams { thread_source: Option, base_instructions: BaseInstructions, dynamic_tools: Vec, + multi_agent_version: Option, }, Resume { path: PathBuf, @@ -172,9 +174,24 @@ impl RolloutRecorderParams { thread_source, base_instructions, dynamic_tools, + multi_agent_version: None, } } + pub fn with_multi_agent_version( + mut self, + multi_agent_version: Option, + ) -> Self { + if let Self::Create { + multi_agent_version: version, + .. + } = &mut self + { + *version = multi_agent_version; + } + self + } + pub fn resume(path: PathBuf) -> Self { Self::Resume { path } } @@ -661,6 +678,7 @@ impl RolloutRecorder { thread_source, base_instructions, dynamic_tools, + multi_agent_version, } => { let log_file_info = precompute_log_file_info(config, conversation_id)?; let path = log_file_info.path.clone(); @@ -696,7 +714,7 @@ impl RolloutRecorder { Some(dynamic_tools) }, memory_mode: (!config.generate_memories()).then_some("disabled".to_string()), - multi_agent_version: None, + multi_agent_version, }; (None, Some(log_file_info), path, Some(session_meta)) diff --git a/codex-rs/thread-store/src/in_memory.rs b/codex-rs/thread-store/src/in_memory.rs index 02e64a1ff..b02fc1585 100644 --- a/codex-rs/thread-store/src/in_memory.rs +++ b/codex-rs/thread-store/src/in_memory.rs @@ -11,6 +11,9 @@ use codex_protocol::ThreadId; use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::RolloutItem; +use codex_protocol::protocol::SessionMeta; +use codex_protocol::protocol::SessionMetaLine; +use codex_protocol::protocol::ThreadMemoryMode; use crate::AppendThreadItemsParams; use crate::ArchiveThreadParams; @@ -164,7 +167,32 @@ impl ThreadStore for InMemoryThreadStore { async fn create_thread(&self, params: CreateThreadParams) -> ThreadStoreResult<()> { let mut state = self.state.lock().await; state.calls.create_thread += 1; - state.histories.entry(params.thread_id).or_default(); + let session_meta = SessionMeta { + id: params.thread_id, + forked_from_id: params.forked_from_id, + parent_thread_id: params.parent_thread_id, + cwd: params.metadata.cwd.clone().unwrap_or_default(), + agent_nickname: params.source.get_nickname(), + agent_role: params.source.get_agent_role(), + agent_path: params.source.get_agent_path().map(Into::into), + source: params.source.clone(), + thread_source: params.thread_source, + model_provider: Some(params.metadata.model_provider.clone()), + base_instructions: Some(params.base_instructions.clone()), + dynamic_tools: (!params.dynamic_tools.is_empty()).then(|| params.dynamic_tools.clone()), + memory_mode: matches!(params.metadata.memory_mode, ThreadMemoryMode::Disabled) + .then_some("disabled".to_string()), + multi_agent_version: params.multi_agent_version, + ..SessionMeta::default() + }; + state + .histories + .entry(params.thread_id) + .or_default() + .push(RolloutItem::SessionMeta(SessionMetaLine { + meta: session_meta, + git: None, + })); state.created_threads.insert(params.thread_id, params); Ok(()) } @@ -172,7 +200,11 @@ impl ThreadStore for InMemoryThreadStore { async fn resume_thread(&self, params: ResumeThreadParams) -> ThreadStoreResult<()> { let mut state = self.state.lock().await; state.calls.resume_thread += 1; - state.histories.entry(params.thread_id).or_default(); + if let Some(history) = params.history { + state.histories.insert(params.thread_id, history); + } else { + state.histories.entry(params.thread_id).or_default(); + } if let Some(rollout_path) = params.rollout_path { state.rollout_paths.insert(rollout_path, params.thread_id); } diff --git a/codex-rs/thread-store/src/local/create_thread.rs b/codex-rs/thread-store/src/local/create_thread.rs index a71bb48b0..8c630f995 100644 --- a/codex-rs/thread-store/src/local/create_thread.rs +++ b/codex-rs/thread-store/src/local/create_thread.rs @@ -35,7 +35,8 @@ pub(super) async fn create_thread( params.thread_source, params.base_instructions, params.dynamic_tools, - ), + ) + .with_multi_agent_version(params.multi_agent_version), ) .await .map_err(|err| ThreadStoreError::Internal { diff --git a/codex-rs/thread-store/src/local/mod.rs b/codex-rs/thread-store/src/local/mod.rs index 85fa6ad78..146bfbd84 100644 --- a/codex-rs/thread-store/src/local/mod.rs +++ b/codex-rs/thread-store/src/local/mod.rs @@ -1019,6 +1019,7 @@ mod tests { thread_source: None, base_instructions: BaseInstructions::default(), dynamic_tools: Vec::new(), + multi_agent_version: None, metadata: thread_metadata(), } } diff --git a/codex-rs/thread-store/src/types.rs b/codex-rs/thread-store/src/types.rs index 7c09259a6..1ab42a311 100644 --- a/codex-rs/thread-store/src/types.rs +++ b/codex-rs/thread-store/src/types.rs @@ -9,6 +9,7 @@ use codex_protocol::models::PermissionProfile; use codex_protocol::openai_models::ReasoningEffort; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::GitInfo; +use codex_protocol::protocol::MultiAgentVersion; use codex_protocol::protocol::RolloutItem; use codex_protocol::protocol::SessionSource; use codex_protocol::protocol::ThreadMemoryMode as MemoryMode; @@ -72,6 +73,8 @@ pub struct CreateThreadParams { pub base_instructions: BaseInstructions, /// Dynamic tools available to the thread at startup. pub dynamic_tools: Vec, + /// Multi-agent runtime selected when the thread was created. + pub multi_agent_version: Option, /// Metadata captured for the newly created thread. pub metadata: ThreadPersistenceMetadata, }