Dev Tools (adk-devtools)
adk-devtools は、コーディングエージェントが必要とする内側ループ用のツールセットです。読み取り、編集、検索、実行を行い、各操作は ワークスペースディレクトリにスコープされます。これは adk-core のみに依存する独立した公開可能な crate であり、任意の LlmAgent と組み合わせられます(CodingAgent harness があなたのために接続します)。
ツール
DevToolset は、6 つのツールをまとめた Toolset です:
| ツール | パラメータ | 挙動 |
|---|---|---|
read_file | path, offset?, limit? | ファイル内容を行番号付きで返す |
write_file | path, content | ファイルを作成/上書きする(親ディレクトリを作成する) |
edit_file | path, old_string, new_string, replace_all? | 完全一致文字列置換 |
glob | pattern, path? | glob に一致するファイルを一覧表示(例: src/**/*.rs) |
grep | pattern, path?, glob?, case_insensitive? | 正規表現による内容検索 |
bash | command, timeout_secs? | ワークスペースのルートでシェルコマンドを実行 |
知っておくべき安全動作を2つ挙げます。
edit_fileは、そのファイルをセッション内で事前にread_fileしていることを要求し、デフォルトでは対象文字列は ちょうど1回 出現していなければなりません(これを上書きするにはreplace_all)。これは、無条件の上書きを防ぐためです。grepは、一般的なビルド/VCS ディレクトリ(target、.git、node_modules、…)や、バイナリ/大きすぎるファイルをスキップします。
bash ツールは、コマンドの実行中に ToolContext::emit_progress を使って stdout/stderr を1行ずつ ストリーム します。そのため、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/...を読み書きできません。包含は、文字通りのパスではなく 解決後 のパスに対して強制されます。つまり、ルートの外を指すシンボリックリンクは、見かけ上はルート内にあっても拒否されます。これは、シンボリックリンクされた末尾コンポーネントとシンボリックリンクされた親ディレクトリの両方をカバーするため、リダイレクトされたディレクトリ経由での作成も拒否されます。ターゲットが workspace 内に収まるシンボリックリンクはそのまま機能し続けます。リポジトリには内部リンクが正当に含まれるためです。このチェックはロックではありません。チェックとその後の open の間に植え込まれたシンボリックリンクは、それでもたどられてしまいます。この隙を塞ぐには、プラットフォームの no-follow セマンティクスを伴う descriptor-relative なトラバーサルが必要です。ファイルツールは、歩き回るエージェントに対する包含として扱い、workspace に並行して書き込める adversary に対する分離としては扱わないでください。
-
読み取り専用モード —
Workspace::read_only(..)は変更系ツールを完全に隠します(モデルが見るのはread_file/glob/grepだけです)。 -
bash環境はクリアされる — コマンドはPATH、HOME、LANG、LC_ALL、TMPDIR、TERM、USER、SHELLだけを受け取るため、エージェントプロセスが保持している provider API キーはenvでは読み取れません。Workspace::inherit_env(true)は、以前の「すべて渡す」動作を復元し、env_allowlistはそのセットを置き換えます。 -
bashのタイムアウト + 出力上限 — 長すぎる、またはおしゃべりすぎるコマンドは制限されます。タイムアウトしたコマンドは プロセスグループ として kill されるため、それが開始したものもすべて kill されます。以前は直接の子プロセスにだけ signal が送られ、子孫は生き残っていました。
直接使う
ツールセットを任意のエージェントに追加します。
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 は workspace が許可するツールだけを公開するため、読み取り専用の workspace なら自動的に読み取り専用のエージェントになります。
サンドボックスモデル
Phase 1 は bash を host-local に実行します(sh -c、作業ディレクトリは root に固定)し、タイムアウトとクリアされた環境を伴います。これで何が得られて、何が得られないか:
| 強制される | 強制されない |
|---|---|
| ファイルツールは、symlink 経由を含め、ルート外を解決できない | bash は引き続き絶対パスを使える — 作業ディレクトリは OS の境界ではない |
| コマンドは agent の環境変数を読み取れない | コマンドはネットワークにアクセスできる |
| タイムアウトによりコマンドとその子孫が終了する | メモリや CPU を制限するものはない |
つまり、これはパス内に限定され、環境は分離され、境界はあるものの、OS は分離されていません。ポリシーの語彙は adk-code の SandboxPolicy と一致しています。強い分離が必要な場合は、コンテナ化された実行環境の背後で bash を実行してください(design doc を参照)。adk-guardrail(コマンドの allowlist、シークレットの秘匿化)およびトークン化されたツール向けの adk-auth(例: GitHub)と組み合わせてください。
次へ: The harness →