Simplify Galaxy permissions and preserve explicit user authorization
This commit is contained in:
@@ -251,6 +251,7 @@ fn prepare_rig_turn_for_provider(
|
||||
tool_result_archive,
|
||||
messages_sent,
|
||||
global_rules,
|
||||
permission_mode,
|
||||
mcp_context,
|
||||
..
|
||||
} = params;
|
||||
@@ -292,6 +293,13 @@ fn prepare_rig_turn_for_provider(
|
||||
}
|
||||
}
|
||||
let mut system_prompt = build_system_prompt(&input, &tools, &global_rules, mode);
|
||||
system_prompt.push_str(match permission_mode {
|
||||
crate::ai::execution_profiles::PermissionMode::ReadOnly => "\n## Permission Mode: Read Only\nOnly inspection and search tools are available. Describe proposed changes without executing commands, editing, delegating, or invoking MCP/computer use.\n",
|
||||
crate::ai::execution_profiles::PermissionMode::AskFirst => "\n## Permission Mode: Ask First\nGalaxy asks for approval before actions and remembers exact approved commands in their working directory. Do not request blanket permission in prose; submit the concrete tool action for the approval pane.\n",
|
||||
crate::ai::execution_profiles::PermissionMode::GalaxyDecides => "\n## Permission Mode: Galaxy Decides\nGalaxy's independent terminal-use model resolves tool permissions without asking the user. Treat denials as binding. Revise the action scope or provide concrete missing justification addressing the stated risk, or use a safer approach. Never repeat an unchanged denied request, seek user approval to override it, or claim a denied action ran. Work autonomously and report concrete blockers when no authorized approach remains. For routine inspection, prefer the permission fast path: pwd, simple ls commands, git --version, git --no-pager -c core.fsmonitor=false status --short, or git --no-pager -c core.fsmonitor=false diff --no-ext-diff --no-textconv --stat (optionally --cached). Shell expansions, chaining, redirects and other command forms still require model review.\n",
|
||||
});
|
||||
|
||||
system_prompt.push_str("Approval of a long-running command covers monitoring and interaction with that same conversation-owned command while you retain control. Use the existing command block; do not request permission again or restart the command just to interact with it. A new command requires its own permission decision.\n");
|
||||
|
||||
let mut new_messages = input_messages(input, tool_results, max_context_tokens);
|
||||
let mut persistent_messages = message_history;
|
||||
|
||||
@@ -52,7 +52,7 @@ pub(crate) fn action_from_tool_call(
|
||||
wait_until_completion: optional_boolean(input, "wait_until_complete")?
|
||||
.unwrap_or(false),
|
||||
uses_pager: Some(optional_boolean(input, "uses_pager")?.unwrap_or(false)),
|
||||
rationale: None,
|
||||
rationale: optional_string(input, "rationale")?,
|
||||
citations: Vec::new(),
|
||||
},
|
||||
"read_files" => AIAgentActionType::ReadFiles(ReadFilesRequest {
|
||||
|
||||
@@ -46,6 +46,28 @@ fn shell_calls_become_domain_actions_without_a_proto_round_trip() {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shell_permission_rationale_is_separate_from_executable_command() {
|
||||
let action = action_from_tool_call(
|
||||
"task-1",
|
||||
&call(
|
||||
"run_shell_command",
|
||||
serde_json::json!({
|
||||
"command": "git push origin master",
|
||||
"rationale": "The user requested a normal push to origin/master."
|
||||
}),
|
||||
),
|
||||
&SkillPathOrigin::Local,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(matches!(action.action,
|
||||
AIAgentActionType::RequestCommandOutput { command, rationale: Some(rationale), .. }
|
||||
if command == "git push origin master"
|
||||
&& rationale == "The user requested a normal push to origin/master."
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_control_calls_become_domain_actions() {
|
||||
let action = action_from_tool_call(
|
||||
|
||||
Reference in New Issue
Block a user