Skip to main content

ldp_protocol/types/
session.rs

1//! LDP session types.
2//!
3//! Sessions are governed multi-round contexts — the key difference from
4//! stateless A2A/MCP invocations. Session management is internal to the
5//! adapter; JamJet's workflow engine sees only request→response.
6
7use crate::types::payload::NegotiatedPayload;
8use crate::types::trust::TrustDomain;
9use chrono::{DateTime, Utc};
10use serde::{Deserialize, Serialize};
11
12/// State of an LDP session.
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum SessionState {
16    /// HELLO sent, waiting for response.
17    Initiating,
18    /// Session proposed, awaiting acceptance.
19    Proposed,
20    /// Session active — tasks can be submitted.
21    Active,
22    /// Session suspended (can be resumed).
23    Suspended,
24    /// Session terminated.
25    Closed,
26    /// Session failed to establish.
27    Failed,
28}
29
30/// An active LDP session.
31///
32/// Sessions are cached by the `SessionManager` and reused across
33/// multiple `invoke()` calls to the same delegate.
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct LdpSession {
36    /// Unique session identifier.
37    pub session_id: String,
38
39    /// Remote delegate endpoint.
40    pub remote_url: String,
41
42    /// Remote delegate ID.
43    pub remote_delegate_id: String,
44
45    /// Current session state.
46    pub state: SessionState,
47
48    /// Negotiated payload mode for this session.
49    pub payload: NegotiatedPayload,
50
51    /// Trust domain of the remote delegate.
52    pub trust_domain: TrustDomain,
53
54    /// When the session was established.
55    pub created_at: DateTime<Utc>,
56
57    /// When the session was last used.
58    pub last_used: DateTime<Utc>,
59
60    /// Session TTL in seconds (after which it expires if unused).
61    pub ttl_secs: u64,
62
63    /// Number of tasks submitted in this session.
64    pub task_count: u64,
65}
66
67impl LdpSession {
68    /// Check if the session is still active and not expired.
69    pub fn is_active(&self) -> bool {
70        if self.state != SessionState::Active {
71            return false;
72        }
73        let elapsed = Utc::now()
74            .signed_duration_since(self.last_used)
75            .num_seconds();
76        elapsed < self.ttl_secs as i64
77    }
78
79    /// Touch the session (update last_used timestamp).
80    pub fn touch(&mut self) {
81        self.last_used = Utc::now();
82    }
83}
84
85/// Configuration for establishing a new LDP session.
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct SessionConfig {
88    /// Preferred payload modes, ordered by preference.
89    pub preferred_payload_modes: Vec<crate::types::payload::PayloadMode>,
90
91    /// Session TTL in seconds.
92    pub ttl_secs: u64,
93
94    /// Trust domain requirement (if set, only delegates in this domain are accepted).
95    pub required_trust_domain: Option<String>,
96}
97
98impl Default for SessionConfig {
99    fn default() -> Self {
100        Self {
101            preferred_payload_modes: vec![
102                crate::types::payload::PayloadMode::SemanticFrame,
103                crate::types::payload::PayloadMode::Text,
104            ],
105            ttl_secs: 3600, // 1 hour default
106            required_trust_domain: None,
107        }
108    }
109}