diff --git a/openhands/core/config/agent_config.py b/openhands/core/config/agent_config.py index 2420c89387..393ddc6bd7 100644 --- a/openhands/core/config/agent_config.py +++ b/openhands/core/config/agent_config.py @@ -1,6 +1,6 @@ from __future__ import annotations -from pydantic import BaseModel, Field, ValidationError +from pydantic import BaseModel, ConfigDict, Field, ValidationError from openhands.core.config.condenser_config import CondenserConfig, NoOpCondenserConfig from openhands.core.config.extended_config import ExtendedConfig @@ -47,7 +47,7 @@ class AgentConfig(BaseModel): extended: ExtendedConfig = Field(default_factory=lambda: ExtendedConfig({})) """Extended configuration for the agent.""" - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') @classmethod def from_toml_section(cls, data: dict) -> dict[str, AgentConfig]: diff --git a/openhands/core/config/condenser_config.py b/openhands/core/config/condenser_config.py index 9c9a056d80..804198143d 100644 --- a/openhands/core/config/condenser_config.py +++ b/openhands/core/config/condenser_config.py @@ -2,7 +2,7 @@ from __future__ import annotations from typing import Literal, cast -from pydantic import BaseModel, Field, ValidationError +from pydantic import BaseModel, ConfigDict, Field, ValidationError from openhands.core import logger from openhands.core.config.llm_config import LLMConfig @@ -13,7 +13,7 @@ class NoOpCondenserConfig(BaseModel): type: Literal['noop'] = Field('noop') - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') class ObservationMaskingCondenserConfig(BaseModel): @@ -26,7 +26,7 @@ class ObservationMaskingCondenserConfig(BaseModel): ge=1, ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') class BrowserOutputCondenserConfig(BaseModel): @@ -55,7 +55,7 @@ class RecentEventsCondenserConfig(BaseModel): default=100, description='Maximum number of events to keep.', ge=1 ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') class LLMSummarizingCondenserConfig(BaseModel): @@ -82,7 +82,7 @@ class LLMSummarizingCondenserConfig(BaseModel): description='Maximum length of the event representations to be passed to the LLM.', ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') class AmortizedForgettingCondenserConfig(BaseModel): @@ -102,7 +102,7 @@ class AmortizedForgettingCondenserConfig(BaseModel): ge=0, ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') class LLMAttentionCondenserConfig(BaseModel): @@ -125,7 +125,7 @@ class LLMAttentionCondenserConfig(BaseModel): ge=0, ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') class StructuredSummaryCondenserConfig(BaseModel): @@ -152,7 +152,7 @@ class StructuredSummaryCondenserConfig(BaseModel): description='Maximum length of the event representations to be passed to the LLM.', ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') class CondenserPipelineConfig(BaseModel): @@ -167,7 +167,7 @@ class CondenserPipelineConfig(BaseModel): description='List of condenser configurations to be used in the pipeline.', ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') # Type alias for convenience diff --git a/openhands/core/config/kubernetes_config.py b/openhands/core/config/kubernetes_config.py index 1ba554825c..69528744bc 100644 --- a/openhands/core/config/kubernetes_config.py +++ b/openhands/core/config/kubernetes_config.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field, ValidationError +from pydantic import BaseModel, ConfigDict, Field, ValidationError class KubernetesConfig(BaseModel): @@ -62,7 +62,7 @@ class KubernetesConfig(BaseModel): description='Run the runtime sandbox container in privileged mode for use with docker-in-docker', ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') @classmethod def from_toml_section(cls, data: dict) -> dict[str, 'KubernetesConfig']: diff --git a/openhands/core/config/llm_config.py b/openhands/core/config/llm_config.py index c39986746a..2706fc5fb8 100644 --- a/openhands/core/config/llm_config.py +++ b/openhands/core/config/llm_config.py @@ -3,7 +3,7 @@ from __future__ import annotations import os from typing import Any -from pydantic import BaseModel, Field, SecretStr, ValidationError +from pydantic import BaseModel, ConfigDict, Field, SecretStr, ValidationError from openhands.core.logger import LOG_DIR from openhands.core.logger import openhands_logger as logger @@ -92,7 +92,7 @@ class LLMConfig(BaseModel): description='Safety settings for models that support them (like Mistral AI and Gemini)', ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') @classmethod def from_toml_section(cls, data: dict) -> dict[str, LLMConfig]: diff --git a/openhands/core/config/mcp_config.py b/openhands/core/config/mcp_config.py index dab456de00..6a20a63b20 100644 --- a/openhands/core/config/mcp_config.py +++ b/openhands/core/config/mcp_config.py @@ -2,7 +2,7 @@ import os from typing import TYPE_CHECKING from urllib.parse import urlparse -from pydantic import BaseModel, Field, ValidationError, model_validator +from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator if TYPE_CHECKING: from openhands.core.config.openhands_config import OpenHandsConfig @@ -72,7 +72,7 @@ class MCPConfig(BaseModel): stdio_servers: list[MCPStdioServerConfig] = Field(default_factory=list) shttp_servers: list[MCPSHTTPServerConfig] = Field(default_factory=list) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') @staticmethod def _normalize_servers(servers_data: list[dict | str]) -> list[dict]: diff --git a/openhands/core/config/openhands_config.py b/openhands/core/config/openhands_config.py index 69b94db2f1..d2908f0530 100644 --- a/openhands/core/config/openhands_config.py +++ b/openhands/core/config/openhands_config.py @@ -1,7 +1,7 @@ import os from typing import Any, ClassVar -from pydantic import BaseModel, Field, SecretStr +from pydantic import BaseModel, ConfigDict, Field, SecretStr from openhands.core import logger from openhands.core.config.agent_config import AgentConfig @@ -114,7 +114,7 @@ class OpenHandsConfig(BaseModel): defaults_dict: ClassVar[dict] = {} - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') def get_llm_config(self, name: str = 'llm') -> LLMConfig: """'llm' is the name for default config (for backward compatibility prior to 0.8).""" diff --git a/openhands/core/config/sandbox_config.py b/openhands/core/config/sandbox_config.py index 887a020d8a..a57422325d 100644 --- a/openhands/core/config/sandbox_config.py +++ b/openhands/core/config/sandbox_config.py @@ -1,6 +1,6 @@ import os -from pydantic import BaseModel, Field, ValidationError, model_validator +from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator class SandboxConfig(BaseModel): @@ -88,7 +88,7 @@ class SandboxConfig(BaseModel): description="Volume mounts in the format 'host_path:container_path[:mode]', e.g. '/my/host/dir:/workspace:rw'. Multiple mounts can be specified using commas, e.g. '/path1:/workspace/path1,/path2:/workspace/path2:ro'", ) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') @classmethod def from_toml_section(cls, data: dict) -> dict[str, 'SandboxConfig']: diff --git a/openhands/core/config/security_config.py b/openhands/core/config/security_config.py index 20c975f786..774e8ad4d9 100644 --- a/openhands/core/config/security_config.py +++ b/openhands/core/config/security_config.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field, ValidationError +from pydantic import BaseModel, ConfigDict, Field, ValidationError class SecurityConfig(BaseModel): @@ -12,7 +12,7 @@ class SecurityConfig(BaseModel): confirmation_mode: bool = Field(default=False) security_analyzer: str | None = Field(default=None) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') @classmethod def from_toml_section(cls, data: dict) -> dict[str, 'SecurityConfig']: diff --git a/openhands/integrations/provider.py b/openhands/integrations/provider.py index 2e60f90476..e35c924391 100644 --- a/openhands/integrations/provider.py +++ b/openhands/integrations/provider.py @@ -5,6 +5,7 @@ from typing import Annotated, Any, Coroutine, Literal, overload from pydantic import ( BaseModel, + ConfigDict, Field, SecretStr, WithJsonSchema, @@ -34,10 +35,10 @@ class ProviderToken(BaseModel): user_id: str | None = Field(default=None) host: str | None = Field(default=None) - model_config = { - 'frozen': True, # Makes the entire model immutable - 'validate_assignment': True, - } + model_config = ConfigDict( + frozen=True, # Makes the entire model immutable + validate_assignment=True, + ) @classmethod def from_value(cls, token_value: ProviderToken | dict[str, str]) -> ProviderToken: @@ -62,10 +63,10 @@ class CustomSecret(BaseModel): secret: SecretStr = Field(default_factory=lambda: SecretStr('')) description: str = Field(default='') - model_config = { - 'frozen': True, # Makes the entire model immutable - 'validate_assignment': True, - } + model_config = ConfigDict( + frozen=True, # Makes the entire model immutable + validate_assignment=True, + ) @classmethod def from_value(cls, secret_value: CustomSecret | dict[str, str]) -> CustomSecret: diff --git a/openhands/mcp/client.py b/openhands/mcp/client.py index 2256dba396..8b90fe98a1 100644 --- a/openhands/mcp/client.py +++ b/openhands/mcp/client.py @@ -4,7 +4,7 @@ from fastmcp import Client from fastmcp.client.transports import SSETransport, StreamableHttpTransport from mcp import McpError from mcp.types import CallToolResult -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field from openhands.core.config.mcp_config import MCPSHTTPServerConfig, MCPSSEServerConfig from openhands.core.logger import openhands_logger as logger @@ -16,14 +16,13 @@ class MCPClient(BaseModel): A collection of tools that connects to an MCP server and manages available tools through the Model Context Protocol. """ + model_config = ConfigDict(arbitrary_types_allowed=True) + client: Optional[Client] = None description: str = 'MCP client tools for server interaction' tools: list[MCPClientTool] = Field(default_factory=list) tool_map: dict[str, MCPClientTool] = Field(default_factory=dict) - class Config: - arbitrary_types_allowed = True - async def _initialize_and_list_tools(self) -> None: """Initialize session and populate tool map.""" if not self.client: diff --git a/openhands/mcp/tool.py b/openhands/mcp/tool.py index 7d99f78809..7bbf332a58 100644 --- a/openhands/mcp/tool.py +++ b/openhands/mcp/tool.py @@ -1,4 +1,5 @@ from mcp.types import Tool +from pydantic import ConfigDict class MCPClientTool(Tool): @@ -9,8 +10,7 @@ class MCPClientTool(Tool): by the MCPClient for each operation. """ - class Config: - arbitrary_types_allowed = True + model_config = ConfigDict(arbitrary_types_allowed=True) def to_param(self) -> dict: """Convert tool to function call format.""" diff --git a/openhands/server/routes/manage_conversations.py b/openhands/server/routes/manage_conversations.py index d2999e304f..563487ceb3 100644 --- a/openhands/server/routes/manage_conversations.py +++ b/openhands/server/routes/manage_conversations.py @@ -7,7 +7,7 @@ from datetime import datetime, timezone from fastapi import APIRouter, Depends, status from fastapi.responses import JSONResponse from jinja2 import Environment, FileSystemLoader -from pydantic import BaseModel, Field +from pydantic import BaseModel, ConfigDict, Field from openhands.core.config.llm_config import LLMConfig from openhands.core.logger import openhands_logger as logger @@ -88,7 +88,7 @@ class InitSessionRequest(BaseModel): if os.getenv('ALLOW_SET_CONVERSATION_ID', '0') == '1': conversation_id: str = Field(default_factory=lambda: uuid.uuid4().hex) - model_config = {'extra': 'forbid'} + model_config = ConfigDict(extra='forbid') class ConversationResponse(BaseModel): diff --git a/openhands/server/session/conversation_init_data.py b/openhands/server/session/conversation_init_data.py index ea3f1f4d6b..4f459d8857 100644 --- a/openhands/server/session/conversation_init_data.py +++ b/openhands/server/session/conversation_init_data.py @@ -1,4 +1,4 @@ -from pydantic import Field +from pydantic import ConfigDict, Field from openhands.integrations.provider import CUSTOM_SECRETS_TYPE, PROVIDER_TOKEN_TYPE from openhands.integrations.service_types import ProviderType @@ -18,6 +18,6 @@ class ConversationInitData(Settings): conversation_instructions: str | None = Field(default=None) git_provider: ProviderType | None = Field(default=None) - model_config = { - 'arbitrary_types_allowed': True, - } + model_config = ConfigDict( + arbitrary_types_allowed=True, + ) diff --git a/openhands/server/settings.py b/openhands/server/settings.py index b3f4dee784..7399d619c1 100644 --- a/openhands/server/settings.py +++ b/openhands/server/settings.py @@ -2,6 +2,7 @@ from __future__ import annotations from pydantic import ( BaseModel, + ConfigDict, SecretStr, ) @@ -39,7 +40,7 @@ class GETSettingsModel(Settings): llm_api_key_set: bool search_api_key_set: bool = False - model_config = {'use_enum_values': True} + model_config = ConfigDict(use_enum_values=True) class CustomSecretWithoutValueModel(BaseModel): diff --git a/openhands/storage/data_models/settings.py b/openhands/storage/data_models/settings.py index 2230447180..a037ef643b 100644 --- a/openhands/storage/data_models/settings.py +++ b/openhands/storage/data_models/settings.py @@ -2,6 +2,7 @@ from __future__ import annotations from pydantic import ( BaseModel, + ConfigDict, Field, SecretStr, SerializationInfo, @@ -45,9 +46,9 @@ class Settings(BaseModel): email: str | None = None email_verified: bool | None = None - model_config = { - 'validate_assignment': True, - } + model_config = ConfigDict( + validate_assignment=True, + ) @field_serializer('llm_api_key', 'search_api_key') def api_key_serializer(self, api_key: SecretStr | None, info: SerializationInfo): diff --git a/openhands/storage/data_models/user_secrets.py b/openhands/storage/data_models/user_secrets.py index 76318d723f..43db861e21 100644 --- a/openhands/storage/data_models/user_secrets.py +++ b/openhands/storage/data_models/user_secrets.py @@ -3,6 +3,7 @@ from typing import Any from pydantic import ( BaseModel, + ConfigDict, Field, SerializationInfo, field_serializer, @@ -31,11 +32,11 @@ class UserSecrets(BaseModel): default_factory=lambda: MappingProxyType({}) ) - model_config = { - 'frozen': True, - 'validate_assignment': True, - 'arbitrary_types_allowed': True, - } + model_config = ConfigDict( + frozen=True, + validate_assignment=True, + arbitrary_types_allowed=True, + ) @field_serializer('provider_tokens') def provider_tokens_serializer(