Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T02:06:50.898Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

omega_exo_lane.rs

316 lines · 14.0 KB · rust
1//! The Exo harness lane. `OMEGA-DELTA-0042`, omega#87.
2//!
3//! Omega drives **`exoharness/exo`** — the recursive-self-improvement agent
4//! harness from the Braintrust orbit — as one more executor lane beneath Omega
5//! Agent, beside the native loop and the ACP agents. It is **not** exo labs'
6//! `exo-explore/exo` cluster-inference appliance; omega#86 was closed for
7//! targeting the wrong one, and [`EXO_PIN`] names the repository so the
8//! distinction is a field rather than a sentence.
9//!
10//! This crate is the **law**, and it is a leaf: no GPUI, no process, no
11//! filesystem, no clock. It decides which Exo is admitted ([`pin`]), which
12//! command lines exist ([`command`]), where Exo may be reached ([`endpoint`]),
13//! which Exo agents may be run ([`capability`]), and what a turn's output means
14//! ([`turn`]). The half that spawns a process and builds a thread lives in
15//! `crates/agent_ui/src/omega_exo_connection.rs`, for the same reason the
16//! router's decision half lives here and its dispatch half lives there: a law
17//! that needs GPUI to check is a law nobody checks.
18//!
19//! # Streaming and self-modification authority
20//!
21//! Exo sends live text, tool calls, tool results, and completion records through
22//! its ACP standard-input transport. Omega attaches that transport through
23//! `crates/agent_servers`.
24//!
25//! Self-modification is off by default. A person can authorize one exact turn
26//! in a dedicated confirmation dialog. The grant binds the source, binary,
27//! agent, conversation, tool modules, mounts, draft, generation, and expiry.
28//! The send path consumes the grant once and writes a durable receipt.
29//!
30//! # Which executor class an Exo thread reports, and why
31//!
32//! [`ExecutorClass`] is closed at three variants by `OMEGA-AGENT-AC-04`, and it
33//! answers one question: **who ran the work.** An Exo thread reports
34//! [`ExecutorClass::ExternalAcp`].
35//!
36//! * Not [`ExecutorClass::NativeLoop`]. That is the first-party claim — Omega's
37//!   own in-process loop in `crates/agent`. Presenting somebody else's output
38//!   as Omega's own is the dishonest attribution omega#77 exists to stop, and
39//!   this would be its worst case: Exo's agent has an unrestricted networked
40//!   shell.
41//! * Not [`ExecutorClass::EngineLane`]. An engine lane *is* Full Auto
42//!   authority. `ExecutorDisclosure::is_coherent` requires a `run_ref` on one,
43//!   and the router will not route an unpinned thread to one because owner gate
44//!   8 admits only an explicit human action into that authority. Exo has no
45//!   engine run, no run reference, and no receipt. A lane that reported
46//!   `EngineLane` would be a new door into Full Auto authority reachable by
47//!   adding an executor — a fourth of exactly the kind that were removed from
48//!   OpenAgents Desktop on 2026-07-25. An Exo agent with a shell is precisely
49//!   the caller that gate exists for.
50//! * So [`ExecutorClass::ExternalAcp`]. Its documentation says "an external ACP
51//!   agent reached through `crates/agent_servers`", and Tier A reaches Exo over
52//!   its CLI rather than over ACP — so the fit is worth stating rather than
53//!   assuming. The class is about the *executor*, not the *wire*: a separate
54//!   process, outside Omega, that Omega does not own, that reports no model
55//!   through `AgentConnection::model_selector`, and that must carry no
56//!   `run_ref` — which is exactly what `is_coherent` requires of this class and
57//!   exactly what is true of Exo. Tier B swaps the CLI for ACP and **the class
58//!   does not change**, which is the test that the class was about the right
59//!   thing.
60//!
61//! A fourth variant was considered and not taken. It would need a revision of
62//! `OMEGA-AGENT-AC-04`, and the argument for it would have to be that the wire
63//! is part of who ran the work. It is not: the wire is why the lane is coarse,
64//! and the coarseness is visible to the reader without a class, because no text
65//! delta ever arrives. That argument is written here so a later reader can
66//! disagree with something concrete rather than re-derive it.
67//!
68//! # The disclosure names Exo, its executor, and its model
69//!
70//! [`ExecutorDisclosure`] is a record of parts a label renders, never a stored
71//! label — omega#74's binding condition, held mechanically by
72//! `EXECUTOR_DISCLOSURE_FIELDS`. So the lane adds no field. It fills the ones
73//! that exist:
74//!
75//! | Part | Exo |
76//! | --- | --- |
77//! | `class` | `ExternalAcp`, for the reasons above |
78//! | `agent_id` | `exo/<executor>` — the process and the executor inside it |
79//! | `provider` | the model binding's base URL, or *not disclosed* |
80//! | `model` | the upstream model the binding resolves to |
81//! | `run_ref` | `None`; Exo holds no Omega run authority |
82//!
83//! `provider` is genuinely `None` for a default binding, because Exo's LLM
84//! binding has no provider field at all — only an optional base URL. Saying
85//! "not disclosed" is the honest third option omega#77 added for exactly this,
86//! and it is better than deriving "openai" from the absence of a URL, which
87//! would be Omega inventing a fact about somebody else's configuration.
88
89pub mod authority;
90pub mod capability;
91pub mod command;
92pub mod endpoint;
93pub mod pin;
94pub mod turn;
95
96pub use capability::{ExoAgent, ExoAgentReadError, ExoConversation, ExoMount, SelfModification};
97pub use command::{ADMITTED_LANE_ARGV, ARGUMENT_TERMINATOR, ExoArg, ExoCommand, ExoRoot};
98pub use endpoint::{EXO_SERVE_DEFAULT_BIND, LoopbackEndpoint, OffLoopback};
99pub use pin::{EXO_HARNESS_ID, EXO_PIN, ExoPin, ExoPinMismatch, ObservedExoCheckout, admits_bytes};
100pub use turn::{ExoToolActivity, ExoTurn, NotATurn};
101
102use omega_front_door::{ExecutorClass, ExecutorDisclosure, RouteReason};
103
104/// The executor class an Exo thread reports. See the module documentation for
105/// why this is the one, and why it is not a fourth.
106pub const EXO_EXECUTOR_CLASS: ExecutorClass = ExecutorClass::ExternalAcp;
107
108/// One row of `exo model list`.
109#[derive(Clone, Debug, PartialEq, Eq)]
110pub struct ExoModelBinding {
111    /// The local binding name, which is what an agent record refers to.
112    pub name: String,
113    /// The model the binding actually resolves to upstream.
114    pub upstream_model: String,
115    /// The base URL, when the binding names one. `None` for Exo's default,
116    /// which carries no provider information at all.
117    pub base_url: Option<String>,
118}
119
120impl ExoModelBinding {
121    /// Read `exo model list` output.
122    ///
123    /// The table is elastic-tab-expanded, so columns are separated by runs of
124    /// two or more spaces. A row this build cannot split into four columns is
125    /// skipped rather than guessed at: a half-read binding would produce a
126    /// disclosure naming a model nobody configured.
127    #[must_use]
128    pub fn read_table(stdout: &str) -> Vec<Self> {
129        stdout
130            .lines()
131            .skip(1)
132            .filter_map(|line| {
133                let columns: Vec<&str> = line
134                    .split("  ")
135                    .map(str::trim)
136                    .filter(|column| !column.is_empty())
137                    .collect();
138                let [name, upstream_model, _secret, base_url] = columns.as_slice() else {
139                    return None;
140                };
141                Some(Self {
142                    name: (*name).to_owned(),
143                    upstream_model: (*upstream_model).to_owned(),
144                    base_url: (*base_url != "default").then(|| (*base_url).to_owned()),
145                })
146            })
147            .collect()
148    }
149}
150
151/// Everything a thread on this lane discloses.
152///
153/// Assembled from what Exo reported about itself: [`ExoAgent`] from
154/// `agent show`, and the matching [`ExoModelBinding`] from `model list`. A
155/// binding Exo did not report is *absent*, never invented.
156#[derive(Clone, Debug, PartialEq, Eq)]
157pub struct ExoLaneIdentity {
158    /// The executor Exo runs the turn with: `basic`, `rlm`, `typescript`,
159    /// `codex`, `claude-code`, `cursor`, or a module path.
160    pub executor: String,
161    /// The model the agent's binding resolves to upstream, when Exo reported a
162    /// binding for it.
163    pub model: Option<String>,
164    /// The binding's base URL, when it has one.
165    pub provider: Option<String>,
166}
167
168impl ExoLaneIdentity {
169    /// Bind an agent to the model bindings Exo reported.
170    #[must_use]
171    pub fn resolve(agent: &ExoAgent, bindings: &[ExoModelBinding]) -> Self {
172        let binding = bindings.iter().find(|binding| binding.name == agent.model);
173        Self {
174            executor: agent.harness.clone(),
175            model: binding.map(|binding| binding.upstream_model.clone()),
176            provider: binding.and_then(|binding| binding.base_url.clone()),
177        }
178    }
179
180    /// The identifier a thread on this lane presents.
181    ///
182    /// One string, because [`ExecutorDisclosure`] has one field for it and the
183    /// field list is closed on purpose. Both halves are facts Exo reported: the
184    /// process is `exo`, and the executor inside it is what `agent show` said.
185    #[must_use]
186    pub fn agent_id(&self) -> String {
187        format!("exo/{}", self.executor)
188    }
189
190    /// The disclosure record for a thread on this lane.
191    #[must_use]
192    pub fn disclosure(&self, route: Option<RouteReason>) -> ExecutorDisclosure {
193        ExecutorDisclosure {
194            class: EXO_EXECUTOR_CLASS,
195            agent_id: self.agent_id(),
196            provider: self.provider.clone(),
197            model: self.model.clone(),
198            run_ref: None,
199            route,
200        }
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207
208    /// Real `exo model list` output from the pinned Exo, 2026-07-25.
209    const DRIVEN_MODELS: &str = "\
210MODEL     UPSTREAM_MODEL  SECRET  BASE_URL
211gpt5mini  gpt-5-mini      openai  default
212";
213
214    fn driven_agent() -> ExoAgent {
215        ExoAgent {
216            slug: "omega-lane".into(),
217            harness: "basic".into(),
218            model: "gpt5mini".into(),
219            agent_authored_tools: false,
220            tool_modules: 0,
221            tool_module_paths: Vec::new(),
222            read_write_mount: false,
223            mounts: Vec::new(),
224            networking: false,
225        }
226    }
227
228    #[test]
229    fn the_model_table_that_was_driven_reads_back() {
230        let bindings = ExoModelBinding::read_table(DRIVEN_MODELS);
231        assert_eq!(
232            bindings,
233            vec![ExoModelBinding {
234                name: "gpt5mini".into(),
235                upstream_model: "gpt-5-mini".into(),
236                base_url: None,
237            }]
238        );
239    }
240
241    /// The disclosure line, on the identity that was actually driven. It names
242    /// Exo, the executor inside it, and the model — and it says the provider is
243    /// not disclosed rather than inventing one.
244    #[test]
245    fn an_exo_thread_names_exo_its_executor_and_its_model() {
246        let identity =
247            ExoLaneIdentity::resolve(&driven_agent(), &ExoModelBinding::read_table(DRIVEN_MODELS));
248        let disclosure = identity.disclosure(Some(RouteReason::PinHonored));
249        assert!(disclosure.is_coherent());
250
251        let line = disclosure.label();
252        assert!(line.contains("exo/"), "{line}");
253        assert!(line.contains("basic"), "{line}");
254        assert!(line.contains("gpt-5-mini"), "{line}");
255        assert!(line.contains("provider not disclosed"), "{line}");
256        assert!(line.starts_with(EXO_EXECUTOR_CLASS.token()), "{line}");
257    }
258
259    /// The class decision, as an oracle rather than a comment. An Exo thread
260    /// must never claim Omega's own loop, and must never claim engine-lane
261    /// authority.
262    #[test]
263    fn an_exo_thread_claims_neither_omegas_own_loop_nor_full_auto_authority() {
264        assert_ne!(EXO_EXECUTOR_CLASS, ExecutorClass::NativeLoop);
265        assert_ne!(EXO_EXECUTOR_CLASS, ExecutorClass::EngineLane);
266        let identity =
267            ExoLaneIdentity::resolve(&driven_agent(), &ExoModelBinding::read_table(DRIVEN_MODELS));
268        let disclosure = identity.disclosure(Some(RouteReason::PinHonored));
269        assert_eq!(disclosure.run_ref, None, "Exo holds no Omega run authority");
270
271        // The same record with engine-lane authority claimed is incoherent, so
272        // the coherence law is what stops it rather than this lane's manners.
273        let forged = ExecutorDisclosure {
274            class: ExecutorClass::EngineLane,
275            ..disclosure
276        };
277        assert!(!forged.is_coherent());
278    }
279
280    /// A binding Exo did not report leaves the model absent. The alternative —
281    /// falling back to the agent's local alias — would put `gpt5mini` in a
282    /// field that means "the model that served the turn".
283    #[test]
284    fn an_unreported_binding_leaves_the_model_undisclosed() {
285        let identity = ExoLaneIdentity::resolve(&driven_agent(), &[]);
286        assert_eq!(identity.model, None);
287        let disclosure = identity.disclosure(None);
288        assert!(disclosure.is_coherent());
289        assert!(disclosure.label().contains("model not disclosed"));
290    }
291
292    #[test]
293    fn a_binding_with_a_base_url_discloses_it_as_the_provider() {
294        let bindings = ExoModelBinding::read_table(
295            "MODEL  UPSTREAM_MODEL  SECRET  BASE_URL\n\
296             glm    z-ai/glm-5.2    or      https://openrouter.ai/api/v1\n",
297        );
298        let agent = ExoAgent {
299            model: "glm".into(),
300            ..driven_agent()
301        };
302        let identity = ExoLaneIdentity::resolve(&agent, &bindings);
303        assert_eq!(
304            identity.provider.as_deref(),
305            Some("https://openrouter.ai/api/v1")
306        );
307        assert_eq!(identity.model.as_deref(), Some("z-ai/glm-5.2"));
308        assert!(identity.disclosure(None).is_coherent());
309    }
310}
311pub use authority::{
312    ExoGrantRefusal, ExoSelfModificationCapability, ExoSelfModificationConsentOrigin,
313    ExoSelfModificationGrant, ExoSelfModificationGrantRequest, ExoSelfModificationReceipt,
314    ObservedExoCapabilityState, ObservedReadWriteMount, ObservedToolModule,
315};
316
Served at tenant.openagents/omega Member data and write actions are omitted.