feat: add 'todofinish' tool to mark tasks as completed in the todo list; update system prompts for task execution

This commit is contained in:
asepharyana
2026-07-12 13:52:00 +07:00
parent abc7a58e31
commit 48d2dc3ad6
5 changed files with 93 additions and 6 deletions
+1 -1
View File
@@ -13,6 +13,6 @@ Core principles:
9. After making changes, verify they work by running builds or tests.
14. TASK MANAGEMENT: Every time the user gives a command, you MUST immediately use the `todowrite` tool to record it as a task.
15. RELENTLESS EXECUTION: Once a task is recorded, you MUST execute it until it is 100% finished. Do not stop calling tools and do not finish your turn prematurely. If you encounter errors, fix them and continue relentlessly until the goal is achieved.
15. RELENTLESS EXECUTION: Once a task is recorded, you MUST execute it until it is 100% finished. When a task is fully complete, use the `todofinish` tool to mark it as done in your todo list. Do not stop calling tools and do not finish your turn prematurely. If you encounter errors, fix them and continue relentlessly until the goal is achieved.
Available tools are described in the system-tools.txt section. Use them judiciously — prefer the simplest tool that accomplishes the task.
+9 -5
View File
@@ -10,7 +10,7 @@ Core tools:
- grep(pattern, path?) — Search for a pattern in files.
- glob(pattern) — List files matching a glob pattern.
- write(path, content, reason) — Write content to a file. Reason is required.
- edit(path, old, new, reason) — Replace text in a file. Reason is required.
- edit(path, old, new, replace_all?, reason) — Replace text in a file. Reason is required.
- delete(path) — Delete a file or empty directory.
- bash(command) — Run a shell command. Use for builds, tests, git ops.
- bash_output(job_id) — Poll output of a background bash job.
@@ -18,6 +18,7 @@ Core tools:
- cd(path) — Change working directory.
- dir_list(path) — List directory contents.
- dir_cache_update() — Refresh the directory cache.
- pong(message?) — Simple connectivity check. Echoes back the message.
Git tools:
- git_operator(args, confirm_destructive?) — Run git commands. Some destructive
@@ -27,17 +28,20 @@ Git tools:
Memory & Planning:
- remember(text, type?) — Save to memory (type: lesson | reference | feedback).
- recall(query) — Search memory for relevant entries.
- remember(name, description, content, kind) — Save to memory (kind: project | reference | lesson | feedback).
- recall(name?) — Read a specific memory entry, or list all if name is omitted.
- forget(name) — Remove a memory entry.
- plan_enter() — Enter plan mode (for planning before changes).
- plan_ready() — Mark plan as ready for execution.
- plan_enter(plan, sign_off) — Enter plan mode (provide a step-by-step plan and sign-off message).
- plan_ready(confirmation) — Signal that you are ready to execute the approved plan.
- seqthink(thought) — Record a chain-of-thought step.
- todowrite(task) — Append a task to the session todo list.
- todofinish(task_index?) — Mark a task (or all if omitted) as finished in todo.md.
Workflow:
- workflow_run(script, args) — Fan out work to sub-agents. Use for complex
multi-step tasks needing parallel analysis or verification. Pass inline
scripts with agent(), parallel(), and pipeline() primitives.
- note_finding(text) — Share a finding with sibling agents in the same workflow run.
Language Server Protocol (LSP) tools:
- lsp_connect(name, command, args?, language_id) — Start an LSP server for a
+1
View File
@@ -158,6 +158,7 @@ pub fn all_tools() -> Vec<Box<dyn Tool>> {
Box::new(super::tool::utility::dir_cache_update::DirCacheUpdate),
Box::new(super::tool::utility::pong::Pong),
Box::new(super::tool::utility::todowrite::Todowrite),
Box::new(super::tool::utility::todofinish::Todofinish),
Box::new(super::tool::lsp::LspConnect),
Box::new(super::tool::lsp::LspDiagnostics),
Box::new(super::tool::lsp::LspHover),
+1
View File
@@ -5,3 +5,4 @@ pub mod dir_cache_update;
pub mod dir_list;
pub mod pong;
pub mod todowrite;
pub mod todofinish;
+81
View File
@@ -0,0 +1,81 @@
//! Tool for marking tasks as finished in the session's todo list.
use serde_json::{json, Value};
use anyhow::{Result, anyhow};
use std::path::PathBuf;
use super::super::{Tool, ToolCtx};
/// Tool that marks tasks as finished in the session's todo.md.
pub struct Todofinish;
impl Tool for Todofinish {
fn name(&self) -> &'static str {
"todofinish"
}
fn description(&self) -> &'static str {
"Mark tasks as finished in the session todo list (todo.md). You can mark all tasks as finished by leaving the 'task_index' empty, or specify a 1-based index to finish a specific task."
}
fn parameters(&self) -> Value {
json!({
"type": "object",
"properties": {
"task_index": {
"type": "integer",
"description": "Optional 1-based index of the task to mark as finished. If omitted, ALL unfinished tasks will be marked as finished."
}
}
})
}
fn run(&self, ctx: &ToolCtx, args: &Value) -> Result<String> {
let path: PathBuf = ctx.session_dir.join("todo.md");
if !path.exists() {
return Ok("No todo.md found in session directory. Nothing to finish.".to_string());
}
let content = std::fs::read_to_string(&path)
.map_err(|e| anyhow!("failed to read todo.md: {}", e))?;
let task_index = args.get("task_index").and_then(|v| v.as_i64());
let mut new_content = String::new();
let mut task_count = 0;
let mut modified = false;
for line in content.lines() {
if line.trim_start().starts_with("- [ ]") {
task_count += 1;
if let Some(target) = task_index {
if task_count == target {
new_content.push_str(&line.replacen("- [ ]", "- [x]", 1));
modified = true;
} else {
new_content.push_str(line);
}
} else {
// Mark all as finished
new_content.push_str(&line.replacen("- [ ]", "- [x]", 1));
modified = true;
}
} else {
new_content.push_str(line);
}
new_content.push('\n');
}
if !modified {
return Ok("No unfinished tasks found or index out of bounds.".to_string());
}
std::fs::write(&path, new_content)
.map_err(|e| anyhow!("failed to write to todo.md: {}", e))?;
if let Some(idx) = task_index {
Ok(format!("Successfully marked task {} as finished.", idx))
} else {
Ok("Successfully marked ALL tasks as finished.".to_string())
}
}
}