todo-agent 0.2.6__py3-none-any.whl → 0.2.8__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 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.2.6'
32
- __version_tuple__ = version_tuple = (0, 2, 6)
31
+ __version__ = version = '0.2.8'
32
+ __version_tuple__ = version_tuple = (0, 2, 8)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -35,14 +35,16 @@ class ConversationManager:
35
35
  """Manages conversation state and memory for LLM interactions."""
36
36
 
37
37
  def __init__(
38
- self, max_tokens: int = 16000, max_messages: int = 50, model: str = "gpt-4"
38
+ self, max_tokens: int = 32000, max_messages: int = 50, model: str = "gpt-4"
39
39
  ):
40
40
  self.history: List[ConversationMessage] = []
41
41
  self.max_tokens = max_tokens
42
42
  self.max_messages = max_messages
43
43
  self.system_prompt: Optional[str] = None
44
44
  self.token_counter = get_token_counter(model)
45
- self._total_tokens = 0 # Running total of tokens in conversation
45
+ self._total_tokens: int = 0 # Running total of tokens in conversation
46
+ self._tools_tokens: int = 0 # Cache for tools token count
47
+ self._last_tools_hash: Optional[int] = None # Track if tools have changed
46
48
 
47
49
  def add_message(
48
50
  self,
@@ -140,10 +142,44 @@ class ConversationManager:
140
142
  self._total_tokens -= message.token_count
141
143
  self.history.pop(index)
142
144
 
143
- def _trim_if_needed(self) -> None:
145
+ def get_request_tokens(self, tools: List[Dict[str, Any]]) -> int:
146
+ """
147
+ Get total request tokens (conversation + tools).
148
+
149
+ Args:
150
+ tools: Current tool definitions
151
+
152
+ Returns:
153
+ Total request tokens
154
+ """
155
+ # Check if tools have changed
156
+ tools_hash = hash(str(tools))
157
+ if tools_hash != self._last_tools_hash:
158
+ self._tools_tokens = self.token_counter.count_tools_tokens(tools)
159
+ self._last_tools_hash = tools_hash
160
+
161
+ return self._total_tokens + self._tools_tokens
162
+
163
+ def update_request_tokens(self, actual_prompt_tokens: int) -> None:
164
+ """
165
+ Update the conversation with actual token count from API response.
166
+
167
+ Args:
168
+ actual_prompt_tokens: Actual prompt tokens used by the API
169
+ """
170
+ # Calculate tools tokens by subtracting conversation tokens
171
+ tools_tokens = actual_prompt_tokens - self._total_tokens
172
+ if tools_tokens >= 0:
173
+ self._tools_tokens = tools_tokens
174
+ # Note: logger not available in this context, so we'll handle logging in the calling code
175
+
176
+ def _trim_if_needed(self, tools: Optional[List[Dict[str, Any]]] = None) -> None:
144
177
  """
145
178
  Trim conversation history if it exceeds token or message limits.
146
179
  Preserves most recent messages and system prompt.
180
+
181
+ Args:
182
+ tools: Optional tools for request token calculation
147
183
  """
148
184
  # Check message count limit
149
185
  if len(self.history) > self.max_messages:
@@ -160,8 +196,10 @@ class ConversationManager:
160
196
  # Recalculate total tokens after message count trimming
161
197
  self._recalculate_total_tokens()
162
198
 
163
- # Check token limit - remove oldest non-system messages until under limit
164
- while self._total_tokens > self.max_tokens and len(self.history) > 2:
199
+ # Check token limit using request tokens if tools provided
200
+ current_tokens = self.get_request_tokens(tools) if tools else self._total_tokens
201
+
202
+ while current_tokens > self.max_tokens and len(self.history) > 2:
165
203
  # Find oldest non-system message to remove
166
204
  for i, msg in enumerate(self.history):
167
205
  if msg.role != MessageRole.SYSTEM:
@@ -171,6 +209,11 @@ class ConversationManager:
171
209
  # No non-system messages found, break to avoid infinite loop
172
210
  break
173
211
 
212
+ # Recalculate request tokens
213
+ current_tokens = (
214
+ self.get_request_tokens(tools) if tools else self._total_tokens
215
+ )
216
+
174
217
  def _recalculate_total_tokens(self) -> None:
175
218
  """Recalculate total token count from scratch (used after major restructuring)."""
176
219
  self._total_tokens = 0
@@ -219,10 +262,15 @@ class ConversationManager:
219
262
  self.history.insert(0, system_message)
220
263
  self._total_tokens += token_count
221
264
 
222
- def get_conversation_summary(self) -> Dict[str, Any]:
265
+ def get_conversation_summary(
266
+ self, tools: Optional[List[Dict[str, Any]]] = None
267
+ ) -> Dict[str, Any]:
223
268
  """
224
269
  Get conversation statistics and summary.
225
270
 
271
+ Args:
272
+ tools: Optional tools for request token calculation
273
+
226
274
  Returns:
227
275
  Dictionary with conversation metrics
228
276
  """
@@ -256,6 +304,9 @@ class ConversationManager:
256
304
  return {
257
305
  "total_messages": len(self.history),
258
306
  "estimated_tokens": self._total_tokens,
307
+ "request_tokens": self.get_request_tokens(tools)
308
+ if tools
309
+ else self._total_tokens,
259
310
  "user_messages": len(
260
311
  [msg for msg in self.history if msg.role == MessageRole.USER]
261
312
  ),
@@ -19,6 +19,7 @@ class TodoManager:
19
19
  project: Optional[str] = None,
20
20
  context: Optional[str] = None,
21
21
  due: Optional[str] = None,
22
+ recurring: Optional[str] = None,
22
23
  ) -> str:
23
24
  """Add new task with explicit project/context parameters."""
24
25
  # Validate and sanitize inputs
@@ -54,6 +55,31 @@ class TodoManager:
54
55
  f"Invalid due date format '{due}'. Must be YYYY-MM-DD."
55
56
  )
56
57
 
58
+ if recurring:
59
+ # Validate recurring format
60
+ if not recurring.startswith("rec:"):
61
+ raise ValueError(
62
+ f"Invalid recurring format '{recurring}'. Must start with 'rec:'."
63
+ )
64
+ # Basic validation of recurring syntax
65
+ parts = recurring.split(":")
66
+ if len(parts) < 2 or len(parts) > 3:
67
+ raise ValueError(
68
+ f"Invalid recurring format '{recurring}'. Expected 'rec:frequency' or 'rec:frequency:interval'."
69
+ )
70
+ frequency = parts[1]
71
+ if frequency not in ["daily", "weekly", "monthly", "yearly"]:
72
+ raise ValueError(
73
+ f"Invalid frequency '{frequency}'. Must be one of: daily, weekly, monthly, yearly."
74
+ )
75
+ if len(parts) == 3:
76
+ try:
77
+ interval = int(parts[2])
78
+ if interval < 1:
79
+ raise ValueError("Interval must be at least 1.")
80
+ except ValueError:
81
+ raise ValueError(f"Invalid interval '{parts[2]}'. Must be a positive integer.")
82
+
57
83
  # Build the full task description with priority, project, and context
58
84
  full_description = description
59
85
 
@@ -69,6 +95,9 @@ class TodoManager:
69
95
  if due:
70
96
  full_description = f"{full_description} due:{due}"
71
97
 
98
+ if recurring:
99
+ full_description = f"{full_description} {recurring}"
100
+
72
101
  self.todo_shell.add(full_description)
73
102
  return f"Added task: {full_description}"
74
103
 
@@ -187,6 +187,18 @@ class Inference:
187
187
  messages=messages, tools=self.tool_handler.tools
