رفتن به محتوا

فهرست‌های Todo

ردیابی todo راهی ساختاریافته برای مدیریت کارها و نمایش پیشرفت به کاربران فراهم می‌کند. Claude Agent SDK یک قابلیت todoیِ داخلی دارد که به سازماندهیِ ورک‌فلوهای پیچیده و باخبر نگه‌داشتنِ کاربران از روند پیشرفتِ کار کمک می‌کند.

todoها از یک چرخه‌ی عمرِ قابل‌پیش‌بینی پیروی می‌کنند:

  1. هنگام شناسایی کارها به‌عنوان pending ایجاد می‌شوند
  2. هنگام شروع کار به in_progress فعال می‌شوند
  3. وقتی کار با موفقیت تمام شد تکمیل می‌شوند
  4. وقتی همه‌ی کارهای یک گروه تکمیل شدند حذف می‌شوند

چه زمانی todoها به کار می‌روند

Section titled “چه زمانی todoها به کار می‌روند”

این SDK به‌طور خودکار برای این موارد todo می‌سازد:

  • کارهای پیچیده‌ی چندمرحله‌ای که به ۳ اقدام مجزا یا بیشتر نیاز دارند
  • فهرست‌های کاریِ ارائه‌شده توسط کاربر وقتی چند مورد ذکر شده باشد
  • عملیاتِ غیرپیش‌پاافتاده که از ردیابیِ پیشرفت بهره می‌برند
  • درخواست‌های صریح وقتی کاربران سازماندهیِ todo را می‌خواهند
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Optimize my React app performance and track progress with todos",
// Re-enable TodoWrite, which this example monitors. Without it, the SDK uses
// Task tools instead and these tool_use blocks never appear.
options: { maxTurns: 15, env: { ...process.env, CLAUDE_CODE_ENABLE_TASKS: "0" } }
})) {
// Todo updates are reflected in the message stream
if (message.type === "assistant") {
for (const block of message.message.content) {
if (block.type === "tool_use" && block.name === "TodoWrite") {
const todos = block.input.todos;
console.log("Todo Status Update:");
todos.forEach((todo, index) => {
const status =
todo.status === "completed" ? "✅" : todo.status === "in_progress" ? "🔧" : "❌";
console.log(`${index + 1}. ${status} ${todo.content}`);
});
}
}
}
}
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock
async for message in query(
prompt="Optimize my React app performance and track progress with todos",
# Re-enable TodoWrite, which this example monitors. Without it, the SDK uses
# Task tools instead and these tool_use blocks never appear.
options=ClaudeAgentOptions(max_turns=15, env={"CLAUDE_CODE_ENABLE_TASKS": "0"}),
):
# Todo updates are reflected in the message stream
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, ToolUseBlock) and block.name == "TodoWrite":
todos = block.input["todos"]
print("Todo Status Update:")
for i, todo in enumerate(todos):
status = (
"✅"
if todo["status"] == "completed"
else "🔧"
if todo["status"] == "in_progress"
else "❌"
)
print(f"{i + 1}. {status} {todo['content']}")
import { query } from "@anthropic-ai/claude-agent-sdk";
class TodoTracker {
private todos: any[] = [];
displayProgress() {
if (this.todos.length === 0) return;
const completed = this.todos.filter((t) => t.status === "completed").length;
const inProgress = this.todos.filter((t) => t.status === "in_progress").length;
const total = this.todos.length;
console.log(`\nProgress: ${completed}/${total} completed`);
console.log(`Currently working on: ${inProgress} task(s)\n`);
this.todos.forEach((todo, index) => {
const icon =
todo.status === "completed" ? "✅" : todo.status === "in_progress" ? "🔧" : "❌";
const text = todo.status === "in_progress" ? todo.activeForm : todo.content;
console.log(`${index + 1}. ${icon} ${text}`);
});
}
async trackQuery(prompt: string) {
for await (const message of query({
prompt,
// Re-enable TodoWrite, which this tracker watches for.
options: { maxTurns: 20, env: { ...process.env, CLAUDE_CODE_ENABLE_TASKS: "0" } }
})) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if (block.type === "tool_use" && block.name === "TodoWrite") {
this.todos = block.input.todos;
this.displayProgress();
}
}
}
}
}
}
// Usage
const tracker = new TodoTracker();
await tracker.trackQuery("Build a complete authentication system with todos");
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock
from typing import List, Dict
class TodoTracker:
def __init__(self):
self.todos: List[Dict] = []
def display_progress(self):
if not self.todos:
return
completed = len([t for t in self.todos if t["status"] == "completed"])
in_progress = len([t for t in self.todos if t["status"] == "in_progress"])
total = len(self.todos)
print(f"\nProgress: {completed}/{total} completed")
print(f"Currently working on: {in_progress} task(s)\n")
for i, todo in enumerate(self.todos):
icon = (
"✅"
if todo["status"] == "completed"
else "🔧"
if todo["status"] == "in_progress"
else "❌"
)
text = (
todo["activeForm"]
if todo["status"] == "in_progress"
else todo["content"]
)
print(f"{i + 1}. {icon} {text}")
async def track_query(self, prompt: str):
async for message in query(
prompt=prompt,
# Re-enable TodoWrite, which this tracker watches for.
options=ClaudeAgentOptions(max_turns=20, env={"CLAUDE_CODE_ENABLE_TASKS": "0"}),
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, ToolUseBlock) and block.name == "TodoWrite":
self.todos = block.input["todos"]
self.display_progress()
# Usage
tracker = TodoTracker()
await tracker.track_query("Build a complete authentication system with todos")

