mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2026-06-15 23:20:32 +03:00
* wip agent builder * refactor structure for agent builder * improve ui for add block menu and sidebar * lint * node ui improvement * handle deleting variable in all nodes * add headers and body to apiCall node * lint * Agent flow builder backend (#3078) * wip agent builder backend * save/load agent tasks * lint * refactor agent task to use uuids instead of names * placeholder for run task * update frontend sidebar + seperate backend to agent-tasks utils * lint * add deleting of agent tasks * create AgentTasks class + wip load agent tasks into aibitat * lint * inject + call agent tasks * wip call agent tasks * add llm instruction + fix api calling blocks * add ui + backend for editing/toggling agent tasks * lint * add back middlewares * disable run task + add navigate to home on logo click * implement normalizePath to prevent path traversal * wip make api calling more consistent * lint * rename all references from task to flow * patch load flow bug when on editing page * remove unneeded files/comments * lint * fix delete endpoint + rename load flows * add move block to ui + fix api-call backend + add telemetry * lint * add web scraping block * only allow admin for agent builder --------- Co-authored-by: timothycarambat <rambat1010@gmail.com> * Move AgentFlowManager flows to static simplify UI states Handle LLM prompt flow when provided non-string * delete/edit menu for agent flow panel + update flow icon * lint * fix open builder button hidden bug * add tooltips to move up/down block buttons * add tooltip to delete block * truncate block description to fit on blocklist component * light mode agent builder sidebar * light mode api call block * fix light mode styles for agent builder blocks * agent flow fetch in UI * sync delete flow * agent flow ui/ux improvements * remove unused AgentSidebar component * comment out /run * UI changes and updates for flow builder * format flow panel info * update link handling * ui tweaks to header menu * remove unused import * update doc links update block icons * bump readme * Patch code block header oddity resolves #3117 * bump dev image --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
147 lines
4.3 KiB
JavaScript
147 lines
4.3 KiB
JavaScript
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");
|
|
|
|
class FlowExecutor {
|
|
constructor() {
|
|
this.variables = {};
|
|
this.introspect = () => {}; // Default no-op introspect
|
|
this.logger = console.info; // Default console.info
|
|
}
|
|
|
|
attachLogging(introspectFn, loggerFn) {
|
|
this.introspect = introspectFn || (() => {});
|
|
this.logger = loggerFn || console.info;
|
|
}
|
|
|
|
// Utility to replace variables in config
|
|
replaceVariables(config) {
|
|
const deepReplace = (obj) => {
|
|
if (typeof obj === "string") {
|
|
return obj.replace(/\${([^}]+)}/g, (match, varName) => {
|
|
return this.variables[varName] !== undefined
|
|
? this.variables[varName]
|
|
: match;
|
|
});
|
|
}
|
|
if (Array.isArray(obj)) {
|
|
return obj.map((item) => deepReplace(item));
|
|
}
|
|
if (obj && typeof obj === "object") {
|
|
const result = {};
|
|
for (const [key, value] of Object.entries(obj)) {
|
|
result[key] = deepReplace(value);
|
|
}
|
|
return result;
|
|
}
|
|
return obj;
|
|
};
|
|
|
|
return deepReplace(config);
|
|
}
|
|
|
|
// Main execution method
|
|
async executeStep(step) {
|
|
const config = this.replaceVariables(step.config);
|
|
let result;
|
|
// Create execution context with introspect
|
|
const context = {
|
|
introspect: this.introspect,
|
|
variables: this.variables,
|
|
logger: this.logger,
|
|
model: process.env.LLM_PROVIDER_MODEL || "gpt-4",
|
|
provider: process.env.LLM_PROVIDER || "openai",
|
|
};
|
|
|
|
switch (step.type) {
|
|
case FLOW_TYPES.START.type:
|
|
// For start blocks, we just initialize variables if they're not already set
|
|
if (config.variables) {
|
|
config.variables.forEach((v) => {
|
|
if (v.name && !this.variables[v.name]) {
|
|
this.variables[v.name] = v.value || "";
|
|
}
|
|
});
|
|
}
|
|
result = this.variables;
|
|
break;
|
|
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;
|
|
case FLOW_TYPES.WEB_SCRAPING.type:
|
|
result = await executeWebScraping(config, context);
|
|
break;
|
|
default:
|
|
throw new Error(`Unknown flow type: ${step.type}`);
|
|
}
|
|
|
|
// Store result in variable if specified
|
|
if (config.resultVariable || config.responseVariable) {
|
|
const varName = config.resultVariable || config.responseVariable;
|
|
this.variables[varName] = result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Execute entire flow
|
|
async executeFlow(
|
|
flow,
|
|
initialVariables = {},
|
|
introspectFn = null,
|
|
loggerFn = null
|
|
) {
|
|
await Telemetry.sendTelemetry("agent_flow_execution_started");
|
|
|
|
// Initialize variables with both initial values and any passed-in values
|
|
this.variables = {
|
|
...(
|
|
flow.config.steps.find((s) => s.type === "start")?.config?.variables ||
|
|
[]
|
|
).reduce((acc, v) => ({ ...acc, [v.name]: v.value }), {}),
|
|
...initialVariables, // This will override any default values with passed-in values
|
|
};
|
|
|
|
this.attachLogging(introspectFn, loggerFn);
|
|
const results = [];
|
|
|
|
for (const step of flow.config.steps) {
|
|
try {
|
|
const result = await this.executeStep(step);
|
|
results.push({ success: true, result });
|
|
} catch (error) {
|
|
results.push({ success: false, error: error.message });
|
|
break;
|
|
}
|
|
}
|
|
|
|
return {
|
|
success: results.every((r) => r.success),
|
|
results,
|
|
variables: this.variables,
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
FlowExecutor,
|
|
FLOW_TYPES,
|
|
};
|