mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-09 15:17:59 -05:00
feat(frontend): Add special handling for AGENT block type in form and output handlers (#11595)
<!-- Clearly explain the need for these changes: --> Agent blocks require different handling compared to standard blocks, particularly for: - Handle ID generation (using direct keys instead of generated IDs) - Form data storage structure (nested under `inputs` key) - Field ID parsing (filtering out schema path prefixes) This PR implements special handling for `BlockUIType.AGENT` throughout the form rendering and output handling components to ensure agents work correctly in the flow editor. ### Changes 🏗️ <!-- Concisely describe all of the changes made in this pull request: --> - **CustomNode.tsx**: Pass `uiType` prop to `OutputHandler` component - **FormCreator.tsx**: - Store agent form data in `hardcodedValues.inputs` instead of directly in `hardcodedValues` - Extract initial values from `hardcodedValues.inputs` for agent blocks - **OutputHandler.tsx**: - Accept `uiType` prop - Use direct key as handle ID for agents instead of `generateHandleId(key)` - **useMarketplaceAgentsContent.ts**: - Fetch full agent details using `getV2GetLibraryAgent` before adding to builder - Ensures agent schemas are properly populated (fixes issue where marketplace endpoint returns empty schemas) - **AnyOfField.tsx**: Generate handle IDs for agents by filtering out "root" and "properties" from schema path - **FieldTemplate.tsx**: Apply same handle ID generation logic for agent fields ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Add an agent block from marketplace and verify it renders correctly - [x] Connect inputs/outputs to/from an agent block and verify connections work - [x] Fill in form fields for an agent block and verify data persists correctly - [x] Verify agent blocks work in both new and existing flows - [x] Test that non-agent blocks still work as before (regression test)
This commit is contained in:
@@ -106,7 +106,11 @@ export const CustomNode: React.FC<NodeProps<CustomNode>> = React.memo(
|
||||
/>
|
||||
<NodeAdvancedToggle nodeId={nodeId} />
|
||||
{data.uiType != BlockUIType.OUTPUT && (
|
||||
<OutputHandler outputSchema={outputSchema} nodeId={nodeId} />
|
||||
<OutputHandler
|
||||
uiType={data.uiType}
|
||||
outputSchema={outputSchema}
|
||||
nodeId={nodeId}
|
||||
/>
|
||||
)}
|
||||
<NodeDataRenderer nodeId={nodeId} />
|
||||
</div>
|
||||
|
||||
@@ -20,17 +20,32 @@ export const FormCreator = React.memo(
|
||||
className?: string;
|
||||
}) => {
|
||||
const updateNodeData = useNodeStore((state) => state.updateNodeData);
|
||||
|
||||
const getHardCodedValues = useNodeStore(
|
||||
(state) => state.getHardCodedValues,
|
||||
);
|
||||
|
||||
const handleChange = ({ formData }: any) => {
|
||||
if ("credentials" in formData && !formData.credentials?.id) {
|
||||
delete formData.credentials;
|
||||
}
|
||||
updateNodeData(nodeId, { hardcodedValues: formData });
|
||||
|
||||
const updatedValues =
|
||||
uiType === BlockUIType.AGENT
|
||||
? {
|
||||
...getHardCodedValues(nodeId),
|
||||
inputs: formData,
|
||||
}
|
||||
: formData;
|
||||
|
||||
updateNodeData(nodeId, { hardcodedValues: updatedValues });
|
||||
};
|
||||
|
||||
const initialValues = getHardCodedValues(nodeId);
|
||||
const hardcodedValues = getHardCodedValues(nodeId);
|
||||
const initialValues =
|
||||
uiType === BlockUIType.AGENT
|
||||
? (hardcodedValues.inputs ?? {})
|
||||
: hardcodedValues;
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
|
||||
@@ -14,13 +14,16 @@ import {
|
||||
import { useEdgeStore } from "@/app/(platform)/build/stores/edgeStore";
|
||||
import { getTypeDisplayInfo } from "./helpers";
|
||||
import { generateHandleId } from "../handlers/helpers";
|
||||
import { BlockUIType } from "../../types";
|
||||
|
||||
export const OutputHandler = ({
|
||||
outputSchema,
|
||||
nodeId,
|
||||
uiType,
|
||||
}: {
|
||||
outputSchema: RJSFSchema;
|
||||
nodeId: string;
|
||||
uiType: BlockUIType;
|
||||
}) => {
|
||||
const { isOutputConnected } = useEdgeStore();
|
||||
const properties = outputSchema?.properties || {};
|
||||
@@ -79,7 +82,9 @@ export const OutputHandler = ({
|
||||
</Text>
|
||||
|
||||
<NodeHandle
|
||||
handleId={generateHandleId(key)}
|
||||
handleId={
|
||||
uiType === BlockUIType.AGENT ? key : generateHandleId(key)
|
||||
}
|
||||
isConnected={isConnected}
|
||||
side="right"
|
||||
/>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||
import { getV2GetSpecificAgent } from "@/app/api/__generated__/endpoints/store/store";
|
||||
import {
|
||||
getGetV2ListLibraryAgentsQueryKey,
|
||||
getV2GetLibraryAgent,
|
||||
usePostV2AddMarketplaceAgent,
|
||||
} from "@/app/api/__generated__/endpoints/library/library";
|
||||
import {
|
||||
@@ -151,7 +152,12 @@ export const useBlockMenuSearch = () => {
|
||||
});
|
||||
|
||||
const libraryAgent = response.data as LibraryAgent;
|
||||
addAgentToBuilder(libraryAgent);
|
||||
|
||||
const { data: libraryAgentDetails } = await getV2GetLibraryAgent(
|
||||
libraryAgent.id,
|
||||
);
|
||||
|
||||
addAgentToBuilder(libraryAgentDetails as LibraryAgent);
|
||||
|
||||
toast({
|
||||
title: "Agent Added",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { getGetV2GetBuilderItemCountsQueryKey } from "@/app/api/__generated__/endpoints/default/default";
|
||||
import {
|
||||
getGetV2ListLibraryAgentsQueryKey,
|
||||
getV2GetLibraryAgent,
|
||||
usePostV2AddMarketplaceAgent,
|
||||
} from "@/app/api/__generated__/endpoints/library/library";
|
||||
import {
|
||||
@@ -105,8 +106,16 @@ export const useMarketplaceAgentsContent = () => {
|
||||
},
|
||||
});
|
||||
|
||||
// Here, libraryAgent has empty input and output schemas.
|
||||
// Not updating the endpoint because this endpoint is used elsewhere.
|
||||
// TODO: Create a new endpoint for builder specific to marketplace agents.
|
||||
const libraryAgent = response.data as LibraryAgent;
|
||||
addAgentToBuilder(libraryAgent);
|
||||
|
||||
const { data: libraryAgentDetails } = await getV2GetLibraryAgent(
|
||||
libraryAgent.id,
|
||||
);
|
||||
|
||||
addAgentToBuilder(libraryAgentDetails as LibraryAgent);
|
||||
|
||||
toast({
|
||||
title: "Agent Added",
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/atoms/Tooltip/BaseTooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { BlockUIType } from "@/app/(platform)/build/components/types";
|
||||
|
||||
type TypeOption = {
|
||||
type: string;
|
||||
@@ -47,7 +48,14 @@ export const AnyOfField = ({
|
||||
onBlur,
|
||||
onFocus,
|
||||
}: FieldProps) => {
|
||||
const handleId = generateHandleId(idSchema.$id ?? "");
|
||||
const handleId =
|
||||
formContext.uiType === BlockUIType.AGENT
|
||||
? (idSchema.$id ?? "")
|
||||
.split("_")
|
||||
.filter((p) => p !== "root" && p !== "properties" && p.length > 0)
|
||||
.join("_") || ""
|
||||
: generateHandleId(idSchema.$id ?? "");
|
||||
|
||||
const updatedFormContexrt = { ...formContext, fromAnyOf: true };
|
||||
|
||||
const { nodeId, showHandles = true } = updatedFormContexrt;
|
||||
|
||||
@@ -58,7 +58,15 @@ const FieldTemplate: React.FC<FieldTemplateProps> = ({
|
||||
|
||||
let handleId = null;
|
||||
if (!isArrayItem) {
|
||||
handleId = generateHandleId(fieldId);
|
||||
if (uiType === BlockUIType.AGENT) {
|
||||
const parts = fieldId.split("_");
|
||||
const filtered = parts.filter(
|
||||
(p) => p !== "root" && p !== "properties" && p.length > 0,
|
||||
);
|
||||
handleId = filtered.join("_") || "";
|
||||
} else {
|
||||
handleId = generateHandleId(fieldId);
|
||||
}
|
||||
} else {
|
||||
handleId = arrayFieldHandleId;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user