6.9 KiB
Agent Tasks: Short-Term Memory via Context-Injected Task List
Summary
Add a tasks system that serves as the agent's short-term working memory. The agent can break down goals into steps, track progress, and see its current task list in every prompt context. Tasks are file-backed (not stored on Nostr) and managed via a dedicated task_manage tool.
How It Works
flowchart TD
A[User sends message] --> B[Context builder runs]
B --> C[Template resolver hits tasks_content variable]
C --> D[Read tasks.json from disk]
D --> E{Tasks exist?}
E -->|Yes| F[Format tasks as readable text]
E -->|No| G[Return empty string - section skipped]
F --> H[Inject as system message in prompt]
G --> H
H --> I[LLM sees current tasks in context]
I --> J{LLM decides to update tasks?}
J -->|Yes| K[LLM calls task_manage tool]
K --> L[Tool updates tasks.json on disk]
L --> M[Tool result returned to LLM]
J -->|No| N[LLM responds normally]
Design
Storage: tasks.json
A simple JSON file in the agent's working directory. Structure:
{
"tasks": [
{
"id": 1,
"text": "Query admin relay list to find active relays",
"status": "done",
"created_at": 1709535600,
"updated_at": 1709535660
},
{
"id": 2,
"text": "Draft long-form article about Nostr relay setup",
"status": "active",
"created_at": 1709535600,
"updated_at": 1709535600
},
{
"id": 3,
"text": "Publish article as kind 30023",
"status": "pending",
"created_at": 1709535600,
"updated_at": 1709535600
}
],
"next_id": 4
}
Task statuses: pending, active, done
Tool: task_manage
A single tool with an action parameter that covers all operations:
| Action | Parameters | Description |
|---|---|---|
list |
(none) | Return all tasks with status |
add |
text, optional status |
Add a new task, default status pending |
update |
id, optional text, optional status |
Update text and/or status of a task |
remove |
id |
Remove a task by ID |
clear |
optional status |
Remove all tasks, or all with a given status |
replace |
tasks (array of text strings) |
Replace entire task list with new items |
The replace action is important — it lets the LLM rewrite the whole plan in one call rather than doing add/remove/update one at a time. This is the most common pattern: the agent works out a plan and writes all steps at once.
Tool schema:
{
"name": "task_manage",
"description": "Manage the agent task list - short-term working memory for tracking steps in a plan. Tasks appear in your context on every message.",
"parameters": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["list", "add", "update", "remove", "clear", "replace"]
},
"text": { "type": "string" },
"id": { "type": "integer" },
"status": { "type": "string", "enum": ["pending", "active", "done"] },
"tasks": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["action"]
}
}
Context Section: agent_tasks
New section in the context template, placed after adopted_skills and before dm_history:
- section: agent_tasks
role: system
skip_if_empty: true
content: |
{{tasks_content}}
Template Variable: {{tasks_content}}
New resolver in agent_template_resolve_var() that:
- Reads
tasks.jsonfrom the working directory - Parses the JSON
- Formats active/pending tasks as readable text
- Returns empty string if no tasks exist (section gets skipped via
skip_if_empty)
Rendered format in context:
### Current Tasks
Your active task list - short-term working memory for tracking plan steps.
- [x] 1. Query admin relay list to find active relays
- [-] 2. Draft long-form article about Nostr relay setup
- [ ] 3. Publish article as kind 30023
Legend: [x] = done, [-] = active, [ ] = pending
Done tasks are included so the agent has continuity about what it already accomplished, but they could be pruned after a configurable count or age to save tokens.
System Prompt Addition
Add to the agent's behavioral rules in the soul/system prompt:
### Task Management
- You have a task list that serves as your short-term working memory.
- When working on multi-step goals, use task_manage to track your plan.
- Update task status as you complete steps.
- Your current tasks appear in your context automatically.
Implementation Steps
1. Add task_manage tool implementation in tools.c
- New
execute_task_manage()function - Reads/writes
tasks.jsonin the working directory (usesbuild_tool_pathfor sandboxing) - Handles all 6 actions: list, add, update, remove, clear, replace
- Returns JSON result with success/failure and current task list
2. Register task_manage tool schema in tools_build_openai_schema_json()
- Add tool definition (t35 or next available) with the schema above
3. Wire task_manage into tools_execute() dispatch
- Add
strcmp(tool_name, "task_manage")branch callingexecute_task_manage()
4. Add {{tasks_content}} template variable resolver in agent.c
- New
build_tasks_content_string()function - Reads
tasks.json, formats as markdown checklist - Add to
agent_template_resolve_var()for var nametasks_content
5. Add agent_tasks section to context template
- Add the new section in
context_template.md - Place after
adopted_skills, beforedm_history - Use
skip_if_empty: trueso it costs zero tokens when no tasks exist
6. Add section detection for context logging
- Add
agent_tasksdetection indetect_context_section()inagent.c
7. Add task management guidance to system prompt
- Brief behavioral instruction so the agent knows when/how to use the task list
Token Budget Considerations
- Empty task list: 0 tokens (skipped via
skip_if_empty) - Typical 5-task plan: ~80-120 tokens
- Maximum reasonable list of 15 tasks: ~250-350 tokens
- Consider pruning done tasks older than N turns or keeping only the last M done tasks
Future: User-Facing To-Do List (Nostr)
This is explicitly not the user-facing to-do list. That future feature would:
- Store items as Nostr events (likely a NIP-51 style list or custom kind)
- Be visible to the user via Nostr clients
- Have its own separate tool (
todo_manageor similar) - Potentially reference agent tasks that graduate to user-visible items
The agent tasks system is purely internal working memory.
Files Modified
| File | Change |
|---|---|
src/tools.c |
Add execute_task_manage(), tool schema, dispatch entry |
src/agent.c |
Add build_tasks_content_string(), resolver entry, section detection |
context_template.md |
Add agent_tasks section |
| Soul/system prompt (kind 31120) | Add task management behavioral guidance |