Files
didactyl/plans/agent_tasks.md

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:

  1. Reads tasks.json from the working directory
  2. Parses the JSON
  3. Formats active/pending tasks as readable text
  4. 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.json in the working directory (uses build_tool_path for 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 calling execute_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 name tasks_content

5. Add agent_tasks section to context template

  • Add the new section in context_template.md
  • Place after adopted_skills, before dm_history
  • Use skip_if_empty: true so it costs zero tokens when no tasks exist

6. Add section detection for context logging

  • Add agent_tasks detection in detect_context_section() in agent.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_manage or 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