Agent Client Protocol (ACP) — это стандартизированный протокол обмена сообщениями для взаимодействия с искусственными интеллектами-агентами. ACP определяет единый интерфейс коммуникации между кодовыми редакторами (IDE) и AI-агентами, обеспечивая совместимость между различными реализациями без привязки к конкретному поставщику.
Протокол был разработан для решения проблемы фрагментации экосистемы AI-агентов. Ранее каждый редактор кода (Zed, JetBrains IDE, VS Code) требовал собственных интеграций с каждым агентом (Claude Code, Gemini CLI, GitHub Copilot), что приводило к:
ACP решает эти проблемы, предоставляя открытый стандарт, который позволяет любому агенту, реализующему протокол, беспрепятственно интегрироваться с любым совместимым редактором.
ACP был инициирован командой Zed Industries и получил активную поддержку JetBrains. В октябре 2025 года JetBrains и Zed объединились для публичного объявления о совместной разработке протокола как открытого стандарта для интеграции AI-агентов в IDE.
Ключевые вклады:
Обе компании подчеркивают открытость стандарта: ACP распространяется под лицензией Apache и доступен для использования любыми разработчиками и организациями.
Agent Client Protocol (ACP) — это JSON-RPC 2.0-совместимый протокол, предназначенный для обмена сообщениями между AI-агентами и клиентскими приложениями (в первую очередь, кодовыми редакторами).
Основные принципы
| Принцип | Описание |
|---|---|
| Простота | Минималистичная структура сообщений, основанная на JSON-RPC 2.0 |
| Расширяемость | Система capabilities позволяет агентам и клиентам объявлять поддерживаемые функции |
| Языковая независимость | Протокол не привязан к конкретному языку программирования |
ACP реализует классическую клиент-серверную модель:
Протокол поддерживает как однонаправленную, так и двунаправленную коммуникацию, что позволяет реализовать потоковую передачу данных и уведомления о событиях в реальном времени.
Примечание: Полная поддержка удалённых агентов находится в разработке. Команда ACP активно сотрудничает с платформами агентов для обеспечения соответствия протокола требованиям облачных развертываний.
Историческая хронология:
До появления ACP экосистема AI-агентов страдала от следующих проблем:
До ACP интеграция Claude Code в Zed требовала:
// Zed должен был иметь специальную интеграцию для Claude Code
{
"agent_type": "claude_code",
"api_endpoint": "https://api.anthropic.com/v1/messages",
"auth_method": "Bearer token",
"message_format": "claude-specific-schema"
}
А для Gemini CLI — другая интеграция:
// Zed должен был иметь специальную интеграцию для Gemini CLI
{
"agent_type": "gemini_cli",
"command": "gemini",
"args": ["--mode", "chat"],
"message_format": "gemini-specific-schema"
}
ACP решает эту проблему, предоставляя единый формат сообщений:
// Единый формат для всех агентов через ACP
{
"jsonrpc": "2.0",
"method": "session/prompt",
"params": {
"session_id": "abc123",
"content": "Как работает ACP?"
}
}
| Характеристика | ACP | OpenAI Functions API |
|---|---|---|
| Назначение | Коммуникация между редактором и агентом | Вызов функций/инструментов LLM |
| Стандарт | Открытый, независимый | Проприетарный, привязан к OpenAI |
| Структура | JSON-RPC 2.0 | REST API с JSON |
| Расширяемость | Система capabilities | Фиксированная схема |
Преимущества ACP:
| Характеристика | ACP | LangChain |
|---|---|---|
| Уровень | Протокол коммуникации | Фреймворк для построения агентов |
| Фокус | Интеграция с редакторами | Разработка агентов |
| Формат | JSON-RPC 2.0 | Python-объекты |
| Использование | Внешняя коммуникация | Внутренняя логика агента |
ACP и LangChain не конкурируют, а дополняют друг друга:
| Характеристика | ACP | Custom HTTP API |
|---|---|---|
| Стандартизация | Единый стандарт | Кастомная реализация |
| Совместимость | Работает со всеми ACP-совместимыми редакторами | Требует кастомной интеграции |
| Документация | Официальная спецификация | Часто отсутствует или неполная |
| Поддержка | Сообщество и официальные SDK | Только команда проекта |
ACP поддерживает три основных паттерна коммуникации:
| Паттерн | Направление | Описание |
|---|---|---|
| Request-Response | Клиент → Сервер | Синхронные запросы с ожиданием ответа |
| Event Notification | Сервер → Клиент | Асинхронные уведомления о событиях |
| Bidirectional | Оба направления | Полноценный двунаправленный диалог |
ACP поддерживает три основных канала коммуникации:
ACP использует JSON-RPC 2.0 как основу для структуры сообщений. Этот протокол обеспечивает простую, но мощную основу для удалённого вызова процедур (RPC), поддерживающую как синхронные запросы-ответы, так и асинхронные уведомления.
Каждое сообщение ACP — это валидный JSON-объект со следующими обязательными полями:
{
"jsonrpc": "2.0",
"id": 1,
"method": "session/prompt",
"params": { ... }
}
Ответ от сервера содержит либо поле result, либо поле error:
// Успешный ответ
{
"jsonrpc": "2.0",
"id": 1,
"result": { ... }
}
// Ответ с ошибкой
{
"jsonrpc": "2.0",
"id": 1,
"error": { ... }
}
ACP поддерживает все стандартные коды JSON-RPC 2.0 и добавляет специфичные для AI-агентов коды.
Стандартные коды JSON-RPC 2.0:
| Код | Название | Описание |
|---|---|---|
| -32700 | Parse error | Неверный JSON в запросе |
| -32600 | Invalid Request | Неверный формат JSON-RPC запроса |
| -32601 | Method not found | Метод не найден |
| -32602 | Invalid params | Неверные параметры метода |
| -32603 | Internal error | Внутренняя ошибка сервера |
Специфичные коды ACP:
| Код | Название | Описание |
|---|---|---|
| -32000 | Token limit exceeded | Превышен лимит токенов в сессии |
| -32001 | Tool not found | Запрошенный инструмент не найден |
| -32002 | Session not found | Сессия не найдена |
| -32003 | Session ended | Сессия уже завершена |
| -32004 | Execution cancelled | Выполнение было отменено |
| -32005 | Invalid tool result | Неверный результат выполнения инструмента |
| -32006 | Rate limit exceeded | Превышен лимит запросов |
| -32007 | Invalid message format | Неверный формат сообщения |
| -32008 | Authentication failed | Ошибка аутентификации |
| -32009 | Permission denied | Недостаточно прав для выполнения операции |
ACP расширяет базовый JSON-RPC 2.0, добавляя поля и методы, специфичные для AI-агентов.
ACP определяет следующие основные методы:
| Метод | Описание | Тип |
|---|---|---|
initialize |
Инициализация клиента и получение capabilities агента | Request |
authenticate |
Аутентификация клиента | Request |
session/new |
Создать новую сессию | Request |
session/load |
Загрузить существующую сессию | Request |
session/list |
Получить список активных сессий | Request |
session/prompt |
Выполнить запрос к агенту и получить полный ответ | Request |
session/cancel |
Отменить выполняющийся запрос | Notification |
session/request_permission |
Запросить разрешение на выполнение операции | Request |
fs/read_text_file |
Прочитать текстовый файл | Request |
fs/write_text_file |
Записать текстовый файл | Request |
terminal/* |
Выполнить команду в терминале | Request |
Полный список методов вы можете посмотреть на сайте https://agentclientprotocol.com/protocol/schema
Основной блок контента для сообщений. Является основным контейнером для всех данных, возвращаемых агентом.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
type |
string | Да | Тип блока ("text", "tool_call", "tool_result") |
text |
string | Нет | Текстовое содержимое |
tool_call_id |
string | Нет | ID вызова инструмента |
name |
string | Нет | Имя инструмента (для tool_call) |
arguments |
object | Нет | Аргументы для инструмента (для tool_call) |
is_error |
boolean | Нет | Флаг ошибки выполнения (для tool_result) |
error_message |
string | Нет | Сообщение об ошибке (для tool_result) |
Обновление состояния сессии. Отправляется сервером клиенту как уведомление.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
session_id |
string | Да | ID сессии |
update |
object | Да | Объект обновления |
update.type |
string | Да | Тип обновления ("message", "tool_call", "tool_result", "state") |
update.content |
array | Нет | Массив блоков контента |
update.state |
object | Нет | Состояние сессии |
Уведомление о событии сессии. Стриминг частей ответа сервера клиенту.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
session_id |
string | Да | ID сессии |
notification |
object | Да | Объект уведомления |
notification.type |
string | Да | Тип уведомления |
notification.data |
object | Нет | Дополнительные данные |
Уведомление от агента.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
agent_id |
string | Да | ID агента |
notification |
object | Да | Объект уведомления |
notification.type |
string | Да | Тип уведомления |
notification.data |
object | Нет | Дополнительные данные |
Выполняет запрос к агенту и возвращает полный результат в одном ответе.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
session_id |
string | Да | ID сессии для контекста |
content |
array | Да | Массив блоков контента запроса |
metadata |
object | Нет | Метаданные запроса |
timeout_ms |
integer | Нет | Таймаут в миллисекундах |
ACP-клиент — это приложение, которое инициирует запросы к AI-агенту. Обычно это кодовый редактор (Zed, JetBrains IDE, VS Code) или другая интегрированная среда разработки.
ACP поддерживает три основных канала коммуникации: stdio, WebSocket и HTTP.
stdio соединение — основной метод для локальных агентов, запущенных как подпроцессы.
WebSocket соединение — предпочтительный метод для удалённых агентов, обеспечивающий двунаправленную коммуникацию в реальном времени.
HTTP соединение — используется для запросов-ответов без постоянного соединения. Подходит для простых сценариев или когда WebSocket недоступен.
ACP-сервер — это AI-агент, который получает запросы от клиента, обрабатывает их и выполняет инструменты.
ACP-сервер может быть интегрирован с различными AI-моделями:
ACP-клиент — это приложение, которое инициирует запросы к AI-агенту. Обычно это кодовый редактор (Zed, JetBrains IDE, VS Code), но мы создадим универсальный клиент для демонстрации.
Для работы примеров потребуется библиотека websockets для WebSocket-соединений:
pip install websockets
"""
ACP Client Example
Полный пример ACP-клиента с поддержкой WebSocket, потоковой передачи
и управления сессиями.
"""
import asyncio
import json
import websockets
from typing import Dict, Any, Optional, List, Callable
from dataclasses import dataclass, field
from enum import Enum
import uuid
class MessageRole(Enum):
"""Роли сообщений"""
USER = "user"
ASSISTANT = "assistant"
@dataclass
class ContentBlock:
"""Блок контента сообщения"""
type: str # "text", "image", "tool_call", "tool_result"
text: Optional[str] = None
tool_call_id: Optional[str] = None
name: Optional[str] = None
arguments: Optional[Dict[str, Any]] = None
is_error: bool = False
error_message: Optional[str] = None
@dataclass
class Session:
"""Сессия взаимодействия с агентом"""
session_id: str
messages: List[Dict[str, Any]] = field(default_factory=list)
tools: List[Dict[str, Any]] = field(default_factory=list)
capabilities: Dict[str, Any] = field(default_factory=dict)
class ACPClient:
"""
ACP-клиент для взаимодействия с AI-агентами.
Поддерживает WebSocket соединение, потоковую передачу и управление сессиями.
"""
def __init__(self, websocket_url: str = "ws://localhost:8080/acp"):
"""
Инициализация клиента.
Args:
websocket_url: URL WebSocket-сервера ACP
"""
self.websocket_url = websocket_url
self.websocket = None
self.request_id = 0
self.pending_requests: Dict[int, asyncio.Future] = {}
self.event_handlers: Dict[str, Callable] = {}
self.sessions: Dict[str, Session] = {}
self.current_session: Optional[Session] = None
self._receive_task: Optional[asyncio.Task] = None
self._connected = False
async def connect(self) -> bool:
"""
Установка соединения с ACP-сервером.
Returns:
True при успешном подключении, False в противном случае
"""
try:
self.websocket = await websockets.connect(
self.websocket_url,
ping_interval=20,
ping_timeout=10
)
self._connected = True
# Запуск цикла приёма сообщений
self._receive_task = asyncio.create_task(self._receive_loop())
return True
except Exception as e:
print(f"Ошибка подключения: {e}")
return False
async def disconnect(self):
"""Закрытие соединения с сервером"""
if self._receive_task:
self._receive_task.cancel()
try:
await self._receive_task
except asyncio.CancelledError:
pass
if self.websocket:
await self.websocket.close()
self.websocket = None
self._connected = False
ACP-сервер — это AI-агент, который получает запросы от клиента, обрабатывает их и выполняет инструменты.
// Запрос от клиента
{
"jsonrpc": "2.0",
"id": 1,
"method": "session/new",
"params": {
"capabilities": {
"tools": {"tool_calling": true},
"text": {"input": true, "output": true}
}
}
}
// Ответ от сервера
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"session_id": "sess_abc123",
"capabilities": {
"tools": {"tool_calling": true},
"text": {"input": true, "output": true}
},
"session_state": "active"
}
}
// Запрос от клиента
{
"jsonrpc": "2.0",
"id": 2,
"method": "session/prompt",
"params": {
"session_id": "sess_abc123",
"content": [
{
"type": "text",
"text": "Какой сегодня день?"
}
]
}
}
// Ответ от сервера
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"session_id": "sess_abc123",
"content": [
{
"type": "text",
"text": "Сегодня среда, 9 апреля 2025 года."
}
],
"stop_reason": "end_turn"
}
}
Критически важный аспект ACP, который часто упускают в первых реализациях: протокол предполагает долгоживущий (long-running) процесс сервера, а не запуск нового процесса на каждый запрос.
Когда IDE (клиент) подключается к агенту, она запускает один дочерний процесс через stdio (pipes) и поддерживает это соединение на протяжении всей сессии работы с агентом. Это архитектурное решение обусловлено несколькими факторами:
| Требование | Почему adhoc-процессы не подходят |
|---|---|
| Сохранение контекста | История диалога, кэш инструментов, состояние файлов — всё должно сохраняться между запросами пользователя |
| Стриминг токенов | ACP поддерживает потоковую передачу ответа через уведомления session/notification. Процесс не может завершиться до окончания генерации |
| Двусторонняя коммуникация | Клиент может в любой момент отправить session/cancel, запросить выполнение инструмента или обновить контекст — для этого нужен открытый канал |
| Производительность | Холодный старт процесса + загрузка модели в память занимает секунды. Долгоживущий процесс держит модель "горячей" |
| Спецификация протокола | initialize определён как стартовое рукопожатие, после которого следует серия сессионных запросов — это stateful-протокол |
┌─────────────────────────────────────────┐
│ 1. IDE запускает процесс агента │
│ (через ProcessBuilder / subprocess) │
└────────────────┬────────────────────────┘
▼
┌─────────────────────────────────────────┐
│ 2. Рукопожатие: initialize │
│ • Обмен capabilities │
│ • Согласование версии протокола │
└────────────────┬────────────────────────┘
▼
┌─────────────────────────────────────────┐
│ 3. Создание сессии: session/new │
│ • Возвращает session_id │
│ • Инициализирует контекст диалога │
└────────────────┬────────────────────────┘
▼
┌─────────────────────────────────────────┐
│ 4. Цикл работы с сессией: │
│ • session/prompt → ответ или стрим │
│ • session/notification ← события │
│ • session/cancel ← отмена (опц.) │
│ • tools/call → выполнение инструмента│
└────────────────┬────────────────────────┘
▼
┌─────────────────────────────────────────┐
│ 5. Завершение: session/destroy │
│ или закрытие stdin со стороны IDE │
│ → агент корректно завершает работу │
└─────────────────────────────────────────┘
stdioПри реализации сервера над stdin/stdout необходимо соблюдать три строгих правила:
Newline-delimited JSON: Каждое сообщение (запрос, ответ, уведомление) должно заканчиваться символом \n. Клиент читает stdout построчно (readline()), и отсутствие \n приведёт к зависанию парсера.
Чистый stdout: В поток stdout допускается записывать только валидные JSON-RPC сообщения. Любой print(), traceback, лог отладки или бинарный вывод сломает протокол. Для диагностики используйте stderr.
Асинхронная обработка: Чтение stdin и запись в stdout не должны блокировать друг друга. Обработка session/prompt должна запускаться в фоновой задаче (asyncio.create_task), чтобы сервер продолжал принимать новые сообщения (например, session/cancel) во время генерации ответа.
Когда пользователь закрывает чат или отключает агента, IDE закрывает stdin процесса. Сервер должен корректно обработать EOF в sys.stdin.readline() как сигнал к завершению:
0Эта модель обеспечивает предсказуемое управление ресурсами и совместимость со всеми клиентами, реализующими спецификацию ACP.
"""
ACP Server (Agent Client Protocol)
Пример демо реализации для подключения к IDE (JetBrains, Zed и др.)
Транспорт: JSON-RPC 2.0 over stdio
"""
import asyncio
import json
import sys
import logging
from typing import Dict, Any, Optional
import uuid
# ⚠️ ВАЖНО: Все логи должны идти в stderr. stdout зарезервирован только для JSON-RPC!
logging.basicConfig(
stream=sys.stderr,
level=logging.INFO,
format='%(asctime)s [ACP] %(levelname)s: %(message)s'
)
logger = logging.getLogger(__name__)
class ACPServer:
def __init__(self, agent_name: str = "CustomAgent", agent_version: str = "1.0.0"):
self.agent_name = agent_name
self.agent_version = agent_version
self.sessions: Dict[str, Dict[str, Any]] = {}
self._running = True
async def run(self):
"""Основной цикл чтения сообщений из stdin"""
logger.info("🟢 ACP Server запущен. Ожидание подключений от IDE...")
while self._running:
try:
# Читаем строку из stdin асинхронно (не блокируя event loop)
line = await asyncio.to_thread(sys.stdin.readline)
except EOFError:
break
if not line:
break
line = line.strip()
if not line:
continue
try:
message = json.loads(line)
await self._route_message(message)
except json.JSONDecodeError as e:
logger.error(f"❌ Invalid JSON: {e}")
except Exception as e:
logger.exception(f"❌ Routing error: {e}")
logger.info("🔴 ACP Server остановлен.")
async def _route_message(self, msg: Dict[str, Any]):
"""Маршрутизация входящего JSON-RPC сообщения"""
if "id" in msg and "method" in msg:
await self._handle_request(msg)
elif "method" in msg and "id" not in msg:
logger.debug(f"Получено уведомление от клиента: {msg.get('method')}")
else:
logger.warning(f"Неизвестный формат сообщения: {msg}")
async def _handle_request(self, msg: Dict[str, Any]):
"""Обработка запросов от IDE"""
method = msg["method"]
msg_id = msg["id"]
params = msg.get("params", {})
try:
if method == "initialize":
result = await self._initialize(params)
elif method == "session/new":
result = await self._session_new(params)
elif method == "session/prompt":
result = await self._session_prompt(msg_id, params)
elif method == "session/destroy":
result = await self._session_destroy(params)
else:
await self._send_error(msg_id, -32601, f"Method not supported: {method}")
return
await self._send_response(msg_id, result)
except Exception as e:
logger.exception(f"Ошибка в {method}")
await self._send_error(msg_id, -32603, f"Internal error: {str(e)}")
# ─────────────── ACP МЕТОДЫ ───────────────
async def _initialize(self, params: Dict) -> Dict:
"""Рукопожатие: обмен capabilities"""
logger.info("🤝 Initialize запрос от IDE")
return {
"protocolVersion": "1.0",
"agentName": self.agent_name,
"agentVersion": self.agent_version,
"capabilities": {
"streaming": True,
"tools": ["file_read", "file_write", "run_terminal"],
"context_awareness": True
}
}
async def _session_new(self, params: Dict) -> Dict:
"""Создание новой сессии диалога"""
session_id = str(uuid.uuid4())
self.sessions[session_id] = {
"id": session_id,
"history": [],
"context_files": []
}
logger.info(f"📝 Создана сессия: {session_id}")
return {"sessionId": session_id}
async def _session_prompt(self, request_id: int, params: Dict) -> Dict:
"""Получение промпта. Запускает генерацию в фоне."""
session_id = params.get("sessionId")
prompt = params.get("prompt", [])
if not session_id or session_id not in self.sessions:
await self._send_error(request_id, -32602, "Invalid sessionId")
return None
# Сохраняем пользовательский запрос в историю
self.sessions[session_id]["history"].append({"role": "user", "content": prompt})
# Запускаем генерацию асинхронно, чтобы не блокировать stdin
asyncio.create_task(self._generate_and_stream(session_id, prompt))
# ACP требует немедленного подтверждения для streaming-запросов
return {"sessionId": session_id, "status": "accepted"}
async def _session_destroy(self, params: Dict) -> Dict:
"""Завершение сессии"""
session_id = params.get("sessionId")
self.sessions.pop(session_id, None)
logger.info(f"🗑️ Сессия закрыта: {session_id}")
return {"success": True}
# ─────────────── ЛОГИКА АГЕНТА ───────────────
async def _generate_and_stream(self, session_id: str, prompt: list):
"""
ЗДЕСЬ ПОДКЛЮЧАЕТСЯ ТВОЙ РЕАЛЬНЫЙ LLM/АГЕНТ.
Пока используем эмуляцию стриминга для демонстрации.
"""
logger.info(f"🧠 Начинаю генерацию для сессии {session_id}")
# Пример: симуляция токенов от модели
chunks = ["Привет! ", "Я ", "твой ", "кастомный ", "ACP-агент. ", "Готов ", "помочь. 🚀"]
for chunk in chunks:
await asyncio.sleep(0.4) # Имитация задержки модели
await self._send_chunk(session_id, chunk)
# Сигнал окончания стрима
await self._send_chunk(session_id, "", done=True)
logger.info("✅ Генерация завершена.")
async def _send_chunk(self, session_id: str, text: str, done: bool = False):
"""Отправка чанка ответа в IDE через notification"""
update = {
"sessionUpdate": "agentMessageChunk",
"chunk": {
"content": {"type": "text", "text": text},
"role": "assistant",
"timestamp": asyncio.get_event_loop().time()
}
}
if done:
update["chunk"]["done"] = True
await self._send_notification(session_id, update)
# ─────────────── СЕРВИСНЫЕ МЕТОДЫ ───────────────
async def _send_response(self, msg_id: Any, result: Dict):
await self._write_json({"jsonrpc": "2.0", "id": msg_id, "result": result})
async def _send_error(self, msg_id: Any, code: int, message: str):
await self._write_json({
"jsonrpc": "2.0",
"id": msg_id,
"error": {"code": code, "message": message}
})
async def _send_notification(self, session_id: str, params: Dict):
await self._write_json({
"jsonrpc": "2.0",
"method": "session/notification",
"params": {"sessionId": session_id, "update": params}
})
async def _write_json(self, obj: Dict):
"""Атомарная запись JSON в stdout с переводом строки"""
loop = asyncio.get_running_loop()
data = json.dumps(obj, ensure_ascii=False) + "\n"
await asyncio.to_thread(sys.stdout.write, data)
await asyncio.to_thread(sys.stdout.flush)
if __name__ == "__main__":
# Запуск сервера. Python 3.9+
server = ACPServer(agent_name="MyPythonAgent", agent_version="0.1.0")
try:
asyncio.run(server.run())
except KeyboardInterrupt:
server._running = False
except Exception as e:
logger.exception("Критическая ошибка сервера")
sys.exit(1)
Интеграция ACP в интегрированные среды разработки (IDE) — один из ключевых сценариев использования протокола. ACP обеспечивает единый интерфейс между редакторами кода и AI-агентами, позволяя разработчикам получать помощь от искусственного интеллекта непосредственно в своей рабочей среде.
Интеграция позволяет использовать любые ACP-совместимые агенты (Claude Code, Gemini CLI, локальные модели) без необходимости установки специальных плагинов для каждого агента.
Zed Editor был первым редактором, который получил полную поддержку ACP. Интеграция реализована на уровне ядра редактора и позволяет использовать любые ACP-совместимые агенты.
ACP позволяет IDE реализовывать следующие AI-функции:
| Функция | Описание | Пример использования |
|---|---|---|
| Code completion | Автоматическое завершение кода | Генерация функций, классов, шаблонов |
| Code explanation | Объяснение кода | Описание сложных фрагментов на естественном языке |
| Refactoring suggestions | Предложения по рефакторингу | Улучшение структуры кода |
| Error debugging | Отладка ошибок | Анализ стек-трейсов и предложение решений |
| Test generation | Генерация тестов | Создание unit-тестов для кода |
| Documentation generation | Генерация документации | Создание docstrings и комментариев |
ACP обеспечивает совместимость между различными агентными фреймворками, позволяя разработчикам использовать привычные инструменты для построения агентов, а затем интегрировать их в IDE через стандартный протокол.
ACP находит применение в корпоративных решениях:
В этом приложении представлены JSON-схемы типов сообщений, используемых в Agent Client Protocol (ACP). Все схемы соответствуют стандарту JSON-RPC 2.0 с расширениями ACP.
Каждое сообщение ACP — это валидный JSON-объект со следующей базовой структурой:
{
"jsonrpc": "2.0",
"id": 1,
"method": "session/prompt",
"params": { ... }
}
Поля:
jsonrpc (string, обязательное): Версия протокола JSON-RPC. Всегда "2.0" для ACP.id (integer/string, обязательное): Уникальный идентификатор запроса. Должен быть уникален в пределах одной сессии.method (string, обязательное): Имя вызываемого метода. Методы имеют префикс session/, fs/, terminal/ или event/.params (object/array/null, опциональное): Параметры метода.Выполняет агента и возвращает полный результат в одном ответе.
{
"jsonrpc": "2.0",
"id": 1,
"method": "session/prompt",
"params": {
"session_id": "sess_abc123",
"content": [
{
"type": "text",
"text": "Какой сегодня день?"
}
],
"metadata": {
"priority": "normal",
"timeout_ms": 30000
}
}
}
Параметры:
session_id (string, обязательное): ID сессии для контекста.content (array, обязательное): Массив блоков контента запроса.metadata (object, опциональное): Метаданные запроса.timeout_ms (integer, опциональное): Таймаут в миллисекундах.Создает новую сессию.
{
"jsonrpc": "2.0",
"id": 5,
"method": "session/new",
"params": {
"capabilities": {
"tools": {
"tool_calling": true
},
"text": {
"input": true,
"output": true
}
}
}
}
Параметры:
capabilities (object, опциональное): Поддерживаемые возможности клиента.Ответ на запрос session/prompt.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"session_id": "sess_abc123",
"content": [
{
"type": "text",
"text": "Сегодня среда, 9 апреля 2025 года."
}
],
"stop_reason": "end_turn",
"metadata": {
"tokens_used": 256,
"execution_time_ms": 1523
}
}
}
Поля результата:
session_id (string, обязательное): ID сессии.content (array, обязательное): Массив блоков результата.stop_reason (string, обязательное): Причина остановки ("end_turn", "max_tokens", "tool_calls").metadata (object, опциональное): Метаданные ответа.Обновление состояния сессии.
{
"jsonrpc": "2.0",
"method": "session/update",
"params": {
"session_id": "sess_abc123",
"update": {
"type": "state",
"state": {
"turn_count": 5,
"last_message_id": "msg_abc123",
"tokens_used": 1250
}
}
}
}
Обработка ошибок является критически важной частью реализации ACP. Протокол предоставляет детальную систему кодов ошибок и рекомендации по их обработке как на стороне клиента, так и на стороне сервера.
| Код ошибки | Название | Описание | Рекомендация |
|---|---|---|---|
| -32700 | Parse error | Неверный JSON в запросе | Проверить синтаксис JSON |
| -32600 | Invalid Request | Неверная структура JSON-RPC | Проверить обязательные поля |
| -32601 | Method not found | Метод не найден | Проверить имя метода |
| -32602 | Invalid params | Неверные параметры | Проверить параметры запроса |
| -32603 | Internal error | Внутренняя ошибка сервера | Сообщить администратору |
| Код ошибки | Название | Описание | Рекомендация |
|---|---|---|---|
| -32000 | Token limit exceeded | Превышен лимит токенов в сессии | Завершить текущую сессию и создать новую |
| -32001 | Tool not found | Запрошенный инструмент не найден | Проверить имя инструмента и доступные возможности агента |
| -32002 | Session not found | Сессия не найдена | Создать новую сессию через session/new |
| -32003 | Session ended | Сессия уже завершена | Создать новую сессию через session/new |
| -32004 | Execution cancelled | Выполнение было отменено | Проверить статус сессии и повторить запрос |
| -32005 | Invalid tool result | Неверный результат выполнения инструмента | Проверить формат результата инструмента |
| -32006 | Rate limit exceeded | Превышен лимит запросов | Подождать и повторить запрос позже |
| -32007 | Invalid message format | Неверный формат сообщения | Проверить структуру JSON-сообщения |
| -32008 | Authentication failed | Ошибка аутентификации | Проверить API ключ и права доступа |
| -32009 | Permission denied | Недостаточно прав для выполнения операции | Проверить права доступа пользователя |
// JSON-RPC 2.0 структура
{
"jsonrpc": "2.0",
"id": "request-id",
"error": {
"code": -32601,
"message": "Method not found",
"data": {
"method": "session/prompt",
"timestamp": "2025-04-09T10:00:00Z",
"request_id": "request-id"
}
}
}
// ACP расширенная структура
{
"jsonrpc": "2.0",
"id": "request-id",
"error": {
"code": -32002,
"message": "Session not found",
"data": {
"session_id": "session-uuid",
"timestamp": "2025-04-09T10:00:00Z",
"request_id": "request-id",
"suggested_action": "Create new session",
"retry_after": 5
}
}
}
// Обработка JSON-RPC ошибок
try:
data = json.loads(message)
except json.JSONDecodeError as e:
error_response = {
"jsonrpc": "2.0",
"id": None,
"error": {
"code": -32700,
"message": "Parse error",
"data": {
"error": str(e),
"received_message": message[:200]
}
}
}
await websocket.send(json.dumps(error_response))
// Пример обработки ACP ошибок
async def handle_execute(message: Dict[str, Any]) -> Dict[str, Any]:
params = message.get("params", {})
session_id = params.get("session_id")
session = await session_manager.get_session(session_id)
if not session:
return {
"jsonrpc": "2.0",
"id": message.get("id"),
"error": {
"code": -32002,
"message": "Session not found",
"data": {
"session_id": session_id,
"suggested_action": "Call session/new first"
}
}
}
# Обработка запроса...