todo-agent 0.2.9__py3-none-any.whl → 0.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,26 +6,28 @@ AVAILABLE TOOLS:
6
6
  Discovery Tools (Call FIRST):
7
7
  - list_projects() - Get all available projects from todo.txt
8
8
  - list_contexts() - Get all available contexts from todo.txt
9
- - list_tasks(filter?) - List current tasks with optional filtering
10
- - list_completed_tasks(filter?, project?, context?, text_search?, date_from?, date_to?) - List completed tasks with optional filtering
9
+ - list_tasks() - List all current tasks from todo.txt
10
+ - list_completed_tasks() - List all completed tasks from done.txt
11
11
 
12
12
  Task Management Tools:
13
- - add_task(description, priority?, project?, context?, due?, recurring?) - Add new task to todo.txt
13
+ - add_task(description, priority?, project?, context?, due?, duration?) - Add new task to todo.txt
14
14
  - complete_task(task_number) - Mark task as complete by line number
15
15
  - replace_task(task_number, new_description) - Replace entire task content
16
16
  - append_to_task(task_number, text) - Add text to end of existing task
17
17
  - prepend_to_task(task_number, text) - Add text to beginning of existing task
18
18
  - delete_task(task_number, term?) - Delete entire task or remove specific term
19
+ - created_completed_task(description, completion_date?, project?, context?) - Create task and immediately mark as completed
19
20
 
20
21
  Priority Management Tools:
21
22
  - set_priority(task_number, priority) - Set or change task priority (A-Z)
22
23
  - remove_priority(task_number) - Remove priority from task
24
+
25
+ Task Modification Tools:
23
26
  - set_due_date(task_number, due_date) - Set or update due date for a task by intelligently rewriting it (use empty string to remove due date)
24
27
  - set_context(task_number, context) - Set or update context for a task by intelligently rewriting it (use empty string to remove context)
25
28
  - set_project(task_number, projects) - Set or update projects for a task by intelligently rewriting it (handles array of projects with add/remove operations)
26
29
 
27
30
  Utility Tools:
28
- - get_overview() - Show task statistics and summary
29
31
  - move_task(task_number, destination, source?) - Move task between files
30
32
  - archive_tasks() - Archive completed tasks from todo.txt to done.txt
31
33
  - get_calendar(month, year) - Get calendar for specific month and year
@@ -68,6 +70,7 @@ class ToolCallHandler:
68
70
  ),
69
71
  "parameters": {"type": "object", "properties": {}, "required": []},
70
72
  },
73
+ "progress_description": "📁 Discovering available projects...",
71
74
  },
72
75
  {
73
76
  "type": "function",
@@ -83,132 +86,67 @@ class ToolCallHandler:
83
86
  ),
84
87
  "parameters": {"type": "object", "properties": {}, "required": []},
85
88
  },
89
+ "progress_description": "📍 Finding available contexts...",
86
90
  },
87
91
  {
88
92
  "type": "function",
89
93
  "function": {
90
94
  "name": "list_tasks",
91
95
  "description": (
92
- "List current tasks with optional filtering. Use this when: "
96
+ "List all current tasks from todo.txt. Use this when: "
93
97
  "1) User wants to see their tasks, "
94
- "2) You need to find a specific task by description, "
95
- "3) You need to check for potential duplicates before adding new tasks, "
96
- "4) You need to understand the current state before making changes, "
97
- "5) User says they finished/completed a task and you need to find the matching task. "
98
+ "2) You need to check for potential duplicates before adding new tasks, "
99
+ "3) You need to understand the current state before making changes, "
100
+ "4) User says they finished/completed a task and you need to find the matching task. "
98
101
  "CRITICAL: ALWAYS use this before add_task() to check for similar existing tasks. "
99
102
  "CRITICAL: ALWAYS use this when user mentions task completion to find the correct task number. "
100
- "COMPLETION INTELLIGENCE: When searching for completion matches, if exactly one task clearly "
101
- "matches the user's description, proceed to complete it immediately without asking for confirmation. "
102
- "IMPORTANT: When presenting the results to the user, convert the raw todo.txt format "
103
- "into conversational language. Do not show the raw format like '(A) task +project @context'. "
104
103
  "STRATEGIC CONTEXT: This is the primary discovery tool - call this FIRST when you need to "
105
- "understand existing tasks before making any modifications."
104
+ "understand existing tasks before making any modifications. Always get the complete task list "
105
+ "for full context rather than trying to filter."
106
106
  ),
107
- "parameters": {
108
- "type": "object",
109
- "properties": {
110
- "filter": {
111
- "type": "string",
112
- "description": (
113
- "Optional filter string (e.g., '+work', '@office', '(A)') - "
114
- "use when you want to see only specific tasks or when searching for completion matches"
115
- ),
116
- }
117
- },
118
- "required": [],
119
- },
107
+ "parameters": {"type": "object", "properties": {}, "required": []},
120
108
  },
109
+ "progress_description": "📋 Scanning your task list...",
121
110
  },
