UNPKG

@unified-llm/core

Version:

Unified LLM interface (in-memory).

111 lines 4.55 kB
import { sanitizeToolCallResult } from "../mcp-utils.js"; import { logTimed, toModelSafeError } from "../logging.js"; import { createDefaultClock } from "../timing.js"; export const NOOP_LOGGER = { debug: () => { }, info: () => { }, warn: () => { }, error: () => { }, child: () => NOOP_LOGGER, }; function safeJsonParse(value, fallback) { if (!value) return fallback; try { return JSON.parse(value); } catch (_a) { return fallback; } } /** * tool call を実行して結果を文字列として返す(プロバイダー非依存)。 * * - localToolHandlers が該当すれば優先 * - それ以外は MCP に委譲 * - 例外は握りつぶして `{ ok:false, error }` を output に詰める(LLMループを止めない) * - sanitizeToolCallResult を適用して安全化 */ export async function executeToolCalls(toolCalls, toolNameToClient, localToolHandlers, options) { var _a, _b; const logger = (_a = options === null || options === void 0 ? void 0 : options.logger) !== null && _a !== void 0 ? _a : NOOP_LOGGER; const clock = (_b = options === null || options === void 0 ? void 0 : options.clock) !== null && _b !== void 0 ? _b : createDefaultClock(); const tasks = toolCalls.map(async (call) => { var _a; if (!call.callId) { throw new Error(`Missing callId for tool call: ${call.name}`); } const args = typeof call.arguments === "string" ? safeJsonParse(call.arguments, {}) : (_a = call.arguments) !== null && _a !== void 0 ? _a : {}; try { const localHandler = localToolHandlers === null || localToolHandlers === void 0 ? void 0 : localToolHandlers.get(call.name); if (localHandler) { logger.info("tool.call.request", { tool: call.name, call_id: call.callId, kind: "local", args: JSON.stringify(args), }); const result = await logTimed(logger, clock, "tool.call.completed", { tool: call.name, call_id: call.callId, kind: "local", args_keys_count: Object.keys(args).length, }, async () => localHandler(args), "info"); const outputText = typeof result === "string" ? result : JSON.stringify(result !== null && result !== void 0 ? result : { ok: true }); logger.info("tool.call.result", { tool: call.name, call_id: call.callId, kind: "local", result: outputText, }); return { name: call.name, callId: call.callId, output: outputText }; } const mcpClient = toolNameToClient.get(call.name); if (!mcpClient) { throw new Error(`No MCP client registered for tool: ${call.name}`); } logger.info("tool.call.request", { tool: call.name, call_id: call.callId, kind: "mcp", args: JSON.stringify(args), }); const result = await logTimed(logger, clock, "tool.call.completed", { tool: call.name, call_id: call.callId, kind: "mcp", args_keys_count: Object.keys(args).length, }, async () => mcpClient.callTool({ name: call.name, arguments: args }), "info"); const { sanitizedResult } = sanitizeToolCallResult(result); logger.info("tool.call.result", { tool: call.name, call_id: call.callId, kind: "mcp", result: JSON.stringify(sanitizedResult), }); return { name: call.name, callId: call.callId, output: JSON.stringify(sanitizedResult), }; } catch (err) { logger.error("tool.call.failed", { tool: call.name, call_id: call.callId, error: toModelSafeError(err), }); return { name: call.name, callId: call.callId, output: JSON.stringify({ ok: false, error: toModelSafeError(err) }), }; } }); return Promise.all(tasks); } //# sourceMappingURL=execute-tool-calls.js.map