@just-every/ensemble
Version:
LLM provider abstraction layer with unified streaming interface
139 lines • 5.98 kB
JavaScript
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
;