1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Agent Client Protocol を使って独自 Agent を Zed 上で動かす

Posted at

今年 (2025年) の9月に Agent Client Protocl (ACP) という、 コーディングエージェント (Claude Code, Gemini CLI, Codex など) とクライアントの通信を標準化するための規格が Zed から発表されました。

今回はこれを使って Zed 上で独自の Agent を作って動かしてみようと思います。

Agent Client Protocol とは

image.png

Agent Client Protocl (ACP) は、コーディングエージェント (Claude Code, Gemini CLI, Codex など) とクライアント (各種エディタ、開発ツールなど) の通信を標準化するための規格です。

LSP や MCP と同じような存在で、クライアントが ACP に対応すると、様々なコーディングエージェントに対応でき、エージェントが ACP に対応すると、いろんなクライアントで動かせるようになります。

対応クライアント

2025/12 現在では、様々なエディタやツールでも ACP への対応が行われています。

JetBrains IDE でも対応がアナウンスされています。

Emacs, NeoVim, Obsidian などでもプラグインを使って ACP 経由で Agent を利用することが可能です。

他の対応ツールは ↓ から確認可能です。

ACP を使った Agent を作る

ACP には Python, Rust, TypeScript 用の SDK が用意されており、これを利用することで Zed に対応した Agent を作ることができます。

サンプルコードもそれぞれ用意されています。今回はこれの TypeScript 用のを拡張して作成してみます。

※ 今回のコードは↓から確認可能です。

Agent のサンプルを動かす

Ref: https://github.com/agentclientprotocol/typescript-sdk/tree/main/src/examples#running-the-agent

まずは一旦サンプルコードをそのままの状態で動かします。

