Skip to main content

steer_cli/commands/session/
show.rs

1use async_trait::async_trait;
2use chrono::{TimeZone, Utc};
3use eyre::{Result, eyre};
4
5use super::super::Command;
6use steer_core::api::Model;
7use steer_core::session::{SessionManager, SessionManagerConfig};
8use steer_core::utils::session::{create_session_store_with_config, resolve_session_store_config};
9
10pub struct ShowSessionCommand {
11    pub session_id: String,
12    pub remote: Option<String>,
13    pub session_db: Option<std::path::PathBuf>,
14}
15
16#[async_trait]
17impl Command for ShowSessionCommand {
18    async fn execute(&self) -> Result<()> {
19        // If remote is specified, handle via gRPC
20        if let Some(remote_addr) = &self.remote {
21            return self.handle_remote(remote_addr).await;
22        }
23
24        // Local session handling
25        let store_config = resolve_session_store_config(self.session_db.clone())?;
26        let session_store = create_session_store_with_config(store_config).await?;
27        let session_manager_config = SessionManagerConfig {
28            max_concurrent_sessions: 10,
29            default_model: Model::default(),
30            auto_persist: true,
31        };
32
33        let session_manager = SessionManager::new(session_store, session_manager_config);
34
35        let session_info = session_manager
36            .get_session(&self.session_id)
37            .await
38            .map_err(|e| eyre!("Failed to get session: {}", e))?;
39
40        match session_info {
41            Some(info) => {
42                println!("Session Details:");
43                println!("ID: {}", info.id);
44                println!(
45                    "Created: {}",
46                    info.created_at.format("%Y-%m-%d %H:%M:%S UTC")
47                );
48                println!(
49                    "Updated: {}",
50                    info.updated_at.format("%Y-%m-%d %H:%M:%S UTC")
51                );
52                println!("Messages: {}", info.message_count);
53                println!(
54                    "Last Model: {}",
55                    info.last_model
56                        .map(|m| m.as_ref().to_string())
57                        .unwrap_or_else(|| "N/A".to_string())
58                );
59
60                if !info.metadata.is_empty() {
61                    println!("Metadata:");
62                    for (key, value) in &info.metadata {
63                        println!("  {key}: {value}");
64                    }
65                }
66            }
67            None => {
68                return Err(eyre!("Session not found: {}", self.session_id));
69            }
70        }
71
72        Ok(())
73    }
74}
75
76impl ShowSessionCommand {
77    async fn handle_remote(&self, remote_addr: &str) -> Result<()> {
78        use steer_grpc::GrpcClientAdapter;
79
80        // Connect to the gRPC server
81        let client = GrpcClientAdapter::connect(remote_addr).await.map_err(|e| {
82            eyre!(
83                "Failed to connect to remote server at {}: {}",
84                remote_addr,
85                e
86            )
87        })?;
88
89        let session_state = client
90            .get_session(&self.session_id)
91            .await
92            .map_err(|e| eyre!("Failed to get remote session: {}", e))?;
93
94        match session_state {
95            Some(state) => {
96                println!("Remote Session Details:");
97                println!("ID: {}", state.id);
98
99                if let Some(created_at) = state.created_at {
100                    let secs = created_at.seconds;
101                    let nsecs = created_at.nanos as u32;
102                    let datetime = Utc.timestamp_opt(secs, nsecs).single();
103                    match datetime {
104                        Some(dt) => println!("Created: {}", dt.format("%Y-%m-%d %H:%M:%S UTC")),
105                        None => println!("Created: N/A"),
106                    }
107                }
108
109                if let Some(updated_at) = state.updated_at {
110                    let secs = updated_at.seconds;
111                    let nsecs = updated_at.nanos as u32;
112                    let datetime = Utc.timestamp_opt(secs, nsecs).single();
113                    match datetime {
114                        Some(dt) => println!("Updated: {}", dt.format("%Y-%m-%d %H:%M:%S UTC")),
115                        None => println!("Updated: N/A"),
116                    }
117                }
118
119                println!("Messages: {}", state.messages.len());
120                println!("Last Event Sequence: {}", state.last_event_sequence);
121                println!("Approved Tools: {:?}", state.approved_tools);
122
123                if !state.metadata.is_empty() {
124                    println!("Metadata:");
125                    for (key, value) in &state.metadata {
126                        println!("  {key}: {value}");
127                    }
128                }
129            }
130            None => {
131                return Err(eyre!("Remote session not found: {}", self.session_id));
132            }
133        }
134
135        Ok(())
136    }
137}