s02
Herramientas
Herramientas y EjecuciónOne Handler Per Tool
120 LOC4 herramientasTool dispatch map
The loop stays the same; new tools register into the dispatch map
s01 > [ s02 ] s03 > s04 > s05 > s06 | s07 > s08 > s09 > s10 > s11 > s12
"Agregar una herramienta significa agregar un gestor" -- el bucle permanece igual; las nuevas herramientas se registran en el mapa de distribución.
Problema
Con solo bash, el agente usa el shell para todo. cat trunca de manera impredecible, sed falla con caracteres especiales, y cada llamada bash es una superficie de seguridad sin restricciones. Herramientas dedicadas como read_file y write_file te permiten aplicar sandboxing de rutas a nivel de herramienta.
La idea clave: agregar herramientas no requiere modificar el bucle.
Solución
+--------+ +-------+ +------------------+
| User | ---> | LLM | ---> | Tool Dispatch |
| prompt | | | | { |
+--------+ +---+---+ | bash: run_bash |
^ | read: run_read |
| | write: run_wr |
+-----------+ edit: run_edit |
tool_result | } |
+------------------+
El mapa de distribución es un dict: {nombre_herramienta: función_gestor}.
Una sola búsqueda reemplaza cualquier cadena if/elif.
Cómo Funciona
- Cada herramienta obtiene una función handler. El sandboxing de ruta previene el escape del espacio de trabajo.
def safe_path(p: str) -> Path:
path = (WORKDIR / p).resolve()
if not path.is_relative_to(WORKDIR):
raise ValueError(f"Path escapes workspace: {p}")
return path
def run_read(path: str, limit: int = None) -> str:
text = safe_path(path).read_text()
lines = text.splitlines()
if limit and limit < len(lines):
lines = lines[:limit]
return "\n".join(lines)[:50000]
- El mapa de distribución vincula nombres de herramientas a gestores.
TOOL_HANDLERS = {
"bash": lambda **kw: run_bash(kw["command"]),
"read_file": lambda **kw: run_read(kw["path"], kw.get("limit")),
"write_file": lambda **kw: run_write(kw["path"], kw["content"]),
"edit_file": lambda **kw: run_edit(kw["path"], kw["old_text"],
kw["new_text"]),
}
- En el bucle, busca el gestor por nombre. El cuerpo del bucle en sí mismo no cambia desde s01.
for block in response.content:
if block.type == "tool_use":
handler = TOOL_HANDLERS.get(block.name)
output = handler(**block.input) if handler \
else f"Unknown tool: {block.name}"
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": output,
})
Agregar una herramienta = agregar un gestor + agregar una entrada de esquema. El bucle nunca cambia.
Qué Cambió Respecto a s01
| Componente | Antes (s01) | Después (s02) |
|---|---|---|
| Herramientas | 1 (solo bash) | 4 (bash, read, write, edit) |
| Distribución | Llamada bash codificada | TOOL_HANDLERS dict |
| Seguridad ruta | None | safe_path() sandbox |
| Bucle agente | Sin cambios | Sin cambios |
Pruébalo
python agents/s02_tool_use.py
Leer el archivo requirements.txtCrear un archivo llamado greet.py con una función greet(name)Editar greet.py para agregar un docstring a la funciónLeer greet.py para verificar que la edición funcionó
