agentic_evolve_mcp/tools/
evolve_coverage.rs1use std::sync::Arc;
4use tokio::sync::Mutex;
5
6use serde::Deserialize;
7use serde_json::{json, Value};
8
9use agentic_evolve_core::types::pattern::{
10 FunctionSignature, Language, ParamSignature, Visibility,
11};
12
13use crate::session::SessionManager;
14use crate::types::{McpError, McpResult, ToolCallResult, ToolDefinition};
15
16#[derive(Debug, Deserialize)]
17struct CoverageParams {
18 signatures: Vec<SignatureInput>,
19 #[serde(default = "default_threshold")]
20 threshold: f64,
21}
22
23#[derive(Debug, Deserialize)]
24struct SignatureInput {
25 name: String,
26 language: String,
27 #[serde(default)]
28 params: Vec<ParamInput>,
29 #[serde(default)]
30 return_type: Option<String>,
31 #[serde(default)]
32 is_async: bool,
33}
34
35#[derive(Debug, Deserialize)]
36struct ParamInput {
37 name: String,
38 #[serde(rename = "type", default = "default_type")]
39 param_type: String,
40 #[serde(default)]
41 is_optional: bool,
42}
43
44fn default_threshold() -> f64 {
45 0.5
46}
47
48fn default_type() -> String {
49 "Any".to_string()
50}
51
52pub fn definition() -> ToolDefinition {
54 ToolDefinition {
55 name: "evolve_coverage".to_string(),
56 description: Some("Get pattern coverage for a set of function signatures".to_string()),
57 input_schema: json!({
58 "type": "object",
59 "properties": {
60 "signatures": {
61 "type": "array",
62 "items": {
63 "type": "object",
64 "properties": {
65 "name": { "type": "string" },
66 "language": { "type": "string" },
67 "params": {
68 "type": "array",
69 "items": {
70 "type": "object",
71 "properties": {
72 "name": { "type": "string" },
73 "type": { "type": "string" },
74 "is_optional": { "type": "boolean" }
75 },
76 "required": ["name"]
77 }
78 },
79 "return_type": { "type": "string" },
80 "is_async": { "type": "boolean" }
81 },
82 "required": ["name", "language"]
83 },
84 "description": "Function signatures to check coverage for"
85 },
86 "threshold": {
87 "type": "number",
88 "default": 0.5,
89 "description": "Minimum match score to consider covered (0.0 to 1.0)"
90 },
91 "include_content": {
92 "type": "boolean",
93 "default": false,
94 "description": "Include full template content in response"
95 },
96 "intent": {
97 "type": "string",
98 "enum": ["exists", "ids", "summary", "full"],
99 "description": "Response detail level"
100 },
101 "since": {
102 "type": "integer",
103 "description": "Only return data changed after this Unix timestamp"
104 },
105 "token_budget": {
106 "type": "integer",
107 "description": "Maximum token budget for the response"
108 },
109 "max_results": {
110 "type": "integer",
111 "default": 10,
112 "description": "Maximum number of results to return"
113 },
114 "cursor": {
115 "type": "string",
116 "description": "Pagination cursor from a previous response"
117 }
118 },
119 "required": ["signatures"]
120 }),
121 }
122}
123
124pub async fn execute(
126 args: Value,
127 session: &Arc<Mutex<SessionManager>>,
128) -> McpResult<ToolCallResult> {
129 let params: CoverageParams =
130 serde_json::from_value(args).map_err(|e| McpError::InvalidParams(e.to_string()))?;
131
132 let signatures: Vec<FunctionSignature> = params
133 .signatures
134 .into_iter()
135 .map(|s| {
136 let language = Language::from_name(&s.language);
137 let sig_params: Vec<ParamSignature> = s
138 .params
139 .into_iter()
140 .map(|p| ParamSignature {
141 name: p.name,
142 param_type: p.param_type,
143 is_optional: p.is_optional,
144 })
145 .collect();
146 FunctionSignature {
147 name: s.name,
148 params: sig_params,
149 return_type: s.return_type,
150 language,
151 is_async: s.is_async,
152 visibility: Visibility::Public,
153 }
154 })
155 .collect();
156
157 let session = session.lock().await;
158 let report = session.coverage(&signatures, params.threshold);
159
160 Ok(ToolCallResult::json(&report))
161}