@mastra/stagehand 0.3.2 → 0.3.3-alpha.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @mastra/stagehand
2
2
 
3
+ ## 0.3.3-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed browser close tracking so agent-initiated Stagehand shutdowns are reported accurately. ([#21452](https://github.com/mastra-ai/mastra/pull/21452))
8
+
9
+ - Updated dependencies [[`59d8898`](https://github.com/mastra-ai/mastra/commit/59d8898c8cb48b342fe5bcb5eee803cc8cc95060), [`a40f915`](https://github.com/mastra-ai/mastra/commit/a40f9157690d89ef13ce825cc88e30be581de5d4)]:
10
+ - @mastra/core@1.59.0-alpha.5
11
+
3
12
  ## 0.3.2
4
13
 
5
14
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -231,14 +231,17 @@ function createCloseTool(browser) {
231
231
  inputSchema: closeInputSchema,
232
232
  execute: async (_input, { agent }) => {
233
233
  const threadId = agent?.threadId;
234
+ browser.setCurrentThread(threadId);
234
235
  if (browser.getScope() !== "shared") {
235
236
  if (!threadId) throw new Error("stagehand_close requires agent.threadId when browser scope is not shared");
237
+ browser.markBrowserCloseReason("agent", threadId);
236
238
  await browser.closeThreadSession(threadId);
237
239
  return {
238
240
  success: true,
239
241
  hint: "Thread's browser session closed. A new session will be created on next use."
240
242
  };
241
243
  }
244
+ browser.markBrowserCloseReason("agent");
242
245
  await browser.close();
243
246
  return {
244
247
  success: true,
@@ -442,6 +445,7 @@ var StagehandBrowser = class extends _mastra_core_browser.MastraBrowser {
442
445
  stagehandConfig;
443
446
  /** Debounce timers per thread for tab change reconnection */
444
447
  tabChangeDebounceTimers = /* @__PURE__ */ new Map();
448
+ pendingCloseReasons = /* @__PURE__ */ new Map();
445
449
  constructor(config = {}) {
446
450
  super(config);
447
451
  this.id = `stagehand-${Date.now()}`;
@@ -521,6 +525,7 @@ var StagehandBrowser = class extends _mastra_core_browser.MastraBrowser {
521
525
  return stagehand;
522
526
  }
523
527
  async doLaunch() {
528
+ this.pendingCloseReasons.clear();
524
529
  const scope = this.getScope();
525
530
  this.threadManager.setCreateStagehand(() => this.createStagehandInstance());
526
531
  if (scope === "thread") return;
@@ -548,6 +553,7 @@ var StagehandBrowser = class extends _mastra_core_browser.MastraBrowser {
548
553
  const handleDisconnect = () => {
549
554
  if (disconnectHandled) return;
550
555
  disconnectHandled = true;
556
+ this.rememberClosedBrowserState(stagehand, "user", threadId);
551
557
  onDisconnect();
552
558
  };
553
559
  try {
@@ -588,9 +594,30 @@ var StagehandBrowser = class extends _mastra_core_browser.MastraBrowser {
588
594
  this.patchExitType();
589
595
  }
590
596
  async closeThreadSession(threadId) {
597
+ const stagehand = this.threadManager.getExistingManagerForThread(threadId);
598
+ if (stagehand) this.rememberClosedBrowserState(stagehand, "agent", threadId);
591
599
  await super.closeThreadSession(threadId);
592
600
  this.patchExitType();
593
601
  }
602
+ browserStateKey(threadId) {
603
+ return threadId ?? this.getCurrentThread() ?? _mastra_core_browser.DEFAULT_THREAD_ID;
604
+ }
605
+ markBrowserCloseReason(reason, threadId) {
606
+ this.pendingCloseReasons.set(this.browserStateKey(threadId), reason);
607
+ }
608
+ getCloseReason(threadId) {
609
+ return this.pendingCloseReasons.get(this.browserStateKey(threadId)) ?? this.pendingCloseReasons.get(_mastra_core_browser.DEFAULT_THREAD_ID);
610
+ }
611
+ rememberClosedBrowserState(stagehand, reason, threadId) {
612
+ const state = this.getBrowserStateFromStagehand(stagehand, threadId);
613
+ if (!state || state.tabs.length === 0) return;
614
+ const closedState = {
615
+ ...state,
616
+ closeReason: this.getCloseReason(threadId) ?? reason
617
+ };
618
+ if (threadId) this.threadManager.updateBrowserState(threadId, closedState);
619
+ else this.lastBrowserState = closedState;
620
+ }
594
621
  patchExitType() {
595
622
  if (!this.config.profile) return;
596
623
  patchProfileExitType(this.config.profile, this.logger);
@@ -947,9 +974,9 @@ var StagehandBrowser = class extends _mastra_core_browser.MastraBrowser {
947
974
  if (scope === "thread" && effectiveThreadId) {
948
975
  const stagehand = this.threadManager.getExistingManagerForThread(effectiveThreadId);
949
976
  if (!stagehand) return null;
950
- return this.getBrowserStateFromStagehand(stagehand);
977
+ return this.getBrowserStateFromStagehand(stagehand, effectiveThreadId);
951
978
  }
952
- return this.getBrowserStateFromStagehand(this.sharedManager);
979
+ return this.getBrowserStateFromStagehand(this.sharedManager, effectiveThreadId);
953
980
  } catch {
954
981
  return null;
955
982
  }
@@ -961,23 +988,26 @@ var StagehandBrowser = class extends _mastra_core_browser.MastraBrowser {
961
988
  getBrowserStateForThread(threadId) {
962
989
  const effectiveThreadId = threadId ?? this.getCurrentThread() ?? _mastra_core_browser.DEFAULT_THREAD_ID;
963
990
  const stagehand = this.threadManager.getExistingManagerForThread(effectiveThreadId);
964
- return this.getBrowserStateFromStagehand(stagehand);
991
+ return this.getBrowserStateFromStagehand(stagehand, effectiveThreadId);
965
992
  }
966
993
  /**
967
994
  * Get browser state from a specific Stagehand instance.
968
995
  */
969
- getBrowserStateFromStagehand(stagehand) {
996
+ getBrowserStateFromStagehand(stagehand, threadId) {
970
997
  if (!stagehand?.context) return null;
971
998
  try {
972
999
  const pages = stagehand.context.pages();
973
1000
  const activePage = stagehand.context.activePage();
974
1001
  let activeIndex = 0;
1002
+ const tabs = pages.map((page, index) => {
1003
+ if (page === activePage) activeIndex = index;
1004
+ return { url: page.url() };
1005
+ });
1006
+ const closeReason = this.getCloseReason(threadId);
975
1007
  return {
976
- tabs: pages.map((page, index) => {
977
- if (page === activePage) activeIndex = index;
978
- return { url: page.url() };
979
- }),
980
- activeTabIndex: activeIndex
1008
+ tabs,
1009
+ activeTabIndex: activeIndex,
1010
+ ...closeReason ? { closeReason } : {}
981
1011
  };
982
1012
  } catch {
983
1013
  return null;