This repository has been archived by the owner on Oct 14, 2024. It is now read-only.
forked from Significant-Gravitas/AutoGPT
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat(Builder): Add Runner input and ouput screens (Significant-Gravit…
…as#8038) * Feat(Builder): Add Runner input and ouput screens * Fix run button not working * prettier * prettier again -- forgot flow * fix input scaling + auto close on run * removed "Runner Input" button to make it auto open runner input if input block is + Fixed issue with output not showing in output UI * replaced runner output icon and added a new icon for it * replaced IconOutput icon with LogOut from lucide-react * prettier * fix type safety issue + add error handling for formatOutput * Updates based on comments * prettier for utils
- Loading branch information
Showing
7 changed files
with
434 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import React, { | ||
useState, | ||
useCallback, | ||
forwardRef, | ||
useImperativeHandle, | ||
} from "react"; | ||
import RunnerInputUI from "./runner-ui/RunnerInputUI"; | ||
import RunnerOutputUI from "./runner-ui/RunnerOutputUI"; | ||
import { Node } from "@xyflow/react"; | ||
import { filterBlocksByType } from "@/lib/utils"; | ||
import { BlockIORootSchema } from "@/lib/autogpt-server-api/types"; | ||
|
||
interface RunnerUIWrapperProps { | ||
nodes: Node[]; | ||
setNodes: React.Dispatch<React.SetStateAction<Node[]>>; | ||
isRunning: boolean; | ||
requestSaveAndRun: () => void; | ||
} | ||
|
||
export interface RunnerUIWrapperRef { | ||
openRunnerInput: () => void; | ||
openRunnerOutput: () => void; | ||
runOrOpenInput: () => void; | ||
} | ||
|
||
const RunnerUIWrapper = forwardRef<RunnerUIWrapperRef, RunnerUIWrapperProps>( | ||
({ nodes, setNodes, isRunning, requestSaveAndRun }, ref) => { | ||
const [isRunnerInputOpen, setIsRunnerInputOpen] = useState(false); | ||
const [isRunnerOutputOpen, setIsRunnerOutputOpen] = useState(false); | ||
|
||
const getBlockInputsAndOutputs = useCallback(() => { | ||
const inputBlocks = filterBlocksByType( | ||
nodes, | ||
(node) => node.data.block_id === "c0a8e994-ebf1-4a9c-a4d8-89d09c86741b", | ||
); | ||
|
||
const outputBlocks = filterBlocksByType( | ||
nodes, | ||
(node) => node.data.block_id === "363ae599-353e-4804-937e-b2ee3cef3da4", | ||
); | ||
|
||
const inputs = inputBlocks.map((node) => ({ | ||
id: node.id, | ||
type: "input" as const, | ||
inputSchema: node.data.inputSchema as BlockIORootSchema, | ||
hardcodedValues: { | ||
name: (node.data.hardcodedValues as any).name || "", | ||
description: (node.data.hardcodedValues as any).description || "", | ||
value: (node.data.hardcodedValues as any).value, | ||
placeholder_values: | ||
(node.data.hardcodedValues as any).placeholder_values || [], | ||
limit_to_placeholder_values: | ||
(node.data.hardcodedValues as any).limit_to_placeholder_values || | ||
false, | ||
}, | ||
})); | ||
|
||
const outputs = outputBlocks.map((node) => ({ | ||
id: node.id, | ||
type: "output" as const, | ||
outputSchema: node.data.outputSchema as BlockIORootSchema, | ||
hardcodedValues: { | ||
name: (node.data.hardcodedValues as any).name || "Output", | ||
description: | ||
(node.data.hardcodedValues as any).description || | ||
"Output from the agent", | ||
value: (node.data.hardcodedValues as any).value, | ||
}, | ||
result: (node.data.executionResults as any)?.at(-1)?.data?.output, | ||
})); | ||
|
||
return { inputs, outputs }; | ||
}, [nodes]); | ||
|
||
const handleInputChange = useCallback( | ||
(nodeId: string, field: string, value: string) => { | ||
setNodes((nds) => | ||
nds.map((node) => { | ||
if (node.id === nodeId) { | ||
return { | ||
...node, | ||
data: { | ||
...node.data, | ||
hardcodedValues: { | ||
...(node.data.hardcodedValues as any), | ||
[field]: value, | ||
}, | ||
}, | ||
}; | ||
} | ||
return node; | ||
}), | ||
); | ||
}, | ||
[setNodes], | ||
); | ||
|
||
const openRunnerInput = () => setIsRunnerInputOpen(true); | ||
const openRunnerOutput = () => setIsRunnerOutputOpen(true); | ||
|
||
const runOrOpenInput = () => { | ||
const { inputs } = getBlockInputsAndOutputs(); | ||
if (inputs.length > 0) { | ||
openRunnerInput(); | ||
} else { | ||
requestSaveAndRun(); | ||
} | ||
}; | ||
|
||
useImperativeHandle(ref, () => ({ | ||
openRunnerInput, | ||
openRunnerOutput, | ||
runOrOpenInput, | ||
})); | ||
|
||
return ( | ||
<> | ||
<RunnerInputUI | ||
isOpen={isRunnerInputOpen} | ||
onClose={() => setIsRunnerInputOpen(false)} | ||
blockInputs={getBlockInputsAndOutputs().inputs} | ||
onInputChange={handleInputChange} | ||
onRun={() => { | ||
setIsRunnerInputOpen(false); | ||
requestSaveAndRun(); | ||
}} | ||
isRunning={isRunning} | ||
/> | ||
<RunnerOutputUI | ||
isOpen={isRunnerOutputOpen} | ||
onClose={() => setIsRunnerOutputOpen(false)} | ||
blockOutputs={getBlockInputsAndOutputs().outputs} | ||
/> | ||
</> | ||
); | ||
}, | ||
); | ||
|
||
RunnerUIWrapper.displayName = "RunnerUIWrapper"; | ||
|
||
export default RunnerUIWrapper; |
61 changes: 61 additions & 0 deletions
61
rnd/autogpt_builder/src/components/runner-ui/RunnerInputBlock.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React from "react"; | ||
import { Input } from "@/components/ui/input"; | ||
import { | ||
Select, | ||
SelectContent, | ||
SelectItem, | ||
SelectTrigger, | ||
SelectValue, | ||
} from "@/components/ui/select"; | ||
|
||
interface InputBlockProps { | ||
id: string; | ||
name: string; | ||
description?: string; | ||
value: string; | ||
placeholder_values?: any[]; | ||
onInputChange: (id: string, field: string, value: string) => void; | ||
} | ||
|
||
export function InputBlock({ | ||
id, | ||
name, | ||
description, | ||
value, | ||
placeholder_values, | ||
onInputChange, | ||
}: InputBlockProps) { | ||
return ( | ||
<div className="space-y-1"> | ||
<h3 className="text-base font-semibold">{name || "Unnamed Input"}</h3> | ||
{description && <p className="text-sm text-gray-600">{description}</p>} | ||
<div> | ||
{placeholder_values && placeholder_values.length > 1 ? ( | ||
<Select | ||
onValueChange={(value) => onInputChange(id, "value", value)} | ||
value={value} | ||
> | ||
<SelectTrigger className="w-full"> | ||
<SelectValue placeholder="Select a value" /> | ||
</SelectTrigger> | ||
<SelectContent> | ||
{placeholder_values.map((placeholder, index) => ( | ||
<SelectItem key={index} value={placeholder.toString()}> | ||
{placeholder.toString()} | ||
</SelectItem> | ||
))} | ||
</SelectContent> | ||
</Select> | ||
) : ( | ||
<Input | ||
id={`${id}-Value`} | ||
value={value} | ||
onChange={(e) => onInputChange(id, "value", e.target.value)} | ||
placeholder={placeholder_values?.[0]?.toString() || "Enter value"} | ||
className="w-full" | ||
/> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
} |
33 changes: 33 additions & 0 deletions
33
rnd/autogpt_builder/src/components/runner-ui/RunnerInputList.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import React from "react"; | ||
import { ScrollArea } from "@/components/ui/scroll-area"; | ||
import { InputBlock } from "./RunnerInputBlock"; | ||
import { BlockInput } from "./RunnerInputUI"; | ||
|
||
interface InputListProps { | ||
blockInputs: BlockInput[]; | ||
onInputChange: (nodeId: string, field: string, value: string) => void; | ||
} | ||
|
||
export function InputList({ blockInputs, onInputChange }: InputListProps) { | ||
return ( | ||
<ScrollArea className="h-[20vh] overflow-auto pr-4 sm:h-[30vh] md:h-[40vh] lg:h-[50vh]"> | ||
<div className="space-y-4"> | ||
{blockInputs && blockInputs.length > 0 ? ( | ||
blockInputs.map((block) => ( | ||
<InputBlock | ||
key={block.id} | ||
id={block.id} | ||
name={block.hardcodedValues.name} | ||
description={block.hardcodedValues.description} | ||
value={block.hardcodedValues.value?.toString() || ""} | ||
placeholder_values={block.hardcodedValues.placeholder_values} | ||
onInputChange={onInputChange} | ||
/> | ||
)) | ||
) : ( | ||
<p>No input blocks available.</p> | ||
)} | ||
</div> | ||
</ScrollArea> | ||
); | ||
} |
74 changes: 74 additions & 0 deletions
74
rnd/autogpt_builder/src/components/runner-ui/RunnerInputUI.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import React from "react"; | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogDescription, | ||
DialogFooter, | ||
} from "@/components/ui/dialog"; | ||
import { Button } from "@/components/ui/button"; | ||
import { BlockIORootSchema } from "@/lib/autogpt-server-api/types"; | ||
import { InputList } from "./RunnerInputList"; | ||
|
||
export interface BlockInput { | ||
id: string; | ||
inputSchema: BlockIORootSchema; | ||
hardcodedValues: { | ||
name: string; | ||
description: string; | ||
value: any; | ||
placeholder_values?: any[]; | ||
limit_to_placeholder_values?: boolean; | ||
}; | ||
} | ||
|
||
interface RunSettingsUiProps { | ||
isOpen: boolean; | ||
onClose: () => void; | ||
blockInputs: BlockInput[]; | ||
onInputChange: (nodeId: string, field: string, value: string) => void; | ||
onRun: () => void; | ||
isRunning: boolean; | ||
} | ||
|
||
export function RunnerInputUI({ | ||
isOpen, | ||
onClose, | ||
blockInputs, | ||
onInputChange, | ||
onRun, | ||
isRunning, | ||
}: RunSettingsUiProps) { | ||
const handleRun = () => { | ||
onRun(); | ||
onClose(); | ||
}; | ||
|
||
return ( | ||
<Dialog open={isOpen} onOpenChange={onClose}> | ||
<DialogContent className="flex max-h-[80vh] flex-col overflow-hidden sm:max-w-[400px] md:max-w-[500px] lg:max-w-[600px]"> | ||
<DialogHeader className="px-4 py-4"> | ||
<DialogTitle className="text-2xl">Run Settings</DialogTitle> | ||
<DialogDescription className="mt-2 text-sm"> | ||
Configure settings for running your agent. | ||
</DialogDescription> | ||
</DialogHeader> | ||
<div className="flex-grow overflow-y-auto px-4 py-4"> | ||
<InputList blockInputs={blockInputs} onInputChange={onInputChange} /> | ||
</div> | ||
<DialogFooter className="px-6 py-4"> | ||
<Button | ||
onClick={handleRun} | ||
className="px-8 py-2 text-lg" | ||
disabled={isRunning} | ||
> | ||
{isRunning ? "Running..." : "Run"} | ||
</Button> | ||
</DialogFooter> | ||
</DialogContent> | ||
</Dialog> | ||
); | ||
} | ||
|
||
export default RunnerInputUI; |
Oops, something went wrong.