git_iris/agents/tools/
content_update.rs1use anyhow::Result;
7use rig::completion::ToolDefinition;
8use rig::tool::Tool;
9use serde::{Deserialize, Serialize};
10use serde_json::json;
11use std::sync::Arc;
12use tokio::sync::mpsc;
13
14use super::common::parameters_schema;
15
16crate::define_tool_error!(ContentUpdateError);
18
19#[derive(Debug, Clone)]
21pub enum ContentUpdate {
22 Commit {
24 emoji: Option<String>,
25 title: String,
26 message: String,
27 },
28 PR { content: String },
30 Review { content: String },
32}
33
34pub const CONTENT_UPDATE_CHANNEL_CAPACITY: usize = 100;
36
37pub type ContentUpdateSender = mpsc::Sender<ContentUpdate>;
39pub type ContentUpdateReceiver = mpsc::Receiver<ContentUpdate>;
40
41#[must_use]
43pub fn create_content_update_channel() -> (ContentUpdateSender, ContentUpdateReceiver) {
44 mpsc::channel(CONTENT_UPDATE_CHANNEL_CAPACITY)
45}
46
47#[derive(Clone)]
53pub struct UpdateCommitTool {
54 sender: Arc<ContentUpdateSender>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
58pub struct UpdateCommitArgs {
59 #[serde(default)]
61 pub emoji: Option<String>,
62 pub title: String,
64 #[serde(default)]
66 pub message: Option<String>,
67}
68
69impl UpdateCommitTool {
70 #[must_use]
71 pub fn new(sender: ContentUpdateSender) -> Self {
72 Self {
73 sender: Arc::new(sender),
74 }
75 }
76}
77
78impl Tool for UpdateCommitTool {
79 const NAME: &'static str = "update_commit";
80 type Error = ContentUpdateError;
81 type Args = UpdateCommitArgs;
82 type Output = String;
83
84 async fn definition(&self, _: String) -> ToolDefinition {
85 ToolDefinition {
86 name: "update_commit".to_string(),
87 description: "Update the current commit message. Use this when the user asks you to modify, change, or rewrite the commit message. The update will be applied immediately.".to_string(),
88 parameters: parameters_schema::<UpdateCommitArgs>(),
89 }
90 }
91
92 async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
93 tracing::info!(
94 "update_commit tool called! emoji={:?}, title={}, message_len={}",
95 args.emoji,
96 args.title,
97 args.message.as_ref().map_or(0, std::string::String::len)
98 );
99
100 let update = ContentUpdate::Commit {
101 emoji: args.emoji.clone(),
102 title: args.title.clone(),
103 message: args.message.clone().unwrap_or_default(),
104 };
105
106 self.sender.try_send(update).map_err(|e| {
107 tracing::error!("Failed to send content update: {}", e);
108 ContentUpdateError(format!("Failed to send update: {}", e))
109 })?;
110
111 tracing::info!("Content update sent successfully via channel");
112
113 let result = json!({
114 "success": true,
115 "message": "Commit message updated successfully",
116 "new_title": args.title,
117 "emoji": args.emoji
118 });
119
120 serde_json::to_string_pretty(&result).map_err(|e| ContentUpdateError(e.to_string()))
121 }
122}
123
124#[derive(Clone)]
130pub struct UpdatePRTool {
131 sender: Arc<ContentUpdateSender>,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
135pub struct UpdatePRArgs {
136 pub content: String,
138}
139
140impl UpdatePRTool {
141 #[must_use]
142 pub fn new(sender: ContentUpdateSender) -> Self {
143 Self {
144 sender: Arc::new(sender),
145 }
146 }
147}
148
149impl Tool for UpdatePRTool {
150 const NAME: &'static str = "update_pr";
151 type Error = ContentUpdateError;
152 type Args = UpdatePRArgs;
153 type Output = String;
154
155 async fn definition(&self, _: String) -> ToolDefinition {
156 ToolDefinition {
157 name: "update_pr".to_string(),
158 description: "Update the current PR description. Use this when the user asks you to modify, change, or rewrite the PR content.".to_string(),
159 parameters: parameters_schema::<UpdatePRArgs>(),
160 }
161 }
162
163 async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
164 let content_len = args.content.len();
165 let update = ContentUpdate::PR {
166 content: args.content,
167 };
168
169 self.sender
170 .try_send(update)
171 .map_err(|e| ContentUpdateError(format!("Failed to send update: {}", e)))?;
172
173 let result = json!({
174 "success": true,
175 "message": "PR description updated successfully",
176 "content_length": content_len
177 });
178
179 serde_json::to_string_pretty(&result).map_err(|e| ContentUpdateError(e.to_string()))
180 }
181}
182
183#[derive(Clone)]
189pub struct UpdateReviewTool {
190 sender: Arc<ContentUpdateSender>,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
194pub struct UpdateReviewArgs {
195 pub content: String,
197}
198
199impl UpdateReviewTool {
200 #[must_use]
201 pub fn new(sender: ContentUpdateSender) -> Self {
202 Self {
203 sender: Arc::new(sender),
204 }
205 }
206}
207
208impl Tool for UpdateReviewTool {
209 const NAME: &'static str = "update_review";
210 type Error = ContentUpdateError;
211 type Args = UpdateReviewArgs;
212 type Output = String;
213
214 async fn definition(&self, _: String) -> ToolDefinition {
215 ToolDefinition {
216 name: "update_review".to_string(),
217 description: "Update the current code review. Use this when the user asks you to modify, change, or rewrite the review content.".to_string(),
218 parameters: parameters_schema::<UpdateReviewArgs>(),
219 }
220 }
221
222 async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
223 let content_len = args.content.len();
224 let update = ContentUpdate::Review {
225 content: args.content,
226 };
227
228 self.sender
229 .try_send(update)
230 .map_err(|e| ContentUpdateError(format!("Failed to send update: {}", e)))?;
231
232 let result = json!({
233 "success": true,
234 "message": "Review updated successfully",
235 "content_length": content_len
236 });
237
238 serde_json::to_string_pretty(&result).map_err(|e| ContentUpdateError(e.to_string()))
239 }
240}