@mastra/agent-browser 0.1.0-alpha.0 → 0.1.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 +33 -0
- package/dist/index.cjs +58 -217
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -84
- package/dist/index.d.ts +18 -84
- package/dist/index.js +58 -217
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @mastra/agent-browser
|
|
2
2
|
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add browser automation support with screencast streaming, input injection, and thread isolation ([#14938](https://github.com/mastra-ai/mastra/pull/14938))
|
|
8
|
+
|
|
9
|
+
**New Features:**
|
|
10
|
+
- Browser tools for web automation (navigate, click, type, scroll, extract, etc.)
|
|
11
|
+
- Real-time screencast streaming via WebSocket
|
|
12
|
+
- Mouse and keyboard input injection
|
|
13
|
+
- Thread-scoped browser isolation (`scope: 'thread'`)
|
|
14
|
+
- State persistence and restoration across sessions
|
|
15
|
+
- Support for cloud providers (Browserbase, Browser-Use, Browserless)
|
|
16
|
+
|
|
17
|
+
**Configuration:**
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { AgentBrowser } from '@mastra/agent-browser';
|
|
21
|
+
|
|
22
|
+
const browser = new AgentBrowser({
|
|
23
|
+
headless: true,
|
|
24
|
+
scope: 'thread', // Each thread gets isolated browser
|
|
25
|
+
viewport: { width: 1280, height: 720 },
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const agent = mastra.getAgent('my-agent', { browser });
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- Updated dependencies [[`cb15509`](https://github.com/mastra-ai/mastra/commit/cb15509b58f6a83e11b765c945082afc027db972), [`81e4259`](https://github.com/mastra-ai/mastra/commit/81e425939b4ceeb4f586e9b6d89c3b1c1f2d2fe7), [`951b8a1`](https://github.com/mastra-ai/mastra/commit/951b8a1b5ef7e1474c59dc4f2b9fc1a8b1e508b6), [`80c5668`](https://github.com/mastra-ai/mastra/commit/80c5668e365470d3a96d3e953868fd7a643ff67c), [`3d478c1`](https://github.com/mastra-ai/mastra/commit/3d478c1e13f17b80f330ac49d7aa42ef929b93ff), [`2b4ea10`](https://github.com/mastra-ai/mastra/commit/2b4ea10b053e4ea1ab232d536933a4a3c4cba999), [`a0544f0`](https://github.com/mastra-ai/mastra/commit/a0544f0a1e6bd52ac12676228967c1938e43648d), [`6039f17`](https://github.com/mastra-ai/mastra/commit/6039f176f9c457304825ff1df8c83b8e457376c0), [`06b928d`](https://github.com/mastra-ai/mastra/commit/06b928dfc2f5630d023467476cc5919dfa858d0a), [`6a8d984`](https://github.com/mastra-ai/mastra/commit/6a8d9841f2933456ee1598099f488d742b600054), [`c8c86aa`](https://github.com/mastra-ai/mastra/commit/c8c86aa1458017fbd1c0776fdc0c520d129df8a6)]:
|
|
34
|
+
- @mastra/core@1.22.0
|
|
35
|
+
|
|
3
36
|
## 0.1.0-alpha.0
|
|
4
37
|
|
|
5
38
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -7,12 +7,9 @@ var zod = require('zod');
|
|
|
7
7
|
|
|
8
8
|
// src/agent-browser.ts
|
|
9
9
|
var AgentBrowserThreadManager = class extends browser.ThreadManager {
|
|
10
|
-
sharedManager = null;
|
|
11
10
|
browserConfig;
|
|
12
11
|
resolveCdpUrl;
|
|
13
12
|
onBrowserCreated;
|
|
14
|
-
/** Map of thread ID to dedicated browser manager (for 'thread' scope) */
|
|
15
|
-
threadBrowsers = /* @__PURE__ */ new Map();
|
|
16
13
|
constructor(config) {
|
|
17
14
|
super(config);
|
|
18
15
|
this.browserConfig = config.browserConfig;
|
|
@@ -20,25 +17,11 @@ var AgentBrowserThreadManager = class extends browser.ThreadManager {
|
|
|
20
17
|
this.onBrowserCreated = config.onBrowserCreated;
|
|
21
18
|
}
|
|
22
19
|
/**
|
|
23
|
-
*
|
|
20
|
+
* Get the page for a specific thread, creating session if needed.
|
|
24
21
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Clear the shared browser manager (called when browser disconnects).
|
|
30
|
-
*/
|
|
31
|
-
clearSharedManager() {
|
|
32
|
-
this.sharedManager = null;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Get the shared browser manager.
|
|
36
|
-
*/
|
|
37
|
-
getSharedManager() {
|
|
38
|
-
if (!this.sharedManager) {
|
|
39
|
-
throw new Error("Browser not launched");
|
|
40
|
-
}
|
|
41
|
-
return this.sharedManager;
|
|
22
|
+
async getPageForThread(threadId) {
|
|
23
|
+
const manager = await this.getManagerForThread(threadId);
|
|
24
|
+
return manager.getPage();
|
|
42
25
|
}
|
|
43
26
|
/**
|
|
44
27
|
* Create a new session for a thread.
|
|
@@ -69,7 +52,7 @@ var AgentBrowserThreadManager = class extends browser.ThreadManager {
|
|
|
69
52
|
throw error;
|
|
70
53
|
}
|
|
71
54
|
session.manager = manager;
|
|
72
|
-
this.
|
|
55
|
+
this.threadManagers.set(threadId, manager);
|
|
73
56
|
try {
|
|
74
57
|
if (savedState && savedState.tabs.length > 0) {
|
|
75
58
|
this.logger?.debug?.(`Restoring browser state for thread ${threadId}: ${savedState.tabs.length} tabs`);
|
|
@@ -77,7 +60,7 @@ var AgentBrowserThreadManager = class extends browser.ThreadManager {
|
|
|
77
60
|
}
|
|
78
61
|
this.onBrowserCreated?.(manager, threadId);
|
|
79
62
|
} catch (error) {
|
|
80
|
-
this.
|
|
63
|
+
this.threadManagers.delete(threadId);
|
|
81
64
|
session.manager = void 0;
|
|
82
65
|
try {
|
|
83
66
|
await manager.close();
|
|
@@ -117,13 +100,6 @@ var AgentBrowserThreadManager = class extends browser.ThreadManager {
|
|
|
117
100
|
this.logger?.warn?.(`Failed to restore browser state: ${error}`);
|
|
118
101
|
}
|
|
119
102
|
}
|
|
120
|
-
/**
|
|
121
|
-
* Switch to an existing session.
|
|
122
|
-
* For 'thread' scope, no switching needed - each thread has its own manager.
|
|
123
|
-
* For 'shared' scope, nothing to switch.
|
|
124
|
-
*/
|
|
125
|
-
async switchToSession(_session) {
|
|
126
|
-
}
|
|
127
103
|
/**
|
|
128
104
|
* Get the browser manager for a specific session.
|
|
129
105
|
*/
|
|
@@ -139,61 +115,15 @@ var AgentBrowserThreadManager = class extends browser.ThreadManager {
|
|
|
139
115
|
async doDestroySession(session) {
|
|
140
116
|
if (this.scope === "thread" && session.manager) {
|
|
141
117
|
await session.manager.close();
|
|
142
|
-
this.threadBrowsers.delete(session.threadId);
|
|
143
118
|
}
|
|
144
119
|
}
|
|
145
120
|
/**
|
|
146
121
|
* Destroy all sessions (called during browser close).
|
|
122
|
+
* doDestroySession handles closing individual browser managers.
|
|
147
123
|
*/
|
|
148
124
|
async destroyAllSessions() {
|
|
149
|
-
for (const [threadId, manager] of this.threadBrowsers) {
|
|
150
|
-
try {
|
|
151
|
-
await manager.close();
|
|
152
|
-
} catch {
|
|
153
|
-
this.logger?.debug?.(`Failed to close browser for thread: ${threadId}`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
this.threadBrowsers.clear();
|
|
157
125
|
await super.destroyAllSessions();
|
|
158
126
|
}
|
|
159
|
-
/**
|
|
160
|
-
* Check if any thread browsers are still running.
|
|
161
|
-
*/
|
|
162
|
-
hasActiveThreadBrowsers() {
|
|
163
|
-
return this.threadBrowsers.size > 0;
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Get the browser manager for an existing thread session without creating a new one.
|
|
167
|
-
* Returns null if no session exists for the thread.
|
|
168
|
-
*/
|
|
169
|
-
getExistingManagerForThread(threadId) {
|
|
170
|
-
if (this.scope === "thread") {
|
|
171
|
-
return this.threadBrowsers.get(threadId) ?? null;
|
|
172
|
-
}
|
|
173
|
-
return this.sharedManager;
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Clear all session tracking without closing browsers.
|
|
177
|
-
* Used when browsers have been externally closed and we just need to reset state.
|
|
178
|
-
*/
|
|
179
|
-
clearAllSessions() {
|
|
180
|
-
this.threadBrowsers.clear();
|
|
181
|
-
this.sessions.clear();
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Clear a specific thread's session without closing the browser.
|
|
185
|
-
* Used when a thread's browser has been externally closed.
|
|
186
|
-
* Preserves the browser state for potential restoration.
|
|
187
|
-
* @param threadId - The thread ID to clear
|
|
188
|
-
*/
|
|
189
|
-
clearSession(threadId) {
|
|
190
|
-
const session = this.sessions.get(threadId);
|
|
191
|
-
if (session?.browserState) {
|
|
192
|
-
this.savedBrowserStates.set(threadId, session.browserState);
|
|
193
|
-
}
|
|
194
|
-
this.threadBrowsers.delete(threadId);
|
|
195
|
-
this.sessions.delete(threadId);
|
|
196
|
-
}
|
|
197
127
|
};
|
|
198
128
|
var gotoInputSchema = zod.z.object({
|
|
199
129
|
url: zod.z.string().describe("The URL to navigate to"),
|
|
@@ -562,30 +492,18 @@ function createAgentBrowserTools(browser) {
|
|
|
562
492
|
}
|
|
563
493
|
|
|
564
494
|
// src/agent-browser.ts
|
|
565
|
-
var AgentBrowser = class
|
|
495
|
+
var AgentBrowser = class extends browser.MastraBrowser {
|
|
566
496
|
id;
|
|
567
497
|
name = "AgentBrowser";
|
|
568
498
|
provider = "vercel-labs/agent-browser";
|
|
569
|
-
/** Primary browser manager (for 'none' mode, also used as fallback) */
|
|
570
|
-
browserManager = null;
|
|
571
499
|
defaultTimeout = 3e4;
|
|
572
|
-
/** Active screencast streams per thread (for triggering reconnects on tab changes) */
|
|
573
|
-
activeScreencastStreams = /* @__PURE__ */ new Map();
|
|
574
|
-
/** Default key for shared scope */
|
|
575
|
-
static SHARED_STREAM_KEY = "__shared__";
|
|
576
500
|
constructor(config = {}) {
|
|
577
501
|
super(config);
|
|
578
502
|
this.id = `agent-browser-${Date.now()}`;
|
|
579
503
|
if (config.timeout) {
|
|
580
504
|
this.defaultTimeout = config.timeout;
|
|
581
505
|
}
|
|
582
|
-
|
|
583
|
-
if (config.cdpUrl && effectiveScope === "thread") {
|
|
584
|
-
this.logger.warn?.(
|
|
585
|
-
'Browser scope "thread" is not supported when connecting via cdpUrl. Falling back to "shared" (shared browser connection).'
|
|
586
|
-
);
|
|
587
|
-
effectiveScope = "shared";
|
|
588
|
-
}
|
|
506
|
+
const effectiveScope = config.cdpUrl ? config.scope ?? "shared" : config.scope ?? "thread";
|
|
589
507
|
this.threadManager = new AgentBrowserThreadManager({
|
|
590
508
|
scope: effectiveScope,
|
|
591
509
|
browserConfig: config,
|
|
@@ -602,13 +520,13 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
602
520
|
});
|
|
603
521
|
}
|
|
604
522
|
// ---------------------------------------------------------------------------
|
|
605
|
-
// Thread
|
|
523
|
+
// Thread Scope (delegated to ThreadManager)
|
|
606
524
|
// ---------------------------------------------------------------------------
|
|
607
525
|
/**
|
|
608
526
|
* Ensure browser is ready and thread session exists.
|
|
609
527
|
* Creates a new page/context for the current thread if needed.
|
|
610
528
|
*
|
|
611
|
-
* For '
|
|
529
|
+
* For 'thread' scope, we need to create the thread session BEFORE
|
|
612
530
|
* calling super.ensureReady() because the base class's ensureReady() will
|
|
613
531
|
* call checkBrowserAlive(), which needs at least one thread browser to exist.
|
|
614
532
|
*/
|
|
@@ -626,7 +544,7 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
626
544
|
}
|
|
627
545
|
/**
|
|
628
546
|
* Get the browser manager for the current thread.
|
|
629
|
-
* Delegates to ThreadManager for
|
|
547
|
+
* Delegates to ThreadManager for scope handling.
|
|
630
548
|
*/
|
|
631
549
|
async getManagerForThread(threadId) {
|
|
632
550
|
const effectiveThreadId = threadId ?? this.getCurrentThread();
|
|
@@ -639,33 +557,17 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
639
557
|
}
|
|
640
558
|
return this.threadManager.getManagerForThread(effectiveThreadId);
|
|
641
559
|
}
|
|
642
|
-
/**
|
|
643
|
-
* Get the page for a specific thread.
|
|
644
|
-
* For thread-isolated modes, ensures we're on the correct context/page.
|
|
645
|
-
*/
|
|
646
|
-
async getPageForThread(threadId) {
|
|
647
|
-
const manager = await this.getManagerForThread(threadId);
|
|
648
|
-
return manager.getPage();
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* Close a specific thread's browser session.
|
|
652
|
-
* Delegates to ThreadManager and notifies registered callbacks.
|
|
653
|
-
*/
|
|
654
|
-
async closeThreadSession(threadId) {
|
|
655
|
-
await this.threadManager.destroySession(threadId);
|
|
656
|
-
this.notifyBrowserClosed(threadId);
|
|
657
|
-
}
|
|
658
560
|
// ---------------------------------------------------------------------------
|
|
659
561
|
// Lifecycle
|
|
660
562
|
// ---------------------------------------------------------------------------
|
|
661
563
|
async doLaunch() {
|
|
662
564
|
const scope = this.threadManager.getScope();
|
|
663
565
|
if (scope === "thread") {
|
|
664
|
-
this.
|
|
665
|
-
this.threadManager.setSharedManager(this.
|
|
566
|
+
this.sharedManager = new agentBrowser.BrowserManager();
|
|
567
|
+
this.threadManager.setSharedManager(this.sharedManager);
|
|
666
568
|
return;
|
|
667
569
|
}
|
|
668
|
-
this.
|
|
570
|
+
this.sharedManager = new agentBrowser.BrowserManager();
|
|
669
571
|
const localConfig = this.config;
|
|
670
572
|
const launchOptions = {
|
|
671
573
|
headless: localConfig.headless ?? true,
|
|
@@ -674,15 +576,15 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
674
576
|
if (localConfig.cdpUrl) {
|
|
675
577
|
launchOptions.cdpUrl = await this.resolveCdpUrl(localConfig.cdpUrl);
|
|
676
578
|
}
|
|
677
|
-
await this.
|
|
678
|
-
this.threadManager.setSharedManager(this.
|
|
679
|
-
this.
|
|
579
|
+
await this.sharedManager.launch(launchOptions);
|
|
580
|
+
this.threadManager.setSharedManager(this.sharedManager);
|
|
581
|
+
this.setupCloseListenerForSharedScope(this.sharedManager);
|
|
680
582
|
}
|
|
681
583
|
/**
|
|
682
|
-
* Set up close event listeners for '
|
|
584
|
+
* Set up close event listeners for 'shared' scope browser.
|
|
683
585
|
* This handles the case where the shared browser is closed externally.
|
|
684
586
|
*/
|
|
685
|
-
|
|
587
|
+
setupCloseListenerForSharedScope(manager) {
|
|
686
588
|
try {
|
|
687
589
|
let disconnectHandled = false;
|
|
688
590
|
const handleDisconnect = () => {
|
|
@@ -710,10 +612,10 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
710
612
|
await this.threadManager.destroyAllSessions();
|
|
711
613
|
this.setCurrentThread(void 0);
|
|
712
614
|
const scope = this.threadManager.getScope();
|
|
713
|
-
if (scope === "shared" && this.
|
|
714
|
-
await this.
|
|
615
|
+
if (scope === "shared" && this.sharedManager) {
|
|
616
|
+
await this.sharedManager.close();
|
|
715
617
|
}
|
|
716
|
-
this.
|
|
618
|
+
this.sharedManager = null;
|
|
717
619
|
}
|
|
718
620
|
/**
|
|
719
621
|
* Check if the browser is still alive by verifying the page is connected.
|
|
@@ -722,13 +624,13 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
722
624
|
async checkBrowserAlive() {
|
|
723
625
|
const scope = this.threadManager.getScope();
|
|
724
626
|
if (scope === "thread") {
|
|
725
|
-
return this.threadManager.
|
|
627
|
+
return this.threadManager.hasActiveThreadManagers();
|
|
726
628
|
}
|
|
727
|
-
if (!this.
|
|
629
|
+
if (!this.sharedManager) {
|
|
728
630
|
return false;
|
|
729
631
|
}
|
|
730
632
|
try {
|
|
731
|
-
const page = this.
|
|
633
|
+
const page = this.sharedManager.getPage();
|
|
732
634
|
const url = page.url();
|
|
733
635
|
if (url && url !== "about:blank") {
|
|
734
636
|
const state = await this.getBrowserState();
|
|
@@ -767,28 +669,21 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
767
669
|
async getPage(explicitThreadId) {
|
|
768
670
|
const scope = this.getScope();
|
|
769
671
|
const threadId = explicitThreadId ?? this.getCurrentThread();
|
|
770
|
-
if (scope === "thread"
|
|
771
|
-
return this.getPageForThread(threadId);
|
|
672
|
+
if (scope === "thread") {
|
|
673
|
+
return this.threadManager.getPageForThread(threadId);
|
|
772
674
|
}
|
|
773
|
-
if (!this.
|
|
774
|
-
return this.
|
|
675
|
+
if (!this.sharedManager) throw new Error("Browser not launched");
|
|
676
|
+
return this.sharedManager.getPage();
|
|
775
677
|
}
|
|
776
678
|
/**
|
|
777
|
-
*
|
|
778
|
-
*
|
|
779
|
-
* For 'shared' scope, notifies all callbacks.
|
|
679
|
+
* Get the active page for a thread (implements abstract method from base class).
|
|
680
|
+
* Returns null if no page is available, unlike getPage which throws.
|
|
780
681
|
*/
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
this.logger.debug?.(`Cleared browser session for thread: ${threadId}`);
|
|
787
|
-
this.notifyBrowserClosed(threadId);
|
|
788
|
-
} else {
|
|
789
|
-
this.browserManager = null;
|
|
790
|
-
this.threadManager.clearSharedManager();
|
|
791
|
-
super.handleBrowserDisconnected();
|
|
682
|
+
async getActivePage(threadId) {
|
|
683
|
+
try {
|
|
684
|
+
return await this.getPage(threadId);
|
|
685
|
+
} catch {
|
|
686
|
+
return null;
|
|
792
687
|
}
|
|
793
688
|
}
|
|
794
689
|
/**
|
|
@@ -819,15 +714,6 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
819
714
|
} catch {
|
|
820
715
|
}
|
|
821
716
|
}
|
|
822
|
-
/**
|
|
823
|
-
* Handle browser disconnection for a specific thread.
|
|
824
|
-
* Called when a thread's browser is closed externally.
|
|
825
|
-
*/
|
|
826
|
-
handleThreadBrowserDisconnected(threadId) {
|
|
827
|
-
this.threadManager.clearSession(threadId);
|
|
828
|
-
this.logger.debug?.(`Cleared browser session for thread: ${threadId}`);
|
|
829
|
-
this.notifyBrowserClosed(threadId);
|
|
830
|
-
}
|
|
831
717
|
/**
|
|
832
718
|
* Create an error response from an exception.
|
|
833
719
|
* Extends base class to add agent-browser specific error handling.
|
|
@@ -951,6 +837,16 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
951
837
|
return null;
|
|
952
838
|
}
|
|
953
839
|
}
|
|
840
|
+
/**
|
|
841
|
+
* Get browser state for a thread (implements abstract method from base class).
|
|
842
|
+
* Sync version that uses existing manager lookup without creating sessions.
|
|
843
|
+
*/
|
|
844
|
+
getBrowserStateForThread(threadId) {
|
|
845
|
+
const effectiveThreadId = threadId ?? this.getCurrentThread() ?? browser.DEFAULT_THREAD_ID;
|
|
846
|
+
const manager = this.threadManager.getExistingManagerForThread(effectiveThreadId);
|
|
847
|
+
if (!manager) return null;
|
|
848
|
+
return this.getBrowserStateForManager(manager);
|
|
849
|
+
}
|
|
954
850
|
/**
|
|
955
851
|
* Get browser state from a specific manager instance.
|
|
956
852
|
*/
|
|
@@ -990,29 +886,6 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
990
886
|
return 0;
|
|
991
887
|
}
|
|
992
888
|
}
|
|
993
|
-
/**
|
|
994
|
-
* Update the browser state in the thread session.
|
|
995
|
-
* Called on navigation, tab open/close to keep state fresh.
|
|
996
|
-
*/
|
|
997
|
-
updateSessionBrowserState(threadId) {
|
|
998
|
-
try {
|
|
999
|
-
const effectiveThreadId = threadId ?? this.getCurrentThread() ?? browser.DEFAULT_THREAD_ID;
|
|
1000
|
-
const scope = this.threadManager.getScope();
|
|
1001
|
-
let manager = null;
|
|
1002
|
-
if (scope === "thread") {
|
|
1003
|
-
manager = this.threadManager.getExistingManagerForThread(effectiveThreadId);
|
|
1004
|
-
} else {
|
|
1005
|
-
manager = this.browserManager;
|
|
1006
|
-
}
|
|
1007
|
-
if (manager) {
|
|
1008
|
-
const state = this.getBrowserStateForManager(manager);
|
|
1009
|
-
if (state) {
|
|
1010
|
-
this.threadManager.updateBrowserState(effectiveThreadId, state);
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
} catch {
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
889
|
// ---------------------------------------------------------------------------
|
|
1017
890
|
// 1. browser_goto - Navigate to URL
|
|
1018
891
|
// ---------------------------------------------------------------------------
|
|
@@ -1435,10 +1308,10 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
1435
1308
|
);
|
|
1436
1309
|
}
|
|
1437
1310
|
await browser.switchTo(input.index);
|
|
1438
|
-
await this.
|
|
1311
|
+
await this.reconnectScreencastForThread(threadId, "tab switch");
|
|
1439
1312
|
const page = browser.getPage();
|
|
1440
1313
|
const pageUrl = page.url();
|
|
1441
|
-
const streamKey = this.getStreamKey(
|
|
1314
|
+
const streamKey = this.getStreamKey(threadId);
|
|
1442
1315
|
const stream = this.activeScreencastStreams.get(streamKey);
|
|
1443
1316
|
if (pageUrl && stream?.isActive()) {
|
|
1444
1317
|
stream.emitUrl(pageUrl);
|
|
@@ -1461,7 +1334,7 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
1461
1334
|
);
|
|
1462
1335
|
}
|
|
1463
1336
|
await browser.closeTab(input.index);
|
|
1464
|
-
await this.
|
|
1337
|
+
await this.reconnectScreencastForThread(threadId, "tab close");
|
|
1465
1338
|
this.updateSessionBrowserState(threadId);
|
|
1466
1339
|
const tabsList = await browser.listTabs?.() ?? [];
|
|
1467
1340
|
return {
|
|
@@ -1557,47 +1430,15 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
1557
1430
|
// ---------------------------------------------------------------------------
|
|
1558
1431
|
// Screencast (for Studio live view)
|
|
1559
1432
|
// ---------------------------------------------------------------------------
|
|
1560
|
-
/**
|
|
1561
|
-
* Get the stream key for a thread (or shared key for shared scope).
|
|
1562
|
-
*/
|
|
1563
|
-
getStreamKey(threadId) {
|
|
1564
|
-
return threadId || _AgentBrowser.SHARED_STREAM_KEY;
|
|
1565
|
-
}
|
|
1566
|
-
/**
|
|
1567
|
-
* Trigger a screencast reconnect after tab changes.
|
|
1568
|
-
* Called internally when tabs are switched or closed.
|
|
1569
|
-
*/
|
|
1570
|
-
async reconnectScreencast(_reason) {
|
|
1571
|
-
const threadId = this.getCurrentThread();
|
|
1572
|
-
const streamKey = this.getStreamKey(threadId);
|
|
1573
|
-
const stream = this.activeScreencastStreams.get(streamKey);
|
|
1574
|
-
if (stream?.isActive()) {
|
|
1575
|
-
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
1576
|
-
if (stream?.isActive()) {
|
|
1577
|
-
try {
|
|
1578
|
-
await stream.reconnect();
|
|
1579
|
-
const manager = this.threadManager.getExistingManagerForThread(threadId) ?? this.browserManager;
|
|
1580
|
-
const activePage = manager?.getPage();
|
|
1581
|
-
if (activePage) {
|
|
1582
|
-
const url = activePage.url();
|
|
1583
|
-
if (url) {
|
|
1584
|
-
stream.emitUrl(url);
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
} catch (err) {
|
|
1588
|
-
console.error("[AgentBrowser] Failed to reconnect screencast:", err);
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
1433
|
async startScreencast(_options) {
|
|
1594
|
-
const
|
|
1434
|
+
const requestedThreadId = _options?.threadId;
|
|
1435
|
+
const effectiveThreadId = this.getScope() === "thread" ? requestedThreadId ?? this.getCurrentThread() ?? browser.DEFAULT_THREAD_ID : requestedThreadId;
|
|
1595
1436
|
let browserManager;
|
|
1596
|
-
if (this.getScope() === "thread"
|
|
1597
|
-
browserManager = await this.getManagerForThread(
|
|
1437
|
+
if (this.getScope() === "thread") {
|
|
1438
|
+
browserManager = await this.getManagerForThread(effectiveThreadId);
|
|
1598
1439
|
} else {
|
|
1599
|
-
if (!this.
|
|
1600
|
-
browserManager = this.
|
|
1440
|
+
if (!this.sharedManager) throw new Error("Browser not launched");
|
|
1441
|
+
browserManager = this.sharedManager;
|
|
1601
1442
|
}
|
|
1602
1443
|
const provider = {
|
|
1603
1444
|
getCdpSession: async () => {
|
|
@@ -1611,7 +1452,7 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
1611
1452
|
isBrowserRunning: () => browserManager.isLaunched()
|
|
1612
1453
|
};
|
|
1613
1454
|
const stream = new browser.ScreencastStreamImpl(provider, _options);
|
|
1614
|
-
const streamKey = this.getStreamKey(
|
|
1455
|
+
const streamKey = this.getStreamKey(effectiveThreadId);
|
|
1615
1456
|
this.activeScreencastStreams.set(streamKey, stream);
|
|
1616
1457
|
const context = browserManager.getContext();
|
|
1617
1458
|
if (context) {
|
|
@@ -1630,7 +1471,7 @@ var AgentBrowser = class _AgentBrowser extends browser.MastraBrowser {
|
|
|
1630
1471
|
const onFrameNavigated = (frame) => {
|
|
1631
1472
|
if (!frame.parentFrame()) {
|
|
1632
1473
|
stream.emitUrl(frame.url());
|
|
1633
|
-
this.updateSessionBrowserState(
|
|
1474
|
+
this.updateSessionBrowserState(effectiveThreadId);
|
|
1634
1475
|
}
|
|
1635
1476
|
};
|
|
1636
1477
|
page.on("framenavigated", onFrameNavigated);
|