diff --git a/codex-rs/core/src/context/world_state/collaboration_mode.rs b/codex-rs/core/src/context/world_state/collaboration_mode.rs new file mode 100644 index 0000000000..4fd114fe3e --- /dev/null +++ b/codex-rs/core/src/context/world_state/collaboration_mode.rs @@ -0,0 +1,40 @@ +use super::WorldStateSection; +use super::developer_message; +use crate::context::CollaborationModeInstructions; +use crate::context::ContextualUserFragment; +use crate::session::turn_context::TurnContext; +use codex_protocol::config_types::CollaborationMode; +use codex_protocol::models::ResponseItem; +use codex_protocol::protocol::TurnContextItem; + +#[derive(Debug, Default)] +pub(crate) struct CollaborationModeState { + baseline: Option>, + enabled: bool, +} + +impl CollaborationModeState { + pub(crate) fn from_turn_context(turn_context: &TurnContext) -> Self { + Self { + baseline: Some(Some(turn_context.collaboration_mode.clone())), + enabled: turn_context.config.include_collaboration_mode_instructions, + } + } + + pub(crate) fn from_turn_context_item(turn_context_item: &TurnContextItem) -> Self { + Self { + baseline: Some(turn_context_item.collaboration_mode.clone()), + enabled: false, + } + } +} + +impl WorldStateSection for CollaborationModeState { + fn render_diff(&self, previous: &Self) -> Option { + if !self.enabled || self.baseline == previous.baseline { + return None; + } + CollaborationModeInstructions::from_collaboration_mode(self.baseline.as_ref()?.as_ref()?) + .map(|instructions| developer_message(instructions.render())) + } +} diff --git a/codex-rs/core/src/context/world_state/mod.rs b/codex-rs/core/src/context/world_state/mod.rs index bbe8313961..4613d768a3 100644 --- a/codex-rs/core/src/context/world_state/mod.rs +++ b/codex-rs/core/src/context/world_state/mod.rs @@ -1,14 +1,35 @@ +mod collaboration_mode; mod environment; -mod settings; +mod model; +mod multi_agent_mode; +mod permissions; +mod personality; +mod realtime; +use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseItem; use indexmap::IndexMap; use std::any::Any; use std::any::TypeId; use std::fmt; +pub(crate) use collaboration_mode::CollaborationModeState; pub(crate) use environment::EnvironmentsState; -pub(crate) use settings::SettingsState; +pub(crate) use model::ModelState; +pub(crate) use multi_agent_mode::MultiAgentModeState; +pub(crate) use permissions::PermissionsState; +pub(crate) use personality::PersonalityState; +pub(crate) use realtime::RealtimeState; + +fn developer_message(text: String) -> ResponseItem { + ResponseItem::Message { + id: None, + role: "developer".to_string(), + content: vec![ContentItem::InputText { text }], + phase: None, + metadata: None, + } +} trait ErasedWorldStateSection: Send + Sync { fn as_any(&self) -> &dyn Any; @@ -67,7 +88,8 @@ impl WorldState { } pub(crate) fn render_diff(&self, previous: &Self) -> Vec { - self.sections + let section_items = self + .sections .iter() .filter_map(|(type_id, section)| { let previous = previous @@ -76,6 +98,29 @@ impl WorldState { .map(|section| section.as_any()); section.render_diff(previous) }) - .collect() + .collect::>(); + let mut items = Vec::with_capacity(section_items.len()); + for item in section_items { + match (items.last_mut(), item) { + ( + Some(ResponseItem::Message { + id: None, + role: previous_role, + content: previous_content, + phase: None, + metadata: None, + }), + ResponseItem::Message { + id: None, + role, + content, + phase: None, + metadata: None, + }, + ) if *previous_role == role => previous_content.extend(content), + (_, item) => items.push(item), + } + } + items } } diff --git a/codex-rs/core/src/context/world_state/model.rs b/codex-rs/core/src/context/world_state/model.rs new file mode 100644 index 0000000000..813e1a8bcc --- /dev/null +++ b/codex-rs/core/src/context/world_state/model.rs @@ -0,0 +1,44 @@ +use super::WorldStateSection; +use super::developer_message; +use crate::context::ContextualUserFragment; +use crate::context::ModelSwitchInstructions; +use crate::session::turn_context::TurnContext; +use codex_protocol::models::ResponseItem; + +#[derive(Debug, Default)] +pub(crate) struct ModelState { + model: Option, + instructions: String, +} + +impl ModelState { + pub(crate) fn from_turn_context(turn_context: &TurnContext) -> Self { + Self { + model: Some(turn_context.model_info.slug.clone()), + instructions: turn_context + .model_info + .get_model_instructions(turn_context.personality), + } + } + + pub(crate) fn from_previous_model(model: Option<&str>) -> Self { + Self { + model: model.map(str::to_string), + instructions: String::new(), + } + } + + pub(crate) fn rendered_diff(&self, previous: &Self) -> Option { + let previous_model = previous.model.as_ref()?; + if self.model.as_ref() == Some(previous_model) || self.instructions.is_empty() { + return None; + } + Some(ModelSwitchInstructions::new(&self.instructions).render()) + } +} + +impl WorldStateSection for ModelState { + fn render_diff(&self, previous: &Self) -> Option { + self.rendered_diff(previous).map(developer_message) + } +} diff --git a/codex-rs/core/src/context/world_state/multi_agent_mode.rs b/codex-rs/core/src/context/world_state/multi_agent_mode.rs new file mode 100644 index 0000000000..baceb4552d --- /dev/null +++ b/codex-rs/core/src/context/world_state/multi_agent_mode.rs @@ -0,0 +1,52 @@ +use super::WorldStateSection; +use super::developer_message; +use crate::context::ContextualUserFragment; +use crate::context::MultiAgentModeInstructions; +use crate::session::multi_agents; +use crate::session::turn_context::TurnContext; +use codex_features::Feature; +use codex_protocol::config_types::MultiAgentMode; +use codex_protocol::models::ResponseItem; +use codex_protocol::protocol::TurnContextItem; + +#[derive(Debug, Default)] +pub(crate) struct MultiAgentModeState(Option>); + +impl MultiAgentModeState { + pub(crate) fn from_turn_context(turn_context: &TurnContext) -> Self { + Self(Some(multi_agents::effective_multi_agent_mode( + turn_context.multi_agent_version, + &turn_context.config.multi_agent_v2, + &turn_context.session_source, + turn_context.multi_agent_mode, + turn_context + .config + .features + .enabled(Feature::MultiAgentMode), + ))) + } + + pub(crate) fn from_turn_context_item(turn_context_item: &TurnContextItem) -> Self { + Self(Some(turn_context_item.multi_agent_mode)) + } +} + +impl WorldStateSection for MultiAgentModeState { + fn render_diff(&self, previous: &Self) -> Option { + let previous_mode = previous.0.as_ref()?; + let current_mode = self.0.as_ref()?; + if current_mode == previous_mode { + return None; + } + let mode = match current_mode { + Some(mode) => *mode, + None if *previous_mode == Some(MultiAgentMode::Proactive) => { + MultiAgentMode::ExplicitRequestOnly + } + None => return None, + }; + Some(developer_message( + MultiAgentModeInstructions::new(mode).render(), + )) + } +} diff --git a/codex-rs/core/src/context/world_state/permissions.rs b/codex-rs/core/src/context/world_state/permissions.rs new file mode 100644 index 0000000000..726ac0fa20 --- /dev/null +++ b/codex-rs/core/src/context/world_state/permissions.rs @@ -0,0 +1,74 @@ +use super::WorldStateSection; +use super::developer_message; +use crate::context::ContextualUserFragment; +use crate::context::PermissionsInstructions; +use crate::session::turn_context::TurnContext; +use codex_execpolicy::Policy; +use codex_features::Feature; +use codex_protocol::models::PermissionProfile; +use codex_protocol::models::ResponseItem; +use codex_protocol::protocol::AskForApproval; +use codex_protocol::protocol::TurnContextItem; + +#[derive(Debug, PartialEq)] +struct PermissionValues { + permission_profile: PermissionProfile, + approval_policy: AskForApproval, +} + +#[derive(Debug, Default)] +pub(crate) struct PermissionsState { + values: Option, + rendered: Option, +} + +impl PermissionsState { + pub(crate) fn from_turn_context(turn_context: &TurnContext, exec_policy: &Policy) -> Self { + let rendered = turn_context + .config + .include_permissions_instructions + .then(|| { + PermissionsInstructions::from_permission_profile( + &turn_context.permission_profile, + turn_context.approval_policy.value(), + turn_context.config.approvals_reviewer, + exec_policy, + #[allow(deprecated)] + &turn_context.cwd, + turn_context + .config + .features + .enabled(Feature::ExecPermissionApprovals), + turn_context + .config + .features + .enabled(Feature::RequestPermissionsTool), + ) + .render() + }); + Self { + values: Some(PermissionValues { + permission_profile: turn_context.permission_profile(), + approval_policy: turn_context.approval_policy.value(), + }), + rendered, + } + } + + pub(crate) fn from_turn_context_item(turn_context_item: &TurnContextItem) -> Self { + Self { + values: Some(PermissionValues { + permission_profile: turn_context_item.permission_profile(), + approval_policy: turn_context_item.approval_policy, + }), + rendered: None, + } + } +} + +impl WorldStateSection for PermissionsState { + fn render_diff(&self, previous: &Self) -> Option { + let rendered = self.rendered.as_ref()?; + (self.values != previous.values).then(|| developer_message(rendered.clone())) + } +} diff --git a/codex-rs/core/src/context/world_state/personality.rs b/codex-rs/core/src/context/world_state/personality.rs new file mode 100644 index 0000000000..eacbedb8cb --- /dev/null +++ b/codex-rs/core/src/context/world_state/personality.rs @@ -0,0 +1,60 @@ +use super::WorldStateSection; +use super::developer_message; +use crate::context::ContextualUserFragment; +use crate::context::PersonalitySpecInstructions; +use crate::session::turn_context::TurnContext; +use codex_protocol::config_types::Personality; +use codex_protocol::models::ResponseItem; +use codex_protocol::openai_models::ModelInfo; +use codex_protocol::protocol::TurnContextItem; + +#[derive(Debug, Default)] +pub(crate) struct PersonalityState { + enabled: bool, + model: Option, + personality: Option, + spec: Option, +} + +impl PersonalityState { + pub(crate) fn from_turn_context(turn_context: &TurnContext, enabled: bool) -> Self { + let personality = turn_context.personality; + Self { + enabled, + model: Some(turn_context.model_info.slug.clone()), + personality, + spec: personality + .and_then(|personality| Self::message(&turn_context.model_info, personality)), + } + } + + pub(crate) fn from_turn_context_item(turn_context_item: &TurnContextItem) -> Self { + Self { + enabled: false, + model: Some(turn_context_item.model.clone()), + personality: turn_context_item.personality, + spec: None, + } + } + + pub(crate) fn message(model_info: &ModelInfo, personality: Personality) -> Option { + model_info + .model_messages + .as_ref() + .and_then(|spec| spec.get_personality_message(Some(personality))) + .filter(|message| !message.is_empty()) + } +} + +impl WorldStateSection for PersonalityState { + fn render_diff(&self, previous: &Self) -> Option { + if !self.enabled || self.model != previous.model || self.personality == previous.personality + { + return None; + } + self.personality?; + self.spec + .as_ref() + .map(|spec| developer_message(PersonalitySpecInstructions::new(spec).render())) + } +} diff --git a/codex-rs/core/src/context/world_state/realtime.rs b/codex-rs/core/src/context/world_state/realtime.rs new file mode 100644 index 0000000000..05774c676a --- /dev/null +++ b/codex-rs/core/src/context/world_state/realtime.rs @@ -0,0 +1,60 @@ +use super::WorldStateSection; +use super::developer_message; +use crate::context::ContextualUserFragment; +use crate::context::RealtimeEndInstructions; +use crate::context::RealtimeStartInstructions; +use crate::context::RealtimeStartWithInstructions; +use crate::session::turn_context::TurnContext; +use codex_protocol::models::ResponseItem; + +#[derive(Debug, Default)] +pub(crate) struct RealtimeState { + active: Option, + active_fallback: Option, + start_instructions: Option, +} + +impl RealtimeState { + pub(crate) fn from_turn_context(turn_context: &TurnContext) -> Self { + Self { + active: Some(turn_context.realtime_active), + active_fallback: None, + start_instructions: turn_context + .config + .experimental_realtime_start_instructions + .clone(), + } + } + + pub(crate) fn from_previous(active: Option, active_fallback: Option) -> Self { + Self { + active, + active_fallback, + start_instructions: None, + } + } + + pub(crate) fn rendered_diff(&self, previous: &Self) -> Option { + match (previous.active, self.active.unwrap_or(false)) { + (Some(true), false) => Some(RealtimeEndInstructions::new("inactive").render()), + (Some(false), true) | (None, true) => Some( + if let Some(instructions) = self.start_instructions.as_deref() { + RealtimeStartWithInstructions::new(instructions).render() + } else { + RealtimeStartInstructions.render() + }, + ), + (Some(true), true) | (Some(false), false) => None, + (None, false) => previous + .active_fallback + .filter(|active| *active) + .map(|_| RealtimeEndInstructions::new("inactive").render()), + } + } +} + +impl WorldStateSection for RealtimeState { + fn render_diff(&self, previous: &Self) -> Option { + self.rendered_diff(previous).map(developer_message) + } +} diff --git a/codex-rs/core/src/context/world_state/settings.rs b/codex-rs/core/src/context/world_state/settings.rs deleted file mode 100644 index 1c6b4ef3fc..0000000000 --- a/codex-rs/core/src/context/world_state/settings.rs +++ /dev/null @@ -1,303 +0,0 @@ -use super::WorldStateSection; -use crate::context::CollaborationModeInstructions; -use crate::context::ContextualUserFragment; -use crate::context::ModelSwitchInstructions; -use crate::context::MultiAgentModeInstructions; -use crate::context::PermissionsInstructions; -use crate::context::PersonalitySpecInstructions; -use crate::context::RealtimeEndInstructions; -use crate::context::RealtimeStartInstructions; -use crate::context::RealtimeStartWithInstructions; -use crate::session::PreviousTurnSettings; -use crate::session::multi_agents; -use crate::session::turn_context::TurnContext; -use codex_execpolicy::Policy; -use codex_features::Feature; -use codex_protocol::config_types::CollaborationMode; -use codex_protocol::config_types::MultiAgentMode; -use codex_protocol::config_types::Personality; -use codex_protocol::models::ContentItem; -use codex_protocol::models::PermissionProfile; -use codex_protocol::models::ResponseItem; -use codex_protocol::openai_models::ModelInfo; -use codex_protocol::protocol::AskForApproval; -use codex_protocol::protocol::TurnContextItem; - -#[derive(Debug, PartialEq)] -struct PermissionValues { - permission_profile: PermissionProfile, - approval_policy: AskForApproval, -} - -#[derive(Debug, Default)] -pub(crate) struct SettingsState { - model: Option, - model_instructions: String, - permissions: Option, - permissions_rendered: Option, - // The outer option tracks whether a baseline exists; the inner option is the effective mode. - collaboration_mode: Option>, - collaboration_mode_enabled: bool, - multi_agent_mode: Option>, - realtime_active: Option, - realtime_active_fallback: Option, - realtime_start_instructions: Option, - personality_enabled: bool, - personality_model: Option, - personality: Option, - personality_spec: Option, -} - -impl SettingsState { - pub(crate) fn from_turn_context( - turn_context: &TurnContext, - exec_policy: &Policy, - personality_enabled: bool, - ) -> Self { - let permissions_rendered = - turn_context - .config - .include_permissions_instructions - .then(|| { - PermissionsInstructions::from_permission_profile( - &turn_context.permission_profile, - turn_context.approval_policy.value(), - turn_context.config.approvals_reviewer, - exec_policy, - #[allow(deprecated)] - &turn_context.cwd, - turn_context - .config - .features - .enabled(Feature::ExecPermissionApprovals), - turn_context - .config - .features - .enabled(Feature::RequestPermissionsTool), - ) - .render() - }); - let model = turn_context.model_info.slug.clone(); - let personality = turn_context.personality; - Self { - model: Some(model.clone()), - model_instructions: turn_context.model_info.get_model_instructions(personality), - permissions: Some(PermissionValues { - permission_profile: turn_context.permission_profile(), - approval_policy: turn_context.approval_policy.value(), - }), - permissions_rendered, - collaboration_mode: Some(Some(turn_context.collaboration_mode.clone())), - collaboration_mode_enabled: turn_context.config.include_collaboration_mode_instructions, - multi_agent_mode: Some(multi_agents::effective_multi_agent_mode( - turn_context.multi_agent_version, - &turn_context.config.multi_agent_v2, - &turn_context.session_source, - turn_context.multi_agent_mode, - turn_context - .config - .features - .enabled(Feature::MultiAgentMode), - )), - realtime_active: Some(turn_context.realtime_active), - realtime_active_fallback: None, - realtime_start_instructions: turn_context - .config - .experimental_realtime_start_instructions - .clone(), - personality_enabled, - personality_model: Some(model), - personality, - personality_spec: personality.and_then(|personality| { - Self::personality_message(&turn_context.model_info, personality) - }), - } - } - - pub(crate) fn from_turn_context_item( - turn_context_item: &TurnContextItem, - previous_turn_settings: Option<&PreviousTurnSettings>, - ) -> Self { - Self { - model: previous_turn_settings.map(|settings| settings.model.clone()), - model_instructions: String::new(), - permissions: Some(PermissionValues { - permission_profile: turn_context_item.permission_profile(), - approval_policy: turn_context_item.approval_policy, - }), - permissions_rendered: None, - collaboration_mode: Some(turn_context_item.collaboration_mode.clone()), - collaboration_mode_enabled: false, - multi_agent_mode: Some(turn_context_item.multi_agent_mode), - realtime_active: turn_context_item.realtime_active, - realtime_active_fallback: previous_turn_settings - .and_then(|settings| settings.realtime_active), - realtime_start_instructions: None, - personality_enabled: false, - personality_model: Some(turn_context_item.model.clone()), - personality: turn_context_item.personality, - personality_spec: None, - } - } - - pub(crate) fn model_update( - previous_turn_settings: Option<&PreviousTurnSettings>, - turn_context: &TurnContext, - ) -> Option { - render_model_update( - previous_turn_settings.map(|settings| settings.model.as_str()), - Some(turn_context.model_info.slug.as_str()), - &turn_context - .model_info - .get_model_instructions(turn_context.personality), - ) - } - - pub(crate) fn realtime_update( - previous: Option<&TurnContextItem>, - previous_turn_settings: Option<&PreviousTurnSettings>, - turn_context: &TurnContext, - ) -> Option { - render_realtime_update( - previous.and_then(|item| item.realtime_active), - previous_turn_settings.and_then(|settings| settings.realtime_active), - turn_context.realtime_active, - turn_context - .config - .experimental_realtime_start_instructions - .as_deref(), - ) - } - - pub(crate) fn personality_message( - model_info: &ModelInfo, - personality: Personality, - ) -> Option { - model_info - .model_messages - .as_ref() - .and_then(|spec| spec.get_personality_message(Some(personality))) - .filter(|message| !message.is_empty()) - } - - fn model_diff(&self, previous: &Self) -> Option { - render_model_update( - previous.model.as_deref(), - self.model.as_deref(), - &self.model_instructions, - ) - } - - fn permissions_diff(&self, previous: &Self) -> Option { - let rendered = self.permissions_rendered.as_ref()?; - (self.permissions != previous.permissions).then(|| rendered.clone()) - } - - fn collaboration_mode_diff(&self, previous: &Self) -> Option { - if !self.collaboration_mode_enabled - || self.collaboration_mode == previous.collaboration_mode - { - return None; - } - let collaboration_mode = self.collaboration_mode.as_ref()?.as_ref()?; - CollaborationModeInstructions::from_collaboration_mode(collaboration_mode) - .map(|instructions| instructions.render()) - } - - fn multi_agent_mode_diff(&self, previous: &Self) -> Option { - let previous_mode = previous.multi_agent_mode.as_ref()?; - let current_mode = self.multi_agent_mode.as_ref()?; - if current_mode == previous_mode { - return None; - } - match current_mode { - Some(mode) => Some(MultiAgentModeInstructions::new(*mode).render()), - None if *previous_mode == Some(MultiAgentMode::Proactive) => { - Some(MultiAgentModeInstructions::new(MultiAgentMode::ExplicitRequestOnly).render()) - } - None => None, - } - } - - fn realtime_diff(&self, previous: &Self) -> Option { - render_realtime_update( - previous.realtime_active, - previous.realtime_active_fallback, - self.realtime_active.unwrap_or(false), - self.realtime_start_instructions.as_deref(), - ) - } - - fn personality_diff(&self, previous: &Self) -> Option { - if !self.personality_enabled - || self.personality_model != previous.personality_model - || self.personality == previous.personality - { - return None; - } - self.personality?; - self.personality_spec - .as_ref() - .map(|spec| PersonalitySpecInstructions::new(spec).render()) - } -} - -impl WorldStateSection for SettingsState { - fn render_diff(&self, previous: &Self) -> Option { - // Keep model-switch instructions first so the new model sees its guidance before other - // settings updates, while retaining one developer message for the complete diff. - let content = [ - self.model_diff(previous), - self.permissions_diff(previous), - self.collaboration_mode_diff(previous), - self.multi_agent_mode_diff(previous), - self.realtime_diff(previous), - self.personality_diff(previous), - ] - .into_iter() - .flatten() - .map(|text| ContentItem::InputText { text }) - .collect::>(); - (!content.is_empty()).then(|| ResponseItem::Message { - id: None, - role: "developer".to_string(), - content, - phase: None, - metadata: None, - }) - } -} - -fn render_model_update( - previous_model: Option<&str>, - current_model: Option<&str>, - model_instructions: &str, -) -> Option { - let previous_model = previous_model?; - if current_model == Some(previous_model) || model_instructions.is_empty() { - return None; - } - Some(ModelSwitchInstructions::new(model_instructions).render()) -} - -fn render_realtime_update( - previous_active: Option, - previous_active_fallback: Option, - active: bool, - start_instructions: Option<&str>, -) -> Option { - match (previous_active, active) { - (Some(true), false) => Some(RealtimeEndInstructions::new("inactive").render()), - (Some(false), true) | (None, true) => { - Some(if let Some(instructions) = start_instructions { - RealtimeStartWithInstructions::new(instructions).render() - } else { - RealtimeStartInstructions.render() - }) - } - (Some(true), true) | (Some(false), false) => None, - (None, false) => previous_active_fallback - .filter(|realtime_active| *realtime_active) - .map(|_| RealtimeEndInstructions::new("inactive").render()), - } -} diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index d72e8a9dec..4ff4af2137 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -32,7 +32,9 @@ use crate::context::NetworkRuleSaved; use crate::context::PermissionsInstructions; use crate::context::PersonalitySpecInstructions; use crate::context::RecommendedPluginsInstructions; -use crate::context::world_state::SettingsState; +use crate::context::world_state::ModelState; +use crate::context::world_state::PersonalityState; +use crate::context::world_state::RealtimeState; use crate::current_time::TimeProvider; use crate::default_skill_metadata_budget; use crate::environment_selection::TurnEnvironmentSnapshot; @@ -3029,8 +3031,12 @@ impl Session { state.auto_compact_window_id(), ) }; - if let Some(model_switch_message) = - SettingsState::model_update(previous_turn_settings.as_ref(), turn_context) + if let Some(model_switch_message) = ModelState::from_turn_context(turn_context) + .rendered_diff(&ModelState::from_previous_model( + previous_turn_settings + .as_ref() + .map(|settings| settings.model.as_str()), + )) { developer_sections.push(model_switch_message); } @@ -3072,10 +3078,15 @@ impl Session { { developer_sections.push(collab_instructions.render()); } - if let Some(realtime_update) = SettingsState::realtime_update( - reference_context_item.as_ref(), - previous_turn_settings.as_ref(), - turn_context, + if let Some(realtime_update) = RealtimeState::from_turn_context(turn_context).rendered_diff( + &RealtimeState::from_previous( + reference_context_item + .as_ref() + .and_then(|item| item.realtime_active), + previous_turn_settings + .as_ref() + .and_then(|settings| settings.realtime_active), + ), ) { developer_sections.push(realtime_update); } @@ -3087,7 +3098,7 @@ impl Session { && base_instructions == model_info.get_model_instructions(Some(personality)); if !has_baked_personality && let Some(personality_message) = - SettingsState::personality_message(&model_info, personality) + PersonalityState::message(&model_info, personality) { developer_sections .push(PersonalitySpecInstructions::new(personality_message).render()); diff --git a/codex-rs/core/src/session/world_state.rs b/codex-rs/core/src/session/world_state.rs index 086ea36340..2b4c0f1489 100644 --- a/codex-rs/core/src/session/world_state.rs +++ b/codex-rs/core/src/session/world_state.rs @@ -2,7 +2,12 @@ use super::PreviousTurnSettings; use super::Session; use super::turn_context::TurnContext; use crate::context::EnvironmentsState; -use crate::context::world_state::SettingsState; +use crate::context::world_state::CollaborationModeState; +use crate::context::world_state::ModelState; +use crate::context::world_state::MultiAgentModeState; +use crate::context::world_state::PermissionsState; +use crate::context::world_state::PersonalityState; +use crate::context::world_state::RealtimeState; use crate::context::world_state::WorldState; use crate::environment_selection::TurnEnvironmentSnapshot; use codex_execpolicy::Policy; @@ -17,9 +22,16 @@ fn build_world_state_from_turn_context_with_environments( personality_feature_enabled: bool, ) -> WorldState { let mut world_state = WorldState::default(); - world_state.add_section(SettingsState::from_turn_context( + world_state.add_section(ModelState::from_turn_context(turn_context)); + world_state.add_section(PermissionsState::from_turn_context( turn_context, exec_policy, + )); + world_state.add_section(CollaborationModeState::from_turn_context(turn_context)); + world_state.add_section(MultiAgentModeState::from_turn_context(turn_context)); + world_state.add_section(RealtimeState::from_turn_context(turn_context)); + world_state.add_section(PersonalityState::from_turn_context( + turn_context, personality_feature_enabled, )); if turn_context.config.include_environment_context { @@ -36,10 +48,21 @@ pub(crate) fn build_world_state_from_turn_context_item( previous_turn_settings: Option<&PreviousTurnSettings>, ) -> WorldState { let mut world_state = WorldState::default(); - world_state.add_section(SettingsState::from_turn_context_item( - turn_context_item, - previous_turn_settings, + world_state.add_section(ModelState::from_previous_model( + previous_turn_settings.map(|settings| settings.model.as_str()), )); + world_state.add_section(PermissionsState::from_turn_context_item(turn_context_item)); + world_state.add_section(CollaborationModeState::from_turn_context_item( + turn_context_item, + )); + world_state.add_section(MultiAgentModeState::from_turn_context_item( + turn_context_item, + )); + world_state.add_section(RealtimeState::from_previous( + turn_context_item.realtime_active, + previous_turn_settings.and_then(|settings| settings.realtime_active), + )); + world_state.add_section(PersonalityState::from_turn_context_item(turn_context_item)); world_state.add_section(EnvironmentsState::from_turn_context_item(turn_context_item)); world_state }