Magic Wand Button to improve prompts in all blocks (#4060)
This commit is contained in:
@@ -20,3 +20,95 @@ export const BITWARDEN_CLIENT_SECRET_AWS_SECRET_KEY =
|
|||||||
"SKYVERN_BITWARDEN_CLIENT_SECRET";
|
"SKYVERN_BITWARDEN_CLIENT_SECRET";
|
||||||
export const BITWARDEN_MASTER_PASSWORD_AWS_SECRET_KEY =
|
export const BITWARDEN_MASTER_PASSWORD_AWS_SECRET_KEY =
|
||||||
"SKYVERN_BITWARDEN_MASTER_PASSWORD";
|
"SKYVERN_BITWARDEN_MASTER_PASSWORD";
|
||||||
|
|
||||||
|
type AiImproveConfig = {
|
||||||
|
useCase: string;
|
||||||
|
context: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createAiImproveConfig = (
|
||||||
|
block: string,
|
||||||
|
field: string,
|
||||||
|
extraContext: Record<string, unknown> = {},
|
||||||
|
): AiImproveConfig => ({
|
||||||
|
useCase: `workflow_editor.${block}.${field}`,
|
||||||
|
context: {
|
||||||
|
block_type: block,
|
||||||
|
field,
|
||||||
|
...extraContext,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const AI_IMPROVE_CONFIGS = {
|
||||||
|
task: {
|
||||||
|
navigationGoal: createAiImproveConfig("task", "navigation_goal"),
|
||||||
|
dataExtractionGoal: createAiImproveConfig("task", "data_extraction_goal"),
|
||||||
|
completeCriterion: createAiImproveConfig("task", "complete_criterion"),
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
navigationGoal: createAiImproveConfig("action", "navigation_goal"),
|
||||||
|
errorCodeMapping: createAiImproveConfig("action", "error_code_mapping"),
|
||||||
|
},
|
||||||
|
navigation: {
|
||||||
|
navigationGoal: createAiImproveConfig("navigation", "navigation_goal"),
|
||||||
|
completeCriterion: createAiImproveConfig(
|
||||||
|
"navigation",
|
||||||
|
"complete_criterion",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
extraction: {
|
||||||
|
dataExtractionGoal: createAiImproveConfig(
|
||||||
|
"extraction",
|
||||||
|
"data_extraction_goal",
|
||||||
|
),
|
||||||
|
dataSchema: createAiImproveConfig("extraction", "data_schema"),
|
||||||
|
},
|
||||||
|
validation: {
|
||||||
|
completeCriterion: createAiImproveConfig(
|
||||||
|
"validation",
|
||||||
|
"complete_criterion",
|
||||||
|
),
|
||||||
|
terminateCriterion: createAiImproveConfig(
|
||||||
|
"validation",
|
||||||
|
"terminate_criterion",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
login: {
|
||||||
|
navigationGoal: createAiImproveConfig("login", "navigation_goal"),
|
||||||
|
completeCriterion: createAiImproveConfig("login", "complete_criterion"),
|
||||||
|
terminateCriterion: createAiImproveConfig("login", "terminate_criterion"),
|
||||||
|
},
|
||||||
|
fileDownload: {
|
||||||
|
navigationGoal: createAiImproveConfig("file_download", "navigation_goal"),
|
||||||
|
completeCriterion: createAiImproveConfig(
|
||||||
|
"file_download",
|
||||||
|
"complete_criterion",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
taskV2: {
|
||||||
|
prompt: createAiImproveConfig("task_v2", "prompt"),
|
||||||
|
},
|
||||||
|
textPrompt: {
|
||||||
|
prompt: createAiImproveConfig("text_prompt", "prompt"),
|
||||||
|
jsonSchema: createAiImproveConfig("text_prompt", "json_schema"),
|
||||||
|
},
|
||||||
|
humanInteraction: {
|
||||||
|
instructions: createAiImproveConfig("human_interaction", "instructions"),
|
||||||
|
positiveDescriptor: createAiImproveConfig(
|
||||||
|
"human_interaction",
|
||||||
|
"positive_descriptor",
|
||||||
|
),
|
||||||
|
negativeDescriptor: createAiImproveConfig(
|
||||||
|
"human_interaction",
|
||||||
|
"negative_descriptor",
|
||||||
|
),
|
||||||
|
body: createAiImproveConfig("human_interaction", "body"),
|
||||||
|
},
|
||||||
|
sendEmail: {
|
||||||
|
subject: createAiImproveConfig("send_email", "subject"),
|
||||||
|
body: createAiImproveConfig("send_email", "body"),
|
||||||
|
},
|
||||||
|
httpRequest: {
|
||||||
|
body: createAiImproveConfig("http_request", "body"),
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { errorMappingExampleValue } from "../types";
|
|||||||
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
|
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { placeholders, helpTooltips } from "../../helpContent";
|
import { placeholders, helpTooltips } from "../../helpContent";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
import { WorkflowBlockInputTextarea } from "@/components/WorkflowBlockInputTextarea";
|
import { WorkflowBlockInputTextarea } from "@/components/WorkflowBlockInputTextarea";
|
||||||
import { useRerender } from "@/hooks/useRerender";
|
import { useRerender } from "@/hooks/useRerender";
|
||||||
import { BlockCodeEditor } from "@/routes/workflows/components/BlockCodeEditor";
|
import { BlockCodeEditor } from "@/routes/workflows/components/BlockCodeEditor";
|
||||||
@@ -139,10 +140,7 @@ function ActionNode({ id, data, type }: NodeProps<ActionNode>) {
|
|||||||
<HelpTooltip content={navigationGoalTooltip} />
|
<HelpTooltip content={navigationGoalTooltip} />
|
||||||
</div>
|
</div>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
aiImprove={{
|
aiImprove={AI_IMPROVE_CONFIGS.action.navigationGoal}
|
||||||
context: { block_type: "Action Block" },
|
|
||||||
useCase: "task_v1_prompt",
|
|
||||||
}}
|
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ navigationGoal: value });
|
update({ navigationGoal: value });
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
|||||||
import { useRerender } from "@/hooks/useRerender";
|
import { useRerender } from "@/hooks/useRerender";
|
||||||
|
|
||||||
import { DisableCache } from "../DisableCache";
|
import { DisableCache } from "../DisableCache";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
|
|
||||||
function ExtractionNode({ id, data, type }: NodeProps<ExtractionNode>) {
|
function ExtractionNode({ id, data, type }: NodeProps<ExtractionNode>) {
|
||||||
const [facing, setFacing] = useState<"front" | "back">("front");
|
const [facing, setFacing] = useState<"front" | "back">("front");
|
||||||
@@ -113,6 +114,7 @@ function ExtractionNode({ id, data, type }: NodeProps<ExtractionNode>) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.extraction.dataExtractionGoal}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
if (!editable) {
|
if (!editable) {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import { useRerender } from "@/hooks/useRerender";
|
|||||||
import { BROWSER_DOWNLOAD_TIMEOUT_SECONDS } from "@/api/types";
|
import { BROWSER_DOWNLOAD_TIMEOUT_SECONDS } from "@/api/types";
|
||||||
|
|
||||||
import { DisableCache } from "../DisableCache";
|
import { DisableCache } from "../DisableCache";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
|
|
||||||
const urlTooltip =
|
const urlTooltip =
|
||||||
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
|
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
|
||||||
@@ -132,6 +133,7 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
|
|||||||
<HelpTooltip content={navigationGoalTooltip} />
|
<HelpTooltip content={navigationGoalTooltip} />
|
||||||
</div>
|
</div>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.fileDownload.navigationGoal}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ navigationGoal: value });
|
update({ navigationGoal: value });
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
} from "@/components/ui/accordion";
|
} from "@/components/ui/accordion";
|
||||||
import { useRerender } from "@/hooks/useRerender";
|
import { useRerender } from "@/hooks/useRerender";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
|
|
||||||
const instructionsTooltip =
|
const instructionsTooltip =
|
||||||
"Instructions shown to the user for review. Explain what needs to be reviewed and what action should be taken.";
|
"Instructions shown to the user for review. Explain what needs to be reviewed and what action should be taken.";
|
||||||
@@ -169,6 +170,7 @@ function HumanInteractionNode({
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-xs text-slate-300">Body</Label>
|
<Label className="text-xs text-slate-300">Body</Label>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.humanInteraction.body}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ body: value });
|
update({ body: value });
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
|||||||
import { useRerender } from "@/hooks/useRerender";
|
import { useRerender } from "@/hooks/useRerender";
|
||||||
|
|
||||||
import { DisableCache } from "../DisableCache";
|
import { DisableCache } from "../DisableCache";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
|
|
||||||
function LoginNode({ id, data, type }: NodeProps<LoginNode>) {
|
function LoginNode({ id, data, type }: NodeProps<LoginNode>) {
|
||||||
const blockScriptStore = useBlockScriptStore();
|
const blockScriptStore = useBlockScriptStore();
|
||||||
@@ -127,6 +128,7 @@ function LoginNode({ id, data, type }: NodeProps<LoginNode>) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.login.navigationGoal}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ navigationGoal: value });
|
update({ navigationGoal: value });
|
||||||
@@ -187,6 +189,7 @@ function LoginNode({ id, data, type }: NodeProps<LoginNode>) {
|
|||||||
Complete if...
|
Complete if...
|
||||||
</Label>
|
</Label>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.login.completeCriterion}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ completeCriterion: value });
|
update({ completeCriterion: value });
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuer
|
|||||||
import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
||||||
|
|
||||||
import { DisableCache } from "../DisableCache";
|
import { DisableCache } from "../DisableCache";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
|
|
||||||
function NavigationNode({ id, data, type }: NodeProps<NavigationNode>) {
|
function NavigationNode({ id, data, type }: NodeProps<NavigationNode>) {
|
||||||
const { blockLabel: urlBlockLabel } = useParams();
|
const { blockLabel: urlBlockLabel } = useParams();
|
||||||
@@ -136,6 +137,7 @@ function NavigationNode({ id, data, type }: NodeProps<NavigationNode>) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.navigation.navigationGoal}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ navigationGoal: value });
|
update({ navigationGoal: value });
|
||||||
@@ -184,6 +186,9 @@ function NavigationNode({ id, data, type }: NodeProps<NavigationNode>) {
|
|||||||
Complete if...
|
Complete if...
|
||||||
</Label>
|
</Label>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={
|
||||||
|
AI_IMPROVE_CONFIGS.navigation.completeCriterion
|
||||||
|
}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ completeCriterion: value });
|
update({ completeCriterion: value });
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { useParams } from "react-router-dom";
|
|||||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||||
import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
|
|
||||||
function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
|
function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
|
||||||
const { editable, label } = data;
|
const { editable, label } = data;
|
||||||
@@ -94,6 +95,7 @@ function SendEmailNode({ id, data }: NodeProps<SendEmailNode>) {
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-xs text-slate-300">Body</Label>
|
<Label className="text-xs text-slate-300">Body</Label>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.sendEmail.body}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ body: value });
|
update({ body: value });
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { Handle, NodeProps, Position, useEdges, useNodes } from "@xyflow/react";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { AppNode } from "..";
|
import { AppNode } from "..";
|
||||||
import { helpTooltips, placeholders } from "../../helpContent";
|
import { helpTooltips, placeholders } from "../../helpContent";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
import { getAvailableOutputParameterKeys } from "../../workflowEditorUtils";
|
import { getAvailableOutputParameterKeys } from "../../workflowEditorUtils";
|
||||||
import { dataSchemaExampleValue, errorMappingExampleValue } from "../types";
|
import { dataSchemaExampleValue, errorMappingExampleValue } from "../types";
|
||||||
import { ParametersMultiSelect } from "./ParametersMultiSelect";
|
import { ParametersMultiSelect } from "./ParametersMultiSelect";
|
||||||
@@ -137,10 +138,7 @@ function TaskNode({ id, data, type }: NodeProps<TaskNode>) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
aiImprove={{
|
aiImprove={AI_IMPROVE_CONFIGS.task.navigationGoal}
|
||||||
context: { block_type: "Task Block" },
|
|
||||||
useCase: "task_v1_prompt",
|
|
||||||
}}
|
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ navigationGoal: value });
|
update({ navigationGoal: value });
|
||||||
@@ -176,6 +174,7 @@ function TaskNode({ id, data, type }: NodeProps<TaskNode>) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.task.dataExtractionGoal}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ dataExtractionGoal: value });
|
update({ dataExtractionGoal: value });
|
||||||
@@ -209,6 +208,7 @@ function TaskNode({ id, data, type }: NodeProps<TaskNode>) {
|
|||||||
Complete if...
|
Complete if...
|
||||||
</Label>
|
</Label>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.task.completeCriterion}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ completeCriterion: value });
|
update({ completeCriterion: value });
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { ModelSelector } from "@/components/ModelSelector";
|
|||||||
import { cn } from "@/util/utils";
|
import { cn } from "@/util/utils";
|
||||||
import { NodeHeader } from "../components/NodeHeader";
|
import { NodeHeader } from "../components/NodeHeader";
|
||||||
import { NodeTabs } from "../components/NodeTabs";
|
import { NodeTabs } from "../components/NodeTabs";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||||
@@ -107,7 +108,7 @@ function Taskv2Node({ id, data, type }: NodeProps<Taskv2Node>) {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
aiImprove={{ useCase: "task_v2_prompt" }}
|
aiImprove={AI_IMPROVE_CONFIGS.taskV2.prompt}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ prompt: value });
|
update({ prompt: value });
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { useParams } from "react-router-dom";
|
|||||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||||
import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
|
|
||||||
function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
|
function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
|
||||||
const { editable, label } = data;
|
const { editable, label } = data;
|
||||||
@@ -75,6 +76,7 @@ function TextPromptNode({ id, data }: NodeProps<TextPromptNode>) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.textPrompt.prompt}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ prompt: value });
|
update({ prompt: value });
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import { useUpdate } from "@/routes/workflows/editor/useUpdate";
|
|||||||
import { useRerender } from "@/hooks/useRerender";
|
import { useRerender } from "@/hooks/useRerender";
|
||||||
|
|
||||||
import { DisableCache } from "../DisableCache";
|
import { DisableCache } from "../DisableCache";
|
||||||
|
import { AI_IMPROVE_CONFIGS } from "../../constants";
|
||||||
|
|
||||||
function ValidationNode({ id, data, type }: NodeProps<ValidationNode>) {
|
function ValidationNode({ id, data, type }: NodeProps<ValidationNode>) {
|
||||||
const [facing, setFacing] = useState<"front" | "back">("front");
|
const [facing, setFacing] = useState<"front" | "back">("front");
|
||||||
@@ -114,6 +115,7 @@ function ValidationNode({ id, data, type }: NodeProps<ValidationNode>) {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.validation.completeCriterion}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ completeCriterion: value });
|
update({ completeCriterion: value });
|
||||||
@@ -125,6 +127,7 @@ function ValidationNode({ id, data, type }: NodeProps<ValidationNode>) {
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-xs text-slate-300">Terminate if...</Label>
|
<Label className="text-xs text-slate-300">Terminate if...</Label>
|
||||||
<WorkflowBlockInputTextarea
|
<WorkflowBlockInputTextarea
|
||||||
|
aiImprove={AI_IMPROVE_CONFIGS.validation.terminateCriterion}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
update({ terminateCriterion: value });
|
update({ terminateCriterion: value });
|
||||||
|
|||||||
Reference in New Issue
Block a user