UNPKG

@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.

117 lines (115 loc) β€’ 4.62 kB
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." }; }; export { executeParallelTools, getTool, getToolSchemas, planTools, registerHookProcessor, registerTool, synthesizeFinalReply };