UNPKG

n8n

Version:

n8n Workflow Automation Tool

121 lines 5.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createSearchKnowledgeTool = createSearchKnowledgeTool; const tool_1 = require("@n8n/agents/tool"); const node_crypto_1 = require("node:crypto"); const csv_operation_1 = require("./csv.operation"); const file_references_1 = require("./file-references"); const read_operation_1 = require("./read.operation"); const search_operation_1 = require("./search.operation"); const schemas_1 = require("./schemas"); function createSearchKnowledgeTool({ agentId, projectId, knowledgeService, commandService, }) { return new tool_1.Tool('search_knowledge') .description('List, read, search, and query files uploaded to this agent knowledge base. ' + 'Use this when the user asks about uploaded documents or facts likely contained in them.') .systemInstruction('Use search_knowledge to inspect uploaded knowledge files. Do not claim a file says something ' + 'unless you found it via list, search, read, or a CSV operation. Search defaults to output_mode=files_with_matches. ' + 'Use output_mode=count for counts and output_mode=content only after narrowing to a file or exact phrase. ' + 'For conceptual multi-term lookup, use queries with match_mode instead of writing regex by hand. ' + 'Use read for grounded citations. Cite only file names and line ranges from read results. ' + 'Never mention uploaded file ids, relative paths, binary ids, or storage ids to users. ' + 'For unfamiliar CSVs, call csv_profile first. Use csv_query for rows, csv_distinct for possible values, and csv_aggregate for counts or numeric calculations. ' + 'Do not answer from the first CSV row when rowCount is high or truncated; refine filters using ambiguity hints.') .input(schemas_1.searchKnowledgeInputSchema) .output(schemas_1.searchKnowledgeOutputSchema) .handler(async (input) => { let parsedInput; try { parsedInput = (0, schemas_1.parseSearchKnowledgeInput)(input); } catch (error) { return { operation: (0, schemas_1.getSearchKnowledgeOperation)(input), files: [], error: toToolErrorMessage(error), }; } if (parsedInput.operation === 'list') { try { return { operation: 'list', files: await knowledgeService.listWorkspaceFiles(agentId, projectId), }; } catch (error) { return { operation: 'list', files: [], error: toToolErrorMessage(error), }; } } let files = []; try { const fileReferences = (0, file_references_1.getRequiredFileReferences)(parsedInput); files = await knowledgeService.resolveWorkspaceFiles(agentId, projectId, fileReferences); const cacheKey = buildWorkspaceCacheKey(projectId, agentId, files); return await commandService.withCachedWorkspace(cacheKey, async (workspaceRoot) => { await knowledgeService.materializeWorkspace(agentId, projectId, workspaceRoot, { fileReferences, }); }, async (workspaceRoot) => await handleKnowledgeOperation(parsedInput, workspaceRoot, files, commandService)); } catch (error) { return { operation: parsedInput.operation, files, error: toToolErrorMessage(error), }; } }) .build(); } function buildWorkspaceCacheKey(projectId, agentId, files) { const signature = files .map((file) => `${file.relativePath}:${file.fileSizeBytes}`) .sort() .join('|'); return `${projectId}:${agentId}:${(0, node_crypto_1.createHash)('sha1').update(signature).digest('hex')}`; } function toToolErrorMessage(error) { const message = error instanceof Error ? error.message : String(error); return message.replace(/(^|[\s'"(])\/(?:[^\s'"()]+\/)*[^\s'"()]+/g, '$1[path]'); } async function handleKnowledgeOperation(input, workspaceRoot, files, commandService) { switch (input.operation) { case 'list': return { operation: 'list', files, }; case 'search': return await (0, search_operation_1.runSearchOperation)(input, workspaceRoot, files, commandService); case 'read': return await (0, read_operation_1.runReadOperation)(input, workspaceRoot, files, commandService); case 'csv_query': return { operation: 'csv_query', files, csv: await (0, csv_operation_1.queryCsv)(workspaceRoot, files, input), }; case 'csv_profile': return { operation: 'csv_profile', files, csvProfile: await (0, csv_operation_1.profileCsv)(workspaceRoot, files, input), }; case 'csv_distinct': return { operation: 'csv_distinct', files, csvDistinct: await (0, csv_operation_1.distinctCsv)(workspaceRoot, files, input), }; case 'csv_aggregate': return { operation: 'csv_aggregate', files, csvAggregate: await (0, csv_operation_1.aggregateCsv)(workspaceRoot, files, input), }; } } //# sourceMappingURL=tool.js.map