> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentscope.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Message & Event

> The core data abstractions for agent communication and streaming

Message and Event are the two fundamental data structures in AgentScope.

* **Message** — the unit of inter-agent communication and persistence. Each `Msg` represents a complete conversation turn that is stored in context and exchanged between agents.
* **Event** — the unit of frontend interaction and streaming. Events carry incremental progress updates (text tokens, tool call fragments, permission requests) and drive real-time UIs and human-in-the-loop workflows.

A sequence of events produced during a single `reply` call accumulates into exactly one assistant `Msg`. This guarantees that the complete message state is always recoverable from its event stream.

## Message

An instance of the `Msg` class in AgentScope contains a complete conversation turn — a user input, or a complete assistant response, organized through different types of content blocks (Blocks).

<Tip>
  1. Running an agent's `reply_stream` once produces a complete `Msg` instance, containing all information such as multiple rounds of reasoning, tool calls, and execution results.
  2. During frontend rendering, a `Msg` instance corresponds to a single complete message bubble.
</Tip>

### Structure

The `Msg` class has the following core fields:

| Field         | Type                                | Description                                       |
| ------------- | ----------------------------------- | ------------------------------------------------- |
| `id`          | `str`                               | Unique message identifier                         |
| `name`        | `str`                               | Name of the sender                                |
| `role`        | `"user" \| "assistant" \| "system"` | The sender's role                                 |
| `content`     | `list[ContentBlock]`                | Ordered list of content blocks                    |
| `metadata`    | `dict`                              | Arbitrary key-value metadata                      |
| `created_at`  | `str`                               | ISO 8601 timestamp of creation                    |
| `finished_at` | `str \| None`                       | ISO 8601 timestamp when the message was finalized |
| `usage`       | `Usage`                             | Token usage statistics (for assistant messages)   |

### Content Blocks

Message content is composed of typed blocks. Each block represents a distinct piece of information:

