Skip to main content
The Conversation component orchestrates agent execution through structured message flows and state management. It serves as the primary interface for interacting with agents, managing their lifecycle from initialization to completion. Source: openhands-sdk/openhands/sdk/conversation/

Core Responsibilities

The Conversation system has four primary responsibilities:
  1. Agent Lifecycle Management - Initialize, run, pause, and terminate agents
  2. State Orchestration - Maintain conversation history, events, and execution status
  3. Workspace Coordination - Bridge agent operations with execution environments
  4. Runtime Services - Provide persistence, monitoring, security, and visualization

Architecture

Key Components

ComponentPurposeDesign
ConversationUnified entrypointReturns correct implementation based on workspace type
LocalConversationLocal executionRuns agent directly in process
RemoteConversationRemote executionDelegates to agent-server via HTTP/WebSocket
ConversationStateState containerPydantic model with validation and serialization
EventLogEvent storageImmutable append-only store with efficient queries

Factory Pattern

The Conversation class automatically selects the correct implementation based on workspace type: Dispatch Logic:
  • Local: String paths or LocalWorkspace → in-process execution
  • Remote: RemoteWorkspace → agent-server via HTTP/WebSocket
This abstraction enables switching deployment modes without code changes—just swap the workspace type.

State Management

State updates follow a two-path pattern depending on the type of change: Two Update Patterns:
  1. State-Only Updates - Modify fields without appending events (e.g., status changes, stat increments)
  2. Event-Based Updates - Append to event log when new messages, actions, or observations occur
Thread Safety:
  • FIFO Lock ensures ordered, atomic updates
  • Callbacks fire after successful commit
  • Read operations never block writes

Execution Models

The conversation system supports two execution models with identical APIs:

Local vs Remote Execution

AspectLocalConversationRemoteConversation
ExecutionIn-processRemote container/server
CommunicationDirect function callsHTTP + WebSocket
State SyncImmediateNetwork serialized
Use CaseDevelopment, CLI toolsProduction, web apps
IsolationProcess-levelContainer-level
Key Insight: Same API surface means switching between local and remote requires only changing workspace type—no code changes.

Auxiliary Services

The conversation system provides pluggable services that operate independently on the event stream:
ServicePurposeArchitecture Pattern
Event LogAppend-only immutable storageEvent sourcing with indexing
PersistenceAuto-save & resumeDebounced writes, incremental events
Stuck DetectionLoop preventionSliding window pattern matching
VisualizationExecution diagramsEvent stream → visual representation
Secret RegistrySecure value storageMemory-only with masked logging
Design Principle: Services read from the event log but never mutate state directly.

Invariants (Normative)

Conversation Factory: Workspace Chooses Implementation

Natural language invariant:
  • Conversation(...) is a factory that returns LocalConversation unless the provided workspace is a RemoteWorkspace.
  • When workspace is remote, persistence_dir must be unset (None).
OCL-like (conceptual):
  • context Conversation::__new__ pre RemoteNoPersistence: workspace.oclIsKindOf(RemoteWorkspace) implies persistence_dir = null

ConversationState: Validated Snapshot + Event Log

Natural language invariants:
  • ConversationState is the only component intended to hold mutable execution status (IDLE, RUNNING, WAITING_FOR_CONFIRMATION, etc.).
  • ConversationState owns persistence (FileStore) and the event store; all other components treat persistence as an implementation detail.

Confirmation Mode Predicate

The SDK exposes a single predicate for confirmation mode:
  • Confirmation mode is active iff state.security_analyzer != None and the confirmation policy is not NeverConfirm.

ask_agent() Must Be Stateless

Natural language invariant (from the public contract):
  • BaseConversation.ask_agent(question) must not append events, mutate execution status, or persist anything. It is safe to call concurrently with run().

Secrets Persistence Requires a Cipher

Natural language invariant:
  • If ConversationState is persisted without a cipher, secret values are redacted and cannot be recovered on restore.
(Implication: use Cipher when persistence is enabled and you expect to resume with secrets intact.)

Component Relationships

How Conversation Interacts

Relationship Characteristics:
  • Conversation → Agent: One-way orchestration, agent reports back via state updates
  • Conversation → Workspace: Configuration only, workspace doesn’t know about conversation
  • Agent → Conversation: Indirect via state events

See Also