Skip to main content

nucel_agent_core/
session.rs

1use chrono::{DateTime, Utc};
2use std::path::PathBuf;
3use std::sync::Arc;
4
5use async_trait::async_trait;
6
7use crate::error::Result;
8use crate::types::{AgentCost, AgentResponse, ExecutorType};
9
10/// Metadata about a session (persistable, cloneable).
11#[derive(Debug, Clone)]
12pub struct SessionMetadata {
13    pub session_id: String,
14    pub executor_type: ExecutorType,
15    pub working_dir: PathBuf,
16    pub created_at: DateTime<Utc>,
17    pub model: Option<String>,
18}
19
20/// Session implementation trait.
21/// Providers implement this to control query/cost/close behavior.
22#[async_trait]
23pub trait SessionImpl: Send + Sync {
24    async fn query(&self, prompt: &str) -> Result<AgentResponse>;
25    async fn total_cost(&self) -> Result<AgentCost>;
26    async fn close(&self) -> Result<()>;
27}
28
29/// Active agent session.
30///
31/// Returned by `AgentExecutor::spawn()` or `resume()`.
32/// Use `query()` for follow-up prompts, `total_cost()` for spend tracking,
33/// and `close()` to clean up.
34pub struct AgentSession {
35    /// Unique session identifier.
36    pub session_id: String,
37    /// Which executor created this session.
38    pub executor_type: ExecutorType,
39    /// Working directory.
40    pub working_dir: PathBuf,
41    /// Creation timestamp.
42    pub created_at: DateTime<Utc>,
43    /// Model being used.
44    pub model: Option<String>,
45
46    pub(crate) inner: Arc<dyn SessionImpl>,
47}
48
49impl std::fmt::Debug for AgentSession {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        f.debug_struct("AgentSession")
52            .field("session_id", &self.session_id)
53            .field("executor_type", &self.executor_type)
54            .field("working_dir", &self.working_dir)
55            .field("created_at", &self.created_at)
56            .field("model", &self.model)
57            .finish_non_exhaustive()
58    }
59}
60
61impl AgentSession {
62    /// Create a new session with an inner implementation.
63    pub fn new(
64        session_id: impl Into<String>,
65        executor_type: ExecutorType,
66        working_dir: impl Into<PathBuf>,
67        model: Option<String>,
68        inner: Arc<dyn SessionImpl>,
69    ) -> Self {
70        Self {
71            session_id: session_id.into(),
72            executor_type,
73            working_dir: working_dir.into(),
74            created_at: Utc::now(),
75            model,
76            inner,
77        }
78    }
79
80    /// Send a follow-up prompt to the agent.
81    pub async fn query(&self, prompt: &str) -> Result<AgentResponse> {
82        self.inner.query(prompt).await
83    }
84
85    /// Get the accumulated cost of this session.
86    pub async fn total_cost(&self) -> Result<AgentCost> {
87        self.inner.total_cost().await
88    }
89
90    /// Close the session and release resources.
91    pub async fn close(self) -> Result<()> {
92        self.inner.close().await
93    }
94
95    /// Session metadata snapshot.
96    pub fn metadata(&self) -> SessionMetadata {
97        SessionMetadata {
98            session_id: self.session_id.clone(),
99            executor_type: self.executor_type,
100            working_dir: self.working_dir.clone(),
101            created_at: self.created_at,
102            model: self.model.clone(),
103        }
104    }
105}