@morphllm/morphsdk 0.2.74 → 0.2.76

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/{chunk-B5A4XLSQ.js → chunk-FY32COVL.js} +1 -1
  2. package/dist/{chunk-B5A4XLSQ.js.map → chunk-FY32COVL.js.map} +1 -1
  3. package/dist/{chunk-4WJSTOHP.js → chunk-G2EJHZSA.js} +2 -2
  4. package/dist/{chunk-QIG7YPFW.js → chunk-HBIDSKIQ.js} +14 -3
  5. package/dist/chunk-HBIDSKIQ.js.map +1 -0
  6. package/dist/{chunk-KEHWEBFQ.js → chunk-KILYNOE4.js} +5 -5
  7. package/dist/{chunk-POVU2CPK.js → chunk-P2LHXSMG.js} +2 -2
  8. package/dist/{chunk-IYLEB6BY.js → chunk-RK2MR3N2.js} +2 -2
  9. package/dist/{chunk-NGF2VIQV.js → chunk-XREWLWLA.js} +2 -2
  10. package/dist/{chunk-SMGZ6A64.js → chunk-YPKNMYD4.js} +17 -1
  11. package/dist/chunk-YPKNMYD4.js.map +1 -0
  12. package/dist/client.cjs +26 -1
  13. package/dist/client.cjs.map +1 -1
  14. package/dist/client.js +7 -7
  15. package/dist/index.cjs +26 -1
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.js +8 -8
  18. package/dist/tools/browser/index.cjs.map +1 -1
  19. package/dist/tools/browser/index.js.map +1 -1
  20. package/dist/tools/warp_grep/anthropic.cjs +26 -1
  21. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  22. package/dist/tools/warp_grep/anthropic.js +4 -4
  23. package/dist/tools/warp_grep/client.cjs +26 -1
  24. package/dist/tools/warp_grep/client.cjs.map +1 -1
  25. package/dist/tools/warp_grep/client.js +3 -3
  26. package/dist/tools/warp_grep/gemini.cjs +26 -1
  27. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  28. package/dist/tools/warp_grep/gemini.js +3 -3
  29. package/dist/tools/warp_grep/harness.cjs +26 -1
  30. package/dist/tools/warp_grep/harness.cjs.map +1 -1
  31. package/dist/tools/warp_grep/harness.js +2 -2
  32. package/dist/tools/warp_grep/index.cjs +28 -1
  33. package/dist/tools/warp_grep/index.cjs.map +1 -1
  34. package/dist/tools/warp_grep/index.d.ts +1 -0
  35. package/dist/tools/warp_grep/index.js +7 -4
  36. package/dist/tools/warp_grep/openai.cjs +26 -1
  37. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  38. package/dist/tools/warp_grep/openai.js +4 -4
  39. package/dist/tools/warp_grep/providers/local.cjs +26 -1
  40. package/dist/tools/warp_grep/providers/local.cjs.map +1 -1
  41. package/dist/tools/warp_grep/providers/local.js +2 -2
  42. package/dist/tools/warp_grep/utils/paths.cjs +17 -0
  43. package/dist/tools/warp_grep/utils/paths.cjs.map +1 -1
  44. package/dist/tools/warp_grep/utils/paths.d.ts +13 -1
  45. package/dist/tools/warp_grep/utils/paths.js +3 -1
  46. package/dist/tools/warp_grep/vercel.cjs +26 -1
  47. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  48. package/dist/tools/warp_grep/vercel.js +4 -4
  49. package/package.json +1 -1
  50. package/dist/chunk-QIG7YPFW.js.map +0 -1
  51. package/dist/chunk-SMGZ6A64.js.map +0 -1
  52. /package/dist/{chunk-4WJSTOHP.js.map → chunk-G2EJHZSA.js.map} +0 -0
  53. /package/dist/{chunk-KEHWEBFQ.js.map → chunk-KILYNOE4.js.map} +0 -0
  54. /package/dist/{chunk-POVU2CPK.js.map → chunk-P2LHXSMG.js.map} +0 -0
  55. /package/dist/{chunk-IYLEB6BY.js.map → chunk-RK2MR3N2.js.map} +0 -0
  56. /package/dist/{chunk-NGF2VIQV.js.map → chunk-XREWLWLA.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
- import "./chunk-B5A4XLSQ.js";
1
+ import "./chunk-FY32COVL.js";
2
2
  import {
3
3
  AnthropicToolFactory,
4
4
  MorphClient,
5
5
  OpenAIToolFactory,
6
6
  VercelToolFactory
7
- } from "./chunk-KEHWEBFQ.js";
8
- import "./chunk-IYLEB6BY.js";
9
- import "./chunk-4WJSTOHP.js";
10
- import "./chunk-POVU2CPK.js";
7
+ } from "./chunk-KILYNOE4.js";
8
+ import "./chunk-RK2MR3N2.js";
9
+ import "./chunk-G2EJHZSA.js";
10
+ import "./chunk-P2LHXSMG.js";
11
11
  import "./chunk-KW7OEGZK.js";
12
12
  import {
13
13
  WarpGrepClient
14
- } from "./chunk-NGF2VIQV.js";
14
+ } from "./chunk-XREWLWLA.js";
15
15
  import "./chunk-RRWN62VU.js";
16
16
  import "./chunk-26QXQFLZ.js";
17
17
  import "./chunk-DCIUCDWJ.js";
@@ -20,9 +20,9 @@ import "./chunk-5QRN3JNB.js";
20
20
  import "./chunk-Q5AHGIQO.js";
21
21
  import {
22
22
  LocalRipgrepProvider
23
- } from "./chunk-QIG7YPFW.js";
23
+ } from "./chunk-HBIDSKIQ.js";
24
24
  import "./chunk-G2RSY56Q.js";
25
- import "./chunk-SMGZ6A64.js";
25
+ import "./chunk-YPKNMYD4.js";
26
26
  import "./chunk-TPP2UGQP.js";
27
27
  import "./chunk-XT5ZO6ES.js";
