@browserbasehq/orca 3.0.0-test.1 → 3.0.1

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.
package/dist/index.js CHANGED
@@ -603,6 +603,19 @@ function captureHybridSnapshot(page, options) {
603
603
  const perFrameMaps = /* @__PURE__ */ new Map();
604
604
  const requestedFocus = (_b = options == null ? void 0 : options.focusSelector) == null ? void 0 : _b.trim();
605
605
  if (requestedFocus) {
606
+ const logScopeFallback = () => {
607
+ var _a2;
608
+ v3Logger({
609
+ message: `Unable to narrow scope with selector. Falling back to using full DOM`,
610
+ level: 1,
611
+ auxiliary: {
612
+ arguments: {
613
+ value: `selector: ${(_a2 = options == null ? void 0 : options.focusSelector) == null ? void 0 : _a2.trim()}`,
614
+ type: "string"
615
+ }
616
+ }
617
+ });
618
+ };
606
619
  try {
607
620
  let targetFrameId;
608
621
  let tailSelector;
@@ -641,7 +654,7 @@ function captureHybridSnapshot(page, options) {
641
654
  /*attemptOwnerLookup=*/
642
655
  sameSessionAsParent
643
656
  );
644
- const { outline, urlMap } = yield a11yForFrame(
657
+ const { outline, urlMap, scopeApplied } = yield a11yForFrame(
645
658
  owningSess,
646
659
  targetFrameId,
647
660
  {
@@ -663,7 +676,7 @@ function captureHybridSnapshot(page, options) {
663
676
  }
664
677
  }
665
678
  const combinedUrlMap2 = __spreadValues({}, urlMap);
666
- return {
679
+ const snapshot = {
667
680
  combinedTree: outline,
668
681
  combinedXpathMap: combinedXpathMap2,
669
682
  combinedUrlMap: combinedUrlMap2,
@@ -676,7 +689,12 @@ function captureHybridSnapshot(page, options) {
676
689
  }
677
690
  ]
678
691
  };
692
+ if (scopeApplied) {
693
+ return snapshot;
694
+ }
695
+ logScopeFallback();
679
696
  } catch (e) {
697
+ logScopeFallback();
680
698
  }
681
699
  }
682
700
  function buildSessionDomIndex(session, pierce2) {
@@ -1144,6 +1162,7 @@ function a11yForFrame(session, frameId, opts) {
1144
1162
  const enc = opts.encode(be);
1145
1163
  urlMap[enc] = url;
1146
1164
  }
1165
+ let scopeApplied = false;
1147
1166
  const nodesForOutline = yield (() => __async(null, null, function* () {
1148
1167
  var _a2, _b2, _c;
1149
1168
  const sel = (_a2 = opts.focusSelector) == null ? void 0 : _a2.trim();
@@ -1160,6 +1179,7 @@ function a11yForFrame(session, frameId, opts) {
1160
1179
  if (typeof be !== "number") return nodes;
1161
1180
  const target = nodes.find((n) => n.backendDOMNodeId === be);
1162
1181
  if (!target) return nodes;
1182
+ scopeApplied = true;
1163
1183
  const keep = /* @__PURE__ */ new Set([target.nodeId]);
1164
1184
  const queue = [target];
1165
1185
  while (queue.length) {
@@ -1181,7 +1201,7 @@ function a11yForFrame(session, frameId, opts) {
1181
1201
  const decorated = decorateRoles(nodesForOutline, opts);
1182
1202
  const { tree } = yield buildHierarchicalTree(decorated, opts);
1183
1203
  const simplified = tree.map((n) => formatTreeLine(n)).join("\n");
1184
- return { outline: simplified.trimEnd(), urlMap };
1204
+ return { outline: simplified.trimEnd(), urlMap, scopeApplied };
1185
1205
  });
1186
1206
  }
1187
1207
  function resolveObjectIdForXPath(session, xpath, frameId) {
@@ -1532,6 +1552,7 @@ var IFRAME_STEP_RE;
1532
1552
  var init_snapshot = __esm({
1533
1553
  "lib/v3/understudy/a11y/snapshot.ts"() {
1534
1554
  init_executionContextRegistry();
1555
+ init_logger();
1535
1556
  IFRAME_STEP_RE = /^iframe(?:\[\d+])?$/i;
1536
1557
  }
1537
1558
  });
@@ -3908,11 +3929,11 @@ var require_src = __commonJS({
3908
3929
  var require_is_docker = __commonJS({
3909
3930
  "../../node_modules/.pnpm/is-docker@2.2.1/node_modules/is-docker/index.js"(exports2, module2) {
3910
3931
  "use strict";
3911
- var fs7 = require("fs");
3932
+ var fs8 = require("fs");
3912
3933
  var isDocker;
3913
3934
  function hasDockerEnv() {
3914
3935
  try {
3915
- fs7.statSync("/.dockerenv");
3936
+ fs8.statSync("/.dockerenv");
3916
3937
  return true;
3917
3938
  } catch (_) {
3918
3939
  return false;
@@ -3920,7 +3941,7 @@ var require_is_docker = __commonJS({
3920
3941
  }
3921
3942
  function hasDockerCGroup() {
3922
3943
  try {
3923
- return fs7.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
3944
+ return fs8.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
3924
3945
  } catch (_) {
3925
3946
  return false;
3926
3947
  }
@@ -3939,7 +3960,7 @@ var require_is_wsl = __commonJS({
3939
3960
  "../../node_modules/.pnpm/is-wsl@2.2.0/node_modules/is-wsl/index.js"(exports2, module2) {
3940
3961
  "use strict";
3941
3962
  var os3 = require("os");
3942
- var fs7 = require("fs");
3963
+ var fs8 = require("fs");
3943
3964
  var isDocker = require_is_docker();
3944
3965
  var isWsl3 = () => {
3945
3966
  if (process.platform !== "linux") {
@@ -3952,7 +3973,7 @@ var require_is_wsl = __commonJS({
3952
3973
  return true;
3953
3974
  }
3954
3975
  try {
3955
- return fs7.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
3976
+ return fs8.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !isDocker() : false;
3956
3977
  } catch (_) {
3957
3978
  return false;
3958
3979
  }
@@ -3965,6 +3986,342 @@ var require_is_wsl = __commonJS({
3965
3986
  }
3966
3987
  });
3967
3988
 
3989
+ // lib/v3/understudy/consoleMessage.ts
3990
+ function formatRemoteObject(obj) {
3991
+ var _a;
3992
+ if (!obj) return "";
3993
+ if ("value" in obj) {
3994
+ const value = obj.value;
3995
+ if (value === void 0) return "";
3996
+ if (typeof value === "string") return value;
3997
+ try {
3998
+ return JSON.stringify(value);
3999
+ } catch (e) {
4000
+ return String(value);
4001
+ }
4002
+ }
4003
+ if (obj.unserializableValue) return obj.unserializableValue;
4004
+ if (obj.description) return obj.description;
4005
+ return (_a = obj.type) != null ? _a : "";
4006
+ }
4007
+ var ConsoleMessage;
4008
+ var init_consoleMessage = __esm({
4009
+ "lib/v3/understudy/consoleMessage.ts"() {
4010
+ ConsoleMessage = class {
4011
+ constructor(event, pageRef) {
4012
+ this.event = event;
4013
+ this.pageRef = pageRef;
4014
+ }
4015
+ type() {
4016
+ return this.event.type;
4017
+ }
4018
+ text() {
4019
+ const args = this.args();
4020
+ if (!args.length) return "";
4021
+ return args.map((arg) => formatRemoteObject(arg)).filter((chunk) => chunk.length > 0).join(" ");
4022
+ }
4023
+ args() {
4024
+ return this.event.args ? [...this.event.args] : [];
4025
+ }
4026
+ location() {
4027
+ var _a, _b;
4028
+ const frame = (_b = (_a = this.event.stackTrace) == null ? void 0 : _a.callFrames) == null ? void 0 : _b[0];
4029
+ return {
4030
+ url: frame == null ? void 0 : frame.url,
4031
+ lineNumber: frame == null ? void 0 : frame.lineNumber,
4032
+ columnNumber: frame == null ? void 0 : frame.columnNumber
4033
+ };
4034
+ }
4035
+ page() {
4036
+ return this.pageRef;
4037
+ }
4038
+ timestamp() {
4039
+ return this.event.timestamp;
4040
+ }
4041
+ raw() {
4042
+ return this.event;
4043
+ }
4044
+ toString() {
4045
+ return this.text();
4046
+ }
4047
+ };
4048
+ }
4049
+ });
4050
+
4051
+ // lib/v3/understudy/response.ts
4052
+ function createDeferred() {
4053
+ let resolve3;
4054
+ let reject;
4055
+ const promise = new Promise((res, rej) => {
4056
+ resolve3 = res;
4057
+ reject = rej;
4058
+ });
4059
+ return { promise, resolve: resolve3, reject };
4060
+ }
4061
+ function normaliseHeaderName(name) {
4062
+ return name.toLowerCase();
4063
+ }
4064
+ function splitHeaderValues(value) {
4065
+ return value.split(/\r?\n/).map((part) => part.trim()).filter(Boolean);
4066
+ }
4067
+ function parseHeadersText(headersText) {
4068
+ if (!headersText) return [];
4069
+ const lines = headersText.split(/\r?\n/);
4070
+ const entries = [];
4071
+ for (const line of lines) {
4072
+ if (!line || line.startsWith("HTTP/")) continue;
4073
+ const index = line.indexOf(":");
4074
+ if (index === -1) continue;
4075
+ const name = line.slice(0, index).trim();
4076
+ const value = line.slice(index + 1).trim();
4077
+ entries.push({ name, value });
4078
+ }
4079
+ return entries;
4080
+ }
4081
+ var Response;
4082
+ var init_response = __esm({
4083
+ "lib/v3/understudy/response.ts"() {
4084
+ Response = class {
4085
+ /**
4086
+ * Build a response wrapper from the CDP notification associated with a
4087
+ * navigation. The constructor captures the owning page/session so follow-up
4088
+ * methods (body/text/json) can query CDP on-demand. The `response` payload is
4089
+ * the raw `Protocol.Network.Response` object emitted by Chrome.
4090
+ */
4091
+ constructor(params) {
4092
+ this.headersArrayCache = null;
4093
+ this.allHeadersCache = null;
4094
+ this.headerValuesMap = /* @__PURE__ */ new Map();
4095
+ this.finishedDeferred = createDeferred();
4096
+ this.finishedSettled = false;
4097
+ this.extraInfoHeaders = null;
4098
+ var _a;
4099
+ this.page = params.page;
4100
+ this.session = params.session;
4101
+ this.requestId = params.requestId;
4102
+ this.frameId = params.frameId;
4103
+ this.loaderId = params.loaderId;
4104
+ this.response = params.response;
4105
+ this.fromServiceWorkerFlag = params.fromServiceWorker;
4106
+ if (params.response.remoteIPAddress && params.response.remotePort !== void 0) {
4107
+ this.serverAddress = {
4108
+ ipAddress: params.response.remoteIPAddress,
4109
+ port: params.response.remotePort
4110
+ };
4111
+ } else {
4112
+ this.serverAddress = null;
4113
+ }
4114
+ this.headersObject = {};
4115
+ for (const [name, value] of Object.entries((_a = this.response.headers) != null ? _a : {})) {
4116
+ const lower = normaliseHeaderName(name);
4117
+ if (value === void 0) continue;
4118
+ const values = splitHeaderValues(String(value));
4119
+ this.headerValuesMap.set(lower, values);
4120
+ this.headersObject[lower] = values.join(", ");
4121
+ }
4122
+ }
4123
+ /** URL associated with the navigation request. */
4124
+ url() {
4125
+ return this.response.url;
4126
+ }
4127
+ /** HTTP status code reported by Chrome. */
4128
+ status() {
4129
+ return this.response.status;
4130
+ }
4131
+ /** Human-readable status text that accompanied the response. */
4132
+ statusText() {
4133
+ return this.response.statusText;
4134
+ }
4135
+ /** Convenience predicate that checks for 2xx statuses. */
4136
+ ok() {
4137
+ const status = this.status();
4138
+ return status >= 200 && status <= 299;
4139
+ }
4140
+ /** Returns the Stagehand frame object that initiated the navigation. */
4141
+ frame() {
4142
+ if (!this.frameId) return null;
4143
+ try {
4144
+ return this.page.frameForId(this.frameId);
4145
+ } catch (e) {
4146
+ return null;
4147
+ }
4148
+ }
4149
+ /** Indicates whether the response was serviced by a Service Worker. */
4150
+ fromServiceWorker() {
4151
+ return this.fromServiceWorkerFlag;
4152
+ }
4153
+ /**
4154
+ * Returns TLS security metadata when provided by the browser. In practice
4155
+ * this includes certificate issuer, protocol, and validity interval.
4156
+ */
4157
+ securityDetails() {
4158
+ return __async(this, null, function* () {
4159
+ var _a;
4160
+ return (_a = this.response.securityDetails) != null ? _a : null;
4161
+ });
4162
+ }
4163
+ /** Returns the resolved server address for the navigation when available. */
4164
+ serverAddr() {
4165
+ return __async(this, null, function* () {
4166
+ var _a;
4167
+ return (_a = this.serverAddress) != null ? _a : null;
4168
+ });
4169
+ }
4170
+ /**
4171
+ * Returns the response headers normalised to lowercase keys. Matches the
4172
+ * behaviour of Playwright's `headers()` by eliding duplicate header entries.
4173
+ */
4174
+ headers() {
4175
+ return __spreadValues({}, this.headersObject);
4176
+ }
4177
+ /**
4178
+ * Returns all headers including those only surfaced through
4179
+ * `responseReceivedExtraInfo` such as `set-cookie`. Values are reported as the
4180
+ * browser sends them (no further splitting or concatenation).
4181
+ */
4182
+ allHeaders() {
4183
+ return __async(this, null, function* () {
4184
+ var _a, _b;
4185
+ if (this.allHeadersCache) return __spreadValues({}, this.allHeadersCache);
4186
+ const source = (_b = (_a = this.extraInfoHeaders) != null ? _a : this.response.headers) != null ? _b : {};
4187
+ const map = {};
4188
+ for (const [name, value] of Object.entries(source)) {
4189
+ map[name] = String(value);
4190
+ }
4191
+ this.allHeadersCache = map;
4192
+ return __spreadValues({}, map);
4193
+ });
4194
+ }
4195
+ /** Returns a concatenated header string for the supplied header name. */
4196
+ headerValue(name) {
4197
+ return __async(this, null, function* () {
4198
+ const values = yield this.headerValues(name);
4199
+ if (!values.length) return null;
4200
+ return values.join(", ");
4201
+ });
4202
+ }
4203
+ /** Returns all values for a header (case-insensitive lookup). */
4204
+ headerValues(name) {
4205
+ return __async(this, null, function* () {
4206
+ var _a;
4207
+ const lower = normaliseHeaderName(name);
4208
+ if (this.extraInfoHeaders) {
4209
+ const raw = (_a = this.extraInfoHeaders[name]) != null ? _a : this.extraInfoHeaders[lower];
4210
+ if (raw !== void 0) {
4211
+ return splitHeaderValues(String(raw));
4212
+ }
4213
+ }
4214
+ const values = this.headerValuesMap.get(lower);
4215
+ return values ? [...values] : [];
4216
+ });
4217
+ }
4218
+ /**
4219
+ * Returns header entries preserving their original wire casing and ordering.
4220
+ * Falls back to the CDP object when the raw header text is unavailable.
4221
+ */
4222
+ headersArray() {
4223
+ return __async(this, null, function* () {
4224
+ var _a, _b;
4225
+ if (this.headersArrayCache) return [...this.headersArrayCache];
4226
+ const entriesFromText = parseHeadersText(this.extraInfoHeadersText);
4227
+ if (entriesFromText.length > 0) {
4228
+ this.headersArrayCache = entriesFromText;
4229
+ return [...entriesFromText];
4230
+ }
4231
+ const entries = [];
4232
+ const source = (_b = (_a = this.extraInfoHeaders) != null ? _a : this.response.headers) != null ? _b : {};
4233
+ for (const [name, value] of Object.entries(source)) {
4234
+ const values = splitHeaderValues(String(value));
4235
+ for (const val of values) {
4236
+ entries.push({ name, value: val });
4237
+ }
4238
+ }
4239
+ this.headersArrayCache = entries;
4240
+ return [...entries];
4241
+ });
4242
+ }
4243
+ /**
4244
+ * Requests the raw response body from Chrome DevTools Protocol. The method is
4245
+ * intentionally lazy because not every caller needs the payload, and CDP only
4246
+ * allows retrieving it once the response completes.
4247
+ */
4248
+ body() {
4249
+ return __async(this, null, function* () {
4250
+ const result = yield this.session.send(
4251
+ "Network.getResponseBody",
4252
+ { requestId: this.requestId }
4253
+ ).catch((error) => {
4254
+ throw new Error(`Failed to retrieve response body: ${String(error)}`);
4255
+ });
4256
+ if (result.base64Encoded) {
4257
+ return Buffer.from(result.body, "base64");
4258
+ }
4259
+ return Buffer.from(result.body, "utf-8");
4260
+ });
4261
+ }
4262
+ /** Decodes the response body as UTF-8 text. */
4263
+ text() {
4264
+ return __async(this, null, function* () {
4265
+ const buffer = yield this.body();
4266
+ return buffer.toString("utf-8");
4267
+ });
4268
+ }
4269
+ /** Parses the response body as JSON and throws if parsing fails. */
4270
+ json() {
4271
+ return __async(this, null, function* () {
4272
+ const text = yield this.text();
4273
+ try {
4274
+ return JSON.parse(text);
4275
+ } catch (error) {
4276
+ throw new Error(`Failed to parse JSON response: ${String(error)}`);
4277
+ }
4278
+ });
4279
+ }
4280
+ /**
4281
+ * Resolves once the underlying network request completes or fails. Mirrors
4282
+ * Playwright's behaviour by resolving to `null` on success and to an `Error`
4283
+ * instance when Chrome reports `Network.loadingFailed`.
4284
+ */
4285
+ finished() {
4286
+ return __async(this, null, function* () {
4287
+ return this.finishedDeferred.promise;
4288
+ });
4289
+ }
4290
+ /**
4291
+ * Internal helper invoked by the navigation tracker when CDP reports extra
4292
+ * header information. This keeps the cached header views in sync with the
4293
+ * richer metadata.
4294
+ */
4295
+ applyExtraInfo(event) {
4296
+ var _a;
4297
+ this.extraInfoHeaders = event.headers;
4298
+ this.extraInfoHeadersText = event.headersText;
4299
+ this.allHeadersCache = null;
4300
+ this.headersArrayCache = null;
4301
+ this.headersObject = {};
4302
+ this.headerValuesMap.clear();
4303
+ const source = (_a = event.headers) != null ? _a : {};
4304
+ for (const [name, value] of Object.entries(source)) {
4305
+ const lower = normaliseHeaderName(name);
4306
+ const segments = splitHeaderValues(String(value));
4307
+ this.headerValuesMap.set(lower, segments);
4308
+ this.headersObject[lower] = segments.join(", ");
4309
+ }
4310
+ }
4311
+ /** Marks the response as finished and resolves the `finished()` promise. */
4312
+ markFinished(error) {
4313
+ if (this.finishedSettled) return;
4314
+ this.finishedSettled = true;
4315
+ if (error) {
4316
+ this.finishedDeferred.resolve(error);
4317
+ } else {
4318
+ this.finishedDeferred.resolve(null);
4319
+ }
4320
+ }
4321
+ };
4322
+ }
4323
+ });
4324
+
3968
4325
  // lib/v3/understudy/frame.ts
3969
4326
  var Frame;
3970
4327
  var init_frame = __esm({
@@ -4084,12 +4441,32 @@ var init_frame = __esm({
4084
4441
  /** Page.captureScreenshot (frame-scoped session) */
4085
4442
  screenshot(options) {
4086
4443
  return __async(this, null, function* () {
4444
+ var _a;
4087
4445
  yield this.session.send("Page.enable");
4446
+ const format = (_a = options == null ? void 0 : options.type) != null ? _a : "png";
4088
4447
  const params = {
4089
- format: "png",
4448
+ format,
4449
+ fromSurface: true,
4090
4450
  captureBeyondViewport: options == null ? void 0 : options.fullPage
4091
4451
  };
4092
- if (options == null ? void 0 : options.clip) params.clip = __spreadProps(__spreadValues({}, options.clip), { scale: 1 });
4452
+ const clampScale = (value) => Math.min(2, Math.max(0.1, value));
4453
+ const normalizedScale = typeof (options == null ? void 0 : options.scale) === "number" ? clampScale(options.scale) : void 0;
4454
+ if (options == null ? void 0 : options.clip) {
4455
+ const clip = {
4456
+ x: options.clip.x,
4457
+ y: options.clip.y,
4458
+ width: options.clip.width,
4459
+ height: options.clip.height,
4460
+ scale: normalizedScale != null ? normalizedScale : 1
4461
+ };
4462
+ params.clip = clip;
4463
+ } else if (normalizedScale !== void 0 && normalizedScale !== 1) {
4464
+ params.scale = normalizedScale;
4465
+ }
4466
+ if (format === "jpeg" && typeof (options == null ? void 0 : options.quality) === "number") {
4467
+ const q = Math.round(options.quality);
4468
+ params.quality = Math.min(100, Math.max(0, q));
4469
+ }
4093
4470
  const { data } = yield this.session.send(
4094
4471
  "Page.captureScreenshot",
4095
4472
  params
@@ -4925,14 +5302,529 @@ var init_lifecycleWatcher = __esm({
4925
5302
  }
4926
5303
  });
4927
5304
 
5305
+ // lib/v3/understudy/navigationResponseTracker.ts
5306
+ var NavigationResponseTracker;
5307
+ var init_navigationResponseTracker = __esm({
5308
+ "lib/v3/understudy/navigationResponseTracker.ts"() {
5309
+ init_response();
5310
+ NavigationResponseTracker = class {
5311
+ /**
5312
+ * Create a tracker bound to a specific navigation command. The tracker begins
5313
+ * listening for network events immediately so it should be constructed before
5314
+ * the navigation request is dispatched.
5315
+ */
5316
+ constructor(params) {
5317
+ this.selectedRequestId = null;
5318
+ this.selectedResponse = null;
5319
+ this.acceptNextWithoutLoader = false;
5320
+ this.responseResolved = false;
5321
+ this.pendingResponsesByLoader = /* @__PURE__ */ new Map();
5322
+ this.pendingExtraInfo = /* @__PURE__ */ new Map();
5323
+ this.listeners = [];
5324
+ this.page = params.page;
5325
+ this.session = params.session;
5326
+ this.navigationCommandId = params.navigationCommandId;
5327
+ this.responsePromise = new Promise((resolve3) => {
5328
+ this.resolveResponse = (value) => {
5329
+ if (this.responseResolved) return;
5330
+ this.responseResolved = true;
5331
+ resolve3(value);
5332
+ };
5333
+ });
5334
+ this.installListeners();
5335
+ }
5336
+ /** Stop listening for CDP events and release any pending bookkeeping. */
5337
+ dispose() {
5338
+ for (const { event, handler } of this.listeners) {
5339
+ this.session.off(event, handler);
5340
+ }
5341
+ this.listeners.length = 0;
5342
+ this.pendingResponsesByLoader.clear();
5343
+ this.pendingExtraInfo.clear();
5344
+ }
5345
+ /**
5346
+ * Hint the tracker with the loader id returned by `Page.navigate`. Chrome only
5347
+ * emits this once the browser begins navigating, so we store early responses
5348
+ * and match them once the loader id is known.
5349
+ */
5350
+ setExpectedLoaderId(loaderId) {
5351
+ if (!loaderId) return;
5352
+ this.expectedLoaderId = loaderId;
5353
+ const pending = this.pendingResponsesByLoader.get(loaderId);
5354
+ if (pending) {
5355
+ this.pendingResponsesByLoader.delete(loaderId);
5356
+ this.selectResponse(pending);
5357
+ }
5358
+ }
5359
+ /**
5360
+ * Some navigation APIs (reload/history traversal) do not provide a loader id
5361
+ * up front. This flag instructs the tracker to accept the next qualifying
5362
+ * document response even if no loader id has been announced yet.
5363
+ */
5364
+ expectNavigationWithoutKnownLoader() {
5365
+ this.acceptNextWithoutLoader = true;
5366
+ }
5367
+ /**
5368
+ * Returns a promise that resolves with the matched response (or `null` when
5369
+ * no document response was observed).
5370
+ */
5371
+ navigationCompleted() {
5372
+ return __async(this, null, function* () {
5373
+ if (!this.responseResolved) {
5374
+ queueMicrotask(() => {
5375
+ if (!this.responseResolved) this.resolveResponse(null);
5376
+ });
5377
+ }
5378
+ return this.responsePromise;
5379
+ });
5380
+ }
5381
+ /** Expose the raw response promise (mainly for tests). */
5382
+ response() {
5383
+ return __async(this, null, function* () {
5384
+ return this.responsePromise;
5385
+ });
5386
+ }
5387
+ /** Register all CDP listeners relevant to navigation tracking. */
5388
+ installListeners() {
5389
+ this.addListener("Network.responseReceived", (event) => {
5390
+ this.onResponseReceived(event);
5391
+ });
5392
+ this.addListener("Network.responseReceivedExtraInfo", (event) => {
5393
+ this.onResponseReceivedExtraInfo(
5394
+ event
5395
+ );
5396
+ });
5397
+ this.addListener("Network.loadingFinished", (event) => {
5398
+ this.onLoadingFinished(event);
5399
+ });
5400
+ this.addListener("Network.loadingFailed", (event) => {
5401
+ this.onLoadingFailed(event);
5402
+ });
5403
+ }
5404
+ /** Attach a CDP listener and track it for later disposal. */
5405
+ addListener(event, handler) {
5406
+ this.session.on(event, handler);
5407
+ this.listeners.push({ event, handler });
5408
+ }
5409
+ /** Handle the initial response payload for document navigations. */
5410
+ onResponseReceived(event) {
5411
+ var _a;
5412
+ if (!this.page.isCurrentNavigationCommand(this.navigationCommandId)) return;
5413
+ if (!event || !event.response) return;
5414
+ if (event.type !== "Document") return;
5415
+ if (event.frameId !== this.page.mainFrameId()) return;
5416
+ const loaderId = (_a = event.loaderId) != null ? _a : "";
5417
+ if (this.acceptNextWithoutLoader) {
5418
+ this.acceptNextWithoutLoader = false;
5419
+ this.selectResponse(event);
5420
+ return;
5421
+ }
5422
+ if (this.expectedLoaderId) {
5423
+ if (loaderId && loaderId !== this.expectedLoaderId) {
5424
+ this.pendingResponsesByLoader.set(loaderId, event);
5425
+ return;
5426
+ }
5427
+ this.selectResponse(event);
5428
+ return;
5429
+ }
5430
+ if (loaderId) {
5431
+ this.pendingResponsesByLoader.set(loaderId, event);
5432
+ return;
5433
+ }
5434
+ this.selectResponse(event);
5435
+ }
5436
+ /** Merge auxiliary header information once Chrome exposes it. */
5437
+ onResponseReceivedExtraInfo(event) {
5438
+ var _a;
5439
+ if (!event || !event.requestId) return;
5440
+ if (this.selectedRequestId && event.requestId === this.selectedRequestId) {
5441
+ (_a = this.selectedResponse) == null ? void 0 : _a.applyExtraInfo(event);
5442
+ return;
5443
+ }
5444
+ this.pendingExtraInfo.set(event.requestId, event);
5445
+ }
5446
+ /** Resolve the response's finished promise when the request completes. */
5447
+ onLoadingFinished(event) {
5448
+ var _a;
5449
+ if (!event || !event.requestId) return;
5450
+ if (event.requestId !== this.selectedRequestId) return;
5451
+ (_a = this.selectedResponse) == null ? void 0 : _a.markFinished(null);
5452
+ }
5453
+ /** Resolve the response's finished promise with an error on failure. */
5454
+ onLoadingFailed(event) {
5455
+ var _a;
5456
+ if (!event || !event.requestId) return;
5457
+ if (event.requestId !== this.selectedRequestId) return;
5458
+ const errorText = event.errorText || "Navigation request failed";
5459
+ (_a = this.selectedResponse) == null ? void 0 : _a.markFinished(new Error(errorText));
5460
+ }
5461
+ /**
5462
+ * Create the `Response` wrapper for the chosen document response and
5463
+ * resolve awaiting consumers. Subsequent events flesh out the header/body
5464
+ * helpers and mark the request as finished.
5465
+ */
5466
+ selectResponse(event) {
5467
+ var _a, _b, _c, _d, _e, _f;
5468
+ if (event.loaderId) {
5469
+ this.pendingResponsesByLoader.delete(event.loaderId);
5470
+ }
5471
+ if (this.responseResolved) return;
5472
+ if (this.selectedResponse) return;
5473
+ const protocol = (_c = (_b = (_a = event.response) == null ? void 0 : _a.protocol) == null ? void 0 : _b.toLowerCase()) != null ? _c : "";
5474
+ const url = (_e = (_d = event.response) == null ? void 0 : _d.url) != null ? _e : "";
5475
+ const isDataUrl = protocol === "data" || url.startsWith("data:");
5476
+ const isAboutUrl = protocol === "about" || url.startsWith("about:");
5477
+ if (isDataUrl || isAboutUrl) {
5478
+ this.pendingExtraInfo.delete(event.requestId);
5479
+ this.selectedRequestId = null;
5480
+ this.selectedResponse = null;
5481
+ this.resolveResponse(null);
5482
+ return;
5483
+ }
5484
+ const response = new Response({
5485
+ page: this.page,
5486
+ session: this.session,
5487
+ requestId: event.requestId,
5488
+ frameId: event.frameId,
5489
+ loaderId: event.loaderId,
5490
+ response: event.response,
5491
+ fromServiceWorker: Boolean((_f = event.response) == null ? void 0 : _f.fromServiceWorker)
5492
+ });
5493
+ this.selectedRequestId = event.requestId;
5494
+ this.selectedResponse = response;
5495
+ const extraInfo = this.pendingExtraInfo.get(event.requestId);
5496
+ if (extraInfo) {
5497
+ response.applyExtraInfo(extraInfo);
5498
+ this.pendingExtraInfo.delete(event.requestId);
5499
+ }
5500
+ this.resolveResponse(response);
5501
+ }
5502
+ };
5503
+ }
5504
+ });
5505
+
5506
+ // lib/v3/understudy/screenshotUtils.ts
5507
+ function collectFramesForScreenshot(page) {
5508
+ const seen = /* @__PURE__ */ new Map();
5509
+ const main = page.mainFrame();
5510
+ seen.set(main.frameId, main);
5511
+ for (const frame of page.frames()) {
5512
+ seen.set(frame.frameId, frame);
5513
+ }
5514
+ return Array.from(seen.values());
5515
+ }
5516
+ function normalizeScreenshotClip(clip) {
5517
+ const x = Number(clip.x);
5518
+ const y = Number(clip.y);
5519
+ const width = Number(clip.width);
5520
+ const height = Number(clip.height);
5521
+ for (const [key, value] of Object.entries({ x, y, width, height })) {
5522
+ if (!Number.isFinite(value)) {
5523
+ throw new Error(`screenshot: clip.${key} must be a finite number`);
5524
+ }
5525
+ }
5526
+ if (width <= 0 || height <= 0) {
5527
+ throw new Error("screenshot: clip width/height must be positive");
5528
+ }
5529
+ return { x, y, width, height };
5530
+ }
5531
+ function computeScreenshotScale(page, mode) {
5532
+ return __async(this, null, function* () {
5533
+ if (mode !== "css") return void 0;
5534
+ try {
5535
+ const frame = page.mainFrame();
5536
+ const dpr = yield frame.evaluate(() => {
5537
+ const ratio = Number(window.devicePixelRatio || 1);
5538
+ return Number.isFinite(ratio) && ratio > 0 ? ratio : 1;
5539
+ }).catch(() => 1);
5540
+ const safeRatio = Number.isFinite(dpr) && dpr > 0 ? dpr : 1;
5541
+ return Math.min(2, Math.max(0.1, 1 / safeRatio));
5542
+ } catch (e) {
5543
+ return 1;
5544
+ }
5545
+ });
5546
+ }
5547
+ function setTransparentBackground(session) {
5548
+ return __async(this, null, function* () {
5549
+ yield session.send("Emulation.setDefaultBackgroundColorOverride", {
5550
+ color: { r: 0, g: 0, b: 0, a: 0 }
5551
+ }).catch(() => {
5552
+ });
5553
+ return () => __async(null, null, function* () {
5554
+ yield session.send("Emulation.setDefaultBackgroundColorOverride", {}).catch(() => {
5555
+ });
5556
+ });
5557
+ });
5558
+ }
5559
+ function applyStyleToFrames(frames, css, label) {
5560
+ return __async(this, null, function* () {
5561
+ const trimmed = css.trim();
5562
+ if (!trimmed) return () => __async(null, null, function* () {
5563
+ });
5564
+ const token = `__v3_style_${label}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
5565
+ yield Promise.all(
5566
+ frames.map(
5567
+ (frame) => frame.evaluate(
5568
+ ({ css: css2, token: token2 }) => {
5569
+ try {
5570
+ const doc = document;
5571
+ if (!doc) return;
5572
+ const style = doc.createElement("style");
5573
+ style.setAttribute("data-stagehand-style", token2);
5574
+ style.textContent = css2;
5575
+ const parent = doc.head || doc.documentElement || doc.body;
5576
+ parent == null ? void 0 : parent.appendChild(style);
5577
+ } catch (e) {
5578
+ }
5579
+ },
5580
+ { css: trimmed, token }
5581
+ ).catch(() => {
5582
+ })
5583
+ )
5584
+ );
5585
+ return () => __async(null, null, function* () {
5586
+ yield Promise.all(
5587
+ frames.map(
5588
+ (frame) => frame.evaluate((token2) => {
5589
+ try {
5590
+ const doc = document;
5591
+ if (!doc) return;
5592
+ const nodes = doc.querySelectorAll(
5593
+ `[data-stagehand-style="${token2}"]`
5594
+ );
5595
+ nodes.forEach((node) => node.remove());
5596
+ } catch (e) {
5597
+ }
5598
+ }, token).catch(() => {
5599
+ })
5600
+ )
5601
+ );
5602
+ });
5603
+ });
5604
+ }
5605
+ function disableAnimations(frames) {
5606
+ return __async(this, null, function* () {
5607
+ const css = `
5608
+ *,
5609
+ *::before,
5610
+ *::after {
5611
+ animation-delay: 0s !important;
5612
+ animation-duration: 0s !important;
5613
+ animation-iteration-count: 1 !important;
5614
+ animation-play-state: paused !important;
5615
+ transition-property: none !important;
5616
+ transition-duration: 0s !important;
5617
+ transition-delay: 0s !important;
5618
+ }`;
5619
+ const cleanup = yield applyStyleToFrames(frames, css, "animations");
5620
+ yield Promise.all(
5621
+ frames.map(
5622
+ (frame) => frame.evaluate(() => {
5623
+ var _a, _b, _c, _d, _e;
5624
+ try {
5625
+ const animations = typeof document.getAnimations === "function" ? document.getAnimations() : [];
5626
+ for (const animation of animations) {
5627
+ try {
5628
+ const details = (_b = (_a = animation.effect) == null ? void 0 : _a.getComputedTiming) == null ? void 0 : _b.call(_a);
5629
+ if (details && details.iterations !== Infinity) {
5630
+ (_c = animation.finish) == null ? void 0 : _c.call(animation);
5631
+ } else {
5632
+ (_d = animation.cancel) == null ? void 0 : _d.call(animation);
5633
+ }
5634
+ } catch (e) {
5635
+ (_e = animation.cancel) == null ? void 0 : _e.call(animation);
5636
+ }
5637
+ }
5638
+ } catch (e) {
5639
+ }
5640
+ }).catch(() => {
5641
+ })
5642
+ )
5643
+ );
5644
+ return cleanup;
5645
+ });
5646
+ }
5647
+ function hideCaret(frames) {
5648
+ return __async(this, null, function* () {
5649
+ const css = `
5650
+ input,
5651
+ textarea,
5652
+ [contenteditable],
5653
+ [contenteditable=""],
5654
+ [contenteditable="true"],
5655
+ [contenteditable="plaintext-only"],
5656
+ *:focus {
5657
+ caret-color: transparent !important;
5658
+ }`;
5659
+ return applyStyleToFrames(frames, css, "caret");
5660
+ });
5661
+ }
5662
+ function applyMaskOverlays(locators, color) {
5663
+ return __async(this, null, function* () {
5664
+ var _a;
5665
+ const rectsByFrame = /* @__PURE__ */ new Map();
5666
+ for (const locator of locators) {
5667
+ try {
5668
+ const info = yield resolveMaskRect(locator);
5669
+ if (!info) continue;
5670
+ const list = (_a = rectsByFrame.get(info.frame)) != null ? _a : [];
5671
+ list.push(info.rect);
5672
+ rectsByFrame.set(info.frame, list);
5673
+ } catch (e) {
5674
+ }
5675
+ }
5676
+ if (rectsByFrame.size === 0) {
5677
+ return () => __async(null, null, function* () {
5678
+ });
5679
+ }
5680
+ const token = `__v3_mask_${Date.now()}_${Math.random().toString(36).slice(2)}`;
5681
+ yield Promise.all(
5682
+ Array.from(rectsByFrame.entries()).map(
5683
+ ([frame, rects]) => frame.evaluate(
5684
+ ({ rects: rects2, color: color2, token: token2 }) => {
5685
+ try {
5686
+ const doc = document;
5687
+ if (!doc) return;
5688
+ const root = doc.documentElement || doc.body;
5689
+ if (!root) return;
5690
+ for (const rect of rects2) {
5691
+ const el = doc.createElement("div");
5692
+ el.setAttribute("data-stagehand-mask", token2);
5693
+ el.style.position = "absolute";
5694
+ el.style.left = `${rect.x}px`;
5695
+ el.style.top = `${rect.y}px`;
5696
+ el.style.width = `${rect.width}px`;
5697
+ el.style.height = `${rect.height}px`;
5698
+ el.style.backgroundColor = color2;
5699
+ el.style.pointerEvents = "none";
5700
+ el.style.zIndex = "2147483647";
5701
+ el.style.opacity = "1";
5702
+ el.style.mixBlendMode = "normal";
5703
+ root.appendChild(el);
5704
+ }
5705
+ } catch (e) {
5706
+ }
5707
+ },
5708
+ { rects, color, token }
5709
+ ).catch(() => {
5710
+ })
5711
+ )
5712
+ );
5713
+ return () => __async(null, null, function* () {
5714
+ yield Promise.all(
5715
+ Array.from(rectsByFrame.keys()).map(
5716
+ (frame) => frame.evaluate((token2) => {
5717
+ try {
5718
+ const doc = document;
5719
+ if (!doc) return;
5720
+ const nodes = doc.querySelectorAll(
5721
+ `[data-stagehand-mask="${token2}"]`
5722
+ );
5723
+ nodes.forEach((node) => node.remove());
5724
+ } catch (e) {
5725
+ }
5726
+ }, token).catch(() => {
5727
+ })
5728
+ )
5729
+ );
5730
+ });
5731
+ });
5732
+ }
5733
+ function resolveMaskRect(locator) {
5734
+ return __async(this, null, function* () {
5735
+ const frame = locator.getFrame();
5736
+ const session = frame.session;
5737
+ let objectId = null;
5738
+ try {
5739
+ const resolved = yield locator.resolveNode();
5740
+ objectId = resolved.objectId;
5741
+ const result = yield session.send(
5742
+ "Runtime.callFunctionOn",
5743
+ {
5744
+ objectId,
5745
+ functionDeclaration: `function() {
5746
+ if (!this || typeof this.getBoundingClientRect !== 'function') return null;
5747
+ const rect = this.getBoundingClientRect();
5748
+ if (!rect) return null;
5749
+ const style = window.getComputedStyle(this);
5750
+ if (!style) return null;
5751
+ if (style.visibility === 'hidden' || style.display === 'none') return null;
5752
+ if (rect.width <= 0 || rect.height <= 0) return null;
5753
+ return {
5754
+ x: rect.left + window.scrollX,
5755
+ y: rect.top + window.scrollY,
5756
+ width: rect.width,
5757
+ height: rect.height,
5758
+ };
5759
+ }`,
5760
+ returnByValue: true
5761
+ }
5762
+ );
5763
+ if (result.exceptionDetails) {
5764
+ return null;
5765
+ }
5766
+ const rect = result.result.value;
5767
+ if (!rect) return null;
5768
+ const { x, y, width, height } = rect;
5769
+ if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
5770
+ return null;
5771
+ }
5772
+ return { frame, rect: { x, y, width, height } };
5773
+ } catch (e) {
5774
+ return null;
5775
+ } finally {
5776
+ if (objectId) {
5777
+ yield session.send("Runtime.releaseObject", { objectId }).catch(() => {
5778
+ });
5779
+ }
5780
+ }
5781
+ });
5782
+ }
5783
+ function runScreenshotCleanups(cleanups) {
5784
+ return __async(this, null, function* () {
5785
+ for (let i = cleanups.length - 1; i >= 0; i -= 1) {
5786
+ const fn = cleanups[i];
5787
+ if (!fn) continue;
5788
+ try {
5789
+ const result = fn();
5790
+ if (result && typeof result.then === "function") {
5791
+ yield result;
5792
+ }
5793
+ } catch (e) {
5794
+ }
5795
+ }
5796
+ });
5797
+ }
5798
+ function withScreenshotTimeout(timeoutMs, task) {
5799
+ return __async(this, null, function* () {
5800
+ if (!timeoutMs || timeoutMs <= 0) return task();
5801
+ let timer = null;
5802
+ const timeoutPromise = new Promise((_, reject) => {
5803
+ timer = setTimeout(() => {
5804
+ reject(new Error(`screenshot: timeout of ${timeoutMs}ms exceeded`));
5805
+ }, timeoutMs);
5806
+ });
5807
+ try {
5808
+ return yield Promise.race([task(), timeoutPromise]);
5809
+ } finally {
5810
+ if (timer) clearTimeout(timer);
5811
+ }
5812
+ });
5813
+ }
5814
+ var init_screenshotUtils = __esm({
5815
+ "lib/v3/understudy/screenshotUtils.ts"() {
5816
+ }
5817
+ });
5818
+
4928
5819
  // lib/v3/understudy/page.ts
4929
5820
  var page_exports = {};
4930
5821
  __export(page_exports, {
4931
5822
  Page: () => Page
4932
5823
  });
4933
- var LIFECYCLE_NAME, Page;
5824
+ var import_fs5, LIFECYCLE_NAME, Page;
4934
5825
  var init_page = __esm({
4935
5826
  "lib/v3/understudy/page.ts"() {
5827
+ import_fs5 = require("fs");
4936
5828
  init_logger();
4937
5829
  init_frame();
4938
5830
  init_frameLocator();
@@ -4941,6 +5833,9 @@ var init_page = __esm({
4941
5833
  init_frameRegistry();
4942
5834
  init_networkManager();
4943
5835
  init_lifecycleWatcher();
5836
+ init_navigationResponseTracker();
5837
+ init_consoleMessage();
5838
+ init_screenshotUtils();
4944
5839
  LIFECYCLE_NAME = {
4945
5840
  load: "load",
4946
5841
  domcontentloaded: "DOMContentLoaded",
@@ -4964,6 +5859,8 @@ var init_page = __esm({
4964
5859
  this.latestNavigationCommandId = 0;
4965
5860
  /** Optional API client for routing page operations to the API */
4966
5861
  this.apiClient = null;
5862
+ this.consoleListeners = /* @__PURE__ */ new Set();
5863
+ this.consoleHandlers = /* @__PURE__ */ new Map();
4967
5864
  // --- Optional visual cursor overlay management ---
4968
5865
  this.cursorEnabled = false;
4969
5866
  // Track pressed modifier keys
@@ -5165,6 +6062,9 @@ var init_page = __esm({
5165
6062
  var _a;
5166
6063
  if (childSession.id) this.sessions.set(childSession.id, childSession);
5167
6064
  this.networkManager.trackSession(childSession);
6065
+ if (this.consoleListeners.size > 0) {
6066
+ this.installConsoleTap(childSession);
6067
+ }
5168
6068
  this.registry.adoptChildSession(
5169
6069
  (_a = childSession.id) != null ? _a : "child",
5170
6070
  childMainFrameId
@@ -5218,6 +6118,7 @@ var init_page = __esm({
5218
6118
  this.registry.onFrameDetached(fid, "remove");
5219
6119
  this.frameCache.delete(fid);
5220
6120
  }
6121
+ this.teardownConsoleTap(sessionId);
5221
6122
  this.sessions.delete(sessionId);
5222
6123
  this.networkManager.untrackSession(sessionId);
5223
6124
  }
@@ -5248,10 +6149,65 @@ var init_page = __esm({
5248
6149
  unregisterSessionForNetwork(sessionId) {
5249
6150
  this.networkManager.untrackSession(sessionId);
5250
6151
  }
6152
+ on(event, listener) {
6153
+ if (event !== "console") {
6154
+ throw new Error(`Unsupported event: ${event}`);
6155
+ }
6156
+ const firstListener = this.consoleListeners.size === 0;
6157
+ this.consoleListeners.add(listener);
6158
+ if (firstListener) {
6159
+ this.ensureConsoleTaps();
6160
+ }
6161
+ return this;
6162
+ }
6163
+ once(event, listener) {
6164
+ if (event !== "console") {
6165
+ throw new Error(`Unsupported event: ${event}`);
6166
+ }
6167
+ const wrapper = (message) => {
6168
+ this.off("console", wrapper);
6169
+ listener(message);
6170
+ };
6171
+ return this.on("console", wrapper);
6172
+ }
6173
+ off(event, listener) {
6174
+ if (event !== "console") {
6175
+ throw new Error(`Unsupported event: ${event}`);
6176
+ }
6177
+ this.consoleListeners.delete(listener);
6178
+ if (this.consoleListeners.size === 0) {
6179
+ this.removeAllConsoleTaps();
6180
+ }
6181
+ return this;
6182
+ }
5251
6183
  // ---------------- MAIN APIs ----------------
5252
6184
  targetId() {
5253
6185
  return this._targetId;
5254
6186
  }
6187
+ /**
6188
+ * Send a CDP command through the main session.
6189
+ * Allows external consumers to execute arbitrary Chrome DevTools Protocol commands.
6190
+ *
6191
+ * @param method - The CDP method name (e.g., "Page.enable", "Runtime.evaluate")
6192
+ * @param params - Optional parameters for the CDP command
6193
+ * @returns Promise resolving to the typed CDP response
6194
+ *
6195
+ * @example
6196
+ * // Enable the Runtime domain
6197
+ * await page.sendCDP("Runtime.enable");
6198
+ *
6199
+ * @example
6200
+ * // Evaluate JavaScript with typed response
6201
+ * const result = await page.sendCDP<Protocol.Runtime.EvaluateResponse>(
6202
+ * "Runtime.evaluate",
6203
+ * { expression: "1 + 1" }
6204
+ * );
6205
+ */
6206
+ sendCDP(method, params) {
6207
+ return __async(this, null, function* () {
6208
+ return this.mainSession.send(method, params);
6209
+ });
6210
+ }
5255
6211
  /** Seed the cached URL before navigation events converge. */
5256
6212
  seedCurrentUrl(url) {
5257
6213
  if (!url) return;
@@ -5290,6 +6246,8 @@ var init_page = __esm({
5290
6246
  yield new Promise((r) => setTimeout(r, 25));
5291
6247
  }
5292
6248
  this.networkManager.dispose();
6249
+ this.removeAllConsoleTaps();
6250
+ this.consoleListeners.clear();
5293
6251
  });
5294
6252
  }
5295
6253
  getFullFrameTree() {
@@ -5312,6 +6270,71 @@ var init_page = __esm({
5312
6270
  listAllFrameIds() {
5313
6271
  return this.registry.listAllFrames();
5314
6272
  }
6273
+ ensureConsoleTaps() {
6274
+ if (this.consoleListeners.size === 0) return;
6275
+ this.installConsoleTap(this.mainSession);
6276
+ for (const session of this.sessions.values()) {
6277
+ this.installConsoleTap(session);
6278
+ }
6279
+ }
6280
+ installConsoleTap(session) {
6281
+ const key = this.sessionKey(session);
6282
+ if (this.consoleHandlers.has(key)) return;
6283
+ void session.send("Runtime.enable").catch(() => {
6284
+ });
6285
+ const handler = (evt) => {
6286
+ this.emitConsole(evt);
6287
+ };
6288
+ session.on(
6289
+ "Runtime.consoleAPICalled",
6290
+ handler
6291
+ );
6292
+ this.consoleHandlers.set(key, handler);
6293
+ }
6294
+ sessionKey(session) {
6295
+ var _a;
6296
+ return (_a = session.id) != null ? _a : "__root__";
6297
+ }
6298
+ resolveSessionByKey(key) {
6299
+ if (this.mainSession.id) {
6300
+ if (this.mainSession.id === key) return this.mainSession;
6301
+ } else if (key === "__root__") {
6302
+ return this.mainSession;
6303
+ }
6304
+ return this.sessions.get(key);
6305
+ }
6306
+ teardownConsoleTap(key) {
6307
+ const handler = this.consoleHandlers.get(key);
6308
+ if (!handler) return;
6309
+ const session = this.resolveSessionByKey(key);
6310
+ session == null ? void 0 : session.off("Runtime.consoleAPICalled", handler);
6311
+ this.consoleHandlers.delete(key);
6312
+ }
6313
+ removeAllConsoleTaps() {
6314
+ for (const key of [...this.consoleHandlers.keys()]) {
6315
+ this.teardownConsoleTap(key);
6316
+ }
6317
+ }
6318
+ emitConsole(evt) {
6319
+ if (this.consoleListeners.size === 0) return;
6320
+ const message = new ConsoleMessage(evt, this);
6321
+ const listeners = [...this.consoleListeners];
6322
+ for (const listener of listeners) {
6323
+ try {
6324
+ listener(message);
6325
+ } catch (error) {
6326
+ v3Logger({
6327
+ category: "page",
6328
+ message: "Console listener threw",
6329
+ level: 2,
6330
+ auxiliary: {
6331
+ error: { value: String(error), type: "string" },
6332
+ type: { value: evt.type, type: "string" }
6333
+ }
6334
+ });
6335
+ }
6336
+ }
6337
+ }
5315
6338
  // -------- Convenience APIs delegated to the current main frame --------
5316
6339
  /**
5317
6340
  * Navigate the page; optionally wait for a lifecycle state.
@@ -5323,6 +6346,11 @@ var init_page = __esm({
5323
6346
  const waitUntil = (_a = options == null ? void 0 : options.waitUntil) != null ? _a : "domcontentloaded";
5324
6347
  const timeout = (_b = options == null ? void 0 : options.timeoutMs) != null ? _b : 15e3;
5325
6348
  const navigationCommandId = this.beginNavigationCommand();
6349
+ const tracker = new NavigationResponseTracker({
6350
+ page: this,
6351
+ session: this.mainSession,
6352
+ navigationCommandId
6353
+ });
5326
6354
  const watcher = new LifecycleWatcher({
5327
6355
  page: this,
5328
6356
  mainSession: this.mainSession,
@@ -5339,17 +6367,22 @@ var init_page = __esm({
5339
6367
  this.mainFrameId()
5340
6368
  );
5341
6369
  this._currentUrl = url;
5342
- return;
6370
+ return null;
5343
6371
  }
5344
6372
  const response = yield this.mainSession.send(
5345
6373
  "Page.navigate",
5346
6374
  { url }
5347
6375
  );
5348
6376
  this._currentUrl = url;
5349
- if (response == null ? void 0 : response.loaderId) watcher.setExpectedLoaderId(response.loaderId);
6377
+ if (response == null ? void 0 : response.loaderId) {
6378
+ watcher.setExpectedLoaderId(response.loaderId);
6379
+ tracker.setExpectedLoaderId(response.loaderId);
6380
+ }
5350
6381
  yield watcher.wait();
6382
+ return yield tracker.navigationCompleted();
5351
6383
  } finally {
5352
6384
  watcher.dispose();
6385
+ tracker.dispose();
5353
6386
  }
5354
6387
  });
5355
6388
  }
@@ -5362,6 +6395,12 @@ var init_page = __esm({
5362
6395
  const waitUntil = options == null ? void 0 : options.waitUntil;
5363
6396
  const timeout = (_a = options == null ? void 0 : options.timeoutMs) != null ? _a : 15e3;
5364
6397
  const navigationCommandId = this.beginNavigationCommand();
6398
+ const tracker = new NavigationResponseTracker({
6399
+ page: this,
6400
+ session: this.mainSession,
6401
+ navigationCommandId
6402
+ });
6403
+ tracker.expectNavigationWithoutKnownLoader();
5365
6404
  const watcher = waitUntil ? new LifecycleWatcher({
5366
6405
  page: this,
5367
6406
  mainSession: this.mainSession,
@@ -5377,8 +6416,10 @@ var init_page = __esm({
5377
6416
  if (watcher) {
5378
6417
  yield watcher.wait();
5379
6418
  }
6419
+ return yield tracker.navigationCompleted();
5380
6420
  } finally {
5381
6421
  watcher == null ? void 0 : watcher.dispose();
6422
+ tracker.dispose();
5382
6423
  }
5383
6424
  });
5384
6425
  }
@@ -5392,10 +6433,16 @@ var init_page = __esm({
5392
6433
  "Page.getNavigationHistory"
5393
6434
  );
5394
6435
  const prev = entries[currentIndex - 1];
5395
- if (!prev) return;
6436
+ if (!prev) return null;
5396
6437
  const waitUntil = options == null ? void 0 : options.waitUntil;
5397
6438
  const timeout = (_a = options == null ? void 0 : options.timeoutMs) != null ? _a : 15e3;
5398
6439
  const navigationCommandId = this.beginNavigationCommand();
6440
+ const tracker = new NavigationResponseTracker({
6441
+ page: this,
6442
+ session: this.mainSession,
6443
+ navigationCommandId
6444
+ });
6445
+ tracker.expectNavigationWithoutKnownLoader();
5399
6446
  const watcher = waitUntil ? new LifecycleWatcher({
5400
6447
  page: this,
5401
6448
  mainSession: this.mainSession,
@@ -5412,8 +6459,10 @@ var init_page = __esm({
5412
6459
  if (watcher) {
5413
6460
  yield watcher.wait();
5414
6461
  }
6462
+ return yield tracker.navigationCompleted();
5415
6463
  } finally {
5416
6464
  watcher == null ? void 0 : watcher.dispose();
6465
+ tracker.dispose();
5417
6466
  }
5418
6467
  });
5419
6468
  }
@@ -5427,10 +6476,16 @@ var init_page = __esm({
5427
6476
  "Page.getNavigationHistory"
5428
6477
  );
5429
6478
  const next = entries[currentIndex + 1];
5430
- if (!next) return;
6479
+ if (!next) return null;
5431
6480
  const waitUntil = options == null ? void 0 : options.waitUntil;
5432
6481
  const timeout = (_a = options == null ? void 0 : options.timeoutMs) != null ? _a : 15e3;
5433
6482
  const navigationCommandId = this.beginNavigationCommand();
6483
+ const tracker = new NavigationResponseTracker({
6484
+ page: this,
6485
+ session: this.mainSession,
6486
+ navigationCommandId
6487
+ });
6488
+ tracker.expectNavigationWithoutKnownLoader();
5434
6489
  const watcher = waitUntil ? new LifecycleWatcher({
5435
6490
  page: this,
5436
6491
  mainSession: this.mainSession,
@@ -5447,8 +6502,10 @@ var init_page = __esm({
5447
6502
  if (watcher) {
5448
6503
  yield watcher.wait();
5449
6504
  }
6505
+ return yield tracker.navigationCompleted();
5450
6506
  } finally {
5451
6507
  watcher == null ? void 0 : watcher.dispose();
6508
+ tracker.dispose();
5452
6509
  }
5453
6510
  });
5454
6511
  }
@@ -5500,11 +6557,99 @@ var init_page = __esm({
5500
6557
  });
5501
6558
  }
5502
6559
  /**
5503
- * Capture a screenshot (delegated to the current main frame).
6560
+ * Capture a screenshot with Playwright-style options.
6561
+ *
6562
+ * @param options Optional screenshot configuration.
6563
+ * @param options.animations Control CSS/Web animations during capture. Use
6564
+ * "disabled" to fast-forward finite animations and pause infinite ones.
6565
+ * @param options.caret Either hide the text caret (default) or leave it
6566
+ * visible via "initial".
6567
+ * @param options.clip Restrict capture to a specific rectangle (in CSS
6568
+ * pixels). Cannot be combined with `fullPage`.
6569
+ * @param options.fullPage Capture the full scrollable page instead of the
6570
+ * current viewport.
6571
+ * @param options.mask Array of locators that should be covered with an
6572
+ * overlay while the screenshot is taken.
6573
+ * @param options.maskColor CSS color used for the mask overlay (default
6574
+ * `#FF00FF`).
6575
+ * @param options.omitBackground Make the default page background transparent
6576
+ * (PNG only).
6577
+ * @param options.path File path to write the screenshot to. The file extension
6578
+ * determines the image type when `type` is not explicitly provided.
6579
+ * @param options.quality JPEG quality (0–100). Only applies when
6580
+ * `type === "jpeg"`.
6581
+ * @param options.scale Render scale: use "css" for one pixel per CSS pixel,
6582
+ * otherwise the default "device" leverages the current device pixel ratio.
6583
+ * @param options.style Additional CSS text injected into every frame before
6584
+ * capture (removed afterwards).
6585
+ * @param options.timeout Maximum capture duration in milliseconds before a
6586
+ * timeout error is thrown.
6587
+ * @param options.type Image format (`"png"` by default).
5504
6588
  */
5505
6589
  screenshot(options) {
5506
6590
  return __async(this, null, function* () {
5507
- return this.mainFrameWrapper.screenshot(options);
6591
+ var _a, _b, _c, _d, _e;
6592
+ const opts = options != null ? options : {};
6593
+ const type = (_a = opts.type) != null ? _a : "png";
6594
+ if (type !== "png" && type !== "jpeg") {
6595
+ throw new Error(`screenshot: unsupported image type "${type}"`);
6596
+ }
6597
+ if (opts.fullPage && opts.clip) {
6598
+ throw new Error("screenshot: clip and fullPage cannot be used together");
6599
+ }
6600
+ if (type === "png" && typeof opts.quality === "number") {
6601
+ throw new Error(
6602
+ 'screenshot: quality option is only valid for type="jpeg"'
6603
+ );
6604
+ }
6605
+ const caretMode = (_b = opts.caret) != null ? _b : "hide";
6606
+ const animationsMode = (_c = opts.animations) != null ? _c : "allow";
6607
+ const scaleMode = (_d = opts.scale) != null ? _d : "device";
6608
+ const frames = collectFramesForScreenshot(this);
6609
+ const clip = opts.clip ? normalizeScreenshotClip(opts.clip) : void 0;
6610
+ const captureScale = yield computeScreenshotScale(this, scaleMode);
6611
+ const maskLocators = ((_e = opts.mask) != null ? _e : []).filter(
6612
+ (locator) => Boolean(locator)
6613
+ );
6614
+ const cleanupTasks = [];
6615
+ const exec = () => __async(this, null, function* () {
6616
+ var _a2;
6617
+ try {
6618
+ if (opts.omitBackground) {
6619
+ cleanupTasks.push(yield setTransparentBackground(this.mainSession));
6620
+ }
6621
+ if (animationsMode === "disabled") {
6622
+ cleanupTasks.push(yield disableAnimations(frames));
6623
+ }
6624
+ if (caretMode === "hide") {
6625
+ cleanupTasks.push(yield hideCaret(frames));
6626
+ }
6627
+ if (opts.style && opts.style.trim()) {
6628
+ cleanupTasks.push(
6629
+ yield applyStyleToFrames(frames, opts.style, "custom")
6630
+ );
6631
+ }
6632
+ if (maskLocators.length > 0) {
6633
+ cleanupTasks.push(
6634
+ yield applyMaskOverlays(maskLocators, (_a2 = opts.maskColor) != null ? _a2 : "#FF00FF")
6635
+ );
6636
+ }
6637
+ const buffer = yield this.mainFrameWrapper.screenshot({
6638
+ fullPage: opts.fullPage,
6639
+ clip,
6640
+ type,
6641
+ quality: type === "jpeg" ? opts.quality : void 0,
6642
+ scale: captureScale
6643
+ });
6644
+ if (opts.path) {
6645
+ yield import_fs5.promises.writeFile(opts.path, buffer);
6646
+ }
6647
+ return buffer;
6648
+ } finally {
6649
+ yield runScreenshotCleanups(cleanupTasks);
6650
+ }
6651
+ });
6652
+ return withScreenshotTimeout(opts.timeout, exec);
5508
6653
  });
5509
6654
  }
5510
6655
  /**
@@ -6222,12 +7367,14 @@ var init_page = __esm({
6222
7367
  // lib/v3/index.ts
6223
7368
  var v3_exports = {};
6224
7369
  __export(v3_exports, {
7370
+ AISdkClient: () => AISdkClient2,
6225
7371
  AVAILABLE_CUA_MODELS: () => AVAILABLE_CUA_MODELS,
6226
7372
  AgentProvider: () => AgentProvider,
6227
7373
  AgentScreenshotProviderError: () => AgentScreenshotProviderError,
6228
7374
  AnnotatedScreenshotText: () => AnnotatedScreenshotText,
6229
7375
  BrowserbaseSessionNotFoundError: () => BrowserbaseSessionNotFoundError,
6230
7376
  CaptchaTimeoutError: () => CaptchaTimeoutError,
7377
+ ConsoleMessage: () => ConsoleMessage,
6231
7378
  ContentFrameNotFoundError: () => ContentFrameNotFoundError,
6232
7379
  CreateChatCompletionResponseError: () => CreateChatCompletionResponseError,
6233
7380
  ExperimentalApiConflictError: () => ExperimentalApiConflictError,
@@ -6240,6 +7387,7 @@ __export(v3_exports, {
6240
7387
  MCPConnectionError: () => MCPConnectionError,
6241
7388
  MissingEnvironmentVariableError: () => MissingEnvironmentVariableError,
6242
7389
  MissingLLMConfigurationError: () => MissingLLMConfigurationError,
7390
+ Response: () => Response,
6243
7391
  Stagehand: () => V3,
6244
7392
  StagehandAPIError: () => StagehandAPIError,
6245
7393
  StagehandAPIUnauthorizedError: () => StagehandAPIUnauthorizedError,
@@ -6289,13 +7437,13 @@ module.exports = __toCommonJS(v3_exports);
6289
7437
 
6290
7438
  // lib/v3/v3.ts
6291
7439
  var import_dotenv = __toESM(require("dotenv"));
6292
- var import_fs5 = __toESM(require("fs"));
7440
+ var import_fs6 = __toESM(require("fs"));
6293
7441
  var import_os2 = __toESM(require("os"));
6294
7442
  var import_path5 = __toESM(require("path"));
6295
7443
  var import_process2 = __toESM(require("process"));
6296
7444
 
6297
7445
  // lib/version.ts
6298
- var STAGEHAND_VERSION = "3.0.0-test.1";
7446
+ var STAGEHAND_VERSION = "3.0.1";
6299
7447
 
6300
7448
  // lib/v3/types/public/sdkErrors.ts
6301
7449
  var StagehandError = class extends Error {
@@ -6520,7 +7668,7 @@ var StagehandShadowSegmentNotFoundError = class extends StagehandError {
6520
7668
 
6521
7669
  // lib/utils.ts
6522
7670
  var import_genai = require("@google/genai");
6523
- var import_zod = require("zod");
7671
+ var import_v3 = require("zod/v3");
6524
7672
  var ID_PATTERN = /^\d+-\d+$/;
6525
7673
  function validateZodSchema(schema, data) {
6526
7674
  const result = schema.safeParse(data);
@@ -6544,28 +7692,28 @@ function decorateGeminiSchema(geminiSchema, zodSchema2) {
6544
7692
  function toGeminiSchema(zodSchema2) {
6545
7693
  const zodType = getZodType(zodSchema2);
6546
7694
  switch (zodType) {
6547
- case "array": {
6548
- const arraySchema = zodSchema2;
6549
- const element = arraySchema._zod.def.element;
7695
+ case "ZodArray": {
6550
7696
  return decorateGeminiSchema(
6551
7697
  {
6552
7698
  type: import_genai.Type.ARRAY,
6553
- items: toGeminiSchema(element != null ? element : import_zod.z.any())
7699
+ items: toGeminiSchema(
7700
+ zodSchema2.element
7701
+ )
6554
7702
  },
6555
7703
  zodSchema2
6556
7704
  );
6557
7705
  }
6558
- case "object": {
7706
+ case "ZodObject": {
6559
7707
  const properties = {};
6560
7708
  const required = [];
6561
- const objectSchema = zodSchema2;
6562
- const shape = objectSchema._zod.def.shape;
6563
- Object.entries(shape).forEach(([key, value]) => {
6564
- properties[key] = toGeminiSchema(value);
6565
- if (getZodType(value) !== "optional") {
6566
- required.push(key);
7709
+ Object.entries(zodSchema2.shape).forEach(
7710
+ ([key, value]) => {
7711
+ properties[key] = toGeminiSchema(value);
7712
+ if (getZodType(value) !== "ZodOptional") {
7713
+ required.push(key);
7714
+ }
6567
7715
  }
6568
- });
7716
+ );
6569
7717
  return decorateGeminiSchema(
6570
7718
  {
6571
7719
  type: import_genai.Type.OBJECT,
@@ -6575,45 +7723,39 @@ function toGeminiSchema(zodSchema2) {
6575
7723
  zodSchema2
6576
7724
  );
6577
7725
  }
6578
- case "string":
6579
- case "url":
7726
+ case "ZodString":
6580
7727
  return decorateGeminiSchema(
6581
7728
  {
6582
7729
  type: import_genai.Type.STRING
6583
7730
  },
6584
7731
  zodSchema2
6585
7732
  );
6586
- case "number":
7733
+ case "ZodNumber":
6587
7734
  return decorateGeminiSchema(
6588
7735
  {
6589
7736
  type: import_genai.Type.NUMBER
6590
7737
  },
6591
7738
  zodSchema2
6592
7739
  );
6593
- case "boolean":
7740
+ case "ZodBoolean":
6594
7741
  return decorateGeminiSchema(
6595
7742
  {
6596
7743
  type: import_genai.Type.BOOLEAN
6597
7744
  },
6598
7745
  zodSchema2
6599
7746
  );
6600
- case "enum": {
6601
- const enumSchema = zodSchema2;
6602
- const values = Object.values(enumSchema._zod.def.entries);
7747
+ case "ZodEnum":
6603
7748
  return decorateGeminiSchema(
6604
7749
  {
6605
7750
  type: import_genai.Type.STRING,
6606
- enum: values
7751
+ enum: zodSchema2._def.values
6607
7752
  },
6608
7753
  zodSchema2
6609
7754
  );
6610
- }
6611
- case "default":
6612
- case "nullable":
6613
- case "optional": {
6614
- const wrapperSchema = zodSchema2;
6615
- const innerType = wrapperSchema._zod.def.innerType;
6616
- const innerSchema = toGeminiSchema(innerType);
7755
+ case "ZodDefault":
7756
+ case "ZodNullable":
7757
+ case "ZodOptional": {
7758
+ const innerSchema = toGeminiSchema(zodSchema2._def.innerType);
6617
7759
  return decorateGeminiSchema(
6618
7760
  __spreadProps(__spreadValues({}, innerSchema), {
6619
7761
  nullable: true
@@ -6621,23 +7763,14 @@ function toGeminiSchema(zodSchema2) {
6621
7763
  zodSchema2
6622
7764
  );
6623
7765
  }
6624
- case "literal": {
6625
- const literalSchema = zodSchema2;
6626
- const values = literalSchema._zod.def.values;
7766
+ case "ZodLiteral":
6627
7767
  return decorateGeminiSchema(
6628
7768
  {
6629
7769
  type: import_genai.Type.STRING,
6630
- enum: values
7770
+ enum: [zodSchema2._def.value]
6631
7771
  },
6632
7772
  zodSchema2
6633
7773
  );
6634
- }
6635
- case "pipe": {
6636
- const pipeSchema = zodSchema2;
6637
- const inSchema = pipeSchema._zod.def.in;
6638
- return toGeminiSchema(inSchema);
6639
- }
6640
- // Standalone transforms and any unknown types fall through to default
6641
7774
  default:
6642
7775
  return decorateGeminiSchema(
6643
7776
  {
@@ -6649,40 +7782,21 @@ function toGeminiSchema(zodSchema2) {
6649
7782
  }
6650
7783
  }
6651
7784
  function getZodType(schema) {
6652
- var _a, _b;
6653
- const schemaWithDef = schema;
6654
- if ((_b = (_a = schemaWithDef._zod) == null ? void 0 : _a.def) == null ? void 0 : _b.type) {
6655
- return schemaWithDef._zod.def.type;
6656
- }
6657
- throw new Error(
6658
- `Unable to determine Zod schema type. Schema: ${JSON.stringify(schema)}`
6659
- );
7785
+ return schema._def.typeName;
6660
7786
  }
6661
7787
  function transformSchema(schema, currentPath) {
6662
7788
  var _a, _b;
6663
- if (isKind(schema, "url")) {
6664
- const transformed = makeIdStringSchema(schema);
6665
- return [transformed, [{ segments: [] }]];
6666
- }
6667
- if (isKind(schema, "string")) {
6668
- const stringSchema = schema;
6669
- const checks = stringSchema._zod.def.checks;
6670
- const format = (_a = stringSchema._zod.bag) == null ? void 0 : _a.format;
6671
- const hasUrlCheck = ((_b = checks == null ? void 0 : checks.some((check) => {
6672
- var _a2, _b2;
6673
- return ((_b2 = (_a2 = check._zod) == null ? void 0 : _a2.def) == null ? void 0 : _b2.check) === "url";
6674
- })) != null ? _b : false) || format === "url";
7789
+ if (isKind(schema, import_v3.ZodFirstPartyTypeKind.ZodString)) {
7790
+ const hasUrlCheck = (_b = (_a = schema._def.checks) == null ? void 0 : _a.some(
7791
+ (check) => check.kind === "url"
7792
+ )) != null ? _b : false;
6675
7793
  if (hasUrlCheck) {
6676
7794
  return [makeIdStringSchema(schema), [{ segments: [] }]];
6677
7795
  }
6678
7796
  return [schema, []];
6679
7797
  }
6680
- if (isKind(schema, "object")) {
6681
- const objectSchema = schema;
6682
- const shape = objectSchema._zod.def.shape;
6683
- if (!shape) {
6684
- return [schema, []];
6685
- }
7798
+ if (isKind(schema, import_v3.ZodFirstPartyTypeKind.ZodObject)) {
7799
+ const shape = schema._def.shape();
6686
7800
  const newShape = {};
6687
7801
  const urlPaths = [];
6688
7802
  let changed = false;
@@ -6704,17 +7818,12 @@ function transformSchema(schema, currentPath) {
6704
7818
  }
6705
7819
  }
6706
7820
  if (changed) {
6707
- const newSchema = import_zod.z.object(newShape);
6708
- return [newSchema, urlPaths];
7821
+ return [import_v3.z.object(newShape), urlPaths];
6709
7822
  }
6710
7823
  return [schema, urlPaths];
6711
7824
  }
6712
- if (isKind(schema, "array")) {
6713
- const arraySchema = schema;
6714
- const itemType = arraySchema._zod.def.element;
6715
- if (!itemType) {
6716
- return [schema, []];
6717
- }
7825
+ if (isKind(schema, import_v3.ZodFirstPartyTypeKind.ZodArray)) {
7826
+ const itemType = schema._def.type;
6718
7827
  const [transformedItem, childPaths] = transformSchema(itemType, [
6719
7828
  ...currentPath,
6720
7829
  "*"
@@ -6724,17 +7833,12 @@ function transformSchema(schema, currentPath) {
6724
7833
  segments: ["*", ...cp.segments]
6725
7834
  }));
6726
7835
  if (changed) {
6727
- const newSchema = import_zod.z.array(transformedItem);
6728
- return [newSchema, arrayPaths];
7836
+ return [import_v3.z.array(transformedItem), arrayPaths];
6729
7837
  }
6730
7838
  return [schema, arrayPaths];
6731
7839
  }
6732
- if (isKind(schema, "union")) {
6733
- const unionSchema = schema;
6734
- const unionOptions = unionSchema._zod.def.options;
6735
- if (!unionOptions || unionOptions.length === 0) {
6736
- return [schema, []];
6737
- }
7840
+ if (isKind(schema, import_v3.ZodFirstPartyTypeKind.ZodUnion)) {
7841
+ const unionOptions = schema._def.options;
6738
7842
  const newOptions = [];
6739
7843
  let changed = false;
6740
7844
  let allPaths = [];
@@ -6751,19 +7855,15 @@ function transformSchema(schema, currentPath) {
6751
7855
  });
6752
7856
  if (changed) {
6753
7857
  return [
6754
- import_zod.z.union(newOptions),
7858
+ import_v3.z.union(newOptions),
6755
7859
  allPaths
6756
7860
  ];
6757
7861
  }
6758
7862
  return [schema, allPaths];
6759
7863
  }
6760
- if (isKind(schema, "intersection")) {
6761
- const intersectionSchema = schema;
6762
- const leftType = intersectionSchema._zod.def.left;
6763
- const rightType = intersectionSchema._zod.def.right;
6764
- if (!leftType || !rightType) {
6765
- return [schema, []];
6766
- }
7864
+ if (isKind(schema, import_v3.ZodFirstPartyTypeKind.ZodIntersection)) {
7865
+ const leftType = schema._def.left;
7866
+ const rightType = schema._def.right;
6767
7867
  const [left, leftPaths] = transformSchema(leftType, [
6768
7868
  ...currentPath,
6769
7869
  "intersection_left"
@@ -6775,50 +7875,33 @@ function transformSchema(schema, currentPath) {
6775
7875
  const changed = left !== leftType || right !== rightType;
6776
7876
  const allPaths = [...leftPaths, ...rightPaths];
6777
7877
  if (changed) {
6778
- return [import_zod.z.intersection(left, right), allPaths];
7878
+ return [import_v3.z.intersection(left, right), allPaths];
6779
7879
  }
6780
7880
  return [schema, allPaths];
6781
7881
  }
6782
- if (isKind(schema, "optional")) {
6783
- const optionalSchema = schema;
6784
- const innerType = optionalSchema._zod.def.innerType;
6785
- if (!innerType) {
6786
- return [schema, []];
6787
- }
7882
+ if (isKind(schema, import_v3.ZodFirstPartyTypeKind.ZodOptional)) {
7883
+ const innerType = schema._def.innerType;
6788
7884
  const [inner, innerPaths] = transformSchema(innerType, currentPath);
6789
7885
  if (inner !== innerType) {
6790
- return [import_zod.z.optional(inner), innerPaths];
7886
+ return [import_v3.z.optional(inner), innerPaths];
6791
7887
  }
6792
7888
  return [schema, innerPaths];
6793
7889
  }
6794
- if (isKind(schema, "nullable")) {
6795
- const nullableSchema = schema;
6796
- const innerType = nullableSchema._zod.def.innerType;
6797
- if (!innerType) {
6798
- return [schema, []];
6799
- }
7890
+ if (isKind(schema, import_v3.ZodFirstPartyTypeKind.ZodNullable)) {
7891
+ const innerType = schema._def.innerType;
6800
7892
  const [inner, innerPaths] = transformSchema(innerType, currentPath);
6801
7893
  if (inner !== innerType) {
6802
- return [import_zod.z.nullable(inner), innerPaths];
7894
+ return [import_v3.z.nullable(inner), innerPaths];
6803
7895
  }
6804
7896
  return [schema, innerPaths];
6805
7897
  }
6806
- if (isKind(schema, "pipe")) {
6807
- const pipeSchema = schema;
6808
- const inSchema = pipeSchema._zod.def.in;
6809
- const outSchema = pipeSchema._zod.def.out;
6810
- if (!inSchema || !outSchema) {
6811
- return [schema, []];
6812
- }
6813
- const [newIn, inPaths] = transformSchema(inSchema, currentPath);
6814
- const [newOut, outPaths] = transformSchema(outSchema, currentPath);
6815
- const allPaths = [...inPaths, ...outPaths];
6816
- const changed = newIn !== inSchema || newOut !== outSchema;
6817
- if (changed) {
6818
- const result = import_zod.z.pipe(newIn, newOut);
6819
- return [result, allPaths];
7898
+ if (isKind(schema, import_v3.ZodFirstPartyTypeKind.ZodEffects)) {
7899
+ const baseSchema = schema._def.schema;
7900
+ const [newBaseSchema, basePaths] = transformSchema(baseSchema, currentPath);
7901
+ if (newBaseSchema !== baseSchema) {
7902
+ return [import_v3.z.effect(newBaseSchema, schema._def.effect), basePaths];
6820
7903
  }
6821
- return [schema, allPaths];
7904
+ return [schema, basePaths];
6822
7905
  }
6823
7906
  return [schema, []];
6824
7907
  }
@@ -6864,18 +7947,17 @@ function injectUrls(obj, path6, idToUrlMapping) {
6864
7947
  }
6865
7948
  }
6866
7949
  function isKind(s, kind) {
6867
- try {
6868
- return getZodType(s) === kind;
6869
- } catch (e) {
6870
- return false;
6871
- }
7950
+ return s._def.typeName === kind;
6872
7951
  }
6873
7952
  function makeIdStringSchema(orig) {
6874
- var _a;
6875
- const userDesc = (_a = orig.description) != null ? _a : "";
7953
+ var _a, _b, _c;
7954
+ const userDesc = (
7955
+ // Zod ≥3.23 exposes .description directly; fall back to _def for older minor versions
7956
+ (_c = (_b = orig.description) != null ? _b : (_a = orig._def) == null ? void 0 : _a.description) != null ? _c : ""
7957
+ );
6876
7958
  const base = `This field must be the element-ID in the form 'frameId-backendId' (e.g. "0-432").`;
6877
7959
  const composed = userDesc.trim().length > 0 ? `${base} that follows this user-defined description: ${userDesc}` : base;
6878
- return import_zod.z.string().regex(ID_PATTERN).describe(composed);
7960
+ return import_v3.z.string().regex(ID_PATTERN).describe(composed);
6879
7961
  }
6880
7962
  var providerEnvVarMap = {
6881
7963
  openai: "OPENAI_API_KEY",
@@ -6921,7 +8003,7 @@ function jsonSchemaToZod(schema) {
6921
8003
  for (const key in schema.properties) {
6922
8004
  shape[key] = jsonSchemaToZod(schema.properties[key]);
6923
8005
  }
6924
- let zodObject = import_zod.z.object(shape);
8006
+ let zodObject = import_v3.z.object(shape);
6925
8007
  if (schema.required && Array.isArray(schema.required)) {
6926
8008
  const requiredFields = schema.required.reduce(
6927
8009
  (acc, field) => __spreadProps(__spreadValues({}, acc), { [field]: true }),
@@ -6934,30 +8016,30 @@ function jsonSchemaToZod(schema) {
6934
8016
  }
6935
8017
  return zodObject;
6936
8018
  } else {
6937
- return import_zod.z.object({});
8019
+ return import_v3.z.object({});
6938
8020
  }
6939
8021
  case "array":
6940
8022
  if (schema.items) {
6941
- let zodArray = import_zod.z.array(jsonSchemaToZod(schema.items));
8023
+ let zodArray = import_v3.z.array(jsonSchemaToZod(schema.items));
6942
8024
  if (schema.description) {
6943
8025
  zodArray = zodArray.describe(schema.description);
6944
8026
  }
6945
8027
  return zodArray;
6946
8028
  } else {
6947
- return import_zod.z.array(import_zod.z.any());
8029
+ return import_v3.z.array(import_v3.z.any());
6948
8030
  }
6949
8031
  case "string": {
6950
8032
  if (schema.enum) {
6951
- return import_zod.z.string().refine((val) => schema.enum.includes(val));
8033
+ return import_v3.z.string().refine((val) => schema.enum.includes(val));
6952
8034
  }
6953
- let zodString = import_zod.z.string();
8035
+ let zodString = import_v3.z.string();
6954
8036
  if (schema.description) {
6955
8037
  zodString = zodString.describe(schema.description);
6956
8038
  }
6957
8039
  return zodString;
6958
8040
  }
6959
8041
  case "number": {
6960
- let zodNumber = import_zod.z.number();
8042
+ let zodNumber = import_v3.z.number();
6961
8043
  if (schema.minimum !== void 0) {
6962
8044
  zodNumber = zodNumber.min(schema.minimum);
6963
8045
  }
@@ -6970,14 +8052,14 @@ function jsonSchemaToZod(schema) {
6970
8052
  return zodNumber;
6971
8053
  }
6972
8054
  case "boolean": {
6973
- let zodBoolean = import_zod.z.boolean();
8055
+ let zodBoolean = import_v3.z.boolean();
6974
8056
  if (schema.description) {
6975
8057
  zodBoolean = zodBoolean.describe(schema.description);
6976
8058
  }
6977
8059
  return zodBoolean;
6978
8060
  }
6979
8061
  default:
6980
- return import_zod.z.any();
8062
+ return import_v3.z.any();
6981
8063
  }
6982
8064
  }
6983
8065
 
@@ -7030,7 +8112,18 @@ function isTestEnvironment() {
7030
8112
  var _StagehandLogger = class _StagehandLogger {
7031
8113
  constructor(options = {}, externalLogger) {
7032
8114
  this.isTest = isTestEnvironment();
7033
- this.usePino = this.isTest ? false : options.usePino !== false;
8115
+ this.externalLogger = externalLogger;
8116
+ const externalProvided = typeof externalLogger === "function";
8117
+ const explicitUsePino = options.usePino;
8118
+ if (this.isTest) {
8119
+ this.usePino = false;
8120
+ } else if (explicitUsePino === true) {
8121
+ this.usePino = true;
8122
+ } else if (explicitUsePino === false) {
8123
+ this.usePino = false;
8124
+ } else {
8125
+ this.usePino = !externalProvided;
8126
+ }
7034
8127
  if (this.usePino) {
7035
8128
  if (!_StagehandLogger.sharedPinoLogger) {
7036
8129
  _StagehandLogger.sharedPinoLogger = createLogger(options);
@@ -7038,7 +8131,6 @@ var _StagehandLogger = class _StagehandLogger {
7038
8131
  this.logger = _StagehandLogger.sharedPinoLogger;
7039
8132
  }
7040
8133
  this.verbose = 1;
7041
- this.externalLogger = externalLogger;
7042
8134
  }
7043
8135
  /**
7044
8136
  * Set the verbosity level
@@ -7307,7 +8399,7 @@ var ActCache = class {
7307
8399
  }
7308
8400
  }
7309
8401
  });
7310
- return yield this.replayCachedActions(entry, page, timeout);
8402
+ return yield this.replayCachedActions(context, entry, page, timeout);
7311
8403
  });
7312
8404
  }
7313
8405
  store(context, result) {
@@ -7357,7 +8449,7 @@ var ActCache = class {
7357
8449
  });
7358
8450
  return (0, import_crypto.createHash)("sha256").update(payload).digest("hex");
7359
8451
  }
7360
- replayCachedActions(entry, page, timeout) {
8452
+ replayCachedActions(context, entry, page, timeout) {
7361
8453
  return __async(this, null, function* () {
7362
8454
  const handler = this.getActHandler();
7363
8455
  if (!handler) {
@@ -7393,6 +8485,13 @@ var ActCache = class {
7393
8485
  });
7394
8486
  const message = actionResults.map((r) => r.message).filter((m) => m && m.trim().length > 0).join(" \u2192 ") || entry.message || `Replayed ${entry.actions.length} cached action${entry.actions.length === 1 ? "" : "s"}.`;
7395
8487
  const actionDescription = entry.actionDescription || ((_b = actionResults[actionResults.length - 1]) == null ? void 0 : _b.actionDescription) || ((_c = entry.actions[entry.actions.length - 1]) == null ? void 0 : _c.description) || entry.instruction;
8488
+ if (success && actions.length > 0 && this.haveActionsChanged(entry.actions, actions)) {
8489
+ yield this.refreshCacheEntry(context, __spreadProps(__spreadValues({}, entry), {
8490
+ actions,
8491
+ message,
8492
+ actionDescription
8493
+ }));
8494
+ }
7396
8495
  return {
7397
8496
  success,
7398
8497
  message,
@@ -7403,6 +8502,67 @@ var ActCache = class {
7403
8502
  return yield this.runWithTimeout(execute, timeout);
7404
8503
  });
7405
8504
  }
8505
+ haveActionsChanged(original, updated) {
8506
+ var _a, _b, _c, _d;
8507
+ if (original.length !== updated.length) {
8508
+ return true;
8509
+ }
8510
+ for (let i = 0; i < original.length; i += 1) {
8511
+ const orig = original[i];
8512
+ const next = updated[i];
8513
+ if (!next) {
8514
+ return true;
8515
+ }
8516
+ if (orig.selector !== next.selector) {
8517
+ return true;
8518
+ }
8519
+ if (orig.description !== next.description) {
8520
+ return true;
8521
+ }
8522
+ if (((_a = orig.method) != null ? _a : "") !== ((_b = next.method) != null ? _b : "")) {
8523
+ return true;
8524
+ }
8525
+ const origArgs = (_c = orig.arguments) != null ? _c : [];
8526
+ const nextArgs = (_d = next.arguments) != null ? _d : [];
8527
+ if (origArgs.length !== nextArgs.length) {
8528
+ return true;
8529
+ }
8530
+ for (let j = 0; j < origArgs.length; j += 1) {
8531
+ if (origArgs[j] !== nextArgs[j]) {
8532
+ return true;
8533
+ }
8534
+ }
8535
+ }
8536
+ return false;
8537
+ }
8538
+ refreshCacheEntry(context, entry) {
8539
+ return __async(this, null, function* () {
8540
+ const { error, path: path6 } = yield this.storage.writeJson(
8541
+ `${context.cacheKey}.json`,
8542
+ entry
8543
+ );
8544
+ if (error && path6) {
8545
+ this.logger({
8546
+ category: "cache",
8547
+ message: "failed to update act cache entry after self-heal",
8548
+ level: 0,
8549
+ auxiliary: {
8550
+ error: { value: String(error), type: "string" }
8551
+ }
8552
+ });
8553
+ return;
8554
+ }
8555
+ this.logger({
8556
+ category: "cache",
8557
+ message: "act cache entry updated after self-heal",
8558
+ level: 2,
8559
+ auxiliary: {
8560
+ instruction: { value: context.instruction, type: "string" },
8561
+ url: { value: context.pageUrl, type: "string" }
8562
+ }
8563
+ });
8564
+ });
8565
+ }
7406
8566
  runWithTimeout(run, timeout) {
7407
8567
  return __async(this, null, function* () {
7408
8568
  if (!timeout) {
@@ -7898,7 +9058,7 @@ var CacheStorage = class _CacheStorage {
7898
9058
  };
7899
9059
 
7900
9060
  // lib/inference.ts
7901
- var import_zod2 = require("zod");
9061
+ var import_v32 = require("zod/v3");
7902
9062
 
7903
9063
  // lib/prompt.ts
7904
9064
  function buildUserInstructionsString(userProvidedInstructions) {
@@ -8157,11 +9317,11 @@ function extract(_0) {
8157
9317
  logInferenceToFile = false
8158
9318
  }) {
8159
9319
  var _a, _b, _c, _d, _e, _f, _g, _h;
8160
- const metadataSchema = import_zod2.z.object({
8161
- progress: import_zod2.z.string().describe(
9320
+ const metadataSchema = import_v32.z.object({
9321
+ progress: import_v32.z.string().describe(
8162
9322
  "progress of what has been extracted so far, as concise as possible"
8163
9323
  ),
8164
- completed: import_zod2.z.boolean().describe(
9324
+ completed: import_v32.z.boolean().describe(
8165
9325
  "true if the goal is now accomplished. Use this conservatively, only when sure that the goal has been completed."
8166
9326
  )
8167
9327
  });
@@ -8311,20 +9471,20 @@ function observe(_0) {
8311
9471
  }) {
8312
9472
  var _a, _b, _c, _d;
8313
9473
  const isGPT5 = llmClient.modelName.includes("gpt-5");
8314
- const observeSchema = import_zod2.z.object({
8315
- elements: import_zod2.z.array(
8316
- import_zod2.z.object({
8317
- elementId: import_zod2.z.string().describe(
9474
+ const observeSchema = import_v32.z.object({
9475
+ elements: import_v32.z.array(
9476
+ import_v32.z.object({
9477
+ elementId: import_v32.z.string().describe(
8318
9478
  "the ID string associated with the element. Never include surrounding square brackets. This field must follow the format of 'number-number'."
8319
9479
  ),
8320
- description: import_zod2.z.string().describe(
9480
+ description: import_v32.z.string().describe(
8321
9481
  "a description of the accessible element and its purpose"
8322
9482
  ),
8323
- method: import_zod2.z.string().describe(
9483
+ method: import_v32.z.string().describe(
8324
9484
  "the candidate method/action to interact with the element. Select one of the available Playwright interaction methods."
8325
9485
  ),
8326
- arguments: import_zod2.z.array(
8327
- import_zod2.z.string().describe(
9486
+ arguments: import_v32.z.array(
9487
+ import_v32.z.string().describe(
8328
9488
  "the arguments to pass to the method. For example, for a click, the arguments are empty, but for a fill, the arguments are the value to fill in."
8329
9489
  )
8330
9490
  )
@@ -8418,20 +9578,20 @@ function act(_0) {
8418
9578
  }) {
8419
9579
  var _a, _b;
8420
9580
  const isGPT5 = llmClient.modelName.includes("gpt-5");
8421
- const actSchema = import_zod2.z.object({
8422
- elementId: import_zod2.z.string().describe(
9581
+ const actSchema = import_v32.z.object({
9582
+ elementId: import_v32.z.string().describe(
8423
9583
  "the ID string associated with the element. Never include surrounding square brackets. This field must follow the format of 'number-number'."
8424
9584
  ),
8425
- description: import_zod2.z.string().describe("a description of the accessible element and its purpose"),
8426
- method: import_zod2.z.string().describe(
9585
+ description: import_v32.z.string().describe("a description of the accessible element and its purpose"),
9586
+ method: import_v32.z.string().describe(
8427
9587
  "the candidate method/action to interact with the element. Select one of the available Playwright interaction methods."
8428
9588
  ),
8429
- arguments: import_zod2.z.array(
8430
- import_zod2.z.string().describe(
9589
+ arguments: import_v32.z.array(
9590
+ import_v32.z.string().describe(
8431
9591
  "the arguments to pass to the method. For example, for a click, the arguments are empty, but for a fill, the arguments are the value to fill in."
8432
9592
  )
8433
9593
  ),
8434
- twoStep: import_zod2.z.boolean()
9594
+ twoStep: import_v32.z.boolean()
8435
9595
  });
8436
9596
  const messages = [
8437
9597
  buildActSystemPrompt(userProvidedInstructions),
@@ -8512,12 +9672,12 @@ function act(_0) {
8512
9672
  init_logger();
8513
9673
 
8514
9674
  // lib/v3/types/public/methods.ts
8515
- var import_zod3 = require("zod");
8516
- var defaultExtractSchema = import_zod3.z.object({
8517
- extraction: import_zod3.z.string()
9675
+ var import_v33 = require("zod/v3");
9676
+ var defaultExtractSchema = import_v33.z.object({
9677
+ extraction: import_v33.z.string()
8518
9678
  });
8519
- var pageTextSchema = import_zod3.z.object({
8520
- pageText: import_zod3.z.string()
9679
+ var pageTextSchema = import_v33.z.object({
9680
+ pageText: import_v33.z.string()
8521
9681
  });
8522
9682
  var V3FunctionName = /* @__PURE__ */ ((V3FunctionName2) => {
8523
9683
  V3FunctionName2["ACT"] = "ACT";
@@ -9500,7 +10660,7 @@ var ActHandler = class {
9500
10660
  // lib/v3/handlers/extractHandler.ts
9501
10661
  init_logger();
9502
10662
  init_snapshot();
9503
- var import_zod4 = require("zod");
10663
+ var import_v34 = require("zod/v3");
9504
10664
  function transformUrlStringsToNumericIds(schema) {
9505
10665
  const [finalSchema, urlPaths] = transformSchema(schema, []);
9506
10666
  return [finalSchema, urlPaths];
@@ -9554,7 +10714,7 @@ var ExtractHandler = class {
9554
10714
  const baseSchema = schema != null ? schema : defaultExtractSchema;
9555
10715
  const isObjectSchema = !!((_c = baseSchema._def) == null ? void 0 : _c.shape);
9556
10716
  const WRAP_KEY = "value";
9557
- const objectSchema = isObjectSchema ? baseSchema : import_zod4.z.object({ [WRAP_KEY]: baseSchema });
10717
+ const objectSchema = isObjectSchema ? baseSchema : import_v34.z.object({ [WRAP_KEY]: baseSchema });
9558
10718
  const [transformedSchema, urlFieldPaths] = transformUrlStringsToNumericIds(objectSchema);
9559
10719
  const extractionResponse = yield extract({
9560
10720
  instruction,
@@ -9741,11 +10901,11 @@ var ObserveHandler = class {
9741
10901
 
9742
10902
  // lib/v3/agent/tools/v3-goto.ts
9743
10903
  var import_ai = require("ai");
9744
- var import_zod5 = require("zod");
10904
+ var import_v35 = require("zod/v3");
9745
10905
  var createGotoTool = (v3) => (0, import_ai.tool)({
9746
10906
  description: "Navigate to a specific URL",
9747
- inputSchema: import_zod5.z.object({
9748
- url: import_zod5.z.string().describe("The URL to navigate to")
10907
+ inputSchema: import_v35.z.object({
10908
+ url: import_v35.z.string().describe("The URL to navigate to")
9749
10909
  }),
9750
10910
  execute: (_0) => __async(null, [_0], function* ({ url }) {
9751
10911
  var _a;
@@ -9773,11 +10933,11 @@ var createGotoTool = (v3) => (0, import_ai.tool)({
9773
10933
 
9774
10934
  // lib/v3/agent/tools/v3-act.ts
9775
10935
  var import_ai2 = require("ai");
9776
- var import_zod6 = require("zod");
10936
+ var import_v36 = require("zod/v3");
9777
10937
  var createActTool = (v3, executionModel) => (0, import_ai2.tool)({
9778
10938
  description: "Perform an action on the page (click, type). Provide a short, specific phrase that mentions the element type.",
9779
- inputSchema: import_zod6.z.object({
9780
- action: import_zod6.z.string().describe(
10939
+ inputSchema: import_v36.z.object({
10940
+ action: import_v36.z.string().describe(
9781
10941
  'Describe what to click or type, e.g. "click the Login button" or "type "John" into the first name input"'
9782
10942
  )
9783
10943
  }),
@@ -9818,10 +10978,10 @@ var createActTool = (v3, executionModel) => (0, import_ai2.tool)({
9818
10978
 
9819
10979
  // lib/v3/agent/tools/v3-screenshot.ts
9820
10980
  var import_ai3 = require("ai");
9821
- var import_zod7 = require("zod");
10981
+ var import_v37 = require("zod/v3");
9822
10982
  var createScreenshotTool = (v3) => (0, import_ai3.tool)({
9823
10983
  description: "Takes a screenshot (PNG) of the current page. Use this to quickly verify page state.",
9824
- inputSchema: import_zod7.z.object({}),
10984
+ inputSchema: import_v37.z.object({}),
9825
10985
  execute: () => __async(null, null, function* () {
9826
10986
  v3.logger({
9827
10987
  category: "agent",
@@ -9845,11 +11005,11 @@ var createScreenshotTool = (v3) => (0, import_ai3.tool)({
9845
11005
 
9846
11006
  // lib/v3/agent/tools/v3-wait.ts
9847
11007
  var import_ai4 = require("ai");
9848
- var import_zod8 = require("zod");
11008
+ var import_v38 = require("zod/v3");
9849
11009
  var createWaitTool = (v3) => (0, import_ai4.tool)({
9850
11010
  description: "Wait for a specified time",
9851
- inputSchema: import_zod8.z.object({
9852
- timeMs: import_zod8.z.number().describe("Time in milliseconds")
11011
+ inputSchema: import_v38.z.object({
11012
+ timeMs: import_v38.z.number().describe("Time in milliseconds")
9853
11013
  }),
9854
11014
  execute: (_0) => __async(null, [_0], function* ({ timeMs }) {
9855
11015
  v3.logger({
@@ -9873,11 +11033,11 @@ var createWaitTool = (v3) => (0, import_ai4.tool)({
9873
11033
 
9874
11034
  // lib/v3/agent/tools/v3-navback.ts
9875
11035
  var import_ai5 = require("ai");
9876
- var import_zod9 = require("zod");
11036
+ var import_v39 = require("zod/v3");
9877
11037
  var createNavBackTool = (v3) => (0, import_ai5.tool)({
9878
11038
  description: "Navigate back to the previous page",
9879
- inputSchema: import_zod9.z.object({
9880
- reasoningText: import_zod9.z.string().describe("Why you're going back")
11039
+ inputSchema: import_v39.z.object({
11040
+ reasoningText: import_v39.z.string().describe("Why you're going back")
9881
11041
  }),
9882
11042
  execute: () => __async(null, null, function* () {
9883
11043
  v3.logger({
@@ -9897,12 +11057,12 @@ var createNavBackTool = (v3) => (0, import_ai5.tool)({
9897
11057
 
9898
11058
  // lib/v3/agent/tools/v3-close.ts
9899
11059
  var import_ai6 = require("ai");
9900
- var import_zod10 = require("zod");
11060
+ var import_v310 = require("zod/v3");
9901
11061
  var createCloseTool = () => (0, import_ai6.tool)({
9902
11062
  description: "Complete the task and close",
9903
- inputSchema: import_zod10.z.object({
9904
- reasoning: import_zod10.z.string().describe("Summary of what was accomplished"),
9905
- taskComplete: import_zod10.z.boolean().describe("Whether the task was completed successfully")
11063
+ inputSchema: import_v310.z.object({
11064
+ reasoning: import_v310.z.string().describe("Summary of what was accomplished"),
11065
+ taskComplete: import_v310.z.boolean().describe("Whether the task was completed successfully")
9906
11066
  }),
9907
11067
  execute: (_0) => __async(null, [_0], function* ({ reasoning, taskComplete }) {
9908
11068
  return { success: true, reasoning, taskComplete };
@@ -9911,10 +11071,10 @@ var createCloseTool = () => (0, import_ai6.tool)({
9911
11071
 
9912
11072
  // lib/v3/agent/tools/v3-ariaTree.ts
9913
11073
  var import_ai7 = require("ai");
9914
- var import_zod11 = require("zod");
11074
+ var import_v311 = require("zod/v3");
9915
11075
  var createAriaTreeTool = (v3) => (0, import_ai7.tool)({
9916
11076
  description: "gets the accessibility (ARIA) hybrid tree text for the current page. use this to understand structure and content.",
9917
- inputSchema: import_zod11.z.object({}),
11077
+ inputSchema: import_v311.z.object({}),
9918
11078
  execute: () => __async(null, null, function* () {
9919
11079
  v3.logger({
9920
11080
  category: "agent",
@@ -9942,17 +11102,17 @@ ${result.content}` }]
9942
11102
 
9943
11103
  // lib/v3/agent/tools/v3-fillform.ts
9944
11104
  var import_ai8 = require("ai");
9945
- var import_zod12 = require("zod");
11105
+ var import_v312 = require("zod/v3");
9946
11106
  var createFillFormTool = (v3, executionModel) => (0, import_ai8.tool)({
9947
11107
  description: `\u{1F4DD} FORM FILL - MULTI-FIELD INPUT TOOL
9948
11108
  For any form with 2+ inputs/textareas. Faster than individual typing.`,
9949
- inputSchema: import_zod12.z.object({
9950
- fields: import_zod12.z.array(
9951
- import_zod12.z.object({
9952
- action: import_zod12.z.string().describe(
11109
+ inputSchema: import_v312.z.object({
11110
+ fields: import_v312.z.array(
11111
+ import_v312.z.object({
11112
+ action: import_v312.z.string().describe(
9953
11113
  'Description of typing action, e.g. "type foo into the email field"'
9954
11114
  ),
9955
- value: import_zod12.z.string().describe("Text to type into the target")
11115
+ value: import_v312.z.string().describe("Text to type into the target")
9956
11116
  })
9957
11117
  ).min(1, "Provide at least one field to fill")
9958
11118
  }),
@@ -9996,12 +11156,12 @@ For any form with 2+ inputs/textareas. Faster than individual typing.`,
9996
11156
 
9997
11157
  // lib/v3/agent/tools/v3-scroll.ts
9998
11158
  var import_ai9 = require("ai");
9999
- var import_zod13 = require("zod");
11159
+ var import_v313 = require("zod/v3");
10000
11160
  var createScrollTool = (v3) => (0, import_ai9.tool)({
10001
11161
  description: "Scroll the page",
10002
- inputSchema: import_zod13.z.object({
10003
- pixels: import_zod13.z.number().describe("Number of pixels to scroll up or down"),
10004
- direction: import_zod13.z.enum(["up", "down"]).describe("Direction to scroll")
11162
+ inputSchema: import_v313.z.object({
11163
+ pixels: import_v313.z.number().describe("Number of pixels to scroll up or down"),
11164
+ direction: import_v313.z.enum(["up", "down"]).describe("Direction to scroll")
10005
11165
  }),
10006
11166
  execute: (_0) => __async(null, [_0], function* ({ pixels, direction }) {
10007
11167
  v3.logger({
@@ -10033,37 +11193,49 @@ var createScrollTool = (v3) => (0, import_ai9.tool)({
10033
11193
 
10034
11194
  // lib/v3/agent/tools/v3-extract.ts
10035
11195
  var import_ai10 = require("ai");
10036
- var import_zod14 = require("zod");
11196
+ var import_v314 = require("zod/v3");
10037
11197
  function evaluateZodSchema(schemaStr, logger) {
10038
11198
  var _a;
10039
11199
  try {
10040
11200
  const fn = new Function("z", `return ${schemaStr}`);
10041
- return fn(import_zod14.z);
11201
+ return fn(import_v314.z);
10042
11202
  } catch (e) {
10043
11203
  logger == null ? void 0 : logger({
10044
11204
  category: "agent",
10045
11205
  message: `Failed to evaluate schema: ${(_a = e == null ? void 0 : e.message) != null ? _a : String(e)}`,
10046
11206
  level: 0
10047
11207
  });
10048
- throw new Error(
10049
- "Invalid schema: Ensure you're passing a valid Zod schema expression, e.g. z.object({ title: z.string() })"
10050
- );
11208
+ return import_v314.z.any();
10051
11209
  }
10052
11210
  }
10053
11211
  var createExtractTool = (v3, executionModel, logger) => (0, import_ai10.tool)({
10054
- description: "Extract structured data. Optionally provide an instruction and Zod schema.",
10055
- inputSchema: import_zod14.z.object({
10056
- instruction: import_zod14.z.string().optional(),
10057
- schema: import_zod14.z.string().optional().describe("Zod schema as code, e.g. z.object({ title: z.string() })"),
10058
- selector: import_zod14.z.string().optional()
11212
+ description: `Extract structured data from the current page based on a provided schema.
11213
+
11214
+ USAGE GUIDELINES:
11215
+ - Keep schemas MINIMAL - only include fields essential for the task
11216
+ - IMPORANT: only use this if explicitly asked for structured output. In most scenarios, you should use the aria tree tool over this.
11217
+ - If you need to extract a link, make sure the type defintion follows the format of z.string().url()
11218
+ EXAMPLES:
11219
+ 1. Extract a single value:
11220
+ instruction: "extract the product price"
11221
+ schema: "z.object({ price: z.number()})"
11222
+
11223
+ 2. Extract multiple fields:
11224
+ instruction: "extract product name and price"
11225
+ schema: "z.object({ name: z.string(), price: z.number() })"
11226
+
11227
+ 3. Extract arrays:
11228
+ instruction: "extract all product names and prices"
11229
+ schema: "z.object({ products: z.array(z.object({ name: z.string(), price: z.number() })) })"`,
11230
+ inputSchema: import_v314.z.object({
11231
+ instruction: import_v314.z.string(),
11232
+ schema: import_v314.z.string().optional().describe("Zod schema as code, e.g. z.object({ title: z.string() })")
10059
11233
  }),
10060
- execute: (_0) => __async(null, [_0], function* ({ instruction, schema, selector }) {
11234
+ execute: (_0) => __async(null, [_0], function* ({ instruction, schema }) {
10061
11235
  var _a;
10062
11236
  try {
10063
11237
  const parsedSchema = schema ? evaluateZodSchema(schema, logger) : void 0;
10064
- const result = yield v3.extract(instruction, parsedSchema, __spreadProps(__spreadValues({}, executionModel ? { model: executionModel } : {}), {
10065
- selector
10066
- }));
11238
+ const result = yield v3.extract(instruction, parsedSchema, __spreadValues({}, executionModel ? { model: executionModel } : {}));
10067
11239
  return { success: true, result };
10068
11240
  } catch (error) {
10069
11241
  return { success: false, error: (_a = error == null ? void 0 : error.message) != null ? _a : String(error) };
@@ -10224,12 +11396,12 @@ function mapToolResultToActions({
10224
11396
  case "fillForm":
10225
11397
  return mapFillFormToolResult(toolResult, args, reasoning);
10226
11398
  default:
10227
- return [createStandardAction(toolCallName, args, reasoning)];
11399
+ return [createStandardAction(toolCallName, toolResult, args, reasoning)];
10228
11400
  }
10229
11401
  }
10230
11402
  function mapActToolResult(toolResult, args, reasoning) {
10231
11403
  if (!toolResult || typeof toolResult !== "object") {
10232
- return [createStandardAction("act", args, reasoning)];
11404
+ return [createStandardAction("act", toolResult, args, reasoning)];
10233
11405
  }
10234
11406
  const result = toolResult;
10235
11407
  const output = result.output || result;
@@ -10245,7 +11417,7 @@ function mapActToolResult(toolResult, args, reasoning) {
10245
11417
  }
10246
11418
  function mapFillFormToolResult(toolResult, args, reasoning) {
10247
11419
  if (!toolResult || typeof toolResult !== "object") {
10248
- return [createStandardAction("fillForm", args, reasoning)];
11420
+ return [createStandardAction("fillForm", toolResult, args, reasoning)];
10249
11421
  }
10250
11422
  const result = toolResult;
10251
11423
  const output = result.output || result;
@@ -10266,12 +11438,17 @@ function mapFillFormToolResult(toolResult, args, reasoning) {
10266
11438
  }
10267
11439
  return actions;
10268
11440
  }
10269
- function createStandardAction(toolCallName, args, reasoning) {
10270
- return __spreadValues({
11441
+ function createStandardAction(toolCallName, toolResult, args, reasoning) {
11442
+ const action = __spreadValues({
10271
11443
  type: toolCallName,
10272
11444
  reasoning,
10273
11445
  taskCompleted: toolCallName === "close" ? args == null ? void 0 : args.taskComplete : false
10274
11446
  }, args);
11447
+ if (toolCallName !== "ariaTree" && toolResult) {
11448
+ const { output } = toolResult;
11449
+ Object.assign(action, output);
11450
+ }
11451
+ return action;
10275
11452
  }
10276
11453
 
10277
11454
  // lib/v3/handlers/v3AgentHandler.ts
@@ -10416,7 +11593,7 @@ var V3AgentHandler = class {
10416
11593
  buildSystemPrompt(executionInstruction, systemInstructions) {
10417
11594
  if (systemInstructions) {
10418
11595
  return `${systemInstructions}
10419
- Your current goal: ${executionInstruction}`;
11596
+ Your current goal: ${executionInstruction} when the task is complete, use the "close" tool with taskComplete: true`;
10420
11597
  }
10421
11598
  return `You are a web automation assistant using browser automation tools to accomplish the user's goal.
10422
11599
 
@@ -10457,7 +11634,7 @@ init_snapshot();
10457
11634
 
10458
11635
  // lib/v3/agent/AnthropicCUAClient.ts
10459
11636
  var import_sdk = __toESM(require("@anthropic-ai/sdk"));
10460
- var import_zod15 = require("zod");
11637
+ var import_zod_to_json_schema = require("zod-to-json-schema");
10461
11638
 
10462
11639
  // lib/v3/agent/AgentClient.ts
10463
11640
  var AgentClient = class {
@@ -10960,7 +12137,7 @@ var AnthropicCUAClient = class extends AgentClient {
10960
12137
  };
10961
12138
  if (this.tools && Object.keys(this.tools).length > 0) {
10962
12139
  const customTools = Object.entries(this.tools).map(([name, tool12]) => {
10963
- const jsonSchema2 = import_zod15.z.toJSONSchema(tool12.inputSchema);
12140
+ const jsonSchema2 = (0, import_zod_to_json_schema.zodToJsonSchema)(tool12.inputSchema);
10964
12141
  const inputSchema = {
10965
12142
  type: "object",
10966
12143
  properties: jsonSchema2.properties || {},
@@ -11824,7 +13001,7 @@ var import_genai3 = require("@google/genai");
11824
13001
 
11825
13002
  // lib/v3/agent/utils/googleCustomToolHandler.ts
11826
13003
  var import_genai2 = require("@google/genai");
11827
- var import_zod16 = require("zod");
13004
+ var import_zod_to_json_schema2 = require("zod-to-json-schema");
11828
13005
  function executeGoogleCustomTool(toolName, toolArgs, tools, functionCall, logger) {
11829
13006
  return __async(this, null, function* () {
11830
13007
  try {
@@ -11892,7 +13069,7 @@ function convertToolSetToFunctionDeclarations(tools) {
11892
13069
  }
11893
13070
  function convertToolToFunctionDeclaration(name, tool12) {
11894
13071
  try {
11895
- const jsonSchema2 = import_zod16.z.toJSONSchema(tool12.inputSchema);
13072
+ const jsonSchema2 = (0, import_zod_to_json_schema2.zodToJsonSchema)(tool12.inputSchema);
11896
13073
  const parameters = convertJsonSchemaToGoogleParameters(jsonSchema2);
11897
13074
  return {
11898
13075
  name,
@@ -14549,7 +15726,7 @@ var AISdkClient = class extends LLMClient {
14549
15726
 
14550
15727
  // lib/v3/llm/AnthropicClient.ts
14551
15728
  var import_sdk3 = __toESM(require("@anthropic-ai/sdk"));
14552
- var import_zod17 = require("zod");
15729
+ var import_zod_to_json_schema3 = require("zod-to-json-schema");
14553
15730
  var AnthropicClient = class extends LLMClient {
14554
15731
  constructor({
14555
15732
  modelName,
@@ -14659,7 +15836,7 @@ var AnthropicClient = class extends LLMClient {
14659
15836
  });
14660
15837
  let toolDefinition;
14661
15838
  if (options.response_model) {
14662
- const jsonSchema2 = import_zod17.z.toJSONSchema(options.response_model.schema);
15839
+ const jsonSchema2 = (0, import_zod_to_json_schema3.zodToJsonSchema)(options.response_model.schema);
14663
15840
  const { properties: schemaProperties, required: schemaRequired } = extractSchemaProperties(jsonSchema2);
14664
15841
  toolDefinition = {
14665
15842
  name: "print_extracted_data",
@@ -14791,7 +15968,7 @@ var extractSchemaProperties = (jsonSchema2) => {
14791
15968
 
14792
15969
  // lib/v3/llm/CerebrasClient.ts
14793
15970
  var import_openai2 = __toESM(require("openai"));
14794
- var import_zod18 = require("zod");
15971
+ var import_zod_to_json_schema4 = require("zod-to-json-schema");
14795
15972
  var CerebrasClient = class extends LLMClient {
14796
15973
  constructor({
14797
15974
  modelName,
@@ -14853,7 +16030,7 @@ var CerebrasClient = class extends LLMClient {
14853
16030
  }
14854
16031
  }));
14855
16032
  if (options.response_model) {
14856
- const jsonSchema2 = import_zod18.z.toJSONSchema(options.response_model.schema);
16033
+ const jsonSchema2 = (0, import_zod_to_json_schema4.zodToJsonSchema)(options.response_model.schema);
14857
16034
  const schemaProperties = jsonSchema2.properties || {};
14858
16035
  const schemaRequired = jsonSchema2.required || [];
14859
16036
  const responseTool = {
@@ -15378,7 +16555,7 @@ ${firstPartText.text}`;
15378
16555
 
15379
16556
  // lib/v3/llm/GroqClient.ts
15380
16557
  var import_openai3 = __toESM(require("openai"));
15381
- var import_zod19 = require("zod");
16558
+ var import_zod_to_json_schema5 = require("zod-to-json-schema");
15382
16559
  var GroqClient = class extends LLMClient {
15383
16560
  constructor({
15384
16561
  modelName,
@@ -15440,7 +16617,7 @@ var GroqClient = class extends LLMClient {
15440
16617
  }
15441
16618
  }));
15442
16619
  if (options.response_model) {
15443
- const jsonSchema2 = import_zod19.z.toJSONSchema(options.response_model.schema);
16620
+ const jsonSchema2 = (0, import_zod_to_json_schema5.zodToJsonSchema)(options.response_model.schema);
15444
16621
  const schemaProperties = jsonSchema2.properties || {};
15445
16622
  const schemaRequired = jsonSchema2.required || [];
15446
16623
  const responseTool = {
@@ -15598,8 +16775,8 @@ var GroqClient = class extends LLMClient {
15598
16775
 
15599
16776
  // lib/v3/llm/OpenAIClient.ts
15600
16777
  var import_openai4 = __toESM(require("openai"));
15601
- var import_zod20 = require("openai/helpers/zod");
15602
- var import_zod21 = require("zod");
16778
+ var import_zod = require("openai/helpers/zod");
16779
+ var import_zod_to_json_schema6 = __toESM(require("zod-to-json-schema"));
15603
16780
  var OpenAIClient = class extends LLMClient {
15604
16781
  constructor({
15605
16782
  modelName,
@@ -15710,7 +16887,7 @@ ${JSON.stringify(
15710
16887
  if (this.modelName.startsWith("o1") || this.modelName.startsWith("o3")) {
15711
16888
  try {
15712
16889
  const parsedSchema = JSON.stringify(
15713
- import_zod21.z.toJSONSchema(options.response_model.schema)
16890
+ (0, import_zod_to_json_schema6.default)(options.response_model.schema)
15714
16891
  );
15715
16892
  options.messages.push({
15716
16893
  role: "user",
@@ -15736,7 +16913,7 @@ ${parsedSchema}
15736
16913
  throw error;
15737
16914
  }
15738
16915
  } else {
15739
- responseFormat = (0, import_zod20.zodResponseFormat)(
16916
+ responseFormat = (0, import_zod.zodResponseFormat)(
15740
16917
  options.response_model.schema,
15741
16918
  options.response_model.name
15742
16919
  );
@@ -15920,7 +17097,7 @@ ${parsedSchema}
15920
17097
  }
15921
17098
  };
15922
17099
 
15923
- // ../../node_modules/.pnpm/@ai-sdk+provider-utils@3.0.12_zod@4.1.12/node_modules/@ai-sdk/provider-utils/dist/index.mjs
17100
+ // ../../node_modules/.pnpm/@ai-sdk+provider-utils@3.0.12_zod@3.25.67/node_modules/@ai-sdk/provider-utils/dist/index.mjs
15924
17101
  var import_provider = require("@ai-sdk/provider");
15925
17102
  var import_provider2 = require("@ai-sdk/provider");
15926
17103
  var import_provider3 = require("@ai-sdk/provider");
@@ -16057,14 +17234,14 @@ var EventSourceParserStream = class extends TransformStream {
16057
17234
  }
16058
17235
  };
16059
17236
 
16060
- // ../../node_modules/.pnpm/@ai-sdk+provider-utils@3.0.12_zod@4.1.12/node_modules/@ai-sdk/provider-utils/dist/index.mjs
17237
+ // ../../node_modules/.pnpm/@ai-sdk+provider-utils@3.0.12_zod@3.25.67/node_modules/@ai-sdk/provider-utils/dist/index.mjs
16061
17238
  var import_provider9 = require("@ai-sdk/provider");
16062
17239
  var import_provider10 = require("@ai-sdk/provider");
16063
17240
  var import_provider11 = require("@ai-sdk/provider");
16064
17241
  var z42 = __toESM(require("zod/v4"), 1);
16065
- var import_v3 = require("zod/v3");
16066
- var import_v32 = require("zod/v3");
16067
- var import_v33 = require("zod/v3");
17242
+ var import_v315 = require("zod/v3");
17243
+ var import_v316 = require("zod/v3");
17244
+ var import_v317 = require("zod/v3");
16068
17245
  function combineHeaders(...headers) {
16069
17246
  return headers.reduce(
16070
17247
  (combinedHeaders, currentHeaders) => __spreadValues(__spreadValues({}, combinedHeaders), currentHeaders != null ? currentHeaders : {}),
@@ -16881,7 +18058,7 @@ function parseArrayDef(def, refs) {
16881
18058
  const res = {
16882
18059
  type: "array"
16883
18060
  };
16884
- if (((_a = def.type) == null ? void 0 : _a._def) && ((_c = (_b = def.type) == null ? void 0 : _b._def) == null ? void 0 : _c.typeName) !== import_v32.ZodFirstPartyTypeKind.ZodAny) {
18061
+ if (((_a = def.type) == null ? void 0 : _a._def) && ((_c = (_b = def.type) == null ? void 0 : _b._def) == null ? void 0 : _c.typeName) !== import_v316.ZodFirstPartyTypeKind.ZodAny) {
16885
18062
  res.items = parseDef(def.type._def, __spreadProps(__spreadValues({}, refs), {
16886
18063
  currentPath: [...refs.currentPath, "items"]
16887
18064
  }));
@@ -17370,18 +18547,18 @@ function parseRecordDef(def, refs) {
17370
18547
  currentPath: [...refs.currentPath, "additionalProperties"]
17371
18548
  }))) != null ? _a : refs.allowedAdditionalProperties
17372
18549
  };
17373
- if (((_b = def.keyType) == null ? void 0 : _b._def.typeName) === import_v33.ZodFirstPartyTypeKind.ZodString && ((_c = def.keyType._def.checks) == null ? void 0 : _c.length)) {
18550
+ if (((_b = def.keyType) == null ? void 0 : _b._def.typeName) === import_v317.ZodFirstPartyTypeKind.ZodString && ((_c = def.keyType._def.checks) == null ? void 0 : _c.length)) {
17374
18551
  const _a2 = parseStringDef(def.keyType._def, refs), { type } = _a2, keyType = __objRest(_a2, ["type"]);
17375
18552
  return __spreadProps(__spreadValues({}, schema), {
17376
18553
  propertyNames: keyType
17377
18554
  });
17378
- } else if (((_d = def.keyType) == null ? void 0 : _d._def.typeName) === import_v33.ZodFirstPartyTypeKind.ZodEnum) {
18555
+ } else if (((_d = def.keyType) == null ? void 0 : _d._def.typeName) === import_v317.ZodFirstPartyTypeKind.ZodEnum) {
17379
18556
  return __spreadProps(__spreadValues({}, schema), {
17380
18557
  propertyNames: {
17381
18558
  enum: def.keyType._def.values
17382
18559
  }
17383
18560
  });
17384
- } else if (((_e = def.keyType) == null ? void 0 : _e._def.typeName) === import_v33.ZodFirstPartyTypeKind.ZodBranded && def.keyType._def.type._def.typeName === import_v33.ZodFirstPartyTypeKind.ZodString && ((_f = def.keyType._def.type._def.checks) == null ? void 0 : _f.length)) {
18561
+ } else if (((_e = def.keyType) == null ? void 0 : _e._def.typeName) === import_v317.ZodFirstPartyTypeKind.ZodBranded && def.keyType._def.type._def.typeName === import_v317.ZodFirstPartyTypeKind.ZodString && ((_f = def.keyType._def.type._def.checks) == null ? void 0 : _f.length)) {
17385
18562
  const _b2 = parseBrandedDef(
17386
18563
  def.keyType._def,
17387
18564
  refs
@@ -17707,73 +18884,73 @@ var parseReadonlyDef = (def, refs) => {
17707
18884
  };
17708
18885
  var selectParser = (def, typeName, refs) => {
17709
18886
  switch (typeName) {
17710
- case import_v3.ZodFirstPartyTypeKind.ZodString:
18887
+ case import_v315.ZodFirstPartyTypeKind.ZodString:
17711
18888
  return parseStringDef(def, refs);
17712
- case import_v3.ZodFirstPartyTypeKind.ZodNumber:
18889
+ case import_v315.ZodFirstPartyTypeKind.ZodNumber:
17713
18890
  return parseNumberDef(def);
17714
- case import_v3.ZodFirstPartyTypeKind.ZodObject:
18891
+ case import_v315.ZodFirstPartyTypeKind.ZodObject:
17715
18892
  return parseObjectDef(def, refs);
17716
- case import_v3.ZodFirstPartyTypeKind.ZodBigInt:
18893
+ case import_v315.ZodFirstPartyTypeKind.ZodBigInt:
17717
18894
  return parseBigintDef(def);
17718
- case import_v3.ZodFirstPartyTypeKind.ZodBoolean:
18895
+ case import_v315.ZodFirstPartyTypeKind.ZodBoolean:
17719
18896
  return parseBooleanDef();
17720
- case import_v3.ZodFirstPartyTypeKind.ZodDate:
18897
+ case import_v315.ZodFirstPartyTypeKind.ZodDate:
17721
18898
  return parseDateDef(def, refs);
17722
- case import_v3.ZodFirstPartyTypeKind.ZodUndefined:
18899
+ case import_v315.ZodFirstPartyTypeKind.ZodUndefined:
17723
18900
  return parseUndefinedDef();
17724
- case import_v3.ZodFirstPartyTypeKind.ZodNull:
18901
+ case import_v315.ZodFirstPartyTypeKind.ZodNull:
17725
18902
  return parseNullDef();
17726
- case import_v3.ZodFirstPartyTypeKind.ZodArray:
18903
+ case import_v315.ZodFirstPartyTypeKind.ZodArray:
17727
18904
  return parseArrayDef(def, refs);
17728
- case import_v3.ZodFirstPartyTypeKind.ZodUnion:
17729
- case import_v3.ZodFirstPartyTypeKind.ZodDiscriminatedUnion:
18905
+ case import_v315.ZodFirstPartyTypeKind.ZodUnion:
18906
+ case import_v315.ZodFirstPartyTypeKind.ZodDiscriminatedUnion:
17730
18907
  return parseUnionDef(def, refs);
17731
- case import_v3.ZodFirstPartyTypeKind.ZodIntersection:
18908
+ case import_v315.ZodFirstPartyTypeKind.ZodIntersection:
17732
18909
  return parseIntersectionDef(def, refs);
17733
- case import_v3.ZodFirstPartyTypeKind.ZodTuple:
18910
+ case import_v315.ZodFirstPartyTypeKind.ZodTuple:
17734
18911
  return parseTupleDef(def, refs);
17735
- case import_v3.ZodFirstPartyTypeKind.ZodRecord:
18912
+ case import_v315.ZodFirstPartyTypeKind.ZodRecord:
17736
18913
  return parseRecordDef(def, refs);
17737
- case import_v3.ZodFirstPartyTypeKind.ZodLiteral:
18914
+ case import_v315.ZodFirstPartyTypeKind.ZodLiteral:
17738
18915
  return parseLiteralDef(def);
17739
- case import_v3.ZodFirstPartyTypeKind.ZodEnum:
18916
+ case import_v315.ZodFirstPartyTypeKind.ZodEnum:
17740
18917
  return parseEnumDef(def);
17741
- case import_v3.ZodFirstPartyTypeKind.ZodNativeEnum:
18918
+ case import_v315.ZodFirstPartyTypeKind.ZodNativeEnum:
17742
18919
  return parseNativeEnumDef(def);
17743
- case import_v3.ZodFirstPartyTypeKind.ZodNullable:
18920
+ case import_v315.ZodFirstPartyTypeKind.ZodNullable:
17744
18921
  return parseNullableDef(def, refs);
17745
- case import_v3.ZodFirstPartyTypeKind.ZodOptional:
18922
+ case import_v315.ZodFirstPartyTypeKind.ZodOptional:
17746
18923
  return parseOptionalDef(def, refs);
17747
- case import_v3.ZodFirstPartyTypeKind.ZodMap:
18924
+ case import_v315.ZodFirstPartyTypeKind.ZodMap:
17748
18925
  return parseMapDef(def, refs);
17749
- case import_v3.ZodFirstPartyTypeKind.ZodSet:
18926
+ case import_v315.ZodFirstPartyTypeKind.ZodSet:
17750
18927
  return parseSetDef(def, refs);
17751
- case import_v3.ZodFirstPartyTypeKind.ZodLazy:
18928
+ case import_v315.ZodFirstPartyTypeKind.ZodLazy:
17752
18929
  return () => def.getter()._def;
17753
- case import_v3.ZodFirstPartyTypeKind.ZodPromise:
18930
+ case import_v315.ZodFirstPartyTypeKind.ZodPromise:
17754
18931
  return parsePromiseDef(def, refs);
17755
- case import_v3.ZodFirstPartyTypeKind.ZodNaN:
17756
- case import_v3.ZodFirstPartyTypeKind.ZodNever:
18932
+ case import_v315.ZodFirstPartyTypeKind.ZodNaN:
18933
+ case import_v315.ZodFirstPartyTypeKind.ZodNever:
17757
18934
  return parseNeverDef();
17758
- case import_v3.ZodFirstPartyTypeKind.ZodEffects:
18935
+ case import_v315.ZodFirstPartyTypeKind.ZodEffects:
17759
18936
  return parseEffectsDef(def, refs);
17760
- case import_v3.ZodFirstPartyTypeKind.ZodAny:
18937
+ case import_v315.ZodFirstPartyTypeKind.ZodAny:
17761
18938
  return parseAnyDef();
17762
- case import_v3.ZodFirstPartyTypeKind.ZodUnknown:
18939
+ case import_v315.ZodFirstPartyTypeKind.ZodUnknown:
17763
18940
  return parseUnknownDef();
17764
- case import_v3.ZodFirstPartyTypeKind.ZodDefault:
18941
+ case import_v315.ZodFirstPartyTypeKind.ZodDefault:
17765
18942
  return parseDefaultDef(def, refs);
17766
- case import_v3.ZodFirstPartyTypeKind.ZodBranded:
18943
+ case import_v315.ZodFirstPartyTypeKind.ZodBranded:
17767
18944
  return parseBrandedDef(def, refs);
17768
- case import_v3.ZodFirstPartyTypeKind.ZodReadonly:
18945
+ case import_v315.ZodFirstPartyTypeKind.ZodReadonly:
17769
18946
  return parseReadonlyDef(def, refs);
17770
- case import_v3.ZodFirstPartyTypeKind.ZodCatch:
18947
+ case import_v315.ZodFirstPartyTypeKind.ZodCatch:
17771
18948
  return parseCatchDef(def, refs);
17772
- case import_v3.ZodFirstPartyTypeKind.ZodPipeline:
18949
+ case import_v315.ZodFirstPartyTypeKind.ZodPipeline:
17773
18950
  return parsePipelineDef(def, refs);
17774
- case import_v3.ZodFirstPartyTypeKind.ZodFunction:
17775
- case import_v3.ZodFirstPartyTypeKind.ZodVoid:
17776
- case import_v3.ZodFirstPartyTypeKind.ZodSymbol:
18951
+ case import_v315.ZodFirstPartyTypeKind.ZodFunction:
18952
+ case import_v315.ZodFirstPartyTypeKind.ZodVoid:
18953
+ case import_v315.ZodFirstPartyTypeKind.ZodSymbol:
17777
18954
  return void 0;
17778
18955
  default:
17779
18956
  return /* @__PURE__ */ ((_) => void 0)(typeName);
@@ -17860,7 +19037,7 @@ var getRefs = (options) => {
17860
19037
  )
17861
19038
  });
17862
19039
  };
17863
- var zodToJsonSchema = (schema, options) => {
19040
+ var zodToJsonSchema7 = (schema, options) => {
17864
19041
  var _a;
17865
19042
  const refs = getRefs(options);
17866
19043
  let definitions = typeof options === "object" && options.definitions ? Object.entries(options.definitions).reduce(
@@ -17905,7 +19082,7 @@ var zodToJsonSchema = (schema, options) => {
17905
19082
  combined.$schema = "http://json-schema.org/draft-07/schema#";
17906
19083
  return combined;
17907
19084
  };
17908
- var zod_to_json_schema_default = zodToJsonSchema;
19085
+ var zod_to_json_schema_default = zodToJsonSchema7;
17909
19086
  function zod3Schema(zodSchema2, options) {
17910
19087
  var _a;
17911
19088
  const useReferences = (_a = options == null ? void 0 : options.useReferences) != null ? _a : false;
@@ -17997,7 +19174,7 @@ function withoutTrailingSlash(url) {
17997
19174
  return url == null ? void 0 : url.replace(/\/$/, "");
17998
19175
  }
17999
19176
 
18000
- // ../../node_modules/.pnpm/@ai-sdk+openai@2.0.53_zod@4.1.12/node_modules/@ai-sdk/openai/dist/index.mjs
19177
+ // ../../node_modules/.pnpm/@ai-sdk+openai@2.0.53_zod@3.25.67/node_modules/@ai-sdk/openai/dist/index.mjs
18001
19178
  var import_provider12 = require("@ai-sdk/provider");
18002
19179
  var import_v4 = require("zod/v4");
18003
19180
  var import_provider13 = require("@ai-sdk/provider");
@@ -22387,7 +23564,7 @@ function createOpenAI(options = {}) {
22387
23564
  }
22388
23565
  var openai = createOpenAI();
22389
23566
 
22390
- // ../../node_modules/.pnpm/@ai-sdk+anthropic@2.0.34_zod@4.1.12/node_modules/@ai-sdk/anthropic/dist/index.mjs
23567
+ // ../../node_modules/.pnpm/@ai-sdk+anthropic@2.0.34_zod@3.25.67/node_modules/@ai-sdk/anthropic/dist/index.mjs
22391
23568
  var import_provider20 = require("@ai-sdk/provider");
22392
23569
  var import_provider21 = require("@ai-sdk/provider");
22393
23570
  var import_v421 = require("zod/v4");
@@ -25426,7 +26603,7 @@ function createAnthropic(options = {}) {
25426
26603
  }
25427
26604
  var anthropic = createAnthropic();
25428
26605
 
25429
- // ../../node_modules/.pnpm/@ai-sdk+google@2.0.23_zod@4.1.12/node_modules/@ai-sdk/google/dist/index.mjs
26606
+ // ../../node_modules/.pnpm/@ai-sdk+google@2.0.23_zod@3.25.67/node_modules/@ai-sdk/google/dist/index.mjs
25430
26607
  var import_provider24 = require("@ai-sdk/provider");
25431
26608
  var import_v437 = require("zod/v4");
25432
26609
  var import_v438 = require("zod/v4");
@@ -26978,7 +28155,7 @@ function createGoogleGenerativeAI(options = {}) {
26978
28155
  }
26979
28156
  var google = createGoogleGenerativeAI();
26980
28157
 
26981
- // ../../node_modules/.pnpm/@ai-sdk+openai-compatible@1.0.22_zod@4.1.12/node_modules/@ai-sdk/openai-compatible/dist/index.mjs
28158
+ // ../../node_modules/.pnpm/@ai-sdk+openai-compatible@1.0.22_zod@3.25.67/node_modules/@ai-sdk/openai-compatible/dist/index.mjs
26982
28159
  var import_provider27 = require("@ai-sdk/provider");
26983
28160
  var import_v446 = require("zod/v4");
26984
28161
  var import_provider28 = require("@ai-sdk/provider");
@@ -28298,7 +29475,7 @@ var openaiCompatibleImageResponseSchema = import_v453.z.object({
28298
29475
  data: import_v453.z.array(import_v453.z.object({ b64_json: import_v453.z.string() }))
28299
29476
  });
28300
29477
 
28301
- // ../../node_modules/.pnpm/@ai-sdk+xai@2.0.26_zod@4.1.12/node_modules/@ai-sdk/xai/dist/index.mjs
29478
+ // ../../node_modules/.pnpm/@ai-sdk+xai@2.0.26_zod@3.25.67/node_modules/@ai-sdk/xai/dist/index.mjs
28302
29479
  var import_provider32 = require("@ai-sdk/provider");
28303
29480
  var import_v454 = require("zod/v4");
28304
29481
  var import_provider33 = require("@ai-sdk/provider");
@@ -29050,7 +30227,7 @@ function createXai(options = {}) {
29050
30227
  }
29051
30228
  var xai = createXai();
29052
30229
 
29053
- // ../../node_modules/.pnpm/@ai-sdk+openai@2.0.53_zod@4.1.12/node_modules/@ai-sdk/openai/dist/internal/index.mjs
30230
+ // ../../node_modules/.pnpm/@ai-sdk+openai@2.0.53_zod@3.25.67/node_modules/@ai-sdk/openai/dist/internal/index.mjs
29054
30231
  var import_provider35 = require("@ai-sdk/provider");
29055
30232
  var import_v457 = require("zod/v4");
29056
30233
  var import_provider36 = require("@ai-sdk/provider");
@@ -33273,7 +34450,7 @@ function mapWebSearchOutput2(action) {
33273
34450
  }
33274
34451
  }
33275
34452
 
33276
- // ../../node_modules/.pnpm/@ai-sdk+azure@2.0.54_zod@4.1.12/node_modules/@ai-sdk/azure/dist/index.mjs
34453
+ // ../../node_modules/.pnpm/@ai-sdk+azure@2.0.54_zod@3.25.67/node_modules/@ai-sdk/azure/dist/index.mjs
33277
34454
  var azureOpenaiTools = {
33278
34455
  codeInterpreter: codeInterpreter2,
33279
34456
  fileSearch: fileSearch2,
@@ -33378,7 +34555,7 @@ function createAzure(options = {}) {
33378
34555
  }
33379
34556
  var azure = createAzure();
33380
34557
 
33381
- // ../../node_modules/.pnpm/@ai-sdk+groq@2.0.24_zod@4.1.12/node_modules/@ai-sdk/groq/dist/index.mjs
34558
+ // ../../node_modules/.pnpm/@ai-sdk+groq@2.0.24_zod@3.25.67/node_modules/@ai-sdk/groq/dist/index.mjs
33382
34559
  var import_provider43 = require("@ai-sdk/provider");
33383
34560
  var import_provider44 = require("@ai-sdk/provider");
33384
34561
  var import_v477 = require("zod/v4");
@@ -34260,7 +35437,7 @@ function createGroq(options = {}) {
34260
35437
  }
34261
35438
  var groq = createGroq();
34262
35439
 
34263
- // ../../node_modules/.pnpm/@ai-sdk+cerebras@1.0.25_zod@4.1.12/node_modules/@ai-sdk/cerebras/dist/index.mjs
35440
+ // ../../node_modules/.pnpm/@ai-sdk+cerebras@1.0.25_zod@3.25.67/node_modules/@ai-sdk/cerebras/dist/index.mjs
34264
35441
  var import_provider47 = require("@ai-sdk/provider");
34265
35442
  var import_v482 = require("zod/v4");
34266
35443
  var VERSION8 = true ? "1.0.25" : "0.0.0-test";
@@ -34312,7 +35489,7 @@ function createCerebras(options = {}) {
34312
35489
  }
34313
35490
  var cerebras = createCerebras();
34314
35491
 
34315
- // ../../node_modules/.pnpm/@ai-sdk+togetherai@1.0.23_zod@4.1.12/node_modules/@ai-sdk/togetherai/dist/index.mjs
35492
+ // ../../node_modules/.pnpm/@ai-sdk+togetherai@1.0.23_zod@3.25.67/node_modules/@ai-sdk/togetherai/dist/index.mjs
34316
35493
  var import_v483 = require("zod/v4");
34317
35494
  var TogetherAIImageModel = class {
34318
35495
  constructor(modelId, config) {
@@ -34443,7 +35620,7 @@ function createTogetherAI(options = {}) {
34443
35620
  }
34444
35621
  var togetherai = createTogetherAI();
34445
35622
 
34446
- // ../../node_modules/.pnpm/@ai-sdk+mistral@2.0.19_zod@4.1.12/node_modules/@ai-sdk/mistral/dist/index.mjs
35623
+ // ../../node_modules/.pnpm/@ai-sdk+mistral@2.0.19_zod@3.25.67/node_modules/@ai-sdk/mistral/dist/index.mjs
34447
35624
  var import_provider48 = require("@ai-sdk/provider");
34448
35625
  var import_v484 = require("zod/v4");
34449
35626
  var import_provider49 = require("@ai-sdk/provider");
@@ -35226,7 +36403,7 @@ function createMistral(options = {}) {
35226
36403
  }
35227
36404
  var mistral = createMistral();
35228
36405
 
35229
- // ../../node_modules/.pnpm/@ai-sdk+deepseek@1.0.23_zod@4.1.12/node_modules/@ai-sdk/deepseek/dist/index.mjs
36406
+ // ../../node_modules/.pnpm/@ai-sdk+deepseek@1.0.23_zod@3.25.67/node_modules/@ai-sdk/deepseek/dist/index.mjs
35230
36407
  var import_provider52 = require("@ai-sdk/provider");
35231
36408
  var import_v488 = require("zod/v4");
35232
36409
  var buildDeepseekMetadata = (usage) => {
@@ -35316,7 +36493,7 @@ function createDeepSeek(options = {}) {
35316
36493
  }
35317
36494
  var deepseek = createDeepSeek();
35318
36495
 
35319
- // ../../node_modules/.pnpm/@ai-sdk+perplexity@2.0.13_zod@4.1.12/node_modules/@ai-sdk/perplexity/dist/index.mjs
36496
+ // ../../node_modules/.pnpm/@ai-sdk+perplexity@2.0.13_zod@3.25.67/node_modules/@ai-sdk/perplexity/dist/index.mjs
35320
36497
  var import_provider53 = require("@ai-sdk/provider");
35321
36498
  var import_v489 = require("zod/v4");
35322
36499
  var import_provider54 = require("@ai-sdk/provider");
@@ -35746,7 +36923,7 @@ function createPerplexity(options = {}) {
35746
36923
  }
35747
36924
  var perplexity = createPerplexity();
35748
36925
 
35749
- // ../../node_modules/.pnpm/ollama-ai-provider-v2@1.5.0_zod@4.1.12/node_modules/ollama-ai-provider-v2/dist/index.mjs
36926
+ // ../../node_modules/.pnpm/ollama-ai-provider-v2@1.5.0_zod@3.25.67/node_modules/ollama-ai-provider-v2/dist/index.mjs
35750
36927
  var import_provider55 = require("@ai-sdk/provider");
35751
36928
  var import_v490 = require("zod/v4");
35752
36929
  var import_v491 = require("zod/v4");
@@ -37344,6 +38521,111 @@ var LOG_LEVEL_NAMES = {
37344
38521
  2: "debug"
37345
38522
  };
37346
38523
 
38524
+ // lib/v3/types/public/page.ts
38525
+ init_consoleMessage();
38526
+ init_response();
38527
+
38528
+ // examples/external_clients/aisdk.ts
38529
+ var import_ai14 = require("ai");
38530
+ var AISdkClient2 = class extends LLMClient {
38531
+ constructor({ model }) {
38532
+ super(model.modelId);
38533
+ this.type = "aisdk";
38534
+ this.model = model;
38535
+ }
38536
+ createChatCompletion(_0) {
38537
+ return __async(this, arguments, function* ({
38538
+ options
38539
+ }) {
38540
+ var _a, _b, _c, _d, _e, _f;
38541
+ const formattedMessages = options.messages.map(
38542
+ (message) => {
38543
+ if (Array.isArray(message.content)) {
38544
+ if (message.role === "system") {
38545
+ const systemMessage = {
38546
+ role: "system",
38547
+ content: message.content.map((c) => "text" in c ? c.text : "").join("\n")
38548
+ };
38549
+ return systemMessage;
38550
+ }
38551
+ const contentParts = message.content.map((content) => {
38552
+ if ("image_url" in content) {
38553
+ const imageContent = {
38554
+ type: "image",
38555
+ image: content.image_url.url
38556
+ };
38557
+ return imageContent;
38558
+ } else {
38559
+ const textContent = {
38560
+ type: "text",
38561
+ text: content.text
38562
+ };
38563
+ return textContent;
38564
+ }
38565
+ });
38566
+ if (message.role === "user") {
38567
+ const userMessage = {
38568
+ role: "user",
38569
+ content: contentParts
38570
+ };
38571
+ return userMessage;
38572
+ } else {
38573
+ const textOnlyParts = contentParts.map((part) => ({
38574
+ type: "text",
38575
+ text: part.type === "image" ? "[Image]" : part.text
38576
+ }));
38577
+ const assistantMessage = {
38578
+ role: "assistant",
38579
+ content: textOnlyParts
38580
+ };
38581
+ return assistantMessage;
38582
+ }
38583
+ }
38584
+ return {
38585
+ role: message.role,
38586
+ content: message.content
38587
+ };
38588
+ }
38589
+ );
38590
+ if (options.response_model) {
38591
+ const response2 = yield (0, import_ai14.generateObject)({
38592
+ model: this.model,
38593
+ messages: formattedMessages,
38594
+ schema: options.response_model.schema
38595
+ });
38596
+ return {
38597
+ data: response2.object,
38598
+ usage: {
38599
+ prompt_tokens: (_a = response2.usage.inputTokens) != null ? _a : 0,
38600
+ completion_tokens: (_b = response2.usage.outputTokens) != null ? _b : 0,
38601
+ total_tokens: (_c = response2.usage.totalTokens) != null ? _c : 0
38602
+ }
38603
+ };
38604
+ }
38605
+ const tools = {};
38606
+ for (const rawTool of options.tools) {
38607
+ tools[rawTool.name] = {
38608
+ description: rawTool.description,
38609
+ inputSchema: rawTool.parameters
38610
+ };
38611
+ }
38612
+ const response = yield (0, import_ai14.generateText)({
38613
+ model: this.model,
38614
+ messages: formattedMessages,
38615
+ tools
38616
+ });
38617
+ return {
38618
+ data: response.text,
38619
+ usage: {
38620
+ prompt_tokens: (_d = response.usage.inputTokens) != null ? _d : 0,
38621
+ completion_tokens: (_e = response.usage.outputTokens) != null ? _e : 0,
38622
+ total_tokens: (_f = response.usage.totalTokens) != null ? _f : 0
38623
+ }
38624
+ };
38625
+ });
38626
+ }
38627
+ };
38628
+
37347
38629
  // lib/v3/understudy/context.ts
37348
38630
  init_logger();
37349
38631
 
@@ -38181,7 +39463,7 @@ function resolveModel(model) {
38181
39463
 
38182
39464
  // lib/v3/api.ts
38183
39465
  var import_fetch_cookie = __toESM(require("fetch-cookie"));
38184
- var import_zod22 = require("zod");
39466
+ var import_zod_to_json_schema7 = __toESM(require("zod-to-json-schema"));
38185
39467
  var StagehandAPIClient = class {
38186
39468
  constructor({ apiKey, projectId, logger }) {
38187
39469
  this.apiKey = apiKey;
@@ -38275,7 +39557,7 @@ var StagehandAPIClient = class {
38275
39557
  options,
38276
39558
  frameId
38277
39559
  }) {
38278
- const jsonSchema2 = zodSchema2 ? import_zod22.z.toJSONSchema(zodSchema2) : void 0;
39560
+ const jsonSchema2 = zodSchema2 ? (0, import_zod_to_json_schema7.default)(zodSchema2) : void 0;
38279
39561
  const args = {
38280
39562
  schema: jsonSchema2,
38281
39563
  instruction,
@@ -38351,6 +39633,85 @@ var StagehandAPIClient = class {
38351
39633
  return response;
38352
39634
  });
38353
39635
  }
39636
+ getReplayMetrics() {
39637
+ return __async(this, null, function* () {
39638
+ if (!this.sessionId) {
39639
+ throw new StagehandAPIError("sessionId is required to fetch metrics.");
39640
+ }
39641
+ const response = yield this.request(`/sessions/${this.sessionId}/replay`, {
39642
+ method: "GET"
39643
+ });
39644
+ if (response.status !== 200) {
39645
+ const errorText = yield response.text();
39646
+ this.logger({
39647
+ category: "api",
39648
+ message: `Failed to fetch metrics. Status ${response.status}: ${errorText}`,
39649
+ level: 0
39650
+ });
39651
+ throw new StagehandHttpError(
39652
+ `Failed to fetch metrics with status ${response.status}: ${errorText}`
39653
+ );
39654
+ }
39655
+ const data = yield response.json();
39656
+ if (!data.success) {
39657
+ throw new StagehandAPIError(
39658
+ `Failed to fetch metrics: ${data.error || "Unknown error"}`
39659
+ );
39660
+ }
39661
+ const apiData = data.data || {};
39662
+ const metrics = {
39663
+ actPromptTokens: 0,
39664
+ actCompletionTokens: 0,
39665
+ actInferenceTimeMs: 0,
39666
+ extractPromptTokens: 0,
39667
+ extractCompletionTokens: 0,
39668
+ extractInferenceTimeMs: 0,
39669
+ observePromptTokens: 0,
39670
+ observeCompletionTokens: 0,
39671
+ observeInferenceTimeMs: 0,
39672
+ agentPromptTokens: 0,
39673
+ agentCompletionTokens: 0,
39674
+ agentInferenceTimeMs: 0,
39675
+ totalPromptTokens: 0,
39676
+ totalCompletionTokens: 0,
39677
+ totalInferenceTimeMs: 0
39678
+ };
39679
+ const pages = apiData.pages || [];
39680
+ for (const page of pages) {
39681
+ const actions = page.actions || [];
39682
+ for (const action of actions) {
39683
+ const method = (action.method || "").toLowerCase();
39684
+ const tokenUsage = action.tokenUsage;
39685
+ if (tokenUsage) {
39686
+ const inputTokens = tokenUsage.inputTokens || 0;
39687
+ const outputTokens = tokenUsage.outputTokens || 0;
39688
+ const timeMs = tokenUsage.timeMs || 0;
39689
+ if (method === "act") {
39690
+ metrics.actPromptTokens += inputTokens;
39691
+ metrics.actCompletionTokens += outputTokens;
39692
+ metrics.actInferenceTimeMs += timeMs;
39693
+ } else if (method === "extract") {
39694
+ metrics.extractPromptTokens += inputTokens;
39695
+ metrics.extractCompletionTokens += outputTokens;
39696
+ metrics.extractInferenceTimeMs += timeMs;
39697
+ } else if (method === "observe") {
39698
+ metrics.observePromptTokens += inputTokens;
39699
+ metrics.observeCompletionTokens += outputTokens;
39700
+ metrics.observeInferenceTimeMs += timeMs;
39701
+ } else if (method === "agent") {
39702
+ metrics.agentPromptTokens += inputTokens;
39703
+ metrics.agentCompletionTokens += outputTokens;
39704
+ metrics.agentInferenceTimeMs += timeMs;
39705
+ }
39706
+ metrics.totalPromptTokens += inputTokens;
39707
+ metrics.totalCompletionTokens += outputTokens;
39708
+ metrics.totalInferenceTimeMs += timeMs;
39709
+ }
39710
+ }
39711
+ }
39712
+ return metrics;
39713
+ });
39714
+ }
38354
39715
  execute(_0) {
38355
39716
  return __async(this, arguments, function* ({
38356
39717
  method,
@@ -38531,15 +39892,15 @@ var _V3 = class _V3 {
38531
39892
  this.externalLogger = opts.logger;
38532
39893
  this.verbose = (_a = opts.verbose) != null ? _a : 1;
38533
39894
  this.instanceId = (_d = (_c = (_b = globalThis.crypto) == null ? void 0 : _b.randomUUID) == null ? void 0 : _c.call(_b)) != null ? _d : `${Date.now()}-${Math.floor(Math.random() * 1e9)}`;
38534
- this.stagehandLogger = new StagehandLogger(
38535
- {
38536
- usePino: !opts.disablePino,
38537
- pretty: true,
38538
- level: "info"
38539
- // Most permissive - filtering happens at instance level
38540
- },
38541
- opts.logger
38542
- );
39895
+ const loggerOptions = {
39896
+ pretty: true,
39897
+ level: "info"
39898
+ // Most permissive - filtering happens at instance level
39899
+ };
39900
+ if (opts.disablePino !== void 0) {
39901
+ loggerOptions.usePino = !opts.disablePino;
39902
+ }
39903
+ this.stagehandLogger = new StagehandLogger(loggerOptions, opts.logger);
38543
39904
  this.stagehandLogger.setVerbosity(this.verbose);
38544
39905
  try {
38545
39906
  if (this.externalLogger) {
@@ -38557,11 +39918,12 @@ var _V3 = class _V3 {
38557
39918
  this.logInferenceToFile = (_f = opts.logInferenceToFile) != null ? _f : false;
38558
39919
  this.llmProvider = new LLMProvider(this.logger);
38559
39920
  this.domSettleTimeoutMs = opts.domSettleTimeout;
38560
- this.disableAPI = (_g = opts.disableAPI) != null ? _g : true;
39921
+ this.disableAPI = (_g = opts.disableAPI) != null ? _g : false;
38561
39922
  const baseClientOptions = clientOptions ? __spreadValues({}, clientOptions) : {};
38562
39923
  if (opts.llmClient) {
38563
39924
  this.llmClient = opts.llmClient;
38564
39925
  this.modelClientOptions = baseClientOptions;
39926
+ this.disableAPI = true;
38565
39927
  } else {
38566
39928
  let apiKey = baseClientOptions.apiKey;
38567
39929
  if (!apiKey) {
@@ -38612,11 +39974,24 @@ var _V3 = class _V3 {
38612
39974
  this.opts = opts;
38613
39975
  _V3._instances.add(this);
38614
39976
  }
39977
+ get browserbaseSessionID() {
39978
+ return this.browserbaseSessionId;
39979
+ }
38615
39980
  /**
38616
39981
  * Async property for metrics so callers can `await v3.metrics`.
38617
- * Returning a Promise future-proofs async aggregation/storage.
39982
+ * When using API mode, fetches metrics from the API. Otherwise returns local metrics.
38618
39983
  */
38619
39984
  get metrics() {
39985
+ if (this.apiClient) {
39986
+ return this.apiClient.getReplayMetrics().catch((error) => {
39987
+ this.logger({
39988
+ category: "metrics",
39989
+ message: `Failed to fetch metrics from API: ${error}`,
39990
+ level: 0
39991
+ });
39992
+ return this.stagehandMetrics;
39993
+ });
39994
+ }
38620
39995
  return Promise.resolve(this.stagehandMetrics);
38621
39996
  }
38622
39997
  resolveLlmClient(model) {
@@ -38891,8 +40266,8 @@ var _V3 = class _V3 {
38891
40266
  let createdTemp = false;
38892
40267
  if (!userDataDir) {
38893
40268
  const base = import_path5.default.join(import_os2.default.tmpdir(), "stagehand-v3");
38894
- import_fs5.default.mkdirSync(base, { recursive: true });
38895
- userDataDir = import_fs5.default.mkdtempSync(import_path5.default.join(base, "profile-"));
40269
+ import_fs6.default.mkdirSync(base, { recursive: true });
40270
+ userDataDir = import_fs6.default.mkdtempSync(import_path5.default.join(base, "profile-"));
38896
40271
  createdTemp = true;
38897
40272
  }
38898
40273
  const defaults2 = [
@@ -39321,7 +40696,7 @@ var _V3 = class _V3 {
39321
40696
  }
39322
40697
  try {
39323
40698
  if (this.state.createdTempProfile && !this.state.preserveUserDataDir && this.state.userDataDir) {
39324
- import_fs5.default.rmSync(this.state.userDataDir, { recursive: true, force: true });
40699
+ import_fs6.default.rmSync(this.state.userDataDir, { recursive: true, force: true });
39325
40700
  }
39326
40701
  } catch (e) {
39327
40702
  }
@@ -39461,23 +40836,29 @@ var _V3 = class _V3 {
39461
40836
  * Mirrors the v2 Stagehand.agent() tool mode (no CUA provider here).
39462
40837
  */
39463
40838
  agent(options) {
39464
- var _a, _b, _c;
40839
+ var _a, _b;
39465
40840
  this.logger({
39466
40841
  category: "agent",
39467
- message: "Creating v3 agent instance with options:",
40842
+ message: `Creating v3 agent instance with options: ${JSON.stringify(options)}`,
39468
40843
  level: 1,
39469
- auxiliary: {
40844
+ auxiliary: __spreadValues({
39470
40845
  cua: { value: (options == null ? void 0 : options.cua) ? "true" : "false", type: "boolean" },
39471
- model: typeof (options == null ? void 0 : options.model) === "string" ? { value: options.model, type: "string" } : { value: options.model.modelName, type: "string" },
40846
+ model: (options == null ? void 0 : options.model) ? typeof (options == null ? void 0 : options.model) === "string" ? { value: options.model, type: "string" } : { value: options.model.modelName, type: "string" } : { value: this.llmClient.modelName, type: "string" },
39472
40847
  systemPrompt: { value: (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : "", type: "string" },
39473
- tools: { value: JSON.stringify((_b = options == null ? void 0 : options.tools) != null ? _b : {}), type: "object" },
40848
+ tools: { value: JSON.stringify((_b = options == null ? void 0 : options.tools) != null ? _b : {}), type: "object" }
40849
+ }, (options == null ? void 0 : options.integrations) && {
39474
40850
  integrations: {
39475
- value: JSON.stringify((_c = options == null ? void 0 : options.integrations) != null ? _c : []),
40851
+ value: JSON.stringify(options.integrations),
39476
40852
  type: "object"
39477
40853
  }
39478
- }
40854
+ })
39479
40855
  });
39480
40856
  if (options == null ? void 0 : options.cua) {
40857
+ if (((options == null ? void 0 : options.integrations) || (options == null ? void 0 : options.tools)) && !this.experimental) {
40858
+ throw new Error(
40859
+ "MCP integrations and custom tools are experimental. Enable experimental: true in V3 options."
40860
+ );
40861
+ }
39481
40862
  const modelToUse = (options == null ? void 0 : options.model) || __spreadValues({
39482
40863
  modelName: this.modelName
39483
40864
  }, this.modelClientOptions);
@@ -39575,9 +40956,9 @@ Do not ask follow up questions, the user will trust your judgement.`
39575
40956
  execute: (instructionOrOptions) => __async(this, null, function* () {
39576
40957
  return withInstanceLogContext(this.instanceId, () => __async(this, null, function* () {
39577
40958
  var _a2, _b2;
39578
- if ((options == null ? void 0 : options.integrations) && !this.experimental) {
40959
+ if (((options == null ? void 0 : options.integrations) || (options == null ? void 0 : options.tools)) && !this.experimental) {
39579
40960
  throw new Error(
39580
- "MCP integrations are experimental. Enable experimental: true in V3 options."
40961
+ "MCP integrations and custom tools are experimental. Enable experimental: true in V3 options."
39581
40962
  );
39582
40963
  }
39583
40964
  const tools = (options == null ? void 0 : options.integrations) ? yield resolveTools(options.integrations, options.tools) : (_a2 = options == null ? void 0 : options.tools) != null ? _a2 : {};
@@ -39661,13 +41042,13 @@ function isObserveResult(v) {
39661
41042
 
39662
41043
  // lib/v3Evaluator.ts
39663
41044
  var import_dotenv2 = __toESM(require("dotenv"));
39664
- var import_zod23 = require("zod");
41045
+ var import_v318 = require("zod/v3");
39665
41046
  import_dotenv2.default.config();
39666
- var EvaluationSchema = import_zod23.z.object({
39667
- evaluation: import_zod23.z.enum(["YES", "NO"]),
39668
- reasoning: import_zod23.z.string()
41047
+ var EvaluationSchema = import_v318.z.object({
41048
+ evaluation: import_v318.z.enum(["YES", "NO"]),
41049
+ reasoning: import_v318.z.string()
39669
41050
  });
39670
- var BatchEvaluationSchema = import_zod23.z.array(EvaluationSchema);
41051
+ var BatchEvaluationSchema = import_v318.z.array(EvaluationSchema);
39671
41052
  var V3Evaluator = class {
39672
41053
  constructor(v3, modelName, modelClientOptions) {
39673
41054
  this.silentLogger = () => {
@@ -39882,12 +41263,14 @@ I'm providing ${screenshots.length} screenshots showing the progression of the t
39882
41263
  };
39883
41264
  // Annotate the CommonJS export names for ESM import in node:
39884
41265
  0 && (module.exports = {
41266
+ AISdkClient,
39885
41267
  AVAILABLE_CUA_MODELS,
39886
41268
  AgentProvider,
39887
41269
  AgentScreenshotProviderError,
39888
41270
  AnnotatedScreenshotText,
39889
41271
  BrowserbaseSessionNotFoundError,
39890
41272
  CaptchaTimeoutError,
41273
+ ConsoleMessage,
39891
41274
  ContentFrameNotFoundError,
39892
41275
  CreateChatCompletionResponseError,
39893
41276
  ExperimentalApiConflictError,
@@ -39900,6 +41283,7 @@ I'm providing ${screenshots.length} screenshots showing the progression of the t
39900
41283
  MCPConnectionError,
39901
41284
  MissingEnvironmentVariableError,
39902
41285
  MissingLLMConfigurationError,
41286
+ Response,
39903
41287
  Stagehand,
39904
41288
  StagehandAPIError,
39905
41289
  StagehandAPIUnauthorizedError,