From fe641f759f1725fc32920b228a4b9a86f2d13966 Mon Sep 17 00:00:00 2001 From: charley-oai Date: Wed, 21 Jan 2026 14:14:21 -0800 Subject: [PATCH] Add collaboration_mode to TurnContextItem (#9583) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - add optional `collaboration_mode` to `TurnContextItem` in rollouts - persist the current collaboration mode when recording turn context (sampling + compaction) ## Rationale We already persist turn context data for resume logic. Capturing collaboration mode in the rollout gives us the mode context for each turn, enabling follow‑up work to diff mode instructions correctly on resume. ## Changes - protocol: add optional `collaboration_mode` field to `TurnContextItem` - core: persist collaboration mode alongside other turn context settings in rollouts --- codex-rs/core/src/codex.rs | 11 +++++++++++ codex-rs/core/src/compact.rs | 6 ++++++ codex-rs/core/tests/suite/resume_warning.rs | 1 + codex-rs/protocol/src/protocol.rs | 2 ++ 4 files changed, 20 insertions(+) diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index a05521e80..a3b3aba9a 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -1061,6 +1061,11 @@ impl Session { .await } + pub(crate) async fn current_collaboration_mode(&self) -> CollaborationMode { + let state = self.state.lock().await; + state.session_configuration.collaboration_mode.clone() + } + fn build_environment_update_item( &self, previous: Option<&Arc>, @@ -3096,11 +3101,17 @@ async fn try_run_sampling_request( prompt: &Prompt, cancellation_token: CancellationToken, ) -> CodexResult { + // TODO: If we need to guarantee the persisted mode always matches the prompt used for this + // turn, capture it in TurnContext at creation time. Using SessionConfiguration here avoids + // duplicating model settings on TurnContext, but a later Op could update the session config + // before this write occurs. + let collaboration_mode = sess.current_collaboration_mode().await; let rollout_item = RolloutItem::TurnContext(TurnContextItem { cwd: turn_context.cwd.clone(), approval_policy: turn_context.approval_policy, sandbox_policy: turn_context.sandbox_policy.clone(), model: turn_context.client.get_model(), + collaboration_mode: Some(collaboration_mode), effort: turn_context.client.get_reasoning_effort(), summary: turn_context.client.get_reasoning_summary(), user_instructions: turn_context.user_instructions.clone(), diff --git a/codex-rs/core/src/compact.rs b/codex-rs/core/src/compact.rs index 970eb0054..958686c14 100644 --- a/codex-rs/core/src/compact.rs +++ b/codex-rs/core/src/compact.rs @@ -84,11 +84,17 @@ async fn run_compact_task_inner( let max_retries = turn_context.client.get_provider().stream_max_retries(); let mut retries = 0; + // TODO: If we need to guarantee the persisted mode always matches the prompt used for this + // turn, capture it in TurnContext at creation time. Using SessionConfiguration here avoids + // duplicating model settings on TurnContext, but an Op after turn start could update the + // session config before this write occurs. + let collaboration_mode = sess.current_collaboration_mode().await; let rollout_item = RolloutItem::TurnContext(TurnContextItem { cwd: turn_context.cwd.clone(), approval_policy: turn_context.approval_policy, sandbox_policy: turn_context.sandbox_policy.clone(), model: turn_context.client.get_model(), + collaboration_mode: Some(collaboration_mode), effort: turn_context.client.get_reasoning_effort(), summary: turn_context.client.get_reasoning_summary(), user_instructions: turn_context.user_instructions.clone(), diff --git a/codex-rs/core/tests/suite/resume_warning.rs b/codex-rs/core/tests/suite/resume_warning.rs index 8c3ecf7af..162e0e26e 100644 --- a/codex-rs/core/tests/suite/resume_warning.rs +++ b/codex-rs/core/tests/suite/resume_warning.rs @@ -26,6 +26,7 @@ fn resume_history( approval_policy: config.approval_policy.value(), sandbox_policy: config.sandbox_policy.get().clone(), model: previous_model.to_string(), + collaboration_mode: None, effort: config.model_reasoning_effort, summary: config.model_reasoning_summary, user_instructions: None, diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 533fe04d8..1a9029f27 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -1602,6 +1602,8 @@ pub struct TurnContextItem { pub approval_policy: AskForApproval, pub sandbox_policy: SandboxPolicy, pub model: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub collaboration_mode: Option, #[serde(skip_serializing_if = "Option::is_none")] pub effort: Option, pub summary: ReasoningSummaryConfig,