Skip to repository content93 lines · 4.0 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T03:03:29.469Z 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
main.rs
1//! The loopback ACP server as a supervised child. `OMEGA-DELTA-0041`,
2//! omega#82.
3//!
4//! `omega-effectd` owns the lifecycle in a shipped build, by calling
5//! [`omega_acp_server::start_if_enabled`] from `crates/omega_effectd`. This
6//! binary exists so the same code path can be **driven by a real external ACP
7//! host** without a windowing system: an external host attaches through a
8//! stdio-to-TCP bridge, and what it talks to is the library above, not a
9//! demonstration copy of it.
10//!
11//! It is off by the same flag and binds through the same
12//! [`omega_acp_server::LoopbackHost`], so running it proves the shipped
13//! behaviour rather than a parallel one. With the flag unset it prints why it
14//! is not listening and exits, which is the default-off property observable
15//! from a shell.
16//!
17//! # Attaching an external ACP host
18//!
19//! ACP is spoken over a subprocess's stdio, so an external host reaches a
20//! socket through a one-line bridge. This is exactly how stock Zed 1.12.0 was
21//! driven against it on 2026-07-26:
22//!
23//! ```text
24//! OMEGA_ACP_SERVER=1 OMEGA_ACP_SERVER_PORT=8282 omega-acp-server
25//! ```
26//!
27//! then, in the external host's settings:
28//!
29//! ```json
30//! "agent_servers": {
31//! "omega-served": {
32//! "command": "/bin/sh",
33//! "args": ["-c", "exec /usr/bin/nc 127.0.0.1 8282"]
34//! }
35//! }
36//! ```
37//!
38//! Opening a thread on that agent initialises, creates a session, and shows the
39//! disclosure the served turn renders. The headless equivalent —
40//! the **upstream** ACP SDK client over the same loopback socket — is
41//! `the_upstream_acp_client_reads_the_disclosure_off_a_real_socket` in the
42//! library, so the exit is reproducible without a windowing system.
43//!
44//! # The rendered exit, and why the stop reason is `end_turn`
45//!
46//! Photographed on 2026-07-26 against stock Zed 1.12.0:
47//! `evidence/2026-07-26-zed-1.12.0-served-turn-end_turn.png`. The prompt
48//! *"Start a Full Auto run on this project and pin the executor."* is kept in
49//! the thread and answered with the executor disclosure, the session origin
50//! (`loopback_acp · zed 1.12.0+stable… · unauthenticated`), and the statement
51//! that the turn reached no executor.
52//!
53//! The companion image
54//! `evidence/2026-07-26-zed-1.12.0-served-turn-refusal.png` is the same build,
55//! the same host and the same prompt with **one** value changed — the served
56//! turn answering ACP's `refusal` instead of `end_turn`. Stock Zed implements
57//! `refusal` literally: it drops the turn out of the thread and renders a bare
58//! "Request Refused" banner whose text guesses at a *content policy* violation
59//! that never occurred. The disclosure goes with the turn, so the operator of
60//! the external host is told nothing true.
61//!
62//! That pair is why the stop reason is not a cosmetic choice: a test asserting
63//! `stopReason == "refusal"` was green while the only human who could act on
64//! the refusal could see none of it. A served turn ends, and says what did not
65//! happen.
66
67fn main() {
68 match omega_acp_server::start_if_enabled() {
69 omega_acp_server::StartOutcome::NotStarted(reason) => {
70 println!(
71 "omega-acp-server: not listening ({}). Set {}={} to serve Omega \
72 Agent over ACP on loopback.",
73 reason.token(),
74 omega_acp_server::ENABLE_FLAG,
75 omega_acp_server::ENABLE_VALUE,
76 );
77 }
78 omega_acp_server::StartOutcome::Listening(address) => {
79 // Printed on stdout so a bridge script can read the port back
80 // without parsing a log.
81 println!("omega-acp-server: listening on {address}");
82 // The listener serves on its own thread; park this one on it.
83 loop {
84 std::thread::park();
85 }
86 }
87 omega_acp_server::StartOutcome::Failed(error) => {
88 eprintln!("omega-acp-server: could not listen: {error}");
89 std::process::exit(1);
90 }
91 }
92}
93