stagehand 4.0.3a0.dev1474__tar.gz → 4.0.3a0.dev1475__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 (35) hide show
  1. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/PKG-INFO +1 -1
  2. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/pyproject.toml +1 -1
  3. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_extension/service-worker.js +135 -49
  4. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_generated/protocol_version.py +1 -1
  5. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/stagehand.py +8 -2
  6. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/README.md +0 -0
  7. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/__init__.py +0 -0
  8. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_extension/blank.html +0 -0
  9. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_extension/content-script.js +0 -0
  10. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_extension/manifest.json +0 -0
  11. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_extension/offscreen/service-worker-heartbeat.html +0 -0
  12. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_extension/offscreen/service-worker-heartbeat.js +0 -0
  13. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_extension/wake-service-worker.html +0 -0
  14. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_extension/wake-service-worker.js +0 -0
  15. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_generated/__init__.py +0 -0
  16. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_generated/input_types.py +0 -0
  17. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_generated/models.py +0 -0
  18. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_sdk_identity.py +0 -0
  19. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/_validation.py +0 -0
  20. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/browser.py +0 -0
  21. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/browser_clipboard.py +0 -0
  22. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/browser_context.py +0 -0
  23. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/browserbase_session.py +0 -0
  24. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/cdp_client.py +0 -0
  25. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/client_models.py +0 -0
  26. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/client_types.py +0 -0
  27. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/extension_assets.py +0 -0
  28. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/file_upload.py +0 -0
  29. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/locator.py +0 -0
  30. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/page.py +0 -0
  31. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/py.typed +0 -0
  32. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/response.py +0 -0
  33. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/rpc_client.py +0 -0
  34. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/timeouts.py +0 -0
  35. {stagehand-4.0.3a0.dev1474 → stagehand-4.0.3a0.dev1475}/src/stagehand/webmcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stagehand
3
- Version: 4.0.3a0.dev1474
3
+ Version: 4.0.3a0.dev1475
4
4
  Summary: Browserbase's SDK for building browser agents
5
5
  Keywords: ai,browser,automation,web-scraping,testing
6
6
  Author: Browserbase
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stagehand"
3
- version = "4.0.3a0.dev1474"
3
+ version = "4.0.3a0.dev1475"
4
4
  description = "Browserbase's SDK for building browser agents"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -7359,7 +7359,7 @@ function isRecord$1(value) {
7359
7359
  }
7360
7360
  var package_default$1 = {
7361
7361
  name: "@browserbasehq/stagehand-protocol",
7362
- version: "2.0.0-alpha-d49d643ce9311f16b3ab21289c3bcc01bf0eb097",
7362
+ version: "2.0.0-alpha-341433acac46a305ad6c2f9a0445e907675f4fb4",
7363
7363
  "private": true,
7364
7364
  type: "module",
7365
7365
  scripts: {
@@ -11460,7 +11460,9 @@ var RPCClient = class {
11460
11460
  });
11461
11461
  return;
11462
11462
  }
11463
+ let releaseStagehandInstanceRequest;
11463
11464
  try {
11465
+ if (request.data.method !== StagehandMethods.stagehandInit.name && request.data.method !== StagehandMethods.stagehandClose.name) releaseStagehandInstanceRequest = this.router.runtime.acquireStagehandInstanceRequest();
11464
11466
  const result = await this.router.handle(stagehandRequest.data, runtimeAttachments);
11465
11467
  const parsedResult = method.result.safeParse(result);
11466
11468
  if (!parsedResult.success) {
@@ -11470,6 +11472,7 @@ var RPCClient = class {
11470
11472
  });
11471
11473
  return;
11472
11474
  }
