UNPKG

n8n

Version:

n8n Workflow Automation Tool

110 lines 4.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createAgentModelTurnRecorder = createAgentModelTurnRecorder; const mock_utils_1 = require("./mock-utils"); const request_sanitizer_1 = require("./request-sanitizer"); const MAX_RECORDED_REQUEST_CHARS = 8_000; const MAX_RECORDED_RESPONSE_CHARS = 16_000; function providerFromUrl(url) { try { const host = new URL(url).hostname; if (host.endsWith('openai.com')) return 'openai'; if (host.endsWith('anthropic.com')) return 'anthropic'; if (host.endsWith('googleapis.com')) return 'google'; if (host.endsWith('openai.azure.com')) return 'azure-openai'; return host; } catch { return undefined; } } function tryParseJson(text) { try { return JSON.parse(text); } catch { return undefined; } } function recordableText(text, maxChars) { const parsed = tryParseJson(text); const serialized = parsed === undefined ? text : JSON.stringify((0, request_sanitizer_1.redactSecretKeys)(parsed)); return (0, request_sanitizer_1.truncateForLlm)((0, request_sanitizer_1.redactSecretValuePatterns)(serialized), maxChars); } function recordableRequestBody(body) { if (typeof body !== 'string') { return body === undefined || body === null ? undefined : '[non-string request body]'; } const parsed = tryParseJson(body); if (parsed === undefined) return (0, request_sanitizer_1.truncateForLlm)((0, request_sanitizer_1.redactSecretValuePatterns)(body), MAX_RECORDED_REQUEST_CHARS); const serialized = (0, request_sanitizer_1.redactSecretValuePatterns)(JSON.stringify((0, request_sanitizer_1.redactSecretKeys)(parsed))); if (serialized.length <= MAX_RECORDED_REQUEST_CHARS) { return tryParseJson(serialized) ?? serialized; } return (0, request_sanitizer_1.truncateForLlm)(serialized, MAX_RECORDED_REQUEST_CHARS); } function stripQuery(url) { const queryStart = url.indexOf('?'); return queryStart === -1 ? url : `${url.slice(0, queryStart)}?[query redacted]`; } function createAgentModelTurnRecorder(baseFetch, logger) { const turns = []; const pendingReads = []; const recordingFetch = async (input, init) => { const url = (0, mock_utils_1.resolveUrl)(input); const turn = { url: stripQuery(url), provider: providerFromUrl(url), streamed: false, requestBody: recordableRequestBody(init?.body), }; turns.push(turn); const startedAt = Date.now(); let response; try { response = await baseFetch(input, init); } catch (error) { turn.durationMs = Date.now() - startedAt; turn.error = error instanceof Error ? error.message : String(error); throw error; } turn.durationMs = Date.now() - startedAt; turn.status = response.status; turn.streamed = (response.headers.get('content-type') ?? '').includes('text/event-stream'); try { const teed = response.clone(); pendingReads.push(teed .text() .then((text) => { turn.responseBody = recordableText(text, MAX_RECORDED_RESPONSE_CHARS); }) .catch((error) => { logger.debug('[EvalAgentMock] Model turn tee failed', { url: stripQuery(url), error: error instanceof Error ? error.message : String(error), }); })); } catch (error) { logger.debug('[EvalAgentMock] Model response clone failed', { url: stripQuery(url), error: error instanceof Error ? error.message : String(error), }); } return response; }; return { fetch: recordingFetch, turns, async flush() { await Promise.allSettled(pendingReads); }, }; } //# sourceMappingURL=agent-model-turn-recorder.js.map