| Block Type        | Description                                                                                                                                                         |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TextBlock`       | Plain text content                                                                                                                                                  |
| `DataBlock`       | Binary data (images, audio, video, etc.), either via base64 or URL                                                                                                  |
| `ThinkingBlock`   | Model reasoning (chain-of-thought)                                                                                                                                  |
| `ToolCallBlock`   | Tool call, containing name, input, and state                                                                                                                        |
| `ToolResultBlock` | Tool execution result                                                                                                                                               |
| `HintBlock`       | Hint information (e.g., scheduled-task triggers, team messages, background tool results); supports multimodal data and uses `source` to identify the hint's origin. |

<Note>
  Role constraints are enforced at construction:

  * `msg.role=="user"` messages can only contain `TextBlock` and `DataBlock`;
  * `msg.role=="system"` messages can only contain `TextBlock`;
  * `msg.role=="assistant"` messages can contain all block types.
</Note>

These content blocks carry different data information, and their detailed fields are described below:

<AccordionGroup>
  <Accordion title="TextBlock" description="Text data">
    | Field  | Type  | Description                                                                  |
    | ------ | ----- | ---------------------------------------------------------------------------- |
    | `type` | `str` | Fixed as `"text"`.                                                           |
    | `text` | `str` | The actual text content.                                                     |
    | `id`   | `str` | The unique identifier of the content block (auto-generated UUID by default). |
  </Accordion>

  <Accordion title="ThinkingBlock" description="The model's reasoning process">
    This content block allows passing through custom metadata defined by the model provider (such as the `signature` in Anthropic models, etc.).

    | Field      | Type  | Description                                                                  |
    | ---------- | ----- | ---------------------------------------------------------------------------- |
    | `type`     | `str` | Fixed as `"thinking"`.                                                       |
    | `thinking` | `str` | The reasoning or chain-of-thought text of the model.                         |
    | `id`       | `str` | The unique identifier of the content block (auto-generated UUID by default). |
  </Accordion>

  <Accordion title="DataBlock" description="Multimodal data (such as image, audio, video, etc.)">
    | Field    | Type                        | Description                                                                  |
    | -------- | --------------------------- | ---------------------------------------------------------------------------- |
    | `type`   | `str`                       | Fixed as `"data"`.                                                           |
    | `id`     | `str`                       | The unique identifier of the content block (auto-generated UUID by default). |
    | `source` | `Base64Source \| URLSource` | Identifies the data source. Supports Base64 input or URL input.              |
    | `name`   | `str \| None`               | Optional field, indicating the name of this content asset.                   |

    **Data Source Configuration:**

    * **`Base64Source`**:
      * `type`: Fixed as `"base64"`.
      * `data`: Base64-encoded binary data.
      * `media_type`: Media type (e.g., `"image/png"`, `"audio/mpeg"`, `"video/mp4"`, etc.).
    * **`URLSource`**:
      * `type`: Fixed as `"url"`.
      * `url`: A valid URI/URL string satisfying the RFC 3986 standard.
      * `media_type`: Media type (e.g., `"image/png"`, `"audio/wav"`, etc.).
  </Accordion>

  <Accordion title="HintBlock" description="Hint information used to guide the LLM">
    When finally passed to the LLM API, `HintBlock` is also converted to a standard user message (User message).

    To avoid confusion with user inputs, it is recommended to use XML tags (e.g., `<system-reminder>...</system-reminder>`) to wrap the hint content.

    | Field    | Type                                  | Description                                                                                |
    | -------- | ------------------------------------- | ------------------------------------------------------------------------------------------ |
    | `type`   | `str`                                 | Fixed as `"hint"`.                                                                         |
    | `hint`   | `str \| list[TextBlock \| DataBlock]` | The hint content — supports either plain text or a list of compound multimodal blocks.     |
    | `id`     | `str`                                 | The unique identifier of the content block (auto-generated UUID by default).               |
    | `source` | `str \| None`                         | Sender/origin label of the hint (can be a JSON string for frontend parsing and rendering). |
  </Accordion>

  <Accordion title="ToolCallBlock" description="Data and state of a tool call">
    | Field             | Type                   | Description                                                                                                                                                                                                                                                                                                                                                                                             |
    | ----------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `type`            | `str`                  | Fixed as `"tool_call"`.                                                                                                                                                                                                                                                                                                                                                                                 |
    | `id`              | `str`                  | Unique identifier for this tool call.                                                                                                                                                                                                                                                                                                                                                                   |
    | `name`            | `str`                  | Name of the tool to be called.                                                                                                                                                                                                                                                                                                                                                                          |
    | `input`           | `str`                  | Tool call parameters in JSON string format.                                                                                                                                                                                                                                                                                                                                                             |
    | `state`           | `ToolCallState`        | Tool call state:<br />• `"pending"`: Pending, has not passed verification and permission checks.<br />• `"asking"`: Suspended, waiting for user authorization.<br />• `"allowed"`: Approved by the user or permission rules, waiting to execute.<br />• `"submitted"`: Submitted externally and waiting for execution results.<br />• `"finished"`: Execution completed (whether successful or failed). |
    | `suggested_rules` | `list[PermissionRule]` | Suggested authorization rules attached when the user confirms.                                                                                                                                                                                                                                                                                                                                          |
  </Accordion>

  <Accordion title="ToolResultBlock" description="Data and state of tool execution results">
    The `id` of a `ToolResultBlock` must match the `id` of the launching `ToolCallBlock`. Supports multimodal data.

    | Field    | Type                                  | Description                                                                                                                                                                                                                                                     |
    | -------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `type`   | `str`                                 | Fixed as `"tool_result"`.                                                                                                                                                                                                                                       |
    | `id`     | `str`                                 | Unique ID matching the corresponding tool call.                                                                                                                                                                                                                 |
    | `name`   | `str`                                 | Name of the tool called.                                                                                                                                                                                                                                        |
    | `output` | `str \| list[TextBlock \| DataBlock]` | Execution output — supports either plain text or multimodal data.                                                                                                                                                                                               |
    | `state`  | `ToolResultState`                     | Tool execution state:<br />• `"running"`: Tool executing.<br />• `"success"`: Finished successfully.<br />• `"error"`: Finished with error.<br />• `"interrupted"`: Interrupted by the user.<br />• `"denied"`: Denied execution by the user or security rules. |
  </Accordion>
</AccordionGroup>

### Create Messages

AgentScope provides three shortcut methods to construct `Msg` objects to avoid repeatedly setting the `role` parameter, and supports building `TextBlock`s from strings:

| Factory Function              | Role        |
| ----------------------------- | ----------- |
| `UserMsg(name, content)`      | `user`      |
| `AssistantMsg(name, content)` | `assistant` |
| `SystemMsg(name, content)`    | `system`    |

When the `content` parameter is a string, it is automatically wrapped into a `TextBlock`.

<CodeGroup>
  ```python Create Text Message theme={null}
  from agentscope.message import UserMsg, SystemMsg, AssistantMsg

  # User message
  user_msg = UserMsg(
      name="user",
      content="What's in this image?"
  )

  # System message, used only for system prompts
  system_msg = SystemMsg(
      name="system",
      content="You are an AI assistant named Friday."
  )

  # Assistant message
  assistant_msg = AssistantMsg(
      name="Friday",
      content="Hello, how can I help you today?"
  )
  ```

  ```python Create Multimodal Message theme={null}
  from agentscope.message import UserMsg, TextBlock, DataBlock, Base64Source

  # User message
  user_msg = UserMsg(
      name="user",
      content=[
          TextBlock(text="Describe this image:"),
          DataBlock(
              source=Base64Source(
                  data="...",
                  media_type="image/png"
              )
          ),
      ],
  )
  ```

  ```python Create Tool Call Message theme={null}
  from agentscope.message import AssistantMsg, ThinkingBlock, TextBlock, ToolCallBlock, ToolCallState, ToolResultBlock, ToolResultState

  assistant_msg = AssistantMsg(
      name="Friday",
      content=[
          ThinkingBlock(thinking="I should invoke a tool to search for the weather."),
          TextBlock(text="Let me search the weather in Beijing."),
          ToolCallBlock(
              id="tool_call_1",
              name="weather_search",
              input='{"city": "Beijing"}',
              state=ToolCallState.FINISHED,
          ),
          ToolResultBlock(
              id="tool_call_1",
              name="weather_search",
              output="The weather in Beijing is sunny, with a temperature of 25°C.",
              state=ToolResultState.SUCCESS,
          ),
      ]
  )
  ```
</CodeGroup>

### Access Content

`Msg` provides helper methods to extract specific block types:

| Method                             | Returns                                            |
| ---------------------------------- | -------------------------------------------------- |
| `get_text_content(separator="\n")` | Concatenated text from all `TextBlock`s, or `None` |
| `get_content_blocks(block_type)`   | Filtered list of blocks by type                    |
| `has_content_blocks(block_type)`   | `True` if blocks of the given type exist           |

```python theme={null}
# Get all text content
text = msg.get_text_content()

# Get all tool calls
tool_calls = msg.get_content_blocks("tool_call")

# Check if message has tool results
if msg.has_content_blocks("tool_result"):
    ...
```

## Event

Events are the streaming counterpart of messages. While the agent executes, it yields a sequence of `AgentEvent` objects that represent incremental progress — text tokens arriving, tool calls being constructed, results streaming back. Each event is lightweight and self-contained.

### Event Lifecycle

Every event carries a `reply_id` that links it to the message being constructed. Within a reply, `block_id` or `tool_call_id` identifies which content block an event belongs to. Events follow a **start → delta → end** pattern for each content block:

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant Agent

    Agent->>Client: ReplyStartEvent

    rect rgba(100, 150, 255, 0.1)
        Note over Client,Agent: Reasoning Phase
        Agent->>Client: ModelCallStartEvent
        rect rgba(200, 200, 100, 0.1)
            Note over Client,Agent: TextBlock (block_id)
            Agent->>Client: TextBlockStartEvent
            Agent->>Client: TextBlockDeltaEvent (×N)
            Agent->>Client: TextBlockEndEvent
        end
        rect rgba(200, 200, 100, 0.1)
            Note over Client,Agent: DataBlock (block_id)
            Agent->>Client: DataBlockStartEvent
            Agent->>Client: DataBlockDeltaEvent (×N)
            Agent->>Client: DataBlockEndEvent
        end
        rect rgba(200, 200, 100, 0.1)
            Note over Client,Agent: ToolCallBlock (tool_call_id)
            Agent->>Client: ToolCallStartEvent
            Agent->>Client: ToolCallDeltaEvent (×N)
            Agent->>Client: ToolCallEndEvent
        end
        Agent->>Client: ModelCallEndEvent
    end

    rect rgba(100, 255, 150, 0.1)
        Note over Client,Agent: Acting Phase
        rect rgba(200, 200, 100, 0.1)
            Note over Client,Agent: ToolResultBlock (tool_call_id)
            Agent->>Client: ToolResultStartEvent
            Agent->>Client: ToolResultTextDeltaEvent (×N)
            Agent->>Client: ToolResultDataDeltaEvent (×N)
            Agent->>Client: ToolResultEndEvent
        end
    end

    Agent->>Client: ReplyEndEvent
```

