ACPクライアントまたはホストを構築する

ADK-Rustアプリケーションがコーディング作業を外部のACPプロセスに委任する必要がある場合は、クライアント方向を使用します。アプリケーションはホストとして存続し、プロジェクトの選択、ユーザー体験、承認ルール、およびコーディングエージェントに提供するローカルサービスを所有します。

インストール

[dependencies]
adk-acp = "2.1.0"

デフォルトの機能セットはクライアント実装です。ADK-Rustエージェントを公開する場合にのみ、server機能が必要です。

クライアントの形状を選択する

製品形状API
新しいプロセスによる、分離された単一タスクprompt_agent_with_policy
テキスト以外(画像、音声、リソース)のコンテンツを含む、分離された単一タスクprompt_agent_content_with_policy
LLMエージェントが利用できるコーディング専門家AcpAgentTool
複数の名前付きコーディング専門家AcpToolset
継続中のプロジェクトに関する会話AcpSession
ターンの実行中に表示されるテキストとツールの進行状況stream_prompt

一回限りのプロンプト

use adk_acp::{
    AcpAgentConfig, PermissionPolicy, prompt_agent_with_policy,
};
use std::sync::Arc;

let config = AcpAgentConfig::new("my-coding-agent --acp")
    .working_dir("/absolute/path/to/project");

let answer = prompt_agent_with_policy(
    &config,
    "Inspect the failing test and explain the cause.",
    Arc::new(PermissionPolicy::DenyAll),
).await?;

DenyAllがデフォルトなのは、起動されたコーディングエージェントが実際の副作用を伴う操作を要求できるためです。AutoApproveは、信頼できるローカルワークフロー内でのみ使用してください。

リッチなプロンプトコンテンツを送信する

prompt_agent_content_with_policyは文字列だけでなく、完全なadk_core::Content値を送信するため、プロンプトにテキスト以外のコンテンツを含めることができます。埋め込みリソース、画像、音声のパーツは破棄されず、共有コンテンツモジュールを介して対応するACPコンテンツブロックにマッピングされます。テキストは常に保持されます。送信可能なACP表現を持たないパーツはスキップされ、ブロックにまったくマッピングされないプロンプトは拒否されます。

use adk_acp::{AcpAgentConfig, PermissionPolicy};
use adk_acp::connection::prompt_agent_content_with_policy;
use adk_core::{Content, Part};
use std::sync::Arc;

let mut content = Content::new("user");
content.parts.push(Part::Text { text: "What is in this image?".into() });
content.parts.push(Part::InlineData { mime_type: "image/png".into(), data: png_bytes });

let config = AcpAgentConfig::new("my-coding-agent --acp")
    .working_dir("/absolute/path/to/project");

let answer = prompt_agent_content_with_policy(
    &config,
    &content,
    Arc::new(PermissionPolicy::DenyAll),
).await?;

ADKエージェントから委任する

use adk_acp::{AcpAgentTool, PermissionDecision, PermissionPolicy};
use adk_agent::LlmAgentBuilder;
use std::sync::Arc;

let policy = PermissionPolicy::Custom(Box::new(|request| {
    if request.title.to_ascii_lowercase().contains("delete") {
        PermissionDecision::deny()
    } else {
        PermissionDecision::allow_once()
    }
}));

let coding_agent = AcpAgentTool::new("my-coding-agent --acp")
    .name("repository_specialist")
    .description("Inspect and improve the current Rust repository")
    .working_dir("/absolute/path/to/project")
    .permission_policy(policy);

let coordinator = LlmAgentBuilder::new("coordinator")
    .model(model)
    .instruction("Delegate repository changes to repository_specialist.")
    .tool(Arc::new(coding_agent))
    .build()?;

AcpAgentTool呼び出しは、新しいプロセスとセッションを開始します。委任するタスクが自己完結しており、コーディネーターがツールの結果として最終テキストだけを必要とする場合は、この形式を選択してください。

永続セッションとキャンセル

use adk_acp::{AcpAgentConfig, AcpSession, PermissionPolicy};
use std::sync::Arc;

let config = AcpAgentConfig::new("my-coding-agent --acp")
    .working_dir("/absolute/path/to/project");
let mut session = AcpSession::start(
    config,
    Arc::new(PermissionPolicy::DenyAll),
).await?;

let first = session.prompt("Map the error-handling modules.").await?;
let second = session.prompt("Now inspect the most central one.").await?;

let cancel = session.cancellation_handle()?;
// Move `cancel` into a stop-button, timeout, or shutdown task while another
// task awaits `session.prompt(...)`.

