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,540 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Integration Tests for TMLPD v2.0
|
|
3
|
+
|
|
4
|
+
Tests all phases working together:
|
|
5
|
+
- Phase 1: Agent Skills
|
|
6
|
+
- Phase 2: Routing Workflow
|
|
7
|
+
- Phase 3: Simple Memory
|
|
8
|
+
- Phase 4: Enhanced Checkpointing
|
|
9
|
+
- Phase 5: Orchestrator-Workers
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
import asyncio
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
import tempfile
|
|
16
|
+
import shutil
|
|
17
|
+
import json
|
|
18
|
+
|
|
19
|
+
from src.skills.skill_manager import SkillManager
|
|
20
|
+
from src.agents.skill_enhanced_agent import TMLEnhancedAgent
|
|
21
|
+
from src.workflows.router import TaskRouter
|
|
22
|
+
from src.memory.simple_memory import SimpleProjectMemory
|
|
23
|
+
from src.state.simple_checkpoint import SimpleCheckpoint
|
|
24
|
+
from src.workflows.orchestrator import OrchestratorWorkflow
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@pytest.fixture
|
|
28
|
+
def temp_dir():
|
|
29
|
+
"""Create temporary directory for tests"""
|
|
30
|
+
temp = Path(tempfile.mkdtemp())
|
|
31
|
+
yield temp
|
|
32
|
+
shutil.rmtree(temp)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
def test_skills_dir(temp_dir):
|
|
37
|
+
"""Create test skills directory"""
|
|
38
|
+
skills_dir = temp_dir / "skills"
|
|
39
|
+
skills_dir.mkdir()
|
|
40
|
+
|
|
41
|
+
# Create test skill
|
|
42
|
+
frontend_skill = skills_dir / "frontend"
|
|
43
|
+
frontend_skill.mkdir()
|
|
44
|
+
(frontend_skill / "SKILL.md").write_text("""---
|
|
45
|
+
name: "React Frontend"
|
|
46
|
+
description: "Best practices for React components with TypeScript and state management"
|
|
47
|
+
---
|
|
48
|
+
# React Frontend Development
|
|
49
|
+
|
|
50
|
+
This skill covers:
|
|
51
|
+
- TypeScript integration
|
|
52
|
+
- Component structure
|
|
53
|
+
- State management
|
|
54
|
+
- Testing with React Testing Library
|
|
55
|
+
""")
|
|
56
|
+
|
|
57
|
+
return str(skills_dir)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class TestPhase1AgentSkills:
|
|
61
|
+
"""Test Phase 1: Agent Skills"""
|
|
62
|
+
|
|
63
|
+
def test_skill_manager_initialization(self, test_skills_dir):
|
|
64
|
+
"""Test SkillManager initialization"""
|
|
65
|
+
manager = SkillManager(test_skills_dir)
|
|
66
|
+
|
|
67
|
+
assert len(manager.list_skills()) > 0
|
|
68
|
+
assert "React Frontend" in manager.list_skills()
|
|
69
|
+
|
|
70
|
+
def test_skill_progressive_disclosure(self, test_skills_dir):
|
|
71
|
+
"""Test progressive disclosure (Level 1 → Level 2)"""
|
|
72
|
+
manager = SkillManager(test_skills_dir)
|
|
73
|
+
|
|
74
|
+
# Level 1: Metadata should be loaded
|
|
75
|
+
assert len(manager.skills) > 0
|
|
76
|
+
|
|
77
|
+
# Level 2: Full content should load on demand
|
|
78
|
+
skill = manager.load_skill("React Frontend")
|
|
79
|
+
assert skill.content is not None
|
|
80
|
+
assert "TypeScript integration" in skill.content
|
|
81
|
+
|
|
82
|
+
def test_skill_discovery(self, test_skills_dir):
|
|
83
|
+
"""Test get_relevant_skills for discovery"""
|
|
84
|
+
manager = SkillManager(test_skills_dir)
|
|
85
|
+
|
|
86
|
+
relevant = manager.get_relevant_skills(
|
|
87
|
+
"Build a React component with TypeScript"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
assert len(relevant) > 0
|
|
91
|
+
assert "React Frontend" in relevant
|
|
92
|
+
|
|
93
|
+
def test_enhanced_agent_with_skills(self, test_skills_dir):
|
|
94
|
+
"""Test TMLEnhancedAgent with assigned skills"""
|
|
95
|
+
agent = TMLEnhancedAgent(
|
|
96
|
+
agent_id="test-agent",
|
|
97
|
+
provider="anthropic",
|
|
98
|
+
model="claude-sonnet-4",
|
|
99
|
+
skills_dir=test_skills_dir,
|
|
100
|
+
assigned_skills=["React Frontend"]
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
assert "React Frontend" in agent.get_assigned_skills()
|
|
104
|
+
|
|
105
|
+
# Execute task
|
|
106
|
+
task = {
|
|
107
|
+
"description": "Create a React button component",
|
|
108
|
+
"requirements": "Use TypeScript"
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
result = agent.execute_task(task)
|
|
112
|
+
assert result is not None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class TestPhase2RoutingWorkflow:
|
|
116
|
+
"""Test Phase 2: Routing Workflow"""
|
|
117
|
+
|
|
118
|
+
def test_router_initialization(self, test_skills_dir):
|
|
119
|
+
"""Test TaskRouter initialization"""
|
|
120
|
+
router = TaskRouter(skills_dir=test_skills_dir)
|
|
121
|
+
|
|
122
|
+
assert router.skill_manager is not None
|
|
123
|
+
assert router.config is not None
|
|
124
|
+
|
|
125
|
+
def test_task_classification_simple(self, test_skills_dir):
|
|
126
|
+
"""Test classification of simple task"""
|
|
127
|
+
router = TaskRouter(skills_dir=test_skills_dir)
|
|
128
|
+
|
|
129
|
+
task = {
|
|
130
|
+
"description": "Create a React button"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
classification = router.classify_task(task)
|
|
134
|
+
|
|
135
|
+
assert classification["task_type"] in ["simple", "workflow", "agent"]
|
|
136
|
+
assert 0 <= classification["complexity"] <= 1
|
|
137
|
+
|
|
138
|
+
def test_task_classification_complex(self, test_skills_dir):
|
|
139
|
+
"""Test classification of complex task"""
|
|
140
|
+
router = TaskRouter(skills_dir=test_skills_dir)
|
|
141
|
+
|
|
142
|
+
task = {
|
|
143
|
+
"description": "Create a full-stack application with React frontend and Node.js backend, then deploy to cloud, then set up CI/CD pipeline"
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
classification = router.classify_task(task)
|
|
147
|
+
|
|
148
|
+
# Should be classified as workflow or agent due to complexity
|
|
149
|
+
assert classification["task_type"] in ["workflow", "agent"]
|
|
150
|
+
assert classification["complexity"] > 0.5
|
|
151
|
+
|
|
152
|
+
def test_routing_to_skill(self, test_skills_dir):
|
|
153
|
+
"""Test routing to direct skill (80% case)"""
|
|
154
|
+
router = TaskRouter(skills_dir=test_skills_dir)
|
|
155
|
+
|
|
156
|
+
task = {
|
|
157
|
+
"description": "Create a React button"
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
result = router.route(task)
|
|
161
|
+
|
|
162
|
+
assert result["strategy"] in ["direct_skill", "workflow", "agent"]
|
|
163
|
+
assert "execution_plan" in result
|
|
164
|
+
|
|
165
|
+
def test_routing_statistics(self, test_skills_dir):
|
|
166
|
+
"""Test routing statistics tracking"""
|
|
167
|
+
router = TaskRouter(skills_dir=test_skills_dir)
|
|
168
|
+
|
|
169
|
+
# Route several tasks
|
|
170
|
+
for i in range(5):
|
|
171
|
+
router.route({"description": f"Test task {i}"})
|
|
172
|
+
|
|
173
|
+
stats = router.get_routing_stats()
|
|
174
|
+
assert stats["total_tasks"] == 5
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class TestPhase3SimpleMemory:
|
|
178
|
+
"""Test Phase 3: Simple Memory"""
|
|
179
|
+
|
|
180
|
+
def test_memory_initialization(self, temp_dir):
|
|
181
|
+
"""Test SimpleProjectMemory initialization"""
|
|
182
|
+
memory_file = temp_dir / "memory.json"
|
|
183
|
+
memory = SimpleProjectMemory(str(memory_file))
|
|
184
|
+
|
|
185
|
+
assert memory_file.exists()
|
|
186
|
+
assert memory.memory is not None
|
|
187
|
+
|
|
188
|
+
def test_remember_pattern(self, temp_dir):
|
|
189
|
+
"""Test storing a successful pattern"""
|
|
190
|
+
memory_file = temp_dir / "memory.json"
|
|
191
|
+
memory = SimpleProjectMemory(str(memory_file))
|
|
192
|
+
|
|
193
|
+
task = {"description": "Create React button"}
|
|
194
|
+
result = {
|
|
195
|
+
"success": True,
|
|
196
|
+
"tokens_used": 100,
|
|
197
|
+
"cost": 0.01,
|
|
198
|
+
"execution_time": 2.5
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
pattern_id = memory.remember_pattern(
|
|
202
|
+
task=task,
|
|
203
|
+
result=result,
|
|
204
|
+
agent_id="test-agent",
|
|
205
|
+
skills_used=["React Frontend"]
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
assert pattern_id is not None
|
|
209
|
+
assert len(memory.memory["patterns"]) == 1
|
|
210
|
+
|
|
211
|
+
def test_recall_patterns(self, temp_dir):
|
|
212
|
+
"""Test recalling similar patterns"""
|
|
213
|
+
memory_file = temp_dir / "memory.json"
|
|
214
|
+
memory = SimpleProjectMemory(str(memory_file))
|
|
215
|
+
|
|
216
|
+
# Store a pattern
|
|
217
|
+
task = {"description": "Create React button component"}
|
|
218
|
+
result = {"success": True, "tokens_used": 100, "cost": 0.01}
|
|
219
|
+
|
|
220
|
+
memory.remember_pattern(
|
|
221
|
+
task=task,
|
|
222
|
+
result=result,
|
|
223
|
+
agent_id="test-agent",
|
|
224
|
+
skills_used=["React Frontend"]
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Recall similar pattern
|
|
228
|
+
current_task = {"description": "Build React button with TypeScript"}
|
|
229
|
+
patterns = memory.recall_patterns(current_task)
|
|
230
|
+
|
|
231
|
+
assert len(patterns) > 0
|
|
232
|
+
|
|
233
|
+
def test_get_best_agent(self, temp_dir):
|
|
234
|
+
"""Test getting best agent from memory"""
|
|
235
|
+
memory_file = temp_dir / "memory.json"
|
|
236
|
+
memory = SimpleProjectMemory(str(memory_file))
|
|
237
|
+
|
|
238
|
+
# Store successful pattern
|
|
239
|
+
task = {"description": "Create React component"}
|
|
240
|
+
result = {"success": True}
|
|
241
|
+
|
|
242
|
+
memory.remember_pattern(
|
|
243
|
+
task=task,
|
|
244
|
+
result=result,
|
|
245
|
+
agent_id="frontend-agent",
|
|
246
|
+
skills_used=["React Frontend"]
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# Get best agent
|
|
250
|
+
best = memory.get_best_agent_for_task({"description": "Build React component"})
|
|
251
|
+
|
|
252
|
+
assert best is not None
|
|
253
|
+
assert best["agent_id"] == "frontend-agent"
|
|
254
|
+
|
|
255
|
+
def test_memory_insights(self, temp_dir):
|
|
256
|
+
"""Test getting memory insights"""
|
|
257
|
+
memory_file = temp_dir / "memory.json"
|
|
258
|
+
memory = SimpleProjectMemory(str(memory_file))
|
|
259
|
+
|
|
260
|
+
# Store multiple patterns
|
|
261
|
+
for i in range(5):
|
|
262
|
+
task = {"description": f"Test task {i}"}
|
|
263
|
+
result = {"success": True, "tokens_used": 100 * (i + 1)}
|
|
264
|
+
|
|
265
|
+
memory.remember_pattern(
|
|
266
|
+
task=task,
|
|
267
|
+
result=result,
|
|
268
|
+
agent_id="test-agent",
|
|
269
|
+
skills_used=["React Frontend"]
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
insights = memory.get_insights()
|
|
273
|
+
assert insights["total_patterns"] == 5
|
|
274
|
+
assert insights["successful_patterns"] == 5
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class TestPhase4Checkpointing:
|
|
278
|
+
"""Test Phase 4: Enhanced Checkpointing"""
|
|
279
|
+
|
|
280
|
+
def test_checkpoint_initialization(self, temp_dir):
|
|
281
|
+
"""Test SimpleCheckpoint initialization"""
|
|
282
|
+
checkpoint_dir = temp_dir / "checkpoints"
|
|
283
|
+
checkpoint = SimpleCheckpoint(str(checkpoint_dir))
|
|
284
|
+
|
|
285
|
+
assert checkpoint_dir.exists()
|
|
286
|
+
assert checkpoint.index is not None
|
|
287
|
+
|
|
288
|
+
def test_create_checkpoint(self, temp_dir):
|
|
289
|
+
"""Test creating a checkpoint"""
|
|
290
|
+
checkpoint_dir = temp_dir / "checkpoints"
|
|
291
|
+
checkpoint = SimpleCheckpoint(str(checkpoint_dir))
|
|
292
|
+
|
|
293
|
+
state = {"current_task": "task_1", "progress": 50}
|
|
294
|
+
|
|
295
|
+
checkpoint_id = checkpoint.create_checkpoint(
|
|
296
|
+
state=state,
|
|
297
|
+
name="test_checkpoint"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
assert checkpoint_id is not None
|
|
301
|
+
assert len(checkpoint.index["checkpoints"]) == 1
|
|
302
|
+
|
|
303
|
+
def test_restore_checkpoint(self, temp_dir):
|
|
304
|
+
"""Test restoring from checkpoint"""
|
|
305
|
+
checkpoint_dir = temp_dir / "checkpoints"
|
|
306
|
+
checkpoint = SimpleCheckpoint(str(checkpoint_dir))
|
|
307
|
+
|
|
308
|
+
# Create checkpoint
|
|
309
|
+
state = {"current_task": "task_1", "progress": 50}
|
|
310
|
+
checkpoint_id = checkpoint.create_checkpoint(state=state)
|
|
311
|
+
|
|
312
|
+
# Restore checkpoint
|
|
313
|
+
restored_state = checkpoint.restore_checkpoint(checkpoint_id)
|
|
314
|
+
|
|
315
|
+
assert restored_state == state
|
|
316
|
+
|
|
317
|
+
def test_list_checkpoints(self, temp_dir):
|
|
318
|
+
"""Test listing checkpoints"""
|
|
319
|
+
checkpoint_dir = temp_dir / "checkpoints"
|
|
320
|
+
checkpoint = SimpleCheckpoint(str(checkpoint_dir))
|
|
321
|
+
|
|
322
|
+
# Create multiple checkpoints
|
|
323
|
+
for i in range(3):
|
|
324
|
+
checkpoint.create_checkpoint(
|
|
325
|
+
state={"task": i},
|
|
326
|
+
name=f"checkpoint_{i}"
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
# List checkpoints
|
|
330
|
+
checkpoints = checkpoint.list_checkpoints()
|
|
331
|
+
|
|
332
|
+
assert len(checkpoints) == 3
|
|
333
|
+
|
|
334
|
+
def test_checkpoint_validation(self, temp_dir):
|
|
335
|
+
"""Test checkpoint validation"""
|
|
336
|
+
checkpoint_dir = temp_dir / "checkpoints"
|
|
337
|
+
checkpoint = SimpleCheckpoint(str(checkpoint_dir))
|
|
338
|
+
|
|
339
|
+
# Create checkpoint
|
|
340
|
+
state = {"test": "data"}
|
|
341
|
+
checkpoint.create_checkpoint(state=state)
|
|
342
|
+
|
|
343
|
+
# Validate all
|
|
344
|
+
validation = checkpoint.validate_all_checkpoints()
|
|
345
|
+
|
|
346
|
+
assert validation["total"] == 1
|
|
347
|
+
assert validation["valid"] == 1
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class TestPhase5Orchestrator:
|
|
351
|
+
"""Test Phase 5: Orchestrator-Workers"""
|
|
352
|
+
|
|
353
|
+
@pytest.mark.asyncio
|
|
354
|
+
async def test_orchestrator_initialization(self, test_skills_dir, temp_dir):
|
|
355
|
+
"""Test OrchestratorWorkflow initialization"""
|
|
356
|
+
orchestrator = OrchestratorWorkflow(
|
|
357
|
+
skills_dir=test_skills_dir,
|
|
358
|
+
memory_file=str(temp_dir / "memory.json"),
|
|
359
|
+
checkpoint_dir=str(temp_dir / "checkpoints")
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
assert orchestrator.skill_manager is not None
|
|
363
|
+
assert orchestrator.memory is not None
|
|
364
|
+
assert orchestrator.checkpoint is not None
|
|
365
|
+
|
|
366
|
+
@pytest.mark.asyncio
|
|
367
|
+
async def test_task_breakdown(self, test_skills_dir, temp_dir):
|
|
368
|
+
"""Test breaking down complex task"""
|
|
369
|
+
orchestrator = OrchestratorWorkflow(
|
|
370
|
+
skills_dir=test_skills_dir,
|
|
371
|
+
memory_file=str(temp_dir / "memory.json")
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
task = {
|
|
375
|
+
"description": "Create component then add styling then write tests"
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
subtasks = await orchestrator._break_down_task(task)
|
|
379
|
+
|
|
380
|
+
assert len(subtasks) > 0
|
|
381
|
+
assert "description" in subtasks[0]
|
|
382
|
+
|
|
383
|
+
@pytest.mark.asyncio
|
|
384
|
+
async def test_execute_simple_orchestration(self, test_skills_dir, temp_dir):
|
|
385
|
+
"""Test simple orchestration workflow"""
|
|
386
|
+
orchestrator = OrchestratorWorkflow(
|
|
387
|
+
skills_dir=test_skills_dir,
|
|
388
|
+
memory_file=str(temp_dir / "memory.json"),
|
|
389
|
+
checkpoint_dir=str(temp_dir / "checkpoints")
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
task = {
|
|
393
|
+
"description": "Create a React button component",
|
|
394
|
+
"requirements": "Use TypeScript"
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
result = await orchestrator.execute_task(
|
|
398
|
+
task,
|
|
399
|
+
enable_checkpointing=False
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
assert result is not None
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
class TestFullIntegration:
|
|
406
|
+
"""Test full system integration"""
|
|
407
|
+
|
|
408
|
+
@pytest.mark.asyncio
|
|
409
|
+
async def test_end_to_end_workflow(self, test_skills_dir, temp_dir):
|
|
410
|
+
"""Test complete workflow: Route → Execute → Remember → Checkpoint"""
|
|
411
|
+
|
|
412
|
+
# Setup
|
|
413
|
+
router = TaskRouter(skills_dir=test_skills_dir)
|
|
414
|
+
memory_file = temp_dir / "memory.json"
|
|
415
|
+
checkpoint_dir = temp_dir / "checkpoints"
|
|
416
|
+
|
|
417
|
+
memory = SimpleProjectMemory(str(memory_file))
|
|
418
|
+
checkpoint = SimpleCheckpoint(str(checkpoint_dir))
|
|
419
|
+
|
|
420
|
+
# Step 1: Route task
|
|
421
|
+
task = {"description": "Create React button component"}
|
|
422
|
+
routing_result = router.route(task)
|
|
423
|
+
|
|
424
|
+
assert routing_result["strategy"] in ["direct_skill", "workflow", "agent"]
|
|
425
|
+
|
|
426
|
+
# Step 2: Execute task (if direct skill)
|
|
427
|
+
if routing_result["strategy"] == "direct_skill":
|
|
428
|
+
agent = routing_result["execution_plan"]["agent"]
|
|
429
|
+
execution_result = agent.execute_task(task)
|
|
430
|
+
|
|
431
|
+
# Step 3: Remember successful pattern
|
|
432
|
+
if execution_result.get("success"):
|
|
433
|
+
memory.remember_pattern(
|
|
434
|
+
task=task,
|
|
435
|
+
result=execution_result,
|
|
436
|
+
agent_id=agent.agent_id,
|
|
437
|
+
skills_used=agent.get_assigned_skills()
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
# Step 4: Create checkpoint
|
|
441
|
+
checkpoint.create_checkpoint(
|
|
442
|
+
state={"task": task, "result": execution_result},
|
|
443
|
+
name="after_execution"
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
# Verify everything worked
|
|
447
|
+
assert len(memory.memory["patterns"]) > 0
|
|
448
|
+
assert len(checkpoint.index["checkpoints"]) > 0
|
|
449
|
+
|
|
450
|
+
@pytest.mark.asyncio
|
|
451
|
+
async def test_memory_enhanced_routing(self, test_skills_dir, temp_dir):
|
|
452
|
+
"""Test routing enhanced by memory"""
|
|
453
|
+
|
|
454
|
+
# Setup
|
|
455
|
+
router = TaskRouter(skills_dir=test_skills_dir)
|
|
456
|
+
memory_file = temp_dir / "memory.json"
|
|
457
|
+
memory = SimpleProjectMemory(str(memory_file))
|
|
458
|
+
|
|
459
|
+
# Store a successful pattern
|
|
460
|
+
task = {"description": "Create React component"}
|
|
461
|
+
result = {"success": True}
|
|
462
|
+
|
|
463
|
+
memory.remember_pattern(
|
|
464
|
+
task=task,
|
|
465
|
+
result=result,
|
|
466
|
+
agent_id="frontend-agent",
|
|
467
|
+
skills_used=["React Frontend"]
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Now route similar task
|
|
471
|
+
best_agent = memory.get_best_agent_for_task(task)
|
|
472
|
+
|
|
473
|
+
assert best_agent is not None
|
|
474
|
+
assert best_agent["agent_id"] == "frontend-agent"
|
|
475
|
+
|
|
476
|
+
@pytest.mark.asyncio
|
|
477
|
+
async def test_checkpoint_recovery_workflow(self, test_skills_dir, temp_dir):
|
|
478
|
+
"""Test recovery from checkpoint"""
|
|
479
|
+
|
|
480
|
+
checkpoint_dir = temp_dir / "checkpoints"
|
|
481
|
+
checkpoint = SimpleCheckpoint(str(checkpoint_dir))
|
|
482
|
+
|
|
483
|
+
# Create checkpoint with task state
|
|
484
|
+
task = {"description": "Create React component", "step": 1}
|
|
485
|
+
checkpoint_id = checkpoint.create_checkpoint(
|
|
486
|
+
state={"current_task": task, "step": 1},
|
|
487
|
+
name="work_in_progress"
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
# Simulate crash and recovery
|
|
491
|
+
restored_state = checkpoint.restore_checkpoint(checkpoint_id)
|
|
492
|
+
|
|
493
|
+
assert restored_state["current_task"] == task
|
|
494
|
+
assert restored_state["step"] == 1
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
# Performance tests
|
|
498
|
+
|
|
499
|
+
class TestPerformance:
|
|
500
|
+
"""Test performance characteristics"""
|
|
501
|
+
|
|
502
|
+
def test_skill_loading_performance(self, test_skills_dir):
|
|
503
|
+
"""Test skill loading is fast"""
|
|
504
|
+
import time
|
|
505
|
+
|
|
506
|
+
manager = SkillManager(test_skills_dir)
|
|
507
|
+
|
|
508
|
+
start = time.time()
|
|
509
|
+
manager.reload_skills()
|
|
510
|
+
duration = time.time() - start
|
|
511
|
+
|
|
512
|
+
# Should load metadata in under 1 second
|
|
513
|
+
assert duration < 1.0
|
|
514
|
+
|
|
515
|
+
def test_pattern_recall_performance(self, temp_dir):
|
|
516
|
+
"""Test pattern recall is fast"""
|
|
517
|
+
import time
|
|
518
|
+
|
|
519
|
+
memory_file = temp_dir / "memory.json"
|
|
520
|
+
memory = SimpleProjectMemory(str(memory_file))
|
|
521
|
+
|
|
522
|
+
# Store many patterns
|
|
523
|
+
for i in range(100):
|
|
524
|
+
task = {"description": f"Test task {i}"}
|
|
525
|
+
result = {"success": True}
|
|
526
|
+
|
|
527
|
+
memory.remember_pattern(
|
|
528
|
+
task=task,
|
|
529
|
+
result=result,
|
|
530
|
+
agent_id="test-agent",
|
|
531
|
+
skills_used=["Test Skill"]
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
# Test recall speed
|
|
535
|
+
start = time.time()
|
|
536
|
+
patterns = memory.recall_patterns({"description": "Test task 50"})
|
|
537
|
+
duration = time.time() - start
|
|
538
|
+
|
|
539
|
+
# Should recall in under 0.5 seconds even with 100 patterns
|
|
540
|
+
assert duration < 0.5
|