Skip to content

Commit 2a09ea9

Browse files
author
kiran-garre
committed
Add append-only context and "modified files" fields to "complete" command of todo_list
1 parent da54512 commit 2a09ea9

File tree

4 files changed

+64
-52
lines changed

4 files changed

+64
-52
lines changed

crates/chat-cli/src/cli/chat/cli/todos.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
#![allow(warnings)]
2-
31
use clap::Subcommand;
4-
use std::{io, path::PathBuf};
2+
use std::path::PathBuf;
53
use crate::{cli::chat::tools::todo::TodoState, os::Os};
64
use crossterm::{
75
execute,
@@ -14,10 +12,7 @@ use crate::cli::chat::{
1412
ChatState,
1513
};
1614

17-
use eyre::{
18-
Result,
19-
bail,
20-
};
15+
use eyre::Result;
2116

2217
use crate::cli::chat::tools::todo::{
2318
build_path,
@@ -71,21 +66,21 @@ impl TodoSubcommand {
7166
execute!(
7267
session.stderr,
7368
style::Print("No to-do lists to show"),
74-
);
69+
)?;
7570
}
7671
for e in entries {
7772
execute!(
7873
session.stderr,
7974
style::Print(e),
8075
style::Print("\n"),
81-
);
76+
)?;
8277
}
8378
}
84-
Err(e) => {
79+
Err(_) => {
8580
execute!(
8681
session.stderr,
8782
style::Print("Could not show to-do lists"),
88-
);
83+
)?;
8984
}
9085
}
9186
},
@@ -99,34 +94,37 @@ impl TodoSubcommand {
9994
execute!(
10095
session.stderr,
10196
style::Print("No to-do lists to show"),
102-
);
97+
)?;
10398
} else {
10499
let selection = FuzzySelect::new()
105100
.with_prompt("Select task:")
106101
.items(&entries)
107102
.report(false)
108103
.interact_opt()
109-
.unwrap_or(None); // FIX: workaround for ^C during selection
104+
.unwrap_or(None);
110105

111106
if let Some(index) = selection {
112107
if index < entries.len() {
113108
execute!(
114109
session.stderr,
115110
style::Print("⟳ Resuming: ".magenta()),
116111
style::Print(format!("{}\n", entries[index].description.clone())),
117-
);
112+
)?;
118113
return session.resume_todo(os, entries[index].path.clone()).await;
119114
}
120115
}
121116
}
122117
}
118+
// %%% FIX %%%
123119
Err(e) => println!("{:?}", e),
120+
// %%% --- %%%
124121
};
125122
},
126123
};
127124
Ok(ChatState::PromptUser { skip_printing_tools: true })
128125
}
129126

