Skip to repository content224 lines · 9.6 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T04:02:46.378Z 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
omega_executor_disclosure.rs
1//! Who executed a thread. OMEGA-DELTA-0021.
2//!
3//! Omega presents one chat surface over three executor classes: its own
4//! in-process agent loop, out-of-process ACP agents such as `codex-acp`, and
5//! `omega-effectd` engine lanes. Without disclosure all three look identical to
6//! the reader — output appears in an Omega window and reads as Omega's own
7//! work. That is a false attribution claim, made silently.
8//!
9//! # The record lives in `omega_front_door`, and this is only the binding
10//!
11//! [`omega_front_door::ExecutorDisclosure`] is the typed record. That is
12//! omega#74's binding condition on the owner's identity decision: the agent
13//! does not sign with its own principal, *on the condition that disclosure is
14//! stored as a typed record that a label renders, never as a label string.*
15//! A record of parts can be handed to a signer later; a rendered line cannot,
16//! so storing the line would silently convert a reversible owner decision into
17//! an irreversible one.
18//!
19//! This module holds the part that record deliberately cannot: reading a live
20//! thread. `omega_front_door` is a leaf that depends on nothing, so it cannot
21//! see GPUI, `acp_thread`, or a connection. The extension trait below is that
22//! bridge, and it lives here rather than in `crates/acp_thread` so the upstream
23//! thread type carries no Omega state and a rebase cannot quietly drop it.
24//!
25//! # Why nothing new is persisted
26//!
27//! omega#77's falsifier names a *new* GPUI-owned durable store as a failure,
28//! and its deliverable says the disclosure persists through existing thread
29//! persistence. Every part of the record already has a durable home, so the
30//! record is a projection over them rather than a fourth copy that can drift:
31//!
32//! | Part | Durable home |
33//! | --- | --- |
34//! | class, agent id | the connection, rebuilt from `sidebar_threads.agent_id` |
35//! | provider, model | `DbThread.model`, restored by `Thread::from_db` |
36//! | run ref | `full-auto-host-correlation.json`, reloaded at startup |
37//!
38//! A projection cannot disagree with the thread it describes. A cached copy
39//! can, and a disclosure that disagrees with its executor is worse than none.
40
41use std::rc::Rc;
42
43use acp_thread::{AcpThread, AgentConnection};
44use agent::NativeAgentConnection;
45use agent_client_protocol::schema::v1 as acp;
46use agent_servers::AcpConnection;
47use gpui::App;
48use omega_front_door::{ExecutorClass, ExecutorDisclosure};
49
50/// Read a thread's executor disclosure.
51///
52/// An Omega extension trait over the shared thread type, rather than an
53/// inherent method on it and rather than a fork of it. A rebase that reshapes
54/// `AcpThread` cannot silently drop the disclosure: it would drop the `impl`
55/// below, and this crate would stop compiling.
56pub trait ThreadExecutorDisclosure {
57 /// Who executed this thread, before any engine-lane re-attribution.
58 fn omega_executor_disclosure(&self, cx: &App) -> ExecutorDisclosure;
59}
60
61impl ThreadExecutorDisclosure for AcpThread {
62 fn omega_executor_disclosure(&self, cx: &App) -> ExecutorDisclosure {
63 classify_connection(self.connection().clone(), self.session_id(), cx)
64 }
65}
66
67/// Re-attribute a disclosure to the engine run that owns the thread.
68///
69/// The executing agent's identity is kept. A host-bridge thread really is a
70/// `codex-acp` process underneath, and the honest reading is "this run
71/// delegated to this agent", not "a run did it".
72#[must_use]
73pub fn delegated_to_run(mut disclosure: ExecutorDisclosure, run_ref: String) -> ExecutorDisclosure {
74 disclosure.class = ExecutorClass::EngineLane;
75 disclosure.run_ref = Some(run_ref);
76 disclosure
77}
78
79/// Classify a connection by its concrete type.
80///
81/// A checked downcast, not a name comparison. `agent_id()` is a display-facing
82/// identifier — omega#75 is renaming Omega's own, and an extension can set its
83/// own to anything — so deciding *what ran* from it would make the disclosure a
84/// string match on a label, which is the failure mode this whole surface exists
85/// to avoid.
86///
87/// The fallback is [`ExecutorClass::ExternalAcp`] rather than the native loop,
88/// and that direction is deliberate: `NativeLoop` is the first-party claim, and
89/// an unrecognised connection defaulting to it would present somebody else's
90/// output as Omega's own. Guessing wrong towards "not ours" costs precision;
91/// guessing wrong towards "ours" is the dishonest attribution omega#77 exists
92/// to stop.
93fn classify_connection(
94 connection: Rc<dyn AgentConnection>,
95 session_id: &acp::SessionId,
96 cx: &App,
97) -> ExecutorDisclosure {
98 let agent_id = connection.agent_id().0.to_string();
99
100 if let Some(native) = connection.clone().downcast::<NativeAgentConnection>() {
101 let (provider, model) = native
102 .thread(session_id, cx)
103 .and_then(|thread| {
104 thread.read(cx).model().map(|model| {
105 (
106 Some(model.provider_id().0.to_string()),
107 Some(model.id().0.to_string()),
108 )
109 })
110 })
111 .unwrap_or((None, None));
112 return ExecutorDisclosure {
113 class: ExecutorClass::NativeLoop,
114 agent_id,
115 provider,
116 model,
117 run_ref: None,
118 route: crate::omega_router::recorded_route(session_id),
119 };
120 }
121
122 // `OMEGA-DELTA-0042`, omega#87. The Exo harness lane. Recognised by its
123 // concrete type for the same reason the native loop is: `agent_id()` on
124 // this connection is *derived from what Exo said about itself*, so
125 // classifying by it would let an Exo install decide its own class.
126 //
127 // Exo reports `ExternalAcp`. The reasoning — and the argument against a
128 // fourth class — is in `omega_exo_lane`'s module documentation. What is
129 // added here over the shared fallback below is the model: Exo does tell
130 // Omega which model served, so the lane says so instead of "not disclosed".
131 if let Some(exo) = connection
132 .clone()
133 .downcast::<crate::omega_exo_connection::ExoHarnessConnection>()
134 {
135 // `None` before Exo has been asked. An identity nobody observed is
136 // absent, never invented.
137 let identity = exo.identity();
138 return ExecutorDisclosure {
139 class: omega_exo_lane::EXO_EXECUTOR_CLASS,
140 agent_id: identity
141 .as_ref()
142 .map_or_else(|| agent_id.clone(), omega_exo_lane::ExoLaneIdentity::agent_id),
143 provider: identity.as_ref().and_then(|identity| identity.provider.clone()),
144 model: identity.and_then(|identity| identity.model),
145 run_ref: None,
146 route: crate::omega_router::recorded_route(session_id),
147 };
148 }
149
150 // `AcpConnection` shares the fallback, but is recognised explicitly so an
151 // unrecognised connection type leaves a trace instead of passing silently.
152 if connection.downcast::<AcpConnection>().is_none() {
153 log::debug!(
154 "OMEGA-DELTA-0021: disclosing {agent_id} as an external ACP agent; \
155 its connection type is not one this build recognises"
156 );
157 }
158
159 ExecutorDisclosure {
160 class: ExecutorClass::ExternalAcp,
161 agent_id,
162 provider: None,
163 model: None,
164 run_ref: None,
165 route: crate::omega_router::recorded_route(session_id),
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 /// OMEGA-DELTA-0021. Delegating to a run keeps the agent that actually ran
174 /// the work, and produces a coherent record.
175 #[test]
176 fn delegating_to_a_run_keeps_the_executing_agent() {
177 let routed = ExecutorDisclosure {
178 class: ExecutorClass::ExternalAcp,
179 agent_id: "codex-acp".into(),
180 provider: None,
181 model: None,
182 run_ref: None,
183 route: Some(omega_front_door::RouteReason::PinHonored),
184 };
185 assert!(routed.is_coherent());
186
187 let delegated = delegated_to_run(routed, "operation.full-auto.77".into());
188 assert_eq!(delegated.class, ExecutorClass::EngineLane);
189 assert_eq!(delegated.agent_id, "codex-acp");
190 assert_eq!(delegated.run_ref.as_deref(), Some("operation.full-auto.77"));
191 assert!(delegated.is_coherent());
192
193 let line = delegated.label();
194 assert!(line.contains("codex-acp"), "{line:?}");
195 assert!(line.contains("engine_lane"), "{line:?}");
196 assert!(line.contains("operation.full-auto.77"), "{line:?}");
197 }
198
199 /// The honest-attribution rule as an oracle: only the native loop is
200 /// Omega's own output, so no routed or delegated record may carry the
201 /// first-party class.
202 #[test]
203 fn a_routed_or_delegated_record_never_claims_the_native_loop() {
204 for class in [ExecutorClass::ExternalAcp, ExecutorClass::EngineLane] {
205 let run_ref = (class == ExecutorClass::EngineLane).then(|| "run.1".to_string());
206 let disclosure = ExecutorDisclosure {
207 class,
208 agent_id: "codex-acp".into(),
209 provider: None,
210 model: None,
211 run_ref,
212 route: Some(omega_front_door::RouteReason::PinHonored),
213 };
214 assert!(disclosure.is_coherent(), "{class:?}");
215 assert_ne!(disclosure.class, ExecutorClass::NativeLoop);
216 assert!(
217 disclosure.label().starts_with(class.token()),
218 "the line must lead with the class that ran the work: {}",
219 disclosure.label()
220 );
221 }
222 }
223}
224