do_memory_mcp/server/tools/
episode_create.rs1use crate::server::MemoryMCPServer;
7use anyhow::{Result, anyhow};
8use do_memory_core::{TaskContext, TaskType};
9use serde_json::{Value, json};
10use tracing::debug;
11use tracing::info;
12
13fn parse_complexity(s: &str) -> do_memory_core::ComplexityLevel {
15 match s {
16 "simple" => do_memory_core::ComplexityLevel::Simple,
17 "moderate" => do_memory_core::ComplexityLevel::Moderate,
18 "complex" => do_memory_core::ComplexityLevel::Complex,
19 _ => do_memory_core::ComplexityLevel::Moderate,
20 }
21}
22
23fn parse_task_type(task_type: &str) -> Result<TaskType> {
25 match task_type {
26 "code_generation" => Ok(TaskType::CodeGeneration),
27 "debugging" => Ok(TaskType::Debugging),
28 "refactoring" => Ok(TaskType::Refactoring),
29 "testing" => Ok(TaskType::Testing),
30 "analysis" => Ok(TaskType::Analysis),
31 "documentation" => Ok(TaskType::Documentation),
32 _ => Err(anyhow!(
33 "Invalid task_type: {}. Must be one of: code_generation, debugging, refactoring, testing, analysis, documentation",
34 task_type
35 )),
36 }
37}
38
39impl MemoryMCPServer {
40 pub async fn create_episode_tool(&self, args: Value) -> Result<Value> {
55 debug!("Creating episode with args: {}", args);
56
57 let task_description = args
59 .get("task_description")
60 .and_then(|v| v.as_str())
61 .ok_or_else(|| anyhow!("Missing required field: task_description"))?
62 .to_string();
63
64 let domain = args
65 .get("domain")
66 .and_then(|v| v.as_str())
67 .ok_or_else(|| anyhow!("Missing required field: domain"))?
68 .to_string();
69
70 let task_type_str = args
71 .get("task_type")
72 .and_then(|v| v.as_str())
73 .ok_or_else(|| anyhow!("Missing required field: task_type"))?;
74
75 let task_type = parse_task_type(task_type_str)?;
77
78 let language = args
80 .get("language")
81 .and_then(|v| v.as_str())
82 .map(|s| s.to_string());
83
84 let framework = args
85 .get("framework")
86 .and_then(|v| v.as_str())
87 .map(|s| s.to_string());
88
89 let tags = args
90 .get("tags")
91 .and_then(|v| v.as_array())
92 .map(|arr| {
93 arr.iter()
94 .filter_map(|v| v.as_str().map(|s| s.to_string()))
95 .collect()
96 })
97 .unwrap_or_default();
98
99 let complexity = args
100 .get("complexity")
101 .and_then(|v| v.as_str())
102 .map(parse_complexity)
103 .unwrap_or(do_memory_core::ComplexityLevel::Moderate);
104
105 let context = TaskContext {
107 language,
108 framework,
109 complexity,
110 domain: domain.clone(),
111 tags,
112 };
113
114 let episode_id = self
116 .memory
117 .start_episode(task_description.clone(), context, task_type)
118 .await;
119
120 info!(
121 episode_id = %episode_id,
122 task_description = %task_description,
123 domain = %domain,
124 "Created new episode via MCP"
125 );
126
127 Ok(json!({
128 "success": true,
129 "episode_id": episode_id.to_string(),
130 "task_description": task_description,
131 "domain": domain,
132 "task_type": task_type_str,
133 "message": "Episode created successfully"
134 }))
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn test_parse_task_type_valid() {
144 assert!(parse_task_type("code_generation").is_ok());
145 assert!(parse_task_type("debugging").is_ok());
146 assert!(parse_task_type("refactoring").is_ok());
147 assert!(parse_task_type("testing").is_ok());
148 assert!(parse_task_type("analysis").is_ok());
149 assert!(parse_task_type("documentation").is_ok());
150 }
151
152 #[test]
153 fn test_parse_task_type_invalid() {
154 assert!(parse_task_type("invalid").is_err());
155 assert!(parse_task_type("").is_err());
156 }
157
158 #[test]
159 fn test_parse_complexity() {
160 assert_eq!(
161 parse_complexity("simple"),
162 do_memory_core::ComplexityLevel::Simple
163 );
164 assert_eq!(
165 parse_complexity("moderate"),
166 do_memory_core::ComplexityLevel::Moderate
167 );
168 assert_eq!(
169 parse_complexity("complex"),
170 do_memory_core::ComplexityLevel::Complex
171 );
172 assert_eq!(
173 parse_complexity("unknown"),
174 do_memory_core::ComplexityLevel::Moderate
175 );
176 }
177}