1use serde::{Deserialize, Serialize};
8use std::collections::{HashMap, HashSet};
9
10use crate::agent::AgentId;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct PermissionSet {
17 pub allowed: HashSet<Permission>,
18 pub denied: HashSet<Permission>,
19 pub default_policy: DefaultPolicy,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
23#[non_exhaustive]
24pub enum Permission {
25 VaultRead,
26 VaultWrite,
27 VaultDelete,
28 FileRead,
29 FileWrite,
30 FileDelete,
31 ShellExec,
32 NetworkAccess,
33 MemoryRead,
34 MemoryWrite,
35 TaskCreate,
36 TaskModify,
37 CollectiveRead,
38 CollectiveWrite,
39 Custom(String),
40}
41
42#[derive(Debug, Clone, Default, Serialize, Deserialize)]
43pub enum DefaultPolicy {
44 #[default]
45 AllowUnlessExplicitlyDenied,
46 DenyUnlessExplicitlyAllowed,
47}
48
49impl PermissionSet {
50 pub fn fully_open() -> Self {
51 Self {
52 allowed: HashSet::new(),
53 denied: HashSet::new(),
54 default_policy: DefaultPolicy::AllowUnlessExplicitlyDenied,
55 }
56 }
57
58 pub fn fully_locked() -> Self {
59 Self {
60 allowed: HashSet::new(),
61 denied: HashSet::new(),
62 default_policy: DefaultPolicy::DenyUnlessExplicitlyAllowed,
63 }
64 }
65
66 pub fn is_allowed(&self, permission: &Permission) -> bool {
67 if self.denied.contains(permission) {
68 return false;
69 }
70 if self.allowed.contains(permission) {
71 return true;
72 }
73 matches!(
74 self.default_policy,
75 DefaultPolicy::AllowUnlessExplicitlyDenied
76 )
77 }
78}
79
80impl Default for PermissionSet {
81 fn default() -> Self {
82 Self::fully_open()
83 }
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct ToolPolicy {
91 pub rules: HashMap<String, ToolConstraint>,
92 pub default: ToolDefaultPolicy,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
96#[non_exhaustive]
97pub enum ToolConstraint {
98 Allowed {
99 max_calls_per_turn: Option<u32>,
100 max_calls_per_session: Option<u32>,
101 },
102 Denied,
103 RequiresApproval,
104}
105
106#[derive(Debug, Clone, Default, Serialize, Deserialize)]
107pub enum ToolDefaultPolicy {
108 #[default]
109 AllowAll,
110 DenyUnlisted,
111}
112
113impl ToolPolicy {
114 pub fn open() -> Self {
115 Self {
116 rules: HashMap::new(),
117 default: ToolDefaultPolicy::AllowAll,
118 }
119 }
120
121 pub fn allows_without_approval(&self, tool_name: &str) -> bool {
123 match self.rules.get(tool_name) {
124 Some(ToolConstraint::Denied) => false,
125 Some(ToolConstraint::Allowed { .. }) => true,
126 Some(ToolConstraint::RequiresApproval) => false,
127 None => matches!(self.default, ToolDefaultPolicy::AllowAll),
128 }
129 }
130
131 pub fn requires_approval(&self, tool_name: &str) -> bool {
133 matches!(
134 self.rules.get(tool_name),
135 Some(ToolConstraint::RequiresApproval)
136 )
137 }
138
139 pub fn constraint(&self, tool_name: &str) -> Option<&ToolConstraint> {
141 self.rules.get(tool_name)
142 }
143
144 pub fn is_tool_allowed(&self, tool_name: &str) -> bool {
146 self.allows_without_approval(tool_name)
147 }
148}
149
150impl Default for ToolPolicy {
151 fn default() -> Self {
152 Self::open()
153 }
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct CommunicationRules {
161 pub can_delegate_to: Option<HashSet<AgentId>>,
162 pub can_query: Option<HashSet<AgentId>>,
163 pub cannot_contact: HashSet<AgentId>,
164 pub default: CommunicationDefault,
165}
166
167#[derive(Debug, Clone, Default, Serialize, Deserialize)]
168pub enum CommunicationDefault {
169 #[default]
170 AllowAll,
171 DelegateOnly,
172 DenyAll,
173}
174
175impl CommunicationRules {
176 pub fn open() -> Self {
177 Self {
178 can_delegate_to: None,
179 can_query: None,
180 cannot_contact: HashSet::new(),
181 default: CommunicationDefault::AllowAll,
182 }
183 }
184
185 pub fn can_reach(&self, target: &AgentId) -> bool {
186 if self.cannot_contact.contains(target) {
187 return false;
188 }
189 match &self.can_delegate_to {
190 Some(allowed) => allowed.contains(target),
191 None => !matches!(self.default, CommunicationDefault::DenyAll),
192 }
193 }
194
195 pub fn can_query(&self, target: &AgentId) -> bool {
197 if self.cannot_contact.contains(target) {
198 return false;
199 }
200 match &self.can_query {
201 Some(allowed) => allowed.contains(target),
202 None => !matches!(self.default, CommunicationDefault::DenyAll),
203 }
204 }
205}
206
207impl Default for CommunicationRules {
208 fn default() -> Self {
209 Self::open()
210 }
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct ContextBudget {
218 pub self_context_tokens: u32,
219 pub collective_tokens: u32,
220 pub task_context_tokens: u32,
221 pub execution_awareness_tokens: u32,
222 pub handoff_context_tokens: u32,
223 pub overflow_policy: OverflowPolicy,
224}
225
226#[derive(Debug, Clone, Default, Serialize, Deserialize)]
227pub enum OverflowPolicy {
228 Compress,
229 Truncate,
230 #[default]
231 Warn,
232}
233
234impl Default for ContextBudget {
235 fn default() -> Self {
236 Self {
237 self_context_tokens: 4096,
238 collective_tokens: 2048,
239 task_context_tokens: 1024,
240 execution_awareness_tokens: 512,
241 handoff_context_tokens: 512,
242 overflow_policy: OverflowPolicy::Warn,
243 }
244 }
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
251pub struct WriteGovernance {
252 pub own_memory: WriteAccess,
253 pub collective: WriteAccess,
254 pub vault: WriteAccess,
255 pub task_store: WriteAccess,
256}
257
258#[derive(Debug, Clone, Default, Serialize, Deserialize)]
259#[non_exhaustive]
260pub enum WriteAccess {
261 #[default]
262 Free,
263 RequiresGrant,
264 ReadOnly,
265 Attributed,
266}
267
268impl Default for WriteGovernance {
269 fn default() -> Self {
270 Self {
271 own_memory: WriteAccess::Free,
272 collective: WriteAccess::Free,
273 vault: WriteAccess::Free,
274 task_store: WriteAccess::Free,
275 }
276 }
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
283#[non_exhaustive]
284pub enum Guardrail {
285 MaxOutputTokens(u32),
286 MustCiteSources,
287 NoCodeExecution,
288 MaxToolCallsPerTurn(u32),
289 Custom { name: String, description: String },
290}