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),
+ );
+ },
}));