todo list formatting
This commit is contained in:
@@ -10,6 +10,7 @@ pub struct ConsoleUiWriter {
|
|||||||
current_tool_args: Mutex<Vec<(String, String)>>,
|
current_tool_args: Mutex<Vec<(String, String)>>,
|
||||||
current_output_line: Mutex<Option<String>>,
|
current_output_line: Mutex<Option<String>>,
|
||||||
output_line_printed: Mutex<bool>,
|
output_line_printed: Mutex<bool>,
|
||||||
|
in_todo_tool: Mutex<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConsoleUiWriter {
|
impl ConsoleUiWriter {
|
||||||
@@ -19,6 +20,60 @@ impl ConsoleUiWriter {
|
|||||||
current_tool_args: Mutex::new(Vec::new()),
|
current_tool_args: Mutex::new(Vec::new()),
|
||||||
current_output_line: Mutex::new(None),
|
current_output_line: Mutex::new(None),
|
||||||
output_line_printed: Mutex::new(false),
|
output_line_printed: Mutex::new(false),
|
||||||
|
in_todo_tool: Mutex::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_todo_line(&self, line: &str) {
|
||||||
|
// Transform and print todo list lines elegantly
|
||||||
|
let trimmed = line.trim();
|
||||||
|
|
||||||
|
// Skip the "📝 TODO list:" prefix line
|
||||||
|
if trimmed.starts_with("📝 TODO list:") || trimmed == "📝 TODO list is empty" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle empty lines
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
println!();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect indentation level
|
||||||
|
let indent_count = line.chars().take_while(|c| c.is_whitespace()).count();
|
||||||
|
let indent = " ".repeat(indent_count / 2); // Convert spaces to visual indent
|
||||||
|
|
||||||
|
// Format based on line type
|
||||||
|
if trimmed.starts_with("- [ ]") {
|
||||||
|
// Incomplete task
|
||||||
|
let task = trimmed.strip_prefix("- [ ]").unwrap_or(trimmed).trim();
|
||||||
|
println!("{}☐ {}", indent, task);
|
||||||
|
} else if trimmed.starts_with("- [x]") || trimmed.starts_with("- [X]") {
|
||||||
|
// Completed task
|
||||||
|
let task = trimmed.strip_prefix("- [x]")
|
||||||
|
.or_else(|| trimmed.strip_prefix("- [X]"))
|
||||||
|
.unwrap_or(trimmed)
|
||||||
|
.trim();
|
||||||
|
println!("{}\x1b[2m☑ {}\x1b[0m", indent, task);
|
||||||
|
} else if trimmed.starts_with("- ") {
|
||||||
|
// Regular bullet point
|
||||||
|
let item = trimmed.strip_prefix("- ").unwrap_or(trimmed).trim();
|
||||||
|
println!("{}• {}", indent, item);
|
||||||
|
} else if trimmed.starts_with("# ") {
|
||||||
|
// Heading
|
||||||
|
let heading = trimmed.strip_prefix("# ").unwrap_or(trimmed).trim();
|
||||||
|
println!("\n\x1b[1m{}\x1b[0m", heading);
|
||||||
|
} else if trimmed.starts_with("## ") {
|
||||||
|
// Subheading
|
||||||
|
let subheading = trimmed.strip_prefix("## ").unwrap_or(trimmed).trim();
|
||||||
|
println!("\n\x1b[1m{}\x1b[0m", subheading);
|
||||||
|
} else if trimmed.starts_with("**") && trimmed.ends_with("**") {
|
||||||
|
// Bold text (section marker)
|
||||||
|
let text = trimmed.trim_start_matches("**").trim_end_matches("**");
|
||||||
|
println!("{}\x1b[1m{}\x1b[0m", indent, text);
|
||||||
|
} else {
|
||||||
|
// Regular text or note
|
||||||
|
println!("{}{}", indent, trimmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,6 +108,15 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
// Store the tool name and clear args for collection
|
// Store the tool name and clear args for collection
|
||||||
*self.current_tool_name.lock().unwrap() = Some(tool_name.to_string());
|
*self.current_tool_name.lock().unwrap() = Some(tool_name.to_string());
|
||||||
self.current_tool_args.lock().unwrap().clear();
|
self.current_tool_args.lock().unwrap().clear();
|
||||||
|
|
||||||
|
// Check if this is a todo tool call
|
||||||
|
let is_todo = tool_name == "todo_read" || tool_name == "todo_write";
|
||||||
|
*self.in_todo_tool.lock().unwrap() = is_todo;
|
||||||
|
|
||||||
|
// For todo tools, we'll skip the normal header and print a custom one later
|
||||||
|
if is_todo {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_arg(&self, key: &str, value: &str) {
|
fn print_tool_arg(&self, key: &str, value: &str) {
|
||||||
@@ -75,6 +139,12 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_output_header(&self) {
|
fn print_tool_output_header(&self) {
|
||||||
|
// Skip normal header for todo tools
|
||||||
|
if *self.in_todo_tool.lock().unwrap() {
|
||||||
|
println!(); // Just add a newline
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
// Now print the tool header with the most important arg in bold green
|
// Now print the tool header with the most important arg in bold green
|
||||||
if let Some(tool_name) = self.current_tool_name.lock().unwrap().as_ref() {
|
if let Some(tool_name) = self.current_tool_name.lock().unwrap().as_ref() {
|
||||||
@@ -144,10 +214,21 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_output_line(&self, line: &str) {
|
fn print_tool_output_line(&self, line: &str) {
|
||||||
|
// Special handling for todo tools
|
||||||
|
if *self.in_todo_tool.lock().unwrap() {
|
||||||
|
self.print_todo_line(line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
println!("│ \x1b[2m{}\x1b[0m", line);
|
println!("│ \x1b[2m{}\x1b[0m", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_output_summary(&self, count: usize) {
|
fn print_tool_output_summary(&self, count: usize) {
|
||||||
|
// Skip for todo tools
|
||||||
|
if *self.in_todo_tool.lock().unwrap() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"│ \x1b[2m({} line{})\x1b[0m",
|
"│ \x1b[2m({} line{})\x1b[0m",
|
||||||
count,
|
count,
|
||||||
@@ -156,6 +237,13 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_timing(&self, duration_str: &str) {
|
fn print_tool_timing(&self, duration_str: &str) {
|
||||||
|
// For todo tools, just print a simple completion message
|
||||||
|
if *self.in_todo_tool.lock().unwrap() {
|
||||||
|
println!();
|
||||||
|
*self.in_todo_tool.lock().unwrap() = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the duration string to determine color
|
// Parse the duration string to determine color
|
||||||
// Format is like "1.5s", "500ms", "2m 30.0s"
|
// Format is like "1.5s", "500ms", "2m 30.0s"
|
||||||
let color_code = if duration_str.ends_with("ms") {
|
let color_code = if duration_str.ends_with("ms") {
|
||||||
|
|||||||
@@ -776,27 +776,6 @@ impl<W: UiWriter> Agent<W> {
|
|||||||
// For native tool calling providers, use a more explicit system prompt
|
// For native tool calling providers, use a more explicit system prompt
|
||||||
"You are G3, an AI programming agent of the same skill level as a seasoned engineer at a major technology company. You analyze given tasks and write code to achieve goals.
|
"You are G3, an AI programming agent of the same skill level as a seasoned engineer at a major technology company. You analyze given tasks and write code to achieve goals.
|
||||||
|
|
||||||
# Task Management
|
|
||||||
|
|
||||||
Use todo_read and todo_write for tasks with 3+ steps, multiple files/components, or uncertain scope.
|
|
||||||
|
|
||||||
Workflow:
|
|
||||||
- Start: read → write checklist
|
|
||||||
- During: read → update progress
|
|
||||||
- End: verify all complete
|
|
||||||
|
|
||||||
Warning: todo_write overwrites entirely; always todo_read first (skipping is an error)
|
|
||||||
|
|
||||||
Keep items short, specific, action-oriented. Not using the todo tools for complex tasks is an error.
|
|
||||||
|
|
||||||
Template:
|
|
||||||
- [ ] Implement feature X
|
|
||||||
- [ ] Update API
|
|
||||||
- [ ] Write tests
|
|
||||||
- [ ] Run tests
|
|
||||||
- [ ] Run lint
|
|
||||||
- [ ] Blocked: waiting on credentials
|
|
||||||
|
|
||||||
You have access to tools. When you need to accomplish a task, you MUST use the appropriate tool. Do not just describe what you would do - actually use the tools.
|
You have access to tools. When you need to accomplish a task, you MUST use the appropriate tool. Do not just describe what you would do - actually use the tools.
|
||||||
|
|
||||||
IMPORTANT: You must call tools to achieve goals. When you receive a request:
|
IMPORTANT: You must call tools to achieve goals. When you receive a request:
|
||||||
@@ -815,18 +794,9 @@ When taking screenshots of specific windows (like \"my Safari window\" or \"my t
|
|||||||
|
|
||||||
Do not explain what you're going to do - just do it by calling the tools.
|
Do not explain what you're going to do - just do it by calling the tools.
|
||||||
|
|
||||||
# Response Guidelines
|
|
||||||
|
|
||||||
- Use Markdown formatting for all responses except tool calls.
|
|
||||||
- Whenever taking actions, use the pronoun 'I'
|
|
||||||
".to_string()
|
|
||||||
} else {
|
|
||||||
// For non-native providers (embedded models), use JSON format instructions
|
|
||||||
"You are G3, a general-purpose AI agent. Your goal is to analyze and solve problems by writing code.
|
|
||||||
|
|
||||||
# Task Management
|
# Task Management
|
||||||
|
|
||||||
Use todo_read and todo_write for tasks with 3+ steps, multiple files/components, or uncertain scope.
|
Use todo_read and todo_write for tasks with 2+ steps, multiple files/components, or uncertain scope.
|
||||||
|
|
||||||
Workflow:
|
Workflow:
|
||||||
- Start: read → write checklist
|
- Start: read → write checklist
|
||||||
@@ -841,6 +811,21 @@ Template:
|
|||||||
- [ ] Implement feature X
|
- [ ] Implement feature X
|
||||||
- [ ] Update API
|
- [ ] Update API
|
||||||
- [ ] Write tests
|
- [ ] Write tests
|
||||||
|
- [ ] Run tests
|
||||||
|
- [ ] Run lint
|
||||||
|
- [ ] Blocked: waiting on credentials
|
||||||
|
|
||||||
|
|
||||||
|
# Response Guidelines
|
||||||
|
|
||||||
|
- Use Markdown formatting for all responses except tool calls.
|
||||||
|
- Whenever taking actions, use the pronoun 'I'
|
||||||
|
".to_string()
|
||||||
|
} else {
|
||||||
|
// For non-native providers (embedded models), use JSON format instructions
|
||||||
|
"You are G3, a general-purpose AI agent. Your goal is to analyze and solve problems by writing code.
|
||||||
|
|
||||||
|
You have access to tools. When you need to accomplish a task, you MUST use the appropriate tool. Do not just describe what you would do - actually use the tools.
|
||||||
|
|
||||||
# Tool Call Format
|
# Tool Call Format
|
||||||
|
|
||||||
@@ -887,6 +872,24 @@ The tool will execute immediately and you'll receive the result (success or erro
|
|||||||
3. STOP when the original request was satisfied
|
3. STOP when the original request was satisfied
|
||||||
4. Call the final_output tool when done
|
4. Call the final_output tool when done
|
||||||
|
|
||||||
|
# Task Management
|
||||||
|
|
||||||
|
Use todo_read and todo_write for tasks with 3+ steps, multiple files/components, or uncertain scope.
|
||||||
|
|
||||||
|
Workflow:
|
||||||
|
- Start: read → write checklist
|
||||||
|
- During: read → update progress
|
||||||
|
- End: verify all complete
|
||||||
|
|
||||||
|
Warning: todo_write overwrites entirely; always todo_read first (skipping is an error)
|
||||||
|
|
||||||
|
Keep items short, specific, action-oriented. Not using the todo tools for complex tasks is an error.
|
||||||
|
|
||||||
|
Template:
|
||||||
|
- [ ] Implement feature X
|
||||||
|
- [ ] Update API
|
||||||
|
- [ ] Write tests
|
||||||
|
|
||||||
# Response Guidelines
|
# Response Guidelines
|
||||||
|
|
||||||
- Use Markdown formatting for all responses except tool calls.
|
- Use Markdown formatting for all responses except tool calls.
|
||||||
@@ -1814,13 +1817,20 @@ The tool will execute immediately and you'll receive the result (success or erro
|
|||||||
const MAX_LINE_WIDTH: usize = 80;
|
const MAX_LINE_WIDTH: usize = 80;
|
||||||
let output_len = output_lines.len();
|
let output_len = output_lines.len();
|
||||||
|
|
||||||
for line in output_lines {
|
// For todo tools, show all lines without truncation
|
||||||
|
let is_todo_tool = tool_call.tool == "todo_read" || tool_call.tool == "todo_write";
|
||||||
|
let max_lines_to_show = if is_todo_tool { output_len } else { MAX_LINES };
|
||||||
|
|
||||||
|
for (idx, line) in output_lines.iter().enumerate() {
|
||||||
|
if !is_todo_tool && idx >= max_lines_to_show {
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Clip line to max width
|
// Clip line to max width
|
||||||
let clipped_line = truncate_line(line, MAX_LINE_WIDTH);
|
let clipped_line = truncate_line(line, MAX_LINE_WIDTH);
|
||||||
self.ui_writer.update_tool_output_line(&clipped_line);
|
self.ui_writer.update_tool_output_line(&clipped_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if output_len > MAX_LINES {
|
if !is_todo_tool && output_len > MAX_LINES {
|
||||||
self.ui_writer.print_tool_output_summary(output_len);
|
self.ui_writer.print_tool_output_summary(output_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user