@morphllm/morphsdk 0.2.94 → 0.2.95

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 (134) hide show
  1. package/dist/{chunk-YJ354BA2.js → chunk-2AMEQAO2.js} +2 -2
  2. package/dist/chunk-2AMEQAO2.js.map +1 -0
  3. package/dist/{chunk-EI4UKP24.js → chunk-2HMEZZKK.js} +2 -2
  4. package/dist/{chunk-EI4UKP24.js.map → chunk-2HMEZZKK.js.map} +1 -1
  5. package/dist/{chunk-UJ7LVT5G.js → chunk-2VERUKO2.js} +1 -1
  6. package/dist/chunk-2VERUKO2.js.map +1 -0
  7. package/dist/{chunk-VHOWYK66.js → chunk-43LQLGP6.js} +23 -33
  8. package/dist/chunk-43LQLGP6.js.map +1 -0
  9. package/dist/{chunk-R7WN43L2.js → chunk-4KMBU6T3.js} +4 -4
  10. package/dist/{chunk-BVVDDTI7.js → chunk-73RV6EXR.js} +2 -2
  11. package/dist/{chunk-IH3KN4AT.js → chunk-7D6TXC7X.js} +2 -2
  12. package/dist/{chunk-FIA6LBW2.js → chunk-O7LDZA52.js} +2 -2
  13. package/dist/{chunk-5QIWYEHJ.js → chunk-PE4KGDA6.js} +1 -8
  14. package/dist/chunk-PE4KGDA6.js.map +1 -0
  15. package/dist/{chunk-SQN4DUQS.js → chunk-Q6Y4R236.js} +26 -2
  16. package/dist/chunk-Q6Y4R236.js.map +1 -0
  17. package/dist/{chunk-TXYCM4NP.js → chunk-QAT5UVPX.js} +3 -3
  18. package/dist/{chunk-M7GFXRKL.js → chunk-QJP62BXH.js} +157 -72
  19. package/dist/chunk-QJP62BXH.js.map +1 -0
  20. package/dist/{chunk-AV6YV2MH.js → chunk-R7IQWNSA.js} +8 -8
  21. package/dist/chunk-R7IQWNSA.js.map +1 -0
  22. package/dist/{chunk-ESRZJRTQ.js → chunk-SI2CKRKJ.js} +86 -56
  23. package/dist/chunk-SI2CKRKJ.js.map +1 -0
  24. package/dist/{chunk-FMWNVTJJ.js → chunk-TSENDJQI.js} +6 -6
  25. package/dist/chunk-TSENDJQI.js.map +1 -0
  26. package/dist/{chunk-IUG2FHNN.js → chunk-XH7P7HVT.js} +1 -8
  27. package/dist/chunk-XH7P7HVT.js.map +1 -0
  28. package/dist/{chunk-WSQMWVSD.js → chunk-YZ5NCWO2.js} +6 -6
  29. package/dist/chunk-YZ5NCWO2.js.map +1 -0
  30. package/dist/{chunk-4WO7PJNT.js → chunk-ZYTAKEBW.js} +8 -8
  31. package/dist/client.cjs +280 -162
  32. package/dist/client.cjs.map +1 -1
  33. package/dist/client.js +18 -18
  34. package/dist/index.cjs +280 -162
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.js +18 -18
  37. package/dist/tools/browser/anthropic.cjs +54 -23
  38. package/dist/tools/browser/anthropic.cjs.map +1 -1
  39. package/dist/tools/browser/anthropic.js +7 -7
  40. package/dist/tools/browser/core.cjs +262 -124
  41. package/dist/tools/browser/core.cjs.map +1 -1
  42. package/dist/tools/browser/core.d.ts +24 -24
  43. package/dist/tools/browser/core.js +5 -5
  44. package/dist/tools/browser/errors.cjs.map +1 -1
  45. package/dist/tools/browser/errors.d.ts +1 -1
  46. package/dist/tools/browser/errors.js +1 -1
  47. package/dist/tools/browser/index.cjs +277 -139
  48. package/dist/tools/browser/index.cjs.map +1 -1
  49. package/dist/tools/browser/index.d.ts +3 -3
  50. package/dist/tools/browser/index.js +12 -12
  51. package/dist/tools/browser/index.js.map +1 -1
  52. package/dist/tools/browser/live.cjs +25 -1
  53. package/dist/tools/browser/live.cjs.map +1 -1
  54. package/dist/tools/browser/live.js +1 -1
  55. package/dist/tools/browser/openai.cjs +54 -23
  56. package/dist/tools/browser/openai.cjs.map +1 -1
  57. package/dist/tools/browser/openai.js +7 -7
  58. package/dist/tools/browser/profiles/core.cjs +85 -54
  59. package/dist/tools/browser/profiles/core.cjs.map +1 -1
  60. package/dist/tools/browser/profiles/core.d.ts +33 -25
  61. package/dist/tools/browser/profiles/core.js +5 -3
  62. package/dist/tools/browser/profiles/index.cjs +85 -54
  63. package/dist/tools/browser/profiles/index.cjs.map +1 -1
  64. package/dist/tools/browser/profiles/index.d.ts +2 -2
  65. package/dist/tools/browser/profiles/index.js +5 -3
  66. package/dist/tools/browser/profiles/types.cjs +1 -1
  67. package/dist/tools/browser/profiles/types.cjs.map +1 -1
  68. package/dist/tools/browser/profiles/types.d.ts +28 -9
  69. package/dist/tools/browser/profiles/types.js +1 -1
  70. package/dist/tools/browser/prompts.cjs +1 -1
  71. package/dist/tools/browser/prompts.cjs.map +1 -1
  72. package/dist/tools/browser/prompts.d.ts +1 -1
  73. package/dist/tools/browser/prompts.js +1 -1
  74. package/dist/tools/browser/types.cjs.map +1 -1
  75. package/dist/tools/browser/types.d.ts +54 -52
  76. package/dist/tools/browser/vercel.cjs +56 -25
  77. package/dist/tools/browser/vercel.cjs.map +1 -1
  78. package/dist/tools/browser/vercel.d.ts +1 -1
  79. package/dist/tools/browser/vercel.js +7 -7
  80. package/dist/tools/fastapply/anthropic.cjs +0 -7
  81. package/dist/tools/fastapply/anthropic.cjs.map +1 -1
  82. package/dist/tools/fastapply/anthropic.js +1 -1
  83. package/dist/tools/fastapply/index.cjs +0 -14
  84. package/dist/tools/fastapply/index.cjs.map +1 -1
  85. package/dist/tools/fastapply/index.js +2 -2
  86. package/dist/tools/fastapply/openai.cjs +0 -7
  87. package/dist/tools/fastapply/openai.cjs.map +1 -1
  88. package/dist/tools/fastapply/openai.js +1 -1
  89. package/dist/tools/index.cjs +0 -14
  90. package/dist/tools/index.cjs.map +1 -1
  91. package/dist/tools/index.js +2 -2
  92. package/dist/tools/warp_grep/agent/runner.cjs +18 -98
  93. package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
  94. package/dist/tools/warp_grep/agent/runner.js +2 -3
  95. package/dist/tools/warp_grep/anthropic.cjs +18 -98
  96. package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
  97. package/dist/tools/warp_grep/anthropic.js +8 -9
  98. package/dist/tools/warp_grep/client.cjs +18 -98
  99. package/dist/tools/warp_grep/client.cjs.map +1 -1
  100. package/dist/tools/warp_grep/client.js +7 -8
  101. package/dist/tools/warp_grep/gemini.cjs +18 -98
  102. package/dist/tools/warp_grep/gemini.cjs.map +1 -1
  103. package/dist/tools/warp_grep/gemini.js +7 -8
  104. package/dist/tools/warp_grep/gemini.js.map +1 -1
  105. package/dist/tools/warp_grep/harness.js +10 -10
  106. package/dist/tools/warp_grep/index.cjs +18 -98
  107. package/dist/tools/warp_grep/index.cjs.map +1 -1
  108. package/dist/tools/warp_grep/index.js +10 -11
  109. package/dist/tools/warp_grep/openai.cjs +18 -98
  110. package/dist/tools/warp_grep/openai.cjs.map +1 -1
  111. package/dist/tools/warp_grep/openai.js +8 -9
  112. package/dist/tools/warp_grep/providers/local.js +2 -2
  113. package/dist/tools/warp_grep/vercel.cjs +18 -98
  114. package/dist/tools/warp_grep/vercel.cjs.map +1 -1
  115. package/dist/tools/warp_grep/vercel.js +8 -9
  116. package/dist/{vercel-CsnNSdze.d.ts → vercel-CVF27qFK.d.ts} +10 -10
  117. package/package.json +1 -1
  118. package/dist/chunk-5QIWYEHJ.js.map +0 -1
  119. package/dist/chunk-AV6YV2MH.js.map +0 -1
  120. package/dist/chunk-ESRZJRTQ.js.map +0 -1
  121. package/dist/chunk-FMWNVTJJ.js.map +0 -1
  122. package/dist/chunk-IUG2FHNN.js.map +0 -1
  123. package/dist/chunk-M7GFXRKL.js.map +0 -1
  124. package/dist/chunk-SQN4DUQS.js.map +0 -1
  125. package/dist/chunk-UJ7LVT5G.js.map +0 -1
  126. package/dist/chunk-VHOWYK66.js.map +0 -1
  127. package/dist/chunk-WSQMWVSD.js.map +0 -1
  128. package/dist/chunk-YJ354BA2.js.map +0 -1
  129. /package/dist/{chunk-R7WN43L2.js.map → chunk-4KMBU6T3.js.map} +0 -0
  130. /package/dist/{chunk-BVVDDTI7.js.map → chunk-73RV6EXR.js.map} +0 -0
  131. /package/dist/{chunk-IH3KN4AT.js.map → chunk-7D6TXC7X.js.map} +0 -0
  132. /package/dist/{chunk-FIA6LBW2.js.map → chunk-O7LDZA52.js.map} +0 -0
  133. /package/dist/{chunk-TXYCM4NP.js.map → chunk-QAT5UVPX.js.map} +0 -0
  134. /package/dist/{chunk-4WO7PJNT.js.map → chunk-ZYTAKEBW.js.map} +0 -0
