#[async_trait]
impl ToolHandler for PdmtTool {
fn metadata(&self) -> Option<ToolInfo> {
let schema = json!({
"type": "object",
"properties": {
"requirements": {
"type": "array",
"items": { "type": "string" },
"description": "Requirements to convert into deterministic actionable todos"
},
"project_name": { "type": "string", "description": "Project or component name" },
"granularity": { "type": "string", "enum": ["low", "medium", "high"], "description": "Task detail level (default: high)" },
"quality_config": {
"type": "object",
"description": "Quality enforcement config",
"properties": {
"enforcement_mode": { "type": "string", "enum": ["strict", "advisory", "auto_fix"] },
"coverage_threshold": { "type": "number" },
"max_complexity": { "type": "integer" },
"require_doctests": { "type": "boolean" },
"require_property_tests": { "type": "boolean" },
"require_examples": { "type": "boolean" },
"zero_satd_tolerance": { "type": "boolean" }
}
}
},
"required": ["requirements"]
});
Some(build_tool_info(
"pdmt_deterministic_todos",
"Generate deterministic, quality-enforced todo lists from a list of requirements.",
schema,
))
}
async fn handle(&self, args: Value, _extra: RequestHandlerExtra) -> Result<Value> {
debug!("Handling pdmt_deterministic_todos with args: {}", args);
let input: PdmtInput = serde_json::from_value(args)
.map_err(|e| Error::validation(format!("Invalid arguments: {e}")))?;
if input.requirements.is_empty() {
return Err(Error::validation("Requirements list cannot be empty"));
}
info!(
"Generating deterministic todos for {} requirements",
input.requirements.len()
);
let enforcement_mode = match input.quality_config.enforcement_mode.as_str() {
"strict" => EnforcementMode::Strict,
"advisory" => EnforcementMode::Advisory,
"auto_fix" | "autofix" => EnforcementMode::AutoFix,
_ => {
return Err(Error::validation(format!(
"Invalid enforcement mode: {}. Must be 'strict', 'advisory', or 'auto_fix'",
input.quality_config.enforcement_mode
)))
}
};
let quality_config = PdmtQualityConfig {
enforcement_mode,
coverage_threshold: input.quality_config.coverage_threshold,
max_complexity: input.quality_config.max_complexity,
require_doctests: input.quality_config.require_doctests,
require_property_tests: input.quality_config.require_property_tests,
require_examples: input.quality_config.require_examples,
zero_satd_tolerance: input.quality_config.zero_satd_tolerance,
};
let todo_list = self
.service
.generate_todos(
input.requirements,
input.project_name,
&input.granularity,
quality_config,
)
.map_err(|e| Error::internal(format!("Failed to generate todos: {e}")))?;
let quality_validation = self
.quality_enforcer
.enforce_quality_standards(&todo_list)
.await
.map_err(|e| Error::internal(format!("Quality validation failed: {e}")))?;
let total_todos = todo_list.todos.len();
let estimated_total_hours: f32 = todo_list.todos.iter().map(|t| t.estimated_hours).sum();
let output = PdmtOutput {
success: quality_validation.overall_passed,
message: if quality_validation.overall_passed {
format!(
"Successfully generated {total_todos} deterministic todos with quality enforcement"
)
} else {
format!(
"Generated {total_todos} todos but quality validation failed. Review violations."
)
},
todo_list: Some(
serde_json::to_value(&todo_list)
.map_err(|e| Error::internal(format!("Failed to serialize todo list: {e}")))?,
),
quality_validation: Some(serde_json::to_value(&quality_validation).map_err(|e| {
Error::internal(format!("Failed to serialize validation results: {e}"))
})?),
total_todos,
estimated_total_hours,
};
if quality_validation.overall_passed {
info!(
"Successfully generated {} todos totaling {} hours",
total_todos, estimated_total_hours
);
} else {
error!(
"Quality validation failed with {} recommendations",
quality_validation.recommendations.len()
);
}
serde_json::to_value(output)
.map_err(|e| Error::internal(format!("Serialization error: {e}")))
}
}