122
111
  {
123
112
  "type": "function",
124
113
  "function": {
125
114
  "name": "list_completed_tasks",
126
115
  "description": (
127
- "List completed tasks from done.txt with optional filtering. Use this when: "
116
+ "List all completed tasks from done.txt. Use this when: "
128
117
  "1) User tries to complete a task that might already be done, "
129
118
  "2) User asks about completed tasks, "
130
119
  "3) You need to verify task status before taking action, "
131
- "4) User wants to search for specific completed tasks by project, context, text, or date. "
120
+ "4) User wants to see their task completion history. "
132
121
  "STRATEGIC CONTEXT: Call this BEFORE complete_task() to verify the task hasn't already "
133
122
  "been completed, preventing duplicate completion attempts. "
134
- "FILTERING: Use the filtering parameters to help users find specific completed tasks "
135
- "when they ask about work tasks, home tasks, tasks from a specific date, etc. "
136
- "DATE FILTERING LIMITATIONS: Due to todo.sh constraints, date filtering has specific behavior: "
137
- "• When both date_from and date_to are provided, filtering uses the year-month pattern (YYYY-MM) "
138
- "from date_from, matching all tasks in that month. "
139
- "• When only date_from is provided, filtering uses the exact date pattern (YYYY-MM-DD). "
140
- "• When only date_to is provided, filtering uses the year-month pattern (YYYY-MM) from date_to. "
141
- "• Complex date ranges (e.g., spanning multiple months) are not supported by todo.sh."
123
+ "Always get the complete completed task list for full historical context rather than "
124
+ "trying to filter by specific criteria."
142
125
  ),
143
- "parameters": {
144
- "type": "object",
145
- "properties": {
146
- "filter": {
147
- "type": "string",
148
- "description": (
149
- "Optional raw filter string (e.g., '+work', '@office') - "
150
- "use for advanced filtering when other parameters aren't sufficient"
151
- ),
152
- },
153
- "project": {
154
- "type": "string",
155
- "description": (
156
- "Optional project name to filter by (without the + symbol) - "
157
- "e.g., 'work', 'home', 'bills'"
158
- ),
159
- },
160
- "context": {
161
- "type": "string",
162
- "description": (
163
- "Optional context name to filter by (without the @ symbol) - "
164
- "e.g., 'office', 'home', 'phone'"
165
- ),
166
- },
167
- "text_search": {
168
- "type": "string",
169
- "description": (
170
- "Optional text to search for in task descriptions - "
171
- "e.g., 'review', 'call', 'email'"
172
- ),
173
- },
174
- "date_from": {
175
- "type": "string",
176
- "description": (
177
- "Optional start date for filtering (YYYY-MM-DD format) - "
178
- "e.g., '2025-08-01'. When used alone, matches exact date. "
179
- "When used with date_to, uses year-month pattern (YYYY-MM) for month-based filtering."
180
- ),
181
- },
182
- "date_to": {
183
- "type": "string",
184
- "description": (
185
- "Optional end date for filtering (YYYY-MM-DD format) - "
186
- "e.g., '2025-08-31'. When used alone, uses year-month pattern (YYYY-MM) "
187
- "for month-based filtering. When used with date_from, uses date_from's year-month pattern."
188
- ),
189
- },
190
- },
191
- "required": [],
192
- },
126
+ "parameters": {"type": "object", "properties": {}, "required": []},
193
127
  },
128
+ "progress_description": "✅ Checking completion history...",
194
129
  },
