Skip to main content

stynx_code_tools/infrastructure/
brief_tool.rs

1use stynx_code_errors::AppResult;
2use stynx_code_types::{PermissionLevel, Tool};
3use serde_json::{Value, json};
4
5pub struct BriefTool;
6
7impl BriefTool {
8    pub fn new() -> Self {
9        Self
10    }
11}
12
13#[async_trait::async_trait]
14impl Tool for BriefTool {
15    fn name(&self) -> &str {
16        "brief"
17    }
18
19    fn description(&self) -> &str {
20        "Return content as structured output, optionally with a title."
21    }
22
23    fn input_schema(&self) -> Value {
24        json!({
25            "type": "object",
26            "properties": {
27                "content": {
28                    "type": "string",
29                    "description": "The content to output"
30                },
31                "title": {
32                    "type": "string",
33                    "description": "Optional title for the output"
34                }
35            },
36            "required": ["content"]
37        })
38    }
39
40    fn permission_level(&self) -> PermissionLevel {
41        PermissionLevel::ReadOnly
42    }
43
44    fn is_read_only(&self, _input: &Value) -> bool { true }
45    fn is_concurrent_safe(&self, _input: &Value) -> bool { true }
46
47    async fn execute(&self, input: Value) -> AppResult<String> {
48        let content = input
49            .get("content")
50            .and_then(|v| v.as_str())
51            .ok_or_else(|| stynx_code_errors::AppError::Tool("missing 'content' field".into()))?;
52
53        let title = input.get("title").and_then(|v| v.as_str());
54
55        tracing::info!(title, content_len = content.len(), "brief output");
56
57        match title {
58            Some(t) => Ok(format!("## {t}\n\n{content}")),
59            None => Ok(content.to_string()),
60        }
61    }
62}