1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//! Capability registry types used by `iron-core`.
use std::collections::HashMap;
/// Stable identifier for a capability family.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CapabilityId(pub &'static str);
impl CapabilityId {
/// Filesystem capability identifier.
pub const FILESYSTEM: CapabilityId = CapabilityId("iron.filesystem");
/// Terminal capability identifier.
pub const TERMINAL: CapabilityId = CapabilityId("iron.terminal");
/// Shell capability identifier.
pub const SHELL: CapabilityId = CapabilityId("iron.shell");
}
impl std::fmt::Display for CapabilityId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
/// Describes a capability exposed by the runtime.
#[derive(Debug, Clone)]
pub struct CapabilityDescriptor {
/// Stable capability identifier.
pub id: CapabilityId,
/// Human-readable capability name.
pub name: &'static str,
/// Human-readable capability description.
pub description: &'static str,
/// Backend selected for this capability.
pub backend: CapabilityBackend,
/// Whether using this capability requires permission.
pub requires_permission: bool,
}
/// Backend implementation used for a capability.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CapabilityBackend {
/// Use the built-in local implementation.
Local,
/// Use an ACP client override.
AcpOverride,
}
/// Decision returned from a capability permission request.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PermissionDecision {
/// Allow the capability use.
Allow,
/// Deny the capability use.
Deny,
/// Cancel the enclosing prompt.
Cancel,
}
/// Permission request emitted for a capability-mediated tool call.
#[derive(Debug, Clone)]
pub struct PermissionRequest {
/// Unique tool call identifier.
pub tool_call_id: String,
/// Tool name requesting the capability.
pub tool_name: String,
/// Capability involved in the request, when known.
pub capability_id: Option<CapabilityId>,
/// Human-readable request description.
pub description: String,
/// Structured tool arguments.
pub arguments: serde_json::Value,
}
/// Permission response for a capability request.
#[derive(Debug, Clone)]
pub struct PermissionResponse {
/// Final permission decision.
pub decision: PermissionDecision,
}
/// Constructors for the built-in capability descriptors.
pub struct BuiltinCapabilities;
impl BuiltinCapabilities {
/// Filesystem capability descriptor.
pub fn filesystem() -> CapabilityDescriptor {
CapabilityDescriptor {
id: CapabilityId::FILESYSTEM,
name: "Filesystem",
description: "Read and write files in the workspace",
backend: CapabilityBackend::Local,
requires_permission: true,
}
}
/// Terminal capability descriptor.
pub fn terminal() -> CapabilityDescriptor {
CapabilityDescriptor {
id: CapabilityId::TERMINAL,
name: "Terminal",
description: "Execute commands in a terminal",
backend: CapabilityBackend::Local,
requires_permission: true,
}
}
/// Shell capability descriptor.
pub fn shell() -> CapabilityDescriptor {
CapabilityDescriptor {
id: CapabilityId::SHELL,
name: "Shell",
description: "Execute shell commands",
backend: CapabilityBackend::Local,
requires_permission: true,
}
}
/// Return all built-in capability descriptors.
pub fn all() -> Vec<CapabilityDescriptor> {
vec![Self::filesystem(), Self::terminal(), Self::shell()]
}
}
/// Registry of known capabilities.
#[derive(Debug, Default)]
pub struct CapabilityRegistry {
capabilities: HashMap<CapabilityId, CapabilityDescriptor>,
}
impl CapabilityRegistry {
/// Create an empty capability registry.
pub fn new() -> Self {
Self::default()
}
/// Create a capability registry pre-populated with built-ins.
pub fn with_builtins() -> Self {
let mut registry = Self::new();
for desc in BuiltinCapabilities::all() {
registry.register(desc);
}
registry
}
/// Register or replace a capability descriptor.
pub fn register(&mut self, descriptor: CapabilityDescriptor) {
self.capabilities.insert(descriptor.id, descriptor);
}
/// Look up a capability descriptor.
pub fn get(&self, id: CapabilityId) -> Option<&CapabilityDescriptor> {
self.capabilities.get(&id)
}
/// Look up a mutable capability descriptor.
pub fn get_mut(&mut self, id: CapabilityId) -> Option<&mut CapabilityDescriptor> {
self.capabilities.get_mut(&id)
}
/// Iterate over all registered capabilities.
pub fn iter(&self) -> impl Iterator<Item = (&CapabilityId, &CapabilityDescriptor)> {
self.capabilities.iter()
}
/// Return the number of registered capabilities.
pub fn len(&self) -> usize {
self.capabilities.len()
}
/// Return whether the registry is empty.
pub fn is_empty(&self) -> bool {
self.capabilities.is_empty()
}
/// Return the backend configured for a capability.
pub fn backend_for(&self, id: CapabilityId) -> Option<CapabilityBackend> {
self.capabilities.get(&id).map(|d| d.backend)
}
/// Return whether a capability requires permission.
pub fn requires_permission(&self, id: CapabilityId) -> bool {
self.capabilities
.get(&id)
.map(|d| d.requires_permission)
.unwrap_or(false)
}
/// Return whether a capability is serviced by an ACP override.
pub fn is_acp_overridden(&self, id: CapabilityId) -> bool {
self.backend_for(id) == Some(CapabilityBackend::AcpOverride)
}
}