以下の方法で設定できます。

  1. https://github.com/agentclientprotocol/typescript-sdk を git clone する
  2. Zed の Agent Panel から、Settings → Add Agent を選択
    • image.png
    • image.png
  3. 以下の設定を追加
    • (※ 絶対パスが必要。 ~ は不可)
  "agent_servers": {
    "Example Agent": {
      "command": "npx",
      "args": [
        "tsx",
        "/path/to/agent-client-protocol/src/examples/agent.ts"
      ]
  }

追加すると、Agent を選択する際に、今回追加した Agent が選べ、利用できるようになります。

image.png

デフォルトでは、決まったメッセージを出力するようになっています。

image.png

ACP の通信の内容を確認する

Zed にはデバッグ用のコマンドとして、 dev: open acp logs というコマンドで、 ACP の通信の内容をログとして表示することができます。

image.png

通信内容を確認したり、ログを流すことも出来るので開発時のデバッグに便利です。

スクリーンショット 2025-12-31 10.24.39.png

ちなみに、このログを見る限りでは Zed は新しく Agent とのセッションを開始するたびに、 Agent サーバーを再起動しているみたいです。開発時に再読み込みしたい場合はセッションを都度開き直すと良いです。

サンプルコードを改造する

それではこれを改造してみます。

Agent の一連の流れ

TypeScript SDK には AgentAgentSideConnection など、 ACP の通信の一連の流れが class や interface として実装されています。

クライアントからプロンプトが送信されると、 Agent の prompt メソッドが呼ばれます。
このメソッドの中で Agent としての返答を行います。

import * as acp from "../acp.js";

class ExampleAgent implements acp.Agent {
  private connection: acp.AgentSideConnection;
  private sessions: Map<string, AgentSession>;

  async prompt(params: acp.PromptRequest): Promise<acp.PromptResponse> {
    const session = this.sessions.get(params.sessionId);

    if (!session) {
      throw new Error(`Session ${params.sessionId} not found`);
    }

    try {
      // prompt を実際に処理
      // prompt を送信
      await this.connection.sessionUpdate({
        sessionId,
        update: {
          sessionUpdate: "agent_message_chunk",
          content: {
            type: "text",
            text: "response",
          },
        },
      });
    } catch (err) {
      if (session.pendingPrompt.signal.aborted) {
        return { stopReason: "cancelled" };
      }

      throw err;
    }

    return {
      stopReason: "end_turn",
    };
  }
}

AI SDK の設定

LLM を利用する箇所は AI SDK を使います。
LLM はローカルで動く LM Studio を使います。

import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
import { ToolLoopAgent, type ToolSet, tool } from "ai";

const provider = createOpenAICompatible({
  name: "lmstudio",
  baseURL: "http://localhost:1234/v1",
});
const model = provider("qwen/qwen3-vl-4b");

AI SDK には、「ツールを適宜実行する Agent」を ToolLoopAgent として実装できます。

import { ToolLoopAgent } from 'ai';

const agent = new ToolLoopAgent({
  model,
  tools: {
    // 後で実装する
  },
});

const stream = agent.stream({
  messages: [
    {
      role: "system",
      content: `You are AI agent to assist a user with software development tasks.
You can read and modify files in the user's project directory as needed to complete the tasks.
Always ask for permission before making changes to critical files like configuration files.`,
    },
    {
      role: "user",
      content: prompt,
    },
  ],
});

for await (const part of result.fullStream) {
  switch (part.type) {
    case "text-delta": {
      const { text } = part;

      await this.connection.sessionUpdate({
        sessionId,
        update: {
          sessionUpdate: "agent_message_chunk",
          content: {
            type: "text",
            text,
          },
        },
      });
      break;
    }

これで、ひとまず LLM に返答を行わせることが可能になります。

image.png

ファイルの読み込みや書き込みを行う

コーディング系のエージェントでよくあるのといえば、ファイルの読み書きですが、これらは ACP の機能として使うことができます。(この機能を使ってファイルの編集を行うと、Agent の画面で編集した内容を確認できます)

AI SDK の Tools (https://ai-sdk.dev/docs/agents/building-agents#tools) と組み合わせて使うことで、 AI 側が必要な情報をクライアント側から取得することができます。

import { tool } from "ai";

const tools = {
  readFile: tool({
    description: "Read the content of a file",
    inputSchema: z.object({ /* パラメータの定義 */ }),
    execute: async ({ path, line, limit }, { toolCallId }) => {
      // path の line 行目から limit 行分 Client 側が取得して返す
      const { content } = await this.connection.readTextFile({
        sessionId,
        path,
        line,
        limit,
      });
    
      return { content };
   },
  }),
}

説明は割愛するのですが、他にも command の実行を行う機能や、チェックリストの管理を行う機能、モードの切替を行う機能など、現状の AI エージェントの UI としてある機能は大体ある感じです。

実行の許可を求める

// 実行予定の Tool の内容を伝える
await connection.sessionUpdate({
  sessionId,
  update: {
    sessionUpdate: "tool_call",
    title: "echo 1",
    toolCallId,
    status: "pending",
  },
});

// 実行許可をユーザーに取る。選ばれた選択肢が outcome に入る
const { outcome } = await connection.requestPermission({
  sessionId,
  toolCall: {
    toolCallId,
  },
  options: [
    {
      kind: "allow_once",
      name: "echo 1",
      optionId: "allow",
    },
    {
      kind: "reject_once",
      name: "Reject echo 1",
      optionId: "reject",
    },
  ],
});

if (outcome.optionId !== "allow") {
  throw new NotPermittedError("Canceled for echo 1");
}

実際に実行すると以下のように実行してよいかが出てきます。

image.png

ちなみに、ユーザーに許可を取るかなどは Agent 側に完全に任されています。許可せずに Tool を勝手に実行することも可能ですし、尋ねる選択肢も自由です。

Agent の完成 :tada:

…という感じで、これらの機能を使うことで Zed 上で AI Agent を動かすことが可能になります。
実際の実装は typescript-sdk/src/examples/agent.ts at modify-example-agent · tomoasleep/typescript-sdk から見れます。

image.png

image.png

ちゃんと編集した内容もエディタから確認できて、いわゆるエージェントっぽい感じですね。

image.png

ACP の全体的な雰囲気として、現状のコーディングエージェントの機能としてあるものをそのまま落とし込んだという感じで、進化の激しいエージェントにどれだけ追従できるかとかは正直わからんところがありますが、サーバー部分だけを作ればいろんなクライアント側に UI を任せられる点、エージェントをサクッと作るという点では (AI SDK が整っているのもあり) 非常に優れている印象です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?