Skip to main content

Todo Lists

ติดตามและแสดง todos โดยใช้ Claude Agent SDK สำหรับการจัดการงานที่เป็นระเบียบ

Todo tracking ให้วิธีที่มีโครงสร้างในการจัดการงานและแสดงความคืบหน้าให้ผู้ใช้เห็น Claude Agent SDK มีฟังก์ชัน todo ในตัวที่ช่วยจัดระเบียบ workflows ที่ซับซ้อนและแจ้งผู้ใช้เกี่ยวกับความคืบหน้าของงาน

note

ตั้งแต่ TypeScript Agent SDK 0.3.142 และ Claude Code v2.1.142 เป็นต้นมา sessions จะใช้ structured Task tools TaskCreate, TaskUpdate, TaskGet, และ TaskList แทน TodoWrite ดู การ Migrate ไปยัง Task tools สำหรับวิธีที่โค้ด monitoring เปลี่ยนแปลง ตัวอย่างในหน้านี้ตั้งค่า CLAUDE_CODE_ENABLE_TASKS=0 เพื่อยังคงแสดง TodoWrite สำหรับ sessions ที่ยังไม่ได้ migrate

Todo Lifecycle

Todos ปฏิบัติตาม lifecycle ที่คาดเดาได้:

  1. Created เป็น pending เมื่อ tasks ถูกระบุ
  2. Activated เป็น in_progress เมื่องานเริ่มต้น
  3. Completed เมื่อ task เสร็จสิ้นสำเร็จ
  4. Removed เมื่อ tasks ทั้งหมดในกลุ่มเสร็จสมบูรณ์

เมื่อใดที่ Todos ถูกใช้

SDK สร้าง todos โดยอัตโนมัติสำหรับ:

  • Tasks ที่มีหลายขั้นตอนซับซ้อน ที่ต้องการการกระทำที่แตกต่างกัน 3 หรือมากกว่า
  • Task lists ที่ผู้ใช้ให้มา เมื่อมีการกล่าวถึงหลายรายการ
  • การดำเนินการที่ไม่ trivial ที่ได้รับประโยชน์จากการติดตามความคืบหน้า
  • คำขอที่ชัดเจน เมื่อผู้ใช้ขอการจัดระเบียบ todo

ตัวอย่าง

การ Monitor การเปลี่ยนแปลง 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']}")

การแสดงความคืบหน้าแบบ Real-time

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")

Migrate ไปยัง Task tools

Task tools แบ่ง call TodoWrite เดียวออกเป็น TaskCreate สำหรับแต่ละรายการใหม่และ TaskUpdate สำหรับการเปลี่ยนแปลงสถานะแต่ละครั้ง โดยมี TaskList และ TaskGet สำหรับ model ในการอ่านรายการปัจจุบัน โค้ด monitoring ของคุณยังคงตรวจสอบ tool_use blocks ใน assistant stream แต่รักษา map ที่มี key เป็น task ID แทนที่จะแทนที่ list ทั้งหมดในทุก call

ด้วย TodoWriteด้วย Task tools
หนึ่ง tool call เขียน array todos ทั้งหมดใหม่TaskCreate เพิ่มหนึ่งรายการ, TaskUpdate patch หนึ่งรายการด้วย taskId
Match block.name === "TodoWrite"Match block.name === "TaskCreate" หรือ "TaskUpdate"
รูปร่าง item: { content, status, activeForm }TaskCreate input: { subject, description, activeForm?, metadata? }
Render block.input.todos โดยตรงAccumulate items ในการ calls หรืออ่าน snapshot จาก TaskList tool result
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']}")

เอกสารที่เกี่ยวข้อง