Herramientas de desarrollo (adk-devtools)
adk-devtools es el conjunto de herramientas de ciclo interno que necesita un agente de programación: leer, editar, buscar y ejecutar, con cada operación limitada a un directorio de trabajo. Es un crate independiente y publicable que depende solo de adk-core, por lo que se compone con cualquier LlmAgent (el harness de CodingAgent lo conecta por ti).
Las herramientas
DevToolset es un Toolset que agrupa seis herramientas:
| Herramienta | Parámetros | Comportamiento |
|---|---|---|
read_file | path, offset?, limit? | Devuelve el contenido del archivo, con numeración de líneas |
write_file | path, content | Crear/sobrescribir un archivo (crea directorios padre) |
edit_file | path, old_string, new_string, replace_all? | Reemplazo exacto de cadena |
glob | pattern, path? | Lista archivos que coinciden con un glob (p. ej. src/**/*.rs) |
grep | pattern, path?, glob?, case_insensitive? | Búsqueda de contenido con expresiones regulares |
bash | command, timeout_secs? | Ejecuta un comando de shell en la raíz del espacio de trabajo |
Dos comportamientos de seguridad que conviene conocer:
edit_filerequiere unaread_fileprevia de ese archivo en la sesión, y por defecto la cadena objetivo debe aparecer exactamente una vez (replace_allpara anularlo). Esto protege contra sobrescrituras ciegas.grepomite los directorios comunes de compilación/VCS (target,.git,node_modules, …) y los archivos binarios o de tamaño excesivo.
La herramienta bash transmite su stdout/stderr línea por línea mediante
ToolContext::emit_progress a medida que se ejecuta el comando, de modo que las UI pueden mostrar una
terminal en vivo. Cada fragmento llega como un evento parcial en el EventStream del agente
(detectarlo con event.tool_progress_stream()); la salida completa sigue
devolviéndose como resultado final de la herramienta. Ver el
ejemplo streaming_bash y
Streaming Progress from a Tool.
El Workspace
Un Workspace ancla cada operación a un directorio y aplica una pequeña política:
use adk_devtools::Workspace;
use std::time::Duration;
let ws = Workspace::new("./my-repo"); // read-write, bash enabled
let ws = Workspace::read_only("./my-repo"); // explore/plan: no writes, no bash
let ws = Workspace::new("./my-repo")
.allow_bash(false) // file edits, but no shell
.bash_timeout(Duration::from_secs(60))
.max_output_bytes(512 * 1024);
-
Contención de ruta — cualquier ruta que se resuelva fuera de la raíz se rechaza, así que el agente no puede leer ni escribir
../../etc/.... La contención se impone contra la ruta resuelta, no solo la literal: un enlace simbólico que apunte fuera de la raíz se rechaza aunque esté lexicográficamente dentro. Eso cubre un componente final enlazado simbólicamente y un directorio padre enlazado simbólicamente, así que también se deniega la creación a través de un directorio redirigido. Un enlace simbólico cuyo destino permanezca dentro del espacio de trabajo sigue funcionando, ya que los repositorios contienen legítimamente enlaces internos.La comprobación no es un bloqueo. Un enlace simbólico insertado entre la comprobación y la posterior apertura todavía se seguiría; cerrar esa ventana requiere recorrido relativo al descriptor con semántica de no-follow de la plataforma. Trata las herramientas de archivos como contención frente a un agente que deambula, no como aislamiento frente a un adversario que puede escribir en el espacio de trabajo de forma concurrente.
-
Modo de solo lectura —
Workspace::read_only(..)oculta por completo las herramientas que modifican (el modelo solo veread_file/glob/grep). -
Entorno de
bashlimpiado — el comando recibe soloPATH,HOME,LANG,LC_ALL,TMPDIR,TERM,USERySHELL, así que las claves de API del proveedor que mantiene el agente no son legibles conenv.Workspace::inherit_env(true)restaura el antiguo comportamiento de pasar todo, yenv_allowlistreemplaza el conjunto. -
Tiempo de espera + límites de salida de
bash— los comandos largos o muy verbosos quedan limitados. Un comando que agota el tiempo se mata como un grupo de procesos, así que todo lo que inició también se mata; antes solo se señalaba al hijo directo y los descendientes sobrevivían.
Uso directo
Adjunta el conjunto de herramientas a cualquier agente:
use adk_devtools::{DevToolset, Workspace};
use adk_agent::LlmAgentBuilder;
use std::sync::Arc;
let agent = LlmAgentBuilder::new("coder")
.model(model)
.toolset(Arc::new(DevToolset::new(Workspace::new("./my-repo"))))
.build()?;
DevToolset solo expone las herramientas que permite el espacio de trabajo, así que un
espacio de trabajo de solo lectura genera automáticamente un agente de solo lectura.
Modelo de aislamiento
La fase 1 ejecuta bash en el host local (sh -c, directorio de trabajo fijado a la raíz) con un
tiempo de espera y un entorno limpiado. Qué ofrece esto y qué no ofrece:
| Imposible de hacer cumplir | No se impone |
|---|---|
| Las herramientas de archivos no pueden resolver fuera de la raíz, incluso a través de enlaces simbólicos | bash todavía puede usar rutas absolutas — el directorio de trabajo no es un límite del sistema operativo |
| El comando no puede leer las variables de entorno del agente | El comando puede acceder a la red |
| Un tiempo de espera termina el comando y sus descendientes | Nada limita la memoria ni la CPU |
Así que está contenido en la ruta, aislado del entorno y acotado, pero no aislado del sistema operativo. El vocabulario de la política se alinea con adk-code's SandboxPolicy; para un
aislamiento fuerte, ejecute bash detrás de un ejecutor contenedorizado (consulte el
documento de diseño).
Combine con adk-guardrail (listas de अनुमति de comandos,
redacción de secretos) y adk-auth para
herramientas con tokens (p. ej. GitHub).
Siguiente: El harness →