ابزارهای Task فراخوانیِ واحدِ TodoWrite را به TaskCreate برای هر مورد جدید و TaskUpdate برای هر تغییرِ وضعیت تقسیم می‌کنند، و TaskList و TaskGet هم در دسترسِ مدل هستند تا فهرستِ فعلی را بازخوانی کند. کدِ پایشِ تو همچنان بلاک‌های tool_use را در استریمِ دستیار بررسی می‌کند، اما به‌جای جایگزین‌کردنِ کل فهرست در هر فراخوانی، یک نگاشت (map) را که کلیدش شناسه‌ی تسک است نگه می‌دارد. {/* min-version: 2.1.142 */}ابزارهای Task از TypeScript Agent SDK نسخه‌ی 0.3.142 و Claude Code v2.1.142 به بعد پیش‌فرض هستند، پس هیچ تغییری در options.env لازم نیست.

با TodoWriteبا ابزارهای Task
یک فراخوانیِ ابزار کلِ آرایه‌ی todos را بازنویسی می‌کندTaskCreate یک مورد اضافه می‌کند، TaskUpdate یک مورد را بر اساس taskId وصله می‌کند
تطبیق با block.name === "TodoWrite"تطبیق با block.name === "TaskCreate" یا "TaskUpdate"
شکل مورد: { content, status, activeForm }ورودیِ TaskCreate: { subject, description, activeForm?, metadata? }. ورودیِ TaskUpdate: { taskId, status?, subject?, description?, activeForm?, addBlocks?, addBlockedBy?, owner?, metadata? }. مقدار status یکی از "pending"، "in_progress" یا "completed" است؛ برای حذف، status: "deleted" بگذار
block.input.todos را مستقیماً رندر کنموردها را در طول فراخوانی‌ها انباشته کن، یا یک snapshot از نتیجه‌ی ابزار TaskList بخوان

شناسه‌ی تسکِ تخصیص‌یافته در ورودیِ TaskCreate نیست. این شناسه در tool_resultِ متناظر به‌صورت { task: { id, subject } } برمی‌گردد، پس آن را از بلاکِ نتیجه بردار تا کلیدِ نگاشتت شود. مثالِ زیر کمترین تغییرِ لازم در حلقه‌ی پایش تغییرات todo را نشان می‌دهد. برای رندرِ یک فهرستِ کامل، در استریم منتظرِ نتیجه‌ی ابزار TaskList بمان، یا نتایجِ TaskCreate و ورودی‌های TaskUpdate را در یک نگاشت انباشته کن:

import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Optimize my React app performance",
})) {
if (message.type !== "assistant") continue;
for (const block of message.message.content) {
if (block.type !== "tool_use") continue;
if (block.name === "TaskCreate") {
const input = block.input as { subject: string };
console.log(`+ ${input.subject}`);
} else if (block.name === "TaskUpdate") {
const input = block.input as { taskId: string; status?: string };
if (input.status) console.log(` ${input.taskId} -> ${input.status}`);
}
}
}
from claude_agent_sdk import query, AssistantMessage, ToolUseBlock
async for message in query(
prompt="Optimize my React app performance",
):
if not isinstance(message, AssistantMessage):
continue
for block in message.content:
if not isinstance(block, ToolUseBlock):
continue
if block.name == "TaskCreate":
print(f"+ {block.input['subject']}")
elif block.name == "TaskUpdate" and block.input.get("status"):
print(f" {block.input['taskId']} -> {block.input['status']}")