@gopluto_ai/llm-tools-orchestration
Version:
A scalable tools or functions orchestration SDK for LLM agents using OpenAI's /v1/responses API with memory, hooks, and tool planning support. Alternative of MCP for LLM tools orchestration.
125 lines (122 loc) β’ 4.81 kB
JavaScript
;
const toolRegistry = [];
const hookProcessors = {};
const registerTool = (tool) => toolRegistry.push(tool);
const registerHookProcessor = (hookName, processor) => {
hookProcessors[hookName] = processor;
};
const getToolSchemas = () => toolRegistry.map(({ type, name, description, parameters }) => ({
type, name, description, parameters,
}));
const getTool = (name) => toolRegistry.find(t => t.name === name);
const runHooks = async (hookNames = [], memory) => {
for (const hook of hookNames) {
const processor = hookProcessors[hook];
if (processor)
memory = await processor(memory);
}
return memory;
};
const planTools = async (messages, getOpenAIResData, modal = "gpt-4o") => {
const messagesData = {
agentContext: messages.sysprompt,
conversationHistory: messages.conversationHistory,
agentMemory: messages.agentMemory || {},
userPrompt: messages.userMessage,
functions: getToolSchemas(),
};
console.log("π§ Planning initiated with:", messagesData);
const final = await getOpenAIResData(messagesData, modal);
console.log("π© Response from OpenAI:", final);
const message = final.aiResponse;
// No tools triggered β direct reply
if (message && (!final.function_call || final.function_call.length === 0)) {
return {
tools: [],
neededTools: [],
args: {},
directReply: message,
convTopic: final.convTopic || "General",
newMemory: final.newMemory || {},
modal: final.modal || "gpt-4o",
usage: final.usage,
};
}
// Tool calls exist β parse them
if (Array.isArray(final.function_call) && final.function_call.length > 0) {
const args = {};
const neededTools = [];
final.function_call.forEach((tool) => {
const parsedArgs = typeof tool.arguments === "string"
? JSON.parse(tool.arguments)
: tool.arguments;
args[tool.name] = {
...parsedArgs,
call_id: tool.call_id,
};
neededTools.push(tool.name);
});
return {
tools: final.function_call,
neededTools,
args,
directReply: message || "",
convTopic: final.convTopic || "General",
newMemory: final.newMemory || {},
modal: final.modal || "gpt-4o",
usage: final.usage,
};
}
throw new Error("β Invalid GPT planning response format");
};
const executeParallelTools = async (toolList, argsMap, memory) => {
if (!Array.isArray(toolList) || toolList.length === 0) {
throw new Error("No tools to execute");
}
const toolCalls = toolList.map(async (toolName) => {
const tool = getTool(toolName);
if (!tool)
throw new Error(`Tool ${toolName} not found`);
memory = await runHooks(tool.preHooks || [], memory);
const result = await tool.handler(argsMap[toolName], memory);
memory = await runHooks(tool.postHooks || [], memory);
return {
name: toolName,
result,
call_id: argsMap[toolName]?.call_id || null,
};
});
const results = await Promise.all(toolCalls);
return results;
};
const synthesizeFinalReply = async (userMessage, toolResults, messages, tools, getOpenAIResData, modal = "gpt-4o") => {
const toolResultsWithNames = toolResults.map(({ name, result, call_id }) => ({
recipient_name: name,
call_id,
data: result, // Ensure data is always an object
}));
const agentContext = `
system context: ${messages.sysprompt.content}
Additional Instruction:
Here is the data returned by tools you called:
Please generate a useful, human-like reply summarizing and give the data whatβs most relevant data in json.`;
const messagesData = {
agentContext, // β
now a string
function_output: toolResultsWithNames,
function_called: tools, // β
array of function calls
conversationHistory: messages.conversationHistory,
agentMemory: messages.agentMemory || {},
userPrompt: messages.userMessage,
};
console.log("Synthesizing final reply with messages:");
const final = await getOpenAIResData(messagesData, modal);
console.log("Final synthesized reply:");
return final || { aiResponse: "No reply generated." };
};
exports.executeParallelTools = executeParallelTools;
exports.getTool = getTool;
exports.getToolSchemas = getToolSchemas;
exports.planTools = planTools;
exports.registerHookProcessor = registerHookProcessor;
exports.registerTool = registerTool;
exports.synthesizeFinalReply = synthesizeFinalReply;