mirror of
https://github.com/openai/codex.git
synced 2026-10-31 19:28:49 +00:00
codex: persist multi-agent version metadata
This commit is contained in:
@@ -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>,
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user