UNPKG

lynkr

Version:

Self-hosted LLM gateway and tier-routing proxy for Claude Code, Cursor, and Codex. Routes across Ollama, AWS Bedrock, OpenRouter, Databricks, Azure OpenAI, llama.cpp, and LM Studio with prompt caching, MCP tools, and 60-80% cost savings.

207 lines (176 loc) 6.21 kB
/** * Smart Payload Cloning & Size Estimation * * Optimizes deep-cloning of LLM request payloads to avoid * wasting memory on large base64 media blocks that will be * discarded by flattenBlocks() for most providers. * * @module utils/payload */ const logger = require('../logger'); /** * Estimate the byte size of message content without full serialization. * Scans for base64 image/audio data blocks and text blocks. * * @param {Object} payload - Request payload * @returns {number} Estimated size in bytes */ function estimateContentSize(payload) { if (!payload || !Array.isArray(payload.messages)) return 0; let size = 0; for (const msg of payload.messages) { if (!msg) continue; if (typeof msg.content === 'string') { size += msg.content.length; continue; } if (!Array.isArray(msg.content)) continue; for (const block of msg.content) { if (!block || typeof block !== 'object') continue; if (block.text) { size += block.text.length; } // Anthropic image format if (block.source?.data) { size += block.source.data.length; } // OpenAI image_url format (inline base64) if (block.image_url?.url && block.image_url.url.startsWith('data:')) { size += block.image_url.url.length; } // tool_result content if (block.type === 'tool_result' && typeof block.content === 'string') { size += block.content.length; } } } return size; } /** * Check if any message content block has base64 media data exceeding threshold. * * @param {Object} payload - Request payload * @param {number} threshold - Size threshold in bytes (default 1MB) * @returns {boolean} */ function hasLargeMedia(payload, threshold = 1_048_576) { if (!payload || !Array.isArray(payload.messages)) return false; for (const msg of payload.messages) { if (!msg || !Array.isArray(msg.content)) continue; for (const block of msg.content) { if (!block || typeof block !== 'object') continue; // Anthropic base64 image if (block.source?.data && block.source.data.length > threshold) { return true; } // OpenAI inline base64 image if (block.image_url?.url && block.image_url.url.length > threshold) { return true; } } } return false; } // Block types that flattenBlocks() discards (returns empty string) const HEAVY_BLOCK_TYPES = new Set(['image', 'audio', 'image_url', 'video']); /** * Check if a content block is a heavy media block that flattenBlocks() discards. * @param {Object} block * @returns {boolean} */ function isHeavyMediaBlock(block) { if (!block || typeof block !== 'object') return false; if (HEAVY_BLOCK_TYPES.has(block.type)) return true; if (block.source?.type === 'base64') return true; return false; } /** * Clone payload optimized for providers that will flatten content. * Skips cloning heavy media blocks since flattenBlocks() discards them. * * @param {Object} payload * @returns {Object} Cloned payload with media placeholders */ function cloneWithFlattenAwareness(payload) { const clean = { ...payload }; // Deep-clone messages array but skip heavy media blocks if (Array.isArray(payload.messages)) { clean.messages = payload.messages.map(msg => { if (!msg) return msg; const cloned = { ...msg }; if (Array.isArray(msg.content)) { cloned.content = msg.content.map(block => { if (!block || typeof block !== 'object') return block; // Skip heavy media blocks — flattenBlocks() produces "" for these if (isHeavyMediaBlock(block)) { return { type: block.type, _skipped: true }; } // Shallow clone small blocks (text, tool_result, tool_use) if (block.type === 'tool_result' && typeof block.content === 'object') { return { ...block, content: JSON.parse(JSON.stringify(block.content)) }; } return { ...block }; }); } else if (typeof msg.content === 'object' && msg.content !== null) { cloned.content = { ...msg.content }; } // Clone tool_calls if present if (Array.isArray(msg.tool_calls)) { cloned.tool_calls = JSON.parse(JSON.stringify(msg.tool_calls)); } return cloned; }); } // Deep-clone small arrays that get mutated if (Array.isArray(payload.tools)) { clean.tools = JSON.parse(JSON.stringify(payload.tools)); } if (Array.isArray(payload.system)) { clean.system = JSON.parse(JSON.stringify(payload.system)); } else if (typeof payload.system === 'string') { clean.system = payload.system; } return clean; } /** * Smart deep-clone a request payload. * * - If willFlatten is true: skips cloning heavy media blocks (they'll be discarded) * - If willFlatten is false: uses structuredClone (faster than JSON round-trip) * - Falls back to JSON.parse(JSON.stringify()) for compatibility * * @param {Object} payload - Request payload to clone * @param {Object} options * @param {boolean} options.willFlatten - Whether flattenBlocks() will run (true for most providers) * @returns {Object} Cloned payload */ function clonePayloadSmart(payload, options = {}) { if (!payload) return {}; const { willFlatten = false } = options; // Fast path: provider will flatten content — skip cloning media blocks if (willFlatten && Array.isArray(payload.messages)) { const hasMedia = payload.messages.some(msg => Array.isArray(msg?.content) && msg.content.some(isHeavyMediaBlock) ); if (hasMedia) { logger.debug('[payload] Using flatten-aware clone (skipping media blocks)'); return cloneWithFlattenAwareness(payload); } } // Medium path: structuredClone (faster, no string intermediate) if (typeof structuredClone === 'function') { try { return structuredClone(payload); } catch { // structuredClone can fail on functions, symbols, etc. } } // Slow path: JSON round-trip (original behavior) return JSON.parse(JSON.stringify(payload)); } module.exports = { estimateContentSize, hasLargeMedia, clonePayloadSmart, isHeavyMediaBlock, };