mirror of
https://github.com/openai/codex.git
synced 2026-09-06 15:29:32 +00:00
Split world state settings by topic
This commit is contained in:
40
codex-rs/core/src/context/world_state/collaboration_mode.rs
Normal file
40
codex-rs/core/src/context/world_state/collaboration_mode.rs
Normal file
@@ -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<Option<CollaborationMode>>,
|
||||
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<ResponseItem> {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
@@ -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<ResponseItem> {
|
||||
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::<Vec<_>>();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
44
codex-rs/core/src/context/world_state/model.rs
Normal file
44
codex-rs/core/src/context/world_state/model.rs
Normal file
@@ -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<String>,
|
||||
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<String> {
|
||||
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<ResponseItem> {
|
||||
self.rendered_diff(previous).map(developer_message)
|
||||
}
|
||||
}
|
||||
52
codex-rs/core/src/context/world_state/multi_agent_mode.rs
Normal file
52
codex-rs/core/src/context/world_state/multi_agent_mode.rs
Normal file
@@ -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<Option<MultiAgentMode>>);
|
||||
|
||||
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<ResponseItem> {
|
||||
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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
74
codex-rs/core/src/context/world_state/permissions.rs
Normal file
74
codex-rs/core/src/context/world_state/permissions.rs
Normal file
@@ -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<PermissionValues>,
|
||||
rendered: Option<String>,
|
||||
}
|
||||
|
||||
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<ResponseItem> {
|
||||
let rendered = self.rendered.as_ref()?;
|
||||
(self.values != previous.values).then(|| developer_message(rendered.clone()))
|
||||
}
|
||||
}
|
||||
60
codex-rs/core/src/context/world_state/personality.rs
Normal file
60
codex-rs/core/src/context/world_state/personality.rs
Normal file
@@ -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<String>,
|
||||
personality: Option<Personality>,
|
||||
spec: Option<String>,
|
||||
}
|
||||
|
||||
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<String> {
|
||||
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<ResponseItem> {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
60
codex-rs/core/src/context/world_state/realtime.rs
Normal file
60
codex-rs/core/src/context/world_state/realtime.rs
Normal file
@@ -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<bool>,
|
||||
active_fallback: Option<bool>,
|
||||
start_instructions: Option<String>,
|
||||
}
|
||||
|
||||
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<bool>, active_fallback: Option<bool>) -> Self {
|
||||
Self {
|
||||
active,
|
||||
active_fallback,
|
||||
start_instructions: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn rendered_diff(&self, previous: &Self) -> Option<String> {
|
||||
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<ResponseItem> {
|
||||
self.rendered_diff(previous).map(developer_message)
|
||||
}
|
||||
}
|
||||
@@ -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<String>,
|
||||
model_instructions: String,
|
||||
permissions: Option<PermissionValues>,
|
||||
permissions_rendered: Option<String>,
|
||||
// The outer option tracks whether a baseline exists; the inner option is the effective mode.
|
||||
collaboration_mode: Option<Option<CollaborationMode>>,
|
||||
collaboration_mode_enabled: bool,
|
||||
multi_agent_mode: Option<Option<MultiAgentMode>>,
|
||||
realtime_active: Option<bool>,
|
||||
realtime_active_fallback: Option<bool>,
|
||||
realtime_start_instructions: Option<String>,
|
||||
personality_enabled: bool,
|
||||
personality_model: Option<String>,
|
||||
personality: Option<Personality>,
|
||||
personality_spec: Option<String>,
|
||||
}
|
||||
|
||||
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<String> {
|
||||
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<String> {
|
||||
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<String> {
|
||||
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<String> {
|
||||
render_model_update(
|
||||
previous.model.as_deref(),
|
||||
self.model.as_deref(),
|
||||
&self.model_instructions,
|
||||
)
|
||||
}
|
||||
|
||||
fn permissions_diff(&self, previous: &Self) -> Option<String> {
|
||||
let rendered = self.permissions_rendered.as_ref()?;
|
||||
(self.permissions != previous.permissions).then(|| rendered.clone())
|
||||
}
|
||||
|
||||
fn collaboration_mode_diff(&self, previous: &Self) -> Option<String> {
|
||||
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<String> {
|
||||
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<String> {
|
||||
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<String> {
|
||||
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<ResponseItem> {
|
||||
// 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::<Vec<_>>();
|
||||
(!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<String> {
|
||||
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<bool>,
|
||||
previous_active_fallback: Option<bool>,
|
||||
active: bool,
|
||||
start_instructions: Option<&str>,
|
||||
) -> Option<String> {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user