UNPKG

n8n-nodes-sap-ai-core

Version:

n8n nodes for SAP AI Core LLM and embeddings integration

169 lines 7.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.N8nLlmTracing = void 0; // N8nLlmTracing.ts const base_1 = require("@langchain/core/callbacks/base"); const n8n_workflow_1 = require("n8n-workflow"); const TIKTOKEN_ESTIMATE_MODEL = 'gpt-4o'; // Simple pick function to avoid lodash dependency function pick(object, keys) { const result = {}; for (const key of keys) { if (key in object) { result[key] = object[key]; } } return result; } class N8nLlmTracing extends base_1.BaseCallbackHandler { constructor(executionFunctions, options) { super(); this.executionFunctions = executionFunctions; this.name = 'N8nLlmTracing'; this.awaitHandlers = true; this.connectionType = "ai_languageModel" /* NodeConnectionType.AiLanguageModel */; this.promptTokensEstimate = 0; this.completionTokensEstimate = 0; this.runsMap = {}; this.options = { // Default(OpenAI format) parser tokensUsageParser: (result) => { var _a, _b, _c, _d, _e, _f; const completionTokens = (_c = (_b = (_a = result === null || result === void 0 ? void 0 : result.llmOutput) === null || _a === void 0 ? void 0 : _a.tokenUsage) === null || _b === void 0 ? void 0 : _b.completionTokens) !== null && _c !== void 0 ? _c : 0; const promptTokens = (_f = (_e = (_d = result === null || result === void 0 ? void 0 : result.llmOutput) === null || _d === void 0 ? void 0 : _d.tokenUsage) === null || _e === void 0 ? void 0 : _e.promptTokens) !== null && _f !== void 0 ? _f : 0; return { completionTokens, promptTokens, totalTokens: completionTokens + promptTokens, }; }, errorDescriptionMapper: (error) => error.description, ...options, }; } async estimateTokensFromGeneration(generations) { const messages = generations.flatMap((gen) => gen.map((g) => g.text)); return await this.estimateTokensFromStringList(messages); } async estimateTokensFromStringList(list) { // Simple token estimation - you might want to implement actual tiktoken const text = list.join(' '); return Math.ceil(text.length / 4); // Rough estimate: 4 chars per token } async handleLLMEnd(output, runId) { var _a; const runDetails = (_a = this.runsMap[runId]) !== null && _a !== void 0 ? _a : { index: Object.keys(this.runsMap).length, options: {}, messages: [] }; output.generations = output.generations.map((gen) => gen.map((g) => pick(g, ['text', 'generationInfo']))); const tokenUsageEstimate = { completionTokens: 0, promptTokens: 0, totalTokens: 0, }; const tokenUsage = this.options.tokensUsageParser(output); if (output.generations.length > 0) { tokenUsageEstimate.completionTokens = await this.estimateTokensFromGeneration(output.generations); tokenUsageEstimate.promptTokens = this.promptTokensEstimate; tokenUsageEstimate.totalTokens = tokenUsageEstimate.completionTokens + this.promptTokensEstimate; } const response = { response: { generations: output.generations }, }; if (tokenUsage.completionTokens > 0) { response.tokenUsage = tokenUsage; } else { response.tokenUsageEstimate = tokenUsageEstimate; } const parsedMessages = typeof runDetails.messages === 'string' ? runDetails.messages : runDetails.messages.map((message) => { if (typeof message === 'string') return message; if (typeof (message === null || message === void 0 ? void 0 : message.toJSON) === 'function') return message.toJSON(); return message; }); const sourceNodeRunIndex = this.parentRunIndex !== undefined ? this.parentRunIndex + runDetails.index : undefined; // Fixed: Use correct number of parameters for addOutputData this.executionFunctions.addOutputData(this.connectionType, runDetails.index, [[{ json: { ...response } }]]); // Log AI event (simplified - you might want to implement actual logging) console.log('AI LLM generated output', { messages: parsedMessages, options: runDetails.options, response, }); } async handleLLMStart(llm, prompts, runId) { var _a; const estimatedTokens = await this.estimateTokensFromStringList(prompts); // Fixed: Create a simple index instead of using getNextRunIndex const currentIndex = Object.keys(this.runsMap).length; const sourceNodeRunIndex = this.parentRunIndex !== undefined ? this.parentRunIndex + currentIndex : undefined; const options = llm.type === 'constructor' ? llm.kwargs : llm; // Fixed: Use addInputData with correct parameters const inputResult = this.executionFunctions.addInputData(this.connectionType, [ [ { json: { messages: prompts, estimatedTokens, options, }, }, ], ]); this.runsMap[runId] = { index: (_a = inputResult === null || inputResult === void 0 ? void 0 : inputResult.index) !== null && _a !== void 0 ? _a : currentIndex, options, messages: prompts, }; this.promptTokensEstimate = estimatedTokens; } async handleLLMError(error, runId, parentRunId) { var _a; const runDetails = (_a = this.runsMap[runId]) !== null && _a !== void 0 ? _a : { index: Object.keys(this.runsMap).length, options: {}, messages: [] }; if (typeof error === 'object' && (error === null || error === void 0 ? void 0 : error.hasOwnProperty('headers'))) { const errorWithHeaders = error; Object.keys(errorWithHeaders.headers).forEach((key) => { if (!key.startsWith('x-')) { delete errorWithHeaders.headers[key]; } }); } if (error instanceof n8n_workflow_1.NodeError) { if (this.options.errorDescriptionMapper) { error.description = this.options.errorDescriptionMapper(error); } this.executionFunctions.addOutputData(this.connectionType, runDetails.index, error); } else { this.executionFunctions.addOutputData(this.connectionType, runDetails.index, new n8n_workflow_1.NodeOperationError(this.executionFunctions.getNode(), error, { functionality: 'configuration-node', })); } // Log AI event (simplified) console.log('AI LLM errored', { error: Object.keys(error).length === 0 ? error.toString() : error, runId, parentRunId, }); } setParentRunIndex(runIndex) { this.parentRunIndex = runIndex; } } exports.N8nLlmTracing = N8nLlmTracing; //# sourceMappingURL=N8nLlmTracing.js.map