Skip to content

Commit 5ee469c

Browse files
fix(sdk): simplify persisted AgentSettings migrations
Co-authored-by: openhands <openhands@all-hands.dev>
1 parent a4947fb commit 5ee469c

9 files changed

Lines changed: 83 additions & 552 deletions

File tree

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ When reviewing code, provide constructive feedback:
107107
- `AgentSettings.tools` is part of the exported settings schema so the schema stays aligned with the settings payload that round-trips through `AgentSettings` and drives `create_agent()`.
108108
- `AgentSettings.mcp_config` now uses FastMCP's typed `MCPConfig` at runtime. When serializing settings back to plain data (e.g. `model_dump()` or `create_agent()`), keep the output compact with `exclude_none=True, exclude_defaults=True` so callers still see the familiar `.mcp.json`-style dict shape.
109109
- Persisted `AgentSettings` now have an SDK-owned canonical migration contract: legacy v1 payloads are the raw unversioned settings mapping, while the current canonical format is v2 `{\"version\": 2, \"settings\": ...}`. Use `AgentSettings.load_persisted()`/`dump_persisted()` so consumers share the same upgrade path and preserve sparse overlays with `exclude_unset=True`.
110+
- Keep the persisted-settings contract wrapper-based and product-neutral; do not fold persistence-only version metadata into the runtime `AgentSettings` model or add consumer-specific patch/diff helpers there.
111+
110112
- Anthropic malformed tool-use/tool-result history errors (for example, missing or duplicated ``tool_result`` blocks) are intentionally mapped to a dedicated `LLMMalformedConversationHistoryError` and caught separately in `Agent.step()`, so recovery can still use condensation while logs preserve that this was malformed history rather than a true context-window overflow.
111113
- AgentSkills progressive disclosure goes through `AgentContext.get_system_message_suffix()` into `<available_skills>`, and `openhands.sdk.context.skills.to_prompt()` truncates each prompt description to 1024 characters because the AgentSkills specification caps `description` at 1-1024 characters.
112114
- Workspace-wide uv resolver guardrails belong in the repository root `[tool.uv]` table. When `exclude-newer` is configured there, `uv lock` persists it into the root `uv.lock` `[options]` section as both an absolute cutoff and `exclude-newer-span`, and `uv sync --frozen` continues to use that locked workspace state.

openhands-agent-server/openhands/agent_server/event_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,8 @@ async def start(self):
498498
tags=self.stored.tags,
499499
)
500500

501+
# Set confirmation mode if enabled
501502
conversation.set_confirmation_policy(self.stored.confirmation_policy)
502-
conversation.set_security_analyzer(self.stored.security_analyzer)
503503
self._conversation = conversation
504504

505505
# Register state change callback to automatically publish updates

openhands-agent-server/openhands/agent_server/models.py

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,7 @@
77
from pydantic import BaseModel, Discriminator, Field, Tag, field_validator
88

99
from openhands.agent_server.utils import OpenHandsUUID, utc_now
10-
from openhands.sdk import (
11-
LLM,
12-
Agent,
13-
ConversationSettings,
14-
ImageContent,
15-
Message,
16-
TextContent,
17-
)
10+
from openhands.sdk import LLM, Agent, ImageContent, Message, TextContent
1811
from openhands.sdk.agent.acp_agent import ACPAgent
1912
from openhands.sdk.conversation.conversation_stats import ConversationStats
2013
from openhands.sdk.conversation.secret_registry import SecretRegistry
@@ -112,10 +105,6 @@ class _StartConversationRequestBase(BaseModel):
112105
description="Controls when the conversation will prompt the user before "
113106
"continuing. Defaults to never.",
114107
)
115-
security_analyzer: SecurityAnalyzerBase | None = Field(
116-
default=None,
117-
description="Optional security analyzer to evaluate action risks.",
118-
)
119108
initial_message: SendMessageRequest | None = Field(
120109
default=None, description="Initial message to pass to the LLM"
121110
)
@@ -192,42 +181,12 @@ class StartConversationRequest(_StartConversationRequestBase):
192181

193182
agent: Agent
194183

