opendev_tools_impl/
task_complete.rs1use std::collections::HashMap;
11
12use opendev_tools_core::{BaseTool, ToolContext, ToolResult};
13
14const VALID_STATUSES: &[&str] = &["success", "partial", "failed"];
16
17#[derive(Debug)]
19pub struct TaskCompleteTool;
20
21#[async_trait::async_trait]
22impl BaseTool for TaskCompleteTool {
23 fn name(&self) -> &str {
24 "task_complete"
25 }
26
27 fn description(&self) -> &str {
28 "Call this tool when you have completed the user's request. \
29 You MUST call this tool to end the conversation. \
30 Provide your response to the user in the result parameter."
31 }
32
33 fn parameter_schema(&self) -> serde_json::Value {
34 serde_json::json!({
35 "type": "object",
36 "properties": {
37 "result": {
38 "type": "string",
39 "description": "Your response to the user — what was accomplished or your conversational reply"
40 },
41 "status": {
42 "type": "string",
43 "description": "Completion status: 'success', 'partial', or 'failed'",
44 "enum": VALID_STATUSES,
45 "default": "success"
46 }
47 },
48 "required": ["result"]
49 })
50 }
51
52 async fn execute(
53 &self,
54 args: HashMap<String, serde_json::Value>,
55 _ctx: &ToolContext,
56 ) -> ToolResult {
57 let summary = match args
58 .get("result")
59 .or_else(|| args.get("summary"))
60 .and_then(|v| v.as_str())
61 {
62 Some(s) if !s.trim().is_empty() => s.trim(),
63 _ => return ToolResult::fail("Result is required for task_complete"),
64 };
65
66 let status = args
67 .get("status")
68 .and_then(|v| v.as_str())
69 .unwrap_or("success");
70
71 if !VALID_STATUSES.contains(&status) {
72 return ToolResult::fail(format!(
73 "Invalid status '{status}'. Must be one of: {}",
74 VALID_STATUSES.join(", ")
75 ));
76 }
77
78 let output = format!("Task completed ({status}): {summary}");
79
80 let mut metadata = HashMap::new();
81 metadata.insert("_completion".into(), serde_json::json!(true));
82 metadata.insert("summary".into(), serde_json::json!(summary));
83 metadata.insert("status".into(), serde_json::json!(status));
84
85 ToolResult::ok_with_metadata(output, metadata)
86 }
87}
88
89#[cfg(test)]
90#[path = "task_complete_tests.rs"]
91mod tests;