openhands-agent-server 1.31.2__tar.gz → 1.33.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.
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/PKG-INFO +1 -1
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/agent_profiles_router.py +37 -51
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/conversation_router.py +0 -6
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/conversation_service.py +25 -12
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/skills_service.py +11 -30
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands_agent_server.egg-info/PKG-INFO +1 -1
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/pyproject.toml +1 -1
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/__init__.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/__main__.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/_secrets_exposure.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/api.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/auth_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/bash_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/bash_service.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/config.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/conversation_lease.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/dependencies.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/desktop_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/desktop_service.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/docker/Dockerfile +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/docker/build.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/docker/wallpaper.svg +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/env_parser.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/event_compat.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/event_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/event_service.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/file_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/git_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/hooks_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/hooks_service.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/init_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/llm_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/logging_config.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/mcp_oauth_store.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/mcp_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/middleware.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/models.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/openai/__init__.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/openai/models.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/openai/router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/openai/service.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/openapi.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/persistence/__init__.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/persistence/models.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/persistence/store.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/plugins_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/plugins_service.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/profiles_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/pub_sub.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/py.typed +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/server_details_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/settings_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/skills_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/sockets.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/sub_agents_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/tool_preload_service.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/tool_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/utils.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/vscode_extensions/openhands-settings/extension.js +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/vscode_extensions/openhands-settings/package.json +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/vscode_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/vscode_service.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/workspace_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/workspaces_router.py +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands_agent_server.egg-info/SOURCES.txt +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands_agent_server.egg-info/dependency_links.txt +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands_agent_server.egg-info/entry_points.txt +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands_agent_server.egg-info/requires.txt +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands_agent_server.egg-info/top_level.txt +0 -0
- {openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-agent-server
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.33.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
|
|
@@ -19,13 +19,7 @@ from typing import Annotated, Any
|
|
|
19
19
|
from fastapi import APIRouter, HTTPException, Path, Request, status
|
|
20
20
|
from pydantic import BaseModel, Field, ValidationError
|
|
21
21
|
|
|
22
|
-
from openhands.agent_server._secrets_exposure import
|
|
23
|
-
build_expose_context,
|
|
24
|
-
get_cipher,
|
|
25
|
-
get_config,
|
|
26
|
-
parse_expose_secrets_header,
|
|
27
|
-
translate_missing_cipher,
|
|
28
|
-
)
|
|
22
|
+
from openhands.agent_server._secrets_exposure import get_cipher, get_config
|
|
29
23
|
from openhands.agent_server.persistence import (
|
|
30
24
|
PersistedSettings,
|
|
31
25
|
get_agent_profile_store,
|
|
@@ -33,7 +27,7 @@ from openhands.agent_server.persistence import (
|
|
|
33
27
|
get_settings_store,
|
|
34
28
|
)
|
|
35
29
|
from openhands.agent_server.profiles_router import MAX_PROFILES
|
|
36
|
-
from openhands.agent_server.skills_service import
|
|
30
|
+
from openhands.agent_server.skills_service import discover_profile_skills
|
|
37
31
|
from openhands.sdk.llm import LLM
|
|
38
32
|
from openhands.sdk.llm.llm_profile_store import (
|
|
39
33
|
ProfileLimitExceeded as LLMProfileLimitExceeded,
|
|
@@ -213,7 +207,7 @@ def _seed_default_profile(
|
|
|
213
207
|
settings.agent_settings.llm, cipher
|
|
214
208
|
)
|
|
215
209
|
profile = build_seed_profile(settings.agent_settings, active_llm_profile)
|
|
216
|
-
store.save(profile,
|
|
210
|
+
store.save(profile, max_profiles=MAX_AGENT_PROFILES)
|
|
217
211
|
|
|
218
212
|
profile_id = str(profile.id)
|
|
219
213
|
settings_store = get_settings_store(get_config(request))
|
|
@@ -266,31 +260,24 @@ async def list_agent_profiles(request: Request) -> AgentProfileListResponse:
|
|
|
266
260
|
|
|
267
261
|
|
|
268
262
|
@agent_profiles_router.get("/{name}", response_model=AgentProfileDetailResponse)
|
|
269
|
-
async def get_agent_profile(
|
|
270
|
-
request: Request, name: ProfileName
|
|
271
|
-
) -> AgentProfileDetailResponse:
|
|
263
|
+
async def get_agent_profile(name: ProfileName) -> AgentProfileDetailResponse:
|
|
272
264
|
"""Get a stored profile.
|
|
273
265
|
|
|
274
|
-
|
|
275
|
-
|
|
266
|
+
A profile is secret-free at rest (#4017), so there is nothing to mask or
|
|
267
|
+
expose — unlike the LLM ``/api/profiles`` router, this endpoint has no
|
|
268
|
+
``X-Expose-Secrets`` behavior.
|
|
276
269
|
"""
|
|
277
|
-
expose_mode = parse_expose_secrets_header(request)
|
|
278
|
-
cipher = get_cipher(request)
|
|
279
|
-
|
|
280
270
|
store = get_agent_profile_store()
|
|
281
271
|
try:
|
|
282
272
|
with _store_errors():
|
|
283
|
-
profile = store.load(name
|
|
273
|
+
profile = store.load(name)
|
|
284
274
|
except FileNotFoundError:
|
|
285
275
|
raise HTTPException(
|
|
286
276
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
287
277
|
detail=f"Agent profile '{name}' not found",
|
|
288
278
|
)
|
|
289
279
|
|
|
290
|
-
|
|
291
|
-
with translate_missing_cipher():
|
|
292
|
-
payload = profile.model_dump(mode="json", context=context)
|
|
293
|
-
|
|
280
|
+
payload = profile.model_dump(mode="json")
|
|
294
281
|
return AgentProfileDetailResponse(name=name, profile=payload)
|
|
295
282
|
|
|
296
283
|
|
|
@@ -300,31 +287,29 @@ async def get_agent_profile(
|
|
|
300
287
|
status_code=status.HTTP_201_CREATED,
|
|
301
288
|
)
|
|
302
289
|
async def save_agent_profile(
|
|
303
|
-
|
|
290
|
+
name: ProfileName, body: dict[str, Any]
|
|
304
291
|
) -> AgentProfileMutationResponse:
|
|
305
292
|
"""Save an ``AgentProfile`` under ``name`` (overwriting a namesake).
|
|
306
293
|
|
|
307
294
|
The path ``name`` is authoritative — it overrides any ``name`` in the body.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
295
|
+
The profile is secret-free at rest (#4017), so no cipher/encryption is
|
|
296
|
+
involved. Returns 409 if creating a new profile would exceed
|
|
297
|
+
``MAX_AGENT_PROFILES``.
|
|
311
298
|
"""
|
|
312
|
-
cipher = get_cipher(request)
|
|
313
299
|
try:
|
|
314
300
|
profile = validate_agent_profile({**body, "name": name})
|
|
315
301
|
except ValidationError as e:
|
|
316
|
-
# Match FastAPI's request-validation shape (``detail`` is a list of
|
|
317
|
-
# objects)
|
|
318
|
-
#
|
|
319
|
-
# ``msg``.
|
|
302
|
+
# Match FastAPI's request-validation shape (``detail`` is a list of
|
|
303
|
+
# error objects): ``loc``/``type``/``msg`` (``input`` dropped — see
|
|
304
|
+
# safe_validation_error_detail's docstring for why msg is now safe).
|
|
320
305
|
raise HTTPException(
|
|
321
306
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
322
307
|
detail=safe_validation_error_detail(e),
|
|
323
308
|
)
|
|
324
309
|
except Exception:
|
|
325
|
-
# Any other validation failure (e.g.
|
|
326
|
-
#
|
|
327
|
-
#
|
|
310
|
+
# Any other validation failure (e.g. a schema/migration error) is a
|
|
311
|
+
# client error, never a 500. Stay generic — these messages can embed
|
|
312
|
+
# the input.
|
|
328
313
|
raise HTTPException(
|
|
329
314
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
330
315
|
detail="Invalid agent profile",
|
|
@@ -339,7 +324,7 @@ async def save_agent_profile(
|
|
|
339
324
|
try:
|
|
340
325
|
with _store_errors():
|
|
341
326
|
save_profile_preserving_identity(
|
|
342
|
-
store, profile,
|
|
327
|
+
store, profile, max_profiles=MAX_AGENT_PROFILES
|
|
343
328
|
)
|
|
344
329
|
except ProfileLimitExceeded:
|
|
345
330
|
raise HTTPException(
|
|
@@ -489,36 +474,37 @@ async def materialize_agent_profile(
|
|
|
489
474
|
than raising — the only error status is 404 (unknown profile name).
|
|
490
475
|
resolved_settings is redacted (api_key_set booleans; no raw secrets).
|
|
491
476
|
"""
|
|
492
|
-
cipher = get_cipher(request)
|
|
493
|
-
|
|
494
477
|
store = get_agent_profile_store()
|
|
495
478
|
try:
|
|
496
479
|
with _store_errors():
|
|
497
|
-
profile = store.load(name
|
|
480
|
+
profile = store.load(name)
|
|
498
481
|
except FileNotFoundError:
|
|
499
482
|
raise HTTPException(
|
|
500
483
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
501
484
|
detail=f"Agent profile '{name}' not found",
|
|
502
485
|
)
|
|
503
486
|
|
|
487
|
+
# Still needed here (unlike the profile load above): resolve_agent_profile_
|
|
488
|
+
# dry_run uses it to decrypt the *referenced LLM profile's* own secret.
|
|
489
|
+
cipher = get_cipher(request)
|
|
504
490
|
config = get_config(request)
|
|
505
491
|
settings = get_settings_store(config).load() or PersistedSettings()
|
|
506
492
|
mcp_config = settings.agent_settings.mcp_config
|
|
507
493
|
|
|
508
|
-
# Discover skills off the event loop so the dry-run can report which
|
|
509
|
-
# ``
|
|
510
|
-
#
|
|
511
|
-
#
|
|
512
|
-
#
|
|
494
|
+
# Discover skills off the event loop so the dry-run can report which skills
|
|
495
|
+
# (catalog minus ``disabled_skills``) resolve. Only OpenHands profiles carry
|
|
496
|
+
# user/public skills; ACP profiles do not. A discovery failure must not 500
|
|
497
|
+
# the preview: pass ``available_skills=None`` and surface the failure as its
|
|
498
|
+
# own diagnostic below.
|
|
513
499
|
discovery_error: str | None = None
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
500
|
+
available_skills = None
|
|
501
|
+
if profile.agent_kind == "openhands":
|
|
502
|
+
try:
|
|
503
|
+
available_skills = await asyncio.to_thread(discover_profile_skills)
|
|
504
|
+
except Exception as exc:
|
|
505
|
+
available_skills = None
|
|
506
|
+
discovery_error = str(exc)
|
|
507
|
+
logger.warning("Skill discovery failed during materialize: %s", exc)
|
|
522
508
|
|
|
523
509
|
llm_store = get_llm_profile_store()
|
|
524
510
|
diagnostics = resolve_agent_profile_dry_run(
|
|
@@ -51,7 +51,6 @@ from openhands.sdk.marketplace.registry import (
|
|
|
51
51
|
from openhands.sdk.plugin import PluginFetchError
|
|
52
52
|
from openhands.sdk.profiles.resolver import (
|
|
53
53
|
DanglingMcpServerRef,
|
|
54
|
-
DanglingSkillRef,
|
|
55
54
|
ProfileNotFound,
|
|
56
55
|
)
|
|
57
56
|
from openhands.sdk.tool.client_tool import ClientToolRegistrationError
|
|
@@ -217,11 +216,6 @@ async def start_conversation(
|
|
|
217
216
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
218
217
|
detail={"message": str(e), "dangling_mcp_server_refs": e.missing},
|
|
219
218
|
) from e
|
|
220
|
-
except DanglingSkillRef as e:
|
|
221
|
-
raise HTTPException(
|
|
222
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
223
|
-
detail={"message": str(e), "dangling_skill_refs": e.missing},
|
|
224
|
-
) from e
|
|
225
219
|
except ClientToolRegistrationError as e:
|
|
226
220
|
raise HTTPException(
|
|
227
221
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
|
|
@@ -32,7 +32,7 @@ from openhands.agent_server.models import (
|
|
|
32
32
|
)
|
|
33
33
|
from openhands.agent_server.pub_sub import Subscriber
|
|
34
34
|
from openhands.agent_server.server_details_router import update_last_execution_time
|
|
35
|
-
from openhands.agent_server.skills_service import
|
|
35
|
+
from openhands.agent_server.skills_service import discover_profile_skills
|
|
36
36
|
from openhands.agent_server.utils import safe_rmtree, utc_now
|
|
37
37
|
from openhands.sdk import LLM, AgentContext, Event, Message
|
|
38
38
|
from openhands.sdk.agent.base import AgentBase
|
|
@@ -267,7 +267,6 @@ def _resolve_agent_from_profile(
|
|
|
267
267
|
Raises:
|
|
268
268
|
ProfileNotFound: No stored profile has ``profile_id``.
|
|
269
269
|
DanglingMcpServerRef: A referenced MCP server is absent from the global config.
|
|
270
|
-
DanglingSkillRef: A referenced skill is absent from the discovered catalog.
|
|
271
270
|
ValueError: Profile load or settings validation failure.
|
|
272
271
|
"""
|
|
273
272
|
from openhands.agent_server.persistence.store import (
|
|
@@ -275,6 +274,7 @@ def _resolve_agent_from_profile(
|
|
|
275
274
|
get_llm_profile_store,
|
|
276
275
|
)
|
|
277
276
|
from openhands.sdk.profiles.resolver import ProfileNotFound, resolve_agent_profile
|
|
277
|
+
from openhands.sdk.settings.model import OpenHandsAgentSettings
|
|
278
278
|
|
|
279
279
|
store = get_agent_profile_store()
|
|
280
280
|
profile_name = store.name_for_id(profile_id)
|
|
@@ -282,7 +282,7 @@ def _resolve_agent_from_profile(
|
|
|
282
282
|
raise ProfileNotFound(f"Agent profile with id '{profile_id}' not found")
|
|
283
283
|
|
|
284
284
|
try:
|
|
285
|
-
profile = store.load(profile_name
|
|
285
|
+
profile = store.load(profile_name)
|
|
286
286
|
except FileNotFoundError:
|
|
287
287
|
raise ProfileNotFound(
|
|
288
288
|
f"Agent profile '{profile_name}' (id={profile_id}) not found"
|
|
@@ -292,15 +292,18 @@ def _resolve_agent_from_profile(
|
|
|
292
292
|
f"Failed to load agent profile '{profile_name}': {exc}"
|
|
293
293
|
) from exc
|
|
294
294
|
|
|
295
|
-
#
|
|
296
|
-
#
|
|
297
|
-
#
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
295
|
+
# OpenHands profiles get the discovered catalog minus their ``disabled_skills``
|
|
296
|
+
# deny-list; ACP profiles carry no user/public skills so discovery is skipped.
|
|
297
|
+
# A genuine discovery failure fails the launch loudly rather than silently
|
|
298
|
+
# producing a zero-skill agent.
|
|
299
|
+
available_skills = None
|
|
300
|
+
if profile.agent_kind == "openhands":
|
|
301
|
+
try:
|
|
302
|
+
available_skills = discover_profile_skills()
|
|
303
|
+
except Exception as exc:
|
|
304
|
+
raise ValueError(
|
|
305
|
+
f"Skill discovery failed for profile '{profile_name}': {exc}"
|
|
306
|
+
) from exc
|
|
304
307
|
|
|
305
308
|
llm_store = get_llm_profile_store()
|
|
306
309
|
try:
|
|
@@ -314,6 +317,16 @@ def _resolve_agent_from_profile(
|
|
|
314
317
|
except (TypeError, ValueError) as exc:
|
|
315
318
|
raise ValueError(f"Profile '{profile_name}' failed to resolve: {exc}") from exc
|
|
316
319
|
|
|
320
|
+
if isinstance(settings_config, OpenHandsAgentSettings):
|
|
321
|
+
# Force streaming so this launch path wires on_token: a client can't set
|
|
322
|
+
# llm.stream on a profile's referenced LLM ahead of time. Safe at this
|
|
323
|
+
# layer (not the SDK resolver) because this server wires the token
|
|
324
|
+
# callback whenever any llm.stream is set; a headless resolver caller
|
|
325
|
+
# that never wires on_token is covered by LLM's graceful degradation.
|
|
326
|
+
settings_config = settings_config.model_copy(
|
|
327
|
+
update={"llm": settings_config.llm.model_copy(update={"stream": True})}
|
|
328
|
+
)
|
|
329
|
+
|
|
317
330
|
agent = settings_config.create_agent()
|
|
318
331
|
# Browser is deliberately absent from the deterministic SDK default
|
|
319
332
|
# (environment-dependent); this server knows its runtime, so it injects
|
|
@@ -21,7 +21,6 @@ import tempfile
|
|
|
21
21
|
from dataclasses import dataclass
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from time import monotonic
|
|
24
|
-
from typing import TYPE_CHECKING
|
|
25
24
|
|
|
26
25
|
from pydantic import BaseModel, ValidationError
|
|
27
26
|
|
|
@@ -57,10 +56,6 @@ from openhands.sdk.utils import sanitized_env
|
|
|
57
56
|
from openhands.sdk.utils.path import to_posix_path
|
|
58
57
|
|
|
59
58
|
|
|
60
|
-
if TYPE_CHECKING:
|
|
61
|
-
from openhands.sdk.profiles import ACPAgentProfile, OpenHandsAgentProfile
|
|
62
|
-
|
|
63
|
-
|
|
64
59
|
logger = get_logger(__name__)
|
|
65
60
|
|
|
66
61
|
|
|
@@ -458,20 +453,21 @@ def load_all_skills(
|
|
|
458
453
|
|
|
459
454
|
|
|
460
455
|
def discover_profile_skills() -> list[Skill]:
|
|
461
|
-
"""Skill catalog
|
|
456
|
+
"""Skill catalog an OpenHands profile launches with (#4017).
|
|
462
457
|
|
|
463
458
|
Returns the merged user + public skills — the deterministic sources of
|
|
464
|
-
:func:`load_all_skills
|
|
465
|
-
``
|
|
466
|
-
this does not swallow errors:
|
|
467
|
-
silently resolving the profile
|
|
459
|
+
:func:`load_all_skills`. ``resolve_agent_profile`` keeps all of them except
|
|
460
|
+
the profile's ``disabled_skills`` deny-list. ``load_all_skills`` already
|
|
461
|
+
absorbs and logs benign per-source failures, so this does not swallow errors:
|
|
462
|
+
an unexpected failure propagates rather than silently resolving the profile
|
|
463
|
+
to a zero-skill agent.
|
|
468
464
|
|
|
469
465
|
Org / project skills need auth / workspace context not available at resolve
|
|
470
|
-
time, so they are not in this catalog
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
466
|
+
time, so they are not in this catalog. That is safe under the deny-list
|
|
467
|
+
model: a skill missing from the catalog is simply never disabled (it stays
|
|
468
|
+
on when it does load, e.g. project skills loaded lazily by
|
|
469
|
+
``LocalConversation``) — the old allow-list would instead have dangled and
|
|
470
|
+
failed the launch.
|
|
475
471
|
"""
|
|
476
472
|
return list(
|
|
477
473
|
load_all_skills(
|
|
@@ -483,21 +479,6 @@ def discover_profile_skills() -> list[Skill]:
|
|
|
483
479
|
)
|
|
484
480
|
|
|
485
481
|
|
|
486
|
-
def discover_profile_skills_if_needed(
|
|
487
|
-
profile: "OpenHandsAgentProfile | ACPAgentProfile",
|
|
488
|
-
) -> list[Skill] | None:
|
|
489
|
-
"""Discover the skill catalog a profile needs, or ``None`` to skip discovery.
|
|
490
|
-
|
|
491
|
-
``skill_refs == []`` selects no discovered skills, so the (potentially
|
|
492
|
-
network-bound) discovery is skipped and the resolver receives ``None``. Any
|
|
493
|
-
other value — ``None`` (all discovered) or a name list — needs the catalog.
|
|
494
|
-
Centralizes the skip guard shared by conversation start and the dry-run.
|
|
495
|
-
"""
|
|
496
|
-
if profile.skill_refs == []:
|
|
497
|
-
return None
|
|
498
|
-
return discover_profile_skills()
|
|
499
|
-
|
|
500
|
-
|
|
501
482
|
def sync_public_skills() -> tuple[bool, str]:
|
|
502
483
|
"""Force refresh of public skills from GitHub repository.
|
|
503
484
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-agent-server
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.33.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
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/__init__.py
RENAMED
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/env_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/git_router.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/llm_router.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/mcp_router.py
RENAMED
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/middleware.py
RENAMED
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/openapi.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/pub_sub.py
RENAMED
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/sockets.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.31.2 → openhands_agent_server-1.33.0}/openhands/agent_server/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|