openhands-agent-server 1.7.3__tar.gz → 1.8.0__tar.gz

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.
Files changed (43) hide show
  1. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/PKG-INFO +1 -1
  2. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/conversation_service.py +1 -2
  3. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/env_parser.py +34 -4
  4. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/event_service.py +21 -0
  5. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/sockets.py +2 -2
  6. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands_agent_server.egg-info/PKG-INFO +1 -1
  7. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/pyproject.toml +1 -1
  8. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/__init__.py +0 -0
  9. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/__main__.py +0 -0
  10. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/api.py +0 -0
  11. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/bash_router.py +0 -0
  12. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/bash_service.py +0 -0
  13. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/config.py +0 -0
  14. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/conversation_router.py +0 -0
  15. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/dependencies.py +0 -0
  16. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/desktop_router.py +0 -0
  17. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/desktop_service.py +0 -0
  18. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/docker/Dockerfile +0 -0
  19. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/docker/build.py +0 -0
  20. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/docker/wallpaper.svg +0 -0
  21. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/event_router.py +0 -0
  22. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/file_router.py +0 -0
  23. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/git_router.py +0 -0
  24. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/logging_config.py +0 -0
  25. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/middleware.py +0 -0
  26. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/models.py +0 -0
  27. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/openapi.py +0 -0
  28. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/pub_sub.py +0 -0
  29. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/py.typed +0 -0
  30. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/server_details_router.py +0 -0
  31. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/tool_preload_service.py +0 -0
  32. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/tool_router.py +0 -0
  33. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/utils.py +0 -0
  34. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/vscode_extensions/openhands-settings/extension.js +0 -0
  35. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/vscode_extensions/openhands-settings/package.json +0 -0
  36. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/vscode_router.py +0 -0
  37. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands/agent_server/vscode_service.py +0 -0
  38. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands_agent_server.egg-info/SOURCES.txt +0 -0
  39. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands_agent_server.egg-info/dependency_links.txt +0 -0
  40. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands_agent_server.egg-info/entry_points.txt +0 -0
  41. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands_agent_server.egg-info/requires.txt +0 -0
  42. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/openhands_agent_server.egg-info/top_level.txt +0 -0
  43. {openhands_agent_server-1.7.3 → openhands_agent_server-1.8.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-agent-server
3
- Version: 1.7.3
3
+ Version: 1.8.0
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
@@ -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.8.0
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "openhands-agent-server"
3
- version = "1.7.3"
3
+ version = "1.8.0"
4
4
  description = "OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent"
5
5
 
6
6
  requires-python = ">=3.12"