/** * Todo Tools - Task management for agents * * Provides in-memory task tracking with TodoRead and TodoWrite tools. * Useful for planning and tracking multi-step tasks. */ import type { Tool } from '../types.js'; /** * Task status */ export type TodoStatus = 'pending' | 'in_progress' | 'completed'; /** * A single todo item */ export interface TodoItem { /** * Unique identifier for the todo */ id: string; /** * Task content/description (imperative form) */ content: string; /** * Current status of the task */ status: TodoStatus; /** * Active form of the task (present continuous, e.g., "Implementing feature") */ activeForm?: string; /** * Optional priority (higher = more important) */ priority?: number; /** * Owner agent ID (e.g., 'pm', 'arch', 'dev') * If undefined/null, the task is unassigned */ owner?: string; /** * 1-based task numbers this task is blocked by. * References positions in the todo array. */ blockedBy?: number[]; /** * Creation timestamp */ createdAt: Date; /** * Last update timestamp */ updatedAt: Date; } /** * Input for TodoWrite tool */ export interface TodoWriteInput { /** * The complete list of todos (replaces existing list) */ todos: Array<{ content: string; status: TodoStatus; activeForm?: string; priority?: number; owner?: string; blockedBy?: number[]; }>; } /** * Input for TodoRead tool */ export interface TodoReadInput { /** * Filter by status (optional) */ status?: TodoStatus; /** * Include completed tasks (default: true) */ includeCompleted?: boolean; /** * Filter by owner (optional) * - Specific agent ID: Return only tasks owned by that agent * - 'unassigned': Return only tasks without an owner * - undefined: Return all tasks (no filter) */ owner?: string; } /** * TodoStore manages the in-memory task list */ export declare class TodoStore { private readonly todos; private nextId; /** * Get all todos */ getAll(): TodoItem[]; /** * Get todos filtered by status */ getByStatus(status: TodoStatus): TodoItem[]; /** * Get todos filtered by owner * @param owner - Agent ID, or 'unassigned' for tasks without owner */ getByOwner(owner: string): TodoItem[]; /** * Replace all todos with a new list */ setAll(todos: Array<{ content: string; status: TodoStatus; activeForm?: string; priority?: number; owner?: string; blockedBy?: number[]; }>): void; /** * Add a single todo */ add(todo: { content: string; status: TodoStatus; activeForm?: string; priority?: number; owner?: string; blockedBy?: number[]; }): TodoItem; /** * Update a todo by ID */ update(id: string, updates: Partial>): TodoItem | null; /** * Remove a todo by ID */ remove(id: string): boolean; /** * Clear all todos */ clear(): void; /** * Get count by status */ getCounts(): Record; /** * Get counts by owner * Returns a map of owner ID to count * 'unassigned' key contains count of todos without owner */ getCountsByOwner(): Record; } /** * TodoWrite tool - Update the task list */ export declare const todoWriteTool: Tool; /** * TodoRead tool - Get the current task list */ export declare const todoReadTool: Tool; /** * Input for TodoClaim tool */ export interface TodoClaimInput { /** * The todo ID to claim */ todoId: string; /** * The agent ID claiming the todo */ agentId: string; } /** * Input for TodoHandoff tool */ export interface TodoHandoffInput { /** * The todo ID to hand off */ todoId: string; /** * The agent ID to hand off to */ toAgentId: string; /** * Optional notes about the handoff */ notes?: string; } /** * Factory to create todo tools with a custom store */ export declare function createTodoTools(store?: TodoStore): { todoWrite: Tool; todoRead: Tool; todoClaim: Tool; todoHandoff: Tool; store: TodoStore; }; /** * Reset the default store (useful for testing) */ export declare function resetDefaultTodoStore(): void; /** * Get the default store (useful for testing or direct access) */ export declare function getDefaultTodoStore(): TodoStore; /** * Create a new isolated TodoStore instance. * * Use this when you need state isolation between parallel operations, * such as concurrent sub-agent executions. This prevents state leakage * between parallel runs. * * Inspired by LangGraph issue #6446: Parallel subgraphs with shared * state keys cause InvalidUpdateError. * * @example * ```typescript * // For parallel sub-agents, create isolated stores * const store1 = createIsolatedTodoStore(); * const store2 = createIsolatedTodoStore(); * * // Each sub-agent uses its own store * await Promise.all([ * runWithStore(store1, task1), * runWithStore(store2, task2), * ]); * ``` */ export declare function createIsolatedTodoStore(): TodoStore; /** * Context cleanup options for todo tool calls */ export interface TodoContextCleanupOptions { /** * Keep only the last N todo_write calls (default: 1) */ keepLastN?: number; /** * Also clean up todo_read calls (default: false) */ cleanReads?: boolean; } /** * Filter messages to remove redundant todo tool calls. * This helps prevent context bloat from repeated todo_write calls. * * The function keeps only the last N todo_write calls (default: 1), * removing earlier ones to reduce context size. * * @param messages - Array of messages to filter * @param options - Cleanup options * @returns Filtered messages with redundant todo calls removed */ export declare function cleanupTodoContextMessages(messages: T[], options?: TodoContextCleanupOptions): T[]; /** * Get statistics about todo tool usage in messages */ export declare function getTodoContextStats(messages: Array<{ role: string; content: unknown; }>): { todoWriteCalls: number; todoReadCalls: number; estimatedTokensSaved: number; };