195
130
  {
196
131
  "type": "function",
197
132
  "function": {
198
133
  "name": "add_task",
199
134
  "description": (
200
- "Add a new task to todo.txt. CRITICAL: Before adding ANY task, you MUST "
201
- "use list_tasks() and list_completed_tasks() to check for potential duplicates. Look for tasks with "
202
- "similar descriptions, keywords, or intent. If you find similar tasks, "
135
+ "Add a NEW task to todo.txt with intelligent automatic inference capabilities. "
136
+ "USE CASE: Call this when user wants to create a NEW task, not when they want to complete, modify, or work with existing tasks. "
137
+ "CRITICAL: Before adding ANY task, you MUST use list_tasks() and list_completed_tasks() to check for potential duplicates. "
138
+ "Look for tasks with similar descriptions, keywords, or intent. If you find similar tasks, "
203
139
  "ask the user if they want to add a new task or modify an existing one. "
204
- "AUTOMATIC INFERENCE: When project, context, or due date is not specified, automatically infer appropriate tags "
205
- "and due dates based on the task content, natural language expressions, task nature, calendar context, and existing patterns. "
206
- "DUE DATE INFERENCE: Use parse_date() tool to convert any temporal expressions to YYYY-MM-DD format. "
207
- "Extract temporal expressions and use common sense to infer appropriate due dates based on task type, "
208
- "work patterns, personal schedules, and existing task due date patterns. Only ask for clarification when genuinely ambiguous. "
209
- "Always provide a complete, natural response to the user. "
210
- "STRATEGIC CONTEXT: This is a modification tool - call this LAST after using "
211
- "discovery tools (list_tasks, list_projects, list_contexts list_completed_tasks) "
140
+ "INTELLIGENT INFERENCE ENGINE: This tool automatically infers missing elements to create complete, actionable tasks: "
141
+ "PROJECT INFERENCE: Automatically detect and add appropriate +project tags based on task keywords, semantic patterns, and existing project usage. "
142
+ "CONTEXT INFERENCE: Automatically infer @context tags from task nature, location requirements, and historical context patterns. "
143
+ "DUE DATE INFERENCE: Use parse_date() tool to convert natural language expressions ('tomorrow', 'next week', 'by Friday') to YYYY-MM-DD format. "
144
+ "Apply strategic timing based on task type, work patterns, personal schedules, and existing due date patterns. "
145
+ "DURATION INFERENCE: Automatically estimate appropriate duration: tags based on task complexity, context, and historical patterns. "
146
+ "PRIORITY INFERENCE: Suggest appropriate priority levels (A-Z) based on urgency, importance, and existing priority patterns. "
147
+ "Only ask for clarification when genuinely ambiguous. Always provide a complete, natural response to the user. "
148
+ "STRATEGIC CONTEXT: This is a CREATION tool - call this LAST after using "
149
+ "discovery tools (list_tasks, list_projects, list_contexts, list_completed_tasks) "
212
150
  "to gather all necessary context and verify no duplicates exist."
213
151
  ),
214
152
  "parameters": {
@@ -234,28 +172,26 @@ class ToolCallHandler:
234
172
  "type": "string",
235
173
  "description": "Optional due date in YYYY-MM-DD format. Use parse_date() tool to convert natural language expressions like 'tomorrow', 'next week', 'by Friday' to YYYY-MM-DD format",
236
174
  },
237
- "recurring": {
175
+ "duration": {
238
176
  "type": "string",
239
- "description": "Optional recurring pattern in rec:frequency[:interval] format (e.g., 'rec:daily', 'rec:weekly:2', 'rec:monthly'). Use for tasks that repeat automatically.",
177
+ "description": "Optional duration estimate in format: minutes (e.g., '30m'), hours (e.g., '2h'), or days (e.g., '1d'). Use for time planning and task prioritization.",
240
178
  },
241
179
  },
242
180
  "required": ["description"],
243
181
  },
244
182
  },
183
+ "progress_description": "➕ Creating new task...",
245
184
  },
