@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
@@ -139,7 +139,8 @@ function buildLiveUrl(debugUrl, options = {}) {
139
139
  "debugUrl is required. Ensure your backend returns debugUrl in the task response. Contact support@morphllm.com if you need help."
140
140
  );
141
141
  }
142
- const url = new URL(debugUrl);
142
+ const normalized = normalizeLiveUrl(debugUrl);
143
+ const url = new URL(normalized);
143
144
  if (options.interactive !== void 0) {
144
145
  url.searchParams.set("interactive", String(options.interactive));
145
146
  }
@@ -157,6 +158,29 @@ function buildLiveUrl(debugUrl, options = {}) {
157
158
  }
158
159
  return url.toString();
159
160
  }
161
+ function normalizeLiveUrl(debugUrl) {
162
+ const trimmed = debugUrl.trim();
163
+ if (!trimmed) {
164
+ return trimmed;
165
+ }
166
+ if (trimmed.startsWith("wss://") || trimmed.startsWith("ws://")) {
167
+ return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
168
+ }
169
+ let url;
170
+ try {
171
+ url = new URL(trimmed);
172
+ } catch {
173
+ return trimmed;
174
+ }
175
+ if (url.protocol === "wss:" || url.protocol === "ws:") {
176
+ return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
177
+ }
178
+ const wssParam = url.searchParams.get("wss");
179
+ if (wssParam && (wssParam.startsWith("wss://") || wssParam.startsWith("ws://"))) {
180
+ url.searchParams.set("wss", wssParam);
181
+ }
182
+ return url.toString();
183
+ }
160
184
  function buildLiveIframe(debugUrl, options = {}) {
161
185
  const {
162
186
  width = "100%",
@@ -387,7 +411,7 @@ function transformCreateInput(input) {
387
411
  function transformSession(api) {
388
412
  return {
389
413
  sessionId: api.session_id,
390
- debugUrl: api.debug_url || api.debugUrl || ""
414
+ debugUrl: api.debug_url || ""
391
415
  };
392
416
  }
393
417
  function transformSaveInput(input) {
@@ -412,22 +436,24 @@ var ProfilesClient = class {
412
436
  this.config = config;
413
437
  }
414
438
  /**
415
- * Create a new browser profile.
416
- *
417
- * @param input - Profile creation parameters
418
- * @returns The created profile
419
- * @throws {MorphValidationError} If input validation fails
420
- * @throws {MorphProfileLimitError} If profile limit is exceeded
421
- * @throws {MorphAuthenticationError} If API key is missing or invalid
422
- *
423
- * @example
424
- * ```typescript
425
- * const profile = await morph.browser.profiles.createProfile({
426
- * name: 'LinkedIn Production',
427
- * repoId: 'repo-uuid-here'
428
- * });
429
- * ```
430
- */
439
+ * Create a new browser profile and immediately start a live session.
440
+ *
441
+ * @param input - Profile creation parameters
442
+ * @returns Profile setup handle with live URL + save()
443
+ * @throws {MorphValidationError} If input validation fails
444
+ * @throws {MorphProfileLimitError} If profile limit is exceeded
445
+ * @throws {MorphAuthenticationError} If API key is missing or invalid
446
+ *
447
+ * @example
448
+ * ```typescript
449
+ * const setup = await morph.browser.profiles.createProfile({
450
+ * name: 'LinkedIn Production',
451
+ * repoId: 'owner/repo'
452
+ * });
453
+ * console.log(setup.session.debugUrl);
454
+ * await setup.save();
455
+ * ```
456
+ */
431
457
  async createProfile(input) {
432
458
  return createProfile(input, this.config);
433
459
  }
@@ -443,7 +469,7 @@ var ProfilesClient = class {
443
469
  * const allProfiles = await morph.browser.profiles.listProfiles();
444
470
  *
445
471
  * // List profiles for a specific repo
446
- * const repoProfiles = await morph.browser.profiles.listProfiles('repo-uuid');
472
+ * const repoProfiles = await morph.browser.profiles.listProfiles('owner/repo');
447
473
  * ```
448
474
  */
449
475
  async listProfiles(repoId) {
@@ -467,14 +493,13 @@ var ProfilesClient = class {
467
493
  return getProfile(id, this.config);
468
494
  }
469
495
  /**
470
- * Update a profile's name.
496
+ * Update a profile by opening a live session (no rename).
471
497
  *
472
498
  * @param id - Profile ID
473
- * @param input - Update parameters
474
- * @returns Updated profile
499
+ * @returns Profile setup handle with live URL + save()
475
500
  */
476
- async updateProfile(id, input) {
477
- return updateProfile(id, input, this.config);
501
+ async updateProfile(id) {
502
+ return updateProfile(id, this.config);
478
503
  }
479
504
  /**
480
505
  * Delete a profile.
@@ -518,6 +543,14 @@ var ProfilesClient = class {
518
543
  async saveSession(sessionId, profileId) {
519
544
  return saveProfileSession({ sessionId, profileId }, this.config);
520
545
  }
546
+ /**
547
+ * List available repo IDs (discovery).
548
+ *
549
+ * @returns Repo summaries with profile counts
550
+ */
551
+ async listRepos() {
552
+ return listRepos(this.config);
553
+ }
521
554
  /**
522
555
  * Get the presigned URL for a profile's state.
523
556
  *
@@ -576,7 +609,9 @@ async function createProfile(input, config = {}) {
576
609
  throw parseAPIError(response.status, errorText, requestId);
577
610
  }
578
611
  const apiProfile = await response.json();
579
- return transformProfile(apiProfile);
612
+ const profile = transformProfile(apiProfile);
613
+ const session = await startProfileSession(config, { profileId: profile.id });
614
+ return buildProfileSetup(profile, session, config);
580
615
  }
581
616
  async function listProfiles(config = {}, repoId) {
582
617
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
@@ -617,37 +652,11 @@ async function getProfile(id, config = {}) {
617
652
  delete: () => deleteProfile(id, config)
618
653
  };
619
654
  }
620
- async function updateProfile(id, input, config = {}) {
655
+ async function updateProfile(id, config = {}) {
621
656
  validateId(id, "id");
622
- if (input.name !== void 0) {
623
- if (typeof input.name !== "string") {
624
- throw new MorphValidationError("name must be a string", "name");
625
- }
626
- if (input.name.trim().length === 0) {
627
- throw new MorphValidationError("name cannot be empty", "name");
628
- }
629
- if (input.name.length > 100) {
630
- throw new MorphValidationError("name must be 100 characters or less", "name");
631
- }
632
- }
633
- const apiUrl = config.apiUrl || DEFAULT_API_URL;
634
- const headers = buildHeaders(config);
635
- const response = await fetchWithRetry(
636
- `${apiUrl}/profiles/${encodeURIComponent(id)}`,
637
- {
638
- method: "PATCH",
639
- headers,
640
- body: JSON.stringify(input)
641
- },
642
- config.retryConfig
643
- );
644
- if (!response.ok) {
645
- const errorText = await response.text().catch(() => response.statusText);
646
- const requestId = response.headers.get("x-request-id") || void 0;
647
- throw parseAPIError(response.status, errorText, requestId);
648
- }
649
- const apiProfile = await response.json();
650
- return transformProfile(apiProfile);
657
+ const profile = await fetchProfile(id, config);
658
+ const session = await startProfileSession(config, { profileId: profile.id });
659
+ return buildProfileSetup(profile, session, config);
651
660
  }
652
661
  async function deleteProfile(id, config = {}) {
653
662
  validateId(id, "id");
@@ -710,6 +719,27 @@ async function saveProfileSession(input, config = {}) {
710
719
  const apiProfile = await response.json();
711
720
  return transformProfile(apiProfile);
712
721
  }
722
+ async function listRepos(config = {}) {
723
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
724
+ const headers = buildHeaders(config);
725
+ const response = await fetchWithRetry(
726
+ `${apiUrl}/repos`,
727
+ { method: "GET", headers },
728
+ config.retryConfig
729
+ );
730
+ if (!response.ok) {
731
+ const errorText = await response.text().catch(() => response.statusText);
732
+ const requestId = response.headers.get("x-request-id") || void 0;
733
+ throw parseAPIError(response.status, errorText, requestId);
734
+ }
735
+ const data = await response.json();
736
+ const repos = Array.isArray(data?.repos) ? data.repos : [];
737
+ return repos.map((repo) => ({
738
+ repoId: repo.repo_id,
739
+ repoFullName: repo.repo_full_name,
740
+ profileCount: repo.profile_count ?? 0
741
+ }));
742
+ }
713
743
  async function getProfileState(profileId, config = {}) {
714
744
  validateId(profileId, "profileId");
715
745
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
@@ -734,6 +764,29 @@ function buildHeaders(config) {
734
764
  }
735
765
  return headers;
736
766
  }
767
+ async function fetchProfile(id, config) {
768
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
769
+ const headers = buildHeaders(config);
770
+ const response = await fetchWithRetry(
771
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
772
+ { method: "GET", headers },
773
+ config.retryConfig
774
+ );
775
+ if (!response.ok) {
776
+ const errorText = await response.text().catch(() => response.statusText);
777
+ const requestId = response.headers.get("x-request-id") || void 0;
778
+ throw parseAPIError(response.status, errorText, requestId);
779
+ }
780
+ const apiProfile = await response.json();
781
+ return transformProfile(apiProfile);
782
+ }
783
+ function buildProfileSetup(profile, session, config) {
784
+ return {
785
+ profile,
786
+ session,
787
+ save: () => saveProfileSession({ sessionId: session.sessionId, profileId: profile.id }, config)
788
+ };
789
+ }
737
790
 
738
791
  // tools/browser/core.ts
739
792
  var DEFAULT_CONFIG = {
@@ -776,20 +829,21 @@ var BrowserClient = class {
776
829
  body: JSON.stringify({
777
830
  task: input.task,
778
831
  url: input.url,
779
- max_steps: input.max_steps ?? 10,
832
+ max_steps: input.maxSteps ?? 10,
780
833
  model: input.model ?? "morph-computer-use-v0",
781
- viewport_width: input.viewport_width ?? 1280,
782
- viewport_height: input.viewport_height ?? 720,
783
- external_id: input.external_id,
784
- repo_id: input.repo_id,
785
- commit_id: input.commit_id,
786
- record_video: input.record_video ?? false,
787
- video_width: input.video_width ?? input.viewport_width ?? 1280,
788
- video_height: input.video_height ?? input.viewport_height ?? 720,
789
- allow_resizing: input.allow_resizing ?? false,
834
+ viewport_width: input.viewportWidth ?? 1280,
835
+ viewport_height: input.viewportHeight ?? 720,
836
+ external_id: input.externalId,
837
+ repo_id: input.repoId,
838
+ repo_full_name: input.repoFullName,
839
+ commit_id: input.commitId,
840
+ record_video: input.recordVideo ?? false,
841
+ video_width: input.videoWidth ?? input.viewportWidth ?? 1280,
842
+ video_height: input.videoHeight ?? input.viewportHeight ?? 720,
843
+ allow_resizing: input.allowResizing ?? false,
790
844
  structured_output: "schema" in input ? stringifyStructuredOutput(input.schema) : void 0,
791
845
  auth: input.auth,
792
- profile_id: input.profile_id
846
+ profile_id: input.profileId
793
847
  })
794
848
  });
795
849
  if (!response.ok) {
@@ -797,9 +851,10 @@ var BrowserClient = class {
797
851
  if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);
798
852
  throw new Error(`HTTP ${response.status}: ${errorText}`);
799
853
  }
800
- const result = await response.json();
854
+ const result = mapTaskResult(await response.json());
801
855
  if (debug) {
802
- console.log(`[Browser] \u2705 Task created: recording_id=${result.recording_id ?? "none"} debug_url=${result.debugUrl ? "available" : "none"}`);
856
+ const debugUrl = result.debugUrl;
857
+ console.log(`[Browser] \u2705 Task created: recordingId=${result.recordingId ?? "none"} debugUrl=${debugUrl ? "available" : "none"}`);
803
858
  }
804
859
  if ("schema" in input) {
805
860
  return wrapTaskResponseWithSchema(result, this.config, input.schema);
@@ -854,15 +909,15 @@ async function executeBrowserTask(input, config = {}) {
854
909
  error: 'Task description is required. Example: "Go to example.com and click the login button"'
855
910
  };
856
911
  }
857
- if (input.max_steps !== void 0 && (input.max_steps < 1 || input.max_steps > 50)) {
912
+ if (input.maxSteps !== void 0 && (input.maxSteps < 1 || input.maxSteps > 50)) {
858
913
  return {
859
914
  success: false,
860
- error: "max_steps must be between 1 and 50. Use more steps for complex multi-page flows."
915
+ error: "maxSteps must be between 1 and 50. Use more steps for complex multi-page flows."
861
916
  };
862
917
  }
863
918
  if (debug) {
864
- console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.max_steps ?? 10}`);
865
- console.log(`[Browser] Recording: ${input.record_video ? "yes" : "no"} | Calling ${apiUrl}/browser-task`);
919
+ console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.maxSteps ?? 10}`);
920
+ console.log(`[Browser] Recording: ${input.recordVideo ? "yes" : "no"} | Calling ${apiUrl}/browser-task`);
866
921
  }
867
922
  const startTime = Date.now();
868
923
  try {
@@ -876,20 +931,20 @@ async function executeBrowserTask(input, config = {}) {
876
931
  body: JSON.stringify({
877
932
  task: input.task,
878
933
  url: input.url,
879
- max_steps: input.max_steps ?? 10,
934
+ max_steps: input.maxSteps ?? 10,
880
935
  model: input.model ?? "morph-computer-use-v0",
881
- viewport_width: input.viewport_width ?? 1280,
882
- viewport_height: input.viewport_height ?? 720,
883
- external_id: input.external_id,
884
- repo_id: input.repo_id,
885
- commit_id: input.commit_id,
886
- record_video: input.record_video ?? false,
887
- video_width: input.video_width ?? input.viewport_width ?? 1280,
888
- video_height: input.video_height ?? input.viewport_height ?? 720,
889
- allow_resizing: input.allow_resizing ?? false,
890
- structured_output: input.structured_output,
936
+ viewport_width: input.viewportWidth ?? 1280,
937
+ viewport_height: input.viewportHeight ?? 720,
938
+ external_id: input.externalId,
939
+ repo_id: input.repoId,
940
+ commit_id: input.commitId,
941
+ record_video: input.recordVideo ?? false,
942
+ video_width: input.videoWidth ?? input.viewportWidth ?? 1280,
943
+ video_height: input.videoHeight ?? input.viewportHeight ?? 720,
944
+ allow_resizing: input.allowResizing ?? false,
945
+ structured_output: input.structuredOutput,
891
946
  auth: input.auth,
892
- profile_id: input.profile_id
947
+ profile_id: input.profileId
893
948
  })
894
949
  },
895
950
  config.retryConfig
@@ -897,17 +952,17 @@ async function executeBrowserTask(input, config = {}) {
897
952
  const response = await withTimeout(
898
953
  fetchPromise,
899
954
  timeout,
900
- `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing max_steps.`
955
+ `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing maxSteps.`
901
956
  );
902
957
  if (!response.ok) {
903
958
  const errorText = await response.text().catch(() => response.statusText);
904
959
  if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);
905
960
  throw new Error(`HTTP ${response.status}: ${errorText}`);
906
961
  }
907
- const result = await response.json();
962
+ const result = mapTaskResult(await response.json());
908
963
  const elapsed = Date.now() - startTime;
909
964
  if (debug) {
910
- console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.steps_taken ?? 0} recordingId=${result.recording_id ?? "none"}`);
965
+ console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.stepsTaken ?? 0} recordingId=${result.recordingId ?? "none"}`);
911
966
  }
912
967
  return result;
913
968
  } catch (error) {
@@ -945,7 +1000,7 @@ async function getRecording(recordingId, config = {}) {
945
1000
  if (debug) console.error(`[Browser] getRecording error: ${response.status} - ${errorText}`);
946
1001
  throw new Error(`HTTP ${response.status}: ${errorText}`);
947
1002
  }
948
- const data = await response.json();
1003
+ const data = mapRecordingStatus(await response.json());
949
1004
  if (debug) console.log(`[Browser] Recording status: ${data.status}`);
950
1005
  return {
951
1006
  ...data,
@@ -968,10 +1023,10 @@ async function waitForRecording(recordingId, config = {}, options = {}) {
968
1023
  }
969
1024
  async function executeWithRecording(input, config = {}) {
970
1025
  const taskResult = await executeBrowserTask(input, config);
971
- if (taskResult.recording_id) {
1026
+ if (taskResult.recordingId) {
972
1027
  try {
973
1028
  const recording = await waitForRecording(
974
- taskResult.recording_id,
1029
+ taskResult.recordingId,
975
1030
  config,
976
1031
  { timeout: 6e4, pollInterval: 2e3 }
977
1032
  );
@@ -981,12 +1036,12 @@ async function executeWithRecording(input, config = {}) {
981
1036
  };
982
1037
  } catch (error) {
983
1038
  const errorRecording = {
984
- id: taskResult.recording_id,
1039
+ id: taskResult.recordingId,
985
1040
  status: "ERROR",
986
1041
  error: error instanceof Error ? error.message : String(error),
987
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
988
- getWebp: (options) => getWebp(taskResult.recording_id, config, options),
989
- getErrors: () => getErrors(taskResult.recording_id, config)
1042
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1043
+ getWebp: (options) => getWebp(taskResult.recordingId, config, options),
1044
+ getErrors: () => getErrors(taskResult.recordingId, config)
990
1045
  };
991
1046
  return {
992
1047
  ...taskResult,
@@ -1012,8 +1067,8 @@ async function getErrors(recordingId, config = {}) {
1012
1067
  if (debug) console.error(`[Browser] getErrors error: ${response.status} - ${errorText}`);
1013
1068
  throw new Error(`HTTP ${response.status}: ${errorText}`);
1014
1069
  }
1015
- const errors = await response.json();
1016
- if (debug) console.log(`[Browser] Found ${errors.total_errors} errors`);
1070
+ const errors = mapErrorsResponse(await response.json());
1071
+ if (debug) console.log(`[Browser] Found ${errors.totalErrors} errors`);
1017
1072
  return errors;
1018
1073
  }
1019
1074
  function stringifyStructuredOutput(schema) {
@@ -1046,6 +1101,84 @@ function parseStructuredTaskOutput(result, schema) {
1046
1101
  throw error;
1047
1102
  }
1048
1103
  }
1104
+ function mapTaskResult(api) {
1105
+ if (!api || typeof api !== "object") {
1106
+ return api;
1107
+ }
1108
+ return {
1109
+ success: api.success,
1110
+ result: api.result,
1111
+ error: api.error,
1112
+ stepsTaken: api.steps_taken,
1113
+ executionTimeMs: api.execution_time_ms,
1114
+ urls: api.urls,
1115
+ actionNames: api.action_names,
1116
+ errors: api.errors,
1117
+ modelActions: api.model_actions,
1118
+ isDone: api.is_done,
1119
+ actionHistory: api.action_history,
1120
+ actionResults: api.action_results,
1121
+ hasErrors: api.has_errors,
1122
+ numberOfSteps: api.number_of_steps,
1123
+ judgement: api.judgement,
1124
+ isValidated: api.is_validated,
1125
+ replayId: api.replay_id,
1126
+ replayUrl: api.replay_url,
1127
+ recordingId: api.recording_id,
1128
+ recordingStatus: api.recording_status,
1129
+ taskId: api.task_id,
1130
+ status: api.status,
1131
+ output: api.output,
1132
+ debugUrl: api.debug_url
1133
+ };
1134
+ }
1135
+ function mapRecordingStatus(api) {
1136
+ return {
1137
+ id: api.id,
1138
+ status: api.status,
1139
+ replayUrl: api.replay_url,
1140
+ networkUrl: api.network_url,
1141
+ consoleUrl: api.console_url,
1142
+ videoUrl: api.video_url,
1143
+ totalEvents: api.total_events,
1144
+ fileSize: api.file_size,
1145
+ duration: api.duration,
1146
+ error: api.error,
1147
+ createdAt: api.created_at
1148
+ };
1149
+ }
1150
+ function mapBrowserError(api) {
1151
+ return {
1152
+ type: api.type,
1153
+ message: api.message,
1154
+ url: api.url,
1155
+ timestamp: api.timestamp,
1156
+ screenshotUrl: api.screenshot_url,
1157
+ capturedAt: api.captured_at,
1158
+ status: api.status
1159
+ };
1160
+ }
1161
+ function mapErrorsResponse(api) {
1162
+ return {
1163
+ recordingId: api.recording_id,
1164
+ totalErrors: api.total_errors,
1165
+ errors: Array.isArray(api.errors) ? api.errors.map(mapBrowserError) : []
1166
+ };
1167
+ }
1168
+ function mapWebpResponse(api) {
1169
+ return {
1170
+ webpUrl: api.webp_url,
1171
+ cached: api.cached,
1172
+ width: api.width,
1173
+ fps: api.fps,
1174
+ maxDuration: api.max_duration,
1175
+ fileSize: api.file_size,
1176
+ maxSizeMb: api.max_size_mb,
1177
+ budgetMet: api.budget_met,
1178
+ qualityUsed: api.quality_used,
1179
+ attempts: api.attempts
1180
+ };
1181
+ }
1049
1182
  async function getTaskStatus(taskId, config) {
1050
1183
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
1051
1184
  const debug = config.debug || false;
@@ -1061,7 +1194,7 @@ async function getTaskStatus(taskId, config) {
1061
1194
  if (debug) console.error(`[Browser] getTaskStatus error: ${response.status} - ${errorText}`);
1062
1195
  throw new Error(`HTTP ${response.status}: ${errorText}`);
1063
1196
  }
1064
- const result = await response.json();
1197
+ const result = mapTaskResult(await response.json());
1065
1198
  if (debug) console.log(`[Browser] Task status: ${result.status}`);
1066
1199
  return result;
1067
1200
  }
@@ -1084,42 +1217,44 @@ async function pollTaskUntilComplete(taskId, config, pollConfig = {}) {
1084
1217
  throw new Error(`Task polling timeout after ${timeout}ms`);
1085
1218
  }
1086
1219
  function wrapTaskResponse(result, config) {
1220
+ const debugUrl = result.debugUrl ?? "";
1087
1221
  const wrapped = {
1088
1222
  ...result,
1089
- task_id: result.task_id || "",
1090
- liveUrl: result.task_id ? generateLiveUrl(result.task_id, config) : result.debugUrl || "",
1223
+ debugUrl,
1224
+ taskId: result.taskId || "",
1225
+ liveUrl: result.taskId ? generateLiveUrl(result.taskId, config) : debugUrl,
1091
1226
  complete: async (pollConfig) => {
1092
- if (result.task_id) {
1093
- return pollTaskUntilComplete(result.task_id, config, pollConfig);
1227
+ if (result.taskId) {
1228
+ return pollTaskUntilComplete(result.taskId, config, pollConfig);
1094
1229
  }
1095
- if (result.recording_id) {
1230
+ if (result.recordingId) {
1096
1231
  const recording = await waitForRecording(
1097
- result.recording_id,
1232
+ result.recordingId,
1098
1233
  config,
1099
1234
  pollConfig
1100
1235
  );
1101
1236
  return {
1102
1237
  ...result,
1103
- recording_status: recording.status
1238
+ recordingStatus: recording.status
1104
1239
  };
1105
1240
  }
1106
- throw new Error("Cannot poll completion: no task_id or recording_id available");
1241
+ throw new Error("Cannot poll completion: no taskId or recordingId available");
1107
1242
  },
1108
1243
  // Add Steel live session helpers - either functional or error-throwing
1109
- getLiveUrl: result.debugUrl ? (options) => buildLiveUrl(result.debugUrl, options) : () => {
1244
+ getLiveUrl: debugUrl ? (options) => buildLiveUrl(debugUrl, options) : () => {
1110
1245
  throw new Error(
1111
1246
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
1112
1247
  );
1113
1248
  },
1114
- getLiveIframe: result.debugUrl ? (optionsOrPreset) => {
1249
+ getLiveIframe: debugUrl ? (optionsOrPreset) => {
1115
1250
  const options = resolvePreset(optionsOrPreset);
1116
- return buildLiveIframe(result.debugUrl, options);
1251
+ return buildLiveIframe(debugUrl, options);
1117
1252
  } : () => {
1118
1253
  throw new Error(
1119
1254
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
1120
1255
  );
1121
1256
  },
1122
- getEmbedCode: result.debugUrl ? () => buildEmbedCode(result.debugUrl) : () => {
1257
+ getEmbedCode: debugUrl ? () => buildEmbedCode(debugUrl) : () => {
1123
1258
  throw new Error(
1124
1259
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
1125
1260
  );
@@ -1128,44 +1263,46 @@ function wrapTaskResponse(result, config) {
1128
1263
  return wrapped;
1129
1264
  }
1130
1265
  function wrapTaskResponseWithSchema(result, config, schema) {
1266
+ const debugUrl = result.debugUrl ?? "";
1131
1267
  const parsed = result.output ? parseStructuredTaskOutput(result, schema) : { ...result, parsed: null };
1132
1268
  const wrapped = {
1133
1269
  ...parsed,
1134
- task_id: result.task_id || "",
1135
- liveUrl: result.task_id ? generateLiveUrl(result.task_id, config) : result.debugUrl || "",
1270
+ debugUrl,
1271
+ taskId: result.taskId || "",
1272
+ liveUrl: result.taskId ? generateLiveUrl(result.taskId, config) : debugUrl,
1136
1273
  complete: async (pollConfig) => {
1137
- if (result.task_id) {
1138
- const finalResult = await pollTaskUntilComplete(result.task_id, config, pollConfig);
1274
+ if (result.taskId) {
1275
+ const finalResult = await pollTaskUntilComplete(result.taskId, config, pollConfig);
1139
1276
  return parseStructuredTaskOutput(finalResult, schema);
1140
1277
  }
1141
- if (result.recording_id) {
1278
+ if (result.recordingId) {
1142
1279
  const recording = await waitForRecording(
1143
- result.recording_id,
1280
+ result.recordingId,
1144
1281
  config,
1145
1282
  pollConfig
1146
1283
  );
1147
1284
  return {
1148
1285
  ...parsed,
1149
- recording_status: recording.status
1286
+ recordingStatus: recording.status
1150
1287
  };
1151
1288
  }
1152
- throw new Error("Cannot poll completion: no task_id or recording_id available");
1289
+ throw new Error("Cannot poll completion: no taskId or recordingId available");
1153
1290
  },
1154
1291
  // Add Steel live session helpers - either functional or error-throwing
1155
- getLiveUrl: result.debugUrl ? (options) => buildLiveUrl(result.debugUrl, options) : () => {
1292
+ getLiveUrl: debugUrl ? (options) => buildLiveUrl(debugUrl, options) : () => {
1156
1293
  throw new Error(
1157
1294
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions. "
1158
1295
  );
1159
1296
  },
1160
- getLiveIframe: result.debugUrl ? (optionsOrPreset) => {
1297
+ getLiveIframe: debugUrl ? (optionsOrPreset) => {
1161
1298
  const options = resolvePreset(optionsOrPreset);
1162
- return buildLiveIframe(result.debugUrl, options);
1299
+ return buildLiveIframe(debugUrl, options);
1163
1300
  } : () => {
1164
1301
  throw new Error(
1165
1302
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions."
1166
1303
  );
1167
1304
  },
1168
- getEmbedCode: result.debugUrl ? () => buildEmbedCode(result.debugUrl) : () => {
1305
+ getEmbedCode: debugUrl ? () => buildEmbedCode(debugUrl) : () => {
1169
1306
  throw new Error(
1170
1307
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions."
1171
1308
  );
@@ -1180,10 +1317,11 @@ async function getWebp(recordingId, config = {}, options = {}) {
1180
1317
  throw new Error("API key required for getWebp");
1181
1318
  }
1182
1319
  const params = new URLSearchParams();
1183
- if (options.max_duration !== void 0) params.set("max_duration", String(options.max_duration));
1320
+ if (options.maxDuration !== void 0) params.set("max_duration", String(options.maxDuration));
1184
1321
  if (options.fps !== void 0) params.set("fps", String(options.fps));
1185
1322
  if (options.width !== void 0) params.set("width", String(options.width));
1186
1323
  if (options.quality !== void 0) params.set("quality", String(options.quality));
1324
+ if (options.maxSizeMb !== void 0) params.set("max_size_mb", String(options.maxSizeMb));
1187
1325
  const url = `${apiUrl}/recordings/${recordingId}/webp${params.toString() ? "?" + params.toString() : ""}`;
1188
1326
  if (debug) console.log(`[Browser] getWebp: ${url}`);
1189
1327
  const response = await fetch(url, {
@@ -1195,8 +1333,8 @@ async function getWebp(recordingId, config = {}, options = {}) {
1195
1333
  if (debug) console.error(`[Browser] getWebp error: ${response.status} - ${errorText}`);
1196
1334
  throw new Error(`HTTP ${response.status}: ${errorText}`);
1197
1335
  }
1198
- const result = await response.json();
1199
- if (debug) console.log(`[Browser] WebP ready: ${result.webp_url} (cached: ${result.cached})`);
1336
+ const result = mapWebpResponse(await response.json());
1337
+ if (debug) console.log(`[Browser] WebP ready: ${result.webpUrl} (cached: ${result.cached})`);
1200
1338
  return result;
1201
1339
  }
1202
1340
  async function checkHealth(config = {}) {
@@ -1263,7 +1401,7 @@ Include verification steps:
1263
1401
  ## Requirements
1264
1402
  - **URL**: Must be publicly accessible (use tunnels like ngrok, Cloudflare, or deploy to staging)
1265
1403
  - **Timing**: Use this after implementation, not during coding
1266
- - **Complexity**: Set max_steps higher (20-30) for multi-step user workflows`;
1404
+ - **Complexity**: Set maxSteps higher (20-30) for multi-step user workflows`;
1267
1405
  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"}}]}`;
1268
1406
 
1269
1407
  // tools/browser/anthropic.ts
@@ -1286,7 +1424,7 @@ var browserTool = {
1286
1424
  type: "string",
1287
1425
  description: "Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page."
1288
1426
  },
1289
- max_steps: {
1427
+ maxSteps: {
1290
1428
  type: "number",
1291
1429
  description: "Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.",
1292
1430
  default: 10
@@ -1305,8 +1443,8 @@ function formatResult(result) {
1305
1443
  if (result.success) {
1306
1444
  const parts = [
1307
1445
  "\u2705 Browser task completed successfully",
1308
- `Steps taken: ${result.steps_taken ?? 0}`,
1309
- result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,
1446
+ `Steps taken: ${result.stepsTaken ?? 0}`,
1447
+ result.executionTimeMs ? `Execution time: ${result.executionTimeMs}ms` : null,
1310
1448
  "",
1311
1449
  "Result:",
1312
1450
  result.result || "Task completed"
@@ -1354,7 +1492,7 @@ var browserTool2 = {
1354
1492
  type: "string",
1355
1493
  description: "Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page."
1356
1494
  },
1357
- max_steps: {
1495
+ maxSteps: {
1358
1496
  type: "number",
1359
1497
  description: "Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows.",
1360
1498
  default: 10
@@ -1378,8 +1516,8 @@ function formatResult2(result) {
1378
1516
  if (result.success) {
1379
1517
  const parts = [
1380
1518
  "\u2705 Browser task completed successfully",
1381
- `Steps taken: ${result.steps_taken ?? 0}`,
1382
- result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,
1519
+ `Steps taken: ${result.stepsTaken ?? 0}`,
1520
+ result.executionTimeMs ? `Execution time: ${result.executionTimeMs}ms` : null,
1383
1521
  "",
1384
1522
  "Result:",
1385
1523
  result.result || "Task completed"
@@ -1417,24 +1555,24 @@ function createBrowserTool3(config) {
1417
1555
  const schema = import_zod.z.object({
1418
1556
  task: import_zod.z.string().describe('Natural language description of what to do (e.g., "Test checkout flow for buying a pineapple")'),
1419
1557
  url: import_zod.z.string().optional().describe("Starting URL (e.g., https://3000-xyz.e2b.dev)"),
1420
- max_steps: import_zod.z.number().min(1).max(50).default(10).describe("Maximum number of browser actions to take"),
1558
+ maxSteps: import_zod.z.number().min(1).max(50).default(10).describe("Maximum number of browser actions to take"),
1421
1559
  region: import_zod.z.enum(["sfo", "lon"]).default("sfo").describe("Browserless region: sfo (US West) or lon (Europe)")
1422
1560
  });
1423
1561
  return (0, import_ai.tool)({
1424
1562
  description: BROWSER_TOOL_DESCRIPTION,
1425
1563
  inputSchema: schema,
1426
1564
  execute: async (params) => {
1427
- const { task, url, max_steps, region } = params;
1565
+ const { task, url, maxSteps, region } = params;
1428
1566
  const result = await executeBrowserTask(
1429
- { task, url, max_steps, region },
1567
+ { task, url, maxSteps, region },
1430
1568
  config
1431
1569
  );
1432
1570
  if (result.success) {
1433
1571
  return {
1434
1572
  success: true,
1435
1573
  result: result.result,
1436
- steps_taken: result.steps_taken,
1437
- execution_time_ms: result.execution_time_ms
1574
+ stepsTaken: result.stepsTaken,
1575
+ executionTimeMs: result.executionTimeMs
1438
1576
  };
1439
1577
  }
1440
1578
  return {
@@ -1469,7 +1607,7 @@ var TOOL_PARAMETERS = {
1469
1607
  type: import_generative_ai.SchemaType.STRING,
1470
1608
  description: "Starting URL (e.g., https://3000-xyz.e2b.dev). Required if navigating to a specific page."
1471
1609
  },
1472
- max_steps: {
1610
+ maxSteps: {
1473
1611
  type: import_generative_ai.SchemaType.NUMBER,
1474
1612
  description: "Maximum number of browser actions to take (1-50). Default: 10. Use 15-30 for complex flows."
1475
1613
  },
@@ -1493,8 +1631,8 @@ function formatResult3(result) {
1493
1631
  if (result.success) {
1494
1632
  const parts = [
1495
1633
  "\u2705 Browser task completed successfully",
1496
- `Steps taken: ${result.steps_taken ?? 0}`,
1497
- result.execution_time_ms ? `Execution time: ${result.execution_time_ms}ms` : null,
1634
+ `Steps taken: ${result.stepsTaken ?? 0}`,
1635
+ result.executionTimeMs ? `Execution time: ${result.executionTimeMs}ms` : null,
1498
1636
  "",
1499
1637
  "Result:",
1500
1638
  result.result || "Task completed"