zeph_subagent/fleet.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Fleet registry abstraction for sub-agent session tracking.
5//!
6//! [`FleetRegistry`] is a narrow trait that decouples `zeph-subagent` from the
7//! `zeph-memory` `SqliteStore`. The concrete implementation lives in `zeph-core`
8//! and is injected via `SubAgentManager::set_fleet_registry`.
9
10use std::future::Future;
11use std::pin::Pin;
12use std::sync::Arc;
13
14/// Terminal lifecycle status of an agent session visible in the fleet dashboard.
15///
16/// Only terminal states are represented because [`FleetRegistry::mark_terminal`] is only
17/// called when a session ends. Active sessions are registered via
18/// [`FleetRegistry::register_active`].
19///
20/// Mirrors the terminal variants of `zeph_memory::SessionStatus` without creating a
21/// dependency on that crate.
22#[non_exhaustive]
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum FleetSessionStatus {
25 /// Session ended normally.
26 Completed,
27 /// Session ended due to an unrecoverable error.
28 Failed,
29 /// Session was cancelled by the user.
30 Cancelled,
31}
32
33/// Minimal data needed to register a sub-agent session in the fleet dashboard.
34#[derive(Debug, Clone)]
35pub struct FleetSessionInfo {
36 /// Stable session ID (UUID string).
37 pub id: String,
38 /// Human-readable agent name (from the definition).
39 pub agent_name: String,
40 /// ISO-8601 UTC timestamp of session start.
41 pub started_at: String,
42}
43
44/// Trait that abstracts fleet session persistence for `SubAgentManager`.
45///
46/// Implementors must be `Send + Sync` and handle their own internal error recovery;
47/// the manager logs failures at `warn` level but never propagates them to the caller.
48pub trait FleetRegistry: Send + Sync {
49 /// Register or update a sub-agent session as active.
50 ///
51 /// Called once at sub-agent spawn time. Fire-and-forget: errors are logged
52 /// by the manager and do not abort the spawn.
53 fn register_active<'a>(
54 &'a self,
55 info: &'a FleetSessionInfo,
56 ) -> Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'a>>;
57
58 /// Mark a sub-agent session as terminal.
59 ///
60 /// Called when a sub-agent finishes (collect) or is cancelled.
61 fn mark_terminal<'a>(
62 &'a self,
63 session_id: &'a str,
64 status: FleetSessionStatus,
65 ) -> Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'a>>;
66}
67
68/// Shared, type-erased fleet registry injected into the manager.
69pub type SharedFleetRegistry = Arc<dyn FleetRegistry>;