stagehand 4.2.0a0.dev1586__tar.gz → 4.2.0a0.dev1588__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 (36) hide show
  1. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/PKG-INFO +1 -1
  2. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/pyproject.toml +1 -1
  3. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_extension/service-worker.js +4 -4
  4. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_generated/protocol_version.py +1 -1
  5. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/browser.py +16 -5
  6. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/cdp_client.py +52 -12
  7. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/client_models.py +4 -2
  8. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/client_types.py +2 -0
  9. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/README.md +0 -0
  10. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/__init__.py +0 -0
  11. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_extension/blank.html +0 -0
  12. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_extension/content-script.js +0 -0
  13. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_extension/manifest.json +0 -0
  14. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_extension/offscreen/service-worker-heartbeat.html +0 -0
  15. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_extension/offscreen/service-worker-heartbeat.js +0 -0
  16. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_extension/wake-service-worker.html +0 -0
  17. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_extension/wake-service-worker.js +0 -0
  18. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_generated/__init__.py +0 -0
  19. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_generated/input_types.py +0 -0
  20. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_generated/models.py +0 -0
  21. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_sdk_identity.py +0 -0
  22. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/_validation.py +0 -0
  23. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/browser_clipboard.py +0 -0
  24. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/browser_context.py +0 -0
  25. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/browserbase_services.py +0 -0
  26. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/browserbase_session.py +0 -0
  27. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/extension_assets.py +0 -0
  28. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/file_upload.py +0 -0
  29. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/locator.py +0 -0
  30. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/page.py +0 -0
  31. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/py.typed +0 -0
  32. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/response.py +0 -0
  33. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/rpc_client.py +0 -0
  34. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/stagehand.py +0 -0
  35. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/timeouts.py +0 -0
  36. {stagehand-4.2.0a0.dev1586 → stagehand-4.2.0a0.dev1588}/src/stagehand/webmcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stagehand
3
- Version: 4.2.0a0.dev1586
3
+ Version: 4.2.0a0.dev1588
4
4
  Summary: Browserbase's SDK for building browser agents
5
5
  Keywords: ai,agent,ai-agent,browser,browser-agent,browser-automation,computer-use,headless,playwright,cdp,llm,automation,web-scraping,testing
6
6
  Author: Browserbase
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stagehand"
3
- version = "4.2.0a0.dev1586"
3
+ version = "4.2.0a0.dev1588"
4
4
  description = "Browserbase's SDK for building browser agents"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -7363,7 +7363,7 @@ function isRecord$1(value) {
7363
7363
  }