246
185
  {
247
186
  "type": "function",
248
187
  "function": {
249
188
  "name": "complete_task",
250
189
  "description": (
251
- "Mark a specific task as complete by its line number. IMPORTANT: "
252
- "When user says they finished/completed a task, FIRST use list_tasks() to find matching tasks, "
253
- "then list_completed_tasks() to verify it's not already done. "
254
- "COMPLETION LOGIC: If user's statement clearly matches exactly one task, complete it immediately. "
255
- "If multiple tasks match, show numbered options and ask for clarification. "
256
- "If the match is ambiguous, ask for confirmation. "
257
- "STRATEGIC CONTEXT: This is a modification tool - call this LAST after using "
258
- "discovery tools (list_tasks, list_completed_tasks) to verify the task exists and status."
190
+ "Mark an existing task as complete by its line number. "
191
+ "USE CASE: Only call this when user explicitly states they have finished/completed a task. "
192
+ "WORKFLOW: 1) Use list_tasks() to find the task to complete, 2) Use list_completed_tasks() to verify it's not already done, 3) Call complete_task() with the task number. "
193
+ "NOT FOR: Adding new tasks, modifying task content, or any other task operations. "
194
+ "This tool ONLY marks existing tasks as complete."
259
195
  ),
260
196
  "parameters": {
261
197
  "type": "object",
@@ -268,14 +204,17 @@ class ToolCallHandler:
268
204
  "required": ["task_number"],
269
205
  },
270
206
  },
207
+ "progress_description": "🎯 Marking task complete...",
271
208
  },
272
209
  {
273
210
  "type": "function",
274
211
  "function": {
275
212
  "name": "replace_task",
276
213
  "description": (
277
- "Replace the entire content of a task. IMPORTANT: Use list_tasks() first "
278
- "to find the correct task number if user doesn't specify it. "
214
+ "Replace the entire content of an EXISTING task. "
215
+ "USE CASE: Call this when user wants to completely rewrite an existing task description. "
216
+ "NOT FOR: Creating new tasks, completing tasks, or adding to tasks. "
217
+ "Use list_tasks() first to find the correct task number if user doesn't specify it. "
279
218
  "If multiple tasks match the description, ask for clarification."
280
219
  ),
281
220
  "parameters": {
@@ -293,18 +232,20 @@ class ToolCallHandler:
293
232
  "required": ["task_number", "new_description"],
294
233
  },
295
234
  },
235
+ "progress_description": "✏️ Updating task description...",
296
236
  },
297
237
  {
298
238
  "type": "function",
299
239
  "function": {
300
240
  "name": "append_to_task",
301
241
  "description": (
302
- "Add text to the end of an existing task. Use this when user wants "
303
- "to add additional information to a task without replacing it entirely. "
242
+ "Add text to the end of an EXISTING task. "
243
+ "USE CASE: Call this when user wants to add additional descriptive text, notes, or comments to an existing task. "
244
+ "NOT FOR: Creating new tasks, completing tasks, or adding project/context/due date tags. "
304
245
  "CRITICAL: DO NOT use this for adding project tags (+project) or context tags (@context) - "
305
246
  "use set_project() or set_context() instead. "
306
247
  "DO NOT use this for adding due dates - use set_due_date() instead. "
307
- "This tool is for adding descriptive text, notes, or comments to tasks."
248
+ "This tool is ONLY for adding descriptive text, notes, or comments to existing tasks."
308
249
  ),
309
250
  "parameters": {
310
251
  "type": "object",
@@ -313,22 +254,25 @@ class ToolCallHandler:
313
254
  "type": "integer",
314
255
  "description": "The line number of the task to modify (required)",
315
256
  },
316
- "text": {
257
+ "text_to_append": {
317
258
  "type": "string",
318
- "description": "The text to append to the task (required)",
259
+ "description": "Text to add to the end of the task (required)",
319
260
  },
320
261
  },
321
- "required": ["task_number", "text"],
262
+ "required": ["task_number", "text_to_append"],
322
263
  },
323
264
  },
265
+ "progress_description": "📝 Adding notes to task...",
324
266
  },
325
267
  {
326
268
  "type": "function",
327
269
  "function": {
328
270
  "name": "prepend_to_task",
329
271
  "description": (
330
- "Add text to the beginning of an existing task. Use this when user "
331
- "wants to add a prefix or modifier to a task."
272
+ "Add text to the beginning of an EXISTING task. "
273
+ "USE CASE: Call this when user wants to add a prefix or modifier to an existing task. "
274
+ "NOT FOR: Creating new tasks, completing tasks, or adding project/context/due date tags. "
275
+ "This tool is ONLY for modifying existing tasks by adding text at the beginning."
332
276
  ),
333
277
  "parameters": {
334
278
  "type": "object",
@@ -345,13 +289,16 @@ class ToolCallHandler:
345
289
  "required": ["task_number", "text"],
346
290
  },
347
291
  },
292
+ "progress_description": "📝 Adding prefix to task...",
348
293
  },
