Skip to content

Commit 21e912d

Browse files
Feat remove redis (#6278)
Co-authored-by: openhands <openhands@all-hands.dev>
1 parent 0dd9b95 commit 21e912d

15 files changed

+573
-331
lines changed

openhands/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The key classes in OpenHands are:
2020
* Sandbox: the part of the runtime responsible for running commands, e.g. inside of Docker
2121
* Server: brokers OpenHands sessions over HTTP, e.g. to drive the frontend
2222
* Session: holds a single EventStream, a single AgentController, and a single Runtime. Generally represents a single task (but potentially including several user prompts)
23-
* SessionManager: keeps a list of active sessions, and ensures requests are routed to the correct Session
23+
* ConversationManager: keeps a list of active sessions, and ensures requests are routed to the correct Session
2424

2525
## Control Flow
2626
Here's the basic loop (in pseudocode) that drives agents.

openhands/server/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ The `agent_session.py` file contains the `AgentSession` class, which manages the
125125
- Handling security analysis
126126
- Managing the event stream
127127

128-
### 3. session/manager.py
128+
### 3. session/conversation_manager/conversation_manager.py
129129

130-
The `manager.py` file defines the `SessionManager` class, which is responsible for managing multiple client sessions. Key features include:
130+
The `conversation_manager.py` file defines the `ConversationManager` class, which is responsible for managing multiple client conversations. Key features include:
131131

132-
- Adding and restarting sessions
133-
- Sending messages to specific sessions
134-
- Cleaning up inactive sessions
132+
- Adding and restarting conversations
133+
- Sending messages to specific conversations
134+
- Cleaning up inactive conversations
135135

136136
### 4. listen.py
137137

@@ -148,7 +148,7 @@ The `listen.py` file is the main server file that sets up the FastAPI applicatio
148148
1. **Server Initialization**:
149149
- The FastAPI application is created and configured in `listen.py`.
150150
- CORS middleware and static file serving are set up.
151-
- The `SessionManager` is initialized.
151+
- The `ConversationManager` is initialized.
152152

153153
2. **Client Connection**:
154154
- When a client connects via WebSocket, a new `Session` is created or an existing one is restarted.
@@ -173,7 +173,7 @@ The `listen.py` file is the main server file that sets up the FastAPI applicatio
173173
- Security-related API requests are forwarded to the security analyzer.
174174

175175
7. **Session Management**:
176-
- The `SessionManager` periodically cleans up inactive sessions.
176+
- The `ConversationManager` periodically cleans up inactive sessions.
177177
- It also handles sending messages to specific sessions when needed.
178178

179179
8. **API Endpoints**:

openhands/server/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
from openhands.server.routes.security import app as security_api_router
2222
from openhands.server.routes.settings import app as settings_router
2323
from openhands.server.routes.trajectory import app as trajectory_router
24-
from openhands.server.shared import openhands_config, session_manager
24+
from openhands.server.shared import conversation_manager, openhands_config
2525

2626

2727
@asynccontextmanager
2828
async def _lifespan(app: FastAPI):
29-
async with session_manager:
29+
async with conversation_manager:
3030
yield
3131

3232

openhands/server/config/openhands_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class OpenhandsConfig(OpenhandsConfigInterface):
2525
conversation_store_class: str = (
2626
'openhands.storage.conversation.file_conversation_store.FileConversationStore'
2727
)
28+
conversation_manager_class: str = 'openhands.server.conversation_manager.standalone_conversation_manager.StandaloneConversationManager'
2829

2930
def verify_config(self):
3031
if self.config_cls:
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
from __future__ import annotations
2+
3+
from abc import ABC, abstractmethod
4+
5+
import socketio
6+
7+
from openhands.core.config import AppConfig
8+
from openhands.events.stream import EventStream
9+
from openhands.server.session.conversation import Conversation
10+
from openhands.server.settings import Settings
11+
from openhands.storage.files import FileStore
12+
13+
14+
class ConversationManager(ABC):
15+
"""Abstract base class for managing conversations in OpenHands.
16+
17+
This class defines the interface for managing conversations, whether in standalone
18+
or clustered mode. It handles the lifecycle of conversations, including creation,
19+
attachment, detachment, and cleanup.
20+
"""
21+
22+
sio: socketio.AsyncServer
23+
config: AppConfig
24+
file_store: FileStore
25+
26+
@abstractmethod
27+
async def __aenter__(self):
28+
"""Initialize the conversation manager."""
29+
30+
@abstractmethod
31+
async def __aexit__(self, exc_type, exc_value, traceback):
32+
"""Clean up the conversation manager."""
33+
34+
@abstractmethod
35+
async def attach_to_conversation(self, sid: str) -> Conversation | None:
36+
"""Attach to an existing conversation or create a new one."""
37+
38+
@abstractmethod
39+
async def detach_from_conversation(self, conversation: Conversation):
40+
"""Detach from a conversation."""
41+
42+
@abstractmethod
43+
async def join_conversation(
44+
self, sid: str, connection_id: str, settings: Settings, user_id: str | None
45+
) -> EventStream | None:
46+
"""Join a conversation and return its event stream."""
47+
48+
async def is_agent_loop_running(self, sid: str) -> bool:
49+
"""Check if an agent loop is running for the given session ID."""
50+
sids = await self.get_running_agent_loops(filter_to_sids={sid})
51+
return bool(sids)
52+
53+
@abstractmethod
54+
async def get_running_agent_loops(
55+
self, user_id: str | None = None, filter_to_sids: set[str] | None = None
56+
) -> set[str]:
57+
"""Get all running agent loops, optionally filtered by user ID and session IDs."""
58+
59+
@abstractmethod
60+
async def get_connections(
61+
self, user_id: str | None = None, filter_to_sids: set[str] | None = None
62+
) -> dict[str, str]:
63+
"""Get all connections, optionally filtered by user ID and session IDs."""
64+
65+
@abstractmethod
66+
async def maybe_start_agent_loop(
67+
self,
68+
sid: str,
69+
settings: Settings,
70+
user_id: str | None,
71+
initial_user_msg: str | None = None,
72+
) -> EventStream:
73+
"""Start an event loop if one is not already running"""
74+
75+
@abstractmethod
76+
async def send_to_event_stream(self, connection_id: str, data: dict):
77+
"""Send data to an event stream."""
78+
79+
@abstractmethod
80+
async def disconnect_from_session(self, connection_id: str):
81+
"""Disconnect from a session."""
82+
83+
@abstractmethod
84+
async def close_session(self, sid: str):
85+
"""Close a session."""
86+
87+
@classmethod
88+
@abstractmethod
89+
def get_instance(
90+
cls,
91+
sio: socketio.AsyncServer,
92+
config: AppConfig,
93+
file_store: FileStore,
94+
) -> ConversationManager:
95+
"""Get a store for the user represented by the token given"""

0 commit comments

Comments
 (0)