28
28
  import "./chunk-UBX7QYBD.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../tools/browser/index.ts","../../../tools/utils/resilience.ts","../../../tools/browser/live.ts","../../../tools/browser/core.ts","../../../tools/browser/prompts.ts","../../../tools/browser/anthropic.ts","../../../tools/browser/openai.ts","../../../tools/browser/vercel.ts","../../../tools/browser/gemini.ts"],"sourcesContent":["/**\n * Morph Browser Automation Tool\n * \n * Natural language browser automation for AI agents using browser-use + Browserless.io\n * \n * @example\n * ```typescript\n * import { executeBrowserTask } from 'morphsdk/tools/browser';\n * \n * const result = await executeBrowserTask({\n * task: \"Test checkout flow for buying a pineapple\",\n * url: \"https://3000-abc.e2b.dev\",\n * max_steps: 20\n * });\n * ```\n */\n\nexport {\n BrowserClient,\n executeBrowserTask,\n executeWithRecording,\n getRecording,\n waitForRecording,\n getErrors,\n getWebp,\n checkHealth\n} from './core.js';\nexport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskInputWithSchema,\n BrowserTaskResult,\n BrowserTaskWithPromise,\n BrowserTaskWithPromiseAndSchema,\n RecordingStatus,\n RecordingWithMethods,\n BrowserError,\n ErrorsResponse,\n LiveSessionOptions,\n IframeOptions,\n BrowserModel,\n WebpOptions,\n WebpResponse,\n AuthCredentials,\n} from './types.js';\nexport {\n BROWSER_TOOL_DESCRIPTION,\n BROWSER_SYSTEM_PROMPT,\n} from './prompts.js';\nexport {\n buildLiveUrl,\n buildLiveIframe,\n buildEmbedCode,\n LIVE_PRESETS,\n} from './live.js';\n\n// Re-export all adapters for convenience (matches Warp Grep pattern)\nexport * as anthropic from './anthropic.js';\nexport * as openai from './openai.js';\nexport * as vercel from './vercel.js';\nexport * as gemini from './gemini.js';\n\n","/**\n * Resilience utilities for retry logic and timeout handling\n */\n\nexport interface RetryConfig {\n maxRetries?: number; // Default: 3\n initialDelay?: number; // Default: 1000ms\n maxDelay?: number; // Default: 30000ms\n backoffMultiplier?: number; // Default: 2\n retryableErrors?: string[]; // Default: ['ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND']\n onRetry?: (attempt: number, error: Error) => void;\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<Omit<RetryConfig, 'onRetry'>> = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n retryableErrors: ['ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND'],\n};\n\n/**\n * Retry a fetch request with exponential backoff\n * \n * @param url - Request URL\n * @param options - Fetch options\n * @param retryConfig - Retry configuration\n * @returns Response from fetch\n * \n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * 'https://api.example.com/data',\n * { method: 'POST', body: JSON.stringify(data) },\n * { maxRetries: 5, initialDelay: 500 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n url: string,\n options: RequestInit,\n retryConfig: RetryConfig = {}\n): Promise<Response> {\n const {\n maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,\n initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,\n maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,\n backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,\n retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,\n onRetry,\n } = retryConfig;\n\n let lastError: Error | null = null;\n let delay = initialDelay;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetch(url, options);\n \n // Retry on 429 (rate limit) or 503 (service unavailable)\n if (response.status === 429 || response.status === 503) {\n if (attempt < maxRetries) {\n // Check for Retry-After header\n const retryAfter = response.headers.get('Retry-After');\n const waitTime = retryAfter \n ? parseInt(retryAfter) * 1000 \n : Math.min(delay, maxDelay);\n \n const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);\n if (onRetry) {\n onRetry(attempt + 1, error);\n }\n \n await sleep(waitTime);\n delay *= backoffMultiplier;\n continue;\n }\n }\n\n return response;\n } catch (error) {\n lastError = error as Error;\n \n // Check if error is retryable\n const isRetryable = retryableErrors.some(errType => \n lastError?.message?.includes(errType)\n );\n\n if (!isRetryable || attempt === maxRetries) {\n throw lastError;\n }\n\n // Exponential backoff\n const waitTime = Math.min(delay, maxDelay);\n if (onRetry) {\n onRetry(attempt + 1, lastError);\n }\n \n await sleep(waitTime);\n delay *= backoffMultiplier;\n }\n }\n\n throw lastError || new Error('Max retries exceeded');\n}\n\n/**\n * Add timeout to any promise\n * \n * @param promise - Promise to wrap with timeout\n * @param timeoutMs - Timeout in milliseconds\n * @param errorMessage - Optional custom error message\n * @returns Promise that rejects if timeout is reached\n * \n * @example\n * ```typescript\n * const result = await withTimeout(\n * fetchData(),\n * 5000,\n * 'Data fetch timed out'\n * );\n * ```\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage?: string\n): Promise<T> {\n let timeoutId: NodeJS.Timeout | number;\n \n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n\n try {\n const result = await Promise.race([promise, timeoutPromise]);\n clearTimeout(timeoutId!);\n return result;\n } catch (error) {\n clearTimeout(timeoutId!);\n throw error;\n }\n}\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Unified error type for all tools\n */\nexport class MorphError extends Error {\n constructor(\n message: string,\n public code: string,\n public statusCode?: number,\n public retryable: boolean = false\n ) {\n super(message);\n this.name = 'MorphError';\n }\n}\n\n\n","/**\n * Live session utilities for Morph browser sessions\n * \n * Provides helpers for embedding and sharing live browser sessions with WebRTC streaming.\n */\n\nimport type { LiveSessionOptions, IframeOptions } from './types.js';\n\n/**\n * Preset configurations for common use cases\n */\nexport const LIVE_PRESETS = {\n /** Read-only monitoring (no interaction) */\n readonly: { interactive: false } as LiveSessionOptions,\n /** Interactive control (human-in-the-loop) */\n interactive: { interactive: true } as LiveSessionOptions,\n /** Watch-only without controls */\n monitoring: { interactive: false, showControls: false } as LiveSessionOptions,\n} as const;\n\n/**\n * Build a live session URL with query parameters\n * \n * @param debugUrl - Live session debug URL (e.g., from task.debugUrl)\n * @param options - Live session configuration options\n * @returns URL with query parameters for iframe embedding\n * \n * @example\n * ```typescript\n * const url = buildLiveUrl(task.debugUrl, { interactive: true });\n * // Returns: https://example.com/sessions/abc?interactive=true\n * ```\n */\nexport function buildLiveUrl(\n debugUrl: string,\n options: LiveSessionOptions = {}\n): string {\n if (!debugUrl) {\n throw new Error(\n 'debugUrl is required. Ensure your backend returns debugUrl in the task response. ' +\n 'Contact support@morphllm.com if you need help.'\n );\n } \n\n const url = new URL(debugUrl);\n \n // Add query parameters for supported options\n if (options.interactive !== undefined) {\n url.searchParams.set('interactive', String(options.interactive));\n }\n \n if (options.theme) {\n url.searchParams.set('theme', options.theme);\n }\n \n if (options.showControls !== undefined) {\n url.searchParams.set('showControls', String(options.showControls));\n }\n \n if (options.pageId) {\n url.searchParams.set('pageId', options.pageId);\n }\n \n if (options.pageIndex) {\n url.searchParams.set('pageIndex', options.pageIndex);\n }\n \n return url.toString();\n}\n\n/**\n * Build iframe HTML for embedding a live session\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration including dimensions and session options\n * @returns HTML iframe element as string\n * \n * @example\n * ```typescript\n * const iframe = buildLiveIframe(task.debugUrl, {\n * interactive: true,\n * width: '100%',\n * height: '600px'\n * });\n * ```\n */\nexport function buildLiveIframe(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const {\n width = '100%',\n height = '600px',\n style = '',\n className = '',\n ...sessionOptions\n } = options;\n\n const src = buildLiveUrl(debugUrl, sessionOptions);\n \n // Convert numeric dimensions to pixels\n const widthStr = typeof width === 'number' ? `${width}px` : width;\n const heightStr = typeof height === 'number' ? `${height}px` : height;\n \n // Build style attribute\n const baseStyle = `width: ${widthStr}; height: ${heightStr}; border: none;`;\n const fullStyle = style ? `${baseStyle} ${style}` : baseStyle;\n \n // Build iframe attributes\n const attributes = [\n `src=\"${src}\"`,\n `style=\"${fullStyle}\"`,\n ];\n \n if (className) {\n attributes.push(`class=\"${className}\"`);\n }\n \n return `<iframe ${attributes.join(' ')}></iframe>`;\n}\n\n/**\n * Build complete embed code with HTML snippet\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration\n * @returns Multi-line HTML snippet ready to copy-paste\n * \n * @example\n * ```typescript\n * const code = buildEmbedCode(task.debugUrl, { interactive: false });\n * console.log(code);\n * // <!-- Embed Morph Live Session -->\n * // <iframe src=\"...\" style=\"...\"></iframe>\n * ```\n */\nexport function buildEmbedCode(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const iframe = buildLiveIframe(debugUrl, options);\n return `<!-- Embed Morph Live Session -->\\n${iframe}`;\n}\n\n/**\n * Get live session options from preset name or custom config\n * \n * @internal\n */\nexport function resolvePreset(\n optionsOrPreset?: string | IframeOptions\n): IframeOptions {\n if (!optionsOrPreset) {\n return {};\n }\n \n if (typeof optionsOrPreset === 'string') {\n const preset = LIVE_PRESETS[optionsOrPreset as keyof typeof LIVE_PRESETS];\n if (!preset) {\n throw new Error(\n `Unknown preset: ${optionsOrPreset}. Available presets: ${Object.keys(LIVE_PRESETS).join(', ')}`\n );\n }\n return preset;\n }\n \n return optionsOrPreset;\n}\n\n","/**\n * Core implementation for browser automation tasks\n */\n\nimport { fetchWithRetry, withTimeout } from '../utils/resilience.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskInputWithSchema,\n BrowserTaskResult,\n BrowserTaskWithPromise,\n BrowserTaskWithPromiseAndSchema,\n RecordingStatus,\n RecordingWithMethods,\n ErrorsResponse,\n LiveSessionOptions,\n IframeOptions,\n WebpOptions,\n WebpResponse,\n} from './types.js';\nimport { buildLiveUrl, buildLiveIframe, buildEmbedCode, resolvePreset } from './live.js';\n\nconst DEFAULT_CONFIG = {\n apiUrl: process.env.MORPH_ENVIRONMENT === 'DEV' \n ? 'http://localhost:8000'\n : 'https://browser.morphllm.com',\n timeout: 1000000, // 10 minutes for complex tasks\n debug: false,\n};\n\n/**\n * BrowserClient class for easier usage with instance configuration\n */\nexport class BrowserClient {\n private config: BrowserConfig;\n\n constructor(config: BrowserConfig = {}) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config,\n };\n }\n\n /**\n * Execute a browser automation task\n */\n async execute(input: BrowserTaskInput): Promise<BrowserTaskResult> {\n return executeBrowserTask(input, this.config);\n }\n\n async createTask(input: BrowserTaskInput): Promise<BrowserTaskWithPromise>;\n async createTask<T>(input: BrowserTaskInputWithSchema<T>): Promise<BrowserTaskWithPromiseAndSchema<T>>;\n async createTask<T>(\n input: BrowserTaskInput | BrowserTaskInputWithSchema<T>\n ): Promise<BrowserTaskWithPromise | BrowserTaskWithPromiseAndSchema<T>> {\n const apiUrl = this.config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = this.config.debug || false;\n \n if (debug) {\n console.log(`[Browser] createTask: \"${input.task.slice(0, 60)}...\" url=${input.url || 'none'}`);\n console.log(`[Browser] Calling async endpoint: ${apiUrl}/browser-task/async`);\n }\n \n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.config.apiKey) headers['Authorization'] = `Bearer ${this.config.apiKey}`;\n \n // Call ASYNC endpoint for immediate return with live URL\n const response = await fetch(`${apiUrl}/browser-task/async`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n task: input.task,\n url: input.url,\n max_steps: input.max_steps ?? 10,\n model: input.model ?? 'morph-computer-use-v0',\n viewport_width: input.viewport_width ?? 1280,\n viewport_height: input.viewport_height ?? 720,\n external_id: input.external_id,\n repo_id: input.repo_id,\n commit_id: input.commit_id,\n record_video: input.record_video ?? false,\n video_width: input.video_width ?? input.viewport_width ?? 1280,\n video_height: input.video_height ?? input.viewport_height ?? 720,\n allow_resizing: input.allow_resizing ?? false,\n structured_output: 'schema' in input ? stringifyStructuredOutput(input.schema) : undefined,\n auth: input.auth,\n }),\n });\n \n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n \n const result = await response.json();\n \n if (debug) {\n console.log(`[Browser] ✅ Task created: recording_id=${result.recording_id ?? 'none'} debug_url=${result.debugUrl ? 'available' : 'none'}`);\n }\n \n if ('schema' in input) {\n return wrapTaskResponseWithSchema(result, this.config, input.schema);\n } else {\n return wrapTaskResponse(result, this.config);\n }\n }\n\n /**\n * Execute task with recording and wait for video to be ready\n */\n async executeWithRecording(\n input: BrowserTaskInput & { record_video: true }\n ): Promise<BrowserTaskResult & { recording?: RecordingWithMethods }> {\n return executeWithRecording(input, this.config);\n }\n\n /**\n * Get recording status and URLs\n */\n async getRecording(recordingId: string): Promise<RecordingWithMethods> {\n return getRecording(recordingId, this.config);\n }\n\n /**\n * Wait for recording to complete with automatic polling\n */\n async waitForRecording(\n recordingId: string,\n options?: { timeout?: number; pollInterval?: number }\n ): Promise<RecordingWithMethods> {\n return waitForRecording(recordingId, this.config, options);\n }\n\n /**\n * Get errors from recording with screenshots\n */\n async getErrors(recordingId: string): Promise<ErrorsResponse> {\n return getErrors(recordingId, this.config);\n }\n\n /**\n * Get animated WebP preview of recording\n */\n async getWebp(\n recordingId: string,\n options?: WebpOptions\n ): Promise<WebpResponse> {\n return getWebp(recordingId, this.config, options);\n }\n\n /**\n * Check if browser worker service is healthy\n */\n async checkHealth(): Promise<{\n ok: boolean;\n google_configured: boolean;\n database_configured: boolean;\n s3_configured: boolean;\n error?: string;\n }> {\n return checkHealth(this.config);\n }\n}\n\n/**\n * Execute a natural language browser automation task\n * \n * Returns the full task result including rich agent history data (urls, errors, \n * action_history, judgement, etc.). When using this as an agent tool, use the\n * formatResult() functions from the SDK adapters to return a concise summary.\n * \n * @param input - Task parameters\n * @param config - Optional configuration (apiKey, apiUrl to override default)\n * @returns Task result with success status, findings, and comprehensive execution history\n * \n * @example\n * ```typescript\n * const result = await executeBrowserTask(\n * {\n * task: \"Test checkout flow for buying a pineapple\",\n * url: \"https://3000-abc.e2b.dev\",\n * max_steps: 20,\n * repo_id: \"my-project\",\n * commit_id: \"uuid-here\"\n * },\n * {\n * apiKey: process.env.MORPH_API_KEY,\n * // apiUrl: 'http://localhost:8001' // Override for local testing\n * }\n * );\n * \n * if (result.success) {\n * console.log('Task completed:', result.result);\n * console.log('URLs visited:', result.urls);\n * console.log('Actions taken:', result.action_names);\n * console.log('Has errors:', result.has_errors);\n * console.log('Replay:', result.replay_url);\n * }\n * ```\n */\nexport async function executeBrowserTask(\n input: BrowserTaskInput,\n config: BrowserConfig = {}\n): Promise<BrowserTaskResult> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const timeout = config.timeout || DEFAULT_CONFIG.timeout;\n const debug = config.debug || false;\n\n if (!input.task || input.task.trim().length === 0) {\n return { \n success: false, \n error: 'Task description is required. Example: \"Go to example.com and click the login button\"' \n };\n }\n\n if (input.max_steps !== undefined && (input.max_steps < 1 || input.max_steps > 50)) {\n return { \n success: false, \n error: 'max_steps must be between 1 and 50. Use more steps for complex multi-page flows.' \n };\n }\n\n if (debug) {\n console.log(`[Browser] Task: \"${input.task.slice(0, 60)}...\" url=${input.url || 'none'} maxSteps=${input.max_steps ?? 10}`);\n console.log(`[Browser] Recording: ${input.record_video ? 'yes' : 'no'} | Calling ${apiUrl}/browser-task`);\n }\n\n const startTime = Date.now();\n\n try {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (config.apiKey) headers['Authorization'] = `Bearer ${config.apiKey}`;\n\n const fetchPromise = fetchWithRetry(\n `${apiUrl}/browser-task`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify({\n task: input.task,\n url: input.url,\n max_steps: input.max_steps ?? 10,\n model: input.model ?? 'morph-computer-use-v0',\n viewport_width: input.viewport_width ?? 1280,\n viewport_height: input.viewport_height ?? 720,\n external_id: input.external_id,\n repo_id: input.repo_id,\n commit_id: input.commit_id,\n record_video: input.record_video ?? false,\n video_width: input.video_width ?? input.viewport_width ?? 1280,\n video_height: input.video_height ?? input.viewport_height ?? 720,\n allow_resizing: input.allow_resizing ?? false,\n structured_output: input.structured_output,\n auth: input.auth,\n }),\n },\n config.retryConfig\n );\n\n const response = await withTimeout(\n fetchPromise,\n timeout,\n `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing max_steps.`\n );\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const result: BrowserTaskResult = await response.json();\n const elapsed = Date.now() - startTime;\n \n if (debug) {\n console.log(`[Browser] ✅ ${result.success ? 'Success' : 'Failed'} in ${elapsed}ms | steps=${result.steps_taken ?? 0} recordingId=${result.recording_id ?? 'none'}`);\n }\n\n return result;\n\n } catch (error) {\n if (error instanceof Error) {\n // Handle network errors\n if (error.message.includes('ECONNREFUSED') || error.message.includes('fetch failed')) {\n return {\n success: false,\n error: `Cannot connect to browser worker at ${apiUrl}. Ensure the service is running and accessible. For local dev, set MORPH_ENVIRONMENT=DEV.`,\n };\n }\n\n return {\n success: false,\n error: error.message,\n };\n }\n\n return {\n success: false,\n error: String(error),\n };\n }\n}\n\n/**\n * Get recording status and video URL\n * \n * @param recordingId - Recording UUID from BrowserTaskResult\n * @param config - Configuration with apiKey\n * @returns Recording with convenience methods (.getWebp(), .getErrors())\n * \n * @example\n * ```typescript\n * const recording = await getRecording('uuid-here', { apiKey: 'key' });\n * \n * // Get animated WebP\n * const { webp_url } = await recording.getWebp({ width: 780 });\n * \n * // Get errors with screenshots\n * const { errors } = await recording.getErrors();\n * ```\n */\nexport async function getRecording(\n recordingId: string,\n config: BrowserConfig = {}\n): Promise<RecordingWithMethods> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = config.debug || false;\n\n if (!config.apiKey) {\n throw new Error('API key required for getRecording');\n }\n\n if (debug) console.log(`[Browser] getRecording: ${recordingId}`);\n\n const response = await fetch(`${apiUrl}/recordings/${recordingId}`, {\n method: 'GET',\n headers: { 'Authorization': `Bearer ${config.apiKey}` },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] getRecording error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const data: RecordingStatus = await response.json();\n if (debug) console.log(`[Browser] Recording status: ${data.status}`);\n\n // Return recording with convenience methods\n return {\n ...data,\n getWebp: (options?: WebpOptions) => getWebp(recordingId, config, options),\n getErrors: () => getErrors(recordingId, config),\n };\n}\n\n/**\n * Wait for recording to complete with automatic polling\n * \n * @param recordingId - Recording UUID\n * @param config - Configuration with apiKey\n * @param options - Polling options\n * @returns Recording status when completed or errored\n * \n * @example\n * ```typescript\n * const result = await executeBrowserTask({ task: '...', record_video: true }, config);\n * if (result.recording_id) {\n * const recording = await waitForRecording(result.recording_id, config, {\n * timeout: 60000, // 1 minute\n * pollInterval: 2000 // Check every 2 seconds\n * });\n * console.log('Video URL:', recording.video_url);\n * }\n * ```\n */\nexport async function waitForRecording(\n recordingId: string,\n config: BrowserConfig = {},\n options: { timeout?: number; pollInterval?: number } = {}\n): Promise<RecordingWithMethods> {\n const timeout = options.timeout ?? 60000; // Default 1 minute\n const pollInterval = options.pollInterval ?? 2000; // Default 2 seconds\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const status = await getRecording(recordingId, config);\n \n if (status.status === 'COMPLETED' || status.status === 'ERROR') {\n return status;\n }\n\n // Wait before next poll\n await new Promise(resolve => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(`Recording timeout after ${timeout}ms - status still pending`);\n}\n\n/**\n * Execute task with recording and wait for video to be ready\n * \n * @param input - Task parameters with record_video=true\n * @param config - Configuration with apiKey\n * @returns Task result with ready video URL\n * \n * @example\n * ```typescript\n * const result = await executeWithRecording(\n * {\n * task: \"Test checkout flow\",\n * url: \"https://example.com\",\n * record_video: true,\n * repo_id: \"my-project\"\n * },\n * { apiKey: process.env.MORPH_API_KEY }\n * );\n * \n * console.log('Task result:', result.result);\n * console.log('Video URL:', result.recording?.video_url);\n * ```\n */\nexport async function executeWithRecording(\n input: BrowserTaskInput & { record_video: true },\n config: BrowserConfig = {}\n): Promise<BrowserTaskResult & { recording?: RecordingWithMethods }> {\n // Execute task with recording\n const taskResult = await executeBrowserTask(input, config);\n\n // If recording was created, wait for it to complete\n if (taskResult.recording_id) {\n try {\n const recording = await waitForRecording(\n taskResult.recording_id,\n config,\n { timeout: 60000, pollInterval: 2000 }\n );\n return {\n ...taskResult,\n recording,\n };\n } catch (error) {\n // Return task result even if recording fails\n // Still attach convenience methods for consistent API\n const errorRecording: RecordingWithMethods = {\n id: taskResult.recording_id,\n status: 'ERROR',\n error: error instanceof Error ? error.message : String(error),\n created_at: new Date().toISOString(),\n getWebp: (options?: WebpOptions) => getWebp(taskResult.recording_id!, config, options),\n getErrors: () => getErrors(taskResult.recording_id!, config),\n };\n return {\n ...taskResult,\n recording: errorRecording,\n };\n }\n }\n\n return taskResult;\n}\n\n/**\n * Get errors from recording with screenshots\n * \n * Screenshots are captured in real-time (500ms after error occurs) during the browser session.\n * \n * @param recordingId - Recording UUID from BrowserTaskResult\n * @param config - Configuration with apiKey\n * @returns Errors with real-time screenshots\n * \n * @example\n * ```typescript\n * const { errors, total_errors } = await getErrors('uuid-here', { apiKey: 'key' });\n * \n * console.log(`Found ${total_errors} errors`);\n * \n * errors.forEach(err => {\n * console.log(`[${err.type}] ${err.message}`);\n * if (err.url) console.log(` URL: ${err.url}`);\n * if (err.screenshot_url) console.log(` Screenshot: ${err.screenshot_url}`);\n * \n * // Download screenshot\n * if (err.screenshot_url) {\n * const response = await fetch(err.screenshot_url);\n * const screenshot = await response.arrayBuffer();\n * // Save or process screenshot\n * }\n * });\n * ```\n */\nexport async function getErrors(\n recordingId: string,\n config: BrowserConfig = {}\n): Promise<ErrorsResponse> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = config.debug || false;\n\n if (!config.apiKey) {\n throw new Error('API key required for getErrors');\n }\n\n if (debug) console.log(`[Browser] getErrors: ${recordingId}`);\n\n const response = await fetch(`${apiUrl}/recordings/${recordingId}/errors`, {\n method: 'GET',\n headers: { 'Authorization': `Bearer ${config.apiKey}` },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] getErrors error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const errors = await response.json();\n if (debug) console.log(`[Browser] Found ${errors.total_errors} errors`);\n\n return errors;\n}\n\n/**\n * Helper to serialize Zod schema for API\n */\nfunction stringifyStructuredOutput(schema: any): string {\n try {\n return JSON.stringify({\n type: 'object',\n description: 'Zod schema definition (Zod v3)',\n zodDef: schema._def,\n });\n } catch (error) {\n console.warn('[Browser] Failed to serialize Zod schema:', error);\n return JSON.stringify({\n type: 'object',\n description: 'Schema serialization failed',\n });\n }\n}\n\n/**\n * Parse and validate structured task output\n */\nfunction parseStructuredTaskOutput<T>(\n result: BrowserTaskResult,\n schema: any\n): BrowserTaskResult & { parsed: T | null } {\n if (!result.output) {\n return { ...result, parsed: null };\n }\n\n try {\n const parsed = JSON.parse(result.output);\n const validated = schema.parse(parsed) as T;\n return { ...result, parsed: validated };\n } catch (error) {\n if (error instanceof SyntaxError) {\n return { ...result, parsed: null };\n }\n throw error;\n }\n}\n\n/**\n * Get current task status\n */\nasync function getTaskStatus(\n taskId: string,\n config: BrowserConfig\n): Promise<BrowserTaskResult> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = config.debug || false;\n\n if (debug) console.log(`[Browser] getTaskStatus: ${taskId}`);\n\n const headers: Record<string, string> = {};\n if (config.apiKey) headers['Authorization'] = `Bearer ${config.apiKey}`;\n\n const response = await fetch(`${apiUrl}/tasks/${taskId}`, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] getTaskStatus error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const result: BrowserTaskResult = await response.json();\n if (debug) console.log(`[Browser] Task status: ${result.status}`);\n\n return result;\n}\n\n/**\n * Generate live URL for watching task execution in real-time\n */\nfunction generateLiveUrl(taskId: string, config: BrowserConfig): string {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const baseUrl = apiUrl.replace('/api', '');\n return `${baseUrl}/tasks/${taskId}/live`;\n}\n\n/**\n * Poll task until completion\n */\nasync function pollTaskUntilComplete(\n taskId: string,\n config: BrowserConfig,\n pollConfig: { interval?: number; timeout?: number } = {}\n): Promise<BrowserTaskResult> {\n const interval = pollConfig.interval ?? 2000; // 2 seconds\n const timeout = pollConfig.timeout ?? 300000; // 5 minutes\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const status = await getTaskStatus(taskId, config);\n \n if (status.status === 'completed' || status.status === 'failed') {\n return status;\n }\n\n await new Promise(resolve => setTimeout(resolve, interval));\n }\n\n throw new Error(`Task polling timeout after ${timeout}ms`);\n}\n\n/**\n * Wrap task response with convenience methods\n */\nfunction wrapTaskResponse(\n result: BrowserTaskResult,\n config: BrowserConfig\n): BrowserTaskWithPromise {\n const wrapped: BrowserTaskWithPromise = {\n ...result,\n task_id: result.task_id || '',\n liveUrl: result.task_id \n ? generateLiveUrl(result.task_id, config)\n : result.debugUrl || '',\n complete: async (pollConfig?: { interval?: number; timeout?: number }) => {\n // If we have a task_id, poll task status endpoint\n if (result.task_id) {\n return pollTaskUntilComplete(result.task_id!, config, pollConfig);\n }\n // If we have a recording_id, poll recording status instead\n if (result.recording_id) {\n const recording = await waitForRecording(\n result.recording_id,\n config,\n pollConfig\n );\n // Return a result-like object (recording doesn't have full task result)\n return {\n ...result,\n recording_status: recording.status,\n } as BrowserTaskResult;\n }\n // No way to poll completion\n throw new Error('Cannot poll completion: no task_id or recording_id available');\n },\n // Add Steel live session helpers - either functional or error-throwing\n getLiveUrl: result.debugUrl\n ? (options?: LiveSessionOptions) => buildLiveUrl(result.debugUrl!, options)\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help.'\n );\n },\n getLiveIframe: result.debugUrl\n ? (optionsOrPreset?: string | IframeOptions) => {\n const options = resolvePreset(optionsOrPreset);\n return buildLiveIframe(result.debugUrl!, options);\n }\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help.'\n );\n },\n getEmbedCode: result.debugUrl\n ? () => buildEmbedCode(result.debugUrl!)\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help.'\n );\n },\n };\n\n return wrapped;\n}\n\n/**\n * Wrap task response with schema validation\n */\nfunction wrapTaskResponseWithSchema<T>(\n result: BrowserTaskResult,\n config: BrowserConfig,\n schema: any\n): BrowserTaskWithPromiseAndSchema<T> {\n const parsed = result.output\n ? parseStructuredTaskOutput<T>(result, schema)\n : { ...result, parsed: null };\n\n const wrapped: BrowserTaskWithPromiseAndSchema<T> = {\n ...parsed,\n task_id: result.task_id || '',\n liveUrl: result.task_id\n ? generateLiveUrl(result.task_id, config)\n : result.debugUrl || '',\n complete: async (pollConfig?: { interval?: number; timeout?: number }) => {\n // If we have a task_id, poll task status endpoint\n if (result.task_id) {\n const finalResult = await pollTaskUntilComplete(result.task_id!, config, pollConfig);\n return parseStructuredTaskOutput<T>(finalResult, schema);\n }\n // If we have a recording_id, poll recording status instead\n if (result.recording_id) {\n const recording = await waitForRecording(\n result.recording_id,\n config,\n pollConfig\n );\n // Return parsed result (recording doesn't have task output)\n return {\n ...parsed,\n recording_status: recording.status,\n };\n }\n // No way to poll completion\n throw new Error('Cannot poll completion: no task_id or recording_id available');\n },\n // Add Steel live session helpers - either functional or error-throwing\n getLiveUrl: result.debugUrl\n ? (options?: LiveSessionOptions) => buildLiveUrl(result.debugUrl!, options)\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. ' +\n 'Contact support@morphllm.com if you need help enabling live sessions. '\n );\n },\n getLiveIframe: result.debugUrl\n ? (optionsOrPreset?: string | IframeOptions) => {\n const options = resolvePreset(optionsOrPreset);\n return buildLiveIframe(result.debugUrl!, options);\n }\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. ' +\n 'Contact support@morphllm.com if you need help enabling live sessions.'\n );\n },\n getEmbedCode: result.debugUrl\n ? () => buildEmbedCode(result.debugUrl!)\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. ' +\n 'Contact support@morphllm.com if you need help enabling live sessions.'\n );\n },\n };\n\n return wrapped;\n}\n\n/**\n * Get animated WebP preview of recording\n * \n * Converts the native video recording to an animated WebP. Results are cached in S3.\n * \n * @param recordingId - Recording UUID from BrowserTaskResult\n * @param config - Configuration with apiKey\n * @param options - WebP generation options\n * @returns WebP URL and metadata\n * \n * @example\n * ```typescript\n * const webp = await getWebp('uuid-here', { apiKey: 'key' }, {\n * width: 780,\n * fps: 10,\n * quality: 65,\n * max_duration: 15\n * });\n * console.log('WebP URL:', webp.webp_url);\n * console.log('From cache:', webp.cached);\n * ```\n */\nexport async function getWebp(\n recordingId: string,\n config: BrowserConfig = {},\n options: WebpOptions = {}\n): Promise<WebpResponse> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = config.debug || false;\n\n if (!config.apiKey) {\n throw new Error('API key required for getWebp');\n }\n\n // Build query params\n const params = new URLSearchParams();\n if (options.max_duration !== undefined) params.set('max_duration', String(options.max_duration));\n if (options.fps !== undefined) params.set('fps', String(options.fps));\n if (options.width !== undefined) params.set('width', String(options.width));\n if (options.quality !== undefined) params.set('quality', String(options.quality));\n\n const url = `${apiUrl}/recordings/${recordingId}/webp${params.toString() ? '?' + params.toString() : ''}`;\n \n if (debug) console.log(`[Browser] getWebp: ${url}`);\n\n const response = await fetch(url, {\n method: 'GET',\n headers: { 'Authorization': `Bearer ${config.apiKey}` },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] getWebp error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const result = await response.json();\n if (debug) console.log(`[Browser] WebP ready: ${result.webp_url} (cached: ${result.cached})`);\n\n return result;\n}\n\n/**\n * Check if browser worker service is healthy\n * \n * @param config - Optional configuration\n * @returns Health status\n */\nexport async function checkHealth(config: BrowserConfig = {}): Promise<{\n ok: boolean;\n google_configured: boolean;\n database_configured: boolean;\n s3_configured: boolean;\n error?: string;\n}> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n\n try {\n const response = await fetch(`${apiUrl}/health`, {\n method: 'GET',\n headers: config.apiKey\n ? { 'Authorization': `Bearer ${config.apiKey}` }\n : {},\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data = await response.json();\n return {\n ok: true,\n google_configured: data.google_configured ?? false,\n database_configured: data.database_configured ?? false,\n s3_configured: data.s3_configured ?? false,\n };\n } catch (error) {\n return {\n ok: false,\n google_configured: false,\n database_configured: false,\n s3_configured: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n","/**\n * Tool descriptions and prompts for AI models\n */\n\nexport const BROWSER_TOOL_DESCRIPTION = `Test and verify your implemented code in a live browser. This tool executes natural language test instructions and returns a video recording plus detailed logs to help you debug issues.\n\n## When to Use\nUse this AFTER coding is complete to verify your implementation:\n- You've finished writing/modifying code and need to verify it works\n- You need to test user interactions end-to-end (clicks, forms, navigation)\n- You want to catch runtime errors, console warnings, or network failures\n- You need visual confirmation that UI elements render and behave correctly\n\n## What You Get Back\nThe tool returns debugging artifacts to help you identify and fix issues:\n- **Video recording**: Watch exactly what happened in the browser session\n- **Console logs**: All console.log, warnings, and errors with timestamps\n- **Network logs**: Failed requests, 404s, API errors with screenshots\n- **Error screenshots**: Visual snapshots captured when errors occur\n\n## How to Write Good Tests\nBe specific about the user journey you're testing:\n❌ Bad: \"Test the login feature\"\n✅ Good: \"Navigate to /login, enter 'test@example.com' and 'password123', click the Login button, verify we reach the /dashboard page\"\n\nInclude verification steps:\n✅ \"Click the Add Item button, verify the item appears in the list\"\n✅ \"Submit the form, verify a success message is displayed\"\n\n## Iterating on Failures\n1. Run the test and review the video + logs\n2. Identify the specific issue (console error, failed request, wrong behavior)\n3. Fix the code based on the evidence\n4. Re-run the test to verify the fix\n5. Repeat until test passes\n\n## Requirements\n- **URL**: Must be publicly accessible (use tunnels like ngrok, Cloudflare, or deploy to staging)\n- **Timing**: Use this after implementation, not during coding\n- **Complexity**: Set max_steps higher (20-30) for multi-step user workflows`;\n\n\nexport const BROWSER_SYSTEM_PROMPT = `You are an AI agent designed to automate browser tasks to accomplish the <user_request>. Respond with a valid JSON object in the format: {\"thinking\": \"Reason step-by-step about your current state, history, and the user request to decide your next goal and action. Analyze the browser state and screenshot to confirm the outcome of your last action.\", \"evaluation_previous_goal\": \"A concise, one-sentence evaluation of your last action's outcome (e.g., Success, Failure, or Uncertain).\", \"memory\": \"1-3 sentences summarizing key information and progress so far. This helps you track progress across multiple steps (e.g., items collected, pages visited).\", \"next_goal\": \"A clear, one-sentence description of your immediate next objective.\", \"action\": [{\"action_name\": {\"parameter\": \"value\"}}]}`;\n","/**\n * Anthropic SDK adapter for browser automation tool\n */\n\nimport type { Tool } from '@anthropic-ai/sdk/resources/messages.mjs';\nimport { executeBrowserTask } from './core.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskResult,\n} from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION, BROWSER_SYSTEM_PROMPT } from './prompts.js';\n\n/**\n * Anthropic tool definition for browser automation\n */\nexport const browserTool: Tool = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n input_schema: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n description: 'Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")',\n },\n url: {\n type: 'string',\n description: 'Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page.',\n },\n max_steps: {\n type: 'number',\n description: 'Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.',\n default: 10,\n },\n region: {\n type: 'string',\n enum: ['sfo', 'lon'],\n description: 'Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.',\n default: 'sfo',\n },\n },\n required: ['task'],\n },\n};\n\n/**\n * Format browser task result for Anthropic tool result\n * \n * Returns a concise summary suitable for agent context. The full result object\n * (with urls, errors, action_history, judgement, etc.) is available when calling\n * execute() directly, but this formatted string omits those details to save tokens.\n * \n * @param result - Browser task result with full history data\n * @returns Formatted string summary for tool result\n */\nfunction formatResult(result: BrowserTaskResult): string {\n if (result.success) {\n const parts = [\n '✅ Browser task completed successfully',\n `Steps taken: ${result.steps_taken ?? 0}`,\n result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,\n '',\n 'Result:',\n result.result || 'Task completed',\n ];\n return parts.filter(Boolean).join('\\n');\n }\n\n return `❌ Browser task failed: ${result.error || 'Unknown error'}`;\n}\n\n/**\n * Create a configured browser tool with execute and formatResult methods\n * \n * @param config - Browser worker configuration\n * @returns Tool definition with execute and formatResult methods\n * \n * @example\n * ```typescript\n * import Anthropic from '@anthropic-ai/sdk';\n * import { createBrowserTool } from 'morphsdk/tools/browser/anthropic';\n * \n * const tool = createBrowserTool({\n * apiKey: process.env.MORPH_API_KEY,\n * timeout: 180000\n * });\n * \n * const client = new Anthropic();\n * \n * const response = await client.messages.create({\n * model: 'claude-sonnet-4-5-20250929',\n * tools: [tool], // tool itself is the Tool definition\n * messages: [{\n * role: 'user',\n * content: 'Test the checkout flow at https://3000-abc.e2b.dev'\n * }]\n * });\n * \n * // Execute and format\n * const result = await tool.execute(toolUseBlock.input);\n * const formatted = tool.formatResult(result);\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig) {\n return Object.assign({}, browserTool, {\n execute: async (input: BrowserTaskInput): Promise<BrowserTaskResult> => {\n return executeBrowserTask(input, config);\n },\n formatResult: (result: BrowserTaskResult): string => {\n return formatResult(result);\n },\n getSystemPrompt: (): string => {\n return BROWSER_SYSTEM_PROMPT;\n },\n });\n}\n\n","/**\n * OpenAI SDK adapter for browser automation tool\n */\n\nimport type { ChatCompletionTool } from 'openai/resources/chat/completions.mjs';\nimport { executeBrowserTask } from './core.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskResult,\n} from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION, BROWSER_SYSTEM_PROMPT } from './prompts.js';\n\n/**\n * OpenAI tool definition for browser automation\n */\nexport const browserTool: ChatCompletionTool = {\n type: 'function',\n function: {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n description: 'Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")',\n },\n url: {\n type: 'string',\n description: 'Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page.',\n },\n max_steps: {\n type: 'number',\n description: 'Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.',\n default: 10,\n },\n region: {\n type: 'string',\n enum: ['sfo', 'lon'],\n description: 'Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.',\n default: 'sfo',\n },\n },\n required: ['task'],\n },\n },\n};\n\n/**\n * Execute a browser task (for use in tool call handling)\n * \n * @param input - Tool input parameters (may be JSON string)\n * @param config - Optional browser worker configuration\n * @returns Task execution result\n */\nexport async function execute(\n input: BrowserTaskInput | string,\n config?: BrowserConfig\n): Promise<BrowserTaskResult> {\n // Parse input if it's a JSON string (from OpenAI tool call)\n const parsedInput = typeof input === 'string' ? JSON.parse(input) : input;\n return executeBrowserTask(parsedInput, config);\n}\n\n/**\n * Format browser task result for OpenAI tool result\n * \n * Returns a concise summary suitable for agent context. The full result object\n * (with urls, errors, action_history, judgement, etc.) is available when calling\n * execute() directly, but this formatted string omits those details to save tokens.\n * \n * @param result - Browser task result with full history data\n * @returns Formatted string summary for tool result\n */\nexport function formatResult(result: BrowserTaskResult): string {\n if (result.success) {\n const parts = [\n '✅ Browser task completed successfully',\n `Steps taken: ${result.steps_taken ?? 0}`,\n result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,\n '',\n 'Result:',\n result.result || 'Task completed',\n ];\n return parts.filter(Boolean).join('\\n');\n }\n\n return `❌ Browser task failed: ${result.error || 'Unknown error'}`;\n}\n\n/**\n * Get system prompt for browser automation\n */\nexport function getSystemPrompt(): string {\n return BROWSER_SYSTEM_PROMPT;\n}\n\n/**\n * Create a configured browser tool with execute and formatResult methods\n * \n * @param config - Browser worker configuration\n * @returns Tool definition with execute and formatResult methods\n * \n * @example\n * ```typescript\n * import OpenAI from 'openai';\n * import { createBrowserTool } from 'morphsdk/tools/browser/openai';\n * \n * const tool = createBrowserTool({\n * apiUrl: 'https://browser-worker.example.com'\n * });\n * \n * const client = new OpenAI();\n * \n * const response = await client.chat.completions.create({\n * model: 'gpt-4o',\n * tools: [tool], // tool itself is the ChatCompletionTool\n * messages: [{\n * role: 'user',\n * content: 'Test the checkout at https://3000-abc.e2b.dev'\n * }]\n * });\n * \n * // Execute and format\n * const result = await tool.execute(toolCallArgs);\n * const formatted = tool.formatResult(result);\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig) {\n return Object.assign({}, browserTool, {\n execute: async (input: BrowserTaskInput | string): Promise<BrowserTaskResult> => {\n return execute(input, config);\n },\n formatResult: (result: BrowserTaskResult): string => {\n return formatResult(result);\n },\n getSystemPrompt: (): string => {\n return getSystemPrompt();\n },\n });\n}\n\n","/**\n * Vercel AI SDK adapter for browser automation tool\n */\n\nimport { tool as createTool } from 'ai';\nimport { z } from 'zod';\nimport { executeBrowserTask } from './core.js';\nimport type { BrowserConfig } from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION } from './prompts.js';\n\n/**\n * Create Vercel AI SDK tool for browser automation\n * \n * @param config - Optional browser worker configuration\n * @returns Vercel AI SDK tool\n * \n * @example\n * ```typescript\n * import { generateText } from 'ai';\n * import { anthropic } from '@ai-sdk/anthropic';\n * import { createBrowserTool } from 'morphsdk/tools/browser/vercel';\n * \n * const browserTool = createBrowserTool({\n * apiUrl: 'https://browser-worker.example.com'\n * });\n * \n * const result = await generateText({\n * model: anthropic('claude-sonnet-4-5-20250929'),\n * tools: { browserTask: browserTool },\n * prompt: 'Test the checkout flow at https://3000-abc.e2b.dev',\n * maxSteps: 5\n * });\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig) {\n const schema = z.object({\n task: z.string().describe('Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")'),\n url: z.string().optional().describe('Starting URL (e.g., https://3000-xyz.e2b.dev)'),\n max_steps: z.number().min(1).max(50).default(10).describe('Maximum number of browser actions to take'),\n region: z.enum(['sfo', 'lon']).default('sfo').describe('Browserless region: sfo (US West) or lon (Europe)'),\n });\n\n return createTool({\n description: BROWSER_TOOL_DESCRIPTION,\n inputSchema: schema,\n execute: async (params) => {\n const { task, url, max_steps, region } = params;\n const result = await executeBrowserTask(\n { task, url, max_steps, region },\n config\n );\n\n // Return minimal summary for agent context (to save tokens)\n // Full result with urls, errors, action_history, judgement, etc. is available\n // when calling executeBrowserTask() directly outside of agent tools\n if (result.success) {\n return {\n success: true,\n result: result.result,\n steps_taken: result.steps_taken,\n execution_time_ms: result.execution_time_ms,\n };\n }\n\n return {\n success: false,\n error: result.error,\n };\n },\n });\n}\n\n/**\n * Default browser tool for Vercel AI SDK\n */\nexport const browserTool = createBrowserTool();\n\n","/**\n * Google Gemini SDK adapter for browser automation tool\n */\n\nimport type { FunctionDeclaration, FunctionDeclarationSchema } from '@google/generative-ai';\nimport { SchemaType } from '@google/generative-ai';\nimport { executeBrowserTask } from './core.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskResult,\n} from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION, BROWSER_SYSTEM_PROMPT } from './prompts.js';\n\n/**\n * Parameter schema for the browser tool (Gemini format)\n */\nconst TOOL_PARAMETERS: FunctionDeclarationSchema = {\n type: SchemaType.OBJECT,\n properties: {\n task: {\n type: SchemaType.STRING,\n description: 'Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")',\n },\n url: {\n type: SchemaType.STRING,\n description: 'Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page.',\n },\n max_steps: {\n type: SchemaType.NUMBER,\n description: 'Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.',\n },\n region: {\n type: SchemaType.STRING,\n description: 'Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.',\n },\n },\n required: ['task'],\n};\n\n/**\n * Gemini-native browser function declaration\n * \n * @example\n * ```typescript\n * import { GoogleGenerativeAI } from '@google/generative-ai';\n * import { browserFunctionDeclaration, execute } from '@morphllm/morphsdk/tools/browser/gemini';\n * \n * const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);\n * const model = genAI.getGenerativeModel({\n * model: 'gemini-2.0-flash',\n * tools: [{ functionDeclarations: [browserFunctionDeclaration] }]\n * });\n * \n * const chat = model.startChat();\n * const result = await chat.sendMessage('Test the checkout flow');\n * \n * // Handle function call\n * const call = result.response.functionCalls()?.[0];\n * if (call) {\n * const taskResult = await execute(call.args, { apiKey: 'key' });\n * console.log(taskResult);\n * }\n * ```\n */\nexport const browserFunctionDeclaration: FunctionDeclaration = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: TOOL_PARAMETERS,\n};\n\n/**\n * Execute browser task\n * \n * @param input - Tool input with task and optional url/max_steps\n * @param config - Configuration with apiKey\n * @returns Task execution result\n */\nexport async function execute(\n input: BrowserTaskInput | string,\n config?: BrowserConfig\n): Promise<BrowserTaskResult> {\n const parsedInput = typeof input === 'string' ? JSON.parse(input) : input;\n return executeBrowserTask(parsedInput, config);\n}\n\n/**\n * Format browser task result for Gemini tool result\n * \n * Returns a concise summary suitable for agent context. The full result object\n * (with urls, errors, action_history, judgement, etc.) is available when calling\n * execute() directly, but this formatted string omits those details to save tokens.\n * \n * @param result - Browser task result with full history data\n * @returns Formatted string summary for tool result\n */\nexport function formatResult(result: BrowserTaskResult): string {\n if (result.success) {\n const parts = [\n '✅ Browser task completed successfully',\n `Steps taken: ${result.steps_taken ?? 0}`,\n result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,\n '',\n 'Result:',\n result.result || 'Task completed',\n ];\n return parts.filter(Boolean).join('\\n');\n }\n\n return `❌ Browser task failed: ${result.error || 'Unknown error'}`;\n}\n\n/**\n * Get system prompt for browser automation\n */\nexport function getSystemPrompt(): string {\n return BROWSER_SYSTEM_PROMPT;\n}\n\n/**\n * Gemini tool with execute method attached\n */\nexport interface GeminiBrowserTool extends FunctionDeclaration {\n execute: (input: BrowserTaskInput | string) => Promise<BrowserTaskResult>;\n formatResult: (result: BrowserTaskResult) => string;\n getSystemPrompt: () => string;\n}\n\n/**\n * Create a configured browser tool with execute and formatResult methods\n * \n * @param config - Browser worker configuration\n * @returns Function declaration with execute and formatResult methods\n * \n * @example\n * ```typescript\n * import { GoogleGenerativeAI, FunctionCallingMode } from '@google/generative-ai';\n * import { createBrowserTool } from '@morphllm/morphsdk/tools/browser/gemini';\n * \n * const tool = createBrowserTool({ apiKey: process.env.MORPH_API_KEY });\n * \n * const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);\n * const model = genAI.getGenerativeModel({\n * model: 'gemini-2.0-flash',\n * tools: [{ functionDeclarations: [tool] }],\n * toolConfig: { functionCallingConfig: { mode: FunctionCallingMode.AUTO } }\n * });\n * \n * const chat = model.startChat();\n * const result = await chat.sendMessage('Test the checkout flow at https://example.com');\n * \n * // Handle function call\n * const call = result.response.functionCalls()?.[0];\n * if (call && call.name === tool.name) {\n * const taskResult = await tool.execute(call.args);\n * console.log(tool.formatResult(taskResult));\n * \n * // Send result back to model\n * await chat.sendMessage([{\n * functionResponse: {\n * name: call.name,\n * response: { result: tool.formatResult(taskResult) }\n * }\n * }]);\n * }\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig): GeminiBrowserTool {\n const declaration: FunctionDeclaration = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: TOOL_PARAMETERS,\n };\n\n return Object.assign(declaration, {\n execute: async (input: BrowserTaskInput | string): Promise<BrowserTaskResult> => {\n return execute(input, config);\n },\n formatResult: (result: BrowserTaskResult): string => {\n return formatResult(result);\n },\n getSystemPrompt: (): string => {\n return getSystemPrompt();\n },\n });\n}\n\n// Legacy alias for consistency with some patterns\nexport const browserTool = browserFunctionDeclaration;\n\nexport default browserFunctionDeclaration;\n\n"],"mappings":"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","names":["browserTool","createBrowserTool","formatResult","browserTool","formatResult","createBrowserTool","browserTool","createBrowserTool","createBrowserTool","createTool","browserTool","browserTool","createBrowserTool","execute","formatResult","getSystemPrompt","execute","formatResult","getSystemPrompt","createBrowserTool","browserTool"]}
