From 321ab8a48ad61d1b785dddc9cc12716377eb2be1 Mon Sep 17 00:00:00 2001 From: Abhimanyu Yadav <122007096+Abhi1992002@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:13:04 +0530 Subject: [PATCH] feat(frontend): Add trigger agent banner for webhook-based flows (#11480) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR addresses the need for better user awareness when building trigger-based agents. When a user adds webhook/trigger nodes to their flow, a prominent banner now appears at the bottom of the builder informing them they're creating a "Trigger Agent" and providing a direct link to monitor its activity in the Agent Library. ### Changes 🏗️ - **Added TriggerAgentBanner component**: New banner that displays at the bottom of the builder when the flow contains webhook/trigger nodes - **Implemented webhook node detection**: Added `hasWebhookNodes` method to nodeStore that checks if any nodes are of type WEBHOOK or WEBHOOK_MANUAL - **Conditional banner display**: Builder now shows TriggerAgentBanner instead of BuilderActions when webhook nodes are present - **Dynamic library link**: Banner includes a link to the specific agent in the library (if found) or defaults to the general library page - **Integrated with existing flow context**: Uses the current flowID to fetch the corresponding library agent for proper linking ### 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 a webhook node to a flow and verify the banner appears - [x] Remove all webhook nodes and verify the banner disappears - [x] Test with both WEBHOOK and WEBHOOK_MANUAL node types - [x] Click the library link and verify it navigates to the correct agent page - [x] Test library link fallback when agent is not found in library - [x] Verify banner styling and positioning at bottom center of builder --- .../build/components/FlowEditor/Flow/Flow.tsx | 6 ++- .../Flow/components/TriggerAgentBanner.tsx | 49 +++++++++++++++++++ .../app/(platform)/build/stores/nodeStore.ts | 6 +++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/TriggerAgentBanner.tsx diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx index 86b1e23871..d4c97353b7 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx @@ -16,6 +16,7 @@ import { useCopyPaste } from "./useCopyPaste"; import { FloatingReviewsPanel } from "@/components/organisms/FloatingReviewsPanel/FloatingReviewsPanel"; import { parseAsString, useQueryStates } from "nuqs"; import { CustomControls } from "./components/CustomControl"; +import { TriggerAgentBanner } from "./components/TriggerAgentBanner"; export const Flow = () => { const [{ flowExecutionID }] = useQueryStates({ @@ -27,6 +28,9 @@ export const Flow = () => { const onNodesChange = useNodeStore( useShallow((state) => state.onNodesChange), ); + const hasWebhookNodes = useNodeStore( + useShallow((state) => state.hasWebhookNodes()), + ); const nodeTypes = useMemo(() => ({ custom: CustomNode }), []); const edgeTypes = useMemo(() => ({ custom: CustomEdge }), []); const { edges, onConnect, onEdgesChange } = useCustomEdge(); @@ -76,7 +80,7 @@ export const Flow = () => { - + {hasWebhookNodes ? : } {} {isGraphRunning && } diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/TriggerAgentBanner.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/TriggerAgentBanner.tsx new file mode 100644 index 0000000000..f49a8cdd76 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/components/TriggerAgentBanner.tsx @@ -0,0 +1,49 @@ +import { + Alert, + AlertDescription, + AlertTitle, +} from "@/components/molecules/Alert/Alert"; +import Link from "next/link"; +import { useGetV2GetLibraryAgentByGraphId } from "@/app/api/__generated__/endpoints/library/library"; +import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; +import { useQueryStates, parseAsString } from "nuqs"; + +export const TriggerAgentBanner = () => { + const [{ flowID }] = useQueryStates({ + flowID: parseAsString, + }); + + const { data: libraryAgent } = useGetV2GetLibraryAgentByGraphId( + flowID ?? "", + {}, + { + query: { + select: (x) => { + return x.data as LibraryAgent; + }, + enabled: !!flowID, + }, + }, + ); + + return ( + + You are building a Trigger Agent + + Your agent will listen for its trigger and will run when the time is + right. +
+ You can view its activity in your{" "} + + Agent Library + + . +
+
+ ); +}; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/stores/nodeStore.ts b/autogpt_platform/frontend/src/app/(platform)/build/stores/nodeStore.ts index 3cc5764338..892c0e1cac 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/stores/nodeStore.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/stores/nodeStore.ts @@ -44,6 +44,7 @@ type NodeStore = { ) => void; getNodeExecutionResult: (nodeId: string) => NodeExecutionResult | undefined; getNodeBlockUIType: (nodeId: string) => BlockUIType; + hasWebhookNodes: () => boolean; }; export const useNodeStore = create((set, get) => ({ @@ -204,4 +205,9 @@ export const useNodeStore = create((set, get) => ({ BlockUIType.STANDARD ); }, + hasWebhookNodes: () => { + return get().nodes.some((n) => + [BlockUIType.WEBHOOK, BlockUIType.WEBHOOK_MANUAL].includes(n.data.uiType), + ); + }, }));