anchorbrowser 0.1.0__py3-none-any.whl

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 (100) hide show
  1. anchorbrowser/__init__.py +100 -0
  2. anchorbrowser/_base_client.py +1995 -0
  3. anchorbrowser/_client.py +440 -0
  4. anchorbrowser/_compat.py +219 -0
  5. anchorbrowser/_constants.py +14 -0
  6. anchorbrowser/_exceptions.py +108 -0
  7. anchorbrowser/_files.py +123 -0
  8. anchorbrowser/_models.py +829 -0
  9. anchorbrowser/_qs.py +150 -0
  10. anchorbrowser/_resource.py +43 -0
  11. anchorbrowser/_response.py +832 -0
  12. anchorbrowser/_streaming.py +333 -0
  13. anchorbrowser/_types.py +219 -0
  14. anchorbrowser/_utils/__init__.py +57 -0
  15. anchorbrowser/_utils/_logs.py +25 -0
  16. anchorbrowser/_utils/_proxy.py +65 -0
  17. anchorbrowser/_utils/_reflection.py +42 -0
  18. anchorbrowser/_utils/_resources_proxy.py +24 -0
  19. anchorbrowser/_utils/_streams.py +12 -0
  20. anchorbrowser/_utils/_sync.py +86 -0
  21. anchorbrowser/_utils/_transform.py +447 -0
  22. anchorbrowser/_utils/_typing.py +151 -0
  23. anchorbrowser/_utils/_utils.py +422 -0
  24. anchorbrowser/_version.py +4 -0
  25. anchorbrowser/lib/.keep +4 -0
  26. anchorbrowser/lib/agent.py +69 -0
  27. anchorbrowser/lib/browser.py +186 -0
  28. anchorbrowser/py.typed +0 -0
  29. anchorbrowser/resources/__init__.py +61 -0
  30. anchorbrowser/resources/agent.py +305 -0
  31. anchorbrowser/resources/browser.py +152 -0
  32. anchorbrowser/resources/extensions.py +412 -0
  33. anchorbrowser/resources/profiles.py +553 -0
  34. anchorbrowser/resources/sessions/__init__.py +89 -0
  35. anchorbrowser/resources/sessions/all.py +192 -0
  36. anchorbrowser/resources/sessions/clipboard.py +252 -0
  37. anchorbrowser/resources/sessions/keyboard.py +298 -0
  38. anchorbrowser/resources/sessions/mouse.py +651 -0
  39. anchorbrowser/resources/sessions/recordings/__init__.py +33 -0
  40. anchorbrowser/resources/sessions/recordings/primary.py +176 -0
  41. anchorbrowser/resources/sessions/recordings/recordings.py +357 -0
  42. anchorbrowser/resources/sessions/sessions.py +1122 -0
  43. anchorbrowser/resources/tools.py +529 -0
  44. anchorbrowser/types/__init__.py +32 -0
  45. anchorbrowser/types/extension_delete_response.py +12 -0
  46. anchorbrowser/types/extension_list_response.py +31 -0
  47. anchorbrowser/types/extension_manifest.py +28 -0
  48. anchorbrowser/types/extension_retrieve_response.py +27 -0
  49. anchorbrowser/types/extension_upload_params.py +17 -0
  50. anchorbrowser/types/extension_upload_response.py +31 -0
  51. anchorbrowser/types/profile_create_params.py +31 -0
  52. anchorbrowser/types/profile_list_response.py +43 -0
  53. anchorbrowser/types/profile_retrieve_response.py +36 -0
  54. anchorbrowser/types/profile_update_params.py +27 -0
  55. anchorbrowser/types/session_copy_response.py +12 -0
  56. anchorbrowser/types/session_create_params.py +196 -0
  57. anchorbrowser/types/session_create_response.py +22 -0
  58. anchorbrowser/types/session_drag_and_drop_params.py +26 -0
  59. anchorbrowser/types/session_drag_and_drop_response.py +11 -0
  60. anchorbrowser/types/session_goto_params.py +12 -0
  61. anchorbrowser/types/session_goto_response.py +11 -0
  62. anchorbrowser/types/session_paste_params.py +12 -0
  63. anchorbrowser/types/session_paste_response.py +11 -0
  64. anchorbrowser/types/session_retrieve_downloads_response.py +51 -0
  65. anchorbrowser/types/session_scroll_params.py +26 -0
  66. anchorbrowser/types/session_scroll_response.py +11 -0
  67. anchorbrowser/types/sessions/__init__.py +25 -0
  68. anchorbrowser/types/sessions/all_status_response.py +30 -0
  69. anchorbrowser/types/sessions/clipboard_get_response.py +16 -0
  70. anchorbrowser/types/sessions/clipboard_set_params.py +12 -0
  71. anchorbrowser/types/sessions/clipboard_set_response.py +11 -0
  72. anchorbrowser/types/sessions/keyboard_shortcut_params.py +18 -0
  73. anchorbrowser/types/sessions/keyboard_shortcut_response.py +11 -0
  74. anchorbrowser/types/sessions/keyboard_type_params.py +15 -0
  75. anchorbrowser/types/sessions/keyboard_type_response.py +11 -0
  76. anchorbrowser/types/sessions/mouse_click_params.py +18 -0
  77. anchorbrowser/types/sessions/mouse_click_response.py +11 -0
  78. anchorbrowser/types/sessions/mouse_double_click_params.py +18 -0
  79. anchorbrowser/types/sessions/mouse_double_click_response.py +11 -0
  80. anchorbrowser/types/sessions/mouse_down_params.py +18 -0
  81. anchorbrowser/types/sessions/mouse_down_response.py +11 -0
  82. anchorbrowser/types/sessions/mouse_move_params.py +15 -0
  83. anchorbrowser/types/sessions/mouse_move_response.py +11 -0
  84. anchorbrowser/types/sessions/mouse_up_params.py +18 -0
  85. anchorbrowser/types/sessions/mouse_up_response.py +11 -0
  86. anchorbrowser/types/sessions/recording_list_response.py +46 -0
  87. anchorbrowser/types/sessions/recording_pause_response.py +12 -0
  88. anchorbrowser/types/sessions/recording_resume_response.py +12 -0
  89. anchorbrowser/types/sessions/recordings/__init__.py +3 -0
  90. anchorbrowser/types/shared/__init__.py +3 -0
  91. anchorbrowser/types/shared/success_response.py +15 -0
  92. anchorbrowser/types/tool_fetch_webpage_params.py +26 -0
  93. anchorbrowser/types/tool_fetch_webpage_response.py +7 -0
  94. anchorbrowser/types/tool_perform_web_task_params.py +30 -0
  95. anchorbrowser/types/tool_perform_web_task_response.py +16 -0
  96. anchorbrowser/types/tool_screenshot_webpage_params.py +48 -0
  97. anchorbrowser-0.1.0.dist-info/METADATA +449 -0
  98. anchorbrowser-0.1.0.dist-info/RECORD +100 -0
  99. anchorbrowser-0.1.0.dist-info/WHEEL +4 -0
  100. anchorbrowser-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,186 @@