349
294
  {
350
295
  "type": "function",
351
296
  "function": {
352
297
  "name": "delete_task",
353
298
  "description": (
354
- "Delete an entire task or remove a specific term from a task. "
299
+ "Delete an entire EXISTING task or remove a specific term from an EXISTING task. "
300
+ "USE CASE: Call this when user wants to delete a task completely or remove specific text from an existing task. "
301
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
355
302
  "IMPORTANT: Use list_tasks() first to find the correct task number "
356
303
  "if user doesn't specify it."
357
304
  ),
@@ -373,13 +320,16 @@ class ToolCallHandler:
373
320
  "required": ["task_number"],
374
321
  },
375
322
  },
323
+ "progress_description": "🗑️ Deleting task...",
376
324
  },
377
325
  {
378
326
  "type": "function",
379
327
  "function": {
380
328
  "name": "set_priority",
381
329
  "description": (
382
- "Set or change the priority of a task (A-Z, where A is highest). "
330
+ "Set or change the priority of an EXISTING task (A-Z, where A is highest). "
331
+ "USE CASE: Call this when user wants to add, change, or remove priority on an existing task. "
332
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
383
333
  "IMPORTANT: Use list_tasks() first to find the correct task number "
384
334
  "if user doesn't specify it."
385
335
  ),
@@ -398,13 +348,17 @@ class ToolCallHandler:
398
348
  "required": ["task_number", "priority"],
399
349
  },
400
350
  },
351
+ "progress_description": "🏷️ Setting priority...",
401
352
  },
402
353
  {
403
354
  "type": "function",
404
355
  "function": {
405
356
  "name": "remove_priority",
406
357
  "description": (
407
- "Remove the priority from a task. IMPORTANT: Use list_tasks() first "
358
+ "Remove the priority from an EXISTING task. "
359
+ "USE CASE: Call this when user wants to remove priority from an existing task. "
360
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
361
+ "IMPORTANT: Use list_tasks() first "
408
362
  "to find the correct task number if user doesn't specify it."
409
363
  ),
410
364
  "parameters": {
@@ -418,13 +372,16 @@ class ToolCallHandler:
418
372
  "required": ["task_number"],
419
373
  },
420
374
  },
375
+ "progress_description": "🏷️ Removing priority...",
421
376
  },
422
377
  {
423
378
  "type": "function",
424
379
  "function": {
425
380
  "name": "set_due_date",
426
381
  "description": (
427
- "Set or update the due date for a task by intelligently rewriting it. "
382
+ "Set or update the due date for an EXISTING task by intelligently rewriting it. "
383
+ "USE CASE: Call this when user wants to add, change, or remove a due date on an existing task. "
384
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
428
385
  "This preserves all existing task components (priority, projects, contexts, etc.) "
429
386
  "while updating or adding the due date. Use empty string to remove the due date. "
430
387
  "IMPORTANT: Use list_tasks() first "
@@ -447,13 +404,16 @@ class ToolCallHandler:
447
404
  "required": ["task_number", "due_date"],
448
405
  },
449
406
  },
407
+ "progress_description": "📅 Setting due date...",
450
408
  },
451
409
  {
452
410
  "type": "function",
453
411
  "function": {
454
412
  "name": "set_context",
455
413
  "description": (
456
- "Set or update the context for a task by intelligently rewriting it. "
414
+ "Set or update the context for an EXISTING task by intelligently rewriting it. "
415
+ "USE CASE: Call this when user wants to add, change, or remove a context tag on an existing task. "
416
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
457
417
  "This preserves all existing task components (priority, projects, due date, etc.) "
458
418
  "while updating or adding the context. Use empty string to remove the context. "
459
419
  "PREFERRED METHOD: Use this instead of append_to_task() when adding context tags (@context). "
@@ -476,13 +436,16 @@ class ToolCallHandler:
476
436
  "required": ["task_number", "context"],
477
437
  },
478
438
  },
439
+ "progress_description": "📍 Setting context...",
479
440
  },
