UNPKG

@just-every/ensemble

Version:

LLM provider abstraction layer with unified streaming interface

139 lines 5.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.timeoutPromise = timeoutPromise; exports.agentHasStatusTracking = agentHasStatusTracking; exports.executeToolWithLifecycle = executeToolWithLifecycle; exports.handleToolCall = handleToolCall; exports.prepareToolArguments = prepareToolArguments; const uuid_1 = require("uuid"); const running_tool_tracker_js_1 = require("./running_tool_tracker.cjs"); const sequential_queue_js_1 = require("./sequential_queue.cjs"); const tool_parameter_utils_js_1 = require("./tool_parameter_utils.cjs"); const tool_execution_js_1 = require("../config/tool_execution.cjs"); function timeoutPromise(ms) { return new Promise(resolve => { setTimeout(() => resolve('TIMEOUT'), ms); }); } function agentHasStatusTracking(agent) { if (!agent.tools) return false; return agent.tools.some(tool => tool_execution_js_1.STATUS_TRACKING_TOOLS.has(tool.definition.function.name)); } async function executeToolWithLifecycle(toolCall, tool, agent, signal) { const fnId = toolCall.id || (0, uuid_1.v4)(); const toolName = toolCall.function.name; const argsString = toolCall.function.arguments || '{}'; let args; try { args = prepareToolArguments(argsString, tool); } catch (error) { throw new Error(`Invalid JSON in tool arguments: ${error}`); } const runningTool = running_tool_tracker_js_1.runningToolTracker.addRunningTool(fnId, toolName, agent.agent_id || 'unknown', argsString); const abortSignal = signal || runningTool.abortController?.signal; try { if (tool.injectAgentId) { args.unshift(agent.agent_id || 'ensemble'); } if (tool.injectAbortSignal && abortSignal) { args.push(abortSignal); } const result = await tool.function(...args); await running_tool_tracker_js_1.runningToolTracker.completeRunningTool(fnId, String(result), agent); return String(result); } catch (error) { await running_tool_tracker_js_1.runningToolTracker.failRunningTool(fnId, String(error), agent); throw error; } } async function handleToolCall(toolCall, tool, agent) { const fnId = toolCall.id || (0, uuid_1.v4)(); const toolName = toolCall.function.name; const executeFunction = async () => { if (toolName === 'wait_for_running_tool') { return executeToolWithLifecycle(toolCall, tool, agent); } return Promise.race([ executeToolWithLifecycle(toolCall, tool, agent), new Promise((_, reject) => { const runningTool = running_tool_tracker_js_1.runningToolTracker.getRunningTool(fnId); if (runningTool?.abortController?.signal) { runningTool.abortController.signal.addEventListener('abort', () => reject(new Error('Operation was aborted')), { once: true }); } }), ]); }; const sequential = !!agent.modelSettings?.sequential_tools; const hasStatusTools = agentHasStatusTracking(agent); const excludedFromTimeout = tool_execution_js_1.EXCLUDED_FROM_TIMEOUT_FUNCTIONS.has(toolName); const shouldTimeout = !excludedFromTimeout && hasStatusTools && !sequential; const execute = sequential ? () => (0, sequential_queue_js_1.runSequential)(agent.agent_id || 'unknown', executeFunction) : executeFunction; if (!shouldTimeout) { return execute(); } const result = await Promise.race([ execute().catch(error => { throw error; }), timeoutPromise(tool_execution_js_1.FUNCTION_TIMEOUT_MS), ]); if (result === 'TIMEOUT') { running_tool_tracker_js_1.runningToolTracker.markTimedOut(fnId); return `Tool ${toolName} is running in the background (RunningTool: ${fnId}).`; } return result; } function prepareToolArguments(argsString, tool) { let args; try { if (!argsString || argsString.trim() === '') { args = {}; } else { args = JSON.parse(argsString); } } catch (error) { throw new Error(`Invalid JSON in tool arguments: ${error}`); } if (typeof args === 'object' && args !== null && !Array.isArray(args)) { const paramNames = Object.keys(tool.definition.function.parameters.properties); Object.keys(args).forEach(key => { if (!paramNames.includes(key)) { console.warn(`Removing unknown parameter "${key}" for tool "${tool.definition.function.name}"`); delete args[key]; } }); if (paramNames.length > 0) { return paramNames.map(param => { const value = args[param]; const paramSpec = tool.definition.function.parameters.properties[param]; if ((value === undefined || value === '') && !tool.definition.function.parameters.required?.includes(param)) { return undefined; } const [coercedValue, error] = (0, tool_parameter_utils_js_1.coerceValue)(value, paramSpec, param); if (error && tool.definition.function.parameters.required?.includes(param)) { throw new Error(JSON.stringify({ error: { param, expected: paramSpec.type + (paramSpec.items?.type ? `<${paramSpec.items.type}>` : ''), received: String(value), message: error, }, })); } else if (error) { console.warn(`Parameter coercion warning for ${param}: ${error}`); } return coercedValue; }); } return Object.values(args); } return [args]; } //# sourceMappingURL=tool_execution_manager.js.map