Add todo mode and replace the plan with TODO.md

This commit is contained in:
Ian Gulliver
2026-10-15 07:23:17 -07:00
parent 60a1d221f4
commit 1f44bc6d91
25 changed files with 1259 additions and 637 deletions
+63
View File
@@ -2,6 +2,7 @@ package agents_test
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
@@ -873,6 +874,68 @@ func TestCreateTaskTool(t *testing.T) {
}
}
func TestStartTodo(t *testing.T) {
t.Parallel()
e := newEnv(t)
m := e.manager()
writeTestFile(t, filepath.Join(e.repo, "TODO.md"), "# Todo\n\n- Create hello.txt\n It holds the single line `hi`.\n- Leave this one alone\n")
gitOut(t, e.repo, "add", "TODO.md")
gitOut(t, e.repo, "commit", "--quiet", "--message", "add todo")
_, err := m.StartTodo(e.ctx, e.project, e.user, "No such item", testModel)
if !errors.Is(err, store.ErrNotFound) {
t.Fatalf("start unknown item: %v", err)
}
task, err := m.StartTodo(e.ctx, e.project, e.user, "Create hello.txt", testModel)
if err != nil {
t.Fatalf("start todo: %v", err)
}
if task.TodoItem == nil || *task.TodoItem != "Create hello.txt" || task.Title != "Create hello.txt" {
t.Fatalf("todo task %+v", task)
}
_, err = m.StartTodo(e.ctx, e.project, e.user, "Create hello.txt", testModel)
if !errors.Is(err, agents.ErrConflict) {
t.Fatalf("second start of the same item: %v", err)
}
events := e.waitFor("todo turn end", func(ev api.Event) bool {
return ev.Kind == "turn.ended" && ev.TaskId != nil && *ev.TaskId == task.Id
})
for _, ev := range events {
if ev.Kind == "user.message" && ev.TaskId != nil && *ev.TaskId == task.Id {
text, _ := ev.Payload["text"].(string)
if !strings.Contains(text, "- Create hello.txt\n It holds the single line `hi`.") || !strings.Contains(text, "remove this item from TODO.md") {
t.Fatalf("first prompt %q", text)
}
}
}
stored, err := e.store.GetTask(e.ctx, task.Id)
if err != nil || stored.TodoItem == nil || *stored.TodoItem != "Create hello.txt" {
t.Fatalf("stored task %+v %v", stored, err)
}
todoAfter, err := os.ReadFile(filepath.Join(task.WorktreePath, "TODO.md"))
if err != nil {
t.Fatalf("read worktree TODO.md: %v", err)
}
t.Logf("TODO.md after the turn:\n%s", todoAfter)
if strings.Contains(string(todoAfter), "Create hello.txt") || !strings.Contains(string(todoAfter), "Leave this one alone") {
t.Fatalf("agent didn't remove exactly its item from TODO.md")
}
}
func writeTestFile(t *testing.T, path, content string) {
t.Helper()
err := os.WriteFile(path, []byte(content), 0o644)
if err != nil {
t.Fatalf("write %s: %v", path, err)
}
}
func TestQuestionReachesInbox(t *testing.T) {
t.Parallel()
e := newEnv(t)