Skip to main content

mobius_gateway/wire/
records.rs

1use super::*;
2
3/// Gateway-wide frontend-safe state sent after authentication.
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5pub struct ReadyPayload {
6    pub machine_name: String,
7    pub bots: Vec<BotRecord>,
8    pub sessions: Vec<SessionRecord>,
9    pub background_approvals: Vec<BackgroundApproval>,
10    pub swarm_attentions: Vec<SwarmAttention>,
11    pub swarms: Vec<SwarmRecord>,
12    pub providers: Vec<ProviderStatus>,
13    pub provider_instances: Vec<ProviderInstance>,
14    pub bot_defaults: Option<VersionedAgentConfig>,
15    pub models: Vec<ModelChoice>,
16    pub model_providers: BTreeMap<String, String>,
17    pub middleware_features: Vec<MiddlewareFeature>,
18    pub extensions: Vec<ExtensionRecord>,
19    pub contributions: Vec<FrontendContribution>,
20    pub max_active_sessions: usize,
21    pub session_file_limits: SessionFileLimits,
22}
23
24/// One hidden Bot conversation currently waiting for a human execution decision.
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub struct BackgroundApproval {
27    pub session_id: String,
28    pub bot_id: String,
29    pub turn_id: String,
30    pub request_id: String,
31}
32
33/// One durable Swarm Chat message awaiting an authenticated human response.
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub struct SwarmAttention {
36    pub swarm_id: String,
37    pub swarm_title: String,
38    pub message_id: String,
39    pub bot_id: String,
40    pub text: String,
41}
42
43/// One gateway-managed group of durable Bots.
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub struct SwarmRecord {
46    pub id: String,
47    pub title: String,
48    pub leader_bot_id: String,
49    pub members: Vec<SwarmMemberRecord>,
50    pub messages: Vec<SwarmMessageRecord>,
51    pub updated_at_ms: i64,
52}
53
54/// Stable identity for one Bot in a Swarm.
55#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56pub struct SwarmMemberRecord {
57    pub bot_id: String,
58    pub handle: String,
59}
60
61/// One retained post on a swarm's shared message board.
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
63pub struct SwarmMessageRecord {
64    pub id: String,
65    pub sequence: u64,
66    pub author_bot_id: String,
67    pub author_handle: String,
68    pub source_session_id: String,
69    pub text: String,
70    pub created_at_ms: i64,
71    pub in_reply_to_message_id: Option<String>,
72    pub reply_depth: u8,
73}
74
75/// Gateway-managed scope selected by a human-facing capability request.
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
77#[serde(tag = "type", rename_all = "snake_case")]
78pub enum ContributionScope {
79    Global,
80    Swarm { id: String },
81}
82
83/// Frontend-safe state for one opened session.
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85pub struct SessionReadyPayload {
86    pub latest_sequence: u64,
87    pub next_before_sequence: Option<u64>,
88    pub workspace: WorkspaceInfo,
89    pub git: Option<GitStatus>,
90    pub session: SessionConfiguredEvent,
91    pub contributions: Vec<FrontendContribution>,
92    pub widgets: Vec<SessionWidget>,
93    pub tool_count: usize,
94    pub compaction_count: u64,
95    pub context_limit_tokens: Option<i64>,
96    pub run_stats: RunStats,
97}
98
99/// One currently mounted capability widget and its owning namespace.
100#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
101pub struct SessionWidget {
102    pub capability: String,
103    pub item: FrontendWidget,
104}
105
106/// One visible session with gateway-owned catalog presentation metadata.
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108pub struct SessionRecord {
109    pub session_id: String,
110    pub session_context: mobius::protocol::SessionContext,
111    pub parent_session_id: Option<String>,
112    pub parent_sequence: Option<u64>,
113    pub sequence: u64,
114    pub first_user_message: Option<String>,
115    pub execution_stats: mobius::backend::checkpoint::ExecutionStats,
116    pub title: Option<String>,
117    pub pinned: bool,
118    pub activity: SessionActivity,
119    pub created_at: i64,
120    pub updated_at: i64,
121}
122
123/// Gateway-observed lifecycle state for one session.
124#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
125#[serde(deny_unknown_fields)]
126pub struct SessionActivity {
127    pub state: SessionActivityState,
128    pub turn_id: Option<String>,
129    pub approval_request_id: Option<String>,
130    pub started_at: Option<i64>,
131    pub last_outcome: Option<mobius::backend::checkpoint::ExecutionOutcome>,
132    pub message: Option<String>,
133}
134
135impl Default for SessionActivity {
136    fn default() -> Self {
137        Self {
138            state: SessionActivityState::Idle,
139            turn_id: None,
140            approval_request_id: None,
141            started_at: None,
142            last_outcome: None,
143            message: None,
144        }
145    }
146}
147
148/// Current work state advertised in the session catalog.
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
150#[serde(rename_all = "snake_case")]
151pub enum SessionActivityState {
152    Idle,
153    Running,
154    AwaitingApproval,
155}
156
157/// Canonical workspace identity and path for one chat.
158#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
159pub struct WorkspaceInfo {
160    pub id: String,
161    pub path: PathBuf,
162}
163
164/// Local branch state for a Git-backed workspace.
165#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
166pub struct GitStatus {
167    pub current_branch: String,
168    pub branches: Vec<String>,
169}
170
171/// Public metadata for one SSH identity found on the gateway host.
172#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
173#[serde(deny_unknown_fields)]
174pub struct SshIdentityRecord {
175    pub label: String,
176    pub algorithm: String,
177    pub fingerprint: String,
178}
179
180/// One explicit Git patch selection.
181#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
182#[serde(rename_all = "snake_case")]
183pub enum GitDiffScope {
184    Staged,
185    Unstaged,
186    Committed,
187}
188
189/// Which openable files to include in a workspace catalog.
190#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
191#[serde(rename_all = "snake_case")]
192pub enum WorkspaceFileScope {
193    Modified,
194    All,
195}
196
197/// One regular file confined to the selected chat workspace.
198#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
199pub struct WorkspaceFileRecord {
200    pub path: String,
201    pub size: u64,
202}
203
204/// One bounded folder listing from the gateway host.
205#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
206pub struct DirectoryListing {
207    pub path: PathBuf,
208    pub parent: Option<PathBuf>,
209    pub entries: Vec<DirectoryEntry>,
210}
211
212/// A selectable child folder on the gateway host.
213#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
214pub struct DirectoryEntry {
215    pub name: String,
216    pub path: PathBuf,
217    pub is_directory: bool,
218}
219
220/// A frontend-safe agent composition guarded by an optimistic revision.
221#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
222pub struct VersionedAgentConfig {
223    pub revision: u64,
224    pub config: AgentComposition,
225}
226
227/// Runtime settings an authenticated client may read and replace atomically.
228#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
229#[serde(deny_unknown_fields)]
230pub struct AgentComposition {
231    pub provider: ProviderConfig,
232    pub middleware: MiddlewareConfig,
233    pub extensions: BTreeSet<String>,
234    pub system_prompt: String,
235    pub max_model_steps: u64,
236}
237
238/// Package format of one gateway-managed extension.
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
240#[serde(rename_all = "snake_case")]
241pub enum ExtensionKind {
242    Skill,
243    Plugin,
244}
245
246/// One executable plugin hook shown before digest-bound trust is granted.
247#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
248#[serde(deny_unknown_fields)]
249pub struct ExtensionHookRecord {
250    pub event: String,
251    pub matcher: Option<String>,
252    pub command: String,
253    pub timeout_seconds: u64,
254}
255
256/// Frontend-safe metadata for one installed extension snapshot.
257#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
258#[serde(deny_unknown_fields)]
259pub struct ExtensionRecord {
260    pub id: String,
261    pub capability: String,
262    pub kind: ExtensionKind,
263    pub name: String,
264    pub description: String,
265    pub version: Option<String>,
266    pub source: String,
267    pub reference: Option<String>,
268    pub subdirectory: Option<String>,
269    pub resolved_revision: String,
270    pub digest: String,
271    pub skills: Vec<String>,
272    pub hooks: Vec<ExtensionHookRecord>,
273    pub hooks_trusted: bool,
274}
275
276/// Provider and model settings. Credentials are resolved only on the gateway host.
277#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
278#[serde(deny_unknown_fields)]
279pub struct ProviderConfig {
280    /// Stable identity of one configured setup of `provider`. A gateway may hold
281    /// several instances of the same provider with separate credentials.
282    pub instance: String,
283    pub provider: String,
284    pub model: String,
285    #[serde(default, skip_serializing_if = "Option::is_none")]
286    pub base_url: Option<String>,
287    pub endpoint_auth: ProviderEndpointAuth,
288    #[serde(default, skip_serializing_if = "Option::is_none")]
289    pub reasoning_effort: Option<String>,
290    pub web_search: HostedWebSearch,
291}
292
293/// Authentication applied when calling one configured provider endpoint.
294#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
295#[serde(rename_all = "snake_case")]
296pub enum ProviderEndpointAuth {
297    ProviderDefault,
298    Credentialless,
299}
300
301/// Credential availability exposed without returning credential material.
302#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
303pub struct ProviderStatus {
304    pub provider: String,
305    pub label: String,
306    pub symbol: FrontendSymbol,
307    pub description: String,
308    pub model_ids_configurable: bool,
309    pub auth: ProviderAuthKind,
310    pub default_base_url: Option<String>,
311    pub default_api_key_env: Option<String>,
312    pub models: Vec<ProviderModel>,
313    pub web_search: Vec<FrontendSettingOption>,
314    pub tool_discovery: ToolDiscoveryMode,
315    pub custom_endpoint_tool_discovery: Option<ToolDiscoveryMode>,
316    pub supports_realtime_voice: bool,
317}
318
319/// User-chosen accent for distinguishing provider instances in model selectors.
320#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
321#[serde(rename_all = "snake_case")]
322pub enum ProviderTint {
323    #[default]
324    Blue,
325    Teal,
326    Green,
327    Yellow,
328    Orange,
329    Red,
330    Purple,
331}
332
333/// One durable setup of a provider. Several may share one `provider`.
334#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
335pub struct ProviderInstance {
336    pub label: String,
337    pub tint: ProviderTint,
338    pub configured: bool,
339    #[serde(default, skip_serializing_if = "Option::is_none")]
340    pub credential_hint: Option<String>,
341    pub selection: ProviderConfig,
342    pub model_ids: Vec<String>,
343    pub reasoning_efforts: Vec<String>,
344}
345
346/// Frontend type attached to one authenticated connection.
347#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
348#[serde(rename_all = "snake_case")]
349pub enum ClientKind {
350    Cli,
351    Macos,
352    Ios,
353    Ipados,
354    GatewayDashboard,
355}
356
357/// One paired client and its current connection state.
358#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
359pub struct ClientStatus {
360    pub client_id: String,
361    pub label: String,
362    pub kinds: Vec<ClientKind>,
363    pub connections: usize,
364}
365
366impl ProviderStatus {
367    #[must_use]
368    pub fn configurable_base_url(&self) -> bool {
369        self.default_base_url.is_some()
370    }
371
372    #[must_use]
373    pub fn default_model(&self) -> Option<&ProviderModel> {
374        self.models.first()
375    }
376}
377
378/// One model advertised by a provider manifest.
379#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
380pub struct ProviderModel {
381    pub id: String,
382    pub label: String,
383    pub description: String,
384    pub context_window: i64,
385    pub reasoning: Vec<ReasoningChoice>,
386    pub default_reasoning: Option<String>,
387    pub tool_discovery: ToolDiscoveryMode,
388}
389
390/// One reasoning effort advertised for a provider model.
391#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
392pub struct ReasoningChoice {
393    pub id: String,
394    pub label: String,
395    pub description: String,
396}
397
398/// Frontend-safe provider authentication mechanism.
399#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
400#[serde(rename_all = "snake_case")]
401pub enum ProviderAuthKind {
402    ApiKey,
403    DeviceCode,
404}
405
406/// Enabled optional middleware IDs and their schema-backed settings.
407#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
408#[serde(deny_unknown_fields)]
409pub struct MiddlewareConfig {
410    pub(crate) enabled: BTreeSet<String>,
411    pub settings: BTreeMap<String, BTreeMap<String, FrontendSettingValue>>,
412}
413
414impl MiddlewareConfig {
415    /// Returns whether one advertised optional middleware is enabled.
416    #[must_use]
417    pub fn enabled(&self, id: &str) -> bool {
418        self.enabled.contains(id)
419    }
420
421    /// Updates one advertised optional middleware before gateway validation.
422    pub fn set_enabled(&mut self, id: impl Into<String>, enabled: bool) {
423        let id = id.into();
424        if enabled {
425            self.enabled.insert(id);
426        } else {
427            self.enabled.remove(&id);
428        }
429    }
430
431    /// Returns one advertised middleware setting.
432    #[must_use]
433    pub fn setting(&self, middleware: &str, setting: &str) -> Option<&FrontendSettingValue> {
434        self.settings.get(middleware)?.get(setting)
435    }
436
437    /// Sets or clears one advertised middleware setting before gateway validation.
438    pub fn set_setting(
439        &mut self,
440        middleware: impl Into<String>,
441        setting: impl Into<String>,
442        value: Option<FrontendSettingValue>,
443    ) {
444        let middleware = middleware.into();
445        let setting = setting.into();
446        if let Some(value) = value {
447            self.settings
448                .entry(middleware)
449                .or_default()
450                .insert(setting, value);
451        } else if let Some(settings) = self.settings.get_mut(&middleware) {
452            settings.remove(&setting);
453            if settings.is_empty() {
454                self.settings.remove(&middleware);
455            }
456        }
457    }
458
459    pub(crate) fn entries(&self) -> impl Iterator<Item = &str> {
460        self.enabled.iter().map(String::as_str)
461    }
462}
463
464/// Capability-rendered preview whose inner events remain provider-neutral.
465#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
466pub struct RenderedPreview {
467    pub id: String,
468    pub title: String,
469    pub subtitle: String,
470    pub page_id: String,
471    pub update: FrontendPreviewUpdate,
472    pub events: Vec<RenderedEvent>,
473    pub next: Option<Op>,
474}
475
476/// One preview event and its capability-rendered blocks.
477#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
478pub struct RenderedEvent {
479    pub recorded_at_ms: i64,
480    pub event: EventMsg,
481    pub blocks: Vec<RenderedBlock>,
482}
483
484/// One timestamped semantic event and its deterministic presentation.
485#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
486pub struct RecordedEvent {
487    pub sequence: u64,
488    pub recorded_at_ms: i64,
489    pub event: Event,
490    pub stream_metrics: Vec<StreamMetrics>,
491    pub blocks: Vec<RenderedBlock>,
492    pub preview: Option<RenderedPreview>,
493}
494
495/// Gateway-owned profile and aggregate usage information.
496#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
497pub struct ProfileSnapshot {
498    pub user_name: Option<String>,
499    pub daily_usage: Vec<DailyUsage>,
500    pub run_stats: RunStats,
501    pub recent_run_groups: Vec<SessionRunGroup>,
502}
503
504/// Recent executions grouped under their nearest visible session.
505#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
506pub struct SessionRunGroup {
507    pub session_id: String,
508    pub title: String,
509    pub runs: Vec<RunSummary>,
510}
511
512/// Completed execution totals plus the active run, when one exists.
513#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
514pub struct RunStats {
515    #[serde(flatten)]
516    pub completed: mobius::backend::checkpoint::ExecutionStats,
517    pub active: Option<RunSummary>,
518}
519
520/// Frontend-safe summary of one completed or active user turn.
521#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
522pub struct RunSummary {
523    pub session_id: String,
524    pub submission_id: String,
525    pub turn_id: String,
526    pub started_at_ms: i64,
527    pub finished_at_ms: Option<i64>,
528    pub elapsed_ms: u64,
529    pub outcome: Option<mobius::backend::checkpoint::ExecutionOutcome>,
530    pub model_calls: u64,
531    pub tool_calls: u64,
532    pub failed_tool_calls: u64,
533    pub usage: TokenUsage,
534}
535
536/// Usage accrued during one Unix day.
537#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
538pub struct DailyUsage {
539    pub unix_day: u64,
540    pub provider: String,
541    pub usage: TokenUsage,
542}
543
544/// One durable Bot profile.
545#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
546pub struct BotRecord {
547    pub id: String,
548    pub handle: String,
549    pub name: String,
550    pub description: String,
551    pub tint: ProviderTint,
552    pub config: VersionedAgentConfig,
553}
554
555/// One Bot-owned routine.
556#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
557pub struct Routine {
558    pub id: String,
559    pub bot_id: String,
560    pub workspace: PathBuf,
561    pub instructions: String,
562    pub schedule: RoutineSchedule,
563    pub ends_at: Option<i64>,
564    pub enabled: bool,
565    pub finished: bool,
566    pub next_run_at: Option<i64>,
567}
568
569/// A user-selected scheduling rule.
570#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
571#[serde(deny_unknown_fields)]
572pub struct RoutineSchedule {
573    pub kind: RoutineScheduleKind,
574    pub at: Option<i64>,
575    pub every_seconds: Option<u64>,
576    pub expression: Option<String>,
577    pub time_zone: Option<String>,
578}
579
580/// The supported scheduling rule families.
581#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
582#[serde(rename_all = "snake_case")]
583pub enum RoutineScheduleKind {
584    Once,
585    Interval,
586    Cron,
587}
588
589/// A read-only page of a Bot routine transcript.
590#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
591pub struct RoutineRunPreview {
592    pub routine: Routine,
593    pub run: RoutineRun,
594    pub records: Vec<RecordedEvent>,
595    pub next_before_sequence: Option<u64>,
596}
597
598/// One completed or active invocation of a Bot routine.
599#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
600pub struct RoutineRun {
601    pub id: String,
602    pub routine_id: String,
603    pub bot_id: String,
604    pub started_at: i64,
605    pub finished_at: Option<i64>,
606    pub status: RoutineRunStatus,
607    pub session_id: Option<String>,
608    pub message: Option<String>,
609}
610
611/// Durable state of one routine invocation.
612#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
613#[serde(rename_all = "snake_case")]
614pub enum RoutineRunStatus {
615    Running,
616    Succeeded,
617    Failed,
618    Skipped,
619}