gitai/server/tools/
changelog.rs1use crate::config::Config as GitAIConfig;
6use crate::debug;
7use crate::features::changelog::ChangelogGenerator;
8use crate::git::GitRepo;
9use crate::server::tools::utils::{
10 PilotTool, apply_custom_instructions, create_text_result, parse_detail_level, resolve_git_repo,
11 validate_repository_parameter,
12};
13
14use rmcp::handler::server::tool::cached_schema_for_type;
15use rmcp::model::{CallToolResult, Tool};
16use rmcp::schemars;
17
18use serde::{Deserialize, Serialize};
19use std::borrow::Cow;
20use std::sync::Arc;
21
22#[derive(Debug, Deserialize, Serialize, schemars::JsonSchema)]
24pub struct ChangelogTool {
25 pub from: String,
27
28 #[serde(default)]
30 pub to: String,
31
32 #[serde(default)]
34 pub detail_level: String,
35
36 #[serde(default)]
38 pub custom_instructions: String,
39
40 pub repository: String,
42
43 #[serde(default)]
45 pub version_name: String,
46}
47
48impl ChangelogTool {
49 pub fn get_tool_definition() -> Tool {
51 Tool {
52 name: Cow::Borrowed("gitai_changelog"),
53 description: Some(Cow::Borrowed(
54 "Generate a detailed changelog between two Git references",
55 )),
56 input_schema: cached_schema_for_type::<Self>(),
57 annotations: None,
58 icons: None,
59 output_schema: None,
60 title: None,
61 }
62 }
63}
64
65#[async_trait::async_trait]
66impl PilotTool for ChangelogTool {
67 async fn execute(
69 &self,
70 git_repo: Arc<GitRepo>,
71 config: GitAIConfig,
72 ) -> Result<CallToolResult, anyhow::Error> {
73 debug!("Generating changelog with: {:?}", self);
74
75 validate_repository_parameter(&self.repository)?;
77 let git_repo = resolve_git_repo(Some(self.repository.as_str()), git_repo)?;
78 debug!("Using repository: {}", git_repo.repo_path().display());
79
80 let detail_level = parse_detail_level(&self.detail_level);
82
83 let mut config = config.clone();
85 apply_custom_instructions(&mut config, &self.custom_instructions);
86
87 let to = if self.to.trim().is_empty() {
89 "HEAD".to_string()
90 } else {
91 self.to.clone()
92 };
93
94 let content =
96 ChangelogGenerator::generate(git_repo.clone(), &self.from, &to, &config, detail_level)
97 .await?;
98
99 let version_opt = if self.version_name.is_empty() {
101 None
102 } else {
103 Some(self.version_name.clone())
104 };
105
106 if let Some(version) = &version_opt {
108 debug!("Using custom version name: {}", version);
109 }
110
111 Ok(create_text_result(content))
113 }
114}