mirror of
https://github.com/openai/codex.git
synced 2026-11-13 06:45:07 +00:00
Centralize thread environment selection state (#38423)
## What changed - Make `ThreadEnvironments` the source of truth for live environment selections and use it when building configuration snapshots, permission profiles, per-turn configuration, and MCP refresh inputs. - Keep settings previews side-effect free while applying accepted environment updates consistently to subsequent turns. - Move `EnvironmentConfig` into `codex-protocol` so environment ownership no longer depends on a core-only type. ## Testing - Cover environment previews and snapshots, accepted and rejected steer updates, and active-turn environment stability. GitOrigin-RevId: 7bcf8fb5df1215f720e4e9c419541a51a871aa5e
This commit is contained in:
1 parent
588e18aae5
commit
781445f7c6
16 files changed
+428
-327
No files matched your search
@@ -127,7 +127,6 @@ use codex_protocol::protocol::TurnAbortReason;
|
||||
use codex_protocol::protocol::TurnContextItem;
|
||||
use codex_protocol::protocol::TurnContextNetworkItem;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelections;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use codex_protocol::protocol::WorldStateItem;
|
||||
use codex_protocol::request_permissions::PermissionGrantScope;
|
||||
@@ -697,10 +696,7 @@ impl Session {
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: session_permission_profile_state_from_config(&config)?,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
environments: TurnEnvironmentSelections::new(
|
||||
config.cwd.clone(),
|
||||
environment_selections,
|
||||
),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
@@ -718,7 +714,7 @@ impl Session {
|
||||
user_shell_override,
|
||||
};
|
||||
session_configuration
|
||||
.validate_auto_review_requirement()
|
||||
.validate_auto_review_requirement(&environment_selections)
|
||||
.map_err(|err| CodexErr::InvalidRequest(err.to_string()))?;
|
||||
|
||||
// Generate a unique ID for the lifetime of this session.
|
||||
@@ -727,6 +723,7 @@ impl Session {
|
||||
|
||||
let session = Box::pin(Session::new(
|
||||
session_configuration,
|
||||
&environment_selections,
|
||||
config.clone(),
|
||||
user_instructions,
|
||||
installation_id,
|
||||
@@ -1570,7 +1567,8 @@ impl Session {
|
||||
let notify_config_contributors = !self.services.extensions.config_contributors().is_empty();
|
||||
let (previous_config, new_config, permission_profile_changed, mcp_inputs_changed) = {
|
||||
let mut state = self.state.lock().await;
|
||||
let updated = match state.session_configuration.apply(&updates) {
|
||||
let updated = match self.apply_session_settings(&state.session_configuration, &updates)
|
||||
{
|
||||
Ok(updated) => updated,
|
||||
Err(err) => {
|
||||
warn!("rejected session settings update: {err}");
|
||||
@@ -1579,25 +1577,26 @@ impl Session {
|
||||
};
|
||||
|
||||
let previous_config = notify_config_contributors
|
||||
.then(|| Self::build_effective_session_config(&state.session_configuration));
|
||||
let new_config =
|
||||
notify_config_contributors.then(|| Self::build_effective_session_config(&updated));
|
||||
.then(|| self.build_effective_session_config(&state.session_configuration));
|
||||
let previous_permission_profile = state.session_configuration.permission_profile();
|
||||
let updated_permission_profile = updated.permission_profile();
|
||||
let permission_profile_changed =
|
||||
previous_permission_profile != updated_permission_profile;
|
||||
let mcp_inputs_changed = state.session_configuration.mcp_inputs_differ(&updated);
|
||||
let mcp_inputs_changed =
|
||||
self.mcp_inputs_differ(&state.session_configuration, &updated, &updates);
|
||||
let environment_config = updated.turn_environment_config();
|
||||
if updates.environments.is_some() {
|
||||
if let Some(environments) = &updates.environments {
|
||||
self.services
|
||||
.turn_environments
|
||||
.update_selections(updated.environment_selections(), &environment_config);
|
||||
.update_selections(&environments.environments, &environment_config);
|
||||
} else if state.session_configuration.turn_environment_config() != environment_config {
|
||||
self.services
|
||||
.turn_environments
|
||||
.update_environment_configs(&environment_config);
|
||||
}
|
||||
state.session_configuration = updated;
|
||||
let new_config = notify_config_contributors
|
||||
.then(|| self.build_effective_session_config(&state.session_configuration));
|
||||
if mcp_inputs_changed {
|
||||
self.mark_mcp_runtime_dirty();
|
||||
}
|
||||
@@ -1624,15 +1623,19 @@ impl Session {
|
||||
updates: &SessionSettingsUpdate,
|
||||
) -> ConstraintResult<ThreadConfigSnapshot> {
|
||||
let state = self.state.lock().await;
|
||||
state
|
||||
.session_configuration
|
||||
.apply(updates)
|
||||
.map(|configuration| configuration.thread_config_snapshot())
|
||||
let configuration = self.apply_session_settings(&state.session_configuration, updates)?;
|
||||
let environments = updates.environments.as_ref().map_or_else(
|
||||
|| self.services.turn_environments.selections(),
|
||||
|environments| environments.environments.clone(),
|
||||
);
|
||||
Ok(configuration.thread_config_snapshot(environments))
|
||||
}
|
||||
|
||||
pub(crate) async fn thread_config_snapshot(&self) -> ThreadConfigSnapshot {
|
||||
let state = self.state.lock().await;
|
||||
state.session_configuration.thread_config_snapshot()
|
||||
state
|
||||
.session_configuration
|
||||
.thread_config_snapshot(self.services.turn_environments.selections())
|
||||
}
|
||||
|
||||
pub(crate) async fn set_app_server_client_info(
|
||||
@@ -1662,14 +1665,6 @@ impl Session {
|
||||
.map_or_else(Vec::new, |instructions| instructions.sources().collect())
|
||||
}
|
||||
|
||||
pub(crate) async fn thread_environment_selections(&self) -> Vec<TurnEnvironmentSelection> {
|
||||
let state = self.state.lock().await;
|
||||
state
|
||||
.session_configuration
|
||||
.environment_selections()
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
pub(crate) async fn set_session_startup_prewarm(
|
||||
&self,
|
||||
startup_prewarm: SessionStartupPrewarmHandle,
|
||||
@@ -1708,7 +1703,7 @@ impl Session {
|
||||
let (previous_config, new_config, config) = {
|
||||
let mut state = self.state.lock().await;
|
||||
let previous_config = notify_config_contributors
|
||||
.then(|| Self::build_effective_session_config(&state.session_configuration));
|
||||
.then(|| self.build_effective_session_config(&state.session_configuration));
|
||||
let mut config = (*state.session_configuration.original_config_do_not_use).clone();
|
||||
config.config_layer_stack = config
|
||||
.config_layer_stack
|
||||
@@ -1727,7 +1722,7 @@ impl Session {
|
||||
state.session_configuration.original_config_do_not_use = Arc::clone(&config);
|
||||
self.mark_mcp_runtime_dirty();
|
||||
let new_config = notify_config_contributors
|
||||
.then(|| Self::build_effective_session_config(&state.session_configuration));
|
||||
.then(|| self.build_effective_session_config(&state.session_configuration));
|
||||
(previous_config, new_config, config)
|
||||
};
|
||||
self.emit_config_changed_contributors(previous_config.as_ref(), new_config.as_ref());
|
||||
|
||||
Reference in new issue
Block a user