Fix Galaxy orchestration denial and controls

This commit is contained in:
2026-08-15 08:37:57 -05:00
parent 642cb6adc1
commit 2730712179
14 changed files with 348 additions and 386 deletions
@@ -175,30 +175,32 @@ impl OrchestrationEditState {
self.model_id.clear();
}
}
pub fn from_run_agents_fields(
model_id: &str,
harness_type: &str,
execution_mode: &RunAgentsExecutionMode,
) -> Self {
Self {
let execution_mode = match execution_mode {
RunAgentsExecutionMode::Local | RunAgentsExecutionMode::Remote { .. } => {
RunAgentsExecutionMode::Local
}
};
let mut state = Self {
model_id: model_id.to_string(),
harness_type: harness_type.to_string(),
execution_mode: execution_mode.clone(),
execution_mode,
auth_secret_selection: AuthSecretSelection::Unset,
}
};
state.sanitize_for_local_execution();
state
}
pub fn from_orchestration_config(config: &OrchestrationConfig) -> Self {
let execution_mode = match &config.execution_mode {
OrchestrationExecutionMode::Local => RunAgentsExecutionMode::Local,
OrchestrationExecutionMode::Remote {
environment_id,
worker_host,
} => RunAgentsExecutionMode::Remote {
environment_id: environment_id.clone(),
worker_host: worker_host.clone(),
computer_use_enabled: false,
},
OrchestrationExecutionMode::Local | OrchestrationExecutionMode::Remote { .. } => {
RunAgentsExecutionMode::Local
}
};
let mut state = Self {
model_id: config.model_id.clone(),
@@ -206,30 +208,17 @@ impl OrchestrationEditState {
execution_mode,
auth_secret_selection: AuthSecretSelection::Unset,
};
if matches!(state.execution_mode, RunAgentsExecutionMode::Local) {
state.sanitize_for_local_execution();
}
state.sanitize_for_local_execution();
state
}
/// Toggle Local ↔ Cloud. Resets OpenCode to Oz when switching
/// to Cloud (unsupported combination).
/// Galaxy only supports local child agents, so any mode selection is normalized to Local.
pub fn toggle_execution_mode_to_remote(&mut self, is_remote: bool) {
if is_remote {
if self.harness_type.eq_ignore_ascii_case("opencode") {
self.harness_type = "oz".to_string();
}
if !self.execution_mode.is_remote() {
self.execution_mode = RunAgentsExecutionMode::Remote {
environment_id: String::new(),
worker_host: ORCHESTRATION_WARP_WORKER_HOST.to_string(),
computer_use_enabled: false,
};
}
} else {
self.execution_mode = RunAgentsExecutionMode::Local;
self.sanitize_for_local_execution();
log::warn!("Ignoring remote orchestration selection because Galaxy is local-only");
}
self.execution_mode = RunAgentsExecutionMode::Local;
self.sanitize_for_local_execution();
}
pub fn set_environment_id(&mut self, environment_id: String) {
@@ -251,27 +240,17 @@ impl OrchestrationEditState {
}
/// Returns `Some(reason)` if Accept / Apply must be disabled.
/// Hard blocks: OpenCode + Cloud, and product-disabled local harnesses.
pub fn accept_disabled_reason(&self) -> Option<&'static str> {
match &self.execution_mode {
RunAgentsExecutionMode::Local => Harness::parse_local_child_harness(&self.harness_type)
.and_then(local_harness_product_disabled_message),
RunAgentsExecutionMode::Remote { .. }
if self.harness_type.eq_ignore_ascii_case("opencode") =>
{
Some(
"OpenCode is not supported on Cloud yet. Switch to Local or pick a different harness.",
)
RunAgentsExecutionMode::Remote { .. } => {
Some("Galaxy only supports local child-agent orchestration.")
}
RunAgentsExecutionMode::Remote { .. } => None,
}
}
/// Fills in empty fields from the approved orchestration config.
/// When the LLM omits harness/model/execution_mode to inherit from
/// the active config, the raw request arrives with defaults (empty
/// harness, empty model, Local mode). This resolves those to the
/// config values so the UI shows the intended settings.
/// Fills empty model and harness fields from the approved config while keeping execution local.
pub fn resolve_from_config(&mut self, config: &OrchestrationConfig) {
if self.harness_type.is_empty() && !config.harness_type.is_empty() {
self.harness_type = config.harness_type.clone();
@@ -279,67 +258,24 @@ impl OrchestrationEditState {
if self.model_id.is_empty() && !config.model_id.is_empty() {
self.model_id = config.model_id.clone();
}
if !self.execution_mode.is_remote() && config.execution_mode.is_remote() {
self.execution_mode = Self::from_orchestration_config(config).execution_mode;
}
if matches!(self.execution_mode, RunAgentsExecutionMode::Local) {
self.sanitize_for_local_execution();
}
self.execution_mode = RunAgentsExecutionMode::Local;
self.sanitize_for_local_execution();
}
/// Unconditionally overrides model, harness, and execution mode
/// from the approved orchestration config. The plan config is the
/// user-approved source of truth — the LLM's run_agents call may
/// omit or set these differently, but the config always wins.
///
/// `computer_use_enabled` is preserved from the current state when
/// both sides are Remote, since it is a per-call flag set by the LLM.
/// Applies the approved model and harness while keeping execution local.
pub fn override_from_approved_config(&mut self, config: &OrchestrationConfig) {
self.model_id = config.model_id.clone();
self.harness_type = config.harness_type.clone();
let preserve_computer_use = match (&self.execution_mode, &config.execution_mode) {
(
RunAgentsExecutionMode::Remote {
computer_use_enabled,
..
},
OrchestrationExecutionMode::Remote { .. },
) => Some(*computer_use_enabled),
_ => None,
};
self.execution_mode = Self::from_orchestration_config(config).execution_mode;
if let (
Some(cue),
RunAgentsExecutionMode::Remote {
computer_use_enabled,
..
},
) = (preserve_computer_use, &mut self.execution_mode)
{
*computer_use_enabled = cue;
}
self.execution_mode = RunAgentsExecutionMode::Local;
self.sanitize_for_local_execution();
}
/// Converts to a native `OrchestrationConfig` for storage / match.
/// Converts to a local-only native `OrchestrationConfig` for storage / match.
pub fn to_orchestration_config(&self) -> OrchestrationConfig {
let execution_mode = match &self.execution_mode {
RunAgentsExecutionMode::Local => OrchestrationExecutionMode::Local,
RunAgentsExecutionMode::Remote {
environment_id,
worker_host,
..
} => OrchestrationExecutionMode::Remote {
environment_id: environment_id.clone(),
worker_host: worker_host.clone(),
},
};
OrchestrationConfig {
model_id: self.model_id.clone(),
harness_type: self.harness_type.clone(),
execution_mode,
execution_mode: OrchestrationExecutionMode::Local,
}
}
}
@@ -360,7 +296,6 @@ pub struct OrchestrationPickerHandles<A: OrchestrationControlAction> {
/// auth-secret types.
pub auth_secret_picker: Option<ViewHandle<Dropdown<A>>>,
pub local_toggle: MouseStateHandle,
pub cloud_toggle: MouseStateHandle,
}
impl<A: OrchestrationControlAction> Default for OrchestrationPickerHandles<A> {
@@ -372,7 +307,6 @@ impl<A: OrchestrationControlAction> Default for OrchestrationPickerHandles<A> {
host_picker: None,
auth_secret_picker: None,
local_toggle: MouseStateHandle::default(),
cloud_toggle: MouseStateHandle::default(),
}
}
}
@@ -1805,7 +1739,6 @@ impl Element for AdaptivePickerRow {
// ── Render helpers ──────────────────────────────────────────────────
pub fn render_mode_toggle<A: OrchestrationControlAction>(
is_remote: bool,
handles: &OrchestrationPickerHandles<A>,
appearance: &Appearance,
active_segment_bg: Option<Fill>,
@@ -1822,27 +1755,18 @@ pub fn render_mode_toggle<A: OrchestrationControlAction>(
let local_segment = render_segment_button::<A>(
"Local",
!is_remote,
true,
A::execution_mode_toggled(false),
handles.local_toggle.clone(),
appearance,
active_segment_bg,
);
let cloud_segment = render_segment_button::<A>(
"Cloud",
is_remote,
A::execution_mode_toggled(true),
handles.cloud_toggle.clone(),
appearance,
active_segment_bg,
);
let segment_outer_bg = galaxy_core::ui::theme::color::internal_colors::fg_overlay_2(theme);
let segments_row = Flex::row()
.with_cross_axis_alignment(CrossAxisAlignment::Stretch)
.with_main_axis_alignment(MainAxisAlignment::Start)
.with_main_axis_size(MainAxisSize::Max)
.with_child(Expanded::new(1.0, cloud_segment).finish())
.with_child(Expanded::new(1.0, local_segment).finish())
.finish();
let segmented_control = Container::new(segments_row)
@@ -6,18 +6,6 @@ use super::{
OrchestrationEditState,
};
fn remote_claude_state() -> OrchestrationEditState {
OrchestrationEditState::from_run_agents_fields(
"sonnet",
"claude",
&RunAgentsExecutionMode::Remote {
environment_id: "env-1".to_string(),
worker_host: "warp".to_string(),
computer_use_enabled: false,
},
)
}
fn local_config(harness_type: &str, model_id: &str) -> OrchestrationConfig {
OrchestrationConfig {
model_id: model_id.to_string(),
@@ -26,10 +14,44 @@ fn local_config(harness_type: &str, model_id: &str) -> OrchestrationConfig {
}
}
fn remote_config(harness_type: &str, model_id: &str) -> OrchestrationConfig {
OrchestrationConfig {
model_id: model_id.to_string(),
harness_type: harness_type.to_string(),
execution_mode: OrchestrationExecutionMode::Remote {
environment_id: "env-1".to_string(),
worker_host: "warp".to_string(),
},
}
}
fn remote_mode() -> RunAgentsExecutionMode {
RunAgentsExecutionMode::Remote {
environment_id: "env-1".to_string(),
worker_host: "warp".to_string(),
computer_use_enabled: true,
}
}
#[test]
fn from_orchestration_config_preserves_local_claude() {
fn run_agents_remote_mode_is_normalized_to_local() {
let state = OrchestrationEditState::from_run_agents_fields("sonnet", "claude", &remote_mode());
assert_eq!(state.harness_type, "claude");
assert_eq!(state.model_id, "sonnet");
assert!(matches!(
state.execution_mode,
RunAgentsExecutionMode::Local
));
assert!(should_show_harness_picker(&state));
assert!(!should_show_auth_secret_picker(&state));
}
#[test]
fn remote_orchestration_config_is_normalized_to_local() {
let state =
OrchestrationEditState::from_orchestration_config(&local_config("claude", "sonnet"));
OrchestrationEditState::from_orchestration_config(&remote_config("claude", "sonnet"));
assert_eq!(state.harness_type, "claude");
assert_eq!(state.model_id, "sonnet");
assert!(matches!(
@@ -39,66 +61,24 @@ fn from_orchestration_config_preserves_local_claude() {
}
#[test]
fn harness_picker_stays_visible_for_local_mode() {
let state = OrchestrationEditState::from_run_agents_fields(
fn remote_toggle_remains_local() {
let mut state = OrchestrationEditState::from_run_agents_fields(
"auto",
"oz",
&RunAgentsExecutionMode::Local,
);
assert!(should_show_harness_picker(&state));
}
#[test]
fn harness_picker_stays_visible_for_remote_mode() {
let state = OrchestrationEditState::from_run_agents_fields(
"auto",
"oz",
&RunAgentsExecutionMode::Remote {
environment_id: "env-1".to_string(),
worker_host: "warp".to_string(),
computer_use_enabled: false,
},
);
state.toggle_execution_mode_to_remote(true);
assert!(should_show_harness_picker(&state));
}
#[test]
fn from_orchestration_config_preserves_remote_claude() {
let state = OrchestrationEditState::from_orchestration_config(&OrchestrationConfig {
model_id: "sonnet".to_string(),
harness_type: "claude".to_string(),
execution_mode: OrchestrationExecutionMode::Remote {
environment_id: "env-1".to_string(),
worker_host: "warp".to_string(),
},
});
assert_eq!(state.harness_type, "claude");
assert_eq!(state.model_id, "sonnet");
assert!(matches!(
state.execution_mode,
RunAgentsExecutionMode::Remote {
ref environment_id,
ref worker_host,
computer_use_enabled: false,
} if environment_id == "env-1" && worker_host == "warp"
RunAgentsExecutionMode::Local
));
}
#[test]
fn toggle_to_local_sanitizes_disabled_codex() {
let mut state = OrchestrationEditState::from_run_agents_fields(
"gpt-5",
"codex",
&RunAgentsExecutionMode::Remote {
environment_id: "env-1".to_string(),
worker_host: "warp".to_string(),
computer_use_enabled: false,
},
);
state.toggle_execution_mode_to_remote(false);
fn local_normalization_sanitizes_disabled_harnesses() {
let state = OrchestrationEditState::from_run_agents_fields("gpt-5", "codex", &remote_mode());
assert_eq!(state.harness_type, "oz");
assert_eq!(state.model_id, "");
@@ -109,18 +89,11 @@ fn toggle_to_local_sanitizes_disabled_codex() {
}
#[test]
fn toggle_to_local_preserves_claude() {
let mut state = OrchestrationEditState::from_run_agents_fields(
"sonnet",
"claude",
&RunAgentsExecutionMode::Remote {
environment_id: "env-1".to_string(),
worker_host: "warp".to_string(),
computer_use_enabled: false,
},
);
fn resolve_from_remote_config_inherits_fields_but_stays_local() {
let mut state =
OrchestrationEditState::from_run_agents_fields("", "", &RunAgentsExecutionMode::Local);
state.toggle_execution_mode_to_remote(false);
state.resolve_from_config(&remote_config("claude", "sonnet"));
assert_eq!(state.harness_type, "claude");
assert_eq!(state.model_id, "sonnet");
@@ -131,27 +104,21 @@ fn toggle_to_local_preserves_claude() {
}
#[test]
fn accept_disabled_reason_allows_local_claude_product() {
let state = OrchestrationEditState::from_run_agents_fields(
"auto",
"claude",
&RunAgentsExecutionMode::Local,
);
assert_eq!(state.accept_disabled_reason(), None);
}
fn approved_remote_config_override_stays_local() {
let mut state = OrchestrationEditState::from_run_agents_fields("auto", "oz", &remote_mode());
#[test]
fn resolve_from_config_preserves_local_claude() {
let mut state =
OrchestrationEditState::from_run_agents_fields("", "", &RunAgentsExecutionMode::Local);
state.override_from_approved_config(&remote_config("claude", "sonnet"));
state.resolve_from_config(&local_config("claude", "sonnet"));
assert_eq!(state.harness_type, "claude");
assert_eq!(state.model_id, "sonnet");
assert!(matches!(
state.execution_mode,
RunAgentsExecutionMode::Local
));
assert!(matches!(
state.to_orchestration_config().execution_mode,
OrchestrationExecutionMode::Local
));
}
#[test]
@@ -163,32 +130,29 @@ fn resolve_from_config_sanitizes_disabled_local_codex() {
assert_eq!(state.harness_type, "oz");
assert_eq!(state.model_id, "");
assert!(matches!(
state.execution_mode,
RunAgentsExecutionMode::Local
));
assert_eq!(state.accept_disabled_reason(), None);
}
#[test]
fn select_create_new_auth_secret_marks_creating_new_from_named() {
let mut state = remote_claude_state();
fn local_mode_does_not_expose_managed_auth_secret() {
let mut state = OrchestrationEditState::from_run_agents_fields(
"sonnet",
"claude",
&RunAgentsExecutionMode::Local,
);
state.auth_secret_selection = AuthSecretSelection::Named("my-key".to_string());
assert_eq!(state.auth_secret_name(), Some("my-key"));
state.select_create_new_auth_secret();
// `CreatingNew` (distinct from `Unset`) blocks Accept and isn't re-seeded.
assert!(matches!(
state.auth_secret_selection,
AuthSecretSelection::CreatingNew
));
assert_eq!(state.auth_secret_name(), None);
assert!(should_show_auth_secret_picker(&state));
assert!(!should_show_auth_secret_picker(&state));
}
#[test]
fn select_create_new_auth_secret_marks_creating_new_from_inherit() {
let mut state = remote_claude_state();
fn selecting_create_auth_secret_remains_a_distinct_state() {
let mut state = OrchestrationEditState::from_run_agents_fields(
"sonnet",
"claude",
&RunAgentsExecutionMode::Local,
);
state.auth_secret_selection = AuthSecretSelection::Inherit;
state.select_create_new_auth_secret();
@@ -139,7 +139,7 @@ impl RunAgentsEditState {
skills: self.skills.clone(),
model_id: self.orch.model_id.clone(),
harness_type: self.orch.harness_type.clone(),
execution_mode: self.orch.execution_mode.clone(),
execution_mode: RunAgentsExecutionMode::Local,
agent_run_configs: self.agent_run_configs.clone(),
plan_id: self.plan_id.clone(),
harness_auth_secret_name: self.orch.auth_secret_name().map(str::to_string),
@@ -1490,7 +1490,6 @@ fn render_editor(
column.add_child(
Container::new(oc::render_mode_toggle(
state.orch.execution_mode.is_remote(),
&handles.pickers,
appearance,
None,
@@ -57,30 +57,20 @@ fn make_edit_state_with_orch_fields(
}
#[test]
fn local_to_cloud_initializes_remote_with_empty_environment() {
fn remote_toggle_remains_local() {
let mut state =
RunAgentsEditState::from_request(&make_request("oz", RunAgentsExecutionMode::Local));
state.orch.toggle_execution_mode_to_remote(true);
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
state.orch.toggle_execution_mode_to_remote(true);
let RunAgentsExecutionMode::Remote {
environment_id,
worker_host,
computer_use_enabled,
} = state.orch.execution_mode
else {
panic!("expected Remote after toggle");
};
assert_eq!(environment_id, "");
assert_eq!(worker_host, "warp");
assert!(!computer_use_enabled);
}
#[test]
fn cloud_to_local_drops_environment() {
fn legacy_remote_request_normalizes_to_local() {
let mut state = RunAgentsEditState::from_request(&make_request(
"oz",
RunAgentsExecutionMode::Remote {
@@ -97,15 +87,21 @@ fn cloud_to_local_drops_environment() {
}
#[test]
fn local_to_cloud_resets_opencode_to_oz() {
fn remote_toggle_preserves_supported_local_harness() {
let mut state =
RunAgentsEditState::from_request(&make_request("opencode", RunAgentsExecutionMode::Local));
state.orch.toggle_execution_mode_to_remote(true);
assert_eq!(state.orch.harness_type, "oz");
assert_eq!(state.orch.harness_type, "opencode");
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
}
#[test]
fn cloud_without_env_no_longer_disables_accept() {
fn legacy_remote_request_without_environment_allows_local_acceptance() {
let state = RunAgentsEditState::from_request(&make_request(
"oz",
RunAgentsExecutionMode::Remote {
@@ -114,15 +110,15 @@ fn cloud_without_env_no_longer_disables_accept() {
computer_use_enabled: false,
},
));
assert!(
state.orch.accept_disabled_reason().is_none(),
"Cloud without env should NOT disable Accept (soft recommendation only)"
);
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
assert!(state.orch.accept_disabled_reason().is_none());
}
#[test]
fn cloud_with_opencode_disables_accept() {
// Bypass the toggle helper to test the validation gate directly.
fn legacy_remote_opencode_request_is_normalized_and_allowed_locally() {
let state = RunAgentsEditState::from_request(&make_request(
"opencode",
RunAgentsExecutionMode::Remote {
@@ -131,9 +127,12 @@ fn cloud_with_opencode_disables_accept() {
computer_use_enabled: false,
},
));
let reason = state.orch.accept_disabled_reason();
assert!(reason.is_some(), "Cloud + OpenCode should disable Accept");
assert!(reason.unwrap().contains("OpenCode"));
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
assert_eq!(state.orch.accept_disabled_reason(), None);
}
#[test]
@@ -149,12 +148,11 @@ fn local_with_any_harness_does_not_disable_accept() {
}
#[test]
fn local_with_disabled_codex_disables_accept() {
fn local_with_disabled_codex_is_sanitized() {
let state = make_edit_state_with_orch_fields("codex", RunAgentsExecutionMode::Local);
assert_eq!(
state.orch.accept_disabled_reason(),
Some("Local Codex child agents are temporarily disabled.")
);
assert_eq!(state.orch.harness_type, "oz");
assert_eq!(state.orch.accept_disabled_reason(), None);
}
#[test]
@@ -168,7 +166,7 @@ fn from_request_sanitizes_disabled_local_harness_to_oz() {
}
#[test]
fn cloud_with_env_and_non_opencode_harness_allows_accept() {
fn legacy_remote_harnesses_normalize_and_allow_local_acceptance() {
for harness in ["oz", "claude", "gemini"] {
let state = RunAgentsEditState::from_request(&make_request(
harness,
@@ -178,9 +176,13 @@ fn cloud_with_env_and_non_opencode_harness_allows_accept() {
computer_use_enabled: false,
},
));
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
assert!(
state.orch.accept_disabled_reason().is_none(),
"Cloud + env + {harness} should allow Accept"
"normalized local + {harness} should allow Accept"
);
}
}
@@ -197,7 +199,7 @@ fn set_environment_id_no_op_in_local_mode() {
}
#[test]
fn set_environment_id_updates_remote() {
fn set_environment_id_is_ignored_for_normalized_remote_request() {
let mut state = RunAgentsEditState::from_request(&make_request(
"oz",
RunAgentsExecutionMode::Remote {
@@ -206,15 +208,17 @@ fn set_environment_id_updates_remote() {
computer_use_enabled: false,
},
));
state.orch.set_environment_id("new-env".to_string());
let RunAgentsExecutionMode::Remote { environment_id, .. } = state.orch.execution_mode else {
panic!("expected Remote");
};
assert_eq!(environment_id, "new-env");
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
}
#[test]
fn to_request_round_trips_request_fields() {
fn to_request_preserves_fields_but_normalizes_execution_to_local() {
let mut req = make_request_with_skills(
"claude",
RunAgentsExecutionMode::Remote {
@@ -232,11 +236,15 @@ fn to_request_round_trips_request_fields() {
req.plan_id = "plan-1".to_string();
let state = RunAgentsEditState::from_request(&req);
let round_tripped = state.to_request();
assert_eq!(round_tripped.summary, req.summary);
assert_eq!(round_tripped.base_prompt, req.base_prompt);
assert_eq!(round_tripped.model_id, req.model_id);
assert_eq!(round_tripped.harness_type, req.harness_type);
assert_eq!(round_tripped.execution_mode, req.execution_mode);
assert!(matches!(
round_tripped.execution_mode,
RunAgentsExecutionMode::Local
));
assert_eq!(round_tripped.agent_run_configs, req.agent_run_configs);
assert_eq!(round_tripped.skills, req.skills);
assert_eq!(round_tripped.plan_id, req.plan_id);
@@ -414,34 +422,27 @@ mod override_from_approved_config_tests {
#[test]
fn overrides_even_when_request_has_values() {
let mut state = RunAgentsEditState::from_request(&make_request(
"claude",
RunAgentsExecutionMode::Local,
));
let mut state =
RunAgentsEditState::from_request(&make_request("oz", RunAgentsExecutionMode::Local));
state
.orch
.override_from_approved_config(&local_config("gpt-5", "codex"));
assert_eq!(state.orch.model_id, "gpt-5");
assert_eq!(state.orch.harness_type, "codex");
.override_from_approved_config(&local_config("sonnet", "claude"));
assert_eq!(state.orch.model_id, "sonnet");
assert_eq!(state.orch.harness_type, "claude");
}
#[test]
fn overrides_local_to_remote() {
fn remote_config_override_stays_local() {
let mut state =
RunAgentsEditState::from_request(&make_request("oz", RunAgentsExecutionMode::Local));
state
.orch
.override_from_approved_config(&remote_config("auto", "oz", "env-1"));
let RunAgentsExecutionMode::Remote {
environment_id,
worker_host,
..
} = &state.orch.execution_mode
else {
panic!("expected Remote after override");
};
assert_eq!(environment_id, "env-1");
assert_eq!(worker_host, "warp");
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
}
#[test]
@@ -464,7 +465,7 @@ mod override_from_approved_config_tests {
}
#[test]
fn preserves_computer_use_when_both_remote() {
fn remote_request_and_remote_override_drop_computer_use() {
let mut state = RunAgentsEditState::from_request(&make_request(
"oz",
RunAgentsExecutionMode::Remote {
@@ -476,57 +477,29 @@ mod override_from_approved_config_tests {
state
.orch
.override_from_approved_config(&remote_config("auto", "oz", "new-env"));
let RunAgentsExecutionMode::Remote {
environment_id,
computer_use_enabled,
..
} = &state.orch.execution_mode
else {
panic!("expected Remote");
};
assert_eq!(environment_id, "new-env", "env should come from config");
assert!(
*computer_use_enabled,
"computer_use_enabled should be preserved from original request"
);
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
}
#[test]
fn does_not_carry_computer_use_from_local_to_remote() {
fn approved_local_disabled_harness_is_sanitized() {
let mut state =
RunAgentsEditState::from_request(&make_request("oz", RunAgentsExecutionMode::Local));
state
.orch
.override_from_approved_config(&remote_config("auto", "oz", "env-1"));
let RunAgentsExecutionMode::Remote {
computer_use_enabled,
..
} = &state.orch.execution_mode
else {
panic!("expected Remote");
};
assert!(
!*computer_use_enabled,
"computer_use_enabled should default to false when original was Local"
);
}
.override_from_approved_config(&local_config("gpt-5", "codex"));
#[test]
fn approved_local_disabled_harness_reports_disabled_reason_after_override() {
let mut state =
RunAgentsEditState::from_request(&make_request("oz", RunAgentsExecutionMode::Local));
state
.orch
.override_from_approved_config(&local_config("auto", "codex"));
assert_eq!(
state.orch.accept_disabled_reason(),
Some("Local Codex child agents are temporarily disabled.")
);
assert_eq!(state.orch.harness_type, "oz");
assert_eq!(state.orch.model_id, "");
assert_eq!(state.orch.accept_disabled_reason(), None);
}
}
#[test]
fn local_to_cloud_idempotent_when_already_remote() {
fn remote_toggle_is_idempotently_local() {
let mut state = RunAgentsEditState::from_request(&make_request(
"oz",
RunAgentsExecutionMode::Remote {
@@ -535,21 +508,11 @@ fn local_to_cloud_idempotent_when_already_remote() {
computer_use_enabled: true,
},
));
state.orch.toggle_execution_mode_to_remote(true);
let RunAgentsExecutionMode::Remote {
environment_id,
computer_use_enabled,
..
} = state.orch.execution_mode
else {
panic!("expected Remote");
};
assert_eq!(
environment_id, "env-1",
"toggle to Remote when already Remote should not clobber env"
);
assert!(
computer_use_enabled,
"toggle to Remote when already Remote should not clobber computer_use"
);
assert!(matches!(
state.orch.execution_mode,
RunAgentsExecutionMode::Local
));
}