Skip to content

Commit 43418aa

Browse files
committed
todo.
1 parent 7d985cd commit 43418aa

3 files changed

Lines changed: 229 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Agent Development Guidelines
2+
3+
## File System Usage
4+
5+
### Workspace Directory Convention
6+
7+
When developing agents and tools that need to store persistent data or work with files, **always use `.minion_workspace`** as the default directory instead of other directory names.
8+
9+
#### Why .minion_workspace?
10+
11+
- **Consistency**: All agents and tools use the same workspace directory
12+
- **Organization**: Keeps agent-related files separate from project files
13+
- **Predictability**: Users know where to find agent-generated files
14+
- **Cleanup**: Easy to identify and manage agent workspace files
15+
16+
#### Examples
17+
18+
**✅ Correct Usage:**
19+
```python
20+
# In todo storage
21+
class TodoStorage:
22+
def __init__(self, storage_dir: str = ".minion_workspace"):
23+
self.storage_dir = storage_dir
24+
os.makedirs(storage_dir, exist_ok=True)
25+
26+
# In file tools
27+
def save_agent_data(data, filename):
28+
workspace_dir = ".minion_workspace"
29+
os.makedirs(workspace_dir, exist_ok=True)
30+
filepath = os.path.join(workspace_dir, filename)
31+
# ... save data
32+
```
33+
34+
**❌ Avoid:**
35+
```python
36+
# Don't use custom directory names
37+
storage_dir = ".minion_todos" # Too specific
38+
storage_dir = ".agent_data" # Not standardized
39+
storage_dir = "temp_files" # Not clearly agent-related
40+
```
41+
42+
### File Naming Conventions
43+
44+
Within `.minion_workspace`, use descriptive filenames that include:
45+
- Agent ID or identifier when relevant
46+
- File type or purpose
47+
- Appropriate file extensions
48+
49+
Examples:
50+
- `todos_agent_123.json` - Todo data for specific agent
51+
- `memory_default.json` - Default memory storage
52+
- `logs_session_456.txt` - Session logs
53+
54+
### Implementation Notes
55+
56+
- Always create the `.minion_workspace` directory if it doesn't exist
57+
- Handle file permissions and access errors gracefully
58+
- Use appropriate file formats (JSON for structured data, TXT for logs)
59+
- Include proper error handling for file operations
60+
61+
### Migration
62+
63+
If you have existing tools using other directory names:
64+
1. Update the default directory to `.minion_workspace`
65+
2. Consider migration logic for existing data
66+
3. Update documentation and examples
67+
4. Test with existing agent configurations
68+
#
69+
# Migration from .minion_todos
70+
71+
If you have existing data in `.minion_todos`, you can migrate it to `.minion_workspace`:
72+
73+
```bash
74+
# Copy existing todo files
75+
mkdir -p .minion_workspace
76+
cp .minion_todos/*.json .minion_workspace/
77+
78+
# Verify migration
79+
ls -la .minion_workspace/
80+
```
81+
82+
The todo tools have been updated to use `.minion_workspace` by default, so existing todo data will continue to work after migration.

minion_code/utils/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Utils package

