packfs-core
Version:
Semantic filesystem operations for LLM agent frameworks with natural language understanding. See LLM_AGENT_GUIDE.md for copy-paste examples.
414 lines • 13.6 kB
JavaScript
;
/**
* Intent processing utilities for semantic filesystem operations
* Handles intent parsing, optimization, and traditional operation conversion
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkflowBuilder = exports.NaturalLanguageProcessor = exports.FileTargetProcessor = exports.SemanticIntentOptimizer = exports.TraditionalToSemanticConverter = void 0;
/**
* Converts traditional filesystem method calls to semantic intents
* Enables backward compatibility by translating old-style calls
*/
class TraditionalToSemanticConverter {
/**
* Convert readFile() call to FileAccessIntent
*/
static readFileToIntent(path, options) {
return {
purpose: 'read',
target: { path },
preferences: {
encoding: options?.encoding,
includeMetadata: false
}
};
}
/**
* Convert writeFile() call to ContentUpdateIntent
*/
static writeFileToIntent(path, data, options) {
return {
purpose: 'overwrite',
target: { path },
content: data,
options: {
createPath: options?.createDirs ?? false,
mode: options?.mode
}
};
}
/**
* Convert stat() call to FileAccessIntent
*/
static statToIntent(path) {
return {
purpose: 'metadata',
target: { path },
preferences: {
includeMetadata: true
}
};
}
/**
* Convert exists() call to FileAccessIntent
*/
static existsToIntent(path) {
return {
purpose: 'verify_exists',
target: { path }
};
}
/**
* Convert mkdir() call to OrganizationIntent
*/
static mkdirToIntent(path, options) {
return {
purpose: 'create_directory',
destination: { path },
options: {
recursive: options?.recursive ?? false
}
};
}
/**
* Convert readdir() call to DiscoveryIntent
*/
static readdirToIntent(path, options) {
return {
purpose: 'list',
target: { path },
options: {
recursive: options?.recursive ?? false,
includeContent: false
}
};
}
/**
* Convert unlink() call to RemovalIntent
*/
static unlinkToIntent(path) {
return {
purpose: 'delete_file',
target: { path }
};
}
}
exports.TraditionalToSemanticConverter = TraditionalToSemanticConverter;
/**
* Optimizes and enhances semantic intents based on context and patterns
*/
class SemanticIntentOptimizer {
/**
* Optimize FileAccessIntent based on usage patterns
*/
static optimizeAccessIntent(intent, context) {
const optimized = { ...intent };
// If accessing a recently used file for reading, suggest including metadata
if (intent.purpose === 'read' && context?.recentFiles?.includes(intent.target.path || '')) {
optimized.preferences = {
...optimized.preferences,
includeMetadata: true
};
}
// For large file access, suggest chunking
if (intent.purpose === 'read' && !intent.preferences?.chunkingStrategy) {
optimized.preferences = {
...optimized.preferences,
chunkingStrategy: 'semantic'
};
}
return optimized;
}
/**
* Optimize DiscoveryIntent to improve search efficiency
*/
static optimizeDiscoveryIntent(intent) {
const optimized = { ...intent };
// For semantic searches, limit results and sort by relevance
if (intent.purpose === 'search_semantic' || intent.purpose === 'search_integrated') {
optimized.options = {
maxResults: 50,
sortBy: 'relevance',
...optimized.options
};
}
// For content searches, don't include full content by default
if (intent.purpose === 'search_content') {
optimized.options = {
includeContent: false,
...optimized.options
};
}
return optimized;
}
}
exports.SemanticIntentOptimizer = SemanticIntentOptimizer;
/**
* Analyzes and validates file targets for semantic operations
*/
class FileTargetProcessor {
/**
* Resolve FileTarget to concrete file paths
*/
static async resolveTarget(target, basePath = process.cwd()) {
const paths = [];
// Direct path specification
if (target.path) {
paths.push(this.resolvePath(target.path, basePath));
}
// Pattern-based targeting (glob patterns)
if (target.pattern) {
// Note: In a real implementation, this would use glob library
// For now, return pattern as-is for backend to handle
paths.push(target.pattern);
}
// Semantic query targeting would require vector search
if (target.semanticQuery) {
// This would be handled by the semantic backend
// Return special marker for semantic processing
paths.push(`__semantic:${target.semanticQuery}`);
}
// Criteria-based targeting
if (target.criteria) {
// This would be converted to search parameters
const criteriaStr = JSON.stringify(target.criteria);
paths.push(`__criteria:${criteriaStr}`);
}
return paths.length > 0 ? paths : [basePath];
}
/**
* Validate FileTarget has at least one targeting method
*/
static validateTarget(target) {
return !!(target.path || target.pattern || target.semanticQuery || target.criteria);
}
/**
* Get target type for optimization decisions
*/
static getTargetType(target) {
const types = [];
if (target.path)
types.push('path');
if (target.pattern)
types.push('pattern');
if (target.semanticQuery)
types.push('semantic');
if (target.criteria)
types.push('criteria');
return types.length === 1 ? types[0] : 'mixed';
}
static resolvePath(path, basePath) {
if (path.startsWith('/')) {
return path; // Absolute path
}
return `${basePath}/${path}`.replace(/\/+/g, '/');
}
}
exports.FileTargetProcessor = FileTargetProcessor;
/**
* Natural language processing for intent extraction
*/
class NaturalLanguageProcessor {
/**
* Parse natural language queries into structured intents
* This is a simplified implementation - real version would use NLP models
*/
static parseQuery(query) {
const lowerQuery = query.toLowerCase();
// File writing patterns (check first since create+content is more specific than just content)
if (lowerQuery.includes('write') || lowerQuery.includes('create') || lowerQuery.includes('save')) {
const target = this.extractFileTarget(query);
let content = this.extractContent(query);
// If no explicit content but we're creating something, use a default
if (!content && lowerQuery.includes('create')) {
content = `Created via natural language: ${query}`;
}
// If no specific path but creating a file, generate a reasonable name
if (!target.path && target.semanticQuery && lowerQuery.includes('file')) {
const purpose = query.match(/for\s+(\w+[\s\w]*)/)?.[1] || 'general';
target.path = `${purpose.replace(/\s+/g, '-').toLowerCase()}.txt`;
}
return {
intent: {
purpose: 'create',
target,
content
},
confidence: 0.7
};
}
// File reading patterns
if (lowerQuery.includes('read') || lowerQuery.includes('show') || (lowerQuery.includes('content') && !lowerQuery.includes('with'))) {
return {
intent: {
purpose: 'read',
target: this.extractFileTarget(query)
},
confidence: 0.8
};
}
// File searching patterns
if (lowerQuery.includes('find') || lowerQuery.includes('search') || lowerQuery.includes('look for')) {
return {
intent: {
purpose: 'search_semantic',
target: this.extractFileTarget(query)
},
confidence: 0.75
};
}
// File deletion patterns
if (lowerQuery.includes('delete') || lowerQuery.includes('remove') || lowerQuery.includes('rm')) {
return {
intent: {
purpose: 'delete_file',
target: this.extractFileTarget(query)
},
confidence: 0.9
};
}
// Default to file access with low confidence
return {
intent: {
purpose: 'read',
target: this.extractFileTarget(query)
},
confidence: 0.3
};
}
static extractFileTarget(query) {
// Look for "file called X" or "file named X" patterns first
const calledMatch = query.match(/file\s+(?:called|named)\s+([^\s]+)/i);
if (calledMatch) {
return { path: calledMatch[1] };
}
// Look for common file types by name (README, config, etc.)
const commonFiles = {
'readme': ['readme.md', 'README.md', 'readme.txt', 'README.txt'],
'config': ['config.json', 'config.js', 'config.yaml', 'config.yml'],
'package': ['package.json'],
'license': ['LICENSE', 'LICENSE.txt', 'LICENSE.md']
};
for (const [keyword, filenames] of Object.entries(commonFiles)) {
if (query.toLowerCase().includes(keyword)) {
return { pattern: `*${keyword}*`, semanticQuery: filenames.join(' OR ') };
}
}
// Look for file extensions
const extMatch = query.match(/\b\w+\.\w+\b/);
if (extMatch) {
return { path: extMatch[0] };
}
// Look for quoted filenames (but not content)
const pathMatch = query.match(/["']([^"']*\.[^"']+)["']/);
if (pathMatch) {
return { path: pathMatch[1] };
}
// Fall back to semantic query
return { semanticQuery: query };
}
static extractContent(query) {
// Extract content between quotes or after "with" or "content"
const contentMatch = query.match(/(?:with|containing?|content)\s+["']([^"']+)["']/i);
if (contentMatch && contentMatch[1]) {
return contentMatch[1];
}
// Try to extract any quoted content
const quotedMatch = query.match(/["']([^"']+)["']/);
if (quotedMatch && quotedMatch[1] && !quotedMatch[1].includes('.')) {
// Don't match filenames (containing dots)
return quotedMatch[1];
}
return '';
}
}
exports.NaturalLanguageProcessor = NaturalLanguageProcessor;
/**
* Workflow builder for complex multi-step operations
*/
class WorkflowBuilder {
constructor() {
this.steps = [];
this.stepCounter = 0;
}
/**
* Add a file access step to the workflow
*/
addAccess(intent, dependencies) {
const stepId = `access_${++this.stepCounter}`;
this.steps.push({
operation: 'access',
intent,
dependencies,
id: stepId
});
return stepId;
}
/**
* Add a content update step to the workflow
*/
addUpdate(intent, dependencies) {
const stepId = `update_${++this.stepCounter}`;
this.steps.push({
operation: 'update',
intent,
dependencies,
id: stepId
});
return stepId;
}
/**
* Add an organization step to the workflow
*/
addOrganize(intent, dependencies) {
const stepId = `organize_${++this.stepCounter}`;
this.steps.push({
operation: 'organize',
intent,
dependencies,
id: stepId
});
return stepId;
}
/**
* Add a discovery step to the workflow
*/
addDiscover(intent, dependencies) {
const stepId = `discover_${++this.stepCounter}`;
this.steps.push({
operation: 'discover',
intent,
dependencies,
id: stepId
});
return stepId;
}
/**
* Add a removal step to the workflow
*/
addRemove(intent, dependencies) {
const stepId = `remove_${++this.stepCounter}`;
this.steps.push({
operation: 'remove',
intent,
dependencies,
id: stepId
});
return stepId;
}
/**
* Build the final workflow intent
*/
build(_options) {
return [...this.steps];
}
/**
* Clear all steps and start over
*/
clear() {
this.steps = [];
this.stepCounter = 0;
}
}
exports.WorkflowBuilder = WorkflowBuilder;
//# sourceMappingURL=intent-processor.js.map