Documentation Index
Fetch the complete documentation index at: https://docs.openhands.dev/llms.txt
Use this file to discover all available pages before exploring further.
The Event System provides an immutable, type-safe event framework that drives agent execution and state management. Events form an append-only log that serves as both the agent’s memory and the integration point for auxiliary services.
Source: openhands-sdk/openhands/sdk/event/
Core Responsibilities
The Event System has four primary responsibilities:
- Type Safety - Enforce event schemas through Pydantic models
- LLM Integration - Convert events to/from LLM message formats
- Append-Only Log - Maintain immutable event history
- Service Integration - Enable observers to react to event streams
Architecture
Key Components
| Component | Purpose | Design |
|---|
Event | Base event class | Immutable Pydantic model with ID, timestamp, source |
LLMConvertibleEvent | LLM-compatible events | Abstract class with to_llm_message() method |
MessageEvent | Text messages | User or assistant conversational messages with skills |
ActionEvent | Tool calls | Agent tool invocations with thought, reasoning, security risk |
ObservationBaseEvent | Tool response base | Base for all tool call responses |
ObservationEvent | Tool results | Successful tool execution outcomes |
UserRejectObservation | User rejection | User rejected action in confirmation mode |
AgentErrorEvent | Agent errors | Errors from agent/scaffold (not model output) |
SystemPromptEvent | System context | System prompt with tool schemas |
CondensationSummaryEvent | Condenser summary | LLM-convertible summary of forgotten events |
ConversationStateUpdateEvent | State updates | Key-value conversation state changes |
Condensation | Condensation result | Events being forgotten with optional summary |
CondensationRequest | Request compression | Trigger for conversation history compression |
PauseEvent | User pause | User requested pause of agent execution |
Event Types
LLM-Convertible Events
Events that participate in agent reasoning and can be converted to LLM messages:
| Event Type | Source | Content | LLM Role |
|---|
| MessageEvent (user) | user | Text, images | user |
| MessageEvent (agent) | agent | Text reasoning, skills | assistant |
| ActionEvent | agent | Tool call with thought, reasoning, security risk | assistant with tool_calls |
| ObservationEvent | environment | Tool execution result | tool |
| UserRejectObservation | environment | Rejection reason | tool |
| AgentErrorEvent | agent | Error details | tool |
| SystemPromptEvent | agent | System prompt with tool schemas | system |
| CondensationSummaryEvent | environment | Summary of forgotten events | user |
The event system bridges agent events to LLM messages:
Special Handling - Parallel Function Calling:
When multiple ActionEvents share the same llm_response_id (parallel function calling):
- Group all ActionEvents by
llm_response_id
- Combine into single Message with multiple
tool_calls
- Only first event’s
thought, reasoning_content, and thinking_blocks are included
- All subsequent events in the batch have empty thought fields
Example:
ActionEvent(llm_response_id="abc123", thought="Let me check...", tool_call=tool1)
ActionEvent(llm_response_id="abc123", thought=[], tool_call=tool2)
→ Combined into single Message(role="assistant", content="Let me check...", tool_calls=[tool1, tool2])
Internal Events
Events for metadata, control flow, and user actions (not sent to LLM):
| Event Type | Source | Purpose | Key Fields |
|---|
| ConversationStateUpdateEvent | environment | State synchronization | key (field name), value (serialized data) |
| CondensationRequest | environment | Trigger history compression | Signal to condenser when context window exceeded |
| Condensation | environment | Compression result | forgotten_event_ids, summary, summary_offset |
| PauseEvent | user | User pause action | Indicates agent execution was paused by user |
Source Types:
- user: Event originated from user input
- agent: Event generated by agent logic
- environment: Event from system/framework/tools
Component Relationships
How Events Integrate
source vs LLM role
Events often carry two different concepts that are easy to confuse:
Event.source: where the event originated (user, agent, or environment). This is about attribution.
- LLM
role (e.g. Message.role / MessageEvent.llm_message.role): how the event should be represented to the LLM (system, user, assistant, tool). This is about LLM formatting.
These fields are intentionally independent.
Common examples include:
- Observations: tool results are typically
source="environment" and represented to the LLM with role="tool".
- Synthetic framework messages: the SDK may inject feedback or control messages (e.g. from hooks) as
source="environment" while still using an LLM role="user" so the agent reads it as a user-facing instruction.
Do not infer event origin from LLM role. If you need to distinguish real user input from synthetic/framework messages, rely on Event.source (and any explicit metadata fields on the event), not the LLM role.
Relationship Characteristics:
- Agent → Events: Reads history for context, writes actions/messages
- Conversation → Events: Owns and persists event log
- Tools → Events: Create ObservationEvents after execution
- Services → Events: Read-only observers for monitoring, visualization
Error Events: Agent vs Conversation
Two distinct error events exist in the SDK, with different purpose and visibility:
-
AgentErrorEvent
-
ConversationErrorEvent
See Also