Implementation:OpenHands OpenHands SaasNestedConversationManager Maybe Start Agent Loop
| Knowledge Sources | |
|---|---|
| Domains | Distributed_Systems, Conversation_Management |
| Last Updated | 2026-02-11 21:00 GMT |
Overview
Concrete tool for starting an agent conversation loop with distributed concurrency control, provided by the OpenHands enterprise conversation management layer.
Description
The maybe_start_agent_loop method is the primary entry point for initiating a conversation within the SaaS nested architecture. It orchestrates a multi-step process: acquiring a distributed lock via Redis SET NX to claim conversation ownership, provisioning a remote runtime container, refreshing authentication tokens, pushing configuration to the nested server, and finally starting the agent loop. The method returns an AgentLoopInfo object describing the running loop. If the conversation is already owned by the current node, it returns the existing loop information rather than spawning a duplicate.
The method belongs to the SaasNestedConversationManager dataclass, which extends ConversationManager and holds references to the Socket.IO server, application configuration, server configuration, file store, and event retrieval services.
Usage
Call this method when a user initiates a new conversation or when a conversation needs to be resumed. It is typically invoked from the WebSocket event handler when the first user message arrives. The method is safe to call concurrently from multiple nodes because of the Redis-backed distributed lock.
Code Reference
Source Location
- Repository: OpenHands
- File:
enterprise/server/saas_nested_conversation_manager.py - Lines: L191-236
Signature
async def maybe_start_agent_loop(
self,
sid: str,
settings: Settings,
user_id: str,
initial_user_msg: MessageAction | None = None,
replay_json: str | None = None,
) -> AgentLoopInfo
Import
from enterprise.server.saas_nested_conversation_manager import SaasNestedConversationManager
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| sid | str | Yes | The unique session/conversation identifier used as the lock key and runtime label. |
| settings | Settings | Yes | Application settings including LLM configuration, agent parameters, and provider tokens. |
| user_id | str | Yes | The authenticated user identifier for scoping credentials and permissions. |
| initial_user_msg | None | No | The first user message to inject into the conversation after the agent loop starts. If None, the loop starts without an initial prompt. |
| replay_json | None | No | A JSON string containing a previously recorded event stream to replay into the new conversation. |
Outputs
| Name | Type | Description |
|---|---|---|
| return | AgentLoopInfo | A dataclass containing the agent loop metadata: the runtime URL, conversation ID, and status information needed by callers to communicate with the running loop. |
Usage Examples
Basic Usage
from enterprise.server.saas_nested_conversation_manager import SaasNestedConversationManager
from openhands.events.action import MessageAction
# Assuming manager is already constructed with sio, config, server_config, file_store, event_retrieval
manager: SaasNestedConversationManager = ...
# Start a new conversation with an initial user message
initial_msg = MessageAction(content="Help me refactor the authentication module.")
loop_info = await manager.maybe_start_agent_loop(
sid="conv_abc123",
settings=current_settings,
user_id="user_42",
initial_user_msg=initial_msg,
)
print(f"Agent loop started: {loop_info}")
Resuming a Conversation with Replay
import json
# Replay a previously recorded event stream
replay_events = json.dumps(recorded_event_list)
loop_info = await manager.maybe_start_agent_loop(
sid="conv_abc123",
settings=current_settings,
user_id="user_42",
replay_json=replay_events,
)