@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.
Files changed (128) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/agent/agent.d.ts.map +1 -1
  3. package/dist/agent/index.cjs +8 -8
  4. package/dist/agent/index.js +1 -1
  5. package/dist/browser/browser.d.ts +155 -6
  6. package/dist/browser/browser.d.ts.map +1 -1
  7. package/dist/browser/index.cjs +292 -69
  8. package/dist/browser/index.cjs.map +1 -1
  9. package/dist/browser/index.d.ts +1 -1
  10. package/dist/browser/index.d.ts.map +1 -1
  11. package/dist/browser/index.js +292 -69
  12. package/dist/browser/index.js.map +1 -1
  13. package/dist/browser/thread-manager.d.ts +41 -6
  14. package/dist/browser/thread-manager.d.ts.map +1 -1
  15. package/dist/channels/index.cjs +4 -4
  16. package/dist/channels/index.js +1 -1
  17. package/dist/{chunk-T5EPN63U.cjs → chunk-4CUUOZHE.cjs} +9 -9
  18. package/dist/{chunk-T5EPN63U.cjs.map → chunk-4CUUOZHE.cjs.map} +1 -1
  19. package/dist/{chunk-DOBLNWJ4.js → chunk-7RUFTPIY.js} +4 -4
  20. package/dist/{chunk-DOBLNWJ4.js.map → chunk-7RUFTPIY.js.map} +1 -1
  21. package/dist/{chunk-OBEZWZWL.cjs → chunk-AUJ7TUEZ.cjs} +185 -185
  22. package/dist/{chunk-OBEZWZWL.cjs.map → chunk-AUJ7TUEZ.cjs.map} +1 -1
  23. package/dist/{chunk-27O5T2VT.cjs → chunk-CXQ3QR5K.cjs} +48 -48
  24. package/dist/{chunk-27O5T2VT.cjs.map → chunk-CXQ3QR5K.cjs.map} +1 -1
  25. package/dist/{chunk-YEAJ4WNU.js → chunk-DRITAH5L.js} +3 -3
  26. package/dist/{chunk-YEAJ4WNU.js.map → chunk-DRITAH5L.js.map} +1 -1
  27. package/dist/{chunk-7BCOOVHZ.js → chunk-GYQ22SLZ.js} +4 -4
  28. package/dist/{chunk-7BCOOVHZ.js.map → chunk-GYQ22SLZ.js.map} +1 -1
  29. package/dist/{chunk-CMAULWNV.js → chunk-HPVNBI7J.js} +3 -3
  30. package/dist/{chunk-CMAULWNV.js.map → chunk-HPVNBI7J.js.map} +1 -1
  31. package/dist/{chunk-6RXPK4SK.js → chunk-HXX4JDIB.js} +3 -3
  32. package/dist/{chunk-6RXPK4SK.js.map → chunk-HXX4JDIB.js.map} +1 -1
  33. package/dist/{chunk-XQLIIZJB.cjs → chunk-KLHUYSDF.cjs} +6 -6
  34. package/dist/{chunk-XQLIIZJB.cjs.map → chunk-KLHUYSDF.cjs.map} +1 -1
  35. package/dist/{chunk-NKRYR7II.js → chunk-NLN4DDI6.js} +6 -6
  36. package/dist/{chunk-NKRYR7II.js.map → chunk-NLN4DDI6.js.map} +1 -1
  37. package/dist/{chunk-ELXVJWPF.js → chunk-NMRSL5GT.js} +9 -9
  38. package/dist/{chunk-ELXVJWPF.js.map → chunk-NMRSL5GT.js.map} +1 -1
  39. package/dist/{chunk-RSJKFDKP.cjs → chunk-NVMXENQS.cjs} +17 -17
  40. package/dist/{chunk-RSJKFDKP.cjs.map → chunk-NVMXENQS.cjs.map} +1 -1
  41. package/dist/{chunk-KAEFU5PR.cjs → chunk-PJERQ3YG.cjs} +3 -3
  42. package/dist/chunk-PJERQ3YG.cjs.map +1 -0
  43. package/dist/{chunk-WOFPOL3K.cjs → chunk-QFVPZL25.cjs} +5 -5
  44. package/dist/{chunk-WOFPOL3K.cjs.map → chunk-QFVPZL25.cjs.map} +1 -1
  45. package/dist/{chunk-XW5P6CHZ.cjs → chunk-RHKFYYB6.cjs} +26 -24
  46. package/dist/chunk-RHKFYYB6.cjs.map +1 -0
  47. package/dist/{chunk-O4GMYDMB.js → chunk-TULT7C36.js} +6 -4
  48. package/dist/chunk-TULT7C36.js.map +1 -0
  49. package/dist/{chunk-KYUKC4QI.cjs → chunk-UZVGJ26K.cjs} +77 -77
  50. package/dist/{chunk-KYUKC4QI.cjs.map → chunk-UZVGJ26K.cjs.map} +1 -1
  51. package/dist/{chunk-PQGC24JT.js → chunk-V5FLTMXK.js} +3 -3
  52. package/dist/chunk-V5FLTMXK.js.map +1 -0
  53. package/dist/{chunk-HLG6JE5B.cjs → chunk-VDXTOWVO.cjs} +16 -14
  54. package/dist/chunk-VDXTOWVO.cjs.map +1 -0
  55. package/dist/{chunk-BE4GXCOK.cjs → chunk-VRH5HTH5.cjs} +7 -7
  56. package/dist/{chunk-BE4GXCOK.cjs.map → chunk-VRH5HTH5.cjs.map} +1 -1
  57. package/dist/{chunk-X4JB5HFS.js → chunk-WTVDTW4F.js} +14 -12
  58. package/dist/chunk-WTVDTW4F.js.map +1 -0
  59. package/dist/{chunk-XZJRR6NR.js → chunk-Y7KNCAZY.js} +3 -3
  60. package/dist/{chunk-XZJRR6NR.js.map → chunk-Y7KNCAZY.js.map} +1 -1
  61. package/dist/datasets/index.cjs +11 -11
  62. package/dist/datasets/index.js +1 -1
  63. package/dist/docs/SKILL.md +1 -1
  64. package/dist/docs/assets/SOURCE_MAP.json +154 -154
  65. package/dist/evals/index.cjs +5 -5
  66. package/dist/evals/index.js +2 -2
  67. package/dist/evals/scoreTraces/index.cjs +3 -3
  68. package/dist/evals/scoreTraces/index.js +1 -1
  69. package/dist/harness/index.cjs +7 -7
  70. package/dist/harness/index.js +5 -5
  71. package/dist/index.cjs +2 -2
  72. package/dist/index.js +1 -1
  73. package/dist/llm/index.cjs +20 -20
  74. package/dist/llm/index.js +5 -5
  75. package/dist/llm/model/provider-types.generated.d.ts +3 -2
  76. package/dist/loop/index.cjs +14 -14
  77. package/dist/loop/index.js +1 -1
  78. package/dist/mastra/index.cjs +2 -2
  79. package/dist/mastra/index.js +1 -1
  80. package/dist/mastra-33MCZUH4.cjs +12 -0
  81. package/dist/{mastra-FLOYM4EW.cjs.map → mastra-33MCZUH4.cjs.map} +1 -1
  82. package/dist/mastra-RY543V4U.js +3 -0
  83. package/dist/{mastra-YQRFVXLA.js.map → mastra-RY543V4U.js.map} +1 -1
  84. package/dist/memory/index.cjs +17 -17
  85. package/dist/memory/index.js +1 -1
  86. package/dist/models-dev-2BJQPEQJ.js +3 -0
  87. package/dist/{models-dev-URH3VX3L.js.map → models-dev-2BJQPEQJ.js.map} +1 -1
  88. package/dist/models-dev-OZGJCJIG.cjs +12 -0
  89. package/dist/{models-dev-2W4M2TXF.cjs.map → models-dev-OZGJCJIG.cjs.map} +1 -1
  90. package/dist/netlify-N7PUN3NA.js +3 -0
  91. package/dist/{netlify-S7UHC335.js.map → netlify-N7PUN3NA.js.map} +1 -1
  92. package/dist/netlify-TSDN7D7F.cjs +12 -0
  93. package/dist/{netlify-LCIM6BYA.cjs.map → netlify-TSDN7D7F.cjs.map} +1 -1
  94. package/dist/processor-provider/index.cjs +10 -10
  95. package/dist/processor-provider/index.js +1 -1
  96. package/dist/processors/index.cjs +44 -44
  97. package/dist/processors/index.js +1 -1
  98. package/dist/provider-registry-DBWCMPP3.cjs +40 -0
  99. package/dist/{provider-registry-GK7MD55F.cjs.map → provider-registry-DBWCMPP3.cjs.map} +1 -1
  100. package/dist/provider-registry-EINTM27D.js +3 -0
  101. package/dist/{provider-registry-PN4KYENK.js.map → provider-registry-EINTM27D.js.map} +1 -1
  102. package/dist/provider-registry.json +6 -4
  103. package/dist/relevance/index.cjs +3 -3
  104. package/dist/relevance/index.js +1 -1
  105. package/dist/stream/index.cjs +8 -8
  106. package/dist/stream/index.js +1 -1
  107. package/dist/tool-loop-agent/index.cjs +4 -4
  108. package/dist/tool-loop-agent/index.js +1 -1
  109. package/dist/workflows/evented/index.cjs +10 -10
  110. package/dist/workflows/evented/index.js +1 -1
  111. package/dist/workflows/index.cjs +24 -24
  112. package/dist/workflows/index.js +1 -1
  113. package/package.json +9 -9
  114. package/src/llm/model/provider-types.generated.d.ts +3 -2
  115. package/dist/chunk-HLG6JE5B.cjs.map +0 -1
  116. package/dist/chunk-KAEFU5PR.cjs.map +0 -1
  117. package/dist/chunk-O4GMYDMB.js.map +0 -1
  118. package/dist/chunk-PQGC24JT.js.map +0 -1
  119. package/dist/chunk-X4JB5HFS.js.map +0 -1
  120. package/dist/chunk-XW5P6CHZ.cjs.map +0 -1
  121. package/dist/mastra-FLOYM4EW.cjs +0 -12
  122. package/dist/mastra-YQRFVXLA.js +0 -3
  123. package/dist/models-dev-2W4M2TXF.cjs +0 -12
  124. package/dist/models-dev-URH3VX3L.js +0 -3
  125. package/dist/netlify-LCIM6BYA.cjs +0 -12
  126. package/dist/netlify-S7UHC335.js +0 -3
  127. package/dist/provider-registry-GK7MD55F.cjs +0 -40
  128. package/dist/provider-registry-PN4KYENK.js +0 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/browser/errors.ts","../../src/browser/thread-manager.ts","../../src/browser/browser.ts","../../src/browser/screencast/types.ts","../../src/browser/screencast/screencast-stream.ts","../../src/browser/processor.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Unified error handling for browser tools.\n *\n * All browser tools return errors in this consistent format,\n * providing LLM-friendly messages and recovery hints.\n */\n\n/**\n * Error codes for browser tool failures.\n *\n * These codes help agents understand what went wrong\n * and whether retry or recovery is possible.\n */\nexport type ErrorCode =\n | 'stale_ref' // Ref no longer valid after page change\n | 'element_not_found' // Element doesn't exist\n | 'element_blocked' // Element covered by overlay\n | 'element_not_visible' // Element hidden\n | 'not_focusable' // Can't type into element\n | 'timeout' // Operation timed out\n | 'browser_closed' // Browser was externally closed\n | 'browser_error'; // Generic browser error\n\n/**\n * Structured error response for browser tool failures.\n *\n * Provides LLM-friendly error information with optional recovery hints.\n */\nexport interface BrowserToolError {\n /** Always false for error responses */\n success: false;\n /** Error classification code */\n code: ErrorCode;\n /** LLM-friendly error description */\n message: string;\n /** Suggested recovery action (only when actionable) */\n recoveryHint?: string;\n /** Whether the operation can be retried */\n canRetry: boolean;\n}\n\n/**\n * Error codes that are generally retryable.\n */\nconst RETRYABLE_CODES: Set<ErrorCode> = new Set(['timeout', 'element_blocked']);\n\n/**\n * Creates a structured error response for browser tools.\n *\n * Sets canRetry based on the error code: true for 'timeout' and 'element_blocked'.\n *\n * @param code - Error classification code\n * @param message - LLM-friendly error description\n * @param hint - Optional recovery hint (only when actionable)\n * @returns Typed BrowserToolError with canRetry set automatically\n */\nexport function createError(code: ErrorCode, message: string, hint?: string): BrowserToolError {\n return {\n success: false,\n code,\n message,\n recoveryHint: hint,\n canRetry: RETRYABLE_CODES.has(code),\n };\n}\n","/**\n * ThreadManager - Abstract base class for managing thread-scoped browser sessions.\n *\n * Similar to ProcessManager for workspaces, this centralizes thread lifecycle logic\n * and makes thread isolation reusable across browser providers.\n *\n * Browser scope modes:\n * - 'shared': All threads share a single browser instance\n * - 'thread': Each thread gets its own browser instance (full isolation)\n */\n\nimport type { IMastraLogger } from '../logger';\n\n/** Browser scope mode - determines how browser instances are shared across threads */\nexport type BrowserScope = 'shared' | 'thread';\n\n/** Default thread ID used when no thread is specified */\nexport const DEFAULT_THREAD_ID = '__default__';\n\n/**\n * Represents a single tab's state for persistence.\n */\nexport interface BrowserTabState {\n url: string;\n title?: string;\n}\n\n/**\n * Full browser state for persistence and restoration.\n */\nexport interface BrowserState {\n tabs: BrowserTabState[];\n activeTabIndex: number;\n}\n\n/**\n * Represents an active thread session.\n */\nexport interface ThreadSession {\n /** Unique thread identifier */\n threadId: string;\n /** Timestamp when session was created */\n createdAt: number;\n /** Full browser state for this thread (for restore on relaunch) */\n browserState?: BrowserState;\n}\n\n/**\n * Configuration for ThreadManager.\n */\nexport interface ThreadManagerConfig {\n /** Browser scope mode */\n scope: BrowserScope;\n /** Logger instance */\n logger?: IMastraLogger;\n /** Callback when a new session is created */\n onSessionCreated?: (session: ThreadSession) => void;\n /** Callback when a session is destroyed */\n onSessionDestroyed?: (threadId: string) => void;\n}\n\n/**\n * Abstract base class for managing thread-scoped browser sessions.\n *\n * @typeParam TManager - The browser manager type (e.g., BrowserManagerLike, Stagehand)\n */\nexport abstract class ThreadManager<TManager = unknown> {\n protected readonly scope: BrowserScope;\n protected readonly logger?: IMastraLogger;\n protected readonly sessions = new Map<string, ThreadSession>();\n protected activeThreadId: string = DEFAULT_THREAD_ID;\n\n /** Preserved browser state that survives session clears (for browser restore) */\n protected readonly savedBrowserStates = new Map<string, BrowserState>();\n\n private readonly onSessionCreated?: (session: ThreadSession) => void;\n private readonly onSessionDestroyed?: (threadId: string) => void;\n\n constructor(config: ThreadManagerConfig) {\n this.scope = config.scope;\n this.logger = config.logger;\n this.onSessionCreated = config.onSessionCreated;\n this.onSessionDestroyed = config.onSessionDestroyed;\n }\n\n /**\n * Get the current browser scope mode.\n */\n getScope(): BrowserScope {\n return this.scope;\n }\n\n /**\n * Get the currently active thread ID.\n */\n getActiveThreadId(): string {\n return this.activeThreadId;\n }\n\n /**\n * Get a session by thread ID.\n */\n getSession(threadId: string): ThreadSession | undefined {\n return this.sessions.get(threadId);\n }\n\n /**\n * Check if a session exists for a thread.\n */\n hasSession(threadId: string): boolean {\n return this.sessions.has(threadId);\n }\n\n /**\n * List all active sessions.\n */\n listSessions(): ThreadSession[] {\n return Array.from(this.sessions.values());\n }\n\n /**\n * Get the number of active sessions.\n */\n getSessionCount(): number {\n return this.sessions.size;\n }\n\n /**\n * Get or create a session for a thread, and return the browser manager for that thread.\n *\n * For 'shared' scope, returns the shared manager.\n * For 'thread' scope, creates/returns a dedicated manager for the thread.\n *\n * @param threadId - Thread identifier (uses DEFAULT_THREAD_ID if not provided)\n * @returns The browser manager for the thread\n */\n async getManagerForThread(threadId?: string): Promise<TManager> {\n const effectiveThreadId = threadId ?? DEFAULT_THREAD_ID;\n\n // Shared scope - always use shared manager\n if (this.scope === 'shared' || effectiveThreadId === DEFAULT_THREAD_ID) {\n return this.getSharedManager();\n }\n\n // Check if session already exists\n let session = this.sessions.get(effectiveThreadId);\n\n if (!session) {\n // Create new session\n session = await this.createSession(effectiveThreadId);\n this.sessions.set(effectiveThreadId, session);\n this.logger?.debug?.(`Created thread session: ${effectiveThreadId}`);\n this.onSessionCreated?.(session);\n } else if (this.activeThreadId !== effectiveThreadId) {\n // Switch to existing session\n await this.switchToSession(session);\n }\n\n this.activeThreadId = effectiveThreadId;\n return this.getManagerForSession(session);\n }\n\n /**\n * Destroy a specific thread's session.\n *\n * @param threadId - Thread identifier\n */\n async destroySession(threadId: string): Promise<void> {\n const session = this.sessions.get(threadId);\n if (!session) {\n return;\n }\n\n await this.doDestroySession(session);\n this.sessions.delete(threadId);\n this.logger?.debug?.(`Destroyed thread session: ${threadId}`);\n this.onSessionDestroyed?.(threadId);\n\n // Reset active thread if we destroyed it\n if (this.activeThreadId === threadId) {\n this.activeThreadId = DEFAULT_THREAD_ID;\n }\n }\n\n /**\n * Destroy all thread sessions.\n */\n async destroyAllSessions(): Promise<void> {\n const threadIds = Array.from(this.sessions.keys());\n for (const threadId of threadIds) {\n await this.destroySession(threadId);\n }\n this.activeThreadId = DEFAULT_THREAD_ID;\n }\n\n /**\n * Update the browser state for a thread session.\n * Also saves to persistent storage so state survives session clears.\n */\n updateBrowserState(threadId: string, state: BrowserState): void {\n // Filter out empty/blank tabs\n const filteredTabs = state.tabs.filter(tab => tab.url && tab.url !== 'about:blank');\n if (filteredTabs.length === 0) {\n return;\n }\n\n const filteredState: BrowserState = {\n tabs: filteredTabs,\n activeTabIndex: Math.max(0, Math.min(state.activeTabIndex, filteredTabs.length - 1)),\n };\n\n const session = this.sessions.get(threadId);\n if (session) {\n session.browserState = filteredState;\n }\n // Also save to persistent map so it survives session clears\n this.savedBrowserStates.set(threadId, filteredState);\n }\n\n /**\n * Get the saved browser state for a thread (survives session clears).\n */\n getSavedBrowserState(threadId: string): BrowserState | undefined {\n // First check current session\n const session = this.sessions.get(threadId);\n if (session?.browserState) {\n return session.browserState;\n }\n // Fall back to saved state\n return this.savedBrowserStates.get(threadId);\n }\n\n // ---------------------------------------------------------------------------\n // Abstract methods to be implemented by subclasses\n // ---------------------------------------------------------------------------\n\n /**\n * Get the shared browser manager (used for 'shared' scope and default thread).\n */\n protected abstract getSharedManager(): TManager;\n\n /**\n * Create a new session for a thread.\n * Called when a thread is accessed for the first time.\n */\n protected abstract createSession(threadId: string): Promise<ThreadSession>;\n\n /**\n * Switch to an existing session.\n * May be a no-op depending on isolation mode.\n */\n protected abstract switchToSession(session: ThreadSession): Promise<void>;\n\n /**\n * Get the browser manager for a specific session.\n */\n protected abstract getManagerForSession(session: ThreadSession): TManager;\n\n /**\n * Destroy a session and clean up resources.\n */\n protected abstract doDestroySession(session: ThreadSession): Promise<void>;\n}\n","/**\n * MastraBrowser Base Class\n *\n * Abstract base class for browser providers. Extends MastraBase for logger integration.\n *\n * ## Architecture\n *\n * Each browser provider defines its own tools via the `getTools()` method.\n * This allows different providers to offer different capabilities:\n *\n * - **AgentBrowser**: 17 deterministic tools using refs ([ref=e1], [ref=e2])\n * - **StagehandBrowser**: AI-powered tools (act, extract, observe)\n *\n * ## Two Paradigms\n *\n * Browser providers fall into two paradigms:\n *\n * 1. **Deterministic** (Playwright, agent-browser) - Uses refs and selectors\n * 2. **AI-powered** (Stagehand) - Uses natural language instructions\n *\n * Both extend this base class and implement `getTools()` to return their tools.\n */\n\nimport { MastraBase } from '../base';\nimport { RegisteredLogger } from '../logger/constants';\nimport type { Tool } from '../tools/tool';\nimport { createError } from './errors';\nimport type { BrowserToolError, ErrorCode } from './errors';\nimport type { ScreencastOptions as ScreencastOptionsType } from './screencast/types';\nimport { DEFAULT_THREAD_ID } from './thread-manager';\nimport type { BrowserState, BrowserTabState, BrowserScope, ThreadManager } from './thread-manager';\n\n// Re-export screencast types from the screencast module\nexport type { ScreencastOptions, ScreencastFrameData, ScreencastEvents } from './screencast/types';\n\n// Alias for internal use\ntype ScreencastOptions = ScreencastOptionsType;\n\n// =============================================================================\n// Status & Lifecycle Types\n// =============================================================================\n\n/**\n * Browser provider status.\n */\nexport type BrowserStatus = 'pending' | 'launching' | 'ready' | 'error' | 'closing' | 'closed';\n\n/**\n * Lifecycle hook that fires during browser state transitions.\n */\nexport type BrowserLifecycleHook = (args: { browser: MastraBrowser }) => void | Promise<void>;\n\n// =============================================================================\n// Configuration Types\n// =============================================================================\n\n/**\n * CDP URL provider - can be a static string or an async function.\n * Useful for cloud providers where the CDP URL may change per session.\n */\nexport type CdpUrlProvider = string | (() => string | Promise<string>);\n\n/**\n * Base configuration shared by all browser providers.\n * Provider packages extend this with their own options.\n */\n\nexport interface BrowserConfig {\n /**\n * Whether to run the browser in headless mode (no visible UI).\n * @default true\n */\n headless?: boolean;\n\n /**\n * Browser viewport dimensions.\n * Controls the size of the browser window and how websites render.\n */\n viewport?: {\n width: number;\n height: number;\n };\n\n /**\n * Default timeout in milliseconds for browser operations.\n * @default 10000 (10 seconds)\n */\n timeout?: number;\n\n /**\n * CDP WebSocket URL or async provider function.\n * When provided, connects to an existing browser instead of launching a new one.\n * Useful for cloud providers (Browserbase, Browserless, Kernel, etc.).\n */\n cdpUrl?: CdpUrlProvider;\n\n /**\n * Browser instance scope across threads.\n * - 'shared': All threads share a single browser instance\n * - 'thread': Each thread gets its own browser instance (full isolation)\n * @default 'thread'\n */\n scope?: BrowserScope;\n\n /**\n * Called after the browser reaches 'ready' status.\n */\n onLaunch?: BrowserLifecycleHook;\n\n /**\n * Called before the browser is closed.\n */\n onClose?: BrowserLifecycleHook;\n\n /**\n * Screencast options for streaming browser frames.\n * Controls image format, quality, and dimensions.\n */\n screencast?: ScreencastOptions;\n}\n\n// =============================================================================\n// Screencast Types (re-exported from ./screencast/types)\n// =============================================================================\n\n/**\n * A screencast stream that emits frames.\n * Uses EventEmitter pattern for frame delivery.\n */\nexport interface ScreencastStream {\n /** Stop the screencast */\n stop(): Promise<void>;\n /** Check if screencast is active */\n isActive(): boolean;\n /** Register event handlers */\n on(event: 'frame', handler: (frame: { data: string; viewport: { width: number; height: number } }) => void): this;\n on(event: 'stop', handler: (reason: string) => void): this;\n on(event: 'error', handler: (error: Error) => void): this;\n on(event: 'url', handler: (url: string) => void): this;\n /** Emit a URL update (called by browser providers on navigation) */\n emitUrl(url: string): void;\n}\n\n// =============================================================================\n// Event Injection Types (for Studio live view)\n// =============================================================================\n\n/**\n * Mouse event parameters for CDP injection.\n */\nexport interface MouseEventParams {\n type: 'mousePressed' | 'mouseReleased' | 'mouseMoved' | 'mouseWheel';\n x: number;\n y: number;\n button?: 'left' | 'right' | 'middle' | 'none';\n clickCount?: number;\n deltaX?: number;\n deltaY?: number;\n modifiers?: number;\n}\n\n/**\n * Keyboard event parameters for CDP injection.\n */\nexport interface KeyboardEventParams {\n type: 'keyDown' | 'keyUp' | 'char';\n key?: string;\n code?: string;\n text?: string;\n modifiers?: number;\n /** Windows virtual key code (required for non-printable keys like Enter, Tab, Arrow keys) */\n windowsVirtualKeyCode?: number;\n}\n\n// =============================================================================\n// MastraBrowser Base Class\n// =============================================================================\n\n/**\n * Abstract base class for browser providers.\n *\n * Providers extend this class and implement the abstract methods.\n * Each method corresponds to one of the 17 flat tools.\n */\nexport abstract class MastraBrowser extends MastraBase {\n // ---------------------------------------------------------------------------\n // Abstract Identity (providers must define)\n // ---------------------------------------------------------------------------\n\n /** Unique instance identifier */\n abstract readonly id: string;\n\n /** Human-readable name */\n abstract readonly name: string;\n\n /** Provider type (e.g., 'playwright', 'stagehand', 'browserbase') */\n abstract readonly provider: string;\n\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n\n /** Current lifecycle status */\n status: BrowserStatus = 'pending';\n\n /** Error message when status is 'error' */\n error?: string;\n\n /**\n * Whether the browser is running in headless mode.\n * Returns true by default if not explicitly configured.\n */\n get headless(): boolean {\n return this.config.headless ?? true;\n }\n\n /** Last known browser state before browser was closed (for restore on relaunch) */\n protected lastBrowserState?: BrowserState;\n\n /** Configuration */\n protected readonly config: BrowserConfig;\n\n /**\n * Thread manager for handling thread-scoped browser sessions.\n * Set by subclasses that support thread isolation.\n */\n protected threadManager?: ThreadManager;\n\n /**\n * Current thread ID for browser operations.\n * Used by thread isolation to route operations to the correct session.\n */\n protected currentThreadId: string = DEFAULT_THREAD_ID;\n\n // ---------------------------------------------------------------------------\n // Lifecycle Promise Tracking (prevents race conditions)\n // ---------------------------------------------------------------------------\n\n private _launchPromise?: Promise<void>;\n private _closePromise?: Promise<void>;\n\n // ---------------------------------------------------------------------------\n // Constructor\n // ---------------------------------------------------------------------------\n\n constructor(config: BrowserConfig = {}) {\n super({ name: 'MastraBrowser', component: RegisteredLogger.BROWSER });\n this.config = config;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle Management\n // ---------------------------------------------------------------------------\n\n /**\n * Launch the browser. Override in subclass.\n * Called by launch() wrapper which handles status and race conditions.\n */\n protected abstract doLaunch(): Promise<void>;\n\n /**\n * Close the browser. Override in subclass.\n * Called by close() wrapper which handles status and race conditions.\n */\n protected abstract doClose(): Promise<void>;\n\n /**\n * Launch the browser.\n * Race-condition-safe - handles concurrent calls, status management, and lifecycle hooks.\n */\n async launch(): Promise<void> {\n // Already ready\n if (this.status === 'ready') {\n return;\n }\n\n // Already launching - wait for existing promise\n if (this.status === 'launching' && this._launchPromise) {\n return this._launchPromise;\n }\n\n // Can't launch if closing/closed\n if (this.status === 'closing' || this.status === 'closed') {\n throw new Error(`Cannot launch browser in '${this.status}' state`);\n }\n\n this.status = 'launching';\n this.error = undefined;\n\n this._launchPromise = (async () => {\n try {\n await this.doLaunch();\n this.status = 'ready';\n\n // Fire onLaunch hook\n if (this.config.onLaunch) {\n await this.config.onLaunch({ browser: this });\n }\n\n // Notify onBrowserReady callbacks\n this.notifyBrowserReady();\n } catch (err) {\n this.status = 'error';\n this.error = err instanceof Error ? err.message : String(err);\n throw err;\n } finally {\n this._launchPromise = undefined;\n }\n })();\n\n return this._launchPromise;\n }\n\n /**\n * Close the browser.\n * Race-condition-safe - handles concurrent calls, status management, and lifecycle hooks.\n */\n async close(): Promise<void> {\n // Already closed\n if (this.status === 'closed') {\n return;\n }\n\n // Already closing - wait for existing promise\n if (this.status === 'closing' && this._closePromise) {\n return this._closePromise;\n }\n\n // Wait for in-flight launch to complete before closing\n // This prevents race conditions where close() executes against a half-initialized provider\n if (this.status === 'launching' && this._launchPromise) {\n try {\n await this._launchPromise;\n } catch {\n // Launch failed - status is now 'error', nothing to close\n // Ensure we're in a clean closed state and return early\n this.status = 'closed';\n return;\n }\n }\n\n // Fire onClose hook before closing\n if (this.config.onClose && this.status === 'ready') {\n await this.config.onClose({ browser: this });\n }\n\n // Save browser state before closing for potential restore on relaunch\n const currentState = await this.getBrowserState();\n if (currentState && currentState.tabs.length > 0) {\n this.lastBrowserState = currentState;\n }\n\n this.status = 'closing';\n\n this._closePromise = (async () => {\n try {\n await this.doClose();\n this.status = 'closed';\n this.notifyBrowserClosed();\n } catch (err) {\n this.status = 'error';\n this.error = err instanceof Error ? err.message : String(err);\n throw err;\n } finally {\n this._closePromise = undefined;\n }\n })();\n\n return this._closePromise;\n }\n\n /**\n * Ensure the browser is ready, launching if needed.\n * If browser was previously closed, it will be re-launched.\n */\n async ensureReady(): Promise<void> {\n if (this.status === 'ready') {\n // Check if browser is still alive (handles external closure)\n // checkBrowserAlive() should save lastBrowserState internally if it detects closure\n const stillAlive = await this.checkBrowserAlive();\n if (stillAlive) {\n return;\n }\n // Browser was externally closed, mark as closed for re-launch\n this.status = 'closed';\n }\n if (this.status === 'pending' || this.status === 'error' || this.status === 'closed') {\n // Reset to pending to allow re-launch after close\n if (this.status === 'closed') {\n this.status = 'pending';\n }\n await this.launch();\n return;\n }\n if (this.status === 'launching') {\n await this._launchPromise;\n return;\n }\n if (this.status === 'closing') {\n // Wait for close to complete, then re-launch\n await this._closePromise;\n this.status = 'pending';\n await this.launch();\n return;\n }\n throw new Error(`Browser is ${this.status} and cannot be used`);\n }\n\n /**\n * Check if the browser is still alive.\n * Override in subclass to detect externally closed browsers.\n * @returns true if browser is alive, false if it was externally closed\n */\n protected async checkBrowserAlive(): Promise<boolean> {\n // Default implementation assumes browser is alive if status is ready\n return true;\n }\n\n /**\n * Check if the browser is currently running.\n */\n isBrowserRunning(): boolean {\n return this.status === 'ready';\n }\n\n // ---------------------------------------------------------------------------\n // CDP URL Resolution\n // ---------------------------------------------------------------------------\n\n /**\n * Resolve a CDP URL from a static string or async provider function.\n * @param cdpUrl - Static string or async function returning the CDP URL\n * @returns Resolved CDP URL string\n */\n protected async resolveCdpUrl(cdpUrl: CdpUrlProvider): Promise<string> {\n return typeof cdpUrl === 'function' ? await cdpUrl() : cdpUrl;\n }\n\n /**\n * Resolve an HTTP CDP endpoint to a WebSocket URL by fetching /json/version.\n *\n * Cloud browser providers (Browser-Use, Browserless, etc.) often expose HTTP\n * endpoints that need to be resolved to WebSocket URLs for direct CDP connections.\n *\n * - If the URL starts with `ws://` or `wss://`, returns it as-is\n * - If the URL starts with `http://` or `https://`, fetches /json/version to get webSocketDebuggerUrl\n *\n * @param url - CDP URL (HTTP or WebSocket)\n * @returns WebSocket URL for CDP connection\n */\n protected async resolveWebSocketUrl(url: string): Promise<string> {\n // Already a WebSocket URL\n if (url.startsWith('ws://') || url.startsWith('wss://')) {\n return url;\n }\n\n // HTTP URL - fetch /json/version to get the WebSocket URL\n if (url.startsWith('http://') || url.startsWith('https://')) {\n const baseUrl = url.replace(/\\/$/, ''); // Remove trailing slash\n const versionUrl = `${baseUrl}/json/version`;\n\n this.logger.debug?.(`Resolving WebSocket URL from ${versionUrl}`);\n\n // Add timeout to prevent hanging on dead endpoints\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 10000);\n\n try {\n const response = await fetch(versionUrl, { signal: controller.signal });\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch CDP version info from ${versionUrl}: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = (await response.json()) as { webSocketDebuggerUrl?: string };\n if (!data.webSocketDebuggerUrl) {\n throw new Error(`No webSocketDebuggerUrl found in CDP version response from ${versionUrl}`);\n }\n\n this.logger.debug?.(`Resolved WebSocket URL: ${data.webSocketDebuggerUrl}`);\n return data.webSocketDebuggerUrl;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Timeout resolving WebSocket URL from ${versionUrl} (10s)`);\n }\n throw error;\n }\n }\n\n // Unknown protocol - return as-is and let the caller handle it\n return url;\n }\n\n // ---------------------------------------------------------------------------\n // Disconnection Detection & Error Handling\n // ---------------------------------------------------------------------------\n\n /**\n * Error patterns that indicate browser disconnection.\n * Used by isDisconnectionError() to detect external browser closure.\n */\n protected static readonly DISCONNECTION_PATTERNS = [\n 'Target closed',\n 'Target page, context or browser has been closed',\n 'Browser has been closed',\n 'Connection closed',\n 'Protocol error',\n 'Session closed',\n 'browser has disconnected',\n 'closed externally',\n ];\n\n /**\n * Check if an error message indicates browser disconnection.\n * @param message - Error message to check\n * @returns true if the message indicates disconnection\n */\n isDisconnectionError(message: string): boolean {\n const lowerMessage = message.toLowerCase();\n return MastraBrowser.DISCONNECTION_PATTERNS.some(pattern => lowerMessage.includes(pattern.toLowerCase()));\n }\n\n /**\n * Handle browser disconnection by updating status and notifying listeners.\n * Called when browser is detected as externally closed.\n * Subclasses should call this and also clear their internal instance references.\n */\n handleBrowserDisconnected(): void {\n if (this.status !== 'closed') {\n this.status = 'closed';\n this.logger.debug?.('Browser was externally closed, status set to closed');\n this.notifyBrowserClosed();\n }\n }\n\n /**\n * Create a BrowserToolError from an exception.\n * Handles common error patterns including disconnection detection.\n * Subclasses can override to add provider-specific error handling.\n *\n * @param error - The caught error\n * @param context - Description of what operation failed (e.g., \"Click operation\")\n * @returns Structured BrowserToolError\n */\n protected createErrorFromException(error: unknown, context: string): BrowserToolError {\n const msg = error instanceof Error ? error.message : String(error);\n\n // Check for browser disconnection errors first\n if (this.isDisconnectionError(msg)) {\n this.handleBrowserDisconnected();\n return createError(\n 'browser_closed',\n 'Browser was closed externally.',\n 'The browser window was closed. Please retry to re-launch.',\n );\n }\n\n // Timeout errors\n if (msg.includes('timeout') || msg.includes('Timeout') || msg.includes('aborted')) {\n return createError('timeout', `${context} timed out.`, 'Try again or increase timeout.');\n }\n\n // Not launched errors\n if (msg.includes('not launched') || msg.includes('Browser is not launched')) {\n return createError(\n 'browser_error',\n 'Browser was not initialized.',\n 'This is an internal error - please try again.',\n );\n }\n\n // Default to generic browser error\n return createError('browser_error', `${context} failed: ${msg}`, 'Check the browser state and try again.');\n }\n\n /**\n * Create a specific error type.\n * Convenience method for providers to create typed errors.\n */\n protected createError(code: ErrorCode, message: string, hint?: string): BrowserToolError {\n return createError(code, message, hint);\n }\n\n // ---------------------------------------------------------------------------\n // Browser Ready/Closed Callbacks\n // ---------------------------------------------------------------------------\n\n private _onReadyCallbacks: Set<() => void> = new Set();\n private _onClosedCallbacks: Set<() => void> = new Set();\n /** Thread-specific ready callbacks. Key is threadId. */\n private _onThreadReadyCallbacks: Map<string, Set<() => void>> = new Map();\n /** Thread-specific closed callbacks. Key is threadId. */\n private _onThreadClosedCallbacks: Map<string, Set<() => void>> = new Map();\n\n /**\n * Register a callback to be invoked when the browser becomes ready.\n * If browser is already running, callback is invoked immediately.\n * The callback is ALWAYS registered (even if invoked immediately) so it will\n * also fire on future \"ready\" events (e.g., session creation for thread isolation).\n * @param callback - Function to call when browser is ready\n * @param threadId - Optional thread ID to scope the callback to a specific thread\n * @returns Cleanup function to unregister the callback\n */\n onBrowserReady(callback: () => void, threadId?: string): () => void {\n if (threadId) {\n // Thread-specific callback\n let threadCallbacks = this._onThreadReadyCallbacks.get(threadId);\n if (!threadCallbacks) {\n threadCallbacks = new Set();\n this._onThreadReadyCallbacks.set(threadId, threadCallbacks);\n }\n threadCallbacks.add(callback);\n\n // Check if this specific thread has a session ready\n if (this.hasThreadSession(threadId)) {\n callback();\n }\n\n return () => {\n threadCallbacks!.delete(callback);\n if (threadCallbacks!.size === 0) {\n this._onThreadReadyCallbacks.delete(threadId);\n }\n };\n }\n\n // Global callback (for shared scope or when thread not specified)\n this._onReadyCallbacks.add(callback);\n\n if (this.isBrowserRunning()) {\n // Browser already ready - also invoke immediately\n callback();\n }\n\n return () => {\n this._onReadyCallbacks.delete(callback);\n };\n }\n\n /**\n * Register a callback to be invoked when the browser closes.\n * Useful for screencast to broadcast browser_closed status.\n * @param callback - Function to call when browser closes\n * @param threadId - Optional thread ID to scope the callback to a specific thread\n * @returns Cleanup function to unregister the callback\n */\n onBrowserClosed(callback: () => void, threadId?: string): () => void {\n if (threadId) {\n // Thread-specific callback\n let threadCallbacks = this._onThreadClosedCallbacks.get(threadId);\n if (!threadCallbacks) {\n threadCallbacks = new Set();\n this._onThreadClosedCallbacks.set(threadId, threadCallbacks);\n }\n threadCallbacks.add(callback);\n return () => {\n threadCallbacks!.delete(callback);\n if (threadCallbacks!.size === 0) {\n this._onThreadClosedCallbacks.delete(threadId);\n }\n };\n }\n // Global callback (for shared scope or when thread not specified)\n this._onClosedCallbacks.add(callback);\n return () => {\n this._onClosedCallbacks.delete(callback);\n };\n }\n\n /**\n * Notify registered callbacks that browser is ready.\n * @param threadId - If provided, only notify callbacks for that thread (for thread scope)\n */\n protected notifyBrowserReady(threadId?: string): void {\n if (threadId) {\n // Notify thread-specific callbacks only\n const threadCallbacks = this._onThreadReadyCallbacks.get(threadId);\n if (threadCallbacks) {\n for (const callback of threadCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n }\n } else {\n // Notify global callbacks (for shared scope)\n for (const callback of this._onReadyCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n // Also notify ALL thread callbacks (entire browser is ready - shared scenario)\n for (const [, threadCallbacks] of this._onThreadReadyCallbacks) {\n for (const callback of threadCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n }\n }\n // Do NOT clear callbacks - they should persist across browser restarts\n // so screencast can reconnect after external closure + re-launch\n }\n\n /**\n * Notify registered callbacks that browser has closed.\n * @param threadId - If provided, only notify callbacks for that thread (for thread scope)\n */\n protected notifyBrowserClosed(threadId?: string): void {\n if (threadId) {\n // Notify thread-specific callbacks only\n const threadCallbacks = this._onThreadClosedCallbacks.get(threadId);\n if (threadCallbacks) {\n for (const callback of threadCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n }\n } else {\n // Notify global callbacks (for shared scope)\n for (const callback of this._onClosedCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n // Also notify ALL thread callbacks (entire browser is closing)\n for (const [, threadCallbacks] of this._onThreadClosedCallbacks) {\n for (const callback of threadCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // URL Access (optional - providers that support it should override)\n // ---------------------------------------------------------------------------\n\n /**\n * Get the current page URL without launching the browser.\n * @param threadId - Optional thread ID for thread-isolated browsers\n * @returns The current URL string, or null if browser is not running or not supported\n */\n async getCurrentUrl(_threadId?: string): Promise<string | null> {\n return null;\n }\n\n /**\n * Get the current browser state (all tabs and active tab index).\n * Override in subclass to provide actual tab state.\n * @param _threadId - Optional thread ID for thread-isolated sessions\n * @returns The browser state, or null if not available\n */\n async getBrowserState(_threadId?: string): Promise<BrowserState | null> {\n // Default implementation returns null - providers override\n return null;\n }\n\n /**\n * Get the last known browser state before the browser was closed.\n * Useful for restoring state on relaunch.\n * @param threadId - Optional thread ID for thread-isolated sessions\n * @returns The last browser state, or undefined if not available\n */\n getLastBrowserState(threadId?: string): BrowserState | undefined {\n // For thread isolation, check thread manager first\n if (threadId && this.threadManager) {\n const savedState = this.threadManager.getSavedBrowserState(threadId);\n if (savedState) {\n return savedState;\n }\n }\n return this.lastBrowserState;\n }\n\n /**\n * Get all open tabs with their URLs and titles.\n * Override in subclass to provide actual tab info.\n * @param _threadId - Optional thread ID for thread-isolated sessions\n * @returns Array of tab states\n */\n async getTabState(_threadId?: string): Promise<BrowserTabState[]> {\n // Default implementation returns empty array - providers override\n return [];\n }\n\n /**\n * Get the active tab index.\n * Override in subclass to provide actual active tab index.\n * @param _threadId - Optional thread ID for thread-isolated sessions\n * @returns The active tab index (0-based), or 0 if not available\n */\n async getActiveTabIndex(_threadId?: string): Promise<number> {\n // Default implementation returns 0 - providers override\n return 0;\n }\n\n /**\n * Navigate to a URL (simple form). Override in subclass if supported.\n * Used internally for restoring state on relaunch.\n * Named `navigateTo` to avoid conflicts with tool methods that have richer signatures.\n */\n async navigateTo(_url: string): Promise<void> {\n // Default implementation does nothing - providers can override\n }\n\n // ---------------------------------------------------------------------------\n // Thread Management\n // ---------------------------------------------------------------------------\n\n /**\n * Set the current thread ID for subsequent browser operations.\n * Called by tools before executing browser actions to ensure\n * operations are routed to the correct thread session.\n *\n * @param threadId - The thread ID, or undefined to use the default thread\n */\n setCurrentThread(threadId?: string): void {\n this.currentThreadId = threadId ?? DEFAULT_THREAD_ID;\n }\n\n /**\n * Get the current thread ID.\n * @returns The current thread ID being used for operations\n */\n getCurrentThread(): string {\n return this.currentThreadId;\n }\n\n /**\n * Get the browser scope mode.\n * @returns The scope from threadManager or config, defaults to 'shared'\n */\n getScope(): BrowserScope {\n return this.threadManager?.getScope() ?? this.config.scope ?? 'shared';\n }\n\n // ---------------------------------------------------------------------------\n // Screencast (optional - for Studio live view)\n // ---------------------------------------------------------------------------\n\n /**\n * Start screencast streaming. Override in subclass if supported.\n */\n async startScreencast(_options?: ScreencastOptions): Promise<ScreencastStream> {\n throw new Error('Screencast not supported by this provider');\n }\n\n /**\n * Check if a thread has an existing browser session.\n * Used by startScreencastIfBrowserActive to prevent showing another thread's page.\n *\n * If threadManager is set, delegates to it. Otherwise returns true (no isolation).\n * Subclasses can override for custom behavior.\n *\n * @returns true if session exists or thread isolation is not used\n */\n hasThreadSession(threadId: string): boolean {\n if (!this.threadManager) {\n // No thread manager - all threads share the same session\n return true;\n }\n\n const scope = this.threadManager.getScope();\n\n // Shared scope - all threads share the same session\n if (scope === 'shared') {\n return true;\n }\n\n // Check if this thread has an actual session\n return this.threadManager.hasSession(threadId);\n }\n\n /**\n * Get a session identifier for a specific thread.\n * In thread scope, returns a composite ID (browser:threadId).\n * In shared scope or without thread manager, returns the browser instance ID.\n */\n getSessionId(threadId?: string): string {\n if (!threadId || !this.threadManager) {\n return this.id;\n }\n\n const scope = this.threadManager.getScope();\n\n // Shared scope - all threads share the same session\n if (scope === 'shared') {\n return this.id;\n }\n\n // Thread scope - return composite ID\n return `${this.id}:${threadId}`;\n }\n\n /**\n * Start screencast only if browser is already running.\n * Does NOT launch the browser.\n * Uses config.screencast options as defaults if no options provided.\n *\n * For thread-isolated browsers ('browser' mode):\n * - Returns null if the thread doesn't have an existing browser session\n */\n async startScreencastIfBrowserActive(options?: ScreencastOptions): Promise<ScreencastStream | null> {\n if (!this.isBrowserRunning()) {\n return null;\n }\n\n // Merge config screencast defaults with call-site overrides\n const mergedOptions = this.config.screencast || options ? { ...this.config.screencast, ...options } : undefined;\n\n const threadId = mergedOptions?.threadId;\n const scope = this.threadManager?.getScope() ?? this.config.scope ?? 'shared';\n\n // Shared scope - just start the screencast\n if (scope === 'shared') {\n return this.startScreencast(mergedOptions);\n }\n\n // For 'thread' scope, only start if the thread has an existing session\n if (threadId && !this.hasThreadSession(threadId)) {\n return null;\n }\n\n return this.startScreencast(mergedOptions);\n }\n\n // ---------------------------------------------------------------------------\n // Event Injection (optional - for Studio live view)\n // ---------------------------------------------------------------------------\n\n /**\n * Inject a mouse event. Override in subclass if supported.\n * @param event - Mouse event parameters\n * @param threadId - Optional thread ID for thread-isolated sessions\n */\n async injectMouseEvent(_event: MouseEventParams, _threadId?: string): Promise<void> {\n throw new Error('Mouse event injection not supported by this provider');\n }\n\n /**\n * Inject a keyboard event. Override in subclass if supported.\n * @param event - Keyboard event parameters\n * @param threadId - Optional thread ID for thread-isolated sessions\n */\n async injectKeyboardEvent(_event: KeyboardEventParams, _threadId?: string): Promise<void> {\n throw new Error('Keyboard event injection not supported by this provider');\n }\n\n // ---------------------------------------------------------------------------\n // Abstract Tools Method\n // ---------------------------------------------------------------------------\n\n /**\n * Get the browser tools for this provider.\n *\n * Each provider returns its own set of tools. For example:\n * - AgentBrowser returns 17 deterministic tools using refs\n * - StagehandBrowser might return AI-powered tools (act, extract, observe)\n *\n * @returns Record of tool name to tool definition\n */\n abstract getTools(): Record<string, Tool<any, any>>;\n}\n","/**\n * Screencast types for CDP-based browser streaming.\n *\n * These types are shared between browser providers (AgentBrowser, Stagehand, etc.)\n * that support screencast via CDP.\n */\n\n/**\n * Options for starting a screencast stream.\n */\nexport interface ScreencastOptions {\n /** Image format (default: 'jpeg') */\n format?: 'jpeg' | 'png';\n /** JPEG quality 0-100 (default: 80) */\n quality?: number;\n /** Max width in pixels (default: 1280) */\n maxWidth?: number;\n /** Max height in pixels (default: 720) */\n maxHeight?: number;\n /** Capture every Nth frame (default: 1) */\n everyNthFrame?: number;\n /** Thread ID for thread-scoped screencasts (streams from thread's page) */\n threadId?: string;\n}\n\n/**\n * Data for a single screencast frame.\n */\nexport interface ScreencastFrameData {\n /** Base64-encoded image data */\n data: string;\n /** Frame timestamp in milliseconds */\n timestamp: number;\n /** Viewport information */\n viewport: {\n width: number;\n height: number;\n offsetTop?: number;\n scrollOffsetX?: number;\n scrollOffsetY?: number;\n pageScaleFactor?: number;\n };\n /** CDP session ID for acknowledgment (handled internally) */\n sessionId?: number;\n}\n\n/**\n * Events emitted by ScreencastStream.\n */\nexport interface ScreencastEvents {\n /** Emitted when a new frame is received */\n frame: (frame: ScreencastFrameData) => void;\n /** Emitted when screencast stops */\n stop: (reason: 'manual' | 'browser_closed' | 'error') => void;\n /** Emitted on errors */\n error: (error: Error) => void;\n /** Emitted when the page URL changes (navigation detected) */\n url: (url: string) => void;\n /** Index signature for TypedEmitter compatibility */\n [key: string]: (...args: any[]) => void;\n}\n\n/**\n * Default screencast options.\n */\nexport const SCREENCAST_DEFAULTS: Required<Omit<ScreencastOptions, 'threadId'>> = {\n format: 'jpeg',\n quality: 80,\n maxWidth: 1280,\n maxHeight: 720,\n everyNthFrame: 1,\n};\n\n/**\n * Abstract CDP session interface.\n * Both Playwright's CDPSession and direct CDP connections implement this.\n */\nexport interface CdpSessionLike {\n /** Send a CDP command */\n send(method: string, params?: Record<string, unknown>): Promise<unknown>;\n /** Register an event handler */\n on(event: string, handler: (...args: any[]) => void): void;\n /** Remove an event handler */\n off?(event: string, handler: (...args: any[]) => void): void;\n /** Detach the session */\n detach?(): Promise<void>;\n}\n\n/**\n * Provider interface for getting CDP sessions.\n * Browser providers implement this to expose CDP access.\n */\nexport interface CdpSessionProvider {\n /**\n * Get a CDP session for screencast/input injection.\n * The session should be attached to the current page.\n */\n getCdpSession(): Promise<CdpSessionLike>;\n\n /**\n * Check if the browser is currently running.\n */\n isBrowserRunning(): boolean;\n}\n","/**\n * CDP-based ScreencastStream implementation.\n *\n * This provides a unified screencast implementation that works with any\n * CDP session provider (Playwright, Puppeteer, direct CDP, etc.).\n */\n\nimport { EventEmitter } from 'node:events';\nimport type { CdpSessionLike, CdpSessionProvider, ScreencastFrameData, ScreencastOptions } from './types';\nimport { SCREENCAST_DEFAULTS } from './types';\n\n/**\n * CDP screencast frame event data from Page.screencastFrame\n */\ninterface CdpScreencastFrame {\n data: string;\n sessionId: number;\n metadata?: {\n deviceWidth?: number;\n deviceHeight?: number;\n offsetTop?: number;\n scrollOffsetX?: number;\n scrollOffsetY?: number;\n pageScaleFactor?: number;\n timestamp?: number;\n };\n}\n\n/**\n * ScreencastStream wraps CDP screencast with an event emitter interface.\n *\n * Works with any CDP session provider (Playwright, Puppeteer, direct CDP).\n *\n * @example\n * ```typescript\n * const stream = new ScreencastStream(cdpProvider, { quality: 80 });\n * stream.on('frame', (frame) => {\n * console.log(`Frame: ${frame.viewport.width}x${frame.viewport.height}`);\n * });\n * await stream.start();\n * // Later...\n * await stream.stop();\n * ```\n */\nexport class ScreencastStream extends EventEmitter {\n /** Whether screencast is currently active */\n private active: boolean = false;\n\n /** Resolved options with defaults applied (excludes threadId which is only used for page selection) */\n private options: Required<Omit<ScreencastOptions, 'threadId'>>;\n\n /** CDP session provider */\n private provider: CdpSessionProvider;\n\n /** Current CDP session */\n private cdpSession: CdpSessionLike | null = null;\n\n /** Frame handler reference (for cleanup) */\n private frameHandler: ((params: CdpScreencastFrame) => void) | null = null;\n\n /**\n * Creates a new ScreencastStream.\n *\n * @param provider - CDP session provider (browser instance)\n * @param options - Screencast configuration options\n */\n constructor(provider: CdpSessionProvider, options?: ScreencastOptions) {\n super();\n this.provider = provider;\n // Extract threadId (used by caller for page selection) and merge remaining options\n const { threadId: _, ...cdpOptions } = options ?? {};\n this.options = { ...SCREENCAST_DEFAULTS, ...cdpOptions };\n }\n\n /**\n * Start the screencast.\n * If already active, returns immediately.\n */\n async start(): Promise<void> {\n if (this.active) {\n return;\n }\n\n if (!this.provider.isBrowserRunning()) {\n throw new Error('Browser is not running');\n }\n\n try {\n // Get CDP session from provider\n this.cdpSession = await this.provider.getCdpSession();\n\n // Set up frame handler\n this.frameHandler = (params: CdpScreencastFrame) => {\n const frameData: ScreencastFrameData = {\n data: params.data,\n // CDP provides timestamp in seconds, convert to milliseconds for consistency\n timestamp: params.metadata?.timestamp ? params.metadata.timestamp * 1000 : Date.now(),\n viewport: {\n width: params.metadata?.deviceWidth ?? 0,\n height: params.metadata?.deviceHeight ?? 0,\n offsetTop: params.metadata?.offsetTop,\n scrollOffsetX: params.metadata?.scrollOffsetX,\n scrollOffsetY: params.metadata?.scrollOffsetY,\n pageScaleFactor: params.metadata?.pageScaleFactor,\n },\n sessionId: params.sessionId,\n };\n\n this.emit('frame', frameData);\n\n // Acknowledge frame to continue receiving\n this.acknowledgeFrame(params.sessionId);\n };\n\n this.cdpSession.on('Page.screencastFrame', this.frameHandler);\n\n // Start screencast via CDP\n try {\n await this.cdpSession.send('Page.startScreencast', {\n format: this.options.format,\n quality: this.options.quality,\n maxWidth: this.options.maxWidth,\n maxHeight: this.options.maxHeight,\n everyNthFrame: this.options.everyNthFrame,\n });\n } catch (startError) {\n // Clean up handler before re-throwing to prevent resource leak\n if (this.cdpSession?.off) {\n try {\n this.cdpSession.off('Page.screencastFrame', this.frameHandler);\n } catch {\n // Ignore cleanup errors\n }\n }\n this.frameHandler = null;\n this.cdpSession = null;\n throw startError;\n }\n\n this.active = true;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.emit('error', err);\n throw err;\n }\n }\n\n /**\n * Acknowledge a frame to CDP (required to continue receiving frames).\n */\n private acknowledgeFrame(sessionId: number): void {\n if (!this.cdpSession) return;\n\n this.cdpSession.send('Page.screencastFrameAck', { sessionId }).catch(() => {\n // Ignore ack errors - session may be closed\n });\n }\n\n /**\n * Stop the screencast and release resources.\n * Safe to call even if browser/CDP session is already closed.\n */\n async stop(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n this.active = false;\n let hadError = false;\n\n // Clean up handler regardless of CDP state\n if (this.cdpSession && this.frameHandler && this.cdpSession.off) {\n try {\n this.cdpSession.off('Page.screencastFrame', this.frameHandler);\n } catch {\n // Ignore - session may be dead\n }\n }\n this.frameHandler = null;\n\n // Try to stop screencast via CDP (may fail if browser closed)\n if (this.cdpSession) {\n try {\n await this.cdpSession.send('Page.stopScreencast');\n } catch {\n // Browser/session already closed - this is expected in external close scenarios\n hadError = true;\n }\n this.cdpSession = null;\n }\n\n this.emit('stop', hadError ? 'error' : 'manual');\n }\n\n /**\n * Check if screencast is currently active.\n */\n isActive(): boolean {\n return this.active;\n }\n\n /**\n * Emit a URL update event.\n * Browser providers call this when navigation is detected.\n */\n emitUrl(url: string): void {\n this.emit('url', url);\n }\n\n /**\n * Reconnect the screencast by stopping and restarting.\n * Use this when the active page/tab changes.\n *\n * @returns Promise that resolves when reconnection is complete\n * @throws Error if reconnection fails (also emits 'error' event)\n */\n async reconnect(): Promise<void> {\n // Clean up existing session\n if (this.cdpSession && this.frameHandler && this.cdpSession.off) {\n try {\n this.cdpSession.off('Page.screencastFrame', this.frameHandler);\n } catch {\n // Ignore - session may be dead\n }\n }\n this.frameHandler = null;\n\n // Try to stop screencast on old session (may fail if session is dead)\n if (this.cdpSession) {\n try {\n await this.cdpSession.send('Page.stopScreencast');\n } catch {\n // Old session may already be detached - this is expected\n }\n this.cdpSession = null;\n }\n\n // Mark as inactive so start() will work\n this.active = false;\n\n // Restart with fresh session from provider\n try {\n await this.start();\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n console.error('[ScreencastStream.reconnect] Failed to reconnect:', err);\n // Don't emit 'error' here - start() already emits it before rejecting\n throw err;\n }\n }\n}\n","/**\n * BrowserContextProcessor\n *\n * Input processor that injects browser context into agent prompts.\n * Similar to ChatChannelProcessor for channels.\n *\n * - `processInput`: Adds a system message with stable context (provider, sessionId, headless mode).\n * - `processInputStep`: At step 0, prepends a `<system-reminder>` to the user's message\n * with per-request data (current URL, page title).\n *\n * Reads from `requestContext.get('browser')`.\n *\n * @example\n * ```ts\n * const agent = new Agent({\n * browser: new AgentBrowser({ ... }),\n * inputProcessors: [new BrowserContextProcessor()],\n * });\n * ```\n */\n\nimport type {\n ProcessInputArgs,\n ProcessInputResult,\n ProcessInputStepArgs,\n ProcessInputStepResult,\n} from '../processors/index';\n\n/**\n * Browser context stored in RequestContext.\n * Set by the browser implementation or deployer.\n */\nexport interface BrowserContext {\n /** Browser provider name (e.g., \"agent-browser\", \"stagehand\") */\n provider: string;\n\n /** Session ID for tracking */\n sessionId?: string;\n\n /** Whether browser is running in headless mode */\n headless?: boolean;\n\n /** Current page URL (updated per-request) */\n currentUrl?: string;\n\n /** Current page title (updated per-request) */\n pageTitle?: string;\n\n /** Whether browser is currently running */\n isRunning?: boolean;\n}\n\n/**\n * Input processor that injects browser context into agent prompts.\n */\nexport class BrowserContextProcessor {\n readonly id = 'browser-context';\n\n processInput(args: ProcessInputArgs): ProcessInputResult {\n const ctx = args.requestContext?.get('browser') as BrowserContext | undefined;\n if (!ctx) return args.messageList;\n\n const lines = [`You have access to a browser (${ctx.provider}).`];\n\n if (ctx.headless === false) {\n lines.push('The browser is running in visible mode (not headless).');\n }\n\n if (ctx.sessionId) {\n lines.push(`Session ID: ${ctx.sessionId}`);\n }\n\n const systemMessages = [...args.systemMessages, { role: 'system' as const, content: lines.join(' ') }];\n\n return { messages: args.messages, systemMessages };\n }\n\n processInputStep(args: ProcessInputStepArgs): ProcessInputStepResult | undefined {\n // Only inject per-request context at the first step\n if (args.stepNumber !== 0) return;\n\n const ctx = args.requestContext?.get('browser') as BrowserContext | undefined;\n if (!ctx) return;\n\n const parts: string[] = [];\n\n if (ctx.currentUrl) {\n parts.push(`Current URL: ${ctx.currentUrl}`);\n }\n\n if (ctx.pageTitle) {\n parts.push(`Page title: ${ctx.pageTitle}`);\n }\n\n if (ctx.isRunning === false) {\n parts.push('Browser is not currently running.');\n }\n\n if (parts.length === 0) return;\n\n const reminder = `<system-reminder>${parts.join(' | ')}</system-reminder>\\n\\n`;\n\n // Prepend reminder to the last user message's text parts\n const messages = [...args.messages];\n\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role === 'user') {\n const content = msg.content;\n // MastraMessageContentV2: { format: 2, parts: [...] }\n const existingParts = content.parts ?? [];\n const firstTextIdx = existingParts.findIndex((p: { type: string }) => p.type === 'text');\n\n if (firstTextIdx >= 0) {\n const textPart = existingParts[firstTextIdx] as { type: 'text'; text: string };\n const newParts = [...existingParts];\n newParts[firstTextIdx] = { ...textPart, text: reminder + textPart.text };\n messages[i] = { ...msg, content: { ...content, parts: newParts } };\n } else {\n messages[i] = {\n ...msg,\n content: {\n ...content,\n parts: [{ type: 'text' as const, text: reminder }, ...existingParts],\n },\n };\n }\n break;\n }\n }\n\n return { messages };\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/browser/errors.ts","../../src/browser/processor.ts","../../src/browser/thread-manager.ts","../../src/browser/browser.ts","../../src/browser/screencast/types.ts","../../src/browser/screencast/screencast-stream.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Unified error handling for browser tools.\n *\n * All browser tools return errors in this consistent format,\n * providing LLM-friendly messages and recovery hints.\n */\n\n/**\n * Error codes for browser tool failures.\n *\n * These codes help agents understand what went wrong\n * and whether retry or recovery is possible.\n */\nexport type ErrorCode =\n | 'stale_ref' // Ref no longer valid after page change\n | 'element_not_found' // Element doesn't exist\n | 'element_blocked' // Element covered by overlay\n | 'element_not_visible' // Element hidden\n | 'not_focusable' // Can't type into element\n | 'timeout' // Operation timed out\n | 'browser_closed' // Browser was externally closed\n | 'browser_error'; // Generic browser error\n\n/**\n * Structured error response for browser tool failures.\n *\n * Provides LLM-friendly error information with optional recovery hints.\n */\nexport interface BrowserToolError {\n /** Always false for error responses */\n success: false;\n /** Error classification code */\n code: ErrorCode;\n /** LLM-friendly error description */\n message: string;\n /** Suggested recovery action (only when actionable) */\n recoveryHint?: string;\n /** Whether the operation can be retried */\n canRetry: boolean;\n}\n\n/**\n * Error codes that are generally retryable.\n */\nconst RETRYABLE_CODES: Set<ErrorCode> = new Set(['timeout', 'element_blocked']);\n\n/**\n * Creates a structured error response for browser tools.\n *\n * Sets canRetry based on the error code: true for 'timeout' and 'element_blocked'.\n *\n * @param code - Error classification code\n * @param message - LLM-friendly error description\n * @param hint - Optional recovery hint (only when actionable)\n * @returns Typed BrowserToolError with canRetry set automatically\n */\nexport function createError(code: ErrorCode, message: string, hint?: string): BrowserToolError {\n return {\n success: false,\n code,\n message,\n recoveryHint: hint,\n canRetry: RETRYABLE_CODES.has(code),\n };\n}\n","/**\n * BrowserContextProcessor\n *\n * Input processor that injects browser context into agent prompts.\n * Similar to ChatChannelProcessor for channels.\n *\n * - `processInput`: Adds a system message with stable context (provider, sessionId, headless mode).\n * - `processInputStep`: At step 0, prepends a `<system-reminder>` to the user's message\n * with per-request data (current URL, page title).\n *\n * Reads from `requestContext.get('browser')`.\n *\n * @example\n * ```ts\n * const agent = new Agent({\n * browser: new AgentBrowser({ ... }),\n * inputProcessors: [new BrowserContextProcessor()],\n * });\n * ```\n */\n\nimport type {\n ProcessInputArgs,\n ProcessInputResult,\n ProcessInputStepArgs,\n ProcessInputStepResult,\n} from '../processors/index';\n\n/**\n * Browser context stored in RequestContext.\n * Set by the browser implementation or deployer.\n */\nexport interface BrowserContext {\n /** Browser provider name (e.g., \"agent-browser\", \"stagehand\") */\n provider: string;\n\n /** Session ID for tracking */\n sessionId?: string;\n\n /** Whether browser is running in headless mode */\n headless?: boolean;\n\n /** Current page URL (updated per-request) */\n currentUrl?: string;\n\n /** Current page title (updated per-request) */\n pageTitle?: string;\n\n /** Whether browser is currently running */\n isRunning?: boolean;\n}\n\n/**\n * Input processor that injects browser context into agent prompts.\n */\nexport class BrowserContextProcessor {\n readonly id = 'browser-context';\n\n processInput(args: ProcessInputArgs): ProcessInputResult {\n const ctx = args.requestContext?.get('browser') as BrowserContext | undefined;\n if (!ctx) return args.messageList;\n\n const lines = [`You have access to a browser (${ctx.provider}).`];\n\n if (ctx.headless === false) {\n lines.push('The browser is running in visible mode (not headless).');\n }\n\n if (ctx.sessionId) {\n lines.push(`Session ID: ${ctx.sessionId}`);\n }\n\n const systemMessages = [...args.systemMessages, { role: 'system' as const, content: lines.join(' ') }];\n\n return { messages: args.messages, systemMessages };\n }\n\n processInputStep(args: ProcessInputStepArgs): ProcessInputStepResult | undefined {\n // Only inject per-request context at the first step\n if (args.stepNumber !== 0) return;\n\n const ctx = args.requestContext?.get('browser') as BrowserContext | undefined;\n if (!ctx) return;\n\n const parts: string[] = [];\n\n if (ctx.currentUrl) {\n parts.push(`Current URL: ${ctx.currentUrl}`);\n }\n\n if (ctx.pageTitle) {\n parts.push(`Page title: ${ctx.pageTitle}`);\n }\n\n if (ctx.isRunning === false) {\n parts.push('Browser is not currently running.');\n }\n\n if (parts.length === 0) return;\n\n const reminder = `<system-reminder>${parts.join(' | ')}</system-reminder>\\n\\n`;\n\n // Prepend reminder to the last user message's text parts\n const messages = [...args.messages];\n\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role === 'user') {\n const content = msg.content;\n // MastraMessageContentV2: { format: 2, parts: [...] }\n const existingParts = content.parts ?? [];\n const firstTextIdx = existingParts.findIndex((p: { type: string }) => p.type === 'text');\n\n if (firstTextIdx >= 0) {\n const textPart = existingParts[firstTextIdx] as { type: 'text'; text: string };\n const newParts = [...existingParts];\n newParts[firstTextIdx] = { ...textPart, text: reminder + textPart.text };\n messages[i] = { ...msg, content: { ...content, parts: newParts } };\n } else {\n messages[i] = {\n ...msg,\n content: {\n ...content,\n parts: [{ type: 'text' as const, text: reminder }, ...existingParts],\n },\n };\n }\n break;\n }\n }\n\n return { messages };\n }\n}\n","/**\n * ThreadManager - Abstract base class for managing thread-scoped browser sessions.\n *\n * Similar to ProcessManager for workspaces, this centralizes thread lifecycle logic\n * and makes thread isolation reusable across browser providers.\n *\n * Browser scope modes:\n * - 'shared': All threads share a single browser instance\n * - 'thread': Each thread gets its own browser instance (full isolation)\n */\n\nimport type { IMastraLogger } from '../logger';\n\n/** Browser scope mode - determines how browser instances are shared across threads */\nexport type BrowserScope = 'shared' | 'thread';\n\n/** Default thread ID used when no thread is specified */\nexport const DEFAULT_THREAD_ID = '__default__';\n\n/**\n * Represents a single tab's state for persistence.\n */\nexport interface BrowserTabState {\n url: string;\n title?: string;\n}\n\n/**\n * Full browser state for persistence and restoration.\n */\nexport interface BrowserState {\n tabs: BrowserTabState[];\n activeTabIndex: number;\n}\n\n/**\n * Represents an active thread session.\n */\nexport interface ThreadSession {\n /** Unique thread identifier */\n threadId: string;\n /** Timestamp when session was created */\n createdAt: number;\n /** Full browser state for this thread (for restore on relaunch) */\n browserState?: BrowserState;\n}\n\n/**\n * Configuration for ThreadManager.\n */\nexport interface ThreadManagerConfig {\n /** Browser scope mode */\n scope: BrowserScope;\n /** Logger instance */\n logger?: IMastraLogger;\n /** Callback when a new session is created */\n onSessionCreated?: (session: ThreadSession) => void;\n /** Callback when a session is destroyed */\n onSessionDestroyed?: (threadId: string) => void;\n}\n\n/**\n * Abstract base class for managing thread-scoped browser sessions.\n *\n * @typeParam TManager - The browser manager type (e.g., BrowserManagerLike, Stagehand)\n */\nexport abstract class ThreadManager<TManager = unknown> {\n protected readonly scope: BrowserScope;\n protected readonly logger?: IMastraLogger;\n protected readonly sessions = new Map<string, ThreadSession>();\n protected activeThreadId: string = DEFAULT_THREAD_ID;\n\n /** Preserved browser state that survives session clears (for browser restore) */\n protected readonly savedBrowserStates = new Map<string, BrowserState>();\n\n /** Shared manager instance (used for 'shared' scope) */\n protected sharedManager: TManager | null = null;\n\n /** Map of thread ID to dedicated manager instance (for 'thread' scope) */\n protected readonly threadManagers = new Map<string, TManager>();\n\n private readonly onSessionCreated?: (session: ThreadSession) => void;\n private readonly onSessionDestroyed?: (threadId: string) => void;\n\n constructor(config: ThreadManagerConfig) {\n this.scope = config.scope;\n this.logger = config.logger;\n this.onSessionCreated = config.onSessionCreated;\n this.onSessionDestroyed = config.onSessionDestroyed;\n }\n\n /**\n * Get the current browser scope mode.\n */\n getScope(): BrowserScope {\n return this.scope;\n }\n\n /**\n * Get the currently active thread ID.\n */\n getActiveThreadId(): string {\n return this.activeThreadId;\n }\n\n /**\n * Set the shared manager instance (called after browser launch).\n */\n setSharedManager(manager: TManager): void {\n this.sharedManager = manager;\n }\n\n /**\n * Clear the shared manager instance (called when browser disconnects).\n */\n clearSharedManager(): void {\n this.sharedManager = null;\n }\n\n /**\n * Get the manager for an existing thread session without creating a new one.\n *\n * For 'thread' scope: Returns the thread-specific manager, or null if no session exists.\n * For 'shared' scope: Returns the shared manager (all threads use the same instance).\n *\n * @param threadId - Thread identifier (defaults to DEFAULT_THREAD_ID)\n * @returns The manager for the thread, or null if not found (thread scope only)\n */\n getExistingManagerForThread(threadId?: string): TManager | null {\n const effectiveThreadId = threadId ?? DEFAULT_THREAD_ID;\n if (this.scope === 'thread') {\n return this.threadManagers.get(effectiveThreadId) ?? null;\n }\n return this.sharedManager;\n }\n\n /**\n * Check if any thread managers are still running (for 'thread' scope).\n */\n hasActiveThreadManagers(): boolean {\n return this.threadManagers.size > 0;\n }\n\n /**\n * Clear all session tracking without closing managers.\n * Used when browsers have been externally closed and we just need to reset state.\n */\n clearAllSessions(): void {\n this.threadManagers.clear();\n this.sessions.clear();\n this.activeThreadId = DEFAULT_THREAD_ID;\n }\n\n /**\n * Get a session by thread ID.\n */\n getSession(threadId: string): ThreadSession | undefined {\n return this.sessions.get(threadId);\n }\n\n /**\n * Check if a session exists for a thread.\n */\n hasSession(threadId: string): boolean {\n return this.sessions.has(threadId);\n }\n\n /**\n * List all active sessions.\n */\n listSessions(): ThreadSession[] {\n return Array.from(this.sessions.values());\n }\n\n /**\n * Get the number of active sessions.\n */\n getSessionCount(): number {\n return this.sessions.size;\n }\n\n /**\n * Get or create a session for a thread, and return the browser manager for that thread.\n *\n * For 'shared' scope, returns the shared manager.\n * For 'thread' scope, creates/returns a dedicated manager for the thread.\n *\n * @param threadId - Thread identifier (uses DEFAULT_THREAD_ID if not provided)\n * @returns The browser manager for the thread\n */\n async getManagerForThread(threadId?: string): Promise<TManager> {\n const effectiveThreadId = threadId ?? DEFAULT_THREAD_ID;\n\n // Shared scope - always use shared manager\n if (this.scope === 'shared' || effectiveThreadId === DEFAULT_THREAD_ID) {\n return this.getSharedManager();\n }\n\n // Check if session already exists\n let session = this.sessions.get(effectiveThreadId);\n\n if (!session) {\n // Create new session\n session = await this.createSession(effectiveThreadId);\n this.sessions.set(effectiveThreadId, session);\n this.logger?.debug?.(`Created thread session: ${effectiveThreadId}`);\n this.onSessionCreated?.(session);\n }\n\n this.activeThreadId = effectiveThreadId;\n return this.getManagerForSession(session);\n }\n\n /**\n * Destroy a specific thread's session.\n *\n * @param threadId - Thread identifier\n */\n async destroySession(threadId: string): Promise<void> {\n const session = this.sessions.get(threadId);\n if (!session) {\n return;\n }\n\n await this.doDestroySession(session);\n this.threadManagers.delete(threadId);\n this.sessions.delete(threadId);\n this.logger?.debug?.(`Destroyed thread session: ${threadId}`);\n this.onSessionDestroyed?.(threadId);\n\n // Reset active thread if we destroyed it\n if (this.activeThreadId === threadId) {\n this.activeThreadId = DEFAULT_THREAD_ID;\n }\n }\n\n /**\n * Destroy all thread sessions.\n */\n async destroyAllSessions(): Promise<void> {\n const threadIds = Array.from(this.sessions.keys());\n for (const threadId of threadIds) {\n await this.destroySession(threadId);\n }\n this.activeThreadId = DEFAULT_THREAD_ID;\n }\n\n /**\n * Update the browser state for a thread session.\n * Also saves to persistent storage so state survives session clears.\n */\n updateBrowserState(threadId: string, state: BrowserState): void {\n // Filter out empty/blank tabs\n const filteredTabs = state.tabs.filter(tab => tab.url && tab.url !== 'about:blank');\n if (filteredTabs.length === 0) {\n return;\n }\n\n const filteredState: BrowserState = {\n tabs: filteredTabs,\n activeTabIndex: Math.max(0, Math.min(state.activeTabIndex, filteredTabs.length - 1)),\n };\n\n const session = this.sessions.get(threadId);\n if (session) {\n session.browserState = filteredState;\n }\n // Also save to persistent map so it survives session clears\n this.savedBrowserStates.set(threadId, filteredState);\n }\n\n /**\n * Get the saved browser state for a thread (survives session clears).\n */\n getSavedBrowserState(threadId: string): BrowserState | undefined {\n // First check current session\n const session = this.sessions.get(threadId);\n if (session?.browserState) {\n return session.browserState;\n }\n // Fall back to saved state\n return this.savedBrowserStates.get(threadId);\n }\n\n /**\n * Clear a specific thread's session without closing the browser.\n * Used when a thread's browser has been externally closed.\n * Preserves the browser state for potential restoration.\n *\n * @param threadId - The thread ID to clear\n */\n clearSession(threadId: string): void {\n // Save the browser state before clearing so it can be restored on relaunch\n const session = this.sessions.get(threadId);\n if (session?.browserState) {\n this.savedBrowserStates.set(threadId, session.browserState);\n }\n this.threadManagers.delete(threadId);\n this.sessions.delete(threadId);\n // Reset activeThreadId if we just cleared it\n if (this.activeThreadId === threadId) {\n this.activeThreadId = DEFAULT_THREAD_ID;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Abstract methods to be implemented by subclasses\n // ---------------------------------------------------------------------------\n\n /**\n * Get the shared browser manager (used for 'shared' scope and default thread).\n * @throws Error if shared manager is not initialized\n */\n protected getSharedManager(): TManager {\n if (!this.sharedManager) {\n throw new Error('Browser not launched');\n }\n return this.sharedManager;\n }\n\n /**\n * Create a new session for a thread.\n * Called when a thread is accessed for the first time.\n */\n protected abstract createSession(threadId: string): Promise<ThreadSession>;\n\n /**\n * Get the browser manager for a specific session.\n */\n protected abstract getManagerForSession(session: ThreadSession): TManager;\n\n /**\n * Destroy a session and clean up resources.\n */\n protected abstract doDestroySession(session: ThreadSession): Promise<void>;\n}\n","/**\n * MastraBrowser Base Class\n *\n * Abstract base class for browser providers. Extends MastraBase for logger integration.\n *\n * ## Architecture\n *\n * Each browser provider defines its own tools via the `getTools()` method.\n * This allows different providers to offer different capabilities:\n *\n * - **AgentBrowser**: 17 deterministic tools using refs ([ref=e1], [ref=e2])\n * - **StagehandBrowser**: AI-powered tools (act, extract, observe)\n *\n * ## Two Paradigms\n *\n * Browser providers fall into two paradigms:\n *\n * 1. **Deterministic** (Playwright, agent-browser) - Uses refs and selectors\n * 2. **AI-powered** (Stagehand) - Uses natural language instructions\n *\n * Both extend this base class and implement `getTools()` to return their tools.\n */\n\nimport { MastraBase } from '../base';\nimport { RegisteredLogger } from '../logger/constants';\nimport { isProcessorWorkflow } from '../processors/index';\nimport type { InputProcessor, InputProcessorOrWorkflow } from '../processors/index';\nimport type { Tool } from '../tools/tool';\nimport { createError } from './errors';\nimport type { BrowserToolError, ErrorCode } from './errors';\nimport { BrowserContextProcessor } from './processor';\nimport type { ScreencastOptions as ScreencastOptionsType } from './screencast/types';\nimport { DEFAULT_THREAD_ID } from './thread-manager';\nimport type { BrowserState, BrowserTabState, BrowserScope, ThreadManager } from './thread-manager';\n\n// Re-export screencast types from the screencast module\nexport type { ScreencastOptions, ScreencastFrameData, ScreencastEvents } from './screencast/types';\n\n// Alias for internal use\ntype ScreencastOptions = ScreencastOptionsType;\n\n// =============================================================================\n// Status & Lifecycle Types\n// =============================================================================\n\n/**\n * Browser provider status.\n */\nexport type BrowserStatus = 'pending' | 'launching' | 'ready' | 'error' | 'closing' | 'closed';\n\n/**\n * Lifecycle hook that fires during browser state transitions.\n */\nexport type BrowserLifecycleHook = (args: { browser: MastraBrowser }) => void | Promise<void>;\n\n// =============================================================================\n// Configuration Types\n// =============================================================================\n\n/**\n * CDP URL provider - can be a static string or an async function.\n * Useful for cloud providers where the CDP URL may change per session.\n */\nexport type CdpUrlProvider = string | (() => string | Promise<string>);\n\n/**\n * Base configuration properties shared by all browser providers.\n * This interface contains fields common to all browser configurations.\n *\n * **For extending**: Use this interface when creating provider-specific configs\n * (e.g., `interface MyProviderConfig extends BrowserConfigBase`).\n *\n * **For consuming**: Use {@link BrowserConfig} which adds compile-time validation\n * that `cdpUrl` and `scope: 'thread'` cannot be used together.\n */\nexport interface BrowserConfigBase {\n /**\n * Whether to run the browser in headless mode (no visible UI).\n * @default true\n */\n headless?: boolean;\n\n /**\n * Browser viewport dimensions.\n * Controls the size of the browser window and how websites render.\n */\n viewport?: {\n width: number;\n height: number;\n };\n\n /**\n * Default timeout in milliseconds for browser operations.\n * @default 10000 (10 seconds)\n */\n timeout?: number;\n\n /**\n * CDP WebSocket URL or async provider function.\n * When provided, connects to an existing browser instead of launching a new one.\n * Useful for cloud providers (Browserbase, Browserless, Kernel, etc.).\n *\n * **Important:** When using `cdpUrl`, you must use `scope: 'shared'` (or omit `scope`\n * to let it default to 'shared' behavior). Using `cdpUrl` with `scope: 'thread'`\n * will throw an error because thread isolation requires spawning separate browser\n * instances, which isn't possible when connecting to an existing browser via CDP.\n *\n * @example\n * ```ts\n * // Connect to a local Chrome with remote debugging enabled\n * { cdpUrl: 'ws://localhost:9222' }\n *\n * // Connect to Browserless cloud provider\n * { cdpUrl: 'wss://chrome.browserless.io?token=YOUR_TOKEN', scope: 'shared' }\n *\n * // Use an async provider function for dynamic URLs\n * { cdpUrl: async () => await fetchBrowserlessUrl() }\n * ```\n */\n cdpUrl?: CdpUrlProvider;\n\n /**\n * Browser instance scope across threads.\n *\n * - `'thread'` (default): Each thread gets its own isolated browser instance.\n * Best for parallel agents that need separate browser states.\n *\n * - `'shared'`: All threads share a single browser instance.\n * Required when using `cdpUrl` to connect to an existing browser.\n *\n * **Important:** `scope: 'thread'` cannot be used with `cdpUrl` because thread\n * isolation requires spawning new browser instances, which isn't possible when\n * connecting to an existing browser via CDP. This configuration will throw an error.\n *\n * @default 'thread'\n *\n * @example\n * ```ts\n * // Isolated browsers per thread (default)\n * { scope: 'thread' }\n *\n * // Shared browser for all threads\n * { scope: 'shared' }\n *\n * // When using cdpUrl, scope must be 'shared'\n * { cdpUrl: 'ws://localhost:9222', scope: 'shared' }\n * ```\n */\n scope?: BrowserScope;\n\n /**\n * Called after the browser reaches 'ready' status.\n */\n onLaunch?: BrowserLifecycleHook;\n\n /**\n * Called before the browser is closed.\n */\n onClose?: BrowserLifecycleHook;\n\n /**\n * Screencast options for streaming browser frames.\n * Controls image format, quality, and dimensions.\n */\n screencast?: ScreencastOptions;\n}\n\n/**\n * Browser configuration with compile-time enforcement of cdpUrl/scope compatibility.\n *\n * This type enforces that `cdpUrl` and `scope: 'thread'` cannot be used together:\n * - When `cdpUrl` is provided, `scope` must be `'shared'` or omitted\n * - When `scope: 'thread'` is used, `cdpUrl` must not be provided\n *\n * @example\n * ```ts\n * // Valid configurations:\n * { headless: true } // Local browser, thread scope (default)\n * { scope: 'thread' } // Explicit thread isolation\n * { scope: 'shared' } // Shared browser\n * { cdpUrl: 'ws://localhost:9222' } // CDP connection, defaults to shared\n * { cdpUrl: 'ws://localhost:9222', scope: 'shared' } // CDP with explicit shared\n *\n * // Invalid configuration (TypeScript error):\n * { cdpUrl: 'ws://localhost:9222', scope: 'thread' } // Error: cannot combine cdpUrl with thread scope\n * ```\n */\nexport type BrowserConfig =\n | (BrowserConfigBase & { cdpUrl?: undefined; scope?: BrowserScope })\n | (BrowserConfigBase & { cdpUrl: CdpUrlProvider; scope?: 'shared' });\n\n// =============================================================================\n// Screencast Types (re-exported from ./screencast/types)\n// =============================================================================\n\n/**\n * A screencast stream that emits frames.\n * Uses EventEmitter pattern for frame delivery.\n */\nexport interface ScreencastStream {\n /** Stop the screencast */\n stop(): Promise<void>;\n /** Check if screencast is active */\n isActive(): boolean;\n /** Reconnect the screencast (e.g., after tab change) */\n reconnect(): Promise<void>;\n /** Register event handlers */\n on(event: 'frame', handler: (frame: { data: string; viewport: { width: number; height: number } }) => void): this;\n on(event: 'stop', handler: (reason: string) => void): this;\n on(event: 'error', handler: (error: Error) => void): this;\n on(event: 'url', handler: (url: string) => void): this;\n /** Emit a URL update (called by browser providers on navigation) */\n emitUrl(url: string): void;\n}\n\n// =============================================================================\n// Event Injection Types (for Studio live view)\n// =============================================================================\n\n/**\n * Mouse event parameters for CDP injection.\n */\nexport interface MouseEventParams {\n type: 'mousePressed' | 'mouseReleased' | 'mouseMoved' | 'mouseWheel';\n x: number;\n y: number;\n button?: 'left' | 'right' | 'middle' | 'none';\n clickCount?: number;\n deltaX?: number;\n deltaY?: number;\n modifiers?: number;\n}\n\n/**\n * Keyboard event parameters for CDP injection.\n */\nexport interface KeyboardEventParams {\n type: 'keyDown' | 'keyUp' | 'char';\n key?: string;\n code?: string;\n text?: string;\n modifiers?: number;\n /** Windows virtual key code (required for non-printable keys like Enter, Tab, Arrow keys) */\n windowsVirtualKeyCode?: number;\n}\n\n// =============================================================================\n// MastraBrowser Base Class\n// =============================================================================\n\n/**\n * Abstract base class for browser providers.\n *\n * Providers extend this class and implement the abstract methods.\n * Each method corresponds to one of the 17 flat tools.\n */\nexport abstract class MastraBrowser extends MastraBase {\n // ---------------------------------------------------------------------------\n // Abstract Identity (providers must define)\n // ---------------------------------------------------------------------------\n\n /** Unique instance identifier */\n abstract readonly id: string;\n\n /** Human-readable name */\n abstract readonly name: string;\n\n /** Provider type (e.g., 'playwright', 'stagehand', 'browserbase') */\n abstract readonly provider: string;\n\n // ---------------------------------------------------------------------------\n // State\n // ---------------------------------------------------------------------------\n\n /** Current lifecycle status */\n status: BrowserStatus = 'pending';\n\n /** Error message when status is 'error' */\n error?: string;\n\n /**\n * Whether the browser is running in headless mode.\n * Returns true by default if not explicitly configured.\n */\n get headless(): boolean {\n return this.config.headless ?? true;\n }\n\n /** Last known browser state before browser was closed (for restore on relaunch) */\n protected lastBrowserState?: BrowserState;\n\n /**\n * Shared manager instance for 'shared' scope mode.\n * Type varies by provider (e.g., BrowserManager for agent-browser, Stagehand for stagehand).\n * Providers should cast this to their specific type when accessing.\n */\n protected sharedManager: unknown = null;\n\n /** Configuration */\n protected readonly config: BrowserConfig;\n\n /**\n * Thread manager for handling thread-scoped browser sessions.\n * Set by subclasses that support thread isolation.\n */\n protected threadManager?: ThreadManager;\n\n /**\n * Current thread ID for browser operations.\n * Used by thread isolation to route operations to the correct session.\n */\n protected currentThreadId: string = DEFAULT_THREAD_ID;\n\n // ---------------------------------------------------------------------------\n // Screencast State\n // ---------------------------------------------------------------------------\n\n /** Default key for shared scope screencast streams */\n protected static readonly SHARED_STREAM_KEY = '__shared__';\n\n /** Active screencast streams per thread (for triggering reconnects on tab changes) */\n protected activeScreencastStreams = new Map<string, ScreencastStream>();\n\n /**\n * Get the stream key for a thread (or shared key for shared scope).\n * @param threadId - Optional thread ID\n * @returns The stream key to use for the screencast streams map\n */\n protected getStreamKey(threadId?: string): string {\n return threadId || MastraBrowser.SHARED_STREAM_KEY;\n }\n\n /**\n * Reconnect the active screencast for a specific thread.\n * Called internally when tabs are switched or closed.\n */\n protected async reconnectScreencastForThread(threadId: string | undefined, reason: string): Promise<void> {\n const streamKey = this.getStreamKey(threadId);\n const stream = this.activeScreencastStreams.get(streamKey);\n if (!stream || !stream.isActive()) {\n return;\n }\n\n // Check if browser is still running before attempting reconnect\n if (!this.isBrowserRunning()) {\n this.logger.debug?.('Skipping screencast reconnect - browser not running');\n return;\n }\n\n // For thread scope, also check if this specific thread still has a session\n const scope = this.getScope();\n if (scope === 'thread' && threadId && !this.threadManager?.getExistingManagerForThread(threadId)) {\n this.logger.debug?.(`Skipping screencast reconnect - no session for thread ${threadId}`);\n return;\n }\n\n this.logger.debug?.(`Reconnecting screencast: ${reason}`);\n\n try {\n // Small delay to let tab state settle\n await new Promise(resolve => setTimeout(resolve, 150));\n await stream.reconnect();\n\n // Emit the URL of the new active page after reconnecting\n const activePage = await this.getActivePage(threadId);\n if (activePage) {\n const url = activePage.url();\n if (url) {\n stream.emitUrl(url);\n }\n }\n } catch (error) {\n this.logger.debug?.('Screencast reconnect failed', error);\n }\n }\n\n /**\n * Update the browser state in the thread session.\n * Called on navigation, tab open/close to keep state fresh.\n */\n protected updateSessionBrowserState(threadId?: string): void {\n try {\n const effectiveThreadId = threadId ?? this.getCurrentThread() ?? DEFAULT_THREAD_ID;\n const state = this.getBrowserStateForThread(effectiveThreadId);\n if (state) {\n this.threadManager?.updateBrowserState(effectiveThreadId, state);\n }\n } catch {\n // Silently ignore errors during state update\n }\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle Promise Tracking (prevents race conditions)\n // ---------------------------------------------------------------------------\n\n private _launchPromise?: Promise<void>;\n private _closePromise?: Promise<void>;\n\n // ---------------------------------------------------------------------------\n // Constructor\n // ---------------------------------------------------------------------------\n\n constructor(config: BrowserConfig = {}) {\n super({ name: 'MastraBrowser', component: RegisteredLogger.BROWSER });\n this.config = config;\n\n // Validate configuration: cdpUrl and scope: 'thread' are mutually exclusive\n // When connecting to an external browser via cdpUrl, we connect to a single existing browser.\n // Thread isolation requires spawning separate browser instances, which isn't possible with cdpUrl.\n // Note: The BrowserConfig type enforces this at compile-time, but we keep this runtime check\n // for better error messages when users bypass TypeScript (e.g., from JavaScript or casting).\n // We capture scope before checking cdpUrl to avoid TypeScript narrowing the union type.\n const scope = config.scope;\n if (config.cdpUrl && scope === 'thread') {\n throw new Error(\n 'Invalid browser configuration: \"cdpUrl\" and \"scope: \\'thread\\'\" cannot be used together.\\n\\n' +\n '• cdpUrl connects to a single existing browser instance (all threads share it)\\n' +\n '• scope: \"thread\" requires spawning separate browser instances per thread\\n\\n' +\n 'To fix this, either:\\n' +\n '1. Remove cdpUrl to let the provider spawn separate browser instances (supports thread isolation)\\n' +\n '2. Use scope: \"shared\" when connecting via cdpUrl (all threads share one browser)',\n );\n }\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle Management\n // ---------------------------------------------------------------------------\n\n /**\n * Launch the browser. Override in subclass.\n * Called by launch() wrapper which handles status and race conditions.\n */\n protected abstract doLaunch(): Promise<void>;\n\n /**\n * Close the browser. Override in subclass.\n * Called by close() wrapper which handles status and race conditions.\n */\n protected abstract doClose(): Promise<void>;\n\n /**\n * Launch the browser.\n * Race-condition-safe - handles concurrent calls, status management, and lifecycle hooks.\n */\n async launch(): Promise<void> {\n // Already ready\n if (this.status === 'ready') {\n return;\n }\n\n // Already launching - wait for existing promise\n if (this.status === 'launching' && this._launchPromise) {\n return this._launchPromise;\n }\n\n // Can't launch if closing/closed\n if (this.status === 'closing' || this.status === 'closed') {\n throw new Error(`Cannot launch browser in '${this.status}' state`);\n }\n\n this.status = 'launching';\n this.error = undefined;\n\n this._launchPromise = (async () => {\n try {\n await this.doLaunch();\n this.status = 'ready';\n\n // Fire onLaunch hook\n if (this.config.onLaunch) {\n await this.config.onLaunch({ browser: this });\n }\n\n // Notify onBrowserReady callbacks\n this.notifyBrowserReady();\n } catch (err) {\n this.status = 'error';\n this.error = err instanceof Error ? err.message : String(err);\n throw err;\n } finally {\n this._launchPromise = undefined;\n }\n })();\n\n return this._launchPromise;\n }\n\n /**\n * Close the browser.\n * Race-condition-safe - handles concurrent calls, status management, and lifecycle hooks.\n */\n async close(): Promise<void> {\n // Already closed\n if (this.status === 'closed') {\n return;\n }\n\n // Already closing - wait for existing promise\n if (this.status === 'closing' && this._closePromise) {\n return this._closePromise;\n }\n\n // Wait for in-flight launch to complete before closing\n // This prevents race conditions where close() executes against a half-initialized provider\n if (this.status === 'launching' && this._launchPromise) {\n try {\n await this._launchPromise;\n } catch {\n // Launch failed - status is now 'error', nothing to close\n // Ensure we're in a clean closed state and return early\n this.status = 'closed';\n return;\n }\n }\n\n // Fire onClose hook before closing\n if (this.config.onClose && this.status === 'ready') {\n await this.config.onClose({ browser: this });\n }\n\n // Save browser state before closing for potential restore on relaunch\n const currentState = await this.getBrowserState();\n if (currentState && currentState.tabs.length > 0) {\n this.lastBrowserState = currentState;\n }\n\n this.status = 'closing';\n\n this._closePromise = (async () => {\n try {\n await this.doClose();\n this.status = 'closed';\n this.notifyBrowserClosed();\n } catch (err) {\n this.status = 'error';\n this.error = err instanceof Error ? err.message : String(err);\n throw err;\n } finally {\n this._closePromise = undefined;\n }\n })();\n\n return this._closePromise;\n }\n\n /**\n * Ensure the browser is ready, launching if needed.\n * If browser was previously closed, it will be re-launched.\n */\n async ensureReady(): Promise<void> {\n if (this.status === 'ready') {\n // Check if browser is still alive (handles external closure)\n // checkBrowserAlive() should save lastBrowserState internally if it detects closure\n const stillAlive = await this.checkBrowserAlive();\n if (stillAlive) {\n return;\n }\n // Browser was externally closed, mark as closed for re-launch\n this.status = 'closed';\n }\n if (this.status === 'pending' || this.status === 'error' || this.status === 'closed') {\n // Reset to pending to allow re-launch after close\n if (this.status === 'closed') {\n this.status = 'pending';\n }\n await this.launch();\n return;\n }\n if (this.status === 'launching') {\n await this._launchPromise;\n return;\n }\n if (this.status === 'closing') {\n // Wait for close to complete, then re-launch\n await this._closePromise;\n this.status = 'pending';\n await this.launch();\n return;\n }\n throw new Error(`Browser is ${this.status} and cannot be used`);\n }\n\n /**\n * Check if the browser is still alive.\n * Override in subclass to detect externally closed browsers.\n * @returns true if browser is alive, false if it was externally closed\n */\n protected async checkBrowserAlive(): Promise<boolean> {\n // Default implementation assumes browser is alive if status is ready\n return true;\n }\n\n /**\n * Check if the browser is currently running.\n */\n isBrowserRunning(): boolean {\n return this.status === 'ready';\n }\n\n // ---------------------------------------------------------------------------\n // CDP URL Resolution\n // ---------------------------------------------------------------------------\n\n /**\n * Resolve a CDP URL from a static string or async provider function.\n * @param cdpUrl - Static string or async function returning the CDP URL\n * @returns Resolved CDP URL string\n */\n protected async resolveCdpUrl(cdpUrl: CdpUrlProvider): Promise<string> {\n return typeof cdpUrl === 'function' ? await cdpUrl() : cdpUrl;\n }\n\n /**\n * Resolve an HTTP CDP endpoint to a WebSocket URL by fetching /json/version.\n *\n * Cloud browser providers (Browser-Use, Browserless, etc.) often expose HTTP\n * endpoints that need to be resolved to WebSocket URLs for direct CDP connections.\n *\n * - If the URL starts with `ws://` or `wss://`, returns it as-is\n * - If the URL starts with `http://` or `https://`, fetches /json/version to get webSocketDebuggerUrl\n *\n * @param url - CDP URL (HTTP or WebSocket)\n * @returns WebSocket URL for CDP connection\n */\n protected async resolveWebSocketUrl(url: string): Promise<string> {\n // Already a WebSocket URL\n if (url.startsWith('ws://') || url.startsWith('wss://')) {\n return url;\n }\n\n // HTTP URL - fetch /json/version to get the WebSocket URL\n if (url.startsWith('http://') || url.startsWith('https://')) {\n const baseUrl = url.replace(/\\/$/, ''); // Remove trailing slash\n const versionUrl = `${baseUrl}/json/version`;\n\n this.logger.debug?.(`Resolving WebSocket URL from ${versionUrl}`);\n\n // Add timeout to prevent hanging on dead endpoints\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 10000);\n\n try {\n const response = await fetch(versionUrl, { signal: controller.signal });\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch CDP version info from ${versionUrl}: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = (await response.json()) as { webSocketDebuggerUrl?: string };\n if (!data.webSocketDebuggerUrl) {\n throw new Error(`No webSocketDebuggerUrl found in CDP version response from ${versionUrl}`);\n }\n\n this.logger.debug?.(`Resolved WebSocket URL: ${data.webSocketDebuggerUrl}`);\n return data.webSocketDebuggerUrl;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Timeout resolving WebSocket URL from ${versionUrl} (10s)`);\n }\n throw error;\n }\n }\n\n // Unknown protocol - return as-is and let the caller handle it\n return url;\n }\n\n // ---------------------------------------------------------------------------\n // Disconnection Detection & Error Handling\n // ---------------------------------------------------------------------------\n\n /**\n * Error patterns that indicate browser disconnection.\n * Used by isDisconnectionError() to detect external browser closure.\n */\n protected static readonly DISCONNECTION_PATTERNS = [\n 'Target closed',\n 'Target page, context or browser has been closed',\n 'Browser has been closed',\n 'Connection closed',\n 'Protocol error',\n 'Session closed',\n 'browser has disconnected',\n 'closed externally',\n ];\n\n /**\n * Check if an error message indicates browser disconnection.\n * @param message - Error message to check\n * @returns true if the message indicates disconnection\n */\n isDisconnectionError(message: string): boolean {\n const lowerMessage = message.toLowerCase();\n return MastraBrowser.DISCONNECTION_PATTERNS.some(pattern => lowerMessage.includes(pattern.toLowerCase()));\n }\n\n /**\n * Handle browser disconnection by updating status and notifying listeners.\n * Called when browser is detected as externally closed.\n *\n * For 'thread' scope: clears only the specific thread's session (other threads unaffected)\n * For 'shared' scope: clears the shared manager and updates global status\n */\n handleBrowserDisconnected(): void {\n const scope = this.threadManager?.getScope();\n const threadId = this.getCurrentThread();\n\n if (scope === 'thread' && threadId !== DEFAULT_THREAD_ID) {\n // Only clear the specific thread's session - other threads have independent browsers\n this.threadManager!.clearSession(threadId);\n this.logger.debug?.(`Cleared browser session for thread: ${threadId}`);\n // Notify only this thread's callbacks - do NOT set global status to 'closed'\n // since other threads may still have active browsers\n this.notifyBrowserClosed(threadId);\n } else {\n // For 'shared' scope or default thread, the shared browser is gone\n this.sharedManager = null;\n // Also clear the shared manager in the thread manager so getManagerForThread\n // doesn't return the dead manager\n this.threadManager?.clearSharedManager();\n // Update global status and notify all callbacks\n if (this.status !== 'closed') {\n this.status = 'closed';\n this.logger.debug?.('Browser was externally closed, status set to closed');\n this.notifyBrowserClosed();\n }\n }\n }\n\n /**\n * Create a BrowserToolError from an exception.\n * Handles common error patterns including disconnection detection.\n * Subclasses can override to add provider-specific error handling.\n *\n * @param error - The caught error\n * @param context - Description of what operation failed (e.g., \"Click operation\")\n * @returns Structured BrowserToolError\n */\n protected createErrorFromException(error: unknown, context: string): BrowserToolError {\n const msg = error instanceof Error ? error.message : String(error);\n\n // Check for browser disconnection errors first\n if (this.isDisconnectionError(msg)) {\n this.handleBrowserDisconnected();\n return createError(\n 'browser_closed',\n 'Browser was closed externally.',\n 'The browser window was closed. Please retry to re-launch.',\n );\n }\n\n // Timeout errors\n if (msg.includes('timeout') || msg.includes('Timeout') || msg.includes('aborted')) {\n return createError('timeout', `${context} timed out.`, 'Try again or increase timeout.');\n }\n\n // Not launched errors\n if (msg.includes('not launched') || msg.includes('Browser is not launched')) {\n return createError(\n 'browser_error',\n 'Browser was not initialized.',\n 'This is an internal error - please try again.',\n );\n }\n\n // Default to generic browser error\n return createError('browser_error', `${context} failed: ${msg}`, 'Check the browser state and try again.');\n }\n\n /**\n * Create a specific error type.\n * Convenience method for providers to create typed errors.\n */\n protected createError(code: ErrorCode, message: string, hint?: string): BrowserToolError {\n return createError(code, message, hint);\n }\n\n // ---------------------------------------------------------------------------\n // Browser Ready/Closed Callbacks\n // ---------------------------------------------------------------------------\n\n private _onReadyCallbacks: Set<() => void> = new Set();\n private _onClosedCallbacks: Set<() => void> = new Set();\n /** Thread-specific ready callbacks. Key is threadId. */\n private _onThreadReadyCallbacks: Map<string, Set<() => void>> = new Map();\n /** Thread-specific closed callbacks. Key is threadId. */\n private _onThreadClosedCallbacks: Map<string, Set<() => void>> = new Map();\n\n /**\n * Register a callback to be invoked when the browser becomes ready.\n * If browser is already running, callback is invoked immediately.\n * The callback is ALWAYS registered (even if invoked immediately) so it will\n * also fire on future \"ready\" events (e.g., session creation for thread isolation).\n * @param callback - Function to call when browser is ready\n * @param threadId - Optional thread ID to scope the callback to a specific thread\n * @returns Cleanup function to unregister the callback\n */\n onBrowserReady(callback: () => void, threadId?: string): () => void {\n if (threadId) {\n // Thread-specific callback\n let threadCallbacks = this._onThreadReadyCallbacks.get(threadId);\n if (!threadCallbacks) {\n threadCallbacks = new Set();\n this._onThreadReadyCallbacks.set(threadId, threadCallbacks);\n }\n threadCallbacks.add(callback);\n\n // Check if this specific thread has a session ready\n if (this.hasThreadSession(threadId)) {\n callback();\n }\n\n return () => {\n threadCallbacks!.delete(callback);\n if (threadCallbacks!.size === 0) {\n this._onThreadReadyCallbacks.delete(threadId);\n }\n };\n }\n\n // Global callback (for shared scope or when thread not specified)\n this._onReadyCallbacks.add(callback);\n\n if (this.isBrowserRunning()) {\n // Browser already ready - also invoke immediately\n callback();\n }\n\n return () => {\n this._onReadyCallbacks.delete(callback);\n };\n }\n\n /**\n * Register a callback to be invoked when the browser closes.\n * Useful for screencast to broadcast browser_closed status.\n * @param callback - Function to call when browser closes\n * @param threadId - Optional thread ID to scope the callback to a specific thread\n * @returns Cleanup function to unregister the callback\n */\n onBrowserClosed(callback: () => void, threadId?: string): () => void {\n if (threadId) {\n // Thread-specific callback\n let threadCallbacks = this._onThreadClosedCallbacks.get(threadId);\n if (!threadCallbacks) {\n threadCallbacks = new Set();\n this._onThreadClosedCallbacks.set(threadId, threadCallbacks);\n }\n threadCallbacks.add(callback);\n return () => {\n threadCallbacks!.delete(callback);\n if (threadCallbacks!.size === 0) {\n this._onThreadClosedCallbacks.delete(threadId);\n }\n };\n }\n // Global callback (for shared scope or when thread not specified)\n this._onClosedCallbacks.add(callback);\n return () => {\n this._onClosedCallbacks.delete(callback);\n };\n }\n\n /**\n * Notify registered callbacks that browser is ready.\n * @param threadId - If provided, only notify callbacks for that thread (for thread scope)\n */\n protected notifyBrowserReady(threadId?: string): void {\n if (threadId) {\n // Notify thread-specific callbacks only\n const threadCallbacks = this._onThreadReadyCallbacks.get(threadId);\n if (threadCallbacks) {\n for (const callback of threadCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n }\n } else {\n // Notify global callbacks (for shared scope)\n for (const callback of this._onReadyCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n // Also notify ALL thread callbacks (entire browser is ready - shared scenario)\n for (const [, threadCallbacks] of this._onThreadReadyCallbacks) {\n for (const callback of threadCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n }\n }\n // Do NOT clear callbacks - they should persist across browser restarts\n // so screencast can reconnect after external closure + re-launch\n }\n\n /**\n * Notify registered callbacks that browser has closed.\n * @param threadId - If provided, only notify callbacks for that thread (for thread scope)\n */\n protected notifyBrowserClosed(threadId?: string): void {\n if (threadId) {\n // Notify thread-specific callbacks only\n const threadCallbacks = this._onThreadClosedCallbacks.get(threadId);\n if (threadCallbacks) {\n for (const callback of threadCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n }\n } else {\n // Notify global callbacks (for shared scope)\n for (const callback of this._onClosedCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n // Also notify ALL thread callbacks (entire browser is closing)\n for (const [, threadCallbacks] of this._onThreadClosedCallbacks) {\n for (const callback of threadCallbacks) {\n try {\n callback();\n } catch {\n // Intentionally swallowed - callbacks should not crash the browser\n }\n }\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // URL Access (optional - providers that support it should override)\n // ---------------------------------------------------------------------------\n\n /**\n * Get the current page URL without launching the browser.\n * @param threadId - Optional thread ID for thread-isolated browsers\n * @returns The current URL string, or null if browser is not running or not supported\n */\n async getCurrentUrl(_threadId?: string): Promise<string | null> {\n return null;\n }\n\n /**\n * Get the current browser state (all tabs and active tab index).\n * Override in subclass to provide actual tab state.\n * @param _threadId - Optional thread ID for thread-isolated sessions\n * @returns The browser state, or null if not available\n */\n async getBrowserState(_threadId?: string): Promise<BrowserState | null> {\n // Default implementation returns null - providers override\n return null;\n }\n\n /**\n * Get the last known browser state before the browser was closed.\n * Useful for restoring state on relaunch.\n * @param threadId - Optional thread ID for thread-isolated sessions\n * @returns The last browser state, or undefined if not available\n */\n getLastBrowserState(threadId?: string): BrowserState | undefined {\n // For thread isolation, check thread manager first\n if (threadId && this.threadManager) {\n const savedState = this.threadManager.getSavedBrowserState(threadId);\n if (savedState) {\n return savedState;\n }\n }\n return this.lastBrowserState;\n }\n\n /**\n * Get all open tabs with their URLs and titles.\n * Override in subclass to provide actual tab info.\n * @param _threadId - Optional thread ID for thread-isolated sessions\n * @returns Array of tab states\n */\n async getTabState(_threadId?: string): Promise<BrowserTabState[]> {\n // Default implementation returns empty array - providers override\n return [];\n }\n\n /**\n * Get the active tab index.\n * Override in subclass to provide actual active tab index.\n * @param _threadId - Optional thread ID for thread-isolated sessions\n * @returns The active tab index (0-based), or 0 if not available\n */\n async getActiveTabIndex(_threadId?: string): Promise<number> {\n // Default implementation returns 0 - providers override\n return 0;\n }\n\n /**\n * Navigate to a URL (simple form). Override in subclass if supported.\n * Used internally for restoring state on relaunch.\n * Named `navigateTo` to avoid conflicts with tool methods that have richer signatures.\n */\n async navigateTo(_url: string): Promise<void> {\n // Default implementation does nothing - providers can override\n }\n\n // ---------------------------------------------------------------------------\n // Thread Management\n // ---------------------------------------------------------------------------\n\n /**\n * Set the current thread ID for subsequent browser operations.\n * Called by tools before executing browser actions to ensure\n * operations are routed to the correct thread session.\n *\n * @param threadId - The thread ID, or undefined to use the default thread\n */\n setCurrentThread(threadId?: string): void {\n this.currentThreadId = threadId ?? DEFAULT_THREAD_ID;\n }\n\n /**\n * Get the current thread ID.\n * @returns The current thread ID being used for operations\n */\n getCurrentThread(): string {\n return this.currentThreadId;\n }\n\n /**\n * Get the browser scope mode.\n * @returns The scope from threadManager or config, defaults to 'shared'\n */\n getScope(): BrowserScope {\n return this.threadManager?.getScope() ?? this.config.scope ?? 'shared';\n }\n\n // ---------------------------------------------------------------------------\n // Screencast (optional - for Studio live view)\n // ---------------------------------------------------------------------------\n\n /**\n * Start screencast streaming. Override in subclass if supported.\n */\n async startScreencast(_options?: ScreencastOptions): Promise<ScreencastStream> {\n throw new Error('Screencast not supported by this provider');\n }\n\n /**\n * Check if a thread has an existing browser session.\n * Used by startScreencastIfBrowserActive to prevent showing another thread's page.\n *\n * If threadManager is set, delegates to it. Otherwise returns true (no isolation).\n * Subclasses can override for custom behavior.\n *\n * @returns true if session exists or thread isolation is not used\n */\n hasThreadSession(threadId: string): boolean {\n if (!this.threadManager) {\n // No thread manager - all threads share the same session\n return true;\n }\n\n const scope = this.threadManager.getScope();\n\n // Shared scope - all threads share the same session\n if (scope === 'shared') {\n return true;\n }\n\n // Check if this thread has an actual session\n return this.threadManager.hasSession(threadId);\n }\n\n /**\n * Close a specific thread's browser session.\n * Delegates to ThreadManager and notifies registered callbacks.\n *\n * For 'thread' scope, this closes only that thread's browser instance.\n * For 'shared' scope, this is a no-op (use close() to close the shared browser).\n *\n * @param threadId - The thread ID whose session should be closed\n */\n async closeThreadSession(threadId: string): Promise<void> {\n if (!this.threadManager) {\n return;\n }\n await this.threadManager.destroySession(threadId);\n // Notify callbacks registered for this specific thread\n this.notifyBrowserClosed(threadId);\n }\n\n /**\n * Handle browser disconnection for a specific thread.\n * Called when a thread's browser is closed externally (e.g., user closes browser window).\n * Clears the thread session and notifies registered callbacks.\n *\n * @param threadId - The thread ID whose session was disconnected\n */\n protected handleThreadBrowserDisconnected(threadId: string): void {\n if (!this.threadManager) {\n return;\n }\n this.threadManager.clearSession(threadId);\n this.logger.debug?.(`Cleared browser session for thread: ${threadId}`);\n // Notify only the callbacks registered for this specific thread\n this.notifyBrowserClosed(threadId);\n }\n\n /**\n * Get a session identifier for a specific thread.\n * In thread scope, returns a composite ID (browser:threadId).\n * In shared scope or without thread manager, returns the browser instance ID.\n */\n getSessionId(threadId?: string): string {\n if (!threadId || !this.threadManager) {\n return this.id;\n }\n\n const scope = this.threadManager.getScope();\n\n // Shared scope - all threads share the same session\n if (scope === 'shared') {\n return this.id;\n }\n\n // Thread scope - return composite ID\n return `${this.id}:${threadId}`;\n }\n\n /**\n * Start screencast only if browser is already running.\n * Does NOT launch the browser.\n * Uses config.screencast options as defaults if no options provided.\n *\n * For thread-isolated browsers ('browser' mode):\n * - Returns null if the thread doesn't have an existing browser session\n */\n async startScreencastIfBrowserActive(options?: ScreencastOptions): Promise<ScreencastStream | null> {\n if (!this.isBrowserRunning()) {\n return null;\n }\n\n // Merge config screencast defaults with call-site overrides\n const mergedOptions = this.config.screencast || options ? { ...this.config.screencast, ...options } : undefined;\n\n const threadId = mergedOptions?.threadId;\n const scope = this.threadManager?.getScope() ?? this.config.scope ?? 'shared';\n\n // Shared scope - just start the screencast\n if (scope === 'shared') {\n return this.startScreencast(mergedOptions);\n }\n\n // For 'thread' scope, only start if the thread has an existing session\n if (threadId && !this.hasThreadSession(threadId)) {\n return null;\n }\n\n return this.startScreencast(mergedOptions);\n }\n\n // ---------------------------------------------------------------------------\n // Event Injection (optional - for Studio live view)\n // ---------------------------------------------------------------------------\n\n /**\n * Inject a mouse event. Override in subclass if supported.\n * @param event - Mouse event parameters\n * @param threadId - Optional thread ID for thread-isolated sessions\n */\n async injectMouseEvent(_event: MouseEventParams, _threadId?: string): Promise<void> {\n throw new Error('Mouse event injection not supported by this provider');\n }\n\n /**\n * Inject a keyboard event. Override in subclass if supported.\n * @param event - Keyboard event parameters\n * @param threadId - Optional thread ID for thread-isolated sessions\n */\n async injectKeyboardEvent(_event: KeyboardEventParams, _threadId?: string): Promise<void> {\n throw new Error('Keyboard event injection not supported by this provider');\n }\n\n // ---------------------------------------------------------------------------\n // Abstract Methods (providers must implement)\n // ---------------------------------------------------------------------------\n\n /**\n * Get the active page for a thread.\n * Used by screencast reconnection to emit the current URL.\n *\n * @param threadId - Optional thread ID (uses current thread if not provided)\n * @returns The active Playwright Page, or null if not available\n */\n protected abstract getActivePage(threadId?: string): Promise<{ url(): string } | null>;\n\n /**\n * Get the current browser state for a thread.\n * Used to persist and restore browser state across sessions.\n *\n * @param threadId - Optional thread ID (uses current thread if not provided)\n * @returns Browser state including URL, tabs, and active tab index\n */\n protected abstract getBrowserStateForThread(threadId?: string): BrowserState | null;\n\n // ---------------------------------------------------------------------------\n // Input Processors\n // ---------------------------------------------------------------------------\n\n /**\n * Returns browser input processors (e.g., BrowserContextProcessor for context injection).\n * Skips if the user already added a processor with the same id.\n *\n * This method is similar to AgentChannels.getInputProcessors() and allows\n * browser implementations to provide their own processors.\n *\n * @param configuredProcessors - Processors already configured by the user (for deduplication)\n * @returns Array of input processors for this browser instance\n */\n getInputProcessors(configuredProcessors: InputProcessorOrWorkflow[] = []): InputProcessor[] {\n const hasProcessor = configuredProcessors.some(\n p => !isProcessorWorkflow(p) && 'id' in p && p.id === 'browser-context',\n );\n if (hasProcessor) return [];\n return [new BrowserContextProcessor()];\n }\n\n // ---------------------------------------------------------------------------\n // Abstract Methods - Must be implemented by providers\n // ---------------------------------------------------------------------------\n\n /**\n * Get the browser tools for this provider.\n *\n * Each provider returns its own set of tools. For example:\n * - AgentBrowser returns 17 deterministic tools using refs\n * - StagehandBrowser might return AI-powered tools (act, extract, observe)\n *\n * @returns Record of tool name to tool definition\n */\n abstract getTools(): Record<string, Tool<any, any>>;\n}\n","/**\n * Screencast types for CDP-based browser streaming.\n *\n * These types are shared between browser providers (AgentBrowser, Stagehand, etc.)\n * that support screencast via CDP.\n */\n\n/**\n * Options for starting a screencast stream.\n */\nexport interface ScreencastOptions {\n /** Image format (default: 'jpeg') */\n format?: 'jpeg' | 'png';\n /** JPEG quality 0-100 (default: 80) */\n quality?: number;\n /** Max width in pixels (default: 1280) */\n maxWidth?: number;\n /** Max height in pixels (default: 720) */\n maxHeight?: number;\n /** Capture every Nth frame (default: 1) */\n everyNthFrame?: number;\n /** Thread ID for thread-scoped screencasts (streams from thread's page) */\n threadId?: string;\n}\n\n/**\n * Data for a single screencast frame.\n */\nexport interface ScreencastFrameData {\n /** Base64-encoded image data */\n data: string;\n /** Frame timestamp in milliseconds */\n timestamp: number;\n /** Viewport information */\n viewport: {\n width: number;\n height: number;\n offsetTop?: number;\n scrollOffsetX?: number;\n scrollOffsetY?: number;\n pageScaleFactor?: number;\n };\n /** CDP session ID for acknowledgment (handled internally) */\n sessionId?: number;\n}\n\n/**\n * Events emitted by ScreencastStream.\n */\nexport interface ScreencastEvents {\n /** Emitted when a new frame is received */\n frame: (frame: ScreencastFrameData) => void;\n /** Emitted when screencast stops */\n stop: (reason: 'manual' | 'browser_closed' | 'error') => void;\n /** Emitted on errors */\n error: (error: Error) => void;\n /** Emitted when the page URL changes (navigation detected) */\n url: (url: string) => void;\n /** Index signature for TypedEmitter compatibility */\n [key: string]: (...args: any[]) => void;\n}\n\n/**\n * Default screencast options.\n */\nexport const SCREENCAST_DEFAULTS: Required<Omit<ScreencastOptions, 'threadId'>> = {\n format: 'jpeg',\n quality: 80,\n maxWidth: 1280,\n maxHeight: 720,\n everyNthFrame: 1,\n};\n\n/**\n * Abstract CDP session interface.\n * Both Playwright's CDPSession and direct CDP connections implement this.\n */\nexport interface CdpSessionLike {\n /** Send a CDP command */\n send(method: string, params?: Record<string, unknown>): Promise<unknown>;\n /** Register an event handler */\n on(event: string, handler: (...args: any[]) => void): void;\n /** Remove an event handler */\n off?(event: string, handler: (...args: any[]) => void): void;\n /** Detach the session */\n detach?(): Promise<void>;\n}\n\n/**\n * Provider interface for getting CDP sessions.\n * Browser providers implement this to expose CDP access.\n */\nexport interface CdpSessionProvider {\n /**\n * Get a CDP session for screencast/input injection.\n * The session should be attached to the current page.\n */\n getCdpSession(): Promise<CdpSessionLike>;\n\n /**\n * Check if the browser is currently running.\n */\n isBrowserRunning(): boolean;\n}\n","/**\n * CDP-based ScreencastStream implementation.\n *\n * This provides a unified screencast implementation that works with any\n * CDP session provider (Playwright, Puppeteer, direct CDP, etc.).\n */\n\nimport { EventEmitter } from 'node:events';\nimport type { CdpSessionLike, CdpSessionProvider, ScreencastFrameData, ScreencastOptions } from './types';\nimport { SCREENCAST_DEFAULTS } from './types';\n\n/**\n * CDP screencast frame event data from Page.screencastFrame\n */\ninterface CdpScreencastFrame {\n data: string;\n sessionId: number;\n metadata?: {\n deviceWidth?: number;\n deviceHeight?: number;\n offsetTop?: number;\n scrollOffsetX?: number;\n scrollOffsetY?: number;\n pageScaleFactor?: number;\n timestamp?: number;\n };\n}\n\n/**\n * ScreencastStream wraps CDP screencast with an event emitter interface.\n *\n * Works with any CDP session provider (Playwright, Puppeteer, direct CDP).\n *\n * @example\n * ```typescript\n * const stream = new ScreencastStream(cdpProvider, { quality: 80 });\n * stream.on('frame', (frame) => {\n * console.log(`Frame: ${frame.viewport.width}x${frame.viewport.height}`);\n * });\n * await stream.start();\n * // Later...\n * await stream.stop();\n * ```\n */\nexport class ScreencastStream extends EventEmitter {\n /** Whether screencast is currently active */\n private active: boolean = false;\n\n /** Resolved options with defaults applied (excludes threadId which is only used for page selection) */\n private options: Required<Omit<ScreencastOptions, 'threadId'>>;\n\n /** CDP session provider */\n private provider: CdpSessionProvider;\n\n /** Current CDP session */\n private cdpSession: CdpSessionLike | null = null;\n\n /** Frame handler reference (for cleanup) */\n private frameHandler: ((params: CdpScreencastFrame) => void) | null = null;\n\n /**\n * Creates a new ScreencastStream.\n *\n * @param provider - CDP session provider (browser instance)\n * @param options - Screencast configuration options\n */\n constructor(provider: CdpSessionProvider, options?: ScreencastOptions) {\n super();\n this.provider = provider;\n // Extract threadId (used by caller for page selection) and merge remaining options\n const { threadId: _, ...cdpOptions } = options ?? {};\n this.options = { ...SCREENCAST_DEFAULTS, ...cdpOptions };\n }\n\n /**\n * Start the screencast.\n * If already active, returns immediately.\n */\n async start(): Promise<void> {\n if (this.active) {\n return;\n }\n\n if (!this.provider.isBrowserRunning()) {\n throw new Error('Browser is not running');\n }\n\n try {\n // Get CDP session from provider\n this.cdpSession = await this.provider.getCdpSession();\n\n // Set up frame handler\n this.frameHandler = (params: CdpScreencastFrame) => {\n const frameData: ScreencastFrameData = {\n data: params.data,\n // CDP provides timestamp in seconds, convert to milliseconds for consistency\n timestamp: params.metadata?.timestamp ? params.metadata.timestamp * 1000 : Date.now(),\n viewport: {\n width: params.metadata?.deviceWidth ?? 0,\n height: params.metadata?.deviceHeight ?? 0,\n offsetTop: params.metadata?.offsetTop,\n scrollOffsetX: params.metadata?.scrollOffsetX,\n scrollOffsetY: params.metadata?.scrollOffsetY,\n pageScaleFactor: params.metadata?.pageScaleFactor,\n },\n sessionId: params.sessionId,\n };\n\n this.emit('frame', frameData);\n\n // Acknowledge frame to continue receiving\n this.acknowledgeFrame(params.sessionId);\n };\n\n this.cdpSession.on('Page.screencastFrame', this.frameHandler);\n\n // Start screencast via CDP\n try {\n await this.cdpSession.send('Page.startScreencast', {\n format: this.options.format,\n quality: this.options.quality,\n maxWidth: this.options.maxWidth,\n maxHeight: this.options.maxHeight,\n everyNthFrame: this.options.everyNthFrame,\n });\n } catch (startError) {\n // Clean up handler before re-throwing to prevent resource leak\n if (this.cdpSession?.off) {\n try {\n this.cdpSession.off('Page.screencastFrame', this.frameHandler);\n } catch {\n // Ignore cleanup errors\n }\n }\n this.frameHandler = null;\n this.cdpSession = null;\n throw startError;\n }\n\n this.active = true;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.emit('error', err);\n throw err;\n }\n }\n\n /**\n * Acknowledge a frame to CDP (required to continue receiving frames).\n */\n private acknowledgeFrame(sessionId: number): void {\n if (!this.cdpSession) return;\n\n this.cdpSession.send('Page.screencastFrameAck', { sessionId }).catch(() => {\n // Ignore ack errors - session may be closed\n });\n }\n\n /**\n * Stop the screencast and release resources.\n * Safe to call even if browser/CDP session is already closed.\n */\n async stop(): Promise<void> {\n if (!this.active) {\n return;\n }\n\n this.active = false;\n let hadError = false;\n\n // Clean up handler regardless of CDP state\n if (this.cdpSession && this.frameHandler && this.cdpSession.off) {\n try {\n this.cdpSession.off('Page.screencastFrame', this.frameHandler);\n } catch {\n // Ignore - session may be dead\n }\n }\n this.frameHandler = null;\n\n // Try to stop screencast via CDP (may fail if browser closed)\n if (this.cdpSession) {\n try {\n await this.cdpSession.send('Page.stopScreencast');\n } catch {\n // Browser/session already closed - this is expected in external close scenarios\n hadError = true;\n }\n this.cdpSession = null;\n }\n\n this.emit('stop', hadError ? 'error' : 'manual');\n }\n\n /**\n * Check if screencast is currently active.\n */\n isActive(): boolean {\n return this.active;\n }\n\n /**\n * Emit a URL update event.\n * Browser providers call this when navigation is detected.\n */\n emitUrl(url: string): void {\n this.emit('url', url);\n }\n\n /**\n * Reconnect the screencast by stopping and restarting.\n * Use this when the active page/tab changes.\n *\n * @returns Promise that resolves when reconnection is complete\n * @throws Error if reconnection fails (also emits 'error' event)\n */\n async reconnect(): Promise<void> {\n // Clean up existing session\n if (this.cdpSession && this.frameHandler && this.cdpSession.off) {\n try {\n this.cdpSession.off('Page.screencastFrame', this.frameHandler);\n } catch {\n // Ignore - session may be dead\n }\n }\n this.frameHandler = null;\n\n // Try to stop screencast on old session (may fail if session is dead)\n if (this.cdpSession) {\n try {\n await this.cdpSession.send('Page.stopScreencast');\n } catch {\n // Old session may already be detached - this is expected\n }\n this.cdpSession = null;\n }\n\n // Mark as inactive so start() will work\n this.active = false;\n\n // Restart with fresh session from provider\n try {\n await this.start();\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n console.error('[ScreencastStream.reconnect] Failed to reconnect:', err);\n // Don't emit 'error' here - start() already emits it before rejecting\n throw err;\n }\n }\n}\n"]}