480
441
  {
481
442
  "type": "function",
482
443
  "function": {
483
444
  "name": "set_project",
484
445
  "description": (
485
- "Set or update projects for a task by intelligently rewriting it. "
446
+ "Set or update projects for an EXISTING task by intelligently rewriting it. "
447
+ "USE CASE: Call this when user wants to add, change, or remove project tags on an existing task. "
448
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
486
449
  "This preserves all existing task components and manages projects intelligently. "
487
450
  "Supports multiple projects, prevents duplicates, and groups them together. "
488
451
  "Empty array or empty strings are NOOPs (no changes). "
@@ -509,24 +472,16 @@ class ToolCallHandler:
509
472
  "required": ["task_number", "projects"],
510
473
  },
511
474
  },
512
- },
513
- {
514
- "type": "function",
515
- "function": {
516
- "name": "get_overview",
517
- "description": (
518
- "Show task statistics and summary. Use this when user asks for "
519
- "an overview, summary, or statistics about their tasks."
520
- ),
521
- "parameters": {"type": "object", "properties": {}, "required": []},
522
- },
475
+ "progress_description": "🏷️ Setting project tags...",
523
476
  },
524
477
  {
525
478
  "type": "function",
526
479
  "function": {
527
480
  "name": "move_task",
528
481
  "description": (
529
- "Move a task from one file to another (e.g., from todo.txt to done.txt). "
482
+ "Move an EXISTING task from one file to another (e.g., from todo.txt to done.txt). "
483
+ "USE CASE: Call this when user wants to move a task between different todo files. "
484
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
530
485
  "IMPORTANT: Use list_tasks() first to find the correct task number "
531
486
  "if user doesn't specify it."
532
487
  ),
@@ -549,6 +504,7 @@ class ToolCallHandler:
549
504
  "required": ["task_number", "destination"],
550
505
  },
551
506
  },
507
+ "progress_description": "📦 Moving task...",
552
508
  },
553
509
  {
554
510
  "type": "function",
@@ -561,6 +517,7 @@ class ToolCallHandler:
561
517
  ),
562
518
  "parameters": {"type": "object", "properties": {}, "required": []},
563
519
  },
520
+ "progress_description": "📦 Archiving completed tasks...",
564
521
  },
565
522
  {
566
523
  "type": "function",
@@ -587,6 +544,7 @@ class ToolCallHandler:
587
544
  "required": ["date_expression"],
588
545
  },
589
546
  },
547
+ "progress_description": "📅 Converting date expression...",
590
548
  },
591
549
  {
592
550
  "type": "function",
@@ -622,6 +580,73 @@ class ToolCallHandler:
622
580
  "required": ["month", "year"],
623
581
  },
624
582
  },
583
+ "progress_description": "📅 Generating calendar...",
584
+ },
585
+ {
586
+ "type": "function",
587
+ "function": {
588
+ "name": "created_completed_task",
589
+ "description": (
590
+ "Create a task and immediately mark it as completed. "
591
+ "USE CASE: Call this when user says they completed something on a specific date (e.g., 'I did the laundry today', 'I finished the report yesterday', 'I cleaned the garage last week') "
592
+ "and you have already researched existing tasks to determine no match exists. "
593
+ "WORKFLOW: 1) Use list_tasks() to search for existing tasks, 2) Use list_completed_tasks() to verify it's not already done, "
594
+ "3) If no match found, call this tool to create and complete the task in one operation. "
595
+ "STRATEGIC CONTEXT: This is a convenience tool for the common pattern of 'I did X on [date]' - "
596
+ "it creates a task with the specified completion date and immediately marks it complete. "
597
+ "The LLM should handle the research and decision-making about whether to use this tool."
598
+ ),
599
+ "parameters": {
600
+ "type": "object",
601
+ "properties": {
602
+ "description": {
603
+ "type": "string",
604
+ "description": "The task description of what was completed (required)",
605
+ },
606
+ "completion_date": {
607
+ "type": "string",
608
+ "description": "Optional completion date in YYYY-MM-DD format (defaults to today)",
609
+ },
610
+ "project": {
611
+ "type": "string",
612
+ "description": "Optional project name (without the + symbol) for new task creation",
613
+ },
614
+ "context": {
615
+ "type": "string",
616
+ "description": "Optional context name (without the @ symbol) for new task creation",
617
+ },
618
+ },
619
+ "required": ["description"],
620
+ },
621
+ },
622
+ "progress_description": "✅ Creating completed task...",
623
+ },
624
+ {
625
+ "type": "function",
626
+ "function": {
627
+ "name": "restore_completed_task",
628
+ "description": (
629
+ "Restore a completed task from done.txt back to todo.txt, making it active again. "
630
+ "USE CASE: Call this when user wants to reactivate a previously completed task. "
631
+ "WORKFLOW: 1) Use list_completed_tasks() to find the completed task to restore, "
632
+ "2) Call restore_completed_task() with the task number from done.txt. "
633
+ "NOT FOR: Creating new tasks, completing tasks, or any other task operations. "
634
+ "This tool ONLY restores existing completed tasks to active status. "
635
+ "IMPORTANT: Use list_completed_tasks() first to find the correct task number "
636
+ "if user doesn't specify it."
637
+ ),
638
+ "parameters": {
639
+ "type": "object",
640
+ "properties": {
641
+ "task_number": {
642
+ "type": "integer",
643
+ "description": "The line number of the completed task in done.txt to restore (required)",
644
+ }
645
+ },
646
+ "required": ["task_number"],
647
+ },
648
+ },
649
+ "progress_description": "🔄 Restoring completed task...",
625
650
  },