195-
@classmethod
196-
def from_settings(
197-
cls,
198-
*,
199-
agent: Agent,
200-
workspace: LocalWorkspace,
201-
conversation_settings: ConversationSettings | None = None,
202-
**kwargs: Any,
203-
) -> "StartConversationRequest":
204-
payload = dict(kwargs)
205-
if conversation_settings is not None:
206-
for key, value in conversation_settings.to_start_request_kwargs().items():
207-
payload.setdefault(key, value)
208-
return cls(agent=agent, workspace=workspace, **payload)
209-
210184

211185
class StartACPConversationRequest(_StartConversationRequestBase):
212186
"""Payload to create a conversation with ACP-capable agent support."""
213187

214188
agent: ACPEnabledAgent
215189

216-
@classmethod
217-
def from_settings(
218-
cls,
219-
*,
220-
agent: ACPEnabledAgent,
221-
workspace: LocalWorkspace,
222-
conversation_settings: ConversationSettings | None = None,
223-
**kwargs: Any,
224-
) -> "StartACPConversationRequest":
225-
payload = dict(kwargs)
226-
if conversation_settings is not None:
227-
for key, value in conversation_settings.to_start_request_kwargs().items():
228-
payload.setdefault(key, value)
229-
return cls(agent=agent, workspace=workspace, **payload)
230-
231190

232191
class StoredConversation(StartACPConversationRequest):
233192
"""Stored details about a conversation.

openhands-agent-server/openhands/agent_server/settings_router.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from fastapi import APIRouter
44

5-
from openhands.sdk.settings import AgentSettings, ConversationSettings, SettingsSchema
5+
from openhands.sdk.settings import AgentSettings, SettingsSchema
66

77

88
settings_router = APIRouter(prefix="/settings", tags=["Settings"])
@@ -13,18 +13,7 @@ def _get_agent_settings_schema() -> SettingsSchema:
1313
return AgentSettings.export_schema()
1414

1515

16-
@lru_cache(maxsize=1)
17-
def _get_conversation_settings_schema() -> SettingsSchema:
18-
return ConversationSettings.export_schema()
19-
20-
2116
@settings_router.get("/schema", response_model=SettingsSchema)
2217
async def get_agent_settings_schema() -> SettingsSchema:
2318
"""Return the schema used to render AgentSettings-based settings forms."""
2419
return _get_agent_settings_schema()
25-
26-
27-
@settings_router.get("/conversation-schema", response_model=SettingsSchema)
28-
async def get_conversation_settings_schema() -> SettingsSchema:
29-
"""Return the schema used to render ConversationSettings-based forms."""
30-
return _get_conversation_settings_schema()

openhands-sdk/openhands/sdk/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@
5252
from openhands.sdk.settings import (
5353
AgentSettings,
5454
CondenserSettings,
55-
ConversationSettings,
56-
ConversationVerificationSettings,
5755
SettingsChoice,
5856
SettingsFieldSchema,
5957
SettingsSchema,
@@ -139,8 +137,6 @@
139137
"AgentContext",
140138
"LLMSummarizingCondenser",
141139
"CondenserSettings",
142-
"ConversationSettings",
143-
"ConversationVerificationSettings",
144140
"VerificationSettings",
145141
"AgentSettings",
146142
"SettingsChoice",

openhands-sdk/openhands/sdk/settings/__init__.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
from .model import (
1717
AgentSettings,
1818
CondenserSettings,
19-
ConversationSettings,
20-
ConversationVerificationSettings,
2119
SettingsChoice,
2220
SettingsFieldSchema,
2321
SettingsSchema,
@@ -29,8 +27,6 @@
2927
_MODEL_EXPORTS = {
3028
"AgentSettings",
3129
"CondenserSettings",
32-
"ConversationSettings",
33-
"ConversationVerificationSettings",
3430
"SettingsChoice",
3531
"SettingsFieldSchema",
3632
"SettingsSchema",
@@ -42,8 +38,6 @@
4238
__all__ = [
4339
"AgentSettings",
4440
"CondenserSettings",
45-
"ConversationSettings",
46-
"ConversationVerificationSettings",
4741
"SETTINGS_METADATA_KEY",
4842
"SETTINGS_SECTION_METADATA_KEY",
4943
"SettingProminence",

0 commit comments

Comments
 (0)