All events within the same reply share the same `reply_id`. Within a reply, use `block_id` to correlate text/thinking/data block events, and `tool_call_id` to correlate tool call and tool result events.

### Event Types

All events inherit from `EventBase` which provides common fields:

| Field        | Type  | Description             |
| ------------ | ----- | ----------------------- |
| `id`         | `str` | Unique event identifier |
| `created_at` | `str` | ISO 8601 timestamp      |

Events are grouped by category below. Every event also carries a `reply_id` field (except where noted) that links it to the message being constructed.

<AccordionGroup>
  <Accordion title="Lifecycle Events">
    **ReplyStartEvent** — Agent begins a new reply.

    | Field        | Type  | Description                        |
    | ------------ | ----- | ---------------------------------- |
    | `reply_id`   | `str` | ID of the reply message            |
    | `session_id` | `str` | ID of the session                  |
    | `name`       | `str` | Agent name                         |
    | `role`       | `str` | Agent role (default `"assistant"`) |

    **ReplyEndEvent** — Agent finishes the reply.

    | Field        | Type  | Description             |
    | ------------ | ----- | ----------------------- |
    | `reply_id`   | `str` | ID of the reply message |
    | `session_id` | `str` | ID of the session       |

    **ExceedMaxItersEvent** — Agent reached the maximum reasoning-acting iterations.

    | Field      | Type  | Description             |
    | ---------- | ----- | ----------------------- |
    | `reply_id` | `str` | ID of the reply message |
    | `name`     | `str` | Agent name              |
  </Accordion>

  <Accordion title="Text Streaming Events">
    **TextBlockStartEvent** — A new text block begins.

    | Field      | Type  | Description                         |
    | ---------- | ----- | ----------------------------------- |
    | `reply_id` | `str` | ID of the reply message             |
    | `block_id` | `str` | Unique identifier of the text block |

    **TextBlockDeltaEvent** — Incremental text content arrives.

    | Field      | Type  | Description                         |
    | ---------- | ----- | ----------------------------------- |
    | `reply_id` | `str` | ID of the reply message             |
    | `block_id` | `str` | Unique identifier of the text block |
    | `delta`    | `str` | Incremental text content            |

    **TextBlockEndEvent** — The text block is complete.

    | Field      | Type  | Description                         |
    | ---------- | ----- | ----------------------------------- |
    | `reply_id` | `str` | ID of the reply message             |
    | `block_id` | `str` | Unique identifier of the text block |
  </Accordion>

  <Accordion title="Thinking Streaming Events">
    **ThinkingBlockStartEvent** — A new thinking block begins.

    | Field      | Type  | Description                             |
    | ---------- | ----- | --------------------------------------- |
    | `reply_id` | `str` | ID of the reply message                 |
    | `block_id` | `str` | Unique identifier of the thinking block |

    **ThinkingBlockDeltaEvent** — Incremental thinking content arrives.

    | Field      | Type  | Description                             |
    | ---------- | ----- | --------------------------------------- |
    | `reply_id` | `str` | ID of the reply message                 |
    | `block_id` | `str` | Unique identifier of the thinking block |
    | `delta`    | `str` | Incremental thinking text               |

    **ThinkingBlockEndEvent** — The thinking block is complete.

    | Field      | Type  | Description                             |
    | ---------- | ----- | --------------------------------------- |
    | `reply_id` | `str` | ID of the reply message                 |
    | `block_id` | `str` | Unique identifier of the thinking block |
  </Accordion>

  <Accordion title="Data Streaming Events">
    **DataBlockStartEvent** — A new data block begins (image, audio, etc.).

    | Field        | Type  | Description                         |
    | ------------ | ----- | ----------------------------------- |
    | `reply_id`   | `str` | ID of the reply message             |
    | `block_id`   | `str` | Unique identifier of the data block |
    | `media_type` | `str` | MIME type (e.g. `"image/png"`)      |

    **DataBlockDeltaEvent** — Incremental binary data arrives.

    | Field        | Type  | Description                         |
    | ------------ | ----- | ----------------------------------- |
    | `reply_id`   | `str` | ID of the reply message             |
    | `block_id`   | `str` | Unique identifier of the data block |
    | `data`       | `str` | Incremental base64-encoded data     |
    | `media_type` | `str` | MIME type                           |

    **DataBlockEndEvent** — The data block is complete.

    | Field      | Type  | Description                         |
    | ---------- | ----- | ----------------------------------- |
    | `reply_id` | `str` | ID of the reply message             |
    | `block_id` | `str` | Unique identifier of the data block |
  </Accordion>

  <Accordion title="Tool Call Streaming Events">
    **ToolCallStartEvent** — The agent begins a tool call.

    | Field            | Type  | Description                        |
    | ---------------- | ----- | ---------------------------------- |
    | `reply_id`       | `str` | ID of the reply message            |
    | `tool_call_id`   | `str` | Unique identifier of the tool call |
    | `tool_call_name` | `str` | Name of the tool being called      |

    **ToolCallDeltaEvent** — Incremental tool call input arrives.

    | Field          | Type  | Description                             |
    | -------------- | ----- | --------------------------------------- |
    | `reply_id`     | `str` | ID of the reply message                 |
    | `tool_call_id` | `str` | Unique identifier of the tool call      |
    | `delta`        | `str` | Incremental JSON fragment of tool input |

    **ToolCallEndEvent** — The tool call input is complete.

    | Field          | Type  | Description                        |
    | -------------- | ----- | ---------------------------------- |
    | `reply_id`     | `str` | ID of the reply message            |
    | `tool_call_id` | `str` | Unique identifier of the tool call |
  </Accordion>

  <Accordion title="Tool Result Streaming Events">
    **ToolResultStartEvent** — Tool execution begins.

    | Field            | Type  | Description                       |
    | ---------------- | ----- | --------------------------------- |
    | `reply_id`       | `str` | ID of the reply message           |
    | `tool_call_id`   | `str` | ID of the corresponding tool call |
    | `tool_call_name` | `str` | Name of the tool                  |

    **ToolResultTextDeltaEvent** — Incremental text output from the tool.

    | Field          | Type  | Description                       |
    | -------------- | ----- | --------------------------------- |
    | `reply_id`     | `str` | ID of the reply message           |
    | `tool_call_id` | `str` | ID of the corresponding tool call |
    | `delta`        | `str` | Incremental text content          |

    **ToolResultDataDeltaEvent** — Binary data output from the tool.

    | Field          | Type          | Description                                                  |
    | -------------- | ------------- | ------------------------------------------------------------ |
    | `reply_id`     | `str`         | ID of the reply message                                      |
    | `tool_call_id` | `str`         | ID of the corresponding tool call                            |
    | `block_id`     | `str`         | Unique identifier of the data block                          |
    | `media_type`   | `str`         | MIME type of the content                                     |
    | `data`         | `str \| None` | Base64-encoded data (mutually exclusive with `url`)          |
    | `url`          | `str \| None` | URL pointing to the content (mutually exclusive with `data`) |

    **ToolResultEndEvent** — Tool execution is complete.

    | Field          | Type              | Description                                                            |
    | -------------- | ----------------- | ---------------------------------------------------------------------- |
    | `reply_id`     | `str`             | ID of the reply message                                                |
    | `tool_call_id` | `str`             | ID of the corresponding tool call                                      |
    | `state`        | `ToolResultState` | Final state: `SUCCESS`, `ERROR`, `INTERRUPTED`, `DENIED`, or `RUNNING` |
  </Accordion>

  <Accordion title="Model Call Events">
    **ModelCallStartEvent** — A model API call begins.

    | Field        | Type  | Description                    |
    | ------------ | ----- | ------------------------------ |
    | `reply_id`   | `str` | ID of the reply message        |
    | `model_name` | `str` | Name of the model being called |

    **ModelCallEndEvent** — A model API call completes.

    | Field           | Type  | Description                       |
    | --------------- | ----- | --------------------------------- |
    | `reply_id`      | `str` | ID of the reply message           |
    | `input_tokens`  | `int` | Number of input tokens consumed   |
    | `output_tokens` | `int` | Number of output tokens generated |
  </Accordion>

  <Accordion title="Human-in-the-Loop Events">
    **RequireUserConfirmEvent** — Agent pauses for user confirmation.

    | Field        | Type                  | Description                          |
    | ------------ | --------------------- | ------------------------------------ |
    | `reply_id`   | `str`                 | ID of the reply message              |
    | `tool_calls` | `list[ToolCallBlock]` | Tool calls pending user confirmation |

    **RequireExternalExecutionEvent** — Agent pauses for external execution.

    | Field        | Type                  | Description                          |
    | ------------ | --------------------- | ------------------------------------ |
    | `reply_id`   | `str`                 | ID of the reply message              |
    | `tool_calls` | `list[ToolCallBlock]` | Tool calls to be executed externally |

    **UserConfirmResultEvent** — User provides confirmation results (input event).

    | Field             | Type                  | Description                                     |
    | ----------------- | --------------------- | ----------------------------------------------- |
    | `reply_id`        | `str`                 | ID of the reply message                         |
    | `confirm_results` | `list[ConfirmResult]` | Confirmation results for each pending tool call |

    **ExternalExecutionResultEvent** — External system provides execution results (input event).

    | Field               | Type                    | Description                               |
    | ------------------- | ----------------------- | ----------------------------------------- |
    | `reply_id`          | `str`                   | ID of the reply message                   |
    | `execution_results` | `list[ToolResultBlock]` | Results returned by the external executor |
  </Accordion>

  <Accordion title="One-shot Events">
    Unlike text / thinking / data / tool blocks, these events do not follow the start → delta → end pattern. The full payload arrives in a single event because it is known up-front rather than streamed.

    **HintBlockEvent** — A `HintBlock` is injected into the agent's context (e.g. a scheduled-task trigger, a team message, a result returned by an offloaded background tool).

    | Field      | Type                                  | Description                                                                                                     |
    | ---------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
    | `reply_id` | `str`                                 | ID of the reply message                                                                                         |
    | `block_id` | `str`                                 | Unique identifier of the hint block                                                                             |
    | `hint`     | `str \| list[TextBlock \| DataBlock]` | The hint payload — plain text or a list of multimodal blocks                                                    |
    | `source`   | `str \| None`                         | Optional sender / origin tag (typically a small JSON object describing how the frontend should label this hint) |

    **CustomEvent** — Generic extensible event used by service-layer middleware to notify subscribers about state changes (task progress, team membership, permission updates, …) without polluting the core agent event enum.

    | Field      | Type   | Description                                                |
    | ---------- | ------ | ---------------------------------------------------------- |
    | `reply_id` | `str`  | ID of the reply message                                    |
    | `name`     | `str`  | The signal name (e.g. `"tasks_context"`, `"team_updated"`) |
    | `value`    | `dict` | Arbitrary JSON-serialisable payload for this signal        |
  </Accordion>
