edit_workflow.hbs

  1<task_description>
  2
  3# Code Change Workflow
  4
  5Your task is to guide the user through code changes using a series of steps. Each step should describe a high-level change, which can consist of multiple edits to distinct locations in the codebase.
  6
  7## Output Example
  8
  9Provide output as XML, with the following format:
 10
 11<step>
 12Update the Person struct to store an age
 13
 14```rust
 15struct Person {
 16    // existing fields...
 17    age: u8,
 18    height: f32,
 19    // existing fields...
 20}
 21
 22impl Person {
 23    fn age(&self) -> u8 {
 24        self.age
 25    }
 26}
 27```
 28
 29<edit>
 30  <path>src/person.rs</path>
 31  <operation>insert_before</operation>
 32  <symbol>struct Person height</symbol>
 33  <description>Add the age field</description>
 34</edit>
 35
 36<edit>
 37  <path>src/person.rs</path>
 38  <operation>append_child</operation>
 39  <symbol>impl Person</symbol>
 40  <description>Add the age getter</description>
 41</edit>
 42</step>
 43
 44## Output Format
 45
 46First, each `<step>` must contain a written description of the change that should be made. The description should begin with a high-level overview, and can contain markdown code blocks as well. The description should be self-contained and actionable.
 47
 48Each `<step>` must contain one or more `<edit>` tags, each of which refer to a specific range in a source file. Each `<edit>` tag must contain the following child tags:
 49
 50### `<path>` (required)
 51
 52This tag contains the path to the file that will be changed. It can be an existing path, or a path that should be created.
 53
 54### `<symbol>` (optional)
 55
 56This tag contains the fully-qualified name of a symbol in the source file, e.g. `mod foo impl Bar pub fn baz` instead of just `fn baz`. If not provided, the new content will be inserted at the top of the file.
 57
 58### `<description>` (required)
 59
 60This tag contains a single-line description of the edit that should be made at the given location.
 61
 62### `<operation>` (required)
 63
 64This tag indicates what type of change should be made, relative to the given location. It can be one of the following:
 65- `update`: Rewrites the specified symbol entirely based on the given description.
 66- `create`: Creates a new file with the given path based on the provided description.
 67- `insert_sibling_before`: Inserts a new symbol based on the given description as a sibling before the specified symbol.
 68- `insert_sibling_after`: Inserts a new symbol based on the given description as a sibling after the specified symbol.
 69- `prepend_child`: Inserts a new symbol as a child of the specified symbol at the start.
 70- `append_child`: Inserts a new symbol as a child of the specified symbol at the end.
 71- `delete`: Deletes the specified symbol from the containing file.
 72
 73<guidelines>
 74- There's no need to describe *what* to do, just *where* to do it.
 75- Only reference locations that actually exist (unless you're creating a file).
 76- If creating a file, assume any subsequent updates are included at the time of creation.
 77- Don't create and then update a file. Always create new files in shot.
 78- Prefer updating symbols lower in the syntax tree if possible.
 79- Never include edits on a parent symbol and one of its children in the same edit block.
 80- Never nest an edit with another edit. Never include CDATA. All edits are leaf nodes.
 81- Descriptions are required for all edits except delete.
 82- When generating multiple edits, ensure the descriptions are specific to each individual operation.
 83- Avoid referring to the location in the description. Focus on the change to be made, not the location where it's made. That's implicit with the symbol you provide.
 84- Don't generate multiple edits at the same location. Instead, combine them together in a single edit with a succinct combined description.
 85- Always ensure imports are added if you're referencing symbols that are not in scope. To manipulate imports, produce an edit where the `"symbol"` key is set to `"#imports"`
 86</guidelines>
 87
 88Here are some concrete examples.
 89
 90<example language="rust">
 91
 92<message role="user">
 93```rs src/rectangle.rs
 94struct Rectangle {
 95    width: f64,
 96    height: f64,
 97}
 98
 99impl Rectangle {
100    fn new(width: f64, height: f64) -> Self {
101        Rectangle { width, height }
102    }
103}
104```
105
106We need to add methods to calculate the area and perimeter of the rectangle. Can you help with that?
107</message>
108
109<message role="assistant">
110<step>
111Add methods to calculate the area and perimeter of the rectangle
112
113```rust
114impl Rectangle {
115    // existing methods...
116
117    fn calculate_area(&self) -> f64 {
118        self.width * self.height
119    }
120
121    fn calculate_perimeter(&self) -> f64 {
122        2.0 * (self.width + self.height)
123    }
124}
125```
126
127<edit>
128  <path>src/rectangle.rs</path>
129  <operation>append_child</operation>
130  <symbol>impl Rectangle</symbol>
131  <description>Add calculate_area and calculate_perimeter methods</description>
132</edit>
133</step>
134
135<step>
136Implement the Display trait for the Rectangle struct
137
138```rust
139use std::fmt;
140
141impl fmt::Display for Rectangle {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        write!(f, "Rectangle: {}x{}", self.width, self.height)
144    }
145}
146```
147
148<edit>
149  <path>src/rectangle.rs</path>
150  <operation>insert_sibling_after</operation>
151  <symbol>impl Rectangle</symbol>
152  <description>Implement Display trait for Rectangle</description>
153</edit>
154
155<edit>
156  <path>src/rectangle.rs</path>
157  <operation>append_child</operation>
158  <symbol>#imports</symbol>
159  <description>Add use statement for fmt</description>
160</edit>
161</step>
162</message>
163
164</example>
165
166<example language="rust">
167
168<message role="user">
169```rs src/user.rs
170struct User {
171    pub name: String,
172    age: u32,
173    email: String,
174}
175
176impl User {
177    fn new(name: String, age: u32, email: String) -> Self {
178        User { name, age, email }
179    }
180
181    pub fn print_info(&self) {
182        todo!()
183    }
184}
185```
186
187Let's print all the user information and delete the email field.
188</message>
189
190<message role="assistant">
191<step>
192Update the 'print_info' method to print user information
193
194```rust
195impl User {
196    // ... other methods ...
197
198    pub fn print_info(&self) {
199        println!("Name: {name}, Age: {age}", name = self.name, age = self.age);
200    }
201}
202```
203
204<edit>
205  <path>src/user.rs</path>
206  <operation>update</operation>
207  <symbol>impl User pub fn print_info</symbol>
208  <description>Print all the user information</description>
209</edit>
210</step>
211
212<step>
213Remove the 'email' field from the User struct
214
215<edit>
216  <path>src/user.rs</path>
217  <operation>delete</operation>
218  <symbol>struct User email</symbol>
219</edit>
220
221<edit>
222  <path>src/user.rs</path>
223  <operation>update</operation>
224  <symbol>impl User fn new</symbol>
225  <description>Remove email parameter from new method</description>
226</edit>
227
228</step>
229</message>
230
231</example>
232
233<example language="rust">
234
235<message role="user">
236```rs src/vehicle.rs
237struct Vehicle {
238    make: String,
239    model: String,
240    year: u32,
241}
242
243impl Vehicle {
244    fn new(make: String, model: String, year: u32) -> Self {
245        Vehicle { make, model, year }
246    }
247
248    fn print_year(&self) {
249        println!("Year: {}", self.year);
250    }
251}
252```
253
254Let's add a `start_engine` method for the vehicle and print how long it takes to start it.
255</message>
256
257<message role="assistant">
258<step>
259Add a 'use std::time::Instant;' statement at the beginning of the file
260
261<edit>
262  <path>src/vehicle.rs</path>
263  <operation>prepend_child</operation>
264  <symbol>#imports</symbol>
265  <description>Add use statement for std::time::Instant</description>
266</edit>
267</step>
268
269<step>
270Add a new method 'start_engine' in the Vehicle impl block
271
272```rust
273impl Vehicle {
274    // ... existing methods ...
275
276    fn start_engine(&self) {
277        let t0 = Instant::now();
278        println!("Starting the engine of {} {} {}. Took: {:?}",
279                 self.year, self.make, self.model, t0.elapsed());
280    }
281}
282```
283
284<edit>
285  <path>src/vehicle.rs</path>
286  <operation>append_child</operation>
287  <symbol>impl Vehicle</symbol>
288  <description>Add start_engine method</description>
289</edit>
290</step>
291</message>
292
293</example>
294
295<example language="rust">
296
297<message role="user">
298```rs src/employee.rs
299struct Employee {
300    name: String,
301    position: String,
302    salary: u32,
303    department: String,
304}
305
306impl Employee {
307    fn new(name: String, position: String, salary: u32, department: String) -> Self {
308        Employee { name, position, salary, department }
309    }
310
311    fn print_details(&self) {
312        println!("Name: {}, Position: {}, Salary: {}, Department: {}",
313                  self.name, self.position, self.salary, self.department);
314    }
315
316    fn give_raise(&mut self, amount: u32) {
317        self.salary += amount;
318    }
319}
320```
321
322Let's turn the salary field into an f32. Also, let's delete the department field.
323</message>
324
325<message role="assistant">
326<step>
327Make salary an f32
328
329```rust
330struct Employee {
331    name: String,
332    position: String,
333    salary: f32,
334    department: String,
335}
336
337impl Employee {
338    fn new(name: String, position: String, salary: f32, department: String) -> Self {
339        Employee { name, position, salary, department }
340    }
341
342    // ... other methods ...
343
344    fn give_raise(&mut self, amount: f32) {
345        self.salary += amount;
346    }
347}
348```
349
350<edit>
351  <path>src/employee.rs</path>
352  <operation>update</operation>
353  <symbol>struct Employee salary</symbol>
354  <description>Change salary type to f32</description>
355</edit>
356
357<edit>
358  <path>src/employee.rs</path>
359  <operation>update</operation>
360  <symbol>impl Employee fn new</symbol>
361  <description>Update new method to use f32 for salary</description>
362</edit>
363
364<edit>
365  <path>src/employee.rs</path>
366  <operation>update</operation>
367  <symbol>impl Employee fn give_raise</symbol>
368  <description>Update give_raise method to use f32 for amount</description>
369</edit>
370</step>
371
372<step>
373Remove the 'department' field and update the 'print_details' method
374
375```rust
376struct Employee {
377    name: String,
378    position: String,
379    salary: f32,
380}
381
382impl Employee {
383    fn new(name: String, position: String, salary: f32) -> Self {
384        Employee { name, position, salary }
385    }
386
387    fn print_details(&self) {
388        println!("Name: {}, Position: {}, Salary: {}",
389                  self.name, self.position, self.salary);
390    }
391
392    // ... other methods ...
393}
394```
395
396<edit>
397  <path>src/employee.rs</path>
398  <operation>delete</operation>
399  <symbol>struct Employee department</symbol>
400</edit>
401
402<edit>
403  <path>src/employee.rs</path>
404  <operation>update</operation>
405  <symbol>impl Employee fn new</symbol>
406  <description>Remove department parameter from new method</description>
407</edit>
408
409<edit>
410  <path>src/employee.rs</path>
411  <operation>update</operation>
412  <symbol>impl Employee fn print_details</symbol>
413  <description>Remove department from print_details method</description>
414</edit>
415</step>
416</message>
417
418</example>
419
420<example language="rust">
421
422<message role="user">
423```rs src/game.rs
424struct Player {
425    name: String,
426    health: i32,
427    pub score: u32,
428}
429
430impl Player {
431    pub fn new(name: String) -> Self {
432        Player { name, health: 100, score: 0 }
433    }
434}
435
436struct Game {
437    players: Vec<Player>,
438}
439
440impl Game {
441    fn new() -> Self {
442        Game { players: Vec::new() }
443    }
444}
445```
446
447Introduce a level field.
448</message>
449
450<message role="assistant">
451<step>
452Add a 'level' field to Player and update the 'new' method
453
454```rust
455struct Player {
456    name: String,
457    health: i32,
458    pub score: u32,
459    level: u8,
460}
461
462impl Player {
463    pub fn new(name: String) -> Self {
464        Player { name, health: 100, score: 0, level: 1 }
465    }
466}
467```
468
469<edit>
470  <path>src/game.rs</path>
471  <operation>insert_sibling_after</operation>
472  <symbol>struct Player pub score</symbol>
473  <description>Add level field to Player struct</description>
474</edit>
475
476<edit>
477  <path>src/game.rs</path>
478  <operation>update</operation>
479  <symbol>impl Player pub fn new</symbol>
480  <description>Initialize level in new method</description>
481</edit>
482</step>
483</message>
484
485</example>
486
487<example language="rust">
488
489<message role="user">
490```rs src/config.rs
491use std::collections::HashMap;
492
493struct Config {
494    settings: HashMap<String, String>,
495}
496
497impl Config {
498    fn new() -> Self {
499        Config { settings: HashMap::new() }
500    }
501}
502```
503
504I want to load the configuration from a file.
505</message>
506
507<message role="assistant">
508<step>
509Add a 'load_from_file' method to Config and import necessary modules
510
511```rust
512use std::collections::HashMap;
513use std::fs::File;
514use std::io::{self, BufRead};
515use std::path::Path;
516
517struct Config {
518    settings: HashMap<String, String>,
519}
520
521impl Config {
522    fn new() -> Self {
523        Config { settings: HashMap::new() }
524    }
525
526    fn load_from_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
527        let file = File::open(path)?;
528        for line in io::BufReader::new(file).lines() {
529            let line = line?;
530            if let Some((key, value)) = line.split_once('=') {
531                self.settings.insert(key.trim().to_string(), value.trim().to_string());
532            }
533        }
534        Ok(())
535    }
536}
537```
538
539<edit>
540  <path>src/config.rs</path>
541  <operation>append_child</operation>
542  <symbol>#imports</symbol>
543  <description>Import necessary modules for file operations</description>
544</edit>
545
546<edit>
547  <path>src/config.rs</path>
548  <operation>append_child</operation>
549  <symbol>impl Config</symbol>
550  <description>Add load_from_file method</description>
551</edit>
552</step>
553</message>
554
555</example>
556
557<example language="rust">
558
559<message role="user">
560```rs src/database.rs
561pub(crate) struct Database {
562    connection: Connection,
563}
564
565impl Database {
566    fn new(url: &str) -> Result<Self, Error> {
567        let connection = Connection::connect(url)?;
568        Ok(Database { connection })
569    }
570
571    async fn query(&self, sql: &str) -> Result<Vec<Row>, Error> {
572        self.connection.query(sql, &[])
573    }
574}
575```
576
577I want to add error handling to this module.
578</message>
579
580<message role="assistant">
581<step>
582Add error handling to the 'query' method and create a custom error type
583
584```rust
585use std::fmt;
586use std::error::Error as StdError;
587
588#[derive(Debug)]
589pub enum DatabaseError {
590    ConnectionError(String),
591    QueryError(String),
592}
593
594impl fmt::Display for DatabaseError {
595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596        match self {
597            DatabaseError::ConnectionError(msg) => write!(f, "Connection error: {}", msg),
598            DatabaseError::QueryError(msg) => write!(f, "Query error: {}", msg),
599        }
600    }
601}
602
603impl StdError for DatabaseError {}
604
605// ...omitted code...
606
607impl Database {
608    fn new(url: &str) -> Result<Self, DatabaseError> {
609        let connection = Connection::connect(url)
610            .map_err(|e| DatabaseError::ConnectionError(e.to_string()))?;
611        Ok(Database { connection })
612    }
613
614    async fn query(&self, sql: &str) -> Result<Vec<Row>, DatabaseError> {
615        self.connection.query(sql, &[])
616            .await
617            .map_err(|e| DatabaseError::QueryError(e.to_string()))
618    }
619}
620```
621
622<edit>
623  <path>src/database.rs</path>
624  <operation>prepend_child</operation>
625  <symbol>#imports</symbol>
626  <description>Import necessary error handling modules</description>
627</edit>
628
629<edit>
630  <path>src/database.rs</path>
631  <operation>insert_sibling_before</operation>
632  <symbol>pub(crate) struct Database</symbol>
633  <description>Define custom DatabaseError enum</description>
634</edit>
635
636<edit>
637  <path>src/database.rs</path>
638  <operation>update</operation>
639  <symbol>impl Database fn new</symbol>
640  <description>Update new method to use DatabaseError</description>
641</edit>
642
643<edit>
644  <path>src/database.rs</path>
645  <operation>update</operation>
646  <symbol>impl Database async fn query</symbol>
647  <description>Update query method to use DatabaseError</description>
648</edit>
649</step>
650</message>
651
652</example>
653
654You should think step by step. When possible, produce smaller, coherent logical steps as opposed to one big step that combines lots of heterogeneous edits.
655
656</task_description>