session.close().await?;

キャンセルハンドルは、公式のsession/cancel通知を送信します。キャンセルされた停止理由が届くまでプロンプトの待機を続けてください。これにより、同じセッションでキューに古いレスポンスを残さず、別のプロンプトを受け付けられます。

ターンを UI にストリーミングする

stream_promptは、エージェントのテキスト、思考、ツールの開始、権限の判断、完了、エラーを示すOutputChunk値を生成します。これらに加えて、External_Agentのターンについて、より詳細な2つのビューを提供します。

  • OutputChunk::ToolUpdate — External_Agent の ToolCallUpdate。ツール呼び出し id によって関連付けられ、報告されたステータス、種別、更新されたタイトル、抽出されたコンテンツテキスト、影響を受けるファイルの場所を含みます。これにより、UI は最終テキストだけでなく、ツールの進行状況、差分、影響を受けるファイルの一覧も表示できます。
  • OutputChunk::Usage — External_Agent の UsageUpdate。トークン used とコンテキストウィンドウ size に加え、エージェントが報告する場合は累積 costcurrency も含まれるため、UI でコンテキストウィンドウの使用量を表示できます。

エージェントのメッセージテキストはこれまでどおり正確に公開されるため、テキストチャンクのみを読み取る UI には影響しません。アプリケーションは思考チャンクを非表示にしたり、ツールのアクティビティを個別に表示したり、共有 StatusTracker をインターフェースで公開したりできます。

完全なループについては、実行可能な acp_client_host クレートを参照してください。

エージェントがファイルを要求できるようにする

AcpFileSystem を実装し、AcpAgentConfig::filesystem で関連付けます。読み取りおよび書き込み機能は、supports_readsupports_write を通じて個別に通知されます。

コールバックは絶対パスを受け取ります。本番ホストでは、次の処理を行う必要があります。

  1. 承認済みのワークスペースと要求されたパスを正規化する。
  2. シンボリックリンクによる脱出を含め、承認済みのルート外にあるパスを拒否する。
  3. 未保存のエディターバッファーでディスク上のコンテンツを上書きするかどうかを決定する。
  4. ファイルサイズと行範囲の制限を適用する。
  5. アプリケーションが書き込みを実装し、認可している場合にのみ、書き込み機能を通知する。

作業ディレクトリはコンテキストであり、サンドボックスではありません。ファイルシステムの検証と OS プロセス境界は、それぞれ異なる問題を解決します。

エージェントがコマンドを実行できるようにする

AcpTerminal を実装し、AcpAgentConfig::terminal で関連付けます。ACP はターミナルを 1 つの機能として通知するため、ホストは作成、出力、待機、強制終了、解放のライフサイクル全体を実装する必要があります。

ホストは、コマンド許可リスト、作業ディレクトリのルール、環境変数、出力制限、プロセス分離、クリーンアップ動作を選択します。ターミナルコールバックは JSON-RPC のディスパッチループ外で実行されるため、長時間の待機によって権限やキャンセルの通信が停止することはありません。

セッションに MCP サーバーを提供する

use adk_acp::AcpAgentConfig;
use adk_acp::agent_client_protocol::schema::v1::{
    McpServer, McpServerStdio,
};

let tools = McpServer::Stdio(
    McpServerStdio::new("project-tools", "/absolute/path/to/mcp-server")
        .args(vec!["--read-only".into()]),
);

let config = AcpAgentConfig::new("my-coding-agent --acp")
    .working_dir("/absolute/path/to/project")
    .mcp_server(tools);

安定版 ACP v1 では、エージェントが stdio MCP 設定を受け入れる必要があります。HTTP および SSE のエントリは、外部エージェントがこれらのオプションのトランスポートを通知した場合にのみ送信されます。AcpAgentConfig のデバッグ出力には、秘密の値を出力せずに名前と環境キーが一覧表示されます。

権限ポリシー

すべての権限リクエストには、セッション ID、正確なツール呼び出し ID、ツールの種類、未加工の入力、エージェントが提示したすべてのオプションが含まれます。オプション ID は不透明です。ADK-Rust は許可および拒否のセマンティクスに従って照合し、元の ID を返します。偽造された選択はキャンセルになります。

PermissionPolicy::async_custom は、デスクトップダイアログ、Web 承認 UI、または組織のポリシーサービスを待機できます。スレッドをブロックするのではなく、この API を通じて人間とのやり取りを待機することで、ディスパッチループの応答性を維持します。

次へ

ACPクライアントまたはホストを構築する - ADK-Rust ドキュメント | ADK-Rust