Skip to content

Commit 0b8d357

Browse files
authored
Add event synchronously (#2700)
* add to event stream sync * remove async from tests
1 parent 1b10e2b commit 0b8d357

File tree

7 files changed

+31
-37
lines changed

7 files changed

+31
-37
lines changed

opendevin/controller/agent_controller.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ async def report_error(self, message: str, exception: Exception | None = None):
122122
self.state.last_error = message
123123
if exception:
124124
self.state.last_error += f': {exception}'
125-
await self.event_stream.add_event(ErrorObservation(message), EventSource.AGENT)
125+
self.event_stream.add_event(ErrorObservation(message), EventSource.AGENT)
126126

127127
async def add_history(self, action: Action, observation: Observation):
128128
if isinstance(action, NullAction) and isinstance(observation, NullObservation):
@@ -211,7 +211,7 @@ async def set_agent_state_to(self, new_state: AgentState):
211211
if new_state == AgentState.STOPPED or new_state == AgentState.ERROR:
212212
self.reset_task()
213213

214-
await self.event_stream.add_event(
214+
self.event_stream.add_event(
215215
AgentStateChangedObservation('', self.state.agent_state), EventSource.AGENT
216216
)
217217

@@ -221,8 +221,6 @@ async def set_agent_state_to(self, new_state: AgentState):
221221

222222
def get_agent_state(self):
223223
"""Returns the current state of the agent task."""
224-
if self.delegate is not None:
225-
return self.delegate.get_agent_state()
226224
return self.state.agent_state
227225

228226
async def start_delegate(self, action: AgentDelegateAction):
@@ -301,7 +299,7 @@ async def _step(self):
301299
# clean up delegate status
302300
self.delegate = None
303301
self.delegateAction = None
304-
await self.event_stream.add_event(obs, EventSource.AGENT)
302+
self.event_stream.add_event(obs, EventSource.AGENT)
305303
return
306304

307305
logger.info(
@@ -358,7 +356,7 @@ async def _step(self):
358356
await self.add_history(action, NullObservation(''))
359357

360358
if not isinstance(action, NullAction):
361-
await self.event_stream.add_event(action, EventSource.AGENT)
359+
self.event_stream.add_event(action, EventSource.AGENT)
362360

363361
await self.update_state_after_step()
364362

opendevin/core/logger.py

+2
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ def get_console_handler():
114114
"""
115115
console_handler = logging.StreamHandler()
116116
console_handler.setLevel(logging.INFO)
117+
if config.debug:
118+
console_handler.setLevel(logging.DEBUG)
117119
console_handler.setFormatter(console_formatter)
118120
return console_handler
119121

opendevin/core/main.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,15 @@ async def run_agent_controller(
100100
# start event is a MessageAction with the task, either resumed or new
101101
if config.enable_cli_session and initial_state is not None:
102102
# we're resuming the previous session
103-
await event_stream.add_event(
103+
event_stream.add_event(
104104
MessageAction(
105105
content="Let's get back on track. If you experienced errors before, do NOT resume your task. Ask me about it."
106106
),
107107
EventSource.USER,
108108
)
109109
elif initial_state is None:
110110
# init with the provided task
111-
await event_stream.add_event(MessageAction(content=task_str), EventSource.USER)
111+
event_stream.add_event(MessageAction(content=task_str), EventSource.USER)
112112

113113
async def on_event(event: Event):
114114
if isinstance(event, AgentStateChangedObservation):
@@ -120,10 +120,10 @@ async def on_event(event: Event):
120120
else:
121121
message = fake_user_response_fn(controller.get_state())
122122
action = MessageAction(content=message)
123-
await event_stream.add_event(action, EventSource.USER)
123+
event_stream.add_event(action, EventSource.USER)
124124

125125
event_stream.subscribe(EventStreamSubscriber.MAIN, on_event)
126-
while controller.get_agent_state() not in [
126+
while controller.state.agent_state not in [
127127
AgentState.FINISHED,
128128
AgentState.REJECTED,
129129
AgentState.ERROR,

opendevin/events/stream.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import json
3+
import threading
34
from datetime import datetime
45
from enum import Enum
56
from typing import Callable, Iterable
@@ -25,15 +26,15 @@ class EventStream:
2526
# when there are agent delegates
2627
_subscribers: dict[str, list[Callable]]
2728
_cur_id: int
28-
_lock: asyncio.Lock
29+
_lock: threading.Lock
2930
_file_store: FileStore
3031

3132
def __init__(self, sid: str):
3233
self.sid = sid
3334
self._file_store = get_file_store()
3435
self._subscribers = {}
3536
self._cur_id = 0
36-
self._lock = asyncio.Lock()
37+
self._lock = threading.Lock()
3738
self._reinitialize_from_file_store()
3839

3940
def _reinitialize_from_file_store(self):
@@ -93,12 +94,11 @@ def unsubscribe(self, id: EventStreamSubscriber):
9394
if len(self._subscribers[id]) == 0:
9495
del self._subscribers[id]
9596

96-
# TODO: make this not async
97-
async def add_event(self, event: Event, source: EventSource):
98-
logger.debug(f'Adding event {event} from {source}')
99-
async with self._lock:
100-
event._id = self._cur_id # type: ignore[attr-defined]
97+
def add_event(self, event: Event, source: EventSource):
98+
with self._lock:
99+
event._id = self._cur_id # type: ignore [attr-defined]
101100
self._cur_id += 1
101+
logger.debug(f'Adding {type(event).__name__} id={event.id} from {source.name}')
102102
event._timestamp = datetime.now() # type: ignore[attr-defined]
103103
event._source = source # type: ignore[attr-defined]
104104
data = event_to_dict(event)
@@ -108,5 +108,4 @@ async def add_event(self, event: Event, source: EventSource):
108108
)
109109
for stack in self._subscribers.values():
110110
callback = stack[-1]
111-
logger.debug(f'Notifying subscriber {callback} of event {event}')
112-
await callback(event)
111+
asyncio.create_task(callback(event))

opendevin/runtime/runtime.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ async def on_event(self, event: Event) -> None:
114114
observation = await self.run_action(event)
115115
observation._cause = event.id # type: ignore[attr-defined]
116116
source = event.source if event.source else EventSource.AGENT
117-
await self.event_stream.add_event(observation, source)
117+
self.event_stream.add_event(observation, source)
118118

119119
async def run_action(self, action: Action) -> Observation:
120120
"""
@@ -149,7 +149,7 @@ async def submit_background_obs(self):
149149
for _id, cmd in self.sandbox.background_commands.items():
150150
output = cmd.read_logs()
151151
if output:
152-
await self.event_stream.add_event(
152+
self.event_stream.add_event(
153153
CmdOutputObservation(
154154
content=output, command_id=_id, command=cmd.command
155155
),

opendevin/server/session/session.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ async def loop_recv(self):
6161
logger.exception('Error in loop_recv: %s', e)
6262

6363
async def _initialize_agent(self, data: dict):
64-
await self.agent_session.event_stream.add_event(
64+
self.agent_session.event_stream.add_event(
6565
ChangeAgentStateAction(AgentState.LOADING), EventSource.USER
6666
)
67-
await self.agent_session.event_stream.add_event(
67+
self.agent_session.event_stream.add_event(
6868
AgentStateChangedObservation('', AgentState.LOADING), EventSource.AGENT
6969
)
7070
try:
@@ -75,7 +75,7 @@ async def _initialize_agent(self, data: dict):
7575
f'Error creating controller. Please check Docker is running and visit `{TROUBLESHOOTING_URL}` for more debugging information..'
7676
)
7777
return
78-
await self.agent_session.event_stream.add_event(
78+
self.agent_session.event_stream.add_event(
7979
ChangeAgentStateAction(AgentState.INIT), EventSource.USER
8080
)
8181

@@ -102,7 +102,7 @@ async def dispatch(self, data: dict):
102102
await self._initialize_agent(data)
103103
return
104104
event = event_from_dict(data.copy())
105-
await self.agent_session.event_stream.add_event(event, EventSource.USER)
105+
self.agent_session.event_stream.add_event(event, EventSource.USER)
106106

107107
async def send(self, data: dict[str, object]) -> bool:
108108
try:

tests/unit/test_event_stream.py

+7-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import json
22

3-
import pytest
4-
53
from opendevin.events import EventSource, EventStream
64
from opendevin.events.action import NullAction
75
from opendevin.events.observation import NullObservation
@@ -11,17 +9,15 @@ def collect_events(stream):
119
return [event for event in stream.get_events()]
1210

1311

14-
@pytest.mark.asyncio
15-
async def test_basic_flow():
12+
def test_basic_flow():
1613
stream = EventStream('abc')
17-
await stream.add_event(NullAction(), EventSource.AGENT)
14+
stream.add_event(NullAction(), EventSource.AGENT)
1815
assert len(collect_events(stream)) == 1
1916

2017

21-
@pytest.mark.asyncio
22-
async def test_stream_storage():
18+
def test_stream_storage():
2319
stream = EventStream('def')
24-
await stream.add_event(NullObservation(''), EventSource.AGENT)
20+
stream.add_event(NullObservation(''), EventSource.AGENT)
2521
assert len(collect_events(stream)) == 1
2622
content = stream._file_store.read('sessions/def/events/0.json')
2723
assert content is not None
@@ -38,11 +34,10 @@ async def test_stream_storage():
3834
}
3935

4036

41-
@pytest.mark.asyncio
42-
async def test_rehydration():
37+
def test_rehydration():
4338
stream1 = EventStream('es1')
44-
await stream1.add_event(NullObservation('obs1'), EventSource.AGENT)
45-
await stream1.add_event(NullObservation('obs2'), EventSource.AGENT)
39+
stream1.add_event(NullObservation('obs1'), EventSource.AGENT)
40+
stream1.add_event(NullObservation('obs2'), EventSource.AGENT)
4641
assert len(collect_events(stream1)) == 2
4742

4843
stream2 = EventStream('es2')

0 commit comments

Comments
 (0)