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
41pub fn create_content_update_channel() -> (ContentUpdateSender, ContentUpdateReceiver) {
43 mpsc::channel(CONTENT_UPDATE_CHANNEL_CAPACITY)
44}
45
46#[derive(Clone)]
52pub struct UpdateCommitTool {
53 sender: Arc<ContentUpdateSender>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
57pub struct UpdateCommitArgs {
58 #[serde(default)]
60 pub emoji: Option<String>,
61 pub title: String,
63 #[serde(default)]
65 pub message: Option<String>,
66}
67
68impl UpdateCommitTool {
69 pub fn new(sender: ContentUpdateSender) -> Self {
70 Self {
71 sender: Arc::new(sender),
72 }
73 }
74}
75
76impl Tool for UpdateCommitTool {
77 const NAME: &'static str = "update_commit";
78 type Error = ContentUpdateError;
79 type Args = UpdateCommitArgs;
80 type Output = String;
81
82 async fn definition(&self, _: String) -> ToolDefinition {
83 ToolDefinition {
84 name: "update_commit".to_string(),
85 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(),
86 parameters: parameters_schema::<UpdateCommitArgs>(),
87 }
88 }
89
90 async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
91 tracing::info!(
92 "update_commit tool called! emoji={:?}, title={}, message_len={}",
93 args.emoji,
94 args.title,
95 args.message.as_ref().map_or(0, std::string::String::len)
96 );
97
98 let update = ContentUpdate::Commit {
99 emoji: args.emoji.clone(),
100 title: args.title.clone(),
101 message: args.message.clone().unwrap_or_default(),
102 };
103
104 self.sender.try_send(update).map_err(|e| {
105 tracing::error!("Failed to send content update: {}", e);
106 ContentUpdateError(format!("Failed to send update: {}", e))
107 })?;
108
109 tracing::info!("Content update sent successfully via channel");
110
111 let result = json!({
112 "success": true,
113 "message": "Commit message updated successfully",
114 "new_title": args.title,
115 "emoji": args.emoji
116 });
117
118 serde_json::to_string_pretty(&result).map_err(|e| ContentUpdateError(e.to_string()))
119 }
120}
121
122#[derive(Clone)]
128pub struct UpdatePRTool {
129 sender: Arc<ContentUpdateSender>,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
133pub struct UpdatePRArgs {
134 pub content: String,
136}
137
138impl UpdatePRTool {
139 pub fn new(sender: ContentUpdateSender) -> Self {
140 Self {
141 sender: Arc::new(sender),
142 }
143 }
144}
145
146impl Tool for UpdatePRTool {
147 const NAME: &'static str = "update_pr";
148 type Error = ContentUpdateError;
149 type Args = UpdatePRArgs;
150 type Output = String;
151
152 async fn definition(&self, _: String) -> ToolDefinition {
153 ToolDefinition {
154 name: "update_pr".to_string(),
155 description: "Update the current PR description. Use this when the user asks you to modify, change, or rewrite the PR content.".to_string(),
156 parameters: parameters_schema::<UpdatePRArgs>(),
157 }
158 }
159
160 async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
161 let content_len = args.content.len();
162 let update = ContentUpdate::PR {
163 content: args.content,
164 };
165
166 self.sender
167 .try_send(update)
168 .map_err(|e| ContentUpdateError(format!("Failed to send update: {}", e)))?;
169
170 let result = json!({
171 "success": true,
172 "message": "PR description updated successfully",
173 "content_length": content_len
174 });
175
176 serde_json::to_string_pretty(&result).map_err(|e| ContentUpdateError(e.to_string()))
177 }
178}
179
180#[derive(Clone)]
186pub struct UpdateReviewTool {
187 sender: Arc<ContentUpdateSender>,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
191pub struct UpdateReviewArgs {
192 pub content: String,
194}
195
196impl UpdateReviewTool {
197 pub fn new(sender: ContentUpdateSender) -> Self {
198 Self {
199 sender: Arc::new(sender),
200 }
201 }
202}
203
204impl Tool for UpdateReviewTool {
205 const NAME: &'static str = "update_review";
206 type Error = ContentUpdateError;
207 type Args = UpdateReviewArgs;
208 type Output = String;
209
210 async fn definition(&self, _: String) -> ToolDefinition {
211 ToolDefinition {
212 name: "update_review".to_string(),
213 description: "Update the current code review. Use this when the user asks you to modify, change, or rewrite the review content.".to_string(),
214 parameters: parameters_schema::<UpdateReviewArgs>(),
215 }
216 }
217
218 async fn call(&self, args: Self::Args) -> Result<Self::Output, Self::Error> {
219 let content_len = args.content.len();
220 let update = ContentUpdate::Review {
221 content: args.content,
222 };
223
224 self.sender
225 .try_send(update)
226 .map_err(|e| ContentUpdateError(format!("Failed to send update: {}", e)))?;
227
228 let result = json!({
229 "success": true,
230 "message": "Review updated successfully",
231 "content_length": content_len
232 });
233
234 serde_json::to_string_pretty(&result).map_err(|e| ContentUpdateError(e.to_string()))
235 }
236}