1
+ {"version":3,"sources":["../../../tools/browser/index.ts","../../../tools/utils/resilience.ts","../../../tools/browser/live.ts","../../../tools/browser/core.ts","../../../tools/browser/prompts.ts","../../../tools/browser/anthropic.ts","../../../tools/browser/openai.ts","../../../tools/browser/vercel.ts","../../../tools/browser/gemini.ts"],"sourcesContent":["/**\n * Morph Browser Automation Tool\n * \n * Natural language browser automation for AI agents using browser-use + Browserless.io\n * \n * @example\n * ```typescript\n * import { executeBrowserTask } from 'morphsdk/tools/browser';\n * \n * const result = await executeBrowserTask({\n * task: \"Test checkout flow for buying a pineapple\",\n * url: \"https://3000-abc.e2b.dev\",\n * max_steps: 20\n * });\n * ```\n */\n\nexport {\n BrowserClient,\n executeBrowserTask,\n executeWithRecording,\n getRecording,\n waitForRecording,\n getErrors,\n getWebp,\n checkHealth\n} from './core.js';\nexport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskInputWithSchema,\n BrowserTaskResult,\n BrowserTaskWithPromise,\n BrowserTaskWithPromiseAndSchema,\n RecordingStatus,\n RecordingWithMethods,\n BrowserError,\n ErrorsResponse,\n LiveSessionOptions,\n IframeOptions,\n BrowserModel,\n WebpOptions,\n WebpResponse,\n AuthCredentials,\n} from './types.js';\nexport {\n BROWSER_TOOL_DESCRIPTION,\n BROWSER_SYSTEM_PROMPT,\n} from './prompts.js';\nexport {\n buildLiveUrl,\n buildLiveIframe,\n buildEmbedCode,\n LIVE_PRESETS,\n} from './live.js';\n\n// Re-export all adapters for convenience (matches Warp Grep pattern)\nexport * as anthropic from './anthropic.js';\nexport * as openai from './openai.js';\nexport * as vercel from './vercel.js';\nexport * as gemini from './gemini.js';\n\n","/**\n * Resilience utilities for retry logic and timeout handling\n */\n\nexport interface RetryConfig {\n maxRetries?: number; // Default: 3\n initialDelay?: number; // Default: 1000ms\n maxDelay?: number; // Default: 30000ms\n backoffMultiplier?: number; // Default: 2\n retryableErrors?: string[]; // Default: ['ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND']\n onRetry?: (attempt: number, error: Error) => void;\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<Omit<RetryConfig, 'onRetry'>> = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n retryableErrors: ['ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND'],\n};\n\n/**\n * Retry a fetch request with exponential backoff\n * \n * @param url - Request URL\n * @param options - Fetch options\n * @param retryConfig - Retry configuration\n * @returns Response from fetch\n * \n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * 'https://api.example.com/data',\n * { method: 'POST', body: JSON.stringify(data) },\n * { maxRetries: 5, initialDelay: 500 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n url: string,\n options: RequestInit,\n retryConfig: RetryConfig = {}\n): Promise<Response> {\n const {\n maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,\n initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,\n maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,\n backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,\n retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,\n onRetry,\n } = retryConfig;\n\n let lastError: Error | null = null;\n let delay = initialDelay;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetch(url, options);\n \n // Retry on 429 (rate limit) or 503 (service unavailable)\n if (response.status === 429 || response.status === 503) {\n if (attempt < maxRetries) {\n // Check for Retry-After header\n const retryAfter = response.headers.get('Retry-After');\n const waitTime = retryAfter \n ? parseInt(retryAfter) * 1000 \n : Math.min(delay, maxDelay);\n \n const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);\n if (onRetry) {\n onRetry(attempt + 1, error);\n }\n \n await sleep(waitTime);\n delay *= backoffMultiplier;\n continue;\n }\n }\n\n return response;\n } catch (error) {\n lastError = error as Error;\n \n // Check if error is retryable\n const isRetryable = retryableErrors.some(errType => \n lastError?.message?.includes(errType)\n );\n\n if (!isRetryable || attempt === maxRetries) {\n throw lastError;\n }\n\n // Exponential backoff\n const waitTime = Math.min(delay, maxDelay);\n if (onRetry) {\n onRetry(attempt + 1, lastError);\n }\n \n await sleep(waitTime);\n delay *= backoffMultiplier;\n }\n }\n\n throw lastError || new Error('Max retries exceeded');\n}\n\n/**\n * Add timeout to any promise\n * \n * @param promise - Promise to wrap with timeout\n * @param timeoutMs - Timeout in milliseconds\n * @param errorMessage - Optional custom error message\n * @returns Promise that rejects if timeout is reached\n * \n * @example\n * ```typescript\n * const result = await withTimeout(\n * fetchData(),\n * 5000,\n * 'Data fetch timed out'\n * );\n * ```\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage?: string\n): Promise<T> {\n let timeoutId: NodeJS.Timeout | number;\n \n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n\n try {\n const result = await Promise.race([promise, timeoutPromise]);\n clearTimeout(timeoutId!);\n return result;\n } catch (error) {\n clearTimeout(timeoutId!);\n throw error;\n }\n}\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Unified error type for all tools\n */\nexport class MorphError extends Error {\n constructor(\n message: string,\n public code: string,\n public statusCode?: number,\n public retryable: boolean = false\n ) {\n super(message);\n this.name = 'MorphError';\n }\n}\n\n\n","/**\n * Live session utilities for Morph browser sessions\n * \n * Provides helpers for embedding and sharing live browser sessions with WebRTC streaming.\n */\n\nimport type { LiveSessionOptions, IframeOptions } from './types.js';\n\n/**\n * Preset configurations for common use cases\n */\nexport const LIVE_PRESETS = {\n /** Read-only monitoring (no interaction) */\n readonly: { interactive: false } as LiveSessionOptions,\n /** Interactive control (human-in-the-loop) */\n interactive: { interactive: true } as LiveSessionOptions,\n /** Watch-only without controls */\n monitoring: { interactive: false, showControls: false } as LiveSessionOptions,\n} as const;\n\n/**\n * Build a live session URL with query parameters\n * \n * @param debugUrl - Live session debug URL (e.g., from task.debugUrl)\n * @param options - Live session configuration options\n * @returns URL with query parameters for iframe embedding\n * \n * @example\n * ```typescript\n * const url = buildLiveUrl(task.debugUrl, { interactive: true });\n * // Returns: https://example.com/sessions/abc?interactive=true\n * ```\n */\nexport function buildLiveUrl(\n debugUrl: string,\n options: LiveSessionOptions = {}\n): string {\n if (!debugUrl) {\n throw new Error(\n 'debugUrl is required. Ensure your backend returns debugUrl in the task response. ' +\n 'Contact support@morphllm.com if you need help.'\n );\n } \n\n const url = new URL(debugUrl);\n \n // Add query parameters for supported options\n if (options.interactive !== undefined) {\n url.searchParams.set('interactive', String(options.interactive));\n }\n \n if (options.theme) {\n url.searchParams.set('theme', options.theme);\n }\n \n if (options.showControls !== undefined) {\n url.searchParams.set('showControls', String(options.showControls));\n }\n \n if (options.pageId) {\n url.searchParams.set('pageId', options.pageId);\n }\n \n if (options.pageIndex) {\n url.searchParams.set('pageIndex', options.pageIndex);\n }\n \n return url.toString();\n}\n\n/**\n * Build iframe HTML for embedding a live session\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration including dimensions and session options\n * @returns HTML iframe element as string\n * \n * @example\n * ```typescript\n * const iframe = buildLiveIframe(task.debugUrl, {\n * interactive: true,\n * width: '100%',\n * height: '600px'\n * });\n * ```\n */\nexport function buildLiveIframe(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const {\n width = '100%',\n height = '600px',\n style = '',\n className = '',\n ...sessionOptions\n } = options;\n\n const src = buildLiveUrl(debugUrl, sessionOptions);\n \n // Convert numeric dimensions to pixels\n const widthStr = typeof width === 'number' ? `${width}px` : width;\n const heightStr = typeof height === 'number' ? `${height}px` : height;\n \n // Build style attribute\n const baseStyle = `width: ${widthStr}; height: ${heightStr}; border: none;`;\n const fullStyle = style ? `${baseStyle} ${style}` : baseStyle;\n \n // Build iframe attributes\n const attributes = [\n `src=\"${src}\"`,\n `style=\"${fullStyle}\"`,\n ];\n \n if (className) {\n attributes.push(`class=\"${className}\"`);\n }\n \n return `<iframe ${attributes.join(' ')}></iframe>`;\n}\n\n/**\n * Build complete embed code with HTML snippet\n * \n * @param debugUrl - Live session debug URL\n * @param options - Iframe configuration\n * @returns Multi-line HTML snippet ready to copy-paste\n * \n * @example\n * ```typescript\n * const code = buildEmbedCode(task.debugUrl, { interactive: false });\n * console.log(code);\n * // <!-- Embed Morph Live Session -->\n * // <iframe src=\"...\" style=\"...\"></iframe>\n * ```\n */\nexport function buildEmbedCode(\n debugUrl: string,\n options: IframeOptions = {}\n): string {\n const iframe = buildLiveIframe(debugUrl, options);\n return `<!-- Embed Morph Live Session -->\\n${iframe}`;\n}\n\n/**\n * Get live session options from preset name or custom config\n * \n * @internal\n */\nexport function resolvePreset(\n optionsOrPreset?: string | IframeOptions\n): IframeOptions {\n if (!optionsOrPreset) {\n return {};\n }\n \n if (typeof optionsOrPreset === 'string') {\n const preset = LIVE_PRESETS[optionsOrPreset as keyof typeof LIVE_PRESETS];\n if (!preset) {\n throw new Error(\n `Unknown preset: ${optionsOrPreset}. Available presets: ${Object.keys(LIVE_PRESETS).join(', ')}`\n );\n }\n return preset;\n }\n \n return optionsOrPreset;\n}\n\n","/**\n * Core implementation for browser automation tasks\n */\n\nimport { fetchWithRetry, withTimeout } from '../utils/resilience.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskInputWithSchema,\n BrowserTaskResult,\n BrowserTaskWithPromise,\n BrowserTaskWithPromiseAndSchema,\n RecordingStatus,\n RecordingWithMethods,\n ErrorsResponse,\n LiveSessionOptions,\n IframeOptions,\n WebpOptions,\n WebpResponse,\n} from './types.js';\nimport { buildLiveUrl, buildLiveIframe, buildEmbedCode, resolvePreset } from './live.js';\n\nconst DEFAULT_CONFIG = {\n apiUrl: process.env.MORPH_ENVIRONMENT === 'DEV' \n ? 'http://localhost:8000'\n : 'https://browser.morphllm.com',\n timeout: 1000000, // 10 minutes for complex tasks\n debug: false,\n};\n\n/**\n * BrowserClient class for easier usage with instance configuration\n */\nexport class BrowserClient {\n private config: BrowserConfig;\n\n constructor(config: BrowserConfig = {}) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config,\n };\n }\n\n /**\n * Execute a browser automation task\n */\n async execute(input: BrowserTaskInput): Promise<BrowserTaskResult> {\n return executeBrowserTask(input, this.config);\n }\n\n async createTask(input: BrowserTaskInput): Promise<BrowserTaskWithPromise>;\n async createTask<T>(input: BrowserTaskInputWithSchema<T>): Promise<BrowserTaskWithPromiseAndSchema<T>>;\n async createTask<T>(\n input: BrowserTaskInput | BrowserTaskInputWithSchema<T>\n ): Promise<BrowserTaskWithPromise | BrowserTaskWithPromiseAndSchema<T>> {\n const apiUrl = this.config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = this.config.debug || false;\n \n if (debug) {\n console.log(`[Browser] createTask: \"${input.task.slice(0, 60)}...\" url=${input.url || 'none'}`);\n console.log(`[Browser] Calling async endpoint: ${apiUrl}/browser-task/async`);\n }\n \n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (this.config.apiKey) headers['Authorization'] = `Bearer ${this.config.apiKey}`;\n \n // Call ASYNC endpoint for immediate return with live URL\n const response = await fetch(`${apiUrl}/browser-task/async`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n task: input.task,\n url: input.url,\n max_steps: input.max_steps ?? 10,\n model: input.model ?? 'morph-computer-use-v0',\n viewport_width: input.viewport_width ?? 1280,\n viewport_height: input.viewport_height ?? 720,\n external_id: input.external_id,\n repo_id: input.repo_id,\n commit_id: input.commit_id,\n record_video: input.record_video ?? false,\n video_width: input.video_width ?? input.viewport_width ?? 1280,\n video_height: input.video_height ?? input.viewport_height ?? 720,\n allow_resizing: input.allow_resizing ?? false,\n structured_output: 'schema' in input ? stringifyStructuredOutput(input.schema) : undefined,\n auth: input.auth,\n }),\n });\n \n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n \n const result = await response.json();\n \n if (debug) {\n console.log(`[Browser] ✅ Task created: recording_id=${result.recording_id ?? 'none'} debug_url=${result.debugUrl ? 'available' : 'none'}`);\n }\n \n if ('schema' in input) {\n return wrapTaskResponseWithSchema(result, this.config, input.schema);\n } else {\n return wrapTaskResponse(result, this.config);\n }\n }\n\n /**\n * Execute task with recording and wait for video to be ready\n */\n async executeWithRecording(\n input: BrowserTaskInput & { record_video: true }\n ): Promise<BrowserTaskResult & { recording?: RecordingWithMethods }> {\n return executeWithRecording(input, this.config);\n }\n\n /**\n * Get recording status and URLs\n */\n async getRecording(recordingId: string): Promise<RecordingWithMethods> {\n return getRecording(recordingId, this.config);\n }\n\n /**\n * Wait for recording to complete with automatic polling\n */\n async waitForRecording(\n recordingId: string,\n options?: { timeout?: number; pollInterval?: number }\n ): Promise<RecordingWithMethods> {\n return waitForRecording(recordingId, this.config, options);\n }\n\n /**\n * Get errors from recording with screenshots\n */\n async getErrors(recordingId: string): Promise<ErrorsResponse> {\n return getErrors(recordingId, this.config);\n }\n\n /**\n * Get animated WebP preview of recording\n */\n async getWebp(\n recordingId: string,\n options?: WebpOptions\n ): Promise<WebpResponse> {\n return getWebp(recordingId, this.config, options);\n }\n\n /**\n * Check if browser worker service is healthy\n */\n async checkHealth(): Promise<{\n ok: boolean;\n google_configured: boolean;\n database_configured: boolean;\n s3_configured: boolean;\n error?: string;\n }> {\n return checkHealth(this.config);\n }\n}\n\n/**\n * Execute a natural language browser automation task\n * \n * Returns the full task result including rich agent history data (urls, errors, \n * action_history, judgement, etc.). When using this as an agent tool, use the\n * formatResult() functions from the SDK adapters to return a concise summary.\n * \n * @param input - Task parameters\n * @param config - Optional configuration (apiKey, apiUrl to override default)\n * @returns Task result with success status, findings, and comprehensive execution history\n * \n * @example\n * ```typescript\n * const result = await executeBrowserTask(\n * {\n * task: \"Test checkout flow for buying a pineapple\",\n * url: \"https://3000-abc.e2b.dev\",\n * max_steps: 20,\n * repo_id: \"my-project\",\n * commit_id: \"uuid-here\"\n * },\n * {\n * apiKey: process.env.MORPH_API_KEY,\n * // apiUrl: 'http://localhost:8001' // Override for local testing\n * }\n * );\n * \n * if (result.success) {\n * console.log('Task completed:', result.result);\n * console.log('URLs visited:', result.urls);\n * console.log('Actions taken:', result.action_names);\n * console.log('Has errors:', result.has_errors);\n * console.log('Replay:', result.replay_url);\n * }\n * ```\n */\nexport async function executeBrowserTask(\n input: BrowserTaskInput,\n config: BrowserConfig = {}\n): Promise<BrowserTaskResult> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const timeout = config.timeout || DEFAULT_CONFIG.timeout;\n const debug = config.debug || false;\n\n if (!input.task || input.task.trim().length === 0) {\n return { \n success: false, \n error: 'Task description is required. Example: \"Go to example.com and click the login button\"' \n };\n }\n\n if (input.max_steps !== undefined && (input.max_steps < 1 || input.max_steps > 50)) {\n return { \n success: false, \n error: 'max_steps must be between 1 and 50. Use more steps for complex multi-page flows.' \n };\n }\n\n if (debug) {\n console.log(`[Browser] Task: \"${input.task.slice(0, 60)}...\" url=${input.url || 'none'} maxSteps=${input.max_steps ?? 10}`);\n console.log(`[Browser] Recording: ${input.record_video ? 'yes' : 'no'} | Calling ${apiUrl}/browser-task`);\n }\n\n const startTime = Date.now();\n\n try {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (config.apiKey) headers['Authorization'] = `Bearer ${config.apiKey}`;\n\n const fetchPromise = fetchWithRetry(\n `${apiUrl}/browser-task`,\n {\n method: 'POST',\n headers,\n body: JSON.stringify({\n task: input.task,\n url: input.url,\n max_steps: input.max_steps ?? 10,\n model: input.model ?? 'morph-computer-use-v0',\n viewport_width: input.viewport_width ?? 1280,\n viewport_height: input.viewport_height ?? 720,\n external_id: input.external_id,\n repo_id: input.repo_id,\n commit_id: input.commit_id,\n record_video: input.record_video ?? false,\n video_width: input.video_width ?? input.viewport_width ?? 1280,\n video_height: input.video_height ?? input.viewport_height ?? 720,\n allow_resizing: input.allow_resizing ?? false,\n structured_output: input.structured_output,\n auth: input.auth,\n }),\n },\n config.retryConfig\n );\n\n const response = await withTimeout(\n fetchPromise,\n timeout,\n `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing max_steps.`\n );\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const result: BrowserTaskResult = await response.json();\n const elapsed = Date.now() - startTime;\n \n if (debug) {\n console.log(`[Browser] ✅ ${result.success ? 'Success' : 'Failed'} in ${elapsed}ms | steps=${result.steps_taken ?? 0} recordingId=${result.recording_id ?? 'none'}`);\n }\n\n return result;\n\n } catch (error) {\n if (error instanceof Error) {\n // Handle network errors\n if (error.message.includes('ECONNREFUSED') || error.message.includes('fetch failed')) {\n return {\n success: false,\n error: `Cannot connect to browser worker at ${apiUrl}. Ensure the service is running and accessible. For local dev, set MORPH_ENVIRONMENT=DEV.`,\n };\n }\n\n return {\n success: false,\n error: error.message,\n };\n }\n\n return {\n success: false,\n error: String(error),\n };\n }\n}\n\n/**\n * Get recording status and video URL\n * \n * @param recordingId - Recording UUID from BrowserTaskResult\n * @param config - Configuration with apiKey\n * @returns Recording with convenience methods (.getWebp(), .getErrors())\n * \n * @example\n * ```typescript\n * const recording = await getRecording('uuid-here', { apiKey: 'key' });\n * \n * // Get animated WebP\n * const { webp_url } = await recording.getWebp({ width: 780 });\n * \n * // Get errors with screenshots\n * const { errors } = await recording.getErrors();\n * ```\n */\nexport async function getRecording(\n recordingId: string,\n config: BrowserConfig = {}\n): Promise<RecordingWithMethods> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = config.debug || false;\n\n if (!config.apiKey) {\n throw new Error('API key required for getRecording');\n }\n\n if (debug) console.log(`[Browser] getRecording: ${recordingId}`);\n\n const response = await fetch(`${apiUrl}/recordings/${recordingId}`, {\n method: 'GET',\n headers: { 'Authorization': `Bearer ${config.apiKey}` },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] getRecording error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const data: RecordingStatus = await response.json();\n if (debug) console.log(`[Browser] Recording status: ${data.status}`);\n\n // Return recording with convenience methods\n return {\n ...data,\n getWebp: (options?: WebpOptions) => getWebp(recordingId, config, options),\n getErrors: () => getErrors(recordingId, config),\n };\n}\n\n/**\n * Wait for recording to complete with automatic polling\n * \n * @param recordingId - Recording UUID\n * @param config - Configuration with apiKey\n * @param options - Polling options\n * @returns Recording status when completed or errored\n * \n * @example\n * ```typescript\n * const result = await executeBrowserTask({ task: '...', record_video: true }, config);\n * if (result.recording_id) {\n * const recording = await waitForRecording(result.recording_id, config, {\n * timeout: 60000, // 1 minute\n * pollInterval: 2000 // Check every 2 seconds\n * });\n * console.log('Video URL:', recording.video_url);\n * }\n * ```\n */\nexport async function waitForRecording(\n recordingId: string,\n config: BrowserConfig = {},\n options: { timeout?: number; pollInterval?: number } = {}\n): Promise<RecordingWithMethods> {\n const timeout = options.timeout ?? 60000; // Default 1 minute\n const pollInterval = options.pollInterval ?? 2000; // Default 2 seconds\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const status = await getRecording(recordingId, config);\n \n if (status.status === 'COMPLETED' || status.status === 'ERROR') {\n return status;\n }\n\n // Wait before next poll\n await new Promise(resolve => setTimeout(resolve, pollInterval));\n }\n\n throw new Error(`Recording timeout after ${timeout}ms - status still pending`);\n}\n\n/**\n * Execute task with recording and wait for video to be ready\n * \n * @param input - Task parameters with record_video=true\n * @param config - Configuration with apiKey\n * @returns Task result with ready video URL\n * \n * @example\n * ```typescript\n * const result = await executeWithRecording(\n * {\n * task: \"Test checkout flow\",\n * url: \"https://example.com\",\n * record_video: true,\n * repo_id: \"my-project\"\n * },\n * { apiKey: process.env.MORPH_API_KEY }\n * );\n * \n * console.log('Task result:', result.result);\n * console.log('Video URL:', result.recording?.video_url);\n * ```\n */\nexport async function executeWithRecording(\n input: BrowserTaskInput & { record_video: true },\n config: BrowserConfig = {}\n): Promise<BrowserTaskResult & { recording?: RecordingWithMethods }> {\n // Execute task with recording\n const taskResult = await executeBrowserTask(input, config);\n\n // If recording was created, wait for it to complete\n if (taskResult.recording_id) {\n try {\n const recording = await waitForRecording(\n taskResult.recording_id,\n config,\n { timeout: 60000, pollInterval: 2000 }\n );\n return {\n ...taskResult,\n recording,\n };\n } catch (error) {\n // Return task result even if recording fails\n // Still attach convenience methods for consistent API\n const errorRecording: RecordingWithMethods = {\n id: taskResult.recording_id,\n status: 'ERROR',\n error: error instanceof Error ? error.message : String(error),\n created_at: new Date().toISOString(),\n getWebp: (options?: WebpOptions) => getWebp(taskResult.recording_id!, config, options),\n getErrors: () => getErrors(taskResult.recording_id!, config),\n };\n return {\n ...taskResult,\n recording: errorRecording,\n };\n }\n }\n\n return taskResult;\n}\n\n/**\n * Get errors from recording with screenshots\n * \n * Screenshots are captured in real-time (500ms after error occurs) during the browser session.\n * \n * @param recordingId - Recording UUID from BrowserTaskResult\n * @param config - Configuration with apiKey\n * @returns Errors with real-time screenshots\n * \n * @example\n * ```typescript\n * const { errors, total_errors } = await getErrors('uuid-here', { apiKey: 'key' });\n * \n * console.log(`Found ${total_errors} errors`);\n * \n * errors.forEach(err => {\n * console.log(`[${err.type}] ${err.message}`);\n * if (err.url) console.log(` URL: ${err.url}`);\n * if (err.screenshot_url) console.log(` Screenshot: ${err.screenshot_url}`);\n * \n * // Download screenshot\n * if (err.screenshot_url) {\n * const response = await fetch(err.screenshot_url);\n * const screenshot = await response.arrayBuffer();\n * // Save or process screenshot\n * }\n * });\n * ```\n */\nexport async function getErrors(\n recordingId: string,\n config: BrowserConfig = {}\n): Promise<ErrorsResponse> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = config.debug || false;\n\n if (!config.apiKey) {\n throw new Error('API key required for getErrors');\n }\n\n if (debug) console.log(`[Browser] getErrors: ${recordingId}`);\n\n const response = await fetch(`${apiUrl}/recordings/${recordingId}/errors`, {\n method: 'GET',\n headers: { 'Authorization': `Bearer ${config.apiKey}` },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] getErrors error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const errors = await response.json();\n if (debug) console.log(`[Browser] Found ${errors.total_errors} errors`);\n\n return errors;\n}\n\n/**\n * Helper to serialize Zod schema for API\n */\nfunction stringifyStructuredOutput(schema: any): string {\n try {\n return JSON.stringify({\n type: 'object',\n description: 'Zod schema definition (Zod v3)',\n zodDef: schema._def,\n });\n } catch (error) {\n console.warn('[Browser] Failed to serialize Zod schema:', error);\n return JSON.stringify({\n type: 'object',\n description: 'Schema serialization failed',\n });\n }\n}\n\n/**\n * Parse and validate structured task output\n */\nfunction parseStructuredTaskOutput<T>(\n result: BrowserTaskResult,\n schema: any\n): BrowserTaskResult & { parsed: T | null } {\n if (!result.output) {\n return { ...result, parsed: null };\n }\n\n try {\n const parsed = JSON.parse(result.output);\n const validated = schema.parse(parsed) as T;\n return { ...result, parsed: validated };\n } catch (error) {\n if (error instanceof SyntaxError) {\n return { ...result, parsed: null };\n }\n throw error;\n }\n}\n\n/**\n * Get current task status\n */\nasync function getTaskStatus(\n taskId: string,\n config: BrowserConfig\n): Promise<BrowserTaskResult> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = config.debug || false;\n\n if (debug) console.log(`[Browser] getTaskStatus: ${taskId}`);\n\n const headers: Record<string, string> = {};\n if (config.apiKey) headers['Authorization'] = `Bearer ${config.apiKey}`;\n\n const response = await fetch(`${apiUrl}/tasks/${taskId}`, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] getTaskStatus error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const result: BrowserTaskResult = await response.json();\n if (debug) console.log(`[Browser] Task status: ${result.status}`);\n\n return result;\n}\n\n/**\n * Generate live URL for watching task execution in real-time\n */\nfunction generateLiveUrl(taskId: string, config: BrowserConfig): string {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const baseUrl = apiUrl.replace('/api', '');\n return `${baseUrl}/tasks/${taskId}/live`;\n}\n\n/**\n * Poll task until completion\n */\nasync function pollTaskUntilComplete(\n taskId: string,\n config: BrowserConfig,\n pollConfig: { interval?: number; timeout?: number } = {}\n): Promise<BrowserTaskResult> {\n const interval = pollConfig.interval ?? 2000; // 2 seconds\n const timeout = pollConfig.timeout ?? 300000; // 5 minutes\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const status = await getTaskStatus(taskId, config);\n \n if (status.status === 'completed' || status.status === 'failed') {\n return status;\n }\n\n await new Promise(resolve => setTimeout(resolve, interval));\n }\n\n throw new Error(`Task polling timeout after ${timeout}ms`);\n}\n\n/**\n * Wrap task response with convenience methods\n */\nfunction wrapTaskResponse(\n result: BrowserTaskResult,\n config: BrowserConfig\n): BrowserTaskWithPromise {\n const wrapped: BrowserTaskWithPromise = {\n ...result,\n task_id: result.task_id || '',\n liveUrl: result.task_id \n ? generateLiveUrl(result.task_id, config)\n : result.debugUrl || '',\n complete: async (pollConfig?: { interval?: number; timeout?: number }) => {\n // If we have a task_id, poll task status endpoint\n if (result.task_id) {\n return pollTaskUntilComplete(result.task_id!, config, pollConfig);\n }\n // If we have a recording_id, poll recording status instead\n if (result.recording_id) {\n const recording = await waitForRecording(\n result.recording_id,\n config,\n pollConfig\n );\n // Return a result-like object (recording doesn't have full task result)\n return {\n ...result,\n recording_status: recording.status,\n } as BrowserTaskResult;\n }\n // No way to poll completion\n throw new Error('Cannot poll completion: no task_id or recording_id available');\n },\n // Add Steel live session helpers - either functional or error-throwing\n getLiveUrl: result.debugUrl\n ? (options?: LiveSessionOptions) => buildLiveUrl(result.debugUrl!, options)\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help.'\n );\n },\n getLiveIframe: result.debugUrl\n ? (optionsOrPreset?: string | IframeOptions) => {\n const options = resolvePreset(optionsOrPreset);\n return buildLiveIframe(result.debugUrl!, options);\n }\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help.'\n );\n },\n getEmbedCode: result.debugUrl\n ? () => buildEmbedCode(result.debugUrl!)\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help.'\n );\n },\n };\n\n return wrapped;\n}\n\n/**\n * Wrap task response with schema validation\n */\nfunction wrapTaskResponseWithSchema<T>(\n result: BrowserTaskResult,\n config: BrowserConfig,\n schema: any\n): BrowserTaskWithPromiseAndSchema<T> {\n const parsed = result.output\n ? parseStructuredTaskOutput<T>(result, schema)\n : { ...result, parsed: null };\n\n const wrapped: BrowserTaskWithPromiseAndSchema<T> = {\n ...parsed,\n task_id: result.task_id || '',\n liveUrl: result.task_id\n ? generateLiveUrl(result.task_id, config)\n : result.debugUrl || '',\n complete: async (pollConfig?: { interval?: number; timeout?: number }) => {\n // If we have a task_id, poll task status endpoint\n if (result.task_id) {\n const finalResult = await pollTaskUntilComplete(result.task_id!, config, pollConfig);\n return parseStructuredTaskOutput<T>(finalResult, schema);\n }\n // If we have a recording_id, poll recording status instead\n if (result.recording_id) {\n const recording = await waitForRecording(\n result.recording_id,\n config,\n pollConfig\n );\n // Return parsed result (recording doesn't have task output)\n return {\n ...parsed,\n recording_status: recording.status,\n };\n }\n // No way to poll completion\n throw new Error('Cannot poll completion: no task_id or recording_id available');\n },\n // Add Steel live session helpers - either functional or error-throwing\n getLiveUrl: result.debugUrl\n ? (options?: LiveSessionOptions) => buildLiveUrl(result.debugUrl!, options)\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. ' +\n 'Contact support@morphllm.com if you need help enabling live sessions. '\n );\n },\n getLiveIframe: result.debugUrl\n ? (optionsOrPreset?: string | IframeOptions) => {\n const options = resolvePreset(optionsOrPreset);\n return buildLiveIframe(result.debugUrl!, options);\n }\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. ' +\n 'Contact support@morphllm.com if you need help enabling live sessions.'\n );\n },\n getEmbedCode: result.debugUrl\n ? () => buildEmbedCode(result.debugUrl!)\n : () => {\n throw new Error(\n 'Live sessions not available. Your backend must return a debugUrl in the response. ' +\n 'Contact support@morphllm.com if you need help enabling live sessions.'\n );\n },\n };\n\n return wrapped;\n}\n\n/**\n * Get animated WebP preview of recording\n * \n * Converts the native video recording to an animated WebP. Results are cached in S3.\n * \n * @param recordingId - Recording UUID from BrowserTaskResult\n * @param config - Configuration with apiKey\n * @param options - WebP generation options\n * @returns WebP URL and metadata\n * \n * @example\n * ```typescript\n * const webp = await getWebp('uuid-here', { apiKey: 'key' }, {\n * width: 780,\n * fps: 10,\n * quality: 65,\n * max_duration: 15\n * });\n * console.log('WebP URL:', webp.webp_url);\n * console.log('From cache:', webp.cached);\n * ```\n */\nexport async function getWebp(\n recordingId: string,\n config: BrowserConfig = {},\n options: WebpOptions = {}\n): Promise<WebpResponse> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n const debug = config.debug || false;\n\n if (!config.apiKey) {\n throw new Error('API key required for getWebp');\n }\n\n // Build query params\n const params = new URLSearchParams();\n if (options.max_duration !== undefined) params.set('max_duration', String(options.max_duration));\n if (options.fps !== undefined) params.set('fps', String(options.fps));\n if (options.width !== undefined) params.set('width', String(options.width));\n if (options.quality !== undefined) params.set('quality', String(options.quality));\n\n const url = `${apiUrl}/recordings/${recordingId}/webp${params.toString() ? '?' + params.toString() : ''}`;\n \n if (debug) console.log(`[Browser] getWebp: ${url}`);\n\n const response = await fetch(url, {\n method: 'GET',\n headers: { 'Authorization': `Bearer ${config.apiKey}` },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => response.statusText);\n if (debug) console.error(`[Browser] getWebp error: ${response.status} - ${errorText}`);\n throw new Error(`HTTP ${response.status}: ${errorText}`);\n }\n\n const result = await response.json();\n if (debug) console.log(`[Browser] WebP ready: ${result.webp_url} (cached: ${result.cached})`);\n\n return result;\n}\n\n/**\n * Check if browser worker service is healthy\n * \n * @param config - Optional configuration\n * @returns Health status\n */\nexport async function checkHealth(config: BrowserConfig = {}): Promise<{\n ok: boolean;\n google_configured: boolean;\n database_configured: boolean;\n s3_configured: boolean;\n error?: string;\n}> {\n const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;\n\n try {\n const response = await fetch(`${apiUrl}/health`, {\n method: 'GET',\n headers: config.apiKey\n ? { 'Authorization': `Bearer ${config.apiKey}` }\n : {},\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n const data = await response.json();\n return {\n ok: true,\n google_configured: data.google_configured ?? false,\n database_configured: data.database_configured ?? false,\n s3_configured: data.s3_configured ?? false,\n };\n } catch (error) {\n return {\n ok: false,\n google_configured: false,\n database_configured: false,\n s3_configured: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n","/**\n * Tool descriptions and prompts for AI models\n */\n\nexport const BROWSER_TOOL_DESCRIPTION = `Test and verify your implemented code in a live browser. This tool executes natural language test instructions and returns a video recording plus detailed logs to help you debug issues.\n\n## When to Use\nUse this AFTER coding is complete to verify your implementation:\n- You've finished writing/modifying code and need to verify it works\n- You need to test user interactions end-to-end (clicks, forms, navigation)\n- You want to catch runtime errors, console warnings, or network failures\n- You need visual confirmation that UI elements render and behave correctly\n\n## What You Get Back\nThe tool returns debugging artifacts to help you identify and fix issues:\n- **Video recording**: Watch exactly what happened in the browser session\n- **Console logs**: All console.log, warnings, and errors with timestamps\n- **Network logs**: Failed requests, 404s, API errors with screenshots\n- **Error screenshots**: Visual snapshots captured when errors occur\n\n## How to Write Good Tests\nBe specific about the user journey you're testing:\n❌ Bad: \"Test the login feature\"\n✅ Good: \"Navigate to /login, enter 'test@example.com' and 'password123', click the Login button, verify we reach the /dashboard page\"\n\nInclude verification steps:\n✅ \"Click the Add Item button, verify the item appears in the list\"\n✅ \"Submit the form, verify a success message is displayed\"\n\n## Iterating on Failures\n1. Run the test and review the video + logs\n2. Identify the specific issue (console error, failed request, wrong behavior)\n3. Fix the code based on the evidence\n4. Re-run the test to verify the fix\n5. Repeat until test passes\n\n## Requirements\n- **URL**: Must be publicly accessible (use tunnels like ngrok, Cloudflare, or deploy to staging)\n- **Timing**: Use this after implementation, not during coding\n- **Complexity**: Set max_steps higher (20-30) for multi-step user workflows`;\n\n\nexport const BROWSER_SYSTEM_PROMPT = `You are an AI agent designed to automate browser tasks to accomplish the <user_request>. Respond with a valid JSON object in the format: {\"thinking\": \"Reason step-by-step about your current state, history, and the user request to decide your next goal and action. Analyze the browser state and screenshot to confirm the outcome of your last action.\", \"evaluation_previous_goal\": \"A concise, one-sentence evaluation of your last action's outcome (e.g., Success, Failure, or Uncertain).\", \"memory\": \"1-3 sentences summarizing key information and progress so far. This helps you track progress across multiple steps (e.g., items collected, pages visited).\", \"next_goal\": \"A clear, one-sentence description of your immediate next objective.\", \"action\": [{\"action_name\": {\"parameter\": \"value\"}}]}`;\n","/**\n * Anthropic SDK adapter for browser automation tool\n */\n\nimport type { Tool } from '@anthropic-ai/sdk/resources/messages.mjs';\nimport { executeBrowserTask } from './core.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskResult,\n} from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION, BROWSER_SYSTEM_PROMPT } from './prompts.js';\n\n/**\n * Anthropic tool definition for browser automation\n */\nexport const browserTool: Tool = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n input_schema: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n description: 'Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")',\n },\n url: {\n type: 'string',\n description: 'Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page.',\n },\n max_steps: {\n type: 'number',\n description: 'Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.',\n default: 10,\n },\n region: {\n type: 'string',\n enum: ['sfo', 'lon'],\n description: 'Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.',\n default: 'sfo',\n },\n },\n required: ['task'],\n },\n};\n\n/**\n * Format browser task result for Anthropic tool result\n * \n * Returns a concise summary suitable for agent context. The full result object\n * (with urls, errors, action_history, judgement, etc.) is available when calling\n * execute() directly, but this formatted string omits those details to save tokens.\n * \n * @param result - Browser task result with full history data\n * @returns Formatted string summary for tool result\n */\nfunction formatResult(result: BrowserTaskResult): string {\n if (result.success) {\n const parts = [\n '✅ Browser task completed successfully',\n `Steps taken: ${result.steps_taken ?? 0}`,\n result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,\n '',\n 'Result:',\n result.result || 'Task completed',\n ];\n return parts.filter(Boolean).join('\\n');\n }\n\n return `❌ Browser task failed: ${result.error || 'Unknown error'}`;\n}\n\n/**\n * Create a configured browser tool with execute and formatResult methods\n * \n * @param config - Browser worker configuration\n * @returns Tool definition with execute and formatResult methods\n * \n * @example\n * ```typescript\n * import Anthropic from '@anthropic-ai/sdk';\n * import { createBrowserTool } from 'morphsdk/tools/browser/anthropic';\n * \n * const tool = createBrowserTool({\n * apiKey: process.env.MORPH_API_KEY,\n * timeout: 180000\n * });\n * \n * const client = new Anthropic();\n * \n * const response = await client.messages.create({\n * model: 'claude-sonnet-4-5-20250929',\n * tools: [tool], // tool itself is the Tool definition\n * messages: [{\n * role: 'user',\n * content: 'Test the checkout flow at https://3000-abc.e2b.dev'\n * }]\n * });\n * \n * // Execute and format\n * const result = await tool.execute(toolUseBlock.input);\n * const formatted = tool.formatResult(result);\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig) {\n return Object.assign({}, browserTool, {\n execute: async (input: BrowserTaskInput): Promise<BrowserTaskResult> => {\n return executeBrowserTask(input, config);\n },\n formatResult: (result: BrowserTaskResult): string => {\n return formatResult(result);\n },\n getSystemPrompt: (): string => {\n return BROWSER_SYSTEM_PROMPT;\n },\n });\n}\n\n","/**\n * OpenAI SDK adapter for browser automation tool\n */\n\nimport type { ChatCompletionTool } from 'openai/resources/chat/completions.mjs';\nimport { executeBrowserTask } from './core.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskResult,\n} from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION, BROWSER_SYSTEM_PROMPT } from './prompts.js';\n\n/**\n * OpenAI tool definition for browser automation\n */\nexport const browserTool: ChatCompletionTool = {\n type: 'function',\n function: {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n description: 'Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")',\n },\n url: {\n type: 'string',\n description: 'Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page.',\n },\n max_steps: {\n type: 'number',\n description: 'Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.',\n default: 10,\n },\n region: {\n type: 'string',\n enum: ['sfo', 'lon'],\n description: 'Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.',\n default: 'sfo',\n },\n },\n required: ['task'],\n },\n },\n};\n\n/**\n * Execute a browser task (for use in tool call handling)\n * \n * @param input - Tool input parameters (may be JSON string)\n * @param config - Optional browser worker configuration\n * @returns Task execution result\n */\nexport async function execute(\n input: BrowserTaskInput | string,\n config?: BrowserConfig\n): Promise<BrowserTaskResult> {\n // Parse input if it's a JSON string (from OpenAI tool call)\n const parsedInput = typeof input === 'string' ? JSON.parse(input) : input;\n return executeBrowserTask(parsedInput, config);\n}\n\n/**\n * Format browser task result for OpenAI tool result\n * \n * Returns a concise summary suitable for agent context. The full result object\n * (with urls, errors, action_history, judgement, etc.) is available when calling\n * execute() directly, but this formatted string omits those details to save tokens.\n * \n * @param result - Browser task result with full history data\n * @returns Formatted string summary for tool result\n */\nexport function formatResult(result: BrowserTaskResult): string {\n if (result.success) {\n const parts = [\n '✅ Browser task completed successfully',\n `Steps taken: ${result.steps_taken ?? 0}`,\n result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,\n '',\n 'Result:',\n result.result || 'Task completed',\n ];\n return parts.filter(Boolean).join('\\n');\n }\n\n return `❌ Browser task failed: ${result.error || 'Unknown error'}`;\n}\n\n/**\n * Get system prompt for browser automation\n */\nexport function getSystemPrompt(): string {\n return BROWSER_SYSTEM_PROMPT;\n}\n\n/**\n * Create a configured browser tool with execute and formatResult methods\n * \n * @param config - Browser worker configuration\n * @returns Tool definition with execute and formatResult methods\n * \n * @example\n * ```typescript\n * import OpenAI from 'openai';\n * import { createBrowserTool } from 'morphsdk/tools/browser/openai';\n * \n * const tool = createBrowserTool({\n * apiUrl: 'https://browser-worker.example.com'\n * });\n * \n * const client = new OpenAI();\n * \n * const response = await client.chat.completions.create({\n * model: 'gpt-4o',\n * tools: [tool], // tool itself is the ChatCompletionTool\n * messages: [{\n * role: 'user',\n * content: 'Test the checkout at https://3000-abc.e2b.dev'\n * }]\n * });\n * \n * // Execute and format\n * const result = await tool.execute(toolCallArgs);\n * const formatted = tool.formatResult(result);\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig) {\n return Object.assign({}, browserTool, {\n execute: async (input: BrowserTaskInput | string): Promise<BrowserTaskResult> => {\n return execute(input, config);\n },\n formatResult: (result: BrowserTaskResult): string => {\n return formatResult(result);\n },\n getSystemPrompt: (): string => {\n return getSystemPrompt();\n },\n });\n}\n\n","/**\n * Vercel AI SDK adapter for browser automation tool\n */\n\nimport { tool as createTool } from 'ai';\nimport { z } from 'zod';\nimport { executeBrowserTask } from './core.js';\nimport type { BrowserConfig } from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION } from './prompts.js';\n\n/**\n * Create Vercel AI SDK tool for browser automation\n * \n * @param config - Optional browser worker configuration\n * @returns Vercel AI SDK tool\n * \n * @example\n * ```typescript\n * import { generateText } from 'ai';\n * import { anthropic } from '@ai-sdk/anthropic';\n * import { createBrowserTool } from 'morphsdk/tools/browser/vercel';\n * \n * const browserTool = createBrowserTool({\n * apiUrl: 'https://browser-worker.example.com'\n * });\n * \n * const result = await generateText({\n * model: anthropic('claude-sonnet-4-5-20250929'),\n * tools: { browserTask: browserTool },\n * prompt: 'Test the checkout flow at https://3000-abc.e2b.dev',\n * maxSteps: 5\n * });\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig) {\n const schema = z.object({\n task: z.string().describe('Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")'),\n url: z.string().optional().describe('Starting URL (e.g., https://3000-xyz.e2b.dev)'),\n max_steps: z.number().min(1).max(50).default(10).describe('Maximum number of browser actions to take'),\n region: z.enum(['sfo', 'lon']).default('sfo').describe('Browserless region: sfo (US West) or lon (Europe)'),\n });\n\n return createTool({\n description: BROWSER_TOOL_DESCRIPTION,\n inputSchema: schema,\n execute: async (params) => {\n const { task, url, max_steps, region } = params;\n const result = await executeBrowserTask(\n { task, url, max_steps, region },\n config\n );\n\n // Return minimal summary for agent context (to save tokens)\n // Full result with urls, errors, action_history, judgement, etc. is available\n // when calling executeBrowserTask() directly outside of agent tools\n if (result.success) {\n return {\n success: true,\n result: result.result,\n steps_taken: result.steps_taken,\n execution_time_ms: result.execution_time_ms,\n };\n }\n\n return {\n success: false,\n error: result.error,\n };\n },\n });\n}\n\n/**\n * Default browser tool for Vercel AI SDK\n */\nexport const browserTool = createBrowserTool();\n\n","/**\n * Google Gemini SDK adapter for browser automation tool\n */\n\nimport type { FunctionDeclaration, FunctionDeclarationSchema } from '@google/generative-ai';\nimport { SchemaType } from '@google/generative-ai';\nimport { executeBrowserTask } from './core.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskResult,\n} from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION, BROWSER_SYSTEM_PROMPT } from './prompts.js';\n\n/**\n * Parameter schema for the browser tool (Gemini format)\n */\nconst TOOL_PARAMETERS: FunctionDeclarationSchema = {\n type: SchemaType.OBJECT,\n properties: {\n task: {\n type: SchemaType.STRING,\n description: 'Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")',\n },\n url: {\n type: SchemaType.STRING,\n description: 'Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page.',\n },\n max_steps: {\n type: SchemaType.NUMBER,\n description: 'Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.',\n },\n region: {\n type: SchemaType.STRING,\n description: 'Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.',\n },\n },\n required: ['task'],\n};\n\n/**\n * Gemini-native browser function declaration\n * \n * @example\n * ```typescript\n * import { GoogleGenerativeAI } from '@google/generative-ai';\n * import { browserFunctionDeclaration, execute } from '@morphllm/morphsdk/tools/browser/gemini';\n * \n * const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);\n * const model = genAI.getGenerativeModel({\n * model: 'gemini-2.0-flash',\n * tools: [{ functionDeclarations: [browserFunctionDeclaration] }]\n * });\n * \n * const chat = model.startChat();\n * const result = await chat.sendMessage('Test the checkout flow');\n * \n * // Handle function call\n * const call = result.response.functionCalls()?.[0];\n * if (call) {\n * const taskResult = await execute(call.args, { apiKey: 'key' });\n * console.log(taskResult);\n * }\n * ```\n */\nexport const browserFunctionDeclaration: FunctionDeclaration = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: TOOL_PARAMETERS,\n};\n\n/**\n * Execute browser task\n * \n * @param input - Tool input with task and optional url/max_steps\n * @param config - Configuration with apiKey\n * @returns Task execution result\n */\nexport async function execute(\n input: BrowserTaskInput | string,\n config?: BrowserConfig\n): Promise<BrowserTaskResult> {\n const parsedInput = typeof input === 'string' ? JSON.parse(input) : input;\n return executeBrowserTask(parsedInput, config);\n}\n\n/**\n * Format browser task result for Gemini tool result\n * \n * Returns a concise summary suitable for agent context. The full result object\n * (with urls, errors, action_history, judgement, etc.) is available when calling\n * execute() directly, but this formatted string omits those details to save tokens.\n * \n * @param result - Browser task result with full history data\n * @returns Formatted string summary for tool result\n */\nexport function formatResult(result: BrowserTaskResult): string {\n if (result.success) {\n const parts = [\n '✅ Browser task completed successfully',\n `Steps taken: ${result.steps_taken ?? 0}`,\n result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,\n '',\n 'Result:',\n result.result || 'Task completed',\n ];\n return parts.filter(Boolean).join('\\n');\n }\n\n return `❌ Browser task failed: ${result.error || 'Unknown error'}`;\n}\n\n/**\n * Get system prompt for browser automation\n */\nexport function getSystemPrompt(): string {\n return BROWSER_SYSTEM_PROMPT;\n}\n\n/**\n * Gemini tool with execute method attached\n */\nexport interface GeminiBrowserTool extends FunctionDeclaration {\n execute: (input: BrowserTaskInput | string) => Promise<BrowserTaskResult>;\n formatResult: (result: BrowserTaskResult) => string;\n getSystemPrompt: () => string;\n}\n\n/**\n * Create a configured browser tool with execute and formatResult methods\n * \n * @param config - Browser worker configuration\n * @returns Function declaration with execute and formatResult methods\n * \n * @example\n * ```typescript\n * import { GoogleGenerativeAI, FunctionCallingMode } from '@google/generative-ai';\n * import { createBrowserTool } from '@morphllm/morphsdk/tools/browser/gemini';\n * \n * const tool = createBrowserTool({ apiKey: process.env.MORPH_API_KEY });\n * \n * const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);\n * const model = genAI.getGenerativeModel({\n * model: 'gemini-2.0-flash',\n * tools: [{ functionDeclarations: [tool] }],\n * toolConfig: { functionCallingConfig: { mode: FunctionCallingMode.AUTO } }\n * });\n * \n * const chat = model.startChat();\n * const result = await chat.sendMessage('Test the checkout flow at https://example.com');\n * \n * // Handle function call\n * const call = result.response.functionCalls()?.[0];\n * if (call && call.name === tool.name) {\n * const taskResult = await tool.execute(call.args);\n * console.log(tool.formatResult(taskResult));\n * \n * // Send result back to model\n * await chat.sendMessage([{\n * functionResponse: {\n * name: call.name,\n * response: { result: tool.formatResult(taskResult) }\n * }\n * }]);\n * }\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig): GeminiBrowserTool {\n const declaration: FunctionDeclaration = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: TOOL_PARAMETERS,\n };\n\n return Object.assign(declaration, {\n execute: async (input: BrowserTaskInput | string): Promise<BrowserTaskResult> => {\n return execute(input, config);\n },\n formatResult: (result: BrowserTaskResult): string => {\n return formatResult(result);\n },\n getSystemPrompt: (): string => {\n return getSystemPrompt();\n },\n });\n}\n\n// Legacy alias for consistency with some patterns\nexport const browserTool = browserFunctionDeclaration;\n\nexport default browserFunctionDeclaration;\n\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACaA,IAAM,uBAA+D;AAAA,EACnE,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,iBAAiB,CAAC,gBAAgB,aAAa,WAAW;AAC5D;AAmBA,eAAsB,eACpB,KACA,SACA,cAA2B,CAAC,GACT;AACnB,QAAM;AAAA,IACJ,aAAa,qBAAqB;AAAA,IAClC,eAAe,qBAAqB;AAAA,IACpC,WAAW,qBAAqB;AAAA,IAChC,oBAAoB,qBAAqB;AAAA,IACzC,kBAAkB,qBAAqB;AAAA,IACvC;AAAA,EACF,IAAI;AAEJ,MAAI,YAA0B;AAC9B,MAAI,QAAQ;AAEZ,WAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACtD,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK,OAAO;AAGzC,UAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,YAAI,UAAU,YAAY;AAExB,gBAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AACrD,gBAAM,WAAW,aACb,SAAS,UAAU,IAAI,MACvB,KAAK,IAAI,OAAO,QAAQ;AAE5B,gBAAM,QAAQ,IAAI,MAAM,QAAQ,SAAS,MAAM,oBAAoB,QAAQ,IAAI;AAC/E,cAAI,SAAS;AACX,oBAAQ,UAAU,GAAG,KAAK;AAAA,UAC5B;AAEA,gBAAM,MAAM,QAAQ;AACpB,mBAAS;AACT;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,kBAAY;AAGZ,YAAM,cAAc,gBAAgB;AAAA,QAAK,aACvC,WAAW,SAAS,SAAS,OAAO;AAAA,MACtC;AAEA,UAAI,CAAC,eAAe,YAAY,YAAY;AAC1C,cAAM;AAAA,MACR;AAGA,YAAM,WAAW,KAAK,IAAI,OAAO,QAAQ;AACzC,UAAI,SAAS;AACX,gBAAQ,UAAU,GAAG,SAAS;AAAA,MAChC;AAEA,YAAM,MAAM,QAAQ;AACpB,eAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,aAAa,IAAI,MAAM,sBAAsB;AACrD;AAmBA,eAAsB,YACpB,SACA,WACA,cACY;AACZ,MAAI;AAEJ,QAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,gBAAY,WAAW,MAAM;AAC3B,aAAO,IAAI,MAAM,gBAAgB,6BAA6B,SAAS,IAAI,CAAC;AAAA,IAC9E,GAAG,SAAS;AAAA,EACd,CAAC;AAED,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,KAAK,CAAC,SAAS,cAAc,CAAC;AAC3D,iBAAa,SAAU;AACvB,WAAO;AAAA,EACT,SAAS,OAAO;AACd,iBAAa,SAAU;AACvB,UAAM;AAAA,EACR;AACF;AAKA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;AACvD;;;AC5IO,IAAM,eAAe;AAAA;AAAA,EAE1B,UAAU,EAAE,aAAa,MAAM;AAAA;AAAA,EAE/B,aAAa,EAAE,aAAa,KAAK;AAAA;AAAA,EAEjC,YAAY,EAAE,aAAa,OAAO,cAAc,MAAM;AACxD;AAeO,SAAS,aACd,UACA,UAA8B,CAAC,GACvB;AACR,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,IAAI,QAAQ;AAG5B,MAAI,QAAQ,gBAAgB,QAAW;AACrC,QAAI,aAAa,IAAI,eAAe,OAAO,QAAQ,WAAW,CAAC;AAAA,EACjE;AAEA,MAAI,QAAQ,OAAO;AACjB,QAAI,aAAa,IAAI,SAAS,QAAQ,KAAK;AAAA,EAC7C;AAEA,MAAI,QAAQ,iBAAiB,QAAW;AACtC,QAAI,aAAa,IAAI,gBAAgB,OAAO,QAAQ,YAAY,CAAC;AAAA,EACnE;AAEA,MAAI,QAAQ,QAAQ;AAClB,QAAI,aAAa,IAAI,UAAU,QAAQ,MAAM;AAAA,EAC/C;AAEA,MAAI,QAAQ,WAAW;AACrB,QAAI,aAAa,IAAI,aAAa,QAAQ,SAAS;AAAA,EACrD;AAEA,SAAO,IAAI,SAAS;AACtB;AAkBO,SAAS,gBACd,UACA,UAAyB,CAAC,GAClB;AACR,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,MAAM,aAAa,UAAU,cAAc;AAGjD,QAAM,WAAW,OAAO,UAAU,WAAW,GAAG,KAAK,OAAO;AAC5D,QAAM,YAAY,OAAO,WAAW,WAAW,GAAG,MAAM,OAAO;AAG/D,QAAM,YAAY,UAAU,QAAQ,aAAa,SAAS;AAC1D,QAAM,YAAY,QAAQ,GAAG,SAAS,IAAI,KAAK,KAAK;AAGpD,QAAM,aAAa;AAAA,IACjB,QAAQ,GAAG;AAAA,IACX,UAAU,SAAS;AAAA,EACrB;AAEA,MAAI,WAAW;AACb,eAAW,KAAK,UAAU,SAAS,GAAG;AAAA,EACxC;AAEA,SAAO,WAAW,WAAW,KAAK,GAAG,CAAC;AACxC;AAiBO,SAAS,eACd,UACA,UAAyB,CAAC,GAClB;AACR,QAAM,SAAS,gBAAgB,UAAU,OAAO;AAChD,SAAO;AAAA,EAAsC,MAAM;AACrD;AAOO,SAAS,cACd,iBACe;AACf,MAAI,CAAC,iBAAiB;AACpB,WAAO,CAAC;AAAA,EACV;AAEA,MAAI,OAAO,oBAAoB,UAAU;AACvC,UAAM,SAAS,aAAa,eAA4C;AACxE,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR,mBAAmB,eAAe,wBAAwB,OAAO,KAAK,YAAY,EAAE,KAAK,IAAI,CAAC;AAAA,MAChG;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ACjJA,IAAM,iBAAiB;AAAA,EACrB,QAAQ,QAAQ,IAAI,sBAAsB,QACtC,0BACA;AAAA,EACJ,SAAS;AAAA;AAAA,EACT,OAAO;AACT;AAKO,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EAER,YAAY,SAAwB,CAAC,GAAG;AACtC,SAAK,SAAS;AAAA,MACZ,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,OAAqD;AACjE,WAAO,mBAAmB,OAAO,KAAK,MAAM;AAAA,EAC9C;AAAA,EAIA,MAAM,WACJ,OACsE;AACtE,UAAM,SAAS,KAAK,OAAO,UAAU,eAAe;AACpD,UAAM,QAAQ,KAAK,OAAO,SAAS;AAEnC,QAAI,OAAO;AACT,cAAQ,IAAI,0BAA0B,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC,YAAY,MAAM,OAAO,MAAM,EAAE;AAC9F,cAAQ,IAAI,qCAAqC,MAAM,qBAAqB;AAAA,IAC9E;AAEA,UAAM,UAAkC,EAAE,gBAAgB,mBAAmB;AAC7E,QAAI,KAAK,OAAO,OAAQ,SAAQ,eAAe,IAAI,UAAU,KAAK,OAAO,MAAM;AAG/E,UAAM,WAAW,MAAM,MAAM,GAAG,MAAM,uBAAuB;AAAA,MAC3D,QAAQ;AAAA,MACR;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACnB,MAAM,MAAM;AAAA,QACZ,KAAK,MAAM;AAAA,QACX,WAAW,MAAM,aAAa;AAAA,QAC9B,OAAO,MAAM,SAAS;AAAA,QACtB,gBAAgB,MAAM,kBAAkB;AAAA,QACxC,iBAAiB,MAAM,mBAAmB;AAAA,QAC1C,aAAa,MAAM;AAAA,QACnB,SAAS,MAAM;AAAA,QACf,WAAW,MAAM;AAAA,QACjB,cAAc,MAAM,gBAAgB;AAAA,QACpC,aAAa,MAAM,eAAe,MAAM,kBAAkB;AAAA,QAC1D,cAAc,MAAM,gBAAgB,MAAM,mBAAmB;AAAA,QAC7D,gBAAgB,MAAM,kBAAkB;AAAA,QACxC,mBAAmB,YAAY,QAAQ,0BAA0B,MAAM,MAAM,IAAI;AAAA,QACjF,MAAM,MAAM;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,SAAS,UAAU;AACvE,UAAI,MAAO,SAAQ,MAAM,oBAAoB,SAAS,MAAM,MAAM,SAAS,EAAE;AAC7E,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,EAAE;AAAA,IACzD;AAEA,UAAM,SAAS,MAAM,SAAS,KAAK;AAEnC,QAAI,OAAO;AACT,cAAQ,IAAI,+CAA0C,OAAO,gBAAgB,MAAM,cAAc,OAAO,WAAW,cAAc,MAAM,EAAE;AAAA,IAC3I;AAEA,QAAI,YAAY,OAAO;AACrB,aAAO,2BAA2B,QAAQ,KAAK,QAAQ,MAAM,MAAM;AAAA,IACrE,OAAO;AACL,aAAO,iBAAiB,QAAQ,KAAK,MAAM;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBACJ,OACmE;AACnE,WAAO,qBAAqB,OAAO,KAAK,MAAM;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,aAAoD;AACrE,WAAO,aAAa,aAAa,KAAK,MAAM;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBACJ,aACA,SAC+B;AAC/B,WAAO,iBAAiB,aAAa,KAAK,QAAQ,OAAO;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,aAA8C;AAC5D,WAAO,UAAU,aAAa,KAAK,MAAM;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QACJ,aACA,SACuB;AACvB,WAAO,QAAQ,aAAa,KAAK,QAAQ,OAAO;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAMH;AACD,WAAO,YAAY,KAAK,MAAM;AAAA,EAChC;AACF;AAsCA,eAAsB,mBACpB,OACA,SAAwB,CAAC,GACG;AAC5B,QAAM,SAAS,OAAO,UAAU,eAAe;AAC/C,QAAM,UAAU,OAAO,WAAW,eAAe;AACjD,QAAM,QAAQ,OAAO,SAAS;AAE9B,MAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,KAAK,EAAE,WAAW,GAAG;AACjD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,MAAM,cAAc,WAAc,MAAM,YAAY,KAAK,MAAM,YAAY,KAAK;AAClF,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,OAAO;AACT,YAAQ,IAAI,oBAAoB,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC,YAAY,MAAM,OAAO,MAAM,aAAa,MAAM,aAAa,EAAE,EAAE;AAC1H,YAAQ,IAAI,wBAAwB,MAAM,eAAe,QAAQ,IAAI,cAAc,MAAM,eAAe;AAAA,EAC1G;AAEA,QAAM,YAAY,KAAK,IAAI;AAE3B,MAAI;AACF,UAAM,UAAkC,EAAE,gBAAgB,mBAAmB;AAC7E,QAAI,OAAO,OAAQ,SAAQ,eAAe,IAAI,UAAU,OAAO,MAAM;AAErE,UAAM,eAAe;AAAA,MACnB,GAAG,MAAM;AAAA,MACT;AAAA,QACE,QAAQ;AAAA,QACR;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,MAAM,MAAM;AAAA,UACZ,KAAK,MAAM;AAAA,UACX,WAAW,MAAM,aAAa;AAAA,UAC9B,OAAO,MAAM,SAAS;AAAA,UACtB,gBAAgB,MAAM,kBAAkB;AAAA,UACxC,iBAAiB,MAAM,mBAAmB;AAAA,UAC1C,aAAa,MAAM;AAAA,UACnB,SAAS,MAAM;AAAA,UACf,WAAW,MAAM;AAAA,UACjB,cAAc,MAAM,gBAAgB;AAAA,UACpC,aAAa,MAAM,eAAe,MAAM,kBAAkB;AAAA,UAC1D,cAAc,MAAM,gBAAgB,MAAM,mBAAmB;AAAA,UAC7D,gBAAgB,MAAM,kBAAkB;AAAA,UACxC,mBAAmB,MAAM;AAAA,UACzB,MAAM,MAAM;AAAA,QACd,CAAC;AAAA,MACH;AAAA,MACA,OAAO;AAAA,IACT;AAEA,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA;AAAA,MACA,gCAAgC,OAAO;AAAA,IACzC;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,SAAS,UAAU;AACvE,UAAI,MAAO,SAAQ,MAAM,oBAAoB,SAAS,MAAM,MAAM,SAAS,EAAE;AAC7E,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,EAAE;AAAA,IACzD;AAEA,UAAM,SAA4B,MAAM,SAAS,KAAK;AACtD,UAAM,UAAU,KAAK,IAAI,IAAI;AAE7B,QAAI,OAAO;AACT,cAAQ,IAAI,oBAAe,OAAO,UAAU,YAAY,QAAQ,OAAO,OAAO,cAAc,OAAO,eAAe,CAAC,gBAAgB,OAAO,gBAAgB,MAAM,EAAE;AAAA,IACpK;AAEA,WAAO;AAAA,EAET,SAAS,OAAO;AACd,QAAI,iBAAiB,OAAO;AAE1B,UAAI,MAAM,QAAQ,SAAS,cAAc,KAAK,MAAM,QAAQ,SAAS,cAAc,GAAG;AACpF,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,uCAAuC,MAAM;AAAA,QACtD;AAAA,MACF;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,OAAO,KAAK;AAAA,IACrB;AAAA,EACF;AACF;AAoBA,eAAsB,aACpB,aACA,SAAwB,CAAC,GACM;AAC/B,QAAM,SAAS,OAAO,UAAU,eAAe;AAC/C,QAAM,QAAQ,OAAO,SAAS;AAE9B,MAAI,CAAC,OAAO,QAAQ;AAClB,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,MAAI,MAAO,SAAQ,IAAI,2BAA2B,WAAW,EAAE;AAE/D,QAAM,WAAW,MAAM,MAAM,GAAG,MAAM,eAAe,WAAW,IAAI;AAAA,IAClE,QAAQ;AAAA,IACR,SAAS,EAAE,iBAAiB,UAAU,OAAO,MAAM,GAAG;AAAA,EACxD,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,SAAS,UAAU;AACvE,QAAI,MAAO,SAAQ,MAAM,iCAAiC,SAAS,MAAM,MAAM,SAAS,EAAE;AAC1F,UAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,EAAE;AAAA,EACzD;AAEA,QAAM,OAAwB,MAAM,SAAS,KAAK;AAClD,MAAI,MAAO,SAAQ,IAAI,+BAA+B,KAAK,MAAM,EAAE;AAGnE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,CAAC,YAA0B,QAAQ,aAAa,QAAQ,OAAO;AAAA,IACxE,WAAW,MAAM,UAAU,aAAa,MAAM;AAAA,EAChD;AACF;AAsBA,eAAsB,iBACpB,aACA,SAAwB,CAAC,GACzB,UAAuD,CAAC,GACzB;AAC/B,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,YAAY,KAAK,IAAI;AAE3B,SAAO,KAAK,IAAI,IAAI,YAAY,SAAS;AACvC,UAAM,SAAS,MAAM,aAAa,aAAa,MAAM;AAErD,QAAI,OAAO,WAAW,eAAe,OAAO,WAAW,SAAS;AAC9D,aAAO;AAAA,IACT;AAGA,UAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,YAAY,CAAC;AAAA,EAChE;AAEA,QAAM,IAAI,MAAM,2BAA2B,OAAO,2BAA2B;AAC/E;AAyBA,eAAsB,qBACpB,OACA,SAAwB,CAAC,GAC0C;AAEnE,QAAM,aAAa,MAAM,mBAAmB,OAAO,MAAM;AAGzD,MAAI,WAAW,cAAc;AAC3B,QAAI;AACF,YAAM,YAAY,MAAM;AAAA,QACtB,WAAW;AAAA,QACX;AAAA,QACA,EAAE,SAAS,KAAO,cAAc,IAAK;AAAA,MACvC;AACA,aAAO;AAAA,QACL,GAAG;AAAA,QACH;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AAGd,YAAM,iBAAuC;AAAA,QAC3C,IAAI,WAAW;AAAA,QACf,QAAQ;AAAA,QACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC5D,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC,SAAS,CAAC,YAA0B,QAAQ,WAAW,cAAe,QAAQ,OAAO;AAAA,QACrF,WAAW,MAAM,UAAU,WAAW,cAAe,MAAM;AAAA,MAC7D;AACA,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AA+BA,eAAsB,UACpB,aACA,SAAwB,CAAC,GACA;AACzB,QAAM,SAAS,OAAO,UAAU,eAAe;AAC/C,QAAM,QAAQ,OAAO,SAAS;AAE9B,MAAI,CAAC,OAAO,QAAQ;AAClB,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,MAAI,MAAO,SAAQ,IAAI,wBAAwB,WAAW,EAAE;AAE5D,QAAM,WAAW,MAAM,MAAM,GAAG,MAAM,eAAe,WAAW,WAAW;AAAA,IACzE,QAAQ;AAAA,IACR,SAAS,EAAE,iBAAiB,UAAU,OAAO,MAAM,GAAG;AAAA,EACxD,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,SAAS,UAAU;AACvE,QAAI,MAAO,SAAQ,MAAM,8BAA8B,SAAS,MAAM,MAAM,SAAS,EAAE;AACvF,UAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,EAAE;AAAA,EACzD;AAEA,QAAM,SAAS,MAAM,SAAS,KAAK;AACnC,MAAI,MAAO,SAAQ,IAAI,mBAAmB,OAAO,YAAY,SAAS;AAEtE,SAAO;AACT;AAKA,SAAS,0BAA0B,QAAqB;AACtD,MAAI;AACF,WAAO,KAAK,UAAU;AAAA,MACpB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,QAAQ,OAAO;AAAA,IACjB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,KAAK,6CAA6C,KAAK;AAC/D,WAAO,KAAK,UAAU;AAAA,MACpB,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AACF;AAKA,SAAS,0BACP,QACA,QAC0C;AAC1C,MAAI,CAAC,OAAO,QAAQ;AAClB,WAAO,EAAE,GAAG,QAAQ,QAAQ,KAAK;AAAA,EACnC;AAEA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,OAAO,MAAM;AACvC,UAAM,YAAY,OAAO,MAAM,MAAM;AACrC,WAAO,EAAE,GAAG,QAAQ,QAAQ,UAAU;AAAA,EACxC,SAAS,OAAO;AACd,QAAI,iBAAiB,aAAa;AAChC,aAAO,EAAE,GAAG,QAAQ,QAAQ,KAAK;AAAA,IACnC;AACA,UAAM;AAAA,EACR;AACF;AAKA,eAAe,cACb,QACA,QAC4B;AAC5B,QAAM,SAAS,OAAO,UAAU,eAAe;AAC/C,QAAM,QAAQ,OAAO,SAAS;AAE9B,MAAI,MAAO,SAAQ,IAAI,4BAA4B,MAAM,EAAE;AAE3D,QAAM,UAAkC,CAAC;AACzC,MAAI,OAAO,OAAQ,SAAQ,eAAe,IAAI,UAAU,OAAO,MAAM;AAErE,QAAM,WAAW,MAAM,MAAM,GAAG,MAAM,UAAU,MAAM,IAAI;AAAA,IACxD,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,SAAS,UAAU;AACvE,QAAI,MAAO,SAAQ,MAAM,kCAAkC,SAAS,MAAM,MAAM,SAAS,EAAE;AAC3F,UAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,EAAE;AAAA,EACzD;AAEA,QAAM,SAA4B,MAAM,SAAS,KAAK;AACtD,MAAI,MAAO,SAAQ,IAAI,0BAA0B,OAAO,MAAM,EAAE;AAEhE,SAAO;AACT;AAKA,SAAS,gBAAgB,QAAgB,QAA+B;AACtE,QAAM,SAAS,OAAO,UAAU,eAAe;AAC/C,QAAM,UAAU,OAAO,QAAQ,QAAQ,EAAE;AACzC,SAAO,GAAG,OAAO,UAAU,MAAM;AACnC;AAKA,eAAe,sBACb,QACA,QACA,aAAsD,CAAC,GAC3B;AAC5B,QAAM,WAAW,WAAW,YAAY;AACxC,QAAM,UAAU,WAAW,WAAW;AACtC,QAAM,YAAY,KAAK,IAAI;AAE3B,SAAO,KAAK,IAAI,IAAI,YAAY,SAAS;AACvC,UAAM,SAAS,MAAM,cAAc,QAAQ,MAAM;AAEjD,QAAI,OAAO,WAAW,eAAe,OAAO,WAAW,UAAU;AAC/D,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,QAAQ,CAAC;AAAA,EAC5D;AAEA,QAAM,IAAI,MAAM,8BAA8B,OAAO,IAAI;AAC3D;AAKA,SAAS,iBACP,QACA,QACwB;AACxB,QAAM,UAAkC;AAAA,IACtC,GAAG;AAAA,IACH,SAAS,OAAO,WAAW;AAAA,IAC3B,SAAS,OAAO,UACZ,gBAAgB,OAAO,SAAS,MAAM,IACtC,OAAO,YAAY;AAAA,IACvB,UAAU,OAAO,eAAyD;AAExE,UAAI,OAAO,SAAS;AAClB,eAAO,sBAAsB,OAAO,SAAU,QAAQ,UAAU;AAAA,MAClE;AAEA,UAAI,OAAO,cAAc;AACvB,cAAM,YAAY,MAAM;AAAA,UACtB,OAAO;AAAA,UACP;AAAA,UACA;AAAA,QACF;AAEA,eAAO;AAAA,UACL,GAAG;AAAA,UACH,kBAAkB,UAAU;AAAA,QAC9B;AAAA,MACF;AAEA,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAChF;AAAA;AAAA,IAEA,YAAY,OAAO,WACf,CAAC,YAAiC,aAAa,OAAO,UAAW,OAAO,IACxE,MAAM;AACJ,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,IACJ,eAAe,OAAO,WAClB,CAAC,oBAA6C;AAC5C,YAAM,UAAU,cAAc,eAAe;AAC7C,aAAO,gBAAgB,OAAO,UAAW,OAAO;AAAA,IAClD,IACA,MAAM;AACJ,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,IACJ,cAAc,OAAO,WACjB,MAAM,eAAe,OAAO,QAAS,IACrC,MAAM;AACJ,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACN;AAEA,SAAO;AACT;AAKA,SAAS,2BACP,QACA,QACA,QACoC;AACpC,QAAM,SAAS,OAAO,SAClB,0BAA6B,QAAQ,MAAM,IAC3C,EAAE,GAAG,QAAQ,QAAQ,KAAK;AAE9B,QAAM,UAA8C;AAAA,IAClD,GAAG;AAAA,IACH,SAAS,OAAO,WAAW;AAAA,IAC3B,SAAS,OAAO,UACZ,gBAAgB,OAAO,SAAS,MAAM,IACtC,OAAO,YAAY;AAAA,IACvB,UAAU,OAAO,eAAyD;AAExE,UAAI,OAAO,SAAS;AAClB,cAAM,cAAc,MAAM,sBAAsB,OAAO,SAAU,QAAQ,UAAU;AACnF,eAAO,0BAA6B,aAAa,MAAM;AAAA,MACzD;AAEA,UAAI,OAAO,cAAc;AACvB,cAAM,YAAY,MAAM;AAAA,UACtB,OAAO;AAAA,UACP;AAAA,UACA;AAAA,QACF;AAEA,eAAO;AAAA,UACL,GAAG;AAAA,UACH,kBAAkB,UAAU;AAAA,QAC9B;AAAA,MACF;AAEA,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAChF;AAAA;AAAA,IAEA,YAAY,OAAO,WACf,CAAC,YAAiC,aAAa,OAAO,UAAW,OAAO,IACxE,MAAM;AACJ,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAAA,IACJ,eAAe,OAAO,WAClB,CAAC,oBAA6C;AAC5C,YAAM,UAAU,cAAc,eAAe;AAC7C,aAAO,gBAAgB,OAAO,UAAW,OAAO;AAAA,IAClD,IACA,MAAM;AACJ,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAAA,IACJ,cAAc,OAAO,WACjB,MAAM,eAAe,OAAO,QAAS,IACrC,MAAM;AACJ,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAAA,EACN;AAEA,SAAO;AACT;AAwBA,eAAsB,QACpB,aACA,SAAwB,CAAC,GACzB,UAAuB,CAAC,GACD;AACvB,QAAM,SAAS,OAAO,UAAU,eAAe;AAC/C,QAAM,QAAQ,OAAO,SAAS;AAE9B,MAAI,CAAC,OAAO,QAAQ;AAClB,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AAGA,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,QAAQ,iBAAiB,OAAW,QAAO,IAAI,gBAAgB,OAAO,QAAQ,YAAY,CAAC;AAC/F,MAAI,QAAQ,QAAQ,OAAW,QAAO,IAAI,OAAO,OAAO,QAAQ,GAAG,CAAC;AACpE,MAAI,QAAQ,UAAU,OAAW,QAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAC1E,MAAI,QAAQ,YAAY,OAAW,QAAO,IAAI,WAAW,OAAO,QAAQ,OAAO,CAAC;AAEhF,QAAM,MAAM,GAAG,MAAM,eAAe,WAAW,QAAQ,OAAO,SAAS,IAAI,MAAM,OAAO,SAAS,IAAI,EAAE;AAEvG,MAAI,MAAO,SAAQ,IAAI,sBAAsB,GAAG,EAAE;AAElD,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS,EAAE,iBAAiB,UAAU,OAAO,MAAM,GAAG;AAAA,EACxD,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,YAAY,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,SAAS,UAAU;AACvE,QAAI,MAAO,SAAQ,MAAM,4BAA4B,SAAS,MAAM,MAAM,SAAS,EAAE;AACrF,UAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,EAAE;AAAA,EACzD;AAEA,QAAM,SAAS,MAAM,SAAS,KAAK;AACnC,MAAI,MAAO,SAAQ,IAAI,yBAAyB,OAAO,QAAQ,aAAa,OAAO,MAAM,GAAG;AAE5F,SAAO;AACT;AAQA,eAAsB,YAAY,SAAwB,CAAC,GAMxD;AACD,QAAM,SAAS,OAAO,UAAU,eAAe;AAE/C,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,MAAM,WAAW;AAAA,MAC/C,QAAQ;AAAA,MACR,SAAS,OAAO,SACZ,EAAE,iBAAiB,UAAU,OAAO,MAAM,GAAG,IAC7C,CAAC;AAAA,IACP,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,EAAE;AAAA,IAC3C;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,mBAAmB,KAAK,qBAAqB;AAAA,MAC7C,qBAAqB,KAAK,uBAAuB;AAAA,MACjD,eAAe,KAAK,iBAAiB;AAAA,IACvC;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,mBAAmB;AAAA,MACnB,qBAAqB;AAAA,MACrB,eAAe;AAAA,MACf,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D;AAAA,EACF;AACF;;;ACp2BO,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCjC,IAAM,wBAAwB;;;AC1CrC;AAAA;AAAA;AAAA;AAAA;AAgBO,IAAM,cAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,aAAa;AAAA,EACb,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,KAAK;AAAA,QACH,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,WAAW;AAAA,QACT,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,MAAM,CAAC,OAAO,KAAK;AAAA,QACnB,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,UAAU,CAAC,MAAM;AAAA,EACnB;AACF;AAYA,SAAS,aAAa,QAAmC;AACvD,MAAI,OAAO,SAAS;AAClB,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,gBAAgB,OAAO,eAAe,CAAC;AAAA,MACvC,OAAO,oBAAoB,mBAAmB,OAAO,iBAAiB,OAAO;AAAA,MAC7E;AAAA,MACA;AAAA,MACA,OAAO,UAAU;AAAA,IACnB;AACA,WAAO,MAAM,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,EACxC;AAEA,SAAO,+BAA0B,OAAO,SAAS,eAAe;AAClE;AAkCO,SAAS,kBAAkB,QAAwB;AACxD,SAAO,OAAO,OAAO,CAAC,GAAG,aAAa;AAAA,IACpC,SAAS,OAAO,UAAwD;AACtE,aAAO,mBAAmB,OAAO,MAAM;AAAA,IACzC;AAAA,IACA,cAAc,CAAC,WAAsC;AACnD,aAAO,aAAa,MAAM;AAAA,IAC5B;AAAA,IACA,iBAAiB,MAAc;AAC7B,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACH;;;ACpHA;AAAA;AAAA,qBAAAA;AAAA,EAAA,yBAAAC;AAAA,EAAA;AAAA,sBAAAC;AAAA,EAAA;AAAA;AAgBO,IAAMC,eAAkC;AAAA,EAC7C,MAAM;AAAA,EACN,UAAU;AAAA,IACR,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,QACV,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,KAAK;AAAA,UACH,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,WAAW;AAAA,UACT,MAAM;AAAA,UACN,aAAa;AAAA,UACb,SAAS;AAAA,QACX;AAAA,QACA,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,MAAM,CAAC,OAAO,KAAK;AAAA,UACnB,aAAa;AAAA,UACb,SAAS;AAAA,QACX;AAAA,MACF;AAAA,MACA,UAAU,CAAC,MAAM;AAAA,IACnB;AAAA,EACF;AACF;AASA,eAAsB,QACpB,OACA,QAC4B;AAE5B,QAAM,cAAc,OAAO,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;AACpE,SAAO,mBAAmB,aAAa,MAAM;AAC/C;AAYO,SAASC,cAAa,QAAmC;AAC9D,MAAI,OAAO,SAAS;AAClB,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,gBAAgB,OAAO,eAAe,CAAC;AAAA,MACvC,OAAO,oBAAoB,mBAAmB,OAAO,iBAAiB,OAAO;AAAA,MAC7E;AAAA,MACA;AAAA,MACA,OAAO,UAAU;AAAA,IACnB;AACA,WAAO,MAAM,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,EACxC;AAEA,SAAO,+BAA0B,OAAO,SAAS,eAAe;AAClE;AAKO,SAAS,kBAA0B;AACxC,SAAO;AACT;AAiCO,SAASC,mBAAkB,QAAwB;AACxD,SAAO,OAAO,OAAO,CAAC,GAAGF,cAAa;AAAA,IACpC,SAAS,OAAO,UAAiE;AAC/E,aAAO,QAAQ,OAAO,MAAM;AAAA,IAC9B;AAAA,IACA,cAAc,CAAC,WAAsC;AACnD,aAAOC,cAAa,MAAM;AAAA,IAC5B;AAAA,IACA,iBAAiB,MAAc;AAC7B,aAAO,gBAAgB;AAAA,IACzB;AAAA,EACF,CAAC;AACH;;;AC7IA;AAAA;AAAA,qBAAAE;AAAA,EAAA,yBAAAC;AAAA;AAIA,gBAAmC;AACnC,iBAAkB;AA6BX,SAASC,mBAAkB,QAAwB;AACxD,QAAM,SAAS,aAAE,OAAO;AAAA,IACtB,MAAM,aAAE,OAAO,EAAE,SAAS,gGAAgG;AAAA,IAC1H,KAAK,aAAE,OAAO,EAAE,SAAS,EAAE,SAAS,+CAA+C;AAAA,IACnF,WAAW,aAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,SAAS,2CAA2C;AAAA,IACrG,QAAQ,aAAE,KAAK,CAAC,OAAO,KAAK,CAAC,EAAE,QAAQ,KAAK,EAAE,SAAS,mDAAmD;AAAA,EAC5G,CAAC;AAED,aAAO,UAAAC,MAAW;AAAA,IAChB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS,OAAO,WAAW;AACzB,YAAM,EAAE,MAAM,KAAK,WAAW,OAAO,IAAI;AACzC,YAAM,SAAS,MAAM;AAAA,QACnB,EAAE,MAAM,KAAK,WAAW,OAAO;AAAA,QAC/B;AAAA,MACF;AAKA,UAAI,OAAO,SAAS;AAClB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ,OAAO;AAAA,UACf,aAAa,OAAO;AAAA,UACpB,mBAAmB,OAAO;AAAA,QAC5B;AAAA,MACF;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,OAAO;AAAA,MAChB;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAKO,IAAMC,eAAcF,mBAAkB;;;AC3E7C;AAAA;AAAA;AAAA,qBAAAG;AAAA,EAAA,yBAAAC;AAAA,EAAA;AAAA,iBAAAC;AAAA,EAAA,oBAAAC;AAAA,EAAA,uBAAAC;AAAA;AAKA,2BAA2B;AAY3B,IAAM,kBAA6C;AAAA,EACjD,MAAM,gCAAW;AAAA,EACjB,YAAY;AAAA,IACV,MAAM;AAAA,MACJ,MAAM,gCAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,KAAK;AAAA,MACH,MAAM,gCAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,WAAW;AAAA,MACT,MAAM,gCAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,MACN,MAAM,gCAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,UAAU,CAAC,MAAM;AACnB;AA2BO,IAAM,6BAAkD;AAAA,EAC7D,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY;AACd;AASA,eAAsBC,SACpB,OACA,QAC4B;AAC5B,QAAM,cAAc,OAAO,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;AACpE,SAAO,mBAAmB,aAAa,MAAM;AAC/C;AAYO,SAASC,cAAa,QAAmC;AAC9D,MAAI,OAAO,SAAS;AAClB,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,gBAAgB,OAAO,eAAe,CAAC;AAAA,MACvC,OAAO,oBAAoB,mBAAmB,OAAO,iBAAiB,OAAO;AAAA,MAC7E;AAAA,MACA;AAAA,MACA,OAAO,UAAU;AAAA,IACnB;AACA,WAAO,MAAM,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,EACxC;AAEA,SAAO,+BAA0B,OAAO,SAAS,eAAe;AAClE;AAKO,SAASC,mBAA0B;AACxC,SAAO;AACT;AAkDO,SAASC,mBAAkB,QAA2C;AAC3E,QAAM,cAAmC;AAAA,IACvC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,EACd;AAEA,SAAO,OAAO,OAAO,aAAa;AAAA,IAChC,SAAS,OAAO,UAAiE;AAC/E,aAAOH,SAAQ,OAAO,MAAM;AAAA,IAC9B;AAAA,IACA,cAAc,CAAC,WAAsC;AACnD,aAAOC,cAAa,MAAM;AAAA,IAC5B;AAAA,IACA,iBAAiB,MAAc;AAC7B,aAAOC,iBAAgB;AAAA,IACzB;AAAA,EACF,CAAC;AACH;AAGO,IAAME,eAAc;AAE3B,IAAO,iBAAQ;","names":["browserTool","createBrowserTool","formatResult","browserTool","formatResult","createBrowserTool","browserTool","createBrowserTool","createBrowserTool","createTool","browserTool","browserTool","createBrowserTool","execute","formatResult","getSystemPrompt","execute","formatResult","getSystemPrompt","createBrowserTool","browserTool"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../tools/browser/gemini.ts"],"sourcesContent":["/**\n * Google Gemini SDK adapter for browser automation tool\n */\n\nimport type { FunctionDeclaration, FunctionDeclarationSchema } from '@google/generative-ai';\nimport { SchemaType } from '@google/generative-ai';\nimport { executeBrowserTask } from './core.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskResult,\n} from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION, BROWSER_SYSTEM_PROMPT } from './prompts.js';\n\n/**\n * Parameter schema for the browser tool (Gemini format)\n */\nconst TOOL_PARAMETERS: FunctionDeclarationSchema = {\n type: SchemaType.OBJECT,\n properties: {\n task: {\n type: SchemaType.STRING,\n description: 'Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")',\n },\n url: {\n type: SchemaType.STRING,\n description: 'Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page.',\n },\n max_steps: {\n type: SchemaType.NUMBER,\n description: 'Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.',\n },\n region: {\n type: SchemaType.STRING,\n description: 'Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.',\n },\n },\n required: ['task'],\n};\n\n/**\n * Gemini-native browser function declaration\n * \n * @example\n * ```typescript\n * import { GoogleGenerativeAI } from '@google/generative-ai';\n * import { browserFunctionDeclaration, execute } from '@morphllm/morphsdk/tools/browser/gemini';\n * \n * const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);\n * const model = genAI.getGenerativeModel({\n * model: 'gemini-2.0-flash',\n * tools: [{ functionDeclarations: [browserFunctionDeclaration] }]\n * });\n * \n * const chat = model.startChat();\n * const result = await chat.sendMessage('Test the checkout flow');\n * \n * // Handle function call\n * const call = result.response.functionCalls()?.[0];\n * if (call) {\n * const taskResult = await execute(call.args, { apiKey: 'key' });\n * console.log(taskResult);\n * }\n * ```\n */\nexport const browserFunctionDeclaration: FunctionDeclaration = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: TOOL_PARAMETERS,\n};\n\n/**\n * Execute browser task\n * \n * @param input - Tool input with task and optional url/max_steps\n * @param config - Configuration with apiKey\n * @returns Task execution result\n */\nexport async function execute(\n input: BrowserTaskInput | string,\n config?: BrowserConfig\n): Promise<BrowserTaskResult> {\n const parsedInput = typeof input === 'string' ? JSON.parse(input) : input;\n return executeBrowserTask(parsedInput, config);\n}\n\n/**\n * Format browser task result for Gemini tool result\n * \n * Returns a concise summary suitable for agent context. The full result object\n * (with urls, errors, action_history, judgement, etc.) is available when calling\n * execute() directly, but this formatted string omits those details to save tokens.\n * \n * @param result - Browser task result with full history data\n * @returns Formatted string summary for tool result\n */\nexport function formatResult(result: BrowserTaskResult): string {\n if (result.success) {\n const parts = [\n '✅ Browser task completed successfully',\n `Steps taken: ${result.steps_taken ?? 0}`,\n result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,\n '',\n 'Result:',\n result.result || 'Task completed',\n ];\n return parts.filter(Boolean).join('\\n');\n }\n\n return `❌ Browser task failed: ${result.error || 'Unknown error'}`;\n}\n\n/**\n * Get system prompt for browser automation\n */\nexport function getSystemPrompt(): string {\n return BROWSER_SYSTEM_PROMPT;\n}\n\n/**\n * Gemini tool with execute method attached\n */\nexport interface GeminiBrowserTool extends FunctionDeclaration {\n execute: (input: BrowserTaskInput | string) => Promise<BrowserTaskResult>;\n formatResult: (result: BrowserTaskResult) => string;\n getSystemPrompt: () => string;\n}\n\n/**\n * Create a configured browser tool with execute and formatResult methods\n * \n * @param config - Browser worker configuration\n * @returns Function declaration with execute and formatResult methods\n * \n * @example\n * ```typescript\n * import { GoogleGenerativeAI, FunctionCallingMode } from '@google/generative-ai';\n * import { createBrowserTool } from '@morphllm/morphsdk/tools/browser/gemini';\n * \n * const tool = createBrowserTool({ apiKey: process.env.MORPH_API_KEY });\n * \n * const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);\n * const model = genAI.getGenerativeModel({\n * model: 'gemini-2.0-flash',\n * tools: [{ functionDeclarations: [tool] }],\n * toolConfig: { functionCallingConfig: { mode: FunctionCallingMode.AUTO } }\n * });\n * \n * const chat = model.startChat();\n * const result = await chat.sendMessage('Test the checkout flow at https://example.com');\n * \n * // Handle function call\n * const call = result.response.functionCalls()?.[0];\n * if (call && call.name === tool.name) {\n * const taskResult = await tool.execute(call.args);\n * console.log(tool.formatResult(taskResult));\n * \n * // Send result back to model\n * await chat.sendMessage([{\n * functionResponse: {\n * name: call.name,\n * response: { result: tool.formatResult(taskResult) }\n * }\n * }]);\n * }\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig): GeminiBrowserTool {\n const declaration: FunctionDeclaration = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: TOOL_PARAMETERS,\n };\n\n return Object.assign(declaration, {\n execute: async (input: BrowserTaskInput | string): Promise<BrowserTaskResult> => {\n return execute(input, config);\n },\n formatResult: (result: BrowserTaskResult): string => {\n return formatResult(result);\n },\n getSystemPrompt: (): string => {\n return getSystemPrompt();\n },\n });\n}\n\n// Legacy alias for consistency with some patterns\nexport const browserTool = browserFunctionDeclaration;\n\nexport default browserFunctionDeclaration;\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,SAAS,kBAAkB;AAY3B,IAAM,kBAA6C;AAAA,EACjD,MAAM,WAAW;AAAA,EACjB,YAAY;AAAA,IACV,MAAM;AAAA,MACJ,MAAM,WAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,KAAK;AAAA,MACH,MAAM,WAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,WAAW;AAAA,MACT,MAAM,WAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,MACN,MAAM,WAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,UAAU,CAAC,MAAM;AACnB;AA2BO,IAAM,6BAAkD;AAAA,EAC7D,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY;AACd;AASA,eAAsB,QACpB,OACA,QAC4B;AAC5B,QAAM,cAAc,OAAO,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;AACpE,SAAO,mBAAmB,aAAa,MAAM;AAC/C;AAYO,SAAS,aAAa,QAAmC;AAC9D,MAAI,OAAO,SAAS;AAClB,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,gBAAgB,OAAO,eAAe,CAAC;AAAA,MACvC,OAAO,oBAAoB,mBAAmB,OAAO,iBAAiB,OAAO;AAAA,MAC7E;AAAA,MACA;AAAA,MACA,OAAO,UAAU;AAAA,IACnB;AACA,WAAO,MAAM,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,EACxC;AAEA,SAAO,+BAA0B,OAAO,SAAS,eAAe;AAClE;AAKO,SAAS,kBAA0B;AACxC,SAAO;AACT;AAkDO,SAAS,kBAAkB,QAA2C;AAC3E,QAAM,cAAmC;AAAA,IACvC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,EACd;AAEA,SAAO,OAAO,OAAO,aAAa;AAAA,IAChC,SAAS,OAAO,UAAiE;AAC/E,aAAO,QAAQ,OAAO,MAAM;AAAA,IAC9B;AAAA,IACA,cAAc,CAAC,WAAsC;AACnD,aAAO,aAAa,MAAM;AAAA,IAC5B;AAAA,IACA,iBAAiB,MAAc;AAC7B,aAAO,gBAAgB;AAAA,IACzB;AAAA,EACF,CAAC;AACH;AAGO,IAAM,cAAc;AAE3B,IAAO,iBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../tools/browser/gemini.ts"],"sourcesContent":["/**\n * Google Gemini SDK adapter for browser automation tool\n */\n\nimport type { FunctionDeclaration, FunctionDeclarationSchema } from '@google/generative-ai';\nimport { SchemaType } from '@google/generative-ai';\nimport { executeBrowserTask } from './core.js';\nimport type {\n BrowserConfig,\n BrowserTaskInput,\n BrowserTaskResult,\n} from './types.js';\nimport { BROWSER_TOOL_DESCRIPTION, BROWSER_SYSTEM_PROMPT } from './prompts.js';\n\n/**\n * Parameter schema for the browser tool (Gemini format)\n */\nconst TOOL_PARAMETERS: FunctionDeclarationSchema = {\n type: SchemaType.OBJECT,\n properties: {\n task: {\n type: SchemaType.STRING,\n description: 'Natural language description of what to do (e.g., \"Test checkout flow for buying a pineapple\")',\n },\n url: {\n type: SchemaType.STRING,\n description: 'Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page.',\n },\n max_steps: {\n type: SchemaType.NUMBER,\n description: 'Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.',\n },\n region: {\n type: SchemaType.STRING,\n description: 'Browserless region: sfo (US West Coast) or lon (Europe). Default: sfo.',\n },\n },\n required: ['task'],\n};\n\n/**\n * Gemini-native browser function declaration\n * \n * @example\n * ```typescript\n * import { GoogleGenerativeAI } from '@google/generative-ai';\n * import { browserFunctionDeclaration, execute } from '@morphllm/morphsdk/tools/browser/gemini';\n * \n * const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);\n * const model = genAI.getGenerativeModel({\n * model: 'gemini-2.0-flash',\n * tools: [{ functionDeclarations: [browserFunctionDeclaration] }]\n * });\n * \n * const chat = model.startChat();\n * const result = await chat.sendMessage('Test the checkout flow');\n * \n * // Handle function call\n * const call = result.response.functionCalls()?.[0];\n * if (call) {\n * const taskResult = await execute(call.args, { apiKey: 'key' });\n * console.log(taskResult);\n * }\n * ```\n */\nexport const browserFunctionDeclaration: FunctionDeclaration = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: TOOL_PARAMETERS,\n};\n\n/**\n * Execute browser task\n * \n * @param input - Tool input with task and optional url/max_steps\n * @param config - Configuration with apiKey\n * @returns Task execution result\n */\nexport async function execute(\n input: BrowserTaskInput | string,\n config?: BrowserConfig\n): Promise<BrowserTaskResult> {\n const parsedInput = typeof input === 'string' ? JSON.parse(input) : input;\n return executeBrowserTask(parsedInput, config);\n}\n\n/**\n * Format browser task result for Gemini tool result\n * \n * Returns a concise summary suitable for agent context. The full result object\n * (with urls, errors, action_history, judgement, etc.) is available when calling\n * execute() directly, but this formatted string omits those details to save tokens.\n * \n * @param result - Browser task result with full history data\n * @returns Formatted string summary for tool result\n */\nexport function formatResult(result: BrowserTaskResult): string {\n if (result.success) {\n const parts = [\n '✅ Browser task completed successfully',\n `Steps taken: ${result.steps_taken ?? 0}`,\n result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,\n '',\n 'Result:',\n result.result || 'Task completed',\n ];\n return parts.filter(Boolean).join('\\n');\n }\n\n return `❌ Browser task failed: ${result.error || 'Unknown error'}`;\n}\n\n/**\n * Get system prompt for browser automation\n */\nexport function getSystemPrompt(): string {\n return BROWSER_SYSTEM_PROMPT;\n}\n\n/**\n * Gemini tool with execute method attached\n */\nexport interface GeminiBrowserTool extends FunctionDeclaration {\n execute: (input: BrowserTaskInput | string) => Promise<BrowserTaskResult>;\n formatResult: (result: BrowserTaskResult) => string;\n getSystemPrompt: () => string;\n}\n\n/**\n * Create a configured browser tool with execute and formatResult methods\n * \n * @param config - Browser worker configuration\n * @returns Function declaration with execute and formatResult methods\n * \n * @example\n * ```typescript\n * import { GoogleGenerativeAI, FunctionCallingMode } from '@google/generative-ai';\n * import { createBrowserTool } from '@morphllm/morphsdk/tools/browser/gemini';\n * \n * const tool = createBrowserTool({ apiKey: process.env.MORPH_API_KEY });\n * \n * const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);\n * const model = genAI.getGenerativeModel({\n * model: 'gemini-2.0-flash',\n * tools: [{ functionDeclarations: [tool] }],\n * toolConfig: { functionCallingConfig: { mode: FunctionCallingMode.AUTO } }\n * });\n * \n * const chat = model.startChat();\n * const result = await chat.sendMessage('Test the checkout flow at https://example.com');\n * \n * // Handle function call\n * const call = result.response.functionCalls()?.[0];\n * if (call && call.name === tool.name) {\n * const taskResult = await tool.execute(call.args);\n * console.log(tool.formatResult(taskResult));\n * \n * // Send result back to model\n * await chat.sendMessage([{\n * functionResponse: {\n * name: call.name,\n * response: { result: tool.formatResult(taskResult) }\n * }\n * }]);\n * }\n * ```\n */\nexport function createBrowserTool(config?: BrowserConfig): GeminiBrowserTool {\n const declaration: FunctionDeclaration = {\n name: 'browser_task',\n description: BROWSER_TOOL_DESCRIPTION,\n parameters: TOOL_PARAMETERS,\n };\n\n return Object.assign(declaration, {\n execute: async (input: BrowserTaskInput | string): Promise<BrowserTaskResult> => {\n return execute(input, config);\n },\n formatResult: (result: BrowserTaskResult): string => {\n return formatResult(result);\n },\n getSystemPrompt: (): string => {\n return getSystemPrompt();\n },\n });\n}\n\n// Legacy alias for consistency with some patterns\nexport const browserTool = browserFunctionDeclaration;\n\nexport default browserFunctionDeclaration;\n\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,SAAS,kBAAkB;AAY3B,IAAM,kBAA6C;AAAA,EACjD,MAAM,WAAW;AAAA,EACjB,YAAY;AAAA,IACV,MAAM;AAAA,MACJ,MAAM,WAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,KAAK;AAAA,MACH,MAAM,WAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,WAAW;AAAA,MACT,MAAM,WAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,MACN,MAAM,WAAW;AAAA,MACjB,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,UAAU,CAAC,MAAM;AACnB;AA2BO,IAAM,6BAAkD;AAAA,EAC7D,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY;AACd;AASA,eAAsB,QACpB,OACA,QAC4B;AAC5B,QAAM,cAAc,OAAO,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;AACpE,SAAO,mBAAmB,aAAa,MAAM;AAC/C;AAYO,SAAS,aAAa,QAAmC;AAC9D,MAAI,OAAO,SAAS;AAClB,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,gBAAgB,OAAO,eAAe,CAAC;AAAA,MACvC,OAAO,oBAAoB,mBAAmB,OAAO,iBAAiB,OAAO;AAAA,MAC7E;AAAA,MACA;AAAA,MACA,OAAO,UAAU;AAAA,IACnB;AACA,WAAO,MAAM,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,EACxC;AAEA,SAAO,+BAA0B,OAAO,SAAS,eAAe;AAClE;AAKO,SAAS,kBAA0B;AACxC,SAAO;AACT;AAkDO,SAAS,kBAAkB,QAA2C;AAC3E,QAAM,cAAmC;AAAA,IACvC,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,EACd;AAEA,SAAO,OAAO,OAAO,aAAa;AAAA,IAChC,SAAS,OAAO,UAAiE;AAC/E,aAAO,QAAQ,OAAO,MAAM;AAAA,IAC9B;AAAA,IACA,cAAc,CAAC,WAAsC;AACnD,aAAO,aAAa,MAAM;AAAA,IAC5B;AAAA,IACA,iBAAiB,MAAc;AAC7B,aAAO,gBAAgB;AAAA,IACzB;AAAA,EACF,CAAC;AACH;AAGO,IAAM,cAAc;AAE3B,IAAO,iBAAQ;","names":[]}
@@ -1183,6 +1183,21 @@ function isSymlink(p) {
1183
1183
  return false;
1184
1184
  }
1185
1185
  }
