@morphllm/morphsdk 0.2.94 → 0.2.96

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-R7WN43L2.js → chunk-4KMBU6T3.js} +4 -4
  8. package/dist/{chunk-IH3KN4AT.js → chunk-AIXF4GQC.js} +2 -2
  9. package/dist/{chunk-VHOWYK66.js → chunk-BGEEES52.js} +23 -33
  10. package/dist/chunk-BGEEES52.js.map +1 -0
  11. package/dist/{chunk-4WO7PJNT.js → chunk-EZEYREHA.js} +8 -8
  12. package/dist/{chunk-BVVDDTI7.js → chunk-L5WXPMCH.js} +2 -2
  13. package/dist/{chunk-FIA6LBW2.js → chunk-OTPYEYMZ.js} +2 -2
  14. package/dist/{chunk-5QIWYEHJ.js → chunk-PE4KGDA6.js} +1 -8
  15. package/dist/chunk-PE4KGDA6.js.map +1 -0
  16. package/dist/{chunk-SQN4DUQS.js → chunk-Q6Y4R236.js} +26 -2
  17. package/dist/chunk-Q6Y4R236.js.map +1 -0
  18. package/dist/{chunk-TXYCM4NP.js → chunk-QH4BSXOD.js} +3 -3
  19. package/dist/{chunk-M7GFXRKL.js → chunk-QJP62BXH.js} +157 -72
  20. package/dist/chunk-QJP62BXH.js.map +1 -0
  21. package/dist/{chunk-AV6YV2MH.js → chunk-R7IQWNSA.js} +8 -8
  22. package/dist/chunk-R7IQWNSA.js.map +1 -0
  23. package/dist/{chunk-ESRZJRTQ.js → chunk-SI2CKRKJ.js} +86 -56
  24. package/dist/chunk-SI2CKRKJ.js.map +1 -0
  25. package/dist/{chunk-FMWNVTJJ.js → chunk-TSENDJQI.js} +6 -6
  26. package/dist/chunk-TSENDJQI.js.map +1 -0
  27. package/dist/{chunk-IUG2FHNN.js → chunk-XH7P7HVT.js} +1 -8
  28. package/dist/chunk-XH7P7HVT.js.map +1 -0
  29. package/dist/{chunk-WSQMWVSD.js → chunk-YZ5NCWO2.js} +6 -6
  30. package/dist/chunk-YZ5NCWO2.js.map +1 -0
  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-IH3KN4AT.js.map → chunk-AIXF4GQC.js.map} +0 -0
  131. /package/dist/{chunk-4WO7PJNT.js.map → chunk-EZEYREHA.js.map} +0 -0
  132. /package/dist/{chunk-BVVDDTI7.js.map → chunk-L5WXPMCH.js.map} +0 -0
  133. /package/dist/{chunk-FIA6LBW2.js.map → chunk-OTPYEYMZ.js.map} +0 -0
  134. /package/dist/{chunk-TXYCM4NP.js.map → chunk-QH4BSXOD.js.map} +0 -0
@@ -120,7 +120,8 @@ function buildLiveUrl(debugUrl, options = {}) {
120
120
  "debugUrl is required. Ensure your backend returns debugUrl in the task response. Contact support@morphllm.com if you need help."
121
121
  );
122
122
  }
123
- const url = new URL(debugUrl);
123
+ const normalized = normalizeLiveUrl(debugUrl);
124
+ const url = new URL(normalized);
124
125
  if (options.interactive !== void 0) {
125
126
  url.searchParams.set("interactive", String(options.interactive));
126
127
  }
@@ -138,6 +139,29 @@ function buildLiveUrl(debugUrl, options = {}) {
138
139
  }
139
140
  return url.toString();
140
141
  }