minion_code/utils/todo_storage.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
"""Todo storage utilities for managing todo items."""
2+
3+
import json
4+
import os
5+
from typing import List, Dict, Any, Optional
6+
from dataclasses import dataclass, asdict
7+
from enum import Enum
8+
9+
10+
class TodoStatus(Enum):
11+
PENDING = "pending"
12+
IN_PROGRESS = "in_progress"
13+
COMPLETED = "completed"
14+
15+
16+
class TodoPriority(Enum):
17+
HIGH = "high"
18+
MEDIUM = "medium"
19+
LOW = "low"
20+
21+
22+
@dataclass
23+
class TodoItem:
24+
id: str
25+
content: str
26+
status: TodoStatus
27+
priority: TodoPriority
28+
29+
def to_dict(self) -> Dict[str, Any]:
30+
return {
31+
"id": self.id,
32+
"content": self.content,
33+
"status": self.status.value,
34+
"priority": self.priority.value
35+
}
36+
37+
@classmethod
38+
def from_dict(cls, data: Dict[str, Any]) -> 'TodoItem':
39+
return cls(
40+
id=data["id"],
41+
content=data["content"],
42+
status=TodoStatus(data["status"]),
43+
priority=TodoPriority(data["priority"])
44+
)
45+
46+
47+
class TodoStorage:
48+
def __init__(self, storage_dir: str = ".minion_workspace"):
49+
self.storage_dir = storage_dir
50+
os.makedirs(storage_dir, exist_ok=True)
51+
52+
def _get_file_path(self, agent_id: Optional[str] = None) -> str:
53+
filename = f"todos_{agent_id}.json" if agent_id else "todos_default.json"
54+
return os.path.join(self.storage_dir, filename)
55+
56+
def get_todos(self, agent_id: Optional[str] = None) -> List[TodoItem]:
57+
"""Get all todos for a specific agent or default."""
58+
file_path = self._get_file_path(agent_id)
59+
60+
if not os.path.exists(file_path):
61+
return []
62+
63+
try:
64+
with open(file_path, 'r', encoding='utf-8') as f:
65+
data = json.load(f)
66+
return [TodoItem.from_dict(item) for item in data]
67+
except (json.JSONDecodeError, KeyError, ValueError):
68+
return []
69+
70+
def set_todos(self, todos: List[TodoItem], agent_id: Optional[str] = None) -> None:
71+
"""Set todos for a specific agent or default."""
72+
file_path = self._get_file_path(agent_id)
73+
74+
data = [todo.to_dict() for todo in todos]
75+
76+
with open(file_path, 'w', encoding='utf-8') as f:
77+
json.dump(data, f, indent=2, ensure_ascii=False)
78+
79+
def add_todo(self, todo: TodoItem, agent_id: Optional[str] = None) -> None:
80+
"""Add a new todo."""
81+
todos = self.get_todos(agent_id)
82+
todos.append(todo)
83+
self.set_todos(todos, agent_id)
84+
85+
def update_todo(self, todo_id: str, updates: Dict[str, Any], agent_id: Optional[str] = None) -> bool:
86+
"""Update a specific todo. Returns True if found and updated."""
87+
todos = self.get_todos(agent_id)
88+
89+
for todo in todos:
90+
if todo.id == todo_id:
91+
if 'content' in updates:
92+
todo.content = updates['content']
93+
if 'status' in updates:
94+
todo.status = TodoStatus(updates['status'])
95+
if 'priority' in updates:
96+
todo.priority = TodoPriority(updates['priority'])
97+
98+
self.set_todos(todos, agent_id)
99+
return True
100+
101+
return False
102+
103+
def remove_todo(self, todo_id: str, agent_id: Optional[str] = None) -> bool:
104+
"""Remove a todo by ID. Returns True if found and removed."""
105+
todos = self.get_todos(agent_id)
106+
original_length = len(todos)
107+
108+
todos = [todo for todo in todos if todo.id != todo_id]
109+
110+
if len(todos) < original_length:
111+
self.set_todos(todos, agent_id)
112+
return True
113+
114+
return False
115+
116+
def clear_todos(self, agent_id: Optional[str] = None) -> None:
117+
"""Clear all todos for a specific agent."""
118+
self.set_todos([], agent_id)
119+
120+
121+
# Global storage instance
122+
_storage = TodoStorage()
123+
124+
def get_todos(agent_id: Optional[str] = None) -> List[TodoItem]:
125+
"""Get todos from global storage."""
126+
return _storage.get_todos(agent_id)
127+
128+
def set_todos(todos: List[TodoItem], agent_id: Optional[str] = None) -> None:
129+
"""Set todos in global storage."""
130+
_storage.set_todos(todos, agent_id)
131+
132+
def add_todo(todo: TodoItem, agent_id: Optional[str] = None) -> None:
133+
"""Add todo to global storage."""
134+
_storage.add_todo(todo, agent_id)
135+
136+
def update_todo(todo_id: str, updates: Dict[str, Any], agent_id: Optional[str] = None) -> bool:
137+
"""Update todo in global storage."""
138+
return _storage.update_todo(todo_id, updates, agent_id)
139+
140+
def remove_todo(todo_id: str, agent_id: Optional[str] = None) -> bool:
141+
"""Remove todo from global storage."""
142+
return _storage.remove_todo(todo_id, agent_id)
143+
144+
def clear_todos(agent_id: Optional[str] = None) -> None:
145+
"""Clear all todos in global storage."""
146+
_storage.clear_todos(agent_id)

0 commit comments

Comments
 (0)