@@ -5,10 +5,10 @@ export { BROWSER_SYSTEM_PROMPT, BROWSER_TOOL_DESCRIPTION } from './prompts.js';
5
5
  export { LIVE_PRESETS, buildEmbedCode, buildLiveIframe, buildLiveUrl } from './live.js';
6
6
  export { a as anthropic } from '../../anthropic-B6my2oBx.js';
7
7
  export { o as openai } from '../../openai-BQMeDFef.js';
8
- export { v as vercel } from '../../vercel-CsnNSdze.js';
8
+ export { v as vercel } from '../../vercel-CVF27qFK.js';
9
9
  import { FunctionDeclaration } from '@google/generative-ai';
10
10
  export { ProfilesClient } from './profiles/core.js';
11
- export { CreateProfileInput, Profile, ProfileListResponse, ProfileSession, ProfileSessionInput, ProfileStateResponse, ProfileWithMethods, SaveProfileSessionInput, UpdateProfileInput } from './profiles/types.js';
11
+ export { CreateProfileInput, Profile, ProfileListResponse, ProfileSession, ProfileSessionInput, ProfileSetup, ProfileStateResponse, ProfileWithMethods, RepoListResponse, RepoSummary, SaveProfileSessionInput } from './profiles/types.js';
12
12
  export { MorphAPIError, MorphAuthenticationError, MorphError, MorphErrorCode, MorphNotFoundError, MorphProfileLimitError, MorphRateLimitError, MorphValidationError, parseAPIError } from './errors.js';
