deepstrike_sdk/
governance.rs1use compact_str::CompactString;
2use deepstrike_core::governance::constraint::{ConstraintRule, ParamConstraint};
3use deepstrike_core::governance::permission::{PermissionAction, PermissionRule};
4use deepstrike_core::governance::pipeline::GovernancePipeline;
5use deepstrike_core::governance::rate_limit::RateLimit;
6use deepstrike_core::types::agent::AgentIdentity;
7use deepstrike_core::types::message::ToolCall;
8use deepstrike_core::types::policy::GovernanceVerdict as CoreVerdict;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct GovernanceVerdict {
13 pub kind: String,
14 pub reason: Option<String>,
15 pub retry_after_ms: Option<u64>,
16}
17
18pub struct Governance {
20 inner: GovernancePipeline,
21 agent_id: String,
22 session_id: String,
23}
24
25impl Governance {
26 pub fn new(default_action: PermissionAction) -> Self {
27 Self {
28 inner: GovernancePipeline::new(default_action),
29 agent_id: "anonymous".into(),
30 session_id: String::new(),
31 }
32 }
33
34 pub fn allow() -> Self {
35 Self::new(PermissionAction::Allow)
36 }
37
38 pub fn set_identity(&mut self, agent_id: impl Into<String>, session_id: impl Into<String>) {
39 self.agent_id = agent_id.into();
40 self.session_id = session_id.into();
41 }
42
43 pub fn add_permission_rule(&mut self, pattern: impl Into<String>, action: PermissionAction) {
44 self.inner.permission.add_rule(PermissionRule {
45 tool_pattern: CompactString::new(pattern.into()),
46 action,
47 });
48 }
49
50 pub fn block_tool(&mut self, name: impl Into<String>) {
51 self.inner.veto.block_tool(name.into());
52 }
53
54 pub fn set_rate_limit(&mut self, tool_name: impl Into<String>, max_calls: u32, window_ms: u64) {
55 self.inner.rate_limiter.set_limit(
56 tool_name.into(),
57 RateLimit {
58 max_calls,
59 window_ms,
60 },
61 );
62 }
63
64 pub fn require_param(&mut self, tool_name: impl Into<String>, param_path: impl Into<String>) {
65 self.inner.constraints.add(ParamConstraint {
66 tool_name: tool_name.into(),
67 param_path: param_path.into(),
68 rule: ConstraintRule::Required,
69 });
70 }
71
72 pub fn allow_param_values(
73 &mut self,
74 tool_name: impl Into<String>,
75 param_path: impl Into<String>,
76 allowed_values: Vec<String>,
77 ) {
78 self.inner.constraints.add(ParamConstraint {
79 tool_name: tool_name.into(),
80 param_path: param_path.into(),
81 rule: ConstraintRule::Enum(allowed_values),
82 });
83 }
84
85 pub fn limit_param_range(
86 &mut self,
87 tool_name: impl Into<String>,
88 param_path: impl Into<String>,
89 min: Option<f64>,
90 max: Option<f64>,
91 ) {
92 self.inner.constraints.add(ParamConstraint {
93 tool_name: tool_name.into(),
94 param_path: param_path.into(),
95 rule: ConstraintRule::Range { min, max },
96 });
97 }
98
99 pub fn set_time(&mut self, now_ms: u64) {
100 self.inner.set_time(now_ms);
101 }
102
103 pub fn evaluate(&mut self, tool_name: &str, args_json: &str) -> GovernanceVerdict {
104 let args: serde_json::Value =
105 serde_json::from_str(args_json).unwrap_or(serde_json::Value::Null);
106 let call = ToolCall {
107 id: CompactString::new("gov"),
108 name: CompactString::new(tool_name),
109 arguments: args,
110 };
111 let caller = AgentIdentity::new(&self.agent_id, &self.session_id);
112 from_core(self.inner.evaluate(&call, &caller))
113 }
114}
115
116fn from_core(v: CoreVerdict) -> GovernanceVerdict {
117 match v {
118 CoreVerdict::Allow => GovernanceVerdict {
119 kind: "allow".into(),
120 reason: None,
121 retry_after_ms: None,
122 },
123 CoreVerdict::Deny { reason, .. } => GovernanceVerdict {
124 kind: "deny".into(),
125 reason: Some(reason),
126 retry_after_ms: None,
127 },
128 CoreVerdict::RateLimited { retry_after_ms } => GovernanceVerdict {
129 kind: "rate_limited".into(),
130 reason: None,
131 retry_after_ms: Some(retry_after_ms),
132 },
133 CoreVerdict::AskUser { reason } => GovernanceVerdict {
134 kind: "ask_user".into(),
135 reason: Some(reason),
136 retry_after_ms: None,
137 },
138 }
139}