</AccordionGroup>

## Reconstruct Messages from Events

Events and messages are not independent — they are two views of the same data. Every event produced by `reply_stream` can be applied to a `Msg` via `append_event()`, reconstructing the complete message incrementally. This guarantees that the final message state is fully recoverable from the event stream alone.

```python theme={null}
from agentscope.message import Msg, AssistantMsg

msg = None

# Accumulate events into the message
async for event in agent.reply_stream(user_msg):
	if isinstance(event, ReplyStartEvent):
		# Create a new message when the reply starts
		msg = AssistantMsg(name=event.name, content=[], id=event.reply_id)

	else:
		# For all other events, append to the message to reconstruct its state
        msg.append_event(event)
```

The `append_event` method handles all event types:

| Event Type                     | Effect on Msg                                                                                                       |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `ReplyEndEvent`                | Sets `finished_at` timestamp                                                                                        |
| `TextBlockStartEvent`          | Appends a new empty `TextBlock`                                                                                     |
| `TextBlockDeltaEvent`          | Concatenates `delta` to the block's text                                                                            |
| `DataBlockStartEvent`          | Appends a new empty `DataBlock`                                                                                     |
| `DataBlockDeltaEvent`          | Concatenates `data` to the block's base64 content                                                                   |
| `ThinkingBlockStartEvent`      | Appends a new empty `ThinkingBlock`                                                                                 |
| `ThinkingBlockDeltaEvent`      | Concatenates `delta` to the block's thinking text                                                                   |
| `ToolCallStartEvent`           | Appends a new `ToolCallBlock` with empty input                                                                      |
| `ToolCallDeltaEvent`           | Concatenates `delta` to the tool call's input                                                                       |
| `ToolResultStartEvent`         | Appends a new `ToolResultBlock` with empty output                                                                   |
| `ToolResultTextDeltaEvent`     | Appends text to the tool result's output                                                                            |
| `ToolResultDataDeltaEvent`     | Appends a binary data block to the tool result's output                                                             |
| `ToolResultEndEvent`           | Sets the tool result's final `state`                                                                                |
| `HintBlockEvent`               | Appends a `HintBlock` to content (carrying the event's `hint` and `source`) so the hint is persisted and replayable |
| `RequireUserConfirmEvent`      | Updates tool call states to `ASKING`                                                                                |
| `ExternalExecutionResultEvent` | Appends `ToolResultBlock`s to content                                                                               |

<Tip>
  This design makes deployment more flexible: the backend can stream events via SSE to the frontend, which reconstructs and renders the message in real time. Even if the connection is interrupted, replaying the event sequence from any checkpoint can restore the exact message state.
</Tip>

### TypeScript Support

AgentScope provides TypeScript versions of messages and event primitives, so frontends can use the exact same `appendEvent` API to reconstruct messages from the event stream.

Install the TypeScript version of AgentScope:

```bash theme={null}
pnpm install @agentscope-ai/agentscope
```

Example of receiving and reconstructing messages on the frontend:

```typescript theme={null}
import { Msg, AssistantMsg, EventType } from "@agentscope-ai/agentscope/message";

let msg: Msg | null = null;
for await (const event of stream) {
    if (event.type === EventType.REPLY_START) {
        msg = new AssistantMsg({
			name: event.name,
			content: [],
			id: event.reply_id
		});
    } else {
        msg?.appendEvent(event);
    }
}
```

### Example: Streaming UI

A typical pattern for building a streaming interface:

```python theme={null}
from agentscope.message import AssistantMsg, UserMsg
from agentscope.event import (
    ReplyStartEvent,
    TextBlockDeltaEvent,
    ToolCallStartEvent,
    ToolResultEndEvent,
    ReplyEndEvent,
)

msg = None

async for event in agent.reply_stream(UserMsg("user", "Fix the bug")):
    if isinstance(event, ReplyStartEvent):
        msg = AssistantMsg(name=event.name, content=[], id=event.reply_id)

    elif isinstance(event, TextBlockDeltaEvent):
        print(event.delta, end="", flush=True)

    elif isinstance(event, ToolCallStartEvent):
        print(f"\n[Calling {event.tool_call_name}...]")

    elif isinstance(event, ToolResultEndEvent):
        print(f"[Tool finished: {event.state}]")

    elif isinstance(event, ReplyEndEvent):
        print("\n[Done]")

    # Always accumulate into the message
    if msg is not None:
        msg.append_event(event)

# msg now contains the complete reply
```

## Further Reading

<CardGroup cols={2}>
  <Card title="Agent" icon="robot" href="/versions/2.0.4dev/en/building-blocks/agent">
    How the agent produces events and messages in the ReAct loop
  </Card>

  <Card title="Context" icon="database" href="/versions/2.0.4dev/en/building-blocks/context">
    How messages are stored, compressed, and offloaded
  </Card>
</CardGroup>
