Flatten turn collaboration mode state

This commit is contained in:
Ahmed Ibrahim
2026-07-09 16:30:28 -07:00
parent ac3da4fb1a
commit b6ca728faf
16 changed files with 58 additions and 41 deletions
+1 -1
View File
@@ -130,7 +130,7 @@ pub(crate) async fn run_compact_task(
trace_id: turn_context.trace_id.clone(),
started_at: turn_context.turn_timing_state.started_at_unix_secs().await,
model_context_window: turn_context.model_context_window(),
collaboration_mode_kind: turn_context.collaboration_mode.mode,
collaboration_mode_kind: turn_context.mode,
});
sess.send_event(&turn_context, start_event).await;
run_compact_task_inner(
+1 -1
View File
@@ -81,7 +81,7 @@ pub(crate) async fn run_remote_compact_task(
trace_id: turn_context.trace_id.clone(),
started_at: turn_context.turn_timing_state.started_at_unix_secs().await,
model_context_window: turn_context.model_context_window(),
collaboration_mode_kind: turn_context.collaboration_mode.mode,
collaboration_mode_kind: turn_context.mode,
});
sess.send_event(&turn_context, start_event).await;
+1 -1
View File
@@ -92,7 +92,7 @@ pub(crate) async fn run_remote_compact_task(
trace_id: turn_context.trace_id.clone(),
started_at: turn_context.turn_timing_state.started_at_unix_secs().await,
model_context_window: turn_context.model_context_window(),
collaboration_mode_kind: turn_context.collaboration_mode.mode,
collaboration_mode_kind: turn_context.mode,
});
sess.send_event(&turn_context, start_event).await;
+1 -1
View File
@@ -31,7 +31,7 @@ pub(crate) async fn run_manual_compact_task(
trace_id: turn_context.trace_id.clone(),
started_at: turn_context.turn_timing_state.started_at_unix_secs().await,
model_context_window: turn_context.model_context_window(),
collaboration_mode_kind: turn_context.collaboration_mode.mode,
collaboration_mode_kind: turn_context.mode,
});
sess.send_event(&turn_context, start_event).await;
+3 -5
View File
@@ -70,13 +70,11 @@ fn build_collaboration_mode_update_item(
}
let prev = previous?;
if prev.collaboration_mode.as_ref() != Some(&next.collaboration_mode) {
let collaboration_mode = next.collaboration_mode();
if prev.collaboration_mode.as_ref() != Some(&collaboration_mode) {
// If the next mode has empty developer instructions, this returns None and we emit no
// update, so prior collaboration instructions remain in the prompt history.
Some(
CollaborationModeInstructions::from_collaboration_mode(&next.collaboration_mode)?
.render(),
)
Some(CollaborationModeInstructions::from_collaboration_mode(&collaboration_mode)?.render())
} else {
None
}
+1 -1
View File
@@ -86,7 +86,7 @@ impl Session {
let turn_context = self
.new_default_turn_with_sub_id(uuid::Uuid::new_v4().to_string())
.await;
if turn_context.collaboration_mode.mode == ModeKind::Plan {
if turn_context.mode == ModeKind::Plan {
self.clear_reserved_idle_turn(&turn_state).await;
self.maybe_start_turn_for_pending_work().await;
return Err(TryStartTurnIfIdleError::new(
+4 -1
View File
@@ -130,7 +130,10 @@ pub(super) async fn spawn_review_thread(
timezone: parent_turn_context.timezone.clone(),
app_server_client_name: parent_turn_context.app_server_client_name.clone(),
developer_instructions: None,
collaboration_mode: parent_turn_context.collaboration_mode.clone(),
mode: parent_turn_context.mode,
collaboration_mode_developer_instructions: parent_turn_context
.collaboration_mode_developer_instructions
.clone(),
multi_agent_version: MultiAgentVersion::Disabled,
personality: parent_turn_context.personality,
approval_policy: parent_turn_context.approval_policy.clone(),
@@ -180,7 +180,7 @@ async fn record_initial_history_resumed_bare_turn_context_does_not_hydrate_previ
model: previous_model.to_string(),
comp_hash: None,
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
@@ -227,7 +227,7 @@ async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lif
model: previous_model.to_string(),
comp_hash: Some("comp-hash-a".to_string()),
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
@@ -1262,7 +1262,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
model: previous_model.to_string(),
comp_hash: None,
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
@@ -1349,7 +1349,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
model: previous_model.to_string(),
comp_hash: None,
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
@@ -1381,7 +1381,7 @@ async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_tu
model: previous_model.to_string(),
comp_hash: None,
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
@@ -1508,7 +1508,7 @@ async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_fo
model: current_model.to_string(),
comp_hash: None,
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
@@ -1630,7 +1630,7 @@ async fn record_initial_history_resumed_trailing_incomplete_turn_compaction_clea
model: previous_model.to_string(),
comp_hash: None,
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
@@ -1798,7 +1798,7 @@ async fn record_initial_history_resumed_replaced_incomplete_compacted_turn_clear
model: previous_model.to_string(),
comp_hash: None,
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
+4 -4
View File
@@ -2530,7 +2530,7 @@ async fn turn_start_lifecycle_exposes_turn_metadata_and_token_baseline() {
thread_level_id: session.thread_id.to_string(),
turn_level_id: turn_context.sub_id.clone(),
turn_id: turn_context.sub_id.clone(),
collaboration_mode: turn_context.collaboration_mode.clone(),
collaboration_mode: turn_context.collaboration_mode(),
token_usage_at_turn_start,
saw_session_store: true,
saw_thread_store: true,
@@ -3097,7 +3097,7 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() {
model: previous_model.to_string(),
comp_hash: None,
personality: turn_context.personality,
collaboration_mode: Some(turn_context.collaboration_mode.clone()),
collaboration_mode: Some(turn_context.collaboration_mode()),
multi_agent_version: None,
multi_agent_mode: None,
realtime_active: Some(turn_context.realtime_active),
@@ -3991,14 +3991,14 @@ async fn turn_context_with_model_updates_model_fields() {
.await;
assert_eq!(updated.config.model.as_deref(), Some("gpt-5.4"));
assert_eq!(updated.collaboration_mode.model(), "gpt-5.4");
assert_eq!(updated.collaboration_mode().model(), "gpt-5.4");
assert_eq!(updated.model_info, expected_model_info);
assert_eq!(
updated.reasoning_effort,
Some(ReasoningEffortConfig::Medium)
);
assert_eq!(
updated.collaboration_mode.reasoning_effort(),
updated.collaboration_mode().reasoning_effort(),
Some(ReasoningEffortConfig::Medium)
);
assert_eq!(
+2 -2
View File
@@ -787,7 +787,7 @@ async fn track_turn_resolved_config_analytics(
approval_policy: turn_context.approval_policy.value(),
approvals_reviewer: turn_context.config.approvals_reviewer,
sandbox_network_access: turn_context.network_sandbox_policy().is_enabled(),
collaboration_mode: turn_context.collaboration_mode.mode,
collaboration_mode: turn_context.mode,
personality: turn_context.personality,
workspace_kind: turn_context.turn_metadata_state.workspace_kind(),
is_first_turn,
@@ -1994,7 +1994,7 @@ async fn try_run_sampling_request(
let mut should_emit_turn_diff = false;
let mut should_emit_token_count = false;
let reasoning_effort = turn_context.effective_reasoning_effort_for_tracing();
let plan_mode = turn_context.collaboration_mode.mode == ModeKind::Plan;
let plan_mode = turn_context.mode == ModeKind::Plan;
let mut assistant_message_stream_parsers = AssistantMessageStreamParsers::new(plan_mode);
let mut plan_mode_state = plan_mode.then(|| PlanModeStreamState::new(&turn_context.sub_id));
let defer_streamed_turn_items_for_contributors =
+25 -10
View File
@@ -125,7 +125,8 @@ pub struct TurnContext {
pub(crate) timezone: Option<String>,
pub(crate) app_server_client_name: Option<String>,
pub(crate) developer_instructions: Option<String>,
pub(crate) collaboration_mode: CollaborationMode,
pub(crate) mode: ModeKind,
pub(crate) collaboration_mode_developer_instructions: Option<String>,
pub(crate) multi_agent_version: MultiAgentVersion,
pub(crate) personality: Option<Personality>,
pub(crate) approval_policy: Constrained<AskForApproval>,
@@ -156,6 +157,17 @@ impl TurnContext {
|| matches!(self.history_mode, ThreadHistoryMode::Paginated)
}
pub(crate) fn collaboration_mode(&self) -> CollaborationMode {
CollaborationMode {
mode: self.mode,
settings: Settings {
model: self.model_info.slug.clone(),
reasoning_effort: self.reasoning_effort.clone(),
developer_instructions: self.collaboration_mode_developer_instructions.clone(),
},
}
}
pub(crate) fn permission_profile(&self) -> PermissionProfile {
self.permission_profile.clone()
}
@@ -245,11 +257,6 @@ impl TurnContext {
};
config.model_reasoning_effort = reasoning_effort.clone();
let collaboration_mode = self.collaboration_mode.with_updates(
Some(model.clone()),
Some(reasoning_effort.clone()),
/*developer_instructions*/ None,
);
let available_models = models_manager
.list_models(
RefreshStrategy::OnlineIfUncached,
@@ -282,7 +289,10 @@ impl TurnContext {
timezone: self.timezone.clone(),
app_server_client_name: self.app_server_client_name.clone(),
developer_instructions: self.developer_instructions.clone(),
collaboration_mode,
mode: self.mode,
collaboration_mode_developer_instructions: self
.collaboration_mode_developer_instructions
.clone(),
multi_agent_version: self.multi_agent_version,
personality: self.personality,
approval_policy: self.approval_policy.clone(),
@@ -380,7 +390,7 @@ impl TurnContext {
model: self.model_info.slug.clone(),
comp_hash: self.model_info.comp_hash.clone(),
personality: self.personality,
collaboration_mode: Some(self.collaboration_mode.clone()),
collaboration_mode: Some(self.collaboration_mode()),
multi_agent_version: Some(self.multi_agent_version),
multi_agent_mode: super::multi_agents::effective_multi_agent_mode(self),
realtime_active: Some(self.realtime_active),
@@ -497,7 +507,8 @@ impl Session {
sub_id: String,
skills_snapshot: HostSkillsSnapshot,
) -> TurnContext {
let reasoning_effort = session_configuration.collaboration_mode.reasoning_effort();
let collaboration_mode = &session_configuration.collaboration_mode;
let reasoning_effort = collaboration_mode.reasoning_effort();
let reasoning_summary = session_configuration
.model_reasoning_summary
.unwrap_or(model_info.default_reasoning_summary);
@@ -562,7 +573,11 @@ impl Session {
timezone: Some(timezone),
app_server_client_name: session_configuration.app_server_client_name.clone(),
developer_instructions: session_configuration.developer_instructions.clone(),
collaboration_mode: session_configuration.collaboration_mode.clone(),
mode: collaboration_mode.mode,
collaboration_mode_developer_instructions: collaboration_mode
.settings
.developer_instructions
.clone(),
multi_agent_version,
personality: session_configuration.personality,
approval_policy: session_configuration.approval_policy.clone(),
+2 -2
View File
@@ -130,7 +130,7 @@ pub(crate) async fn record_completed_response_item_with_finalized_facts(
|| {
completed_item_defers_mailbox_delivery_to_next_turn(
item,
turn_context.collaboration_mode.mode == ModeKind::Plan,
turn_context.mode == ModeKind::Plan,
)
},
|facts| facts.defers_mailbox_delivery_to_next_turn,
@@ -321,7 +321,7 @@ pub(crate) async fn handle_output_item_done(
previously_active_item: Option<TurnItem>,
) -> Result<OutputItemResult> {
let mut output = OutputItemResult::default();
let plan_mode = ctx.turn_context.collaboration_mode.mode == ModeKind::Plan;
let plan_mode = ctx.turn_context.mode == ModeKind::Plan;
match ToolRouter::build_tool_call(item.clone()) {
// The model emitted a tool call; log it, persist the item immediately, and queue the tool execution.
+2 -1
View File
@@ -12,11 +12,12 @@ impl Session {
turn_context: &TurnContext,
token_usage_at_turn_start: &TokenUsage,
) {
let collaboration_mode = turn_context.collaboration_mode();
for contributor in self.services.extensions.turn_lifecycle_contributors() {
contributor
.on_turn_start(codex_extension_api::TurnStartInput {
turn_id: turn_context.sub_id.as_str(),
collaboration_mode: &turn_context.collaboration_mode,
collaboration_mode: &collaboration_mode,
token_usage_at_turn_start,
session_store: &self.services.session_extension_data,
thread_store: &self.services.thread_extension_data,
+1 -1
View File
@@ -52,7 +52,7 @@ impl SessionTask for RegularTask {
trace_id: ctx.trace_id.clone(),
started_at: ctx.turn_timing_state.started_at_unix_secs().await,
model_context_window: ctx.model_context_window(),
collaboration_mode_kind: ctx.collaboration_mode.mode,
collaboration_mode_kind: ctx.mode,
});
sess.send_event(ctx.as_ref(), event).await;
sess.set_server_reasoning_included(/*included*/ false).await;
+1 -1
View File
@@ -120,7 +120,7 @@ pub(crate) async fn execute_user_shell_command(
trace_id: turn_context.trace_id.clone(),
started_at: turn_context.turn_timing_state.started_at_unix_secs().await,
model_context_window: turn_context.model_context_window(),
collaboration_mode_kind: turn_context.collaboration_mode.mode,
collaboration_mode_kind: turn_context.mode,
});
session.send_event(turn_context.as_ref(), event).await;
}
+1 -1
View File
@@ -81,7 +81,7 @@ impl PlanHandler {
}
};
if turn.collaboration_mode.mode == ModeKind::Plan {
if turn.mode == ModeKind::Plan {
return Err(FunctionCallError::RespondToModel(
"update_plan is a TODO/checklist tool and is not allowed in Plan mode".to_string(),
));