adaptive-memory-multi-model-router 1.2.2 → 1.3.1

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.
Files changed (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -66
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/integrations/airtable.js +20 -0
  6. package/dist/integrations/discord.js +18 -0
  7. package/dist/integrations/github.js +23 -0
  8. package/dist/integrations/gmail.js +19 -0
  9. package/dist/integrations/google-calendar.js +18 -0
  10. package/dist/integrations/index.js +61 -0
  11. package/dist/integrations/jira.js +21 -0
  12. package/dist/integrations/linear.js +19 -0
  13. package/dist/integrations/notion.js +19 -0
  14. package/dist/integrations/slack.js +18 -0
  15. package/dist/integrations/telegram.js +19 -0
  16. package/dist/providers/registry.js +7 -3
  17. package/docs/ARCHITECTURAL-IMPROVEMENTS-2025.md +1391 -0
  18. package/docs/ARCHITECTURAL-IMPROVEMENTS-REVISED-2025.md +1051 -0
  19. package/docs/CONFIGURATION.md +476 -0
  20. package/docs/COUNCIL_DECISION.json +308 -0
  21. package/docs/COUNCIL_SUMMARY.md +265 -0
  22. package/docs/COUNCIL_V2.2_DECISION.md +416 -0
  23. package/docs/IMPROVEMENT_ROADMAP.md +515 -0
  24. package/docs/LLM_COUNCIL_DECISION.md +508 -0
  25. package/docs/QUICK_START_VISIBILITY.md +782 -0
  26. package/docs/REDDIT_GAP_ANALYSIS.md +299 -0
  27. package/docs/RESEARCH_BACKED_IMPROVEMENTS.md +1180 -0
  28. package/docs/TMLPD_QNA.md +751 -0
  29. package/docs/TMLPD_V2.1_COMPLETE.md +763 -0
  30. package/docs/TMLPD_V2.2_RESEARCH_ROADMAP.md +754 -0
  31. package/docs/V2.2_IMPLEMENTATION_COMPLETE.md +446 -0
  32. package/docs/V2_IMPLEMENTATION_GUIDE.md +388 -0
  33. package/docs/VISIBILITY_ADOPTION_PLAN.md +1005 -0
  34. package/docs/launch-content/LAUNCH_EXECUTION_CHECKLIST.md +421 -0
  35. package/docs/launch-content/README.md +457 -0
  36. package/docs/launch-content/assets/cost_comparison_100_tasks.png +0 -0
  37. package/docs/launch-content/assets/cumulative_savings.png +0 -0
  38. package/docs/launch-content/assets/parallel_speedup.png +0 -0
  39. package/docs/launch-content/assets/provider_pricing_comparison.png +0 -0
  40. package/docs/launch-content/assets/task_breakdown_comparison.png +0 -0
  41. package/docs/launch-content/generate_charts.py +313 -0
  42. package/docs/launch-content/hn_show_post.md +139 -0
  43. package/docs/launch-content/partner_outreach_templates.md +745 -0
  44. package/docs/launch-content/reddit_posts.md +467 -0
  45. package/docs/launch-content/twitter_thread.txt +460 -0
  46. package/examples/QUICKSTART.md +1 -1
  47. package/openclaw-alexa-bridge/ALL_REMAINING_FIXES_PLAN.md +313 -0
  48. package/openclaw-alexa-bridge/REMAINING_FIXES_SUMMARY.md +277 -0
  49. package/openclaw-alexa-bridge/src/alexa_handler_no_tmlpd.js +1234 -0
  50. package/openclaw-alexa-bridge/test_fixes.js +77 -0
  51. package/package.json +120 -29
  52. package/package.json.tmp +0 -0
  53. package/qna/TMLPD_QNA.md +3 -3
  54. package/skill/SKILL.md +2 -2
  55. package/src/__tests__/integration/tmpld_integration.test.py +540 -0
  56. package/src/agents/skill_enhanced_agent.py +318 -0
  57. package/src/memory/__init__.py +15 -0
  58. package/src/memory/agentic_memory.py +353 -0
  59. package/src/memory/semantic_memory.py +444 -0
  60. package/src/memory/simple_memory.py +466 -0
  61. package/src/memory/working_memory.py +447 -0
  62. package/src/orchestration/__init__.py +52 -0
  63. package/src/orchestration/execution_engine.py +353 -0
  64. package/src/orchestration/halo_orchestrator.py +367 -0
  65. package/src/orchestration/mcts_workflow.py +498 -0
  66. package/src/orchestration/role_assigner.py +473 -0
  67. package/src/orchestration/task_planner.py +522 -0
  68. package/src/providers/__init__.py +67 -0
  69. package/src/providers/anthropic.py +304 -0
  70. package/src/providers/base.py +241 -0
  71. package/src/providers/cerebras.py +373 -0
  72. package/src/providers/registry.py +476 -0
  73. package/src/routing/__init__.py +30 -0
  74. package/src/routing/universal_router.py +621 -0
  75. package/src/skills/TMLPD-QUICKREF.md +210 -0
  76. package/src/skills/TMLPD-SETUP-SUMMARY.md +157 -0
  77. package/src/skills/TMLPD.md +540 -0
  78. package/src/skills/__tests__/skill_manager.test.ts +328 -0
  79. package/src/skills/skill_manager.py +385 -0
  80. package/src/skills/test-tmlpd.sh +108 -0
  81. package/src/skills/tmlpd-category.yaml +67 -0
  82. package/src/skills/tmlpd-monitoring.yaml +188 -0
  83. package/src/skills/tmlpd-phase.yaml +132 -0
  84. package/src/state/__init__.py +17 -0
  85. package/src/state/simple_checkpoint.py +508 -0
  86. package/src/tmlpd_agent.py +464 -0
  87. package/src/tmpld_v2.py +427 -0
  88. package/src/workflows/__init__.py +18 -0
  89. package/src/workflows/advanced_difficulty_classifier.py +377 -0
  90. package/src/workflows/chaining_executor.py +417 -0
  91. package/src/workflows/difficulty_integration.py +209 -0
  92. package/src/workflows/orchestrator.py +469 -0
  93. package/src/workflows/orchestrator_executor.py +456 -0
  94. package/src/workflows/parallelization_executor.py +382 -0
  95. package/src/workflows/router.py +311 -0
  96. package/test_integration_simple.py +86 -0
  97. package/test_mcts_workflow.py +150 -0
  98. package/test_templd_integration.py +262 -0
  99. package/test_universal_router.py +275 -0
  100. package/tmlpd-pi-extension/README.md +36 -0
  101. package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts +114 -0
  102. package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts.map +1 -0
  103. package/tmlpd-pi-extension/dist/cache/prefixCache.js +285 -0
  104. package/tmlpd-pi-extension/dist/cache/prefixCache.js.map +1 -0
  105. package/tmlpd-pi-extension/dist/cache/responseCache.d.ts +58 -0
  106. package/tmlpd-pi-extension/dist/cache/responseCache.d.ts.map +1 -0
  107. package/tmlpd-pi-extension/dist/cache/responseCache.js +153 -0
  108. package/tmlpd-pi-extension/dist/cache/responseCache.js.map +1 -0
  109. package/tmlpd-pi-extension/dist/cli.js +59 -0
  110. package/tmlpd-pi-extension/dist/cost/costTracker.d.ts +95 -0
  111. package/tmlpd-pi-extension/dist/cost/costTracker.d.ts.map +1 -0
  112. package/tmlpd-pi-extension/dist/cost/costTracker.js +240 -0
  113. package/tmlpd-pi-extension/dist/cost/costTracker.js.map +1 -0
  114. package/tmlpd-pi-extension/dist/index.d.ts +723 -0
  115. package/tmlpd-pi-extension/dist/index.d.ts.map +1 -0
  116. package/tmlpd-pi-extension/dist/index.js +239 -0
  117. package/tmlpd-pi-extension/dist/index.js.map +1 -0
  118. package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts +82 -0
  119. package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts.map +1 -0
  120. package/tmlpd-pi-extension/dist/memory/episodicMemory.js +145 -0
  121. package/tmlpd-pi-extension/dist/memory/episodicMemory.js.map +1 -0
  122. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts +102 -0
  123. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts.map +1 -0
  124. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js +207 -0
  125. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js.map +1 -0
  126. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts +85 -0
  127. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts.map +1 -0
  128. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js +210 -0
  129. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js.map +1 -0
  130. package/tmlpd-pi-extension/dist/providers/localProvider.d.ts +102 -0
  131. package/tmlpd-pi-extension/dist/providers/localProvider.d.ts.map +1 -0
  132. package/tmlpd-pi-extension/dist/providers/localProvider.js +338 -0
  133. package/tmlpd-pi-extension/dist/providers/localProvider.js.map +1 -0
  134. package/tmlpd-pi-extension/dist/providers/registry.d.ts +55 -0
  135. package/tmlpd-pi-extension/dist/providers/registry.d.ts.map +1 -0
  136. package/tmlpd-pi-extension/dist/providers/registry.js +138 -0
  137. package/tmlpd-pi-extension/dist/providers/registry.js.map +1 -0
  138. package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts +68 -0
  139. package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts.map +1 -0
  140. package/tmlpd-pi-extension/dist/routing/advancedRouter.js +332 -0
  141. package/tmlpd-pi-extension/dist/routing/advancedRouter.js.map +1 -0
  142. package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts +101 -0
  143. package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts.map +1 -0
  144. package/tmlpd-pi-extension/dist/tools/tmlpdTools.js +368 -0
  145. package/tmlpd-pi-extension/dist/tools/tmlpdTools.js.map +1 -0
  146. package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts +96 -0
  147. package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts.map +1 -0
  148. package/tmlpd-pi-extension/dist/utils/batchProcessor.js +170 -0
  149. package/tmlpd-pi-extension/dist/utils/batchProcessor.js.map +1 -0
  150. package/tmlpd-pi-extension/dist/utils/compression.d.ts +61 -0
  151. package/tmlpd-pi-extension/dist/utils/compression.d.ts.map +1 -0
  152. package/tmlpd-pi-extension/dist/utils/compression.js +281 -0
  153. package/tmlpd-pi-extension/dist/utils/compression.js.map +1 -0
  154. package/tmlpd-pi-extension/dist/utils/reliability.d.ts +74 -0
  155. package/tmlpd-pi-extension/dist/utils/reliability.d.ts.map +1 -0
  156. package/tmlpd-pi-extension/dist/utils/reliability.js +177 -0
  157. package/tmlpd-pi-extension/dist/utils/reliability.js.map +1 -0
  158. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts +117 -0
  159. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts.map +1 -0
  160. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js +246 -0
  161. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js.map +1 -0
  162. package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts +50 -0
  163. package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts.map +1 -0
  164. package/tmlpd-pi-extension/dist/utils/tokenUtils.js +124 -0
  165. package/tmlpd-pi-extension/dist/utils/tokenUtils.js.map +1 -0
  166. package/tmlpd-pi-extension/examples/QUICKSTART.md +183 -0
  167. package/tmlpd-pi-extension/package-lock.json +75 -0
  168. package/tmlpd-pi-extension/package.json +172 -0
  169. package/tmlpd-pi-extension/python/examples.py +53 -0
  170. package/tmlpd-pi-extension/python/integrations.py +330 -0
  171. package/tmlpd-pi-extension/python/setup.py +28 -0
  172. package/tmlpd-pi-extension/python/tmlpd.py +369 -0
  173. package/tmlpd-pi-extension/qna/REDDIT_GAP_ANALYSIS.md +299 -0
  174. package/tmlpd-pi-extension/qna/TMLPD_QNA.md +751 -0
  175. package/tmlpd-pi-extension/skill/SKILL.md +238 -0
  176. package/{src → tmlpd-pi-extension/src}/index.ts +1 -1
  177. package/tmlpd-pi-extension/tsconfig.json +18 -0
  178. package/demo/research-demo.js +0 -266
  179. package/notebooks/quickstart.ipynb +0 -157
  180. package/rust/tmlpd.h +0 -268
  181. package/src/cache/prefixCache.ts +0 -365
  182. package/src/routing/advancedRouter.ts +0 -406
  183. package/src/utils/speculativeDecoding.ts +0 -344
  184. /package/{src → tmlpd-pi-extension/src}/cache/responseCache.ts +0 -0
  185. /package/{src → tmlpd-pi-extension/src}/cost/costTracker.ts +0 -0
  186. /package/{src → tmlpd-pi-extension/src}/memory/episodicMemory.ts +0 -0
  187. /package/{src → tmlpd-pi-extension/src}/orchestration/haloOrchestrator.ts +0 -0
  188. /package/{src → tmlpd-pi-extension/src}/orchestration/mctsWorkflow.ts +0 -0
  189. /package/{src → tmlpd-pi-extension/src}/providers/localProvider.ts +0 -0
  190. /package/{src → tmlpd-pi-extension/src}/providers/registry.ts +0 -0
  191. /package/{src → tmlpd-pi-extension/src}/tools/tmlpdTools.ts +0 -0
  192. /package/{src → tmlpd-pi-extension/src}/utils/batchProcessor.ts +0 -0
  193. /package/{src → tmlpd-pi-extension/src}/utils/compression.ts +0 -0
  194. /package/{src → tmlpd-pi-extension/src}/utils/reliability.ts +0 -0
  195. /package/{src → tmlpd-pi-extension/src}/utils/tokenUtils.ts +0 -0
@@ -0,0 +1,466 @@
1
+ """
2
+ Simple Project Memory - Workflow Phase 3
3
+
4
+ Implements lightweight JSON-based memory for learning successful patterns.
5
+ No complex vector databases or embeddings - just simple pattern matching.
6
+
7
+ Philosophy:
8
+ - Keep it simple and transparent
9
+ - Learn from successful executions
10
+ - Recall similar patterns by keyword matching
11
+ - Easy to inspect and debug (plain JSON)
12
+ """
13
+
14
+ from typing import Dict, List, Any, Optional
15
+ from pathlib import Path
16
+ import json
17
+ from datetime import datetime
18
+ from collections import Counter
19
+ import re
20
+
21
+
22
+ class SimpleProjectMemory:
23
+ """
24
+ Simple JSON-based memory for learning and recalling patterns.
25
+
26
+ Stores:
27
+ - Successful task patterns
28
+ - Agent/skill combinations that worked
29
+ - Performance metrics (time, cost, tokens)
30
+ - User preferences
31
+
32
+ Retrieves by:
33
+ - Keyword matching
34
+ - Task similarity
35
+ - Frequency/recency scoring
36
+ """
37
+
38
+ def __init__(self, memory_file: str = ".taskmaster/memory.json"):
39
+ """
40
+ Initialize Simple Project Memory
41
+
42
+ Args:
43
+ memory_file: Path to JSON memory file
44
+ """
45
+ self.memory_file = Path(memory_file)
46
+ self.memory_file.parent.mkdir(parents=True, exist_ok=True)
47
+
48
+ self.memory: Dict[str, Any] = self._load_memory()
49
+
50
+ self.stats = {
51
+ "patterns_stored": 0,
52
+ "patterns_recalled": 0,
53
+ "hits": 0,
54
+ "misses": 0
55
+ }
56
+
57
+ def _load_memory(self) -> Dict[str, Any]:
58
+ """Load memory from JSON file"""
59
+ if self.memory_file.exists():
60
+ try:
61
+ with open(self.memory_file, 'r') as f:
62
+ return json.load(f)
63
+ except Exception as e:
64
+ print(f"Warning: Failed to load memory: {e}")
65
+ return self._empty_memory()
66
+
67
+ return self._empty_memory()
68
+
69
+ def _empty_memory(self) -> Dict[str, Any]:
70
+ """Create empty memory structure"""
71
+ return {
72
+ "version": "1.0",
73
+ "created_at": datetime.now().isoformat(),
74
+ "last_updated": datetime.now().isoformat(),
75
+ "patterns": [],
76
+ "preferences": {},
77
+ "stats": {
78
+ "total_patterns": 0,
79
+ "successful_patterns": 0,
80
+ "failed_patterns": 0
81
+ }
82
+ }
83
+
84
+ def _save_memory(self):
85
+ """Save memory to JSON file"""
86
+ self.memory["last_updated"] = datetime.now().isoformat()
87
+ self.memory["stats"]["total_patterns"] = len(self.memory["patterns"])
88
+
89
+ with open(self.memory_file, 'w') as f:
90
+ json.dump(self.memory, f, indent=2)
91
+
92
+ def remember_pattern(
93
+ self,
94
+ task: Dict[str, Any],
95
+ result: Dict[str, Any],
96
+ agent_id: str,
97
+ skills_used: List[str],
98
+ metadata: Optional[Dict[str, Any]] = None
99
+ ) -> str:
100
+ """
101
+ Store a successful execution pattern.
102
+
103
+ Args:
104
+ task: Task that was executed
105
+ result: Execution result
106
+ agent_id: Agent that performed the task
107
+ skills_used: List of skills used
108
+ metadata: Optional additional metadata
109
+
110
+ Returns:
111
+ Pattern ID
112
+ """
113
+ pattern_id = f"pattern_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
114
+
115
+ # Extract keywords from task description
116
+ description = task.get("description", "")
117
+ keywords = self._extract_keywords(description)
118
+
119
+ pattern = {
120
+ "id": pattern_id,
121
+ "created_at": datetime.now().isoformat(),
122
+ "task": {
123
+ "description": description,
124
+ "keywords": keywords,
125
+ "requirements": task.get("requirements", ""),
126
+ "context": task.get("context", "")
127
+ },
128
+ "execution": {
129
+ "agent_id": agent_id,
130
+ "skills_used": skills_used,
131
+ "model": result.get("model", "unknown"),
132
+ "provider": result.get("provider", "unknown")
133
+ },
134
+ "performance": {
135
+ "success": result.get("success", False),
136
+ "tokens_used": result.get("tokens_used", 0),
137
+ "cost": result.get("cost", 0.0),
138
+ "execution_time": result.get("execution_time", 0.0)
139
+ },
140
+ "metadata": metadata or {},
141
+ "usage_count": 0
142
+ }
143
+
144
+ self.memory["patterns"].append(pattern)
145
+
146
+ if result.get("success"):
147
+ self.memory["stats"]["successful_patterns"] += 1
148
+ else:
149
+ self.memory["stats"]["failed_patterns"] += 1
150
+
151
+ self._save_memory()
152
+ self.stats["patterns_stored"] += 1
153
+
154
+ return pattern_id
155
+
156
+ def recall_patterns(
157
+ self,
158
+ task: Dict[str, Any],
159
+ top_k: int = 3,
160
+ min_success_rate: float = 0.7
161
+ ) -> List[Dict[str, Any]]:
162
+ """
163
+ Recall similar successful patterns.
164
+
165
+ Args:
166
+ task: Current task to find patterns for
167
+ top_k: Maximum number of patterns to return
168
+ min_success_rate: Minimum success rate threshold
169
+
170
+ Returns:
171
+ List of relevant patterns with similarity scores
172
+ """
173
+ description = task.get("description", "")
174
+ current_keywords = self._extract_keywords(description)
175
+
176
+ # Score each pattern
177
+ scored_patterns = []
178
+
179
+ for pattern in self.memory["patterns"]:
180
+ # Skip unsuccessful patterns
181
+ if not pattern["performance"]["success"]:
182
+ continue
183
+
184
+ # Calculate keyword overlap similarity
185
+ pattern_keywords = set(pattern["task"]["keywords"])
186
+ overlap = len(current_keywords & pattern_keywords)
187
+ union = len(current_keywords | pattern_keywords)
188
+
189
+ if union == 0:
190
+ similarity = 0.0
191
+ else:
192
+ similarity = overlap / union
193
+
194
+ # Boost by frequency (previously successful patterns)
195
+ frequency_boost = pattern["usage_count"] * 0.1
196
+
197
+ # Boost by recency (patterns from last 7 days)
198
+ created_at = datetime.fromisoformat(pattern["created_at"])
199
+ days_old = (datetime.now() - created_at).days
200
+ recency_boost = max(0, (7 - days_old) * 0.05)
201
+
202
+ total_score = similarity + frequency_boost + recency_boost
203
+
204
+ if total_score > 0:
205
+ scored_patterns.append({
206
+ "pattern": pattern,
207
+ "similarity": similarity,
208
+ "total_score": total_score
209
+ })
210
+
211
+ # Sort by total score
212
+ scored_patterns.sort(key=lambda x: x["total_score"], reverse=True)
213
+
214
+ # Update stats
215
+ if scored_patterns:
216
+ self.stats["patterns_recalled"] += len(scored_patterns[:top_k])
217
+ self.stats["hits"] += 1
218
+ else:
219
+ self.stats["misses"] += 1
220
+
221
+ # Return top patterns
222
+ return scored_patterns[:top_k]
223
+
224
+ def get_best_agent_for_task(
225
+ self,
226
+ task: Dict[str, Any],
227
+ min_success_rate: float = 0.7
228
+ ) -> Optional[Dict[str, Any]]:
229
+ """
230
+ Get the best agent configuration for a task based on history.
231
+
232
+ Args:
233
+ task: Task to find agent for
234
+ min_success_rate: Minimum success rate threshold
235
+
236
+ Returns:
237
+ Agent configuration dict or None
238
+ """
239
+ patterns = self.recall_patterns(task, top_k=10)
240
+
241
+ if not patterns:
242
+ return None
243
+
244
+ # Find most common successful agent/skill combination
245
+ agent_combinations = []
246
+
247
+ for scored_pattern in patterns:
248
+ pattern = scored_pattern["pattern"]
249
+ execution = pattern["execution"]
250
+
251
+ # Create combination key
252
+ combo_key = (
253
+ execution["agent_id"],
254
+ tuple(sorted(execution["skills_used"]))
255
+ )
256
+
257
+ agent_combinations.append(combo_key)
258
+
259
+ # Count occurrences
260
+ counter = Counter(agent_combinations)
261
+
262
+ if not counter:
263
+ return None
264
+
265
+ # Get most common combination
266
+ best_combo = counter.most_common(1)[0][0]
267
+
268
+ return {
269
+ "agent_id": best_combo[0],
270
+ "skills": list(best_combo[1]),
271
+ "confidence": counter[best_combo] / len(agent_combinations)
272
+ }
273
+
274
+ def set_preference(self, key: str, value: Any):
275
+ """
276
+ Store a user preference.
277
+
278
+ Args:
279
+ key: Preference key
280
+ value: Preference value
281
+ """
282
+ self.memory["preferences"][key] = {
283
+ "value": value,
284
+ "updated_at": datetime.now().isoformat()
285
+ }
286
+
287
+ self._save_memory()
288
+
289
+ def get_preference(self, key: str, default: Any = None) -> Any:
290
+ """
291
+ Get a user preference.
292
+
293
+ Args:
294
+ key: Preference key
295
+ default: Default value if not found
296
+
297
+ Returns:
298
+ Preference value or default
299
+ """
300
+ pref = self.memory["preferences"].get(key)
301
+ return pref["value"] if pref else default
302
+
303
+ def get_insights(self) -> Dict[str, Any]:
304
+ """
305
+ Get insights about patterns and performance.
306
+
307
+ Returns:
308
+ Dictionary with insights
309
+ """
310
+ patterns = self.memory["patterns"]
311
+
312
+ if not patterns:
313
+ return {
314
+ "total_patterns": 0,
315
+ "message": "No patterns stored yet"
316
+ }
317
+
318
+ # Calculate statistics
319
+ successful = [p for p in patterns if p["performance"]["success"]]
320
+ failed = [p for p in patterns if not p["performance"]["success"]]
321
+
322
+ avg_tokens = sum(p["performance"]["tokens_used"] for p in successful) / len(successful) if successful else 0
323
+ avg_cost = sum(p["performance"]["cost"] for p in successful) / len(successful) if successful else 0
324
+ avg_time = sum(p["performance"]["execution_time"] for p in successful) / len(successful) if successful else 0
325
+
326
+ # Most common keywords
327
+ all_keywords = []
328
+ for pattern in patterns:
329
+ all_keywords.extend(pattern["task"]["keywords"])
330
+
331
+ keyword_counter = Counter(all_keywords)
332
+
333
+ # Most used skills
334
+ all_skills = []
335
+ for pattern in patterns:
336
+ all_skills.extend(pattern["execution"]["skills_used"])
337
+
338
+ skill_counter = Counter(all_skills)
339
+
340
+ return {
341
+ "total_patterns": len(patterns),
342
+ "successful_patterns": len(successful),
343
+ "failed_patterns": len(failed),
344
+ "success_rate": len(successful) / len(patterns) if patterns else 0,
345
+ "avg_tokens_per_task": avg_tokens,
346
+ "avg_cost_per_task": avg_cost,
347
+ "avg_execution_time": avg_time,
348
+ "top_keywords": keyword_counter.most_common(10),
349
+ "top_skills": skill_counter.most_common(10),
350
+ "memory_stats": self.stats
351
+ }
352
+
353
+ def _extract_keywords(self, text: str) -> set:
354
+ """
355
+ Extract keywords from text.
356
+
357
+ Args:
358
+ text: Text to extract from
359
+
360
+ Returns:
361
+ Set of keywords
362
+ """
363
+ # Remove common words
364
+ stop_words = {
365
+ "the", "a", "an", "and", "or", "but", "in", "on", "at", "to",
366
+ "for", "of", "with", "by", "from", "as", "is", "was", "are",
367
+ "been", "be", "have", "has", "had", "do", "does", "did", "will",
368
+ "would", "should", "could", "may", "might", "can", "this", "that"
369
+ }
370
+
371
+ # Extract words
372
+ words = re.findall(r'\w+', text.lower())
373
+
374
+ # Filter stop words and short words
375
+ keywords = {w for w in words if w not in stop_words and len(w) > 2}
376
+
377
+ return keywords
378
+
379
+ def export_memory(self, export_path: str):
380
+ """
381
+ Export memory to a file.
382
+
383
+ Args:
384
+ export_path: Path to export to
385
+ """
386
+ export_path = Path(export_path)
387
+ export_path.parent.mkdir(parents=True, exist_ok=True)
388
+
389
+ with open(export_path, 'w') as f:
390
+ json.dump(self.memory, f, indent=2)
391
+
392
+ print(f"Memory exported to {export_path}")
393
+
394
+ def import_memory(self, import_path: str):
395
+ """
396
+ Import memory from a file.
397
+
398
+ Args:
399
+ import_path: Path to import from
400
+ """
401
+ import_path = Path(import_path)
402
+
403
+ if not import_path.exists():
404
+ raise FileNotFoundError(f"Import file not found: {import_path}")
405
+
406
+ with open(import_path, 'r') as f:
407
+ imported_memory = json.load(f)
408
+
409
+ # Merge patterns
410
+ self.memory["patterns"].extend(imported_memory.get("patterns", []))
411
+
412
+ # Merge preferences
413
+ self.memory["preferences"].update(imported_memory.get("preferences", {}))
414
+
415
+ self._save_memory()
416
+
417
+ print(f"Memory imported from {import_path}")
418
+
419
+ def clear_old_patterns(self, days_old: int = 30):
420
+ """
421
+ Clear patterns older than specified days.
422
+
423
+ Args:
424
+ days_old: Age threshold in days
425
+ """
426
+ cutoff_date = datetime.now().timestamp() - (days_old * 24 * 60 * 60)
427
+
428
+ old_patterns = []
429
+ for pattern in self.memory["patterns"]:
430
+ created_at = datetime.fromisoformat(pattern["created_at"]).timestamp()
431
+
432
+ if created_at < cutoff_date:
433
+ old_patterns.append(pattern)
434
+
435
+ for pattern in old_patterns:
436
+ self.memory["patterns"].remove(pattern)
437
+
438
+ self._save_memory()
439
+
440
+ print(f"Cleared {len(old_patterns)} patterns older than {days_old} days")
441
+
442
+
443
+ # Convenience function for quick pattern storage
444
+
445
+ def remember_success(
446
+ task: Dict[str, Any],
447
+ result: Dict[str, Any],
448
+ agent_id: str,
449
+ skills_used: List[str],
450
+ memory_file: str = ".taskmaster/memory.json"
451
+ ) -> str:
452
+ """
453
+ Quick function to remember a successful pattern.
454
+
455
+ Args:
456
+ task: Task that was executed
457
+ result: Execution result
458
+ agent_id: Agent ID
459
+ skills_used: Skills used
460
+ memory_file: Path to memory file
461
+
462
+ Returns:
463
+ Pattern ID
464
+ """
465
+ memory = SimpleProjectMemory(memory_file)
466
+ return memory.remember_pattern(task, result, agent_id, skills_used)