127+
/// Convert all to-do list state files to displayable entries
130128
async fn get_descriptions_and_statuses(self, os: &Os) -> Result<Vec<TodoDisplayEntry>> {
131129
let mut out = Vec::new();
132130
let mut entries = os.fs.read_dir(
@@ -167,7 +165,7 @@ fn prewrap(text: &str) -> String {
167165
let mut current_line_length = 0;
168166
let words: Vec<&str> = text.split_whitespace().collect();
169167

170-
for (i, word) in words.iter().enumerate() {
168+
for (_, word) in words.iter().enumerate() {
171169
let word_length = word.len();
172170

173171
// If adding this word would exceed the line length and we're not at the start of a line

crates/chat-cli/src/cli/chat/conversation.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,6 @@ impl ConversationState {
876876
}
877877

878878
// For now, just check that file path is valid and deserializable
879-
// QUESTION: How do you pass errors cleanly in the todo_request functions?
880879
pub async fn can_resume_todo(&self, os: &Os, path: &PathBuf) -> Result<String> {
881880
let contents = os.fs.read_to_string(path).await?;
882881
let _ = serde_json::from_str::<TodoState>(&contents)?;

crates/chat-cli/src/cli/chat/tools/todo.rs

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
#![allow(warnings)]
2-
3-
use core::task;
4-
use std::path::{Path, PathBuf};
1+
use std::path::PathBuf;
52
use std::time::{SystemTime, UNIX_EPOCH};
63

74
use std::io::Write;
@@ -11,7 +8,6 @@ use serde::{
118
};
129

1310
use crossterm::{
14-
execute,
1511
queue,
1612
style,
1713
};
@@ -20,26 +16,22 @@ use eyre::{
2016
Result,
2117
bail,
2218
};
23-
use uuid::timestamp::context;
2419

25-
use super::{
26-
InvokeOutput,
27-
MAX_TOOL_RESPONSE_SIZE,
28-
OutputKind,
29-
};
20+
use super::InvokeOutput;
3021

3122
use crate::os::Os;
3223

3324
/*
3425
Demo prompts:
3526
Create a Python package layout with a blank main file and a blank utilities file. Start by making a todo list.
3627
Design your own super simple programming task with 4 steps. Make a todo list for the task, and begin executing those steps.
28+
Implement a basic input to Python type converter where the user can input either a string or integer and it gets converted to the corresponding Python object.
3729
*/
3830

3931
// ########### HARDCODED VALUES ##############
4032
pub const CURRENT_TODO_STATE_PATH: &str = ".aws/amazonq/todos/CURRENT_STATE.txt";
4133
pub const TODO_STATE_FOLDER_PATH: &str = ".aws/amazonq/todos";
42-
// ########### --------------------- ##############
34+
// ########### ---------------- ##############
4335

4436
#[derive(Debug, Clone, Deserialize)]
4537
#[serde(tag = "command")]
@@ -55,6 +47,7 @@ pub enum TodoInput {
5547
Complete {
5648
completed_indices: Vec<usize>,
5749
context_update: String,
50+
modified_files: Option<Vec<String>>,
5851
},
5952

6053
#[serde(rename = "load")]
@@ -68,7 +61,8 @@ pub struct TodoState {
6861
pub tasks: Vec<String>,
6962
pub completed: Vec<bool>,
7063
pub task_description: String,
71-
pub context: String,
64+
pub context: Vec<String>,
65+
pub modified_files: Vec<String>,
7266
}
7367

7468
impl TodoState {
@@ -141,18 +135,21 @@ impl TodoState {
141135

142136
/// Gets the current to-do list path from the fixed state file
143137
pub async fn get_current_todo_path(os: &Os) -> Result<Option<String>> {
144-
let temp = build_path(os, CURRENT_TODO_STATE_PATH, "")?;
145-
let path = os.fs.read_to_string(
146-
build_path(os, CURRENT_TODO_STATE_PATH, "")?
147-
).await?;
148-
if path.len() > 0 {
149-
return Ok(Some(path));
138+
let state_file_path = build_path(os, CURRENT_TODO_STATE_PATH, "")?;
139+
if !os.fs.exists(&state_file_path) {
140+
return Ok(None);
141+
}
142+
143+
let path = os.fs.read_to_string(&state_file_path).await?;
144+
if path.is_empty() {
145+
Ok(None)
146+
} else {
147+
Ok(Some(path.to_string()))
150148
}
151-
Ok(None)
152149
}
153150

154151
/// Sets the current to-do list path in the fixed state file
155-
pub async fn set_current_todo_path(os: &Os, path: &str) -> Result<()> {;
152+
pub async fn set_current_todo_path(os: &Os, path: &str) -> Result<()> {
156153
os.fs.write(
157154
build_path(os, CURRENT_TODO_STATE_PATH, "")?,
158155
path
@@ -180,7 +177,8 @@ impl TodoInput {
180177
tasks: tasks.clone(),
181178
completed: vec![false; tasks.len()],
182179
task_description: task_description.clone(),
183-
context: String::new(),
180+
context: Vec::new(),
181+
modified_files: Vec::new(),
184182
};
185183
let path = build_path(
186184
os,
@@ -191,21 +189,27 @@ impl TodoInput {
191189
TodoState::set_current_todo_path(os, &path.to_string_lossy()).await?;
192190
state
193191
},
194-
TodoInput::Complete { completed_indices, context_update} => {
192+
TodoInput::Complete { completed_indices, context_update, modified_files } => {
195193
let current_path = match TodoState::get_current_todo_path(os).await? {
196194
Some(path) => path,
197195
None => bail!("No todo list is currently loaded"),
198196
};
199197
let mut state = TodoState::load(os, &current_path).await?;
198+
200199
completed_indices.iter().for_each(|i| {
201200
state.completed[*i] = true;
202201
});
203-
state.context = context_update.clone();
202+
203+
state.context.push(context_update.clone());
204+
205+
if let Some(files) = modified_files {
206+
state.modified_files.extend_from_slice(&files);
207+
}
204208
state.save(os, &current_path).await?;
205209
state
206210
},
207211
TodoInput::Load { path } => {
208-
let mut state = TodoState::load(os, &path).await?;
212+
let state = TodoState::load(os, &path).await?;
209213
TodoState::set_current_todo_path(os, path).await?;
210214
state
211215
}
@@ -225,18 +229,22 @@ impl TodoInput {
225229
TodoInput::Create { tasks, task_description } => {
226230
if tasks.len() == 0 {
227231
bail!("No tasks were provided");
232+
} else if tasks.iter().any(|task| task.trim().is_empty()) {
233+
bail!("Tasks cannot be empty");
228234
} else if task_description.is_empty() {
229235
bail!("No task description was provided");
230236
}
231237
}
232-
TodoInput::Complete { completed_indices, context_update } => {
238+
TodoInput::Complete { completed_indices, context_update, .. } => {
233239
let current_path = match TodoState::get_current_todo_path(os).await? {
234240
Some(path) => path,
235241
None => bail!("No todo list is currently loaded"),
236242
};
237-
let mut state = TodoState::load(os, &current_path).await?;
238-
if completed_indices.iter().any(|i| *i > state.completed.len()) {
243+
let state = TodoState::load(os, &current_path).await?;
244+
if completed_indices.iter().any(|i| *i >= state.completed.len()) {
239245
bail!("Completed index is out of bounds");
246+
} else if context_update.len() == 0 {
247+
bail!("No context update was provided");
240248
}
241249
}
242250
TodoInput::Load { path } => {

crates/chat-cli/src/cli/chat/tools/tool_index.json

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,9 @@
233233
"required": ["command"]
234234
}
235235
},
236-
"todo": {
236+
"todo_list": {
237237
"name": "todo_list",
238-
"description": "A tool for creating a TODO list and keeping track of tasks. This tool should be requested EVERY time the user gives you a task that will take multiple steps. A TODO list should be made BEFORE executing any steps. Steps should be marked off AS YOU COMPLETE THEM. DO NOT display your own todo list AT ANY POINT; this is done for you.",
238+
"description": "A tool for creating a TODO list and keeping track of tasks. This tool should be requested EVERY time the user gives you a task that will take multiple steps. A TODO list should be made BEFORE executing any steps. Steps should be marked off AS YOU COMPLETE THEM. DO NOT display your own tasks or todo list AT ANY POINT; this is done for you. Complete the tasks in the same order that you provide them.",
239239
"input_schema": {
240240
"type": "object",
241241
"properties": {
@@ -251,21 +251,28 @@
251251
"type": "string"
252252
}
253253
},
254+
"task_description": {
255+
"description": "Required paramter of `create` command containing a BRIEF summary of the given task. The summary should be detailed enough to refer to without knowing the problem context beforehand.",
256+
"type": "string"
257+
},
254258
"completed_indices": {
255-
"description": "Required parameter of `complete` command containing the 0-INDEXED numbers of EVERY completed task. Each task should be marked as completed IMMEDIATELY after it is finished. DO NOT display your own version of a TODO list.",
259+
"description": "Required parameter of `complete` command containing the 0-INDEXED numbers of EVERY completed task. Each task should be marked as completed IMMEDIATELY after it is finished. DO NOT mark tasks as completed if you skip them.",
256260
"type": "array",
257261
"items": {
258262
"type": "integer"
259263
}
260264
},
261-
"task_description": {
262-
"description": "Required paramter of `create` command containing a BRIEF summary of the given task. The summary should be detailed enough to refer to without knowing the problem context beforehand.",
263-
"type": "string"
264-
},
265265
"context_update": {
266-
"description": "Required parameter of `complete` command containing important task context. Use this command to track important information about the task and its current status.",
266+
"description": "Required parameter of `complete` command containing important task context. Use this command to track important information about the task AND information about files you have read.",
267267
"type": "string"
268268
},
269+
"modified_files": {
270+
"description": "Optional parameter of `complete` command containing a list of paths of files that were modified during the task. This is useful for tracking file changes that are important to the task.",
271+
"type": "array",
272+
"items": {
273+
"type": "string"
274+
}
275+
},
269276
"path": {
270277
"description": "Required parameter of `load` command containing path of todo list to load"
271278
}

0 commit comments

Comments
 (0)