11475
+ await this.router.beforeResponse(stagehandRequest.data);
11473
11476
  await this.runtime.send(JSONRPCSuccessResponseSchema.parse({
11474
11477
  jsonrpc: "2.0",
11475
11478
  id: request.data.id,
@@ -11484,6 +11487,8 @@ var RPCClient = class {
11484
11487
  return;
11485
11488
  }
11486
11489
  await this.sendError(request.data.id, JSONRPCErrorCodes.internalError, error instanceof Error ? error.message : String(error), { name: error instanceof Error ? error.name : "Error" });
11490
+ } finally {
11491
+ releaseStagehandInstanceRequest?.();
11487
11492
  }
11488
11493
  }
11489
11494
  receiveResponse(response) {
@@ -50846,13 +50851,13 @@ async function observe({ params, page, model, clientLLMGenerate, logger, systemP
50846
50851
  //#endregion
50847
50852
  //#region controllers/stagehandController.ts
50848
50853
  function createStagehandController(runtime, options = {}) {
50849
- const closeRuntime = options.close ?? (() => runtime.close());
50854
+ const closeRuntime = options.close ?? (() => runtime.disposeStagehandInstance());
50850
50855
  async function runOperation(name, { logger, telemetryScope }, run) {
50851
50856
  return await logger.span(name, {}, (logger) => runtime.runWithTelemetryContext(telemetryScope, logger, () => run(logger)));
50852
50857
  }
50853
50858
  async function init(params, { logger }) {
50854
50859
  const compatibility = checkProtocolCompatibility(params.protocolVersion, STAGEHAND_PROTOCOL_VERSION);
50855
- if (!compatibility.compatible) throw new StagehandProtocolCompatibilityError(compatibility.reason);
50860
+ if (compatibility.compatible === false) throw new StagehandProtocolCompatibilityError(compatibility.reason);
50856
50861
  logger.setLevel(params.logLevel);
50857
50862
  logger.info("stagehand.init", {});
50858
50863
  return options.initialize ? await options.initialize(params) : await runtime.initialize(params, logger);
@@ -50961,7 +50966,7 @@ var RPCRouter = class {
50961
50966
  }
50962
50967
  async handle(request, runtimeAttachments) {
50963
50968
  const initParams = request.method === StagehandMethods.stagehandInit.name ? request.params : void 0;
50964
- if (initParams) this.runtime.tracing.configure(initParams.telemetry, initParams.clientInfo);
50969
+ if (initParams) await this.runtime.tracing.configure(initParams.telemetry, initParams.clientInfo);
50965
50970
  const parentContext = W3C_TRACE_CONTEXT_PROPAGATOR.extract(ROOT_CONTEXT, request, {
50966
50971
  get(carrier, key) {
50967
50972
  if (key === "traceparent" || key === "tracestate") return carrier[key];
@@ -50996,9 +51001,12 @@ var RPCRouter = class {
50996
51001
  throw error;
50997
51002
  } finally {
50998
51003
  span.end();
50999
- if (request.method === StagehandMethods.stagehandClose.name) await this.runtime.tracing.shutdown();
51000
51004
  }
51001
51005
  }
51006
+ async beforeResponse(request) {
51007
+ if (request.method !== StagehandMethods.stagehandClose.name) return;
51008
+ await this.runtime.tracing.forceFlush().catch(() => void 0);
51009
+ }
51002
51010
  async route(request, context, parsedInitParams) {
51003
51011
  switch (request.method) {
51004
51012
  case "stagehand.init": return this.stagehandController.init(parsedInitParams ?? parseParams(StagehandMethods.stagehandInit, request.params), context);
@@ -51260,14 +51268,10 @@ var StagehandLogger = class StagehandLogger {
51260
51268
  };
51261
51269
  //#endregion
51262
51270
  //#region runtimeState.ts
51263
- var StagehandRuntimeStateSchema = discriminatedUnion("status", [
51264
- strictObject({ status: literal("created") }),
51265
- strictObject({
51266
- status: literal("initialized"),
51267
- initParams: StagehandInitParamsSchema
51268
- }),
51269
- strictObject({ status: literal("closed") })
51270
- ]);
51271
+ var StagehandRuntimeStateSchema = discriminatedUnion("status", [strictObject({ status: literal("idle") }), strictObject({
51272
+ status: literal("initialized"),
51273
+ initParams: StagehandInitParamsSchema
51274
+ })]);
51271
51275
  //#endregion
51272
51276
  //#region ../../node_modules/.pnpm/@opentelemetry+otlp-exporter-base@0.220.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/otlp-exporter-base/build/esm/OTLPExporterBase.js
51273
51277
  var OTLPExporterBase = class {
@@ -53443,7 +53447,7 @@ var WebTracerProvider = class extends BasicTracerProvider {
53443
53447
  };
53444
53448
  var package_default = {
53445
53449
  name: "@browserbasehq/stagehand-extension",
53446
- version: "1.0.2-alpha-d49d643ce9311f16b3ab21289c3bcc01bf0eb097",
53450
+ version: "1.0.2-alpha-341433acac46a305ad6c2f9a0445e907675f4fb4",
53447
53451
  "private": true,
53448
53452
  type: "module",
53449
53453
  scripts: {
@@ -53518,22 +53522,48 @@ function createStagehandTracing(options = {}, dependencies = DEFAULT_TRACING_RUN
53518
53522
  const pendingTracer = trace.getTracer(STAGEHAND_TRACER_NAME);
53519
53523
  let runtime;
53520
53524
  let shutDown = false;
53525
+ let globalsRegistered = false;
53526
+ let lifecycleTail = Promise.resolve();
53527
+ let activeTelemetry;
53528
+ let activeClientInfo;
53529
+ function enqueueLifecycle(run) {
53530
+ const result = lifecycleTail.then(run, run);
53531
+ lifecycleTail = result.catch(() => void 0);
53532
+ return result;
53533
+ }
53521
53534
  return {
53522
53535
  get tracer() {
53523
53536
  return runtime?.tracer ?? pendingTracer;
53524
53537
  },
53525
53538
  configure(telemetry, clientInfo) {
53526
- if (runtime || shutDown) return;
53527
- runtime = createStagehandTracingRuntime({
53528
- ...options,
53529
- clientName: clientInfo.name,
53530
- clientVersion: clientInfo.version
53531
- }, { spanProcessors: [...dependencies.spanProcessors, createOtlpSpanProcessor(telemetry.traces)] });
53539
+ return enqueueLifecycle(async () => {
53540
+ if (shutDown) return;
53541
+ if (runtime && telemetry === activeTelemetry && clientInfo === activeClientInfo) return;
53542
+ const previousRuntime = runtime;
53543
+ runtime = void 0;
53544
+ await previousRuntime?.shutdown();
53545
+ const registerGlobals = options.registerGlobals !== false && !globalsRegistered;
53546
+ runtime = createStagehandTracingRuntime({
53547
+ ...options,
53548
+ clientName: clientInfo.name,
53549
+ clientVersion: clientInfo.version,
53550
+ registerGlobals
53551
+ }, { spanProcessors: [...dependencies.spanProcessors, createOtlpSpanProcessor(telemetry.traces)] });
53552
+ activeTelemetry = telemetry;
53553
+ activeClientInfo = clientInfo;
53554
+ globalsRegistered ||= registerGlobals;
53555
+ });
53532
53556
  },
53533
- forceFlush: () => runtime?.forceFlush() ?? Promise.resolve(),
53557
+ forceFlush: () => enqueueLifecycle(() => runtime?.forceFlush() ?? Promise.resolve()),
53534
53558
  shutdown: () => {
53535
53559
  shutDown = true;
53536
- return runtime?.shutdown() ?? Promise.resolve();
53560
+ return enqueueLifecycle(async () => {
53561
+ const activeRuntime = runtime;
53562
+ runtime = void 0;
53563
+ activeTelemetry = void 0;
53564
+ activeClientInfo = void 0;
53565
+ await activeRuntime?.shutdown();
53566
+ });
53537
53567
  }
53538
53568
  };
53539
53569
  }
@@ -56822,6 +56852,9 @@ var StagehandMetricsAccumulator = class {
56822
56852
  snapshot() {
56823
56853
  return { ...this.values };
56824
56854
  }
56855
+ reset() {
56856
+ Object.assign(this.values, EMPTY_METRICS);
56857
+ }
56825
56858
  };
56826
56859
  //#endregion
56827
56860
  //#region responseHandleTable.ts
@@ -56909,10 +56942,13 @@ var StagehandRuntime = class {
56909
56942
  this.tracing = tracing;
56910
56943
  this.metrics = new StagehandMetricsAccumulator();
56911
56944
  this.responseHandles = new ResponseHandleTable();
56912
- this.state = createStore()(() => StagehandRuntimeStateSchema.parse({ status: "created" }));
56945
+ this.state = createStore()(() => StagehandRuntimeStateSchema.parse({ status: "idle" }));
56913
56946
  this.pagesById = /* @__PURE__ */ new Map();
56914
56947
  this.pageEventSubscriptions = /* @__PURE__ */ new Map();
56915
56948
  this.initializationInProgress = false;
56949
+ this.lifecycleTail = Promise.resolve();
56950
+ this.stagehandInstanceClosing = false;
56951
+ this.activeStagehandInstanceRequests = 0;
56916
56952
  this.logger = new StagehandLogger(tracing, adapters.emitLog);
56917
56953
  }
56918
56954
  async replaceBrowserConnection(params, bootstrapLogger) {
@@ -56932,29 +56968,31 @@ var StagehandRuntime = class {
56932
56968
  }
56933
56969
  }
56934
56970
  async initialize(params, logger = this.logger) {
56935
- const state = this.state.getState();
56936
- if (state.status === "closed") throw new Error("Stagehand has been closed and cannot be initialized again");
56937
56971
  if (this.initializationInProgress) throw new Error("Stagehand initialization is already in progress");
56938
56972
  this.initializationInProgress = true;
56939
56973
  try {
56940
- this.logger.setLevel(params.logLevel);
56941
- if (!this.browserSession) {
56942
- if (!params.browserCdpUrl) throw new Error("stagehand.init requires browserCdpUrl until resident mode is active");
56943
- await this.replaceBrowserConnection({ cdpUrl: params.browserCdpUrl }, logger);
56944
- }
56945
- const pages = await this.runWithTelemetryContext(Symbol("stagehand.init"), logger, async () => {
56946
- if (state.status === "created") await this.browserSession?.prepareForInitialization?.();
56947
- return await this.contextPages();
56948
- });
56949
- this.tracing.configure(params.telemetry, params.clientInfo);
56950
- this.state.setState(StagehandRuntimeStateSchema.parse({
56951
- status: "initialized",
56952
- initParams: params
56953
- }), true);
56954
- return {
56955
- initialized: true,
56956
- pages
56957
- };
56974
+ return await this.enqueueLifecycle(async () => {
56975
+ const state = this.state.getState();
56976
+ if (state.status !== "idle") throw new Error("A Stagehand instance is already initialized");
56977
+ this.logger.setLevel(params.logLevel);
56978
+ if (!this.browserSession?.connected) {
56979
+ if (!params.browserCdpUrl) throw new Error("stagehand.init requires browserCdpUrl until resident mode is active");
56980
+ await this.replaceBrowserConnection({ cdpUrl: params.browserCdpUrl }, logger);
56981
+ }
56982
+ const pages = await this.runWithTelemetryContext(Symbol("stagehand.init"), logger, async () => {
56983
+ if (state.status === "idle") await this.browserSession?.prepareForInitialization?.();
56984
+ return await this.contextPages();
56985
+ });
56986
+ await this.tracing.configure(params.telemetry, params.clientInfo);
56987
+ this.state.setState(StagehandRuntimeStateSchema.parse({
56988
+ status: "initialized",
56989
+ initParams: params
56990
+ }), true);
56991
+ return {
56992
+ initialized: true,
56993
+ pages
56994
+ };
56995
+ });
56958
56996
  } finally {
56959
56997
  this.initializationInProgress = false;
56960
56998
  }
@@ -57291,16 +57329,64 @@ var StagehandRuntime = class {
57291
57329
  return { set: true };
57292
57330
  }
57293
57331
  async close() {
57294
- const session = this.browserSession;
57295
- this.browserSession = void 0;
57332
+ await this.enqueueLifecycle(async () => {
57333
+ const session = this.browserSession;
57334
+ this.browserSession = void 0;
57335
+ this.clearStagehandInstance();
57336
+ await session?.close();
57337
+ });
57338
+ }
57339
+ async disposeStagehandInstance() {
57340
+ if (this.stagehandInstanceDisposal) return await this.stagehandInstanceDisposal;
57341
+ this.stagehandInstanceClosing = true;
57342
+ const disposal = this.enqueueLifecycle(async () => {
57343
+ await this.waitForStagehandInstanceRequests();
57344
+ this.clearStagehandInstance();
57345
+ });
57346
+ this.stagehandInstanceDisposal = disposal.finally(() => {
57347
+ this.stagehandInstanceClosing = false;
57348
+ this.stagehandInstanceDisposal = void 0;
57349
+ });
57350
+ return await this.stagehandInstanceDisposal;
57351
+ }
57352
+ acquireStagehandInstanceRequest() {
57353
+ if (this.stagehandInstanceClosing) throw new Error("Stagehand instance is closing");
57354
+ this.activeStagehandInstanceRequests += 1;
57355
+ let released = false;
57356
+ return () => {
57357
+ if (released) return;
57358
+ released = true;
57359
+ this.activeStagehandInstanceRequests -= 1;
57360
+ if (this.activeStagehandInstanceRequests !== 0) return;
57361
+ this.stagehandInstanceRequestsDrained?.resolve();
57362
+ this.stagehandInstanceRequestsDrained = void 0;
57363
+ };
57364
+ }
57365
+ clearStagehandInstance() {
57296
57366
  this.disposeAllPageEventSubscriptions();
57297
57367
  this.pagesById.clear();
57298
57368
  this.responseHandles.clear();
57299
- try {
57300
- await session?.close();
57301
- } finally {
57302
- this.state.setState(StagehandRuntimeStateSchema.parse({ status: "closed" }), true);
57369
+ this.metrics.reset();
57370
+ this.state.setState(StagehandRuntimeStateSchema.parse({ status: "idle" }), true);
57371
+ }
57372
+ enqueueLifecycle(run) {
57373
+ const result = this.lifecycleTail.then(run, run);
57374
+ this.lifecycleTail = result.then(() => void 0, () => void 0);
57375
+ return result;
57376
+ }
57377
+ waitForStagehandInstanceRequests() {
57378
+ if (this.activeStagehandInstanceRequests === 0) return Promise.resolve();
57379
+ if (!this.stagehandInstanceRequestsDrained) {
57380
+ let resolve;
57381
+ const promise = new Promise((drained) => {
57382
+ resolve = drained;
57383
+ });
57384
+ this.stagehandInstanceRequestsDrained = {
57385
+ promise,
57386
+ resolve
57387
+ };
57303
57388
  }
57389
+ return this.stagehandInstanceRequestsDrained.promise;
57304
57390
  }
57305
57391
  pageRefForId(pageId) {
57306
57392
  return pageRefFromUnderstudyPage(this.resolvePage(pageId));
@@ -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.0.0-alpha-d49d643ce9311f16b3ab21289c3bcc01bf0eb097'
4
+ STAGEHAND_PROTOCOL_VERSION = '2.0.0-alpha-341433acac46a305ad6c2f9a0445e907675f4fb4'
@@ -450,6 +450,7 @@ class Stagehand:
450
450
 
451
451
  async def close(self) -> None:
452
452
  async def close_impl() -> None:
453
+ release_browser_claim = not self._initialized
453
454
  try:
454
455
  if self._initialized and self._rpc_client is not None:
455
456
  try:
@@ -458,10 +459,15 @@ class Stagehand:
458
459
  EmptyParams(),
459
460
  StagehandCloseResult,
460
461
  )
462
+ release_browser_claim = True
461
463
  except CDPConnectionClosedError:
462
- pass
464
+ release_browser_claim = True
463
465
  finally:
464
- await asyncio.shield(self._release_resources())
466
+ try:
467
+ await asyncio.shield(self._release_resources())
468
+ finally:
469
+ if release_browser_claim:
470
+ _release_browser(self._browser_handle)
465
471
 
466
472
  if self._close_task is None:
467
473
  self._close_task = asyncio.create_task(