개발 도구 (adk-devtools)
adk-devtools는 코딩 에이전트가 필요로 하는 inner-loop 도구 모음입니다 — 읽기, 편집, 검색, 실행 — 이 모든 작업은 작업 공간 디렉터리로 범위가 지정됩니다. 이것은 adk-core에만 의존하는 독립적인, 배포 가능한 crate이며, 어떤 LlmAgent와도 함께 사용할 수 있습니다(CodingAgent harness가 이를 연결해 줍니다).
도구들
DevToolset는 여섯 개의 도구를 묶은 Toolset입니다:
| 도구 | 매개변수 | 동작 |
|---|---|---|
read_file | path, offset?, limit? | 파일 내용을 반환하며, 줄 번호가 매겨져 있음 |
write_file | path, content | 파일을 생성/덮어쓰기(상위 디렉터리 생성) |
edit_file | path, old_string, new_string, replace_all? | 정확한 문자열 대체 |
glob | pattern, path? | 글롭과 일치하는 파일 나열(예: src/**/*.rs) |
grep | pattern, path?, glob?, case_insensitive? | 정규식 콘텐츠 검색 |
bash | command, timeout_secs? | 작업 공간 루트에서 셸 명령 실행 |
알아두면 좋은 두 가지 안전 동작:
edit_file는 해당 파일의 사전read_file을 세션에서 요구하며, 기본적으로 대상 문자열은 정확히 한 번 나타나야 합니다(이를 재정의하려면replace_all). 이는 맹목적인 덮어쓰기를 방지합니다.- **
grep**은 일반적인 빌드/VCS 디렉터리(target,.git,node_modules, …)와 바이너리/과대 파일을 건너뜁니다.
bash 도구는 명령이 실행되는 동안 ToolContext::emit_progress을 통해 stdout/stderr를 줄 단위로 스트리밍하므로, UI가 실시간 터미널을 표시할 수 있습니다. 각 청크는 에이전트의 EventStream에서 부분 이벤트로 도착하며(event.tool_progress_stream()로 감지), 전체 출력은 여전히 도구의 최종 결과로 반환됩니다. streaming_bash 예제와 도구로부터의 스트리밍 진행 상황을 참조하세요.
Workspace
Workspace는 모든 작업을 디렉터리 하나에 뿌리내리게 하고 작은 정책을 강제합니다:
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);
-
경로 포함성 — 루트 밖으로 해석되는 모든 경로는 거부되므로, 에이전트는
../../etc/...를 읽거나 쓸 수 없습니다. 포함성은 단순한 문자 그대로의 경로가 아니라 해결된 경로를 기준으로 강제됩니다. 따라서 루트 밖을 가리키는 심볼릭 링크는, 문법적으로는 루트 안에 있더라도 거부됩니다. 이는 심볼릭 링크된 마지막 구성 요소와 심볼릭 링크된 상위 디렉터리를 모두 포함하므로, 리디렉션된 디렉터리를 통한 생성도 거부됩니다. 대상이 워크스페이스 내부에 머무는 심볼릭 링크는 계속 동작하는데, 저장소에는 내부 링크가 합법적으로 포함될 수 있기 때문입니다.이 검사는 잠금이 아닙니다. 검사와 그 다음의 open 사이에 심어 넣은 심볼릭 링크는 여전히 따라가게 됩니다. 그 창을 닫으려면 플랫폼의 no-follow 의미론을 사용한 descriptor-relative traversal이 필요합니다. 파일 도구는 동시적으로 워크스페이스에 쓸 수 있는 적대자가 아니라, 돌아다니는 에이전트에 대한 포함성으로 취급하세요.
-
읽기 전용 모드 —
Workspace::read_only(..)는 변경 도구를 완전히 숨깁니다(모델은read_file/glob/grep만 보게 됩니다). -
bash환경이 지워짐 — 명령은PATH,HOME,LANG,LC_ALL,TMPDIR,TERM,USER,SHELL만 받으므로, 에이전트 프로세스가 보유한 provider API 키는env로 읽을 수 없습니다.Workspace::inherit_env(true)는 이전의 pass-everything 동작을 복원하고,env_allowlist는 집합을 대체합니다. -
bash타임아웃 + 출력 한도 — 오래 걸리거나 말이 많은 명령은 제한됩니다. 타임아웃된 명령은 프로세스 그룹으로 종료되므로, 그 명령이 시작한 것들도 함께 종료됩니다. 이전에는 직접 자식만 신호를 받았고 하위 프로세스는 살아남았습니다.
직접 사용하기
도구 세트를 어떤 에이전트에든 연결하세요:
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는 워크스페이스가 허용하는 도구만 노출하므로, 읽기 전용 워크스페이스는 자동으로 읽기 전용 에이전트를 제공합니다.
샌드박싱 모델
Phase 1은 bash를 호스트 로컬(sh -c, 작업 디렉터리는 루트에 고정)로 실행하며, 타임아웃과 지워진 환경을 적용합니다. 이것이 제공하는 것과 제공하지 않는 것은:
| 강제됨 | 강제되지 않음 |
|---|---|
| 파일 도구는 심볼릭 링크를 통해서도 루트 밖을 확인할 수 없습니다 | bash는 여전히 절대 경로를 사용할 수 있습니다 — 작업 디렉터리는 OS 경계가 아닙니다 |
| 명령은 에이전트의 환경 변수를 읽을 수 없습니다 | 명령은 네트워크에 접근할 수 있습니다 |
| 시간 초과가 명령과 그 하위 프로세스를 종료합니다 | 메모리나 CPU를 제한하는 것은 없습니다 |
따라서 이것은 경로에 포함되고, 환경이 격리되어 있으며, 범위가 제한되지만 운영체제 수준으로는 격리되지 않습니다. 정책 어휘는 adk-code의 SandboxPolicy와 일치합니다. 강한 격리가 필요하면 컨테이너화된 실행기 뒤에서 bash을 실행하세요(자세한 내용은 설계 문서 참조).
adk-guardrail(명령 allowlist,
비밀 정보 마스킹) 및 토큰화된
도구를 위한 adk-auth와 함께 사용하세요(예: GitHub).
다음: 하네스 →