openhands-agent-server 1.23.1__tar.gz → 1.24.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.23.1 → openhands_agent_server-1.24.0}/PKG-INFO +1 -1
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/conversation_router.py +46 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/conversation_service.py +56 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/event_service.py +36 -8
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/models.py +49 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands_agent_server.egg-info/PKG-INFO +1 -1
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/pyproject.toml +1 -1
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/__init__.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/__main__.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/_secrets_exposure.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/api.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/auth_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/bash_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/bash_service.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/cloud_proxy_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/config.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/conversation_lease.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/conversation_router_acp.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/dependencies.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/desktop_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/desktop_service.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/docker/Dockerfile +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/docker/build.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/docker/wallpaper.svg +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/env_parser.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/event_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/file_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/git_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/hooks_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/hooks_service.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/llm_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/logging_config.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/mcp_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/middleware.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/openapi.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/persistence/__init__.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/persistence/models.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/persistence/store.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/profiles_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/pub_sub.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/py.typed +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/server_details_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/settings_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/skills_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/skills_service.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/sockets.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/tool_preload_service.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/tool_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/utils.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/vscode_extensions/openhands-settings/extension.js +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/vscode_extensions/openhands-settings/package.json +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/vscode_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/vscode_service.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/workspace_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/workspaces_router.py +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands_agent_server.egg-info/SOURCES.txt +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands_agent_server.egg-info/dependency_links.txt +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands_agent_server.egg-info/entry_points.txt +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands_agent_server.egg-info/requires.txt +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands_agent_server.egg-info/top_level.txt +0 -0
- {openhands_agent_server-1.23.1 → openhands_agent_server-1.24.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.24.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
|
|
@@ -394,6 +394,52 @@ async def switch_conversation_llm(
|
|
|
394
394
|
return Success()
|
|
395
395
|
|
|
396
396
|
|
|
397
|
+
@conversation_router.post(
|
|
398
|
+
"/{conversation_id}/switch_acp_model",
|
|
399
|
+
responses={
|
|
400
|
+
400: {"description": "Agent is not ACP, or provider can't switch models"},
|
|
401
|
+
404: {"description": "Conversation not found"},
|
|
402
|
+
409: {"description": "ACP session not initialized yet"},
|
|
403
|
+
504: {"description": "ACP server did not answer the model switch in time"},
|
|
404
|
+
},
|
|
405
|
+
)
|
|
406
|
+
async def switch_conversation_acp_model(
|
|
407
|
+
conversation_id: UUID,
|
|
408
|
+
model: str = Body(..., embed=True),
|
|
409
|
+
conversation_service: ConversationService = Depends(get_conversation_service),
|
|
410
|
+
) -> Success:
|
|
411
|
+
"""Switch the model of a running ACP conversation, mid-conversation.
|
|
412
|
+
|
|
413
|
+
Issues a protocol-level ``session/set_model`` call to the ACP subprocess
|
|
414
|
+
so the new model applies to subsequent turns without losing context. Only
|
|
415
|
+
valid for ACP conversations whose provider supports runtime switching.
|
|
416
|
+
"""
|
|
417
|
+
event_service = await conversation_service.get_event_service(conversation_id)
|
|
418
|
+
if event_service is None:
|
|
419
|
+
raise HTTPException(status.HTTP_404_NOT_FOUND)
|
|
420
|
+
try:
|
|
421
|
+
await event_service.switch_acp_model(model)
|
|
422
|
+
except ValueError as e:
|
|
423
|
+
raise HTTPException(
|
|
424
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
425
|
+
detail=str(e),
|
|
426
|
+
)
|
|
427
|
+
except TimeoutError as e:
|
|
428
|
+
# The bounded session/set_model round-trip expired. The ACP server is
|
|
429
|
+
# wedged/slow rather than rejecting the request, so surface a 504
|
|
430
|
+
# instead of an opaque 500.
|
|
431
|
+
raise HTTPException(
|
|
432
|
+
status_code=status.HTTP_504_GATEWAY_TIMEOUT,
|
|
433
|
+
detail=str(e),
|
|
434
|
+
)
|
|
435
|
+
except RuntimeError as e:
|
|
436
|
+
raise HTTPException(
|
|
437
|
+
status_code=status.HTTP_409_CONFLICT,
|
|
438
|
+
detail=str(e),
|
|
439
|
+
)
|
|
440
|
+
return Success()
|
|
441
|
+
|
|
442
|
+
|
|
397
443
|
@conversation_router.patch(
|
|
398
444
|
"/{conversation_id}", responses={404: {"description": "Item not found"}}
|
|
399
445
|
)
|
|
@@ -245,12 +245,68 @@ def _compose_conversation_info(
|
|
|
245
245
|
# Use mode='json' so SecretStr in nested structures (e.g. LookupSecret.headers,
|
|
246
246
|
# agent.agent_context.secrets) serialize to strings. Without it, validation
|
|
247
247
|
# fails because ConversationInfo expects dict[str, str] but receives SecretStr.
|
|
248
|
+
#
|
|
249
|
+
# ACP model state is lifted onto top-level ConversationInfo fields because
|
|
250
|
+
# the agent holds it in PrivateAttrs (ACPAgent is frozen) which don't survive
|
|
251
|
+
# ``model_dump``. ``getattr`` keeps non-ACP agents a no-op. We read the live
|
|
252
|
+
# agent (fresh within a session) and fall back to ``state.agent_state`` —
|
|
253
|
+
# persisted to ``base_state.json`` by ``ACPAgent._init`` (and kept in sync by
|
|
254
|
+
# ``switch_acp_model``) — so cold list reads, where PrivateAttrs are still
|
|
255
|
+
# empty because ``init_state`` hasn't fired, still surface the last-known
|
|
256
|
+
# state. Persisted ``acp_available_models`` is a list of dicts that
|
|
257
|
+
# ``ConversationInfo`` coerces back into ``ACPModelInfo``.
|
|
258
|
+
agent_state = getattr(state, "agent_state", {}) or {}
|
|
259
|
+
agent = state.agent
|
|
260
|
+
# current_model_id: live PrivateAttr (fresh after a runtime switch) → the
|
|
261
|
+
# persisted hint → the authoritative ``acp_model`` the agent runs on resume.
|
|
262
|
+
#
|
|
263
|
+
# The ``acp_model`` fallback is gated on the agent NOT being a live,
|
|
264
|
+
# initialized one. Once ``init_state`` has fired, ``current_model_id`` is the
|
|
265
|
+
# authoritative resolved value — including ``None`` when an override couldn't
|
|
266
|
+
# be applied (unknown provider, or a resume whose ``set_session_model`` the
|
|
267
|
+
# server rejected) — so falling back to ``acp_model`` there would re-assert an
|
|
268
|
+
# override the live session isn't actually running. The fallback is only for
|
|
269
|
+
# *cold* reads (``init_state`` hasn't fired, PrivateAttrs still empty), where
|
|
270
|
+
# the serialized ``acp_model`` is the best last-known hint. The persisted
|
|
271
|
+
# ``acp_current_model_id`` hint is kept honest by ``ACPAgent.init_state`` (it
|
|
272
|
+
# clears the value whenever the override wasn't applied), so it's safe in
|
|
273
|
+
# both cases.
|
|
274
|
+
agent_initialized = bool(getattr(agent, "_initialized", False))
|
|
275
|
+
current_model_id = (
|
|
276
|
+
getattr(agent, "current_model_id", None)
|
|
277
|
+
or agent_state.get("acp_current_model_id")
|
|
278
|
+
or (None if agent_initialized else getattr(agent, "acp_model", None))
|
|
279
|
+
)
|
|
280
|
+
# available_models: the property returns ``[]`` (never ``None``) for *both* a
|
|
281
|
+
# cold-read agent (PrivateAttr default, init_state hasn't fired) and a live
|
|
282
|
+
# agent that genuinely has no models, so an ``is None`` check can't tell them
|
|
283
|
+
# apart — and would drop the persisted picker payload on every cold list
|
|
284
|
+
# read. The ``or`` chain is deliberate: an empty live list falls back to the
|
|
285
|
+
# persisted snapshot, which is exactly right on cold reads (surface the
|
|
286
|
+
# last-known list) and benign for a live empty session (the persisted value
|
|
287
|
+
# is itself empty/absent there).
|
|
288
|
+
available_models = (
|
|
289
|
+
getattr(agent, "available_models", None)
|
|
290
|
+
or agent_state.get("acp_available_models")
|
|
291
|
+
or []
|
|
292
|
+
)
|
|
293
|
+
# Static provider capability. Unlike the two fields above it has no
|
|
294
|
+
# meaningful live-vs-persisted distinction — it's derived from the stable
|
|
295
|
+
# provider identity and written once at session init — so we read the
|
|
296
|
+
# persisted value directly. Defaults False for non-ACP agents and
|
|
297
|
+
# conversations that haven't started a session.
|
|
298
|
+
supports_runtime_model_switch = bool(
|
|
299
|
+
agent_state.get("acp_supports_runtime_model_switch", False)
|
|
300
|
+
)
|
|
248
301
|
return ConversationInfo(
|
|
249
302
|
**state.model_dump(mode="json"),
|
|
250
303
|
title=stored.title,
|
|
251
304
|
metrics=stored.metrics,
|
|
252
305
|
created_at=stored.created_at,
|
|
253
306
|
updated_at=stored.updated_at,
|
|
307
|
+
current_model_id=current_model_id,
|
|
308
|
+
available_models=available_models,
|
|
309
|
+
supports_runtime_model_switch=supports_runtime_model_switch,
|
|
254
310
|
)
|
|
255
311
|
|
|
256
312
|
|
|
@@ -740,8 +740,9 @@ class EventService:
|
|
|
740
740
|
immediately. When possible, the conversation is driven via its native
|
|
741
741
|
``arun()`` coroutine so LLM I/O does not tie up a thread-pool worker.
|
|
742
742
|
For conversations that do not expose ``arun()`` (e.g., custom
|
|
743
|
-
subclasses)
|
|
744
|
-
|
|
743
|
+
subclasses) or whose agent only implements sync ``step()`` (no
|
|
744
|
+
``astep()`` override), the synchronous ``run()`` is executed
|
|
745
|
+
in the thread pool as before.
|
|
745
746
|
|
|
746
747
|
Raises:
|
|
747
748
|
ValueError: If the service is inactive or conversation is already running.
|
|
@@ -773,19 +774,23 @@ class EventService:
|
|
|
773
774
|
# loop is free during LLM I/O. Fall back to thread-pool
|
|
774
775
|
# execution for backward compatibility.
|
|
775
776
|
#
|
|
776
|
-
#
|
|
777
|
+
# All guards are required:
|
|
777
778
|
# • iscoroutinefunction – filters out non-async objects
|
|
778
779
|
# (e.g. MagicMock in tests).
|
|
779
|
-
# • override
|
|
780
|
-
# ``
|
|
781
|
-
#
|
|
782
|
-
#
|
|
783
|
-
#
|
|
780
|
+
# • conversation override – BaseConversation's default
|
|
781
|
+
# ``arun()`` delegates to sync ``run()``, so we require an
|
|
782
|
+
# *actual* override to avoid running a sync-only subclass
|
|
783
|
+
# on the event loop.
|
|
784
|
+
# • agent override – ``LocalConversation`` always overrides
|
|
785
|
+
# ``arun()``, but an agent without an ``astep()`` override
|
|
786
|
+
# runs sync ``step()`` in a worker thread; route it
|
|
787
|
+
# through sync ``run()`` instead.
|
|
784
788
|
arun = getattr(conversation, "arun", None)
|
|
785
789
|
has_native_arun = (
|
|
786
790
|
arun is not None
|
|
787
791
|
and asyncio.iscoroutinefunction(arun)
|
|
788
792
|
and type(conversation).arun is not BaseConversation.arun
|
|
793
|
+
and type(conversation.agent).astep is not AgentBase.astep
|
|
789
794
|
)
|
|
790
795
|
if has_native_arun:
|
|
791
796
|
await conversation.arun()
|
|
@@ -911,6 +916,29 @@ class EventService:
|
|
|
911
916
|
None, self._conversation.set_security_analyzer, security_analyzer
|
|
912
917
|
)
|
|
913
918
|
|
|
919
|
+
async def switch_acp_model(self, model: str) -> None:
|
|
920
|
+
"""Switch the model on a running ACP conversation, mid-conversation.
|
|
921
|
+
|
|
922
|
+
Runs the (blocking) protocol-level ``session/set_model`` round-trip in a
|
|
923
|
+
worker thread, then mirrors the new model into ``meta.json`` so the
|
|
924
|
+
switch survives an agent-server restart: ``start()`` rebuilds the agent
|
|
925
|
+
from ``self.stored.agent`` and ``ConversationState.create()`` copies
|
|
926
|
+
that over the persisted base_state.json on resume. Only ``acp_model``
|
|
927
|
+
needs updating — ``model_post_init`` re-derives the sentinel
|
|
928
|
+
``llm.model`` on reload.
|
|
929
|
+
"""
|
|
930
|
+
if self._conversation is None:
|
|
931
|
+
raise RuntimeError(
|
|
932
|
+
"Conversation is not active; it has not been started or has "
|
|
933
|
+
"been closed."
|
|
934
|
+
)
|
|
935
|
+
loop = asyncio.get_running_loop()
|
|
936
|
+
await loop.run_in_executor(None, self._conversation.switch_acp_model, model)
|
|
937
|
+
self.stored = self.stored.model_copy(
|
|
938
|
+
update={"agent": self.stored.agent.model_copy(update={"acp_model": model})}
|
|
939
|
+
)
|
|
940
|
+
await self.save_meta()
|
|
941
|
+
|
|
914
942
|
async def close(self):
|
|
915
943
|
if self._lease_task is not None:
|
|
916
944
|
self._lease_task.cancel()
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/models.py
RENAMED
|
@@ -9,6 +9,7 @@ from uuid import UUID, uuid4
|
|
|
9
9
|
from pydantic import BaseModel, Field, field_validator
|
|
10
10
|
|
|
11
11
|
from openhands.sdk import LLM
|
|
12
|
+
from openhands.sdk.agent.acp_models import ACPModelInfo
|
|
12
13
|
from openhands.sdk.agent.base import AgentBase
|
|
13
14
|
from openhands.sdk.conversation.conversation_stats import ConversationStats
|
|
14
15
|
from openhands.sdk.conversation.request import ( # re-export for backward compat
|
|
@@ -184,6 +185,54 @@ class _ConversationInfoBase(BaseModel):
|
|
|
184
185
|
"alphanumeric. Values are arbitrary strings up to 256 characters."
|
|
185
186
|
),
|
|
186
187
|
)
|
|
188
|
+
current_model_id: str | None = Field(
|
|
189
|
+
default=None,
|
|
190
|
+
description=(
|
|
191
|
+
"Model the agent is actually using for this session. For ACP "
|
|
192
|
+
"agents, this is lifted off ``ACPAgent.current_model_id`` "
|
|
193
|
+
"(populated from the ``models.currentModelId`` field on the "
|
|
194
|
+
"ACP session response, or from ``acp_model`` when the caller "
|
|
195
|
+
"forced an override). May be an opaque alias (e.g. "
|
|
196
|
+
'claude-agent-acp\'s ``"default"``); match it against '
|
|
197
|
+
"``available_models`` to get a display label. ``None`` for older "
|
|
198
|
+
"ACP servers that don't surface the field, or while the agent is "
|
|
199
|
+
"still initializing. Native OpenHands agents leave this ``None`` — "
|
|
200
|
+
"consumers should read ``agent.llm.model`` for those."
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
available_models: list[ACPModelInfo] = Field(
|
|
204
|
+
default_factory=list,
|
|
205
|
+
description=(
|
|
206
|
+
"Models the ACP server offers for this session, lifted off "
|
|
207
|
+
"``ACPAgent.available_models`` (the ``models.availableModels`` "
|
|
208
|
+
"field on the ACP session response). Each entry carries a "
|
|
209
|
+
"``model_id`` plus an optional ``name``/``description``. Surfaced "
|
|
210
|
+
"verbatim so clients can render a model picker and resolve "
|
|
211
|
+
"``current_model_id`` to a display label themselves — the server "
|
|
212
|
+
"does no name curation. Empty for ACP servers that don't surface "
|
|
213
|
+
"the (UNSTABLE) capability and for native OpenHands agents. "
|
|
214
|
+
"Client contract: ``current_model_id`` is NOT guaranteed to be a "
|
|
215
|
+
"member — a forced ``acp_model`` override may name a model absent "
|
|
216
|
+
"from the list — so treat a miss as 'show the raw id'. Some "
|
|
217
|
+
"entries are opaque aliases whose human identity lives in "
|
|
218
|
+
'``description`` (e.g. claude-agent-acp\'s ``"default"`` -> '
|
|
219
|
+
'``"Opus 4.7 with 1M context · ..."``).'
|
|
220
|
+
),
|
|
221
|
+
)
|
|
222
|
+
supports_runtime_model_switch: bool = Field(
|
|
223
|
+
default=False,
|
|
224
|
+
description=(
|
|
225
|
+
"Whether a live, mid-conversation model switch (via "
|
|
226
|
+
"``session/set_model``) will be attempted for this conversation — "
|
|
227
|
+
"tells the inline picker whether to offer a live-switch control. "
|
|
228
|
+
"Mirrors the SDK's switch gate: ``True`` for known switch-capable "
|
|
229
|
+
"providers; ``True`` for unknown/custom ACP servers too, since "
|
|
230
|
+
"OpenHands attempts the switch optimistically rather than refusing "
|
|
231
|
+
"(a rejection then surfaces as an error). ``False`` for native "
|
|
232
|
+
"OpenHands agents, for a known provider that declares no support, "
|
|
233
|
+
"and before the conversation has started a session."
|
|
234
|
+
),
|
|
235
|
+
)
|
|
187
236
|
|
|
188
237
|
|
|
189
238
|
class ConversationInfo(_ConversationInfoBase):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openhands-agent-server
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.24.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.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/__init__.py
RENAMED
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.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
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/env_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/git_router.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/llm_router.py
RENAMED
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/mcp_router.py
RENAMED
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/middleware.py
RENAMED
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/openapi.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/pub_sub.py
RENAMED
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.0}/openhands/agent_server/sockets.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openhands_agent_server-1.23.1 → openhands_agent_server-1.24.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
|