Every way of consuming a Strands stream yields the same set of events: [async iterators](/docs/user-guide/sdk/streaming/async-iterators/index.md) and, in Python, [callback handlers](/docs/user-guide/sdk/streaming/callback-handlers/index.md). They differ in their execution model, not in what they emit. This page is the reference for every event type the stream produces: lifecycle signals, model output, tool activity, and multi-agent coordination, plus how to serialize events when forwarding them over the wire.

## Event Types

### Lifecycle Events

(( tab "Python" ))
-   **`init_event_loop`**: True at the start of agent invocation initializing
-   **`start_event_loop`**: True when the event loop is starting
-   **`event_loop_throttled_delay`**: Delay, in seconds, that the agent loop waited before retrying a model call after a retryable failure (by default only throttling, see [Retry Strategies](/docs/user-guide/sdk/agents/retry-strategies/index.md))
-   **`message`**: Present when a new message is created
-   **`event`**: Raw event from the model stream
-   **`force_stop`**: True if the event loop was forced to stop
    -   **`force_stop_reason`**: Reason for forced stop
-   **`result`**: The final [`AgentResult`](/docs/api/python/strands.agent.agent_result#AgentResult)
(( /tab "Python" ))

(( tab "TypeScript" ))
Each event emitted from the TypeScript agent is a class with a `type` attribute that has a unique value. When determining an event, you can use `instanceof` on the class, or an equality check on the `event.type` value. All events extend `HookableEvent`, making them both streamable and subscribable via hook callbacks.

-   **`BeforeInvocationEvent`**: Start of agent loop (before any iterations)
    -   **`cancel`**: Set by hook callbacks to cancel the invocation (`boolean | string`)
-   **`AfterInvocationEvent`**: End of agent loop (after all iterations complete)
    -   **`error?`**: Optional error if loop terminated due to exception
-   **`BeforeModelCallEvent`**: Before model invocation
    -   **`messages`**: Array of messages being sent to model
    -   **`cancel`**: Set by hook callbacks to cancel the model call (`boolean | string`)
-   **`AfterModelCallEvent`**: After model invocation
    -   **`message`**: Assistant message returned by model
    -   **`stopReason`**: Why generation stopped
-   **`BeforeToolsEvent`**: Before tools execution
    -   **`message`**: Assistant message containing tool use blocks
-   **`AfterToolsEvent`**: After tools execution
    -   **`message`**: User message containing tool results
-   **`AgentResultEvent`**: Final agent result
    -   **`result`**: The `AgentResult` with `stopReason`, `lastMessage`, and optional `structuredOutput`
(( /tab "TypeScript" ))

### Model Stream Events

(( tab "Python" ))
-   **`data`**: Text chunk from the model’s output
-   **`delta`**: Raw delta content from the model
-   **`reasoning`**: True for reasoning events
    -   **`reasoningText`**: Text from reasoning process
    -   **`reasoning_signature`**: Signature from reasoning process
    -   **`redactedContent`**: Reasoning content redacted by the model
(( /tab "Python" ))

(( tab "TypeScript" ))
-   **`ModelStreamUpdateEvent`**: Wraps transient model streaming deltas. Access the inner event via `.event`:
    -   **`ModelMessageStartEvent`**: Start of a message from the model
    -   **`ModelContentBlockStartEvent`**: Start of a content block (text, toolUse, reasoning, etc.)
    -   **`ModelContentBlockDeltaEvent`**: Content deltas for text, tool input, or reasoning
    -   **`ModelContentBlockStopEvent`**: End of a content block
    -   **`ModelMessageStopEvent`**: End of a message
    -   **`ModelMetadataEvent`**: Usage and metrics metadata
-   **`ContentBlockEvent`**: Wraps a fully assembled content block (TextBlock, ToolUseBlock, ReasoningBlock). Access via `.contentBlock`
-   **`ModelMessageEvent`**: Wraps the complete model message after all blocks are assembled. Access via `.message`
(( /tab "TypeScript" ))

### Tool Events

(( tab "Python" ))
-   **`current_tool_use`**: Information about the current tool being used, including:
    -   **`toolUseId`**: Unique ID for this tool use
    -   **`name`**: Name of the tool
    -   **`input`**: Tool input parameters (accumulated as streaming occurs)
-   **`tool_stream_event`**: Information about [an event streamed from a tool](/docs/user-guide/sdk/tools/custom-tools/index.md#tool-streaming), including:
    -   **`tool_use`**: The [`ToolUse`](/docs/api/python/strands.types.tools#ToolUse) for the tool that streamed the event
    -   **`data`**: The data streamed from the tool
(( /tab "Python" ))

(( tab "TypeScript" ))
-   **`BeforeToolCallEvent`**: Before a tool is executed
    -   **`toolUse`**: The tool use block with `name` and `input`
-   **`AfterToolCallEvent`**: After a tool finishes execution
    -   **`toolUse`**: The tool use block
    -   **`result`**: The tool result block
-   **`ToolStreamUpdateEvent`**: Wraps streaming progress events from a tool. Access via `.event`:
    -   **`data`**: The data streamed from the tool
-   **`ToolResultEvent`**: Wraps a completed tool result. Access via `.result`
(( /tab "TypeScript" ))

### Multi-Agent Events

(( tab "Python" ))
Multi-agent systems ([Graph](/docs/user-guide/sdk/multi-agent/graph/index.md) and [Swarm](/docs/user-guide/sdk/multi-agent/swarm/index.md)) emit additional coordination events:

-   **`multiagent_node_start`**: When a node begins execution
    -   **`type`**: `"multiagent_node_start"`
    -   **`node_id`**: Unique identifier for the node
    -   **`node_type`**: Type of node (`"agent"`, `"swarm"`, `"graph"`)
-   **`multiagent_node_stream`**: Forwarded events from agents/multi-agents with node context
    -   **`type`**: `"multiagent_node_stream"`
    -   **`node_id`**: Identifier of the node generating the event
    -   **`event`**: The original agent event (nested)
-   **`multiagent_node_stop`**: When a node completes execution
    -   **`type`**: `"multiagent_node_stop"`
    -   **`node_id`**: Unique identifier for the node
    -   **`node_result`**: Complete NodeResult with execution details, metrics, and status
-   **`multiagent_handoff`**: When control is handed off between agents (Swarm) or batch transitions (Graph)
    -   **`type`**: `"multiagent_handoff"`
    -   **`from_node_ids`**: List of node IDs completing execution
    -   **`to_node_ids`**: List of node IDs beginning execution
    -   **`message`**: Optional handoff message (typically used in Swarm)
-   **`multiagent_result`**: Final multi-agent result
    -   **`type`**: `"multiagent_result"`
    -   **`result`**: The final GraphResult or SwarmResult

See [Graph streaming](/docs/user-guide/sdk/multi-agent/graph/index.md#streaming-events) and [Swarm streaming](/docs/user-guide/sdk/multi-agent/swarm/index.md#streaming-events) for usage examples.
(( /tab "Python" ))

(( tab "TypeScript" ))
Multi-agent systems ([Graph](/docs/user-guide/sdk/multi-agent/graph/index.md) and [Swarm](/docs/user-guide/sdk/multi-agent/swarm/index.md)) emit additional coordination events. Each event is a class with a `type` attribute, extending `HookableEvent` for both streaming and hook subscription.

-   **`MultiAgentInitializedEvent`**: When a multi-agent orchestrator has finished initialization
    -   **`orchestrator`**: The `MultiAgentBase` instance
-   **`BeforeMultiAgentInvocationEvent`**: Before orchestrator execution starts
    -   **`orchestrator`**: The `MultiAgentBase` instance
    -   **`state`**: The current `MultiAgentState`
-   **`BeforeNodeCallEvent`**: Before a node begins execution
    -   **`nodeId`**: Unique identifier for the node
    -   **`orchestrator`**: The `MultiAgentBase` instance
    -   **`state`**: The current `MultiAgentState`
    -   **`cancel`**: Set by hook callbacks to cancel node execution (`boolean | string`)
-   **`NodeStreamUpdateEvent`**: Forwarded events from agents or nested orchestrators with node context
    -   **`nodeId`**: Identifier of the node generating the event
    -   **`nodeType`**: Type of node (`"agentNode"`, `"multiAgentNode"`)
    -   **`state`**: The current `MultiAgentState`
    -   **`event`**: The inner `AgentStreamEvent` or `MultiAgentStreamEvent`
-   **`NodeCancelEvent`**: When a node is cancelled via `BeforeNodeCallEvent.cancel`
    -   **`nodeId`**: Unique identifier for the node
    -   **`state`**: The current `MultiAgentState`
    -   **`message`**: Cancel reason
-   **`AfterNodeCallEvent`**: After a node completes execution
    -   **`nodeId`**: Unique identifier for the node
    -   **`orchestrator`**: The `MultiAgentBase` instance
    -   **`state`**: The current `MultiAgentState`
    -   **`error?`**: Optional error if the node failed
-   **`NodeResultEvent`**: When a node finishes execution
    -   **`nodeId`**: Unique identifier for the node
    -   **`nodeType`**: Type of node (`"agentNode"`, `"multiAgentNode"`)
    -   **`state`**: The current `MultiAgentState`
    -   **`result`**: The `NodeResult` with `status`, `duration`, `content`, and optional `error`
-   **`MultiAgentHandoffEvent`**: When execution transitions between nodes
    -   **`source`**: Node ID completing execution
    -   **`targets`**: Array of node IDs beginning execution
    -   **`state`**: The current `MultiAgentState`
-   **`AfterMultiAgentInvocationEvent`**: After orchestrator execution completes
    -   **`orchestrator`**: The `MultiAgentBase` instance
    -   **`state`**: The current `MultiAgentState`
-   **`MultiAgentResultEvent`**: Final event in the multi-agent stream
    -   **`result`**: The `MultiAgentResult` with `status`, `results`, `content`, and `duration`

See [Graph streaming](/docs/user-guide/sdk/multi-agent/graph/index.md#streaming-events) and [Swarm streaming](/docs/user-guide/sdk/multi-agent/swarm/index.md#streaming-events) for usage examples.
(( /tab "TypeScript" ))

### Event Serialization

(( tab "Python" ))
Python streaming events are plain dictionaries. The SDK does not include a built-in serialization filter, so you control which events and fields to forward from your processes and servers.

When serving streamed responses (for example, over SSE or WebSockets), you can filter the yielded events to keep payloads compact:

```python
import json

def filter_event(event: dict) -> dict | None:
    """Filter streaming events to only forward relevant data over the wire."""
    # Forward text deltas for real-time display
    if "data" in event:
        return {"type": "text", "data": event["data"]}

    # Forward tool usage for progress indicators
    if "current_tool_use" in event and event["current_tool_use"].get("name"):
        return {"type": "tool", "name": event["current_tool_use"]["name"]}

    # Forward the final result
    if "result" in event:
        return {"type": "result", "stop_reason": str(event["result"].stop_reason)}

    # Skip everything else (lifecycle signals, raw deltas, reasoning, etc.)
    return None


async for event in agent.stream_async("Hello"):
    filtered = filter_event(event)
    if filtered:
        await response.write(f"data: {json.dumps(filtered)}\n\n")
```

This approach lets you tailor the streamed output to your use case, for example forwarding only text deltas for a chat UI or including tool events for a progress dashboard.
(( /tab "Python" ))

(( tab "TypeScript" ))
Every event class implements a `toJSON()` method that `JSON.stringify()` calls automatically. Each serialized event retains its `type` discriminator and the relevant data fields (matching the general shape of the class) while excluding in-memory runtime references (`agent`, `orchestrator`, `state`, `tool`) and mutable hook properties (`cancel`, `retry`). `Error` objects are converted to `{ message: string }`. This applies to single-agent, multi-agent, and A2A events alike.

You can filter which events to forward to the client:

```typescript
for await (const event of agent.stream('Hello')) {
  switch (event.type) {
    // Forward text deltas for real-time display
    case 'modelStreamUpdateEvent':
      if (
        event.event.type === 'modelContentBlockDeltaEvent' &&
        event.event.delta.type === 'textDelta'
      ) {
        console.log(
          `data: ${JSON.stringify({ type: 'text', text: event.event.delta.text })}`
        )
      }
      break

    // Forward tool names for progress indicators
    case 'beforeToolCallEvent':
      console.log(`data: ${JSON.stringify({ type: 'tool', name: event.toolUse.name })}`)
      break

    // Forward the final result
    case 'agentResultEvent':
      console.log(`data: ${JSON.stringify(event)}`)
      break
  }
}
```
(( /tab "TypeScript" ))

## Next Steps

-   Consume these events in async frameworks with [Async Iterators](/docs/user-guide/sdk/streaming/async-iterators/index.md).
-   Intercept them with a function in synchronous Python via [Callback Handlers](/docs/user-guide/sdk/streaming/callback-handlers/index.md).
-   See the Agent API Reference for complete method documentation: [Python](/docs/api/python/strands.agent.agent) | [TypeScript](/docs/api/typescript/Agent/index.md)

## Related pages

- [Async Iterators for Streaming](/docs/user-guide/sdk/streaming/async-iterators/index.md) (1 shared tag)
- [Callback Handlers](/docs/user-guide/sdk/streaming/callback-handlers/index.md) (1 shared tag)
- [Stream responses](/docs/user-guide/sdk/streaming/index.md) (1 shared tag)


## Implementation

### Python

- [harness-sdk/strands-py/src/strands/event_loop/streaming.py](https://github.com/strands-agents/harness-sdk/blob/main/strands-py/src/strands/event_loop/streaming.py)

### TypeScript

- [harness-sdk/strands-ts/src/models/streaming.ts](https://github.com/strands-agents/harness-sdk/blob/main/strands-ts/src/models/streaming.ts)
