Взаимодействие с Claude Managed Agents основано на событиях. Вы отправляете агенту пользовательские события и получаете обратно события агента и сессии для отслеживания статуса.
Все запросы к Managed Agents API требуют бета-заголовка managed-agents-2026-04-01. SDK устанавливает бета-заголовок автоматически.
События передаются в двух направлениях.
user.* запускают сессию и управляют ею по мере выполнения; system.message обновляет системную подсказку агента между ходами.Строки типов событий сессии, span, агента, пользователя и системы следуют соглашению об именовании {domain}.{action}. Исключение составляют события предварительного просмотра дельт, доступные только в потоке (event_start, event_delta). Полный каталог см. в разделе Типы событий справочника.
Каждое сохранённое событие включает временную метку processed_at, указывающую, когда событие было записано на стороне сервера. Если processed_at равно null, это означает, что событие было поставлено в очередь оболочкой и обрабатывается после завершения обработки предшествующих событий.
По умолчанию текст ответа агента поступает в поток в виде буферизованных событий agent.message, каждое из которых генерируется только после завершения запроса к модели, который его породил. Дельты событий позволяют отображать этот текст инкрементально, в виде живого предварительного просмотра, пока модель ещё генерирует его. Предварительный просмотр — это не сам ответ: предварительные просмотры являются вспомогательным средством отображения, предоставляемым по мере возможности, а буферизованное событие agent.message всегда остаётся авторитетной записью. Клиент, игнорирующий предварительные просмотры, всё равно получает полный и корректный поток.
Предварительные просмотры включаются отдельно для каждого потокового соединения. Добавьте параметр запроса event_deltas[] к GET /v1/sessions/{session_id}/events/stream, повторяя его по одному разу для каждого типа события, для которого вы хотите получать предварительный просмотр. Допустимые значения — agent.message и agent.thinking; любое другое значение возвращает ошибку 400. Этот параметр поддерживается только потоком событий уровня сессии. Потоки событий потоков сессии его отклоняют.
Когда начинается событие с предварительным просмотром, поток генерирует event_start, содержащий тип и id предстоящего события:
{
"type": "event_start",
"event": {
"type": "agent.message",
"id": "sevt_01abc..."
}
}Для agent.message за стартовым событием следуют события event_delta, содержащие инкрементальный текст. Каждая дельта указывает событие, которое она дополняет, в event_id, и блок контента, который она дополняет, в delta.index:
{
"type": "event_delta",
"event_id": "sevt_01abc...",
"delta": {
"type": "content_delta",
"index": 0,
"content": {
"type": "text",
"text": "Here is the summary"
}
}
}Когда предварительно просматривается событие agent.thinking, генерируется только event_start. События event_delta за ним не следуют, а контент поступает в буферизованном событии agent.thinking как обычно.
В отличие от сохранённых событий, event_start и event_delta не имеют собственных id или processed_at. Единственный идентификатор, который они несут, — это id события, которое они предварительно просматривают.
Дельты событий используют формат передачи, отличный от потоковой передачи сообщений, и это различие намеренное. Предварительно просматриваемое событие agent.message получает одно событие event_start, за которым следуют только события event_delta. Нет событий начала или окончания для отдельных блоков контента и нет события окончания для самого предварительно просматриваемого события. Тип дельты — content_delta, а не content_block_delta. Код аккумулятора, написанный для Messages API, не переносится без изменений.
SDK для Python, TypeScript и Go включают вспомогательный аккумулятор, который индексирует предварительный просмотр по id события и берёт на себя учёт index. Ручной подход работает на любом языке: в других SDK применяйте его к сгенерированным типам событий.
При ручном подходе рассматривайте предварительный просмотр как черновой буфер, а буферизованное событие — как окончательную запись. Индексируйте буфер по ключу (event_id, index). Выполняйте согласование для каждого запроса к модели: ход открывается одним событием session.status_running, затем в ходе, который завершается нормально, каждый запрос к модели порождает по порядку span.model_request_start, event_start, события event_delta, буферизованное agent.message и, наконец, span.model_request_end (на вкладке «События span»). Обрабатывайте каждое событие по мере его поступления:
event_start зафиксируйте объявленный id. Идентификаторы всегда совпадают: event_start.event.id, каждый event_delta.event_id и id буферизованного agent.message — это одно и то же значение.event_delta добавляйте delta.content.text к записи по ключу (event_id, delta.index) и отображайте накопленный текст. Первая дельта для данного index создаёт эту запись.agent.message, сопоставьте его по id, отбросьте накопленный предварительный просмотр и отобразите вместо него содержимое сообщения.span.model_request_end закройте любой предварительный просмотр, который не был согласован со своим буферизованным событием. Больше дельт для него не поступит. Если ход завершается с ошибкой или прерывается, буферизованное событие может так и не поступить; span.model_request_end всё равно поступает.# Снимки предпросмотра, индексированные по id события. accumulate_managed_agents_event сворачивает каждое
# event_start / event_delta в снимок agent.message; буферизованное
# agent.message заменяет его.
previews: dict[str, BetaManagedAgentsAgentMessageEvent] = {}
# Включаем предпросмотры agent.message для этого соединения
with client.beta.sessions.events.stream(
session.id, event_deltas=["agent.message"]
) as stream:
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [{"type": "text", "text": "Describe the repo in one sentence."}],
},
],
)
for event in stream:
match event.type:
case "event_start":
snapshot = accumulate_managed_agents_event(None, event)
if snapshot is not None:
previews[event.event.id] = snapshot
print(f"event_start {event.event.type} {event.event.id}")
case "event_delta":
preview = accumulate_managed_agents_event(previews.get(event.event_id), event)
if preview is not None:
previews[event.event_id] = preview
text = "".join(block.text for block in preview.content)
print(f"event_delta preview: {text!r}")
case "agent.message":
# Буферизованное событие — это итоговая запись: оно заменяет и закрывает предпросмотр
preview = accumulate_managed_agents_event(previews.pop(event.id, None), event)
text = "".join(block.text for block in preview.content)
print(f"agent.message {event.id} {text!r}")
case "span.model_request_end":
# Дельт больше не будет. Закрываем все предпросмотры, чьё
# буферизованное событие так и не пришло.
for event_id in previews:
print(f"span.model_request_end closing preview for {event_id}")
previews.clear()
case "session.status_idle":
breakПредварительные просмотры оптимизированы для отзывчивости. Учитывайте следующие ограничения при разработке:
agent.message всё равно поступает полностью. Никогда не рассматривайте накопленный предварительный просмотр как окончательный.agent.message, которого ожидал ваш предварительный просмотр. Повторно запросить пропущенные дельты невозможно.agent.thinking: Предварительный просмотр agent.thinking генерирует только event_start как сигнал о том, что блок мышления начался; события event_delta за ним не следуют.event_start и event_delta существуют только в живом потоке. Они не появляются в истории событий сессии (GET /v1/sessions/{session_id}/events).Когда агент вызывает пользовательский инструмент:
agent.custom_tool_use, содержащее имя инструмента и входные данные.session.status_idle, содержащим stop_reason: requires_action. Идентификаторы блокирующих событий находятся в массиве stop_reason.event_ids.user.custom_tool_result для каждого из них, передав идентификатор события в параметре custom_tool_use_id вместе с содержимым результата.running.with client.beta.sessions.events.stream(session.id) as stream:
for event in stream:
if event.type == "session.status_idle" and (stop_reason := event.stop_reason):
match stop_reason.type:
case "requires_action":
for event_id in stop_reason.event_ids:
# Находим событие использования пользовательского инструмента и выполняем его
tool_event = events_by_id[event_id]
result = call_tool(tool_event.name, tool_event.input)
# Отправляем результат обратно
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.custom_tool_result",
"custom_tool_use_id": event_id,
"content": [{"type": "text", "text": result}],
},
],
)
case "end_turn":
breakКогда политика разрешений требует подтверждения перед выполнением инструмента:
agent.tool_use или agent.mcp_tool_use.session.status_idle, содержащим stop_reason: requires_action. Идентификаторы блокирующих событий находятся в массиве stop_reason.event_ids.user.tool_confirmation для каждого из них, передав идентификатор события в параметре tool_use_id. Установите result в значение "allow" или "deny". Используйте deny_message, чтобы объяснить причину отказа.running.with client.beta.sessions.events.stream(session.id) as stream:
for event in stream:
if event.type == "session.status_idle" and (stop_reason := event.stop_reason):
match stop_reason.type:
case "requires_action":
for event_id in stop_reason.event_ids:
# Одобряем ожидающий вызов инструмента
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.tool_confirmation",
"tool_use_id": event_id,
"result": "allow",
},
],
)
case "end_turn":
breakСессии сохраняются между взаимодействиями. История разговора сохраняется, если сессия не удалена явно. Когда сессия переходит в состояние простоя, для её песочницы создаётся контрольная точка, сохраняющая полное состояние песочницы, включая файловую систему, установленные пакеты и любые файлы, созданные агентом. Это позволяет корректно возобновить работу после периода неактивности.
Хотя история сессии сохраняется до её удаления, контрольные точки хранятся только в течение 30 дней после последней активности сессии. Если ваш рабочий процесс требует сохранения полного состояния песочницы (файлов, установленных инструментов и т. д.) дольше 30 дней, отправляйте периодические события user.message, чтобы сбросить таймер неактивности до истечения срока действия контрольной точки.
Чтобы возобновить сессию, отправьте ей событие user.message как обычно:
# В продакшене передайте сохранённый ID сессии, которую хотите возобновить.
ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
events:
- type: user.message
content:
- type: text
text: Now run the tests against the changes you made earlier.
YAMLsystem.message в настоящее время поддерживается только Claude Opus 4.8. Если какая-либо модель, настроенная для агента, не поддерживает внедрение системных сообщений в середине разговора, событие отклоняется с ошибкой валидации model_does_not_support_mid_conversation_system.
Отправьте событие system.message, чтобы обновить системную подсказку агента между ходами. В отличие от поля system в определении агента (которое фиксируется при создании сессии), system.message позволяет изменять системную подсказку по мере выполнения сессии. Используйте его, когда агенту требуются обновлённые указания системного уровня в середине сессии: другая персона, пересмотренные ограничения или контекст, полученный во время выполнения, который должен влиять на поведение модели в дальнейшем.
ant beta:sessions:events send --session-id "$SESSION_ID" <<'YAML'
events:
- type: system.message
content:
- type: text
text: "The user's current timezone is America/New_York."
YAMLsystem.message нельзя отправить, пока сессия простаивает с stop_reason: requires_action. content принимает от 1 до 1000 текстовых элементов.
Объект сессии включает поле usage с накопительной статистикой токенов. Получите сессию после её перехода в состояние простоя, чтобы прочитать актуальные итоговые значения, и используйте их для отслеживания затрат, контроля бюджетов или мониторинга потребления.
{
"id": "sesn_01...",
"status": "idle",
"usage": {
"input_tokens": 5000,
"output_tokens": 3200,
"cache_creation_input_tokens": 2000,
"cache_read_input_tokens": 20000
}
}input_tokens отражает некэшированные входные токены, а output_tokens — общее количество выходных токенов по всем вызовам модели в сессии. Поля cache_creation_input_tokens и cache_read_input_tokens отражают активность кэширования подсказок. Записи кэша имеют TTL 5 минут, поэтому последовательные ходы в пределах этого окна выигрывают от чтения из кэша, что снижает стоимость за токен.
Console предоставляет визуальное представление временной шкалы ваших сессий агента. Перейдите в раздел Claude Managed Agents в Console, чтобы увидеть:
session.errorWas this page helpful?