superlocalmemory 3.4.9 → 3.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -3
- package/docs/cloud-backup.md +174 -0
- package/docs/skill-evolution.md +256 -0
- package/ide/hooks/tool-event-hook.sh +101 -11
- package/package.json +1 -1
- package/pyproject.toml +3 -2
- package/src/superlocalmemory/cli/commands.py +359 -0
- package/src/superlocalmemory/cli/ingest_cmd.py +81 -29
- package/src/superlocalmemory/cli/main.py +32 -0
- package/src/superlocalmemory/cli/setup_wizard.py +54 -11
- package/src/superlocalmemory/core/config.py +35 -0
- package/src/superlocalmemory/core/consolidation_engine.py +138 -0
- package/src/superlocalmemory/core/embedding_worker.py +1 -1
- package/src/superlocalmemory/core/engine.py +19 -0
- package/src/superlocalmemory/core/fact_consolidator.py +425 -0
- package/src/superlocalmemory/core/graph_pruner.py +290 -0
- package/src/superlocalmemory/core/maintenance_scheduler.py +44 -3
- package/src/superlocalmemory/core/recall_pipeline.py +9 -0
- package/src/superlocalmemory/core/tier_manager.py +325 -0
- package/src/superlocalmemory/encoding/entity_resolver.py +96 -28
- package/src/superlocalmemory/evolution/__init__.py +29 -0
- package/src/superlocalmemory/evolution/blind_verifier.py +115 -0
- package/src/superlocalmemory/evolution/evolution_store.py +302 -0
- package/src/superlocalmemory/evolution/mutation_generator.py +181 -0
- package/src/superlocalmemory/evolution/skill_evolver.py +555 -0
- package/src/superlocalmemory/evolution/triggers.py +367 -0
- package/src/superlocalmemory/evolution/types.py +92 -0
- package/src/superlocalmemory/hooks/hook_handlers.py +13 -0
- package/src/superlocalmemory/infra/backup.py +63 -20
- package/src/superlocalmemory/infra/cloud_backup.py +703 -0
- package/src/superlocalmemory/learning/skill_performance_miner.py +422 -0
- package/src/superlocalmemory/mcp/server.py +4 -0
- package/src/superlocalmemory/mcp/tools_evolution.py +338 -0
- package/src/superlocalmemory/retrieval/engine.py +64 -4
- package/src/superlocalmemory/retrieval/forgetting_filter.py +22 -7
- package/src/superlocalmemory/retrieval/strategy.py +2 -2
- package/src/superlocalmemory/server/routes/backup.py +512 -8
- package/src/superlocalmemory/server/routes/behavioral.py +39 -17
- package/src/superlocalmemory/server/routes/evolution.py +213 -0
- package/src/superlocalmemory/server/routes/tiers.py +195 -0
- package/src/superlocalmemory/server/unified_daemon.py +36 -5
- package/src/superlocalmemory/storage/schema_v3410.py +159 -0
- package/src/superlocalmemory/storage/schema_v3411.py +149 -0
- package/src/superlocalmemory/ui/index.html +59 -3
- package/src/superlocalmemory/ui/js/core.js +3 -0
- package/src/superlocalmemory/ui/js/lifecycle.js +83 -0
- package/src/superlocalmemory/ui/js/ng-entities.js +27 -3
- package/src/superlocalmemory/ui/js/ng-shell.js +33 -0
- package/src/superlocalmemory/ui/js/ng-skills.js +611 -0
- package/src/superlocalmemory/ui/js/settings.js +311 -1
- package/src/superlocalmemory.egg-info/PKG-INFO +16 -1
- package/src/superlocalmemory.egg-info/SOURCES.txt +18 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
|
|
5
|
+
"""Mutation Generator — LLM-driven skill improvement.
|
|
6
|
+
|
|
7
|
+
Reads the original SKILL.md + failure evidence + performance data,
|
|
8
|
+
generates an improved version. Apply-retry cycle (3 attempts) for
|
|
9
|
+
malformed output.
|
|
10
|
+
|
|
11
|
+
Token-driven termination: <EVOLUTION_COMPLETE> or <EVOLUTION_FAILED>.
|
|
12
|
+
Adopted from OpenSpace evolver.py patterns.
|
|
13
|
+
|
|
14
|
+
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
import re
|
|
21
|
+
from typing import Optional
|
|
22
|
+
|
|
23
|
+
from superlocalmemory.evolution.types import (
|
|
24
|
+
EvolutionCandidate,
|
|
25
|
+
EvolutionType,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
MAX_APPLY_RETRIES = 3
|
|
31
|
+
MAX_CONTENT_CHARS = 12_000 # Truncate skill content in prompt
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def build_mutation_prompt(
|
|
35
|
+
candidate: EvolutionCandidate,
|
|
36
|
+
original_content: str,
|
|
37
|
+
) -> str:
|
|
38
|
+
"""Build the LLM prompt for skill mutation."""
|
|
39
|
+
truncated = original_content[:MAX_CONTENT_CHARS]
|
|
40
|
+
evidence_text = "\n".join(f"- {e}" for e in candidate.evidence)
|
|
41
|
+
|
|
42
|
+
if candidate.evolution_type == EvolutionType.FIX:
|
|
43
|
+
return _fix_prompt(candidate.skill_name, truncated, evidence_text, candidate.effective_score)
|
|
44
|
+
elif candidate.evolution_type == EvolutionType.DERIVED:
|
|
45
|
+
return _derived_prompt(candidate.skill_name, truncated, evidence_text, candidate.effective_score)
|
|
46
|
+
else:
|
|
47
|
+
return _captured_prompt(candidate.skill_name, evidence_text)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def parse_mutation_output(output: str) -> Optional[str]:
|
|
51
|
+
"""Extract evolved SKILL.md content from LLM output.
|
|
52
|
+
|
|
53
|
+
Looks for content between markdown code fences or after
|
|
54
|
+
<EVOLUTION_COMPLETE> token. Returns None if <EVOLUTION_FAILED>
|
|
55
|
+
or no valid content found.
|
|
56
|
+
"""
|
|
57
|
+
if "<EVOLUTION_FAILED>" in output:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
# Try extracting from code fence
|
|
61
|
+
fence_match = re.search(
|
|
62
|
+
r"```(?:markdown|md)?\s*\n(---\s*\n.*?)```",
|
|
63
|
+
output,
|
|
64
|
+
re.DOTALL,
|
|
65
|
+
)
|
|
66
|
+
if fence_match:
|
|
67
|
+
return fence_match.group(1).strip()
|
|
68
|
+
|
|
69
|
+
# Try extracting after EVOLUTION_COMPLETE token
|
|
70
|
+
complete_match = re.search(
|
|
71
|
+
r"<EVOLUTION_COMPLETE>\s*(---\s*\n.*)",
|
|
72
|
+
output,
|
|
73
|
+
re.DOTALL,
|
|
74
|
+
)
|
|
75
|
+
if complete_match:
|
|
76
|
+
return complete_match.group(1).strip()
|
|
77
|
+
|
|
78
|
+
# Try finding YAML frontmatter directly
|
|
79
|
+
frontmatter_match = re.search(
|
|
80
|
+
r"(---\s*\nname:.*?)(?:\n---|\Z)",
|
|
81
|
+
output,
|
|
82
|
+
re.DOTALL,
|
|
83
|
+
)
|
|
84
|
+
if frontmatter_match:
|
|
85
|
+
# Return everything from the frontmatter start
|
|
86
|
+
idx = output.index(frontmatter_match.group(0))
|
|
87
|
+
return output[idx:].strip()
|
|
88
|
+
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def validate_skill_content(content: str) -> Optional[str]:
|
|
93
|
+
"""Validate evolved skill content. Returns error message or None if valid."""
|
|
94
|
+
if not content or len(content) < 50:
|
|
95
|
+
return "Content too short (< 50 chars)"
|
|
96
|
+
if "---" not in content:
|
|
97
|
+
return "Missing YAML frontmatter (no --- found)"
|
|
98
|
+
if content.count("---") >= 2 and "name:" not in content.split("---")[1]:
|
|
99
|
+
return "Missing 'name:' in frontmatter"
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def build_retry_prompt(original_prompt: str, error: str, attempt: int) -> str:
|
|
104
|
+
"""Build retry prompt after failed mutation attempt."""
|
|
105
|
+
return (
|
|
106
|
+
f"{original_prompt}\n\n"
|
|
107
|
+
f"--- RETRY (attempt {attempt}/{MAX_APPLY_RETRIES}) ---\n"
|
|
108
|
+
f"Previous output was invalid: {error}\n"
|
|
109
|
+
f"Please generate a valid SKILL.md with proper YAML frontmatter "
|
|
110
|
+
f"(--- / name: / description: / ---) followed by markdown instructions.\n"
|
|
111
|
+
f"End with <EVOLUTION_COMPLETE> or <EVOLUTION_FAILED>."
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# ------------------------------------------------------------------
|
|
116
|
+
# Prompt templates
|
|
117
|
+
# ------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
def _fix_prompt(skill_name: str, content: str, evidence: str, score: float) -> str:
|
|
120
|
+
return f"""You are a skill evolution engine. A skill is underperforming and needs repair.
|
|
121
|
+
|
|
122
|
+
SKILL NAME: {skill_name}
|
|
123
|
+
EFFECTIVE SCORE: {score:.0%} (approximate)
|
|
124
|
+
|
|
125
|
+
CURRENT SKILL CONTENT:
|
|
126
|
+
{content}
|
|
127
|
+
|
|
128
|
+
EVIDENCE OF PROBLEMS:
|
|
129
|
+
{evidence}
|
|
130
|
+
|
|
131
|
+
YOUR TASK:
|
|
132
|
+
Generate an improved version of this SKILL.md that addresses the identified problems.
|
|
133
|
+
Keep the same overall structure and purpose. Fix what's broken, don't rewrite from scratch.
|
|
134
|
+
|
|
135
|
+
OUTPUT FORMAT:
|
|
136
|
+
Return the complete improved SKILL.md content inside a markdown code fence.
|
|
137
|
+
The file must start with YAML frontmatter (--- / name: / description: / ---).
|
|
138
|
+
End your response with <EVOLUTION_COMPLETE> if you generated a valid improvement,
|
|
139
|
+
or <EVOLUTION_FAILED> if you cannot improve this skill."""
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _derived_prompt(skill_name: str, content: str, evidence: str, score: float) -> str:
|
|
143
|
+
return f"""You are a skill evolution engine. A skill works for some tasks but not others.
|
|
144
|
+
Create a specialized variant for the failing task type.
|
|
145
|
+
|
|
146
|
+
PARENT SKILL: {skill_name}
|
|
147
|
+
EFFECTIVE SCORE: {score:.0%} (moderate — works sometimes, fails sometimes)
|
|
148
|
+
|
|
149
|
+
PARENT SKILL CONTENT:
|
|
150
|
+
{content}
|
|
151
|
+
|
|
152
|
+
EVIDENCE:
|
|
153
|
+
{evidence}
|
|
154
|
+
|
|
155
|
+
YOUR TASK:
|
|
156
|
+
Create a specialized DERIVED variant that handles the failing cases better.
|
|
157
|
+
Give it a new name (e.g., "{skill_name}-specialized" or a descriptive name).
|
|
158
|
+
Keep the parent's strengths. Add specific handling for the failure patterns.
|
|
159
|
+
|
|
160
|
+
OUTPUT FORMAT:
|
|
161
|
+
Return the complete new SKILL.md inside a markdown code fence.
|
|
162
|
+
Must start with YAML frontmatter (--- / name: / description: / ---).
|
|
163
|
+
End with <EVOLUTION_COMPLETE> or <EVOLUTION_FAILED>."""
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _captured_prompt(skill_name: str, evidence: str) -> str:
|
|
167
|
+
return f"""You are a skill evolution engine. A repeated workflow pattern was detected
|
|
168
|
+
that no existing skill covers. Create a new skill to codify this pattern.
|
|
169
|
+
|
|
170
|
+
PATTERN NAME: {skill_name}
|
|
171
|
+
EVIDENCE:
|
|
172
|
+
{evidence}
|
|
173
|
+
|
|
174
|
+
YOUR TASK:
|
|
175
|
+
Create a new SKILL.md that codifies this workflow pattern into a reusable skill.
|
|
176
|
+
Make it specific and actionable — not generic advice.
|
|
177
|
+
|
|
178
|
+
OUTPUT FORMAT:
|
|
179
|
+
Return the complete SKILL.md inside a markdown code fence.
|
|
180
|
+
Must start with YAML frontmatter (--- / name: / description: / ---).
|
|
181
|
+
End with <EVOLUTION_COMPLETE> or <EVOLUTION_FAILED>."""
|