Add advanced settings in prompt box (#1655)

This commit is contained in:
Shuchang Zheng
2025-01-27 21:47:09 +08:00
committed by GitHub
parent 16ff41f999
commit 7f2413e06d
2 changed files with 134 additions and 63 deletions

View File

@@ -257,3 +257,9 @@ export type ObserverTask = {
output: Record<string, unknown> | null; output: Record<string, unknown> | null;
summary: string | null; summary: string | null;
}; };
export type Createv2TaskRequest = {
user_prompt: string;
webhook_callback_url?: string | null;
proxy_location?: ProxyLocation | null;
};

View File

@@ -1,5 +1,10 @@
import { getClient } from "@/api/AxiosClient"; import { getClient } from "@/api/AxiosClient";
import { ObserverTask, TaskGenerationApiResponse } from "@/api/types"; import {
Createv2TaskRequest,
ObserverTask,
ProxyLocation,
TaskGenerationApiResponse,
} from "@/api/types";
import img from "@/assets/promptBoxBg.png"; import img from "@/assets/promptBoxBg.png";
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea"; import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import { CartIcon } from "@/components/icons/CartIcon"; import { CartIcon } from "@/components/icons/CartIcon";
@@ -37,6 +42,8 @@ import {
generateUniqueEmail, generateUniqueEmail,
} from "../data/sampleTaskData"; } from "../data/sampleTaskData";
import { ExampleCasePill } from "./ExampleCasePill"; import { ExampleCasePill } from "./ExampleCasePill";
import { Input } from "@/components/ui/input";
import { ProxySelector } from "@/components/ProxySelector";
function createTemplateTaskFromTaskGenerationParameters( function createTemplateTaskFromTaskGenerationParameters(
values: TaskGenerationApiResponse, values: TaskGenerationApiResponse,
@@ -137,13 +144,24 @@ function PromptBox() {
const [selectValue, setSelectValue] = useState<"v1" | "v2">("v2"); // Observer is the default const [selectValue, setSelectValue] = useState<"v1" | "v2">("v2"); // Observer is the default
const credentialGetter = useCredentialGetter(); const credentialGetter = useCredentialGetter();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [webhookCallbackUrl, setWebhookCallbackUrl] = useState<string | null>(
null,
);
const [proxyLocation, setProxyLocation] = useState<ProxyLocation>(
ProxyLocation.Residential,
);
const [showAdvancedSettings, setShowAdvancedSettings] = useState(false);
const startObserverCruiseMutation = useMutation({ const startObserverCruiseMutation = useMutation({
mutationFn: async (prompt: string) => { mutationFn: async (prompt: string) => {
const client = await getClient(credentialGetter, "v2"); const client = await getClient(credentialGetter, "v2");
return client.post<{ user_prompt: string }, { data: ObserverTask }>( return client.post<Createv2TaskRequest, { data: ObserverTask }>(
"/tasks", "/tasks",
{ user_prompt: prompt }, {
user_prompt: prompt,
webhook_callback_url: webhookCallbackUrl,
proxy_location: proxyLocation,
},
); );
}, },
onSuccess: (response) => { onSuccess: (response) => {
@@ -190,10 +208,11 @@ function PromptBox() {
.then((response) => response.data); .then((response) => response.data);
}, },
onError: (error: AxiosError) => { onError: (error: AxiosError) => {
const detail = (error.response?.data as { detail?: string })?.detail;
toast({ toast({
variant: "destructive", variant: "destructive",
title: "Error creating task from prompt", title: "Error creating task from prompt",
description: error.message, description: detail ? detail : error.message,
}); });
}, },
}); });
@@ -236,70 +255,116 @@ function PromptBox() {
<span className="text-2xl"> <span className="text-2xl">
What task would you like to accomplish? What task would you like to accomplish?
</span> </span>
<div className="flex w-full max-w-xl items-center rounded-xl bg-slate-700 py-2 pr-4 lg:w-3/4"> <div className="flex w-full max-w-xl flex-col">
<AutoResizingTextarea <div className="flex w-full items-center gap-2 rounded-xl bg-slate-700 py-2 pr-4">
className="min-h-0 resize-none rounded-xl border-transparent px-4 hover:border-transparent focus-visible:ring-0" <AutoResizingTextarea
value={prompt} className="min-h-0 resize-none rounded-xl border-transparent px-4 hover:border-transparent focus-visible:ring-0"
onChange={(e) => setPrompt(e.target.value)} value={prompt}
placeholder="Enter your prompt..." onChange={(e) => setPrompt(e.target.value)}
/> placeholder="Enter your prompt..."
<Select />
value={selectValue} <Select
onValueChange={(value: "v1" | "v2") => { value={selectValue}
setSelectValue(value); onValueChange={(value: "v1" | "v2") => {
}} setSelectValue(value);
> }}
<SelectTrigger className="w-48 focus:ring-0"> >
<SelectValue /> <SelectTrigger className="w-48 focus:ring-0">
</SelectTrigger> <SelectValue />
<SelectContent className="border-slate-500 bg-slate-elevation3"> </SelectTrigger>
<CustomSelectItem value="v1"> <SelectContent className="border-slate-500 bg-slate-elevation3">
<div className="space-y-2"> <CustomSelectItem value="v1">
<div> <div className="space-y-2">
<SelectItemText>Skyvern 1.0</SelectItemText> <div>
<SelectItemText>Skyvern 1.0</SelectItemText>
</div>
<div className="text-xs text-slate-400">
Best for simple tasks
</div>
</div> </div>
<div className="text-xs text-slate-400"> </CustomSelectItem>
Best for simple tasks <CustomSelectItem value="v2" className="hover:bg-slate-800">
<div className="space-y-2">
<div>
<SelectItemText>Skyvern 2.0</SelectItemText>
</div>
<div className="text-xs text-slate-400">
Best for complex tasks
</div>
</div> </div>
</div> </CustomSelectItem>
</CustomSelectItem> </SelectContent>
<CustomSelectItem value="v2" className="hover:bg-slate-800"> </Select>
<div className="space-y-2"> <div className="flex items-center">
<div> <GearIcon
<SelectItemText>Skyvern 2.0</SelectItemText> className="size-6 cursor-pointer"
</div> onClick={() => {
<div className="text-xs text-slate-400"> setShowAdvancedSettings((value) => !value);
Best for complex tasks
</div>
</div>
</CustomSelectItem>
</SelectContent>
</Select>
<div className="flex items-center">
{startObserverCruiseMutation.isPending ||
getTaskFromPromptMutation.isPending ||
saveTaskMutation.isPending ? (
<ReloadIcon className="h-6 w-6 animate-spin" />
) : (
<PaperPlaneIcon
className="h-6 w-6 cursor-pointer"
onClick={async () => {
if (selectValue === "v2") {
startObserverCruiseMutation.mutate(prompt);
return;
}
const taskGenerationResponse =
await getTaskFromPromptMutation.mutateAsync(prompt);
await saveTaskMutation.mutateAsync(taskGenerationResponse);
navigate("/tasks/create/from-prompt", {
state: {
data: taskGenerationResponse,
},
});
}} }}
/> />
)} </div>
<div className="flex items-center">
{startObserverCruiseMutation.isPending ||
getTaskFromPromptMutation.isPending ||
saveTaskMutation.isPending ? (
<ReloadIcon className="size-6 animate-spin" />
) : (
<PaperPlaneIcon
className="size-6 cursor-pointer"
onClick={async () => {
if (selectValue === "v2") {
startObserverCruiseMutation.mutate(prompt);
return;
}
const taskGenerationResponse =
await getTaskFromPromptMutation.mutateAsync(prompt);
await saveTaskMutation.mutateAsync(
taskGenerationResponse,
);
navigate("/tasks/create/from-prompt", {
state: {
data: taskGenerationResponse,
},
});
}}
/>
)}
</div>
</div> </div>
{showAdvancedSettings ? (
<div className="rounded-b-lg px-2">
<div className="space-y-4 rounded-b-xl bg-slate-900 p-4">
<header>Advanced Settings</header>
<div className="flex gap-16">
<div className="w-96">
<div className="text-sm">Webhook Callback URL</div>
<div className="text-xs text-slate-400">
The URL of a webhook endpoint to send the extracted
information
</div>
</div>
<Input
value={webhookCallbackUrl ?? ""}
onChange={(event) => {
setWebhookCallbackUrl(event.target.value);
}}
/>
</div>
<div className="flex gap-16">
<div className="w-96">
<div className="text-sm">Proxy Location</div>
<div className="text-xs text-slate-400">
Route Skyvern through one of our available proxies.
</div>
</div>
<ProxySelector
value={proxyLocation}
onChange={setProxyLocation}
/>
</div>
</div>
</div>
) : null}
</div> </div>
</div> </div>
</div> </div>