codex: persist multi-agent version metadata

This commit is contained in:
Ahmed Ibrahim
2026-05-29 15:33:17 -07:00
parent a076b21730
commit 88f173945d
37 changed files with 386 additions and 3 deletions
+7
View File
@@ -237,6 +237,13 @@ pub enum ToolMode {
CodeModeOnly,
}
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, TS, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum MultiAgentVersion {
V1,
V2,
}
fn deserialize_optional_model_selector<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
+107
View File
@@ -43,6 +43,7 @@ use crate::models::ResponseItem;
use crate::models::SandboxEnforcement;
use crate::models::WebSearchAction;
use crate::num_format::format_with_separators;
use crate::openai_models::MultiAgentVersion;
use crate::openai_models::ReasoningEffort as ReasoningEffortConfig;
use crate::parse_command::ParsedCommand;
use crate::plan_tool::UpdatePlanArgs;
@@ -53,6 +54,7 @@ use crate::user_input::UserInput;
use codex_utils_absolute_path::AbsolutePathBuf;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde_json::Value;
use serde_with::serde_as;
@@ -2461,6 +2463,33 @@ impl InitialHistory {
}
}
}
pub fn get_multi_agent_version(&self) -> Option<MultiAgentVersion> {
match self {
InitialHistory::New | InitialHistory::Cleared => None,
InitialHistory::Resumed(resumed) => resumed
.history
.iter()
.rev()
.find_map(|item| match item {
RolloutItem::SessionMeta(meta_line)
if meta_line.meta.id == resumed.conversation_id =>
{
Some(meta_line.meta.multi_agent_version)
}
_ => None,
})
.flatten(),
InitialHistory::Forked(items) => items
.iter()
.rev()
.find_map(|item| match item {
RolloutItem::SessionMeta(meta_line) => Some(meta_line.meta.multi_agent_version),
_ => None,
})
.flatten(),
}
}
}
fn session_cwd_from_items(items: &[RolloutItem]) -> Option<PathBuf> {
@@ -2734,6 +2763,13 @@ pub struct SessionMeta {
#[serde(skip_serializing_if = "Option::is_none")]
pub agent_path: Option<String>,
pub model_provider: Option<String>,
/// Thread-scoped multi-agent runtime selector.
#[serde(
default,
deserialize_with = "deserialize_optional_multi_agent_version",
skip_serializing_if = "Option::is_none"
)]
pub multi_agent_version: Option<MultiAgentVersion>,
/// base_instructions for the session. This *should* always be present when creating a new session,
/// but may be missing for older sessions. If not present, fall back to rendering the base_instructions
/// from ModelsManager.
@@ -2744,6 +2780,18 @@ pub struct SessionMeta {
pub memory_mode: Option<String>,
}
fn deserialize_optional_multi_agent_version<'de, D>(
deserializer: D,
) -> Result<Option<MultiAgentVersion>, D::Error>
where
D: Deserializer<'de>,
{
let Some(value) = Option::<String>::deserialize(deserializer)? else {
return Ok(None);
};
Ok(serde_json::from_value(Value::String(value)).ok())
}
impl Default for SessionMeta {
fn default() -> Self {
SessionMeta {
@@ -2759,6 +2807,7 @@ impl Default for SessionMeta {
agent_role: None,
agent_path: None,
model_provider: None,
multi_agent_version: None,
base_instructions: None,
dynamic_tools: None,
memory_mode: None,
@@ -5488,4 +5537,62 @@ mod tests {
assert_eq!(info.model_context_window, Some(258_400));
}
#[test]
fn session_meta_treats_unknown_multi_agent_version_as_omitted() -> Result<()> {
let mut value = serde_json::to_value(SessionMeta::default())?;
value["multi_agent_version"] = json!("v3");
let meta: SessionMeta = serde_json::from_value(value)?;
assert_eq!(meta.multi_agent_version, None);
assert_eq!(
serde_json::to_value(meta)?
.as_object()
.expect("session meta should serialize as an object")
.get("multi_agent_version"),
None
);
Ok(())
}
#[test]
fn resumed_history_uses_latest_matching_multi_agent_version() {
let thread_id = ThreadId::new();
let unrelated_thread_id = ThreadId::new();
let initial_history = InitialHistory::Resumed(ResumedHistory {
conversation_id: thread_id,
history: vec![
RolloutItem::SessionMeta(SessionMetaLine {
meta: SessionMeta {
id: thread_id,
..Default::default()
},
git: None,
}),
RolloutItem::SessionMeta(SessionMetaLine {
meta: SessionMeta {
id: unrelated_thread_id,
multi_agent_version: Some(MultiAgentVersion::V1),
..Default::default()
},
git: None,
}),
RolloutItem::SessionMeta(SessionMetaLine {
meta: SessionMeta {
id: thread_id,
multi_agent_version: Some(MultiAgentVersion::V2),
..Default::default()
},
git: None,
}),
],
rollout_path: None,
});
assert_eq!(
initial_history.get_multi_agent_version(),
Some(MultiAgentVersion::V2)
);
}
}