@mastra/core 1.22.0-alpha.2 → 1.22.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 +68 -0
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/index.cjs +8 -8
- package/dist/agent/index.js +1 -1
- package/dist/browser/browser.d.ts +155 -6
- package/dist/browser/browser.d.ts.map +1 -1
- package/dist/browser/index.cjs +292 -69
- package/dist/browser/index.cjs.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +292 -69
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/thread-manager.d.ts +41 -6
- package/dist/browser/thread-manager.d.ts.map +1 -1
- package/dist/channels/index.cjs +4 -4
- package/dist/channels/index.js +1 -1
- package/dist/{chunk-T5EPN63U.cjs → chunk-4CUUOZHE.cjs} +9 -9
- package/dist/{chunk-T5EPN63U.cjs.map → chunk-4CUUOZHE.cjs.map} +1 -1
- package/dist/{chunk-DOBLNWJ4.js → chunk-7RUFTPIY.js} +4 -4
- package/dist/{chunk-DOBLNWJ4.js.map → chunk-7RUFTPIY.js.map} +1 -1
- package/dist/{chunk-OBEZWZWL.cjs → chunk-AUJ7TUEZ.cjs} +185 -185
- package/dist/{chunk-OBEZWZWL.cjs.map → chunk-AUJ7TUEZ.cjs.map} +1 -1
- package/dist/{chunk-27O5T2VT.cjs → chunk-CXQ3QR5K.cjs} +48 -48
- package/dist/{chunk-27O5T2VT.cjs.map → chunk-CXQ3QR5K.cjs.map} +1 -1
- package/dist/{chunk-YEAJ4WNU.js → chunk-DRITAH5L.js} +3 -3
- package/dist/{chunk-YEAJ4WNU.js.map → chunk-DRITAH5L.js.map} +1 -1
- package/dist/{chunk-7BCOOVHZ.js → chunk-GYQ22SLZ.js} +4 -4
- package/dist/{chunk-7BCOOVHZ.js.map → chunk-GYQ22SLZ.js.map} +1 -1
- package/dist/{chunk-CMAULWNV.js → chunk-HPVNBI7J.js} +3 -3
- package/dist/{chunk-CMAULWNV.js.map → chunk-HPVNBI7J.js.map} +1 -1
- package/dist/{chunk-6RXPK4SK.js → chunk-HXX4JDIB.js} +3 -3
- package/dist/{chunk-6RXPK4SK.js.map → chunk-HXX4JDIB.js.map} +1 -1
- package/dist/{chunk-XQLIIZJB.cjs → chunk-KLHUYSDF.cjs} +6 -6
- package/dist/{chunk-XQLIIZJB.cjs.map → chunk-KLHUYSDF.cjs.map} +1 -1
- package/dist/{chunk-NKRYR7II.js → chunk-NLN4DDI6.js} +6 -6
- package/dist/{chunk-NKRYR7II.js.map → chunk-NLN4DDI6.js.map} +1 -1
- package/dist/{chunk-ELXVJWPF.js → chunk-NMRSL5GT.js} +9 -9
- package/dist/{chunk-ELXVJWPF.js.map → chunk-NMRSL5GT.js.map} +1 -1
- package/dist/{chunk-RSJKFDKP.cjs → chunk-NVMXENQS.cjs} +17 -17
- package/dist/{chunk-RSJKFDKP.cjs.map → chunk-NVMXENQS.cjs.map} +1 -1
- package/dist/{chunk-KAEFU5PR.cjs → chunk-PJERQ3YG.cjs} +3 -3
- package/dist/chunk-PJERQ3YG.cjs.map +1 -0
- package/dist/{chunk-WOFPOL3K.cjs → chunk-QFVPZL25.cjs} +5 -5
- package/dist/{chunk-WOFPOL3K.cjs.map → chunk-QFVPZL25.cjs.map} +1 -1
- package/dist/{chunk-XW5P6CHZ.cjs → chunk-RHKFYYB6.cjs} +26 -24
- package/dist/chunk-RHKFYYB6.cjs.map +1 -0
- package/dist/{chunk-O4GMYDMB.js → chunk-TULT7C36.js} +6 -4
- package/dist/chunk-TULT7C36.js.map +1 -0
- package/dist/{chunk-KYUKC4QI.cjs → chunk-UZVGJ26K.cjs} +77 -77
- package/dist/{chunk-KYUKC4QI.cjs.map → chunk-UZVGJ26K.cjs.map} +1 -1
- package/dist/{chunk-PQGC24JT.js → chunk-V5FLTMXK.js} +3 -3
- package/dist/chunk-V5FLTMXK.js.map +1 -0
- package/dist/{chunk-HLG6JE5B.cjs → chunk-VDXTOWVO.cjs} +16 -14
- package/dist/chunk-VDXTOWVO.cjs.map +1 -0
- package/dist/{chunk-BE4GXCOK.cjs → chunk-VRH5HTH5.cjs} +7 -7
- package/dist/{chunk-BE4GXCOK.cjs.map → chunk-VRH5HTH5.cjs.map} +1 -1
- package/dist/{chunk-X4JB5HFS.js → chunk-WTVDTW4F.js} +14 -12
- package/dist/chunk-WTVDTW4F.js.map +1 -0
- package/dist/{chunk-XZJRR6NR.js → chunk-Y7KNCAZY.js} +3 -3
- package/dist/{chunk-XZJRR6NR.js.map → chunk-Y7KNCAZY.js.map} +1 -1
- package/dist/datasets/index.cjs +11 -11
- package/dist/datasets/index.js +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +154 -154
- package/dist/evals/index.cjs +5 -5
- package/dist/evals/index.js +2 -2
- package/dist/evals/scoreTraces/index.cjs +3 -3
- package/dist/evals/scoreTraces/index.js +1 -1
- package/dist/harness/index.cjs +7 -7
- package/dist/harness/index.js +5 -5
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/dist/llm/index.cjs +20 -20
- package/dist/llm/index.js +5 -5
- package/dist/llm/model/provider-types.generated.d.ts +3 -2
- package/dist/loop/index.cjs +14 -14
- package/dist/loop/index.js +1 -1
- package/dist/mastra/index.cjs +2 -2
- package/dist/mastra/index.js +1 -1
- package/dist/mastra-33MCZUH4.cjs +12 -0
- package/dist/{mastra-FLOYM4EW.cjs.map → mastra-33MCZUH4.cjs.map} +1 -1
- package/dist/mastra-RY543V4U.js +3 -0
- package/dist/{mastra-YQRFVXLA.js.map → mastra-RY543V4U.js.map} +1 -1
- package/dist/memory/index.cjs +17 -17
- package/dist/memory/index.js +1 -1
- package/dist/models-dev-2BJQPEQJ.js +3 -0
- package/dist/{models-dev-URH3VX3L.js.map → models-dev-2BJQPEQJ.js.map} +1 -1
- package/dist/models-dev-OZGJCJIG.cjs +12 -0
- package/dist/{models-dev-2W4M2TXF.cjs.map → models-dev-OZGJCJIG.cjs.map} +1 -1
- package/dist/netlify-N7PUN3NA.js +3 -0
- package/dist/{netlify-S7UHC335.js.map → netlify-N7PUN3NA.js.map} +1 -1
- package/dist/netlify-TSDN7D7F.cjs +12 -0
- package/dist/{netlify-LCIM6BYA.cjs.map → netlify-TSDN7D7F.cjs.map} +1 -1
- package/dist/processor-provider/index.cjs +10 -10
- package/dist/processor-provider/index.js +1 -1
- package/dist/processors/index.cjs +44 -44
- package/dist/processors/index.js +1 -1
- package/dist/provider-registry-DBWCMPP3.cjs +40 -0
- package/dist/{provider-registry-GK7MD55F.cjs.map → provider-registry-DBWCMPP3.cjs.map} +1 -1
- package/dist/provider-registry-EINTM27D.js +3 -0
- package/dist/{provider-registry-PN4KYENK.js.map → provider-registry-EINTM27D.js.map} +1 -1
- package/dist/provider-registry.json +6 -4
- package/dist/relevance/index.cjs +3 -3
- package/dist/relevance/index.js +1 -1
- package/dist/stream/index.cjs +8 -8
- package/dist/stream/index.js +1 -1
- package/dist/tool-loop-agent/index.cjs +4 -4
- package/dist/tool-loop-agent/index.js +1 -1
- package/dist/workflows/evented/index.cjs +10 -10
- package/dist/workflows/evented/index.js +1 -1
- package/dist/workflows/index.cjs +24 -24
- package/dist/workflows/index.js +1 -1
- package/package.json +9 -9
- package/src/llm/model/provider-types.generated.d.ts +3 -2
- package/dist/chunk-HLG6JE5B.cjs.map +0 -1
- package/dist/chunk-KAEFU5PR.cjs.map +0 -1
- package/dist/chunk-O4GMYDMB.js.map +0 -1
- package/dist/chunk-PQGC24JT.js.map +0 -1
- package/dist/chunk-X4JB5HFS.js.map +0 -1
- package/dist/chunk-XW5P6CHZ.cjs.map +0 -1
- package/dist/mastra-FLOYM4EW.cjs +0 -12
- package/dist/mastra-YQRFVXLA.js +0 -3
- package/dist/models-dev-2W4M2TXF.cjs +0 -12
- package/dist/models-dev-URH3VX3L.js +0 -3
- package/dist/netlify-LCIM6BYA.cjs +0 -12
- package/dist/netlify-S7UHC335.js +0 -3
- package/dist/provider-registry-GK7MD55F.cjs +0 -40
- package/dist/provider-registry-PN4KYENK.js +0 -3
package/dist/browser/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var chunkVDXTOWVO_cjs = require('../chunk-VDXTOWVO.cjs');
|
|
3
4
|
var chunkDKK77FIJ_cjs = require('../chunk-DKK77FIJ.cjs');
|
|
4
5
|
var chunkHBO2PK7W_cjs = require('../chunk-HBO2PK7W.cjs');
|
|
5
6
|
var events = require('events');
|
|
@@ -16,6 +17,68 @@ function createError(code, message, hint) {
|
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
// src/browser/processor.ts
|
|
21
|
+
var BrowserContextProcessor = class {
|
|
22
|
+
id = "browser-context";
|
|
23
|
+
processInput(args) {
|
|
24
|
+
const ctx = args.requestContext?.get("browser");
|
|
25
|
+
if (!ctx) return args.messageList;
|
|
26
|
+
const lines = [`You have access to a browser (${ctx.provider}).`];
|
|
27
|
+
if (ctx.headless === false) {
|
|
28
|
+
lines.push("The browser is running in visible mode (not headless).");
|
|
29
|
+
}
|
|
30
|
+
if (ctx.sessionId) {
|
|
31
|
+
lines.push(`Session ID: ${ctx.sessionId}`);
|
|
32
|
+
}
|
|
33
|
+
const systemMessages = [...args.systemMessages, { role: "system", content: lines.join(" ") }];
|
|
34
|
+
return { messages: args.messages, systemMessages };
|
|
35
|
+
}
|
|
36
|
+
processInputStep(args) {
|
|
37
|
+
if (args.stepNumber !== 0) return;
|
|
38
|
+
const ctx = args.requestContext?.get("browser");
|
|
39
|
+
if (!ctx) return;
|
|
40
|
+
const parts = [];
|
|
41
|
+
if (ctx.currentUrl) {
|
|
42
|
+
parts.push(`Current URL: ${ctx.currentUrl}`);
|
|
43
|
+
}
|
|
44
|
+
if (ctx.pageTitle) {
|
|
45
|
+
parts.push(`Page title: ${ctx.pageTitle}`);
|
|
46
|
+
}
|
|
47
|
+
if (ctx.isRunning === false) {
|
|
48
|
+
parts.push("Browser is not currently running.");
|
|
49
|
+
}
|
|
50
|
+
if (parts.length === 0) return;
|
|
51
|
+
const reminder = `<system-reminder>${parts.join(" | ")}</system-reminder>
|
|
52
|
+
|
|
53
|
+
`;
|
|
54
|
+
const messages = [...args.messages];
|
|
55
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
56
|
+
const msg = messages[i];
|
|
57
|
+
if (msg.role === "user") {
|
|
58
|
+
const content = msg.content;
|
|
59
|
+
const existingParts = content.parts ?? [];
|
|
60
|
+
const firstTextIdx = existingParts.findIndex((p) => p.type === "text");
|
|
61
|
+
if (firstTextIdx >= 0) {
|
|
62
|
+
const textPart = existingParts[firstTextIdx];
|
|
63
|
+
const newParts = [...existingParts];
|
|
64
|
+
newParts[firstTextIdx] = { ...textPart, text: reminder + textPart.text };
|
|
65
|
+
messages[i] = { ...msg, content: { ...content, parts: newParts } };
|
|
66
|
+
} else {
|
|
67
|
+
messages[i] = {
|
|
68
|
+
...msg,
|
|
69
|
+
content: {
|
|
70
|
+
...content,
|
|
71
|
+
parts: [{ type: "text", text: reminder }, ...existingParts]
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { messages };
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
19
82
|
// src/browser/thread-manager.ts
|
|
20
83
|
var DEFAULT_THREAD_ID = "__default__";
|
|
21
84
|
var ThreadManager = class {
|
|
@@ -25,6 +88,10 @@ var ThreadManager = class {
|
|
|
25
88
|
activeThreadId = DEFAULT_THREAD_ID;
|
|
26
89
|
/** Preserved browser state that survives session clears (for browser restore) */
|
|
27
90
|
savedBrowserStates = /* @__PURE__ */ new Map();
|
|
91
|
+
/** Shared manager instance (used for 'shared' scope) */
|
|
92
|
+
sharedManager = null;
|
|
93
|
+
/** Map of thread ID to dedicated manager instance (for 'thread' scope) */
|
|
94
|
+
threadManagers = /* @__PURE__ */ new Map();
|
|
28
95
|
onSessionCreated;
|
|
29
96
|
onSessionDestroyed;
|
|
30
97
|
constructor(config) {
|
|
@@ -45,6 +112,49 @@ var ThreadManager = class {
|
|
|
45
112
|
getActiveThreadId() {
|
|
46
113
|
return this.activeThreadId;
|
|
47
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Set the shared manager instance (called after browser launch).
|
|
117
|
+
*/
|
|
118
|
+
setSharedManager(manager) {
|
|
119
|
+
this.sharedManager = manager;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Clear the shared manager instance (called when browser disconnects).
|
|
123
|
+
*/
|
|
124
|
+
clearSharedManager() {
|
|
125
|
+
this.sharedManager = null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the manager for an existing thread session without creating a new one.
|
|
129
|
+
*
|
|
130
|
+
* For 'thread' scope: Returns the thread-specific manager, or null if no session exists.
|
|
131
|
+
* For 'shared' scope: Returns the shared manager (all threads use the same instance).
|
|
132
|
+
*
|
|
133
|
+
* @param threadId - Thread identifier (defaults to DEFAULT_THREAD_ID)
|
|
134
|
+
* @returns The manager for the thread, or null if not found (thread scope only)
|
|
135
|
+
*/
|
|
136
|
+
getExistingManagerForThread(threadId) {
|
|
137
|
+
const effectiveThreadId = threadId ?? DEFAULT_THREAD_ID;
|
|
138
|
+
if (this.scope === "thread") {
|
|
139
|
+
return this.threadManagers.get(effectiveThreadId) ?? null;
|
|
140
|
+
}
|
|
141
|
+
return this.sharedManager;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Check if any thread managers are still running (for 'thread' scope).
|
|
145
|
+
*/
|
|
146
|
+
hasActiveThreadManagers() {
|
|
147
|
+
return this.threadManagers.size > 0;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Clear all session tracking without closing managers.
|
|
151
|
+
* Used when browsers have been externally closed and we just need to reset state.
|
|
152
|
+
*/
|
|
153
|
+
clearAllSessions() {
|
|
154
|
+
this.threadManagers.clear();
|
|
155
|
+
this.sessions.clear();
|
|
156
|
+
this.activeThreadId = DEFAULT_THREAD_ID;
|
|
157
|
+
}
|
|
48
158
|
/**
|
|
49
159
|
* Get a session by thread ID.
|
|
50
160
|
*/
|
|
@@ -89,8 +199,6 @@ var ThreadManager = class {
|
|
|
89
199
|
this.sessions.set(effectiveThreadId, session);
|
|
90
200
|
this.logger?.debug?.(`Created thread session: ${effectiveThreadId}`);
|
|
91
201
|
this.onSessionCreated?.(session);
|
|
92
|
-
} else if (this.activeThreadId !== effectiveThreadId) {
|
|
93
|
-
await this.switchToSession(session);
|
|
94
202
|
}
|
|
95
203
|
this.activeThreadId = effectiveThreadId;
|
|
96
204
|
return this.getManagerForSession(session);
|
|
@@ -106,6 +214,7 @@ var ThreadManager = class {
|
|
|
106
214
|
return;
|
|
107
215
|
}
|
|
108
216
|
await this.doDestroySession(session);
|
|
217
|
+
this.threadManagers.delete(threadId);
|
|
109
218
|
this.sessions.delete(threadId);
|
|
110
219
|
this.logger?.debug?.(`Destroyed thread session: ${threadId}`);
|
|
111
220
|
this.onSessionDestroyed?.(threadId);
|
|
@@ -152,6 +261,37 @@ var ThreadManager = class {
|
|
|
152
261
|
}
|
|
153
262
|
return this.savedBrowserStates.get(threadId);
|
|
154
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Clear a specific thread's session without closing the browser.
|
|
266
|
+
* Used when a thread's browser has been externally closed.
|
|
267
|
+
* Preserves the browser state for potential restoration.
|
|
268
|
+
*
|
|
269
|
+
* @param threadId - The thread ID to clear
|
|
270
|
+
*/
|
|
271
|
+
clearSession(threadId) {
|
|
272
|
+
const session = this.sessions.get(threadId);
|
|
273
|
+
if (session?.browserState) {
|
|
274
|
+
this.savedBrowserStates.set(threadId, session.browserState);
|
|
275
|
+
}
|
|
276
|
+
this.threadManagers.delete(threadId);
|
|
277
|
+
this.sessions.delete(threadId);
|
|
278
|
+
if (this.activeThreadId === threadId) {
|
|
279
|
+
this.activeThreadId = DEFAULT_THREAD_ID;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
// Abstract methods to be implemented by subclasses
|
|
284
|
+
// ---------------------------------------------------------------------------
|
|
285
|
+
/**
|
|
286
|
+
* Get the shared browser manager (used for 'shared' scope and default thread).
|
|
287
|
+
* @throws Error if shared manager is not initialized
|
|
288
|
+
*/
|
|
289
|
+
getSharedManager() {
|
|
290
|
+
if (!this.sharedManager) {
|
|
291
|
+
throw new Error("Browser not launched");
|
|
292
|
+
}
|
|
293
|
+
return this.sharedManager;
|
|
294
|
+
}
|
|
155
295
|
};
|
|
156
296
|
|
|
157
297
|
// src/browser/browser.ts
|
|
@@ -172,6 +312,12 @@ var MastraBrowser = class _MastraBrowser extends chunkDKK77FIJ_cjs.MastraBase {
|
|
|
172
312
|
}
|
|
173
313
|
/** Last known browser state before browser was closed (for restore on relaunch) */
|
|
174
314
|
lastBrowserState;
|
|
315
|
+
/**
|
|
316
|
+
* Shared manager instance for 'shared' scope mode.
|
|
317
|
+
* Type varies by provider (e.g., BrowserManager for agent-browser, Stagehand for stagehand).
|
|
318
|
+
* Providers should cast this to their specific type when accessing.
|
|
319
|
+
*/
|
|
320
|
+
sharedManager = null;
|
|
175
321
|
/** Configuration */
|
|
176
322
|
config;
|
|
177
323
|
/**
|
|
@@ -185,6 +331,69 @@ var MastraBrowser = class _MastraBrowser extends chunkDKK77FIJ_cjs.MastraBase {
|
|
|
185
331
|
*/
|
|
186
332
|
currentThreadId = DEFAULT_THREAD_ID;
|
|
187
333
|
// ---------------------------------------------------------------------------
|
|
334
|
+
// Screencast State
|
|
335
|
+
// ---------------------------------------------------------------------------
|
|
336
|
+
/** Default key for shared scope screencast streams */
|
|
337
|
+
static SHARED_STREAM_KEY = "__shared__";
|
|
338
|
+
/** Active screencast streams per thread (for triggering reconnects on tab changes) */
|
|
339
|
+
activeScreencastStreams = /* @__PURE__ */ new Map();
|
|
340
|
+
/**
|
|
341
|
+
* Get the stream key for a thread (or shared key for shared scope).
|
|
342
|
+
* @param threadId - Optional thread ID
|
|
343
|
+
* @returns The stream key to use for the screencast streams map
|
|
344
|
+
*/
|
|
345
|
+
getStreamKey(threadId) {
|
|
346
|
+
return threadId || _MastraBrowser.SHARED_STREAM_KEY;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Reconnect the active screencast for a specific thread.
|
|
350
|
+
* Called internally when tabs are switched or closed.
|
|
351
|
+
*/
|
|
352
|
+
async reconnectScreencastForThread(threadId, reason) {
|
|
353
|
+
const streamKey = this.getStreamKey(threadId);
|
|
354
|
+
const stream = this.activeScreencastStreams.get(streamKey);
|
|
355
|
+
if (!stream || !stream.isActive()) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (!this.isBrowserRunning()) {
|
|
359
|
+
this.logger.debug?.("Skipping screencast reconnect - browser not running");
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const scope = this.getScope();
|
|
363
|
+
if (scope === "thread" && threadId && !this.threadManager?.getExistingManagerForThread(threadId)) {
|
|
364
|
+
this.logger.debug?.(`Skipping screencast reconnect - no session for thread ${threadId}`);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
this.logger.debug?.(`Reconnecting screencast: ${reason}`);
|
|
368
|
+
try {
|
|
369
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
370
|
+
await stream.reconnect();
|
|
371
|
+
const activePage = await this.getActivePage(threadId);
|
|
372
|
+
if (activePage) {
|
|
373
|
+
const url = activePage.url();
|
|
374
|
+
if (url) {
|
|
375
|
+
stream.emitUrl(url);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
} catch (error) {
|
|
379
|
+
this.logger.debug?.("Screencast reconnect failed", error);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Update the browser state in the thread session.
|
|
384
|
+
* Called on navigation, tab open/close to keep state fresh.
|
|
385
|
+
*/
|
|
386
|
+
updateSessionBrowserState(threadId) {
|
|
387
|
+
try {
|
|
388
|
+
const effectiveThreadId = threadId ?? this.getCurrentThread() ?? DEFAULT_THREAD_ID;
|
|
389
|
+
const state = this.getBrowserStateForThread(effectiveThreadId);
|
|
390
|
+
if (state) {
|
|
391
|
+
this.threadManager?.updateBrowserState(effectiveThreadId, state);
|
|
392
|
+
}
|
|
393
|
+
} catch {
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// ---------------------------------------------------------------------------
|
|
188
397
|
// Lifecycle Promise Tracking (prevents race conditions)
|
|
189
398
|
// ---------------------------------------------------------------------------
|
|
190
399
|
_launchPromise;
|
|
@@ -195,6 +404,19 @@ var MastraBrowser = class _MastraBrowser extends chunkDKK77FIJ_cjs.MastraBase {
|
|
|
195
404
|
constructor(config = {}) {
|
|
196
405
|
super({ name: "MastraBrowser", component: chunkHBO2PK7W_cjs.RegisteredLogger.BROWSER });
|
|
197
406
|
this.config = config;
|
|
407
|
+
const scope = config.scope;
|
|
408
|
+
if (config.cdpUrl && scope === "thread") {
|
|
409
|
+
throw new Error(
|
|
410
|
+
`Invalid browser configuration: "cdpUrl" and "scope: 'thread'" cannot be used together.
|
|
411
|
+
|
|
412
|
+
\u2022 cdpUrl connects to a single existing browser instance (all threads share it)
|
|
413
|
+
\u2022 scope: "thread" requires spawning separate browser instances per thread
|
|
414
|
+
|
|
415
|
+
To fix this, either:
|
|
416
|
+
1. Remove cdpUrl to let the provider spawn separate browser instances (supports thread isolation)
|
|
417
|
+
2. Use scope: "shared" when connecting via cdpUrl (all threads share one browser)`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
198
420
|
}
|
|
199
421
|
/**
|
|
200
422
|
* Launch the browser.
|
|
@@ -403,13 +625,25 @@ var MastraBrowser = class _MastraBrowser extends chunkDKK77FIJ_cjs.MastraBase {
|
|
|
403
625
|
/**
|
|
404
626
|
* Handle browser disconnection by updating status and notifying listeners.
|
|
405
627
|
* Called when browser is detected as externally closed.
|
|
406
|
-
*
|
|
628
|
+
*
|
|
629
|
+
* For 'thread' scope: clears only the specific thread's session (other threads unaffected)
|
|
630
|
+
* For 'shared' scope: clears the shared manager and updates global status
|
|
407
631
|
*/
|
|
408
632
|
handleBrowserDisconnected() {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
this.
|
|
633
|
+
const scope = this.threadManager?.getScope();
|
|
634
|
+
const threadId = this.getCurrentThread();
|
|
635
|
+
if (scope === "thread" && threadId !== DEFAULT_THREAD_ID) {
|
|
636
|
+
this.threadManager.clearSession(threadId);
|
|
637
|
+
this.logger.debug?.(`Cleared browser session for thread: ${threadId}`);
|
|
638
|
+
this.notifyBrowserClosed(threadId);
|
|
639
|
+
} else {
|
|
640
|
+
this.sharedManager = null;
|
|
641
|
+
this.threadManager?.clearSharedManager();
|
|
642
|
+
if (this.status !== "closed") {
|
|
643
|
+
this.status = "closed";
|
|
644
|
+
this.logger.debug?.("Browser was externally closed, status set to closed");
|
|
645
|
+
this.notifyBrowserClosed();
|
|
646
|
+
}
|
|
413
647
|
}
|
|
414
648
|
}
|
|
415
649
|
/**
|
|
@@ -700,6 +934,37 @@ var MastraBrowser = class _MastraBrowser extends chunkDKK77FIJ_cjs.MastraBase {
|
|
|
700
934
|
}
|
|
701
935
|
return this.threadManager.hasSession(threadId);
|
|
702
936
|
}
|
|
937
|
+
/**
|
|
938
|
+
* Close a specific thread's browser session.
|
|
939
|
+
* Delegates to ThreadManager and notifies registered callbacks.
|
|
940
|
+
*
|
|
941
|
+
* For 'thread' scope, this closes only that thread's browser instance.
|
|
942
|
+
* For 'shared' scope, this is a no-op (use close() to close the shared browser).
|
|
943
|
+
*
|
|
944
|
+
* @param threadId - The thread ID whose session should be closed
|
|
945
|
+
*/
|
|
946
|
+
async closeThreadSession(threadId) {
|
|
947
|
+
if (!this.threadManager) {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
await this.threadManager.destroySession(threadId);
|
|
951
|
+
this.notifyBrowserClosed(threadId);
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Handle browser disconnection for a specific thread.
|
|
955
|
+
* Called when a thread's browser is closed externally (e.g., user closes browser window).
|
|
956
|
+
* Clears the thread session and notifies registered callbacks.
|
|
957
|
+
*
|
|
958
|
+
* @param threadId - The thread ID whose session was disconnected
|
|
959
|
+
*/
|
|
960
|
+
handleThreadBrowserDisconnected(threadId) {
|
|
961
|
+
if (!this.threadManager) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
this.threadManager.clearSession(threadId);
|
|
965
|
+
this.logger.debug?.(`Cleared browser session for thread: ${threadId}`);
|
|
966
|
+
this.notifyBrowserClosed(threadId);
|
|
967
|
+
}
|
|
703
968
|
/**
|
|
704
969
|
* Get a session identifier for a specific thread.
|
|
705
970
|
* In thread scope, returns a composite ID (browser:threadId).
|
|
@@ -757,6 +1022,26 @@ var MastraBrowser = class _MastraBrowser extends chunkDKK77FIJ_cjs.MastraBase {
|
|
|
757
1022
|
async injectKeyboardEvent(_event, _threadId) {
|
|
758
1023
|
throw new Error("Keyboard event injection not supported by this provider");
|
|
759
1024
|
}
|
|
1025
|
+
// ---------------------------------------------------------------------------
|
|
1026
|
+
// Input Processors
|
|
1027
|
+
// ---------------------------------------------------------------------------
|
|
1028
|
+
/**
|
|
1029
|
+
* Returns browser input processors (e.g., BrowserContextProcessor for context injection).
|
|
1030
|
+
* Skips if the user already added a processor with the same id.
|
|
1031
|
+
*
|
|
1032
|
+
* This method is similar to AgentChannels.getInputProcessors() and allows
|
|
1033
|
+
* browser implementations to provide their own processors.
|
|
1034
|
+
*
|
|
1035
|
+
* @param configuredProcessors - Processors already configured by the user (for deduplication)
|
|
1036
|
+
* @returns Array of input processors for this browser instance
|
|
1037
|
+
*/
|
|
1038
|
+
getInputProcessors(configuredProcessors = []) {
|
|
1039
|
+
const hasProcessor = configuredProcessors.some(
|
|
1040
|
+
(p) => !chunkVDXTOWVO_cjs.isProcessorWorkflow(p) && "id" in p && p.id === "browser-context"
|
|
1041
|
+
);
|
|
1042
|
+
if (hasProcessor) return [];
|
|
1043
|
+
return [new BrowserContextProcessor()];
|
|
1044
|
+
}
|
|
760
1045
|
};
|
|
761
1046
|
|
|
762
1047
|
// src/browser/screencast/types.ts
|
|
@@ -929,68 +1214,6 @@ var ScreencastStream = class extends events.EventEmitter {
|
|
|
929
1214
|
}
|
|
930
1215
|
};
|
|
931
1216
|
|
|
932
|
-
// src/browser/processor.ts
|
|
933
|
-
var BrowserContextProcessor = class {
|
|
934
|
-
id = "browser-context";
|
|
935
|
-
processInput(args) {
|
|
936
|
-
const ctx = args.requestContext?.get("browser");
|
|
937
|
-
if (!ctx) return args.messageList;
|
|
938
|
-
const lines = [`You have access to a browser (${ctx.provider}).`];
|
|
939
|
-
if (ctx.headless === false) {
|
|
940
|
-
lines.push("The browser is running in visible mode (not headless).");
|
|
941
|
-
}
|
|
942
|
-
if (ctx.sessionId) {
|
|
943
|
-
lines.push(`Session ID: ${ctx.sessionId}`);
|
|
944
|
-
}
|
|
945
|
-
const systemMessages = [...args.systemMessages, { role: "system", content: lines.join(" ") }];
|
|
946
|
-
return { messages: args.messages, systemMessages };
|
|
947
|
-
}
|
|
948
|
-
processInputStep(args) {
|
|
949
|
-
if (args.stepNumber !== 0) return;
|
|
950
|
-
const ctx = args.requestContext?.get("browser");
|
|
951
|
-
if (!ctx) return;
|
|
952
|
-
const parts = [];
|
|
953
|
-
if (ctx.currentUrl) {
|
|
954
|
-
parts.push(`Current URL: ${ctx.currentUrl}`);
|
|
955
|
-
}
|
|
956
|
-
if (ctx.pageTitle) {
|
|
957
|
-
parts.push(`Page title: ${ctx.pageTitle}`);
|
|
958
|
-
}
|
|
959
|
-
if (ctx.isRunning === false) {
|
|
960
|
-
parts.push("Browser is not currently running.");
|
|
961
|
-
}
|
|
962
|
-
if (parts.length === 0) return;
|
|
963
|
-
const reminder = `<system-reminder>${parts.join(" | ")}</system-reminder>
|
|
964
|
-
|
|
965
|
-
`;
|
|
966
|
-
const messages = [...args.messages];
|
|
967
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
968
|
-
const msg = messages[i];
|
|
969
|
-
if (msg.role === "user") {
|
|
970
|
-
const content = msg.content;
|
|
971
|
-
const existingParts = content.parts ?? [];
|
|
972
|
-
const firstTextIdx = existingParts.findIndex((p) => p.type === "text");
|
|
973
|
-
if (firstTextIdx >= 0) {
|
|
974
|
-
const textPart = existingParts[firstTextIdx];
|
|
975
|
-
const newParts = [...existingParts];
|
|
976
|
-
newParts[firstTextIdx] = { ...textPart, text: reminder + textPart.text };
|
|
977
|
-
messages[i] = { ...msg, content: { ...content, parts: newParts } };
|
|
978
|
-
} else {
|
|
979
|
-
messages[i] = {
|
|
980
|
-
...msg,
|
|
981
|
-
content: {
|
|
982
|
-
...content,
|
|
983
|
-
parts: [{ type: "text", text: reminder }, ...existingParts]
|
|
984
|
-
}
|
|
985
|
-
};
|
|
986
|
-
}
|
|
987
|
-
break;
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
return { messages };
|
|
991
|
-
}
|
|
992
|
-
};
|
|
993
|
-
|
|
994
1217
|
exports.BrowserContextProcessor = BrowserContextProcessor;
|
|
995
1218
|
exports.DEFAULT_THREAD_ID = DEFAULT_THREAD_ID;
|
|
996
1219
|
exports.MastraBrowser = MastraBrowser;
|