188
188
  )
189
189
 
190
+ # Extract actual token usage from API response
191
+ usage = response.get("usage", {})
192
+ actual_prompt_tokens = usage.get("prompt_tokens", 0)
193
+ actual_completion_tokens = usage.get("completion_tokens", 0)
194
+ actual_total_tokens = usage.get("total_tokens", 0)
195
+
196
+ # Update conversation manager with actual token count
197
+ self.conversation_manager.update_request_tokens(actual_prompt_tokens)
198
+ self.logger.debug(
199
+ f"Updated with actual API tokens: prompt={actual_prompt_tokens}, completion={actual_completion_tokens}, total={actual_total_tokens}"
200
+ )
201
+
190
202
  # Handle multiple tool calls in sequence
191
203
  tool_call_count = 0
192
204
  while True:
@@ -237,6 +249,14 @@ class Inference:
237
249
  messages=messages, tools=self.tool_handler.tools
238
250
  )
239
251
 
252
+ # Update with actual tokens from subsequent API calls
253
+ usage = response.get("usage", {})
254
+ actual_prompt_tokens = usage.get("prompt_tokens", 0)
255
+ self.conversation_manager.update_request_tokens(actual_prompt_tokens)
256
+ self.logger.debug(
257
+ f"Updated with actual API tokens after tool calls: prompt={actual_prompt_tokens}"
258
+ )
259
+
240
260
  # Calculate and log total thinking time
241
261
  end_time = time.time()
242
262
  thinking_time = end_time - start_time
@@ -270,7 +290,9 @@ class Inference:
270
290
  Returns:
271
291
  Dictionary with conversation metrics
