* feat: s01-s14 docs quality overhaul — tool pipeline, single-agent, knowledge & resilience Rewrite code.py and README (zh/en/ja) for s01-s14, each chapter building incrementally on the previous. Key fixes across chapters: - s01-s04: agent loop, tool dispatch, permission pipeline, hooks - s05-s08: todo write, subagent, skill loading, context compact - s09-s11: memory system, system prompt assembly, error recovery - s12-s14: task graph, background tasks, cron scheduler All chapters CC source-verified. Code inherits fixes forward (PROMPT_SECTIONS, json.dumps cache, real-state context, can_start dep protection, etc.). * feat: s15-s19 docs quality overhaul — multi-agent platform: teams, protocols, autonomy, worktree, MCP tools Rewrite code.py and README (zh/en/ja) for s15-s19, the multi-agent platform chapters. Each chapter inherits all previous fixes and adds one mechanism: - s15: agent teams (TeamCreate, teammate threads, shared task list) - s16: team protocols (plan approval, shutdown handshake, consume_inbox) - s17: autonomous agents (idle polling, auto-claim, consume_lead_inbox) - s18: worktree isolation (git worktree, bind_task, cwd switching, safety) - s19: MCP tools (MCPClient, normalize_mcp_name, assemble_tool_pool, no cache) All appendix source code references verified against CC source. Config priority corrected: claude.ai < plugin < user < project < local. * fix: 5 regressions across s05-s19 — glob safety, todo validation, memory extraction, protocol types, dep crash - s05-s09: glob results now filter with is_relative_to(WORKDIR) (inherited from s02) - s06-s08: todo_write validates content/status required fields (inherited from s05) - s09: extract_memories uses pre-compression snapshot instead of compacted messages - s16: submit_plan docstring clarifies protocol-only (not code-level gate) - s17-s19: match_response restores type mismatch validation (from s16) - s17-s19: claim_task deps list handles missing dep files without crashing * fix: s12 Todo V2 logic reversal, s14/s15 cron range validation, s18/s19 worktree name validation - s12 README (zh/en/ja): fix Todo V2 direction — interactive defaults to Task, non-interactive/SDK defaults to TodoWrite. Fix env var name to CLAUDE_CODE_ENABLE_TASKS (not TODO_V2). - s14/s15: add _validate_cron_field with per-field range checks (minute 0-59, hour 0-23, dom 1-31, month 1-12, dow 0-6), step > 0, range lo <= hi. Replace old try/except validation that only caught exceptions. - s18/s19: add validate_worktree_name() to remove_worktree and keep_worktree, not just create_worktree. * fix: align s16-s19 teaching tool consistency * fix pr265 chapter diagrams * Add comprehensive s20 harness chapter * Fix chapter smoke test regressions * Clarify README tutorial track transition --------- Co-authored-by: Haoran <bill-billion@outlook.com>
9.9 KiB
s02: Tool Use — ツール一つ追加、一行追加だけ
s01 → s02 → s03 → s04 → ... → s20
"ツールを一つ追加、ハンドラを一つ追加" — ループはそのまま。新しいツールをディスパッチマップに登録するだけ。
Harness レイヤー: ツールディスパッチ — モデルが触れる範囲を拡張。
ツールは bash 一つだけ
s01 の Agent には bash 一つのツールしかない。ファイルを読むには cat、書くには echo "..." > file.py、編集するには sed。
モデルは「このファイルを読みたい」と考えながら、cat path/to/file と組み立てなければならない。翻訳の層が一つ増え、トークンを無駄にし、エラーも起きやすい。
概要:ツールディスパッチ
s01 のループは完全に保持される(LLM 呼び出し、stop_reason 判定、メッセージ追加 — 一文字も変更なし)。唯一の変更点はツール実行の 1 行:run_bash() が TOOL_HANDLERS[block.name]() の検索ディスパッチに置き換わる。
Agent にツールを追加するには、たった二つ:
- ツールを定義:
TOOLS配列に一条を追加 - ハンドラを登録:
TOOL_HANDLERS辞書に一つのマッピングを追加
1 つのツールから 5 つのツールへ
s01 には bash だけだった:
TOOLS = [{"name": "bash", ...}]
def run_bash(command): ...
s02 では 5 つに増え、各ツールは独立して定義される:
TOOLS = [
{"name": "bash", "description": "Run a shell command.", ...},
{"name": "read_file", "description": "Read file contents.", ...},
{"name": "write_file", "description": "Write content to file.", ...},
{"name": "edit_file", "description": "Replace text in file once.", ...},
{"name": "glob", "description": "Find files by pattern.", ...},
]
各ツールには専用の実装関数がある:
def run_read(path, limit=None):
lines = safe_path(path).read_text().splitlines()
if limit:
lines = lines[:limit]
return "\n".join(lines)
def run_write(path, content):
safe_path(path).write_text(content)
return f"Wrote {len(content)} bytes to {path}"
def run_edit(path, old_text, new_text):
text = safe_path(path).read_text()
if old_text not in text:
return "Error: text not found"
safe_path(path).write_text(text.replace(old_text, new_text, 1))
return f"Edited {path}"
def run_glob(pattern):
import glob as g
return "\n".join(g.glob(pattern, root_dir=WORKDIR))
ツールディスパッチ
TOOL_HANDLERS = {
"bash": run_bash,
"read_file": run_read,
"write_file": run_write,
"edit_file": run_edit,
"glob": run_glob,
}
# ループ内で変更されたのは一行だけ — ハードコードの run_bash から検索ディスパッチへ:
for block in response.content:
if block.type == "tool_use":
handler = TOOL_HANDLERS[block.name] # 検索
output = handler(**block.input) # 呼び出し
results.append(...)
ツールの追加 = TOOLS 配列に一条 + TOOL_HANDLERS 辞書に一行。ループは変わらない。
複数のツール呼び出し
モデルはよく一度に複数の tool_use を返す — 「a.py と b.py を読んで、全 .py ファイルを列挙して」。
教育版は response.content の元の順序で一つずつ実行する。CC のやり方はより複雑:元の順序を保ったまま連続バッチに分割し、バッチ内の並列安全なツールを並行実行し、バッチ間は厳密に順次(付録を参照)。
速查
| 概念 | 一言で |
|---|---|
| TOOL_HANDLERS | ツール名 → ハンドラ関数の辞書。ツール追加 = マッピング一行追加 |
| ツール定義 | モデルに「何ができるか」を伝える JSON schema |
| 複数ツール呼び出し | モデルは一度に複数の tool_use を返す可能性がある。教育版は元の順序で一つずつ実行 |
| ループ不変 | s01 の while True ループ — 一行も変更なし |
s01 からの変更
| コンポーネント | 変更前 (s01) | 変更後 (s02) |
|---|---|---|
| ツール数 | 1 (bash) | 5 (+read, write, edit, glob) |
| ツール実行 | ハードコード run_bash() |
TOOL_HANDLERS 検索ディスパッチ |
| パス安全性 | なし | safe_path 検証(file tools のみ) |
| ループ | while True + stop_reason |
s01 と完全に同一 |
試してみよう
cd learn-claude-code
python s02_tool_use/code.py
以下のプロンプトを試してみよう:
Read the file README.md and tell me what this project is aboutCreate a file called test.py that prints "hello", then read it backFind all Python files in this directoryRead both README.md and requirements.txt, then create a summary file
観察のポイント:モデルがツールを一つだけ呼び出すときと、複数同時に呼び出すときの違い。複数のツール呼び出しは正しい順序で実行されているか?
次へ
Agent は 5 つの専用ツールを持つようになった。file tools は safe_path で保護されるが、bash は制限なし — rm -rf / はまだ実行できる。
→ s03 Permission:ツール実行前にゲートを追加 — この操作は安全か? ユーザーの承認が必要か?
CC ソースコードを深掘り
以下は CC ソースコード
Tool.ts、tools.ts、toolOrchestration.ts、toolExecution.ts、StreamingToolExecutor.tsの検証に基づく。
一、ツール定義方式
教育版:TOOLS 配列 + TOOL_HANDLERS 辞書。定義と実装が分離。
CC:各ツールは buildTool() で作成された独立オブジェクトで、schema、バリデーション、権限、実行を含む。getAllBaseTools() が全ツールを集約。
教育版の分離方式は教学に適している — 読者は「ツール追加 = 二つの定義」と一目で分かる。
二、並列安全性:isConcurrencySafe()
教育版は元の順序で一つずつ実行し、並列処理は行わない。CC は isConcurrencySafe(input) で並列可否を判断する — これは単なる「読み取り専用 vs 書き込み」ではなく、具体的な入力で判断する:
| isReadOnly | isConcurrencySafe | |
|---|---|---|
| FileRead | true | true |
| Glob | true | true |
Bash ls |
true | true ← 重要な違い |
Bash rm |
false | false |
| TaskCreate | false | true ← 状態変更するが並列可能(s12 で紹介) |
CC の Bash ツールの isConcurrencySafe は isReadOnly と同じ — 読み取り専用コマンドは並列可能、書き込みコマンドは不可。TaskCreate はタスクファイルを変更するが、毎回異なるファイルに書き込むため並列可能。
三、パーティションアルゴリズム
CC の partitionToolCalls()(toolOrchestration.ts:91-115)は二つのグループに分けるのではなく、ツール呼び出しを連続ブロックごとにバッチ化する:
[read A, read B, glob *.py, bash "rm x", read C]
→ batch1(並列): [read A, read B, glob *.py]
→ batch2(直列): [bash "rm x"]
→ batch3(並列): [read C]
連続する並列安全な呼び出しを同じバッチにまとめ、真の並列実行を行う(toolOrchestration.ts:152-176、並列数上限あり)。非並列安全な呼び出しに遭遇すると新しいバッチを開始して直列実行。バッチ間は厳密に順次。
四、バリデーションパイプライン
CC の各ツール呼び出しは厳格な 5 段階のバリデーションを経る(toolExecution.ts):
- Zod schema バリデーション(
614-680、教育版は JSON Schema で代替):パラメータの型/構造チェック - ツールレベル validateInput()(
682-733):パラメータ値の検証(例:パスが作業ディレクトリ内か) - PreToolUse フック(
800-862、s04 で詳解):フックはメッセージの返却、入力の変更、実行のブロックが可能 - 権限チェック(
921-931、s03 の核心):canUseTool + checkPermissions → allow/deny/ask - tool.call() の実行(
1207-1222)
教育版は Zod を省略(JSON Schema を使用)、validateInput を省略(安全関数を使用)、権限チェックとフック概念は保持。
五、ストリーミングツール実行
CC の StreamingToolExecutor(StreamingToolExecutor.ts)はモデルがまだ生成中にツールを起動する — モデルの完了を待たない。read_file はモデルが「分析します」と出力中に完了するかもしれない。教育版はこれを実装しない。s01 と同じ目標 — 概念の明確さ、極限のパフォーマンスではない。
六、ツール結果の永続化
各ツールには maxResultSizeChars フィールドがある。この閾値を超える結果はディスクに保存され、モデルにはプレビュー + ファイルパスが表示される。FileRead は特殊 — Infinity に設定され、ファイル読み出し結果の再永続化を防ぐ。具体的には、FileRead の結果が閾値を超えて永続化されると、モデルがその永続化ファイルを次に読むときにまた永続化がトリガーされ → 無限ループ(ファイル読む → 永続化 → 再読み → 再永続化 → ...)になる。