@@ -63,6 +63,10 @@ export declare abstract class ThreadManager<TManager = unknown> {
63
63
  protected activeThreadId: string;
64
64
  /** Preserved browser state that survives session clears (for browser restore) */
65
65
  protected readonly savedBrowserStates: Map<string, BrowserState>;
66
+ /** Shared manager instance (used for 'shared' scope) */
67
+ protected sharedManager: TManager | null;
68
+ /** Map of thread ID to dedicated manager instance (for 'thread' scope) */
69
+ protected readonly threadManagers: Map<string, TManager>;
66
70
  private readonly onSessionCreated?;
67
71
  private readonly onSessionDestroyed?;
68
72
  constructor(config: ThreadManagerConfig);
@@ -74,6 +78,33 @@ export declare abstract class ThreadManager<TManager = unknown> {
74
78
  * Get the currently active thread ID.
75
79
  */
76
80
  getActiveThreadId(): string;
81
+ /**
82
+ * Set the shared manager instance (called after browser launch).
83
+ */
84
+ setSharedManager(manager: TManager): void;
85
+ /**
86
+ * Clear the shared manager instance (called when browser disconnects).
87
+ */
88
+ clearSharedManager(): void;
89
+ /**
90
+ * Get the manager for an existing thread session without creating a new one.
91
+ *
92
+ * For 'thread' scope: Returns the thread-specific manager, or null if no session exists.
93
+ * For 'shared' scope: Returns the shared manager (all threads use the same instance).
94
+ *
95
+ * @param threadId - Thread identifier (defaults to DEFAULT_THREAD_ID)
96
+ * @returns The manager for the thread, or null if not found (thread scope only)
97
+ */
98
+ getExistingManagerForThread(threadId?: string): TManager | null;
99
+ /**
100
+ * Check if any thread managers are still running (for 'thread' scope).
101
+ */
102
+ hasActiveThreadManagers(): boolean;
103
+ /**
104
+ * Clear all session tracking without closing managers.
105
+ * Used when browsers have been externally closed and we just need to reset state.
106
+ */
107
+ clearAllSessions(): void;
77
108
  /**
78
109
  * Get a session by thread ID.
79
110
  */
@@ -119,20 +150,24 @@ export declare abstract class ThreadManager<TManager = unknown> {
119
150
  * Get the saved browser state for a thread (survives session clears).
120
151
  */
121
152
  getSavedBrowserState(threadId: string): BrowserState | undefined;
153
+ /**
154
+ * Clear a specific thread's session without closing the browser.
155
+ * Used when a thread's browser has been externally closed.
156
+ * Preserves the browser state for potential restoration.
157
+ *
158
+ * @param threadId - The thread ID to clear
159
+ */
160
+ clearSession(threadId: string): void;
122
161
  /**
123
162
  * Get the shared browser manager (used for 'shared' scope and default thread).
163
+ * @throws Error if shared manager is not initialized
124
164
  */
125
- protected abstract getSharedManager(): TManager;
165
+ protected getSharedManager(): TManager;
126
166
  /**
127
167
  * Create a new session for a thread.
128
168
  * Called when a thread is accessed for the first time.
129
169
  */
130
170
  protected abstract createSession(threadId: string): Promise<ThreadSession>;
131
- /**
132
- * Switch to an existing session.
133
- * May be a no-op depending on isolation mode.
134
- */
135
- protected abstract switchToSession(session: ThreadSession): Promise<void>;
136
171
  /**
137
172
  * Get the browser manager for a specific session.
138
173
  */
@@ -1 +1 @@
1
- {"version":3,"file":"thread-manager.d.ts","sourceRoot":"","sources":["../../src/browser/thread-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"thread-manager.d.ts","sourceRoot":"","sources":["../../src/browser/thread-manager.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,20 @@
1
1
  'use strict';
2
2
 
3
- var chunkHLG6JE5B_cjs = require('../chunk-HLG6JE5B.cjs');
3
+ var chunkVDXTOWVO_cjs = require('../chunk-VDXTOWVO.cjs');
4
4
 
5
5
 
6
6
 
7
7
  Object.defineProperty(exports, "AgentChannels", {
8
8
  enumerable: true,
9
- get: function () { return chunkHLG6JE5B_cjs.AgentChannels; }
9
+ get: function () { return chunkVDXTOWVO_cjs.AgentChannels; }
10
10
  });
11
11
  Object.defineProperty(exports, "ChatChannelProcessor", {
12
12
  enumerable: true,
13
- get: function () { return chunkHLG6JE5B_cjs.ChatChannelProcessor; }
13
+ get: function () { return chunkVDXTOWVO_cjs.ChatChannelProcessor; }
14
14
  });
15
15
  Object.defineProperty(exports, "MastraStateAdapter", {
16
16
  enumerable: true,
17
- get: function () { return chunkHLG6JE5B_cjs.MastraStateAdapter; }
17
+ get: function () { return chunkVDXTOWVO_cjs.MastraStateAdapter; }
18
18
  });
19
19
  //# sourceMappingURL=index.cjs.map
20
20
  //# sourceMappingURL=index.cjs.map
@@ -1,3 +1,3 @@
1
- export { AgentChannels, ChatChannelProcessor, MastraStateAdapter } from '../chunk-O4GMYDMB.js';
1
+ export { AgentChannels, ChatChannelProcessor, MastraStateAdapter } from '../chunk-TULT7C36.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map