13
13
  import '../utils/resilience.js';
14
14
  import '@anthropic-ai/sdk/resources/messages.mjs';
@@ -48,7 +48,7 @@ declare const browserFunctionDeclaration: FunctionDeclaration;
48
48
  /**
49
49
  * Execute browser task
50
50
  *
51
- * @param input - Tool input with task and optional url/max_steps
51
+ * @param input - Tool input with task and optional url/maxSteps
52
52
  * @param config - Configuration with apiKey
53
53
  * @returns Task execution result
54
54
  */
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  vercel_exports
3
- } from "../../chunk-AV6YV2MH.js";
3
+ } from "../../chunk-R7IQWNSA.js";
4
4
  import {
5
5
  anthropic_exports
6
- } from "../../chunk-FMWNVTJJ.js";
6
+ } from "../../chunk-TSENDJQI.js";
7
7
  import {
8
8
  openai_exports
9
- } from "../../chunk-WSQMWVSD.js";
9
+ } from "../../chunk-YZ5NCWO2.js";
10
10
  import {
11
11
  BROWSER_SYSTEM_PROMPT,
12
12
  BROWSER_TOOL_DESCRIPTION
13
- } from "../../chunk-EI4UKP24.js";
13
+ } from "../../chunk-2HMEZZKK.js";
14
14
  import {
15
15
  BrowserClient,
16
16
  checkHealth,
@@ -20,11 +20,11 @@ import {
20
20
  getRecording,
21
21
  getWebp,
22
22
  waitForRecording
23
- } from "../../chunk-M7GFXRKL.js";
23
+ } from "../../chunk-QJP62BXH.js";
24
24
  import {
25
25
  ProfilesClient
26
- } from "../../chunk-ESRZJRTQ.js";
27
- import "../../chunk-YJ354BA2.js";
26
+ } from "../../chunk-SI2CKRKJ.js";
27
+ import "../../chunk-2AMEQAO2.js";
28
28
  import {
29
29
  MorphAPIError,
30
30
  MorphAuthenticationError,
@@ -34,13 +34,13 @@ import {
34
34
  MorphRateLimitError,
35
35
  MorphValidationError,
36
36
  parseAPIError
37
- } from "../../chunk-UJ7LVT5G.js";
37
+ } from "../../chunk-2VERUKO2.js";
38
38
  import {
39
39
  LIVE_PRESETS,
40
40
  buildEmbedCode,
41
41
  buildLiveIframe,
42
42
  buildLiveUrl
43
- } from "../../chunk-SQN4DUQS.js";
43
+ } from "../../chunk-Q6Y4R236.js";
44
44
  import "../../chunk-4VWJFZVS.js";
