Update Copy to cURL buttons to reference the new Runs API spec (#3765)
Co-authored-by: Shuchang Zheng <wintonzheng0325@gmail.com>
This commit is contained in:
@@ -43,6 +43,19 @@ try {
|
||||
newWssBaseUrl = wssBaseUrl.replace("/api", "");
|
||||
}
|
||||
|
||||
// Base URL for the Runs API (strip a leading `/api` segment: /api/v1 -> /v1)
|
||||
const runsApiBaseUrl = (() => {
|
||||
try {
|
||||
const url = new URL(apiBaseUrl);
|
||||
if (url.pathname.startsWith("/api")) {
|
||||
url.pathname = url.pathname.replace(/^\/api/, "");
|
||||
}
|
||||
return `${url.origin}${url.pathname}`;
|
||||
} catch (e) {
|
||||
return apiBaseUrl.replace("/api", "");
|
||||
}
|
||||
})();
|
||||
|
||||
let runtimeApiKey: string | null | undefined;
|
||||
|
||||
function readPersistedApiKey(): string | null {
|
||||
@@ -83,6 +96,7 @@ function clearRuntimeApiKey(): void {
|
||||
|
||||
export {
|
||||
apiBaseUrl,
|
||||
runsApiBaseUrl,
|
||||
environment,
|
||||
artifactApiBaseUrl,
|
||||
apiPathPrefix,
|
||||
|
||||
74
skyvern-frontend/src/util/taskRunPayload.test.ts
Normal file
74
skyvern-frontend/src/util/taskRunPayload.test.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { CreateTaskRequest } from "../api/types";
|
||||
import { buildTaskRunPayload } from "./taskRunPayload";
|
||||
|
||||
describe("buildTaskRunPayload", () => {
|
||||
it("maps v1 task fields into the Runs API payload shape", () => {
|
||||
const request: CreateTaskRequest = {
|
||||
title: " Test Task ",
|
||||
url: " https://example.com/task ",
|
||||
navigation_goal: "Navigate somewhere",
|
||||
data_extraction_goal: "Collect some data",
|
||||
webhook_callback_url: " https://callback.example.com ",
|
||||
proxy_location: "RESIDENTIAL",
|
||||
extracted_information_schema: { foo: "bar" },
|
||||
error_code_mapping: { ERR42: "Meaningful message" },
|
||||
extra_http_headers: { "X-Trace-Id": "abc123" },
|
||||
totp_identifier: " identifier ",
|
||||
browser_address: " chrome:1234 ",
|
||||
include_action_history_in_verification: true,
|
||||
max_screenshot_scrolls: 7,
|
||||
};
|
||||
|
||||
const payload = buildTaskRunPayload(request);
|
||||
|
||||
expect(payload).toEqual({
|
||||
prompt: "Navigate somewhere\n\nCollect some data",
|
||||
url: "https://example.com/task",
|
||||
proxy_location: "RESIDENTIAL",
|
||||
data_extraction_schema: { foo: "bar" },
|
||||
error_code_mapping: { ERR42: "Meaningful message" },
|
||||
extra_http_headers: { "X-Trace-Id": "abc123" },
|
||||
webhook_url: "https://callback.example.com",
|
||||
totp_identifier: "identifier",
|
||||
browser_address: "chrome:1234",
|
||||
include_action_history_in_verification: true,
|
||||
max_screenshot_scrolls: 7,
|
||||
title: "Test Task",
|
||||
});
|
||||
});
|
||||
|
||||
it("applies prompt fallbacks and drops invalid optional objects", () => {
|
||||
const request: CreateTaskRequest = {
|
||||
title: " ",
|
||||
url: " https://fallback.example.com ",
|
||||
navigation_goal: "",
|
||||
data_extraction_goal: null,
|
||||
webhook_callback_url: " ",
|
||||
proxy_location: null,
|
||||
extracted_information_schema: null,
|
||||
extra_http_headers: "not an object" as unknown as Record<string, string>,
|
||||
error_code_mapping: [] as unknown as Record<string, string>,
|
||||
totp_identifier: null,
|
||||
browser_address: " ",
|
||||
include_action_history_in_verification: null,
|
||||
};
|
||||
|
||||
const payload = buildTaskRunPayload(request);
|
||||
|
||||
expect(payload).toEqual({
|
||||
prompt: "https://fallback.example.com",
|
||||
url: "https://fallback.example.com",
|
||||
proxy_location: null,
|
||||
data_extraction_schema: null,
|
||||
webhook_url: undefined,
|
||||
totp_identifier: undefined,
|
||||
browser_address: undefined,
|
||||
include_action_history_in_verification: null,
|
||||
max_screenshot_scrolls: undefined,
|
||||
title: undefined,
|
||||
extra_http_headers: undefined,
|
||||
error_code_mapping: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
79
skyvern-frontend/src/util/taskRunPayload.ts
Normal file
79
skyvern-frontend/src/util/taskRunPayload.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { CreateTaskRequest, ProxyLocation } from "@/api/types";
|
||||
|
||||
type TaskRunPayload = {
|
||||
prompt: string;
|
||||
url?: string | null;
|
||||
proxy_location?: ProxyLocation | null;
|
||||
data_extraction_schema?: CreateTaskRequest["extracted_information_schema"];
|
||||
error_code_mapping?: Record<string, string> | null;
|
||||
extra_http_headers?: Record<string, string> | null;
|
||||
webhook_url?: string | null;
|
||||
totp_identifier?: string | null;
|
||||
browser_address?: string | null;
|
||||
include_action_history_in_verification?: boolean | null;
|
||||
max_screenshot_scrolls?: number | null;
|
||||
title?: string | null;
|
||||
};
|
||||
|
||||
// Helper to trim and check for empty strings
|
||||
const trim = (s: string | null | undefined): string | undefined => {
|
||||
const t = s?.trim();
|
||||
return t && t.length > 0 ? t : undefined;
|
||||
};
|
||||
|
||||
// Build prompt from navigation_goal + data_extraction_goal
|
||||
function buildPrompt(request: CreateTaskRequest): string {
|
||||
const nav = trim(request.navigation_goal);
|
||||
const extract = trim(request.data_extraction_goal);
|
||||
|
||||
const parts = [nav, extract].filter(Boolean);
|
||||
if (parts.length > 0) return parts.join("\n\n");
|
||||
|
||||
// Fallback chain: try title, then goals again, then url, then default
|
||||
return (
|
||||
trim(request.title) ??
|
||||
nav ??
|
||||
extract ??
|
||||
trim(request.url) ??
|
||||
"Task run triggered from Skyvern UI"
|
||||
);
|
||||
}
|
||||
|
||||
function isValidRecord(val: unknown): val is Record<string, string> {
|
||||
return val != null && typeof val === "object" && !Array.isArray(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a CreateTaskRequest (old schema) to TaskRunPayload (Runs API v2 schema).
|
||||
*
|
||||
* Key transformations:
|
||||
* - navigation_goal + data_extraction_goal → prompt (combined)
|
||||
* - extracted_information_schema → data_extraction_schema
|
||||
* - webhook_callback_url → webhook_url
|
||||
*
|
||||
* Note: max_steps is optional and can be added manually to the cURL if needed.
|
||||
*/
|
||||
function buildTaskRunPayload(request: CreateTaskRequest): TaskRunPayload {
|
||||
return {
|
||||
prompt: buildPrompt(request),
|
||||
url: trim(request.url) ?? null,
|
||||
proxy_location: request.proxy_location ?? null,
|
||||
data_extraction_schema: request.extracted_information_schema,
|
||||
webhook_url: trim(request.webhook_callback_url),
|
||||
totp_identifier: trim(request.totp_identifier),
|
||||
browser_address: trim(request.browser_address),
|
||||
include_action_history_in_verification:
|
||||
request.include_action_history_in_verification,
|
||||
max_screenshot_scrolls: request.max_screenshot_scrolls,
|
||||
title: trim(request.title),
|
||||
extra_http_headers: isValidRecord(request.extra_http_headers)
|
||||
? request.extra_http_headers
|
||||
: undefined,
|
||||
error_code_mapping: isValidRecord(request.error_code_mapping)
|
||||
? request.error_code_mapping
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export type { TaskRunPayload };
|
||||
export { buildTaskRunPayload };
|
||||
Reference in New Issue
Block a user