Skip to repository content299 lines · 10.1 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T03:15:02.834Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
authority.rs
1//! One-turn authority for Exo self-modification. omega#87, Tier C.
2//!
3//! A lane pin does not grant this authority. The host must show the exact
4//! observed capabilities to a person and mint one grant for one turn. The
5//! grant is consumed immediately before the prompt crosses ACP.
6
7use serde::{Deserialize, Serialize};
8use std::cell::Cell;
9
10/// One exact tool module observed in Exo's configuration.
11#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Ord, Serialize)]
12pub struct ObservedToolModule {
13 pub path: String,
14 pub digest: String,
15}
16
17/// One exact read-write mount observed in Exo's effective configuration.
18#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Ord, Serialize)]
19pub struct ObservedReadWriteMount {
20 pub host_path: String,
21 pub mount_path: String,
22}
23
24/// Everything that can widen a self-modifying Exo turn.
25#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
26pub struct ObservedExoCapabilityState {
27 pub source_commit: String,
28 pub source_tree: String,
29 pub binary_digest: String,
30 pub agent: String,
31 pub conversation: String,
32 pub generation: u64,
33 pub agent_authored_tools: bool,
34 pub tool_modules: Vec<ObservedToolModule>,
35 pub read_write_mounts: Vec<ObservedReadWriteMount>,
36}
37
38/// The closed set of self-modification authority a person can grant.
39#[derive(Clone, Debug, Deserialize, PartialEq, Eq, PartialOrd, Ord, Serialize)]
40pub enum ExoSelfModificationCapability {
41 AgentAuthoredTools,
42 ToolModule(ObservedToolModule),
43 ReadWriteMount(ObservedReadWriteMount),
44}
45
46impl ObservedExoCapabilityState {
47 #[must_use]
48 pub fn requested_capabilities(&self) -> Vec<ExoSelfModificationCapability> {
49 let mut capabilities = Vec::new();
50 if self.agent_authored_tools {
51 capabilities.push(ExoSelfModificationCapability::AgentAuthoredTools);
52 }
53 capabilities.extend(
54 self.tool_modules
55 .iter()
56 .cloned()
57 .map(ExoSelfModificationCapability::ToolModule),
58 );
59 capabilities.extend(
60 self.read_write_mounts
61 .iter()
62 .cloned()
63 .map(ExoSelfModificationCapability::ReadWriteMount),
64 );
65 capabilities
66 }
67}
68
69/// The exact request shown in the confirmation surface.
70#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
71pub struct ExoSelfModificationGrantRequest {
72 pub objective: String,
73 pub turn_ref: String,
74 pub observed: ObservedExoCapabilityState,
75 pub capabilities: Vec<ExoSelfModificationCapability>,
76 pub expires_at_ms: u64,
77}
78
79/// Only a visible, dedicated human action can supply this origin.
80#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
81pub enum ExoSelfModificationConsentOrigin {
82 HumanConfirmationDialog,
83}
84
85/// A one-use authority decision.
86#[derive(Debug)]
87pub struct ExoSelfModificationGrant {
88 request: ExoSelfModificationGrantRequest,
89 origin: ExoSelfModificationConsentOrigin,
90 consumed: Cell<bool>,
91}
92
93/// Why a grant did not authorize the send.
94#[derive(Clone, Copy, Debug, PartialEq, Eq)]
95pub enum ExoGrantRefusal {
96 EmptyObjective,
97 NoSelfModificationRequested,
98 CapabilityMismatch,
99 Expired,
100 ConfigurationDrift,
101 TurnMismatch,
102 AlreadyConsumed,
103}
104
105/// Durable input for the host's allow/refuse receipt.
106#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
107pub struct ExoSelfModificationReceipt {
108 pub objective: String,
109 pub turn_ref: String,
110 pub generation: u64,
111 pub expires_at_ms: u64,
112 pub origin: ExoSelfModificationConsentOrigin,
113 pub capabilities: Vec<ExoSelfModificationCapability>,
114 pub observed: ObservedExoCapabilityState,
115}
116
117impl ExoSelfModificationGrant {
118 /// The exact request this grant can authorize.
119 #[must_use]
120 pub fn request(&self) -> &ExoSelfModificationGrantRequest {
121 &self.request
122 }
123
124 /// Mint a grant after the dedicated confirmation action.
125 pub fn mint(
126 request: ExoSelfModificationGrantRequest,
127 origin: ExoSelfModificationConsentOrigin,
128 now_ms: u64,
129 ) -> Result<Self, ExoGrantRefusal> {
130 if request.objective.trim().is_empty() {
131 return Err(ExoGrantRefusal::EmptyObjective);
132 }
133 let observed = request.observed.requested_capabilities();
134 if observed.is_empty() {
135 return Err(ExoGrantRefusal::NoSelfModificationRequested);
136 }
137 if request.capabilities != observed {
138 return Err(ExoGrantRefusal::CapabilityMismatch);
139 }
140 if now_ms >= request.expires_at_ms {
141 return Err(ExoGrantRefusal::Expired);
142 }
143 Ok(Self {
144 request,
145 origin,
146 consumed: Cell::new(false),
147 })
148 }
149
150 /// Consume the grant immediately before the ACP prompt.
151 pub fn consume(
152 &self,
153 current: &ObservedExoCapabilityState,
154 turn_ref: &str,
155 now_ms: u64,
156 ) -> Result<ExoSelfModificationReceipt, ExoGrantRefusal> {
157 if self.consumed.get() {
158 return Err(ExoGrantRefusal::AlreadyConsumed);
159 }
160 if now_ms >= self.request.expires_at_ms {
161 return Err(ExoGrantRefusal::Expired);
162 }
163 if current != &self.request.observed {
164 return Err(ExoGrantRefusal::ConfigurationDrift);
165 }
166 if turn_ref != self.request.turn_ref {
167 return Err(ExoGrantRefusal::TurnMismatch);
168 }
169 self.consumed.set(true);
170 Ok(ExoSelfModificationReceipt {
171 objective: self.request.objective.clone(),
172 turn_ref: self.request.turn_ref.clone(),
173 generation: current.generation,
174 expires_at_ms: self.request.expires_at_ms,
175 origin: self.origin,
176 capabilities: self.request.capabilities.clone(),
177 observed: current.clone(),
178 })
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 fn observed() -> ObservedExoCapabilityState {
187 ObservedExoCapabilityState {
188 source_commit: "commit".into(),
189 source_tree: "tree".into(),
190 binary_digest: "sha256:bytes".into(),
191 agent: "agent".into(),
192 conversation: "conversation".into(),
193 generation: 7,
194 agent_authored_tools: true,
195 tool_modules: vec![ObservedToolModule {
196 path: "/tools/guardian.ts".into(),
197 digest: "sha256:module".into(),
198 }],
199 read_write_mounts: vec![ObservedReadWriteMount {
200 host_path: "/host/exo".into(),
201 mount_path: "/workspace/exo".into(),
202 }],
203 }
204 }
205
206 fn request() -> ExoSelfModificationGrantRequest {
207 let observed = observed();
208 ExoSelfModificationGrantRequest {
209 objective: "Edit, verify, and restart Exo.".into(),
210 turn_ref: "turn-1".into(),
211 capabilities: observed.requested_capabilities(),
212 observed,
213 expires_at_ms: 200,
214 }
215 }
216
217 #[test]
218 fn exact_grant_is_one_use() {
219 let grant = ExoSelfModificationGrant::mint(
220 request(),
221 ExoSelfModificationConsentOrigin::HumanConfirmationDialog,
222 100,
223 )
224 .expect("grant");
225 assert!(grant.consume(&observed(), "turn-1", 101).is_ok());
226 assert_eq!(
227 grant.consume(&observed(), "turn-1", 102),
228 Err(ExoGrantRefusal::AlreadyConsumed)
229 );
230 }
231
232 #[test]
233 fn every_observed_field_is_generation_fenced() {
234 let mutations: [fn(&mut ObservedExoCapabilityState); 8] = [
235 |state: &mut ObservedExoCapabilityState| state.source_commit.push('x'),
236 |state: &mut ObservedExoCapabilityState| state.source_tree.push('x'),
237 |state: &mut ObservedExoCapabilityState| state.binary_digest.push('x'),
238 |state: &mut ObservedExoCapabilityState| state.agent.push('x'),
239 |state: &mut ObservedExoCapabilityState| state.conversation.push('x'),
240 |state: &mut ObservedExoCapabilityState| state.generation += 1,
241 |state: &mut ObservedExoCapabilityState| state.tool_modules[0].digest.push('x'),
242 |state: &mut ObservedExoCapabilityState| {
243 state.read_write_mounts[0].mount_path.push('x')
244 },
245 ];
246 for mutate in mutations {
247 let grant = ExoSelfModificationGrant::mint(
248 request(),
249 ExoSelfModificationConsentOrigin::HumanConfirmationDialog,
250 100,
251 )
252 .expect("grant");
253 let mut changed = observed();
254 mutate(&mut changed);
255 assert_eq!(
256 grant.consume(&changed, "turn-1", 101),
257 Err(ExoGrantRefusal::ConfigurationDrift)
258 );
259 }
260 }
261
262 #[test]
263 fn expired_or_widened_requests_refuse() {
264 assert!(matches!(
265 ExoSelfModificationGrant::mint(
266 request(),
267 ExoSelfModificationConsentOrigin::HumanConfirmationDialog,
268 200
269 ),
270 Err(ExoGrantRefusal::Expired)
271 ));
272 let mut widened = request();
273 widened.capabilities.pop();
274 assert!(matches!(
275 ExoSelfModificationGrant::mint(
276 widened,
277 ExoSelfModificationConsentOrigin::HumanConfirmationDialog,
278 100
279 ),
280 Err(ExoGrantRefusal::CapabilityMismatch)
281 ));
282 }
283
284 #[test]
285 fn a_grant_cannot_move_to_another_turn() {
286 let grant = ExoSelfModificationGrant::mint(
287 request(),
288 ExoSelfModificationConsentOrigin::HumanConfirmationDialog,
289 100,
290 )
291 .expect("grant");
292 assert_eq!(
293 grant.consume(&observed(), "turn-2", 101),
294 Err(ExoGrantRefusal::TurnMismatch)
295 );
296 assert!(grant.consume(&observed(), "turn-1", 102).is_ok());
297 }
298}
299