UNPKG

packfs-core

Version:

Semantic filesystem operations for LLM agent frameworks with natural language understanding. See LLM_AGENT_GUIDE.md for copy-paste examples.

587 lines 24.6 kB
"use strict"; /** * LlamaIndex.TS integration for PackFS semantic filesystem * LlamaIndex TypeScript - https://www.llamaindex.ai/ */ Object.defineProperty(exports, "__esModule", { value: true }); exports.LlamaIndexSemanticFilesystemTool = void 0; exports.createLlamaIndexSemanticFilesystemTool = createLlamaIndexSemanticFilesystemTool; exports.createLlamaIndexSemanticToolSpec = createLlamaIndexSemanticToolSpec; exports.createLlamaIndexSemanticToolSuite = createLlamaIndexSemanticToolSuite; /** * PackFS semantic filesystem tool for LlamaIndex.TS * Compatible with LlamaIndex's function calling and agent frameworks */ class LlamaIndexSemanticFilesystemTool { createTool(config) { return { metadata: { name: 'semantic_filesystem', description: this.getToolDescription().description, parameters: this.getLlamaIndexParameters(), }, call: async (input) => { try { const result = await this.executeOperation(config, input); return this.formatLlamaIndexResponse(result); } catch (error) { throw new Error(`Semantic filesystem error: ${error instanceof Error ? error.message : 'Unknown error'}`); } }, }; } getToolDescription() { return { name: 'semantic_filesystem', description: 'Intelligent file system operations with semantic understanding. Supports natural language queries for reading, writing, searching, and organizing files.', parameters: { type: 'object', properties: { action: { type: 'string', description: 'The type of file operation to perform', enum: ['read', 'write', 'search', 'list', 'organize', 'delete', 'natural_query'], }, query: { type: 'string', description: 'Natural language description of the operation (e.g., "read the configuration file", "find all documentation files")', }, path: { type: 'string', description: 'Specific file or directory path', }, content: { type: 'string', description: 'Content to write when creating or updating files', }, searchTerm: { type: 'string', description: 'Search term or pattern for finding files', }, options: { type: 'object', description: 'Additional options for the operation', }, }, required: ['action'], }, examples: [ { input: '{"action": "natural_query", "query": "read the README file"}', description: 'Use natural language to read a file', }, { input: '{"action": "write", "path": "notes.txt", "content": "My important notes"}', description: 'Create a new file with content', }, { input: '{"action": "search", "searchTerm": "configuration", "options": {"fileTypes": ["json", "yaml"]}}', description: 'Search for configuration files', }, ], }; } validateParameters(params) { const errors = []; if (!params.action) { errors.push('Action is required'); } // Validate action-specific requirements switch (params.action) { case 'read': if (!params.path && !params.query) { errors.push('Read action requires either path or query'); } break; case 'write': if (!params.path) { errors.push('Write action requires path'); } if (!params.content && !params.query) { errors.push('Write action requires content or query'); } break; case 'search': if (!params.searchTerm && !params.query) { errors.push('Search action requires searchTerm or query'); } break; case 'organize': if (!params.source && !params.query) { errors.push('Organize action requires source or query'); } break; case 'delete': if (!params.path && !params.query) { errors.push('Delete action requires path or query'); } break; case 'natural_query': if (!params.query) { errors.push('Natural query action requires query'); } break; } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : undefined, }; } getLlamaIndexParameters() { return { type: 'object', properties: { action: { type: 'string', description: 'The type of file operation to perform', enum: ['read', 'write', 'search', 'list', 'organize', 'delete', 'natural_query'], }, query: { type: 'string', description: 'Natural language description of the operation', }, path: { type: 'string', description: 'Specific file or directory path', }, content: { type: 'string', description: 'Content to write when creating or updating files', }, searchTerm: { type: 'string', description: 'Search term or pattern for finding files', }, source: { type: 'string', description: 'Source path for move/copy operations', }, destination: { type: 'string', description: 'Destination path for move/copy operations', }, options: { type: 'object', description: 'Additional options for the operation', }, }, required: ['action'], }; } async executeOperation(config, input) { const startTime = Date.now(); // Validate parameters const validation = this.validateParameters(input); if (!validation.valid) { return { success: false, error: `Invalid parameters: ${validation.errors?.join(', ')}`, }; } try { let result; // Handle natural language queries if (input.action === 'natural_query' || (input.query && !input.path && !input.searchTerm)) { result = await this.executeNaturalLanguageQuery(config, input.query); } else { result = await this.executeStructuredAction(config, input); } return { success: true, data: result, metadata: { executionTime: Date.now() - startTime, operationType: input.action, filesAccessed: this.extractFilesAccessed(input, result), }, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Unknown error', }; } } async executeNaturalLanguageQuery(config, query) { // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } const nlResult = await config.filesystem.interpretNaturalLanguage({ query, context: { workingDirectory: config.workingDirectory, }, }); if (!nlResult.success) { throw new Error(`Failed to interpret query: ${nlResult.message}`); } // Execute the interpreted intent const intent = nlResult.interpretedIntent; if ('purpose' in intent) { switch (intent.purpose) { case 'read': case 'preview': case 'metadata': case 'verify_exists': case 'create_or_get': // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } return await config.filesystem.accessFile(intent); case 'create': case 'append': case 'overwrite': case 'merge': case 'patch': // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } return await config.filesystem.updateContent(intent); case 'create_directory': case 'move': case 'copy': case 'group_semantic': case 'group_keywords': // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } return await config.filesystem.organizeFiles(intent); case 'list': case 'find': case 'search_content': case 'search_semantic': case 'search_integrated': // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } return await config.filesystem.discoverFiles(intent); case 'delete_file': case 'delete_directory': case 'delete_by_criteria': // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } return await config.filesystem.removeFiles(intent); } } // Handle workflow intents - only if it has workflow structure if ('steps' in intent) { // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } return await config.filesystem.executeWorkflow(intent); } throw new Error('Unrecognized intent type'); } async executeStructuredAction(config, input) { // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } switch (input.action) { case 'read': return await config.filesystem.accessFile({ purpose: 'read', target: { path: input.path }, preferences: input.options, }); case 'write': return await config.filesystem.updateContent({ purpose: input.append ? 'append' : 'create', target: { path: input.path }, content: input.content, options: input.options, }); case 'search': return await config.filesystem.discoverFiles({ purpose: 'search_semantic', target: { semanticQuery: input.searchTerm, criteria: input.options?.fileTypes ? { type: input.options.fileTypes } : undefined, }, options: input.options, }); case 'list': return await config.filesystem.discoverFiles({ purpose: 'list', target: { path: input.path || '.' }, options: input.options, }); case 'organize': const orgPurpose = input.operation || (input.destination ? 'move' : 'create_directory'); return await config.filesystem.organizeFiles({ purpose: orgPurpose, source: input.source ? { path: input.source } : undefined, destination: { path: input.destination || input.path }, options: input.options, }); case 'delete': return await config.filesystem.removeFiles({ purpose: 'delete_file', target: { path: input.path }, options: input.options, }); default: throw new Error(`Unknown action: ${input.action}`); } } formatLlamaIndexResponse(result) { if (!result.success) { throw new Error(result.error || 'Operation failed'); } const data = result.data; // Return structured data for LlamaIndex to process return { success: true, data: data, metadata: result.metadata, }; } extractFilesAccessed(input, result) { const files = []; if (input.path) files.push(input.path); if (input.source) files.push(input.source); if (input.destination) files.push(input.destination); if (result.files && Array.isArray(result.files)) { files.push(...result.files.map((f) => f.path)); } return files; } } exports.LlamaIndexSemanticFilesystemTool = LlamaIndexSemanticFilesystemTool; /** * Create a LlamaIndex.TS compatible semantic filesystem tool */ function createLlamaIndexSemanticFilesystemTool(config) { const adapter = new LlamaIndexSemanticFilesystemTool(); return adapter.createTool(config); } /** * Create a LlamaIndex ToolSpec for the semantic filesystem * This format is used for agent tool registration */ function createLlamaIndexSemanticToolSpec(config) { const adapter = new LlamaIndexSemanticFilesystemTool(); const description = adapter.getToolDescription(); return { name: description.name, description: description.description, parameters: description.parameters, fn: async (params) => { const tool = adapter.createTool(config); const result = await tool.call(params); // Convert result to string for LlamaIndex if (typeof result === 'string') { return result; } return JSON.stringify(result, null, 2); }, }; } /** * Create specialized LlamaIndex tools for different file operations */ function createLlamaIndexSemanticToolSuite(config) { return { fileReader: { metadata: { name: 'read_file', description: 'Read file content using path or natural language description', parameters: { type: 'object', properties: { query: { type: 'string', description: 'Natural language file description or direct path', }, includeMetadata: { type: 'boolean', description: 'Include file metadata in response' }, }, required: ['query'], }, }, call: async (input) => { // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } let target; if (input.query.includes('/') || input.query.includes('.')) { target = { path: input.query }; } else { target = { semanticQuery: input.query }; } const result = await config.filesystem.accessFile({ purpose: 'read', target, preferences: { includeMetadata: input.includeMetadata }, }); if (!result.success) { throw new Error(result.message || 'Failed to read file'); } return { content: result.content, metadata: result.metadata, exists: result.exists, }; }, }, fileWriter: { metadata: { name: 'write_file', description: 'Create or update files with content', parameters: { type: 'object', properties: { path: { type: 'string', description: 'File path to write to' }, content: { type: 'string', description: 'Content to write' }, mode: { type: 'string', enum: ['create', 'append', 'overwrite'], description: 'Write mode', }, createPath: { type: 'boolean', description: 'Create directory path if needed' }, }, required: ['path', 'content'], }, }, call: async (input) => { // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } const result = await config.filesystem.updateContent({ purpose: input.mode || 'create', target: { path: input.path }, content: input.content, options: { createPath: input.createPath }, }); if (!result.success) { throw new Error(result.message || 'Failed to write file'); } return { bytesWritten: result.bytesWritten, created: result.created, path: input.path, }; }, }, fileSearcher: { metadata: { name: 'search_files', description: 'Search for files using semantic queries or patterns', parameters: { type: 'object', properties: { query: { type: 'string', description: 'Search query (semantic or pattern)' }, maxResults: { type: 'number', description: 'Maximum results to return' }, fileTypes: { type: 'array', items: { type: 'string' }, description: 'File extensions to filter by', }, includeContent: { type: 'boolean', description: 'Include file content in results' }, }, required: ['query'], }, }, call: async (input) => { // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } const result = await config.filesystem.discoverFiles({ purpose: 'search_semantic', target: { semanticQuery: input.query, criteria: input.fileTypes ? { type: input.fileTypes } : undefined, }, options: { maxResults: input.maxResults, includeContent: input.includeContent, }, }); if (!result.success) { throw new Error(result.message || 'Search failed'); } return { files: result.files, totalFound: result.totalFound, searchTime: result.searchTime, }; }, }, fileManager: { metadata: { name: 'manage_files', description: 'Move, copy, delete, and organize files', parameters: { type: 'object', properties: { action: { type: 'string', enum: ['move', 'copy', 'delete', 'mkdir'], description: 'Management action', }, source: { type: 'string', description: 'Source path' }, destination: { type: 'string', description: 'Destination path (for move/copy)' }, recursive: { type: 'boolean', description: 'Apply recursively' }, }, required: ['action', 'source'], }, }, call: async (input) => { // Ensure filesystem is initialized if (!config.filesystem) { throw new Error('Filesystem is not initialized. Please provide a valid filesystem or workingDirectory.'); } let result; switch (input.action) { case 'move': case 'copy': result = await config.filesystem.organizeFiles({ purpose: input.action, source: { path: input.source }, destination: { path: input.destination }, options: { recursive: input.recursive }, }); break; case 'delete': result = await config.filesystem.removeFiles({ purpose: 'delete_file', target: { path: input.source }, options: { recursive: input.recursive }, }); break; case 'mkdir': result = await config.filesystem.organizeFiles({ purpose: 'create_directory', destination: { path: input.source }, options: { recursive: input.recursive }, }); break; default: throw new Error(`Unknown action: ${input.action}`); } if (!result.success) { throw new Error(result.message || 'File management operation failed'); } return result; }, }, }; } //# sourceMappingURL=llamaindex-ts.js.map