mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
simplify
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -80,7 +80,7 @@ pub struct TurnContext {
|
||||
pub(crate) compact_prompt: Option<String>,
|
||||
pub(crate) user_instructions: Option<String>,
|
||||
pub(crate) collaboration_mode: CollaborationMode,
|
||||
pub(crate) multi_agent_version: Option<MultiAgentVersion>,
|
||||
pub(crate) multi_agent_version: MultiAgentVersion,
|
||||
pub(crate) personality: Option<Personality>,
|
||||
pub(crate) approval_policy: Constrained<AskForApproval>,
|
||||
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<MultiAgentVersion>,
|
||||
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
|
||||
|
||||
@@ -73,12 +73,12 @@ pub(crate) enum InterruptedTurnHistoryMarker {
|
||||
impl InterruptedTurnHistoryMarker {
|
||||
pub(crate) fn from_config_and_version(
|
||||
config: &Config,
|
||||
multi_agent_version: Option<MultiAgentVersion>,
|
||||
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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -111,11 +111,7 @@ async fn build_runner_options(
|
||||
turn: &Arc<TurnContext>,
|
||||
requested_concurrency: Option<usize>,
|
||||
) -> Result<JobRunnerOptions, FunctionCallError> {
|
||||
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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2727,7 +2727,7 @@ fn multi_agent_version_from_items(
|
||||
items: &[RolloutItem],
|
||||
thread_id: Option<ThreadId>,
|
||||
) -> Option<MultiAgentVersion> {
|
||||
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<CollaborationMode>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub multi_agent_version: Option<MultiAgentVersion>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub realtime_active: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub effort: Option<ReasoningEffortConfig>,
|
||||
@@ -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,
|
||||
|
||||
@@ -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(());
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<MultiAgentVersion> {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Mutex<HashMap<ThreadId, RolloutRecorder>>>,
|
||||
multi_agent_version_update_gate: Arc<Semaphore>,
|
||||
state_db: Option<StateDbHandle>,
|
||||
}
|
||||
|
||||
@@ -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<MultiAgentVersion> {
|
||||
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<Option<MultiAgentVersion>> {
|
||||
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
|
||||
|
||||
@@ -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<MultiAgentVersion> {
|
||||
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)
|
||||
}
|
||||
@@ -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<MultiAgentVersion>;
|
||||
|
||||
/// Appends canonical rollout items to a live thread.
|
||||
///
|
||||
/// This is the raw history API. It does not infer metadata from item contents. Callers that
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user