UNPKG

@just-every/ensemble

Version:

LLM provider abstraction layer with unified streaming interface

211 lines 10.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createSummary = createSummary; exports.read_source = read_source; exports.write_source = write_source; exports.getSummaryTools = getSummaryTools; exports.hasExpansionTools = hasExpansionTools; const promises_1 = __importDefault(require("fs/promises")); const path_1 = __importDefault(require("path")); const crypto_1 = __importDefault(require("crypto")); const create_tool_function_js_1 = require("./create_tool_function.cjs"); const SUMMARIZE_AT_CHARS = 5000; const SUMMARIZE_TRUNCATE_CHARS = 200000; const HASH_MAP_FILENAME = 'summary_hash_map.json'; async function ensureDir(dir) { try { await promises_1.default.mkdir(dir, { recursive: true }); } catch (error) { if (error.code !== 'EEXIST') { throw error; } } } async function loadHashMap(file_path) { try { const data = await promises_1.default.readFile(file_path, 'utf-8'); return JSON.parse(data); } catch (error) { if (error.code === 'ENOENT') { return {}; } console.error(`Error loading summary hash map from ${file_path}:`, error); return {}; } } async function saveHashMap(file_path, map) { try { const data = JSON.stringify(map, null, 2); await promises_1.default.writeFile(file_path, data, 'utf-8'); } catch (error) { console.error(`Error saving summary hash map to ${file_path}:`, error); } } function truncate(text, length = SUMMARIZE_TRUNCATE_CHARS, separator = '\n\n...[truncated for summary]...\n\n') { text = text.trim(); if (text.length <= length) { return text; } return text.substring(0, length * 0.3) + separator + text.substring(text.length - length * 0.7 + separator.length); } async function createSummary(document, context, summaryFn, includeExpansionReferences = false, summariesDir) { if (document.length <= SUMMARIZE_AT_CHARS) { return document; } const finalSummariesDir = summariesDir || './summaries'; await ensureDir(finalSummariesDir); const hashMapPath = path_1.default.join(finalSummariesDir, HASH_MAP_FILENAME); const documentHash = crypto_1.default.createHash('sha256').update(document).digest('hex'); const hashMap = await loadHashMap(hashMapPath); if (hashMap[documentHash]) { const summaryId = hashMap[documentHash]; const summaryFilePath = path_1.default.join(finalSummariesDir, `summary-${summaryId}.txt`); const originalFilePath = path_1.default.join(finalSummariesDir, `original-${summaryId}.txt`); try { const [existingSummary, originalDoc] = await Promise.all([ promises_1.default.readFile(summaryFilePath, 'utf-8'), promises_1.default.readFile(originalFilePath, 'utf-8'), ]); const originalLines = originalDoc.split('\n').length; const summaryLines = existingSummary.split('\n').length; const originalChars = originalDoc.length; const summaryChars = existingSummary.length; const metadata = includeExpansionReferences ? `\n\nSummarized large output to avoid excessive tokens (${originalLines} -> ${summaryLines} lines, ${originalChars} -> ${summaryChars} chars) [Write to file with write_source(${summaryId}, file_path) or read with read_source(${summaryId}, line_start, line_end)]` : `\n\nSummarized large output to avoid excessive tokens (${originalLines} -> ${summaryLines} lines, ${originalChars} -> ${summaryChars} chars)`; console.log(`Retrieved summary from cache for hash: ${documentHash.substring(0, 8)}...`); return existingSummary.trim() + metadata; } catch (error) { console.error(`Error reading cached summary files for ID ${summaryId}:`, error); delete hashMap[documentHash]; await saveHashMap(hashMapPath, hashMap); } } const originalDocumentForSave = document; const originalLines = originalDocumentForSave.split('\n').length; document = truncate(document); const summary = await summaryFn(document, context); const trimmedSummary = summary.trim(); const summaryLines = trimmedSummary.split('\n').length; const newSummaryId = crypto_1.default.randomUUID(); const summaryFilePath = path_1.default.join(finalSummariesDir, `summary-${newSummaryId}.txt`); const originalFilePath = path_1.default.join(finalSummariesDir, `original-${newSummaryId}.txt`); try { await Promise.all([ promises_1.default.writeFile(summaryFilePath, trimmedSummary, 'utf-8'), promises_1.default.writeFile(originalFilePath, originalDocumentForSave, 'utf-8'), ]); hashMap[documentHash] = newSummaryId; await saveHashMap(hashMapPath, hashMap); console.log(`Saved new summary with ID: ${newSummaryId} for hash: ${documentHash.substring(0, 8)}...`); } catch (error) { console.error(`Error saving new summary files for ID ${newSummaryId}:`, error); return trimmedSummary; } const originalChars = originalDocumentForSave.length; const summaryChars = trimmedSummary.length; const metadata = includeExpansionReferences ? `\n\nSummarized large output to avoid excessive tokens (${originalLines} -> ${summaryLines} lines, ${originalChars} -> ${summaryChars} chars) [Write to file with write_source(${newSummaryId}, file_path) or read with read_source(${newSummaryId}, line_start, line_end)]` : `\n\nSummarized large output to avoid excessive tokens (${originalLines} -> ${summaryLines} lines, ${originalChars} -> ${summaryChars} chars)`; return trimmedSummary + metadata; } async function read_source(summary_id, line_start, line_end, summariesDir) { const finalSummariesDir = summariesDir || './summaries'; const originalFilePath = path_1.default.join(finalSummariesDir, `original-${summary_id}.txt`); try { let content = await promises_1.default.readFile(originalFilePath, 'utf-8'); if (line_start !== undefined && line_end !== undefined) { const lines = content.split('\n'); const start = Math.max(0, line_start); const end = Math.min(lines.length, line_end + 1); if (start >= end || start >= lines.length) { return `Error: Invalid line range requested (${line_start}-${line_end}) for document with ${lines.length} lines.`; } content = lines.slice(start, end).join('\n'); } return content; } catch (error) { if (error.code === 'ENOENT') { return `Error: Original document for summary ID '${summary_id}' not found at ${originalFilePath}.`; } console.error(`Error reading original summary source for ID ${summary_id}:`, error); return `Error: Could not retrieve original document for summary ID '${summary_id}'.`; } } async function write_source(summary_id, file_path, summariesDir) { const finalSummariesDir = summariesDir || './summaries'; const originalFilePath = path_1.default.join(finalSummariesDir, `original-${summary_id}.txt`); try { const content = await promises_1.default.readFile(originalFilePath, 'utf-8'); if (!file_path) { return 'Error: file_path is required.'; } try { const directory = path_1.default.dirname(file_path); await promises_1.default.mkdir(directory, { recursive: true }); await promises_1.default.writeFile(file_path, content, 'utf-8'); console.log(`Summary written to file: ${file_path}`); return `Successfully wrote ${content.length} chars to file: ${file_path}\n\nStart of content:\n\n${content.substring(0, 400)}...`; } catch (writeError) { console.error(`Error writing summary to file ${file_path}:`, writeError); return `Error: Could not write summary to file ${file_path}.`; } } catch (error) { if (error.code === 'ENOENT') { return `Error: Original document for summary ID '${summary_id}' not found at ${originalFilePath}.`; } console.error(`Error reading original summary source for ID ${summary_id}:`, error); return `Error: Could not retrieve original document for summary ID '${summary_id}'.`; } } function getSummaryTools(summariesDir) { const readSourceWrapper = async (summary_id, line_start, line_end) => { return read_source(summary_id, line_start, line_end, summariesDir); }; const writeSourceWrapper = async (summary_id, file_path) => { return write_source(summary_id, file_path, summariesDir); }; return [ (0, create_tool_function_js_1.createToolFunction)(readSourceWrapper, 'Read the original (not summarized) document content. If possible, limit lines to limit tokens returned. Results will be truncated to 1000 characters - for larger files, use write_source.', { summary_id: { type: 'string', description: 'The unique ID of the summary.', }, line_start: { type: 'number', description: 'Starting line to retrieve (0-based). Optional.', optional: true, }, line_end: { type: 'number', description: 'Ending line to retrieve (0-based). Optional.', optional: true, }, }), (0, create_tool_function_js_1.createToolFunction)(writeSourceWrapper, 'Write the original (not summarized) document to a file.', { summary_id: { type: 'string', description: 'The unique ID of the summary.', }, file_path: { type: 'string', description: 'Relative or absolute path to write the document to.', }, }), ]; } function hasExpansionTools(toolNames) { return toolNames.includes('write_source') && toolNames.includes('read_source'); } //# sourceMappingURL=summary_utils.js.map