1use serde_json::Value;
2
3use crate::tool::{Effect, ToolSpec};
4
5#[derive(Debug, Clone, PartialEq)]
6pub enum Decision {
7 Allow,
8 Deny { reason: String },
9 RequireApproval { reason: String },
10}
11
12pub trait Policy: Send + Sync {
14 fn decide(&self, spec: &ToolSpec, input: &Value) -> Decision;
15}
16
17impl<F> Policy for F
18where
19 F: Fn(&ToolSpec, &Value) -> Decision + Send + Sync,
20{
21 fn decide(&self, spec: &ToolSpec, input: &Value) -> Decision {
22 self(spec, input)
23 }
24}
25
26#[derive(Debug, Clone)]
29pub struct EffectPolicy {
30 pub approve_at: Option<Effect>,
31}
32
33impl Default for EffectPolicy {
34 fn default() -> Self {
35 Self { approve_at: Some(Effect::Irreversible) }
36 }
37}
38
39impl Policy for EffectPolicy {
40 fn decide(&self, spec: &ToolSpec, _input: &Value) -> Decision {
41 match self.approve_at {
42 Some(level) if spec.effect >= level => {
43 Decision::RequireApproval { reason: format!("`{}` has {:?} effect", spec.name, spec.effect) }
44 }
45 _ => Decision::Allow,
46 }
47 }
48}
49
50pub struct AllowAll;
51
52impl Policy for AllowAll {
53 fn decide(&self, _spec: &ToolSpec, _input: &Value) -> Decision {
54 Decision::Allow
55 }
56}