Skip to content

Commit 52adeba

Browse files
committed
Merge main into sandbox command streaming
2 parents 4fde86d + 6d4f087 commit 52adeba

16 files changed

Lines changed: 512 additions & 8 deletions

File tree

‎CLAUDE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ client.crawl # Website crawling jobs
4747
client.extract # Data extraction jobs
4848
client.web # Web fetch/search operations
4949
client.web.batch_fetch # Batch web fetch operations
50-
client.agents # AI agent integrations (browser_use, cua, claude_computer_use, hyper_agent, gemini_computer_use, grok_computer_use, meta_computer_use)
50+
client.agents # AI agent integrations (browser_use, cua, claude_computer_use, hyper_agent, gemini_computer_use, grok_computer_use, jev_computer_use, meta_computer_use)
5151
client.profiles # Browser profile management
5252
client.extensions # Browser extension management
5353
client.team # Team/credit info

‎hyperbrowser/client/managers/async_manager/agents/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .hyper_agent import HyperAgentManager
55
from .gemini_computer_use import GeminiComputerUseManager
66
from .grok_computer_use import GrokComputerUseManager
7+
from .jev_computer_use import JevComputerUseManager
78
from .meta_computer_use import MetaComputerUseManager
89

910

@@ -15,4 +16,5 @@ def __init__(self, client):
1516
self.hyper_agent = HyperAgentManager(client)
1617
self.gemini_computer_use = GeminiComputerUseManager(client)
1718
self.grok_computer_use = GrokComputerUseManager(client)
19+
self.jev_computer_use = JevComputerUseManager(client)
1820
self.meta_computer_use = MetaComputerUseManager(client)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import asyncio
2+
from typing import Union
3+
4+
from hyperbrowser.client._request import dump_request
5+
from hyperbrowser.exceptions import HyperbrowserError
6+
from hyperbrowser.types import (
7+
StartJevComputerUseTaskParams as StartJevComputerUseTaskParamsDict,
8+
)
9+
10+
from .....models import (
11+
POLLING_ATTEMPTS,
12+
BasicResponse,
13+
JevComputerUseTaskResponse,
14+
JevComputerUseTaskStatusResponse,
15+
StartJevComputerUseTaskParams,
16+
StartJevComputerUseTaskResponse,
17+
)
18+
19+
20+
class JevComputerUseManager:
21+
def __init__(self, client):
22+
self._client = client
23+
24+
async def start(
25+
self,
26+
params: Union[
27+
StartJevComputerUseTaskParamsDict,
28+
StartJevComputerUseTaskParams,
29+
],
30+
) -> StartJevComputerUseTaskResponse:
31+
response = await self._client.transport.post(
32+
self._client._build_url("/task/jev"),
33+
data=dump_request(params, StartJevComputerUseTaskParams),
34+
)
35+
return StartJevComputerUseTaskResponse(**response.data)
36+
37+
async def get(self, job_id: str) -> JevComputerUseTaskResponse:
38+
response = await self._client.transport.get(
39+
self._client._build_url(f"/task/jev/{job_id}")
40+
)
41+
return JevComputerUseTaskResponse(**response.data)
42+
43+
async def get_status(self, job_id: str) -> JevComputerUseTaskStatusResponse:
44+
response = await self._client.transport.get(
45+
self._client._build_url(f"/task/jev/{job_id}/status")
46+
)
47+
return JevComputerUseTaskStatusResponse(**response.data)
48+
49+
async def stop(self, job_id: str) -> BasicResponse:
50+
response = await self._client.transport.put(
51+
self._client._build_url(f"/task/jev/{job_id}/stop")
52+
)
53+
return BasicResponse(**response.data)
54+
55+
async def start_and_wait(
56+
self,
57+
params: Union[
58+
StartJevComputerUseTaskParamsDict,
59+
StartJevComputerUseTaskParams,
60+
],
61+
) -> JevComputerUseTaskResponse:
62+
job_start_resp = await self.start(params)
63+
job_id = job_start_resp.job_id
64+
if not job_id:
65+
raise HyperbrowserError("Failed to start Jev Computer Use task job")
66+
67+
failures = 0
68+
while True:
69+
try:
70+
job_response = await self.get_status(job_id)
71+
if (
72+
job_response.status == "completed"
73+
or job_response.status == "failed"
74+
or job_response.status == "stopped"
75+
):
76+
return await self.get(job_id)
77+
failures = 0
78+
except Exception as e:
79+
failures += 1
80+
if failures >= POLLING_ATTEMPTS:
81+
raise HyperbrowserError(
82+
f"Failed to poll Jev Computer Use task job {job_id} after {POLLING_ATTEMPTS} attempts: {e}"
83+
)
84+
await asyncio.sleep(2)

‎hyperbrowser/client/managers/sync_manager/agents/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .hyper_agent import HyperAgentManager
55
from .gemini_computer_use import GeminiComputerUseManager
66
from .grok_computer_use import GrokComputerUseManager
7+
from .jev_computer_use import JevComputerUseManager
78
from .meta_computer_use import MetaComputerUseManager
89

