1use post_cortex_memory::ConversationMemorySystem;
4use crate::{get_memory_system, MCPToolResult};
5use anyhow::Result;
6use tracing::{error, info, instrument};
7use uuid::Uuid;
8
9async fn persist_workspace_after_mutation(
13 system: &ConversationMemorySystem,
14 workspace_id: Uuid,
15) -> std::result::Result<(), String> {
16 let workspace = system.workspace_manager.get_workspace(&workspace_id);
17 let (ws_name, ws_description, sessions) = match &workspace {
18 Some(ws) => (
19 ws.name.clone(),
20 ws.description.clone(),
21 ws.get_all_sessions(),
22 ),
23 None => (String::new(), String::new(), Vec::new()),
24 };
25 let session_uuids: Vec<Uuid> = sessions.into_iter().map(|(id, _)| id).collect();
26
27 system
28 .storage_actor
29 .save_workspace_metadata(workspace_id, &ws_name, &ws_description, &session_uuids)
30 .await
31}
32
33#[instrument(skip_all, fields(workspace_name = %name))]
35pub async fn create_workspace(name: String, description: String) -> Result<MCPToolResult> {
36 info!("MCP-TOOLS: create_workspace() called with name: '{}'", name);
37 let system = get_memory_system().await?;
38
39 let workspace_id = system
40 .workspace_manager
41 .create_workspace(name.clone(), description.clone());
42
43 if let Err(e) = system
44 .storage_actor
45 .save_workspace_metadata(
46 workspace_id,
47 &name,
48 &description,
49 &Vec::new(),
50 )
51 .await
52 {
53 error!("Failed to persist workspace: {}", e);
54 return Ok(MCPToolResult::error(format!(
55 "Failed to persist workspace: {}",
56 e
57 )));
58 }
59
60 info!("Created workspace {} with ID {}", name, workspace_id);
61
62 Ok(MCPToolResult::success(
63 format!("Created workspace '{}' with ID: {}", name, workspace_id),
64 Some(serde_json::json!({
65 "workspace_id": workspace_id.to_string(),
66 "name": name,
67 "description": description,
68 "session_count": 0
69 })),
70 ))
71}
72
73#[instrument(skip_all, fields(workspace_id = %workspace_id))]
75pub async fn get_workspace(workspace_id: Uuid) -> Result<MCPToolResult> {
76 info!("MCP-TOOLS: get_workspace() called for ID: {}", workspace_id);
77 let system = get_memory_system().await?;
78
79 match system.workspace_manager.get_workspace(&workspace_id) {
80 Some(workspace) => {
81 let sessions = workspace.get_all_sessions();
82 let session_details: Vec<serde_json::Value> = sessions
83 .into_iter()
84 .map(|(id, role)| {
85 serde_json::json!({
86 "session_id": id.to_string(),
87 "role": format!("{:?}", role)
88 })
89 })
90 .collect();
91
92 Ok(MCPToolResult::success(
93 format!("Workspace '{}' retrieved", workspace.name),
94 Some(serde_json::json!({
95 "workspace_id": workspace.id.to_string(),
96 "name": workspace.name,
97 "description": workspace.description,
98 "created_at": workspace.created_at,
99 "sessions": session_details,
100 "session_count": workspace.session_ids.len()
101 })),
102 ))
103 }
104 None => Ok(MCPToolResult::error(format!(
105 "Workspace {} not found",
106 workspace_id
107 ))),
108 }
109}
110
111pub async fn list_workspaces() -> Result<MCPToolResult> {
113 info!("MCP-TOOLS: list_workspaces() called");
114 let system = get_memory_system().await?;
115
116 let workspaces = system.workspace_manager.list_workspaces();
117
118 let workspace_list: Vec<serde_json::Value> = workspaces
119 .into_iter()
120 .map(|ws| {
121 serde_json::json!({
122 "workspace_id": ws.id.to_string(),
123 "name": ws.name,
124 "description": ws.description,
125 "session_count": ws.session_ids.len(),
126 "created_at": ws.created_at
127 })
128 })
129 .collect();
130
131 Ok(MCPToolResult::success(
132 format!("Found {} workspaces", workspace_list.len()),
133 Some(serde_json::json!({
134 "workspaces": workspace_list
135 })),
136 ))
137}
138
139pub async fn delete_workspace(workspace_id: Uuid) -> Result<MCPToolResult> {
141 info!(
142 "MCP-TOOLS: delete_workspace() called for ID: {}",
143 workspace_id
144 );
145 let system = get_memory_system().await?;
146
147 match system.workspace_manager.delete_workspace(&workspace_id) {
148 Some(workspace) => {
149 if let Err(e) = system
150 .storage_actor
151 .delete_workspace(workspace_id)
152 .await
153 {
154 error!("Failed to delete workspace from storage: {}", e);
155 return Ok(MCPToolResult::error(format!(
156 "Failed to delete workspace from storage: {}",
157 e
158 )));
159 }
160
161 info!("Deleted workspace '{}' ({})", workspace.name, workspace_id);
162
163 Ok(MCPToolResult::success(
164 format!("Deleted workspace '{}'", workspace.name),
165 Some(serde_json::json!({
166 "workspace_id": workspace_id.to_string(),
167 "name": workspace.name
168 })),
169 ))
170 }
171 None => Ok(MCPToolResult::error(format!(
172 "Workspace {} not found",
173 workspace_id
174 ))),
175 }
176}
177
178pub async fn add_session_to_workspace(
180 workspace_id: Uuid,
181 session_id: Uuid,
182 role: String,
183) -> Result<MCPToolResult> {
184 info!(
185 "MCP-TOOLS: add_session_to_workspace() called: session {} -> workspace {} (role: {})",
186 session_id, workspace_id, role
187 );
188 let system = get_memory_system().await?;
189
190 let role_enum = match role.to_lowercase().as_str() {
191 "primary" => post_cortex_core::workspace::SessionRole::Primary,
192 "related" => post_cortex_core::workspace::SessionRole::Related,
193 "dependency" => post_cortex_core::workspace::SessionRole::Dependency,
194 "shared" => post_cortex_core::workspace::SessionRole::Shared,
195 _ => post_cortex_core::workspace::SessionRole::Related,
196 };
197
198 match system
199 .workspace_manager
200 .add_session_to_workspace(&workspace_id, session_id, role_enum)
201 {
202 Ok(()) => {
203 if let Err(e) = persist_workspace_after_mutation(&system, workspace_id).await {
204 error!("Failed to update workspace in storage: {}", e);
205 return Ok(MCPToolResult::error(format!(
206 "Failed to update workspace in storage: {}",
207 e
208 )));
209 }
210
211 info!(
212 "Added session {} to workspace {} with role {:?}",
213 session_id, workspace_id, role_enum
214 );
215
216 Ok(MCPToolResult::success(
217 "Added session to workspace successfully".to_string(),
218 Some(serde_json::json!({
219 "workspace_id": workspace_id.to_string(),
220 "session_id": session_id.to_string(),
221 "role": format!("{:?}", role_enum)
222 })),
223 ))
224 }
225 Err(e) => Ok(MCPToolResult::error(format!(
226 "Failed to add session to workspace: {}",
227 e
228 ))),
229 }
230}
231
232pub async fn remove_session_from_workspace(
234 workspace_id: Uuid,
235 session_id: Uuid,
236) -> Result<MCPToolResult> {
237 info!(
238 "MCP-TOOLS: remove_session_from_workspace() called: session {} from workspace {}",
239 session_id, workspace_id
240 );
241 let system = get_memory_system().await?;
242
243 match system
244 .workspace_manager
245 .remove_session_from_workspace(&workspace_id, &session_id)
246 {
247 Ok(Some(role)) => {
248 if let Err(e) = persist_workspace_after_mutation(&system, workspace_id).await {
249 error!("Failed to remove session from workspace in storage: {}", e);
250 return Ok(MCPToolResult::error(format!(
251 "Failed to remove session from workspace in storage: {}",
252 e
253 )));
254 }
255
256 info!(
257 "Removed session {} from workspace {} (was role {:?})",
258 session_id, workspace_id, role
259 );
260
261 Ok(MCPToolResult::success(
262 "Removed session from workspace successfully".to_string(),
263 Some(serde_json::json!({
264 "workspace_id": workspace_id.to_string(),
265 "session_id": session_id.to_string(),
266 "previous_role": format!("{:?}", role)
267 })),
268 ))
269 }
270 Ok(None) => Ok(MCPToolResult::error(format!(
271 "Session {} not found in workspace {}",
272 session_id, workspace_id
273 ))),
274 Err(e) => Ok(MCPToolResult::error(e)),
275 }
276}