Jon/sky 5906 debugger show actions inputs outputs for a block run (#3202)

This commit is contained in:
Jonathan Dobson
2025-08-15 07:25:04 -04:00
committed by GitHub
parent 654cdb14e4
commit 40d104c193
33 changed files with 898 additions and 121 deletions

View File

@@ -0,0 +1,67 @@
import { useEffect } from "react";
import { useParams } from "react-router-dom";
import { ReactFlowProvider } from "@xyflow/react";
import { useWorkflowQuery } from "../hooks/useWorkflowQuery";
import { WorkflowSettings } from "../types/workflowTypes";
import { getElements } from "@/routes/workflows/editor/workflowEditorUtils";
import { getInitialParameters } from "@/routes/workflows/editor/utils";
import { Workspace } from "@/routes/workflows/editor/Workspace";
import { useWorkflowParametersStore } from "@/store/WorkflowParametersStore";
function Debugger() {
const { workflowPermanentId } = useParams();
const { data: workflow } = useWorkflowQuery({
workflowPermanentId,
});
const setParameters = useWorkflowParametersStore(
(state) => state.setParameters,
);
useEffect(() => {
if (workflow) {
const initialParameters = getInitialParameters(workflow);
setParameters(initialParameters);
}
}, [workflow, setParameters]);
if (!workflow) {
return null;
}
const settings: WorkflowSettings = {
persistBrowserSession: workflow.persist_browser_session,
proxyLocation: workflow.proxy_location,
webhookCallbackUrl: workflow.webhook_callback_url,
model: workflow.model,
maxScreenshotScrolls: workflow.max_screenshot_scrolls,
extraHttpHeaders: workflow.extra_http_headers
? JSON.stringify(workflow.extra_http_headers)
: null,
useScriptCache: workflow.generate_script,
scriptCacheKey: workflow.cache_key,
};
const elements = getElements(
workflow.workflow_definition.blocks,
settings,
true,
);
return (
<div className="relative flex h-screen w-full">
<ReactFlowProvider>
<Workspace
initialEdges={elements.edges}
initialNodes={elements.nodes}
initialTitle={workflow.title}
showBrowser={true}
workflow={workflow}
/>
</ReactFlowProvider>
</div>
);
}
export { Debugger };

View File

@@ -0,0 +1,201 @@
import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery";
import { CodeEditor } from "../components/CodeEditor";
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import { useActiveWorkflowRunItem } from "@/routes/workflows/workflowRun/useActiveWorkflowRunItem";
import { useWorkflowRunTimelineQuery } from "../hooks/useWorkflowRunTimelineQuery";
import { isAction, isWorkflowRunBlock } from "../types/workflowRunTypes";
import { findBlockSurroundingAction } from "@/routes/workflows/workflowRun/workflowTimelineUtils";
import { DebuggerTaskBlockParameters } from "./DebuggerTaskBlockParameters";
import { isTaskVariantBlock, WorkflowBlockTypes } from "../types/workflowTypes";
import { Input } from "@/components/ui/input";
import { ProxySelector } from "@/components/ProxySelector";
import { DebuggerSendEmailBlockParameters } from "./DebuggerSendEmailBlockInfo";
import { ProxyLocation } from "@/api/types";
import { KeyValueInput } from "@/components/KeyValueInput";
import { HelpTooltip } from "@/components/HelpTooltip";
function DebuggerPostRunParameters() {
const { data: workflowRunTimeline, isLoading: workflowRunTimelineIsLoading } =
useWorkflowRunTimelineQuery();
const [activeItem] = useActiveWorkflowRunItem();
const { data: workflowRun, isLoading: workflowRunIsLoading } =
useWorkflowRunQuery();
const parameters = workflowRun?.parameters ?? {};
if (workflowRunIsLoading || workflowRunTimelineIsLoading) {
return <div>Loading workflow parameters...</div>;
}
if (!workflowRun || !workflowRunTimeline) {
return null;
}
function getActiveBlock() {
if (!workflowRunTimeline) {
return;
}
if (isWorkflowRunBlock(activeItem)) {
return activeItem;
}
if (isAction(activeItem)) {
return findBlockSurroundingAction(
workflowRunTimeline,
activeItem.action_id,
);
}
}
const activeBlock = getActiveBlock();
const isTaskV2 = workflowRun.task_v2 !== null;
const webhookCallbackUrl = isTaskV2
? workflowRun.task_v2?.webhook_callback_url
: workflowRun.webhook_callback_url;
const proxyLocation = isTaskV2
? workflowRun.task_v2?.proxy_location
: workflowRun.proxy_location;
const extraHttpHeaders = isTaskV2
? workflowRun.task_v2?.extra_http_headers
: workflowRun.extra_http_headers;
return (
<div className="space-y-5">
{activeBlock && isTaskVariantBlock(activeBlock) ? (
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Task Block Parameters</h1>
<DebuggerTaskBlockParameters block={activeBlock} />
</div>
</div>
) : null}
{activeBlock &&
activeBlock.block_type === WorkflowBlockTypes.SendEmail ? (
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Email Block Parameters</h1>
<DebuggerSendEmailBlockParameters
body={activeBlock?.body ?? ""}
recipients={activeBlock?.recipients ?? []}
subject={activeBlock?.subject ?? ""}
/>
</div>
</div>
) : null}
{activeBlock && activeBlock.block_type === WorkflowBlockTypes.ForLoop ? (
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">For Loop Block Parameters</h1>
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Loop Values</h1>
<HelpTooltip content="The values that are being looped over." />
</div>
<CodeEditor
className="w-full"
language="json"
value={JSON.stringify(activeBlock?.loop_values, null, 2)}
readOnly
minHeight="96px"
maxHeight="200px"
/>
</div>
</div>
</div>
) : null}
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Workflow Parameters</h1>
{Object.entries(parameters).map(([key, value]) => {
return (
<div key={key} className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">{key}</h1>
<HelpTooltip content="The value of the parameter." />
</div>
{typeof value === "string" ||
typeof value === "number" ||
typeof value === "boolean" ? (
<AutoResizingTextarea value={String(value)} readOnly />
) : (
<CodeEditor
value={JSON.stringify(value, null, 2)}
readOnly
language="json"
minHeight="96px"
maxHeight="200px"
className="w-full"
/>
)}
</div>
);
})}
{Object.entries(parameters).length === 0 ? (
<div className="text-sm">
No input parameters found for this workflow
</div>
) : null}
<h1 className="text-sm font-bold">Other Workflow Parameters</h1>
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Webhook Callback URL</h1>
<HelpTooltip content="The webhook callback URL for the workflow." />
</div>
<Input value={webhookCallbackUrl ?? ""} readOnly />
</div>
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Proxy Location</h1>
<HelpTooltip content="The proxy location for the workflow." />
</div>
<ProxySelector
value={proxyLocation ?? ProxyLocation.Residential}
onChange={() => {
// TODO
}}
/>
</div>
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Extra HTTP Headers</h1>
<HelpTooltip content="The extra HTTP headers for the workflow." />
</div>
<div className="w-full">
<KeyValueInput
value={
extraHttpHeaders ? JSON.stringify(extraHttpHeaders) : null
}
readOnly={true}
onChange={() => {}}
/>
</div>
</div>
</div>
</div>
{workflowRun.task_v2 ? (
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Task 2.0 Parameters</h1>
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Task 2.0 Prompt</h1>
<HelpTooltip content="The original prompt for the task." />
</div>
<AutoResizingTextarea
value={workflowRun.task_v2?.prompt ?? ""}
readOnly
/>
</div>
<AutoResizingTextarea
value={workflowRun.task_v2?.prompt ?? ""}
readOnly
/>
</div>
</div>
) : null}
</div>
);
}
export { DebuggerPostRunParameters };

View File

@@ -0,0 +1,35 @@
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
import { DebuggerRunTimeline } from "./DebuggerRunTimeline";
function DebuggerRun() {
const { data: workflowRun } = useWorkflowRunQuery();
const workflowFailureReason = workflowRun?.failure_reason ? (
<div
className="align-self-start max-h-[8rem] w-full overflow-y-auto rounded-md border border-red-600 p-4"
style={{
backgroundColor: "rgba(220, 38, 38, 0.10)",
width: "calc(100% - 2rem)",
}}
>
<div className="font-bold">Workflow Failure Reason</div>
<div className="text-sm">{workflowRun.failure_reason}</div>
</div>
) : null;
return (
<div className="flex h-full w-full flex-col items-center justify-start overflow-hidden overflow-y-auto">
{workflowFailureReason}
<div className="h-full w-full">
<DebuggerRunTimeline
activeItem="stream"
onActionItemSelected={() => {}}
onBlockItemSelected={() => {}}
onObserverThoughtCardSelected={() => {}}
/>
</div>
</div>
);
}
export { DebuggerRun };

View File

@@ -0,0 +1,175 @@
import { FileIcon } from "@radix-ui/react-icons";
import { CodeEditor } from "../components/CodeEditor";
import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery";
import { useActiveWorkflowRunItem } from "@/routes/workflows/workflowRun/useActiveWorkflowRunItem";
import {
hasExtractedInformation,
isAction,
isWorkflowRunBlock,
} from "../types/workflowRunTypes";
import { findBlockSurroundingAction } from "@/routes/workflows/workflowRun/workflowTimelineUtils";
import { useWorkflowRunTimelineQuery } from "../hooks/useWorkflowRunTimelineQuery";
import { Status } from "@/api/types";
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import { isTaskVariantBlock } from "../types/workflowTypes";
function DebuggerRunOutput() {
const { data: workflowRunTimeline, isLoading: workflowRunTimelineIsLoading } =
useWorkflowRunTimelineQuery();
const [activeItem] = useActiveWorkflowRunItem();
const { data: workflowRun } = useWorkflowRunQuery();
if (workflowRunTimelineIsLoading) {
return <div>Loading...</div>;
}
if (!workflowRunTimeline) {
return null;
}
function getActiveBlock() {
if (!workflowRunTimeline) {
return;
}
if (isWorkflowRunBlock(activeItem)) {
return activeItem;
}
if (isAction(activeItem)) {
return findBlockSurroundingAction(
workflowRunTimeline,
activeItem.action_id,
);
}
}
const activeBlock = getActiveBlock();
const showExtractedInformation =
activeBlock &&
isTaskVariantBlock(activeBlock) &&
activeBlock.status === Status.Completed;
const outputs = workflowRun?.outputs;
const fileUrls = workflowRun?.downloaded_file_urls ?? [];
const observerOutput = workflowRun?.task_v2?.output;
const webhookFailureReasonData =
workflowRun?.task_v2?.webhook_failure_reason ??
workflowRun?.webhook_failure_reason;
return (
<div className="space-y-5">
{webhookFailureReasonData ? (
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Webhook Failure Reason</h1>
<div className="space-y-2 text-yellow-600">
{webhookFailureReasonData}
</div>
</div>
</div>
) : null}
{activeBlock ? (
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Block Outputs</h1>
{activeBlock.output === null ? (
<div className="text-sm">This block has no outputs</div>
) : isTaskVariantBlock(activeBlock) ? (
<div className="space-y-2">
<h2 className="text-sm">
{showExtractedInformation
? "Extracted Information"
: "Failure Reason"}
</h2>
{showExtractedInformation ? (
<CodeEditor
language="json"
value={JSON.stringify(
(hasExtractedInformation(activeBlock.output) &&
activeBlock.output.extracted_information) ??
null,
null,
2,
)}
minHeight="96px"
maxHeight="200px"
readOnly
/>
) : (
<AutoResizingTextarea
value={
activeBlock.status === "canceled"
? "This block was cancelled"
: activeBlock.failure_reason ?? ""
}
readOnly
/>
)}
</div>
) : (
<div className="space-y-2">
<h2 className="text-sm">Output</h2>
<CodeEditor
language="json"
value={JSON.stringify(activeBlock.output, null, 2)}
minHeight="96px"
maxHeight="200px"
readOnly
/>
</div>
)}
</div>
</div>
) : null}
{observerOutput ? (
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Task 2.0 Output</h1>
<CodeEditor
language="json"
value={JSON.stringify(observerOutput, null, 2)}
readOnly
minHeight="96px"
maxHeight="200px"
/>
</div>
</div>
) : null}
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Workflow Run Outputs</h1>
<CodeEditor
language="json"
value={outputs ? JSON.stringify(outputs, null, 2) : ""}
readOnly
minHeight="96px"
maxHeight="200px"
/>
</div>
</div>
<div className="rounded bg-slate-elevation2 p-6">
<div className="space-y-4">
<h1 className="text-sm font-bold">Workflow Run Downloaded Files</h1>
<div className="space-y-2">
{fileUrls.length > 0 ? (
fileUrls.map((url, index) => {
return (
<div key={url} title={url} className="flex gap-2">
<FileIcon className="size-6" />
<a href={url} className="underline underline-offset-4">
<span>{`File ${index + 1}`}</span>
</a>
</div>
);
})
) : (
<div className="text-sm">No files downloaded</div>
)}
</div>
</div>
</div>
</div>
);
}
export { DebuggerRunOutput };

View File

@@ -0,0 +1,129 @@
import { ScrollArea, ScrollAreaViewport } from "@/components/ui/scroll-area";
import { Skeleton } from "@/components/ui/skeleton";
import { statusIsFinalized } from "@/routes/tasks/types";
import { useWorkflowRunQuery } from "../hooks/useWorkflowRunQuery";
import { useWorkflowRunTimelineQuery } from "../hooks/useWorkflowRunTimelineQuery";
import {
isBlockItem,
isObserverThought,
isTaskVariantBlockItem,
isThoughtItem,
ObserverThought,
WorkflowRunBlock,
} from "../types/workflowRunTypes";
import { ThoughtCard } from "@/routes/workflows/workflowRun/ThoughtCard";
import {
ActionItem,
WorkflowRunOverviewActiveElement,
} from "@/routes/workflows/workflowRun/WorkflowRunOverview";
import { WorkflowRunTimelineBlockItem } from "@/routes/workflows/workflowRun/WorkflowRunTimelineBlockItem";
type Props = {
activeItem: WorkflowRunOverviewActiveElement;
onObserverThoughtCardSelected: (item: ObserverThought) => void;
onActionItemSelected: (item: ActionItem) => void;
onBlockItemSelected: (item: WorkflowRunBlock) => void;
};
function DebuggerRunTimeline({
activeItem,
onObserverThoughtCardSelected,
onActionItemSelected,
onBlockItemSelected,
}: Props) {
const { data: workflowRun, isLoading: workflowRunIsLoading } =
useWorkflowRunQuery();
const { data: workflowRunTimeline, isLoading: workflowRunTimelineIsLoading } =
useWorkflowRunTimelineQuery();
if (workflowRunIsLoading || workflowRunTimelineIsLoading) {
return <Skeleton className="h-full w-full" />;
}
if (!workflowRun || !workflowRunTimeline) {
return (
<div className="flex h-full w-full flex-col items-center justify-center rounded-xl bg-[#020817] p-12">
<div className="flex h-full w-full flex-col items-center justify-center gap-4">
<div>
Hi! 👋 We're experimenting with a new feature called debugger.
</div>
<div>
This debugger allows you to see the state of your workflow in a live
browser.
</div>
<div>
You can run individual blocks, instead of the whole workflow.
</div>
<div>
To get started, press the play button on a block in your workflow.
</div>
</div>
</div>
);
}
const workflowRunIsFinalized = statusIsFinalized(workflowRun);
const numberOfActions = workflowRunTimeline.reduce((total, current) => {
if (isTaskVariantBlockItem(current)) {
return total + current.block!.actions!.length;
}
return total + 0;
}, 0);
return (
<div className="w-full min-w-0 space-y-4 rounded bg-slate-elevation1 p-4">
<div className="grid w-full grid-cols-2 gap-2">
<div className="flex items-center justify-center rounded bg-slate-elevation3 px-4 py-3 text-xs">
Actions: {numberOfActions}
</div>
<div className="flex items-center justify-center rounded bg-slate-elevation3 px-4 py-3 text-xs">
Steps: {workflowRun.total_steps ?? 0}
</div>
</div>
{!workflowRunIsFinalized && workflowRunTimeline.length === 0 && (
<Skeleton className="h-full w-full" />
)}
<ScrollArea>
<ScrollAreaViewport className="h-full w-full">
<div className="w-full space-y-4">
{workflowRunIsFinalized && workflowRunTimeline.length === 0 && (
<div>Workflow timeline is empty</div>
)}
{workflowRunTimeline?.map((timelineItem) => {
if (isBlockItem(timelineItem)) {
return (
<WorkflowRunTimelineBlockItem
key={timelineItem.block.workflow_run_block_id}
subItems={timelineItem.children}
activeItem={activeItem}
block={timelineItem.block}
onActionClick={onActionItemSelected}
onBlockItemClick={onBlockItemSelected}
onThoughtCardClick={onObserverThoughtCardSelected}
/>
);
}
if (isThoughtItem(timelineItem)) {
return (
<ThoughtCard
key={timelineItem.thought.thought_id}
active={
isObserverThought(activeItem) &&
activeItem.thought_id === timelineItem.thought.thought_id
}
onClick={onObserverThoughtCardSelected}
thought={timelineItem.thought}
/>
);
}
})}
</div>
</ScrollAreaViewport>
</ScrollArea>
</div>
);
}
export { DebuggerRunTimeline };

View File

@@ -0,0 +1,43 @@
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import { Input } from "@/components/ui/input";
import { HelpTooltip } from "@/components/HelpTooltip";
type Props = {
recipients: Array<string>;
body: string;
subject: string;
};
function DebuggerSendEmailBlockParameters({
recipients,
body,
subject,
}: Props) {
return (
<div className="space-y-4">
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">To</h1>
<HelpTooltip content="The recipients of the email." />
</div>
<Input value={recipients.join(", ")} readOnly />
</div>
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Subject</h1>
<HelpTooltip content="The subject of the email." />
</div>
<Input value={subject} readOnly />
</div>
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Body</h1>
<HelpTooltip content="The body of the email." />
</div>
<AutoResizingTextarea value={body} readOnly />
</div>
</div>
);
}
export { DebuggerSendEmailBlockParameters };

View File

@@ -0,0 +1,147 @@
import { AutoResizingTextarea } from "@/components/AutoResizingTextarea/AutoResizingTextarea";
import { Input } from "@/components/ui/input";
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
import { WorkflowRunBlock } from "../types/workflowRunTypes";
import { isTaskVariantBlock, WorkflowBlockTypes } from "../types/workflowTypes";
import { Switch } from "@/components/ui/switch";
import { HelpTooltip } from "@/components/HelpTooltip";
type Props = {
block: WorkflowRunBlock;
};
function DebuggerTaskBlockParameters({ block }: Props) {
const isTaskVariant = isTaskVariantBlock(block);
if (!isTaskVariant) {
return null;
}
const showNavigationParameters =
block.block_type === WorkflowBlockTypes.Task ||
block.block_type === WorkflowBlockTypes.Action ||
block.block_type === WorkflowBlockTypes.Login ||
block.block_type === WorkflowBlockTypes.Navigation;
const showDataExtractionParameters =
block.block_type === WorkflowBlockTypes.Task ||
block.block_type === WorkflowBlockTypes.Extraction;
const showValidationParameters =
block.block_type === WorkflowBlockTypes.Validation;
const showIncludeActionHistoryInVerification =
block.block_type === WorkflowBlockTypes.Task ||
block.block_type === WorkflowBlockTypes.Navigation;
return (
<>
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">URL</h1>
<HelpTooltip content="The starting URL for the block." />
</div>
<Input value={block.url ?? ""} readOnly />
</div>
{showNavigationParameters ? (
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Navigation Goal</h1>
<HelpTooltip content="What should Skyvern do on this page?" />
</div>
<AutoResizingTextarea value={block.navigation_goal ?? ""} readOnly />
</div>
) : null}
{showNavigationParameters ? (
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-nowrap text-sm">Navigation Payload</h1>
<HelpTooltip content="Specify important parameters, routes, or states." />
</div>
<CodeEditor
className="w-full"
language="json"
value={JSON.stringify(block.navigation_payload, null, 2)}
readOnly
minHeight="96px"
maxHeight="200px"
/>
</div>
) : null}
{showDataExtractionParameters ? (
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Data Extraction Goal</h1>
<HelpTooltip content="What outputs are you looking to get?" />
</div>
<AutoResizingTextarea
value={block.data_extraction_goal ?? ""}
readOnly
/>
</div>
) : null}
{showDataExtractionParameters ? (
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Data Schema</h1>
<HelpTooltip content="Specify the output format in JSON" />
</div>
<CodeEditor
className="w-full"
language="json"
value={JSON.stringify(block.data_schema, null, 2)}
readOnly
minHeight="96px"
maxHeight="200px"
/>
</div>
) : null}
{showValidationParameters ? (
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Completion Criteria</h1>
<HelpTooltip content="Complete if..." />
</div>
<AutoResizingTextarea
value={block.complete_criterion ?? ""}
readOnly
/>
</div>
) : null}
{showValidationParameters ? (
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-sm">Termination Criteria</h1>
<HelpTooltip content="Terminate if..." />
</div>
<AutoResizingTextarea
value={block.terminate_criterion ?? ""}
readOnly
/>
</div>
) : null}
{showIncludeActionHistoryInVerification ? (
<div className="flex flex-col gap-2">
<div className="flex w-full items-center justify-start gap-2">
<h1 className="text-nowrap text-sm">Include Action History</h1>
<HelpTooltip content="Whether to include action history in the completion verification" />
</div>
<div className="w-full">
<Switch
checked={block.include_action_history_in_verification ?? false}
disabled
/>
</div>
</div>
) : null}
</>
);
}
export { DebuggerTaskBlockParameters };