Skip to content

Commit a52d6aa

Browse files
NikhilShahicursoragentnikhil
authored
Add reasoning effort to OpenAI CUA and Claude Computer Use (#124)
* Add reasoning effort to OpenAI CUA and Claude Computer Use Expose the new reasoningEffort request field on both agents, matching the API and the existing Grok/Meta Computer Use pattern. Co-authored-by: nikhil <nikhil@metlo.com> * Bump version from 1.4.2 to 1.4.3 Co-authored-by: nikhil <nikhil@metlo.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: nikhil <nikhil@metlo.com>
1 parent 664afbf commit a52d6aa

8 files changed

Lines changed: 87 additions & 3 deletions

File tree

hyperbrowser/models/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@
168168
HyperAgentLlm,
169169
BrowserUseLlm,
170170
ClaudeComputerUseLlm,
171+
ClaudeComputerUseReasoningEffort,
171172
CuaLlm,
173+
CuaReasoningEffort,
172174
GrokComputerUseLlm,
173175
GrokReasoningEffort,
174176
MetaComputerUseLlm,
@@ -428,7 +430,9 @@
428430
"HyperAgentLlm",
429431
"BrowserUseLlm",
430432
"ClaudeComputerUseLlm",
433+
"ClaudeComputerUseReasoningEffort",
431434
"CuaLlm",
435+
"CuaReasoningEffort",
432436
"Country",
433437
"DownloadsStatus",
434438
"FetchScreenshotFormat",

hyperbrowser/models/agents/claude_computer_use.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from pydantic import BaseModel, ConfigDict, Field
66

77
from ..session import CreateSessionParams
8-
from ..consts import ClaudeComputerUseLlm
8+
from ..consts import ClaudeComputerUseLlm, ClaudeComputerUseReasoningEffort
99

1010
ClaudeComputerUseTaskStatus = Literal[
1111
"pending", "running", "completed", "failed", "stopped"
@@ -35,6 +35,9 @@ class StartClaudeComputerUseTaskParams(BaseModel):
3535

3636
task: str
3737
llm: Optional[ClaudeComputerUseLlm] = Field(default=None, serialization_alias="llm")
38+
reasoning_effort: Optional[ClaudeComputerUseReasoningEffort] = Field(
39+
default=None, serialization_alias="reasoningEffort"
40+
)
3841
session_id: Optional[str] = Field(default=None, serialization_alias="sessionId")
3942
max_failures: Optional[int] = Field(default=None, serialization_alias="maxFailures")
4043
max_steps: Optional[int] = Field(default=None, serialization_alias="maxSteps")

hyperbrowser/models/agents/cua.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from pydantic import BaseModel, ConfigDict, Field
66

7-
from ..consts import CuaLlm
7+
from ..consts import CuaLlm, CuaReasoningEffort
88
from ..session import CreateSessionParams
99

1010
CuaTaskStatus = Literal["pending", "running", "completed", "failed", "stopped"]
@@ -45,6 +45,9 @@ class StartCuaTaskParams(BaseModel):
4545

4646
task: str
4747
llm: Optional[CuaLlm] = Field(default=None, serialization_alias="llm")
48+
reasoning_effort: Optional[CuaReasoningEffort] = Field(
49+
default=None, serialization_alias="reasoningEffort"
50+
)
4851
session_id: Optional[str] = Field(default=None, serialization_alias="sessionId")
4952
max_failures: Optional[int] = Field(default=None, serialization_alias="maxFailures")
5053
max_steps: Optional[int] = Field(default=None, serialization_alias="maxSteps")

hyperbrowser/models/consts.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@
8181
"claude-sonnet-4-20250514",
8282
"claude-3-7-sonnet-20250219",
8383
]
84+
ClaudeComputerUseReasoningEffort = Literal[
85+
"low",
86+
"medium",
87+
"high",
88+
"xhigh",
89+
"max",
90+
]
8491
CuaLlm = Literal[
8592
"computer-use-preview",
8693
"gpt-6-astra",
@@ -91,6 +98,14 @@
9198
"gpt-5.4",
9299
"gpt-5.4-mini",
93100
]
101+
CuaReasoningEffort = Literal[
102+
"none",
103+
"low",
104+
"medium",
105+
"high",
106+
"xhigh",
107+
"max",
108+
]
94109
GeminiComputerUseLlm = Literal[
95110
"gemini-3.8-flash",
96111
"gemini-3.7-flash",

hyperbrowser/types/agents.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
BrowserUseLlm,
77
BrowserUseVersion,
88
ClaudeComputerUseLlm,
9+
ClaudeComputerUseReasoningEffort,
910
CuaLlm,
11+
CuaReasoningEffort,
1012
GeminiComputerUseLlm,
1113
GrokComputerUseLlm,
1214
GrokReasoningEffort,
@@ -66,6 +68,7 @@ class StartClaudeComputerUseTaskParams(TypedDict, total=False):
6668

6769
task: Required[str]
6870
llm: Optional[ClaudeComputerUseLlm]
71+
reasoning_effort: Optional[ClaudeComputerUseReasoningEffort]
6972
session_id: Optional[str]
7073
max_failures: Optional[int]
7174
max_steps: Optional[int]
@@ -158,6 +161,7 @@ class StartCuaTaskParams(TypedDict, total=False):
158161

159162
task: Required[str]
160163
llm: Optional[CuaLlm]
164+
reasoning_effort: Optional[CuaReasoningEffort]
161165
session_id: Optional[str]
162166
max_failures: Optional[int]
163167
max_steps: Optional[int]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "hyperbrowser"
3-
version = "1.4.2"
3+
version = "1.4.3"
44
description = "Python SDK for hyperbrowser"
55
authors = ["Nikhil Shahi <nshahi1998@gmail.com>"]
66
license = "MIT"

tests/test_request_compat.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
normalize_pydantic_schema,
99
)
1010
from hyperbrowser.models import (
11+
ClaudeComputerUseApiKeys,
1112
CuaBaseUrls,
1213
CreateSandboxParams,
1314
CreateSessionParams,
1415
MetaComputerUseApiKeys,
1516
StartBrowserUseTaskParams,
17+
StartClaudeComputerUseTaskParams,
1618
StartCuaTaskParams,
1719
StartMetaComputerUseTaskParams,
1820
)
@@ -83,6 +85,8 @@ def test_mapping_uses_existing_cross_field_validation():
8385
def test_cua_custom_base_url_serializes_for_mapping_and_legacy_model():
8486
mapping = {
8587
"task": "Complete the task",
88+
"llm": "gpt-5.6-terra",
89+
"reasoning_effort": "high",
8690
"use_custom_api_keys": True,
8791
"api_keys": {"openai": "openai-key"},
8892
"base_urls": {
@@ -91,6 +95,8 @@ def test_cua_custom_base_url_serializes_for_mapping_and_legacy_model():
9195
}
9296
legacy = StartCuaTaskParams(
9397
task="Complete the task",
98+
llm="gpt-5.6-terra",
99+
reasoning_effort="high",
94100
use_custom_api_keys=True,
95101
api_keys={"openai": "openai-key"},
96102
base_urls=CuaBaseUrls(openai="https://example.openai.azure.com/openai/v1/"),
@@ -102,6 +108,8 @@ def test_cua_custom_base_url_serializes_for_mapping_and_legacy_model():
102108
)
103109
assert dump_request(mapping, StartCuaTaskParams) == {
104110
"task": "Complete the task",
111+
"llm": "gpt-5.6-terra",
112+
"reasoningEffort": "high",
105113
"useCustomApiKeys": True,
106114
"apiKeys": {"openai": "openai-key"},
107115
"baseUrls": {
@@ -110,6 +118,35 @@ def test_cua_custom_base_url_serializes_for_mapping_and_legacy_model():
110118
}
111119

112120

121+
def test_claude_computer_use_serializes_reasoning_effort_for_mapping_and_legacy_model():
122+
mapping = {
123+
"task": "Complete the task",
124+
"llm": "claude-opus-5",
125+
"reasoning_effort": "xhigh",
126+
"use_custom_api_keys": True,
127+
"api_keys": {"anthropic": "anthropic-key"},
128+
}
129+
legacy = StartClaudeComputerUseTaskParams(
130+
task="Complete the task",
131+
llm="claude-opus-5",
132+
reasoning_effort="xhigh",
133+
use_custom_api_keys=True,
134+
api_keys=ClaudeComputerUseApiKeys(anthropic="anthropic-key"),
135+
)
136+
137+
assert dump_request(mapping, StartClaudeComputerUseTaskParams) == dump_request(
138+
legacy,
139+
StartClaudeComputerUseTaskParams,
140+
)
141+
assert dump_request(mapping, StartClaudeComputerUseTaskParams) == {
142+
"task": "Complete the task",
143+
"llm": "claude-opus-5",
144+
"reasoningEffort": "xhigh",
145+
"useCustomApiKeys": True,
146+
"apiKeys": {"anthropic": "anthropic-key"},
147+
}
148+
149+
113150
def test_meta_computer_use_serializes_for_mapping_and_legacy_model():
114151
mapping = {
115152
"task": "Complete the task",

tests/typecheck/valid_requests.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,22 @@ def valid_sync_requests(client: Hyperbrowser) -> None:
9999
client.agents.cua.start(
100100
{
101101
"task": "Complete the task",
102+
"llm": "gpt-5.6-terra",
103+
"reasoning_effort": "high",
102104
"use_custom_api_keys": True,
103105
"api_keys": {"openai": "openai-key"},
104106
"base_urls": {
105107
"openai": "https://example.openai.azure.com/openai/v1/",
106108
},
107109
}
108110
)
111+
client.agents.claude_computer_use.start(
112+
{
113+
"task": "Complete the task",
114+
"llm": "claude-opus-5",
115+
"reasoning_effort": "xhigh",
116+
}
117+
)
109118
client.agents.meta_computer_use.start(
110119
{
111120
"task": "Complete the task",
@@ -235,13 +244,22 @@ async def valid_async_requests(client: AsyncHyperbrowser) -> None:
235244
await client.agents.cua.start(
236245
{
237246
"task": "Complete the task",
247+
"llm": "gpt-5.4",
248+
"reasoning_effort": "none",
238249
"use_custom_api_keys": True,
239250
"api_keys": {"openai": "openai-key"},
240251
"base_urls": {
241252
"openai": "https://example.openai.azure.com/openai/v1/",
242253
},
243254
}
244255
)
256+
await client.agents.claude_computer_use.start(
257+
{
258+
"task": "Complete the task",
259+
"llm": "claude-sonnet-4-6",
260+
"reasoning_effort": "max",
261+
}
262+
)
245263
await client.agents.meta_computer_use.start(
246264
{
247265
"task": "Complete the task",

0 commit comments

Comments
 (0)