steer_cli/commands/session/
show.rs1use 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 let Some(remote_addr) = &self.remote {
21 return self.handle_remote(remote_addr).await;
22 }
23
24 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 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}