use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use crate::agent::AgentId;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PermissionSet {
pub allowed: HashSet<Permission>,
pub denied: HashSet<Permission>,
pub default_policy: DefaultPolicy,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Permission {
VaultRead,
VaultWrite,
VaultDelete,
FileRead,
FileWrite,
FileDelete,
ShellExec,
NetworkAccess,
MemoryRead,
MemoryWrite,
TaskCreate,
TaskModify,
CollectiveRead,
CollectiveWrite,
Custom(String),
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub enum DefaultPolicy {
#[default]
AllowUnlessExplicitlyDenied,
DenyUnlessExplicitlyAllowed,
}
impl PermissionSet {
pub fn fully_open() -> Self {
Self {
allowed: HashSet::new(),
denied: HashSet::new(),
default_policy: DefaultPolicy::AllowUnlessExplicitlyDenied,
}
}
pub fn fully_locked() -> Self {
Self {
allowed: HashSet::new(),
denied: HashSet::new(),
default_policy: DefaultPolicy::DenyUnlessExplicitlyAllowed,
}
}
pub fn is_allowed(&self, permission: &Permission) -> bool {
if self.denied.contains(permission) {
return false;
}
if self.allowed.contains(permission) {
return true;
}
matches!(
self.default_policy,
DefaultPolicy::AllowUnlessExplicitlyDenied
)
}
}
impl Default for PermissionSet {
fn default() -> Self {
Self::fully_open()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolPolicy {
pub rules: HashMap<String, ToolConstraint>,
pub default: ToolDefaultPolicy,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum ToolConstraint {
Allowed {
max_calls_per_turn: Option<u32>,
max_calls_per_session: Option<u32>,
},
Denied,
RequiresApproval,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub enum ToolDefaultPolicy {
#[default]
AllowAll,
DenyUnlisted,
}
impl ToolPolicy {
pub fn open() -> Self {
Self {
rules: HashMap::new(),
default: ToolDefaultPolicy::AllowAll,
}
}
pub fn allows_without_approval(&self, tool_name: &str) -> bool {
match self.rules.get(tool_name) {
Some(ToolConstraint::Denied) => false,
Some(ToolConstraint::Allowed { .. }) => true,
Some(ToolConstraint::RequiresApproval) => false,
None => matches!(self.default, ToolDefaultPolicy::AllowAll),
}
}
pub fn requires_approval(&self, tool_name: &str) -> bool {
matches!(
self.rules.get(tool_name),
Some(ToolConstraint::RequiresApproval)
)
}
pub fn constraint(&self, tool_name: &str) -> Option<&ToolConstraint> {
self.rules.get(tool_name)
}
pub fn is_tool_allowed(&self, tool_name: &str) -> bool {
self.allows_without_approval(tool_name)
}
}
impl Default for ToolPolicy {
fn default() -> Self {
Self::open()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommunicationRules {
pub can_delegate_to: Option<HashSet<AgentId>>,
pub can_query: Option<HashSet<AgentId>>,
pub cannot_contact: HashSet<AgentId>,
pub default: CommunicationDefault,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub enum CommunicationDefault {
#[default]
AllowAll,
DelegateOnly,
DenyAll,
}
impl CommunicationRules {
pub fn open() -> Self {
Self {
can_delegate_to: None,
can_query: None,
cannot_contact: HashSet::new(),
default: CommunicationDefault::AllowAll,
}
}
pub fn can_reach(&self, target: &AgentId) -> bool {
if self.cannot_contact.contains(target) {
return false;
}
match &self.can_delegate_to {
Some(allowed) => allowed.contains(target),
None => !matches!(self.default, CommunicationDefault::DenyAll),
}
}
pub fn can_query(&self, target: &AgentId) -> bool {
if self.cannot_contact.contains(target) {
return false;
}
match &self.can_query {
Some(allowed) => allowed.contains(target),
None => !matches!(self.default, CommunicationDefault::DenyAll),
}
}
}
impl Default for CommunicationRules {
fn default() -> Self {
Self::open()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContextBudget {
pub self_context_tokens: u32,
pub collective_tokens: u32,
pub task_context_tokens: u32,
pub execution_awareness_tokens: u32,
pub handoff_context_tokens: u32,
pub overflow_policy: OverflowPolicy,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub enum OverflowPolicy {
Compress,
Truncate,
#[default]
Warn,
}
impl Default for ContextBudget {
fn default() -> Self {
Self {
self_context_tokens: 4096,
collective_tokens: 2048,
task_context_tokens: 1024,
execution_awareness_tokens: 512,
handoff_context_tokens: 512,
overflow_policy: OverflowPolicy::Warn,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WriteGovernance {
pub own_memory: WriteAccess,
pub collective: WriteAccess,
pub vault: WriteAccess,
pub task_store: WriteAccess,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[non_exhaustive]
pub enum WriteAccess {
#[default]
Free,
RequiresGrant,
ReadOnly,
Attributed,
}
impl Default for WriteGovernance {
fn default() -> Self {
Self {
own_memory: WriteAccess::Free,
collective: WriteAccess::Free,
vault: WriteAccess::Free,
task_store: WriteAccess::Free,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Guardrail {
MaxOutputTokens(u32),
MustCiteSources,
NoCodeExecution,
MaxToolCallsPerTurn(u32),
Custom { name: String, description: String },
}