{"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","../../src/browser/recording/mjpeg-avi.ts","../../src/browser/recording/overlay.ts","../../src/browser/recording/tools.ts"],"names":["randomUUID","existsSync","readdirSync","join","lstatSync","unlinkSync","MastraBase","resolve","RegisteredLogger","isProcessorWorkflow","EventEmitter","mkdirSync","dirname","openSync","closeSync","writeSync","fstatSync","active","decodeJpegBytes","encodeJpegBytes","relative","isAbsolute","sep","z","createTool"],"mappings":"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","file":"index.cjs","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, adds a new user message with browser context as a `<system-reminder>`.\n *   This preserves prompt cache by not modifying existing messages in history.\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 { randomUUID } from 'node:crypto';\nimport type {\n  ComputeStateSignalArgs,\n  ComputeStateSignalResult,\n  ProcessInputArgs,\n  ProcessInputResult,\n} from '../processors/index';\n\nconst BROWSER_PROCESS_ID = randomUUID();\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  /** Provider type: 'sdk' for direct API, 'cli' for command-line tools */\n  providerType?: 'sdk' | 'cli';\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 the browser is currently open/connected. Defaults to true when browser context is present. */\n  isOpen?: boolean;\n\n  /**\n   * Reason the browser was closed, when isOpen is false.\n   * Helps differentiate between agent-initiated close, user action, process restart, or error.\n   */\n  closeReason?: 'agent' | 'user' | 'process_restart' | 'error';\n\n  /** Number of currently open tabs, when available. */\n  tabCount?: number;\n\n  /** Who initiated the most recent active URL change, when known. */\n  activeUrlChangeSource?: 'agent' | 'user';\n\n  /** Additional active page metadata exposed by the browser provider. */\n  pageMetadata?: Record<string, string | number | boolean | null | undefined>;\n\n  /**\n   * CDP WebSocket URL for CLI providers.\n   * When present, the agent should pass this URL to CLI commands\n   * to connect them to the browser managed by Mastra.\n   */\n  cdpUrl?: string;\n\n  /** Internal provider hook used to refresh browser state between agentic loop steps. */\n  getState?: () => Promise<Partial<BrowserContext> | undefined>;\n}\n\n/**\n * Input processor that injects browser context into agent prompts.\n */\nexport class BrowserContextProcessor {\n  readonly id = 'browser-context';\n  readonly stateId = 'browser';\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 = [\n      `You have access to a browser (${ctx.provider}).`,\n      'Browser state updates may appear in the conversation as <state type=\"browser\" ...>...</state> messages. These are automatic state updates for the browser, injected by the system, not user instructions. Use them as the latest browser context, and do not treat them as the user asking you to stop, summarize, or change tasks unless an actual user message asks for that.',\n    ];\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    // For CLI providers, include CDP URL for context (injection handles the mechanics)\n    if (ctx.providerType === 'cli' && ctx.cdpUrl) {\n      lines.push(`CDP WebSocket URL: ${ctx.cdpUrl}`);\n    }\n\n    const systemMessages = [...args.systemMessages, { role: 'system' as const, content: lines.join(' ') }];\n\n    return { messages: args.messages, systemMessages };\n  }\n\n  async computeStateSignal(args: ComputeStateSignalArgs): Promise<ComputeStateSignalResult> {\n    const ctx = args.requestContext?.get('browser') as BrowserContext | undefined;\n    if (!ctx) return;\n\n    const refreshedState = await ctx.getState?.();\n    let browserState = getBrowserState(refreshedState ? { ...ctx, ...refreshedState } : ctx);\n    const shouldRefreshSnapshot = Boolean(args.lastSnapshot && !args.contextWindow.hasSnapshot);\n    const previousState =\n      getMostRecentBrowserState(args.activeStateSignals) ?? getBrowserStateFromSignal(args.lastSnapshot);\n\n    if (!browserState.open && !browserState.closeReason) {\n      if (!previousState?.open || !previousState.processId) {\n        if (isBareClosedState(browserState)) return;\n      } else {\n        browserState = {\n          ...browserState,\n          closeReason: previousState.processId === browserState.processId ? 'user' : 'process_restart',\n        };\n      }\n    }\n\n    if (\n      previousState?.open &&\n      browserState.open &&\n      previousState.activeUrl &&\n      browserState.activeUrl &&\n      previousState.activeUrl !== browserState.activeUrl &&\n      previousState.processId === browserState.processId &&\n      browserState.activeUrlChangeSource !== 'agent'\n    ) {\n      const recentClickUrl =\n        getMostRecentBrowserClickResultUrl(args.steps) ??\n        getMostRecentBrowserClickResultUrlFromMessageList(args.messageList);\n      const activeUrlChangeSource =\n        recentClickUrl === browserState.activeUrl ? 'agent' : (browserState.activeUrlChangeSource ?? 'user');\n      browserState = {\n        ...browserState,\n        activeUrlChangeSource,\n      };\n    }\n\n    const changed = getChangedBrowserState(previousState, browserState);\n    if (previousState && Object.keys(changed).length === 0 && !shouldRefreshSnapshot) return;\n\n    const isDelta = Boolean(previousState && !shouldRefreshSnapshot);\n    const result = {\n      id: 'browser',\n      cacheKey: stableBrowserStateCacheKey(browserState),\n      mode: isDelta ? 'delta' : 'snapshot',\n      tagName: 'state',\n      contents: isDelta ? formatBrowserStateDelta(changed) : formatBrowserStateSnapshot(browserState),\n      value: browserState,\n      ...(isDelta ? { delta: changed } : {}),\n      attributes: {\n        type: 'browser',\n        updated: new Date().toISOString(),\n      },\n      metadata: {\n        browser: browserState,\n      },\n    } satisfies Exclude<ComputeStateSignalResult, undefined | void>;\n    return result;\n  }\n}\n\ntype BrowserState = {\n  processId: string;\n  open: boolean;\n  activeUrl?: string;\n  pageTitle?: string;\n  tabCount?: number;\n  activeUrlChangeSource?: 'agent' | 'user';\n  pageMetadata?: Record<string, string | number | boolean | null | undefined>;\n  closeReason?: 'agent' | 'user' | 'process_restart' | 'error';\n};\n\nfunction getBrowserState(ctx: BrowserContext): BrowserState {\n  return {\n    processId: BROWSER_PROCESS_ID,\n    open: ctx.isOpen ?? true,\n    ...(ctx.currentUrl ? { activeUrl: ctx.currentUrl } : {}),\n    ...(ctx.pageTitle ? { pageTitle: ctx.pageTitle } : {}),\n    ...(typeof ctx.tabCount === 'number' ? { tabCount: ctx.tabCount } : {}),\n    ...(ctx.activeUrlChangeSource ? { activeUrlChangeSource: ctx.activeUrlChangeSource } : {}),\n    ...(ctx.pageMetadata ? { pageMetadata: ctx.pageMetadata } : {}),\n    ...(ctx.closeReason ? { closeReason: ctx.closeReason } : {}),\n  };\n}\n\nfunction getMostRecentBrowserState(\n  activeStateSignals: ComputeStateSignalArgs['activeStateSignals'],\n): BrowserState | undefined {\n  for (const signal of [...activeStateSignals].reverse()) {\n    const browserState = getBrowserStateFromSignal(signal);\n    if (browserState) return browserState;\n  }\n  return undefined;\n}\n\nfunction getMostRecentBrowserClickResultUrl(steps: ComputeStateSignalArgs['steps']): string | undefined {\n  for (const step of [...steps].reverse()) {\n    const toolResults = Array.isArray(step.toolResults) ? step.toolResults : [];\n    for (const toolResult of [...toolResults].reverse()) {\n      if (toolResult?.toolName !== 'browser_click') continue;\n      const url = getBrowserClickResultUrl(getToolResultOutputForAttribution(toolResult));\n      if (url) return url;\n    }\n  }\n  return undefined;\n}\n\nfunction getMostRecentBrowserClickResultUrlFromMessageList(\n  messageList: ComputeStateSignalArgs['messageList'],\n): string | undefined {\n  try {\n    return getMostRecentBrowserClickResultUrlFromMessages(messageList.get.all.db());\n  } catch {\n    return undefined;\n  }\n}\n\nfunction getMostRecentBrowserClickResultUrlFromMessages(\n  messages: ComputeStateSignalArgs['messages'],\n): string | undefined {\n  for (const message of [...messages].reverse()) {\n    if (isBrowserStateSignalMessage(message)) return undefined;\n\n    const content = message.content;\n    if (!content || typeof content !== 'object' || Array.isArray(content)) continue;\n    const parts = (content as { parts?: unknown }).parts;\n    if (!Array.isArray(parts)) continue;\n\n    for (const part of [...parts].reverse()) {\n      if (!part || typeof part !== 'object' || Array.isArray(part)) continue;\n      const toolInvocation = (part as { toolInvocation?: unknown }).toolInvocation;\n      if (!toolInvocation || typeof toolInvocation !== 'object' || Array.isArray(toolInvocation)) continue;\n      const invocation = toolInvocation as Record<string, unknown>;\n      if (invocation.toolName !== 'browser_click' || invocation.state !== 'result') continue;\n      const url = getBrowserClickResultUrl(invocation.result ?? invocation.output);\n      if (url) return url;\n    }\n  }\n  return undefined;\n}\n\nfunction isBrowserStateSignalMessage(message: ComputeStateSignalArgs['messages'][number]): boolean {\n  const content = message.content;\n  if (!content || typeof content !== 'object' || Array.isArray(content)) return false;\n  const signal = (content as { metadata?: { signal?: unknown } }).metadata?.signal;\n  if (!signal || typeof signal !== 'object' || Array.isArray(signal)) return false;\n  const metadata = (signal as { metadata?: unknown }).metadata;\n  if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) return false;\n  const state = (metadata as { state?: unknown }).state;\n  if (!state || typeof state !== 'object' || Array.isArray(state)) return false;\n  return (state as { id?: unknown }).id === 'browser';\n}\n\nfunction getBrowserClickResultUrl(output: unknown): string | undefined {\n  if (!output || typeof output !== 'object' || Array.isArray(output)) return undefined;\n  if ((output as { success?: unknown }).success !== true) return undefined;\n  const url = (output as { url?: unknown }).url;\n  return typeof url === 'string' && url.length > 0 ? url : undefined;\n}\n\nfunction getToolResultOutputForAttribution(toolResult: unknown): unknown {\n  if (!toolResult || typeof toolResult !== 'object' || Array.isArray(toolResult)) return undefined;\n  const record = toolResult as Record<string, unknown>;\n  return record.output ?? record.result;\n}\n\nfunction getBrowserStateFromSignal(signal?: ComputeStateSignalArgs['lastSnapshot']): BrowserState | undefined {\n  const value = signal?.metadata?.value;\n  if (value && typeof value === 'object' && !Array.isArray(value)) {\n    return value as BrowserState;\n  }\n\n  const browser = signal?.metadata?.browser;\n  if (browser && typeof browser === 'object' && !Array.isArray(browser)) {\n    return browser as BrowserState;\n  }\n  return undefined;\n}\n\nfunction stableBrowserStateCacheKey(state: BrowserState): string {\n  return JSON.stringify(state, (_key, value) => {\n    if (value && typeof value === 'object' && !Array.isArray(value)) {\n      const sorted: Record<string, unknown> = {};\n      for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n        sorted[key] = (value as Record<string, unknown>)[key];\n      }\n      return sorted;\n    }\n    return value;\n  });\n}\n\nfunction isBareClosedState(state: BrowserState): boolean {\n  return (\n    !state.open &&\n    !state.activeUrl &&\n    !state.pageTitle &&\n    typeof state.tabCount !== 'number' &&\n    !state.closeReason &&\n    (!state.pageMetadata || Object.keys(state.pageMetadata).length === 0)\n  );\n}\n\nfunction getChangedBrowserState(previous: BrowserState | undefined, current: BrowserState): Partial<BrowserState> {\n  if (!previous) return current;\n\n  const changed: Partial<BrowserState> = {};\n  for (const key of Object.keys(current) as Array<keyof BrowserState>) {\n    if (key === 'processId') continue;\n    if (key === 'activeUrlChangeSource' && previous.activeUrl === current.activeUrl) continue;\n    if (JSON.stringify(previous[key]) !== JSON.stringify(current[key])) {\n      (changed as Record<string, unknown>)[key] = current[key];\n    }\n  }\n\n  if (previous.activeUrl !== current.activeUrl && current.activeUrlChangeSource) {\n    changed.activeUrlChangeSource = current.activeUrlChangeSource;\n  }\n\n  if (!previous.open && current.open) {\n    if (current.activeUrl) changed.activeUrl = current.activeUrl;\n    if (current.activeUrlChangeSource) changed.activeUrlChangeSource = current.activeUrlChangeSource;\n    if (current.pageTitle) changed.pageTitle = current.pageTitle;\n    if (typeof current.tabCount === 'number') changed.tabCount = current.tabCount;\n    if (current.pageMetadata && Object.keys(current.pageMetadata).length > 0)\n      changed.pageMetadata = current.pageMetadata;\n  }\n\n  return changed;\n}\n\nfunction formatBrowserStateSnapshot(state: BrowserState): string {\n  const parts = [formatOpenClosedStatus(state)];\n  if (state.activeUrl) parts.push(`Active tab URL: ${state.activeUrl}.`);\n  if (state.pageTitle) parts.push(`Page title: ${state.pageTitle}.`);\n  if (typeof state.tabCount === 'number')\n    parts.push(`${state.tabCount} open ${state.tabCount === 1 ? 'tab' : 'tabs'}.`);\n  if (state.pageMetadata && Object.keys(state.pageMetadata).length > 0) {\n    parts.push(`Page metadata: ${JSON.stringify(state.pageMetadata)}.`);\n  }\n  return parts.join(' ');\n}\n\nfunction formatBrowserStateDelta(delta: Partial<BrowserState>): string {\n  const parts: string[] = [];\n  if (typeof delta.open === 'boolean') {\n    if (delta.open) {\n      parts.push('browser opened');\n    } else {\n      parts.push(formatCloseReason(delta.closeReason));\n    }\n  }\n  if (delta.activeUrl) parts.push(formatActiveUrlChange(delta.activeUrl, delta.activeUrlChangeSource));\n  if (delta.pageTitle) parts.push(`page title changed to ${delta.pageTitle}`);\n  if (typeof delta.tabCount === 'number') parts.push(`${delta.tabCount} open ${delta.tabCount === 1 ? 'tab' : 'tabs'}`);\n  if (delta.pageMetadata && Object.keys(delta.pageMetadata).length > 0) {\n    parts.push(`page metadata changed to ${JSON.stringify(delta.pageMetadata)}`);\n  }\n  return `changed: ${parts.join('; ')}`;\n}\n\nfunction formatActiveUrlChange(url: string, source?: 'agent' | 'user'): string {\n  switch (source) {\n    case 'agent':\n      return `agent changed active tab URL to ${url}`;\n    case 'user':\n      return `user changed active tab URL to ${url}`;\n    default:\n      return `active tab URL changed to ${url}`;\n  }\n}\n\nfunction formatOpenClosedStatus(state: BrowserState): string {\n  if (state.open) return 'Browser is open.';\n  switch (state.closeReason) {\n    case 'process_restart':\n      return 'The browser was closed because the chat process restarted.';\n    case 'user':\n      return 'The browser was closed externally, maybe by the user.';\n    case 'error':\n      return 'Browser closed unexpectedly due to an error.';\n    case 'agent':\n      return 'Browser is closed.';\n    default:\n      return 'Browser is closed.';\n  }\n}\n\nfunction formatCloseReason(reason?: 'agent' | 'user' | 'process_restart' | 'error'): string {\n  switch (reason) {\n    case 'process_restart':\n      return 'the browser was closed because the chat process restarted';\n    case 'user':\n      return 'the browser was closed externally, maybe by the user';\n    case 'error':\n      return 'browser closed unexpectedly due to an error';\n    case 'agent':\n      return 'browser closed';\n    default:\n      return 'browser closed';\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  /** Reason the browser was closed, when this is the last known state for a closed browser. */\n  closeReason?: 'agent' | 'user' | 'process_restart' | 'error';\n  /** Who initiated the most recent active URL change, when known. */\n  activeUrlChangeSource?: 'agent' | 'user';\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  protected readonly onSessionCreated?: (session: ThreadSession) => void;\n  protected 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    // For thread scope, always create/use a dedicated session (even for DEFAULT_THREAD_ID)\n    if (this.scope === 'shared') {\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      ...state,\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 { existsSync, unlinkSync, lstatSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\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// Profile Lock File Cleanup\n// =============================================================================\n\n/**\n * Lock files that Chrome/Chromium creates in the profile directory.\n * These can become stale if the browser doesn't shut down cleanly.\n */\nconst CHROME_LOCK_FILES = ['SingletonLock', 'SingletonSocket', 'SingletonCookie', 'chrome.pid', 'RunningChromeVersion'];\n\n/**\n * Clean up stale Chrome lock files from a profile directory.\n *\n * Chrome creates lock files (SingletonLock, SingletonSocket, etc.) to prevent\n * multiple instances from using the same profile. If the browser crashes or\n * doesn't shut down cleanly, these files can remain and block future launches.\n *\n * This function removes these lock files, allowing the profile to be reused.\n * It's safe to call even if the files don't exist.\n *\n * @param profilePath - Path to the Chrome profile directory\n * @param logger - Optional logger for debug output\n */\nexport function cleanupProfileLockFiles(\n  profilePath: string,\n  logger?: { debug?: (message: string) => void; warn?: (message: string) => void },\n): void {\n  if (!profilePath || !existsSync(profilePath)) {\n    return;\n  }\n\n  try {\n    const entries = readdirSync(profilePath);\n    for (const entry of entries) {\n      if (CHROME_LOCK_FILES.includes(entry)) {\n        const fullPath = join(profilePath, entry);\n        try {\n          const stat = lstatSync(fullPath);\n          // Remove both regular files and symlinks\n          if (stat.isFile() || stat.isSymbolicLink()) {\n            unlinkSync(fullPath);\n            logger?.debug?.(`Removed stale lock file: ${fullPath}`);\n          }\n        } catch (err) {\n          // File may have been removed between readdir and unlink, ignore\n          logger?.warn?.(`Failed to remove lock file ${fullPath}: ${err}`);\n        }\n      }\n    }\n  } catch (err) {\n    // Profile directory may not be readable, ignore\n    logger?.warn?.(`Failed to clean up profile lock files in ${profilePath}: ${err}`);\n  }\n}\n\n// =============================================================================\n// Process Group Cleanup\n// =============================================================================\n\n/**\n * Kill a browser process and its children by sending SIGKILL to the process group.\n *\n * When Chrome/Chromium is launched, it spawns child processes (GPU, renderer,\n * network, storage, crashpad handlers). If the main process exits uncleanly,\n * these children can become orphaned. Killing the process group ensures all\n * related processes are cleaned up.\n *\n * Note: Process group signaling (`-pid`) is POSIX-only. On Windows, this\n * function is a no-op and orphaned child processes must be cleaned up by\n * other means (e.g., taskkill).\n *\n * @param pid - The PID of the main browser process. If undefined, this is a no-op.\n * @param logger - Optional logger for debug output.\n */\nexport function killProcessGroup(\n  pid: number | undefined,\n  logger?: { debug?: (message: string) => void; warn?: (message: string) => void },\n): void {\n  if (pid == null) return;\n  try {\n    process.kill(-pid, 'SIGKILL');\n    logger?.debug?.(`Killed process group for PID ${pid}`);\n  } catch (err) {\n    // ESRCH = process already gone — expected\n    const code = (err as NodeJS.ErrnoException).code;\n    if (code !== 'ESRCH') {\n      logger?.warn?.(`Failed to kill process group ${pid}: ${code ?? err}`);\n    }\n  }\n}\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  // Profile & Authentication Options\n  // ==========================================================================\n\n  /**\n   * Path to a Chrome/Chromium user data directory (profile).\n   * When provided, the browser will use this profile's cookies, localStorage,\n   * extensions, and other session data.\n   *\n   * **Important:** Chrome only allows one process to access a profile at a time.\n   * If Chrome is already running with this profile, the browser will fail to launch.\n   * Either close Chrome first, or use a copy of the profile.\n   *\n   * @example\n   * ```ts\n   * // macOS Chrome default profile\n   * { profile: '/Users/you/Library/Application Support/Google/Chrome' }\n   *\n   * // Custom profile directory\n   * { profile: '/path/to/my-automation-profile' }\n   * ```\n   */\n  profile?: string;\n\n  /**\n   * Path to the browser executable to use.\n   * By default, Playwright/Stagehand use their bundled Chromium.\n   * Use this to launch a specific browser installation instead.\n   *\n   * @example\n   * ```ts\n   * // macOS Chrome\n   * { executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' }\n   *\n   * // Linux Chrome\n   * { executablePath: '/usr/bin/google-chrome' }\n   *\n   * // Windows Chrome\n   * { executablePath: 'C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe' }\n   * ```\n   */\n  executablePath?: string;\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 identifier (e.g., 'playwright', 'stagehand', 'browserbase') */\n  abstract readonly provider: string;\n\n  /**\n   * Provider type for runtime enforcement.\n   * - 'sdk': SDK providers (AgentBrowser, StagehandBrowser) — use with Agent.browser\n   * - 'cli': CLI providers (BrowserViewer) — use with Workspace.browser\n   * Defaults to 'sdk' for backward compatibility with existing providers.\n   */\n  readonly providerType: 'sdk' | 'cli' = 'sdk';\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  // Process ID Tracking (for orphaned process cleanup)\n  // ---------------------------------------------------------------------------\n\n  /**\n   * PID of the shared browser process.\n   * Set by providers after launch so the base class can kill the process group\n   * (GPU, renderer, crashpad, etc.) when the browser disconnects or closes.\n   */\n  protected sharedBrowserPid?: number;\n\n  /**\n   * PIDs of per-thread browser processes.\n   * Set by providers after creating a thread session.\n   */\n  protected threadBrowserPids = new Map<string, number>();\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    // Validate: cdpUrl is incompatible with launch-time options (profile, executablePath).\n    // CDP connects to an already-running browser — it has its own profile and executable.\n    if (config.cdpUrl && (config.profile || config.executablePath)) {\n      const conflicting = [config.profile && 'profile', config.executablePath && 'executablePath']\n        .filter(Boolean)\n        .join(' and ');\n      throw new Error(\n        `Invalid browser configuration: \"cdpUrl\" cannot be used with ${conflicting}.\\n\\n` +\n          '• cdpUrl connects to an existing browser (which has its own profile and executable)\\n' +\n          '• profile and executablePath are launch-time options for spawning a new browser\\n\\n' +\n          'To fix this, either:\\n' +\n          '1. Remove cdpUrl to launch a new browser with your profile/executable\\n' +\n          '2. Remove profile/executablePath to connect to the existing browser via CDP',\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   * Get the CDP WebSocket URL for connecting to this browser.\n   * CLI providers (BrowserViewer) implement this to expose the URL for CLI tools.\n   * SDK providers typically return null as they manage their own CDP connections.\n   *\n   * @param _threadId - Thread identifier (for thread-scoped browsers)\n   * @returns The CDP WebSocket URL (e.g., ws://127.0.0.1:9222/devtools/browser/...)\n   */\n  getCdpUrl(_threadId?: string): string | null {\n    return null;\n  }\n\n  /**\n   * Launch the browser.\n   * Race-condition-safe - handles concurrent calls, status management, and lifecycle hooks.\n   * @param _threadId - Thread identifier (for thread-scoped browsers, launches a browser for that thread)\n   */\n  async launch(threadId?: string): Promise<void> {\n    // Set current thread if provided, so thread-scoped browsers launch for that thread\n    if (threadId !== undefined) {\n      this.setCurrentThread(threadId);\n    }\n\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        // Clean up stale lock files only after confirmed shutdown.\n        // Removing them from a live profile (if doClose threw) could cause corruption.\n        if (this.config.profile) {\n          cleanupProfileLockFiles(this.config.profile, this.logger);\n        }\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        // Kill orphaned child processes (GPU, renderer, crashpad, etc.)\n        killProcessGroup(this.sharedBrowserPid, this.logger);\n        this.sharedBrowserPid = undefined;\n        for (const [, pid] of this.threadBrowserPids) {\n          killProcessGroup(pid, this.logger);\n        }\n        this.threadBrowserPids.clear();\n      }\n    })();\n\n    return this._closePromise;\n  }\n\n  /**\n   * Connect to an external browser via CDP URL for screencast.\n   *\n   * Use this when an agent is using their own external CDP (e.g., browser-use cloud).\n   * Connects Playwright to the external browser to enable screencast without launching\n   * our own browser.\n   *\n   * Override this in subclasses that support external CDP connections.\n   * The base implementation throws an error.\n   *\n   * @param cdpUrl - The external CDP WebSocket URL (wss://... or ws://...)\n   * @param threadId - Thread ID to associate the session with\n   */\n  async connectToExternalCdp(_cdpUrl: string, _threadId?: string): Promise<void> {\n    throw new Error(`${this.provider} does not support connecting to external CDP`);\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   * @param _threadId - Thread identifier (for thread-scoped browsers)\n   */\n  isBrowserRunning(_threadId?: string): 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      // Kill orphaned child processes for this thread\n      const pid = this.threadBrowserPids.get(threadId);\n      killProcessGroup(pid, this.logger);\n      this.threadBrowserPids.delete(threadId);\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      // Kill orphaned child processes for the shared browser\n      killProcessGroup(this.sharedBrowserPid, this.logger);\n      this.sharedBrowserPid = undefined;\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    // Clean up stale lock files in the profile directory\n    // This is especially important for external/manual close which may leave locks behind\n    if (this.config.profile) {\n      cleanupProfileLockFiles(this.config.profile, this.logger);\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    // Kill orphaned child processes for this thread\n    const pid = this.threadBrowserPids.get(threadId);\n    killProcessGroup(pid, this.logger);\n    this.threadBrowserPids.delete(threadId);\n    // Notify callbacks registered for this specific thread\n    this.notifyBrowserClosed(threadId);\n    // Clean up any stale lock files in the profile directory\n    if (this.config.profile) {\n      cleanupProfileLockFiles(this.config.profile, this.logger);\n    }\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    // Kill orphaned child processes for this thread\n    const pid = this.threadBrowserPids.get(threadId);\n    killProcessGroup(pid, this.logger);\n    this.threadBrowserPids.delete(threadId);\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    // Clean up any stale lock files in the profile directory\n    if (this.config.profile) {\n      cleanupProfileLockFiles(this.config.profile, this.logger);\n    }\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    // 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    // Check if browser is running (pass threadId for thread-scoped checks)\n    if (!this.isBrowserRunning(threadId)) {\n      return null;\n    }\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      // eslint-disable-next-line no-console\n      console.log(\n        `[MastraBrowser] startScreencastIfBrowserActive: hasThreadSession(${threadId})=false, scope=${scope}`,\n      );\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","/**\n * Pure-JS Motion-JPEG AVI muxer.\n *\n * Writes a list of JPEG frames into an AVI 1.0 container so that the resulting\n * `.avi` file plays in QuickTime / Preview / VLC / Chromium without depending\n * on ffmpeg or any native module.\n *\n * Implements the bare minimum of the RIFF/AVI spec needed for an MJPEG video\n * stream with no audio. All fields are little-endian.\n *\n * Reference: https://learn.microsoft.com/en-us/windows/win32/directshow/avi-riff-file-reference\n */\n\nimport { closeSync, fstatSync, mkdirSync, openSync, writeSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\n/** A single MJPEG frame to mux. */\nexport interface MjpegFrame {\n  /** JPEG bytes (must start with the SOI marker 0xFF 0xD8). */\n  bytes: Uint8Array;\n  /** Milliseconds since recording start. Used to compute the average frame rate. */\n  timestampMs: number;\n}\n\nexport interface MjpegAviOptions {\n  /** Frame width in pixels. */\n  width: number;\n  /** Frame height in pixels. */\n  height: number;\n}\n\nconst FOURCC_RIFF = fourcc('RIFF');\nconst FOURCC_AVI = fourcc('AVI ');\nconst FOURCC_LIST = fourcc('LIST');\nconst FOURCC_HDRL = fourcc('hdrl');\nconst FOURCC_AVIH = fourcc('avih');\nconst FOURCC_STRL = fourcc('strl');\nconst FOURCC_STRH = fourcc('strh');\nconst FOURCC_STRF = fourcc('strf');\nconst FOURCC_VIDS = fourcc('vids');\nconst FOURCC_MJPG = fourcc('MJPG');\nconst FOURCC_MOVI = fourcc('movi');\nconst FOURCC_IDX1 = fourcc('idx1');\nconst FOURCC_00DC = fourcc('00dc');\n\nconst AVIF_HASINDEX = 0x00000010;\nconst AVIIF_KEYFRAME = 0x00000010;\n\nconst AVIH_SIZE = 56;\nconst STRH_SIZE = 56;\nconst STRF_SIZE = 40; // BITMAPINFOHEADER, no extra data\nconst LIST_TYPE_SIZE = 4; // 4 bytes for the LIST type (\"hdrl\", \"movi\", etc.)\nconst CHUNK_HEADER_SIZE = 8; // fourcc (4) + size (4)\nconst MAX_U32 = 0xffffffff;\nconst MAX_I16 = 0x7fff;\n\nfunction fourcc(s: string): Buffer {\n  if (s.length !== 4) {\n    throw new Error(`fourcc must be 4 ASCII characters, got \"${s}\"`);\n  }\n  return Buffer.from(s, 'ascii');\n}\n\n/**\n * Encode a list of MJPEG frames as an AVI 1.0 file.\n *\n * The file is written incrementally to disk so we don't have to hold the whole\n * AVI in memory — large recordings can be hundreds of MB.\n */\nexport function writeMjpegAviFile(filePath: string, frames: readonly MjpegFrame[], opts: MjpegAviOptions): void {\n  if (frames.length === 0) {\n    throw new Error('writeMjpegAviFile: at least one frame is required');\n  }\n  if (opts.width <= 0 || opts.height <= 0 || !Number.isInteger(opts.width) || !Number.isInteger(opts.height)) {\n    throw new Error(`writeMjpegAviFile: invalid dimensions ${opts.width}x${opts.height}`);\n  }\n  if (opts.width > MAX_I16 || opts.height > MAX_I16) {\n    throw new Error(`writeMjpegAviFile: dimensions exceed AVI header bounds: ${opts.width}x${opts.height}`);\n  }\n  for (let i = 0; i < frames.length; i++) {\n    assertJpegFrame(frames[i]!.bytes, i);\n  }\n\n  mkdirSync(dirname(filePath), { recursive: true });\n\n  // Frame rate: derived from the elapsed time between the first and last\n  // captured frames. AVI's main header stores a single dwMicroSecPerFrame, so\n  // playback is even-paced; that matches MJPEG's typical usage.\n  const elapsedMs =\n    frames.length > 1 ? Math.max(1, frames[frames.length - 1]!.timestampMs - frames[0]!.timestampMs) : 1000;\n  const fps = Math.max(1, Math.min(120, Math.round((frames.length * 1000) / elapsedMs)));\n  const microSecPerFrame = Math.round(1_000_000 / fps);\n\n  const maxFrameLen = frames.reduce((m, f) => Math.max(m, f.bytes.length), 0);\n  assertU32(maxFrameLen, 'max frame length');\n  const totalFrameBytes = frames.reduce((sum, f) => sum + CHUNK_HEADER_SIZE + paddedLength(f.bytes.length), 0);\n  assertU32(totalFrameBytes, 'total frame bytes');\n\n  // -------------------------------------------------------------------------\n  // Pre-compute header bytes\n  // -------------------------------------------------------------------------\n\n  const hdrl = buildHdrl({\n    width: opts.width,\n    height: opts.height,\n    microSecPerFrame,\n    totalFrames: frames.length,\n    maxFrameLen,\n  });\n\n  // movi list size: 4 bytes for the \"movi\" type fourcc + all frame chunks.\n  const moviPayloadSize = LIST_TYPE_SIZE + totalFrameBytes;\n  assertU32(moviPayloadSize, 'movi list size');\n  // idx1 chunk size: 16 bytes per entry.\n  const idx1PayloadSize = frames.length * 16;\n  assertU32(idx1PayloadSize, 'idx1 chunk size');\n\n  // RIFF payload size = 4 (\"AVI \") + hdrl LIST (header+size+payload) +\n  //                     movi LIST (header+size+payload) + idx1 chunk (header+payload)\n  const riffPayloadSize =\n    4 + CHUNK_HEADER_SIZE + hdrl.length + CHUNK_HEADER_SIZE + moviPayloadSize + CHUNK_HEADER_SIZE + idx1PayloadSize;\n  assertU32(riffPayloadSize, 'RIFF payload size');\n\n  // -------------------------------------------------------------------------\n  // Write the file\n  // -------------------------------------------------------------------------\n\n  const fd = openSync(filePath, 'w');\n  try {\n    // RIFF header\n    writeFourCC(fd, FOURCC_RIFF);\n    writeU32(fd, riffPayloadSize);\n    writeFourCC(fd, FOURCC_AVI);\n\n    // hdrl LIST\n    writeFourCC(fd, FOURCC_LIST);\n    writeU32(fd, hdrl.length);\n    writeBuffer(fd, hdrl);\n\n    // movi LIST\n    writeFourCC(fd, FOURCC_LIST);\n    writeU32(fd, moviPayloadSize);\n    writeFourCC(fd, FOURCC_MOVI);\n\n    // Track per-frame offsets relative to the start of the \"movi\" type fourcc\n    // (i.e. offset 0 == the \"movi\" tag itself). This is the convention most\n    // AVI parsers expect for idx1.\n    const moviStartOffset = currentOffset(fd) - LIST_TYPE_SIZE;\n    const frameOffsets: number[] = [];\n\n    for (const frame of frames) {\n      const offset = currentOffset(fd) - moviStartOffset;\n      frameOffsets.push(offset);\n      writeFourCC(fd, FOURCC_00DC);\n      writeU32(fd, frame.bytes.length);\n      writeBuffer(fd, Buffer.from(frame.bytes.buffer, frame.bytes.byteOffset, frame.bytes.byteLength));\n      // Chunks are word-aligned: pad odd-length chunks with a zero byte.\n      if (frame.bytes.length % 2 === 1) {\n        writeBuffer(fd, Buffer.from([0]));\n      }\n    }\n\n    // idx1 chunk\n    writeFourCC(fd, FOURCC_IDX1);\n    writeU32(fd, idx1PayloadSize);\n    const idx1 = Buffer.alloc(idx1PayloadSize);\n    for (let i = 0; i < frames.length; i++) {\n      const base = i * 16;\n      FOURCC_00DC.copy(idx1, base);\n      idx1.writeUInt32LE(AVIIF_KEYFRAME, base + 4);\n      idx1.writeUInt32LE(frameOffsets[i]!, base + 8);\n      idx1.writeUInt32LE(frames[i]!.bytes.length, base + 12);\n    }\n    writeBuffer(fd, idx1);\n  } finally {\n    closeSync(fd);\n  }\n}\n\n/** Build the contents of the hdrl LIST (without the leading LIST/size/hdrl tag). */\nfunction buildHdrl(args: {\n  width: number;\n  height: number;\n  microSecPerFrame: number;\n  totalFrames: number;\n  maxFrameLen: number;\n}): Buffer {\n  const { width, height, microSecPerFrame, totalFrames, maxFrameLen } = args;\n  assertU32(microSecPerFrame, 'microseconds per frame');\n  assertU32(totalFrames, 'total frames');\n  assertU32(maxFrameLen, 'max frame length');\n  const maxBytesPerSec = Math.round((maxFrameLen * 1_000_000) / microSecPerFrame);\n  assertU32(maxBytesPerSec, 'max bytes per second');\n  const sizeImage = width * height * 3;\n  assertU32(sizeImage, 'bitmap image size');\n\n  // Inner size:\n  //   \"hdrl\" (4) + avih chunk header (8) + avih payload (56)\n  //     + strl LIST tag (4) + LIST size (4) + \"strl\" (4)\n  //       + strh chunk header (8) + strh payload (56)\n  //       + strf chunk header (8) + strf payload (40)\n  const strlPayloadSize = LIST_TYPE_SIZE + CHUNK_HEADER_SIZE + STRH_SIZE + CHUNK_HEADER_SIZE + STRF_SIZE;\n  const hdrlPayloadSize = LIST_TYPE_SIZE + CHUNK_HEADER_SIZE + AVIH_SIZE + CHUNK_HEADER_SIZE + strlPayloadSize;\n  const buf = Buffer.alloc(hdrlPayloadSize);\n\n  let p = 0;\n  FOURCC_HDRL.copy(buf, p);\n  p += 4;\n\n  // avih chunk\n  FOURCC_AVIH.copy(buf, p);\n  p += 4;\n  buf.writeUInt32LE(AVIH_SIZE, p);\n  p += 4;\n  // dwMicroSecPerFrame\n  buf.writeUInt32LE(microSecPerFrame, p);\n  p += 4;\n  // dwMaxBytesPerSec\n  buf.writeUInt32LE(maxBytesPerSec, p);\n  p += 4;\n  // dwPaddingGranularity\n  buf.writeUInt32LE(0, p);\n  p += 4;\n  // dwFlags\n  buf.writeUInt32LE(AVIF_HASINDEX, p);\n  p += 4;\n  // dwTotalFrames\n  buf.writeUInt32LE(totalFrames, p);\n  p += 4;\n  // dwInitialFrames\n  buf.writeUInt32LE(0, p);\n  p += 4;\n  // dwStreams\n  buf.writeUInt32LE(1, p);\n  p += 4;\n  // dwSuggestedBufferSize\n  buf.writeUInt32LE(maxFrameLen, p);\n  p += 4;\n  // dwWidth, dwHeight\n  buf.writeUInt32LE(width, p);\n  p += 4;\n  buf.writeUInt32LE(height, p);\n  p += 4;\n  // dwReserved[4]\n  p += 16;\n\n  // strl LIST\n  FOURCC_LIST.copy(buf, p);\n  p += 4;\n  buf.writeUInt32LE(strlPayloadSize, p);\n  p += 4;\n  FOURCC_STRL.copy(buf, p);\n  p += 4;\n\n  // strh chunk\n  FOURCC_STRH.copy(buf, p);\n  p += 4;\n  buf.writeUInt32LE(STRH_SIZE, p);\n  p += 4;\n  FOURCC_VIDS.copy(buf, p);\n  p += 4; // fccType\n  FOURCC_MJPG.copy(buf, p);\n  p += 4; // fccHandler\n  // dwFlags, wPriority, wLanguage, dwInitialFrames\n  buf.writeUInt32LE(0, p);\n  p += 4;\n  buf.writeUInt16LE(0, p);\n  p += 2;\n  buf.writeUInt16LE(0, p);\n  p += 2;\n  buf.writeUInt32LE(0, p);\n  p += 4;\n  // dwScale, dwRate -> rate/scale = fps\n  buf.writeUInt32LE(microSecPerFrame, p);\n  p += 4;\n  buf.writeUInt32LE(1_000_000, p);\n  p += 4;\n  // dwStart\n  buf.writeUInt32LE(0, p);\n  p += 4;\n  // dwLength (frames)\n  buf.writeUInt32LE(totalFrames, p);\n  p += 4;\n  // dwSuggestedBufferSize\n  buf.writeUInt32LE(maxFrameLen, p);\n  p += 4;\n  // dwQuality (-1 == default)\n  buf.writeInt32LE(-1, p);\n  p += 4;\n  // dwSampleSize\n  buf.writeUInt32LE(0, p);\n  p += 4;\n  // rcFrame (left, top, right, bottom) as 16-bit ints\n  buf.writeInt16LE(0, p);\n  p += 2;\n  buf.writeInt16LE(0, p);\n  p += 2;\n  buf.writeInt16LE(width, p);\n  p += 2;\n  buf.writeInt16LE(height, p);\n  p += 2;\n\n  // strf chunk (BITMAPINFOHEADER for MJPG)\n  FOURCC_STRF.copy(buf, p);\n  p += 4;\n  buf.writeUInt32LE(STRF_SIZE, p);\n  p += 4;\n  // biSize\n  buf.writeUInt32LE(STRF_SIZE, p);\n  p += 4;\n  // biWidth, biHeight\n  buf.writeInt32LE(width, p);\n  p += 4;\n  buf.writeInt32LE(height, p);\n  p += 4;\n  // biPlanes, biBitCount\n  buf.writeUInt16LE(1, p);\n  p += 2;\n  buf.writeUInt16LE(24, p);\n  p += 2;\n  // biCompression = \"MJPG\"\n  FOURCC_MJPG.copy(buf, p);\n  p += 4;\n  // biSizeImage\n  buf.writeUInt32LE(sizeImage, p);\n  p += 4;\n  // biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant\n  buf.writeInt32LE(0, p);\n  p += 4;\n  buf.writeInt32LE(0, p);\n  p += 4;\n  buf.writeUInt32LE(0, p);\n  p += 4;\n  buf.writeUInt32LE(0, p);\n  p += 4;\n\n  if (p !== hdrlPayloadSize) {\n    throw new Error(`buildHdrl internal error: wrote ${p} bytes, expected ${hdrlPayloadSize}`);\n  }\n  return buf;\n}\n\nfunction paddedLength(n: number): number {\n  return n + (n & 1);\n}\n\nfunction assertJpegFrame(bytes: Uint8Array, index: number): void {\n  if (bytes.length < 2 || bytes[0] !== 0xff || bytes[1] !== 0xd8) {\n    throw new Error(`writeMjpegAviFile: frame ${index} is not a JPEG frame (missing SOI marker)`);\n  }\n}\n\nfunction assertU32(value: number, field: string): void {\n  if (!Number.isSafeInteger(value) || value < 0 || value > MAX_U32) {\n    throw new Error(`writeMjpegAviFile: ${field} exceeds 32-bit AVI limit (${value})`);\n  }\n}\n\n// ---------------------------------------------------------------------------\n// File I/O helpers\n// ---------------------------------------------------------------------------\n\nconst u32buf = Buffer.alloc(4);\n\nfunction writeFourCC(fd: number, fc: Buffer): void {\n  writeSync(fd, fc, 0, 4);\n}\n\nfunction writeU32(fd: number, value: number): void {\n  assertU32(value, 'uint32 field');\n  u32buf.writeUInt32LE(value, 0);\n  writeSync(fd, u32buf, 0, 4);\n}\n\nfunction writeBuffer(fd: number, buf: Buffer): void {\n  writeSync(fd, buf, 0, buf.length);\n}\n\nfunction currentOffset(fd: number): number {\n  return fstatSync(fd).size;\n}\n","/**\n * Pure functions for caption overlay rendering on screencast frames.\n *\n * Kept separate from browser-recording.ts so the lifecycle/tool code stays\n * focused and the pixel-level logic is easy to test.\n */\n\nimport { decode as decodeJpegBytes, encode as encodeJpegBytes } from 'jpeg-js';\n\n/** A caption is a short piece of agent-authored text shown for a window of time. */\nexport interface RecordingCaption {\n  /** Milliseconds since recording start when the caption was added. */\n  timestampMs: number;\n  /** Plain text caption. */\n  text: string;\n  /** How long the caption should remain visible (ms). */\n  durationMs: number;\n}\n\n/** Decoded RGBA frame buffer. */\nexport interface RgbaFrame {\n  width: number;\n  height: number;\n  /** Tightly packed RGBA pixels (width * height * 4 bytes). */\n  data: Uint8ClampedArray;\n}\n\n/**\n * Pick the caption that should be visible at a given timestamp.\n *\n * If multiple captions overlap (a new caption starts before the previous\n * expires), the newer one wins.\n *\n * Returns undefined when no caption is active at `t`.\n */\nexport function selectCaptionAt(captions: readonly RecordingCaption[], t: number): RecordingCaption | undefined {\n  let active: RecordingCaption | undefined;\n  for (const c of captions) {\n    if (t >= c.timestampMs && t < c.timestampMs + c.durationMs) {\n      if (!active || c.timestampMs > active.timestampMs) {\n        active = c;\n      }\n    }\n  }\n  return active;\n}\n\n/**\n * Decode a JPEG buffer into an RGBA pixel array.\n * Throws when the JPEG cannot be parsed.\n */\nexport function decodeJpeg(jpegBytes: Uint8Array): RgbaFrame {\n  const decoded = decodeJpegBytes(jpegBytes, { useTArray: true, formatAsRGBA: true });\n  return {\n    width: decoded.width,\n    height: decoded.height,\n    data: new Uint8ClampedArray(decoded.data.buffer, decoded.data.byteOffset, decoded.data.byteLength),\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Bitmap font\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal 5x7 bitmap font covering printable ASCII (0x20..0x7E).\n * Each glyph is 5 columns × 7 rows, encoded as 7 bytes (one per row).\n * Bit 4 (0x10) of each row byte is the leftmost pixel.\n *\n * This is intentionally tiny so we don't need a TrueType/system font.\n */\nconst FONT_5x7: Record<string, readonly number[]> = {\n  ' ': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],\n  '!': [0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04],\n  '\"': [0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00],\n  '#': [0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x00, 0x00],\n  $: [0x04, 0x0f, 0x14, 0x0e, 0x05, 0x1e, 0x04],\n  '%': [0x19, 0x19, 0x02, 0x04, 0x08, 0x13, 0x13],\n  '&': [0x08, 0x14, 0x14, 0x08, 0x15, 0x12, 0x0d],\n  \"'\": [0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00],\n  '(': [0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02],\n  ')': [0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08],\n  '*': [0x00, 0x04, 0x15, 0x0e, 0x15, 0x04, 0x00],\n  '+': [0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x00],\n  ',': [0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08],\n  '-': [0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00],\n  '.': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04],\n  '/': [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00],\n  '0': [0x0e, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0e],\n  '1': [0x04, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x0e],\n  '2': [0x0e, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1f],\n  '3': [0x1f, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0e],\n  '4': [0x02, 0x06, 0x0a, 0x12, 0x1f, 0x02, 0x02],\n  '5': [0x1f, 0x10, 0x1e, 0x01, 0x01, 0x11, 0x0e],\n  '6': [0x06, 0x08, 0x10, 0x1e, 0x11, 0x11, 0x0e],\n  '7': [0x1f, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08],\n  '8': [0x0e, 0x11, 0x11, 0x0e, 0x11, 0x11, 0x0e],\n  '9': [0x0e, 0x11, 0x11, 0x0f, 0x01, 0x02, 0x0c],\n  ':': [0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00],\n  ';': [0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x08],\n  '<': [0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02],\n  '=': [0x00, 0x00, 0x1f, 0x00, 0x1f, 0x00, 0x00],\n  '>': [0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08],\n  '?': [0x0e, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04],\n  '@': [0x0e, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0e],\n  A: [0x0e, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11],\n  B: [0x1e, 0x11, 0x11, 0x1e, 0x11, 0x11, 0x1e],\n  C: [0x0e, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0e],\n  D: [0x1c, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1c],\n  E: [0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x1f],\n  F: [0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x10],\n  G: [0x0e, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0f],\n  H: [0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11],\n  I: [0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e],\n  J: [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0c],\n  K: [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11],\n  L: [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f],\n  M: [0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11],\n  N: [0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11],\n  O: [0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e],\n  P: [0x1e, 0x11, 0x11, 0x1e, 0x10, 0x10, 0x10],\n  Q: [0x0e, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0d],\n  R: [0x1e, 0x11, 0x11, 0x1e, 0x14, 0x12, 0x11],\n  S: [0x0e, 0x11, 0x10, 0x0e, 0x01, 0x11, 0x0e],\n  T: [0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04],\n  U: [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e],\n  V: [0x11, 0x11, 0x11, 0x11, 0x11, 0x0a, 0x04],\n  W: [0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0a],\n  X: [0x11, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x11],\n  Y: [0x11, 0x11, 0x11, 0x0a, 0x04, 0x04, 0x04],\n  Z: [0x1f, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1f],\n  '[': [0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e],\n  '\\\\': [0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00],\n  ']': [0x0e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0e],\n  '^': [0x04, 0x0a, 0x11, 0x00, 0x00, 0x00, 0x00],\n  _: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f],\n  '`': [0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00],\n  a: [0x00, 0x00, 0x0e, 0x01, 0x0f, 0x11, 0x0f],\n  b: [0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x1e],\n  c: [0x00, 0x00, 0x0e, 0x11, 0x10, 0x11, 0x0e],\n  d: [0x01, 0x01, 0x0d, 0x13, 0x11, 0x11, 0x0f],\n  e: [0x00, 0x00, 0x0e, 0x11, 0x1f, 0x10, 0x0e],\n  f: [0x02, 0x05, 0x04, 0x0e, 0x04, 0x04, 0x04],\n  g: [0x00, 0x00, 0x0f, 0x11, 0x0f, 0x01, 0x0e],\n  h: [0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x11],\n  i: [0x04, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x0e],\n  j: [0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0c],\n  k: [0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12],\n  l: [0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0e],\n  m: [0x00, 0x00, 0x1a, 0x15, 0x15, 0x11, 0x11],\n  n: [0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11],\n  o: [0x00, 0x00, 0x0e, 0x11, 0x11, 0x11, 0x0e],\n  p: [0x00, 0x00, 0x1e, 0x11, 0x1e, 0x10, 0x10],\n  q: [0x00, 0x00, 0x0d, 0x13, 0x0f, 0x01, 0x01],\n  r: [0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10],\n  s: [0x00, 0x00, 0x0e, 0x10, 0x0e, 0x01, 0x1e],\n  t: [0x04, 0x04, 0x0e, 0x04, 0x04, 0x05, 0x02],\n  u: [0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0d],\n  v: [0x00, 0x00, 0x11, 0x11, 0x11, 0x0a, 0x04],\n  w: [0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0a],\n  x: [0x00, 0x00, 0x11, 0x0a, 0x04, 0x0a, 0x11],\n  y: [0x00, 0x00, 0x11, 0x11, 0x0f, 0x01, 0x0e],\n  z: [0x00, 0x00, 0x1f, 0x02, 0x04, 0x08, 0x1f],\n  '{': [0x02, 0x04, 0x04, 0x08, 0x04, 0x04, 0x02],\n  '|': [0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04],\n  '}': [0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08],\n  '~': [0x00, 0x00, 0x08, 0x15, 0x02, 0x00, 0x00],\n};\n\nconst FONT_WIDTH = 5;\nconst FONT_HEIGHT = 7;\nconst FONT_GAP = 1;\n\n/**\n * Replace any unsupported character with `?` so we never crash on emoji\n * or non-ASCII input. Captions are intentionally short ASCII-ish text.\n */\nfunction safeChar(c: string): string {\n  return Object.prototype.hasOwnProperty.call(FONT_5x7, c) ? c : '?';\n}\n\n/** Pixel width of a string at the given scale. */\nfunction measureText(text: string, scale: number): number {\n  const codePoints = Array.from(text);\n  if (codePoints.length === 0) return 0;\n  return codePoints.length * FONT_WIDTH * scale + (codePoints.length - 1) * FONT_GAP * scale;\n}\n\ninterface DrawTextOpts {\n  /** RGB color for the text. */\n  color: [number, number, number];\n  /** Integer scaling factor (1, 2, 3...). */\n  scale: number;\n  /** Top-left pixel position. */\n  x: number;\n  y: number;\n}\n\nfunction drawText(frame: RgbaFrame, text: string, opts: DrawTextOpts): void {\n  const { width, height, data } = frame;\n  const { color, scale } = opts;\n  let cursorX = opts.x;\n  const baseY = opts.y;\n\n  for (const rawChar of text) {\n    const ch = safeChar(rawChar);\n    const glyph = FONT_5x7[ch]!;\n    for (let row = 0; row < FONT_HEIGHT; row++) {\n      const bits = glyph[row]!;\n      for (let col = 0; col < FONT_WIDTH; col++) {\n        if ((bits >> (FONT_WIDTH - 1 - col)) & 1) {\n          // Fill the scale x scale block for this lit pixel.\n          for (let dy = 0; dy < scale; dy++) {\n            for (let dx = 0; dx < scale; dx++) {\n              const px = cursorX + col * scale + dx;\n              const py = baseY + row * scale + dy;\n              if (px < 0 || px >= width || py < 0 || py >= height) continue;\n              const idx = (py * width + px) * 4;\n              data[idx] = color[0];\n              data[idx + 1] = color[1];\n              data[idx + 2] = color[2];\n              data[idx + 3] = 255;\n            }\n          }\n        }\n      }\n    }\n    cursorX += (FONT_WIDTH + FONT_GAP) * scale;\n  }\n}\n\n/** Options controlling how a caption is drawn over a frame. */\nexport interface CaptionOverlayOptions {\n  /** Integer scaling factor for the bitmap font. Default 2. */\n  fontScale?: number;\n  /** Vertical padding (in pixels) above and below the text inside the strip. */\n  padding?: number;\n  /** Bottom margin between the strip and the bottom of the frame. */\n  marginBottom?: number;\n  /** Background RGB color. Default black. */\n  backgroundColor?: [number, number, number];\n  /** Background alpha 0..255. Default ~180 (semi-transparent). */\n  backgroundAlpha?: number;\n  /** Text RGB color. Default white. */\n  textColor?: [number, number, number];\n}\n\nconst DEFAULT_OPTS: Required<CaptionOverlayOptions> = {\n  fontScale: 2,\n  padding: 6,\n  marginBottom: 8,\n  backgroundColor: [0, 0, 0],\n  backgroundAlpha: 180,\n  textColor: [255, 255, 255],\n};\n\n/**\n * Draw a caption at the bottom of the frame in-place.\n *\n * Renders a semi-transparent dark strip with the text centered on top.\n * Long captions are truncated with an ellipsis to fit the frame width.\n */\nexport function drawCaptionOnFrame(frame: RgbaFrame, caption: string, options: CaptionOverlayOptions = {}): void {\n  const opts: Required<CaptionOverlayOptions> = { ...DEFAULT_OPTS, ...options };\n  const { width, height, data } = frame;\n  if (width <= 0 || height <= 0) return;\n  if (!caption || caption.trim().length === 0) return;\n\n  const scale = Math.max(1, Math.floor(opts.fontScale));\n  const textHeight = FONT_HEIGHT * scale;\n  const stripHeight = textHeight + opts.padding * 2;\n  const stripTop = Math.max(0, height - stripHeight - opts.marginBottom);\n  const stripBottom = Math.min(height, stripTop + stripHeight);\n  if (stripTop >= stripBottom) return;\n\n  // Truncate text if it overflows the available width.\n  const maxTextWidth = Math.max(0, width - 16);\n  let text = caption;\n  if (measureText(text, scale) > maxTextWidth) {\n    const ellipsis = '...';\n    const codePoints = Array.from(text);\n    while (codePoints.length > 0 && measureText(codePoints.join('') + ellipsis, scale) > maxTextWidth) {\n      codePoints.pop();\n    }\n    text = codePoints.join('') + ellipsis;\n  }\n\n  // Composite the semi-transparent background over the existing pixels.\n  const [br, bg, bb] = opts.backgroundColor;\n  const alpha = Math.min(255, Math.max(0, opts.backgroundAlpha)) / 255;\n  for (let y = stripTop; y < stripBottom; y++) {\n    for (let x = 0; x < width; x++) {\n      const idx = (y * width + x) * 4;\n      const r = data[idx]!;\n      const g = data[idx + 1]!;\n      const b = data[idx + 2]!;\n      data[idx] = Math.round(r * (1 - alpha) + br * alpha);\n      data[idx + 1] = Math.round(g * (1 - alpha) + bg * alpha);\n      data[idx + 2] = Math.round(b * (1 - alpha) + bb * alpha);\n      data[idx + 3] = 255;\n    }\n  }\n\n  // Center text horizontally inside the strip.\n  const textWidth = measureText(text, scale);\n  const textX = Math.max(0, Math.floor((width - textWidth) / 2));\n  const textY = stripTop + Math.floor((stripHeight - textHeight) / 2);\n\n  drawText(frame, text, { color: opts.textColor, scale, x: textX, y: textY });\n}\n\n/**\n * Encode an RGBA frame back into JPEG bytes. Used by the recording pipeline\n * when re-encoding a frame after burning a caption onto it.\n */\nexport function encodeJpeg(frame: RgbaFrame, quality = 80): Uint8Array {\n  const encoded = encodeJpegBytes(\n    {\n      data: Buffer.from(frame.data.buffer, frame.data.byteOffset, frame.data.byteLength),\n      width: frame.width,\n      height: frame.height,\n    },\n    quality,\n  );\n  return new Uint8Array(encoded.data.buffer, encoded.data.byteOffset, encoded.data.byteLength);\n}\n","/**\n * Opt-in browser recording tools.\n *\n * Wraps the existing browser screencast infrastructure to capture frames, lets\n * the agent drop short captions at specific moments, and encodes the result as\n * a Motion-JPEG AVI video written to disk. The AVI format is used because it\n * can be muxed in pure JavaScript (no ffmpeg) and plays natively in QuickTime /\n * Preview / VLC / browsers.\n */\n\nimport { isAbsolute, join, relative, resolve, sep } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { createTool } from '../../tools';\nimport type { MastraBrowser, ScreencastStream } from '../browser';\nimport { writeMjpegAviFile } from './mjpeg-avi.js';\nimport type { MjpegFrame } from './mjpeg-avi.js';\nimport { decodeJpeg, drawCaptionOnFrame, encodeJpeg, selectCaptionAt } from './overlay.js';\nimport type { RecordingCaption } from './overlay.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_MAX_DURATION_MS = 30_000;\nconst HARD_CAP_MAX_DURATION_MS = 120_000;\nconst DEFAULT_EVERY_NTH_FRAME = 2;\nconst DEFAULT_MAX_WIDTH = 1024;\nconst DEFAULT_MAX_HEIGHT = 720;\n\nconst MAX_CAPTION_LENGTH = 80;\nconst DEFAULT_CAPTION_DURATION_MS = 2_500;\nconst MIN_CAPTION_SPACING_MS = 500;\n\n// Cap the number of buffered frames so a runaway recording can't OOM the host.\nconst MAX_BUFFERED_FRAMES = 2_000;\n\n// How long a frame stall must persist before the watchdog reissues the\n// screencast. CDP frames at quality 80 / everyNthFrame 2 normally arrive at\n// ≥2/s on an active page; idle pages can go 1-2s between frames so we leave\n// generous headroom.\nconst FRAME_STALL_MS = 4_000;\n\n// How often the watchdog polls. Cheap (one Date.now compare) so 1s is fine.\nconst WATCHDOG_INTERVAL_MS = 1_000;\n\n// ---------------------------------------------------------------------------\n// Recording state\n// ---------------------------------------------------------------------------\n\ninterface BufferedFrame {\n  /** Milliseconds since recording start. */\n  timestampMs: number;\n  /** Raw JPEG bytes returned by CDP. */\n  bytes: Uint8Array;\n}\n\nexport interface BrowserRecordingOptions {\n  /** Directory where browser recordings are written. */\n  outputDir: string;\n  /** Default maximum recording duration in ms (default 30 000, hard cap 120 000). */\n  maxDurationMs?: number;\n  /** Default max frame width in pixels (default 1024). */\n  maxWidth?: number;\n  /** Default max frame height in pixels (default 720). */\n  maxHeight?: number;\n}\n\ninterface RecordingState {\n  id: string;\n  stream: ScreencastStream;\n  startedAt: number;\n  maxDurationMs: number;\n  outputPath: string;\n  frames: BufferedFrame[];\n  captions: RecordingCaption[];\n  autoStopTimer: NodeJS.Timeout | null;\n  /** Set when the screencast fails so the next tool call surfaces it. */\n  pendingError: Error | null;\n  /** Set after stop() begins so we don't double-stop. */\n  stopping: boolean;\n  /** Last caption timestamp (for rate-limiting). */\n  lastCaptionAt: number;\n  /** Wall-clock ms (Date.now) of last frame seen, for watchdog. */\n  lastFrameAt: number;\n  /** Watchdog that reconnects the screencast if frames stall. */\n  watchdogTimer: NodeJS.Timeout | null;\n  /** True while a reconnect is in flight; suppresses parallel attempts. */\n  reconnecting: boolean;\n}\n\n/**\n * Module-local state. Only one recording at a time per process — this is\n * intentional and is enforced by the browser_record tool.\n */\nlet active: RecordingState | null = null;\n\nfunction generateRecordingId(): string {\n  return `rec_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction recordingsDir(outputDir: string): string {\n  return resolve(outputDir);\n}\n\nfunction defaultOutputPath(id: string, outputDir: string): string {\n  return join(recordingsDir(outputDir), `${id}.avi`);\n}\n\nfunction resolveOutputPath(id: string, outputDir: string, requestedPath?: string): string {\n  const baseDir = recordingsDir(outputDir);\n  const outputPath = requestedPath ? resolve(requestedPath) : defaultOutputPath(id, outputDir);\n  const rel = relative(baseDir, outputPath);\n  if (rel === '' || isAbsolute(rel) || rel === '..' || rel.startsWith(`..${sep}`)) {\n    throw new Error(`Recording outputPath must be inside ${baseDir}`);\n  }\n  return outputPath;\n}\n\nfunction clearState(): void {\n  if (active?.autoStopTimer) {\n    clearTimeout(active.autoStopTimer);\n  }\n  if (active?.watchdogTimer) {\n    clearInterval(active.watchdogTimer);\n  }\n  active = null;\n}\n\n/** Internal: stop the screencast, ignoring errors. */\nasync function safeStop(stream: ScreencastStream): Promise<void> {\n  try {\n    await stream.stop();\n  } catch {\n    // Browser may already be gone — that's fine.\n  }\n}\n\n// ---------------------------------------------------------------------------\n// MJPEG AVI encoding\n// ---------------------------------------------------------------------------\n\n/**\n * Produce one captioned JPEG frame ready to be muxed into the AVI container.\n *\n * If there's no active caption at this frame's timestamp the original JPEG\n * bytes are returned as-is — re-encoding is only needed when a caption needs\n * to be burned onto the frame.\n */\nfunction buildCaptionedFrame(state: RecordingState, frame: BufferedFrame): MjpegFrame {\n  const caption = selectCaptionAt(state.captions, frame.timestampMs);\n  if (!caption) {\n    return { bytes: frame.bytes, timestampMs: frame.timestampMs };\n  }\n  const rgba = decodeJpeg(frame.bytes);\n  drawCaptionOnFrame(rgba, caption.text);\n  return { bytes: encodeJpeg(rgba, 80), timestampMs: frame.timestampMs };\n}\n\n/**\n * Encode all buffered frames as an MJPEG AVI file written directly to disk.\n *\n * Returns the dimensions of the first frame (used to populate the AVI header).\n * The AVI stream has one fixed frame size, so fail fast if the browser changes\n * screencast dimensions mid-recording.\n */\nfunction encodeFramesAsAvi(\n  state: RecordingState,\n  outputPath: string,\n): { width: number; height: number; written: number } {\n  if (state.frames.length === 0) {\n    throw new Error('No frames captured during recording');\n  }\n\n  // Inspect the first frame to learn the dimensions for the AVI header.\n  const firstRgba = decodeJpeg(state.frames[0]!.bytes);\n  const width = firstRgba.width;\n  const height = firstRgba.height;\n\n  const muxFrames: MjpegFrame[] = [];\n  for (const frame of state.frames) {\n    const rgba = decodeJpeg(frame.bytes);\n    if (rgba.width !== width || rgba.height !== height) {\n      throw new Error(\n        `Frame dimensions changed during recording: expected ${width}x${height}, got ${rgba.width}x${rgba.height}`,\n      );\n    }\n    const out = buildCaptionedFrame(state, frame);\n    muxFrames.push(out);\n  }\n\n  writeMjpegAviFile(outputPath, muxFrames, { width, height });\n  return { width, height, written: muxFrames.length };\n}\n\n// ---------------------------------------------------------------------------\n// Lifecycle helpers\n// ---------------------------------------------------------------------------\n\nasync function startRecording(\n  browser: MastraBrowser,\n  opts: {\n    maxDurationMs?: number;\n    everyNthFrame?: number;\n    maxWidth?: number;\n    maxHeight?: number;\n    outputPath?: string;\n    threadId?: string;\n    outputDir: string;\n  },\n): Promise<{ id: string; outputPath: string; maxDurationMs: number }> {\n  if (active) {\n    throw new Error(\n      'A browser recording is already active. Call browser_record with action=\"stop\" before starting a new recording.',\n    );\n  }\n\n  const maxDurationMs = Math.min(\n    HARD_CAP_MAX_DURATION_MS,\n    Math.max(1_000, opts.maxDurationMs ?? DEFAULT_MAX_DURATION_MS),\n  );\n  const everyNthFrame = Math.max(1, Math.floor(opts.everyNthFrame ?? DEFAULT_EVERY_NTH_FRAME));\n  const maxWidth = Math.max(160, Math.floor(opts.maxWidth ?? DEFAULT_MAX_WIDTH));\n  const maxHeight = Math.max(120, Math.floor(opts.maxHeight ?? DEFAULT_MAX_HEIGHT));\n\n  const id = generateRecordingId();\n  const outputPath = resolveOutputPath(id, opts.outputDir, opts.outputPath);\n\n  let stream: ScreencastStream;\n  try {\n    // Bind screencast to the same thread/page the agent is interacting with.\n    // Without this, getPageForThread() can pick a different page than the one\n    // being navigated, so Page.screencastFrame never fires.\n    browser.setCurrentThread(opts.threadId);\n    await browser.ensureReady();\n    stream = await browser.startScreencast({\n      // JPEG is the well-tested format for CDP screencast (matches Studio\n      // live viewer); PNG mode is unreliable across Chromium builds.\n      format: 'jpeg',\n      quality: 80,\n      maxWidth,\n      maxHeight,\n      everyNthFrame,\n      threadId: opts.threadId,\n    });\n  } catch (error) {\n    const msg = error instanceof Error ? error.message : String(error);\n    throw new Error(`Failed to start browser recording: ${msg}`);\n  }\n\n  const startedAt = Date.now();\n  const state: RecordingState = {\n    id,\n    stream,\n    startedAt,\n    maxDurationMs,\n    outputPath,\n    frames: [],\n    captions: [],\n    autoStopTimer: null,\n    pendingError: null,\n    stopping: false,\n    lastCaptionAt: -Infinity,\n    lastFrameAt: startedAt,\n    watchdogTimer: null,\n    reconnecting: false,\n  };\n\n  // Set active state *before* attaching listeners so frames arriving on the\n  // very next tick aren't dropped by the `!active` guard.\n  active = state;\n\n  stream.on('frame', (frame: { data: string }) => {\n    if (!active || active.id !== id || active.stopping) return;\n    active.lastFrameAt = Date.now();\n    if (active.frames.length >= MAX_BUFFERED_FRAMES) return;\n    try {\n      const buf = Buffer.from(frame.data, 'base64');\n      active.frames.push({\n        timestampMs: Date.now() - active.startedAt,\n        bytes: new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength),\n      });\n    } catch (err) {\n      active.pendingError = err instanceof Error ? err : new Error(String(err));\n    }\n  });\n\n  stream.on('error', (err: Error) => {\n    if (active && active.id === id) {\n      active.pendingError = err;\n    }\n  });\n\n  stream.on('stop', (reason: string) => {\n    if (active && active.id === id && reason !== 'manual' && !active.stopping) {\n      active.pendingError = new Error(`Browser screencast stopped unexpectedly (reason: ${reason})`);\n    }\n  });\n\n  state.autoStopTimer = setTimeout(() => {\n    // Fire-and-forget; tool calls will pick up the result on the next stop call.\n    if (active && active.id === id && !active.stopping) {\n      active.stopping = true;\n      safeStop(stream).catch(() => {});\n    }\n  }, maxDurationMs);\n\n  // Watchdog: CDP screencasts can silently stop delivering frames after some\n  // cross-origin navigations and tab swaps. If no frame has arrived in\n  // FRAME_STALL_MS we re-issue the screencast against the currently active\n  // page via stream.reconnect(). This is self-healing for any cause of\n  // frame stoppage (target detach, navigation race, etc.).\n  const watchdog = () => {\n    if (!active || active.id !== id || active.stopping) return;\n    const elapsedSinceFrame = Date.now() - active.lastFrameAt;\n    if (elapsedSinceFrame >= FRAME_STALL_MS && !active.reconnecting) {\n      active.reconnecting = true;\n      void (async () => {\n        try {\n          browser.setCurrentThread(opts.threadId);\n          await stream.reconnect();\n          // Pretend a frame just arrived so we don't immediately retry.\n          if (active && active.id === id) {\n            active.lastFrameAt = Date.now();\n          }\n        } catch (err) {\n          if (active && active.id === id) {\n            active.pendingError = err instanceof Error ? err : new Error(String(err));\n          }\n        } finally {\n          if (active && active.id === id) {\n            active.reconnecting = false;\n          }\n        }\n      })();\n    }\n  };\n  state.watchdogTimer = setInterval(watchdog, WATCHDOG_INTERVAL_MS);\n\n  return { id, outputPath, maxDurationMs };\n}\n\nasync function stopRecording(): Promise<{\n  filePath: string;\n  frameCount: number;\n  captionCount: number;\n  durationMs: number;\n}> {\n  if (!active) {\n    throw new Error('No browser recording is active. Call browser_record with action=\"start\" first.');\n  }\n  const state = active;\n  state.stopping = true;\n  if (state.autoStopTimer) {\n    clearTimeout(state.autoStopTimer);\n    state.autoStopTimer = null;\n  }\n  if (state.watchdogTimer) {\n    clearInterval(state.watchdogTimer);\n    state.watchdogTimer = null;\n  }\n\n  await safeStop(state.stream);\n\n  if (state.pendingError) {\n    const err = state.pendingError;\n    clearState();\n    throw new Error(`Browser recording failed: ${err.message}`);\n  }\n\n  const outputPath = state.outputPath;\n  try {\n    encodeFramesAsAvi(state, outputPath);\n  } catch (err) {\n    clearState();\n    const msg = err instanceof Error ? err.message : String(err);\n    throw new Error(`Failed to write recording to ${outputPath}: ${msg}`);\n  }\n\n  const result = {\n    filePath: outputPath,\n    frameCount: state.frames.length,\n    captionCount: state.captions.length,\n    durationMs:\n      state.frames.length > 0 ? state.frames[state.frames.length - 1]!.timestampMs : Date.now() - state.startedAt,\n  };\n  clearState();\n  return result;\n}\n\nfunction addCaption(text: string, durationMs: number | undefined): { captionCount: number; timestampMs: number } {\n  if (!active) {\n    throw new Error('No browser recording is active. Call browser_record with action=\"start\" before adding a caption.');\n  }\n  if (active.stopping) {\n    throw new Error('Recording is already stopping; cannot add more captions.');\n  }\n  const trimmed = text.trim();\n  if (trimmed.length === 0) {\n    throw new Error('Caption text must be a non-empty string.');\n  }\n  const capped = trimmed.length > MAX_CAPTION_LENGTH ? trimmed.slice(0, MAX_CAPTION_LENGTH - 1) + '…' : trimmed;\n\n  const now = Date.now();\n  const timestampMs = now - active.startedAt;\n\n  // Rate-limit captions to prevent overlay flicker — drop captions arriving\n  // too quickly after the previous one.\n  if (now - active.lastCaptionAt < MIN_CAPTION_SPACING_MS) {\n    // Replace the last caption's text instead of stacking another entry.\n    const last = active.captions[active.captions.length - 1];\n    if (last) {\n      last.text = capped;\n      last.durationMs = Math.max(\n        last.durationMs,\n        Math.min(HARD_CAP_MAX_DURATION_MS, durationMs ?? DEFAULT_CAPTION_DURATION_MS),\n      );\n      active.lastCaptionAt = now;\n      return { captionCount: active.captions.length, timestampMs: last.timestampMs };\n    }\n  }\n\n  active.captions.push({\n    timestampMs,\n    text: capped,\n    durationMs: Math.max(500, Math.min(HARD_CAP_MAX_DURATION_MS, durationMs ?? DEFAULT_CAPTION_DURATION_MS)),\n  });\n  active.lastCaptionAt = now;\n  return { captionCount: active.captions.length, timestampMs };\n}\n\nfunction getStatus(): {\n  active: boolean;\n  frameCount?: number;\n  captionCount?: number;\n  elapsedMs?: number;\n  maxDurationMs?: number;\n} {\n  if (!active) {\n    return { active: false };\n  }\n  return {\n    active: true,\n    frameCount: active.frames.length,\n    captionCount: active.captions.length,\n    elapsedMs: Date.now() - active.startedAt,\n    maxDurationMs: active.maxDurationMs,\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Test-only helpers\n// ---------------------------------------------------------------------------\n\n/** @internal Exposed for tests so they can reset state between cases. */\nexport function __resetRecordingStateForTests(): void {\n  if (active?.autoStopTimer) {\n    clearTimeout(active.autoStopTimer);\n  }\n  if (active?.watchdogTimer) {\n    clearInterval(active.watchdogTimer);\n  }\n  if (active?.stream) {\n    // Best-effort cleanup so a leaked stream doesn't break subsequent tests.\n    void safeStop(active.stream);\n  }\n  active = null;\n}\n\n/** @internal Exposed for tests. */\nexport function __isRecordingActive(): boolean {\n  return active !== null;\n}\n\n// ---------------------------------------------------------------------------\n// Tool factory\n// ---------------------------------------------------------------------------\n\nconst recordSchema = z.object({\n  action: z\n    .enum(['start', 'stop', 'status'])\n    .describe(\n      'Lifecycle action: \"start\" begins a new recording, \"stop\" finalizes it and writes the MJPEG .avi video to disk, \"status\" reports whether one is active.',\n    ),\n  maxDurationMs: z\n    .number()\n    .int()\n    .positive()\n    .optional()\n    .describe('Only used with action=\"start\". Maximum recording duration in ms (default 30000, hard cap 120000).'),\n  everyNthFrame: z\n    .number()\n    .int()\n    .positive()\n    .optional()\n    .describe('Only used with action=\"start\". Capture every Nth screencast frame (default 2). Higher = smaller file.'),\n  maxWidth: z\n    .number()\n    .int()\n    .positive()\n    .optional()\n    .describe('Only used with action=\"start\". Max frame width in pixels (default 1024).'),\n  maxHeight: z\n    .number()\n    .int()\n    .positive()\n    .optional()\n    .describe('Only used with action=\"start\". Max frame height in pixels (default 720).'),\n  outputPath: z\n    .string()\n    .min(1)\n    .optional()\n    .describe(\n      'Only used with action=\"start\". Absolute path inside the configured recording output directory. Defaults to a generated file there.',\n    ),\n});\n\nconst recordCaptionSchema = z.object({\n  text: z\n    .string()\n    .min(1)\n    .max(MAX_CAPTION_LENGTH)\n    .describe('Very short caption (max ~6 words) describing what you just did in the browser.'),\n  durationMs: z\n    .number()\n    .int()\n    .positive()\n    .optional()\n    .describe('How long the caption should remain visible in the video (ms). Default 2500ms.'),\n});\n\n/**\n * Create opt-in browser recording tools bound to a browser.\n *\n * These tools are alpha and are only exposed when a browser provider or caller\n * explicitly enables recording and provides a safe output directory.\n */\nexport function createBrowserRecordingTools(browser: MastraBrowser, options: BrowserRecordingOptions) {\n  const outputDir = recordingsDir(options.outputDir);\n  return {\n    browser_record: createTool({\n      id: 'browser_record',\n      description:\n        'Control browser video recording. Use action=\"start\" to begin recording the current browser session, then add labels via browser_record_caption as you work, then call this tool again with action=\"stop\" to encode and save an MJPEG .avi video (plays in Preview/QuickTime/VLC/browsers). Use action=\"status\" to check whether a recording is currently active. Recording auto-stops at the duration cap.',\n      inputSchema: recordSchema,\n      execute: async (input, { agent }) => {\n        try {\n          if (input.action === 'start') {\n            const { id, outputPath, maxDurationMs } = await startRecording(browser, {\n              maxDurationMs: options.maxDurationMs,\n              maxWidth: options.maxWidth,\n              maxHeight: options.maxHeight,\n              ...input,\n              threadId: agent?.threadId,\n              outputDir,\n            });\n            return {\n              content: `Recording started (id: ${id}). Will auto-stop after ${maxDurationMs}ms or when you call this tool with action=\"stop\". Output: ${outputPath}`,\n              action: 'start' as const,\n              recordingId: id,\n              outputPath,\n              maxDurationMs,\n              isError: false,\n            };\n          }\n          if (input.action === 'stop') {\n            const result = await stopRecording();\n            return {\n              content: `Recording saved to ${result.filePath} (${result.frameCount} frames, ${result.captionCount} captions, ${result.durationMs}ms).`,\n              action: 'stop' as const,\n              ...result,\n              isError: false,\n            };\n          }\n          const status = getStatus();\n          return {\n            content: status.active\n              ? `Recording active: ${status.frameCount} frames, ${status.captionCount} captions, ${status.elapsedMs}ms elapsed (cap ${status.maxDurationMs}ms).`\n              : 'No browser recording is active.',\n            action: 'status' as const,\n            ...status,\n            isError: false,\n          };\n        } catch (err) {\n          const msg = err instanceof Error ? err.message : String(err);\n          return { content: msg, isError: true };\n        }\n      },\n    }),\n\n    browser_record_caption: createTool({\n      id: 'browser_record_caption',\n      description:\n        'Add a very short, plain-language caption (max ~6 words) describing what you just did in the browser. The caption is burned onto the recorded video at the current moment. Only call this while a recording is active (see browser_record action=\"start\").',\n      inputSchema: recordCaptionSchema,\n      execute: async ({ text, durationMs }) => {\n        try {\n          const { captionCount, timestampMs } = addCaption(text, durationMs);\n          return {\n            content: `Caption added at ${timestampMs}ms (total: ${captionCount}).`,\n            captionCount,\n            timestampMs,\n            isError: false,\n          };\n        } catch (err) {\n          const msg = err instanceof Error ? err.message : String(err);\n          return { content: msg, isError: true };\n        }\n      },\n    }),\n  };\n}\n"]}