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