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,473 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RoleAssigner - Specialized Agent Assignment
|
|
3
|
+
|
|
4
|
+
Based on arXiv:2505.13516 (HALO) and arXiv:2506.12508v3 (AgentOrchestra)
|
|
5
|
+
|
|
6
|
+
This module implements Tier 2 of HALO orchestration:
|
|
7
|
+
- Analyzes subtask requirements
|
|
8
|
+
- Assigns specialized agents with appropriate capabilities
|
|
9
|
+
- Creates agent configurations for each subtask
|
|
10
|
+
- Optimizes agent selection for cost and quality
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
from typing import Dict, List, Any, Optional
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from enum import Enum
|
|
17
|
+
|
|
18
|
+
from .task_planner import SubTask, TaskType
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AgentRole(Enum):
|
|
22
|
+
"""Specialized agent roles"""
|
|
23
|
+
PLANNER = "planner" # Strategic thinking, decomposition
|
|
24
|
+
CODER = "coder" # Code generation, implementation
|
|
25
|
+
ANALYST = "analyst" # Data analysis, reasoning
|
|
26
|
+
RESEARCHER = "researcher" # Information gathering
|
|
27
|
+
TESTER = "tester" # Verification, validation
|
|
28
|
+
DEPLOYER = "deployer" # Infrastructure, deployment
|
|
29
|
+
GENERALIST = "generalist" # Jack-of-all-trades
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ModelCapability(Enum):
|
|
33
|
+
"""Model capabilities for routing"""
|
|
34
|
+
CODE_GENERATION = "code_generation"
|
|
35
|
+
TEXT_GENERATION = "text_generation"
|
|
36
|
+
DATA_ANALYSIS = "data_analysis"
|
|
37
|
+
REASONING = "reasoning"
|
|
38
|
+
SPEED = "speed"
|
|
39
|
+
COST_EFFICIENCY = "cost_efficiency"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class AgentConfig:
|
|
44
|
+
"""Configuration for an assigned agent"""
|
|
45
|
+
agent_id: str
|
|
46
|
+
role: AgentRole
|
|
47
|
+
model_provider: str # "anthropic", "openai", "cerebras", etc.
|
|
48
|
+
model_name: str
|
|
49
|
+
capabilities: List[str]
|
|
50
|
+
cost_per_1k_tokens: float
|
|
51
|
+
quality_score: float # 0-1
|
|
52
|
+
temperature: float = 0.7
|
|
53
|
+
max_tokens: int = 4096
|
|
54
|
+
|
|
55
|
+
def to_dict(self) -> Dict:
|
|
56
|
+
return {
|
|
57
|
+
"agent_id": self.agent_id,
|
|
58
|
+
"role": self.role.value,
|
|
59
|
+
"model_provider": self.model_provider,
|
|
60
|
+
"model_name": self.model_name,
|
|
61
|
+
"capabilities": self.capabilities,
|
|
62
|
+
"cost_per_1k_tokens": self.cost_per_1k_tokens,
|
|
63
|
+
"quality_score": self.quality_score,
|
|
64
|
+
"temperature": self.temperature,
|
|
65
|
+
"max_tokens": self.max_tokens
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class AgentAssignment:
|
|
71
|
+
"""Result of agent assignment for a subtask"""
|
|
72
|
+
subtask_id: str
|
|
73
|
+
agent_config: AgentConfig
|
|
74
|
+
confidence: float # 0-1, how well-suited the agent is
|
|
75
|
+
reasoning: str
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class RoleAssigner:
|
|
79
|
+
"""
|
|
80
|
+
Assign specialized agents to subtasks
|
|
81
|
+
|
|
82
|
+
Implements Tier 2 of HALO orchestration:
|
|
83
|
+
- Analyzes subtask requirements
|
|
84
|
+
- Selects optimal agent for each subtask
|
|
85
|
+
- Balances cost and quality
|
|
86
|
+
- Creates agent configurations
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(self):
|
|
90
|
+
"""Initialize role assigner with model registry"""
|
|
91
|
+
self.model_registry = self._build_model_registry()
|
|
92
|
+
self.agent_pool = []
|
|
93
|
+
|
|
94
|
+
async def assign_roles(
|
|
95
|
+
self,
|
|
96
|
+
subtasks: List[SubTask],
|
|
97
|
+
optimization_target: str = "quality" # "quality", "cost", "balanced"
|
|
98
|
+
) -> Dict[str, AgentAssignment]:
|
|
99
|
+
"""
|
|
100
|
+
Assign agents to all subtasks
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
subtasks: List of subtasks requiring agents
|
|
104
|
+
optimization_target: "quality" (best model), "cost" (cheapest), "balanced"
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Dict mapping subtask_id -> AgentAssignment
|
|
108
|
+
"""
|
|
109
|
+
assignments = {}
|
|
110
|
+
|
|
111
|
+
for subtask in subtasks:
|
|
112
|
+
assignment = await self._assign_agent(subtask, optimization_target)
|
|
113
|
+
assignments[subtask.id] = assignment
|
|
114
|
+
|
|
115
|
+
return assignments
|
|
116
|
+
|
|
117
|
+
async def _assign_agent(
|
|
118
|
+
self,
|
|
119
|
+
subtask: SubTask,
|
|
120
|
+
optimization_target: str
|
|
121
|
+
) -> AgentAssignment:
|
|
122
|
+
"""
|
|
123
|
+
Assign optimal agent for a single subtask
|
|
124
|
+
"""
|
|
125
|
+
# Step 1: Determine required role based on task type
|
|
126
|
+
required_role = self._map_task_type_to_role(subtask.task_type)
|
|
127
|
+
|
|
128
|
+
# Step 2: Get candidate models for this role
|
|
129
|
+
candidates = self._get_candidates_for_role(
|
|
130
|
+
required_role,
|
|
131
|
+
subtask.required_capabilities
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Step 3: Score candidates based on optimization target
|
|
135
|
+
scored_candidates = []
|
|
136
|
+
for candidate in candidates:
|
|
137
|
+
score = self._score_candidate(
|
|
138
|
+
candidate,
|
|
139
|
+
subtask,
|
|
140
|
+
optimization_target
|
|
141
|
+
)
|
|
142
|
+
scored_candidates.append((candidate, score))
|
|
143
|
+
|
|
144
|
+
# Step 4: Select best candidate
|
|
145
|
+
scored_candidates.sort(key=lambda x: x[1], reverse=True)
|
|
146
|
+
best_model, best_score = scored_candidates[0]
|
|
147
|
+
|
|
148
|
+
# Step 5: Create agent config
|
|
149
|
+
agent_config = AgentConfig(
|
|
150
|
+
agent_id=f"{required_role.value}_{subtask.id}",
|
|
151
|
+
role=required_role,
|
|
152
|
+
model_provider=best_model["provider"],
|
|
153
|
+
model_name=best_model["model"],
|
|
154
|
+
capabilities=best_model["capabilities"],
|
|
155
|
+
cost_per_1k_tokens=best_model["cost_per_1k_tokens"],
|
|
156
|
+
quality_score=best_model["quality_score"],
|
|
157
|
+
temperature=self._determine_temperature(subtask),
|
|
158
|
+
max_tokens=self._determine_max_tokens(subtask)
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Step 6: Calculate confidence
|
|
162
|
+
confidence = min(1.0, best_score / 100.0)
|
|
163
|
+
|
|
164
|
+
# Step 7: Generate reasoning
|
|
165
|
+
reasoning = self._generate_reasoning(agent_config, subtask, best_score)
|
|
166
|
+
|
|
167
|
+
return AgentAssignment(
|
|
168
|
+
subtask_id=subtask.id,
|
|
169
|
+
agent_config=agent_config,
|
|
170
|
+
confidence=confidence,
|
|
171
|
+
reasoning=reasoning
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def _build_model_registry(self) -> Dict[str, List[Dict]]:
|
|
175
|
+
"""
|
|
176
|
+
Build registry of available models with their capabilities
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Dict mapping role -> list of model configs
|
|
180
|
+
"""
|
|
181
|
+
return {
|
|
182
|
+
AgentRole.PLANNER: [
|
|
183
|
+
{
|
|
184
|
+
"provider": "anthropic",
|
|
185
|
+
"model": "claude-3-5-sonnet-20241022",
|
|
186
|
+
"capabilities": ["reasoning", "planning", "architecture"],
|
|
187
|
+
"cost_per_1k_tokens": 0.003,
|
|
188
|
+
"quality_score": 0.98
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"provider": "openai",
|
|
192
|
+
"model": "gpt-4o",
|
|
193
|
+
"capabilities": ["reasoning", "planning"],
|
|
194
|
+
"cost_per_1k_tokens": 0.0025,
|
|
195
|
+
"quality_score": 0.95
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
AgentRole.CODER: [
|
|
199
|
+
{
|
|
200
|
+
"provider": "anthropic",
|
|
201
|
+
"model": "claude-3-5-sonnet-20241022",
|
|
202
|
+
"capabilities": ["code_generation", "reasoning"],
|
|
203
|
+
"cost_per_1k_tokens": 0.003,
|
|
204
|
+
"quality_score": 0.97
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"provider": "openai",
|
|
208
|
+
"model": "gpt-4o",
|
|
209
|
+
"capabilities": ["code_generation"],
|
|
210
|
+
"cost_per_1k_tokens": 0.0025,
|
|
211
|
+
"quality_score": 0.94
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"provider": "cerebras",
|
|
215
|
+
"model": "llama-3.3-70b",
|
|
216
|
+
"capabilities": ["code_generation", "speed"],
|
|
217
|
+
"cost_per_1k_tokens": 0.0001,
|
|
218
|
+
"quality_score": 0.75
|
|
219
|
+
}
|
|
220
|
+
],
|
|
221
|
+
AgentRole.ANALYST: [
|
|
222
|
+
{
|
|
223
|
+
"provider": "anthropic",
|
|
224
|
+
"model": "claude-3-5-sonnet-20241022",
|
|
225
|
+
"capabilities": ["data_analysis", "reasoning"],
|
|
226
|
+
"cost_per_1k_tokens": 0.003,
|
|
227
|
+
"quality_score": 0.96
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"provider": "openai",
|
|
231
|
+
"model": "gpt-4o",
|
|
232
|
+
"capabilities": ["data_analysis"],
|
|
233
|
+
"cost_per_1k_tokens": 0.0025,
|
|
234
|
+
"quality_score": 0.93
|
|
235
|
+
}
|
|
236
|
+
],
|
|
237
|
+
AgentRole.RESEARCHER: [
|
|
238
|
+
{
|
|
239
|
+
"provider": "openai",
|
|
240
|
+
"model": "gpt-4o",
|
|
241
|
+
"capabilities": ["text_generation", "reasoning"],
|
|
242
|
+
"cost_per_1k_tokens": 0.0025,
|
|
243
|
+
"quality_score": 0.94
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"provider": "perplexity",
|
|
247
|
+
"model": "sonar-small-online",
|
|
248
|
+
"capabilities": ["text_generation", "speed", "online"],
|
|
249
|
+
"cost_per_1k_tokens": 0.0002,
|
|
250
|
+
"quality_score": 0.80
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
AgentRole.TESTER: [
|
|
254
|
+
{
|
|
255
|
+
"provider": "anthropic",
|
|
256
|
+
"model": "claude-3-5-sonnet-20241022",
|
|
257
|
+
"capabilities": ["reasoning", "testing"],
|
|
258
|
+
"cost_per_1k_tokens": 0.003,
|
|
259
|
+
"quality_score": 0.95
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"provider": "openai",
|
|
263
|
+
"model": "gpt-4o-mini",
|
|
264
|
+
"capabilities": ["testing", "speed"],
|
|
265
|
+
"cost_per_1k_tokens": 0.00015,
|
|
266
|
+
"quality_score": 0.85
|
|
267
|
+
}
|
|
268
|
+
],
|
|
269
|
+
AgentRole.DEPLOYER: [
|
|
270
|
+
{
|
|
271
|
+
"provider": "anthropic",
|
|
272
|
+
"model": "claude-3-5-sonnet-20241022",
|
|
273
|
+
"capabilities": ["reasoning", "deployment"],
|
|
274
|
+
"cost_per_1k_tokens": 0.003,
|
|
275
|
+
"quality_score": 0.94
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"provider": "openai",
|
|
279
|
+
"model": "gpt-4o",
|
|
280
|
+
"capabilities": ["deployment"],
|
|
281
|
+
"cost_per_1k_tokens": 0.0025,
|
|
282
|
+
"quality_score": 0.92
|
|
283
|
+
}
|
|
284
|
+
],
|
|
285
|
+
AgentRole.GENERALIST: [
|
|
286
|
+
{
|
|
287
|
+
"provider": "anthropic",
|
|
288
|
+
"model": "claude-3-5-sonnet-20241022",
|
|
289
|
+
"capabilities": ["text_generation", "reasoning", "code_generation"],
|
|
290
|
+
"cost_per_1k_tokens": 0.003,
|
|
291
|
+
"quality_score": 0.96
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"provider": "openai",
|
|
295
|
+
"model": "gpt-4o",
|
|
296
|
+
"capabilities": ["text_generation", "code_generation"],
|
|
297
|
+
"cost_per_1k_tokens": 0.0025,
|
|
298
|
+
"quality_score": 0.93
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"provider": "cerebras",
|
|
302
|
+
"model": "llama-3.3-70b",
|
|
303
|
+
"capabilities": ["speed", "cost_efficiency"],
|
|
304
|
+
"cost_per_1k_tokens": 0.0001,
|
|
305
|
+
"quality_score": 0.70
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
def _map_task_type_to_role(self, task_type: TaskType) -> AgentRole:
|
|
311
|
+
"""Map task type to agent role"""
|
|
312
|
+
mapping = {
|
|
313
|
+
TaskType.PLANNING: AgentRole.PLANNER,
|
|
314
|
+
TaskType.CODING: AgentRole.CODER,
|
|
315
|
+
TaskType.ANALYSIS: AgentRole.ANALYST,
|
|
316
|
+
TaskType.RESEARCH: AgentRole.RESEARCHER,
|
|
317
|
+
TaskType.TESTING: AgentRole.TESTER,
|
|
318
|
+
TaskType.DEPLOYMENT: AgentRole.DEPLOYER
|
|
319
|
+
}
|
|
320
|
+
return mapping.get(task_type, AgentRole.GENERALIST)
|
|
321
|
+
|
|
322
|
+
def _get_candidates_for_role(
|
|
323
|
+
self,
|
|
324
|
+
role: AgentRole,
|
|
325
|
+
required_capabilities: List[str]
|
|
326
|
+
) -> List[Dict]:
|
|
327
|
+
"""Get candidate models for a given role"""
|
|
328
|
+
candidates = self.model_registry.get(role, [])
|
|
329
|
+
|
|
330
|
+
# Filter by required capabilities
|
|
331
|
+
if required_capabilities:
|
|
332
|
+
filtered = []
|
|
333
|
+
for candidate in candidates:
|
|
334
|
+
if all(cap in candidate["capabilities"] for cap in required_capabilities):
|
|
335
|
+
filtered.append(candidate)
|
|
336
|
+
candidates = filtered or self.model_registry.get(AgentRole.GENERALIST, [])
|
|
337
|
+
|
|
338
|
+
return candidates
|
|
339
|
+
|
|
340
|
+
def _score_candidate(
|
|
341
|
+
self,
|
|
342
|
+
candidate: Dict,
|
|
343
|
+
subtask: SubTask,
|
|
344
|
+
optimization_target: str
|
|
345
|
+
) -> float:
|
|
346
|
+
"""
|
|
347
|
+
Score a candidate model for a subtask
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
Score 0-100
|
|
351
|
+
"""
|
|
352
|
+
# Base score from quality
|
|
353
|
+
score = candidate["quality_score"] * 50
|
|
354
|
+
|
|
355
|
+
# Adjust based on optimization target
|
|
356
|
+
if optimization_target == "quality":
|
|
357
|
+
# Prioritize quality score
|
|
358
|
+
score += candidate["quality_score"] * 50
|
|
359
|
+
elif optimization_target == "cost":
|
|
360
|
+
# Prioritize low cost (invert cost score)
|
|
361
|
+
cost_score = (1.0 / (candidate["cost_per_1k_tokens"] + 0.0001)) * 10
|
|
362
|
+
score += cost_score
|
|
363
|
+
else: # "balanced"
|
|
364
|
+
# Balance quality and cost
|
|
365
|
+
cost_score = (1.0 / (candidate["cost_per_1k_tokens"] + 0.0001)) * 5
|
|
366
|
+
score += (candidate["quality_score"] * 25) + cost_score
|
|
367
|
+
|
|
368
|
+
# Adjust for difficulty matching
|
|
369
|
+
if subtask.difficulty > 70 and candidate["quality_score"] > 0.9:
|
|
370
|
+
score += 10 # Bonus: high-quality model for hard task
|
|
371
|
+
elif subtask.difficulty < 40 and candidate["cost_per_1k_tokens"] < 0.001:
|
|
372
|
+
score += 10 # Bonus: cheap model for easy task
|
|
373
|
+
|
|
374
|
+
return min(100, score)
|
|
375
|
+
|
|
376
|
+
def _determine_temperature(self, subtask: SubTask) -> float:
|
|
377
|
+
"""Determine optimal temperature for subtask"""
|
|
378
|
+
if subtask.task_type in [TaskType.CODING, TaskType.DEPLOYMENT]:
|
|
379
|
+
return 0.3 # Lower temperature for precise tasks
|
|
380
|
+
elif subtask.task_type in [TaskType.RESEARCH, TaskType.ANALYSIS]:
|
|
381
|
+
return 0.7 # Medium temperature for exploration
|
|
382
|
+
else:
|
|
383
|
+
return 0.5 # Balanced default
|
|
384
|
+
|
|
385
|
+
def _determine_max_tokens(self, subtask: SubTask) -> int:
|
|
386
|
+
"""Determine max tokens for subtask"""
|
|
387
|
+
if subtask.task_type == TaskType.CODING:
|
|
388
|
+
return 8192 # Code generation needs more tokens
|
|
389
|
+
elif subtask.task_type == TaskType.RESEARCH:
|
|
390
|
+
return 4096 # Moderate for research
|
|
391
|
+
else:
|
|
392
|
+
return 2048 # Default
|
|
393
|
+
|
|
394
|
+
def _generate_reasoning(
|
|
395
|
+
self,
|
|
396
|
+
agent_config: AgentConfig,
|
|
397
|
+
subtask: SubTask,
|
|
398
|
+
score: float
|
|
399
|
+
) -> str:
|
|
400
|
+
"""Generate human-readable reasoning for assignment"""
|
|
401
|
+
return (
|
|
402
|
+
f"Assigned {agent_config.model_provider}/{agent_config.model_name} "
|
|
403
|
+
f"({agent_config.role.value}) to {subtask.id}. "
|
|
404
|
+
f"Match score: {score:.1f}/100. "
|
|
405
|
+
f"Quality: {agent_config.quality_score:.2f}, "
|
|
406
|
+
f"Cost: ${agent_config.cost_per_1k_tokens:.4f}/1K tokens"
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
def get_assignment_stats(
|
|
410
|
+
self,
|
|
411
|
+
assignments: Dict[str, AgentAssignment]
|
|
412
|
+
) -> Dict[str, Any]:
|
|
413
|
+
"""Get statistics about agent assignments"""
|
|
414
|
+
role_counts = {}
|
|
415
|
+
provider_costs = {}
|
|
416
|
+
|
|
417
|
+
for assignment in assignments.values():
|
|
418
|
+
role = assignment.agent_config.role.value
|
|
419
|
+
role_counts[role] = role_counts.get(role, 0) + 1
|
|
420
|
+
|
|
421
|
+
provider = assignment.agent_config.model_provider
|
|
422
|
+
cost = assignment.agent_config.cost_per_1k_tokens
|
|
423
|
+
provider_costs[provider] = provider_costs.get(provider, 0) + cost
|
|
424
|
+
|
|
425
|
+
return {
|
|
426
|
+
"total_assignments": len(assignments),
|
|
427
|
+
"role_distribution": role_counts,
|
|
428
|
+
"estimated_total_cost_per_1k_tokens": provider_costs,
|
|
429
|
+
"average_confidence": sum(
|
|
430
|
+
a.confidence for a in assignments.values()
|
|
431
|
+
) / len(assignments) if assignments else 0
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
# Example usage
|
|
436
|
+
async def main():
|
|
437
|
+
"""Example of RoleAssigner usage"""
|
|
438
|
+
from .task_planner import TaskPlanner, TaskType
|
|
439
|
+
|
|
440
|
+
# Create planner and assigner
|
|
441
|
+
planner = TaskPlanner()
|
|
442
|
+
assigner = RoleAssigner()
|
|
443
|
+
|
|
444
|
+
# Create a complex task
|
|
445
|
+
task = {
|
|
446
|
+
"description": "Build a REST API with user authentication",
|
|
447
|
+
"context": {"requirements": ["JWT", "PostgreSQL"]}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
# Decompose task
|
|
451
|
+
decomposition = await planner.decompose(task)
|
|
452
|
+
|
|
453
|
+
# Assign agents
|
|
454
|
+
assignments = await assigner.assign_roles(
|
|
455
|
+
decomposition.subtasks,
|
|
456
|
+
optimization_target="balanced"
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
print(f"Assigned {len(assignments)} agents:")
|
|
460
|
+
for subtask_id, assignment in assignments.items():
|
|
461
|
+
print(f"\n{subtask_id}:")
|
|
462
|
+
print(f" Agent: {assignment.agent_config.model_provider}/{assignment.agent_config.model_name}")
|
|
463
|
+
print(f" Role: {assignment.agent_config.role.value}")
|
|
464
|
+
print(f" Reasoning: {assignment.reasoning}")
|
|
465
|
+
print(f" Confidence: {assignment.confidence:.2f}")
|
|
466
|
+
|
|
467
|
+
# Stats
|
|
468
|
+
stats = assigner.get_assignment_stats(assignments)
|
|
469
|
+
print(f"\nStats: {stats}")
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
if __name__ == "__main__":
|
|
473
|
+
asyncio.run(main())
|