142
+ function normalizeLiveUrl(debugUrl) {
143
+ const trimmed = debugUrl.trim();
144
+ if (!trimmed) {
145
+ return trimmed;
146
+ }
147
+ if (trimmed.startsWith("wss://") || trimmed.startsWith("ws://")) {
148
+ return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
149
+ }
150
+ let url;
151
+ try {
152
+ url = new URL(trimmed);
153
+ } catch {
154
+ return trimmed;
155
+ }
156
+ if (url.protocol === "wss:" || url.protocol === "ws:") {
157
+ return `https://live.browser-use.com?wss=${encodeURIComponent(trimmed)}`;
158
+ }
159
+ const wssParam = url.searchParams.get("wss");
160
+ if (wssParam && (wssParam.startsWith("wss://") || wssParam.startsWith("ws://"))) {
161
+ url.searchParams.set("wss", wssParam);
162
+ }
163
+ return url.toString();
164
+ }
141
165
  function buildLiveIframe(debugUrl, options = {}) {
142
166
  const {
143
167
  width = "100%",
@@ -368,7 +392,7 @@ function transformCreateInput(input) {
368
392
  function transformSession(api) {
369
393
  return {
370
394
  sessionId: api.session_id,
371
- debugUrl: api.debug_url || api.debugUrl || ""
395
+ debugUrl: api.debug_url || ""
372
396
  };
373
397
  }
374
398
  function transformSaveInput(input) {
@@ -393,22 +417,24 @@ var ProfilesClient = class {
393
417
  this.config = config;
394
418
  }
395
419
  /**
396
- * Create a new browser profile.
397
- *
398
- * @param input - Profile creation parameters
399
- * @returns The created profile
400
- * @throws {MorphValidationError} If input validation fails
401
- * @throws {MorphProfileLimitError} If profile limit is exceeded
402
- * @throws {MorphAuthenticationError} If API key is missing or invalid
403
- *
404
- * @example
405
- * ```typescript
406
- * const profile = await morph.browser.profiles.createProfile({
407
- * name: 'LinkedIn Production',
408
- * repoId: 'repo-uuid-here'
409
- * });
410
- * ```
411
- */
420
+ * Create a new browser profile and immediately start a live session.
421
+ *
422
+ * @param input - Profile creation parameters
423
+ * @returns Profile setup handle with live URL + save()
424
+ * @throws {MorphValidationError} If input validation fails
425
+ * @throws {MorphProfileLimitError} If profile limit is exceeded
426
+ * @throws {MorphAuthenticationError} If API key is missing or invalid
427
+ *
428
+ * @example
429
+ * ```typescript
430
+ * const setup = await morph.browser.profiles.createProfile({
431
+ * name: 'LinkedIn Production',
432
+ * repoId: 'owner/repo'
433
+ * });
434
+ * console.log(setup.session.debugUrl);
435
+ * await setup.save();
436
+ * ```
437
+ */
412
438
  async createProfile(input) {
413
439
  return createProfile(input, this.config);
414
440
  }
@@ -424,7 +450,7 @@ var ProfilesClient = class {
424
450
  * const allProfiles = await morph.browser.profiles.listProfiles();
425
451
  *
426
452
  * // List profiles for a specific repo
427
- * const repoProfiles = await morph.browser.profiles.listProfiles('repo-uuid');
453
+ * const repoProfiles = await morph.browser.profiles.listProfiles('owner/repo');
428
454
  * ```
429
455
  */
430
456
  async listProfiles(repoId) {
@@ -448,14 +474,13 @@ var ProfilesClient = class {
448
474
  return getProfile(id, this.config);
449
475
  }
450
476
  /**
451
- * Update a profile's name.
477
+ * Update a profile by opening a live session (no rename).
452
478
  *
453
479
  * @param id - Profile ID
454
- * @param input - Update parameters
455
- * @returns Updated profile
480
+ * @returns Profile setup handle with live URL + save()
456
481
  */
457
- async updateProfile(id, input) {
458
- return updateProfile(id, input, this.config);
482
+ async updateProfile(id) {
483
+ return updateProfile(id, this.config);
459
484
  }
460
485
  /**
461
486
  * Delete a profile.
@@ -499,6 +524,14 @@ var ProfilesClient = class {
499
524
  async saveSession(sessionId, profileId) {
500
525
  return saveProfileSession({ sessionId, profileId }, this.config);
501
526
  }
527
+ /**
528
+ * List available repo IDs (discovery).
529
+ *
530
+ * @returns Repo summaries with profile counts
531
+ */
532
+ async listRepos() {
533
+ return listRepos(this.config);
534
+ }
502
535
  /**
503
536
  * Get the presigned URL for a profile's state.
504
537
  *
@@ -557,7 +590,9 @@ async function createProfile(input, config = {}) {
557
590
  throw parseAPIError(response.status, errorText, requestId);
558
591
  }
559
592
  const apiProfile = await response.json();
560
- return transformProfile(apiProfile);
593
+ const profile = transformProfile(apiProfile);
594
+ const session = await startProfileSession(config, { profileId: profile.id });
595
+ return buildProfileSetup(profile, session, config);
561
596
  }
562
597
  async function listProfiles(config = {}, repoId) {
563
598
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
@@ -598,37 +633,11 @@ async function getProfile(id, config = {}) {
598
633
  delete: () => deleteProfile(id, config)
599
634
  };
600
635
  }
601
- async function updateProfile(id, input, config = {}) {
636
+ async function updateProfile(id, config = {}) {
602
637
  validateId(id, "id");
603
- if (input.name !== void 0) {
604
- if (typeof input.name !== "string") {
605
- throw new MorphValidationError("name must be a string", "name");
606
- }
607
- if (input.name.trim().length === 0) {
608
- throw new MorphValidationError("name cannot be empty", "name");
609
- }
610
- if (input.name.length > 100) {
611
- throw new MorphValidationError("name must be 100 characters or less", "name");
612
- }
613
- }
614
- const apiUrl = config.apiUrl || DEFAULT_API_URL;
615
- const headers = buildHeaders(config);
616
- const response = await fetchWithRetry(
617
- `${apiUrl}/profiles/${encodeURIComponent(id)}`,
618
- {
619
- method: "PATCH",
620
- headers,
621
- body: JSON.stringify(input)
622
- },
623
- config.retryConfig
624
- );
625
- if (!response.ok) {
626
- const errorText = await response.text().catch(() => response.statusText);
627
- const requestId = response.headers.get("x-request-id") || void 0;
628
- throw parseAPIError(response.status, errorText, requestId);
629
- }
630
- const apiProfile = await response.json();
631
- return transformProfile(apiProfile);
638
+ const profile = await fetchProfile(id, config);
639
+ const session = await startProfileSession(config, { profileId: profile.id });
640
+ return buildProfileSetup(profile, session, config);
632
641
  }
633
642
  async function deleteProfile(id, config = {}) {
634
643
  validateId(id, "id");
@@ -691,6 +700,27 @@ async function saveProfileSession(input, config = {}) {
691
700
  const apiProfile = await response.json();
692
701
  return transformProfile(apiProfile);
693
702
  }
703
+ async function listRepos(config = {}) {
704
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
705
+ const headers = buildHeaders(config);
706
+ const response = await fetchWithRetry(
707
+ `${apiUrl}/repos`,
708
+ { method: "GET", headers },
709
+ config.retryConfig
710
+ );
711
+ if (!response.ok) {
712
+ const errorText = await response.text().catch(() => response.statusText);
713
+ const requestId = response.headers.get("x-request-id") || void 0;
714
+ throw parseAPIError(response.status, errorText, requestId);
715
+ }
716
+ const data = await response.json();
717
+ const repos = Array.isArray(data?.repos) ? data.repos : [];
718
+ return repos.map((repo) => ({
719
+ repoId: repo.repo_id,
720
+ repoFullName: repo.repo_full_name,
721
+ profileCount: repo.profile_count ?? 0
722
+ }));
723
+ }
694
724
  async function getProfileState(profileId, config = {}) {
695
725
  validateId(profileId, "profileId");
696
726
  const apiUrl = config.apiUrl || DEFAULT_API_URL;
@@ -715,6 +745,29 @@ function buildHeaders(config) {
715
745
  }
716
746
  return headers;
717
747
  }
748
+ async function fetchProfile(id, config) {
749
+ const apiUrl = config.apiUrl || DEFAULT_API_URL;
750
+ const headers = buildHeaders(config);
751
+ const response = await fetchWithRetry(
752
+ `${apiUrl}/profiles/${encodeURIComponent(id)}`,
753
+ { method: "GET", headers },
754
+ config.retryConfig
755
+ );
756
+ if (!response.ok) {
757
+ const errorText = await response.text().catch(() => response.statusText);
758
+ const requestId = response.headers.get("x-request-id") || void 0;
759
+ throw parseAPIError(response.status, errorText, requestId);
760
+ }
761
+ const apiProfile = await response.json();
762
+ return transformProfile(apiProfile);
763
+ }
764
+ function buildProfileSetup(profile, session, config) {
765
+ return {
766
+ profile,
767
+ session,
768
+ save: () => saveProfileSession({ sessionId: session.sessionId, profileId: profile.id }, config)
769
+ };
770
+ }
718
771
 
719
772
  // tools/browser/core.ts
720
773
  var DEFAULT_CONFIG = {
@@ -757,20 +810,21 @@ var BrowserClient = class {
757
810
  body: JSON.stringify({
758
811
  task: input.task,
759
812
  url: input.url,
760
- max_steps: input.max_steps ?? 10,
813
+ max_steps: input.maxSteps ?? 10,
761
814
  model: input.model ?? "morph-computer-use-v0",
762
- viewport_width: input.viewport_width ?? 1280,
763
- viewport_height: input.viewport_height ?? 720,
764
- external_id: input.external_id,
765
- repo_id: input.repo_id,
766
- commit_id: input.commit_id,
767
- record_video: input.record_video ?? false,
768
- video_width: input.video_width ?? input.viewport_width ?? 1280,
769
- video_height: input.video_height ?? input.viewport_height ?? 720,
770
- allow_resizing: input.allow_resizing ?? false,
815
+ viewport_width: input.viewportWidth ?? 1280,
816
+ viewport_height: input.viewportHeight ?? 720,
817
+ external_id: input.externalId,
818
+ repo_id: input.repoId,
819
+ repo_full_name: input.repoFullName,
820
+ commit_id: input.commitId,
821
+ record_video: input.recordVideo ?? false,
822
+ video_width: input.videoWidth ?? input.viewportWidth ?? 1280,
823
+ video_height: input.videoHeight ?? input.viewportHeight ?? 720,
824
+ allow_resizing: input.allowResizing ?? false,
771
825
  structured_output: "schema" in input ? stringifyStructuredOutput(input.schema) : void 0,
772
826
  auth: input.auth,
773
- profile_id: input.profile_id
827
+ profile_id: input.profileId
774
828
  })
775
829
  });
776
830
  if (!response.ok) {
@@ -778,9 +832,10 @@ var BrowserClient = class {
778
832
  if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);
779
833
  throw new Error(`HTTP ${response.status}: ${errorText}`);
780
834
  }
781
- const result = await response.json();
835
+ const result = mapTaskResult(await response.json());
782
836
  if (debug) {
783
- console.log(`[Browser] \u2705 Task created: recording_id=${result.recording_id ?? "none"} debug_url=${result.debugUrl ? "available" : "none"}`);
837
+ const debugUrl = result.debugUrl;
838
+ console.log(`[Browser] \u2705 Task created: recordingId=${result.recordingId ?? "none"} debugUrl=${debugUrl ? "available" : "none"}`);
784
839
  }
785
840
  if ("schema" in input) {
786
841
  return wrapTaskResponseWithSchema(result, this.config, input.schema);
@@ -835,15 +890,15 @@ async function executeBrowserTask(input, config = {}) {
835
890
  error: 'Task description is required. Example: "Go to example.com and click the login button"'
836
891
  };
837
892
  }
838
- if (input.max_steps !== void 0 && (input.max_steps < 1 || input.max_steps > 50)) {
893
+ if (input.maxSteps !== void 0 && (input.maxSteps < 1 || input.maxSteps > 50)) {
839
894
  return {
840
895
  success: false,
841
- error: "max_steps must be between 1 and 50. Use more steps for complex multi-page flows."
896
+ error: "maxSteps must be between 1 and 50. Use more steps for complex multi-page flows."
842
897
  };
843
898
  }
844
899
  if (debug) {
845
- console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.max_steps ?? 10}`);
846
- console.log(`[Browser] Recording: ${input.record_video ? "yes" : "no"} | Calling ${apiUrl}/browser-task`);
900
+ console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.maxSteps ?? 10}`);
901
+ console.log(`[Browser] Recording: ${input.recordVideo ? "yes" : "no"} | Calling ${apiUrl}/browser-task`);
847
902
  }
848
903
  const startTime = Date.now();
849
904
  try {
@@ -857,20 +912,20 @@ async function executeBrowserTask(input, config = {}) {
857
912
  body: JSON.stringify({
858
913
  task: input.task,
859
914
  url: input.url,
860
- max_steps: input.max_steps ?? 10,
915
+ max_steps: input.maxSteps ?? 10,
861
916
  model: input.model ?? "morph-computer-use-v0",
862
- viewport_width: input.viewport_width ?? 1280,
863
- viewport_height: input.viewport_height ?? 720,
864
- external_id: input.external_id,
865
- repo_id: input.repo_id,
866
- commit_id: input.commit_id,
867
- record_video: input.record_video ?? false,
868
- video_width: input.video_width ?? input.viewport_width ?? 1280,
869
- video_height: input.video_height ?? input.viewport_height ?? 720,
870
- allow_resizing: input.allow_resizing ?? false,
871
- structured_output: input.structured_output,
917
+ viewport_width: input.viewportWidth ?? 1280,
918
+ viewport_height: input.viewportHeight ?? 720,
919
+ external_id: input.externalId,
920
+ repo_id: input.repoId,
921
+ commit_id: input.commitId,
922
+ record_video: input.recordVideo ?? false,
923
+ video_width: input.videoWidth ?? input.viewportWidth ?? 1280,
924
+ video_height: input.videoHeight ?? input.viewportHeight ?? 720,
925
+ allow_resizing: input.allowResizing ?? false,
926
+ structured_output: input.structuredOutput,
872
927
  auth: input.auth,
873
- profile_id: input.profile_id
928
+ profile_id: input.profileId
874
929
  })
875
930
  },
876
931
  config.retryConfig
@@ -878,17 +933,17 @@ async function executeBrowserTask(input, config = {}) {
878
933
  const response = await withTimeout(
879
934
  fetchPromise,
880
935
  timeout,
881
- `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing max_steps.`
936
+ `Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing maxSteps.`
882
937
  );
883
938
  if (!response.ok) {
884
939
  const errorText = await response.text().catch(() => response.statusText);
885
940
  if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);
886
941
  throw new Error(`HTTP ${response.status}: ${errorText}`);
887
942
  }
888
- const result = await response.json();
943
+ const result = mapTaskResult(await response.json());
889
944
  const elapsed = Date.now() - startTime;
890
945
  if (debug) {
891
- console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.steps_taken ?? 0} recordingId=${result.recording_id ?? "none"}`);
946
+ console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.stepsTaken ?? 0} recordingId=${result.recordingId ?? "none"}`);
892
947
  }
893
948
  return result;
894
949
  } catch (error) {
@@ -926,7 +981,7 @@ async function getRecording(recordingId, config = {}) {
926
981
  if (debug) console.error(`[Browser] getRecording error: ${response.status} - ${errorText}`);
927
982
  throw new Error(`HTTP ${response.status}: ${errorText}`);
928
983
  }
929
- const data = await response.json();
984
+ const data = mapRecordingStatus(await response.json());
930
985
  if (debug) console.log(`[Browser] Recording status: ${data.status}`);
931
986
  return {
932
987
  ...data,
@@ -949,10 +1004,10 @@ async function waitForRecording(recordingId, config = {}, options = {}) {
949
1004
  }
950
1005
  async function executeWithRecording(input, config = {}) {
951
1006
  const taskResult = await executeBrowserTask(input, config);
952
- if (taskResult.recording_id) {
1007
+ if (taskResult.recordingId) {
953
1008
  try {
954
1009
  const recording = await waitForRecording(
955
- taskResult.recording_id,
1010
+ taskResult.recordingId,
956
1011
  config,
957
1012
  { timeout: 6e4, pollInterval: 2e3 }
958
1013
  );
@@ -962,12 +1017,12 @@ async function executeWithRecording(input, config = {}) {
962
1017
  };
963
1018
  } catch (error) {
964
1019
  const errorRecording = {
965
- id: taskResult.recording_id,
1020
+ id: taskResult.recordingId,
966
1021
  status: "ERROR",
967
1022
  error: error instanceof Error ? error.message : String(error),
968
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
969
- getWebp: (options) => getWebp(taskResult.recording_id, config, options),
970
- getErrors: () => getErrors(taskResult.recording_id, config)
1023
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1024
+ getWebp: (options) => getWebp(taskResult.recordingId, config, options),
1025
+ getErrors: () => getErrors(taskResult.recordingId, config)
971
1026
  };
972
1027
  return {
973
1028
  ...taskResult,
@@ -993,8 +1048,8 @@ async function getErrors(recordingId, config = {}) {
993
1048
  if (debug) console.error(`[Browser] getErrors error: ${response.status} - ${errorText}`);
994
1049
  throw new Error(`HTTP ${response.status}: ${errorText}`);
995
1050
  }
996
- const errors = await response.json();
997
- if (debug) console.log(`[Browser] Found ${errors.total_errors} errors`);
1051
+ const errors = mapErrorsResponse(await response.json());
1052
+ if (debug) console.log(`[Browser] Found ${errors.totalErrors} errors`);
998
1053
  return errors;
999
1054
  }
1000
1055
  function stringifyStructuredOutput(schema) {
@@ -1027,6 +1082,84 @@ function parseStructuredTaskOutput(result, schema) {
1027
1082
  throw error;
1028
1083
  }
1029
1084
  }
1085
+ function mapTaskResult(api) {
1086
+ if (!api || typeof api !== "object") {
1087
+ return api;
1088
+ }
1089
+ return {
1090
+ success: api.success,
1091
+ result: api.result,
1092
+ error: api.error,
1093
+ stepsTaken: api.steps_taken,
1094
+ executionTimeMs: api.execution_time_ms,
1095
+ urls: api.urls,
1096
+ actionNames: api.action_names,
1097
+ errors: api.errors,
1098
+ modelActions: api.model_actions,
1099
+ isDone: api.is_done,
1100
+ actionHistory: api.action_history,
1101
+ actionResults: api.action_results,
1102
+ hasErrors: api.has_errors,
1103
+ numberOfSteps: api.number_of_steps,
1104
+ judgement: api.judgement,
1105
+ isValidated: api.is_validated,
1106
+ replayId: api.replay_id,
1107
+ replayUrl: api.replay_url,
1108
+ recordingId: api.recording_id,
1109
+ recordingStatus: api.recording_status,
1110
+ taskId: api.task_id,
1111
+ status: api.status,
1112
+ output: api.output,
1113
+ debugUrl: api.debug_url
1114
+ };
1115
+ }
1116
+ function mapRecordingStatus(api) {
1117
+ return {
1118
+ id: api.id,
1119
+ status: api.status,
1120
+ replayUrl: api.replay_url,
1121
+ networkUrl: api.network_url,
1122
+ consoleUrl: api.console_url,
1123
+ videoUrl: api.video_url,
1124
+ totalEvents: api.total_events,
1125
+ fileSize: api.file_size,
1126
+ duration: api.duration,
1127
+ error: api.error,
1128
+ createdAt: api.created_at
1129
+ };
1130
+ }
1131
+ function mapBrowserError(api) {
1132
+ return {
1133
+ type: api.type,
1134
+ message: api.message,
1135
+ url: api.url,
1136
+ timestamp: api.timestamp,
1137
+ screenshotUrl: api.screenshot_url,
1138
+ capturedAt: api.captured_at,
1139
+ status: api.status
1140
+ };
1141
+ }
1142
+ function mapErrorsResponse(api) {
1143
+ return {
1144
+ recordingId: api.recording_id,
1145
+ totalErrors: api.total_errors,
1146
+ errors: Array.isArray(api.errors) ? api.errors.map(mapBrowserError) : []
1147
+ };
1148
+ }
1149
+ function mapWebpResponse(api) {
1150
+ return {
1151
+ webpUrl: api.webp_url,
1152
+ cached: api.cached,
1153
+ width: api.width,
1154
+ fps: api.fps,
1155
+ maxDuration: api.max_duration,
1156
+ fileSize: api.file_size,
1157
+ maxSizeMb: api.max_size_mb,
1158
+ budgetMet: api.budget_met,
1159
+ qualityUsed: api.quality_used,
1160
+ attempts: api.attempts
1161
+ };
1162
+ }
1030
1163
  async function getTaskStatus(taskId, config) {
1031
1164
  const apiUrl = config.apiUrl || DEFAULT_CONFIG.apiUrl;
1032
1165
  const debug = config.debug || false;
@@ -1042,7 +1175,7 @@ async function getTaskStatus(taskId, config) {
1042
1175
  if (debug) console.error(`[Browser] getTaskStatus error: ${response.status} - ${errorText}`);
1043
1176
  throw new Error(`HTTP ${response.status}: ${errorText}`);
1044
1177
  }
1045
- const result = await response.json();
1178
+ const result = mapTaskResult(await response.json());
1046
1179
  if (debug) console.log(`[Browser] Task status: ${result.status}`);
1047
1180
  return result;
1048
1181
  }
@@ -1065,42 +1198,44 @@ async function pollTaskUntilComplete(taskId, config, pollConfig = {}) {
1065
1198
  throw new Error(`Task polling timeout after ${timeout}ms`);
1066
1199
  }
1067
1200
  function wrapTaskResponse(result, config) {
1201
+ const debugUrl = result.debugUrl ?? "";
1068
1202
  const wrapped = {
1069
1203
  ...result,
1070
- task_id: result.task_id || "",
1071
- liveUrl: result.task_id ? generateLiveUrl(result.task_id, config) : result.debugUrl || "",
1204
+ debugUrl,
1205
+ taskId: result.taskId || "",
1206
+ liveUrl: result.taskId ? generateLiveUrl(result.taskId, config) : debugUrl,
1072
1207
  complete: async (pollConfig) => {
1073
- if (result.task_id) {
1074
- return pollTaskUntilComplete(result.task_id, config, pollConfig);
1208
+ if (result.taskId) {
1209
+ return pollTaskUntilComplete(result.taskId, config, pollConfig);
1075
1210
  }
1076
- if (result.recording_id) {
1211
+ if (result.recordingId) {
1077
1212
  const recording = await waitForRecording(
1078
- result.recording_id,
1213
+ result.recordingId,
1079
1214
  config,
1080
1215
  pollConfig
1081
1216
  );
1082
1217
  return {
1083
1218
  ...result,
1084
- recording_status: recording.status
1219
+ recordingStatus: recording.status
1085
1220
  };
1086
1221
  }
1087
- throw new Error("Cannot poll completion: no task_id or recording_id available");
1222
+ throw new Error("Cannot poll completion: no taskId or recordingId available");
1088
1223
  },
1089
1224
  // Add Steel live session helpers - either functional or error-throwing
1090
- getLiveUrl: result.debugUrl ? (options) => buildLiveUrl(result.debugUrl, options) : () => {
1225
+ getLiveUrl: debugUrl ? (options) => buildLiveUrl(debugUrl, options) : () => {
1091
1226
  throw new Error(
1092
1227
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
1093
1228
  );
1094
1229
  },
1095
- getLiveIframe: result.debugUrl ? (optionsOrPreset) => {
1230
+ getLiveIframe: debugUrl ? (optionsOrPreset) => {
1096
1231
  const options = resolvePreset(optionsOrPreset);
1097
- return buildLiveIframe(result.debugUrl, options);
1232
+ return buildLiveIframe(debugUrl, options);
1098
1233
  } : () => {
1099
1234
  throw new Error(
1100
1235
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
1101
1236
  );
1102
1237
  },
1103
- getEmbedCode: result.debugUrl ? () => buildEmbedCode(result.debugUrl) : () => {
1238
+ getEmbedCode: debugUrl ? () => buildEmbedCode(debugUrl) : () => {
1104
1239
  throw new Error(
1105
1240
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help."
1106
1241
  );
@@ -1109,44 +1244,46 @@ function wrapTaskResponse(result, config) {
1109
1244
  return wrapped;
1110
1245
  }
1111
1246
  function wrapTaskResponseWithSchema(result, config, schema) {
1247
+ const debugUrl = result.debugUrl ?? "";
1112
1248
  const parsed = result.output ? parseStructuredTaskOutput(result, schema) : { ...result, parsed: null };
1113
1249
  const wrapped = {
1114
1250
  ...parsed,
1115
- task_id: result.task_id || "",
1116
- liveUrl: result.task_id ? generateLiveUrl(result.task_id, config) : result.debugUrl || "",
1251
+ debugUrl,
1252
+ taskId: result.taskId || "",
1253
+ liveUrl: result.taskId ? generateLiveUrl(result.taskId, config) : debugUrl,
1117
1254
  complete: async (pollConfig) => {
1118
- if (result.task_id) {
1119
- const finalResult = await pollTaskUntilComplete(result.task_id, config, pollConfig);
1255
+ if (result.taskId) {
1256
+ const finalResult = await pollTaskUntilComplete(result.taskId, config, pollConfig);
1120
1257
  return parseStructuredTaskOutput(finalResult, schema);
1121
1258
  }
1122
- if (result.recording_id) {
1259
+ if (result.recordingId) {
1123
1260
  const recording = await waitForRecording(
1124
- result.recording_id,
1261
+ result.recordingId,
1125
1262
  config,
1126
1263
  pollConfig
1127
1264
  );
1128
1265
  return {
1129
1266
  ...parsed,
1130
- recording_status: recording.status
1267
+ recordingStatus: recording.status
1131
1268
  };
1132
1269
  }
1133
- throw new Error("Cannot poll completion: no task_id or recording_id available");
1270
+ throw new Error("Cannot poll completion: no taskId or recordingId available");
1134
1271
  },
1135
1272
  // Add Steel live session helpers - either functional or error-throwing
1136
- getLiveUrl: result.debugUrl ? (options) => buildLiveUrl(result.debugUrl, options) : () => {
1273
+ getLiveUrl: debugUrl ? (options) => buildLiveUrl(debugUrl, options) : () => {
1137
1274
  throw new Error(
1138
1275
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions. "
1139
1276
  );
1140
1277
  },
1141
- getLiveIframe: result.debugUrl ? (optionsOrPreset) => {
1278
+ getLiveIframe: debugUrl ? (optionsOrPreset) => {
1142
1279
  const options = resolvePreset(optionsOrPreset);
1143
- return buildLiveIframe(result.debugUrl, options);
1280
+ return buildLiveIframe(debugUrl, options);
1144
1281
  } : () => {
1145
1282
  throw new Error(
1146
1283
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions."
1147
1284
  );
1148
1285
  },
1149
- getEmbedCode: result.debugUrl ? () => buildEmbedCode(result.debugUrl) : () => {
1286
+ getEmbedCode: debugUrl ? () => buildEmbedCode(debugUrl) : () => {
1150
1287
  throw new Error(
1151
1288
  "Live sessions not available. Your backend must return a debugUrl in the response. Contact support@morphllm.com if you need help enabling live sessions."
1152
1289
  );
@@ -1161,10 +1298,11 @@ async function getWebp(recordingId, config = {}, options = {}) {
1161
1298
  throw new Error("API key required for getWebp");
1162
1299
  }
1163
1300
  const params = new URLSearchParams();
1164
- if (options.max_duration !== void 0) params.set("max_duration", String(options.max_duration));
1301
+ if (options.maxDuration !== void 0) params.set("max_duration", String(options.maxDuration));
1165
1302
  if (options.fps !== void 0) params.set("fps", String(options.fps));
1166
1303
  if (options.width !== void 0) params.set("width", String(options.width));
1167
1304
  if (options.quality !== void 0) params.set("quality", String(options.quality));
1305
+ if (options.maxSizeMb !== void 0) params.set("max_size_mb", String(options.maxSizeMb));
1168
1306
  const url = `${apiUrl}/recordings/${recordingId}/webp${params.toString() ? "?" + params.toString() : ""}`;
1169
1307
  if (debug) console.log(`[Browser] getWebp: ${url}`);
1170
1308
  const response = await fetch(url, {
@@ -1176,8 +1314,8 @@ async function getWebp(recordingId, config = {}, options = {}) {
1176
1314
  if (debug) console.error(`[Browser] getWebp error: ${response.status} - ${errorText}`);
1177
1315
  throw new Error(`HTTP ${response.status}: ${errorText}`);
1178
1316
  }
1179
- const result = await response.json();
1180
- if (debug) console.log(`[Browser] WebP ready: ${result.webp_url} (cached: ${result.cached})`);
1317
+ const result = mapWebpResponse(await response.json());
1318
+ if (debug) console.log(`[Browser] WebP ready: ${result.webpUrl} (cached: ${result.cached})`);
1181
1319
  return result;
1182
1320
  }
1183
1321
  async function checkHealth(config = {}) {