Tool use bình thường: bạn define schema + function.
- Dùng built-in str_replace_editor tool của Anthropic
- Implement handlers cho 6 commands: view, str_replace, create, insert, undo_edit
- So sánh built-in tool vs custom tool
- Hiểu đây chính là foundation của Claude Code
6 commands
Claude decide command nào qua input param command.
| Command | Task |
|---|---|
| view | Xem file content hoặc list directory |
| str_replace | Replace text trong file |
| create | Tạo file mới |
| insert | Insert dòng mới tại line number |
| undo_edit | Undo edit gần nhất |
Schema declaration
Không cần viết full schema. Chỉ declare tool type + name:
Claude "expand" schema nội bộ → nhận input types đầy đủ.
def get_text_edit_schema(model: str) -> dict:
"""Return schema version matching model."""
if model.startswith("claude-sonnet-5") or model.startswith("claude-opus-4"):
return {
"type": "text_editor_20260101", # check docs cho version mới
"name": "str_replace_based_edit_tool",
}
elif model.startswith("claude-3-7"):
return {
"type": "text_editor_20250124",
"name": "str_replace_editor",
}
# ...Implement handler
Đây là phần bạn write. Mỗi command = case xử lý:
import os
from pathlib import Path
# Track undo history
edit_history = []
def handle_text_editor(command: str, **kwargs) -> str:
"""Dispatch text editor commands."""
if command == "view":
return cmd_view(**kwargs)
elif command == "str_replace":
return cmd_str_replace(**kwargs)
elif command == "create":
return cmd_create(**kwargs)
elif command == "insert":
return cmd_insert(**kwargs)
elif command == "undo_edit":
return cmd_undo_edit(**kwargs)
else:
raise ValueError(f"Unknown command: {command}")
def cmd_view(path: str, view_range: list = None) -> str:
"""View file or directory."""
p = Path(path)
if not p.exists():
raise FileNotFoundError(f"{path} does not exist")
if p.is_dir():
# List directory
items = [f.name for f in p.iterdir()]
return f"Directory {path}:\n" + "\n".join(items)
# Read file
content = p.read_text()
lines = content.split("\n")
if view_range:
start, end = view_range
lines = lines[start-1:end]
numbered = [f"{i+start}: {line}" for i, line in enumerate(lines)]
else:
numbered = [f"{i+1}: {line}" for i, line in enumerate(lines)]
return "\n".join(numbered)
def cmd_str_replace(path: str, old_str: str, new_str: str) -> str:
"""Replace old_str with new_str in file. old_str must be unique."""
p = Path(path)
content = p.read_text()
count = content.count(old_str)
if count == 0:
raise ValueError(f"old_str not found in {path}")
if count > 1:
raise ValueError(f"old_str appears {count} times in {path}, must be unique")
# Save for undo
edit_history.append((path, content))
new_content = content.replace(old_str, new_str, 1)
p.write_text(new_content)
return f"Replaced in {path}"
def cmd_create(path: str, file_text: str) -> str:
"""Create new file."""
p = Path(path)
if p.exists():
raise FileExistsError(f"{path} already exists")
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(file_text)
edit_history.append((path, None)) # creation marker
return f"Created {path}"
def cmd_insert(path: str, insert_line: int, new_str: str) -> str:
"""Insert new_str at insert_line."""
p = Path(path)
content = p.read_text()
lines = content.split("\n")
edit_history.append((path, content))
lines.insert(insert_line, new_str)
p.write_text("\n".join(lines))
return f"Inserted at line {insert_line} in {path}"
def cmd_undo_edit(path: str) -> str:
"""Undo last edit."""
# Find last edit to this path
for i in range(len(edit_history) - 1, -1, -1):
saved_path, saved_content = edit_history[i]
if saved_path == path:
if saved_content is None:
# Was created → delete
Path(path).unlink()
edit_history.pop(i)
return f"Undid creation of {path}"
else:
# Restore
Path(path).write_text(saved_content)
edit_history.pop(i)
return f"Restored {path}"
raise ValueError(f"No edit history for {path}")Integrate with conversation loop
Claude sequence:
- view(path="main.py") → read file
- Identify function
- str_replace(path, old_str="def calculate(...)", new_str="def calculate(...)\n '''Docstring'''")
- Confirm
def run_tool_with_editor(name, input_data):
"""Dispatch including text editor."""
if name == "str_replace_based_edit_tool":
return handle_text_editor(**input_data)
# ... other tools
return TOOL_FUNCTIONS[name](**input_data)
# Main
text_editor_schema = get_text_edit_schema(MODEL)
final, history = run_conversation(
"Open main.py, find function 'calculate' and add docstring.",
tools=[text_editor_schema]
)Ví dụ thực chiến: Add unit tests
User: "Open ./main.py, add function to calculate pi to 5 digits. Create ./test.py with tests."
Claude sequence:
Final: Text response summary changes.
Đây chính là mini Claude Code bạn vừa xây.
- view("main.py") — see existing code
- str_replace("main.py", old, new) — add function
- view("main.py") — verify
- create("test.py", test_code) — new test file
- Optional: view("test.py") — verify
Built-in tool vs custom tool
Khi nào dùng built-in: file operations (text_editor), web search, code execution (Module 6 covers). Anthropic trained Claude thành thạo các tools này.
Khi nào custom: domain-specific (CRM, your API, business logic).
| Built-in (text_editor) | Custom tool | |
|---|---|---|
| Schema | Anthropic defined | Bạn write |
| Function | Bạn implement | Bạn implement |
| Naming | Fixed names | Bạn chọn |
| Updates | Anthropic improve | Bạn maintain |
Security considerations
Text editor = Claude có thể modify files.
1. Sandbox directory
Never allow access ngoài sandbox trong production.
2. Read-only mode
Cho dev/debug, disable write operations:
def cmd_view(path: str, ...):
resolved = Path(path).resolve()
allowed_dir = Path("/sandbox").resolve()
if not str(resolved).startswith(str(allowed_dir)):
raise PermissionError(f"Access denied: {path}")
# ...2. Read-only mode
3. Backup trước edit
READ_ONLY = True
def cmd_str_replace(...):
if READ_ONLY:
raise PermissionError("Read-only mode")3. Backup trước edit
def cmd_str_replace(path, ...):
# Auto-backup
shutil.copy(path, f"{path}.bak.{timestamp()}")
...Anti-patterns
❌ Cho Claude full filesystem access
Claude có thể accidentally rm -rf hay edit wrong file.
Fix: Sandbox + whitelist.
❌ Không track edit history
Undo không work.
Fix: Save content trước khi modify.
❌ Dùng built-in tool khi task đơn giản
Cho task "read 1 file", built-in overkill — viết tool read_file đơn giản.
Fix: Built-in cho scenarios cần đầy đủ 6 commands.
❌ Không version model cho schema
Schema version depends model. Hardcode → break khi upgrade.
Fix: get_text_edit_schema(model) function.
Áp dụng ngay
Bài tập 1: Setup + test basic (20 phút)
Implement handler. Test:
Bài tập 2: Refactor task (30 phút)
run_conversation(
"Create a file called hello.py with print('hello world')",
tools=[text_editor_schema]
)Bài tập 2: Refactor task (30 phút)
Claude sẽ: view → multiple str_replace → verify. Observe loop.
run_conversation(
"Open ./sample.py. Find all function def, add docstring to each that lacks one.",
tools=[text_editor_schema]
)Tóm tắt
🎯 Text editor = built-in tool cho file ops. Schema từ Anthropic, function bạn viết.
🎯 6 commands: view, str_replace, create, insert, undo_edit.
🎯 Sandbox + backup là must-have cho security.
🎯 Đây là foundation của Claude Code — hiểu tool này = hiểu cách Claude Code work.
🎯 Built-in cho common tasks, custom cho domain-specific.
Củng cố những gì bạn vừa học
12 câu trắc nghiệm · đạt từ 70% · câu hỏi và đáp án xáo trộn mỗi lần.