---
title: Предварительный просмотр ответов с помощью дельт событий
url: https://platform.claude.com/docs/ru/managed-agents/event-deltas
description: Отображайте текст ответа агента в виде живого предварительного просмотра, пока модель ещё генерирует его.
featureMetadata:
  topic:
    title: Managed Agents
    url: https://platform.claude.com/docs/en/managed-agents/overview
  status: beta
  betaHeader: managed-agents-2026-04-01
---

По умолчанию текст ответа агента поступает в [поток событий сессии](https://platform.claude.com/docs/ru/managed-agents/events-and-streaming) в виде буферизованных событий `agent.message`. Каждое из них отправляется только после завершения запроса к модели, который его создал. «Event deltas» (дельты событий) позволяют отображать этот текст постепенно, в виде живого предварительного просмотра, пока модель ещё генерирует его.

Предварительный просмотр — это вспомогательное средство отображения, работающее по принципу «best effort» (наилучших усилий), а буферизованное `agent.message` всегда является авторитетной записью. Клиент, игнорирующий предварительный просмотр, всё равно получает полный и корректный поток.

## Включение предварительного просмотра

Предварительный просмотр включается отдельно для каждого подключения к потоку. Добавьте параметр запроса `event_deltas[]` к потоку, который вы читаете, и повторите его по одному разу для каждого типа событий, для которого нужен предварительный просмотр. Допустимые значения — `agent.message` и `agent.thinking`. Любое другое значение возвращает ошибку 400, как и запрос с более чем 100 значениями.

Оба эндпоинта потоков принимают этот параметр:

* **Поток уровня сессии:** `GET /v1/sessions/{session_id}/events/stream`
* **Поток треда сессии:** `GET /v1/sessions/{session_id}/threads/{thread_id}/stream`

Предварительный просмотр субагента появляется в [собственном потоке треда этого субагента](https://platform.claude.com/docs/ru/managed-agents/event-deltas#preview-session-thread-events).

`[]` — это шаблон glob оболочки, поэтому заключайте URL в кавычки всякий раз, когда формируете запрос в оболочке. В примерах скобки закодированы как `%5B%5D`, что тоже работает.

### События предварительного просмотра

Когда начинается событие с предварительным просмотром, поток отправляет `event_start`, содержащее тип и `id` предстоящего события:

```json
{
  "type": "event_start",
  "event": {
    "type": "agent.message",
    "id": "sevt_01abc..."
  }
}
```

Для `agent.message` за началом следуют события `event_delta`, содержащие инкрементальный текст. Каждая дельта указывает событие, которое она дополняет, в `event_id`, а блок содержимого, который она дополняет, — в `delta.index`:

```json
{
  "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` события, для которого они показывают предварительный просмотр. Их строки типов также являются исключением из соглашения об именовании `{domain}.{action}` для сохраняемых событий.

<Note>
  Дельты событий используют формат передачи, отличный от [потоковой передачи сообщений](https://platform.claude.com/docs/ru/build-with-claude/streaming), и это различие намеренное. Для `agent.message` с предварительным просмотром отправляется одно `event_start`, за которым следуют только события `event_delta`. Нет событий начала или окончания для отдельных блоков содержимого и нет события окончания для самого события с предварительным просмотром. Тип дельты — `content_delta`, а не `content_block_delta`. Код аккумулятора, написанный для Messages API, не переносится без изменений.
</Note>

## Накопление и согласование

Каждый SDK, поддерживающий дельты событий, включает [вспомогательный аккумулятор](https://platform.claude.com/docs/ru/managed-agents/event-deltas#sdk-accumulator-helpers), который берёт на себя учёт `index` за вас. Ручной подход, описанный в этом разделе, работает на любом языке, когда вам нужен собственный учёт. Применяйте его к сгенерированным типам событий.

При ручном подходе храните текст предварительного просмотра во временной карте с ключом `(event_id, index)` и считайте буферизованное событие записью. Согласовывайте их для каждого запроса к модели.

Ход начинается с одного события `session.status_running`. В ходе, который завершается нормально, каждый запрос к модели затем создаёт следующие события по порядку:

1. `span.model_request_start`
2. `event_start`
3. События `event_delta`
4. Буферизованное `agent.message`
5. [`span.model_request_end`](https://platform.claude.com/docs/ru/managed-agents/reference#event-types) (на вкладке Span events)

При передаче это часть последовательности с предварительным просмотром, перемежающаяся с другими буферизованными событиями подключения:

```text wrap
event_start     {"event": {"type": "agent.message", "id": "sevt_01abc..."}}
event_delta     {"event_id": "sevt_01abc...", "delta": {"type": "content_delta", "index": 0, "content": {"type": "text", "text": "..."}}}
...
agent.message   {"id": "sevt_01abc...", "content": [...]}
```

Строка `event_delta` повторяется по одному разу для каждого фрагмента текста. Обрабатывайте каждое событие по мере поступления:

1. При `event_start` запомните объявленный `id`. Идентификаторы всегда совпадают: `event_start.event.id`, каждый `event_delta.event_id` и `id` буферизованного `agent.message` имеют одно и то же значение.
2. При каждом `event_delta` добавляйте `delta.content.text` к записи по ключу `(event_id, delta.index)` и отображайте текущий текст. Первая дельта для `index` создаёт эту запись.
3. Когда поступает буферизованное `agent.message`, сопоставьте его по `id`, отбросьте накопленный предварительный просмотр и вместо него отобразите содержимое сообщения.
4. При `span.model_request_end` закройте любой предварительный просмотр, который не был согласован с буферизованным событием. Дельт для него больше не будет. Если ход завершается ошибкой или прерывается, буферизованное событие может так и не поступить, но `span.model_request_end` всё равно поступит.

Этот подход опирается на две гарантии:

* Конкатенация дельт предварительного просмотра в порядке поступления с ключом `(event_id, index)` даёт префикс `content[index].text` в буферизованном событии. Это не обязательно весь текст, поскольку дельты могут быть [отброшены под нагрузкой](https://platform.claude.com/docs/ru/managed-agents/event-deltas#limitations).
* Подключение отправляет не более одного `event_start` на каждый `event_id`, а буферизованное событие — это последнее, что это подключение доставляет для данного `id`.

### Вспомогательные аккумуляторы SDK

Вспомогательный аккумулятор каждого SDK берёт на себя учёт `index` (csharp, go: `Index`). Вспомогательные аккумуляторы Go, Java, Ruby и C# также используют `id` (csharp, go: `ID`) события в качестве ключа накапливаемого предварительного просмотра. При использовании вспомогательных аккумуляторов Python, TypeScript и PHP ведите эту карту самостоятельно и добавляйте каждую дельту в запись для её `id` (csharp, go: `ID`).

Следующие примеры включают предварительный просмотр `agent.message` и согласовывают его с буферизованным событием:

<CodeGroup exclude="shell:cURL, shell:CLI">
  <CodeGroupItem language="cURL">
    Этот рабочий процесс требует больше логики, чем одна команда оболочки. Используйте [Claude SDK](https://platform.claude.com/docs/ru/cli-sdks-libraries/overview) для его выполнения.
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    Этот рабочий процесс требует больше логики, чем одна команда оболочки. Используйте [Claude SDK](https://platform.claude.com/docs/ru/cli-sdks-libraries/overview) для его выполнения.
  </CodeGroupItem>

  ```python Python
  # Снимки превью по 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
  ```

  ```typescript TypeScript
  // Снимки предпросмотра по id события. `accumulateManagedAgentsEvent`
  // сворачивает предпросмотры event_start / event_delta в снимок agent.message.
  const previews = new Map<string, BetaManagedAgentsAgentMessageEvent>();

  // Включаем предпросмотр agent.message только для этого соединения
  const stream = await client.beta.sessions.events.stream(session.id, {
    event_deltas: ["agent.message"]
  });
  await client.beta.sessions.events.send(session.id, {
    events: [
      {
        type: "user.message",
        content: [{ type: "text", text: "Summarize the repo README" }]
      }
    ]
  });

  deltas: for await (const event of stream) {
    switch (event.type) {
      case "event_start": {
        // 1. Запомните объявленный id и откройте снимок. Дельты и
        //    буферизованное событие имеют тот же id.
        const preview = accumulateManagedAgentsEvent(undefined, event);
        if (preview) {
          previews.set(event.event.id, preview);
        }
        console.log(`event_start             ${event.event.type} ${event.event.id}`);
        break;
      }
      case "event_delta": {
        // 2. Добавьте фрагмент в снимок и отобразите его
        const preview = accumulateManagedAgentsEvent(previews.get(event.event_id), event);
        if (preview) {
          previews.set(event.event_id, preview);
          const text = preview.content
            .map((block) => (block.type === "text" ? block.text : ""))
            .join("");
          console.log(`event_delta             preview: ${JSON.stringify(text)}`);
        }
        break;
      }
      case "agent.message": {
        // 3. Буферизованное событие — это запись: оно заменяет и закрывает предпросмотр
        const message = accumulateManagedAgentsEvent(previews.get(event.id), event);
        previews.delete(event.id);
        const text = message.content
          .map((block) => (block.type === "text" ? block.text : ""))
          .join("");
        console.log(`agent.message           ${event.id} ${JSON.stringify(text)}`);
        break;
      }
      case "span.model_request_end":
        // 4. Дельт больше не будет. Закройте все несогласованные предпросмотры.
        for (const eventId of previews.keys()) {
          console.log(`span.model_request_end  closing preview for ${eventId}`);
        }
        previews.clear();
        break;
      case "session.status_idle":
        break deltas;
    }
  }
  stream.controller.abort();
  ```

  ```csharp C#
  // Включаем дельты событий: события agent.message показываются в предпросмотре по мере создания.
  using var stream = await client.Beta.Sessions.Events.WithRawResponse.StreamStreaming(
      session.ID,
      new() { EventDeltas = [BetaManagedAgentsDeltaType.AgentMessage] }
  );
  await client.Beta.Sessions.Events.Send(session.ID, new()
  {
      Events =
      [
          new BetaManagedAgentsUserMessageEventParams
          {
              Type = BetaManagedAgentsUserMessageEventParamsType.UserMessage,
              Content =
              [
                  new BetaManagedAgentsTextBlock
                  {
                      Type = BetaManagedAgentsTextBlockType.Text,
                      Text = "Write a haiku about event streams.",
                  },
              ],
          },
      ],
  });

  // Накапливаем фрагменты предпросмотра по (id события, индекс контента). Буферизованное
  // agent.message, которое следует далее, содержит полный контент, поэтому оно заменяет
  // накопленный предпросмотр, а не дописывается к нему.
  Dictionary<string, SortedDictionary<long, string>> previews = [];

  await foreach (var streamEvent in stream.Enumerate())
  {
      if (streamEvent.TryPickStartEvent(out var start))
      {
          // Предпросмотр, открытый для события с этим id. Этот поток подписан только
          // на дельты agent.message; TryPick* возвращает false вместо исключения,
          // поэтому другие типы предпросмотра (включая добавленные позже) пропускаются.
          if (start.Event.TryPickAgentMessage(out var preview))
          {
              Console.WriteLine($"event_start             {preview.Type.Raw()} {preview.ID}");
          }
      }
      else if (streamEvent.TryPickDeltaEvent(out var delta))
      {
          // Вставка по новому индексу, дописывание по существующему
          if (!previews.TryGetValue(delta.EventID, out var fragments))
          {
              previews[delta.EventID] = fragments = [];
          }
          var index = delta.Delta.Index ?? 0;
          fragments[index] = fragments.GetValueOrDefault(index, "") + delta.Delta.Content.Text;
          Console.WriteLine($"event_delta             preview: {fragments[index]}");
      }
      else if (streamEvent.TryPickAgentMessageEvent(out var message))
      {
          // Дельты доставляются без гарантий: отбросьте предпросмотр и используйте буферизованное событие
          previews.Remove(message.ID);
          var text = string.Concat(message.Content.Select(block =>
              block.TryPickBetaManagedAgentsTextBlock(out var textBlock) ? textBlock.Text : ""));
          Console.WriteLine($"agent.message           {message.ID} {text}");
      }
      else if (streamEvent.TryPickSpanModelRequestEndEvent(out _))
      {
          // Дельт больше не будет; закрываем все предпросмотры, которые так и не были согласованы.
          foreach (var eventId in previews.Keys)
          {
              Console.WriteLine($"span.model_request_end  closing preview for {eventId}");
          }
          previews.Clear();
      }
      else if (streamEvent.TryPickSessionStatusIdleEvent(out _))
      {
          break;
      }
  }
  ```

  ```go Go
  	// Включаем инкрементальные превью событий agent.message
  	stream := client.Beta.Sessions.Events.StreamEvents(ctx, session.ID, anthropic.BetaSessionEventStreamParams{
  		EventDeltas: []anthropic.BetaManagedAgentsDeltaType{
  			anthropic.BetaManagedAgentsDeltaTypeAgentMessage,
  		},
  	})

  	if _, err := client.Beta.Sessions.Events.Send(ctx, session.ID, anthropic.BetaSessionEventSendParams{
  		Events: []anthropic.BetaManagedAgentsEventParamsUnion{{
  			OfUserMessage: &anthropic.BetaManagedAgentsUserMessageEventParams{
  				Type: anthropic.BetaManagedAgentsUserMessageEventParamsTypeUserMessage,
  				Content: []anthropic.BetaManagedAgentsUserMessageEventParamsContentUnion{{
  					OfText: &anthropic.BetaManagedAgentsTextBlockParam{
  						Type: anthropic.BetaManagedAgentsTextBlockTypeText,
  						Text: "Write a haiku about the ocean.",
  					},
  				}},
  			},
  		}},
  	}); err != nil {
  		panic(err)
  	}

  	// Аккумулятор сворачивает фрагменты event_start / event_delta в
  	// снимки agent.message по id события. Нулевое значение готово к использованию.
  	var previews anthropic.BetaManagedAgentsEventAccumulator

  deltas:
  	for stream.Next() {
  		event := stream.Current()
  		previews.Accumulate(event)

  		switch event := event.AsAny().(type) {
  		case anthropic.BetaManagedAgentsStartEvent:
  			fmt.Printf("event_start             %s %s\n", event.Event.Type, event.Event.ID)
  		case anthropic.BetaManagedAgentsDeltaEvent:
  			fmt.Printf("event_delta             preview: %q\n", previews.AgentMessageText(event.EventID))
  		case anthropic.BetaManagedAgentsAgentMessageEvent:
  			// Буферизованное событие содержит полный контент: аккумулятор
  			// заменяет им превью
  			fmt.Printf("agent.message           %s %q\n", event.ID, previews.AgentMessageText(event.ID))
  		case anthropic.BetaManagedAgentsSpanModelRequestEndEvent:
  			// Для этого запроса дельт больше не будет. Аккумулятор
  			// здесь сбрасывает свои снимки, закрывая превью, которые так и не были
  			// согласованы буферизованным agent.message.
  			fmt.Println("span.model_request_end  no more deltas for this request")
  		case anthropic.BetaManagedAgentsSessionStatusIdleEvent:
  			break deltas
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  	stream.Close()
  ```

  ```java Java
  // Текст превью по ID события, затем по индексу контента. Буферизованный agent.message заменяет его.
  Map<String, Map<Long, StringBuilder>> previews = new HashMap<>();

  // Включить превью agent.message для этого соединения
  try (var stream = client.beta().sessions().events().streamStreaming(
          session.id(),
          EventStreamParams.builder()
              .addEventDelta(BetaManagedAgentsDeltaType.AGENT_MESSAGE)
              .build()
  )) {
      client.beta().sessions().events().send(
          session.id(),
          EventSendParams.builder()
              .addEvent(BetaManagedAgentsUserMessageEventParams.builder()
                  .type(BetaManagedAgentsUserMessageEventParams.Type.USER_MESSAGE)
                  .addTextContent("Describe the repo in one sentence.")
                  .build())
              .build()
      );

      Iterable<BetaManagedAgentsStreamSessionEvents> events = stream.stream()::iterator;
      deltas:
      for (var event : events) {
          switch (event.type().value()) {
              case EVENT_START -> {
                  if (event.asEventStart().event().isAgentMessage()) {
                      var preview = event.asEventStart().event().asAgentMessage();
                      IO.println("event_start             " + preview.type().asString() + " " + preview.id());
                  }
              }
              case EVENT_DELTA -> {
                  var eventDelta = event.asEventDelta();
                  var fragment = eventDelta.delta();
                  var buffer = previews
                      .computeIfAbsent(eventDelta.eventId(), _ -> new HashMap<>())
                      .computeIfAbsent(fragment.index().orElse(0L), _ -> new StringBuilder());
                  buffer.append(fragment.content().text());
                  IO.println("event_delta             preview: " + buffer);
              }
              case AGENT_MESSAGE -> {
                  // Буферизованное событие — это запись: удалите его превью, отобразите его контент
                  var message = event.asAgentMessage();
                  previews.remove(message.id());
                  var text = message.content().stream()
                      .flatMap(block -> block.text().stream())
                      .map(textBlock -> textBlock.text())
                      .collect(Collectors.joining());
                  IO.println("agent.message           " + message.id() + " " + text);
              }
              case SPAN_MODEL_REQUEST_END -> {
                  // Дельт больше не будет. Закройте превью, чьё буферизованное событие так и не пришло.
                  previews.keySet().forEach(eventId ->
                      IO.println("span.model_request_end  closing preview for " + eventId));
                  previews.clear();
              }
              case SESSION_STATUS_IDLE -> {
                  break deltas;
              }
          }
      }
  }
  ```

  ```php PHP
  use Anthropic\Beta\Sessions\BetaManagedAgentsDeltaEvent;
  use Anthropic\Beta\Sessions\BetaManagedAgentsDeltaType;
  use Anthropic\Beta\Sessions\BetaManagedAgentsStartEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionStatusIdleEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsSpanModelRequestEndEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock;
  use Anthropic\Lib\Sessions\EventAccumulator;

  // Снимки предпросмотра по id события. EventAccumulator::accumulate() добавляет каждое
  // event_start / event_delta в снимок agent.message; буферизованное
  // agent.message заменяет его.
  $previews = [];

  // Текст снимка или события agent.message
  $textOf = fn (ManagedAgentsAgentMessageEvent $message): string => implode(
      '',
      array_map(
          fn ($block) => $block->text,
          array_filter(
              $message->content,
              fn ($block) => $block instanceof ManagedAgentsTextBlock,
          ),
      ),
  );

  // Включить предпросмотр agent.message для этого соединения
  $stream = $client->beta->sessions->events->streamStream(
      $session->id,
      eventDeltas: [BetaManagedAgentsDeltaType::AGENT_MESSAGE],
  );

  $client->beta->sessions->events->send(
      $session->id,
      events: [
          [
              'type' => 'user.message',
              'content' => [['type' => 'text', 'text' => 'Describe the repo in one sentence.']],
          ],
      ],
  );

  foreach ($stream as $event) {
      switch (true) {
          case $event instanceof BetaManagedAgentsStartEvent:
              $snapshot = EventAccumulator::accumulate(null, $event);
              if ($snapshot !== null) {
                  $previews[$event->event->id] = $snapshot;
              }
              printf("event_start             %s %s\n", $event->event->type, $event->event->id);
              break;
          case $event instanceof BetaManagedAgentsDeltaEvent:
              // Пропустить запоздавшую дельту для уже заменённого или закрытого предпросмотра
              if (!isset($previews[$event->eventID])) {
                  break; // Break switch statement
              }
              $previews[$event->eventID] = EventAccumulator::accumulate($previews[$event->eventID], $event);
              printf("event_delta             preview: %s\n", json_encode($textOf($previews[$event->eventID])));
              break;
          case $event instanceof ManagedAgentsAgentMessageEvent:
              // Буферизованное событие — это запись: оно заменяет и закрывает предпросмотр
              unset($previews[$event->id]);
              printf("agent.message           %s %s\n", $event->id, json_encode($textOf($event)));
              break;
          case $event instanceof ManagedAgentsSpanModelRequestEndEvent:
              // Дельт больше не будет. Закройте любой предпросмотр, чьё
              // буферизованное событие так и не пришло.
              foreach (array_keys($previews) as $eventID) {
                  printf("span.model_request_end  closing preview for %s\n", $eventID);
              }
              $previews = [];
              break;
          case $event instanceof ManagedAgentsSessionStatusIdleEvent:
              break 2; // Break foreach loop
      }
  }
  $stream->close();
  ```

  ```ruby Ruby
  # Включаем дельты событий: превью agent.message передаются потоком как инкрементные фрагменты.
  stream = client.beta.sessions.events.stream_events(
    session.id,
    event_deltas: [Anthropic::Beta::BetaManagedAgentsDeltaType::AGENT_MESSAGE]
  )

  client.beta.sessions.events.send_(
    session.id,
    events: [{
      type: "user.message",
      content: [{type: "text", text: "Give a one-sentence project tagline."}]
    }]
  )

  # Накапливаем фрагменты превью по (event_id, index) в явно изменяемые
  # буферы (`+""`), чтобы `<<` дописывал на месте. Буферизованный agent.message с
  # тем же id является авторитетным и заменяет всё, что собрали дельты.
  buffers = Hash.new do |by_event, event_id|
    by_event[event_id] = Hash.new { |fragments, index| fragments[index] = +"" }
  end

  stream.each do |event|
    case event
    when Anthropic::Beta::BetaManagedAgentsStartEvent
      puts "event_start             #{event.event.type} #{event.event.id}"
    when Anthropic::Beta::BetaManagedAgentsDeltaEvent
      delta = event.delta
      fragment = delta.content.text
      buffers[event.event_id][delta.index || 0] << fragment
      puts "event_delta             preview: #{buffers[event.event_id][delta.index || 0].inspect}"
    when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
      # Замена: отбрасываем накопленное превью и отображаем полное событие.
      buffers.delete(event.id)
      puts "agent.message           #{event.id} #{event.content.map(&:text).join.inspect}"
    when Anthropic::Beta::Sessions::BetaManagedAgentsSpanModelRequestEndEvent
      # Дельт больше не будет. Закрываем все превью, которые так и не были согласованы.
      buffers.each_key { |event_id| puts "span.model_request_end  closing preview for #{event_id}" }
      buffers.clear
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionStatusIdleEvent
      break
    else
      # игнорируем прочие типы событий
    end
  end
  ```
</CodeGroup>

## Предварительный просмотр событий тредов сессии

В [мультиагентной](https://platform.claude.com/docs/ru/managed-agents/multiagent-orchestration) сессии у каждого треда сессии есть собственный поток событий. Он принимает тот же параметр `event_deltas[]` с теми же значениями.

Подключение показывает предварительный просмотр только для треда, который оно читает. Поток уровня сессии показывает предварительный просмотр основного треда, а предварительный просмотр дочернего треда никогда не дублируется в него. Чтобы наблюдать за текстом субагента по мере его генерации моделью, откройте поток треда этого субагента.

Путь потока треда заканчивается на `/threads/{thread_id}/stream`. `/events/stream` существует только на уровне сессии, поэтому эндпоинта `/threads/{thread_id}/events/stream` нет.

`event_start` и `event_delta` имеют в потоке треда ту же структуру, что и в потоке уровня сессии, и подход [накопления и согласования](https://platform.claude.com/docs/ru/managed-agents/event-deltas#accumulate-and-reconcile) применяется в том виде, в каком он описан. Запускайте по одному экземпляру аккумулятора на каждое подключение к потоку.

<CodeGroup>
  ```bash cURL
  # Поток thread принимает тот же параметр event_deltas[], что и поток сессии.
  # Закодируйте скобки (%5B%5D) и заключите URL в кавычки.
  curl --fail-with-body -sS -N \
    "https://api.anthropic.com/v1/sessions/$SESSION_ID/threads/$THREAD_ID/stream?beta=true&event_deltas%5B%5D=agent.message" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: managed-agents-2026-04-01" \
    -H "accept: text/event-stream"
  ```

  ```bash CLI
  # Поток треда принимает тот же параметр event_deltas, что и поток сессии,
  # по одному флагу --event-delta на каждый тип события для предпросмотра.
  ant beta:sessions:threads:events stream \
    --session-id "$SESSION_ID" \
    --thread-id "$THREAD_ID" \
    --event-delta agent.message
  ```

  ```python Python
  # Получаем треды сессии и выбираем дочерний: у дочерних тредов parent_thread_id
  # не null, а у основного треда parent_thread_id равен null.
  child_thread = next(
      thread
      for thread in client.beta.sessions.threads.list(session.id)
      if thread.parent_thread_id is not None
  )

  # Поток дочернего треда принимает тот же параметр event_deltas, что и
  # поток сессии.
  with client.beta.sessions.threads.events.stream(
      child_thread.id,
      session_id=session.id,
      event_deltas=["agent.message"],
  ) as stream:
      for event in stream:
          match event.type:
              case "event_delta":
                  print(event.delta.content.text, end="")
              case "agent.message":
                  # Буферизованное событие — авторитетная запись; отображаем его содержимое
                  print()
                  for block in event.content:
                      if block.type == "text":
                          print(block.text, end="")
                  print()
              case "session.thread_status_idle":
                  break
  ```

  ```typescript TypeScript
  // Получаем потоки сессии и выбираем дочерний: у дочерних потоков parent_thread_id
  // не null, а у основного потока parent_thread_id равен null.
  let childThreadId: string | undefined;
  for await (const thread of client.beta.sessions.threads.list(session.id)) {
    if (thread.parent_thread_id !== null) {
      childThreadId = thread.id;
      break;
    }
  }
  if (!childThreadId) {
    throw new Error("No child thread found");
  }

  // Поток дочернего треда принимает тот же параметр event_deltas, что и
  // поток сессии.
  const stream = await client.beta.sessions.threads.events.stream(childThreadId, {
    session_id: session.id,
    event_deltas: ["agent.message"]
  });

  threadDeltas: for await (const event of stream) {
    switch (event.type) {
      case "event_delta":
        process.stdout.write(event.delta.content.text);
        break;
      case "agent.message": {
        // Буферизованное событие — авторитетная запись; отображаем его содержимое.
        process.stdout.write("\n");
        const text = event.content
          .map((block) => (block.type === "text" ? block.text : ""))
          .join("");
        console.log(text);
        break;
      }
      case "session.thread_status_idle":
        break threadDeltas;
    }
  }
  stream.controller.abort();
  ```

  ```csharp C#
  // Получаем список тредов сессии и выбираем дочерний: у дочерних тредов parent_thread_id
  // не null, а у основного треда parent_thread_id равен null.
  var threads = await client.Beta.Sessions.Threads.List(session.ID);
  var childThread = threads.Items.First(thread => thread.ParentThreadID is not null);

  // Поток дочернего треда принимает тот же параметр event_deltas, что и
  // поток сессии.
  using var stream = await client.Beta.Sessions.Threads.Events.WithRawResponse.StreamStreaming(
      childThread.ID,
      new() { SessionID = session.ID, EventDeltas = [BetaManagedAgentsDeltaType.AgentMessage] }
  );

  await foreach (var streamEvent in stream.Enumerate())
  {
      if (streamEvent.TryPickDeltaEvent(out var delta))
      {
          Console.Write(delta.Delta.Content.Text);
      }
      else if (streamEvent.TryPickAgentMessageEvent(out var message))
      {
          // Буферизованное событие — авторитетная запись; отображаем его контент.
          Console.WriteLine();
          var text = string.Concat(message.Content.Select(block =>
              block.TryPickBetaManagedAgentsTextBlock(out var textBlock) ? textBlock.Text : ""));
          Console.WriteLine(text);
      }
      else if (streamEvent.TryPickSessionThreadStatusIdleEvent(out _))
      {
          break;
      }
  }
  ```

  ```go Go
  	// Получаем список тредов сессии и выбираем дочерний: у дочерних тредов parent_thread_id
  	// не null, а у основного треда parent_thread_id равен null.
  	var childThreadID string
  	threads := client.Beta.Sessions.Threads.ListAutoPaging(ctx, session.ID, anthropic.BetaSessionThreadListParams{})
  	for threads.Next() {
  		if thread := threads.Current(); thread.ParentThreadID != "" {
  			childThreadID = thread.ID
  			break
  		}
  	}
  	if err := threads.Err(); err != nil {
  		panic(err)
  	}

  	// Поток дочернего треда принимает тот же параметр event_deltas, что и
  	// поток сессии; запускайте один цикл чтения на каждое соединение потока.
  	stream := client.Beta.Sessions.Threads.Events.StreamEvents(ctx, childThreadID, anthropic.BetaSessionThreadEventStreamParams{
  		SessionID: session.ID,
  		EventDeltas: []anthropic.BetaManagedAgentsDeltaType{
  			anthropic.BetaManagedAgentsDeltaTypeAgentMessage,
  		},
  	})

  threadDeltas:
  	for stream.Next() {
  		switch event := stream.Current().AsAny().(type) {
  		case anthropic.BetaManagedAgentsDeltaEvent:
  			fmt.Print(event.Delta.Content.Text)
  		case anthropic.BetaManagedAgentsAgentMessageEvent:
  			// Буферизованное событие — авторитетная запись; отображаем его контент.
  			fmt.Println()
  			// список конкретного типа: BetaManagedAgentsTextBlock
  			for _, block := range event.Content {
  				fmt.Print(block.Text)
  			}
  			fmt.Println()
  		case anthropic.BetaManagedAgentsSessionThreadStatusIdleEvent:
  			break threadDeltas
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  	stream.Close()
  ```

  ```java Java
  // Получаем треды сессии и выбираем дочерний: у дочерних тредов parent_thread_id
  // не null, а у основного треда parent_thread_id равен null.
  var childThread = client.beta().sessions().threads().list(session.id()).autoPager().stream()
      .filter(thread -> thread.parentThreadId().isPresent())
      .findFirst()
      .orElseThrow();

  // Поток дочернего треда принимает тот же параметр event_deltas, что и поток
  // сессии. Его класс параметров имеет то же простое имя, что и сессионный, поэтому уточните его.
  try (var stream = client.beta().sessions().threads().events().streamStreaming(
          childThread.id(),
          com.anthropic.models.beta.sessions.threads.events.EventStreamParams.builder()
              .sessionId(session.id())
              .addEventDelta(BetaManagedAgentsDeltaType.AGENT_MESSAGE)
              .build()
  )) {
      Iterable<BetaManagedAgentsStreamSessionThreadEvents> events = stream.stream()::iterator;
      threadDeltas:
      for (var event : events) {
          switch (event.type().value()) {
              case EVENT_DELTA -> IO.print(event.asEventDelta().delta().content().text());
              case AGENT_MESSAGE -> {
                  // Буферизованное событие — авторитетная запись; отобразите его контент.
                  IO.println();
                  event.asAgentMessage().content().forEach(block -> block.text().ifPresent(textBlock -> IO.print(textBlock.text())));
                  IO.println();
              }
              case SESSION_THREAD_STATUS_IDLE -> {
                  break threadDeltas;
              }
          }
      }
  }
  ```

  ```php PHP
  use Anthropic\Beta\Sessions\BetaManagedAgentsDeltaEvent;
  use Anthropic\Beta\Sessions\BetaManagedAgentsDeltaType;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsAgentMessageEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsSessionThreadStatusIdleEvent;
  use Anthropic\Beta\Sessions\Events\ManagedAgentsTextBlock;

  // Получите список потоков сессии и выберите дочерний: у дочерних потоков parentThreadID
  // не null, а у основного потока parentThreadID равен null.
  $childThread = null;
  foreach ($client->beta->sessions->threads->list($session->id)->pagingEachItem() as $thread) {
      if ($thread->parentThreadID !== null) {
          $childThread = $thread;
          break;
      }
  }

  // Поток событий дочернего потока принимает тот же параметр eventDeltas, что и
  // поток сессии.
  $stream = $client->beta->sessions->threads->events->streamStream(
      $childThread->id,
      sessionID: $session->id,
      eventDeltas: [BetaManagedAgentsDeltaType::AGENT_MESSAGE],
  );

  foreach ($stream as $event) {
      switch (true) {
          case $event instanceof BetaManagedAgentsDeltaEvent:
              echo $event->delta->content->text;
              break;
          case $event instanceof ManagedAgentsAgentMessageEvent:
              // Буферизованное событие — авторитетная запись; отобразите его содержимое
              echo "\n";
              foreach ($event->content as $block) {
                  if ($block instanceof ManagedAgentsTextBlock) {
                      echo $block->text;
                  }
              }
              echo "\n";
              break;
          case $event instanceof ManagedAgentsSessionThreadStatusIdleEvent:
              break 2; // Break foreach loop
      }
  }
  $stream->close();
  ```

  ```ruby Ruby
  # Получаем треды сессии и выбираем дочерний: у дочерних тредов parent_thread_id
  # не null, а у основного треда parent_thread_id равен null.
  child_thread = client.beta.sessions.threads.list(session.id).to_enum.find { it.parent_thread_id }

  # Поток дочернего треда принимает тот же параметр event_deltas, что и
  # поток сессии.
  stream = client.beta.sessions.threads.events.stream_events(
    child_thread.id,
    session_id: session.id,
    event_deltas: [Anthropic::Beta::BetaManagedAgentsDeltaType::AGENT_MESSAGE]
  )

  stream.each do |event|
    case event
    when Anthropic::Beta::BetaManagedAgentsDeltaEvent
      print event.delta.content.text
    when Anthropic::Beta::Sessions::BetaManagedAgentsAgentMessageEvent
      # Буферизованное событие — авторитетная запись; отображаем его содержимое.
      puts
      event.content.each { print it.text }
      puts
    when Anthropic::Beta::Sessions::BetaManagedAgentsSessionThreadStatusIdleEvent
      break
    else
      # игнорируем прочие типы событий
    end
  end
  ```
</CodeGroup>

Цикл чтения завершается при [`session.thread_status_idle`](https://platform.claude.com/docs/ru/managed-agents/reference#event-types) — событии, отправляемом, когда ход треда сессии завершается и тред переходит в состояние простоя.

## Ограничения

* **Best effort:** под нагрузкой сервер может отбрасывать дельты для события. В этом случае вы получаете непрерывный префикс текста, после чего дельты для этого события больше не поступают. Буферизованное `agent.message` всё равно поступает полностью. Никогда не считайте накопленный предварительный просмотр окончательным.
* **Нет повторной доставки при переподключении:** дельты доставляются только подключению, которое их включило, пока оно открыто. Это относится как к потоку уровня сессии, так и к каждому потоку треда сессии. Подключение, открытое после начала запроса к модели, не получает дельт для этого выполняющегося события. Повторно запросить пропущенные дельты невозможно.
* **Один тред, только текст:** предварительный просмотр охватывает текст ассистента в [треде, который читает подключение](https://platform.claude.com/docs/ru/managed-agents/event-deltas#preview-session-thread-events). Использование инструментов, результаты инструментов и результаты MCP никогда не показываются в предварительном просмотре.
* **Никогда не сохраняются:** `event_start` и `event_delta` существуют только в живом потоке. Они не появляются в истории событий сессии (`GET /v1/sessions/{session_id}/events`) или в истории событий какого-либо треда сессии.

## Устранение неполадок с предварительным просмотром

| Что вы видите                                                             | Что это означает                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Поток с буферизованными событиями, но без `event_start` или `event_delta` | Подключение, которое вы читаете, не включило предварительный просмотр, или ход вообще не затронул тред, поток которого вы получаете. `event_deltas[]` применяется к каждому подключению, а не к сессии. Чтобы узнать, какой тред выполнялся, получите список тредов сессии (`GET /v1/sessions/{session_id}/threads`).                                                                       |
| Поток, который обрывается во время предварительного просмотра             | Дельты не доставляются повторно. Следуйте [процедуре переподключения](https://platform.claude.com/docs/ru/managed-agents/events-and-streaming#reconnect-without-missing-events): снова откройте поток и получите историю событий. История включает все буферизованные события, отправленные, пока вы были отключены, включая `agent.message`, которого ожидал ваш предварительный просмотр. |
| Ошибка 404 для URL потока                                                 | Неверен путь или идентификатор, либо запрос вообще не содержит бета-заголовка managed-agents. Эндпоинты тредов доступны только в бета-версии, поэтому без заголовка они не существуют.                                                                                                                                                                                                      |
| Ошибка 400 с упоминанием `event_deltas`                                   | Допускаются только `agent.message` и `agent.thinking`.                                                                                                                                                                                                                                                                                                                                      |

## Следующие шаги

<CardGroup cols={2}>
  <Card title="Поток событий сессии" icon="lightning" href="https://platform.claude.com/docs/ru/managed-agents/events-and-streaming">
    Отправляйте события, получайте ответы в потоковом режиме, а также прерывайте или перенаправляйте сессию во время выполнения.
  </Card>

  <Card title="Мультиагентная оркестрация" icon="stack" href="https://platform.claude.com/docs/ru/managed-agents/multiagent-orchestration">
    Координируйте работу нескольких агентов в рамках одной сессии.
  </Card>
</CardGroup>
