diff --git a/hyperbrowser/models/__init__.py b/hyperbrowser/models/__init__.py index 04678b09..931c7560 100644 --- a/hyperbrowser/models/__init__.py +++ b/hyperbrowser/models/__init__.py @@ -134,6 +134,7 @@ StartCuaTaskParams, StartCuaTaskResponse, CuaApiKeys, + CuaBaseUrls, CuaTaskStatus, ) from .agents.hyper_agent import ( @@ -493,6 +494,7 @@ "GeminiComputerUseApiKeys", "GrokComputerUseApiKeys", "CuaApiKeys", + "CuaBaseUrls", "HyperAgentApiKeys", "GrokComputerUseLlm", "GrokReasoningEffort", diff --git a/hyperbrowser/models/agents/cua.py b/hyperbrowser/models/agents/cua.py index c5990e3a..f99f4eb6 100644 --- a/hyperbrowser/models/agents/cua.py +++ b/hyperbrowser/models/agents/cua.py @@ -22,6 +22,18 @@ class CuaApiKeys(BaseModel): openai: Optional[str] = Field(default=None, serialization_alias="openai") +class CuaBaseUrls(BaseModel): + """ + Provider base URLs for the CUA task. + """ + + model_config = ConfigDict( + populate_by_alias=True, + ) + + openai: Optional[str] = Field(default=None, serialization_alias="openai") + + class StartCuaTaskParams(BaseModel): """ Parameters for creating a new CUA task. @@ -46,6 +58,9 @@ class StartCuaTaskParams(BaseModel): default=None, serialization_alias="useCustomApiKeys" ) api_keys: Optional[CuaApiKeys] = Field(default=None, serialization_alias="apiKeys") + base_urls: Optional[CuaBaseUrls] = Field( + default=None, serialization_alias="baseUrls" + ) use_computer_action: Optional[bool] = Field( default=None, serialization_alias="useComputerAction" ) diff --git a/hyperbrowser/types/__init__.py b/hyperbrowser/types/__init__.py index ad886119..405b8989 100644 --- a/hyperbrowser/types/__init__.py +++ b/hyperbrowser/types/__init__.py @@ -16,6 +16,7 @@ BrowserUseApiKeys, ClaudeComputerUseApiKeys, CuaApiKeys, + CuaBaseUrls, GeminiComputerUseApiKeys, GrokComputerUseApiKeys, HyperAgentApiKeys, @@ -173,6 +174,7 @@ "BrowserUseApiKeys", "ClaudeComputerUseApiKeys", "CuaApiKeys", + "CuaBaseUrls", "GeminiComputerUseApiKeys", "GrokComputerUseApiKeys", "HyperAgentApiKeys", diff --git a/hyperbrowser/types/agents.py b/hyperbrowser/types/agents.py index 5d9bd4dd..56fa9a31 100644 --- a/hyperbrowser/types/agents.py +++ b/hyperbrowser/types/agents.py @@ -123,6 +123,12 @@ class CuaApiKeys(TypedDict, total=False): openai: Optional[str] +class CuaBaseUrls(TypedDict, total=False): + """Provider base URLs for an OpenAI CUA task.""" + + openai: Optional[str] + + class StartCuaTaskParams(TypedDict, total=False): """Parameters for starting an OpenAI CUA task.""" @@ -135,6 +141,7 @@ class StartCuaTaskParams(TypedDict, total=False): session_options: Optional[CreateSessionParams] use_custom_api_keys: Optional[bool] api_keys: Optional[CuaApiKeys] + base_urls: Optional[CuaBaseUrls] use_computer_action: Optional[bool] @@ -165,6 +172,7 @@ class StartHyperAgentTaskParams(TypedDict, total=False): "BrowserUseApiKeys", "ClaudeComputerUseApiKeys", "CuaApiKeys", + "CuaBaseUrls", "GeminiComputerUseApiKeys", "GrokComputerUseApiKeys", "HyperAgentApiKeys", diff --git a/pyproject.toml b/pyproject.toml index 203a172d..955e8319 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "hyperbrowser" -version = "1.2.2" +version = "1.2.3" description = "Python SDK for hyperbrowser" authors = ["Nikhil Shahi "] license = "MIT" diff --git a/tests/test_request_compat.py b/tests/test_request_compat.py index 9217d8c4..b052881f 100644 --- a/tests/test_request_compat.py +++ b/tests/test_request_compat.py @@ -8,9 +8,11 @@ normalize_pydantic_schema, ) from hyperbrowser.models import ( + CuaBaseUrls, CreateSandboxParams, CreateSessionParams, StartBrowserUseTaskParams, + StartCuaTaskParams, ) from hyperbrowser.tools import _normalize_extract_tool_params @@ -76,6 +78,36 @@ def test_mapping_uses_existing_cross_field_validation(): ) +def test_cua_custom_base_url_serializes_for_mapping_and_legacy_model(): + mapping = { + "task": "Complete the task", + "use_custom_api_keys": True, + "api_keys": {"openai": "openai-key"}, + "base_urls": { + "openai": "https://example.openai.azure.com/openai/v1/", + }, + } + legacy = StartCuaTaskParams( + task="Complete the task", + use_custom_api_keys=True, + api_keys={"openai": "openai-key"}, + base_urls=CuaBaseUrls(openai="https://example.openai.azure.com/openai/v1/"), + ) + + assert dump_request(mapping, StartCuaTaskParams) == dump_request( + legacy, + StartCuaTaskParams, + ) + assert dump_request(mapping, StartCuaTaskParams) == { + "task": "Complete the task", + "useCustomApiKeys": True, + "apiKeys": {"openai": "openai-key"}, + "baseUrls": { + "openai": "https://example.openai.azure.com/openai/v1/", + }, + } + + def test_raw_json_schema_is_copied_without_rewriting_or_dereferencing(): schema = { "$defs": { diff --git a/tests/typecheck/valid_requests.py b/tests/typecheck/valid_requests.py index 34e9fdcd..6f4eeb1b 100644 --- a/tests/typecheck/valid_requests.py +++ b/tests/typecheck/valid_requests.py @@ -96,6 +96,16 @@ def valid_sync_requests(client: Hyperbrowser) -> None: "session_options": {"use_stealth": True}, } ) + client.agents.cua.start( + { + "task": "Complete the task", + "use_custom_api_keys": True, + "api_keys": {"openai": "openai-key"}, + "base_urls": { + "openai": "https://example.openai.azure.com/openai/v1/", + }, + } + ) client.sandboxes.create( { "image_name": "node", @@ -182,6 +192,16 @@ async def valid_async_requests(client: AsyncHyperbrowser) -> None: }, } ) + await client.agents.cua.start( + { + "task": "Complete the task", + "use_custom_api_keys": True, + "api_keys": {"openai": "openai-key"}, + "base_urls": { + "openai": "https://example.openai.azure.com/openai/v1/", + }, + } + ) await client.sandboxes.create( { "snapshot_name": "ready-to-run",