Add Galaxy Decides risk reviews and focus implementation prompts

This commit is contained in:
2026-09-28 12:23:49 -05:00
parent 2a89d03866
commit cc064d4050
17 changed files with 1015 additions and 114 deletions
+25 -84
View File
@@ -96,8 +96,8 @@ use crate::settings::{
AIAutoDetectionEnabled, AICommandDenylist, AISettings, AISettingsChangedEvent, AcpEnabled,
AcpProviderConfig, AgentModeCodingPermissionsType, AgentModeCommandExecutionDenylist,
AgentModeCommandExecutionPredicate, AgentModeQuerySuggestionsEnabled, BedrockAutoLogin,
BedrockEnabled, BedrockModelConfig, CodeSettings, CodebaseContextEnabled, CrosscheckEnabled,
FileBasedMcpEnabled, GitOperationsAutogenEnabled, IncludeAgentCommandsInHistory, InputSettings,
BedrockEnabled, BedrockModelConfig, CodeSettings, CodebaseContextEnabled, FileBasedMcpEnabled,
GitOperationsAutogenEnabled, IncludeAgentCommandsInHistory, InputSettings,
IntelligentAutosuggestionsEnabled, LongRunningCommandSubmissionMode, MemoryEnabled,
NLDInTerminalEnabled, NaturalLanguageAutosuggestionsEnabled, OpenAIModelConfig,
OpenAIProviderConfig, OrchestrationMessageDisplayMode, PromptSubmissionMode,
@@ -167,8 +167,6 @@ pub enum AISubpage {
ProviderBedrock,
/// ACP provider settings.
ProviderACP,
/// Experimental features.
Experiments,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -189,7 +187,6 @@ impl AISubpage {
SettingsSection::ProviderChatGPTSubscription => Some(Self::ProviderChatGPTSubscription),
SettingsSection::ProviderBedrock => Some(Self::ProviderBedrock),
SettingsSection::ProviderACP => Some(Self::ProviderACP),
SettingsSection::Experiments => Some(Self::Experiments),
// AgentMCPServers renders the standalone MCPServers page, not an AI subpage.
_ => None,
}
@@ -1430,6 +1427,10 @@ impl AISettingsPageView {
"Always ask",
AISettingsPageAction::SetApplyCodeDiffs(ActionPermission::AlwaysAsk),
),
DropdownItem::new(
"Galaxy Decides",
AISettingsPageAction::SetApplyCodeDiffs(ActionPermission::GalaxyDecides),
),
],
ctx,
);
@@ -1460,6 +1461,10 @@ impl AISettingsPageView {
"Always ask",
AISettingsPageAction::SetReadFiles(ActionPermission::AlwaysAsk),
),
DropdownItem::new(
"Galaxy Decides",
AISettingsPageAction::SetReadFiles(ActionPermission::GalaxyDecides),
),
],
ctx,
);
@@ -1490,6 +1495,10 @@ impl AISettingsPageView {
"Always ask",
AISettingsPageAction::SetExecuteCommands(ActionPermission::AlwaysAsk),
),
DropdownItem::new(
"Galaxy Decides",
AISettingsPageAction::SetExecuteCommands(ActionPermission::GalaxyDecides),
),
],
ctx,
);
@@ -1520,6 +1529,10 @@ impl AISettingsPageView {
"Ask on first write",
AISettingsPageAction::SetWriteToPty(WriteToPtyPermission::AskOnFirstWrite),
),
DropdownItem::new(
"Galaxy Decides",
AISettingsPageAction::SetWriteToPty(WriteToPtyPermission::GalaxyDecides),
),
],
ctx,
);
@@ -1550,6 +1563,10 @@ impl AISettingsPageView {
"Always ask",
AISettingsPageAction::SetMCPPermissions(ActionPermission::AlwaysAsk),
),
DropdownItem::new(
"Galaxy Decides",
AISettingsPageAction::SetMCPPermissions(ActionPermission::GalaxyDecides),
),
],
ctx,
);
@@ -2214,9 +2231,6 @@ impl AISettingsPageView {
ProviderSetupProviderType::Acp,
)));
}
Some(AISubpage::Experiments) => {
widgets.push(Box::new(ExperimentsWidget::default()));
}
}
// Subpage widgets render their own subheader-sized titles internally,
@@ -2598,6 +2612,7 @@ impl AISettingsPageView {
ActionPermission::AgentDecides | ActionPermission::Unknown => 0,
ActionPermission::AlwaysAllow => 1,
ActionPermission::AlwaysAsk => 2,
ActionPermission::GalaxyDecides => 3,
};
menu.set_selected_by_index(active, ctx);
@@ -2623,6 +2638,7 @@ impl AISettingsPageView {
WriteToPtyPermission::AlwaysAllow => 0,
WriteToPtyPermission::AlwaysAsk | WriteToPtyPermission::Unknown => 1,
WriteToPtyPermission::AskOnFirstWrite => 2,
WriteToPtyPermission::GalaxyDecides => 3,
};
menu.set_selected_by_index(active, ctx);
@@ -2999,7 +3015,6 @@ pub enum AISettingsPageAction {
agent: Option<CLIAgent>,
},
ToggleCloudAgentComputerUse,
ToggleCrosscheckEnabled,
}
impl TypedActionView for AISettingsPageView {
@@ -3664,12 +3679,6 @@ impl TypedActionView for AISettingsPageView {
});
ctx.notify();
}
AISettingsPageAction::ToggleCrosscheckEnabled => {
AISettings::handle(ctx).update(ctx, |settings, ctx| {
report_if_error!(settings.crosscheck_enabled.toggle_and_save_value(ctx));
});
ctx.notify();
}
AISettingsPageAction::ToggleBedrockEnabled => {
AISettings::handle(ctx).update(ctx, |settings, ctx| {
if !*settings.bedrock_enabled.value() {
@@ -5265,6 +5274,7 @@ impl AgentsWidget {
}
if current_mcp_setting == ActionPermission::AlwaysAllow
|| current_mcp_setting == ActionPermission::GalaxyDecides
|| current_mcp_setting == ActionPermission::AgentDecides
{
let denylist = self.render_mcp_list(
@@ -8073,75 +8083,6 @@ impl SettingsWidget for CustomModelRoutersWidget {
}
}
// ── Experiments widget ──────────────────────────────────────────────────────
#[derive(Default)]
struct ExperimentsWidget {
crosscheck_toggle: SwitchStateHandle,
}
impl SettingsWidget for ExperimentsWidget {
type View = AISettingsPageView;
fn search_terms(&self) -> &str {
"experiments crosscheck review reviewer sub-agent feedback loop lgtm"
}
fn should_render(&self, _app: &AppContext) -> bool {
FeatureFlag::CrosscheckWork.is_enabled()
}
fn render(
&self,
view: &Self::View,
appearance: &Appearance,
app: &AppContext,
) -> Box<dyn Element> {
let ai_settings = AISettings::as_ref(app);
let is_any_ai_enabled = ai_settings.is_any_ai_enabled(app);
let header = build_sub_header(
appearance,
"Experiments",
Some(styles::header_font_color(is_any_ai_enabled, app)),
)
.with_margin_bottom(HEADER_PADDING)
.finish();
let crosscheck_toggle = render_ai_setting_toggle::<CrosscheckEnabled>(
"Crosscheck Work",
AISettingsPageAction::ToggleCrosscheckEnabled,
*ai_settings.crosscheck_enabled,
is_any_ai_enabled,
self.crosscheck_toggle.clone(),
&view.local_only_icon_tooltip_states,
app,
);
let crosscheck_description = render_ai_setting_description(
"When enabled, a reviewer agent critiques the main agent's output after each turn. \
The feedback loop continues until the reviewer responds with \"LGTM!\" or the \
maximum iteration count is reached.",
is_any_ai_enabled,
app,
);
let model_description = render_ai_setting_description(
"Configure the reviewer model and max iterations in settings.toml under \
[agents.experiments].",
is_any_ai_enabled,
app,
);
Flex::column()
.with_child(header)
.with_child(crosscheck_toggle)
.with_child(crosscheck_description)
.with_child(model_description)
.finish()
}
}
mod styles {
use galaxy_core::ui::appearance::Appearance;
use galaxy_core::ui::theme::Fill;
@@ -245,7 +245,7 @@ impl View for ExecutionProfileView {
));
match profile.execute_commands {
ActionPermission::AlwaysAllow => {
ActionPermission::AlwaysAllow | ActionPermission::GalaxyDecides => {
permissions_column.add_child(render_command_denylist(
&profile,
appearance,
@@ -325,7 +325,7 @@ impl View for ExecutionProfileView {
));
match profile.mcp_permissions {
ActionPermission::AlwaysAllow => {
ActionPermission::AlwaysAllow | ActionPermission::GalaxyDecides => {
permissions_column.add_child(render_mcp_denylist(
&profile,
appearance,
@@ -700,6 +700,7 @@ fn render_action_permission_line_with_icon(
ActionPermission::AgentDecides => "Agent decides",
ActionPermission::AlwaysAllow => "Always allow",
ActionPermission::AlwaysAsk => "Always ask",
ActionPermission::GalaxyDecides => "Galaxy Decides",
ActionPermission::Unknown => "Unknown",
};
render_permission_line_with_icon(icon, label, permission_text, appearance, is_ai_enabled)
@@ -715,6 +716,7 @@ fn render_write_to_pty_permission_line_with_icon(
let permission_text = match permission {
WriteToPtyPermission::AlwaysAllow => "Always allow",
WriteToPtyPermission::AlwaysAsk => "Always ask",
WriteToPtyPermission::GalaxyDecides => "Galaxy Decides",
WriteToPtyPermission::AskOnFirstWrite => "Ask on first write",
WriteToPtyPermission::Unknown => "Unknown",
};
@@ -732,6 +734,7 @@ fn render_computer_use_permission_line_with_icon(
crate::ai::execution_profiles::ComputerUsePermission::Never
| crate::ai::execution_profiles::ComputerUsePermission::Unknown => "Never",
crate::ai::execution_profiles::ComputerUsePermission::AlwaysAsk => "Always ask",
crate::ai::execution_profiles::ComputerUsePermission::GalaxyDecides => "Galaxy Decides",
crate::ai::execution_profiles::ComputerUsePermission::AlwaysAllow => "Always allow",
};
render_permission_line_with_icon(icon, label, permission_text, appearance, is_ai_enabled)
@@ -765,6 +768,7 @@ fn render_run_agents_permission_line_with_icon(
RunAgentsPermission::NeverAllow | RunAgentsPermission::Unknown => "Never",
RunAgentsPermission::AlwaysAllow => "Always allow",
RunAgentsPermission::AlwaysAsk => "Always ask",
RunAgentsPermission::GalaxyDecides => "Galaxy Decides",
};
render_permission_line_with_icon(icon, label, permission_text, appearance, is_ai_enabled)
}
-6
View File
@@ -246,7 +246,6 @@ pub enum SettingsSection {
Knowledge,
ThirdPartyCLIAgents,
Models,
Experiments,
// ── Providers umbrella subpages ──
ProviderOpenAI,
ProviderLiteLLM,
@@ -280,7 +279,6 @@ impl Display for SettingsSection {
SettingsSection::Knowledge => write!(f, "Knowledge"),
SettingsSection::ThirdPartyCLIAgents => write!(f, "Third party CLI agents"),
SettingsSection::Models => write!(f, "Models"),
SettingsSection::Experiments => write!(f, "Experiments"),
SettingsSection::ProviderOpenAI => write!(f, "OpenAI"),
SettingsSection::ProviderLiteLLM => write!(f, "LiteLLM"),
SettingsSection::ProviderChatGPTSubscription => write!(f, "ChatGPT Subscription"),
@@ -310,7 +308,6 @@ impl SettingsSection {
| Self::Knowledge
| Self::ThirdPartyCLIAgents
| Self::Models
| Self::Experiments
)
}
@@ -335,7 +332,6 @@ impl SettingsSection {
| Self::Knowledge
| Self::ThirdPartyCLIAgents
| Self::Models
| Self::Experiments
| Self::ProviderOpenAI
| Self::ProviderLiteLLM
| Self::ProviderChatGPTSubscription
@@ -371,7 +367,6 @@ impl SettingsSection {
Self::AgentMCPServers,
Self::Knowledge,
Self::ThirdPartyCLIAgents,
Self::Experiments,
]
}
@@ -421,7 +416,6 @@ impl FromStr for SettingsSection {
"Agent Client Protocol" | "ACP" => Ok(Self::ProviderACP),
"Indexing and projects" | "CodeIndexing" => Ok(Self::CodeIndexing),
"Editor and Code Review" | "EditorAndCodeReview" => Ok(Self::EditorAndCodeReview),
"Experiments" => Ok(Self::Experiments),
"Wormhole" => Ok(Self::Wormhole),
_ => Err(()),
}
+3 -4
View File
@@ -110,7 +110,6 @@ fn current_settings_display_names_round_trip() {
SettingsSection::ThirdPartyCLIAgents,
"Third party CLI agents",
),
(SettingsSection::Experiments, "Experiments"),
(SettingsSection::ProviderOpenAI, "OpenAI"),
(SettingsSection::ProviderLiteLLM, "LiteLLM"),
(
@@ -217,7 +216,7 @@ fn collapsed_umbrellas_each_form_one_navigation_stop() {
NavStop::CollapsedUmbrella {
nav_index: 0,
first_subpage: SettingsSection::WarpAgent,
last_subpage: SettingsSection::Experiments,
last_subpage: SettingsSection::ThirdPartyCLIAgents,
}
);
assert_eq!(
@@ -272,7 +271,7 @@ fn collapsed_umbrella_uses_first_and_last_visible_subpages() {
let stops = build_nav_stops(&nav_items, |section| {
!matches!(
section,
SettingsSection::WarpAgent | SettingsSection::Models | SettingsSection::Experiments
SettingsSection::WarpAgent | SettingsSection::Models
)
});
@@ -412,7 +411,7 @@ fn cycling_leaves_an_expanded_umbrella_after_its_last_subpage() {
simulate_cycle(
&nav_items,
&stops,
SettingsSection::Experiments,
SettingsSection::ThirdPartyCLIAgents,
CycleDirection::Down,
),
SettingsSection::ProviderOpenAI