hyperbrowser 1.9.4__tar.gz → 1.11.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.
Files changed (127) hide show
  1. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/PKG-INFO +35 -1
  2. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/README.md +34 -0
  3. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/computer_action.py +39 -6
  4. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/session.py +3 -0
  5. hyperbrowser-1.11.0/hyperbrowser/client/managers/async_manager/webmcp.py +98 -0
  6. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/computer_action.py +39 -6
  7. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/session.py +3 -0
  8. hyperbrowser-1.11.0/hyperbrowser/client/managers/sync_manager/webmcp.py +98 -0
  9. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/__init__.py +35 -0
  10. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/computer_action.py +39 -0
  11. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/session.py +6 -0
  12. hyperbrowser-1.11.0/hyperbrowser/models/webmcp.py +126 -0
  13. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/transport/async_transport.py +18 -2
  14. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/transport/base.py +8 -1
  15. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/transport/sync.py +18 -2
  16. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/__init__.py +13 -0
  17. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/computer_action.py +24 -0
  18. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/session.py +1 -0
  19. hyperbrowser-1.11.0/hyperbrowser/types/webmcp.py +22 -0
  20. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/pyproject.toml +1 -1
  21. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/LICENSE +0 -0
  22. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/__init__.py +0 -0
  23. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/build_context.py +0 -0
  24. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/_request.py +0 -0
  25. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/async_client.py +0 -0
  26. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/base.py +0 -0
  27. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/__init__.py +0 -0
  28. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/browser_use.py +0 -0
  29. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/claude_computer_use.py +0 -0
  30. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/cua.py +0 -0
  31. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/gemini_computer_use.py +0 -0
  32. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/grok_computer_use.py +0 -0
  33. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/hyper_agent.py +0 -0
  34. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/jev_computer_use.py +0 -0
  35. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/agents/meta_computer_use.py +0 -0
  36. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/crawl.py +0 -0
  37. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/extension.py +0 -0
  38. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/extract.py +0 -0
  39. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/profile.py +0 -0
  40. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/sandbox.py +0 -0
  41. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/sandboxes/__init__.py +0 -0
  42. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_files.py +0 -0
  43. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_processes.py +0 -0
  44. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_terminal.py +0 -0
  45. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_transport.py +0 -0
  46. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/scrape.py +0 -0
  47. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/team.py +0 -0
  48. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/volume.py +0 -0
  49. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/web/__init__.py +0 -0
  50. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/web/batch_fetch.py +0 -0
  51. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/async_manager/web/crawl.py +0 -0
  52. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sandboxes/__init__.py +0 -0
  53. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sandboxes/dockerfile_analysis.py +0 -0
  54. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sandboxes/dockerignore.py +0 -0
  55. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sandboxes/image_build.py +0 -0
  56. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sandboxes/image_resolution.py +0 -0
  57. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sandboxes/process_output.py +0 -0
  58. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sandboxes/shared.py +0 -0
  59. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/__init__.py +0 -0
  60. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/browser_use.py +0 -0
  61. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/claude_computer_use.py +0 -0
  62. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/cua.py +0 -0
  63. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/gemini_computer_use.py +0 -0
  64. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/grok_computer_use.py +0 -0
  65. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/hyper_agent.py +0 -0
  66. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/jev_computer_use.py +0 -0
  67. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/agents/meta_computer_use.py +0 -0
  68. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/crawl.py +0 -0
  69. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/extension.py +0 -0
  70. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/extract.py +0 -0
  71. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/profile.py +0 -0
  72. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/sandbox.py +0 -0
  73. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/sandboxes/__init__.py +0 -0
  74. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_files.py +0 -0
  75. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_processes.py +0 -0
  76. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_terminal.py +0 -0
  77. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_transport.py +0 -0
  78. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/scrape.py +0 -0
  79. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/team.py +0 -0
  80. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/volume.py +0 -0
  81. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/web/__init__.py +0 -0
  82. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/web/batch_fetch.py +0 -0
  83. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/managers/sync_manager/web/crawl.py +0 -0
  84. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/client/sync.py +0 -0
  85. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/config.py +0 -0
  86. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/exceptions.py +0 -0
  87. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/image_builds.py +0 -0
  88. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/_parsers.py +0 -0
  89. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/agents/browser_use.py +0 -0
  90. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/agents/claude_computer_use.py +0 -0
  91. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/agents/cua.py +0 -0
  92. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/agents/gemini_computer_use.py +0 -0
  93. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/agents/grok_computer_use.py +0 -0
  94. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/agents/hyper_agent.py +0 -0
  95. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/agents/jev_computer_use.py +0 -0
  96. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/agents/meta_computer_use.py +0 -0
  97. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/consts.py +0 -0
  98. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/crawl.py +0 -0
  99. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/extension.py +0 -0
  100. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/extract.py +0 -0
  101. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/profile.py +0 -0
  102. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/sandbox.py +0 -0
  103. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/scrape.py +0 -0
  104. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/team.py +0 -0
  105. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/volume.py +0 -0
  106. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/web/batch_fetch.py +0 -0
  107. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/web/branding.py +0 -0
  108. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/web/common.py +0 -0
  109. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/web/crawl.py +0 -0
  110. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/web/fetch.py +0 -0
  111. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/models/web/search.py +0 -0
  112. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/py.typed +0 -0
  113. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/sandbox_common.py +0 -0
  114. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/tools/__init__.py +0 -0
  115. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/tools/anthropic.py +0 -0
  116. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/tools/openai.py +0 -0
  117. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/tools/schema.py +0 -0
  118. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/_json.py +0 -0
  119. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/agents.py +0 -0
  120. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/crawl.py +0 -0
  121. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/extension.py +0 -0
  122. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/extract.py +0 -0
  123. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/profile.py +0 -0
  124. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/sandbox.py +0 -0
  125. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/scrape.py +0 -0
  126. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/volume.py +0 -0
  127. {hyperbrowser-1.9.4 → hyperbrowser-1.11.0}/hyperbrowser/types/web.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperbrowser
3
- Version: 1.9.4
3
+ Version: 1.11.0
4
4
  Summary: Python SDK for hyperbrowser
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -62,6 +62,40 @@ Profile names must match `^[A-Za-z0-9._-]+$`.
62
62
 
63
63
  `base_url` and `HYPERBROWSER_BASE_URL` accept either `https://host` or `https://host/api`. The client normalizes both to the same control-plane base URL.
64
64
 
65
+ ## WebMCP page tools
66
+
67
+ Create a session with `{"enable_web_mcp": True}` (default: false), then navigate
68
+ to a page that exposes WebMCP tools using Playwright. With that session open:
69
+
70
+ ```python
71
+ discovery = client.sessions.webmcp.list_tools(session.id)
72
+ # Select a tool using its name, source page/frame, and input schema.
73
+ tool = next(tool for tool in discovery.tools if tool.name == "search")
74
+ result = client.sessions.webmcp.invoke(session.id, {
75
+ "tool_ref": tool.tool_ref,
76
+ "input": {"query": "flights to Tokyo"}, # Match the selected tool's schema.
77
+ })
78
+ print(result.status, result.output)
79
+ ```
80
+
81
+ For long-running tools or forms awaiting human submission, use
82
+ `client.sessions.webmcp.start(session_id, params)`, then
83
+ `client.sessions.webmcp.get_result(session_id, invocation_id, {"wait_seconds": 30})`
84
+ until the status is terminal. `client.sessions.webmcp.cancel(session_id, invocation_id)`
85
+ requests best-effort cancellation. Blocking invocation defaults to 60 seconds
86
+ (maximum 120); `start` defaults to 300 seconds (maximum 3,600) via `timeout_seconds`.
87
+ All five methods also work with `AsyncHyperbrowser` by adding `await`.
88
+
89
+ Discover tools again after navigation. Invocations never automatically retry;
90
+ losing a response can leave an unknown outcome. Handles are ephemeral and
91
+ terminal results expire after 10 minutes or earlier eviction. Check result
92
+ status and truncation metadata before using output. Tool input and output keys
93
+ are not renamed. Request TypedDicts are available in `hyperbrowser.types`, and
94
+ Pydantic request/response models in `hyperbrowser.models`.
95
+
96
+ See the [WebMCP guide](https://hyperbrowser.ai/docs/sessions/webmcp) for complete
97
+ examples, cancellation behavior, human submission, and limits.
98
+
65
99
  ## Usage
66
100
 
67
101
  Hyperbrowser 1.0 accepts plain dictionaries for request parameters. Method
@@ -34,6 +34,40 @@ Profile names must match `^[A-Za-z0-9._-]+$`.
34
34
 
35
35
  `base_url` and `HYPERBROWSER_BASE_URL` accept either `https://host` or `https://host/api`. The client normalizes both to the same control-plane base URL.
36
36
 
37
+ ## WebMCP page tools
38
+
39
+ Create a session with `{"enable_web_mcp": True}` (default: false), then navigate
40
+ to a page that exposes WebMCP tools using Playwright. With that session open:
41
+
42
+ ```python
43
+ discovery = client.sessions.webmcp.list_tools(session.id)
44
+ # Select a tool using its name, source page/frame, and input schema.
45
+ tool = next(tool for tool in discovery.tools if tool.name == "search")
46
+ result = client.sessions.webmcp.invoke(session.id, {
47
+ "tool_ref": tool.tool_ref,
48
+ "input": {"query": "flights to Tokyo"}, # Match the selected tool's schema.
49
+ })
50
+ print(result.status, result.output)
51
+ ```
52
+
53
+ For long-running tools or forms awaiting human submission, use
54
+ `client.sessions.webmcp.start(session_id, params)`, then
55
+ `client.sessions.webmcp.get_result(session_id, invocation_id, {"wait_seconds": 30})`
56
+ until the status is terminal. `client.sessions.webmcp.cancel(session_id, invocation_id)`
57
+ requests best-effort cancellation. Blocking invocation defaults to 60 seconds
58
+ (maximum 120); `start` defaults to 300 seconds (maximum 3,600) via `timeout_seconds`.
59
+ All five methods also work with `AsyncHyperbrowser` by adding `await`.
60
+
61
+ Discover tools again after navigation. Invocations never automatically retry;
62
+ losing a response can leave an unknown outcome. Handles are ephemeral and
63
+ terminal results expire after 10 minutes or earlier eviction. Check result
64
+ status and truncation metadata before using output. Tool input and output keys
65
+ are not renamed. Request TypedDicts are available in `hyperbrowser.types`, and
66
+ Pydantic request/response models in `hyperbrowser.models`.
67
+
68
+ See the [WebMCP guide](https://hyperbrowser.ai/docs/sessions/webmcp) for complete
69
+ examples, cancellation behavior, human submission, and limits.
70
+
37
71
  ## Usage
38
72
 
39
73
  Hyperbrowser 1.0 accepts plain dictionaries for request parameters. Method
@@ -12,6 +12,8 @@ from hyperbrowser.models import (
12
12
  PressKeysActionParams,
13
13
  MoveMouseActionParams,
14
14
  ScreenshotActionParams,
15
+ CursorPositionActionParams,
16
+ ScrollAtCursorActionParams,
15
17
  ScrollActionParams,
16
18
  TypeTextActionParams,
17
19
  Coordinate,
@@ -38,6 +40,7 @@ _ACTION_PARAM_MODELS = {
38
40
  ComputerAction.MOVE_MOUSE.value: MoveMouseActionParams,
39
41
  ComputerAction.PRESS_KEYS.value: PressKeysActionParams,
40
42
  ComputerAction.SCREENSHOT.value: ScreenshotActionParams,
43
+ ComputerAction.CURSOR_POSITION.value: CursorPositionActionParams,
41
44
  ComputerAction.SCROLL.value: ScrollActionParams,
42
45
  ComputerAction.TYPE_TEXT.value: TypeTextActionParams,
43
46
  ComputerAction.GET_CLIPBOARD_TEXT.value: GetClipboardTextActionParams,
@@ -47,6 +50,9 @@ _ACTION_PARAM_MODELS = {
47
50
 
48
51
 
49
52
  def _action_param_model(params):
53
+ if isinstance(params, ScrollAtCursorActionParams):
54
+ return ScrollAtCursorActionParams
55
+
50
56
  for model in _ACTION_PARAM_MODELS.values():
51
57
  if isinstance(params, model):
52
58
  return model
@@ -56,6 +62,8 @@ def _action_param_model(params):
56
62
  if isinstance(action, ComputerAction):
57
63
  action = action.value
58
64
  model = _ACTION_PARAM_MODELS.get(action)
65
+ if model is ScrollActionParams and "x" not in params and "y" not in params:
66
+ return ScrollAtCursorActionParams
59
67
  if model is not None:
60
68
  return model
61
69
 
@@ -71,18 +79,13 @@ class ComputerActionManager:
71
79
  session: Union[SessionDetail, str],
72
80
  params: Union[ComputerActionParamsDict, ComputerActionParams],
73
81
  ) -> ComputerActionResponse:
82
+ payload = dump_request(params, _action_param_model(params), name="params")
74
83
  if isinstance(session, str):
75
84
  session = await self._client.sessions.get(session)
76
85
 
77
86
  if not session.computer_action_endpoint:
78
87
  raise ValueError("Computer action endpoint not available for this session")
79
88
 
80
- payload = dump_request(
81
- params,
82
- _action_param_model(params),
83
- name="params",
84
- )
85
-
86
89
  response = await self._client.transport.post(
87
90
  session.computer_action_endpoint,
88
91
  data=payload,
@@ -97,12 +100,14 @@ class ComputerActionManager:
97
100
  button: ComputerActionMouseButton = "left",
98
101
  num_clicks: int = 1,
99
102
  return_screenshot: bool = False,
103
+ keys: Optional[List[str]] = None,
100
104
  ) -> ComputerActionResponse:
101
105
  params = ClickActionParams(
102
106
  x=x,
103
107
  y=y,
104
108
  button=button,
105
109
  num_clicks=num_clicks,
110
+ keys=keys,
106
111
  return_screenshot=return_screenshot,
107
112
  )
108
113
  return await self._execute_request(session, params)
@@ -123,6 +128,14 @@ class ComputerActionManager:
123
128
  params = ScreenshotActionParams()
124
129
  return await self._execute_request(session, params)
125
130
 
131
+ async def cursor_position(
132
+ self,
133
+ session: Union[SessionDetail, str],
134
+ return_screenshot: bool = False,
135
+ ) -> ComputerActionResponse:
136
+ params = CursorPositionActionParams(return_screenshot=return_screenshot)
137
+ return await self._execute_request(session, params)
138
+
126
139
  async def press_keys(
127
140
  self,
128
141
  session: Union[SessionDetail, str],
@@ -169,6 +182,7 @@ class ComputerActionManager:
169
182
  session: Union[SessionDetail, str],
170
183
  path: List[Union[CoordinateDict, Coordinate]],
171
184
  return_screenshot: bool = False,
185
+ keys: Optional[List[str]] = None,
172
186
  ) -> ComputerActionResponse:
173
187
  params = DragActionParams(
174
188
  path=[
@@ -176,6 +190,7 @@ class ComputerActionManager:
176
190
  for coordinate in path
177
191
  ],
178
192
  return_screenshot=return_screenshot,
193
+ keys=keys,
179
194
  )
180
195
  return await self._execute_request(session, params)
181
196
 
@@ -197,12 +212,30 @@ class ComputerActionManager:
197
212
  scroll_x: int,
198
213
  scroll_y: int,
199
214
  return_screenshot: bool = False,
215
+ keys: Optional[List[str]] = None,
200
216
  ) -> ComputerActionResponse:
201
217
  params = ScrollActionParams(
202
218
  x=x,
203
219
  y=y,
204
220
  scroll_x=scroll_x,
205
221
  scroll_y=scroll_y,
222
+ keys=keys,
223
+ return_screenshot=return_screenshot,
224
+ )
225
+ return await self._execute_request(session, params)
226
+
227
+ async def scroll_at_cursor(
228
+ self,
229
+ session: Union[SessionDetail, str],
230
+ scroll_x: int = 0,
231
+ scroll_y: int = 0,
232
+ return_screenshot: bool = False,
233
+ keys: Optional[List[str]] = None,
234
+ ) -> ComputerActionResponse:
235
+ params = ScrollAtCursorActionParams(
236
+ scroll_x=scroll_x,
237
+ scroll_y=scroll_y,
238
+ keys=keys,
206
239
  return_screenshot=return_screenshot,
207
240
  )
208
241
  return await self._execute_request(session, params)
@@ -1,4 +1,6 @@
1
1
  import warnings
2
+
3
+ from .webmcp import WebMCPManager
2
4
  from collections.abc import Mapping
3
5
  from typing import IO, List, Optional, Union, overload
4
6
 
@@ -68,6 +70,7 @@ class SessionManager:
68
70
  def __init__(self, client):
69
71
  self._client = client
70
72
  self.event_logs = SessionEventLogsManager(client)
73
+ self.webmcp = WebMCPManager(client)
71
74
 
72
75
  async def create(
73
76
  self,
@@ -0,0 +1,98 @@
1
+ from typing import Optional, Union
2
+ from urllib.parse import quote
3
+
4
+ from hyperbrowser.client._request import coerce_request, dump_request
5
+ from hyperbrowser.models.webmcp import (
6
+ WebMCPInvocation,
7
+ WebMCPInvokeParams,
8
+ WebMCPInvokeResult,
9
+ WebMCPResultParams,
10
+ WebMCPStartParams,
11
+ WebMCPToolsResponse,
12
+ )
13
+ from hyperbrowser.types.webmcp import (
14
+ WebMCPInvokeParams as WebMCPInvokeParamsDict,
15
+ WebMCPResultParams as WebMCPResultParamsDict,
16
+ WebMCPStartParams as WebMCPStartParamsDict,
17
+ )
18
+
19
+
20
+ class WebMCPManager:
21
+ """Discover and invoke page tools in sessions created with enable_web_mcp=True."""
22
+
23
+ def __init__(self, client):
24
+ self._client = client
25
+
26
+ def _url(self, session_id: str, suffix: str) -> str:
27
+ return self._client._build_url(
28
+ f"/session/{quote(session_id, safe='')}/webmcp{suffix}"
29
+ )
30
+
31
+ async def list_tools(self, session_id: str) -> WebMCPToolsResponse:
32
+ """Discover document-bound tools across the session's tabs and frames."""
33
+ response = await self._client.transport.get(
34
+ self._url(session_id, "/tools"), timeout=max(self._client.timeout, 40)
35
+ )
36
+ return WebMCPToolsResponse(**response.data)
37
+
38
+ async def invoke(
39
+ self,
40
+ session_id: str,
41
+ params: Union[WebMCPInvokeParamsDict, WebMCPInvokeParams],
42
+ ) -> WebMCPInvokeResult:
43
+ """Invoke once and wait. A form can return awaiting_submission with a handle.
44
+
45
+ This POST is never automatically retried: losing its response can leave the
46
+ outcome unknown, and repeating it could duplicate a side effect.
47
+ """
48
+ request = coerce_request(params, WebMCPInvokeParams)
49
+ response = await self._client.transport.post(
50
+ self._url(session_id, "/invoke"),
51
+ data=dump_request(request, WebMCPInvokeParams),
52
+ timeout=max(self._client.timeout, request.timeout_seconds + 35),
53
+ )
54
+ return WebMCPInvokeResult(**response.data)
55
+
56
+ async def start(
57
+ self,
58
+ session_id: str,
59
+ params: Union[WebMCPStartParamsDict, WebMCPStartParams],
60
+ ) -> WebMCPInvocation:
61
+ """Start once and return a handle; use get_result to observe its outcome."""
62
+ response = await self._client.transport.post(
63
+ self._url(session_id, "/invocations"),
64
+ data=dump_request(params, WebMCPStartParams),
65
+ timeout=max(self._client.timeout, 40),
66
+ )
67
+ return WebMCPInvocation(**response.data)
68
+
69
+ async def get_result(
70
+ self,
71
+ session_id: str,
72
+ invocation_id: str,
73
+ params: Optional[Union[WebMCPResultParamsDict, WebMCPResultParams]] = None,
74
+ ) -> WebMCPInvocation:
75
+ """Read or long-poll once. Running/awaiting_submission can remain pending.
76
+
77
+ Handles are in memory. Terminal results expire after 10 minutes and may
78
+ be evicted sooner; browser shutdown or receiver restart also loses them.
79
+ """
80
+ request = coerce_request(
81
+ params if params is not None else {}, WebMCPResultParams
82
+ )
83
+ response = await self._client.transport.get(
84
+ self._url(session_id, f"/invocations/{quote(invocation_id, safe='')}"),
85
+ params=dump_request(request, WebMCPResultParams),
86
+ timeout=max(self._client.timeout, request.wait_seconds + 20),
87
+ )
88
+ return WebMCPInvocation(**response.data)
89
+
90
+ async def cancel(self, session_id: str, invocation_id: str) -> WebMCPInvocation:
91
+ """Request best-effort cancellation. Completion can win; side effects persist."""
92
+ response = await self._client.transport.post(
93
+ self._url(
94
+ session_id, f"/invocations/{quote(invocation_id, safe='')}/cancel"
95
+ ),
96
+ timeout=max(self._client.timeout, 20),
97
+ )
98
+ return WebMCPInvocation(**response.data)
@@ -12,6 +12,8 @@ from hyperbrowser.models import (
12
12
  PressKeysActionParams,
13
13
  MoveMouseActionParams,
14
14
  ScreenshotActionParams,
15
+ CursorPositionActionParams,
16
+ ScrollAtCursorActionParams,
15
17
  ScrollActionParams,
16
18
  TypeTextActionParams,
17
19
  Coordinate,
@@ -38,6 +40,7 @@ _ACTION_PARAM_MODELS = {
38
40
  ComputerAction.MOVE_MOUSE.value: MoveMouseActionParams,
39
41
  ComputerAction.PRESS_KEYS.value: PressKeysActionParams,
40
42
  ComputerAction.SCREENSHOT.value: ScreenshotActionParams,
43
+ ComputerAction.CURSOR_POSITION.value: CursorPositionActionParams,
41
44
  ComputerAction.SCROLL.value: ScrollActionParams,
42
45
  ComputerAction.TYPE_TEXT.value: TypeTextActionParams,
43
46
  ComputerAction.GET_CLIPBOARD_TEXT.value: GetClipboardTextActionParams,
@@ -47,6 +50,9 @@ _ACTION_PARAM_MODELS = {
47
50
 
48
51
 
49
52
  def _action_param_model(params):
53
+ if isinstance(params, ScrollAtCursorActionParams):
54
+ return ScrollAtCursorActionParams
55
+
50
56
  for model in _ACTION_PARAM_MODELS.values():
51
57
  if isinstance(params, model):
52
58
  return model
@@ -56,6 +62,8 @@ def _action_param_model(params):
56
62
  if isinstance(action, ComputerAction):
57
63
  action = action.value
58
64
  model = _ACTION_PARAM_MODELS.get(action)
65
+ if model is ScrollActionParams and "x" not in params and "y" not in params:
66
+ return ScrollAtCursorActionParams
59
67
  if model is not None:
60
68
  return model
61
69
 
@@ -71,18 +79,13 @@ class ComputerActionManager:
71
79
  session: Union[SessionDetail, str],
72
80
  params: Union[ComputerActionParamsDict, ComputerActionParams],
73
81
  ) -> ComputerActionResponse:
82
+ payload = dump_request(params, _action_param_model(params), name="params")
74
83
  if isinstance(session, str):
75
84
  session = self._client.sessions.get(session)
76
85
 
77
86
  if not session.computer_action_endpoint:
78
87
  raise ValueError("Computer action endpoint not available for this session")
79
88
 
80
- payload = dump_request(
81
- params,
82
- _action_param_model(params),
83
- name="params",
84
- )
85
-
86
89
  response = self._client.transport.post(
87
90
  session.computer_action_endpoint,
88
91
  data=payload,
@@ -97,12 +100,14 @@ class ComputerActionManager:
97
100
  button: ComputerActionMouseButton = "left",
98
101
  num_clicks: int = 1,
99
102
  return_screenshot: bool = False,
103
+ keys: Optional[List[str]] = None,
100
104
  ) -> ComputerActionResponse:
101
105
  params = ClickActionParams(
102
106
  x=x,
103
107
  y=y,
104
108
  button=button,
105
109
  num_clicks=num_clicks,
110
+ keys=keys,
106
111
  return_screenshot=return_screenshot,
107
112
  )
108
113
  return self._execute_request(session, params)
@@ -123,6 +128,14 @@ class ComputerActionManager:
123
128
  params = ScreenshotActionParams()
124
129
  return self._execute_request(session, params)
125
130
 
131
+ def cursor_position(
132
+ self,
133
+ session: Union[SessionDetail, str],
134
+ return_screenshot: bool = False,
135
+ ) -> ComputerActionResponse:
136
+ params = CursorPositionActionParams(return_screenshot=return_screenshot)
137
+ return self._execute_request(session, params)
138
+
126
139
  def press_keys(
127
140
  self,
128
141
  session: Union[SessionDetail, str],
@@ -169,6 +182,7 @@ class ComputerActionManager:
169
182
  session: Union[SessionDetail, str],
170
183
  path: List[Union[CoordinateDict, Coordinate]],
171
184
  return_screenshot: bool = False,
185
+ keys: Optional[List[str]] = None,
172
186
  ) -> ComputerActionResponse:
173
187
  params = DragActionParams(
174
188
  path=[
@@ -176,6 +190,7 @@ class ComputerActionManager:
176
190
  for coordinate in path
177
191
  ],
178
192
  return_screenshot=return_screenshot,
193
+ keys=keys,
179
194
  )
180
195
  return self._execute_request(session, params)
181
196
 
@@ -197,12 +212,30 @@ class ComputerActionManager:
197
212
  scroll_x: int,
198
213
  scroll_y: int,
199
214
  return_screenshot: bool = False,
215
+ keys: Optional[List[str]] = None,
200
216
  ) -> ComputerActionResponse:
201
217
  params = ScrollActionParams(
202
218
  x=x,
203
219
  y=y,
204
220
  scroll_x=scroll_x,
205
221
  scroll_y=scroll_y,
222
+ keys=keys,
223
+ return_screenshot=return_screenshot,
224
+ )
225
+ return self._execute_request(session, params)
226
+
227
+ def scroll_at_cursor(
228
+ self,
229
+ session: Union[SessionDetail, str],
230
+ scroll_x: int = 0,
231
+ scroll_y: int = 0,
232
+ return_screenshot: bool = False,
233
+ keys: Optional[List[str]] = None,
234
+ ) -> ComputerActionResponse:
235
+ params = ScrollAtCursorActionParams(
236
+ scroll_x=scroll_x,
237
+ scroll_y=scroll_y,
238
+ keys=keys,
206
239
  return_screenshot=return_screenshot,
207
240
  )
208
241
  return self._execute_request(session, params)
@@ -1,4 +1,6 @@
1
1
  import warnings
2
+
3
+ from .webmcp import WebMCPManager
2
4
  from collections.abc import Mapping
3
5
  from typing import IO, List, Optional, Union, overload
4
6
 
@@ -68,6 +70,7 @@ class SessionManager:
68
70
  def __init__(self, client):
69
71
  self._client = client
70
72
  self.event_logs = SessionEventLogsManager(client)
73
+ self.webmcp = WebMCPManager(client)
71
74
 
72
75
  def create(
73
76
  self,
@@ -0,0 +1,98 @@
1
+ from typing import Optional, Union
2
+ from urllib.parse import quote
3
+
4
+ from hyperbrowser.client._request import coerce_request, dump_request
5
+ from hyperbrowser.models.webmcp import (
6
+ WebMCPInvocation,
7
+ WebMCPInvokeParams,
8
+ WebMCPInvokeResult,
9
+ WebMCPResultParams,
10
+ WebMCPStartParams,
11
+ WebMCPToolsResponse,
12
+ )
13
+ from hyperbrowser.types.webmcp import (
14
+ WebMCPInvokeParams as WebMCPInvokeParamsDict,
15
+ WebMCPResultParams as WebMCPResultParamsDict,
16
+ WebMCPStartParams as WebMCPStartParamsDict,
17
+ )
18
+
19
+
20
+ class WebMCPManager:
21
+ """Discover and invoke page tools in sessions created with enable_web_mcp=True."""
22
+
23
+ def __init__(self, client):
24
+ self._client = client
25
+
26
+ def _url(self, session_id: str, suffix: str) -> str:
27
+ return self._client._build_url(
28
+ f"/session/{quote(session_id, safe='')}/webmcp{suffix}"
29
+ )
30
+
31
+ def list_tools(self, session_id: str) -> WebMCPToolsResponse:
32
+ """Discover document-bound tools across the session's tabs and frames."""
33
+ response = self._client.transport.get(
34
+ self._url(session_id, "/tools"), timeout=max(self._client.timeout, 40)
35
+ )
36
+ return WebMCPToolsResponse(**response.data)
37
+
38
+ def invoke(
39
+ self,
40
+ session_id: str,
41
+ params: Union[WebMCPInvokeParamsDict, WebMCPInvokeParams],
42
+ ) -> WebMCPInvokeResult:
43
+ """Invoke once and wait. A form can return awaiting_submission with a handle.
44
+
45
+ This POST is never automatically retried: losing its response can leave the
46
+ outcome unknown, and repeating it could duplicate a side effect.
47
+ """
48
+ request = coerce_request(params, WebMCPInvokeParams)
49
+ response = self._client.transport.post(
50
+ self._url(session_id, "/invoke"),
51
+ data=dump_request(request, WebMCPInvokeParams),
52
+ timeout=max(self._client.timeout, request.timeout_seconds + 35),
53
+ )
54
+ return WebMCPInvokeResult(**response.data)
55
+
56
+ def start(
57
+ self,
58
+ session_id: str,
59
+ params: Union[WebMCPStartParamsDict, WebMCPStartParams],
60
+ ) -> WebMCPInvocation:
61
+ """Start once and return a handle; use get_result to observe its outcome."""
62
+ response = self._client.transport.post(
63
+ self._url(session_id, "/invocations"),
64
+ data=dump_request(params, WebMCPStartParams),
65
+ timeout=max(self._client.timeout, 40),
66
+ )
67
+ return WebMCPInvocation(**response.data)
68
+
69
+ def get_result(
70
+ self,
71
+ session_id: str,
72
+ invocation_id: str,
73
+ params: Optional[Union[WebMCPResultParamsDict, WebMCPResultParams]] = None,
74
+ ) -> WebMCPInvocation:
75
+ """Read or long-poll once. Running/awaiting_submission can remain pending.
76
+
77
+ Handles are in memory. Terminal results expire after 10 minutes and may
78
+ be evicted sooner; browser shutdown or receiver restart also loses them.
79
+ """
80
+ request = coerce_request(
81
+ params if params is not None else {}, WebMCPResultParams
82
+ )
83
+ response = self._client.transport.get(
84
+ self._url(session_id, f"/invocations/{quote(invocation_id, safe='')}"),
85
+ params=dump_request(request, WebMCPResultParams),
86
+ timeout=max(self._client.timeout, request.wait_seconds + 20),
87
+ )
88
+ return WebMCPInvocation(**response.data)
89
+
90
+ def cancel(self, session_id: str, invocation_id: str) -> WebMCPInvocation:
91
+ """Request best-effort cancellation. Completion can win; side effects persist."""
92
+ response = self._client.transport.post(
93
+ self._url(
94
+ session_id, f"/invocations/{quote(invocation_id, safe='')}/cancel"
95
+ ),
96
+ timeout=max(self._client.timeout, 20),
97
+ )
98
+ return WebMCPInvocation(**response.data)
@@ -1,3 +1,18 @@
1
+ from .webmcp import (
2
+ WebMCPAnnotations,
3
+ WebMCPFrame,
4
+ WebMCPSource,
5
+ WebMCPTool,
6
+ WebMCPToolsResponse,
7
+ WebMCPInvokeParams,
8
+ WebMCPStartParams,
9
+ WebMCPResultParams,
10
+ WebMCPInvokeStatus,
11
+ WebMCPInvocationStatus,
12
+ WebMCPInvokeResult,
13
+ WebMCPInvocationError,
14
+ WebMCPInvocation,
15
+ )
1
16
  from .web.batch_fetch import (
2
17
  StartBatchFetchJobParams,
3
18
  StartBatchFetchJobResponse,
@@ -274,6 +289,8 @@ from .computer_action import (
274
289
  MoveMouseActionParams,
275
290
  PressKeysActionParams,
276
291
  ScreenshotActionParams,
292
+ CursorPositionActionParams,
293
+ ScrollAtCursorActionParams,
277
294
  ScrollActionParams,
278
295
  TypeTextActionParams,
279
296
  ComputerActionMouseButton,
@@ -283,6 +300,7 @@ from .computer_action import (
283
300
  ComputerActionWindow,
284
301
  ComputerActionResponseDataClipboardText,
285
302
  ComputerActionResponseDataListWindows,
303
+ ComputerActionResponseDataCursorPosition,
286
304
  ComputerActionResponseData,
287
305
  )
288
306
  from .session import (
@@ -436,6 +454,20 @@ from .sandbox import (
436
454
  from .team import TeamCreditInfo
437
455
 
438
456
  __all__ = [
457
+ "WebMCPAnnotations",
458
+ "WebMCPFrame",
459
+ "WebMCPSource",
460
+ "WebMCPTool",
461
+ "WebMCPToolsResponse",
462
+ "WebMCPInvokeParams",
463
+ "WebMCPStartParams",
464
+ "WebMCPResultParams",
465
+ "WebMCPInvokeStatus",
466
+ "WebMCPInvocationStatus",
467
+ "WebMCPInvokeResult",
468
+ "WebMCPInvocationError",
469
+ "WebMCPInvocation",
470
+
439
471
  # consts
440
472
  "ISO639_1",
441
473
  "POLLING_ATTEMPTS",
@@ -779,6 +811,8 @@ __all__ = [
779
811
  "MoveMouseActionParams",
780
812
  "PressKeysActionParams",
781
813
  "ScreenshotActionParams",
814
+ "CursorPositionActionParams",
815
+ "ScrollAtCursorActionParams",
782
816
  "ScrollActionParams",
783
817
  "TypeTextActionParams",
784
818
  "ComputerActionMouseButton",
@@ -788,6 +822,7 @@ __all__ = [
788
822
  "ComputerActionWindow",
789
823
  "ComputerActionResponseDataClipboardText",
790
824
  "ComputerActionResponseDataListWindows",
825
+ "ComputerActionResponseDataCursorPosition",
791
826
  "ComputerActionResponseData",
792
827
  # web
793
828
  "StartBatchFetchJobParams",