- Message — the primitive of agent-to-agent communication and persistence. Each
Msgis a complete conversation turn, stored in the context and passed between agents. - Event — the primitive 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 flows.
call always condenses into exactly one assistant Msg, ensuring the full message state can be reconstructed from the event stream alone.
Message
Msg (io.agentscope.core.message) represents one turn of conversation — a user input, an agent reply, or a system instruction — with content modelled as an ordered list of typed ContentBlocks.
Structure
The core fields onMsg (via getters):
Content blocks
Message content is composed of typed blocks, each representing one type of information. Block classes live inio.agentscope.core.message:
Role constraints are enforced at construction:
USER only allows text/data/image/audio/video blocks; SYSTEM only allows TextBlock; ASSISTANT allows all block types.Creating a message
The role-pinned subclasses (io.agentscope.core.message.UserMessage / AssistantMessage / SystemMessage / ToolResultMessage) provide convenient constructors. When content is a plain string, it is wrapped in a TextBlock automatically.
metadata, timestamp, usage, generateReason), use each subclass’s builder():
Accessing content
Msg provides helpers for extracting specific block types:
Event
Events are the streaming counterpart of messages. While the agent runs, it emits a sequence ofAgentEvents (io.agentscope.core.event) representing incremental progress — text tokens arriving, tool calls being assembled, results streaming back. Each event is lightweight and self-contained.
Event lifecycle
Every event carriesgetReplyId(), tying it to the message being assembled. Within a reply, getBlockId() or getToolCallId() acts as a correlation key for events that belong to the same content-block lifecycle. Events follow a start → delta → end pattern:
All events in one reply share the same replyId. Within a reply, blockId ties text/thinking/data block events together; toolCallId ties tool calls and tool results. A blockId is scoped to its replyId and does not have to be a globally unique generated ID. When a block type can have at most one lifecycle within a reply, an implementation may use a stable type key, such as a fixed key for the text block.
Event types
All events extendAgentEvent (io.agentscope.core.event), which exposes the common methods:
Events are grouped below; unless noted otherwise, every event also carries
getReplyId() linking it to the message being assembled.
Lifecycle events
Lifecycle events
AgentStartEvent — agent begins a new reply.
AgentEndEvent — agent finishes a reply.
ExceedMaxItersEvent — agent hit the max reasoning-acting iteration limit.
RequestStopEvent — early-stop request raised by middleware or a tool.
Text streaming events
Text streaming events
TextBlockStartEvent — a new text block begins.
TextBlockDeltaEvent — incremental text content arrives.
TextBlockEndEvent — text block completes.
Thinking streaming events
Thinking streaming events
ThinkingBlockStartEvent / ThinkingBlockDeltaEvent / ThinkingBlockEndEvent — same shape as the text streaming events; specific to the model’s chain of thought. Its
blockId has the same reply-scoped correlation-key semantics.Data streaming events
Data streaming events
DataBlockStartEvent / DataBlockDeltaEvent / DataBlockEndEvent — same shape as the text streaming events, carrying images / audio / video binary data:
DataBlockStartEvent:getMediaType()returns the MIME type (e.g."image/png").DataBlockDeltaEvent:getData()returns incremental base64-encoded data.
Tool-call streaming events
Tool-call streaming events
ToolCallStartEvent — agent begins a tool call.
ToolCallDeltaEvent — incremental tool-call arguments arrive;
getDelta() returns a JSON fragment.ToolCallEndEvent — tool-call arguments complete.Tool-result streaming events
Tool-result streaming events
ToolResultStartEvent — tool starts executing (carries
toolCallId, toolCallName).ToolResultTextDeltaEvent — incremental text output from the tool; getDelta() returns a text fragment.ToolResultDataDeltaEvent — incremental binary output from the tool; similar to DataBlockDeltaEvent with mediaType / data / url.ToolResultEndEvent — tool completes.Model-call events
Model-call events
ModelCallStartEvent — model API call starts (carries
modelName).ModelCallEndEvent — model API call completes (carries inputTokens / outputTokens).Human-in-the-loop events
Human-in-the-loop events
RequireUserConfirmEvent — agent pauses for user confirmation.
RequireExternalExecutionEvent — agent pauses for external execution.
UserConfirmResultEvent — emitted when a later
call() resumes a paused permission HITL request.
It carries one or more ConfirmResults, and its replyId matches the earlier RequireUserConfirmEvent.ExternalExecutionResultEvent — emitted when a later
call() resumes a paused external-execution request.
It carries one or more ToolResultBlocks, and its replyId matches the earlier RequireExternalExecutionEvent.AllToolsDeniedEvent — the user denied all tool calls from the most recent reasoning step via HITL confirmation. This event is emitted through the
onActing middleware chain, allowing middlewares to emit a RequestStopEvent to stop the agent. If no middleware handles it, the agent continues to the next reasoning iteration (backward compatible).Subagent events
Subagent events
SubagentExposedEvent — a subagent spawned via
agent_spawn(expose_to_user=true) has been exposed as a user-addressable entry point. SSE / streaming consumers can use this to render a new conversation entry in the UI.Reconstructing messages from events
Events and messages are not separate worlds — they are two views of the same data. The event stream fromstreamEvents can be aggregated by replyId / blockId / toolCallId to reconstruct a complete AssistantMessage, ensuring the final message state is fully recoverable from events alone.
See agentscope-core’s agent/StreamingHook.java and agentscope-examples/documentation/.../streaming/AgentEventStreamExample.java for the standard pattern of grouping by block ID and accumulating content with Reactor operators.
Example: streaming UI
A typical streaming UI loop (a Spring WebFlux SSE form is shown instreaming/StreamingWebExample.java):
Further reading
Agent
How agents emit events and messages in the ReAct loop
Context
How messages are stored and persisted