Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/run-eval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ on:
sdk_ref:
description: SDK commit/ref to evaluate (must be a semantic version like v1.0.0 unless 'Allow unreleased branches' is checked)
required: true
default: v1.21.1
default: v1.22.0
Comment thread
neubig marked this conversation as resolved.




Expand Down
2 changes: 1 addition & 1 deletion openhands-agent-server/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "openhands-agent-server"
version = "1.21.1"
version = "1.22.0"
description = "OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent"

requires-python = ">=3.12"
Expand Down
2 changes: 1 addition & 1 deletion openhands-sdk/openhands/sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
_DEPRECATED_SDK_EXPORTS: dict[str, dict[str, str]] = {
"LLMAgentSettings": {
"deprecated_in": "1.19.0",
"removed_in": "1.22.0",
"removed_in": "1.24.0",
"details": (
"Use ``OpenHandsAgentSettings`` directly. "
"``LLMAgentSettings`` was renamed in v1.19.0."
Expand Down
2 changes: 1 addition & 1 deletion openhands-sdk/openhands/sdk/settings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def __getattr__(name: str) -> Any:
warn_deprecated(
f"Importing {name!r} from openhands.sdk.settings",
deprecated_in="1.19.0",
removed_in="1.22.0",
removed_in="1.24.0",
details=(
"Use ``OpenHandsAgentSettings`` directly. "
"``LLMAgentSettings`` was renamed in v1.19.0."
Expand Down
84 changes: 19 additions & 65 deletions openhands-sdk/openhands/sdk/settings/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,65 +294,6 @@ class VerificationSettings(BaseModel):
},
)

# -- Deprecated (moved to ConversationSettings) --
confirmation_mode: bool = Field(
default=False,
description="Require user confirmation before executing risky actions.",
deprecated=(
"Deprecated in 1.17.0; use ConversationSettings.confirmation_mode "
"instead. Will be removed in 1.22.0."
),
json_schema_extra={
SETTINGS_METADATA_KEY: SettingsFieldMetadata(
label="Confirmation mode",
prominence=SettingProminence.MAJOR,
).model_dump()
},
)
security_analyzer: SecurityAnalyzerType | None = Field(
default=None,
description=("Security analyzer that evaluates actions before execution."),
deprecated=(
"Deprecated in 1.17.0; use ConversationSettings.security_analyzer "
"instead. Will be removed in 1.22.0."
),
json_schema_extra={
SETTINGS_METADATA_KEY: SettingsFieldMetadata(
label="Security analyzer",
prominence=SettingProminence.MAJOR,
depends_on=("confirmation_mode",),
).model_dump()
},
)

@field_validator("confirmation_mode", mode="before")
@classmethod
def _warn_confirmation_mode(cls, v: Any) -> Any:
if v:
from openhands.sdk.utils.deprecation import warn_deprecated

warn_deprecated(
"VerificationSettings.confirmation_mode",
deprecated_in="1.17.0",
removed_in="1.22.0",
details="Use ConversationSettings.confirmation_mode instead.",
)
return v

@field_validator("security_analyzer", mode="before")
@classmethod
def _warn_security_analyzer(cls, v: Any) -> Any:
if v is not None:
from openhands.sdk.utils.deprecation import warn_deprecated

warn_deprecated(
"VerificationSettings.security_analyzer",
deprecated_in="1.17.0",
removed_in="1.22.0",
details="Use ConversationSettings.security_analyzer instead.",
)
return v


def _default_llm_settings() -> LLM:
model = LLM.model_fields["model"].get_default()
Expand All @@ -362,7 +303,7 @@ def _default_llm_settings() -> LLM:

_RequestT = TypeVar("_RequestT")

AGENT_SETTINGS_SCHEMA_VERSION = 2
AGENT_SETTINGS_SCHEMA_VERSION = 3
CONVERSATION_SETTINGS_SCHEMA_VERSION = 1


Expand Down Expand Up @@ -484,7 +425,7 @@ def _migrate_agent_settings_v1_to_v2(payload: dict[str, Any]) -> dict[str, Any]:
persisted payloads carried ``agent_kind: 'llm'``. The two classes are
field-compatible (``LLMAgentSettings`` is a subclass of
``OpenHandsAgentSettings`` that only narrows the discriminator literal),
and ``LLMAgentSettings`` is scheduled for removal in v1.22.0. Rewriting
and ``LLMAgentSettings`` is scheduled for removal in v1.24.0. Rewriting
the discriminator on read lets callers that explicitly validate as
``OpenHandsAgentSettings`` (the canonical class) accept legacy data
without losing any fields.
Expand All @@ -496,6 +437,19 @@ def _migrate_agent_settings_v1_to_v2(payload: dict[str, Any]) -> dict[str, Any]:
return migrated


def _migrate_agent_settings_v2_to_v3(payload: dict[str, Any]) -> dict[str, Any]:
"""Drop deprecated verification fields moved to ``ConversationSettings``."""
migrated = dict(payload)
verification = migrated.get("verification")
if isinstance(verification, Mapping):
verification = dict(verification)
verification.pop("confirmation_mode", None)
verification.pop("security_analyzer", None)
migrated["verification"] = verification
migrated["schema_version"] = 3
return migrated


def _migrate_conversation_settings_v0_to_v1(
payload: dict[str, Any],
) -> dict[str, Any]:
Expand All @@ -507,6 +461,7 @@ def _migrate_conversation_settings_v0_to_v1(
_AGENT_SETTINGS_MIGRATIONS: dict[int, PersistedSettingsMigrator] = {
0: _migrate_agent_settings_v0_to_v1,
1: _migrate_agent_settings_v1_to_v2,
2: _migrate_agent_settings_v2_to_v3,
}
_CONVERSATION_SETTINGS_MIGRATIONS: dict[int, PersistedSettingsMigrator] = {
0: _migrate_conversation_settings_v0_to_v1,
Expand Down Expand Up @@ -1269,7 +1224,7 @@ class LLMAgentSettings(OpenHandsAgentSettings):

Use :class:`OpenHandsAgentSettings` for all new code.

Scheduled for removal in v1.22.0.
Scheduled for removal in v1.24.0.
"""

# Keep agent_kind as Literal["llm"] so the API-breakage checker sees no
Expand Down Expand Up @@ -1365,8 +1320,7 @@ class AgentSettings(LLMAgentSettings):
* Use :func:`validate_agent_settings` to validate raw payloads
into the correct variant.

Scheduled for removal in v1.22.0 (5 minor releases after the
discriminated-union landing in v1.17.1).
Scheduled for removal in v1.23.0.
"""

@classmethod
Expand All @@ -1388,7 +1342,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
warn_deprecated(
"AgentSettings",
deprecated_in="1.17.0",
removed_in="1.22.0",
removed_in="1.23.0",
details=(
"Use ``OpenHandsAgentSettings`` (for an LLM agent) or "
"``ACPAgentSettings`` (for an ACP agent) directly; use "
Expand Down
2 changes: 1 addition & 1 deletion openhands-sdk/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "openhands-sdk"
version = "1.21.1"
version = "1.22.0"
Comment thread
neubig marked this conversation as resolved.
description = "OpenHands SDK - Core functionality for building AI agents"

requires-python = ">=3.12"
Expand Down
2 changes: 1 addition & 1 deletion openhands-tools/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "openhands-tools"
version = "1.21.1"
version = "1.22.0"
description = "OpenHands Tools - Runtime tools for AI agents"

requires-python = ">=3.12"
Expand Down
2 changes: 1 addition & 1 deletion openhands-workspace/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "openhands-workspace"
version = "1.21.1"
version = "1.22.0"
description = "OpenHands Workspace - Docker and container-based workspace implementations"

requires-python = ">=3.12"
Expand Down
35 changes: 28 additions & 7 deletions tests/sdk/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def test_agent_settings_from_persisted_migrates_v0_llm_payload() -> None:
settings = AgentSettings.from_persisted({"llm": {"model": "test-model"}})

assert isinstance(settings, OpenHandsAgentSettings)
assert settings.schema_version == 2
assert settings.schema_version == 3
assert settings.agent_kind == "openhands"
assert settings.llm.model == "test-model"

Expand All @@ -369,8 +369,8 @@ def test_agent_settings_from_persisted_dispatches_current_acp_payload() -> None:
)

assert isinstance(settings, ACPAgentSettings)
# v1 → v2 is a no-op for ACP payloads, but the schema_version is bumped.
assert settings.schema_version == 2
# v1 → v2 → v3 keeps ACP payloads intact while bumping schema_version.
assert settings.schema_version == 3
assert settings.acp_command == ["npx", "-y", "claude-agent-acp"]


Expand All @@ -386,14 +386,35 @@ def test_agent_settings_from_persisted_canonicalizes_legacy_llm_kind() -> None:
)

assert isinstance(settings, OpenHandsAgentSettings)
assert settings.schema_version == 2
assert settings.schema_version == 3
assert settings.agent_kind == "openhands"
assert settings.llm.model == "legacy-model"


def test_agent_settings_from_persisted_drops_legacy_verification_fields() -> None:
settings = AgentSettings.from_persisted(
{
"schema_version": 2,
"agent_kind": "openhands",
"verification": {
"critic_enabled": True,
"confirmation_mode": True,
"security_analyzer": "llm",
},
}
)

assert isinstance(settings, OpenHandsAgentSettings)
assert settings.schema_version == 3
verification = settings.verification.model_dump(mode="json")
assert verification["critic_enabled"] is True
assert "confirmation_mode" not in verification
assert "security_analyzer" not in verification


def test_agent_settings_from_persisted_rejects_newer_schema_version() -> None:
with pytest.raises(ValueError, match="newer than supported version 2"):
AgentSettings.from_persisted({"schema_version": 3, "llm": {"model": "m"}})
with pytest.raises(ValueError, match="newer than supported version 3"):
AgentSettings.from_persisted({"schema_version": 4, "llm": {"model": "m"}})


def test_conversation_settings_from_persisted_migrates_v0_payload() -> None:
Expand Down Expand Up @@ -654,7 +675,7 @@ def test_legacy_agent_settings_still_instantiates_as_llm_variant() -> None:
settings = AgentSettings(llm=LLM(model="test-model"))

# The legacy name emits a DeprecationWarning on construction. The
# warning's scheduled removal is in 1.22.0 per the class docstring.
# warning's scheduled removal is in 1.23.0 per the class docstring.
assert any("AgentSettings" in str(w.message) for w in caught), (
f"expected deprecation warning, got: {[str(w.message) for w in caught]}"
)
Expand Down
8 changes: 4 additions & 4 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading