todo-agent 0.3.5__py3-none-any.whl → 0.3.6__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.
- todo_agent/_version.py +2 -2
- todo_agent/infrastructure/prompts/system_prompt.txt +13 -8
- todo_agent/infrastructure/todo_shell.py +4 -0
- todo_agent/interface/cli.py +53 -0
- todo_agent/interface/formatters.py +1 -0
- todo_agent/interface/tools.py +6 -5
- todo_agent/main.py +25 -6
- {todo_agent-0.3.5.dist-info → todo_agent-0.3.6.dist-info}/METADATA +1 -1
- {todo_agent-0.3.5.dist-info → todo_agent-0.3.6.dist-info}/RECORD +13 -13
- {todo_agent-0.3.5.dist-info → todo_agent-0.3.6.dist-info}/WHEEL +0 -0
- {todo_agent-0.3.5.dist-info → todo_agent-0.3.6.dist-info}/entry_points.txt +0 -0
- {todo_agent-0.3.5.dist-info → todo_agent-0.3.6.dist-info}/licenses/LICENSE +0 -0
- {todo_agent-0.3.5.dist-info → todo_agent-0.3.6.dist-info}/top_level.txt +0 -0
todo_agent/_version.py
CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
28
28
|
commit_id: COMMIT_ID
|
29
29
|
__commit_id__: COMMIT_ID
|
30
30
|
|
31
|
-
__version__ = version = '0.3.
|
32
|
-
__version_tuple__ = version_tuple = (0, 3,
|
31
|
+
__version__ = version = '0.3.6'
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 6)
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
@@ -104,23 +104,28 @@ Example: add_task(description='Put out trash and recycling', project='weekly', c
|
|
104
104
|
|
105
105
|
**Parent Task Format**: `(A) Child task description +project @context due:YYYY-MM-DD duration:2h parent:12`
|
106
106
|
|
107
|
-
### Task Completion Protocol
|
107
|
+
### Task Completion Protocol
|
108
|
+
NOTE: use complete_task() for existing non-recurring tasks
|
108
109
|
1. **Discovery**: Use `list_tasks()` to search semantically in active tasks
|
109
|
-
2. **For Recurring Tasks
|
110
|
+
2. **For Non-Recurring Tasks**:
|
111
|
+
- The task will NOT have the tag "rec:"
|
112
|
+
- Single match → use `complete_task(task_number='XX')` to mark existing active tasks complete
|
113
|
+
- Multiple/fuzzy → show options
|
114
|
+
- No match → suggest alternatives
|
115
|
+
3. **For Recurring Tasks** (containing +daily, +weekly, +monthly, +weekdays, etc.):
|
116
|
+
- The task will have the tag "rec:"
|
110
117
|
- **USE** `create_completed_task()` with the original task number as parent_number
|
111
118
|
- **PRESERVE** the original recurring task for future occurrences. **IMPORTANT** DO NOT MARK COMPLETE! DO NOT MODIFY!
|
112
119
|
- **TOOL CALL**: `create_completed_task(description='Task description', parent_number='XX', completion_date='YYYY-MM-DD', context='context', project='project')`
|
113
|
-
|
114
|
-
- Single match → use `complete_task(task_number='XX')`
|
115
|
-
- Multiple/fuzzy → show options
|
116
|
-
- No match → suggest alternatives
|
120
|
+
|
117
121
|
|
118
122
|
### Recurring Task Completion Examples
|
123
|
+
NOTE: ONLY USE create_completed_task() for RECURRING TASKS!
|
119
124
|
- **User says**: "I put out the trash" → Find `(B) Put out trash and recycling +weekly +thursday @home duration:5m`
|
120
|
-
- **Tool Call**: `create_completed_task(description='Put out trash and recycling', parent_number='B', completion_date='YYYY-MM-DD', context='home', project='weekly')`
|
125
|
+
- **Tool Call**: ONLY FOR EXISTING TASKS! `create_completed_task(description='Put out trash and recycling', parent_number='B', completion_date='YYYY-MM-DD', context='home', project='weekly')`
|
121
126
|
- **Result**: Original task remains active for next Thursday
|
122
127
|
- **User says**: "Done with standup" → Find `Standup meeting at 9:00AM +daily +weekdays @office duration:10m`
|
123
|
-
- **Tool Call**: `create_completed_task(description='Standup meeting at 9:00AM', parent_number='XX', completion_date='YYYY-MM-DD', context='office', project='daily')`
|
128
|
+
- **Tool Call**: ONLY FOR EXISTING TASKS! `create_completed_task(description='Standup meeting at 9:00AM', parent_number='XX', completion_date='YYYY-MM-DD', context='office', project='daily')`
|
124
129
|
- **Result**: Original task remains active for next weekday
|
125
130
|
|
126
131
|
### Task Suggestions
|
@@ -182,6 +182,10 @@ class TodoShell:
|
|
182
182
|
"""Archive completed tasks."""
|
183
183
|
return self.execute(["todo.sh", "-f", "archive"])
|
184
184
|
|
185
|
+
def get_help(self) -> str:
|
186
|
+
"""Get todo.sh help output."""
|
187
|
+
return self.execute(["todo.sh", "help"], suppress_color=False)
|
188
|
+
|
185
189
|
def set_due_date(self, task_number: int, due_date: str) -> str:
|
186
190
|
"""
|
187
191
|
Set or update due date for a task by intelligently rewriting it.
|
todo_agent/interface/cli.py
CHANGED
@@ -225,6 +225,23 @@ class CLI:
|
|
225
225
|
self.console.print(table)
|
226
226
|
self.console.print("Or just type your request naturally!", style="italic green")
|
227
227
|
|
228
|
+
def _print_todo_help(self) -> None:
|
229
|
+
"""Print todo.sh help information."""
|
230
|
+
try:
|
231
|
+
# Get todo.sh help output
|
232
|
+
help_output = self.todo_shell.get_help()
|
233
|
+
formatted_output = TaskFormatter.format_task_list(help_output)
|
234
|
+
help_panel = PanelFormatter.create_task_panel(
|
235
|
+
formatted_output, title="📋 Todo.sh Help"
|
236
|
+
)
|
237
|
+
self.console.print(help_panel)
|
238
|
+
except Exception as e:
|
239
|
+
self.logger.error(f"Error getting todo.sh help: {e!s}")
|
240
|
+
error_msg = ResponseFormatter.format_error(
|
241
|
+
f"Failed to get todo.sh help: {e!s}"
|
242
|
+
)
|
243
|
+
self.console.print(error_msg)
|
244
|
+
|
228
245
|
def _print_about(self) -> None:
|
229
246
|
"""Print about information in a formatted panel."""
|
230
247
|
about_panel = PanelFormatter.create_about_panel()
|
@@ -280,6 +297,37 @@ class CLI:
|
|
280
297
|
if not user_input:
|
281
298
|
continue
|
282
299
|
|
300
|
+
# Handle todo.sh passthrough commands (starting with /)
|
301
|
+
if user_input.startswith("/"):
|
302
|
+
self.logger.debug(
|
303
|
+
f"Processing todo.sh passthrough command: {user_input}"
|
304
|
+
)
|
305
|
+
try:
|
306
|
+
# Remove the leading / and execute as todo.sh command
|
307
|
+
todo_command = user_input[1:].strip()
|
308
|
+
if not todo_command:
|
309
|
+
self.console.print(
|
310
|
+
ResponseFormatter.format_error("Empty todo.sh command")
|
311
|
+
)
|
312
|
+
continue
|
313
|
+
|
314
|
+
# Execute the todo.sh command directly
|
315
|
+
output = self.todo_shell.execute(
|
316
|
+
["todo.sh", *todo_command.split()]
|
317
|
+
)
|
318
|
+
formatted_output = TaskFormatter.format_task_list(output)
|
319
|
+
task_panel = PanelFormatter.create_task_panel(
|
320
|
+
formatted_output, title="📋 Todo.sh Output"
|
321
|
+
)
|
322
|
+
self.console.print(task_panel)
|
323
|
+
except Exception as e:
|
324
|
+
self.logger.error(f"Error executing todo.sh command: {e!s}")
|
325
|
+
error_msg = ResponseFormatter.format_error(
|
326
|
+
f"Todo.sh command failed: {e!s}"
|
327
|
+
)
|
328
|
+
self.console.print(error_msg)
|
329
|
+
continue
|
330
|
+
|
283
331
|
# Handle special commands
|
284
332
|
if user_input.lower() == "clear":
|
285
333
|
self.logger.info("User requested conversation clear")
|
@@ -302,6 +350,11 @@ class CLI:
|
|
302
350
|
self._print_help()
|
303
351
|
continue
|
304
352
|
|
353
|
+
if user_input.lower() == "todo-help":
|
354
|
+
self.logger.debug("User requested todo.sh help")
|
355
|
+
self._print_todo_help()
|
356
|
+
continue
|
357
|
+
|
305
358
|
if user_input.lower() == "about":
|
306
359
|
self.logger.debug("User requested about information")
|
307
360
|
self._print_about()
|
@@ -357,6 +357,7 @@ class TableFormatter:
|
|
357
357
|
("clear", "Clear conversation history"),
|
358
358
|
("stats", "Show conversation statistics"),
|
359
359
|
("help", "Show this help message"),
|
360
|
+
("todo-help", "Show todo.sh help"),
|
360
361
|
("about", "Show application information"),
|
361
362
|
("list", "List all tasks (no LLM interaction)"),
|
362
363
|
("done", "List completed tasks (no LLM interaction)"),
|
todo_agent/interface/tools.py
CHANGED
@@ -626,13 +626,14 @@ class ToolCallHandler:
|
|
626
626
|
"name": "create_completed_task",
|
627
627
|
"description": (
|
628
628
|
"Create a task and immediately mark it as completed. "
|
629
|
-
"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') "
|
629
|
+
"USE CASE: WHEN NO MATCH IS FOUND! 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') "
|
630
630
|
"and you have already researched existing tasks to determine no match exists. "
|
631
|
-
"WORKFLOW: 1) Use list_tasks() to search for existing tasks,
|
632
|
-
"
|
631
|
+
"WORKFLOW: 1) Use list_tasks() to search for existing tasks, "
|
632
|
+
"2) Use list_completed_tasks() to verify it's not already done, "
|
633
|
+
"3) If a match is found, use complete_task() to mark it complete, "
|
634
|
+
"4) If no match found, call this tool to create and complete the task in one operation. "
|
633
635
|
"STRATEGIC CONTEXT: This is a convenience tool for the common pattern of 'I did X on [date]' - "
|
634
|
-
"it creates a task with the specified completion date and immediately marks it complete. "
|
635
|
-
"The LLM should handle the research and decision-making about whether to use this tool."
|
636
|
+
"when no task match is found, it creates a task with the specified completion date and immediately marks it complete. "
|
636
637
|
),
|
637
638
|
"parameters": {
|
638
639
|
"type": "object",
|
todo_agent/main.py
CHANGED
@@ -12,7 +12,7 @@ from .interface.cli import CLI
|
|
12
12
|
def main() -> None:
|
13
13
|
"""Main application entry point."""
|
14
14
|
from ._version import __version__
|
15
|
-
|
15
|
+
|
16
16
|
parser = argparse.ArgumentParser(
|
17
17
|
description=f"Todo.sh LLM Agent - Natural language task management (v{__version__})",
|
18
18
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
@@ -27,18 +27,20 @@ Examples:
|
|
27
27
|
)
|
28
28
|
|
29
29
|
parser.add_argument(
|
30
|
-
"--version",
|
30
|
+
"--version",
|
31
|
+
"-v",
|
31
32
|
action="version",
|
32
33
|
version=f"%(prog)s {__version__}",
|
33
34
|
help="Show version information and exit",
|
34
35
|
)
|
35
|
-
|
36
|
+
|
36
37
|
parser.add_argument(
|
37
|
-
"--help",
|
38
|
+
"--help",
|
39
|
+
"-h",
|
38
40
|
action="help",
|
39
41
|
help="Show this help message and exit",
|
40
42
|
)
|
41
|
-
|
43
|
+
|
42
44
|
parser.add_argument(
|
43
45
|
"command",
|
44
46
|
nargs="?",
|
@@ -53,11 +55,28 @@ Examples:
|
|
53
55
|
if args.command:
|
54
56
|
# Single command mode
|
55
57
|
# Handle special commands that don't need LLM processing
|
56
|
-
if args.command.lower() in ["help", "about"]:
|
58
|
+
if args.command.lower() in ["help", "about", "todo-help"]:
|
57
59
|
if args.command.lower() == "help":
|
58
60
|
cli._print_help()
|
59
61
|
elif args.command.lower() == "about":
|
60
62
|
cli._print_about()
|
63
|
+
elif args.command.lower() == "todo-help":
|
64
|
+
cli._print_todo_help()
|
65
|
+
elif args.command.startswith("/"):
|
66
|
+
# Handle todo.sh passthrough commands
|
67
|
+
try:
|
68
|
+
# Remove the leading / and execute as todo.sh command
|
69
|
+
todo_command = args.command[1:].strip()
|
70
|
+
if not todo_command:
|
71
|
+
print("Error: Empty todo.sh command")
|
72
|
+
sys.exit(1)
|
73
|
+
|
74
|
+
# Execute the todo.sh command directly
|
75
|
+
output = cli.todo_shell.execute(["todo.sh", *todo_command.split()])
|
76
|
+
print(output)
|
77
|
+
except Exception as e:
|
78
|
+
print(f"Error: Todo.sh command failed: {e}")
|
79
|
+
sys.exit(1)
|
61
80
|
else:
|
62
81
|
# Process through LLM
|
63
82
|
response = cli.run_single_request(args.command)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
todo_agent/__init__.py,sha256=RUowhd14r3tqB_7rl83unGV8oBjra3UOIl7jix-33fk,254
|
2
|
-
todo_agent/_version.py,sha256=
|
3
|
-
todo_agent/main.py,sha256=
|
2
|
+
todo_agent/_version.py,sha256=DPG4bRRG7SLMPQyCzFx7koj75iQndn-UI-ENmNbYVCQ,704
|
3
|
+
todo_agent/main.py,sha256=3kFRat2mG_57z1JR6UzsWDGLZ8G8EYuw9h9F8Xpo_mc,2857
|
4
4
|
todo_agent/core/__init__.py,sha256=QAZ4it63pXv5-DxtNcuSAmg7ZnCY5ackI5yycvKHr9I,365
|
5
5
|
todo_agent/core/conversation_manager.py,sha256=9aAWogswZe9Cs7wKT47RG-cLh1LQ5D9RbhUHJVUyTS8,13549
|
6
6
|
todo_agent/core/exceptions.py,sha256=ilVL5hyPHGYQXsLm0pYivMbhbamupG77r8TbiQr2tAU,2034
|
@@ -14,17 +14,17 @@ todo_agent/infrastructure/llm_client_factory.py,sha256=-tktnVOIF7B45WR7AuLoi7MKn
|
|
14
14
|
todo_agent/infrastructure/logger.py,sha256=2ykG_0lyzmEGxDF6ZRl1qiTUGDuFeQgzv4Na6vRmXcM,4110
|
15
15
|
todo_agent/infrastructure/ollama_client.py,sha256=V_zAeBjIEzB8PZXyzFeiLMLA5qf3y4WV2_6Vqxn1ujc,5629
|
16
16
|
todo_agent/infrastructure/openrouter_client.py,sha256=0pxIKvHItwVijFz8l4loOeCa4HUpMvTYROcwYJh3iyI,6748
|
17
|
-
todo_agent/infrastructure/todo_shell.py,sha256=
|
17
|
+
todo_agent/infrastructure/todo_shell.py,sha256=ft7wKWykMKEHD1ZD_k1R8a_Zje7vLnG1yD8770TNVBQ,20738
|
18
18
|
todo_agent/infrastructure/token_counter.py,sha256=PCKheOVJbp1s89yhh_i6iKgURMt9mVoYkwjQJCc2xCE,4958
|
19
|
-
todo_agent/infrastructure/prompts/system_prompt.txt,sha256=
|
19
|
+
todo_agent/infrastructure/prompts/system_prompt.txt,sha256=DwvuXoSZY5-lRk1WcinU57PIqGH-omy1oC5P5FBEOog,12670
|
20
20
|
todo_agent/interface/__init__.py,sha256=vDD3rQu4qDkpvVwGVtkDzE1M4IiSHYzTif4GbYSFWaI,457
|
21
|
-
todo_agent/interface/cli.py,sha256=
|
22
|
-
todo_agent/interface/formatters.py,sha256=
|
21
|
+
todo_agent/interface/cli.py,sha256=opVubVwLlcU5ImUyGlS21Es49xuzNjkivPiEsxRiLj0,18922
|
22
|
+
todo_agent/interface/formatters.py,sha256=Kcm8-E9OkvjnqaUvQuwrYKqUmknduAUP5z0A6rOaeG8,20129
|
23
23
|
todo_agent/interface/progress.py,sha256=EpPa20Hrnjv_TBIp0tzViVciThqsOvAHuYO4v2rc8eI,1751
|
24
|
-
todo_agent/interface/tools.py,sha256=
|
25
|
-
todo_agent-0.3.
|
26
|
-
todo_agent-0.3.
|
27
|
-
todo_agent-0.3.
|
28
|
-
todo_agent-0.3.
|
29
|
-
todo_agent-0.3.
|
30
|
-
todo_agent-0.3.
|
24
|
+
todo_agent/interface/tools.py,sha256=U3LF7VZy27n2aLbxDD7uIEt8OPeXgXCz0I83ins4WdM,54507
|
25
|
+
todo_agent-0.3.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
26
|
+
todo_agent-0.3.6.dist-info/METADATA,sha256=iqTh--OWn4ocfSIVeK3F35RC7SoFc4nASidx8K67Bos,10056
|
27
|
+
todo_agent-0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
28
|
+
todo_agent-0.3.6.dist-info/entry_points.txt,sha256=4W7LrCib6AXP5IZDwWRht8S5gutLu5oNfTJHGbt4oHs,52
|
29
|
+
todo_agent-0.3.6.dist-info/top_level.txt,sha256=a65mlPIhPZHuq2bRIi_sCMAIJsUddvXt171OBF6r6co,11
|
30
|
+
todo_agent-0.3.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|