openhands-agent-server 1.7.3__py3-none-any.whl → 1.7.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import importlib
2
3
  import logging
3
4
  from dataclasses import dataclass, field
4
5
  from pathlib import Path
@@ -406,8 +407,6 @@ class ConversationService:
406
407
  )
407
408
  # Dynamically register tools when resuming persisted conversations
408
409
  if stored.tool_module_qualnames:
409
- import importlib
410
-
411
410
  for (
412
411
  tool_name,
413
412
  module_qualname,
@@ -17,7 +17,10 @@ from uuid import UUID
17
17
 
18
18
  from pydantic import BaseModel, SecretStr, TypeAdapter
19
19
 
20
- from openhands.sdk.utils.models import DiscriminatedUnionMixin
20
+ from openhands.sdk.utils.models import (
21
+ DiscriminatedUnionMixin,
22
+ get_known_concrete_subclasses,
23
+ )
21
24
 
22
25
 
23
26
  # Define Missing type
@@ -268,6 +271,26 @@ class UnionEnvParser(EnvParser):
268
271
  output.write("\n")
269
272
 
270
273
 
274
+ @dataclass
275
+ class DiscriminatedUnionEnvParser(EnvParser):
276
+ parsers: dict[str, EnvParser]
277
+
278
+ def from_env(self, key: str) -> JsonType:
279
+ kind = os.environ.get(f"{key}_KIND", MISSING)
280
+ if kind is MISSING:
281
+ return MISSING
282
+ assert isinstance(kind, str)
283
+ parser = self.parsers[kind]
284
+ parser_result = parser.from_env(key)
285
+ assert isinstance(parser_result, dict)
286
+ parser_result["kind"] = kind
287
+ return parser_result
288
+
289
+ def to_env(self, key: str, value: Any, output: IO):
290
+ parser = self.parsers[value.kind]
291
+ parser.to_env(key, value, output)
292
+
293
+
271
294
  @dataclass
272
295
  class DelayedParser(EnvParser):
273
296
  """Delayed parser for circular dependencies"""
@@ -341,9 +364,16 @@ def get_env_parser(target_type: type, parsers: dict[type, EnvParser]) -> EnvPars
341
364
  if issubclass(target_type, DiscriminatedUnionMixin) and (
342
365
  inspect.isabstract(target_type) or ABC in target_type.__bases__
343
366
  ):
344
- serializable_type = target_type.get_serializable_type()
345
- if serializable_type != target_type:
346
- return get_env_parser(target_type.get_serializable_type(), parsers)
367
+ delayed = DelayedParser()
368
+ parsers[target_type] = delayed # Prevent circular dependency
369
+ sub_parsers = {
370
+ c.__name__: get_env_parser(c, parsers)
371
+ for c in get_known_concrete_subclasses(target_type)
372
+ }
373
+ parser = DiscriminatedUnionEnvParser(sub_parsers)
374
+ delayed.parser = parser
375
+ parsers[target_type] = parser
376
+ return parser
347
377
  if issubclass(target_type, BaseModel): # type: ignore
348
378
  delayed = DelayedParser()
349
379
  parsers[target_type] = delayed # Prevent circular dependency
@@ -19,6 +19,7 @@ from openhands.sdk.conversation.state import (
19
19
  ConversationExecutionStatus,
20
20
  ConversationState,
21
21
  )
22
+ from openhands.sdk.event import AgentErrorEvent
22
23
  from openhands.sdk.event.conversation_state import ConversationStateUpdateEvent
23
24
  from openhands.sdk.event.llm_completion_log import LLMCompletionLogEvent
24
25
  from openhands.sdk.security.analyzer import SecurityAnalyzerBase
@@ -439,6 +440,26 @@ class EventService:
439
440
  # Setup stats streaming for remote execution
440
441
  self._setup_stats_streaming(self._conversation.agent)
441
442
 
443
+ # If the execution_status was "running" while serialized, then the
444
+ # conversation can't possibly be running - something is wrong
445
+ state = self._conversation.state
446
+ if state.execution_status == ConversationExecutionStatus.RUNNING:
447
+ state.execution_status = ConversationExecutionStatus.ERROR
448
+ # Add error event for the first unmatched action to inform the agent
449
+ unmatched_actions = ConversationState.get_unmatched_actions(state.events)
450
+ if unmatched_actions:
451
+ first_action = unmatched_actions[0]
452
+ error_event = AgentErrorEvent(
453
+ tool_name=first_action.tool_name,
454
+ tool_call_id=first_action.tool_call_id,
455
+ error=(
456
+ "A restart occurred while this tool was in progress. "
457
+ "This may indicate a fatal memory error or system crash. "
458
+ "The tool execution was interrupted and did not complete."
459
+ ),
460
+ )
461
+ self._conversation._on_event(error_event)
462
+
442
463
  # Publish initial state update
443
464
  await self._publish_state_update()
444
465
 
@@ -139,7 +139,7 @@ async def bash_events_socket(
139
139
 
140
140
  async def _send_event(event: Event, websocket: WebSocket):
141
141
  try:
142
- dumped = event.model_dump()
142
+ dumped = event.model_dump(mode="json")
143
143
  await websocket.send_json(dumped)
144
144
  except Exception:
145
145
  logger.exception("error_sending_event:{event}", stack_info=True)
@@ -157,7 +157,7 @@ class _WebSocketSubscriber(Subscriber):
157
157
 
158
158
  async def _send_bash_event(event: BashEventBase, websocket: WebSocket):
159
159
  try:
160
- dumped = event.model_dump()
160
+ dumped = event.model_dump(mode="json")
161
161
  await websocket.send_json(dumped)
162
162
  except Exception:
163
163
  logger.exception("error_sending_event:{event}", stack_info=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-agent-server
3
- Version: 1.7.3
3
+ Version: 1.7.4
4
4
  Summary: OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: aiosqlite>=0.19
@@ -5,13 +5,13 @@ openhands/agent_server/bash_router.py,sha256=9aKNxzdKSlKoYJ3ngvdf4rjv1_iNNmpRoZk
5
5
  openhands/agent_server/bash_service.py,sha256=QgTSyQoxlk52BnZuo35xlX7u7-3xs5BvvaKU3AEva_w,14083
6
6
  openhands/agent_server/config.py,sha256=EQdoN39cOeI63zEpAQ7WyhMpo-9tHNTsLMalU0d4kHw,5479
7
7
  openhands/agent_server/conversation_router.py,sha256=lz-dnfPXrVBiGZ9GhYqfteCWJ4pq7AcnWqxsKWwCfc0,11178
8
- openhands/agent_server/conversation_service.py,sha256=g_DKR9NJo5RjSnlITMxKUctwUyTN5tLp6sD8Q1N0tsM,27079
8
+ openhands/agent_server/conversation_service.py,sha256=Oj8IBSY9ZYbduOOBatd3I0H_kSyH7xi22Y_MyhfL5Tk,27058
9
9
  openhands/agent_server/dependencies.py,sha256=H3zyOc8uthpXseB3E7rWNccKIj7PlyfcgCYwFvmFq4c,2629
10
10
  openhands/agent_server/desktop_router.py,sha256=OaCmevO33eUo3jTwiXBmQ3uT3ONu4-tqgBfYpZWrHSA,1349
11
11
  openhands/agent_server/desktop_service.py,sha256=iCwQJXK4DvGuBXKOQ1oko60wXkf_pYHCubOzBsd2k60,7415
12
- openhands/agent_server/env_parser.py,sha256=iVoxrTy2VzGZAzZq7ODkOZ-iV5Qw-et6Xd0ojWeMzTk,14050
12
+ openhands/agent_server/env_parser.py,sha256=NBa5p_JGYJVMMdCJJ_jicW1iAGS6h8AG_HVlcQ2dxaY,14929
13
13
  openhands/agent_server/event_router.py,sha256=XM46zcqPOXStISfihzsPXPfsW_23E50brmBHk04ncVI,6156
14
- openhands/agent_server/event_service.py,sha256=LblAF94qrZGBsAce4HUjlCn4BT5RHdWY8SzGqOTGJKY,24023
14
+ openhands/agent_server/event_service.py,sha256=N-RKeXox4dMsZv-8brwYRtt5p2axfznPfd6C-8TKXk4,25189
15
15
  openhands/agent_server/file_router.py,sha256=ysDjIKzDNbi7m95JrH6kP6BYcBhTJhTpJVMkNtYVYhs,4011
16
16
  openhands/agent_server/git_router.py,sha256=g0cVeyJ_mUAuieZ3bbTl5Xvm94FnNwRt07iNBASiXgU,844
17
17
  openhands/agent_server/logging_config.py,sha256=DPPxIl1tUVGiui-JVSKgs73KXPFfDNX2ivGuZSkbLe4,1832
@@ -21,7 +21,7 @@ openhands/agent_server/openapi.py,sha256=RJWaOnM9NjzrH-fJi3PoIBv5d0sH5z8zZTdvYzS
21
21
  openhands/agent_server/pub_sub.py,sha256=yPB84Wub7A2uwUWsW_grbxomWmKaWyGuo6dVNUzg1FU,2755
22
22
  openhands/agent_server/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  openhands/agent_server/server_details_router.py,sha256=LCa0NQ3SOw-IgJh3rDJL5GolFOpZcX_-XEbDLHF8dN4,950
24
- openhands/agent_server/sockets.py,sha256=WFx77Qp2FUStwdpLyONPENX3e_874IqkLjxzlNPb3e4,6584
24
+ openhands/agent_server/sockets.py,sha256=pWjuRpWeqPw-T5svqb5mO7JCAVcCptQyHxc6lDYHhvY,6606
25
25
  openhands/agent_server/tool_preload_service.py,sha256=2QuFyn7jC4Ifq2aUhs9j8876wSBdY0eeoLo4qEVi-yA,2341
26
26
  openhands/agent_server/tool_router.py,sha256=vM_9UKUzfChLK9B9Z3DL4VtKNdDw4w635knu9N36y0c,676
27
27
  openhands/agent_server/utils.py,sha256=ajivE_kGCJ9qUhF9H3Qu7DUKg7uDvDQk16JcO3XntEs,1926
@@ -32,8 +32,8 @@ openhands/agent_server/docker/build.py,sha256=Egsge_yIVCeiJ_gvva6VyPeQtOp0WjZFsW
32
32
  openhands/agent_server/docker/wallpaper.svg,sha256=FR2g_b5mzz0x5EvRTKO93ASnWPagAyeS9RI3vRQBAsw,11532
33
33
  openhands/agent_server/vscode_extensions/openhands-settings/extension.js,sha256=xoCKZ6YXlzlTWnTC52HuzX0sn9s77Vma-47WgEibO88,858
34
34
  openhands/agent_server/vscode_extensions/openhands-settings/package.json,sha256=eCkuBBYEVArEjpp7c_m0H207OCLEygZhBLUEkeFNWOg,289
35
- openhands_agent_server-1.7.3.dist-info/METADATA,sha256=vmWo6337iN8ugke45vPY9Z7Lb3N44-lRwpCXkOdj7tI,468
36
- openhands_agent_server-1.7.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
- openhands_agent_server-1.7.3.dist-info/entry_points.txt,sha256=uLQzPhqDqe85Dy9DvPiBE2CeqkwCryggr1Ty_mq65NA,70
38
- openhands_agent_server-1.7.3.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
39
- openhands_agent_server-1.7.3.dist-info/RECORD,,
35
+ openhands_agent_server-1.7.4.dist-info/METADATA,sha256=vORux5iXdgAuW3ktRWyF3A5hez9vp_LC-__UCvYNG_I,468
36
+ openhands_agent_server-1.7.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
+ openhands_agent_server-1.7.4.dist-info/entry_points.txt,sha256=uLQzPhqDqe85Dy9DvPiBE2CeqkwCryggr1Ty_mq65NA,70
38
+ openhands_agent_server-1.7.4.dist-info/top_level.txt,sha256=jHgVu9I0Blam8BXFgedoGKfglPF8XvW1TsJFIjcgP4E,10
39
+ openhands_agent_server-1.7.4.dist-info/RECORD,,