hyperbrowser 0.76.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of hyperbrowser might be problematic. Click here for more details.

Files changed (60) hide show
  1. hyperbrowser-0.76.0/LICENSE +21 -0
  2. hyperbrowser-0.76.0/PKG-INFO +131 -0
  3. hyperbrowser-0.76.0/README.md +105 -0
  4. hyperbrowser-0.76.0/hyperbrowser/__init__.py +5 -0
  5. hyperbrowser-0.76.0/hyperbrowser/client/async_client.py +46 -0
  6. hyperbrowser-0.76.0/hyperbrowser/client/base.py +42 -0
  7. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/agents/__init__.py +14 -0
  8. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/agents/browser_use.py +79 -0
  9. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/agents/claude_computer_use.py +71 -0
  10. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/agents/cua.py +67 -0
  11. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/agents/gemini_computer_use.py +71 -0
  12. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/agents/hyper_agent.py +71 -0
  13. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/computer_action.py +165 -0
  14. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/crawl.py +117 -0
  15. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/extension.py +52 -0
  16. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/extract.py +64 -0
  17. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/profile.py +45 -0
  18. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/scrape.py +172 -0
  19. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/session.py +123 -0
  20. hyperbrowser-0.76.0/hyperbrowser/client/managers/async_manager/team.py +12 -0
  21. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/agents/__init__.py +14 -0
  22. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/agents/browser_use.py +77 -0
  23. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/agents/claude_computer_use.py +71 -0
  24. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/agents/cua.py +67 -0
  25. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/agents/gemini_computer_use.py +71 -0
  26. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/agents/hyper_agent.py +69 -0
  27. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/computer_action.py +165 -0
  28. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/crawl.py +118 -0
  29. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/extension.py +52 -0
  30. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/extract.py +63 -0
  31. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/profile.py +45 -0
  32. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/scrape.py +170 -0
  33. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/session.py +117 -0
  34. hyperbrowser-0.76.0/hyperbrowser/client/managers/sync_manager/team.py +12 -0
  35. hyperbrowser-0.76.0/hyperbrowser/client/sync.py +40 -0
  36. hyperbrowser-0.76.0/hyperbrowser/config.py +22 -0
  37. hyperbrowser-0.76.0/hyperbrowser/exceptions.py +38 -0
  38. hyperbrowser-0.76.0/hyperbrowser/models/__init__.py +340 -0
  39. hyperbrowser-0.76.0/hyperbrowser/models/agents/browser_use.py +299 -0
  40. hyperbrowser-0.76.0/hyperbrowser/models/agents/claude_computer_use.py +135 -0
  41. hyperbrowser-0.76.0/hyperbrowser/models/agents/cua.py +163 -0
  42. hyperbrowser-0.76.0/hyperbrowser/models/agents/gemini_computer_use.py +135 -0
  43. hyperbrowser-0.76.0/hyperbrowser/models/agents/hyper_agent.py +153 -0
  44. hyperbrowser-0.76.0/hyperbrowser/models/computer_action.py +208 -0
  45. hyperbrowser-0.76.0/hyperbrowser/models/consts.py +644 -0
  46. hyperbrowser-0.76.0/hyperbrowser/models/crawl.py +104 -0
  47. hyperbrowser-0.76.0/hyperbrowser/models/extension.py +27 -0
  48. hyperbrowser-0.76.0/hyperbrowser/models/extract.py +81 -0
  49. hyperbrowser-0.76.0/hyperbrowser/models/profile.py +80 -0
  50. hyperbrowser-0.76.0/hyperbrowser/models/scrape.py +226 -0
  51. hyperbrowser-0.76.0/hyperbrowser/models/session.py +404 -0
  52. hyperbrowser-0.76.0/hyperbrowser/models/team.py +15 -0
  53. hyperbrowser-0.76.0/hyperbrowser/tools/__init__.py +126 -0
  54. hyperbrowser-0.76.0/hyperbrowser/tools/anthropic.py +80 -0
  55. hyperbrowser-0.76.0/hyperbrowser/tools/openai.py +105 -0
  56. hyperbrowser-0.76.0/hyperbrowser/tools/schema.py +189 -0
  57. hyperbrowser-0.76.0/hyperbrowser/transport/async_transport.py +114 -0
  58. hyperbrowser-0.76.0/hyperbrowser/transport/base.py +61 -0
  59. hyperbrowser-0.76.0/hyperbrowser/transport/sync.py +93 -0
  60. hyperbrowser-0.76.0/pyproject.toml +25 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 S2 Labs Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyperbrowser
3
+ Version: 0.76.0
4
+ Summary: Python SDK for hyperbrowser
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Author: Nikhil Shahi
8
+ Author-email: nshahi1998@gmail.com
9
+ Requires-Python: >=3.8,<4.0
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Requires-Dist: httpx (>=0.23.0,<1)
20
+ Requires-Dist: jsonref (>=1.1.0)
21
+ Requires-Dist: pydantic (>=2.0,<3)
22
+ Project-URL: Homepage, https://github.com/hyperbrowserai/python-sdk
23
+ Project-URL: Repository, https://github.com/hyperbrowserai/python-sdk
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Hyperbrowser Python SDK
27
+
28
+ Checkout the full documentation [here](https://docs.hyperbrowser.ai/)
29
+
30
+ ## Installation
31
+
32
+ Currently Hyperbrowser supports creating a browser session in two ways:
33
+
34
+ - Async Client
35
+ - Sync Client
36
+
37
+ It can be installed from `pypi` by running :
38
+
39
+ ```shell
40
+ pip install hyperbrowser
41
+ ```
42
+
43
+ ## Configuration
44
+
45
+ Both the sync and async client follow similar configuration params
46
+
47
+ ### API Key
48
+ The API key can be configured either from the constructor arguments or environment variables using `HYPERBROWSER_API_KEY`
49
+
50
+ ## Usage
51
+
52
+ ### Async
53
+
54
+ ```python
55
+ import asyncio
56
+ from pyppeteer import connect
57
+ from hyperbrowser import AsyncHyperbrowser
58
+
59
+ HYPERBROWSER_API_KEY = "test-key"
60
+
61
+ async def main():
62
+ async with AsyncHyperbrowser(api_key=HYPERBROWSER_API_KEY) as client:
63
+ session = await client.sessions.create()
64
+
65
+ ws_endpoint = session.ws_endpoint
66
+ browser = await connect(browserWSEndpoint=ws_endpoint, defaultViewport=None)
67
+
68
+ # Get pages
69
+ pages = await browser.pages()
70
+ if not pages:
71
+ raise Exception("No pages available")
72
+
73
+ page = pages[0]
74
+
75
+ # Navigate to a website
76
+ print("Navigating to Hacker News...")
77
+ await page.goto("https://news.ycombinator.com/")
78
+ page_title = await page.title()
79
+ print("Page title:", page_title)
80
+
81
+ await page.close()
82
+ await browser.disconnect()
83
+ await client.sessions.stop(session.id)
84
+ print("Session completed!")
85
+
86
+ # Run the asyncio event loop
87
+ asyncio.get_event_loop().run_until_complete(main())
88
+ ```
89
+ ### Sync
90
+
91
+ ```python
92
+ from playwright.sync_api import sync_playwright
93
+ from hyperbrowser import Hyperbrowser
94
+
95
+ HYPERBROWSER_API_KEY = "test-key"
96
+
97
+ def main():
98
+ client = Hyperbrowser(api_key=HYPERBROWSER_API_KEY)
99
+ session = client.sessions.create()
100
+
101
+ ws_endpoint = session.ws_endpoint
102
+
103
+ # Launch Playwright and connect to the remote browser
104
+ with sync_playwright() as p:
105
+ browser = p.chromium.connect_over_cdp(ws_endpoint)
106
+ context = browser.new_context()
107
+
108
+ # Get the first page or create a new one
109
+ if len(context.pages) == 0:
110
+ page = context.new_page()
111
+ else:
112
+ page = context.pages[0]
113
+
114
+ # Navigate to a website
115
+ print("Navigating to Hacker News...")
116
+ page.goto("https://news.ycombinator.com/")
117
+ page_title = page.title()
118
+ print("Page title:", page_title)
119
+
120
+ page.close()
121
+ browser.close()
122
+ print("Session completed!")
123
+ client.sessions.stop(session.id)
124
+
125
+ # Run the asyncio event loop
126
+ main()
127
+ ```
128
+ ## License
129
+
130
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
131
+
@@ -0,0 +1,105 @@
1
+ # Hyperbrowser Python SDK
2
+
3
+ Checkout the full documentation [here](https://docs.hyperbrowser.ai/)
4
+
5
+ ## Installation
6
+
7
+ Currently Hyperbrowser supports creating a browser session in two ways:
8
+
9
+ - Async Client
10
+ - Sync Client
11
+
12
+ It can be installed from `pypi` by running :
13
+
14
+ ```shell
15
+ pip install hyperbrowser
16
+ ```
17
+
18
+ ## Configuration
19
+
20
+ Both the sync and async client follow similar configuration params
21
+
22
+ ### API Key
23
+ The API key can be configured either from the constructor arguments or environment variables using `HYPERBROWSER_API_KEY`
24
+
25
+ ## Usage
26
+
27
+ ### Async
28
+
29
+ ```python
30
+ import asyncio
31
+ from pyppeteer import connect
32
+ from hyperbrowser import AsyncHyperbrowser
33
+
34
+ HYPERBROWSER_API_KEY = "test-key"
35
+
36
+ async def main():
37
+ async with AsyncHyperbrowser(api_key=HYPERBROWSER_API_KEY) as client:
38
+ session = await client.sessions.create()
39
+
40
+ ws_endpoint = session.ws_endpoint
41
+ browser = await connect(browserWSEndpoint=ws_endpoint, defaultViewport=None)
42
+
43
+ # Get pages
44
+ pages = await browser.pages()
45
+ if not pages:
46
+ raise Exception("No pages available")
47
+
48
+ page = pages[0]
49
+
50
+ # Navigate to a website
51
+ print("Navigating to Hacker News...")
52
+ await page.goto("https://news.ycombinator.com/")
53
+ page_title = await page.title()
54
+ print("Page title:", page_title)
55
+
56
+ await page.close()
57
+ await browser.disconnect()
58
+ await client.sessions.stop(session.id)
59
+ print("Session completed!")
60
+
61
+ # Run the asyncio event loop
62
+ asyncio.get_event_loop().run_until_complete(main())
63
+ ```
64
+ ### Sync
65
+
66
+ ```python
67
+ from playwright.sync_api import sync_playwright
68
+ from hyperbrowser import Hyperbrowser
69
+
70
+ HYPERBROWSER_API_KEY = "test-key"
71
+
72
+ def main():
73
+ client = Hyperbrowser(api_key=HYPERBROWSER_API_KEY)
74
+ session = client.sessions.create()
75
+
76
+ ws_endpoint = session.ws_endpoint
77
+
78
+ # Launch Playwright and connect to the remote browser
79
+ with sync_playwright() as p:
80
+ browser = p.chromium.connect_over_cdp(ws_endpoint)
81
+ context = browser.new_context()
82
+
83
+ # Get the first page or create a new one
84
+ if len(context.pages) == 0:
85
+ page = context.new_page()
86
+ else:
87
+ page = context.pages[0]
88
+
89
+ # Navigate to a website
90
+ print("Navigating to Hacker News...")
91
+ page.goto("https://news.ycombinator.com/")
92
+ page_title = page.title()
93
+ print("Page title:", page_title)
94
+
95
+ page.close()
96
+ browser.close()
97
+ print("Session completed!")
98
+ client.sessions.stop(session.id)
99
+
100
+ # Run the asyncio event loop
101
+ main()
102
+ ```
103
+ ## License
104
+
105
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,5 @@
1
+ from .client.sync import Hyperbrowser
2
+ from .client.async_client import AsyncHyperbrowser
3
+ from .config import ClientConfig
4
+
5
+ __all__ = ["Hyperbrowser", "AsyncHyperbrowser", "ClientConfig"]
@@ -0,0 +1,46 @@
1
+ from typing import Optional
2
+
3
+ from ..config import ClientConfig
4
+ from ..transport.async_transport import AsyncTransport
5
+ from .base import HyperbrowserBase
6
+ from .managers.async_manager.agents import Agents
7
+ from .managers.async_manager.crawl import CrawlManager
8
+ from .managers.async_manager.extension import ExtensionManager
9
+ from .managers.async_manager.extract import ExtractManager
10
+ from .managers.async_manager.profile import ProfileManager
11
+ from .managers.async_manager.scrape import ScrapeManager
12
+ from .managers.async_manager.session import SessionManager
13
+ from .managers.async_manager.team import TeamManager
14
+ from .managers.async_manager.computer_action import ComputerActionManager
15
+
16
+
17
+ class AsyncHyperbrowser(HyperbrowserBase):
18
+ """Asynchronous Hyperbrowser client"""
19
+
20
+ def __init__(
21
+ self,
22
+ config: Optional[ClientConfig] = None,
23
+ api_key: Optional[str] = None,
24
+ base_url: Optional[str] = None,
25
+ timeout: Optional[int] = 30,
26
+ ):
27
+ super().__init__(AsyncTransport, config, api_key, base_url)
28
+ self.transport.client.timeout = timeout
29
+ self.sessions = SessionManager(self)
30
+ self.scrape = ScrapeManager(self)
31
+ self.crawl = CrawlManager(self)
32
+ self.extract = ExtractManager(self)
33
+ self.profiles = ProfileManager(self)
34
+ self.extensions = ExtensionManager(self)
35
+ self.agents = Agents(self)
36
+ self.team = TeamManager(self)
37
+ self.computer_action = ComputerActionManager(self)
38
+
39
+ async def close(self) -> None:
40
+ await self.transport.close()
41
+
42
+ async def __aenter__(self):
43
+ return self
44
+
45
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
46
+ await self.close()
@@ -0,0 +1,42 @@
1
+ from typing import Optional
2
+
3
+ from hyperbrowser.exceptions import HyperbrowserError
4
+ from ..config import ClientConfig
5
+ from ..transport.base import TransportStrategy
6
+ import os
7
+
8
+
9
+ class HyperbrowserBase:
10
+ """Base class with shared functionality for sync/async clients"""
11
+
12
+ def __init__(
13
+ self,
14
+ transport: TransportStrategy,
15
+ config: Optional[ClientConfig] = None,
16
+ api_key: Optional[str] = None,
17
+ base_url: Optional[str] = None,
18
+ ):
19
+ if config is None:
20
+ config = ClientConfig(
21
+ api_key=(
22
+ api_key
23
+ if api_key is not None
24
+ else os.environ.get("HYPERBROWSER_API_KEY", "")
25
+ ),
26
+ base_url=(
27
+ base_url
28
+ if base_url is not None
29
+ else os.environ.get(
30
+ "HYPERBROWSER_BASE_URL", "https://api.hyperbrowser.ai"
31
+ )
32
+ ),
33
+ )
34
+
35
+ if not config.api_key:
36
+ raise HyperbrowserError("API key must be provided")
37
+
38
+ self.config = config
39
+ self.transport = transport(config.api_key)
40
+
41
+ def _build_url(self, path: str) -> str:
42
+ return f"{self.config.base_url}/api{path}"
@@ -0,0 +1,14 @@
1
+ from .browser_use import BrowserUseManager
2
+ from .cua import CuaManager
3
+ from .claude_computer_use import ClaudeComputerUseManager
4
+ from .hyper_agent import HyperAgentManager
5
+ from .gemini_computer_use import GeminiComputerUseManager
6
+
7
+
8
+ class Agents:
9
+ def __init__(self, client):
10
+ self.browser_use = BrowserUseManager(client)
11
+ self.cua = CuaManager(client)
12
+ self.claude_computer_use = ClaudeComputerUseManager(client)
13
+ self.hyper_agent = HyperAgentManager(client)
14
+ self.gemini_computer_use = GeminiComputerUseManager(client)
@@ -0,0 +1,79 @@
1
+ import asyncio
2
+ import jsonref
3
+
4
+ from hyperbrowser.exceptions import HyperbrowserError
5
+
6
+ from .....models import (
7
+ POLLING_ATTEMPTS,
8
+ BasicResponse,
9
+ BrowserUseTaskResponse,
10
+ BrowserUseTaskStatusResponse,
11
+ StartBrowserUseTaskParams,
12
+ StartBrowserUseTaskResponse,
13
+ )
14
+
15
+
16
+ class BrowserUseManager:
17
+ def __init__(self, client):
18
+ self._client = client
19
+
20
+ async def start(
21
+ self, params: StartBrowserUseTaskParams
22
+ ) -> StartBrowserUseTaskResponse:
23
+ if params.output_model_schema:
24
+ if hasattr(params.output_model_schema, "model_json_schema"):
25
+ params.output_model_schema = jsonref.replace_refs(
26
+ params.output_model_schema.model_json_schema(),
27
+ proxies=False,
28
+ lazy_load=False,
29
+ )
30
+ response = await self._client.transport.post(
31
+ self._client._build_url("/task/browser-use"),
32
+ data=params.model_dump(exclude_none=True, by_alias=True),
33
+ )
34
+ return StartBrowserUseTaskResponse(**response.data)
35
+
36
+ async def get(self, job_id: str) -> BrowserUseTaskResponse:
37
+ response = await self._client.transport.get(
38
+ self._client._build_url(f"/task/browser-use/{job_id}")
39
+ )
40
+ return BrowserUseTaskResponse(**response.data)
41
+
42
+ async def get_status(self, job_id: str) -> BrowserUseTaskStatusResponse:
43
+ response = await self._client.transport.get(
44
+ self._client._build_url(f"/task/browser-use/{job_id}/status")
45
+ )
46
+ return BrowserUseTaskStatusResponse(**response.data)
47
+
48
+ async def stop(self, job_id: str) -> BasicResponse:
49
+ response = await self._client.transport.put(
50
+ self._client._build_url(f"/task/browser-use/{job_id}/stop")
51
+ )
52
+ return BasicResponse(**response.data)
53
+
54
+ async def start_and_wait(
55
+ self, params: StartBrowserUseTaskParams
56
+ ) -> BrowserUseTaskResponse:
57
+ job_start_resp = await self.start(params)
58
+ job_id = job_start_resp.job_id
59
+ if not job_id:
60
+ raise HyperbrowserError("Failed to start browser-use task job")
61
+
62
+ failures = 0
63
+ while True:
64
+ try:
65
+ job_response = await self.get_status(job_id)
66
+ if (
67
+ job_response.status == "completed"
68
+ or job_response.status == "failed"
69
+ or job_response.status == "stopped"
70
+ ):
71
+ return await self.get(job_id)
72
+ failures = 0
73
+ except Exception as e:
74
+ failures += 1
75
+ if failures >= POLLING_ATTEMPTS:
76
+ raise HyperbrowserError(
77
+ f"Failed to poll browser-use task job {job_id} after {POLLING_ATTEMPTS} attempts: {e}"
78
+ )
79
+ await asyncio.sleep(2)
@@ -0,0 +1,71 @@
1
+ import asyncio
2
+
3
+ from hyperbrowser.exceptions import HyperbrowserError
4
+
5
+ from .....models import (
6
+ POLLING_ATTEMPTS,
7
+ BasicResponse,
8
+ ClaudeComputerUseTaskResponse,
9
+ ClaudeComputerUseTaskStatusResponse,
10
+ StartClaudeComputerUseTaskParams,
11
+ StartClaudeComputerUseTaskResponse,
12
+ )
13
+
14
+
15
+ class ClaudeComputerUseManager:
16
+ def __init__(self, client):
17
+ self._client = client
18
+
19
+ async def start(
20
+ self, params: StartClaudeComputerUseTaskParams
21
+ ) -> StartClaudeComputerUseTaskResponse:
22
+ response = await self._client.transport.post(
23
+ self._client._build_url("/task/claude-computer-use"),
24
+ data=params.model_dump(exclude_none=True, by_alias=True),
25
+ )
26
+ return StartClaudeComputerUseTaskResponse(**response.data)
27
+
28
+ async def get(self, job_id: str) -> ClaudeComputerUseTaskResponse:
29
+ response = await self._client.transport.get(
30
+ self._client._build_url(f"/task/claude-computer-use/{job_id}")
31
+ )
32
+ return ClaudeComputerUseTaskResponse(**response.data)
33
+
34
+ async def get_status(self, job_id: str) -> ClaudeComputerUseTaskStatusResponse:
35
+ response = await self._client.transport.get(
36
+ self._client._build_url(f"/task/claude-computer-use/{job_id}/status")
37
+ )
38
+ return ClaudeComputerUseTaskStatusResponse(**response.data)
39
+
40
+ async def stop(self, job_id: str) -> BasicResponse:
41
+ response = await self._client.transport.put(
42
+ self._client._build_url(f"/task/claude-computer-use/{job_id}/stop")
43
+ )
44
+ return BasicResponse(**response.data)
45
+
46
+ async def start_and_wait(
47
+ self, params: StartClaudeComputerUseTaskParams
48
+ ) -> ClaudeComputerUseTaskResponse:
49
+ job_start_resp = await self.start(params)
50
+ job_id = job_start_resp.job_id
51
+ if not job_id:
52
+ raise HyperbrowserError("Failed to start Claude Computer Use task job")
53
+
54
+ failures = 0
55
+ while True:
56
+ try:
57
+ job_response = await self.get_status(job_id)
58
+ if (
59
+ job_response.status == "completed"
60
+ or job_response.status == "failed"
61
+ or job_response.status == "stopped"
62
+ ):
63
+ return await self.get(job_id)
64
+ failures = 0
65
+ except Exception as e:
66
+ failures += 1
67
+ if failures >= POLLING_ATTEMPTS:
68
+ raise HyperbrowserError(
69
+ f"Failed to poll Claude Computer Use task job {job_id} after {POLLING_ATTEMPTS} attempts: {e}"
70
+ )
71
+ await asyncio.sleep(2)
@@ -0,0 +1,67 @@
1
+ import asyncio
2
+
3
+ from hyperbrowser.exceptions import HyperbrowserError
4
+
5
+ from .....models import (
6
+ POLLING_ATTEMPTS,
7
+ BasicResponse,
8
+ CuaTaskResponse,
9
+ CuaTaskStatusResponse,
10
+ StartCuaTaskParams,
11
+ StartCuaTaskResponse,
12
+ )
13
+
14
+
15
+ class CuaManager:
16
+ def __init__(self, client):
17
+ self._client = client
18
+
19
+ async def start(self, params: StartCuaTaskParams) -> StartCuaTaskResponse:
20
+ response = await self._client.transport.post(
21
+ self._client._build_url("/task/cua"),
22
+ data=params.model_dump(exclude_none=True, by_alias=True),
23
+ )
24
+ return StartCuaTaskResponse(**response.data)
25
+
26
+ async def get(self, job_id: str) -> CuaTaskResponse:
27
+ response = await self._client.transport.get(
28
+ self._client._build_url(f"/task/cua/{job_id}")
29
+ )
30
+ return CuaTaskResponse(**response.data)
31
+
32
+ async def get_status(self, job_id: str) -> CuaTaskStatusResponse:
33
+ response = await self._client.transport.get(
34
+ self._client._build_url(f"/task/cua/{job_id}/status")
35
+ )
36
+ return CuaTaskStatusResponse(**response.data)
37
+
38
+ async def stop(self, job_id: str) -> BasicResponse:
39
+ response = await self._client.transport.put(
40
+ self._client._build_url(f"/task/cua/{job_id}/stop")
41
+ )
42
+ return BasicResponse(**response.data)
43
+
44
+ async def start_and_wait(self, params: StartCuaTaskParams) -> CuaTaskResponse:
45
+ job_start_resp = await self.start(params)
46
+ job_id = job_start_resp.job_id
47
+ if not job_id:
48
+ raise HyperbrowserError("Failed to start CUA task job")
49
+
50
+ failures = 0
51
+ while True:
52
+ try:
53
+ job_response = await self.get_status(job_id)
54
+ if (
55
+ job_response.status == "completed"
56
+ or job_response.status == "failed"
57
+ or job_response.status == "stopped"
58
+ ):
59
+ return await self.get(job_id)
60
+ failures = 0
61
+ except Exception as e:
62
+ failures += 1
63
+ if failures >= POLLING_ATTEMPTS:
64
+ raise HyperbrowserError(
65
+ f"Failed to poll CUA task job {job_id} after {POLLING_ATTEMPTS} attempts: {e}"
66
+ )
67
+ await asyncio.sleep(2)
@@ -0,0 +1,71 @@
1
+ import asyncio
2
+
3
+ from hyperbrowser.exceptions import HyperbrowserError
4
+
5
+ from .....models import (
6
+ POLLING_ATTEMPTS,
7
+ BasicResponse,
8
+ GeminiComputerUseTaskResponse,
9
+ GeminiComputerUseTaskStatusResponse,
10
+ StartGeminiComputerUseTaskParams,
11
+ StartGeminiComputerUseTaskResponse,
12
+ )
13
+
14
+
15
+ class GeminiComputerUseManager:
16
+ def __init__(self, client):
17
+ self._client = client
18
+
19
+ async def start(
20
+ self, params: StartGeminiComputerUseTaskParams
21
+ ) -> StartGeminiComputerUseTaskResponse:
22
+ response = await self._client.transport.post(
23
+ self._client._build_url("/task/gemini-computer-use"),
24
+ data=params.model_dump(exclude_none=True, by_alias=True),
25
+ )
26
+ return StartGeminiComputerUseTaskResponse(**response.data)
27
+
28
+ async def get(self, job_id: str) -> GeminiComputerUseTaskResponse:
29
+ response = await self._client.transport.get(
30
+ self._client._build_url(f"/task/gemini-computer-use/{job_id}")
31
+ )
32
+ return GeminiComputerUseTaskResponse(**response.data)
33
+
34
+ async def get_status(self, job_id: str) -> GeminiComputerUseTaskStatusResponse:
35
+ response = await self._client.transport.get(
36
+ self._client._build_url(f"/task/gemini-computer-use/{job_id}/status")
37
+ )
38
+ return GeminiComputerUseTaskStatusResponse(**response.data)
39
+
40
+ async def stop(self, job_id: str) -> BasicResponse:
41
+ response = await self._client.transport.put(
42
+ self._client._build_url(f"/task/gemini-computer-use/{job_id}/stop")
43
+ )
44
+ return BasicResponse(**response.data)
45
+
46
+ async def start_and_wait(
47
+ self, params: StartGeminiComputerUseTaskParams
48
+ ) -> GeminiComputerUseTaskResponse:
49
+ job_start_resp = await self.start(params)
50
+ job_id = job_start_resp.job_id
51
+ if not job_id:
52
+ raise HyperbrowserError("Failed to start Gemini Computer Use task job")
53
+
54
+ failures = 0
55
+ while True:
56
+ try:
57
+ job_response = await self.get_status(job_id)
58
+ if (
59
+ job_response.status == "completed"
60
+ or job_response.status == "failed"
61
+ or job_response.status == "stopped"
62
+ ):
63
+ return await self.get(job_id)
64
+ failures = 0
65
+ except Exception as e:
66
+ failures += 1
67
+ if failures >= POLLING_ATTEMPTS:
68
+ raise HyperbrowserError(
69
+ f"Failed to poll Gemini Computer Use task job {job_id} after {POLLING_ATTEMPTS} attempts: {e}"
70
+ )
71
+ await asyncio.sleep(2)