Skip to repository content209 lines · 5.6 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T05:00:13.504Z 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
protocol.rs
1//! Framed protocol types for `openagents.omega.effectd.v1`.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6pub const PROTOCOL_SCHEMA: &str = "openagents.omega.effectd.v1";
7pub const PROTOCOL_VERSION: u32 = 1;
8pub const SERVICE_VERSION: &str = "0.1.0";
9/// Newline-framed JSON frames must stay under this byte budget (spec §8).
10pub const MAX_FRAME_BYTES: usize = 64 * 1024;
11
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
13#[serde(rename_all = "snake_case")]
14pub enum ProtocolErrorCode {
15 StaleGeneration,
16 UnknownMethod,
17 InvalidRequest,
18 NotRunning,
19 RunNotFound,
20 HostUnavailable,
21 HostTimeout,
22 FrameTooLarge,
23 Internal,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
27pub struct ProtocolError {
28 pub code: ProtocolErrorCode,
29 pub message: String,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct RequestFrame {
34 pub schema: String,
35 pub kind: String,
36 pub id: String,
37 pub generation: u64,
38 pub method: String,
39 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub params: Option<Value>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct ResponseFrame {
45 pub schema: String,
46 pub kind: String,
47 pub id: String,
48 pub generation: u64,
49 pub ok: bool,
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub result: Option<Value>,
52 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub error: Option<ProtocolError>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
57#[serde(rename_all = "snake_case")]
58pub enum HostMethod {
59 ResolveWorkspace,
60 ResolveSyncSession,
61 CreateThread,
62 LaneReadiness,
63 DispatchTurn,
64 RefreshEvidence,
65 InterruptTurn,
66 AppendSystemNote,
67 SarahSessionStatus,
68 SarahBootstrap,
69 SarahRoomSnapshot,
70 SarahSendMessage,
71 SarahInterruptTurn,
72 SarahDeviceGrants,
73 SarahRenewDeviceGrant,
74 SarahRevokeDeviceGrant,
75 #[serde(other)]
76 Unsupported,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct HostRequestFrame {
81 pub schema: String,
82 pub kind: String,
83 pub id: String,
84 pub generation: u64,
85 pub method: HostMethod,
86 pub params: Value,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
90#[serde(rename_all = "snake_case")]
91pub enum HostResponseErrorCode {
92 StaleGeneration,
93 InvalidRequest,
94 Unsupported,
95 Unavailable,
96 Internal,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct HostResponseError {
101 pub code: HostResponseErrorCode,
102 pub message: String,
103}
104
105impl HostResponseError {
106 pub fn unavailable(message: impl Into<String>) -> Self {
107 Self {
108 code: HostResponseErrorCode::Unavailable,
109 message: message.into(),
110 }
111 }
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct HostResponseFrame {
116 pub schema: String,
117 pub kind: String,
118 pub id: String,
119 pub generation: u64,
120 pub ok: bool,
121 #[serde(default, skip_serializing_if = "Option::is_none")]
122 pub result: Option<Value>,
123 #[serde(default, skip_serializing_if = "Option::is_none")]
124 pub error: Option<HostResponseError>,
125}
126
127impl HostResponseFrame {
128 pub fn success(request: &HostRequestFrame, result: Value) -> Self {
129 Self {
130 schema: PROTOCOL_SCHEMA.to_string(),
131 kind: "host_response".to_string(),
132 id: request.id.clone(),
133 generation: request.generation,
134 ok: true,
135 result: Some(result),
136 error: None,
137 }
138 }
139
140 pub fn failure(request: &HostRequestFrame, error: HostResponseError) -> Self {
141 Self {
142 schema: PROTOCOL_SCHEMA.to_string(),
143 kind: "host_response".to_string(),
144 id: request.id.clone(),
145 generation: request.generation,
146 ok: false,
147 result: None,
148 error: Some(error),
149 }
150 }
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
154#[serde(rename_all = "camelCase")]
155pub struct RunSnapshot {
156 pub run_ref: String,
157 #[serde(default)]
158 pub thread_ref: Option<String>,
159 pub state: String,
160 pub title: String,
161 /// Formatted for display. Never re-parsed to derive a duration.
162 pub updated_at: String,
163 /// OMEGA-MOB-31-03 (omega#47): the host's own numeric record of when the
164 /// run began, in epoch milliseconds. `None` when this host never recorded
165 /// one — a run that predates the field, or one that has not started. The
166 /// mobile projection refuses such a run rather than reporting a zero
167 /// unattended duration.
168 #[serde(default)]
169 pub started_at_ms: Option<u64>,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
173#[serde(rename_all = "camelCase")]
174pub struct InitializeResult {
175 pub schema: String,
176 pub protocol_version: u32,
177 pub service_version: String,
178 pub generation: u64,
179 pub capabilities: Vec<String>,
180 pub data_root: String,
181 pub active_run_limit: u32,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
185#[serde(rename_all = "camelCase")]
186pub struct HealthResult {
187 pub ok: bool,
188 pub status: String,
189 pub generation: u64,
190 pub data_root: String,
191 pub active_run_count: u32,
192}
193
194pub fn request_frame(
195 id: impl Into<String>,
196 generation: u64,
197 method: impl Into<String>,
198 params: Option<Value>,
199) -> RequestFrame {
200 RequestFrame {
201 schema: PROTOCOL_SCHEMA.to_string(),
202 kind: "request".to_string(),
203 id: id.into(),
204 generation,
205 method: method.into(),
206 params,
207 }
208}
209