1
+ from typing import TYPE_CHECKING, Any, Dict, Callable, Optional, TypedDict
2
+ from contextlib import contextmanager, asynccontextmanager, _GeneratorContextManager, _AsyncGeneratorContextManager
3
+
4
+ from pydantic import BaseModel
5
+ from playwright.sync_api import Page, Worker, Browser, BrowserContext
6
+ from playwright.async_api import (
7
+ Page as AsyncPage,
8
+ Worker as AsyncWorker,
9
+ Browser as AsyncBrowser,
10
+ BrowserContext as AsyncBrowserContext,
11
+ )
12
+
13
+ if TYPE_CHECKING:
14
+ from collections import Generator, AsyncGenerator
15
+
16
+
17
+ @contextmanager
18
+ def get_playwright_chromium_from_cdp_url(
19
+ api_base_url: str, session_id: str, api_key: str
20
+ ) -> "Generator[Browser, Any, None]":
21
+ from playwright.sync_api import sync_playwright
22
+
23
+ browser = None
24
+ playwright = sync_playwright().start()
25
+ try:
26
+ browser = playwright.chromium.connect_over_cdp(get_cdp_url(api_base_url, session_id, api_key))
27
+ yield browser
28
+ finally:
29
+ if browser:
30
+ browser.close()
31
+ playwright.stop()
32
+
33
+
34
+ @asynccontextmanager
35
+ async def get_async_playwright_chromium_from_cdp_url(
36
+ api_base_url: str, session_id: str, api_key: str
37
+ ) -> "AsyncGenerator[AsyncBrowser, None]":
38
+ from playwright.async_api import async_playwright
39
+
40
+ browser = None
41
+ playwright = await async_playwright().start()
42
+ try:
43
+ browser = await playwright.chromium.connect_over_cdp(get_cdp_url(api_base_url, session_id, api_key))
44
+ yield browser
45
+ finally:
46
+ if browser:
47
+ await browser.close()
48
+ await playwright.stop()
49
+
50
+
51
+ def get_cdp_url(api_base_url: str, session_id: str, api_key: str) -> str:
52
+ return f"{api_base_url.replace('https://', 'wss://').replace('api.', 'connect.')}?apiKey={api_key}&sessionId={session_id}"
53
+
54
+
55
+ def get_agent_ws_url(api_base_url: str, session_id: str) -> str:
56
+ return f"{api_base_url.replace('https://', 'wss://')}/ws?sessionId={session_id}"
57
+
58
+
59
+ def get_ai_service_worker(browser_context: "BrowserContext") -> Optional["Worker"]:
60
+ return next(
61
+ (
62
+ sw
63
+ for sw in browser_context.service_workers
64
+ if "chrome-extension://bppehibnhionalpjigdjdilknbljaeai/background.js" in sw.url
65
+ ),
66
+ None,
67
+ )
68
+
69
+
70
+ async def get_ai_service_worker_async(browser_context: "AsyncBrowserContext") -> Optional["AsyncWorker"]:
71
+ return next(
72
+ (
73
+ sw
74
+ for sw in browser_context.service_workers
75
+ if "chrome-extension://bppehibnhionalpjigdjdilknbljaeai/background.js" in sw.url
76
+ ),
77
+ None,
78
+ )
79
+
80
+
81
+ class BrowserSetup(BaseModel):
82
+ session_id: str
83
+ base_url: str
84
+ api_key: str
85
+ _browser: Optional[Browser] = None
86
+ _async_browser: Optional[AsyncBrowser] = None
87
+ _context_manager: Optional[_GeneratorContextManager[Browser]] = None
88
+ _async_context_manager: Optional[_AsyncGeneratorContextManager[AsyncBrowser]] = None
89
+
90
+ async def __aenter__(self) -> "BrowserSetup":
91
+ self._async_context_manager = get_async_playwright_chromium_from_cdp_url(
92
+ self.base_url,
93
+ self.session_id,
94
+ self.api_key,
95
+ )
96
+ self._async_browser = await self._async_context_manager.__aenter__()
97
+ return self
98
+
99
+ def __enter__(self) -> "BrowserSetup":
100
+ self._context_manager = get_playwright_chromium_from_cdp_url(
101
+ self.base_url,
102
+ self.session_id,
103
+ self.api_key,
104
+ )
105
+ self._browser = self._context_manager.__enter__()
106
+ return self
107
+
108
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> Optional[bool]:
109
+ if self._context_manager:
110
+ return self._context_manager.__exit__(exc_type, exc_val, exc_tb)
111
+ return None
112
+
113
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> Optional[bool]:
114
+ if self._async_context_manager:
115
+ return await self._async_context_manager.__aexit__(exc_type, exc_val, exc_tb)
116
+ return None
117
+
118
+ @property
119
+ def browser_generator(self) -> _GeneratorContextManager[Browser]:
120
+ return get_playwright_chromium_from_cdp_url(
121
+ self.base_url,
122
+ self.session_id,
123
+ self.api_key,
124
+ )
125
+
126
+ @property
127
+ def async_browser_generator(self) -> _AsyncGeneratorContextManager[AsyncBrowser]:
128
+ return get_async_playwright_chromium_from_cdp_url(
129
+ self.base_url,
130
+ self.session_id,
131
+ self.api_key,
132
+ )
133
+
134
+ @property
135
+ def browser(self) -> Browser:
136
+ if self._browser is None:
137
+ raise RuntimeError("BrowserSetup must be used as a context manager")
138
+ return self._browser
139
+
140
+ @property
141
+ async def async_browser(self) -> AsyncBrowser:
142
+ if self._async_browser is None:
143
+ raise RuntimeError("BrowserSetup must be used as a context manager")
144
+ return self._async_browser
145
+
146
+ @property
147
+ def context(self) -> BrowserContext:
148
+ return self.browser.contexts[0]
149
+
150
+ @property
151
+ async def async_context(self) -> AsyncBrowserContext:
152
+ return (await self.async_browser).contexts[0]
153
+
154
+ @property
155
+ def page(self) -> Page:
156
+ return self.context.pages[0]
157
+
158
+ @property
159
+ async def async_page(self) -> AsyncPage:
160
+ return (await self.async_context).pages[0]
161
+
162
+ @property
163
+ def ai(self) -> Worker:
164
+ ai_service_worker = get_ai_service_worker(self.context)
165
+ if not ai_service_worker:
166
+ raise ValueError("AI service worker not found")
167
+ return ai_service_worker
168
+
169
+ @property
170
+ async def async_ai(self) -> AsyncWorker:
171
+ ai_service_worker = await get_ai_service_worker_async(await self.async_context)
172
+ if not ai_service_worker:
173
+ raise ValueError("AI service worker not found")
174
+ return ai_service_worker
175
+
176
+
177
+ class AgentTaskParams(TypedDict, total=False):
178
+ url: Optional[str]
179
+ output_schema: Optional[Dict[str, Any]]
180
+ on_agent_step: Optional[Callable[[str], None]]
181
+
182
+
183
+ class BrowserTaskResponse(TypedDict):
184
+ session_id: str
185
+ task_result_task: Any
186
+ playwright_browser: Any
anchorbrowser/py.typed ADDED
File without changes
@@ -0,0 +1,61 @@
1
+ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ from .tools import (
4
+ ToolsResource,
5
+ AsyncToolsResource,
6
+ ToolsResourceWithRawResponse,
7
+ AsyncToolsResourceWithRawResponse,
8
+ ToolsResourceWithStreamingResponse,
9
+ AsyncToolsResourceWithStreamingResponse,
10
+ )
11
+ from .profiles import (
12
+ ProfilesResource,
13
+ AsyncProfilesResource,
14
+ ProfilesResourceWithRawResponse,
15
+ AsyncProfilesResourceWithRawResponse,
16
+ ProfilesResourceWithStreamingResponse,
17
+ AsyncProfilesResourceWithStreamingResponse,
18
+ )
19
+ from .sessions import (
20
+ SessionsResource,
21
+ AsyncSessionsResource,
22
+ SessionsResourceWithRawResponse,
23
+ AsyncSessionsResourceWithRawResponse,
24
+ SessionsResourceWithStreamingResponse,
25
+ AsyncSessionsResourceWithStreamingResponse,
26
+ )
27
+ from .extensions import (
28
+ ExtensionsResource,
29
+ AsyncExtensionsResource,
30
+ ExtensionsResourceWithRawResponse,
31
+ AsyncExtensionsResourceWithRawResponse,
32
+ ExtensionsResourceWithStreamingResponse,
33
+ AsyncExtensionsResourceWithStreamingResponse,
34
+ )
35
+
36
+ __all__ = [
37
+ "ProfilesResource",
38
+ "AsyncProfilesResource",
39
+ "ProfilesResourceWithRawResponse",
40
+ "AsyncProfilesResourceWithRawResponse",
41
+ "ProfilesResourceWithStreamingResponse",
42
+ "AsyncProfilesResourceWithStreamingResponse",
43
+ "SessionsResource",
44
+ "AsyncSessionsResource",
45
+ "SessionsResourceWithRawResponse",
46
+ "AsyncSessionsResourceWithRawResponse",
47
+ "SessionsResourceWithStreamingResponse",
48
+ "AsyncSessionsResourceWithStreamingResponse",
49
+ "ToolsResource",
50
+ "AsyncToolsResource",
51
+ "ToolsResourceWithRawResponse",
52
+ "AsyncToolsResourceWithRawResponse",
53
+ "ToolsResourceWithStreamingResponse",
54
+ "AsyncToolsResourceWithStreamingResponse",
55
+ "ExtensionsResource",
56
+ "AsyncExtensionsResource",
57
+ "ExtensionsResourceWithRawResponse",
58
+ "AsyncExtensionsResourceWithRawResponse",
59
+ "ExtensionsResourceWithStreamingResponse",
60
+ "AsyncExtensionsResourceWithStreamingResponse",
61
+ ]
@@ -0,0 +1,305 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+
5
+ from .._compat import cached_property
6
+ from .._resource import SyncAPIResource, AsyncAPIResource
7
+ from .._response import (
8
+ to_raw_response_wrapper,
9
+ to_streamed_response_wrapper,
10
+ async_to_raw_response_wrapper,
11
+ async_to_streamed_response_wrapper,
12
+ )
13
+ from ..lib.agent import on_agent_step_sync, create_task_payload, on_agent_step_async
14
+ from ..lib.browser import (
15
+ BrowserSetup,
16
+ AgentTaskParams,
17
+ BrowserTaskResponse,
18
+ )
19
+ from ..types.session_create_params import Session
20
+
21
+ __all__ = ["AgentResource", "AsyncAgentResource"]
22
+
23
+
24
+ class AgentResource(SyncAPIResource):
25
+ @cached_property
26
+ def with_raw_response(self) -> AgentResourceWithRawResponse:
27
+ """
28
+ This property can be used as a prefix for any HTTP method call to return
29
+ the raw response object instead of the parsed content.
30
+
31
+ For more information, see https://www.github.com/anchorbrowser/AnchorBrowser-SDK-Python#accessing-raw-response-data-eg-headers
32
+ """
33
+ return AgentResourceWithRawResponse(self)
34
+
35
+ @cached_property
36
+ def with_streaming_response(self) -> AgentResourceWithStreamingResponse:
37
+ """
38
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
39
+
40
+ For more information, see https://www.github.com/anchorbrowser/AnchorBrowser-SDK-Python#with_streaming_response
41
+ """
42
+ return AgentResourceWithStreamingResponse(self)
43
+
44
+ def task(
45
+ self,
46
+ prompt: str,
47
+ *,
48
+ session_options: Optional[Session] = None,
49
+ task_options: Optional[AgentTaskParams] = None,
50
+ ) -> str:
51
+ """Execute an AI agent task within a browser session.
52
+
53
+ Creates a new browser session and executes the given prompt as an AI agent task.
54
+ The agent can optionally navigate to a specific URL and use a structured output schema.
55
+
56
+ Args:
57
+ prompt (str): The task prompt/instruction for the AI agent to execute.
58
+ session_options (Optional[Session], optional): Configuration options for the
59
+ browser session. Defaults to None, which creates a session with default settings.
60
+ task_options (Optional[AgentTaskParams], optional): Additional task configuration
61
+
62
+ Returns:
63
+ str: The result of the AI agent task execution.
64
+ """
65
+ session = self._client.sessions.create(session=session_options or {})
66
+ if not session.data or not session.data.id:
67
+ raise ValueError("Failed to create session: No session ID returned")
68
+
69
+ with BrowserSetup(
70
+ session_id=session.data.id,
71
+ base_url=str(self._client.base_url),
72
+ api_key=self._client.api_key,
73
+ ) as browser_setup:
74
+ output_schema = None
75
+ if task_options:
76
+ output_schema = task_options.get("output_schema")
77
+ url = task_options.get("url")
78
+ if url:
79
+ browser_setup.page.goto(url)
80
+ on_agent_step = task_options.get("on_agent_step")
81
+ if on_agent_step:
82
+ on_agent_step_sync(on_agent_step, browser_setup)
83
+ task_payload = create_task_payload(prompt, output_schema)
84
+ task_result = str(browser_setup.ai.evaluate(task_payload))
85
+ return task_result
86
+
87
+ def browser_task(
88
+ self,
89
+ prompt: str,
90
+ *,
91
+ session_options: Optional[Session] = None,
92
+ task_options: Optional[AgentTaskParams] = None,
93
+ ) -> BrowserTaskResponse:
94
+ """Execute an AI agent task and return a browser task response with session control.
95
+
96
+ Creates a new browser session, executes the given prompt as an AI agent task \n
97
+ returns a object that includes the session ID, task result, and browser instance for continued interaction by the caller. \n
98
+ This method differs from `task()` by returning control of the browser session to the caller rather than automatically closing it after task completion. \n
99
+ Args:
100
+ prompt (str): The task prompt/instruction for the AI agent to execute. \n
101
+ session_options (Optional[Session], optional): Configuration options for the browser session. Defaults to None, which creates a session with default settings. \n
102
+ task_options (Optional[AgentTaskParams], optional): Additional task configuration including: \n
103
+ - output_schema: Schema for structured output formatting
104
+ - url: URL to navigate to before executing the task
105
+ - on_agent_step: Callback function for agent step events
106
+ Defaults to None.
107
+
108
+ Returns:
109
+ Response object containing:
110
+ - session_id: The ID of the created browser session
111
+ - task_result_task: The result of the AI agent task execution
112
+ - playwright_browser: Browser instance for continued interaction
113
+ """
114
+ session = self._client.sessions.create(session=session_options or {})
115
+ if not session.data or not session.data.id:
116
+ raise ValueError("Failed to create session: No session ID returned")
117
+
118
+ with BrowserSetup(
119
+ session_id=session.data.id,
120
+ base_url=str(self._client.base_url),
121
+ api_key=self._client.api_key,
122
+ ) as browser_setup:
123
+ output_schema = None
124
+ if task_options:
125
+ output_schema = task_options.get("output_schema")
126
+ url = task_options.get("url")
127
+ if url:
128
+ browser_setup.page.goto(url)
129
+ on_agent_step = task_options.get("on_agent_step")
130
+ if on_agent_step:
131
+ on_agent_step_sync(on_agent_step, browser_setup)
132
+ task_payload = create_task_payload(prompt, output_schema)
133
+ task_result = str(browser_setup.ai.evaluate(task_payload))
134
+ return BrowserTaskResponse(
135
+ session_id=session.data.id,
136
+ task_result_task=task_result,
137
+ playwright_browser=browser_setup.browser_generator,
138
+ )
139
+
140
+
141
+ class AsyncAgentResource(AsyncAPIResource):
142
+ @cached_property
143
+ def with_raw_response(self) -> AsyncAgentResourceWithRawResponse:
144
+ """
145
+ This property can be used as a prefix for any HTTP method call to return
146
+ the raw response object instead of the parsed content.
147
+
148
+ For more information, see https://www.github.com/anchorbrowser/AnchorBrowser-SDK-Python#accessing-raw-response-data-eg-headers
149
+ """
150
+ return AsyncAgentResourceWithRawResponse(self)
151
+
152
+ @cached_property
153
+ def with_streaming_response(self) -> AsyncAgentResourceWithStreamingResponse:
154
+ """
155
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
156
+
157
+ For more information, see https://www.github.com/anchorbrowser/AnchorBrowser-SDK-Python#with_streaming_response
158
+ """
159
+ return AsyncAgentResourceWithStreamingResponse(self)
160
+
161
+ async def task(
162
+ self,
163
+ prompt: str,
164
+ *,
165
+ session_options: Optional[Session] = None,
166
+ task_options: Optional[AgentTaskParams] = None,
167
+ ) -> str:
168
+ """Execute an AI agent task within a browser session.
169
+
170
+ Creates a new browser session and executes the given prompt as an AI agent task.
171
+ The agent can optionally navigate to a specific URL and use a structured output schema.
172
+
173
+ Args:
174
+ prompt (str): The task prompt/instruction for the AI agent to execute.
175
+ session_options (Optional[Session], optional): Configuration options for the
176
+ browser session. Defaults to None, which creates a session with default settings.
177
+ task_options (Optional[AgentTaskParams], optional): Additional task configuration
178
+
179
+ Returns:
180
+ str: The result of the AI agent task execution.
181
+ """
182
+ session = await self._client.sessions.create(session=session_options or {})
183
+ if not session.data or not session.data.id:
184
+ raise ValueError("Failed to create session: No session ID returned")
185
+
186
+ browser_setup = BrowserSetup(
187
+ session_id=session.data.id,
188
+ base_url=str(self._client.base_url),
189
+ api_key=self._client.api_key,
190
+ )
191
+
192
+ async with browser_setup:
193
+ output_schema = None
194
+ if task_options:
195
+ output_schema = task_options.get("output_schema")
196
+ url = task_options.get("url")
197
+ if url:
198
+ await (await browser_setup.async_page).goto(url)
199
+ on_agent_step = task_options.get("on_agent_step")
200
+ if on_agent_step:
201
+ on_agent_step_async(on_agent_step, browser_setup)
202
+ task_payload = create_task_payload(prompt, output_schema)
203
+ task_result = await (await browser_setup.async_ai).evaluate(task_payload)
204
+ return str(task_result)
205
+
206
+ async def browser_task(
207
+ self,
208
+ prompt: str,
209
+ *,
210
+ session_options: Optional[Session] = None,
211
+ task_options: Optional[AgentTaskParams] = None,
212
+ ) -> BrowserTaskResponse:
213
+ """Execute an AI agent task and return a browser task response with session control.
214
+
215
+ Creates a new browser session, executes the given prompt as an AI agent task \n
216
+ returns a object that includes the session ID, task result, and browser instance for continued interaction by the caller. \n
217
+ This method differs from `task()` by returning control of the browser session to the caller rather than automatically closing it after task completion. \n
218
+ Args:
219
+ prompt (str): The task prompt/instruction for the AI agent to execute. \n
220
+ session_options (Optional[Session], optional): Configuration options for the browser session. Defaults to None, which creates a session with default settings. \n
221
+ task_options (Optional[AgentTaskParams], optional): Additional task configuration including: \n
222
+ - output_schema: Schema for structured output formatting
223
+ - url: URL to navigate to before executing the task
224
+ - on_agent_step: Callback function for agent step events
225
+ Defaults to None.
226
+
227
+ Returns:
228
+ Response object containing:
229
+ - session_id: The ID of the created browser session
230
+ - task_result_task: The result of the AI agent task execution
231
+ - playwright_browser: Browser instance for continued interaction
232
+ """
233
+ session = await self._client.sessions.create(session=session_options or {})
234
+ if not session.data or not session.data.id:
235
+ raise ValueError("Failed to create session: No session ID returned")
236
+
237
+ async with BrowserSetup(
238
+ session_id=session.data.id,
239
+ base_url=str(self._client.base_url),
240
+ api_key=self._client.api_key,
241
+ ) as browser_setup:
242
+ output_schema = None
243
+ if task_options:
244
+ output_schema = task_options.get("output_schema")
245
+ url = task_options.get("url")
246
+ if url:
247
+ await (await browser_setup.async_page).goto(url)
248
+ on_agent_step = task_options.get("on_agent_step")
249
+ if on_agent_step:
250
+ on_agent_step_async(on_agent_step, browser_setup)
251
+ task_payload = create_task_payload(prompt, output_schema)
252
+ task_result = await (await browser_setup.async_ai).evaluate(task_payload)
253
+ return BrowserTaskResponse(
254
+ session_id=session.data.id,
255
+ task_result_task=task_result,
256
+ playwright_browser=browser_setup.async_browser_generator,
257
+ )
258
+
259
+
260
+ class AgentResourceWithRawResponse:
261
+ def __init__(self, agent: AgentResource) -> None:
262
+ self._agent = agent
263
+
264
+ self.task = to_raw_response_wrapper(
265
+ agent.task,
266
+ )
267
+ self.browser_task = to_raw_response_wrapper(
268
+ agent.browser_task,
269
+ )
270
+
271
+
272
+ class AsyncAgentResourceWithRawResponse:
273
+ def __init__(self, agent: AsyncAgentResource) -> None:
274
+ self._agent = agent
275
+
276
+ self.task = async_to_raw_response_wrapper(
277
+ agent.task,
278
+ )
279
+ self.browser_task = async_to_raw_response_wrapper(
280
+ agent.browser_task,
281
+ )
282
+
283
+
284
+ class AgentResourceWithStreamingResponse:
285
+ def __init__(self, agent: AgentResource) -> None:
286
+ self._agent = agent
287
+
288
+ self.task = to_streamed_response_wrapper(
289
+ agent.task,
290
+ )
291
+ self.browser_task = to_streamed_response_wrapper(
292
+ agent.browser_task,
293
+ )
294
+
295
+
296
+ class AsyncAgentResourceWithStreamingResponse:
297
+ def __init__(self, agent: AsyncAgentResource) -> None:
298
+ self._agent = agent
299
+
300
+ self.task = async_to_streamed_response_wrapper(
301
+ agent.task,
302
+ )
303
+ self.browser_task = async_to_streamed_response_wrapper(
304
+ agent.browser_task,
305
+ )