diff --git a/.github/workflows/dev-build.yaml b/.github/workflows/dev-build.yaml
index 679cf7e72f..4f972c48e9 100644
--- a/.github/workflows/dev-build.yaml
+++ b/.github/workflows/dev-build.yaml
@@ -6,7 +6,7 @@ concurrency:
on:
push:
- branches: ['3872-feat-direct-output-to-chat-from-agent-flows'] # put your current branch to create a build. Core team only.
+ branches: ['3866-feat-import-agent-flows-from-community-hub'] # put your current branch to create a build. Core team only.
paths-ignore:
- '**.md'
- 'cloud-deployments/*'
diff --git a/frontend/src/models/agentFlows.js b/frontend/src/models/agentFlows.js
index fcb82c597a..cb29a71a7f 100644
--- a/frontend/src/models/agentFlows.js
+++ b/frontend/src/models/agentFlows.js
@@ -19,7 +19,7 @@ const AgentFlows = {
body: JSON.stringify({ name, config, uuid }),
})
.then((res) => {
- if (!res.ok) throw new Error(response.error || "Failed to save flow");
+ if (!res.ok) throw new Error(res.error || "Failed to save flow");
return res;
})
.then((res) => res.json())
diff --git a/frontend/src/pages/Admin/AgentBuilder/index.jsx b/frontend/src/pages/Admin/AgentBuilder/index.jsx
index 3838529817..72b4d5c88b 100644
--- a/frontend/src/pages/Admin/AgentBuilder/index.jsx
+++ b/frontend/src/pages/Admin/AgentBuilder/index.jsx
@@ -224,7 +224,9 @@ export default function AgentBuilder() {
await loadAvailableFlows();
} catch (error) {
console.error("Save error details:", error);
- showToast("Failed to save agent flow", "error", { clear: true });
+ showToast(`Failed to save agent flow. ${error.message}`, "error", {
+ clear: true,
+ });
}
};
diff --git a/frontend/src/pages/GeneralSettings/CommunityHub/Authentication/useUserItems.js b/frontend/src/pages/GeneralSettings/CommunityHub/Authentication/useUserItems.js
index 3222f84740..49274aaea2 100644
--- a/frontend/src/pages/GeneralSettings/CommunityHub/Authentication/useUserItems.js
+++ b/frontend/src/pages/GeneralSettings/CommunityHub/Authentication/useUserItems.js
@@ -6,6 +6,7 @@ const DEFAULT_USER_ITEMS = {
agentSkills: { items: [] },
systemPrompts: { items: [] },
slashCommands: { items: [] },
+ agentFlows: { items: [] },
},
teamItems: [],
};
diff --git a/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/Completed/index.jsx b/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/Completed/index.jsx
index 15724a77a8..b7b6fff7a7 100644
--- a/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/Completed/index.jsx
+++ b/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/Completed/index.jsx
@@ -1,5 +1,7 @@
import CommunityHubImportItemSteps from "..";
import CTAButton from "@/components/lib/CTAButton";
+import { Link } from "react-router-dom";
+import paths from "@/utils/paths";
export default function Completed({ settings, setSettings, setStep }) {
return (
@@ -15,6 +17,14 @@ export default function Completed({ settings, setSettings, setStep }) {
imported successfully! It is now available in your AnythingLLM
instance.
+ {settings.item.itemType === "agent-flow" && (
+
+ View "{settings.item.name}" in Agent Skills
+
+ )}
Any changes you make to this {settings.item.itemType} will not be
reflected in the community hub. You can now modify as needed.
diff --git a/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/HubItem/AgentFlow.jsx b/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/HubItem/AgentFlow.jsx
new file mode 100644
index 0000000000..39f8c344b9
--- /dev/null
+++ b/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/HubItem/AgentFlow.jsx
@@ -0,0 +1,80 @@
+import CTAButton from "@/components/lib/CTAButton";
+import CommunityHubImportItemSteps from "../..";
+import showToast from "@/utils/toast";
+import paths from "@/utils/paths";
+import { CircleNotch } from "@phosphor-icons/react";
+import { useState } from "react";
+import AgentFlows from "@/models/agentFlows";
+import { safeJsonParse } from "@/utils/request";
+
+export default function AgentFlow({ item, setStep }) {
+ const flowInfo = safeJsonParse(item.flow, { steps: [] });
+ const [loading, setLoading] = useState(false);
+
+ async function importAgentFlow() {
+ try {
+ setLoading(true);
+ const { success, error, flow } = await AgentFlows.saveFlow(
+ item.name,
+ flowInfo
+ );
+ if (!success) throw new Error(error);
+ if (!!flow?.uuid) await AgentFlows.toggleFlow(flow.uuid, true); // Enable the flow automatically after import
+
+ showToast(`Agent flow imported successfully!`, "success");
+ setStep(CommunityHubImportItemSteps.completed.key);
+ } catch (e) {
+ console.error(e);
+ showToast(`Failed to import agent flow. ${e.message}`, "error");
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ return (
+
+
+
+
+ Agent flows allow you to create reusable sequences of actions that can
+ be triggered by your agent.
+
+
+
Flow Details:
+
Description: {item.description}
+
Steps ({flowInfo.steps.length}):
+
+ {flowInfo.steps.map((step, index) => (
+ - {step.type}
+ ))}
+
+
+
+
+ {loading ? : null}
+ {loading ? "Importing..." : "Import agent flow"}
+
+
+ );
+}
diff --git a/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/HubItem/index.js b/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/HubItem/index.js
index 725ae45f52..4362043c16 100644
--- a/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/HubItem/index.js
+++ b/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/HubItem/index.js
@@ -2,11 +2,13 @@ import SystemPrompt from "./SystemPrompt";
import SlashCommand from "./SlashCommand";
import UnknownItem from "./Unknown";
import AgentSkill from "./AgentSkill";
+import AgentFlow from "./AgentFlow";
const HubItemComponent = {
"agent-skill": AgentSkill,
"system-prompt": SystemPrompt,
"slash-command": SlashCommand,
+ "agent-flow": AgentFlow,
unknown: UnknownItem,
};
diff --git a/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/index.jsx b/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/index.jsx
index 375ec58886..040df74393 100644
--- a/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/index.jsx
+++ b/frontend/src/pages/GeneralSettings/CommunityHub/ImportItem/Steps/PullAndReview/index.jsx
@@ -3,7 +3,6 @@ import CommunityHubImportItemSteps from "..";
import CTAButton from "@/components/lib/CTAButton";
import { useEffect, useState } from "react";
import HubItemComponent from "./HubItem";
-import PreLoader from "@/components/Preloader";
function useGetCommunityHubItem({ importId, updateSettings }) {
const [item, setItem] = useState(null);
diff --git a/frontend/src/pages/GeneralSettings/CommunityHub/Trending/HubItems/HubItemCard/agentFlow.jsx b/frontend/src/pages/GeneralSettings/CommunityHub/Trending/HubItems/HubItemCard/agentFlow.jsx
new file mode 100644
index 0000000000..d2c73f5ec0
--- /dev/null
+++ b/frontend/src/pages/GeneralSettings/CommunityHub/Trending/HubItems/HubItemCard/agentFlow.jsx
@@ -0,0 +1,39 @@
+import { Link } from "react-router-dom";
+import paths from "@/utils/paths";
+import { VisibilityIcon } from "./generic";
+
+export default function AgentFlowHubCard({ item }) {
+ const flow = JSON.parse(item.flow);
+ return (
+
+
+
+
{item.description}
+
+
+
+ {flow.steps.map((step, index) => (
+ - {step.type}
+ ))}
+
+
+
+
+
+ Import →
+
+
+
+ );
+}
diff --git a/frontend/src/pages/GeneralSettings/CommunityHub/Trending/HubItems/HubItemCard/index.jsx b/frontend/src/pages/GeneralSettings/CommunityHub/Trending/HubItems/HubItemCard/index.jsx
index f2d53c0f77..371343a68a 100644
--- a/frontend/src/pages/GeneralSettings/CommunityHub/Trending/HubItems/HubItemCard/index.jsx
+++ b/frontend/src/pages/GeneralSettings/CommunityHub/Trending/HubItems/HubItemCard/index.jsx
@@ -2,6 +2,7 @@ import GenericHubCard from "./generic";
import SystemPromptHubCard from "./systemPrompt";
import SlashCommandHubCard from "./slashCommand";
import AgentSkillHubCard from "./agentSkill";
+import AgentFlowHubCard from "./agentFlow";
export default function HubItemCard({ type, item }) {
switch (type) {
@@ -11,6 +12,8 @@ export default function HubItemCard({ type, item }) {
return ;
case "agentSkills":
return ;
+ case "agentFlows":
+ return ;
default:
return ;
}
diff --git a/frontend/src/pages/GeneralSettings/CommunityHub/utils.js b/frontend/src/pages/GeneralSettings/CommunityHub/utils.js
index 379da33d48..782dae2f55 100644
--- a/frontend/src/pages/GeneralSettings/CommunityHub/utils.js
+++ b/frontend/src/pages/GeneralSettings/CommunityHub/utils.js
@@ -1,6 +1,6 @@
/**
* Convert a type to a readable string for the community hub.
- * @param {("agentSkills" | "agentSkill" | "systemPrompts" | "systemPrompt" | "slashCommands" | "slashCommand")} type
+ * @param {("agentSkills" | "agentSkill" | "systemPrompts" | "systemPrompt" | "slashCommands" | "slashCommand" | "agentFlows" | "agentFlow")} type
* @returns {string}
*/
export function readableType(type) {
@@ -14,12 +14,15 @@ export function readableType(type) {
case "slashCommand":
case "slashCommands":
return "Slash Commands";
+ case "agentFlows":
+ case "agentFlow":
+ return "Agent Flows";
}
}
/**
* Convert a type to a path for the community hub.
- * @param {("agentSkill" | "agentSkills" | "systemPrompt" | "systemPrompts" | "slashCommand" | "slashCommands")} type
+ * @param {("agentSkill" | "agentSkills" | "systemPrompt" | "systemPrompts" | "slashCommand" | "slashCommands" | "agentFlow" | "agentFlows")} type
* @returns {string}
*/
export function typeToPath(type) {
@@ -33,5 +36,8 @@ export function typeToPath(type) {
case "slashCommand":
case "slashCommands":
return "slash-commands";
+ case "agentFlow":
+ case "agentFlows":
+ return "agent-flows";
}
}
diff --git a/server/endpoints/agentFlows.js b/server/endpoints/agentFlows.js
index 75a16c774a..0f3c164acc 100644
--- a/server/endpoints/agentFlows.js
+++ b/server/endpoints/agentFlows.js
@@ -25,12 +25,10 @@ function agentFlowEndpoints(app) {
}
const flow = AgentFlows.saveFlow(name, config, uuid);
- if (!flow) {
- return response.status(500).json({
- success: false,
- error: "Failed to save flow",
- });
- }
+ if (!flow || !flow.success)
+ return response
+ .status(200)
+ .json({ flow: null, error: flow.error || "Failed to save flow" });
if (!uuid) {
await Telemetry.sendTelemetry("agent_flow_created", {
diff --git a/server/utils/agentFlows/executor.js b/server/utils/agentFlows/executor.js
index 81126e2ee7..c41ca9c490 100644
--- a/server/utils/agentFlows/executor.js
+++ b/server/utils/agentFlows/executor.js
@@ -1,8 +1,5 @@
const { FLOW_TYPES } = require("./flowTypes");
const executeApiCall = require("./executors/api-call");
-const executeWebsite = require("./executors/website");
-const executeFile = require("./executors/file");
-const executeCode = require("./executors/code");
const executeLLMInstruction = require("./executors/llm-instruction");
const executeWebScraping = require("./executors/web-scraping");
const { Telemetry } = require("../../models/telemetry");
@@ -161,15 +158,6 @@ class FlowExecutor {
case FLOW_TYPES.API_CALL.type:
result = await executeApiCall(config, context);
break;
- case FLOW_TYPES.WEBSITE.type:
- result = await executeWebsite(config, context);
- break;
- case FLOW_TYPES.FILE.type:
- result = await executeFile(config, context);
- break;
- case FLOW_TYPES.CODE.type:
- result = await executeCode(config, context);
- break;
case FLOW_TYPES.LLM_INSTRUCTION.type:
result = await executeLLMInstruction(config, context);
break;
diff --git a/server/utils/agentFlows/executors/code.js b/server/utils/agentFlows/executors/code.js
deleted file mode 100644
index 6f2dfead3b..0000000000
--- a/server/utils/agentFlows/executors/code.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Execute a code flow step
- * @param {Object} config Flow step configuration
- * @returns {Promise