910

@@ -15,4 +16,5 @@ def __init__(self, client):
1516
self.hyper_agent = HyperAgentManager(client)
1617
self.gemini_computer_use = GeminiComputerUseManager(client)
1718
self.grok_computer_use = GrokComputerUseManager(client)
19+
self.jev_computer_use = JevComputerUseManager(client)
1820
self.meta_computer_use = MetaComputerUseManager(client)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import time
2+
from typing import Union
3+
4+
from hyperbrowser.client._request import dump_request
5+
from hyperbrowser.exceptions import HyperbrowserError
6+
from hyperbrowser.types import (
7+
StartJevComputerUseTaskParams as StartJevComputerUseTaskParamsDict,
8+
)
9+
10+
from .....models import (
11+
POLLING_ATTEMPTS,
12+
BasicResponse,
13+
JevComputerUseTaskResponse,
14+
JevComputerUseTaskStatusResponse,
15+
StartJevComputerUseTaskParams,
16+
StartJevComputerUseTaskResponse,
17+
)
18+
19+
20+
class JevComputerUseManager:
21+
def __init__(self, client):
22+
self._client = client
23+
24+
def start(
25+
self,
26+
params: Union[
27+
StartJevComputerUseTaskParamsDict,
28+
StartJevComputerUseTaskParams,
29+
],
30+
) -> StartJevComputerUseTaskResponse:
31+
response = self._client.transport.post(
32+
self._client._build_url("/task/jev"),
33+
data=dump_request(params, StartJevComputerUseTaskParams),
34+
)
35+
return StartJevComputerUseTaskResponse(**response.data)
36+
37+
def get(self, job_id: str) -> JevComputerUseTaskResponse:
38+
response = self._client.transport.get(
39+
self._client._build_url(f"/task/jev/{job_id}")
40+
)
41+
return JevComputerUseTaskResponse(**response.data)
42+
43+
def get_status(self, job_id: str) -> JevComputerUseTaskStatusResponse:
44+
response = self._client.transport.get(
45+
self._client._build_url(f"/task/jev/{job_id}/status")
46+
)
47+
return JevComputerUseTaskStatusResponse(**response.data)
48+
49+
def stop(self, job_id: str) -> BasicResponse:
50+
response = self._client.transport.put(
51+
self._client._build_url(f"/task/jev/{job_id}/stop")
52+
)
53+
return BasicResponse(**response.data)
54+
55+
def start_and_wait(
56+
self,
57+
params: Union[
58+
StartJevComputerUseTaskParamsDict,
59+
StartJevComputerUseTaskParams,
60+
],
61+
) -> JevComputerUseTaskResponse:
62+
job_start_resp = self.start(params)
63+
job_id = job_start_resp.job_id
64+
if not job_id:
65+
raise HyperbrowserError("Failed to start Jev Computer Use task job")
66+
67+
failures = 0
68+
while True:
69+
try:
70+
job_response = self.get_status(job_id)
71+
if (
72+
job_response.status == "completed"
73+
or job_response.status == "failed"
74+
or job_response.status == "stopped"
75+
):
76+
return self.get(job_id)
77+
failures = 0
78+
except Exception as e:
79+
failures += 1
80+
if failures >= POLLING_ATTEMPTS:
81+
raise HyperbrowserError(
82+
f"Failed to poll Jev Computer Use task job {job_id} after {POLLING_ATTEMPTS} attempts: {e}"
83+
)
84+
time.sleep(2)

