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.
- package/LICENSE +21 -0
- package/README.md +146 -66
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/integrations/airtable.js +20 -0
- package/dist/integrations/discord.js +18 -0
- package/dist/integrations/github.js +23 -0
- package/dist/integrations/gmail.js +19 -0
- package/dist/integrations/google-calendar.js +18 -0
- package/dist/integrations/index.js +61 -0
- package/dist/integrations/jira.js +21 -0
- package/dist/integrations/linear.js +19 -0
- package/dist/integrations/notion.js +19 -0
- package/dist/integrations/slack.js +18 -0
- package/dist/integrations/telegram.js +19 -0
- package/dist/providers/registry.js +7 -3
- package/docs/ARCHITECTURAL-IMPROVEMENTS-2025.md +1391 -0
- package/docs/ARCHITECTURAL-IMPROVEMENTS-REVISED-2025.md +1051 -0
- package/docs/CONFIGURATION.md +476 -0
- package/docs/COUNCIL_DECISION.json +308 -0
- package/docs/COUNCIL_SUMMARY.md +265 -0
- package/docs/COUNCIL_V2.2_DECISION.md +416 -0
- package/docs/IMPROVEMENT_ROADMAP.md +515 -0
- package/docs/LLM_COUNCIL_DECISION.md +508 -0
- package/docs/QUICK_START_VISIBILITY.md +782 -0
- package/docs/REDDIT_GAP_ANALYSIS.md +299 -0
- package/docs/RESEARCH_BACKED_IMPROVEMENTS.md +1180 -0
- package/docs/TMLPD_QNA.md +751 -0
- package/docs/TMLPD_V2.1_COMPLETE.md +763 -0
- package/docs/TMLPD_V2.2_RESEARCH_ROADMAP.md +754 -0
- package/docs/V2.2_IMPLEMENTATION_COMPLETE.md +446 -0
- package/docs/V2_IMPLEMENTATION_GUIDE.md +388 -0
- package/docs/VISIBILITY_ADOPTION_PLAN.md +1005 -0
- package/docs/launch-content/LAUNCH_EXECUTION_CHECKLIST.md +421 -0
- package/docs/launch-content/README.md +457 -0
- package/docs/launch-content/assets/cost_comparison_100_tasks.png +0 -0
- package/docs/launch-content/assets/cumulative_savings.png +0 -0
- package/docs/launch-content/assets/parallel_speedup.png +0 -0
- package/docs/launch-content/assets/provider_pricing_comparison.png +0 -0
- package/docs/launch-content/assets/task_breakdown_comparison.png +0 -0
- package/docs/launch-content/generate_charts.py +313 -0
- package/docs/launch-content/hn_show_post.md +139 -0
- package/docs/launch-content/partner_outreach_templates.md +745 -0
- package/docs/launch-content/reddit_posts.md +467 -0
- package/docs/launch-content/twitter_thread.txt +460 -0
- package/examples/QUICKSTART.md +1 -1
- package/openclaw-alexa-bridge/ALL_REMAINING_FIXES_PLAN.md +313 -0
- package/openclaw-alexa-bridge/REMAINING_FIXES_SUMMARY.md +277 -0
- package/openclaw-alexa-bridge/src/alexa_handler_no_tmlpd.js +1234 -0
- package/openclaw-alexa-bridge/test_fixes.js +77 -0
- package/package.json +120 -29
- package/package.json.tmp +0 -0
- package/qna/TMLPD_QNA.md +3 -3
- package/skill/SKILL.md +2 -2
- package/src/__tests__/integration/tmpld_integration.test.py +540 -0
- package/src/agents/skill_enhanced_agent.py +318 -0
- package/src/memory/__init__.py +15 -0
- package/src/memory/agentic_memory.py +353 -0
- package/src/memory/semantic_memory.py +444 -0
- package/src/memory/simple_memory.py +466 -0
- package/src/memory/working_memory.py +447 -0
- package/src/orchestration/__init__.py +52 -0
- package/src/orchestration/execution_engine.py +353 -0
- package/src/orchestration/halo_orchestrator.py +367 -0
- package/src/orchestration/mcts_workflow.py +498 -0
- package/src/orchestration/role_assigner.py +473 -0
- package/src/orchestration/task_planner.py +522 -0
- package/src/providers/__init__.py +67 -0
- package/src/providers/anthropic.py +304 -0
- package/src/providers/base.py +241 -0
- package/src/providers/cerebras.py +373 -0
- package/src/providers/registry.py +476 -0
- package/src/routing/__init__.py +30 -0
- package/src/routing/universal_router.py +621 -0
- package/src/skills/TMLPD-QUICKREF.md +210 -0
- package/src/skills/TMLPD-SETUP-SUMMARY.md +157 -0
- package/src/skills/TMLPD.md +540 -0
- package/src/skills/__tests__/skill_manager.test.ts +328 -0
- package/src/skills/skill_manager.py +385 -0
- package/src/skills/test-tmlpd.sh +108 -0
- package/src/skills/tmlpd-category.yaml +67 -0
- package/src/skills/tmlpd-monitoring.yaml +188 -0
- package/src/skills/tmlpd-phase.yaml +132 -0
- package/src/state/__init__.py +17 -0
- package/src/state/simple_checkpoint.py +508 -0
- package/src/tmlpd_agent.py +464 -0
- package/src/tmpld_v2.py +427 -0
- package/src/workflows/__init__.py +18 -0
- package/src/workflows/advanced_difficulty_classifier.py +377 -0
- package/src/workflows/chaining_executor.py +417 -0
- package/src/workflows/difficulty_integration.py +209 -0
- package/src/workflows/orchestrator.py +469 -0
- package/src/workflows/orchestrator_executor.py +456 -0
- package/src/workflows/parallelization_executor.py +382 -0
- package/src/workflows/router.py +311 -0
- package/test_integration_simple.py +86 -0
- package/test_mcts_workflow.py +150 -0
- package/test_templd_integration.py +262 -0
- package/test_universal_router.py +275 -0
- package/tmlpd-pi-extension/README.md +36 -0
- package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts +114 -0
- package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/cache/prefixCache.js +285 -0
- package/tmlpd-pi-extension/dist/cache/prefixCache.js.map +1 -0
- package/tmlpd-pi-extension/dist/cache/responseCache.d.ts +58 -0
- package/tmlpd-pi-extension/dist/cache/responseCache.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/cache/responseCache.js +153 -0
- package/tmlpd-pi-extension/dist/cache/responseCache.js.map +1 -0
- package/tmlpd-pi-extension/dist/cli.js +59 -0
- package/tmlpd-pi-extension/dist/cost/costTracker.d.ts +95 -0
- package/tmlpd-pi-extension/dist/cost/costTracker.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/cost/costTracker.js +240 -0
- package/tmlpd-pi-extension/dist/cost/costTracker.js.map +1 -0
- package/tmlpd-pi-extension/dist/index.d.ts +723 -0
- package/tmlpd-pi-extension/dist/index.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/index.js +239 -0
- package/tmlpd-pi-extension/dist/index.js.map +1 -0
- package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts +82 -0
- package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/memory/episodicMemory.js +145 -0
- package/tmlpd-pi-extension/dist/memory/episodicMemory.js.map +1 -0
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts +102 -0
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js +207 -0
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js.map +1 -0
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts +85 -0
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js +210 -0
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js.map +1 -0
- package/tmlpd-pi-extension/dist/providers/localProvider.d.ts +102 -0
- package/tmlpd-pi-extension/dist/providers/localProvider.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/providers/localProvider.js +338 -0
- package/tmlpd-pi-extension/dist/providers/localProvider.js.map +1 -0
- package/tmlpd-pi-extension/dist/providers/registry.d.ts +55 -0
- package/tmlpd-pi-extension/dist/providers/registry.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/providers/registry.js +138 -0
- package/tmlpd-pi-extension/dist/providers/registry.js.map +1 -0
- package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts +68 -0
- package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/routing/advancedRouter.js +332 -0
- package/tmlpd-pi-extension/dist/routing/advancedRouter.js.map +1 -0
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts +101 -0
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.js +368 -0
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.js.map +1 -0
- package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts +96 -0
- package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/utils/batchProcessor.js +170 -0
- package/tmlpd-pi-extension/dist/utils/batchProcessor.js.map +1 -0
- package/tmlpd-pi-extension/dist/utils/compression.d.ts +61 -0
- package/tmlpd-pi-extension/dist/utils/compression.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/utils/compression.js +281 -0
- package/tmlpd-pi-extension/dist/utils/compression.js.map +1 -0
- package/tmlpd-pi-extension/dist/utils/reliability.d.ts +74 -0
- package/tmlpd-pi-extension/dist/utils/reliability.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/utils/reliability.js +177 -0
- package/tmlpd-pi-extension/dist/utils/reliability.js.map +1 -0
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts +117 -0
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js +246 -0
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js.map +1 -0
- package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts +50 -0
- package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts.map +1 -0
- package/tmlpd-pi-extension/dist/utils/tokenUtils.js +124 -0
- package/tmlpd-pi-extension/dist/utils/tokenUtils.js.map +1 -0
- package/tmlpd-pi-extension/examples/QUICKSTART.md +183 -0
- package/tmlpd-pi-extension/package-lock.json +75 -0
- package/tmlpd-pi-extension/package.json +172 -0
- package/tmlpd-pi-extension/python/examples.py +53 -0
- package/tmlpd-pi-extension/python/integrations.py +330 -0
- package/tmlpd-pi-extension/python/setup.py +28 -0
- package/tmlpd-pi-extension/python/tmlpd.py +369 -0
- package/tmlpd-pi-extension/qna/REDDIT_GAP_ANALYSIS.md +299 -0
- package/tmlpd-pi-extension/qna/TMLPD_QNA.md +751 -0
- package/tmlpd-pi-extension/skill/SKILL.md +238 -0
- package/{src → tmlpd-pi-extension/src}/index.ts +1 -1
- package/tmlpd-pi-extension/tsconfig.json +18 -0
- package/demo/research-demo.js +0 -266
- package/notebooks/quickstart.ipynb +0 -157
- package/rust/tmlpd.h +0 -268
- package/src/cache/prefixCache.ts +0 -365
- package/src/routing/advancedRouter.ts +0 -406
- package/src/utils/speculativeDecoding.ts +0 -344
- /package/{src → tmlpd-pi-extension/src}/cache/responseCache.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/cost/costTracker.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/memory/episodicMemory.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/orchestration/haloOrchestrator.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/orchestration/mctsWorkflow.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/providers/localProvider.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/providers/registry.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/tools/tmlpdTools.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/utils/batchProcessor.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/utils/compression.ts +0 -0
- /package/{src → tmlpd-pi-extension/src}/utils/reliability.ts +0 -0
- /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)
|