adaptive-memory-multi-model-router 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -0
- package/demo/research-demo.js +266 -0
- package/dist/cache/prefixCache.d.ts +114 -0
- package/dist/cache/prefixCache.d.ts.map +1 -0
- package/dist/cache/prefixCache.js +285 -0
- package/dist/cache/prefixCache.js.map +1 -0
- package/dist/cache/responseCache.d.ts +58 -0
- package/dist/cache/responseCache.d.ts.map +1 -0
- package/dist/cache/responseCache.js +153 -0
- package/dist/cache/responseCache.js.map +1 -0
- package/dist/cli.js +59 -0
- package/dist/cost/costTracker.d.ts +95 -0
- package/dist/cost/costTracker.d.ts.map +1 -0
- package/dist/cost/costTracker.js +240 -0
- package/dist/cost/costTracker.js.map +1 -0
- package/dist/index.d.ts +723 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +239 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/episodicMemory.d.ts +82 -0
- package/dist/memory/episodicMemory.d.ts.map +1 -0
- package/dist/memory/episodicMemory.js +145 -0
- package/dist/memory/episodicMemory.js.map +1 -0
- package/dist/orchestration/haloOrchestrator.d.ts +102 -0
- package/dist/orchestration/haloOrchestrator.d.ts.map +1 -0
- package/dist/orchestration/haloOrchestrator.js +207 -0
- package/dist/orchestration/haloOrchestrator.js.map +1 -0
- package/dist/orchestration/mctsWorkflow.d.ts +85 -0
- package/dist/orchestration/mctsWorkflow.d.ts.map +1 -0
- package/dist/orchestration/mctsWorkflow.js +210 -0
- package/dist/orchestration/mctsWorkflow.js.map +1 -0
- package/dist/providers/localProvider.d.ts +102 -0
- package/dist/providers/localProvider.d.ts.map +1 -0
- package/dist/providers/localProvider.js +338 -0
- package/dist/providers/localProvider.js.map +1 -0
- package/dist/providers/registry.d.ts +55 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +138 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/routing/advancedRouter.d.ts +68 -0
- package/dist/routing/advancedRouter.d.ts.map +1 -0
- package/dist/routing/advancedRouter.js +332 -0
- package/dist/routing/advancedRouter.js.map +1 -0
- package/dist/tools/tmlpdTools.d.ts +101 -0
- package/dist/tools/tmlpdTools.d.ts.map +1 -0
- package/dist/tools/tmlpdTools.js +368 -0
- package/dist/tools/tmlpdTools.js.map +1 -0
- package/dist/utils/batchProcessor.d.ts +96 -0
- package/dist/utils/batchProcessor.d.ts.map +1 -0
- package/dist/utils/batchProcessor.js +170 -0
- package/dist/utils/batchProcessor.js.map +1 -0
- package/dist/utils/compression.d.ts +61 -0
- package/dist/utils/compression.d.ts.map +1 -0
- package/dist/utils/compression.js +281 -0
- package/dist/utils/compression.js.map +1 -0
- package/dist/utils/reliability.d.ts +74 -0
- package/dist/utils/reliability.d.ts.map +1 -0
- package/dist/utils/reliability.js +177 -0
- package/dist/utils/reliability.js.map +1 -0
- package/dist/utils/speculativeDecoding.d.ts +117 -0
- package/dist/utils/speculativeDecoding.d.ts.map +1 -0
- package/dist/utils/speculativeDecoding.js +246 -0
- package/dist/utils/speculativeDecoding.js.map +1 -0
- package/dist/utils/tokenUtils.d.ts +50 -0
- package/dist/utils/tokenUtils.d.ts.map +1 -0
- package/dist/utils/tokenUtils.js +124 -0
- package/dist/utils/tokenUtils.js.map +1 -0
- package/examples/QUICKSTART.md +183 -0
- package/notebooks/quickstart.ipynb +157 -0
- package/package.json +83 -0
- package/python/examples.py +53 -0
- package/python/integrations.py +330 -0
- package/python/setup.py +28 -0
- package/python/tmlpd.py +369 -0
- package/qna/REDDIT_GAP_ANALYSIS.md +299 -0
- package/qna/TMLPD_QNA.md +751 -0
- package/rust/tmlpd.h +268 -0
- package/skill/SKILL.md +238 -0
- package/src/cache/prefixCache.ts +365 -0
- package/src/cache/responseCache.ts +147 -0
- package/src/cost/costTracker.ts +302 -0
- package/src/index.ts +224 -0
- package/src/memory/episodicMemory.ts +185 -0
- package/src/orchestration/haloOrchestrator.ts +266 -0
- package/src/orchestration/mctsWorkflow.ts +262 -0
- package/src/providers/localProvider.ts +406 -0
- package/src/providers/registry.ts +164 -0
- package/src/routing/advancedRouter.ts +406 -0
- package/src/tools/tmlpdTools.ts +433 -0
- package/src/utils/batchProcessor.ts +232 -0
- package/src/utils/compression.ts +325 -0
- package/src/utils/reliability.ts +221 -0
- package/src/utils/speculativeDecoding.ts +344 -0
- package/src/utils/tokenUtils.ts +145 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TMLPD Episodic Memory Store
|
|
3
|
+
*
|
|
4
|
+
* Stores specific task executions with full context.
|
|
5
|
+
* Reference implementation - for full features see TMLPD v2.x
|
|
6
|
+
*
|
|
7
|
+
* Full TMLPD includes:
|
|
8
|
+
* - JSON-based episodic storage with keyword indexing
|
|
9
|
+
* - Importance scoring and time-based decay
|
|
10
|
+
* - Episodic retrieval by task similarity
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { nanoid } from "nanoid";
|
|
14
|
+
|
|
15
|
+
export interface EpisodicEntry {
|
|
16
|
+
id: string;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
task: {
|
|
19
|
+
description: string;
|
|
20
|
+
type: string;
|
|
21
|
+
complexity: number;
|
|
22
|
+
};
|
|
23
|
+
result: {
|
|
24
|
+
success: boolean;
|
|
25
|
+
output: string;
|
|
26
|
+
duration_ms: number;
|
|
27
|
+
};
|
|
28
|
+
agent: {
|
|
29
|
+
id: string;
|
|
30
|
+
model: string;
|
|
31
|
+
provider: string;
|
|
32
|
+
};
|
|
33
|
+
metadata: Record<string, any>;
|
|
34
|
+
importance: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface MemoryQuery {
|
|
38
|
+
task_type?: string;
|
|
39
|
+
keywords?: string[];
|
|
40
|
+
limit?: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class EpisodicMemoryStore {
|
|
44
|
+
private entries: EpisodicEntry[] = [];
|
|
45
|
+
private maxEntries: number;
|
|
46
|
+
private keywordIndex: Map<string, string[]>;
|
|
47
|
+
|
|
48
|
+
constructor(maxEntries = 1000) {
|
|
49
|
+
this.maxEntries = maxEntries;
|
|
50
|
+
this.keywordIndex = new Map();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Store an episodic memory
|
|
55
|
+
*/
|
|
56
|
+
store(entry: Omit<EpisodicEntry, "id" | "timestamp">): string {
|
|
57
|
+
const id = nanoid(12);
|
|
58
|
+
const fullEntry: EpisodicEntry = {
|
|
59
|
+
...entry,
|
|
60
|
+
id,
|
|
61
|
+
timestamp: Date.now()
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
this.entries.push(fullEntry);
|
|
65
|
+
|
|
66
|
+
// Index keywords
|
|
67
|
+
if (entry.task.description) {
|
|
68
|
+
const words = entry.task.description.toLowerCase().split(/\s+/);
|
|
69
|
+
words.forEach(word => {
|
|
70
|
+
if (word.length > 3) {
|
|
71
|
+
const existing = this.keywordIndex.get(word) || [];
|
|
72
|
+
existing.push(id);
|
|
73
|
+
this.keywordIndex.set(word, existing);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Evict oldest if at capacity
|
|
79
|
+
if (this.entries.length > this.maxEntries) {
|
|
80
|
+
const evicted = this.entries.shift();
|
|
81
|
+
if (evicted) {
|
|
82
|
+
// Clean up keyword index for evicted entry
|
|
83
|
+
for (const [word, ids] of this.keywordIndex.entries()) {
|
|
84
|
+
const filtered = ids.filter(existingId => existingId !== evicted.id);
|
|
85
|
+
if (filtered.length === 0) {
|
|
86
|
+
this.keywordIndex.delete(word);
|
|
87
|
+
} else {
|
|
88
|
+
this.keywordIndex.set(word, filtered);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return id;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Query episodic memories
|
|
99
|
+
*/
|
|
100
|
+
query(query: MemoryQuery): EpisodicEntry[] {
|
|
101
|
+
let results = [...this.entries];
|
|
102
|
+
|
|
103
|
+
if (query.task_type) {
|
|
104
|
+
results = results.filter(e => e.task.type === query.task_type);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (query.keywords && query.keywords.length > 0) {
|
|
108
|
+
const matchingIds = new Set<string>();
|
|
109
|
+
query.keywords.forEach(kw => {
|
|
110
|
+
const lower = kw.toLowerCase();
|
|
111
|
+
for (const [word, ids] of this.keywordIndex.entries()) {
|
|
112
|
+
if (word.includes(lower)) {
|
|
113
|
+
ids.forEach(id => matchingIds.add(id));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
if (matchingIds.size > 0) {
|
|
118
|
+
results = results.filter(e => matchingIds.has(e.id));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return results.slice(-(query.limit || 10));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get similar tasks (for learning)
|
|
127
|
+
*/
|
|
128
|
+
getSimilarTasks(taskDescription: string, limit = 5): EpisodicEntry[] {
|
|
129
|
+
const words = taskDescription.toLowerCase().split(/\s+/);
|
|
130
|
+
const scores = new Map<string, number>();
|
|
131
|
+
|
|
132
|
+
this.entries.forEach(entry => {
|
|
133
|
+
let score = 0;
|
|
134
|
+
const entryWords = entry.task.description.toLowerCase().split(/\s+/);
|
|
135
|
+
words.forEach(w => {
|
|
136
|
+
if (entryWords.includes(w)) score++;
|
|
137
|
+
});
|
|
138
|
+
if (score > 0) {
|
|
139
|
+
scores.set(entry.id, score);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const sorted = Array.from(scores.entries())
|
|
144
|
+
.sort((a, b) => b[1] - a[1])
|
|
145
|
+
.slice(0, limit)
|
|
146
|
+
.map(([id]) => this.entries.find(e => e.id === id))
|
|
147
|
+
.filter(Boolean) as EpisodicEntry[];
|
|
148
|
+
|
|
149
|
+
return sorted;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get statistics
|
|
154
|
+
*/
|
|
155
|
+
getStats() {
|
|
156
|
+
return {
|
|
157
|
+
total_entries: this.entries.length,
|
|
158
|
+
indexed_keywords: this.keywordIndex.size,
|
|
159
|
+
success_rate: this.entries.filter(e => e.result.success).length / Math.max(1, this.entries.length),
|
|
160
|
+
avg_duration_ms: this.entries.reduce((sum, e) => sum + e.result.duration_ms, 0) / Math.max(1, this.entries.length)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Clear all memories
|
|
166
|
+
*/
|
|
167
|
+
clear() {
|
|
168
|
+
this.entries = [];
|
|
169
|
+
this.keywordIndex.clear();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Reference to Full TMLPD Memory System
|
|
175
|
+
*
|
|
176
|
+
* For production use with full features:
|
|
177
|
+
* - Install: npm install tmlpd-skill (Python)
|
|
178
|
+
* - Or integrate with tmlpd-clean/src/memory/
|
|
179
|
+
*
|
|
180
|
+
* Full features include:
|
|
181
|
+
* - Semantic memory with ChromaDB vector embeddings
|
|
182
|
+
* - Time-based importance decay (A-Mem pattern)
|
|
183
|
+
* - Cross-session learning
|
|
184
|
+
* - Episodic + Semantic + Working 3-tier architecture
|
|
185
|
+
*/
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TMLPD HALO Orchestrator Reference
|
|
3
|
+
*
|
|
4
|
+
* Hierarchical Autonomous Logic-Oriented Orchestration
|
|
5
|
+
*
|
|
6
|
+
* Reference implementation - for full features see TMLPD v2.x
|
|
7
|
+
*
|
|
8
|
+
* Full TMLPD includes:
|
|
9
|
+
* - 3-tier hierarchical planning
|
|
10
|
+
* - TaskPlanner: Decompose with dependencies
|
|
11
|
+
* - RoleAssigner: Specialized agent assignment
|
|
12
|
+
* - ExecutionEngine: Parallel with verification
|
|
13
|
+
* - 19.6% improvement on complex tasks
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { MCTSWorkflowOptimizer } from "./mctsWorkflow";
|
|
17
|
+
import { EpisodicMemoryStore } from "../memory/episodicMemory";
|
|
18
|
+
|
|
19
|
+
export interface SubTask {
|
|
20
|
+
id: string;
|
|
21
|
+
description: string;
|
|
22
|
+
dependencies: string[];
|
|
23
|
+
estimatedComplexity: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AgentAssignment {
|
|
27
|
+
subtaskId: string;
|
|
28
|
+
agentId: string;
|
|
29
|
+
model: string;
|
|
30
|
+
estimatedDuration: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ExecutionResult {
|
|
34
|
+
subtaskId: string;
|
|
35
|
+
success: boolean;
|
|
36
|
+
output: string;
|
|
37
|
+
duration_ms: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface HALOConfig {
|
|
41
|
+
maxConcurrent: number;
|
|
42
|
+
optimizationTarget: "quality" | "cost" | "balanced";
|
|
43
|
+
enableMCTS: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const DEFAULT_HALO_CONFIG: HALOConfig = {
|
|
47
|
+
maxConcurrent: 3,
|
|
48
|
+
optimizationTarget: "balanced",
|
|
49
|
+
enableMCTS: false
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* HALO Orchestrator
|
|
54
|
+
*
|
|
55
|
+
* Hierarchical orchestration with 3 tiers:
|
|
56
|
+
* 1. Plan: Decompose task into subtasks with dependencies
|
|
57
|
+
* 2. Assign: Match subtasks to optimal agents
|
|
58
|
+
* 3. Execute: Run in parallel with result verification
|
|
59
|
+
*/
|
|
60
|
+
export class HALOOrchestrator {
|
|
61
|
+
private config: HALOConfig;
|
|
62
|
+
private memory: EpisodicMemoryStore;
|
|
63
|
+
private mcts: MCTSWorkflowOptimizer;
|
|
64
|
+
|
|
65
|
+
constructor(config: Partial<HALOConfig> = {}) {
|
|
66
|
+
this.config = { ...DEFAULT_HALO_CONFIG, ...config };
|
|
67
|
+
this.memory = new EpisodicMemoryStore();
|
|
68
|
+
this.mcts = new MCTSWorkflowOptimizer({ maxIterations: 30 });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Execute task with HALO orchestration
|
|
73
|
+
*/
|
|
74
|
+
async execute(
|
|
75
|
+
taskDescription: string,
|
|
76
|
+
executeFn: (subtask: SubTask, agentId: string) => Promise<ExecutionResult>
|
|
77
|
+
): Promise<{
|
|
78
|
+
success: boolean;
|
|
79
|
+
results: ExecutionResult[];
|
|
80
|
+
strategy: Record<string, string>;
|
|
81
|
+
metadata: any;
|
|
82
|
+
}> {
|
|
83
|
+
// Phase 1: Plan - decompose task
|
|
84
|
+
const subtasks = this.decomposeTask(taskDescription);
|
|
85
|
+
|
|
86
|
+
// Check memory for similar successful strategies
|
|
87
|
+
const similar = this.memory.getSimilarTasks(taskDescription, 3);
|
|
88
|
+
|
|
89
|
+
// Phase 2: Assign - determine optimal agent assignments
|
|
90
|
+
const strategy = this.config.enableMCTS
|
|
91
|
+
? await this.optimizeWithMCTS(subtasks)
|
|
92
|
+
: this.quickAssign(subtasks);
|
|
93
|
+
|
|
94
|
+
// Phase 3: Execute - run with concurrency limit
|
|
95
|
+
const results = await this.executeParallel(subtasks, strategy, executeFn);
|
|
96
|
+
|
|
97
|
+
// Store in episodic memory
|
|
98
|
+
this.memory.store({
|
|
99
|
+
task: {
|
|
100
|
+
description: taskDescription,
|
|
101
|
+
type: this.classifyTask(taskDescription),
|
|
102
|
+
complexity: subtasks.length
|
|
103
|
+
},
|
|
104
|
+
result: {
|
|
105
|
+
success: results.every(r => r.success),
|
|
106
|
+
output: results.map(r => r.output).join("\n---\n"),
|
|
107
|
+
duration_ms: results.reduce((sum, r) => sum + r.duration_ms, 0)
|
|
108
|
+
},
|
|
109
|
+
agent: { id: "halo", model: "composite", provider: "multi" },
|
|
110
|
+
metadata: { strategy, subtaskCount: subtasks.length },
|
|
111
|
+
importance: subtasks.length > 5 ? 0.8 : 0.5
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
success: results.every(r => r.success),
|
|
116
|
+
results,
|
|
117
|
+
strategy,
|
|
118
|
+
metadata: {
|
|
119
|
+
subtasks: subtasks.length,
|
|
120
|
+
optimizationTarget: this.config.optimizationTarget
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Decompose task into subtasks
|
|
127
|
+
*/
|
|
128
|
+
decomposeTask(taskDescription: string): SubTask[] {
|
|
129
|
+
// Simple decomposition - for full NLP-based decomposition see TMLPD
|
|
130
|
+
const words = taskDescription.toLowerCase().split(/\s+/);
|
|
131
|
+
const subtasks: SubTask[] = [];
|
|
132
|
+
|
|
133
|
+
// Detect complexity indicators
|
|
134
|
+
const hasMultipleSteps = /and|then|also|plus|additionally/.test(taskDescription);
|
|
135
|
+
const hasBranching = /if|when|either|option|choice/.test(taskDescription);
|
|
136
|
+
const hasSequential = /first|then|finally|step|last/.test(taskDescription);
|
|
137
|
+
|
|
138
|
+
if (hasMultipleSteps || taskDescription.length > 100) {
|
|
139
|
+
// Multi-subtask decomposition
|
|
140
|
+
const segments = taskDescription.split(/[.,]+/).filter(s => s.trim().length > 10);
|
|
141
|
+
segments.forEach((seg, idx) => {
|
|
142
|
+
subtasks.push({
|
|
143
|
+
id: `subtask-${idx}`,
|
|
144
|
+
description: seg.trim(),
|
|
145
|
+
dependencies: idx > 0 ? [`subtask-${idx - 1}`] : [],
|
|
146
|
+
estimatedComplexity: seg.split(/\s+/).length / 10
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
} else {
|
|
150
|
+
// Single task
|
|
151
|
+
subtasks.push({
|
|
152
|
+
id: "subtask-0",
|
|
153
|
+
description: taskDescription,
|
|
154
|
+
dependencies: [],
|
|
155
|
+
estimatedComplexity: words.length / 10
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return subtasks;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Classify task type
|
|
164
|
+
*/
|
|
165
|
+
classifyTask(description: string): string {
|
|
166
|
+
const lower = description.toLowerCase();
|
|
167
|
+
if (/coding|code|function|class|debug/.test(lower)) return "coding";
|
|
168
|
+
if (/explain|what is|how to|understand/.test(lower)) return "explanation";
|
|
169
|
+
if (/analyze|review|evaluate|assess/.test(lower)) return "analysis";
|
|
170
|
+
if (/create|build|design|implement/.test(lower)) return "creation";
|
|
171
|
+
if (/translate|convert|transform/.test(lower)) return "transformation";
|
|
172
|
+
return "general";
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Quick agent assignment without MCTS
|
|
177
|
+
*/
|
|
178
|
+
quickAssign(subtasks: SubTask[]): Record<string, string> {
|
|
179
|
+
const strategy: Record<string, string> = {};
|
|
180
|
+
const agents = ["claude", "codex", "claude-minimax", "gemini"];
|
|
181
|
+
|
|
182
|
+
subtasks.forEach((subtask, idx) => {
|
|
183
|
+
// Round-robin assignment based on complexity
|
|
184
|
+
if (subtask.estimatedComplexity > 1.5) {
|
|
185
|
+
strategy[subtask.id] = agents[idx % agents.length];
|
|
186
|
+
} else {
|
|
187
|
+
strategy[subtask.id] = "claude-minimax"; // Fast agent for simple tasks
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
return strategy;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Optimize assignment with MCTS
|
|
196
|
+
*/
|
|
197
|
+
private async optimizeWithMCTS(
|
|
198
|
+
subtasks: SubTask[]
|
|
199
|
+
): Promise<Record<string, string>> {
|
|
200
|
+
const subtaskIds = subtasks.map(s => s.id);
|
|
201
|
+
|
|
202
|
+
return await this.mcts.findBestStrategy(subtaskIds, async (assignments) => {
|
|
203
|
+
// Evaluate strategy quality
|
|
204
|
+
// For reference: higher reward for balanced load + successful execution
|
|
205
|
+
const agentLoad = Object.values(assignments).reduce((acc: Record<string, number>, agentId) => {
|
|
206
|
+
acc[agentId] = (acc[agentId] || 0) + 1;
|
|
207
|
+
return acc;
|
|
208
|
+
}, {});
|
|
209
|
+
|
|
210
|
+
const loadBalance = 1 / (1 + Object.values(agentLoad).reduce((max, v) => Math.max(max, v), 0) - 1);
|
|
211
|
+
return loadBalance * 100; // Reward for balanced assignment
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Execute subtasks in parallel with concurrency limit
|
|
217
|
+
*/
|
|
218
|
+
private async executeParallel(
|
|
219
|
+
subtasks: SubTask[],
|
|
220
|
+
strategy: Record<string, string>,
|
|
221
|
+
executeFn: (subtask: SubTask, agentId: string) => Promise<ExecutionResult>
|
|
222
|
+
): Promise<ExecutionResult[]> {
|
|
223
|
+
const results: ExecutionResult[] = [];
|
|
224
|
+
const pending: Promise<void>[] = [];
|
|
225
|
+
let idx = 0;
|
|
226
|
+
|
|
227
|
+
for (const subtask of subtasks) {
|
|
228
|
+
const agentId = strategy[subtask.id] || "claude";
|
|
229
|
+
|
|
230
|
+
const promise = executeFn(subtask, agentId).then(result => {
|
|
231
|
+
results[idx] = result;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
pending.push(promise);
|
|
235
|
+
|
|
236
|
+
if (pending.length >= this.config.maxConcurrent) {
|
|
237
|
+
await Promise.race(pending);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
idx++;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
await Promise.all(pending);
|
|
244
|
+
return results;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get memory statistics
|
|
249
|
+
*/
|
|
250
|
+
getMemoryStats() {
|
|
251
|
+
return this.memory.getStats();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Reference to Full TMLPD HALO
|
|
257
|
+
*
|
|
258
|
+
* Full implementation in tmlpd-clean/src/orchestration/halo_orchestrator.py
|
|
259
|
+
*
|
|
260
|
+
* Features:
|
|
261
|
+
* - NLP-based task decomposition
|
|
262
|
+
* - Dependency graph resolution
|
|
263
|
+
* - Agent capability matching
|
|
264
|
+
* - Result verification and retry
|
|
265
|
+
* - Multi-round refinement for low confidence
|
|
266
|
+
*/
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TMLPD MCTS Workflow Search
|
|
3
|
+
*
|
|
4
|
+
* Monte Carlo Tree Search for workflow optimization.
|
|
5
|
+
* Reference implementation - for full features see TMLPD v2.x
|
|
6
|
+
*
|
|
7
|
+
* Full TMLPD includes:
|
|
8
|
+
* - UCB1 selection policy
|
|
9
|
+
* - Exploration vs exploitation balancing
|
|
10
|
+
* - Workflow state tree building
|
|
11
|
+
* - Strategy learning from execution outcomes
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { nanoid } from "nanoid";
|
|
15
|
+
|
|
16
|
+
export interface WorkflowState {
|
|
17
|
+
stateId: string;
|
|
18
|
+
subtasks: string[];
|
|
19
|
+
completed: string[];
|
|
20
|
+
assignments: Record<string, string>; // subtask -> agent
|
|
21
|
+
totalReward: number;
|
|
22
|
+
visits: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface WorkflowAction {
|
|
26
|
+
type: "assign" | "execute" | "parallelize";
|
|
27
|
+
subtaskId?: string;
|
|
28
|
+
agentId?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface MCTSConfig {
|
|
32
|
+
maxIterations: number;
|
|
33
|
+
explorationConstant: number; // UCB1 exploration parameter
|
|
34
|
+
maxDepth: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const DEFAULT_MCTS_CONFIG: MCTSConfig = {
|
|
38
|
+
maxIterations: 50,
|
|
39
|
+
explorationConstant: 1.414, // sqrt(2) for UCB1
|
|
40
|
+
maxDepth: 5
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export class WorkflowNode {
|
|
44
|
+
state: WorkflowState;
|
|
45
|
+
parent: WorkflowNode | null;
|
|
46
|
+
children: Map<string, WorkflowNode>;
|
|
47
|
+
untriedActions: WorkflowAction[];
|
|
48
|
+
|
|
49
|
+
constructor(state: WorkflowState, parent: WorkflowNode | null = null) {
|
|
50
|
+
this.state = state;
|
|
51
|
+
this.parent = parent;
|
|
52
|
+
this.children = new Map();
|
|
53
|
+
this.untriedActions = [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get averageReward(): number {
|
|
57
|
+
return this.state.visits > 0 ? this.state.totalReward / this.state.visits : 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get isTerminal(): boolean {
|
|
61
|
+
return this.state.subtasks.length === this.state.completed.length;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get isFullyExpanded(): boolean {
|
|
65
|
+
return this.untriedActions.length === 0 && this.children.size > 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* MCTS Workflow Optimizer
|
|
71
|
+
*
|
|
72
|
+
* Uses Monte Carlo Tree Search to find optimal workflow strategies.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const optimizer = new MCTSWorkflowOptimizer();
|
|
77
|
+
* const bestStrategy = optimizer.findBestStrategy(task);
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export class MCTSWorkflowOptimizer {
|
|
81
|
+
private config: MCTSConfig;
|
|
82
|
+
private root: WorkflowNode | null = null;
|
|
83
|
+
private agents: string[];
|
|
84
|
+
|
|
85
|
+
constructor(config: Partial<MCTSConfig> = {}, agents: string[] = []) {
|
|
86
|
+
this.config = { ...DEFAULT_MCTS_CONFIG, ...config };
|
|
87
|
+
this.agents = agents;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Set available agents
|
|
92
|
+
*/
|
|
93
|
+
setAgents(agents: string[]) {
|
|
94
|
+
this.agents = agents;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Find best workflow strategy using MCTS
|
|
99
|
+
*/
|
|
100
|
+
async findBestStrategy(
|
|
101
|
+
subtasks: string[],
|
|
102
|
+
evaluateFn: (strategy: Record<string, string>) => Promise<number> // Returns reward
|
|
103
|
+
): Promise<Record<string, string>> {
|
|
104
|
+
const initialState: WorkflowState = {
|
|
105
|
+
stateId: nanoid(8),
|
|
106
|
+
subtasks,
|
|
107
|
+
completed: [],
|
|
108
|
+
assignments: {},
|
|
109
|
+
totalReward: 0,
|
|
110
|
+
visits: 0
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
this.root = new WorkflowNode(initialState);
|
|
114
|
+
|
|
115
|
+
// Initialize untried actions
|
|
116
|
+
if (this.root) {
|
|
117
|
+
this.root.untriedActions = this.generateActions(subtasks);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// MCTS iterations
|
|
121
|
+
for (let i = 0; i < this.config.maxIterations; i++) {
|
|
122
|
+
await this.mctsIteration(evaluateFn);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Return best strategy
|
|
126
|
+
if (this.root && this.root.children.size > 0) {
|
|
127
|
+
const bestChild = this.selectBestChild(this.root);
|
|
128
|
+
return bestChild?.state.assignments || {};
|
|
129
|
+
} else {
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private async mctsIteration(
|
|
135
|
+
evaluateFn: (strategy: Record<string, string>) => Promise<number>
|
|
136
|
+
) {
|
|
137
|
+
if (!this.root) return;
|
|
138
|
+
|
|
139
|
+
let node = this.selectNode(this.root);
|
|
140
|
+
|
|
141
|
+
if (!node) return;
|
|
142
|
+
|
|
143
|
+
// Expansion
|
|
144
|
+
if (node.untriedActions.length > 0) {
|
|
145
|
+
const action = node.untriedActions.pop()!;
|
|
146
|
+
node = this.expand(node, action);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Simulation (simplified - evaluate async)
|
|
150
|
+
if (node) {
|
|
151
|
+
const reward = await evaluateFn(node.state.assignments);
|
|
152
|
+
this.backpropagate(node, reward);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private selectNode(node: WorkflowNode): WorkflowNode | null {
|
|
157
|
+
while (node && !node.isTerminal) {
|
|
158
|
+
if (node.isFullyExpanded) {
|
|
159
|
+
node = this.ucb1Select(node);
|
|
160
|
+
} else {
|
|
161
|
+
return node;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return node;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private ucb1Select(node: WorkflowNode): WorkflowNode {
|
|
168
|
+
let bestChild: WorkflowNode | null = null;
|
|
169
|
+
let bestUCB = -Infinity;
|
|
170
|
+
|
|
171
|
+
for (const child of node.children.values()) {
|
|
172
|
+
const ucb = this.ucb(child);
|
|
173
|
+
if (ucb > bestUCB) {
|
|
174
|
+
bestUCB = ucb;
|
|
175
|
+
bestChild = child;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return bestChild || node;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private ucb(node: WorkflowNode): number {
|
|
183
|
+
if (node.state.visits === 0) return Infinity;
|
|
184
|
+
const parentVisits = node.parent?.state.visits || 1;
|
|
185
|
+
return node.averageReward +
|
|
186
|
+
this.config.explorationConstant * Math.sqrt(Math.log(parentVisits) / node.state.visits);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private expand(node: WorkflowNode, action: WorkflowAction): WorkflowNode {
|
|
190
|
+
const newAssignments = { ...node.state.assignments };
|
|
191
|
+
|
|
192
|
+
if (action.type === "assign" && action.subtaskId && action.agentId) {
|
|
193
|
+
newAssignments[action.subtaskId] = action.agentId;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const newState: WorkflowState = {
|
|
197
|
+
stateId: nanoid(8),
|
|
198
|
+
subtasks: node.state.subtasks,
|
|
199
|
+
completed: [...node.state.completed],
|
|
200
|
+
assignments: newAssignments,
|
|
201
|
+
totalReward: 0,
|
|
202
|
+
visits: 0
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const child = new WorkflowNode(newState, node);
|
|
206
|
+
node.children.set(newState.stateId, child);
|
|
207
|
+
child.untriedActions = this.generateActions(newState.subtasks);
|
|
208
|
+
|
|
209
|
+
return child;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private generateActions(subtasks: string[]): WorkflowAction[] {
|
|
213
|
+
const actions: WorkflowAction[] = [];
|
|
214
|
+
const availableAgents = this.agents.length > 0 ? this.agents : ["claude", "codex", "gemini"];
|
|
215
|
+
|
|
216
|
+
subtasks.forEach(subtask => {
|
|
217
|
+
availableAgents.forEach(agent => {
|
|
218
|
+
actions.push({
|
|
219
|
+
type: "assign",
|
|
220
|
+
subtaskId: subtask,
|
|
221
|
+
agentId: agent
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
return actions;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private selectBestChild(node: WorkflowNode): WorkflowNode | null {
|
|
230
|
+
let best: WorkflowNode | null = null;
|
|
231
|
+
let bestReward = -Infinity;
|
|
232
|
+
|
|
233
|
+
for (const child of node.children.values()) {
|
|
234
|
+
if (child.averageReward > bestReward) {
|
|
235
|
+
bestReward = child.averageReward;
|
|
236
|
+
best = child;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return best;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private backpropagate(node: WorkflowNode, reward: number) {
|
|
244
|
+
while (node) {
|
|
245
|
+
node.state.visits++;
|
|
246
|
+
node.state.totalReward += reward;
|
|
247
|
+
node = node.parent as WorkflowNode;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Reference to Full TMLPD MCTS
|
|
254
|
+
*
|
|
255
|
+
* Full implementation in tmlpd-clean/src/orchestration/mcts_workflow.py
|
|
256
|
+
*
|
|
257
|
+
* Features:
|
|
258
|
+
* - Full UCB1 with proper exploration constant
|
|
259
|
+
* - Deterministic rollout simulation
|
|
260
|
+
* - Strategy caching with performance tracking
|
|
261
|
+
* - Adaptive depth based on task complexity
|
|
262
|
+
*/
|