various hitl buffs (#3828)

This commit is contained in:
Jonathan Dobson
2025-10-27 16:14:52 -04:00
committed by GitHub
parent 4bb9a650cc
commit c12c047768
5 changed files with 171 additions and 157 deletions

View File

@@ -4,16 +4,26 @@ import { Button } from "@/components/ui/button";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
import { cn } from "@/util/utils";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { toast } from "@/components/ui/use-toast";
import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery";
import { HumanInteractionBlock } from "../types/workflowTypes";
import { WorkflowRunBlock } from "../types/workflowRunTypes";
interface Props {
humanInteractionBlock: HumanInteractionBlock;
workflowRunBlock: WorkflowRunBlock;
}
export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
export function WorkflowRunHumanInteraction({ workflowRunBlock }: Props) {
const credentialGetter = useCredentialGetter();
const queryClient = useQueryClient();
const { data: workflowRun } = useWorkflowRunQuery();
@@ -21,11 +31,14 @@ export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
workflowRun && workflowRun.status === WorkflowRunStatus.Paused;
const buttonLayout =
humanInteractionBlock.positive_descriptor.length < 8 &&
humanInteractionBlock.negative_descriptor.length < 8
(workflowRunBlock.positive_descriptor?.length ?? 0) < 8 &&
(workflowRunBlock.negative_descriptor?.length ?? 0) < 8
? "inline"
: "stacked";
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [choice, setChoice] = useState<"approve" | "reject" | null>(null);
const approveMutation = useMutation({
mutationFn: async () => {
if (!workflowRun) {
@@ -45,8 +58,8 @@ export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
toast({
variant: "success",
title: `${humanInteractionBlock.positive_descriptor}`,
description: `Successfully chose: ${humanInteractionBlock.positive_descriptor}`,
title: `${workflowRunBlock.positive_descriptor}`,
description: `Successfully chose: ${workflowRunBlock.positive_descriptor}`,
});
},
onError: (error) => {
@@ -77,8 +90,8 @@ export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
toast({
variant: "success",
title: `${humanInteractionBlock.negative_descriptor}`,
description: `Successfully chose: ${humanInteractionBlock.negative_descriptor}`,
title: `${workflowRunBlock.negative_descriptor}`,
description: `Successfully chose: ${workflowRunBlock.negative_descriptor}`,
});
},
onError: (error) => {
@@ -96,18 +109,60 @@ export function WorkflowRunHumanInteraction({ humanInteractionBlock }: Props) {
return (
<div className="mt-4 flex flex-col gap-4 rounded-md bg-slate-elevation4 p-4">
<div className="text-sm">{humanInteractionBlock.instructions}</div>
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>
{choice === "approve"
? workflowRunBlock.positive_descriptor
: workflowRunBlock.negative_descriptor}
</DialogTitle>
<DialogDescription>Are you sure?</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Back</Button>
</DialogClose>
<Button
variant={choice === "reject" ? "destructive" : "default"}
onClick={() => {
if (choice === "approve") {
approveMutation.mutate();
} else if (choice === "reject") {
rejectMutation.mutate();
}
}}
>
Proceed
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<div className="text-sm">{workflowRunBlock.instructions}</div>
<div
className={cn("flex gap-2", {
"justify-between": buttonLayout === "inline",
"flex-col": buttonLayout === "stacked",
})}
>
<Button variant="destructive" onClick={() => rejectMutation.mutate()}>
<div>{humanInteractionBlock.negative_descriptor}</div>
<Button
variant="destructive"
onClick={() => {
setChoice("reject");
setIsDialogOpen(true);
}}
>
<div>{workflowRunBlock.negative_descriptor}</div>
</Button>
<Button variant="default" onClick={() => approveMutation.mutate()}>
<div>{humanInteractionBlock.positive_descriptor}</div>
<Button
variant="default"
onClick={() => {
setChoice("approve");
setIsDialogOpen(true);
}}
>
<div>{workflowRunBlock.positive_descriptor}</div>
</Button>
</div>
</div>

View File

@@ -5,7 +5,7 @@ import {
ExternalLinkIcon,
} from "@radix-ui/react-icons";
import { useCallback } from "react";
import { useParams, Link } from "react-router-dom";
import { Link } from "react-router-dom";
import { Status } from "@/api/types";
import { formatDuration, toDuration } from "@/routes/workflows/utils";
@@ -27,13 +27,8 @@ import {
WorkflowRunOverviewActiveElement,
} from "./WorkflowRunOverview";
import { ThoughtCard } from "./ThoughtCard";
import { useWorkflowQuery } from "../hooks/useWorkflowQuery";
import { ObserverThought } from "../types/workflowRunTypes";
import {
HumanInteractionBlock,
isTaskVariantBlock,
type WorkflowApiResponse,
} from "../types/workflowTypes";
import { isTaskVariantBlock } from "../types/workflowTypes";
import { WorkflowRunHumanInteraction } from "./WorkflowRunHumanInteraction";
type Props = {
@@ -45,28 +40,6 @@ type Props = {
onThoughtCardClick: (thought: ObserverThought) => void;
};
const getHumanInteractionBlock = (
block: WorkflowRunBlock,
workflow?: WorkflowApiResponse,
): HumanInteractionBlock | null => {
if (block.block_type !== "human_interaction") {
return null;
}
if (!workflow) {
return null;
}
const blocks = workflow.workflow_definition.blocks;
const candidate = blocks.find((b) => b.label === block.label);
if (!candidate || candidate.block_type !== "human_interaction") {
return null;
}
return candidate as HumanInteractionBlock;
};
function WorkflowRunTimelineBlockItem({
activeItem,
block,
@@ -75,12 +48,6 @@ function WorkflowRunTimelineBlockItem({
onActionClick,
onThoughtCardClick,
}: Props) {
const { workflowPermanentId } = useParams();
const { data: workflow } = useWorkflowQuery({
workflowPermanentId,
});
const humanInteractionBlock = getHumanInteractionBlock(block, workflow);
const actions = block.actions ?? [];
const hasActiveAction =
@@ -203,10 +170,8 @@ function WorkflowRunTimelineBlockItem({
) : null}
</div>
{humanInteractionBlock && (
<WorkflowRunHumanInteraction
humanInteractionBlock={humanInteractionBlock}
/>
{block.block_type === "human_interaction" && (
<WorkflowRunHumanInteraction workflowRunBlock={block} />
)}
{actions.map((action, index) => {