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.
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).
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.
During frontend rendering, a Msg instance corresponds to a single complete message bubble.
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.
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.
These content blocks carry different data information, and their detailed fields are described below:
TextBlock
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).
ThinkingBlock
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).
DataBlock
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.).
HintBlock
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).
ToolCallBlock
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: • "pending": Pending, has not passed verification and permission checks. • "asking": Suspended, waiting for user authorization. • "allowed": Approved by the user or permission rules, waiting to execute. • "submitted": Submitted externally and waiting for execution results. • "finished": Execution completed (whether successful or failed).
suggested_rules
list[PermissionRule]
Suggested authorization rules attached when the user confirms.
ToolResultBlock
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: • "running": Tool executing. • "success": Finished successfully. • "error": Finished with error. • "interrupted": Interrupted by the user. • "denied": Denied execution by the user or security rules.
AgentScope provides three shortcut methods to construct Msg objects to avoid repeatedly setting the role parameter, and supports building TextBlocks 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.
from agentscope.message import UserMsg, SystemMsg, AssistantMsg# User messageuser_msg = UserMsg( name="user", content="What's in this image?")# System message, used only for system promptssystem_msg = SystemMsg( name="system", content="You are an AI assistant named Friday.")# Assistant messageassistant_msg = AssistantMsg( name="Friday", content="Hello, how can I help you today?")
Msg provides helper methods to extract specific block types:
Method
Returns
get_text_content(separator="\n")
Concatenated text from all TextBlocks, 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
# Get all text contenttext = msg.get_text_content()# Get all tool callstool_calls = msg.get_content_blocks("tool_call")# Check if message has tool resultsif msg.has_content_blocks("tool_result"): ...
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.
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: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.
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
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
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
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
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
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.
from agentscope.message import Msg, AssistantMsgmsg = None# Accumulate events into the messageasync 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 ToolResultBlocks to content
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.
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:
pnpm install @agentscope-ai/agentscope
Example of receiving and reconstructing messages on the frontend: