fix task v1 rerun shell command (#3893)
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
|||||||
CreateTaskRequest,
|
CreateTaskRequest,
|
||||||
OrganizationApiResponse,
|
OrganizationApiResponse,
|
||||||
ProxyLocation,
|
ProxyLocation,
|
||||||
|
RunEngine,
|
||||||
} from "@/api/types";
|
} from "@/api/types";
|
||||||
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
|
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -775,7 +776,10 @@ function CreateNewTaskForm({ initialValues }: Props) {
|
|||||||
return {
|
return {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `${runsApiBaseUrl}/run/tasks`,
|
url: `${runsApiBaseUrl}/run/tasks`,
|
||||||
body: buildTaskRunPayload(createTaskRequestObject(formValues)),
|
body: buildTaskRunPayload(
|
||||||
|
createTaskRequestObject(formValues),
|
||||||
|
RunEngine.SkyvernV1,
|
||||||
|
),
|
||||||
headers,
|
headers,
|
||||||
} satisfies ApiCommandOptions;
|
} satisfies ApiCommandOptions;
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
CreateTaskRequest,
|
CreateTaskRequest,
|
||||||
OrganizationApiResponse,
|
OrganizationApiResponse,
|
||||||
ProxyLocation,
|
ProxyLocation,
|
||||||
|
RunEngine,
|
||||||
} from "@/api/types";
|
} from "@/api/types";
|
||||||
import { ProxySelector } from "@/components/ProxySelector";
|
import { ProxySelector } from "@/components/ProxySelector";
|
||||||
import { TestWebhookDialog } from "@/components/TestWebhookDialog";
|
import { TestWebhookDialog } from "@/components/TestWebhookDialog";
|
||||||
@@ -786,7 +787,10 @@ function SavedTaskForm({ initialValues }: Props) {
|
|||||||
return {
|
return {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `${runsApiBaseUrl}/run/tasks`,
|
url: `${runsApiBaseUrl}/run/tasks`,
|
||||||
body: buildTaskRunPayload(createTaskRequestObject(formValues)),
|
body: buildTaskRunPayload(
|
||||||
|
createTaskRequestObject(formValues),
|
||||||
|
RunEngine.SkyvernV1,
|
||||||
|
),
|
||||||
headers,
|
headers,
|
||||||
} satisfies ApiCommandOptions;
|
} satisfies ApiCommandOptions;
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { getClient } from "@/api/AxiosClient";
|
import { getClient } from "@/api/AxiosClient";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
|
RunEngine,
|
||||||
Status,
|
Status,
|
||||||
TaskApiResponse,
|
TaskApiResponse,
|
||||||
WorkflowRunStatusApiResponse,
|
WorkflowRunStatusApiResponse,
|
||||||
@@ -227,7 +228,10 @@ function TaskDetails() {
|
|||||||
return {
|
return {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `${runsApiBaseUrl}/run/tasks`,
|
url: `${runsApiBaseUrl}/run/tasks`,
|
||||||
body: buildTaskRunPayload(createTaskRequestObject(task)),
|
body: buildTaskRunPayload(
|
||||||
|
createTaskRequestObject(task),
|
||||||
|
RunEngine.SkyvernV1,
|
||||||
|
),
|
||||||
headers,
|
headers,
|
||||||
} satisfies ApiCommandOptions;
|
} satisfies ApiCommandOptions;
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ describe("buildTaskRunPayload", () => {
|
|||||||
url: " https://example.com/task ",
|
url: " https://example.com/task ",
|
||||||
navigation_goal: "Navigate somewhere",
|
navigation_goal: "Navigate somewhere",
|
||||||
data_extraction_goal: "Collect some data",
|
data_extraction_goal: "Collect some data",
|
||||||
|
navigation_payload: { name: "John", age: 30 },
|
||||||
webhook_callback_url: " https://callback.example.com ",
|
webhook_callback_url: " https://callback.example.com ",
|
||||||
proxy_location: "RESIDENTIAL",
|
proxy_location: "RESIDENTIAL",
|
||||||
extracted_information_schema: { foo: "bar" },
|
extracted_information_schema: { foo: "bar" },
|
||||||
@@ -23,7 +24,8 @@ describe("buildTaskRunPayload", () => {
|
|||||||
const payload = buildTaskRunPayload(request);
|
const payload = buildTaskRunPayload(request);
|
||||||
|
|
||||||
expect(payload).toEqual({
|
expect(payload).toEqual({
|
||||||
prompt: "Navigate somewhere\n\nCollect some data",
|
prompt:
|
||||||
|
'Navigate somewhere\n\nCollect some data\n\n{"name":"John","age":30}',
|
||||||
url: "https://example.com/task",
|
url: "https://example.com/task",
|
||||||
proxy_location: "RESIDENTIAL",
|
proxy_location: "RESIDENTIAL",
|
||||||
data_extraction_schema: { foo: "bar" },
|
data_extraction_schema: { foo: "bar" },
|
||||||
@@ -44,6 +46,7 @@ describe("buildTaskRunPayload", () => {
|
|||||||
url: " https://fallback.example.com ",
|
url: " https://fallback.example.com ",
|
||||||
navigation_goal: "",
|
navigation_goal: "",
|
||||||
data_extraction_goal: null,
|
data_extraction_goal: null,
|
||||||
|
navigation_payload: null,
|
||||||
webhook_callback_url: " ",
|
webhook_callback_url: " ",
|
||||||
proxy_location: null,
|
proxy_location: null,
|
||||||
extracted_information_schema: null,
|
extracted_information_schema: null,
|
||||||
@@ -71,4 +74,30 @@ describe("buildTaskRunPayload", () => {
|
|||||||
error_code_mapping: undefined,
|
error_code_mapping: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("includes navigation_payload as string in prompt", () => {
|
||||||
|
const request: CreateTaskRequest = {
|
||||||
|
url: "https://example.com",
|
||||||
|
navigation_goal: "Fill form",
|
||||||
|
navigation_payload: '{"email": "test@example.com"}',
|
||||||
|
};
|
||||||
|
|
||||||
|
const payload = buildTaskRunPayload(request);
|
||||||
|
|
||||||
|
expect(payload.prompt).toBe('Fill form\n\n{"email": "test@example.com"}');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats navigation_payload object as JSON in prompt", () => {
|
||||||
|
const request: CreateTaskRequest = {
|
||||||
|
url: "https://example.com",
|
||||||
|
navigation_goal: "Fill form",
|
||||||
|
navigation_payload: { email: "test@example.com", name: "Test" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const payload = buildTaskRunPayload(request);
|
||||||
|
|
||||||
|
expect(payload.prompt).toBe(
|
||||||
|
'Fill form\n\n{"email":"test@example.com","name":"Test"}',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { CreateTaskRequest, ProxyLocation } from "@/api/types";
|
import type { CreateTaskRequest, ProxyLocation, RunEngine } from "@/api/types";
|
||||||
|
|
||||||
type TaskRunPayload = {
|
type TaskRunPayload = {
|
||||||
prompt: string;
|
prompt: string;
|
||||||
@@ -13,6 +13,7 @@ type TaskRunPayload = {
|
|||||||
include_action_history_in_verification?: boolean | null;
|
include_action_history_in_verification?: boolean | null;
|
||||||
max_screenshot_scrolls?: number | null;
|
max_screenshot_scrolls?: number | null;
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
|
engine?: RunEngine | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper to trim and check for empty strings
|
// Helper to trim and check for empty strings
|
||||||
@@ -21,12 +22,33 @@ const trim = (s: string | null | undefined): string | undefined => {
|
|||||||
return t && t.length > 0 ? t : undefined;
|
return t && t.length > 0 ? t : undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build prompt from navigation_goal + data_extraction_goal
|
// Helper to format navigation_payload as a string
|
||||||
|
function formatNavigationPayload(
|
||||||
|
payload: Record<string, unknown> | string | null | undefined,
|
||||||
|
): string | undefined {
|
||||||
|
if (payload == null) return undefined;
|
||||||
|
if (typeof payload === "string") {
|
||||||
|
const trimmed = payload.trim();
|
||||||
|
return trimmed.length > 0 ? trimmed : undefined;
|
||||||
|
}
|
||||||
|
if (typeof payload === "object" && !Array.isArray(payload)) {
|
||||||
|
try {
|
||||||
|
const jsonStr = JSON.stringify(payload);
|
||||||
|
return jsonStr.length > 0 ? jsonStr : undefined;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build prompt from navigation_goal + data_extraction_goal + navigation_payload
|
||||||
function buildPrompt(request: CreateTaskRequest): string {
|
function buildPrompt(request: CreateTaskRequest): string {
|
||||||
const nav = trim(request.navigation_goal);
|
const nav = trim(request.navigation_goal);
|
||||||
const extract = trim(request.data_extraction_goal);
|
const extract = trim(request.data_extraction_goal);
|
||||||
|
const payload = formatNavigationPayload(request.navigation_payload);
|
||||||
|
|
||||||
const parts = [nav, extract].filter(Boolean);
|
const parts = [nav, extract, payload].filter(Boolean);
|
||||||
if (parts.length > 0) return parts.join("\n\n");
|
if (parts.length > 0) return parts.join("\n\n");
|
||||||
|
|
||||||
// Fallback chain: try title, then goals again, then url, then default
|
// Fallback chain: try title, then goals again, then url, then default
|
||||||
@@ -47,14 +69,17 @@ function isValidRecord(val: unknown): val is Record<string, string> {
|
|||||||
* Transforms a CreateTaskRequest (old schema) to TaskRunPayload (Runs API v2 schema).
|
* Transforms a CreateTaskRequest (old schema) to TaskRunPayload (Runs API v2 schema).
|
||||||
*
|
*
|
||||||
* Key transformations:
|
* Key transformations:
|
||||||
* - navigation_goal + data_extraction_goal → prompt (combined)
|
* - navigation_goal + data_extraction_goal + navigation_payload → prompt (combined)
|
||||||
* - extracted_information_schema → data_extraction_schema
|
* - extracted_information_schema → data_extraction_schema
|
||||||
* - webhook_callback_url → webhook_url
|
* - webhook_callback_url → webhook_url
|
||||||
*
|
*
|
||||||
* Note: max_steps is optional and can be added manually to the cURL if needed.
|
* Note: max_steps is optional and can be added manually to the cURL if needed.
|
||||||
*/
|
*/
|
||||||
function buildTaskRunPayload(request: CreateTaskRequest): TaskRunPayload {
|
function buildTaskRunPayload(
|
||||||
return {
|
request: CreateTaskRequest,
|
||||||
|
engine?: RunEngine | null,
|
||||||
|
): TaskRunPayload {
|
||||||
|
const payload: TaskRunPayload = {
|
||||||
prompt: buildPrompt(request),
|
prompt: buildPrompt(request),
|
||||||
url: trim(request.url) ?? null,
|
url: trim(request.url) ?? null,
|
||||||
proxy_location: request.proxy_location ?? null,
|
proxy_location: request.proxy_location ?? null,
|
||||||
@@ -73,6 +98,10 @@ function buildTaskRunPayload(request: CreateTaskRequest): TaskRunPayload {
|
|||||||
? request.error_code_mapping
|
? request.error_code_mapping
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
|
if (engine) {
|
||||||
|
payload.engine = engine;
|
||||||
|
}
|
||||||
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { TaskRunPayload };
|
export type { TaskRunPayload };
|
||||||
|
|||||||
Reference in New Issue
Block a user