Antworten mit Event-Deltas in der Vorschau anzeigen
Zeige den Antworttext des Agenten als Live-Vorschau an, während das Modell ihn noch generiert.
Standardmäßig erreicht der Antworttext des Agenten den Session-Event-Stream als gepufferte agent.message-Events. Jedes davon wird erst ausgegeben, nachdem die Modellanfrage, die es erzeugt hat, abgeschlossen ist. Mit „event deltas" (Event-Deltas) kannst du diesen Text inkrementell als Live-Vorschau rendern, während das Modell ihn noch generiert.
Vorschauen sind eine Best-Effort-Anzeigehilfe, und die gepufferte agent.message ist immer der maßgebliche Datensatz. Ein Client, der Vorschauen ignoriert, erhält trotzdem einen vollständigen, korrekten Stream.
Vorschauen aktivieren
Vorschauen werden pro Stream-Verbindung aktiviert. Füge den Query-Parameter event_deltas[] zu dem Stream hinzu, den du liest, und wiederhole ihn einmal für jeden Event-Typ, den du in der Vorschau sehen möchtest. Die akzeptierten Werte sind agent.message und agent.thinking. Jeder andere Wert gibt einen 400-Fehler zurück, ebenso eine Anfrage mit mehr als 100 Werten.
Beide Stream-Endpunkte akzeptieren den Parameter:
- Stream auf Session-Ebene:
GET /v1/sessions/{session_id}/events/stream - Session-Thread-Stream:
GET /v1/sessions/{session_id}/threads/{thread_id}/stream
Die Vorschauen eines Subagenten erscheinen im eigenen Thread-Stream dieses Subagenten.
[] ist ein Shell-Glob-Muster, setze die URL also in Anführungszeichen, wann immer du die Anfrage in einer Shell erstellst. Die Beispiele kodieren die Klammern prozentual als %5B%5D, was ebenfalls funktioniert.
Vorschau-Events
Wenn ein Event mit Vorschau beginnt, gibt der Stream ein event_start aus, das den Typ und die id des kommenden Events trägt:
{
"type": "event_start",
"event": {
"type": "agent.message",
"id": "sevt_01abc..."
}
}Bei agent.message folgen auf den Start event_delta-Events, die inkrementellen Text tragen. Jedes Delta benennt das Event, das es erweitert, in event_id und den Content-Block, den es erweitert, in delta.index:
{
"type": "event_delta",
"event_id": "sevt_01abc...",
"delta": {
"type": "content_delta",
"index": 0,
"content": {
"type": "text",
"text": "Here is the summary"
}
}
}Bei agent.thinking wird nur das event_start ausgegeben, als Signal, dass ein Thinking-Block begonnen hat. Es folgen keine event_delta-Events. Das gepufferte agent.thinking-Event, das die Vorschau abschließt, ist ein Fortschrittssignal und enthält keinen Thinking-Inhalt.
Anders als persistierte Events haben event_start und event_delta keine eigene id oder processed_at. Der einzige Bezeichner, den sie tragen, ist die id des Events, das sie in der Vorschau anzeigen. Ihre Typ-Strings sind außerdem die Ausnahme von der {domain}.{action}-Namenskonvention persistierter Events.
Akkumulieren und abgleichen
Jedes SDK, das Event-Deltas unterstützt, enthält einen Akkumulator-Helper, der die index-Buchführung für dich übernimmt. Das manuelle Muster in diesem Abschnitt funktioniert in jeder Sprache, wenn du eine eigene Buchführung benötigst. Wende es auf die generierten Event-Typen an.
Beim manuellen Muster hältst du den Vorschautext in einer temporären Map mit dem Schlüssel (event_id, index) und behandelst das gepufferte Event als Datensatz. Gleiche die beiden pro Modellanfrage ab.
Ein Turn beginnt mit einem einzelnen session.status_running-Event. Bei einem normal abgeschlossenen Turn erzeugt jede Modellanfrage dann diese Events in dieser Reihenfolge:
span.model_request_startevent_start- Die
event_delta-Events - Die gepufferte
agent.message span.model_request_end(im Tab „Span-Events“)
Auf der Leitung ist dies der Vorschau-Teil dieser Sequenz, verschachtelt mit den anderen gepufferten Events der Verbindung:
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": [...]}Die event_delta-Zeile wiederholt sich einmal pro Textfragment. Verarbeite jedes Event, sobald es eintrifft:
- Bei
event_startmerkst du dir die angekündigteid. Die Bezeichner stimmen immer überein:event_start.event.id, jedeevent_delta.event_idund dieidder gepuffertenagent.messagehaben denselben Wert. - Bei jedem
event_deltahängst dudelta.content.textan den Eintrag bei(event_id, delta.index)an und renderst den laufenden Text. Das erste Delta für einenindexerstellt diesen Eintrag. - Wenn die gepufferte
agent.messageeintrifft, ordne sie über dieidzu, verwirf die akkumulierte Vorschau und rendere stattdessen den Inhalt der Nachricht. - Bei
span.model_request_endschließt du jede Vorschau, die nicht durch ihr gepuffertes Event abgeglichen wurde. Für sie kommen keine weiteren Deltas mehr. Wenn der Turn fehlschlägt oder unterbrochen wird, trifft das gepufferte Event möglicherweise nie ein,span.model_request_endaber trotzdem.
Das Muster stützt sich auf zwei Garantien:
- Das Verketten der Deltas einer Vorschau in Ankunftsreihenfolge, mit dem Schlüssel
(event_id, index), ergibt ein Präfix voncontent[index].textim gepufferten Event. Es ist nicht unbedingt der gesamte Text, da Deltas unter Last verworfen werden können. - Eine Verbindung gibt höchstens ein
event_startproevent_idaus, und das gepufferte Event ist das Letzte, was diese Verbindung für dieseidliefert.
SDK-Akkumulator-Helper
Der Helper jedes SDKs übernimmt die index-Buchführung. Die Helper für Go, Java, Ruby und C# verwenden außerdem die id des Events als Schlüssel für die akkumulierende Vorschau. Bei den Helpern für Python, TypeScript und PHP führst du diese Map selbst und fügst jedes Delta in den Eintrag für seine id ein.
Die folgenden Beispiele aktivieren Vorschauen für agent.message und gleichen sie mit dem gepufferten Event ab:
# Vorschau-Snapshots, indiziert nach Event-ID. accumulate_managed_agents_event faltet jedes
# event_start / event_delta in einen agent.message-Snapshot; das gepufferte
# agent.message ersetzt ihn.
previews: dict[str, BetaManagedAgentsAgentMessageEvent] = {}
# Aktiviere agent.message-Vorschauen auf dieser Verbindung
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":
# Das gepufferte Event ist der maßgebliche Datensatz: Es ersetzt und schließt die Vorschau
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":
# Es kommen keine weiteren Deltas. Schließe jede Vorschau, deren
# gepuffertes Event nie angekommen ist.
for event_id in previews:
print(f"span.model_request_end closing preview for {event_id}")
previews.clear()
case "session.status_idle":
breakSession-Thread-Events in der Vorschau anzeigen
In einer Multiagenten-Session hat jeder Session-Thread seinen eigenen Event-Stream. Er akzeptiert denselben event_deltas[]-Parameter mit denselben Werten.
Eine Verbindung zeigt nur den Thread in der Vorschau an, den sie liest. Der Stream auf Session-Ebene zeigt den primären Thread in der Vorschau an, und die Vorschauen eines Kind-Threads werden niemals dorthin übertragen. Um den Text eines Subagenten zu verfolgen, während das Modell ihn generiert, öffne den Thread-Stream dieses Subagenten.
Der Pfad eines Thread-Streams endet auf /threads/{thread_id}/stream. /events/stream existiert nur auf Session-Ebene, daher gibt es keinen Endpunkt /threads/{thread_id}/events/stream.
event_start und event_delta haben in einem Thread-Stream dieselbe Form wie im Stream auf Session-Ebene, und das Muster Akkumulieren und abgleichen gilt wie beschrieben. Führe eine Akkumulator-Instanz pro Stream-Verbindung aus.
# Liste die Threads der Session auf und wähle einen Child: Child-Threads haben eine nicht-null
# parent_thread_id, und die parent_thread_id des primären Threads ist null.
child_thread = next(
thread
for thread in client.beta.sessions.threads.list(session.id)
if thread.parent_thread_id is not None
)
# Der Stream des Child-Threads nimmt denselben event_deltas-Parameter wie der
# Session-Stream.
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":
# Das gepufferte Event ist der maßgebliche Datensatz; rendere seinen Inhalt
print()
for block in event.content:
if block.type == "text":
print(block.text, end="")
print()
case "session.thread_status_idle":
breakDie Leseschleife endet bei session.thread_status_idle, dem Event, das ausgegeben wird, wenn der Turn des Session-Threads abgeschlossen ist und der Thread in den Leerlauf geht.
Einschränkungen
- Best Effort: Unter Last kann der Server Deltas für ein Event verwerfen. In diesem Fall erhältst du ein zusammenhängendes Präfix des Textes und danach keine weiteren Deltas für dieses Event. Die gepufferte
agent.messagetrifft trotzdem vollständig ein. Behandle eine akkumulierte Vorschau niemals als endgültig. - Keine Wiedergabe bei erneuter Verbindung: Deltas werden nur an die Verbindung geliefert, die sie aktiviert hat, solange sie geöffnet ist. Dies gilt gleichermaßen für den Stream auf Session-Ebene und für jeden Session-Thread-Stream. Eine Verbindung, die geöffnet wurde, nachdem eine Modellanfrage begonnen hat, erhält keine Deltas für dieses laufende Event. Es gibt keine Möglichkeit, verpasste Deltas erneut anzufordern.
- Ein Thread, nur Text: Vorschauen umfassen Assistententext in dem Thread, den die Verbindung liest. Tool-Nutzung, Tool-Ergebnisse und MCP-Ergebnisse werden niemals in der Vorschau angezeigt.
- Niemals persistiert:
event_startundevent_deltaexistieren nur im Live-Stream. Sie erscheinen weder im Event-Verlauf der Session (GET /v1/sessions/{session_id}/events) noch im Event-Verlauf eines Session-Threads.
Fehlerbehebung bei Vorschauen
| Du siehst | Was es bedeutet |
|---|---|
Einen Stream mit gepufferten Events, aber ohne event_start oder event_delta | Die Verbindung, die du liest, hat die Vorschau nicht aktiviert, oder der Turn hat den Thread, den du streamst, nie berührt. event_deltas[] gilt pro Verbindung, nicht pro Session. Um herauszufinden, welcher Thread ausgeführt wurde, liste die Threads der Session auf (GET /v1/sessions/{session_id}/threads). |
| Einen Stream, der während einer Vorschau abbricht | Deltas werden nicht erneut wiedergegeben. Folge dem Verfahren zur erneuten Verbindung: Öffne den Stream erneut und liste den Event-Verlauf auf. Der Verlauf enthält alle gepufferten Events, die ausgegeben wurden, während du getrennt warst, einschließlich der agent.message, auf die deine Vorschau gewartet hat. |
| Einen 404-Fehler bei der Stream-URL | Der Pfad oder eine ID ist falsch, oder die Anfrage enthält überhaupt keinen Managed-Agents-Beta-Header. Die Thread-Endpunkte sind Beta-geschützt, ohne den Header existieren sie also nicht. |
Einen 400-Fehler, der event_deltas nennt | Nur agent.message und agent.thinking werden akzeptiert. |
Nächste Schritte
Sende Events, streame Antworten und unterbrich oder lenke deine Session während der Ausführung um.
Koordiniere mehrere Agenten innerhalb einer einzigen Session.
Was this page helpful?