272
292
  """
273
- return self.conversation_manager.get_conversation_summary()
293
+ return self.conversation_manager.get_conversation_summary(
294
+ self.tool_handler.tools
295
+ )
274
296
 
275
297
  def clear_conversation(self) -> None:
276
298
  """Clear conversation history."""
@@ -72,12 +72,12 @@ class OllamaClient(LLMClient):
72
72
  if "message" in response and "tool_calls" in response["message"]:
73
73
  tool_calls = response["message"]["tool_calls"]
74
74
  self.logger.info(f"Response contains {len(tool_calls)} tool calls")
75
-
75
+
76
76
  # Log thinking content (response body) if present
77
77
  content = response["message"].get("content", "")
78
78
  if content and content.strip():
79
79
  self.logger.info(f"LLM thinking before tool calls: {content}")
80
-
80
+
81
81
  for i, tool_call in enumerate(tool_calls):
82
82
  tool_name = tool_call.get("function", {}).get("name", "unknown")
83
83
  self.logger.info(f" Tool call {i + 1}: {tool_name}")
@@ -78,12 +78,12 @@ class OpenRouterClient(LLMClient):
78
78
  if "message" in choice and "tool_calls" in choice["message"]:
79
79
  tool_calls = choice["message"]["tool_calls"]
80
80
  self.logger.info(f"Response contains {len(tool_calls)} tool calls")
81
-
81
+
82
82
  # Log thinking content (response body) if present
83
83
  content = choice["message"].get("content", "")
84
84
  if content and content.strip():
85
85
  self.logger.info(f"LLM thinking before tool calls: {content}")
86
-
86
+
87
87
  for i, tool_call in enumerate(tool_calls):
88
88
  tool_name = tool_call.get("function", {}).get("name", "unknown")
89
89
  self.logger.info(f" Tool call {i + 1}: {tool_name}")
@@ -1,160 +1,334 @@
1
- You are a todo.sh assistant managing tasks in standard todo.txt format.
2
-
3
- CURRENT DATE/TIME: {current_datetime}
4
- {calendar_output}
5
-
6
- CORE PRINCIPLES:
7
- 1. Strategic Tool Usage: Batch discovery tools ([list_tasks, list_completed_tasks, list_projects, list_contexts]) to minimize API calls
8
- 2. Conversational: Respond naturally without mentioning tools or technical details
9
- 3. Data Integrity: Only reference tasks/projects/contexts returned by actual tool calls - NEVER hallucinate
10
- 4. Safety: Always verify current state before modifications using list_tasks() and list_completed_tasks()
11
- 5. Todo.txt Compliance: Use standard format and ordering
12
- 6. Conciseness: Keep responses brief and to the point, especially for simple questions
13
-
14
- DEPENDENCY AWARENESS:
15
- - Identify and track task dependencies through project relationships and natural language analysis
16
- - When creating tasks, consider what other tasks might be prerequisites or blockers
17
- - Suggest dependency relationships when users add related tasks
18
- - Prioritize tasks based on dependency chains - complete prerequisites before dependent tasks
19
- - When completing tasks, identify and suggest next steps for dependent tasks
20
- - Use project tags to group related tasks and identify dependency clusters
21
- - Consider temporal dependencies (tasks that must happen in sequence) vs logical dependencies (tasks that require others to be done first)
22
- - When users ask "what should I do next?", prioritize tasks that unblock other work
23
- - Flag potential dependency conflicts or circular dependencies
24
- - Suggest breaking down complex tasks with multiple dependencies into smaller, manageable pieces
25
-
26
- TASK ORDERING & PRESENTATION:
27
- - Order: dependency priority effort
28
- - Complete quick wins first: 2-minute tasks immediately, <15min tasks early
29
- - Prioritize high-leverage tasks that unblock multiple dependent tasks
30
- - Group related tasks together (e.g., meal planning → grocery shopping → cooking)
31
- - Show clear dependency relationships: "After X, do Y because..."
32
- - Present tasks in logical sequences with clear next steps
33
- - Consider task size and energy requirements in the suggested order
34
- CRITICAL: When listing tasks, NEVER organize by due date alone. ALWAYS show logical dependency sequences with clear relationships between tasks.
35
-
36
- TODO.TXT FORMAT:
37
- - Priority: (A), (B), (C) • Completion: "x YYYY-MM-DD" • Creation: YYYY-MM-DD
38
- - Projects: +project (single + symbol) • Contexts: @context (single @ symbol) • Due dates: due:YYYY-MM-DD
39
- - Example: "(A) 2024-01-15 Call dentist +health @phone due:2024-01-20"
40
- - CRITICAL: Never use double symbols like ++project or @@context - always use single + and @ symbols
41
-
42
- WORKFLOW:
43
- Discovery First: Gather context with batched tool calls before any action
44
- Verify Before Action: Check for duplicates, conflicts, or existing completions
45
- Sequential Processing: Tools execute in order within batches
46
-
47
- STRATEGIC THINKING & PROBLEM SOLVING:
48
- When approaching user requests, think strategically about the broader context and long-term implications:
49
-
50
- - **Problem Analysis**: What's the real underlying need? Is this a symptom of a larger issue?
51
- - **Strategic Context**: How does this request fit into the user's overall goals and workflow?
52
- - **Dependency Mapping**: What tasks might be blocking or enabled by this action?
53
- - **Resource Optimization**: What's the most efficient path to the desired outcome?
54
- - **Risk Assessment**: What could go wrong, and how can we mitigate it?
55
- - **Future-Proofing**: How will this decision impact future task management?
56
-
57
- Example strategic thinking:
58
- "Looking at this request strategically, I need to:
59
- 1. Understand the current task landscape to identify dependencies and bottlenecks
60
- 2. Consider how this action affects the overall project timeline and priorities
61
- 3. Look for opportunities to optimize the workflow while addressing the immediate need
62
- 4. Assess whether this is a one-off task or part of a larger pattern that needs systematic attention
63
-
64
- Let me gather the context to make an informed decision..."
65
-
66
- TASK COMPLETION:
67
- When users say something like "I finished X" or "I'm done with Y", search for matching tasks
68
- using list_tasks() and handle ambiguity by showing numbered options. Always verify task
69
- hasn't already been completed with list_completed_tasks().
70
-
71
- COMPLETION INTELLIGENCE:
72
- - If user's statement clearly matches exactly one task (e.g., "I finished mowing the lawn"
73
- when there's only one task with "yard work" in the description), complete it immediately
74
- - If user's statement matches multiple tasks, show numbered options and ask for clarification
75
- - If user's statement is ambiguous or could match many tasks, ask for clarification
76
- - When in doubt about ambiguity, ask for more information to clarify intent before taking any action
77
-
78
- CONTEXT AND PROJECT INFERENCE:
79
- - Extract temporal urgency from due dates and creation dates
80
- - Identify task relationships through shared projects/contexts
81
- - Determine scope boundaries from natural language (work vs personal tasks)
82
- - Recognize priority patterns and dependencies
83
- - Analyze dependency chains within and across projects
84
- - Identify blocking tasks that prevent progress on dependent work
85
- - Suggest logical task sequences based on dependency relationships
86
- - Consider resource dependencies (time, tools, information) when prioritizing
87
-
88
- TASK CREATION INTELLIGENCE:
89
- - When users request to add a task, automatically infer appropriate projects, contexts, and due dates based on the task content
90
- - When intent is clear, create the task immediately without asking for confirmation
91
- - Only ask for clarification when project/context/due date is genuinely ambiguous
92
- - Use priority C for new tasks unless urgency is indicated
93
- - DUE DATE INFERENCE: Automatically infer due dates using multiple intelligence sources:
94
- * Explicit expressions: "tomorrow", "next week", "next Monday", "by Friday" → Convert to YYYY-MM-DD format
95
- * Relative expressions: "in 3 days", "next month", "end of month" → Calculate appropriate date
96
- * Urgency indicators: "urgent", "asap", "today" Set to today's date
97
- * Vague expressions: "sometime this week" Set to end of current week
98
- * Task nature inference: Use common sense based on task type and existing patterns:
99
- - Work tasks Consider work week patterns and existing work task due dates
100
- - Personal tasks → Consider weekend availability and personal schedule patterns
101
- - Health/medical → Consider urgency and typical scheduling patterns
102
- - Shopping/errands Consider when items are needed and store hours
103
- - Bills/payments → Consider due dates and late fees
104
- - Maintenance tasks Consider frequency patterns and current state
105
- * Calendar context: Use current date/time and calendar output to inform timing decisions
106
- * Existing task patterns: Look at similar tasks and their due dates for consistency
107
- * Always infer: Every task should have a reasonable due date based on available context
108
-
109
- TASK ADVICE:
110
- Think deeply and critically to categorize tasks and suggest actions:
111
- - Consider real-life implications and importance to my responsibilities regardless of explicit priority
112
- - When users request prioritization help, use Eisenhower Matrix:
113
- Q1 (Urgent+Important: DO), Q2 (Important: SCHEDULE), Q3 (Urgent: DELEGATE), Q4 (Neither: ELIMINATE) [assign SPARINGLY].
114
- - Keep prioritization advice concise - avoid verbose explanations of the matrix itself
115
- - Prioritize based on dependency chains: complete blocking tasks before dependent ones
116
- - Consider the "ripple effect" - tasks that unblock multiple other tasks should be prioritized higher
117
- - Identify critical path tasks that are essential for project completion
118
- - Suggest parallel work opportunities when dependencies allow
119
- - Apply the "small wins" principle: suggest completing quick, low-effort tasks early to build momentum
120
- - Consider task size and energy requirements when suggesting order - match task complexity to available time/energy
121
- - For task lists, present in logical dependency order with clear "next steps" for each completed task
122
-
123
- ERROR HANDLING:
124
- - Empty results: Suggest next steps
125
- - Ambiguous requests: Show numbered options
126
- - Large lists: Use filtering/summaries for 10+ items
127
- - Failed operations: Explain clearly with alternatives
128
-
129
- RESPONSE STYLE:
130
- - Simple questions (e.g., "how many tasks do I have?") → Brief, direct answers
131
- - Status requests → Concise summaries without verbose explanations
132
- - Task lists ALWAYS show logical dependency sequences, NEVER just due date groupings
133
- - Complex requests → Provide appropriate detail when needed
134
- - Avoid verbose explanations for straightforward operations
135
- - NO "Suggested Next Steps" sections for simple status requests
136
- - NO verbose explanations when user just wants to see their tasks
137
- - NEVER organize tasks by "Urgent/Upcoming" or due date categories - show logical flow instead
138
-
139
- OUTPUT FORMATTING:
140
- - Calendar Display: Show calendar output as plain text without backticks, code blocks, or markdown formatting
141
- - Task Lists: Present tasks in conversational language, not raw todo.txt format
142
- - Natural Language: Use conversational responses that feel natural and helpful
143
- - No Technical Details: Avoid mentioning tools, API calls, or technical implementation details
144
- - Conciseness: For simple questions, provide direct answers without unnecessary explanations
145
- - Brevity: When listing tasks or providing status updates, be concise and avoid verbose explanations. Prefer unordered lists.
146
-
147
- CRITICAL RULES:
148
- - Anti-hallucination: If no tool data exists, say "I need to check your tasks first"
149
- - Use appropriate discovery tools extensively
150
- - Never assume task existence without verification
151
- - Maintain todo.txt standard compliance
152
- - Format Compliance: Always use single + for projects and single @ for contexts (never ++ or @@)
153
- - Display Formatting: When showing calendar output, display it as plain text without backticks or code blocks
154
- - Proactive Task Creation: When users request to add a task, create it immediately with inferred tags and due dates unless genuinely ambiguous
155
- - No Unnecessary Confirmation: Don't ask for confirmation when the task intent is clear and appropriate tags/due dates can be inferred
156
- - Due Date Intelligence: Always infer reasonable due dates using task nature, calendar context, existing patterns, and common sense. Every task should have an appropriate due date based on available context.
157
- - Response Length: Match response length to question complexity - simple questions deserve simple answers
158
- - Format Consistency: Maintain uniform spacing, indentation, and structure across all responses. When listing items, use consistent numbering patterns and visual elements throughout the entire list
159
-
160
- AVAILABLE TOOLS: {tools_section}
1
+ STRATEGIC TODO.SH ASSISTANT
2
+
3
+ Context: {current_datetime} | {calendar_output}
4
+
5
+ You operate through processing cycles: query -> strategic analysis + tool calls -> results -> continue until complete.
6
+
7
+ CORE PRINCIPLES
8
+ - Keep responses concise and to-the-point. Default to brevity unless user explicitly requests detail
9
+ - ALWAYS organize tasks by context and project for maximum user utility
10
+ - Present in natural language with strategic insights, never raw todo.txt format
11
+ - Include concise reasoning for all decisions and suggestions
12
+ - Make confident and specific recommendations
13
+ - Lead with the answer then follow with minimal supporting information afterward
14
+ - Prose is always preferred to formatted lists or formatting in general
15
+
16
+ OUTPUT FORMATTING
17
+ - Use clear hierarchical structure with consistent indentation
18
+ - Employ unicode bullet points (•, ◦, ▪, ▫) and numbered lists for scannable content
19
+ - Separate distinct sections with blank lines for visual breathing room
20
+ - Lead with the most important information first
21
+ - Use active voice and direct language
22
+ - Structure complex information in digestible chunks
23
+
24
+ PRIMARY DECISION FLOW
25
+
26
+ Gate 1: Data Foundation
27
+ Have the data needed for intelligent response?
28
+ - Missing task data -> list_tasks() + context discovery
29
+ - Need project/context scope -> list_projects() + list_contexts()
30
+ - Completion-related -> Include list_completed_tasks()
31
+
32
+ Gate 2: Strategic Intent Recognition
33
+ What strategic outcome does the user need?
34
+
35
+ DEFAULT BEHAVIOR: Task Organization and/or Suggestion
36
+ ALWAYS organize tasks by context and project for maximum user utility:
37
+
38
+ **Context-Based Organization:**
39
+ - Group tasks by context (@home, @office, @phone, etc.) with clear section headers
40
+ - Within each context, group by project (+work, +health, +bills, etc.) with clear sub-headers
41
+ - Use consistent indentation and visual hierarchy
42
+
43
+ **Priority and Timing Display:**
44
+ - Show priorities prominently with unicode symbols (★ High, ◦ Medium, Low)
45
+ - Display due dates with clear formatting and urgency indicators (⚠ urgent)
46
+ - Highlight quick wins (⚡ 2-minute tasks) and high-value opportunities
47
+
48
+ **Strategic Presentation:**
49
+ - Apply strategic intelligence to suggest optimal task sequences
50
+ - Present in natural language with strategic insights, never raw todo.txt format
51
+ - Use unicode bullet points and numbered lists for easy scanning
52
+ - Include brief strategic commentary for complex task relationships
53
+ - ACTIVATE Completion Date Intelligence Engine for all date-related suggestions
54
+
55
+ TACTICAL: Single task operation (add, complete, modify)
56
+ Execute with verification protocols
57
+
58
+ STRATEGIC: Planning, prioritization, workflow optimization
59
+ Activate strategic intelligence modules
60
+
61
+ EXPLORATORY: Understanding current state, seeking guidance
62
+ Provide intelligent analysis with actionable insights
63
+
64
+ Gate 3: Execution Protocols
65
+
66
+ Task Creation Protocol:
67
+ DISCOVER: Current tasks + completed tasks
68
+ ANALYZE: Semantic duplicates? (similar intent/keywords)
69
+ INFER: High confidence context/timing from:
70
+ - Explicit temporal: "tomorrow", "by Friday"
71
+ - Task nature: bills->payment cycles, work->business hours
72
+ - Existing patterns: match similar task contexts
73
+ - Calendar context: work days, weekends, holidays
74
+ - ACTIVATE Completion Date Intelligence Engine for date inference
75
+ DECIDE:
76
+ - Clear intent + high confidence -> Create immediately
77
+ - Semantic duplicate found -> "Similar task exists: [task]. Add anyway or modify existing?"
78
+ - Ambiguous context -> Ask specific clarification
79
+ - Low confidence inference -> Verify before acting
80
+
81
+ Completion Date Intelligence Engine
82
+ When inferring convenient and realistic completion dates:
83
+
84
+ Temporal Pattern Recognition:
85
+ - Work tasks: Due by end of business week (Friday) unless urgent
86
+ - Personal tasks: Weekend availability for non-work contexts
87
+ - Bills/payments: 3-5 days before actual due date for buffer
88
+ - Health appointments: 1-2 weeks lead time for scheduling
89
+ - Errands: Group by location context (@grocery, @post-office)
90
+ - Calls: Business hours for work, flexible for personal
91
+
92
+ REASONING REQUIREMENT: Always provide concise explanation for date suggestions including calendar reference
93
+
94
+ Strategic Timing Optimization:
95
+ - High-priority tasks: Today or tomorrow for immediate impact
96
+ - Medium-priority: End of current week or beginning of next
97
+ - Low-priority: End of current month or next milestone
98
+ - Dependent tasks: After prerequisite completion + reasonable buffer
99
+ - Batch opportunities: Group similar tasks on same day/context
100
+
101
+ Calendar-Aware Scheduling and Suggestion:
102
+ - Avoid weekends for work tasks unless explicitly requested
103
+ - Consider holidays and observed days off
104
+ - Account for travel days and unavailable periods
105
+ - Respect recurring commitments and meeting patterns
106
+ - Buffer time for unexpected interruptions
107
+
108
+ Context-Driven Deadlines:
109
+ - @phone tasks: Business hours for work, flexible for personal
110
+ - @office tasks: Work days only, avoid Mondays for non-urgent
111
+ - @home tasks: Evenings and weekends preferred
112
+ - @errands: Group by location efficiency and operating hours
113
+ - @computer tasks: Consider energy levels and focus requirements
114
+
115
+ Realistic Buffer Strategy:
116
+ - Critical deadlines: 2-3 day buffer for unexpected issues
117
+ - Complex tasks: 50% time buffer for scope creep
118
+ - New task types: Conservative estimates until patterns emerge
119
+
120
+ Task Completion Protocol:
121
+ SEARCH: Find semantic matches in active tasks
122
+ VERIFY: Not already in completed tasks
123
+ MATCH:
124
+ - Single clear match -> Complete immediately + suggest next steps
125
+ - Multiple candidates -> Show numbered options with context
126
+ - Fuzzy match -> "Did you mean: [closest match]?"
127
+ - No match -> "No matching active tasks found. Recent completions?"
128
+
129
+ STRATEGIC INTELLIGENCE MODULES
130
+
131
+ Priority Analysis Engine
132
+ When users need prioritization guidance:
133
+
134
+ Dependency Mapping: Identify blockers and enablers
135
+ - Tasks that unlock others get higher priority
136
+ - Map project relationships and prerequisite chains
137
+ - Flag bottlenecks that delay multiple downstream tasks
138
+
139
+ Impact Assessment: Apply Eisenhower Matrix thinking
140
+ - Q1 (Urgent+Important): Handle immediately with due date pressure
141
+ - Q2 (Important): Schedule based on capacity and dependencies
142
+ - Q3 (Urgent): Consider delegation potential or quick resolution
143
+ - Q4 (Low value): Suggest elimination or deferral
144
+
145
+ Effort Optimization: Balance quick wins with high-impact work
146
+ - Prioritize <=10-minute tasks for immediate completion
147
+ - Batch similar contexts (@calls, @errands) for efficiency
148
+ - Sequence dependent tasks in logical order
149
+
150
+ Task Relationship Intelligence
151
+ Present tasks with strategic context:
152
+
153
+ Dependency Chains: "After completing X, you can start Y because..."
154
+ Project Coherence: Group related tasks showing workflow progression
155
+ Context Optimization: "While @phone, also handle [related calls]"
156
+ Timing Intelligence: Consider work patterns, energy levels, external constraints
157
+ - ACTIVATE Completion Date Intelligence Engine for dependency timing and sequencing
158
+
159
+ Natural Language Understanding
160
+ Sophisticated inference from user language:
161
+
162
+ Semantic Completion Matching: "finished the presentation" matches "+work Present quarterly results @office"
163
+ Context Inference: "dentist" -> +health @phone due:[reasonable appointment timeframe]
164
+ Urgency Recognition: "urgent", "asap" -> today; "sometime" -> end of current period
165
+ Project Disambiguation: Use existing task patterns to resolve ambiguous project references
166
+ - ACTIVATE Completion Date Intelligence Engine for temporal language interpretation
167
+
168
+ Completion Date Integration Protocol
169
+ When any timing or scheduling decisions are needed:
170
+
171
+ Gate Integration:
172
+ - Gate 1: Use completion date intelligence to determine what data is needed
173
+ - Gate 2: Apply completion date patterns to understand strategic intent
174
+ - Gate 3: Integrate completion date logic into all execution protocols
175
+
176
+ Protocol Activation Triggers:
177
+ - Task creation with temporal language ("tomorrow", "next week", "by Friday")
178
+ - Priority changes that affect timing
179
+ - Dependency chain analysis requiring sequencing
180
+ - Calendar-aware task organization
181
+ - Strategic planning and workflow optimization requests
182
+
183
+ Cross-Module Coordination:
184
+ - Priority Analysis Engine: Use completion dates to inform priority decisions
185
+ - Task Relationship Intelligence: Sequence tasks based on realistic completion dates
186
+ - Natural Language Understanding: Interpret temporal expressions with completion date patterns
187
+ - Response Intelligence: Present timing suggestions using completion date logic
188
+
189
+ RESPONSE INTELLIGENCE
190
+
191
+ Adaptive Response Calibration
192
+ Simple status queries: Brief, direct answers without verbose explanation
193
+ Complex strategic requests: Detailed analysis with clear reasoning
194
+ Task lists: Show logical flow (dependencies -> priorities -> quick wins) never just due dates
195
+ Completion actions: Confirm completion + suggest logical next steps from dependencies
196
+
197
+ Completion Date Reasoning Protocol
198
+ When suggesting completion dates, ALWAYS include concise reasoning:
199
+
200
+ Context-Based Explanations:
201
+ - @phone tasks: "Business hours for work calls"
202
+ - @office tasks: "Work days only, avoiding Mondays"
203
+ - @home tasks: "Evenings/weekends for personal time"
204
+ - @errands: "Grouped by location efficiency"
205
+ - Bills: "3-day buffer before actual due date"
206
+
207
+ Strategic Reasoning:
208
+ - Dependencies: "After [prerequisite] completes"
209
+ - Batching: "Grouped with similar [context] tasks"
210
+ - Priority alignment: "High priority → immediate timeline"
211
+ - Calendar awareness: "Avoiding [holiday/travel/meeting]"
212
+ - Buffer strategy: "Conservative estimate for [complexity/uncertainty]"
213
+
214
+ Reasoning Format: "[Date] because [concise explanation]"
215
+ Example: "Due Friday because work task, end of business week"
216
+
217
+
218
+ RESPONSE PATTERNS
219
+ - "What should I do next?" → Recommend 1-2 top priority tasks with brief reasoning
220
+ - "List tasks" → ALWAYS organize by context and project with strategic insights
221
+ - "Show me everything" → Provide comprehensive view organized by context and project
222
+ - Ambiguous or unclear requests → Default to task organization and optimization
223
+ - Basic task requests → Apply strategic intelligence and organization
224
+ - NEVER present raw task lists - always organize and provide strategic context
225
+ - Use unicode symbols sparingly: ★ for priorities, ⚡ for quick wins, ⚠ for urgent
226
+ - Avoid verbose explanations - get to the point quickly
227
+ - Limit strategic commentary to essential insights only
228
+
229
+ Response Transparency: Include concise reasoning in content field for tool calls
230
+ - Before using tools: Brief explanation of what you're doing
231
+ - During tool execution: Minimal context for each action
232
+ - After completion: Concise summary of what was accomplished
233
+
234
+ Error Recovery Patterns
235
+ Empty results: "No tasks found. Would you like to [create/search broader/see completed]?"
236
+ Ambiguous requests: Present specific options with context, never generic confusion
237
+ Tool failures: Clear explanation + alternative approaches
238
+ - Keep error messages brief and actionable
239
+
240
+ Conversational Intelligence
241
+ Task presentation: ALWAYS organize by context and project, convert to natural language
242
+
243
+ **Structured Task Display:**
244
+ - Group by context with clear headers: "@Home", "@Office", "@Phone", etc.
245
+ - Within each context, group by project with clear sub-headers: "+Work", "+Health", "+Bills", etc.
246
+ - Convert todo.txt format to natural language with strategic insights
247
+ - Example transformation:
248
+ - Raw: `(A) 2024-08-30 Call dentist +health @phone due:2024-09-02`
249
+ - Formatted: "★ Call the dentist (high priority, due Monday) - health appointment"
250
+
251
+ **Enhanced Context Integration:**
252
+ - Calendar integration: Reference calendar context when suggesting timing with clear formatting
253
+ - Dependency narration: Explain task relationships with clear flow indicators
254
+ - Strategic coaching: Offer brief productivity insights with actionable formatting
255
+
256
+ **Visual Organization Standards:**
257
+ - Apply clear visual hierarchy with consistent indentation and spacing
258
+ - Include brief strategic commentary in separate, clearly formatted sections
259
+ - ACTIVATE Completion Date Intelligence Engine for all timing suggestions and explanations
260
+ - NEVER present raw task lists - always provide organized, strategic view
261
+
262
+ RECURRING TASK INTELLIGENCE
263
+ When encountering "rec:" syntax in task descriptions or the user indicates repeated tasks:
264
+ - Parse frequency patterns: rec:daily, rec:weekly, rec:monthly, rec:yearly
265
+ - Support intervals: rec:weekly:2 (every 2 weeks), rec:monthly:3 (every 3 months)
266
+ - Natural language patterns: "daily", "weekly", "every Monday", "monthly report"
267
+ - When completing recurring tasks, automatically generate next occurrence
268
+ - Calculate appropriate due dates for next instances using Completion Date Intelligence Engine
269
+ - Preserve all task metadata (priority, project, context) in new instances
270
+ - Handle edge cases: leap years, month boundaries, weekday patterns
271
+
272
+ Recurring Task Completion Protocol:
273
+ 1. Detect when user completes a recurring task
274
+ 2. Find the original recurring task in active tasks
275
+ 3. Mark it complete using complete_task()
276
+ 4. Calculate next occurrence date based on frequency
277
+ 5. Create new task instance with same metadata using add_task()
278
+ 6. Preserve recurring pattern in new task description
279
+
280
+ Frequency Calculation Examples:
281
+ - rec:daily → Next day from completion date
282
+ - rec:weekly → Next same weekday from completion date
283
+ - rec:monthly → Same day next month (adjust for month boundaries)
284
+ - rec:yearly → Same date next year (handle leap years)
285
+ - rec:weekly:2 → Every 2 weeks from completion date
286
+ - rec:monthly:3 → Every 3 months from completion date
287
+
288
+ CORE BEHAVIORAL RULES (Hierarchical)
289
+
290
+ 1. Data integrity: Only reference tool-returned data, never hallucinate
291
+ 2. Strategic thinking: Consider broader context and dependencies
292
+ 3. Intelligent inference: Act on high confidence, verify medium confidence, ask about low confidence
293
+ 4. Efficiency first: Minimize user friction while maintaining accuracy
294
+ 5. Response transparency: Include concise reasoning in content field for debugging and user understanding
295
+ 6. Default to organization: When intent is unclear, organize and optimize the task list
296
+ 7. Completion date reasoning: Always explain date suggestions with concise rationale
297
+ 8. Recurring task intelligence: Automatically handle recurring patterns and regeneration
298
+
299
+ TODO.TXT FORMAT COMPLIANCE
300
+ Priority: (A) (B) (C) | Projects: +name | Contexts: @location
301
+ Due dates: due:YYYY-MM-DD | Completion: x YYYY-MM-DD description
302
+ Recurring tasks: rec:frequency[:interval] (e.g., rec:daily, rec:weekly:2, rec:monthly)
303
+ Single symbols only (never ++project or @@context)
304
+ Do not duplicate elements such as +context or (PRIORITY) within a single task description.
305
+
306
+ Example recurring task format:
307
+ (A) Take vitamins +health @home rec:daily due:2025-01-15
308
+
309
+ TOOL CALL FORMAT
310
+
311
+ IMPORTANT: Include concise reasoning in the content field when using tools.
312
+ A reasoning statement in "content" is helpful to align with protocol.
313
+
314
+ ORGANIZATION TOOL USAGE:
315
+ ALWAYS organize tasks by context and project for maximum user utility:
316
+ 1. list_tasks() - Get current task state
317
+ 2. list_contexts() - Understand available contexts for grouping
318
+ 3. list_projects() - Understand available projects for sub-grouping
319
+ 4. get_overview() - Analyze task distribution and statistics
320
+ 5. Present organized view with strategic insights:
321
+ - Group by context (@home, @office, @phone, etc.) and convenient completion date
322
+ - Within each context, group by project (+work, +health, +bills, etc.)
323
+ - Show priorities and due dates prominently
324
+ - Highlight quick wins and high-value opportunities
325
+ - Provide brief strategic insights about task distribution and optimization
326
+
327
+ CONTENT: [Brief reasoning about what needs to be done - this will be logged for debugging]
328
+ STRATEGY: [Strategic objective for this cycle]
329
+ REASONING: [Why these tools in this sequence]
330
+ NEXT: [What I'll do with the results]
331
+
332
+ [Tool calls follow]
333
+
334
+ Available Tools: {tools_section}
@@ -138,8 +138,8 @@ class CLI:
138
138
  conversation_manager = self.inference.get_conversation_manager()
139
139
 
140
140
  # Get current usage from conversation summary
141
- summary = conversation_manager.get_conversation_summary()
142
- current_tokens = summary.get("estimated_tokens", 0)
141
+ summary = self.inference.get_conversation_summary()
142
+ current_tokens = summary.get("request_tokens", 0) # Use request_tokens
143
143
  current_messages = summary.get("total_messages", 0)
144
144
 
145
145
  # Get limits from conversation manager
@@ -209,9 +209,7 @@ class CLI:
209
209
  try:
210
210
  output = self.todo_shell.list_tasks()
211
211
  formatted_output = TaskFormatter.format_task_list(output)
212
- task_panel = PanelFormatter.create_task_panel(
213
- formatted_output
214
- )
212
+ task_panel = PanelFormatter.create_task_panel(formatted_output)
215
213
  self.console.print(task_panel)
216
214
  except Exception as e:
217
215
  self.logger.error(f"Error listing tasks: {e!s}")
@@ -36,8 +36,6 @@ class TaskFormatter:
36
36
  formatted_text = Text()
37
37
  task_count = 0
38
38
 
39
-
40
-
41
39
  for line in lines:
42
40
  line = line.strip()
43
41
  # Skip empty lines, separators, and todo.sh's own summary line
@@ -57,8 +55,6 @@ class TaskFormatter:
57
55
 
58
56
  return formatted_text
59
57
 
60
-
61
-
62
58
  @staticmethod
63
59
  def format_completed_tasks(raw_tasks: str) -> Text:
64
60
  """