626
651
  ]
627
652
 
@@ -778,8 +803,54 @@ class ToolCallHandler:
778
803
 
779
804
  def execute_tool(self, tool_call: Dict[str, Any]) -> Dict[str, Any]:
780
805
  """Execute a tool call and return the result."""
781
- tool_name = tool_call["function"]["name"]
782
- arguments = tool_call["function"]["arguments"]
806
+ # Validate tool call structure
807
+ if not isinstance(tool_call, dict):
808
+ return {
809
+ "tool_call_id": "unknown",
810
+ "name": "unknown",
811
+ "output": "ERROR: Invalid tool call format",
812
+ "error": True,
813
+ "error_type": "malformed_tool_call",
814
+ "error_details": "Tool call is not a dictionary",
815
+ "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation."
816
+ }
817
+
818
+ if "function" not in tool_call:
819
+ return {
820
+ "tool_call_id": tool_call.get("id", "unknown"),
821
+ "name": "unknown",
822
+ "output": "ERROR: Tool call missing function definition",
823
+ "error": True,
824
+ "error_type": "malformed_tool_call",
825
+ "error_details": "Tool call missing function field",
826
+ "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation."
827
+ }
828
+
829
+ function = tool_call["function"]
830
+ if not isinstance(function, dict):
831
+ return {
832
+ "tool_call_id": tool_call.get("id", "unknown"),
833
+ "name": "unknown",
834
+ "output": "ERROR: Function definition is not a dictionary",
835
+ "error": True,
836
+ "error_type": "malformed_tool_call",
837
+ "error_details": "Function field is not a dictionary",
838
+ "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation."
839
+ }
840
+
841
+ tool_name = function.get("name")
842
+ if not tool_name:
843
+ return {
844
+ "tool_call_id": tool_call.get("id", "unknown"),
845
+ "name": "unknown",
846
+ "output": "ERROR: Tool call missing function name",
847
+ "error": True,
848
+ "error_type": "malformed_tool_call",
849
+ "error_details": "Function missing name field",
850
+ "user_message": "I received a malformed request. Please try again, or type 'clear' to reset our conversation."
851
+ }
852
+
853
+ arguments = function.get("arguments", {})
783
854
  tool_call_id = tool_call.get("id", "unknown")
784
855
 
785
856
  # Handle arguments that might be a string (JSON) or already a dict
@@ -826,11 +897,12 @@ class ToolCallHandler:
826
897
  "set_due_date": self.todo_manager.set_due_date,
827
898
  "set_context": self.todo_manager.set_context,
828
899
  "set_project": self.todo_manager.set_project,
829
- "get_overview": self.todo_manager.get_overview,
830
900
  "move_task": self.todo_manager.move_task,
831
901
  "archive_tasks": self.todo_manager.archive_tasks,
832
902
  "parse_date": self._parse_date,
833
903
  "get_calendar": self._get_calendar,
904
+ "created_completed_task": self.todo_manager.created_completed_task,
905
+ "restore_completed_task": self.todo_manager.restore_completed_task,
834
906
  }
835
907
 
836
908
  if tool_name not in method_map: