mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-06-20 20:23:36 +08:00
fix: align TodoWrite memory model with task system docs
This commit is contained in:
@@ -32,19 +32,21 @@ The dispatch mechanism is unchanged; the new tool is still routed through `TOOL_
|
||||
|
||||
## How It Works
|
||||
|
||||
**The todo_write tool**, accepts a list with statuses, persists to `.tasks/current_todos.json` (teaching version writes to disk for observability), and displays progress in the terminal:
|
||||
**The todo_write tool** accepts a list with statuses, keeps it in the current process memory, and displays progress in the terminal:
|
||||
|
||||
```python
|
||||
CURRENT_TODOS: list[dict] = []
|
||||
|
||||
def run_todo_write(todos: list) -> str:
|
||||
tasks_file = TASKS_DIR / "current_todos.json"
|
||||
tasks_file.write_text(json.dumps(todos, indent=2, ensure_ascii=False))
|
||||
global CURRENT_TODOS
|
||||
CURRENT_TODOS = todos
|
||||
|
||||
lines = ["\n## Current Tasks"]
|
||||
for t in todos:
|
||||
for t in CURRENT_TODOS:
|
||||
icon = {"pending": " ", "in_progress": "▸", "completed": "✓"}[t["status"]]
|
||||
lines.append(f" [{icon}] {t['content']}")
|
||||
print("\n".join(lines))
|
||||
return f"Updated {len(todos)} tasks"
|
||||
return f"Updated {len(CURRENT_TODOS)} tasks"
|
||||
```
|
||||
|
||||
The tool definition joins the other 5 in the dispatch map:
|
||||
@@ -135,7 +137,7 @@ The Agent can plan now. But if a task is too large, say "refactor the entire aut
|
||||
|
||||
CC has two task systems coexisting (`tasks.ts:133-139`):
|
||||
|
||||
- **TodoWrite (V1)**: A simple list tool, data maintained in memory AppState (`TodoWriteTool.ts:65-103`). The teaching version writes to `.tasks/current_todos.json` for observability; the real V1 does not write to disk.
|
||||
- **TodoWrite (V1)**: A simple list tool, data maintained in memory AppState (`TodoWriteTool.ts:65-103`). The teaching version also keeps it in process memory and clears it on exit.
|
||||
- **Task System (V2 = s12)**: File-persisted, dependency graph, concurrency locks, ownership.
|
||||
|
||||
The switch is controlled by `isTodoV2Enabled()`. In the current source: V2 is enabled by default in interactive sessions, V1 in non-interactive (SDK) sessions; setting `CLAUDE_CODE_ENABLE_TASKS` forces V2 regardless. Note the source comment "Force-enable tasks in non-interactive mode" describes the env var path's purpose, not the default branch's return semantics.
|
||||
|
||||
@@ -32,19 +32,21 @@ Agent は作業を開始する。3 つのファイルをリネーム、テスト
|
||||
|
||||
## 仕組み
|
||||
|
||||
**todo_write ツール**、ステータス付きのリストを受け取り、`.tasks/current_todos.json` に永続化(教育版は観察用にディスクに書き込む)、端末に進捗を表示する:
|
||||
**todo_write ツール**は、ステータス付きのリストを受け取り、現在のプロセスメモリに保持し、端末に進捗を表示する:
|
||||
|
||||
```python
|
||||
CURRENT_TODOS: list[dict] = []
|
||||
|
||||
def run_todo_write(todos: list) -> str:
|
||||
tasks_file = TASKS_DIR / "current_todos.json"
|
||||
tasks_file.write_text(json.dumps(todos, indent=2, ensure_ascii=False))
|
||||
global CURRENT_TODOS
|
||||
CURRENT_TODOS = todos
|
||||
|
||||
lines = ["\n## Current Tasks"]
|
||||
for t in todos:
|
||||
for t in CURRENT_TODOS:
|
||||
icon = {"pending": " ", "in_progress": "▸", "completed": "✓"}[t["status"]]
|
||||
lines.append(f" [{icon}] {t['content']}")
|
||||
print("\n".join(lines))
|
||||
return f"Updated {len(todos)} tasks"
|
||||
return f"Updated {len(CURRENT_TODOS)} tasks"
|
||||
```
|
||||
|
||||
ツール定義は他の 5 つと一緒にディスパッチマップに追加される:
|
||||
@@ -135,7 +137,7 @@ Agent は計画できるようになった。しかしタスクが大きすぎ
|
||||
|
||||
CC には二つのタスクシステムが共存している(`tasks.ts:133-139`):
|
||||
|
||||
- **TodoWrite(V1)**:シンプルなリストツール、データはメモリ AppState で管理(`TodoWriteTool.ts:65-103`)。教育版は観察用に `.tasks/current_todos.json` に書き込むが、実際の V1 はディスクに書き込まない
|
||||
- **TodoWrite(V1)**:シンプルなリストツール、データはメモリ AppState で管理(`TodoWriteTool.ts:65-103`)。教育版もプロセスメモリに保持し、終了時に消える
|
||||
- **Task System(V2 = s12)**:ファイル永続化、依存グラフ、並行ロック、ownership
|
||||
|
||||
切り替えは `isTodoV2Enabled()` で制御される。現在のソースコードの実装:対話型セッションでは V2 がデフォルトで有効、非対話型セッション(SDK)では V1 がデフォルトで有効。`CLAUDE_CODE_ENABLE_TASKS` 環境変数を設定するとセッション種別に関わらず V2 が強制有効になる。ソースコメント「Force-enable tasks in non-interactive mode」は環境変数パスの用途を説明しており、デフォルト分岐の戻り値のセマンティクスとは異なるため注意。
|
||||
|
||||
@@ -32,19 +32,21 @@ dispatch 机制不变,新工具仍然走 `TOOL_HANDLERS[block.name]` 分发。
|
||||
|
||||
## 工作原理
|
||||
|
||||
**todo_write 工具**,接收一个带状态的列表,持久化到 `.tasks/current_todos.json`(教学版写盘以便观察),同时在终端显示进度:
|
||||
**todo_write 工具**,接收一个带状态的列表,保存在当前进程内存中,同时在终端显示进度:
|
||||
|
||||
```python
|
||||
CURRENT_TODOS: list[dict] = []
|
||||
|
||||
def run_todo_write(todos: list) -> str:
|
||||
tasks_file = TASKS_DIR / "current_todos.json"
|
||||
tasks_file.write_text(json.dumps(todos, indent=2, ensure_ascii=False))
|
||||
global CURRENT_TODOS
|
||||
CURRENT_TODOS = todos
|
||||
|
||||
lines = ["\n## Current Tasks"]
|
||||
for t in todos:
|
||||
for t in CURRENT_TODOS:
|
||||
icon = {"pending": " ", "in_progress": "▸", "completed": "✓"}[t["status"]]
|
||||
lines.append(f" [{icon}] {t['content']}")
|
||||
print("\n".join(lines))
|
||||
return f"Updated {len(todos)} tasks"
|
||||
return f"Updated {len(CURRENT_TODOS)} tasks"
|
||||
```
|
||||
|
||||
工具定义和其他 5 个工具一起加入 dispatch map:
|
||||
@@ -135,7 +137,7 @@ s06 Subagent → 把大任务拆成子任务,每个子任务派一个独立的
|
||||
|
||||
CC 中有两套任务系统并存(`tasks.ts:133-139`):
|
||||
|
||||
- **TodoWrite(V1)**:一个简单的列表工具,数据在内存 AppState 中维护(`TodoWriteTool.ts:65-103`)。教学版写盘到 `.tasks/current_todos.json` 是为了可观察性,真实 V1 不写盘
|
||||
- **TodoWrite(V1)**:一个简单的列表工具,数据在内存 AppState 中维护(`TodoWriteTool.ts:65-103`)。教学版也保存在进程内存里,退出后清空
|
||||
- **Task System(V2 = s12)**:文件持久化、依赖图、并发锁、ownership
|
||||
|
||||
切换由 `isTodoV2Enabled()` 控制。当前源码的实现逻辑:交互式会话中 V2 默认启用,非交互式会话(SDK)中 V1 默认启用;设置 `CLAUDE_CODE_ENABLE_TASKS` 环境变量可强制启用 V2。注意源码注释 "Force-enable tasks in non-interactive mode" 描述的是 env var 路径的用途,和默认分支的返回值语义不同,阅读时需区分。
|
||||
@@ -153,4 +155,4 @@ Task System 相比 TodoWrite 的核心增量:
|
||||
|
||||
</details>
|
||||
|
||||
<!-- translation-sync: zh@v1, en@v0, ja@v0 -->
|
||||
<!-- translation-sync: zh@v1, en@v1, ja@v1 -->
|
||||
|
||||
@@ -12,7 +12,7 @@ s05: TodoWrite — add a planning tool on top of s04 hooks.
|
||||
todo_write ← NEW
|
||||
+------------------+
|
||||
|
|
||||
.tasks/current_todos.json
|
||||
in-memory current_todos
|
||||
|
|
||||
if rounds_since_todo >= 3:
|
||||
inject <reminder>
|
||||
@@ -28,7 +28,7 @@ Run: python s05_todo_write/code.py
|
||||
Needs: pip install anthropic python-dotenv + ANTHROPIC_API_KEY in .env
|
||||
"""
|
||||
|
||||
import os, subprocess, json
|
||||
import os, subprocess
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
@@ -45,9 +45,9 @@ if os.getenv("ANTHROPIC_BASE_URL"):
|
||||
os.environ.pop("ANTHROPIC_AUTH_TOKEN", None)
|
||||
|
||||
WORKDIR = Path.cwd()
|
||||
TASKS_DIR = WORKDIR / ".tasks"; TASKS_DIR.mkdir(exist_ok=True)
|
||||
client = Anthropic(base_url=os.getenv("ANTHROPIC_BASE_URL"))
|
||||
MODEL = os.environ["MODEL_ID"]
|
||||
CURRENT_TODOS: list[dict] = []
|
||||
|
||||
# s05 change: SYSTEM prompt adds planning guidance
|
||||
SYSTEM = (
|
||||
@@ -122,20 +122,20 @@ def run_glob(pattern: str) -> str:
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
|
||||
def run_todo_write(todos: list) -> str:
|
||||
global CURRENT_TODOS
|
||||
# validate required fields
|
||||
for i, t in enumerate(todos):
|
||||
if "content" not in t or "status" not in t:
|
||||
return f"Error: todos[{i}] missing 'content' or 'status'"
|
||||
if t["status"] not in ("pending", "in_progress", "completed"):
|
||||
return f"Error: todos[{i}] has invalid status '{t['status']}'"
|
||||
tasks_file = TASKS_DIR / "current_todos.json"
|
||||
tasks_file.write_text(json.dumps(todos, indent=2, ensure_ascii=False))
|
||||
CURRENT_TODOS = todos
|
||||
lines = ["\n\033[33m## Current Tasks\033[0m"]
|
||||
for t in todos:
|
||||
for t in CURRENT_TODOS:
|
||||
icon = {"pending": " ", "in_progress": "\033[36m▸\033[0m", "completed": "\033[32m✓\033[0m"}[t["status"]]
|
||||
lines.append(f" [{icon}] {t['content']}")
|
||||
print("\n".join(lines))
|
||||
return f"Updated {len(todos)} tasks"
|
||||
return f"Updated {len(CURRENT_TODOS)} tasks"
|
||||
|
||||
TOOLS = [
|
||||
{"name": "bash", "description": "Run a shell command.",
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
<text x="560" y="173" fill="#166534" font-size="9" font-weight="700" text-anchor="middle">todo_write</text>
|
||||
<text x="560" y="232" fill="#16a34a" font-size="11" font-weight="600" text-anchor="middle">s05 New</text>
|
||||
|
||||
<text x="560" y="196" fill="#64748b" font-size="8" text-anchor="middle">→ .tasks/current_todos.json</text>
|
||||
<text x="560" y="196" fill="#64748b" font-size="8" text-anchor="middle">→ in-memory TODO list</text>
|
||||
|
||||
<!-- Loop back -->
|
||||
<path d="M 620 112 L 660 112 L 660 260 L 90 260 L 90 134" fill="none" stroke="#555" stroke-width="2" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
@@ -73,7 +73,7 @@
|
||||
<text x="560" y="173" fill="#166534" font-size="9" font-weight="700" text-anchor="middle">todo_write</text>
|
||||
<text x="560" y="232" fill="#16a34a" font-size="11" font-weight="600" text-anchor="middle">s05 新規</text>
|
||||
|
||||
<text x="560" y="196" fill="#64748b" font-size="8" text-anchor="middle">→ .tasks/current_todos.json</text>
|
||||
<text x="560" y="196" fill="#64748b" font-size="8" text-anchor="middle">→ メモリ内 TODO リスト</text>
|
||||
|
||||
<!-- ループバック -->
|
||||
<path d="M 620 112 L 660 112 L 660 260 L 90 260 L 90 134" fill="none" stroke="#555" stroke-width="2" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
@@ -73,7 +73,7 @@
|
||||
<text x="560" y="173" fill="#166534" font-size="9" font-weight="700" text-anchor="middle">todo_write</text>
|
||||
<text x="560" y="232" fill="#16a34a" font-size="11" font-weight="600" text-anchor="middle">s05 新增</text>
|
||||
|
||||
<text x="560" y="196" fill="#64748b" font-size="8" text-anchor="middle">→ .tasks/current_todos.json</text>
|
||||
<text x="560" y="196" fill="#64748b" font-size="8" text-anchor="middle">→ 进程内 TODO 列表</text>
|
||||
|
||||
<!-- 回环 -->
|
||||
<path d="M 620 112 L 660 112 L 660 260 L 90 260 L 90 134" fill="none" stroke="#555" stroke-width="2" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Reference in New Issue
Block a user