1use schemars::JsonSchema;
2use serde::{Deserialize, Deserializer, Serialize};
3
4#[derive(Debug, Clone, Deserialize, Serialize)]
7pub struct OpenProjectOutput {
8 pub status: String,
9 pub project_root: String,
10 #[serde(skip_serializing_if = "Option::is_none")]
11 pub detected_lsp_language: Option<String>,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub lsp: Option<String>,
14}
15
16#[derive(Debug, Clone, Deserialize)]
17#[serde(deny_unknown_fields)]
18pub struct ReadCodeInput {
19 pub path: String,
20 pub anchor: String,
21 pub mode: ReadCodeMode,
22}
23
24#[derive(Debug, Clone, Copy, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
25#[serde(rename_all = "lowercase")]
26pub enum ReadCodeMode {
27 Around,
28 Full,
29}
30
31#[derive(Debug, Clone, Deserialize, Serialize)]
32pub struct ReadCodeOutput {
33 pub content: String,
35}
36
37#[derive(Debug, Clone, Deserialize, Serialize)]
38pub struct SearchCodeOutput {
39 pub matches: Vec<SearchHit>,
40}
41
42#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
43pub struct SearchHit {
44 pub path: String,
45 pub hit: String,
46}
47
48#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
49#[serde(rename_all = "lowercase")]
50pub enum SearchMode {
51 #[default]
52 Literal,
53 Regex,
54}
55
56#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
57#[serde(rename_all = "lowercase")]
58pub enum SearchCase {
59 Sensitive,
60 Insensitive,
61 #[default]
62 Smart,
63}
64
65#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
66#[serde(transparent)]
67#[schemars(transparent)]
68pub struct SearchFlag(bool);
69
70impl SearchFlag {
71 #[must_use]
72 pub const fn is_enabled(self) -> bool {
73 self.0
74 }
75}
76
77impl From<bool> for SearchFlag {
78 fn from(value: bool) -> Self {
79 Self(value)
80 }
81}
82
83#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
84pub struct SearchCodeInput {
85 pub query: String,
86 #[serde(default)]
87 pub mode: SearchMode,
88 pub path: Option<String>,
89 #[serde(default, deserialize_with = "deserialize_string_list")]
90 pub include: Vec<String>,
91 #[serde(default, deserialize_with = "deserialize_string_list")]
92 pub exclude: Vec<String>,
93 #[serde(default, deserialize_with = "deserialize_string_list")]
94 pub types: Vec<String>,
95 #[serde(default, deserialize_with = "deserialize_string_list")]
96 pub type_not: Vec<String>,
97 #[serde(default, rename = "case")]
98 pub case_mode: SearchCase,
99 #[serde(default)]
100 pub word: bool,
101 #[serde(default)]
102 pub whole_line: bool,
103 #[serde(default)]
104 pub hidden: SearchFlag,
105 #[serde(default = "default_respect_ignore")]
106 pub respect_ignore: bool,
107 #[serde(default)]
108 pub follow: SearchFlag,
109 pub limit: Option<usize>,
110}
111
112impl Default for SearchCodeInput {
113 fn default() -> Self {
114 Self {
115 query: String::new(),
116 mode: SearchMode::default(),
117 path: None,
118 include: Vec::new(),
119 exclude: Vec::new(),
120 types: Vec::new(),
121 type_not: Vec::new(),
122 case_mode: SearchCase::default(),
123 word: false,
124 whole_line: false,
125 hidden: false.into(),
126 respect_ignore: true,
127 follow: false.into(),
128 limit: None,
129 }
130 }
131}
132
133const fn default_respect_ignore() -> bool {
134 true
135}
136
137fn deserialize_string_list<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
138where
139 D: Deserializer<'de>,
140{
141 #[derive(Deserialize)]
142 #[serde(untagged)]
143 enum StringList {
144 One(String),
145 Many(Vec<String>),
146 }
147
148 let Some(value) = Option::<StringList>::deserialize(deserializer)? else {
149 return Ok(Vec::new());
150 };
151 Ok(match value {
152 StringList::One(value) => vec![value],
153 StringList::Many(values) => values,
154 })
155}
156
157#[derive(Debug, Clone, Deserialize)]
158pub struct EditCodeInput {
159 pub edits: Vec<StructuredEdit>,
160}
161
162#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
164#[serde(rename_all = "lowercase")]
165pub enum EditOp {
166 Replace,
167 Append,
168 Prepend,
169}
170
171#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
173#[serde(untagged)]
174pub enum EditContent {
175 Lines(Vec<String>),
176 Text(String),
177}
178
179impl EditContent {
180 pub fn into_lines(self) -> Vec<String> {
181 match self {
182 Self::Lines(lines) => lines,
183 Self::Text(text) => text.lines().map(str::to_string).collect(),
184 }
185 }
186}
187
188#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
190pub struct StructuredEdit {
191 pub path: String,
193 #[serde(default)]
195 pub op: Option<EditOp>,
196 #[serde(default)]
199 pub start: Option<String>,
200 #[serde(skip_serializing_if = "Option::is_none")]
202 pub end: Option<String>,
203 #[serde(skip_serializing_if = "Option::is_none")]
206 pub content: Option<EditContent>,
207}
208
209#[derive(Debug, Clone, Deserialize)]
210pub struct SourceResponsibilityInput {
211 pub path: String,
212}
213
214#[derive(Debug, Clone, Deserialize, Serialize)]
215pub struct SourceResponsibility {
216 pub is_responsible: bool,
217 pub path: String,
218 #[serde(skip_serializing_if = "Option::is_none")]
219 pub extension: Option<String>,
220 #[serde(skip_serializing_if = "Option::is_none")]
221 pub language: Option<String>,
222 pub reason: String,
223}
224
225#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
228#[serde(rename_all = "snake_case")]
229pub enum PropagationSource {
230 Lsp,
231 OpenEnded,
232}
233
234#[derive(Debug, Clone, Serialize)]
235pub struct EditCodeOutput {
236 pub propagation_results: Vec<PropagationResult>,
237 pub applied_summary: AppliedStructuredEditSummary,
238}
239
240#[derive(Debug, Clone, Serialize)]
241pub struct PropagationResult {
242 pub selector: String,
243 pub reason: String,
244 pub source: PropagationSource,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub lsp_references: Option<Vec<(String, usize, String)>>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub diff_summary: Option<String>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub file_snippet: Option<String>,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub project_files: Option<Vec<String>>,
253}
254
255#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
256#[serde(rename_all = "snake_case")]
257pub enum AppliedStructuredEditOperation {
258 Add,
259 Update,
260}
261
262#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
263pub struct AppliedStructuredEditFile {
264 pub path: String,
265 pub operation: AppliedStructuredEditOperation,
266 pub added_lines: usize,
267 pub removed_lines: usize,
268 pub original_content: String,
269 pub new_content: String,
270}
271
272#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
273pub struct AppliedStructuredEditSummary {
274 pub files: Vec<AppliedStructuredEditFile>,
275}
276
277#[derive(Debug, Clone, Serialize)]
278pub struct ReviewBatch {
279 pub review: Option<ReviewEvent>,
280 pub reviews: Vec<ReviewEvent>,
281 pub returned: usize,
282 pub remaining: usize,
283}
284
285#[derive(Debug, Clone, Serialize)]
286pub struct Reference {
287 pub selector: String,
288 pub line: usize,
289 pub context: String,
290}
291
292#[derive(Debug, Clone, Serialize)]
293#[serde(tag = "type")]
294#[serde(rename_all = "snake_case")]
295pub enum ReviewEvent {
296 KnownReferences {
297 modified_symbol: String,
298 change_summary: String,
299 references: Vec<Reference>,
300 file_snippet: String,
301 },
302 InvestigateImpact {
303 modified_symbol: String,
304 change_summary: String,
305 diff_summary: String,
306 file_snippet: String,
307 project_files: Vec<String>,
308 },
309}