merlyn/server/utils/agentFlows/executors/api-call.js
Sean Hatfield e5f3fb0892
Agent flow builder (#3077)
* 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>
2025-02-12 16:50:43 -08:00

61 lines
1.9 KiB
JavaScript

const { safeJsonParse } = require("../../http");
/**
* Execute an API call flow step
* @param {Object} config Flow step configuration
* @param {Object} context Execution context with introspect function
* @returns {Promise<string>} Response data
*/
async function executeApiCall(config, context) {
const { url, method, headers = [], body, bodyType, formData } = config;
const { introspect } = context;
introspect(`Making ${method} request to external API...`);
const requestConfig = {
method,
headers: headers.reduce((acc, h) => ({ ...acc, [h.key]: h.value }), {}),
};
if (["POST", "PUT", "PATCH"].includes(method)) {
if (bodyType === "form") {
const formDataObj = new URLSearchParams();
formData.forEach(({ key, value }) => formDataObj.append(key, value));
requestConfig.body = formDataObj.toString();
requestConfig.headers["Content-Type"] =
"application/x-www-form-urlencoded";
} else if (bodyType === "json") {
const parsedBody = safeJsonParse(body, null);
if (parsedBody !== null) {
requestConfig.body = JSON.stringify(parsedBody);
}
requestConfig.headers["Content-Type"] = "application/json";
} else if (bodyType === "text") {
requestConfig.body = String(body);
} else {
requestConfig.body = body;
}
}
try {
introspect(`Sending body to ${url}: ${requestConfig?.body || "No body"}`);
const response = await fetch(url, requestConfig);
if (!response.ok) {
introspect(`Request failed with status ${response.status}`);
throw new Error(`HTTP error! status: ${response.status}`);
}
introspect(`API call completed`);
return await response
.text()
.then((text) =>
safeJsonParse(text, "Failed to parse output from API call block")
);
} catch (error) {
console.error(error);
throw new Error(`API Call failed: ${error.message}`);
}
}
module.exports = executeApiCall;