7364
7364
  var package_default$1 = {
7365
7365
  name: "@browserbasehq/stagehand-protocol",
7366
- version: "2.1.0-alpha-87ac4b16ebd8dce3cab7ae06091cf06cde752312",
7366
+ version: "2.1.0-alpha-f2060a689d150957768d92e41eda8decc68bc5bf",
7367
7367
  "private": true,
7368
7368
  type: "module",
7369
7369
  exports: {
@@ -12557,7 +12557,7 @@ strictObject({
12557
12557
  }).meta({ id: "LocalBrowserLaunchOptions" });
12558
12558
  strictObject({
12559
12559
  cdpUrl: string().min(1),
12560
- extensionId: string().min(1).optional()
12560
+ extensionId: string().optional()
12561
12561
  }).meta({ id: "LocalBrowserConnectOptions" });
12562
12562
  var DEFAULT_BROWSERBASE_URL = "https://api.browserbase.com";
12563
12563
  var BrowserbaseClientOptionsSchema = strictObject({
@@ -12579,7 +12579,7 @@ strictObject({
12579
12579
  baseUrl: url().default(DEFAULT_BROWSERBASE_URL),
12580
12580
  clientOptions: BrowserbaseClientOptionsSchema.optional(),
12581
12581
  sessionId: string().min(1),
12582
- extensionId: string().min(1).optional()
12582
+ extensionId: string().optional()
12583
12583
  }).meta({ id: "BrowserbaseConnectOptions" });
12584
12584
  var BrowserbaseCredentialsShape = {
12585
12585
  apiKey: string().min(1),
@@ -54394,7 +54394,7 @@ var WebTracerProvider = class extends BasicTracerProvider {
54394
54394
  };
54395
54395
  var package_default = {
54396
54396
  name: "@browserbasehq/stagehand-extension",
54397
- version: "1.1.0-alpha-87ac4b16ebd8dce3cab7ae06091cf06cde752312",
54397
+ version: "1.1.0-alpha-f2060a689d150957768d92e41eda8decc68bc5bf",
54398
54398
  "private": true,
54399
54399
  type: "module",
54400
54400
  scripts: {
@@ -1,4 +1,4 @@
1
1
  """Generated from packages/protocol/package.json. Do not edit."""
2
2
 
3
3
  PROTOCOL_SEMVER_PATTERN = '^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$'
4
- STAGEHAND_PROTOCOL_VERSION = '2.1.0-alpha-87ac4b16ebd8dce3cab7ae06091cf06cde752312'
4
+ STAGEHAND_PROTOCOL_VERSION = '2.1.0-alpha-f2060a689d150957768d92e41eda8decc68bc5bf'
@@ -305,6 +305,7 @@ async def _connect_browser(
305
305
  origin: Literal["launched", "connected"],
306
306
  source: _BrowserConnectionSource,
307
307
  extension_dir: str | None = None,
308
+ local_extension_dir: Callable[[], str] | None = None,
308
309
  extension_id: str | None = None,
309
310
  preloaded_extension: bool = False,
310
311
  after_connect: Callable[[CDPClient], Awaitable[None]] | None = None,
@@ -316,6 +317,7 @@ async def _connect_browser(
316
317
  cdp_client = await CDPClient.connect(
317
318
  cdp_url=source.cdp_url,
318
319
  extension_dir=extension_dir,
320
+ local_extension_dir=local_extension_dir,
319
321
  extension_id=extension_id,
320
322
  preloaded_extension=preloaded_extension,
321
323
  service_worker_url_includes="service-worker.js",
@@ -532,6 +534,12 @@ class LocalBrowser:
532
534
  cdp_url: str,
533
535
  extension_id: str | None = None,
534
536
  ) -> StagehandBrowser:
537
+ """Connect to an existing browser.
538
+
539
+ Args:
540
+ extension_id: Deprecated and ignored. Omit this argument; Stagehand
541
+ discovers the installed extension automatically.
542
+ """
535
543
  options = LocalBrowserConnectOptions.model_validate({
536
544
  name: value
537
545
  for name, value in (
@@ -540,13 +548,11 @@ class LocalBrowser:
540
548
  )
541
549
  if value is not None
542
550
  })
543
- extension_dir = None if options.extension_id is not None else str(extension_directory())
544
551
  return await _connect_browser(
545
552
  provider="local",
546
553
  origin="connected",
547
554
  source=_ConnectedBrowserSource(options.cdp_url),
548
- extension_dir=extension_dir,
549
- extension_id=options.extension_id,
555
+ local_extension_dir=lambda: str(extension_directory()),
550
556
  worker_init_metadata=_WorkerInitMetadata(api_key=None, browser=None),
551
557
  )
552
558
 
@@ -646,6 +652,12 @@ class BrowserbaseBrowser:
646
652
  session_id: str,
647
653
  extension_id: str | None = None,
648
654
  ) -> StagehandBrowser:
655
+ """Connect to an existing browser.
656
+
657
+ Args:
658
+ extension_id: Deprecated and ignored. Omit this argument; Stagehand
659
+ discovers the installed extension automatically.
660
+ """
649
661
  options = BrowserbaseConnectOptions.model_validate({
650
662
  name: value
651
663
  for name, value in (
@@ -668,8 +680,7 @@ class BrowserbaseBrowser:
668
680
  keep_alive=True,
669
681
  _close_callback=connection.close,
670
682
  ),
671
- extension_id=options.extension_id,
672
- preloaded_extension=options.extension_id is None,
683
+ preloaded_extension=True,
673
684
  worker_init_metadata=_WorkerInitMetadata(
674
685
  api_key=options.api_key,
675
686
  browser=_browser_session_metadata(connection.session_id, connection.region),
@@ -4,7 +4,7 @@ import asyncio
4
4
  import json
5
5
  import re
6
6
  import time
7
- from collections.abc import Mapping
7
+ from collections.abc import Callable, Mapping
8
8
  from contextlib import suppress
9
9
  from dataclasses import dataclass
10
10
  from typing import Any, Literal, Protocol, cast
@@ -253,6 +253,7 @@ class CDPClient:
253
253
  *,
254
254
  cdp_url: str,
255
255
  extension_dir: str | None = None,
256
+ local_extension_dir: Callable[[], str] | None = None,
256
257
  extension_id: str | None = None,
257
258
  preloaded_extension: bool = False,
258
259
  service_worker_url_includes: str | None = None,
@@ -263,9 +264,18 @@ class CDPClient:
263
264
  lifecycle. Direct internal callers must provide cancellation themselves.
264
265
  CDP command acknowledgements inherit that same caller-owned cancellation.
265
266
  """
266
- if sum((bool(extension_dir), bool(extension_id), preloaded_extension)) != 1:
267
+ if (
268
+ sum((
269
+ bool(extension_dir),
270
+ local_extension_dir is not None,
271
+ bool(extension_id),
272
+ preloaded_extension,
273
+ ))
274
+ != 1
275
+ ):
267
276
  raise ValueError(
268
- "Exactly one of extension_dir, extension_id, or preloaded_extension is required"
277
+ "Exactly one of extension_dir, local_extension_dir, extension_id, "
278
+ "or preloaded_extension is required"
269
279
  )
270
280
 
271
281
  web_socket_debugger_url = await _resolve_browser_web_socket_url(cdp_url)
@@ -274,10 +284,14 @@ class CDPClient:
274
284
 
275
285
  try:
276
286
  resolved_extension_id = extension_id
277
- if extension_dir is not None:
287
+ if local_extension_dir is not None:
288
+ resolved_extension_id = await client._resolve_extension(
289
+ load_if_not_found=True, extension_dir=local_extension_dir
290
+ )
291
+ elif extension_dir is not None:
278
292
  resolved_extension_id = await client._load_unpacked_extension(extension_dir)
279
- if preloaded_extension:
280
- resolved_extension_id = await client._discover_installed_stagehand_extension_id()
293
+ elif preloaded_extension:
294
+ resolved_extension_id = await client._resolve_extension(load_if_not_found=False)
281
295
  if resolved_extension_id is None:
282
296
  raise RuntimeError("Stagehand extension ID was not resolved")
283
297
 
@@ -491,12 +505,41 @@ class CDPClient:
491
505
  if error.code == -32601 or "method not found" in str(error).lower():
492
506
  raise RuntimeError(
493
507
  "This Chrome build does not support Extensions.loadUnpacked. "
494
- "Launch with --load-extension and connect using extension_id instead."
508
+ "Preload the Stagehand extension and connect using a Chrome build "
509
+ "that supports Extensions.getExtensions."
495
510
  ) from error
496
511
  raise
497
512
  return _required_string(loaded, "id", "Extensions.loadUnpacked")
498
513
 
499
- async def _discover_installed_stagehand_extension_id(self) -> str:
514
+ async def _resolve_extension(
515
+ self,
516
+ *,
517
+ load_if_not_found: bool,
518
+ extension_dir: Callable[[], str] | None = None,
519
+ ) -> str:
520
+ extension_id: str | None = None
521
+ try:
522
+ extension_id = await self._get_installed_stagehand_extension_id()
523
+ except _CDPCommandError as error:
524
+ unsupported = error.method == "Extensions.getExtensions" and (
525
+ error.code == -32601
526
+ or "method not found" in str(error).lower()
527
+ or "wasn't found" in str(error).lower()
528
+ )
529
+ if not load_if_not_found or not unsupported:
530
+ raise
531
+ if extension_id is not None:
532
+ return extension_id
533
+ if load_if_not_found:
534
+ if extension_dir is None:
535
+ raise ValueError("extension_dir is required to load the Stagehand extension")
536
+ return await self._load_unpacked_extension(extension_dir())
537
+ raise RuntimeError(
538
+ "Stagehand extension is not installed in the connected browser. "
539
+ "The extension must be included when the Browserbase session is created."
540
+ )
541
+
542
+ async def _get_installed_stagehand_extension_id(self) -> str | None:
500
543
  response = await self.send_command("Extensions.getExtensions")
501
544
  installed = [
502
545
  extension
@@ -514,10 +557,7 @@ class CDPClient:
514
557
  raise RuntimeError(
515
558
  "Stagehand extension is installed in the connected browser but is disabled."
516
559
  )
517
- raise RuntimeError(
518
- "Stagehand extension is not installed in the connected browser. "
519
- "The extension must be included when the Browserbase session is created."
520
- )
560
+ return None
521
561
 
522
562
  async def _wait_for_service_worker(
523
563
  self,
@@ -105,7 +105,8 @@ class LocalBrowserConnectOptions(WireModel):
105
105
  model_config = ConfigDict(extra="forbid", strict=True)
106
106
 
107
107
  cdp_url: Annotated[str, Field(min_length=1)]
108
- extension_id: Annotated[str | None, Field(min_length=1)] = None
108
+ extension_id: str | None = None
109
+ """Deprecated and ignored. Omit this field; Stagehand discovers the extension automatically."""
109
110
 
110
111
 
111
112
  class BrowserbaseClientOptions(WireModel):
@@ -125,7 +126,8 @@ class BrowserbaseConnectOptions(WireModel):
125
126
  base_url: Annotated[str, Field(min_length=1)] = DEFAULT_BROWSERBASE_URL
126
127
  client_options: BrowserbaseClientOptions | None = None
127
128
  session_id: Annotated[str, Field(min_length=1)]
128
- extension_id: Annotated[str | None, Field(min_length=1)] = None
129
+ extension_id: str | None = None
130
+ """Deprecated and ignored. Omit this field; Stagehand discovers the extension automatically."""
129
131
 
130
132
 
131
133
  class _BrowserbaseSearchOptions(WireModel):
@@ -66,6 +66,7 @@ class LocalBrowserLaunchOptions(TypedDict, total=False):
66
66
  class LocalBrowserConnectOptions(TypedDict):
67
67
  cdp_url: str
68
68
  extension_id: NotRequired[str]
69
+ """Deprecated and ignored. Omit this field; Stagehand discovers the extension automatically."""
69
70
 
70
71
 
71
72
  class BrowserbaseClientOptions(TypedDict, total=False):
@@ -85,6 +86,7 @@ class BrowserbaseConnectOptions(TypedDict):
85
86
  client_options: NotRequired[BrowserbaseClientOptions]
86
87
  session_id: str
87
88
  extension_id: NotRequired[str]
89
+ """Deprecated and ignored. Omit this field; Stagehand discovers the extension automatically."""
88
90
 
89
91
 
90
92
  class ClientLLM(TypedDict):