45
45
  import {
46
46
  __export
@@ -69,7 +69,7 @@ var TOOL_PARAMETERS = {
69
69
  type: SchemaType.STRING,
70
70
  description: "Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page."
71
71
  },
72
- max_steps: {
72
+ maxSteps: {
73
73
  type: SchemaType.NUMBER,
74
74
  description: "Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows."
75
75
  },
@@ -93,8 +93,8 @@ function formatResult(result) {
93
93
  if (result.success) {
94
94
  const parts = [
95
95
  "\u2705 Browser task completed successfully",
96
- `Steps taken: ${result.steps_taken ?? 0}`,
97
- result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,
96
+ `Steps taken: ${result.stepsTaken ?? 0}`,
97
+ result.executionTimeMs ? `Execution time: ${result.executionTimeMs}ms` : null,
98
98
  "",
99
99
  "Result:",
100
100
  result.result || "Task completed"
@@ -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-3-flash-preview',\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-3-flash-preview',\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\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 maxSteps: {\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-3-flash-preview',\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/maxSteps\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.stepsTaken ?? 0}`,\n result.executionTimeMs ? `Execution time: ${result.executionTimeMs}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-3-flash-preview',\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\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,UAAU;AAAA,MACR,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,cAAc,CAAC;AAAA,MACtC,OAAO,kBAAkB,mBAAmB,OAAO,eAAe,OAAO;AAAA,MACzE;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":[]}
@@ -41,7 +41,8 @@ function buildLiveUrl(debugUrl, options = {}) {
41
41
  "debugUrl is required. Ensure your backend returns debugUrl in the task response. Contact support@morphllm.com if you need help."
42
42
  );
43
43
  }
44
- const url = new URL(debugUrl);
44
+ const normalized = normalizeLiveUrl(debugUrl);
45
+ const url = new URL(normalized);
45
46
  if (options.interactive !== void 0) {
46
47
  url.searchParams.set("interactive", String(options.interactive));
47
48
  }
@@ -59,6 +60,29 @@ function buildLiveUrl(debugUrl, options = {}) {
59
60
  }
60
61
  return url.toString();
61
62
  }
63
+ function normalizeLiveUrl(debugUrl) {
64
+ const trimmed = debugUrl.trim();
65
+ if (!trimmed) {
66
+ return trimmed;
67
+ }
68
+ if (trimmed.startsWith("wss://") || trimmed.startsWith("ws://")) {
69
+ return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
70
+ }
71
+ let url;
72
+ try {
73
+ url = new URL(trimmed);
74
+ } catch {
75
+ return trimmed;
76
+ }
77
+ if (url.protocol === "wss:" || url.protocol === "ws:") {
78
+ return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
79
+ }
80
+ const wssParam = url.searchParams.get("wss");
81
+ if (wssParam && (wssParam.startsWith("wss://") || wssParam.startsWith("ws://"))) {
82
+ url.searchParams.set("wss", wssParam);
83
+ }
84
+ return url.toString();
85
+ }
62
86
  function buildLiveIframe(debugUrl, options = {}) {
63
87
  const {
64
88
  width = "100%",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../tools/browser/live.ts"],"sourcesContent":["/**\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWO,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;","names":[]}
1
+ {"version":3,"sources":["../../../tools/browser/live.ts"],"sourcesContent":["/**\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 normalized = normalizeLiveUrl(debugUrl);\n const url = new URL(normalized);\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\nfunction normalizeLiveUrl(debugUrl: string): string {\n const trimmed = debugUrl.trim();\n if (!trimmed) {\n return trimmed;\n }\n\n if (trimmed.startsWith('wss://') || trimmed.startsWith('ws://')) {\n return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;\n }\n\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n return trimmed;\n }\n\n if (url.protocol === 'wss:' || url.protocol === 'ws:') {\n return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;\n }\n\n const wssParam = url.searchParams.get('wss');\n if (wssParam && (wssParam.startsWith('wss://') || wssParam.startsWith('ws://'))) {\n url.searchParams.set('wss', wssParam);\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"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  buildLiveIframe,
5
5
  buildLiveUrl,
6
6
  resolvePreset
7
- } from "../../chunk-SQN4DUQS.js";
7
+ } from "../../chunk-Q6Y4R236.js";
8
8
  import "../../chunk-PZ5AY32C.js";
9
9
  export {
10
10
  LIVE_PRESETS,
@@ -122,15 +122,15 @@ async function executeBrowserTask(input, config = {}) {
122
122
  error: 'Task description is required. Example: "Go to example.com and click the login button"'
123
123
  };
124
124
  }
125
- if (input.max_steps !== void 0 && (input.max_steps < 1 || input.max_steps > 50)) {
125
+ if (input.maxSteps !== void 0 && (input.maxSteps < 1 || input.maxSteps > 50)) {
126
126
  return {
127
127
  success: false,
128
- error: "max_steps must be between 1 and 50. Use more steps for complex multi-page flows."
128
+ error: "maxSteps must be between 1 and 50. Use more steps for complex multi-page flows."
129
129
  };
130
130
  }
131
131
  if (debug) {
132
- console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.max_steps ?? 10}`);
133
- console.log(`[Browser] Recording: ${input.record_video ? "yes" : "no"} | Calling ${apiUrl}/browser-task`);
132
+ console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.maxSteps ?? 10}`);
133
+ console.log(`[Browser] Recording: ${input.recordVideo ? "yes" : "no"} | Calling ${apiUrl}/browser-task`);
134
134
  }
135
135
  const startTime = Date.now();
136
136
  try {
@@ -144,20 +144,20 @@ async function executeBrowserTask(input, config = {}) {
144
144
  body: JSON.stringify({
145
145
  task: input.task,
146
146
  url: input.url,
147
- max_steps: input.max_steps ?? 10,
147
+ max_steps: input.maxSteps ?? 10,
148
148
  model: input.model ?? "morph-computer-use-v0",
149
- viewport_width: input.viewport_width ?? 1280,
150
- viewport_height: input.viewport_height ?? 720,
151
- external_id: input.external_id,
152
- repo_id: input.repo_id,
153
- commit_id: input.commit_id,
154
- record_video: input.record_video ?? false,
155
- video_width: input.video_width ?? input.viewport_width ?? 1280,
156
- video_height: input.video_height ?? input.viewport_height ?? 720,
157
- allow_resizing: input.allow_resizing ?? false,
158
- structured_output: input.structured_output,
149
+ viewport_width: input.viewportWidth ?? 1280,
150
+ viewport_height: input.viewportHeight ?? 720,
151
+ external_id: input.externalId,
152
+ repo_id: input.repoId,
153
+ commit_id: input.commitId,
154
+ record_video: input.recordVideo ?? false,
155
+ video_width: input.videoWidth ?? input.viewportWidth ?? 1280,
156
+ video_height: input.videoHeight ?? input.viewportHeight ?? 720,
157
+ allow_resizing: input.allowResizing ?? false,
158
+ structured_output: input.structuredOutput,
159
159
  auth: input.auth,
160
- profile_id: input.profile_id
160
+ profile_id: input.profileId
161
161
  })
162
162
  },
163
163
  config.retryConfig
@@ -165,17 +165,17 @@ async function executeBrowserTask(input, config = {}) {
165
165
  const response = await withTimeout(
166
166
  fetchPromise,
167
167
  timeout,
168
- `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing max_steps.`
168
+ `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing maxSteps.`
169
169
  );
170
170
  if (!response.ok) {
171
171
  const errorText = await response.text().catch(() => response.statusText);
172
172
  if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);
173
173
  throw new Error(`HTTP ${response.status}: ${errorText}`);
174
174
  }
175
- const result = await response.json();
175
+ const result = mapTaskResult(await response.json());
176
176
  const elapsed = Date.now() - startTime;
177
177
  if (debug) {
178
- console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.steps_taken ?? 0} recordingId=${result.recording_id ?? "none"}`);
178
+ console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.stepsTaken ?? 0} recordingId=${result.recordingId ?? "none"}`);
179
179
  }
180
180
  return result;
181
181
  } catch (error) {
@@ -197,6 +197,37 @@ async function executeBrowserTask(input, config = {}) {
197
197
  };
198
198
  }
199
199
  }
200
+ function mapTaskResult(api) {
201
+ if (!api || typeof api !== "object") {
202
+ return api;
203
+ }
204
+ return {
205
+ success: api.success,
206
+ result: api.result,
207
+ error: api.error,
208
+ stepsTaken: api.steps_taken,
209
+ executionTimeMs: api.execution_time_ms,
210
+ urls: api.urls,
211
+ actionNames: api.action_names,
212
+ errors: api.errors,
213
+ modelActions: api.model_actions,
214
+ isDone: api.is_done,
215
+ actionHistory: api.action_history,
216
+ actionResults: api.action_results,
217
+ hasErrors: api.has_errors,
218
+ numberOfSteps: api.number_of_steps,
219
+ judgement: api.judgement,
220
+ isValidated: api.is_validated,
221
+ replayId: api.replay_id,
222
+ replayUrl: api.replay_url,
223
+ recordingId: api.recording_id,
224
+ recordingStatus: api.recording_status,
225
+ taskId: api.task_id,
226
+ status: api.status,
227
+ output: api.output,
228
+ debugUrl: api.debug_url
229
+ };
230
+ }
200
231
 
201
232
  // tools/browser/prompts.ts
202
233
  var 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.
@@ -234,7 +265,7 @@ Include verification steps:
234
265
  ## Requirements
235
266
  - **URL**: Must be publicly accessible (use tunnels like ngrok, Cloudflare, or deploy to staging)
236
267
  - **Timing**: Use this after implementation, not during coding
237
- - **Complexity**: Set max_steps higher (20-30) for multi-step user workflows`;
268
+ - **Complexity**: Set maxSteps higher (20-30) for multi-step user workflows`;
238
269
  var 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"}}]}`;
239
270
 
240
271
  // tools/browser/openai.ts
@@ -254,7 +285,7 @@ var browserTool = {
254
285
  type: "string",
255
286
  description: "Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page."
256
287
  },
257
- max_steps: {
288
+ maxSteps: {
258
289
  type: "number",
259
290
  description: "Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.",
260
291
  default: 10
@@ -278,8 +309,8 @@ function formatResult(result) {
278
309
  if (result.success) {
279
310
  const parts = [
280
311
  "\u2705 Browser task completed successfully",
281
- `Steps taken: ${result.steps_taken ?? 0}`,
282
- result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,
312
+ `Steps taken: ${result.stepsTaken ?? 0}`,
313
+ result.executionTimeMs ? `Execution time: ${result.executionTimeMs}ms` : null,
283
314
  "",
284
315
  "Result:",
285
316
  result.result || "Task completed"