‎hyperbrowser/models/__init__.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@
138138
StartMetaComputerUseTaskResponse,
139139
MetaComputerUseApiKeys,
140140
)
141+
from .agents.jev_computer_use import (
142+
JevComputerUseTaskStatus,
143+
JevComputerUseTaskData,
144+
JevComputerUseTaskResponse,
145+
JevComputerUseTaskStatusResponse,
146+
StartJevComputerUseTaskParams,
147+
StartJevComputerUseTaskResponse,
148+
JevComputerUseApiKeys,
149+
)
141150
from .agents.cua import (
142151
CuaTaskData,
143152
CuaTaskResponse,
@@ -175,6 +184,8 @@
175184
GrokReasoningEffort,
176185
MetaComputerUseLlm,
177186
MetaReasoningEffort,
187+
JevComputerUseLlm,
188+
JevTextLlm,
178189
Country,
179190
DownloadsStatus,
180191
FetchScreenshotFormat,
@@ -521,6 +532,12 @@
521532
"MetaComputerUseTaskStatusResponse",
522533
"StartMetaComputerUseTaskParams",
523534
"StartMetaComputerUseTaskResponse",
535+
"JevComputerUseTaskStatus",
536+
"JevComputerUseTaskData",
537+
"JevComputerUseTaskResponse",
538+
"JevComputerUseTaskStatusResponse",
539+
"StartJevComputerUseTaskParams",
540+
"StartJevComputerUseTaskResponse",
524541
"CuaTaskStatus",
525542
"CuaTaskData",
526543
"CuaTaskResponse",
@@ -531,6 +548,7 @@
531548
"ClaudeComputerUseApiKeys",
532549
"GeminiComputerUseApiKeys",
533550
"GrokComputerUseApiKeys",
551+
"JevComputerUseApiKeys",
534552
"MetaComputerUseApiKeys",
535553
"CuaApiKeys",
536554
"CuaBaseUrls",
@@ -539,6 +557,8 @@
539557
"GrokReasoningEffort",
540558
"MetaComputerUseLlm",
541559
"MetaReasoningEffort",
560+
"JevComputerUseLlm",
561+
"JevTextLlm",
542562
"HyperAgentOutputV110",
543563
"HyperAgentStepV110",
544564
# crawl
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from __future__ import annotations
2+
3+
from typing import Any, Dict, List, Literal, Optional
4+
5+
from pydantic import BaseModel, ConfigDict, Field
6+
7+
from ..session import CreateSessionParams
8+
from ..consts import JevComputerUseLlm, JevTextLlm
9+
10+
JevComputerUseTaskStatus = Literal[
11+
"pending", "running", "completed", "failed", "stopped"
12+
]
13+
14+
15+
class JevComputerUseApiKeys(BaseModel):
16+
"""
17+
API keys for the Jev Computer Use task.
18+
"""
19+
20+
model_config = ConfigDict(
21+
populate_by_alias=True,
22+
)
23+
24+
jev: Optional[str] = Field(default=None, serialization_alias="jev")
25+
google: Optional[str] = Field(default=None, serialization_alias="google")
26+
27+
28+
class StartJevComputerUseTaskParams(BaseModel):
29+
"""
30+
Parameters for creating a new Jev Computer Use task.
31+
"""
32+
33+
model_config = ConfigDict(
34+
populate_by_alias=True,
35+
)
36+
37+
task: str
38+
llm: Optional[JevComputerUseLlm] = Field(default=None, serialization_alias="llm")
39+
text_llm: Optional[JevTextLlm] = Field(default=None, serialization_alias="textLlm")
40+
session_id: Optional[str] = Field(default=None, serialization_alias="sessionId")
41+
max_failures: Optional[int] = Field(default=None, serialization_alias="maxFailures")
42+
max_steps: Optional[int] = Field(default=None, serialization_alias="maxSteps")
43+
keep_browser_open: Optional[bool] = Field(
44+
default=None, serialization_alias="keepBrowserOpen"
45+
)
46+
session_options: Optional[CreateSessionParams] = Field(
47+
default=None, serialization_alias="sessionOptions"
48+
)
49+
use_custom_api_keys: Optional[bool] = Field(
50+
default=None, serialization_alias="useCustomApiKeys"
51+
)
52+
api_keys: Optional[JevComputerUseApiKeys] = Field(
53+
default=None, serialization_alias="apiKeys"
54+
)
55+
56+
57+
class StartJevComputerUseTaskResponse(BaseModel):
58+
"""
59+
Response from starting a Jev Computer Use task.
60+
"""
61+
62+
model_config = ConfigDict(
63+
populate_by_alias=True,
64+
)
65+
66+
job_id: str = Field(alias="jobId")
67+
live_url: Optional[str] = Field(default=None, alias="liveUrl")
68+
69+
70+
class JevComputerUseTaskStatusResponse(BaseModel):
71+
"""
72+
Response from getting a Jev Computer Use task status.
73+
"""
74+
75+
model_config = ConfigDict(
76+
populate_by_alias=True,
77+
)
78+
79+
status: JevComputerUseTaskStatus
80+
81+
82+
class JevComputerUseTaskData(BaseModel):
83+
model_config = ConfigDict(
84+
populate_by_alias=True,
85+
)
86+
87+
steps: List[Dict[str, Any]]
88+
final_result: Optional[str] = Field(default=None, alias="finalResult")
89+
90+
91+
class JevComputerUseTaskMetadata(BaseModel):
92+
model_config = ConfigDict(
93+
populate_by_alias=True,
94+
)
95+
96+
input_tokens: Optional[int] = Field(default=None, alias="inputTokens")
97+
output_tokens: Optional[int] = Field(default=None, alias="outputTokens")
98+
num_task_steps_completed: Optional[int] = Field(
99+
default=None, alias="numTaskStepsCompleted"
100+
)
101+
102+
103+
class JevComputerUseTaskResponse(BaseModel):
104+
"""
105+
Response from a Jev Computer Use task.
106+
"""
107+
108+
model_config = ConfigDict(
109+
populate_by_alias=True,
110+
)
111+
112+
job_id: str = Field(alias="jobId")
113+
status: JevComputerUseTaskStatus
114+
metadata: Optional[JevComputerUseTaskMetadata] = Field(
115+
default=None, alias="metadata"
116+
)
117+
data: Optional[JevComputerUseTaskData] = Field(default=None, alias="data")
118+
error: Optional[str] = Field(default=None, alias="error")
119+
live_url: Optional[str] = Field(default=None, alias="liveUrl")

0 commit comments

Comments
 (0)