openhands-agent-server 1.9.1__tar.gz → 1.11.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 (45) hide show
  1. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/PKG-INFO +1 -1
  2. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/__main__.py +50 -0
  3. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/bash_router.py +9 -0
  4. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/bash_service.py +8 -0
  5. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/conversation_service.py +19 -2
  6. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/desktop_service.py +9 -2
  7. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/docker/Dockerfile +3 -3
  8. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/docker/build.py +2 -2
  9. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/event_service.py +24 -3
  10. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/models.py +24 -1
  11. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/skills_service.py +4 -2
  12. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/vscode_service.py +2 -0
  13. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands_agent_server.egg-info/PKG-INFO +1 -1
  14. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/pyproject.toml +1 -1
  15. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/__init__.py +0 -0
  16. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/api.py +0 -0
  17. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/config.py +0 -0
  18. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/conversation_router.py +0 -0
  19. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/dependencies.py +0 -0
  20. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/desktop_router.py +0 -0
  21. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/docker/wallpaper.svg +0 -0
  22. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/env_parser.py +0 -0
  23. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/event_router.py +0 -0
  24. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/file_router.py +0 -0
  25. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/git_router.py +0 -0
  26. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/logging_config.py +0 -0
  27. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/middleware.py +0 -0
  28. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/openapi.py +0 -0
  29. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/pub_sub.py +0 -0
  30. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/py.typed +0 -0
  31. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/server_details_router.py +0 -0
  32. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/skills_router.py +0 -0
  33. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/sockets.py +0 -0
  34. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/tool_preload_service.py +0 -0
  35. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/tool_router.py +0 -0
  36. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/utils.py +0 -0
  37. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/vscode_extensions/openhands-settings/extension.js +0 -0
  38. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/vscode_extensions/openhands-settings/package.json +0 -0
  39. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands/agent_server/vscode_router.py +0 -0
  40. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands_agent_server.egg-info/SOURCES.txt +0 -0
  41. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands_agent_server.egg-info/dependency_links.txt +0 -0
  42. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands_agent_server.egg-info/entry_points.txt +0 -0
  43. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands_agent_server.egg-info/requires.txt +0 -0
  44. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/openhands_agent_server.egg-info/top_level.txt +0 -0
  45. {openhands_agent_server-1.9.1 → openhands_agent_server-1.11.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-agent-server
3
- Version: 1.9.1
3
+ Version: 1.11.0
4
4
  Summary: OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent
5
5
  Project-URL: Source, https://github.com/OpenHands/software-agent-sdk
6
6
  Project-URL: Homepage, https://github.com/OpenHands/software-agent-sdk
@@ -2,6 +2,7 @@ import argparse
2
2
  import atexit
3
3
  import faulthandler
4
4
  import signal
5
+ import sys
5
6
  from types import FrameType
6
7
 
7
8
  import uvicorn
@@ -14,6 +15,43 @@ from openhands.sdk.logger import DEBUG, get_logger
14
15
  logger = get_logger(__name__)
15
16
 
16
17
 
18
+ def check_browser():
19
+ """Check if browser functionality can render about:blank."""
20
+ executor = None
21
+ try:
22
+ # Register tools to ensure browser tools are available
23
+ from openhands.tools.preset.default import register_default_tools
24
+
25
+ register_default_tools(enable_browser=True)
26
+
27
+ # Import browser components
28
+ from openhands.tools.browser_use.definition import BrowserNavigateAction
29
+ from openhands.tools.browser_use.impl import BrowserToolExecutor
30
+
31
+ # Create executor
32
+ executor = BrowserToolExecutor(headless=True, session_timeout_minutes=2)
33
+
34
+ # Try to navigate to about:blank
35
+ action = BrowserNavigateAction(url="about:blank")
36
+ result = executor(action)
37
+
38
+ # Check if the operation was successful
39
+ if result.is_error:
40
+ print(f"Browser check failed: {str(result.content)}")
41
+ return False
42
+
43
+ print("Browser check passed: Successfully rendered about:blank")
44
+ return True
45
+
46
+ except Exception as e:
47
+ print(f"Browser check failed: {e}")
48
+ return False
49
+ finally:
50
+ # Ensure cleanup happens even if an error occurs
51
+ if executor is not None:
52
+ executor.close()
53
+
54
+
17
55
  class LoggingServer(uvicorn.Server):
18
56
  """Custom uvicorn Server that logs signal handling events.
19
57
 
@@ -67,9 +105,21 @@ def main() -> None:
67
105
  action="store_true",
68
106
  help="Enable auto-reload (disabled by default)",
69
107
  )
108
+ parser.add_argument(
109
+ "--check-browser",
110
+ action="store_true",
111
+ help="Check if browser functionality works and exit",
112
+ )
70
113
 
71
114
  args = parser.parse_args()
72
115
 
116
+ # Handle browser check
117
+ if args.check_browser:
118
+ if check_browser():
119
+ sys.exit(0)
120
+ else:
121
+ sys.exit(1)
122
+
73
123
  print(f"🙌 Starting OpenHands Agent Server on {args.host}:{args.port}")
74
124
  print(f"📖 API docs will be available at http://{args.host}:{args.port}/docs")
75
125
  print(f"🔄 Auto-reload: {'enabled' if args.reload else 'disabled'}")
@@ -36,6 +36,14 @@ async def search_bash_events(
36
36
  command_id__eq: UUID | None = None,
37
37
  timestamp__gte: datetime | None = None,
38
38
  timestamp__lt: datetime | None = None,
39
+ order__gt: Annotated[
40
+ int | None,
41
+ Query(
42
+ title="Filter to events with order greater than this value",
43
+ description="Only returns BashOutput events with order > this value. "
44
+ "Useful for polling to fetch only new events since the last poll.",
45
+ ),
46
+ ] = None,
39
47
  sort_order: BashEventSortOrder = BashEventSortOrder.TIMESTAMP,
40
48
  page_id: Annotated[
41
49
  str | None,
@@ -55,6 +63,7 @@ async def search_bash_events(
55
63
  command_id__eq=command_id__eq,
56
64
  timestamp__gte=timestamp__gte,
57
65
  timestamp__lt=timestamp__lt,
66
+ order__gt=order__gt,
58
67
  sort_order=sort_order,
59
68
  page_id=page_id,
60
69
  limit=limit,
@@ -16,6 +16,7 @@ from openhands.agent_server.models import (
16
16
  )
17
17
  from openhands.agent_server.pub_sub import PubSub, Subscriber
18
18
  from openhands.sdk.logger import get_logger
19
+ from openhands.sdk.utils import sanitized_env
19
20
 
20
21
 
21
22
  logger = get_logger(__name__)
@@ -103,6 +104,7 @@ class BashEventService:
103
104
  command_id__eq: UUID | None = None,
104
105
  timestamp__gte: datetime | None = None,
105
106
  timestamp__lt: datetime | None = None,
107
+ order__gt: int | None = None,
106
108
  sort_order: BashEventSortOrder = BashEventSortOrder.TIMESTAMP,
107
109
  page_id: str | None = None,
108
110
  limit: int = 100,
@@ -167,6 +169,11 @@ class BashEventService:
167
169
  for file_path in page_files:
168
170
  event = self._load_event_from_file(file_path)
169
171
  if event is not None:
172
+ # Filter by order if specified (only applies to BashOutput events)
173
+ if order__gt is not None:
174
+ event_order = getattr(event, "order", None)
175
+ if event_order is not None and event_order <= order__gt:
176
+ continue
170
177
  page_events.append(event)
171
178
 
172
179
  return BashEventPage(items=page_events, next_page_id=next_page_id)
@@ -194,6 +201,7 @@ class BashEventService:
194
201
  stdout=asyncio.subprocess.PIPE,
195
202
  stderr=asyncio.subprocess.PIPE,
196
203
  shell=True,
204
+ env=sanitized_env(),
197
205
  )
198
206
 
199
207
  # Track output order and buffers
@@ -34,8 +34,11 @@ logger = logging.getLogger(__name__)
34
34
  def _compose_conversation_info(
35
35
  stored: StoredConversation, state: ConversationState
36
36
  ) -> ConversationInfo:
37
+ # Use mode='json' so SecretStr in nested structures (e.g. LookupSecret.headers,
38
+ # agent.agent_context.secrets) serialize to strings. Without it, validation
39
+ # fails because ConversationInfo expects dict[str, str] but receives SecretStr.
37
40
  return ConversationInfo(
38
- **state.model_dump(),
41
+ **state.model_dump(mode="json"),
39
42
  title=stored.title,
40
43
  metrics=stored.metrics,
41
44
  created_at=stored.created_at,
@@ -235,7 +238,21 @@ class ConversationService:
235
238
  f"{list(request.tool_module_qualnames.keys())}"
236
239
  )
237
240
 
238
- stored = StoredConversation(id=conversation_id, **request.model_dump())
241
+ # Plugin loading is now handled lazily by LocalConversation.
242
+ # Just pass the plugin specs through to StoredConversation.
243
+ # LocalConversation will:
244
+ # 1. Fetch and load plugins on first run()/send_message()
245
+ # 2. Resolve refs to commit SHAs for deterministic resume
246
+ # 3. Merge plugin skills/MCP/hooks into the agent
247
+ #
248
+ # Use mode='json' so SecretStr in nested structures (e.g. LookupSecret.headers)
249
+ # serialize to plain strings. Pass expose_secrets=True so StaticSecret values
250
+ # are preserved through the round-trip; the dict is only used in-process to
251
+ # construct StoredConversation, not sent over the network.
252
+ stored = StoredConversation(
253
+ id=conversation_id,
254
+ **request.model_dump(mode="json", context={"expose_secrets": True}),
255
+ )
239
256
  event_service = await self._start_event_service(stored)
240
257
  initial_message = request.initial_message
241
258
  if initial_message:
@@ -9,6 +9,7 @@ from pathlib import Path
9
9
 
10
10
  from openhands.agent_server.config import get_default_config
11
11
  from openhands.sdk.logger import get_logger
12
+ from openhands.sdk.utils import sanitized_env
12
13
 
13
14
 
14
15
  logger = get_logger(__name__)
@@ -28,7 +29,7 @@ class DesktopService:
28
29
  return True
29
30
 
30
31
  # --- Env defaults (match bash behavior) ---
31
- env = os.environ.copy()
32
+ env = sanitized_env()
32
33
  display = env.get("DISPLAY", ":1")
33
34
  user = env.get("USER") or env.get("USERNAME") or "openhands"
34
35
  home = Path(env.get("HOME") or f"/home/{user}")
@@ -68,6 +69,7 @@ class DesktopService:
68
69
  capture_output=True,
69
70
  text=True,
70
71
  timeout=3,
72
+ env=env,
71
73
  ).returncode
72
74
  == 0
73
75
  )
@@ -105,6 +107,7 @@ class DesktopService:
105
107
  capture_output=True,
106
108
  text=True,
107
109
  timeout=3,
110
+ env=env,
108
111
  ).returncode
109
112
  == 0
110
113
  )
@@ -180,7 +183,11 @@ class DesktopService:
180
183
  # Check if VNC server is running
181
184
  try:
182
185
  result = subprocess.run(
183
- ["pgrep", "-f", "Xvnc"], capture_output=True, text=True, timeout=3
186
+ ["pgrep", "-f", "Xvnc"],
187
+ capture_output=True,
188
+ text=True,
189
+ timeout=3,
190
+ env=sanitized_env(),
184
191
  )
185
192
  return result.returncode == 0
186
193
  except Exception:
@@ -1,6 +1,6 @@
1
1
  # syntax=docker/dockerfile:1.7
2
2
 
3
- ARG BASE_IMAGE=nikolaik/python-nodejs:python3.12-nodejs22
3
+ ARG BASE_IMAGE=nikolaik/python-nodejs:python3.13-nodejs22
4
4
  ARG USERNAME=openhands
5
5
  ARG UID=10001
6
6
  ARG GID=10001
@@ -10,7 +10,7 @@ ARG PORT=8000
10
10
  # Builder (source mode)
11
11
  # We copy source + build a venv here for local dev and debugging.
12
12
  ####################################################################################
13
- FROM python:3.12-bullseye AS builder
13
+ FROM python:3.13-bullseye AS builder
14
14
  ARG USERNAME UID GID
15
15
  ENV UV_PROJECT_ENVIRONMENT=/agent-server/.venv
16
16
  ENV UV_PYTHON_INSTALL_DIR=/agent-server/uv-managed-python
@@ -28,7 +28,7 @@ COPY --chown=${USERNAME}:${USERNAME} openhands-tools ./openhands-tools
28
28
  COPY --chown=${USERNAME}:${USERNAME} openhands-workspace ./openhands-workspace
29
29
  COPY --chown=${USERNAME}:${USERNAME} openhands-agent-server ./openhands-agent-server
30
30
  RUN --mount=type=cache,target=/home/${USERNAME}/.cache,uid=${UID},gid=${GID} \
31
- uv python install 3.12 && uv venv --python 3.12 .venv && uv sync --frozen --no-editable --managed-python
31
+ uv python install 3.13 && uv venv --python 3.13 .venv && uv sync --frozen --no-editable --managed-python
32
32
 
33
33
  ####################################################################################
34
34
  # Binary Builder (binary mode)
@@ -333,7 +333,7 @@ _DEFAULT_PACKAGE_VERSION = _package_version()
333
333
 
334
334
 
335
335
  class BuildOptions(BaseModel):
336
- base_image: str = Field(default="nikolaik/python-nodejs:python3.12-nodejs22")
336
+ base_image: str = Field(default="nikolaik/python-nodejs:python3.13-nodejs22")
337
337
  custom_tags: str = Field(
338
338
  default="", description="Comma-separated list of custom tags."
339
339
  )
@@ -662,7 +662,7 @@ def main(argv: list[str]) -> int:
662
662
  )
663
663
  parser.add_argument(
664
664
  "--base-image",
665
- default=_env("BASE_IMAGE", "nikolaik/python-nodejs:python3.12-nodejs22"),
665
+ default=_env("BASE_IMAGE", "nikolaik/python-nodejs:python3.13-nodejs22"),
666
666
  help="Base image to use (default from $BASE_IMAGE).",
667
667
  )
668
668
  parser.add_argument(
@@ -46,6 +46,7 @@ class EventService:
46
46
  _pub_sub: PubSub[Event] = field(default_factory=lambda: PubSub[Event](), init=False)
47
47
  _run_task: asyncio.Task | None = field(default=None, init=False)
48
48
  _run_lock: asyncio.Lock = field(default_factory=asyncio.Lock, init=False)
49
+ _callback_wrapper: AsyncCallbackWrapper | None = field(default=None, init=False)
49
50
 
50
51
  @property
51
52
  def conversation_dir(self):
@@ -430,19 +431,29 @@ class EventService:
430
431
  self.stored.agent.model_dump(context={"expose_secrets": True}),
431
432
  )
432
433
 
434
+ # Create LocalConversation with plugins and hook_config.
435
+ # Plugins are loaded lazily on first run()/send_message() call.
436
+ # Hook execution semantics: OpenHands runs hooks sequentially with early-exit
437
+ # on block (PreToolUse), unlike Claude Code's parallel execution model.
438
+
439
+ # Create and store callback wrapper to allow flushing pending events
440
+ self._callback_wrapper = AsyncCallbackWrapper(
441
+ self._pub_sub, loop=asyncio.get_running_loop()
442
+ )
443
+
433
444
  conversation = LocalConversation(
434
445
  agent=agent,
435
446
  workspace=workspace,
447
+ plugins=self.stored.plugins,
436
448
  persistence_dir=str(self.conversations_dir),
437
449
  conversation_id=self.stored.id,
438
- callbacks=[
439
- AsyncCallbackWrapper(self._pub_sub, loop=asyncio.get_running_loop())
440
- ],
450
+ callbacks=[self._callback_wrapper],
441
451
  max_iteration_per_run=self.stored.max_iterations,
442
452
  stuck_detection=self.stored.stuck_detection,
443
453
  visualizer=None,
444
454
  secrets=self.stored.secrets,
445
455
  cipher=self.cipher,
456
+ hook_config=self.stored.hook_config,
446
457
  )
447
458
 
448
459
  # Set confirmation mode if enabled
@@ -517,6 +528,16 @@ class EventService:
517
528
  except Exception:
518
529
  logger.exception("Error during conversation run")
519
530
  finally:
531
+ # Wait for all pending events to be published via
532
+ # AsyncCallbackWrapper before publishing the final state update.
533
+ # This prevents a race condition where the conversation status
534
+ # becomes FINISHED before agent events (MessageEvent, ActionEvent,
535
+ # etc.) are published to WebSocket subscribers.
536
+ if self._callback_wrapper:
537
+ await loop.run_in_executor(
538
+ None, self._callback_wrapper.wait_for_pending, 30.0
539
+ )
540
+
520
541
  # Clear task reference and publish state update
521
542
  self._run_task = None
522
543
  await self._publish_state_update()
@@ -12,7 +12,9 @@ from openhands.sdk.conversation.state import (
12
12
  ConversationExecutionStatus,
13
13
  ConversationState,
14
14
  )
15
+ from openhands.sdk.hooks import HookConfig
15
16
  from openhands.sdk.llm.utils.metrics import MetricsSnapshot
17
+ from openhands.sdk.plugin import PluginSource
16
18
  from openhands.sdk.secret import SecretSource
17
19
  from openhands.sdk.security.analyzer import SecurityAnalyzerBase
18
20
  from openhands.sdk.security.confirmation_policy import (
@@ -106,10 +108,31 @@ class StartConversationRequest(BaseModel):
106
108
  "to register the tools for this conversation."
107
109
  ),
108
110
  )
111
+ plugins: list[PluginSource] | None = Field(
112
+ default=None,
113
+ description=(
114
+ "List of plugins to load for this conversation. Plugins are loaded "
115
+ "and their skills/MCP config are merged into the agent. "
116
+ "Hooks are extracted and stored for runtime execution."
117
+ ),
118
+ )
119
+ hook_config: HookConfig | None = Field(
120
+ default=None,
121
+ description=(
122
+ "Optional hook configuration for this conversation. Hooks are shell "
123
+ "scripts that run at key lifecycle events (PreToolUse, PostToolUse, "
124
+ "UserPromptSubmit, Stop, etc.). If both hook_config and plugins are "
125
+ "provided, they are merged with explicit hooks running before plugin "
126
+ "hooks."
127
+ ),
128
+ )
109
129
 
110
130
 
111
131
  class StoredConversation(StartConversationRequest):
112
- """Stored details about a conversation"""
132
+ """Stored details about a conversation.
133
+
134
+ Extends StartConversationRequest with server-assigned fields.
135
+ """
113
136
 
114
137
  id: OpenHandsUUID
115
138
  title: str | None = Field(
@@ -14,7 +14,6 @@ Precedence (later overrides earlier):
14
14
  sandbox < public < user < org < project
15
15
  """
16
16
 
17
- import os
18
17
  import shutil
19
18
  import subprocess
20
19
  import tempfile
@@ -37,6 +36,7 @@ from openhands.sdk.context.skills.utils import (
37
36
  update_skills_repository,
38
37
  )
39
38
  from openhands.sdk.logger import get_logger
39
+ from openhands.sdk.utils import sanitized_env
40
40
 
41
41
 
42
42
  logger = get_logger(__name__)
@@ -120,6 +120,8 @@ def load_org_skills_from_url(
120
120
  # Clone the organization repository (shallow clone for efficiency)
121
121
  logger.info(f"Cloning organization skills repository for {org_name}")
122
122
  try:
123
+ env = sanitized_env()
124
+ env["GIT_TERMINAL_PROMPT"] = "0"
123
125
  subprocess.run(
124
126
  [
125
127
  "git",
@@ -132,7 +134,7 @@ def load_org_skills_from_url(
132
134
  check=True,
133
135
  capture_output=True,
134
136
  timeout=120,
135
- env={**os.environ, "GIT_TERMINAL_PROMPT": "0"},
137
+ env=env,
136
138
  )
137
139
  except subprocess.CalledProcessError:
138
140
  # Repository doesn't exist or access denied - this is expected.
@@ -5,6 +5,7 @@ import os
5
5
  from pathlib import Path
6
6
 
7
7
  from openhands.sdk.logger import get_logger
8
+ from openhands.sdk.utils import sanitized_env
8
9
 
9
10
 
10
11
  logger = get_logger(__name__)
@@ -160,6 +161,7 @@ class VSCodeService:
160
161
  cmd,
161
162
  stdout=asyncio.subprocess.PIPE,
162
163
  stderr=asyncio.subprocess.STDOUT,
164
+ env=sanitized_env(),
163
165
  )
164
166
 
165
167
  # Wait for server to start (look for startup message)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openhands-agent-server
3
- Version: 1.9.1
3
+ Version: 1.11.0
4
4
  Summary: OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent
5
5
  Project-URL: Source, https://github.com/OpenHands/software-agent-sdk
6
6
  Project-URL: Homepage, https://github.com/OpenHands/software-agent-sdk
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "openhands-agent-server"
3
- version = "1.9.1"
3
+ version = "1.11.0"
4
4
  description = "OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent"
5
5
 
6
6
  requires-python = ">=3.12"