Persist multi-agent runtime metadata (#25721)

Stack split from #25708. Original PR intentionally left open. This
second PR persists multi-agent runtime metadata through thread creation,
rollout recording, and thread storage.
This commit is contained in:
jif-oai
2026-06-02 13:05:20 +02:00
committed by GitHub
Unverified
parent 3f1fb7ed8b
commit 0c5ccd18ab
10 changed files with 65 additions and 4 deletions
@@ -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(),
@@ -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(),
@@ -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(),
+1
View File
@@ -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(),
+2
View File
@@ -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(),
+19 -1
View File
@@ -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<ThreadSource>,
base_instructions: BaseInstructions,
dynamic_tools: Vec<DynamicToolSpec>,
multi_agent_version: Option<MultiAgentVersion>,
},
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<MultiAgentVersion>,
) -> 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))
+34 -2
View File
@@ -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);
}
@@ -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 {
+1
View File
@@ -1019,6 +1019,7 @@ mod tests {
thread_source: None,
base_instructions: BaseInstructions::default(),
dynamic_tools: Vec::new(),
multi_agent_version: None,
metadata: thread_metadata(),
}
}
+3
View File
@@ -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<DynamicToolSpec>,
/// Multi-agent runtime selected when the thread was created.
pub multi_agent_version: Option<MultiAgentVersion>,
/// Metadata captured for the newly created thread.
pub metadata: ThreadPersistenceMetadata,
}