Listes de tâches
Suivre et afficher les tâches à l'aide du SDK Claude Agent pour une gestion organisée des tâches
Le suivi des tâches fournit un moyen structuré de gérer les tâches et d'afficher la progression aux utilisateurs. Le SDK Claude Agent inclut une fonctionnalité de tâches intégrée qui aide à organiser les flux de travail complexes et à tenir les utilisateurs informés de la progression des tâches.
À partir du TypeScript Agent SDK 0.3.142 et Claude Code v2.1.142, les sessions utilisent les outils Task structurés TaskCreate, TaskUpdate, TaskGet et TaskList à la place de TodoWrite. Consultez Migrer vers les outils Task pour savoir comment le code de surveillance change. Les exemples de cette page définissent CLAUDE_CODE_ENABLE_TASKS=0 pour continuer à afficher TodoWrite pour les sessions qui n'ont pas encore migré.
Cycle de vie des tâches
Les tâches suivent un cycle de vie prévisible :
- Créées en tant que
pendinglorsque les tâches sont identifiées - Activées en tant que
in_progresslorsque le travail commence - Complétées lorsque la tâche se termine avec succès
- Supprimées lorsque toutes les tâches d'un groupe sont complétées
Quand les tâches sont utilisées
Le SDK crée automatiquement des tâches pour :
- Les tâches complexes multi-étapes nécessitant 3 actions distinctes ou plus
- Les listes de tâches fournies par l'utilisateur lorsque plusieurs éléments sont mentionnés
- Les opérations non triviales qui bénéficient du suivi de la progression
- Les demandes explicites lorsque les utilisateurs demandent une organisation des tâches
Exemples
Surveillance des modifications des tâches
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']}")
Affichage de la progression en temps réel
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")
Migrer vers les outils Task
Les outils Task divisent l'appel unique TodoWrite en TaskCreate pour chaque nouvel élément et TaskUpdate pour chaque changement de statut, avec TaskList et TaskGet disponibles pour que le modèle relise la liste actuelle. Votre code de surveillance inspecte toujours les blocs tool_use dans le flux assistant, mais maintient une carte indexée par ID de tâche au lieu de remplacer la liste entière à chaque appel. {/* min-version: 2.1.142 */}Les outils Task sont le défaut à partir du TypeScript Agent SDK 0.3.142 et Claude Code v2.1.142, donc aucun changement options.env n'est nécessaire.
Avec TodoWrite |
Avec les outils Task |
|---|---|
Un appel d'outil réécrit le tableau todos complet |
TaskCreate ajoute un élément, TaskUpdate corrige un élément par taskId |
Correspond à block.name === "TodoWrite" |
Correspond à block.name === "TaskCreate" ou "TaskUpdate" |
Forme d'élément : { content, status, activeForm } |
Entrée TaskCreate : { subject, description, activeForm?, metadata? }. Entrée TaskUpdate : { taskId, status?, subject?, description?, activeForm?, addBlocks?, addBlockedBy?, owner?, metadata? }. status est "pending", "in_progress" ou "completed" ; définissez status: "deleted" pour supprimer |
Rendre block.input.todos directement |
Accumuler les éléments entre les appels, ou lire un instantané à partir d'un résultat d'outil TaskList |
L'ID de tâche assigné ne se trouve pas dans l'entrée TaskCreate. Il revient dans le bloc tool_result correspondant sous la forme { task: { id, subject } }, donc capturez-le à partir du bloc de résultat pour indexer votre carte. L'exemple suivant montre le changement minimal à la boucle Surveillance des modifications des tâches. Pour rendre une liste complète, regardez un résultat d'outil TaskList dans le flux ou accumulez les résultats TaskCreate et les entrées TaskUpdate dans une carte.
Le flux tool_use d'entrée est la forme brute que le modèle a émise. Claude Code répare certains noms de clés proches mais incorrects avant l'exécution, en mappant id ou task_id à taskId et active_form à activeForm, mais cette réparation n'est pas reflétée dans le flux. Lisez les champs d'entrée TaskUpdate de manière défensive, comme le font les exemples ci-dessous, plutôt que de supposer que le nom canonique est toujours présent.
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;
id?: string;
task_id?: string;
status?: string;
};
const taskId = input.taskId ?? input.id ?? input.task_id;
if (taskId && input.status) console.log(` ${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"):
task_id = (
block.input.get("taskId")
or block.input.get("id")
or block.input.get("task_id")
)
if task_id:
print(f" {task_id} -> {block.input['status']}")