feat(approval): interactive approval workflow for supervised mode (#215)

- Add auto_approve / always_ask fields to AutonomyConfig
- New src/approval/ module: ApprovalManager with session-scoped allowlist,
  ApprovalRequest/Response types, audit logging, CLI interactive prompt
- Insert approval hook in agent_turn before tool execution
- Non-CLI channels auto-approve; CLI shows Y/N/A prompt
- Skip approval for read-only tools (file_read, memory_recall) by default
- 15 unit tests covering all approval logic
This commit is contained in:
stawky 2026-02-16 20:03:26 +08:00 committed by Chummy
parent f489971889
commit ab561baa97
7 changed files with 502 additions and 0 deletions

View file

@ -882,6 +882,22 @@ pub struct AutonomyConfig {
/// Block high-risk shell commands even if allowlisted.
#[serde(default = "default_true")]
pub block_high_risk_commands: bool,
/// Tools that never require approval (e.g. read-only tools).
#[serde(default = "default_auto_approve")]
pub auto_approve: Vec<String>,
/// Tools that always require interactive approval, even after "Always".
#[serde(default = "default_always_ask")]
pub always_ask: Vec<String>,
}
fn default_auto_approve() -> Vec<String> {
vec!["file_read".into(), "memory_recall".into()]
}
fn default_always_ask() -> Vec<String> {
vec![]
}
impl Default for AutonomyConfig {
@ -927,6 +943,8 @@ impl Default for AutonomyConfig {
max_cost_per_day_cents: 500,
require_approval_for_medium_risk: true,
block_high_risk_commands: true,
auto_approve: default_auto_approve(),
always_ask: default_always_ask(),
}
}
}
@ -2157,6 +2175,8 @@ default_temperature = 0.7
max_cost_per_day_cents: 1000,
require_approval_for_medium_risk: false,
block_high_risk_commands: true,
auto_approve: vec!["file_read".into()],
always_ask: vec![],
},
runtime: RuntimeConfig {
kind: "docker".into(),