1186
+ function fixPathRepetition(fullPath) {
1187
+ const segments = fullPath.split(import_path3.default.sep).filter(Boolean);
1188
+ if (segments.length < 2) return null;
1189
+ for (let len = Math.floor(segments.length / 2); len >= 1; len--) {
1190
+ for (let i = 0; i <= segments.length - 2 * len; i++) {
1191
+ const first = segments.slice(i, i + len);
1192
+ const second = segments.slice(i + len, i + 2 * len);
1193
+ if (first.every((seg, idx) => seg === second[idx])) {
1194
+ const fixed = [...segments.slice(0, i), ...segments.slice(i + len)];
1195
+ return import_path3.default.sep + fixed.join(import_path3.default.sep);
1196
+ }
1197
+ }
1198
+ }
1199
+ return null;
1200
+ }
1186
1201
  function isTextualFile(filePath, maxBytes = 2e6) {
1187
1202
  try {
1188
1203
  const st = import_fs.default.statSync(filePath);
@@ -1365,7 +1380,17 @@ Details: ${res.stderr}` : ""}`
1365
1380
  error: `[PATH ERROR] ${err instanceof Error ? err.message : String(err)}`
1366
1381
  };
1367
1382
  }
1368
- const stat = await import_promises2.default.stat(abs).catch(() => null);
1383
+ let stat = await import_promises2.default.stat(abs).catch(() => null);
1384
+ if (!stat || !stat.isFile()) {
1385
+ const fixedPath = fixPathRepetition(abs);
1386
+ if (fixedPath) {
1387
+ const fixedStat = await import_promises2.default.stat(fixedPath).catch(() => null);
1388
+ if (fixedStat?.isFile()) {
1389
+ abs = fixedPath;
1390
+ stat = fixedStat;
1391
+ }
1392
+ }
1393
+ }
1369
1394
  if (!stat || !stat.isFile()) {
1370
1395
  return {
1371
1396
  lines: [],