Skip to main content

everruns_core/
session_resource.rs

1// Session resource registry — generic, session-scoped registry of active resources.
2//
3// Decision: SessionResourceRegistry is the core trait. Any capability registers
4// resources here (sandboxes, subagents, browser sessions, future background work).
5// Agents query it ("what's running?"), infra scans it for cleanup.
6// Decision: resource_id is caller-provided and unique per session. Repeated
7// register calls with the same resource_id update rather than duplicate.
8// Decision: kind is a free-form string for extensibility — no enum.
9// Decision: LeasedResourceStore auto-registers into the registry so existing
10// tool code doesn't change.
11
12use chrono::{DateTime, Utc};
13use serde::{Deserialize, Serialize};
14
15use crate::typed_id::SessionId;
16
17#[cfg(feature = "openapi")]
18use utoipa::ToSchema;
19
20/// Status of a resource in the session resource registry.
21#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
22#[cfg_attr(feature = "openapi", derive(ToSchema))]
23#[serde(rename_all = "snake_case")]
24pub enum SessionResourceStatus {
25    /// Resource is alive and doing work.
26    Active,
27    /// Work finished successfully.
28    Completed,
29    /// Work finished with an error.
30    Failed,
31    /// Resource was explicitly released / cleaned up.
32    Released,
33}
34
35impl std::fmt::Display for SessionResourceStatus {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        match self {
38            Self::Active => write!(f, "active"),
39            Self::Completed => write!(f, "completed"),
40            Self::Failed => write!(f, "failed"),
41            Self::Released => write!(f, "released"),
42        }
43    }
44}
45
46impl From<&str> for SessionResourceStatus {
47    fn from(s: &str) -> Self {
48        match s {
49            "active" => Self::Active,
50            "completed" => Self::Completed,
51            "failed" => Self::Failed,
52            "released" => Self::Released,
53            _ => Self::Active,
54        }
55    }
56}
57
58/// A resource registered in the session resource registry.
59#[derive(Debug, Clone, Serialize, Deserialize)]
60#[cfg_attr(feature = "openapi", derive(ToSchema))]
61pub struct SessionResourceEntry {
62    /// Caller-provided stable ID (unique per session).
63    pub resource_id: String,
64    /// Parent session.
65    #[cfg_attr(feature = "openapi", schema(value_type = String))]
66    pub session_id: SessionId,
67    /// Resource kind: "sandbox", "subagent", "browser_session", etc.
68    pub kind: String,
69    /// Human-readable label.
70    pub display_name: String,
71    /// Lifecycle status.
72    pub status: SessionResourceStatus,
73    /// Kind-specific non-secret metadata.
74    #[serde(default)]
75    pub metadata: serde_json::Value,
76    pub created_at: DateTime<Utc>,
77    pub updated_at: DateTime<Utc>,
78}
79
80/// Input for registering a resource.
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct RegisterSessionResource {
83    pub session_id: SessionId,
84    /// Caller-provided stable ID (leased resource ID, session ID, etc.).
85    pub resource_id: String,
86    /// Resource kind: "sandbox", "subagent", "browser_session", etc.
87    pub kind: String,
88    /// Human-readable label.
89    pub display_name: String,
90    /// Initial status (defaults to Active).
91    #[serde(default = "default_active")]
92    pub status: SessionResourceStatus,
93    /// Kind-specific non-secret metadata.
94    #[serde(default)]
95    pub metadata: serde_json::Value,
96}
97
98fn default_active() -> SessionResourceStatus {
99    SessionResourceStatus::Active
100}
101
102/// Optional filter for listing resources.
103#[derive(Debug, Clone, Default)]
104pub struct SessionResourceFilter {
105    /// Filter by kind (exact match).
106    pub kind: Option<String>,
107    /// Filter by status.
108    pub status: Option<SessionResourceStatus>,
109}