@mastra/agent-browser 0.1.0-alpha.0 → 0.2.0-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 +46 -0
- package/README.md +138 -0
- package/dist/index.cjs +122 -219
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -85
- package/dist/index.d.ts +58 -85
- package/dist/index.js +122 -220
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -5,12 +5,9 @@ import { z } from 'zod';
|
|
|
5
5
|
|
|
6
6
|
// src/agent-browser.ts
|
|
7
7
|
var AgentBrowserThreadManager = class extends ThreadManager {
|
|
8
|
-
sharedManager = null;
|
|
9
8
|
browserConfig;
|
|
10
9
|
resolveCdpUrl;
|
|
11
10
|
onBrowserCreated;
|
|
12
|
-
/** Map of thread ID to dedicated browser manager (for 'thread' scope) */
|
|
13
|
-
threadBrowsers = /* @__PURE__ */ new Map();
|
|
14
11
|
constructor(config) {
|
|
15
12
|
super(config);
|
|
16
13
|
this.browserConfig = config.browserConfig;
|
|
@@ -18,25 +15,11 @@ var AgentBrowserThreadManager = class extends ThreadManager {
|
|
|
18
15
|
this.onBrowserCreated = config.onBrowserCreated;
|
|
19
16
|
}
|
|
20
17
|
/**
|
|
21
|
-
*
|
|
18
|
+
* Get the page for a specific thread, creating session if needed.
|
|
22
19
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Clear the shared browser manager (called when browser disconnects).
|
|
28
|
-
*/
|
|
29
|
-
clearSharedManager() {
|
|
30
|
-
this.sharedManager = null;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Get the shared browser manager.
|
|
34
|
-
*/
|
|
35
|
-
getSharedManager() {
|
|
36
|
-
if (!this.sharedManager) {
|
|
37
|
-
throw new Error("Browser not launched");
|
|
38
|
-
}
|
|
39
|
-
return this.sharedManager;
|
|
20
|
+
async getPageForThread(threadId) {
|
|
21
|
+
const manager = await this.getManagerForThread(threadId);
|
|
22
|
+
return manager.getPage();
|
|
40
23
|
}
|
|
41
24
|
/**
|
|
42
25
|
* Create a new session for a thread.
|
|
@@ -52,7 +35,10 @@ var AgentBrowserThreadManager = class extends ThreadManager {
|
|
|
52
35
|
const manager = new BrowserManager();
|
|
53
36
|
const launchOptions = {
|
|
54
37
|
headless: this.browserConfig.headless ?? true,
|
|
55
|
-
viewport: this.browserConfig.viewport
|
|
38
|
+
viewport: this.browserConfig.viewport,
|
|
39
|
+
profile: this.browserConfig.profile,
|
|
40
|
+
executablePath: this.browserConfig.executablePath,
|
|
41
|
+
storageState: this.browserConfig.storageState
|
|
56
42
|
};
|
|
57
43
|
if (this.browserConfig.cdpUrl && this.resolveCdpUrl) {
|
|
58
44
|
launchOptions.cdpUrl = await this.resolveCdpUrl(this.browserConfig.cdpUrl);
|
|
@@ -67,7 +53,7 @@ var AgentBrowserThreadManager = class extends ThreadManager {
|
|
|
67
53
|
throw error;
|
|
68
54
|
}
|
|
69
55
|
session.manager = manager;
|
|
70
|
-
this.
|
|
56
|
+
this.threadManagers.set(threadId, manager);
|
|
71
57
|
try {
|
|
72
58
|
if (savedState && savedState.tabs.length > 0) {
|
|
73
59
|
this.logger?.debug?.(`Restoring browser state for thread ${threadId}: ${savedState.tabs.length} tabs`);
|
|
@@ -75,7 +61,7 @@ var AgentBrowserThreadManager = class extends ThreadManager {
|
|
|
75
61
|
}
|
|
76
62
|
this.onBrowserCreated?.(manager, threadId);
|
|
77
63
|
} catch (error) {
|
|
78
|
-
this.
|
|
64
|
+
this.threadManagers.delete(threadId);
|
|
79
65
|
session.manager = void 0;
|
|
80
66
|
try {
|
|
81
67
|
await manager.close();
|
|
@@ -115,13 +101,6 @@ var AgentBrowserThreadManager = class extends ThreadManager {
|
|
|
115
101
|
this.logger?.warn?.(`Failed to restore browser state: ${error}`);
|
|
116
102
|
}
|
|
117
103
|
}
|
|
118
|
-
/**
|
|
119
|
-
* Switch to an existing session.
|
|
120
|
-
* For 'thread' scope, no switching needed - each thread has its own manager.
|
|
121
|
-
* For 'shared' scope, nothing to switch.
|
|
122
|
-
*/
|
|
123
|
-
async switchToSession(_session) {
|
|
124
|
-
}
|
|
125
104
|
/**
|
|
126
105
|
* Get the browser manager for a specific session.
|
|
127
106
|
*/
|
|
@@ -137,61 +116,15 @@ var AgentBrowserThreadManager = class extends ThreadManager {
|
|
|
137
116
|
async doDestroySession(session) {
|
|
138
117
|
if (this.scope === "thread" && session.manager) {
|
|
139
118
|
await session.manager.close();
|
|
140
|
-
this.threadBrowsers.delete(session.threadId);
|
|
141
119
|
}
|
|
142
120
|
}
|
|
143
121
|
/**
|
|
144
122
|
* Destroy all sessions (called during browser close).
|
|
123
|
+
* doDestroySession handles closing individual browser managers.
|
|
145
124
|
*/
|
|
146
125
|
async destroyAllSessions() {
|
|
147
|
-
for (const [threadId, manager] of this.threadBrowsers) {
|
|
148
|
-
try {
|
|
149
|
-
await manager.close();
|
|
150
|
-
} catch {
|
|
151
|
-
this.logger?.debug?.(`Failed to close browser for thread: ${threadId}`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
this.threadBrowsers.clear();
|
|
155
126
|
await super.destroyAllSessions();
|
|
156
127
|
}
|
|
157
|
-
/**
|
|
158
|
-
* Check if any thread browsers are still running.
|
|
159
|
-
*/
|
|
160
|
-
hasActiveThreadBrowsers() {
|
|
161
|
-
return this.threadBrowsers.size > 0;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Get the browser manager for an existing thread session without creating a new one.
|
|
165
|
-
* Returns null if no session exists for the thread.
|
|
166
|
-
*/
|
|
167
|
-
getExistingManagerForThread(threadId) {
|
|
168
|
-
if (this.scope === "thread") {
|
|
169
|
-
return this.threadBrowsers.get(threadId) ?? null;
|
|
170
|
-
}
|
|
171
|
-
return this.sharedManager;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Clear all session tracking without closing browsers.
|
|
175
|
-
* Used when browsers have been externally closed and we just need to reset state.
|
|
176
|
-
*/
|
|
177
|
-
clearAllSessions() {
|
|
178
|
-
this.threadBrowsers.clear();
|
|
179
|
-
this.sessions.clear();
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Clear a specific thread's session without closing the browser.
|
|
183
|
-
* Used when a thread's browser has been externally closed.
|
|
184
|
-
* Preserves the browser state for potential restoration.
|
|
185
|
-
* @param threadId - The thread ID to clear
|
|
186
|
-
*/
|
|
187
|
-
clearSession(threadId) {
|
|
188
|
-
const session = this.sessions.get(threadId);
|
|
189
|
-
if (session?.browserState) {
|
|
190
|
-
this.savedBrowserStates.set(threadId, session.browserState);
|
|
191
|
-
}
|
|
192
|
-
this.threadBrowsers.delete(threadId);
|
|
193
|
-
this.sessions.delete(threadId);
|
|
194
|
-
}
|
|
195
128
|
};
|
|
196
129
|
var gotoInputSchema = z.object({
|
|
197
130
|
url: z.string().describe("The URL to navigate to"),
|
|
@@ -559,31 +492,43 @@ function createAgentBrowserTools(browser) {
|
|
|
559
492
|
};
|
|
560
493
|
}
|
|
561
494
|
|
|
495
|
+
// src/utils.ts
|
|
496
|
+
async function getBrowserPid(manager) {
|
|
497
|
+
try {
|
|
498
|
+
let browser = manager.getBrowser();
|
|
499
|
+
if (!browser) {
|
|
500
|
+
const ctx = manager.getContext();
|
|
501
|
+
browser = ctx?.browser?.() ?? null;
|
|
502
|
+
}
|
|
503
|
+
if (!browser) return void 0;
|
|
504
|
+
const cdp = await browser.newBrowserCDPSession();
|
|
505
|
+
try {
|
|
506
|
+
const info = await cdp.send("SystemInfo.getProcessInfo");
|
|
507
|
+
const browserProcess = info.processInfo?.find((p) => p.type === "browser");
|
|
508
|
+
return browserProcess?.id;
|
|
509
|
+
} finally {
|
|
510
|
+
await cdp.detach().catch(() => void 0);
|
|
511
|
+
}
|
|
512
|
+
} catch {
|
|
513
|
+
return void 0;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
562
517
|
// src/agent-browser.ts
|
|
563
|
-
var AgentBrowser = class
|
|
518
|
+
var AgentBrowser = class extends MastraBrowser {
|
|
564
519
|
id;
|
|
565
520
|
name = "AgentBrowser";
|
|
566
521
|
provider = "vercel-labs/agent-browser";
|
|
567
|
-
/** Primary browser manager (for 'none' mode, also used as fallback) */
|
|
568
|
-
browserManager = null;
|
|
569
522
|
defaultTimeout = 3e4;
|
|
570
|
-
/**
|
|
571
|
-
|
|
572
|
-
/** Default key for shared scope */
|
|
573
|
-
static SHARED_STREAM_KEY = "__shared__";
|
|
523
|
+
/** Pending PID lookups — awaited in disconnect handlers to avoid racing. */
|
|
524
|
+
pidLookups = /* @__PURE__ */ new Set();
|
|
574
525
|
constructor(config = {}) {
|
|
575
526
|
super(config);
|
|
576
527
|
this.id = `agent-browser-${Date.now()}`;
|
|
577
528
|
if (config.timeout) {
|
|
578
529
|
this.defaultTimeout = config.timeout;
|
|
579
530
|
}
|
|
580
|
-
|
|
581
|
-
if (config.cdpUrl && effectiveScope === "thread") {
|
|
582
|
-
this.logger.warn?.(
|
|
583
|
-
'Browser scope "thread" is not supported when connecting via cdpUrl. Falling back to "shared" (shared browser connection).'
|
|
584
|
-
);
|
|
585
|
-
effectiveScope = "shared";
|
|
586
|
-
}
|
|
531
|
+
const effectiveScope = config.cdpUrl ? config.scope ?? "shared" : config.scope ?? "thread";
|
|
587
532
|
this.threadManager = new AgentBrowserThreadManager({
|
|
588
533
|
scope: effectiveScope,
|
|
589
534
|
browserConfig: config,
|
|
@@ -600,13 +545,13 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
600
545
|
});
|
|
601
546
|
}
|
|
602
547
|
// ---------------------------------------------------------------------------
|
|
603
|
-
// Thread
|
|
548
|
+
// Thread Scope (delegated to ThreadManager)
|
|
604
549
|
// ---------------------------------------------------------------------------
|
|
605
550
|
/**
|
|
606
551
|
* Ensure browser is ready and thread session exists.
|
|
607
552
|
* Creates a new page/context for the current thread if needed.
|
|
608
553
|
*
|
|
609
|
-
* For '
|
|
554
|
+
* For 'thread' scope, we need to create the thread session BEFORE
|
|
610
555
|
* calling super.ensureReady() because the base class's ensureReady() will
|
|
611
556
|
* call checkBrowserAlive(), which needs at least one thread browser to exist.
|
|
612
557
|
*/
|
|
@@ -614,17 +559,17 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
614
559
|
const scope = this.threadManager.getScope();
|
|
615
560
|
const threadId = this.getCurrentThread();
|
|
616
561
|
const existingSession = this.threadManager.hasSession(threadId);
|
|
617
|
-
if (scope === "thread" &&
|
|
562
|
+
if (scope === "thread" && !existingSession) {
|
|
618
563
|
await this.getManagerForThread(threadId);
|
|
619
564
|
}
|
|
620
565
|
await super.ensureReady();
|
|
621
|
-
if (scope === "thread" &&
|
|
566
|
+
if (scope === "thread" && existingSession) {
|
|
622
567
|
await this.getManagerForThread(threadId);
|
|
623
568
|
}
|
|
624
569
|
}
|
|
625
570
|
/**
|
|
626
571
|
* Get the browser manager for the current thread.
|
|
627
|
-
* Delegates to ThreadManager for
|
|
572
|
+
* Delegates to ThreadManager for scope handling.
|
|
628
573
|
*/
|
|
629
574
|
async getManagerForThread(threadId) {
|
|
630
575
|
const effectiveThreadId = threadId ?? this.getCurrentThread();
|
|
@@ -637,56 +582,47 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
637
582
|
}
|
|
638
583
|
return this.threadManager.getManagerForThread(effectiveThreadId);
|
|
639
584
|
}
|
|
640
|
-
/**
|
|
641
|
-
* Get the page for a specific thread.
|
|
642
|
-
* For thread-isolated modes, ensures we're on the correct context/page.
|
|
643
|
-
*/
|
|
644
|
-
async getPageForThread(threadId) {
|
|
645
|
-
const manager = await this.getManagerForThread(threadId);
|
|
646
|
-
return manager.getPage();
|
|
647
|
-
}
|
|
648
|
-
/**
|
|
649
|
-
* Close a specific thread's browser session.
|
|
650
|
-
* Delegates to ThreadManager and notifies registered callbacks.
|
|
651
|
-
*/
|
|
652
|
-
async closeThreadSession(threadId) {
|
|
653
|
-
await this.threadManager.destroySession(threadId);
|
|
654
|
-
this.notifyBrowserClosed(threadId);
|
|
655
|
-
}
|
|
656
585
|
// ---------------------------------------------------------------------------
|
|
657
586
|
// Lifecycle
|
|
658
587
|
// ---------------------------------------------------------------------------
|
|
659
588
|
async doLaunch() {
|
|
660
589
|
const scope = this.threadManager.getScope();
|
|
661
590
|
if (scope === "thread") {
|
|
662
|
-
this.
|
|
663
|
-
this.threadManager.setSharedManager(this.
|
|
591
|
+
this.sharedManager = new BrowserManager();
|
|
592
|
+
this.threadManager.setSharedManager(this.sharedManager);
|
|
664
593
|
return;
|
|
665
594
|
}
|
|
666
|
-
this.
|
|
595
|
+
this.sharedManager = new BrowserManager();
|
|
667
596
|
const localConfig = this.config;
|
|
668
597
|
const launchOptions = {
|
|
669
598
|
headless: localConfig.headless ?? true,
|
|
670
|
-
viewport: localConfig.viewport
|
|
599
|
+
viewport: localConfig.viewport,
|
|
600
|
+
profile: localConfig.profile,
|
|
601
|
+
executablePath: localConfig.executablePath,
|
|
602
|
+
storageState: localConfig.storageState
|
|
671
603
|
};
|
|
672
604
|
if (localConfig.cdpUrl) {
|
|
673
605
|
launchOptions.cdpUrl = await this.resolveCdpUrl(localConfig.cdpUrl);
|
|
674
606
|
}
|
|
675
|
-
await this.
|
|
676
|
-
this.threadManager.setSharedManager(this.
|
|
677
|
-
this.
|
|
607
|
+
await this.sharedManager.launch(launchOptions);
|
|
608
|
+
this.threadManager.setSharedManager(this.sharedManager);
|
|
609
|
+
this.setupCloseListenerForSharedScope(this.sharedManager);
|
|
678
610
|
}
|
|
679
611
|
/**
|
|
680
|
-
* Set up close event listeners for '
|
|
612
|
+
* Set up close event listeners for 'shared' scope browser.
|
|
681
613
|
* This handles the case where the shared browser is closed externally.
|
|
682
614
|
*/
|
|
683
|
-
|
|
615
|
+
setupCloseListenerForSharedScope(manager) {
|
|
684
616
|
try {
|
|
617
|
+
const pidLookup = getBrowserPid(manager).then((pid) => {
|
|
618
|
+
if (pid && this.sharedManager === manager) this.sharedBrowserPid = pid;
|
|
619
|
+
}).finally(() => this.pidLookups.delete(pidLookup));
|
|
620
|
+
this.pidLookups.add(pidLookup);
|
|
685
621
|
let disconnectHandled = false;
|
|
686
622
|
const handleDisconnect = () => {
|
|
687
623
|
if (disconnectHandled) return;
|
|
688
624
|
disconnectHandled = true;
|
|
689
|
-
this.handleBrowserDisconnected();
|
|
625
|
+
void pidLookup.catch(() => void 0).then(() => this.handleBrowserDisconnected());
|
|
690
626
|
};
|
|
691
627
|
const context = manager.getContext();
|
|
692
628
|
if (context) {
|
|
@@ -705,13 +641,15 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
705
641
|
}
|
|
706
642
|
}
|
|
707
643
|
async doClose() {
|
|
644
|
+
await Promise.allSettled([...this.pidLookups]);
|
|
645
|
+
this.pidLookups.clear();
|
|
708
646
|
await this.threadManager.destroyAllSessions();
|
|
709
647
|
this.setCurrentThread(void 0);
|
|
710
648
|
const scope = this.threadManager.getScope();
|
|
711
|
-
if (scope === "shared" && this.
|
|
712
|
-
await this.
|
|
649
|
+
if (scope === "shared" && this.sharedManager) {
|
|
650
|
+
await this.sharedManager.close();
|
|
713
651
|
}
|
|
714
|
-
this.
|
|
652
|
+
this.sharedManager = null;
|
|
715
653
|
}
|
|
716
654
|
/**
|
|
717
655
|
* Check if the browser is still alive by verifying the page is connected.
|
|
@@ -720,13 +658,13 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
720
658
|
async checkBrowserAlive() {
|
|
721
659
|
const scope = this.threadManager.getScope();
|
|
722
660
|
if (scope === "thread") {
|
|
723
|
-
return this.threadManager.
|
|
661
|
+
return this.threadManager.hasActiveThreadManagers();
|
|
724
662
|
}
|
|
725
|
-
if (!this.
|
|
663
|
+
if (!this.sharedManager) {
|
|
726
664
|
return false;
|
|
727
665
|
}
|
|
728
666
|
try {
|
|
729
|
-
const page = this.
|
|
667
|
+
const page = this.sharedManager.getPage();
|
|
730
668
|
const url = page.url();
|
|
731
669
|
if (url && url !== "about:blank") {
|
|
732
670
|
const state = await this.getBrowserState();
|
|
@@ -765,28 +703,21 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
765
703
|
async getPage(explicitThreadId) {
|
|
766
704
|
const scope = this.getScope();
|
|
767
705
|
const threadId = explicitThreadId ?? this.getCurrentThread();
|
|
768
|
-
if (scope === "thread"
|
|
769
|
-
return this.getPageForThread(threadId);
|
|
706
|
+
if (scope === "thread") {
|
|
707
|
+
return this.threadManager.getPageForThread(threadId);
|
|
770
708
|
}
|
|
771
|
-
if (!this.
|
|
772
|
-
return this.
|
|
709
|
+
if (!this.sharedManager) throw new Error("Browser not launched");
|
|
710
|
+
return this.sharedManager.getPage();
|
|
773
711
|
}
|
|
774
712
|
/**
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
* For 'shared' scope, notifies all callbacks.
|
|
713
|
+
* Get the active page for a thread (implements abstract method from base class).
|
|
714
|
+
* Returns null if no page is available, unlike getPage which throws.
|
|
778
715
|
*/
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
this.logger.debug?.(`Cleared browser session for thread: ${threadId}`);
|
|
785
|
-
this.notifyBrowserClosed(threadId);
|
|
786
|
-
} else {
|
|
787
|
-
this.browserManager = null;
|
|
788
|
-
this.threadManager.clearSharedManager();
|
|
789
|
-
super.handleBrowserDisconnected();
|
|
716
|
+
async getActivePage(threadId) {
|
|
717
|
+
try {
|
|
718
|
+
return await this.getPage(threadId);
|
|
719
|
+
} catch {
|
|
720
|
+
return null;
|
|
790
721
|
}
|
|
791
722
|
}
|
|
792
723
|
/**
|
|
@@ -795,11 +726,17 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
795
726
|
*/
|
|
796
727
|
setupCloseListenerForThread(manager, threadId) {
|
|
797
728
|
try {
|
|
729
|
+
const pidLookup = getBrowserPid(manager).then((pid) => {
|
|
730
|
+
if (pid && this.threadManager?.getExistingManagerForThread(threadId) === manager) {
|
|
731
|
+
this.threadBrowserPids.set(threadId, pid);
|
|
732
|
+
}
|
|
733
|
+
}).finally(() => this.pidLookups.delete(pidLookup));
|
|
734
|
+
this.pidLookups.add(pidLookup);
|
|
798
735
|
let disconnectHandled = false;
|
|
799
736
|
const handleDisconnect = () => {
|
|
800
737
|
if (disconnectHandled) return;
|
|
801
738
|
disconnectHandled = true;
|
|
802
|
-
this.handleThreadBrowserDisconnected(threadId);
|
|
739
|
+
void pidLookup.catch(() => void 0).then(() => this.handleThreadBrowserDisconnected(threadId));
|
|
803
740
|
};
|
|
804
741
|
const context = manager.getContext();
|
|
805
742
|
if (context) {
|
|
@@ -817,15 +754,6 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
817
754
|
} catch {
|
|
818
755
|
}
|
|
819
756
|
}
|
|
820
|
-
/**
|
|
821
|
-
* Handle browser disconnection for a specific thread.
|
|
822
|
-
* Called when a thread's browser is closed externally.
|
|
823
|
-
*/
|
|
824
|
-
handleThreadBrowserDisconnected(threadId) {
|
|
825
|
-
this.threadManager.clearSession(threadId);
|
|
826
|
-
this.logger.debug?.(`Cleared browser session for thread: ${threadId}`);
|
|
827
|
-
this.notifyBrowserClosed(threadId);
|
|
828
|
-
}
|
|
829
757
|
/**
|
|
830
758
|
* Create an error response from an exception.
|
|
831
759
|
* Extends base class to add agent-browser specific error handling.
|
|
@@ -949,6 +877,16 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
949
877
|
return null;
|
|
950
878
|
}
|
|
951
879
|
}
|
|
880
|
+
/**
|
|
881
|
+
* Get browser state for a thread (implements abstract method from base class).
|
|
882
|
+
* Sync version that uses existing manager lookup without creating sessions.
|
|
883
|
+
*/
|
|
884
|
+
getBrowserStateForThread(threadId) {
|
|
885
|
+
const effectiveThreadId = threadId ?? this.getCurrentThread() ?? DEFAULT_THREAD_ID;
|
|
886
|
+
const manager = this.threadManager.getExistingManagerForThread(effectiveThreadId);
|
|
887
|
+
if (!manager) return null;
|
|
888
|
+
return this.getBrowserStateForManager(manager);
|
|
889
|
+
}
|
|
952
890
|
/**
|
|
953
891
|
* Get browser state from a specific manager instance.
|
|
954
892
|
*/
|
|
@@ -989,27 +927,23 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
989
927
|
}
|
|
990
928
|
}
|
|
991
929
|
/**
|
|
992
|
-
*
|
|
993
|
-
*
|
|
930
|
+
* Export the current browser session's storage state (cookies, localStorage) to a JSON file.
|
|
931
|
+
* This can later be loaded via the `storageState` config option to restore the session.
|
|
932
|
+
*
|
|
933
|
+
* @param path - File path to save the storage state JSON
|
|
934
|
+
* @param threadId - Optional thread ID (defaults to current thread)
|
|
994
935
|
*/
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
}
|
|
1005
|
-
if (manager) {
|
|
1006
|
-
const state = this.getBrowserStateForManager(manager);
|
|
1007
|
-
if (state) {
|
|
1008
|
-
this.threadManager.updateBrowserState(effectiveThreadId, state);
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
} catch {
|
|
936
|
+
async exportStorageState(path, threadId) {
|
|
937
|
+
const effectiveThreadId = threadId ?? this.getCurrentThread();
|
|
938
|
+
const manager = this.threadManager.getExistingManagerForThread(effectiveThreadId);
|
|
939
|
+
if (!manager) {
|
|
940
|
+
throw new Error("No browser is running. Launch a browser first before exporting storage state.");
|
|
941
|
+
}
|
|
942
|
+
const context = manager.getContext();
|
|
943
|
+
if (!context) {
|
|
944
|
+
throw new Error("Browser context not available");
|
|
1012
945
|
}
|
|
946
|
+
await context.storageState({ path });
|
|
1013
947
|
}
|
|
1014
948
|
// ---------------------------------------------------------------------------
|
|
1015
949
|
// 1. browser_goto - Navigate to URL
|
|
@@ -1433,10 +1367,10 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
1433
1367
|
);
|
|
1434
1368
|
}
|
|
1435
1369
|
await browser.switchTo(input.index);
|
|
1436
|
-
await this.
|
|
1370
|
+
await this.reconnectScreencastForThread(threadId, "tab switch");
|
|
1437
1371
|
const page = browser.getPage();
|
|
1438
1372
|
const pageUrl = page.url();
|
|
1439
|
-
const streamKey = this.getStreamKey(
|
|
1373
|
+
const streamKey = this.getStreamKey(threadId);
|
|
1440
1374
|
const stream = this.activeScreencastStreams.get(streamKey);
|
|
1441
1375
|
if (pageUrl && stream?.isActive()) {
|
|
1442
1376
|
stream.emitUrl(pageUrl);
|
|
@@ -1459,7 +1393,7 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
1459
1393
|
);
|
|
1460
1394
|
}
|
|
1461
1395
|
await browser.closeTab(input.index);
|
|
1462
|
-
await this.
|
|
1396
|
+
await this.reconnectScreencastForThread(threadId, "tab close");
|
|
1463
1397
|
this.updateSessionBrowserState(threadId);
|
|
1464
1398
|
const tabsList = await browser.listTabs?.() ?? [];
|
|
1465
1399
|
return {
|
|
@@ -1555,47 +1489,15 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
1555
1489
|
// ---------------------------------------------------------------------------
|
|
1556
1490
|
// Screencast (for Studio live view)
|
|
1557
1491
|
// ---------------------------------------------------------------------------
|
|
1558
|
-
/**
|
|
1559
|
-
* Get the stream key for a thread (or shared key for shared scope).
|
|
1560
|
-
*/
|
|
1561
|
-
getStreamKey(threadId) {
|
|
1562
|
-
return threadId || _AgentBrowser.SHARED_STREAM_KEY;
|
|
1563
|
-
}
|
|
1564
|
-
/**
|
|
1565
|
-
* Trigger a screencast reconnect after tab changes.
|
|
1566
|
-
* Called internally when tabs are switched or closed.
|
|
1567
|
-
*/
|
|
1568
|
-
async reconnectScreencast(_reason) {
|
|
1569
|
-
const threadId = this.getCurrentThread();
|
|
1570
|
-
const streamKey = this.getStreamKey(threadId);
|
|
1571
|
-
const stream = this.activeScreencastStreams.get(streamKey);
|
|
1572
|
-
if (stream?.isActive()) {
|
|
1573
|
-
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
1574
|
-
if (stream?.isActive()) {
|
|
1575
|
-
try {
|
|
1576
|
-
await stream.reconnect();
|
|
1577
|
-
const manager = this.threadManager.getExistingManagerForThread(threadId) ?? this.browserManager;
|
|
1578
|
-
const activePage = manager?.getPage();
|
|
1579
|
-
if (activePage) {
|
|
1580
|
-
const url = activePage.url();
|
|
1581
|
-
if (url) {
|
|
1582
|
-
stream.emitUrl(url);
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
} catch (err) {
|
|
1586
|
-
console.error("[AgentBrowser] Failed to reconnect screencast:", err);
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
1492
|
async startScreencast(_options) {
|
|
1592
|
-
const
|
|
1493
|
+
const requestedThreadId = _options?.threadId;
|
|
1494
|
+
const effectiveThreadId = this.getScope() === "thread" ? requestedThreadId ?? this.getCurrentThread() ?? DEFAULT_THREAD_ID : requestedThreadId;
|
|
1593
1495
|
let browserManager;
|
|
1594
|
-
if (this.getScope() === "thread"
|
|
1595
|
-
browserManager = await this.getManagerForThread(
|
|
1496
|
+
if (this.getScope() === "thread") {
|
|
1497
|
+
browserManager = await this.getManagerForThread(effectiveThreadId);
|
|
1596
1498
|
} else {
|
|
1597
|
-
if (!this.
|
|
1598
|
-
browserManager = this.
|
|
1499
|
+
if (!this.sharedManager) throw new Error("Browser not launched");
|
|
1500
|
+
browserManager = this.sharedManager;
|
|
1599
1501
|
}
|
|
1600
1502
|
const provider = {
|
|
1601
1503
|
getCdpSession: async () => {
|
|
@@ -1609,7 +1511,7 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
1609
1511
|
isBrowserRunning: () => browserManager.isLaunched()
|
|
1610
1512
|
};
|
|
1611
1513
|
const stream = new ScreencastStreamImpl(provider, _options);
|
|
1612
|
-
const streamKey = this.getStreamKey(
|
|
1514
|
+
const streamKey = this.getStreamKey(effectiveThreadId);
|
|
1613
1515
|
this.activeScreencastStreams.set(streamKey, stream);
|
|
1614
1516
|
const context = browserManager.getContext();
|
|
1615
1517
|
if (context) {
|
|
@@ -1628,7 +1530,7 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
1628
1530
|
const onFrameNavigated = (frame) => {
|
|
1629
1531
|
if (!frame.parentFrame()) {
|
|
1630
1532
|
stream.emitUrl(frame.url());
|
|
1631
|
-
this.updateSessionBrowserState(
|
|
1533
|
+
this.updateSessionBrowserState(effectiveThreadId);
|
|
1632
1534
|
}
|
|
1633
1535
|
};
|
|
1634
1536
|
page.on("framenavigated", onFrameNavigated);
|
|
@@ -1711,6 +1613,6 @@ var AgentBrowser = class _AgentBrowser extends MastraBrowser {
|
|
|
1711
1613
|
}
|
|
1712
1614
|
};
|
|
1713
1615
|
|
|
1714
|
-
export { AgentBrowser, BROWSER_TOOLS, backInputSchema, browserSchemas, clickInputSchema, closeInputSchema, createAgentBrowserTools, dialogInputSchema, dragInputSchema, evaluateInputSchema, gotoInputSchema, hoverInputSchema, pressInputSchema, scrollInputSchema, selectInputSchema, snapshotInputSchema, tabsInputSchema, typeInputSchema, waitInputSchema };
|
|
1616
|
+
export { AgentBrowser, BROWSER_TOOLS, backInputSchema, browserSchemas, clickInputSchema, closeInputSchema, createAgentBrowserTools, dialogInputSchema, dragInputSchema, evaluateInputSchema, getBrowserPid, gotoInputSchema, hoverInputSchema, pressInputSchema, scrollInputSchema, selectInputSchema, snapshotInputSchema, tabsInputSchema, typeInputSchema, waitInputSchema };
|
|
1715
1617
|
//# sourceMappingURL=index.js.map
|
|
1716
1618
|
//# sourceMappingURL=index.js.map
|