/** * Procedural Memory - Skill-based learning system for intelligent browsing * * This module implements a procedural memory agent that: * - Learns reusable browsing skills from successful trajectories * - Stores skills with vector embeddings for similarity matching * - Retrieves relevant skills based on page context using cosine similarity * - Merges similar skills to prevent redundancy * - Tracks skill performance and adapts over time * * Inspired by: "A Coding Guide to Build a Procedural Memory Agent" * https://www.marktechpost.com/2025/12/09/a-coding-guide-to-build-a-procedural-memory-agent * * Uses PersistentStore for: * - Debounced writes (batches rapid skill updates) * - Atomic writes (temp file + rename for corruption safety) */ import type { VectorStore } from '../utils/vector-store.js'; import type { EmbeddingProvider } from '../utils/embedding-provider.js'; import type { BrowsingSkill, BrowsingAction, BrowsingTrajectory, SkillPreconditions, SkillMatch, PageContext, ProceduralMemoryConfig, SkillWorkflow, CoverageStats, SkillVersion, AntiPattern, SkillExplanation, SkillFeedback, SkillPack, SkillPackMetadata, SkillExportOptions, SkillImportOptions, SkillImportResult, SkillVertical, WorkflowExecutionResult, WorkflowTransitionCondition, CreateWorkflowOptions, WorkflowMatch, WorkflowExecutionOptions } from '../types/index.js'; export declare class ProceduralMemory { private essentialSkills; private domainSpecificSkills; private advancedSkills; private loadedDomains; private get skills(); /** * Set a skill in the appropriate tier-based map. * * Also normalizes the metrics object to ensure backward compatibility * with skills serialized before a field was added. Currently this * means defaulting `lastSuccess` to 0 when missing, since older * skill data on disk doesn't carry it. */ private setSkill; /** * Delete a skill from all tier-based maps */ private deleteSkill; /** * Clear all skills from all tier-based maps */ private clearSkills; private workflows; private trajectoryBuffer; private config; private store; private visitedDomains; private visitedPageTypes; private failedExtractions; private skillVersions; private antiPatterns; private feedbackLog; private vectorStore; private embeddingProvider; constructor(config?: Partial); /** * Set VectorStore and EmbeddingProvider for semantic skill retrieval (LI-006) * When set, retrieveSkills will use semantic search instead of hash-based matching */ setVectorStore(vectorStore: VectorStore, embeddingProvider: EmbeddingProvider): void; /** * Check if VectorStore integration is available */ hasVectorStoreIntegration(): boolean; initialize(): Promise; /** * Create a vector embedding for a skill or context * Uses a deterministic hash-based approach for consistency */ private createEmbedding; /** * Create embedding from a page context */ private createContextEmbedding; /** * Create embedding from a skill */ private createSkillEmbedding; /** * Compute cosine similarity between two vectors */ private cosineSimilarity; /** * Normalize a vector to unit length */ private normalizeVector; /** * Convert a skill to a text representation for semantic embedding * Creates a descriptive text that captures the skill's key characteristics */ private skillToText; /** * Convert a page context to text representation for semantic embedding */ private contextToText; /** * Add a skill to VectorStore for semantic retrieval */ private addSkillToVectorStore; /** * Retrieve skills using VectorStore semantic search */ private retrieveSkillsFromVectorStore; /** * Retrieve the most relevant skills for a given page context * Uses VectorStore semantic search when available (LI-006), falls back to hash-based matching */ retrieveSkillsAsync(context: PageContext, topK?: number): Promise; /** * Retrieve the most relevant skills for a given page context * Uses hash-based cosine similarity (synchronous, original implementation) */ retrieveSkills(context: PageContext, topK?: number): SkillMatch[]; /** * Check if skill preconditions are met for a context */ private checkPreconditions; /** * Record a browsing trajectory for potential skill extraction */ recordTrajectory(trajectory: BrowsingTrajectory): Promise; /** * Extract a skill from a successful trajectory */ private extractAndLearnSkill; /** * Extract meaningful actions from a trajectory */ private extractMeaningfulActions; /** * Infer preconditions from a trajectory */ private inferPreconditions; /** * Find an existing skill similar to the given embedding */ private findSimilarSkill; /** * Merge a new trajectory into an existing skill */ private mergeSkill; /** * Add a new skill to the library */ addSkill(skill: BrowsingSkill): Promise; /** * Remove the least used skill to make room */ private evictLeastUsedSkill; /** * Record skill execution result */ recordSkillExecution(skillId: string, success: boolean, duration: number): Promise; /** * Extract a generalized URL pattern from a specific URL */ private extractUrlPattern; /** * Generate a unique skill ID */ private generateSkillId; /** * Generate a human-readable skill name */ private generateSkillName; /** * Generate a skill description */ private generateSkillDescription; /** * Simple string hash function */ private hashString; /** * Get statistics about the procedural memory */ getStats(): { totalSkills: number; totalTrajectories: number; skillsByDomain: Record; avgSuccessRate: number; mostUsedSkills: Array<{ name: string; uses: number; }>; }; /** * Get all skills (for debugging/export) */ getAllSkills(): BrowsingSkill[]; /** * Get a specific skill by ID */ getSkill(skillId: string): BrowsingSkill | null; /** * Get anti-pattern statistics */ getAntiPatternStats(): { totalAntiPatterns: number; byDomain: Record; mostCommon: Array<{ name: string; occurrences: number; domain?: string; }>; recentlyAdded: Array<{ name: string; domain?: string; createdAt: number; }>; }; /** * Get comprehensive learning progress combining skills, anti-patterns, and coverage */ getLearningProgress(): { skills: { total: number; byDomain: Record; avgSuccessRate: number; topPerformers: Array<{ name: string; successRate: number; uses: number; }>; recentlyCreated: Array<{ name: string; domain: string; createdAt: number; }>; }; antiPatterns: { total: number; byDomain: Record; }; coverage: { coveredDomains: number; uncoveredDomains: string[]; suggestions: Array<{ type: string; value: string; reason: string; priority: string; }>; }; trajectories: { total: number; successful: number; failed: number; }; }; private load; /** * Load domain-specific skills for a given domain (PROG-001) * This is called lazily when SmartBrowser browses a new domain */ loadSkillsForDomain(domain: string): Promise; /** * Load a specific advanced skill by ID (PROG-001) * This is called when an advanced skill is explicitly requested */ loadAdvancedSkill(skillId: string): Promise; /** * Check if a skill matches a domain */ private skillMatchesDomain; /** * Get statistics about loaded vs. unloaded skills (PROG-001) */ getLoadingStats(): { essential: number; domainSpecific: { loaded: number; unloaded: number; }; advanced: { loaded: number; unloaded: number; }; totalLoaded: number; totalUnloaded: number; loadedDomains: string[]; }; private save; /** * Flush any pending writes to disk immediately */ flush(): Promise; /** * Export the full procedural memory for analysis */ exportMemory(): Promise; /** * Import skills from another instance or backup */ importSkills(skillsJson: string, merge?: boolean): Promise; /** * Domain patterns for vertical classification */ private static readonly VERTICAL_PATTERNS; /** * Infer vertical from domain */ private inferVertical; /** * Check if domain matches a pattern (glob-like) * Uses centralized url-pattern-matcher utility (D-007) */ private matchesDomainPattern; /** * Export skills as a portable skill pack */ exportSkillPack(options?: SkillExportOptions): SkillPack; /** * Serialize a skill pack to JSON string */ serializeSkillPack(pack: SkillPack, pretty?: boolean): string; /** * Import skills from a skill pack with advanced options */ importSkillPack(packJson: string, options?: SkillImportOptions): Promise; /** * Get skill pack statistics for the current instance */ getSkillPackStats(): SkillPackMetadata['stats'] & { byVertical: Record; }; /** * Apply decay to skills that haven't been used recently */ applySkillDecay(decayAfterDays?: number, decayRate?: number): number; /** * Remove skills with poor performance */ pruneFailedSkills(minSuccessRate?: number, minUses?: number): number; /** * Get skills grouped by domain for analysis */ getSkillsByDomain(): Map; /** * Create a workflow by composing multiple skills */ createWorkflow(name: string, skillIds: string[], description?: string): SkillWorkflow | null; /** * Get a workflow by ID */ getWorkflow(workflowId: string): SkillWorkflow | null; /** * Get all workflows */ getAllWorkflows(): SkillWorkflow[]; /** * Auto-detect potential workflows from trajectory patterns */ detectPotentialWorkflows(): Array<{ skills: string[]; frequency: number; }>; private mapActionsToSkillNames; /** * Create a workflow with advanced options */ createWorkflowAdvanced(options: CreateWorkflowOptions): SkillWorkflow | null; /** * Create an embedding for a workflow based on its constituent skills */ private createWorkflowEmbedding; /** * Evaluate a transition condition */ private evaluateTransitionCondition; /** * Execute a workflow, running skills in sequence with transition evaluation * * Note: This returns the execution result. The actual skill execution logic * must be provided via the executeSkill callback, as skill execution involves * browser operations that are outside this class's scope. */ executeWorkflow(workflowId: string, executeSkill: (skill: BrowsingSkill, context: PageContext) => Promise<{ success: boolean; output?: unknown; error?: string; }>, pageContext: PageContext, options?: WorkflowExecutionOptions): Promise; /** * Helper to complete workflow execution and update metrics */ private completeWorkflowExecution; /** * Retrieve workflows matching a page context */ retrieveWorkflows(context: PageContext, topK?: number): WorkflowMatch[]; /** * Check if preconditions match a page context */ private matchesPreconditions; /** * Explain why a workflow matches */ private explainWorkflowMatch; /** * Insert a skill into an existing workflow at a specific position */ insertSkillIntoWorkflow(workflowId: string, skillId: string, position: number, transitionCondition?: WorkflowTransitionCondition): boolean; /** * Remove a skill from a workflow */ removeSkillFromWorkflow(workflowId: string, skillId: string): boolean; /** * Reorder skills within a workflow */ reorderWorkflowSkills(workflowId: string, newOrder: string[]): boolean; /** * Delete a workflow */ deleteWorkflow(workflowId: string): boolean; /** * Optimize a workflow by reordering skills based on performance metrics * Skills with higher success rates and shorter durations are moved earlier */ optimizeWorkflow(workflowId: string): boolean; /** * Clone a workflow with a new name */ cloneWorkflow(workflowId: string, newName: string): SkillWorkflow | null; /** * Get workflow statistics */ getWorkflowStats(): { totalWorkflows: number; avgSkillsPerWorkflow: number; topWorkflows: Array<{ name: string; successRate: number; timesUsed: number; }>; avgSuccessRate: number; }; /** * Track a domain visit for coverage analysis */ trackVisit(domain: string, pageType: PageContext['pageType'], success: boolean): void; /** * Get coverage statistics and suggestions for active learning */ getCoverageStats(): CoverageStats; /** * Create enhanced embedding with more features */ private createEnhancedEmbedding; /** * Update createContextEmbedding to use enhanced version */ createContextEmbeddingEnhanced(context: PageContext): number[]; /** * Manually add a skill (for bootstrapping or import) */ addManualSkill(name: string, description: string, preconditions: SkillPreconditions, actionSequence: BrowsingAction[]): BrowsingSkill; /** * Delete a skill by ID (public API) */ removeSkill(skillId: string): boolean; /** * Reset all procedural memory (for testing/debugging) */ reset(): Promise; /** * Create a version snapshot of a skill */ private createVersion; /** * Save a version to the skill's history */ private saveVersion; /** * Get version history for a skill */ getVersionHistory(skillId: string): SkillVersion[]; /** * Rollback a skill to a previous version */ rollbackSkill(skillId: string, targetVersion?: number): Promise; /** * Check if a skill should be auto-rolled back based on performance degradation */ checkForAutoRollback(skillId: string, threshold?: number): boolean; /** * Get the best performing version of a skill */ getBestVersion(skillId: string): SkillVersion | null; /** * Record an anti-pattern from a failed action */ recordAntiPattern(action: BrowsingAction, context: PageContext, consequences: string[], alternatives?: BrowsingAction[]): Promise; /** * Generate a name for an anti-pattern */ private generateAntiPatternName; /** * Check if an action matches any known anti-patterns */ checkAntiPatterns(action: BrowsingAction, context: PageContext): AntiPattern | null; /** * Get all anti-patterns for a domain */ getAntiPatternsForDomain(domain: string): AntiPattern[]; /** * Get all anti-patterns */ getAllAntiPatterns(): AntiPattern[]; /** * Generate a human-readable explanation for a skill */ generateSkillExplanation(skillId: string): SkillExplanation | null; /** * Describe an action in plain English */ private describeAction; /** * Infer the purpose of an action based on context */ private inferActionPurpose; /** * Generate a summary for a skill */ private generateSkillSummary; /** * Describe when a skill is applicable */ private describeApplicability; /** * Describe skill reliability */ private describeReliability; /** * Generate usage tips for a skill */ private generateTips; /** * Record user feedback on a skill application */ recordFeedback(skillId: string, rating: 'positive' | 'negative', context: { url: string; domain: string; }, reason?: string): Promise; /** * Get feedback summary for a skill */ getFeedbackSummary(skillId: string): { positive: number; negative: number; recentFeedback: SkillFeedback[]; commonIssues: string[]; }; /** * Get all feedback */ getAllFeedback(): SkillFeedback[]; /** * Add fallback skills to a skill */ addFallbackSkills(skillId: string, fallbackSkillIds: string[]): Promise; /** * Add prerequisite skills to a skill */ addPrerequisites(skillId: string, prerequisiteSkillIds: string[]): Promise; /** * Check if adding prerequisites would create a circular dependency using DFS */ private wouldCreateCircularDependency; /** * Get fallback skills for a skill */ getFallbackSkills(skillId: string): BrowsingSkill[]; /** * Get prerequisite skills for a skill */ getPrerequisiteSkills(skillId: string): BrowsingSkill[]; /** * Execute a skill with fallback chain */ executeWithFallbacks(skillId: string, executor: (skill: BrowsingSkill) => Promise): Promise<{ success: boolean; executedSkillId: string; attempts: number; }>; /** * Learn verification checks from a browse result * * This method analyzes verification results to: * - Store successful checks as learned verifications * - Track failed checks to prevent similar failures * - Update confidence scores based on historical performance */ learnFromVerification(domain: string, verificationResult: import('../types/verification.js').VerificationResult, browseSuccess: boolean): Promise; /** * Infer verification assertion from check result * * This is a heuristic method that attempts to create assertions based on * the check result message. In practice, the VerificationEngine should * pass the original check for more accurate learning. */ private inferAssertionFromCheckResult; /** * Get learned verification checks for a domain * * Returns high-confidence verification checks that should be applied * when browsing URLs on this domain. */ getLearnedVerifications(domain: string, minConfidence?: number): import('../types/verification.js').VerificationCheck[]; /** * Get all learned verifications across all domains * * Useful for understanding what verifications have been learned system-wide. */ getAllLearnedVerifications(): Array<{ domain: string; check: import('../types/verification.js').VerificationCheck; confidence: number; learnedFrom: 'success' | 'failure'; }>; /** * Update verification confidence based on actual usage * * Called after applying a learned verification to update its confidence * based on whether it correctly predicted success/failure. */ updateVerificationConfidence(domain: string, checkType: 'content' | 'action' | 'state' | 'custom', wasCorrect: boolean): Promise; /** * Create a skill from a recorded workflow * * Converts workflow steps into a reusable browsing skill that * can be applied automatically when matching preconditions are met. */ createSkillFromWorkflow(workflow: import('../types/workflow.js').Workflow): Promise; /** * Replay a workflow with variable substitution * * Executes workflow steps in sequence, optionally substituting variables * in URLs and selectors. Returns results for each step. */ replayWorkflow(workflowId: string, variables: import('../types/workflow.js').WorkflowVariables | undefined, smartBrowser: { browse: (url: string, options?: any) => Promise; }): Promise; /** * Get workflow by ID * Note: Workflows are stored separately from skills */ private recordedWorkflows; getWorkflowById(workflowId: string): import('../types/workflow.js').Workflow | undefined; /** * Store workflow (called by WorkflowRecorder) */ storeWorkflow(workflow: import('../types/workflow.js').Workflow): Promise; /** * List all workflows */ listWorkflows(): import('../types/workflow.js').Workflow[]; /** * Interpolate variables in a string (e.g., URL or selector) * * Supports syntax: {variableName} * Example: "https://example.com/products/{productId}" with {productId: "123"} * becomes "https://example.com/products/123" */ private interpolateVariables; /** * Convert URL to pattern for preconditions * Replaces dynamic segments with wildcards */ private urlToPattern; /** * Bootstrap procedural memory with common skill templates */ bootstrapFromTemplates(): Promise; /** * Generate default actions for a template skill */ private generateTemplateActions; } export declare const proceduralMemory: ProceduralMemory; //# sourceMappingURL=procedural-memory.d.ts.map