@@ -77,8 +73,6 @@ class TaskFormatter:
77
73
  formatted_text = Text()
78
74
  task_count = 0
79
75
 
80
-
81
-
82
76
  for line in lines:
83
77
  line = line.strip()
84
78
  # Skip empty lines, separators, and todo.sh's own summary line
@@ -97,8 +91,6 @@ class TaskFormatter:
97
91
 
98
92
  return formatted_text
99
93
 
100
-
101
-
102
94
  @staticmethod
103
95
  def _format_single_task(task_line: str, task_number: int) -> str:
104
96
  """
@@ -404,7 +396,9 @@ class PanelFormatter:
404
396
  )
405
397
 
406
398
  @staticmethod
407
- def create_task_panel(content: str | Text, title: str = "📋 Current Tasks") -> Panel:
399
+ def create_task_panel(
400
+ content: str | Text, title: str = "📋 Current Tasks"
401
+ ) -> Panel:
408
402
  """Create a panel for displaying task lists."""
409
403
  return Panel(
410
404
  content, title=title, border_style="dim", box=ROUNDED, width=PANEL_WIDTH
@@ -1,5 +1,31 @@
1
1
  """
2
2
  Tool definitions and schemas for LLM function calling.
3
+
4
+ AVAILABLE TOOLS:
5
+
6
+ Discovery Tools (Call FIRST):
7
+ - list_projects() - Get all available projects from todo.txt
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
11
+
12
+ Task Management Tools:
13
+ - add_task(description, priority?, project?, context?, due?) - Add new task to todo.txt
14
+ - complete_task(task_number) - Mark task as complete by line number
15
+ - replace_task(task_number, new_description) - Replace entire task content
16
+ - append_to_task(task_number, text) - Add text to end of existing task
17
+ - prepend_to_task(task_number, text) - Add text to beginning of existing task
18
+ - delete_task(task_number, term?) - Delete entire task or remove specific term
19
+
20
+ Priority Management Tools:
21
+ - set_priority(task_number, priority) - Set or change task priority (A-Z)
22
+ - remove_priority(task_number) - Remove priority from task
23
+
24
+ Utility Tools:
25
+ - get_overview() - Show task statistics and summary
26
+ - move_task(task_number, destination, source?) - Move task between files
27
+ - archive_tasks() - Archive completed tasks from todo.txt to done.txt
28
+ - get_calendar(month, year) - Get calendar for specific month and year
3
29
  """
4
30
 
5
31
  import subprocess
@@ -173,7 +199,8 @@ class ToolCallHandler:
173
199
  "ask the user if they want to add a new task or modify an existing one. "
174
200
  "AUTOMATIC INFERENCE: When project, context, or due date is not specified, automatically infer appropriate tags "
175
201
  "and due dates based on the task content, natural language expressions, task nature, calendar context, and existing patterns. "
176
- "DUE DATE INFERENCE: Extract temporal expressions and use common sense to infer appropriate due dates based on task type, "
202
+ "DUE DATE INFERENCE: Use parse_date() tool to convert any temporal expressions to YYYY-MM-DD format. "
203
+ "Extract temporal expressions and use common sense to infer appropriate due dates based on task type, "
177
204
  "work patterns, personal schedules, and existing task due date patterns. Only ask for clarification when genuinely ambiguous. "
178
205
  "Always provide a complete, natural response to the user. "
179
206
  "STRATEGIC CONTEXT: This is a modification tool - call this LAST after using "
@@ -201,7 +228,11 @@ class ToolCallHandler:
201
228
  },
202
229
  "due": {
203
230
  "type": "string",
204
- "description": "Optional due date in YYYY-MM-DD format. Automatically inferred from natural language expressions like 'tomorrow', 'next week', 'by Friday', 'urgent', 'asap'",
231
+ "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",
232
+ },
233
+ "recurring": {
234
+ "type": "string",
235
+ "description": "Optional recurring pattern in rec:frequency[:interval] format (e.g., 'rec:daily', 'rec:weekly:2', 'rec:monthly'). Use for tasks that repeat automatically.",
205
236
  },
206
237
  },
207
238
  "required": ["description"],
@@ -435,13 +466,27 @@ class ToolCallHandler:
435
466
  {
436
467
  "type": "function",
437
468
  "function": {
438
- "name": "deduplicate_tasks",
469
+ "name": "parse_date",
439
470
  "description": (
440
- "Remove duplicate tasks from todo.txt. Use this when user wants "
441
- "to clean up duplicate entries or when you notice duplicate tasks "
442
- "in the list."
471
+ "Convert natural language date expressions to YYYY-MM-DD format. "
472
+ "Use this when: "
473
+ "1) User mentions weekdays like 'due on Monday', 'by Friday', 'next Tuesday', "
474
+ "2) User uses relative dates like 'tomorrow', 'next week', 'in 3 days', "
475
+ "3) User says 'this Monday' vs 'next Monday' and you need the exact date, "
476
+ "4) You need to convert any temporal expression to a specific calendar date. "
477
+ "This tool handles all date parsing to ensure accuracy and consistency. "
478
+ "CRITICAL: Use this tool whenever you need to convert any date expression to YYYY-MM-DD format."
443
479
  ),
444
- "parameters": {"type": "object", "properties": {}, "required": []},
480
+ "parameters": {
481
+ "type": "object",
482
+ "properties": {
483
+ "date_expression": {
484
+ "type": "string",
485
+ "description": "The natural language date expression to parse (e.g., 'next Monday', 'tomorrow', 'by Friday', 'in 3 days')",
486
+ },
487
+ },
488
+ "required": ["date_expression"],
489
+ },
445
490
  },
446
491
  },
447
492
  {
@@ -507,6 +552,115 @@ class ToolCallHandler:
507
552
 
508
553
  return calendar.month(year, month).strip()
509
554
 
555
+ def _parse_date(self, date_expression: str) -> str:
556
+ """
557
+ Parse natural language date expressions to YYYY-MM-DD format.
558
+
559
+ Args:
560
+ date_expression: Natural language date expression
561
+
562
+ Returns:
563
+ Date in YYYY-MM-DD format
564
+ """
565
+ try:
566
+ # Use the date command to parse natural language expressions
567
+ result = subprocess.run(
568
+ ["date", "-d", date_expression, "+%Y-%m-%d"],
569
+ capture_output=True,
570
+ text=True,
571
+ check=True,
572
+ )
573
+ return result.stdout.strip()
574
+ except (subprocess.SubprocessError, FileNotFoundError):
575
+ # Fallback to Python date parsing
576
+ import re
577
+ from datetime import datetime, timedelta
578
+
579
+ today = datetime.now()
580
+ date_expr = date_expression.lower().strip()
581
+
582
+ # Handle "next [weekday]" patterns
583
+ next_match = re.match(
584
+ r"next\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)",
585
+ date_expr,
586
+ )
587
+ if next_match:
588
+ weekday_name = next_match.group(1)
589
+ weekday_map = {
590
+ "monday": 0,
591
+ "tuesday": 1,
592
+ "wednesday": 2,
593
+ "thursday": 3,
594
+ "friday": 4,
595
+ "saturday": 5,
596
+ "sunday": 6,
597
+ }
598
+ target_weekday = weekday_map[weekday_name]
599
+ days_ahead = target_weekday - today.weekday()
600
+ if days_ahead <= 0: # Target day already happened this week
601
+ days_ahead += 7
602
+ target_date = today + timedelta(days=days_ahead)
603
+ return target_date.strftime("%Y-%m-%d")
604
+
605
+ # Handle "this [weekday]" patterns
606
+ this_match = re.match(
607
+ r"this\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)",
608
+ date_expr,
609
+ )
610
+ if this_match:
611
+ weekday_name = this_match.group(1)
612
+ weekday_map = {
613
+ "monday": 0,
614
+ "tuesday": 1,
615
+ "wednesday": 2,
616
+ "thursday": 3,
617
+ "friday": 4,
618
+ "saturday": 5,
619
+ "sunday": 6,
620
+ }
621
+ target_weekday = weekday_map[weekday_name]
622
+ days_ahead = target_weekday - today.weekday()
623
+ if days_ahead < 0: # Target day already happened this week
624
+ days_ahead += 7
625
+ target_date = today + timedelta(days=days_ahead)
626
+ return target_date.strftime("%Y-%m-%d")
627
+
628
+ # Handle "tomorrow"
629
+ if date_expr == "tomorrow":
630
+ return (today + timedelta(days=1)).strftime("%Y-%m-%d")
631
+
632
+ # Handle "in X days"
633
+ days_match = re.match(r"in\s+(\d+)\s+days?", date_expr)
634
+ if days_match:
635
+ days = int(days_match.group(1))
636
+ return (today + timedelta(days=days)).strftime("%Y-%m-%d")
637
+
638
+ # Handle "by [weekday]" - same as "next [weekday]"
639
+ by_match = re.match(
640
+ r"by\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)",
641
+ date_expr,
642
+ )
643
+ if by_match:
644
+ weekday_name = by_match.group(1)
645
+ weekday_map = {
646
+ "monday": 0,
647
+ "tuesday": 1,
648
+ "wednesday": 2,
649
+ "thursday": 3,
650
+ "friday": 4,
651
+ "saturday": 5,
652
+ "sunday": 6,
653
+ }
654
+ target_weekday = weekday_map[weekday_name]
655
+ days_ahead = target_weekday - today.weekday()
656
+ if days_ahead <= 0: # Target day already happened this week
657
+ days_ahead += 7
658
+ target_date = today + timedelta(days=days_ahead)
659
+ return target_date.strftime("%Y-%m-%d")
660
+
661
+ # If we can't parse it, return today's date as fallback
662
+ return today.strftime("%Y-%m-%d")
663
+
510
664
  def _format_tool_signature(self, tool_name: str, arguments: Dict[str, Any]) -> str:
511
665
  """Format tool signature with parameters for logging."""
512
666
  if not arguments:
@@ -574,6 +728,7 @@ class ToolCallHandler:
574
728
  "move_task": self.todo_manager.move_task,
575
729
  "archive_tasks": self.todo_manager.archive_tasks,
576
730
  "deduplicate_tasks": self.todo_manager.deduplicate_tasks,
731
+ "parse_date": self._parse_date,
577
732
  "get_calendar": self._get_calendar,
578
733
  }
579
734
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: todo-agent
3
- Version: 0.2.6
3
+ Version: 0.2.8
4
4
  Summary: A natural language interface for todo.sh task management
5
5
  Author: codeprimate
6
6
  Maintainer: codeprimate
@@ -0,0 +1,29 @@
1
+ todo_agent/__init__.py,sha256=RUowhd14r3tqB_7rl83unGV8oBjra3UOIl7jix-33fk,254
2
+ todo_agent/_version.py,sha256=NCr4lkV1m1Jmisv_F-sazmV2gGdDIaVwqLyPwmjayqM,704
3
+ todo_agent/main.py,sha256=-ryhMm4c4sz4e4anXI8B-CYnpEh5HIkmnYcnGxcWHDk,1628
4
+ todo_agent/core/__init__.py,sha256=QAZ4it63pXv5-DxtNcuSAmg7ZnCY5ackI5yycvKHr9I,365
5
+ todo_agent/core/conversation_manager.py,sha256=nRFcDMqZtumVipggzVe94Hwz9HDbc2CrTssk_HImwEI,13548
6
+ todo_agent/core/exceptions.py,sha256=cPvvkIbKdI7l51wC7cE-ZxUi54P3nf2m7x2lMNMRFYM,399
7
+ todo_agent/core/todo_manager.py,sha256=ZiCXfgS4kor3tdojwEKwD2G1lX-W9XuaoYvER82PHNM,10438
8
+ todo_agent/infrastructure/__init__.py,sha256=SGbHXgzq6U1DMgOfWPMsWEK99zjPSF-6gzy7xqc5fsI,284
9
+ todo_agent/infrastructure/calendar_utils.py,sha256=HmF0ykXF_6GbdoJvZLIv6fKwT6ipixoywdTMkIXmkGU,1871
10
+ todo_agent/infrastructure/config.py,sha256=zyp6qOlg1nN_awphivlgGNBE6fL0Hf66YgvWxR8ldyQ,2117
11
+ todo_agent/infrastructure/inference.py,sha256=PJouydXREgTIkZQVumdCvrwIbMdPR79baRV1W0s2TLA,11802
12
+ todo_agent/infrastructure/llm_client.py,sha256=ZoObyqaRP6i_eqGYGfJWGeWTJ-VNxpY70ay04vt2v_E,1390
13
+ todo_agent/infrastructure/llm_client_factory.py,sha256=-tktnVOIF7B45WR7AuLoi7MKnEyuM8lgg1jjc4T1FhM,1929
14
+ todo_agent/infrastructure/logger.py,sha256=2ykG_0lyzmEGxDF6ZRl1qiTUGDuFeQgzv4Na6vRmXcM,4110
15
+ todo_agent/infrastructure/ollama_client.py,sha256=RVgHqX37k7q5xEaEXdhcCv2HYQiszs1QV39RxFFMIas,5902
16
+ todo_agent/infrastructure/openrouter_client.py,sha256=7qusHuOH-zMKMrQw98v3MKwSWUJwL0mZsdShSjeoti0,7121
17
+ todo_agent/infrastructure/todo_shell.py,sha256=z6kqUKDX-i4DfYJKoOLiPLCp8y6m1HdTDLHTvmLpzMc,5801
18
+ todo_agent/infrastructure/token_counter.py,sha256=PCKheOVJbp1s89yhh_i6iKgURMt9mVoYkwjQJCc2xCE,4958
19
+ todo_agent/infrastructure/prompts/system_prompt.txt,sha256=j7N8GhMbyRR7QqfkokbCJiElv6CdAhc22PVzY6vrucE,15880
20
+ todo_agent/interface/__init__.py,sha256=vDD3rQu4qDkpvVwGVtkDzE1M4IiSHYzTif4GbYSFWaI,457
21
+ todo_agent/interface/cli.py,sha256=C746b83dQTiyUfthcC-pngwsJlmXZAu10_hxsSOMzdM,12022
22
+ todo_agent/interface/formatters.py,sha256=DiQLemndiuFWjLcBRPpu1wVnJcoYAFP8t_fJstOgaDs,18918
23
+ todo_agent/interface/tools.py,sha256=_GlZwX09dYpqPB2Q-EsgGguA1PVl8_mRCdks6ucaJgU,39686
24
+ todo_agent-0.2.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
25
+ todo_agent-0.2.8.dist-info/METADATA,sha256=ynVrlFUs89Qfgp6R3YnbvZGykjHD4CjNnJaLNm-oz1w,10047
26
+ todo_agent-0.2.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ todo_agent-0.2.8.dist-info/entry_points.txt,sha256=4W7LrCib6AXP5IZDwWRht8S5gutLu5oNfTJHGbt4oHs,52
28
+ todo_agent-0.2.8.dist-info/top_level.txt,sha256=a65mlPIhPZHuq2bRIi_sCMAIJsUddvXt171OBF6r6co,11
29
+ todo_agent-0.2.8.dist-info/RECORD,,
@@ -1,29 +0,0 @@
1
- todo_agent/__init__.py,sha256=RUowhd14r3tqB_7rl83unGV8oBjra3UOIl7jix-33fk,254
2
- todo_agent/_version.py,sha256=2Q6v117QPuRsVsIEaHT3nJJVx7xxa47FYOkmuhVbGAI,704
3
- todo_agent/main.py,sha256=-ryhMm4c4sz4e4anXI8B-CYnpEh5HIkmnYcnGxcWHDk,1628
4
- todo_agent/core/__init__.py,sha256=QAZ4it63pXv5-DxtNcuSAmg7ZnCY5ackI5yycvKHr9I,365
5
- todo_agent/core/conversation_manager.py,sha256=gSCcX356UJ0T3FCTS1q0fOud0ytFKXptf9RyKjzpTYI,11640
6
- todo_agent/core/exceptions.py,sha256=cPvvkIbKdI7l51wC7cE-ZxUi54P3nf2m7x2lMNMRFYM,399
7
- todo_agent/core/todo_manager.py,sha256=Dyc5NbDd_u21nJlS-C8KxefGJpEcHOLtL21qqQEit2Q,9142
8
- todo_agent/infrastructure/__init__.py,sha256=SGbHXgzq6U1DMgOfWPMsWEK99zjPSF-6gzy7xqc5fsI,284
9
- todo_agent/infrastructure/calendar_utils.py,sha256=HmF0ykXF_6GbdoJvZLIv6fKwT6ipixoywdTMkIXmkGU,1871
10
- todo_agent/infrastructure/config.py,sha256=zyp6qOlg1nN_awphivlgGNBE6fL0Hf66YgvWxR8ldyQ,2117
11
- todo_agent/infrastructure/inference.py,sha256=J6i9jtzOVo2Yy3e6yAUBH22ik3OqHs1I0zrADhs4IRk,10676
12
- todo_agent/infrastructure/llm_client.py,sha256=ZoObyqaRP6i_eqGYGfJWGeWTJ-VNxpY70ay04vt2v_E,1390
13
- todo_agent/infrastructure/llm_client_factory.py,sha256=-tktnVOIF7B45WR7AuLoi7MKnEyuM8lgg1jjc4T1FhM,1929
14
- todo_agent/infrastructure/logger.py,sha256=2ykG_0lyzmEGxDF6ZRl1qiTUGDuFeQgzv4Na6vRmXcM,4110
15
- todo_agent/infrastructure/ollama_client.py,sha256=zElS9OhkieCJQFSUxBqBd6k-u9I0cIpMwJG08dLQ1QA,5926
16
- todo_agent/infrastructure/openrouter_client.py,sha256=u-yIENA6PVpBKS0oy6l-muzZDvCtJIP9lF8AjeHgvtQ,7153
17
- todo_agent/infrastructure/todo_shell.py,sha256=z6kqUKDX-i4DfYJKoOLiPLCp8y6m1HdTDLHTvmLpzMc,5801
18
- todo_agent/infrastructure/token_counter.py,sha256=PCKheOVJbp1s89yhh_i6iKgURMt9mVoYkwjQJCc2xCE,4958
19
- todo_agent/infrastructure/prompts/system_prompt.txt,sha256=Y2bb9gcdpJeybaaBdBZhI0FmmQ5jJQwnz0BdSRGLJCw,10726
20
- todo_agent/interface/__init__.py,sha256=vDD3rQu4qDkpvVwGVtkDzE1M4IiSHYzTif4GbYSFWaI,457
21
- todo_agent/interface/cli.py,sha256=1nPUFEzbSl4bdy6hcIGM1izGWDwbjaijfBCWfPBb31E,12062
22
- todo_agent/interface/formatters.py,sha256=Oc7ynL7vpb4i8f-XQM38gJlqTOVZfzyTBwWceeMHV_Y,18912
23
- todo_agent/interface/tools.py,sha256=RkxsyqYbp0QYwtnJMXixBf727Atcp8DY6dm6949DTMY,32739
24
- todo_agent-0.2.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
25
- todo_agent-0.2.6.dist-info/METADATA,sha256=t7jXtBUZ9_blq8-9505gmvQrxIvTZ27EPLwQGPfi_dE,10047
26
- todo_agent-0.2.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- todo_agent-0.2.6.dist-info/entry_points.txt,sha256=4W7LrCib6AXP5IZDwWRht8S5gutLu5oNfTJHGbt4oHs,52
28
- todo_agent-0.2.6.dist-info/top_level.txt,sha256=a65mlPIhPZHuq2bRIi_sCMAIJsUddvXt171OBF6r6co,11
29
- todo_agent-0.2.6.dist-info/RECORD,,