44 "context"
55 "encoding/json"
66 "fmt"
7+ "strings"
78 "sync"
89 "sync/atomic"
910
@@ -60,10 +61,12 @@ type CreateTodosOutput struct {
6061type UpdateTodosOutput struct {
6162 Updated []TodoUpdate `json:"updated,omitempty" jsonschema:"List of successfully updated todos"`
6263 NotFound []string `json:"not_found,omitempty" jsonschema:"IDs of todos that were not found"`
64+ Reminder string `json:"reminder,omitempty" jsonschema:"Reminder about incomplete todos that still need to be completed"`
6365}
6466
6567type ListTodosOutput struct {
66- Todos []Todo `json:"todos" jsonschema:"List of all current todo items"`
68+ Todos []Todo `json:"todos" jsonschema:"List of all current todo items"`
69+ Reminder string `json:"reminder,omitempty" jsonschema:"Reminder about incomplete todos that still need to be completed"`
6770}
6871
6972// TodoStorage defines the storage layer for todo items.
@@ -157,17 +160,20 @@ func (t *TodoTool) Instructions() string {
157160IMPORTANT: You MUST use these tools to track the progress of your tasks:
158161
1591621. Before starting any complex task:
160- - Create a todo for each major step using create_todo
163+ - Create a todo for each major step using create_todos (prefer batch creation)
161164 - Break down complex steps into smaller todos
162165
1631662. While working:
167+ - Update todo status to "in-progress" BEFORE starting each task
168+ - Mark todos as "completed" IMMEDIATELY after finishing each task
164169 - Use list_todos frequently to keep track of remaining work
165- - Mark todos as "completed" when finished
166170
167- 3. Task Management Rules:
168- - Never start a new task without creating a todo for it
169- - Always check list_todos before responding to ensure no steps are missed
170- - Update todo status to reflect current progress
171+ 3. Task Completion Rules:
172+ - EVERY todo you create MUST eventually be marked "completed"
173+ - Before sending your final response, call list_todos to verify ALL todos are completed
174+ - If any todos remain pending or in-progress, complete them or mark them completed before responding
175+ - Never leave todos in a pending or in-progress state when you are done working
176+ - When updating multiple todos, batch them in a single update_todos call
171177
172178This toolset is REQUIRED for maintaining task state and ensuring all steps are completed.`
173179}
@@ -235,6 +241,8 @@ func (h *todoHandler) updateTodos(_ context.Context, params UpdateTodosArgs) (*t
235241
236242 if h .allCompleted () {
237243 h .storage .Clear ()
244+ } else {
245+ result .Reminder = h .incompleteReminder ()
238246 }
239247
240248 return h .jsonResult (result )
@@ -253,12 +261,42 @@ func (h *todoHandler) allCompleted() bool {
253261 return true
254262}
255263
264+ // incompleteReminder returns a reminder string listing any non-completed todos,
265+ // or an empty string if all are completed (or storage is empty).
266+ func (h * todoHandler ) incompleteReminder () string {
267+ all := h .storage .All ()
268+ var pending , inProgress []string
269+ for _ , todo := range all {
270+ switch todo .Status {
271+ case "pending" :
272+ pending = append (pending , fmt .Sprintf ("[%s] %s" , todo .ID , todo .Description ))
273+ case "in-progress" :
274+ inProgress = append (inProgress , fmt .Sprintf ("[%s] %s" , todo .ID , todo .Description ))
275+ }
276+ }
277+ if len (pending ) == 0 && len (inProgress ) == 0 {
278+ return ""
279+ }
280+
281+ var b strings.Builder
282+ b .WriteString ("The following todos are still incomplete and MUST be completed:" )
283+ for _ , s := range inProgress {
284+ b .WriteString (" (in-progress) " + s )
285+ }
286+ for _ , s := range pending {
287+ b .WriteString (" (pending) " + s )
288+ }
289+ return b .String ()
290+ }
291+
256292func (h * todoHandler ) listTodos (_ context.Context , _ tools.ToolCall ) (* tools.ToolCallResult , error ) {
257293 todos := h .storage .All ()
258294 if todos == nil {
259295 todos = []Todo {}
260296 }
261- return h .jsonResult (ListTodosOutput {Todos : todos })
297+ out := ListTodosOutput {Todos : todos }
298+ out .Reminder = h .incompleteReminder ()
299+ return h .jsonResult (out )
262300}
263301
264302func (t * TodoTool ) Tools (context.Context ) ([]tools.Tool , error ) {
0 commit comments