Files
boc/kimi-integration-backup/swarm-orchestrator.mjs
T

223 lines
7.4 KiB
JavaScript
Raw Normal View History

/**
* AAMOS Swarm Orchestrator V2
* Parallell exekvering med dynamisk lastbalansering
*/
import {
MODELS,
kimiCreate,
kimiStream,
qwenCreate,
qwenStream,
claudeChat,
groqChat
} from './model-router.mjs';
// ── Provider-hälsa ────────────────────────────────────────────────────────
const _providerHealth = new Map();
function checkHealth(provider) {
const lastCheck = _providerHealth.get(provider);
if (!lastCheck) return true;
return Date.now() - lastCheck.lastFailure > 30000; // 30s cooldown
}
function markFailure(provider) {
_providerHealth.set(provider, { lastFailure: Date.now(), failures: (_providerHealth.get(provider)?.failures || 0) + 1 });
}
function markSuccess(provider) {
_providerHealth.set(provider, { lastFailure: 0, failures: 0, lastSuccess: Date.now() });
}
// ── Viktad routing ────────────────────────────────────────────────────────
function selectProvider(task, message) {
const providers = [
{ name: 'kimi', models: [MODELS.KIMI_K2_6, MODELS.KIMI_K2_7_CODE, MODELS.KIMI_K2_7_HIGHSPEED], weight: 0.5 },
{ name: 'bedrock', models: [MODELS.QWEN_235B, MODELS.QWEN_32B, MODELS.QWEN_CODER], weight: 0.3 },
{ name: 'groq', models: ['llama-3.3-70b-versatile', 'openai/gpt-oss-120b'], weight: 0.2 },
];
const available = providers.filter(p => checkHealth(p.name));
const totalWeight = available.reduce((a, p) => a + p.weight, 0);
let random = Math.random() * totalWeight;
for (const provider of available) {
random -= provider.weight;
if (random <= 0) return provider;
}
return available[0] || providers[0]; // fallback
}
// ── Swarm exekvering ──────────────────────────────────────────────────────
export async function swarmExecute(tasks, options = {}) {
const {
maxConcurrency = 4,
sharedContext = {},
timeout = 60000,
onProgress = () => {}
} = options;
const startTime = Date.now();
const results = [];
const executing = new Set();
async function executeTask(task, index) {
const taskStart = Date.now();
const provider = selectProvider(task.type, task.message);
onProgress({ type: 'start', task: index, provider: provider.name, model: task.model });
try {
let result;
// Välj rätt execute-funktion baserat på provider
switch(provider.name) {
case 'kimi':
result = await kimiCreate(task.model, sharedContext.system, [
...sharedContext.history || [],
{ role: 'user', content: task.message }
], task.maxTokens || 4096);
break;
case 'bedrock':
result = await qwenCreate(task.model, sharedContext.system, [
...sharedContext.history || [],
{ role: 'user', content: task.message }
], task.maxTokens || 4096);
break;
case 'groq':
result = await groqChat(task.model, sharedContext.system, [
...sharedContext.history || [],
{ role: 'user', content: task.message }
]);
break;
default:
throw new Error(`Okänd provider: ${provider.name}`);
}
markSuccess(provider.name);
const duration = Date.now() - taskStart;
onProgress({ type: 'complete', task: index, duration, provider: provider.name });
return {
status: 'fulfilled',
value: {
task: task.type,
model: task.model,
provider: provider.name,
duration,
result: typeof result === 'string' ? result : result.text,
timestamp: new Date().toISOString(),
}
};
} catch (error) {
markFailure(provider.name);
const duration = Date.now() - taskStart;
onProgress({ type: 'error', task: index, duration, error: error.message });
return {
status: 'rejected',
reason: {
task: task.type,
model: task.model,
provider: provider.name,
duration,
error: error.message,
timestamp: new Date().toISOString(),
}
};
}
}
// Kör med begränsad concurrency
for (let i = 0; i < tasks.length; i++) {
while (executing.size >= maxConcurrency) {
await Promise.race(executing);
}
const promise = executeTask(tasks[i], i).then(result => {
executing.delete(promise);
results[i] = result;
return result;
});
executing.add(promise);
}
// Vänta på alla
await Promise.all(executing);
const totalTime = Date.now() - startTime;
// Sammanställ
const successful = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const failed = results.filter(r => r.status === 'rejected').map(r => r.reason);
return {
successful,
failed,
totalTime,
summary: {
total: tasks.length,
success: successful.length,
failed: failed.length,
avgDuration: successful.reduce((a, r) => a + r.duration, 0) / successful.length || 0,
providers: [...new Set(successful.map(r => r.provider))],
}
};
}
// ── Agent-koordinering ────────────────────────────────────────────────────
export async function coordinateAgents(agents, sharedGoal, options = {}) {
console.log(`🎯 Koordinerar ${agents.length} agenter för: ${sharedGoal}`);
// Fas 1: Planering (Bernt-nivå)
const plan = await swarmExecute([{
type: 'planning',
model: MODELS.KIMI_K2_6,
message: `Planera uppgifter för: ${sharedGoal}. Tillgängliga agenter: ${agents.map(a => a.name).join(', ')}`,
maxTokens: 2048,
}], { sharedContext: { system: 'Du är en expert på att bryta ner komplexa uppgifter i deluppgifter.' } });
// Fas 2: Exekvering (parallell)
const tasks = agents.map(agent => ({
type: agent.specialization[0],
model: agent.model,
message: `${agent.role}: ${sharedGoal}`,
maxTokens: 4096,
}));
const results = await swarmExecute(tasks, {
maxConcurrency: options.maxConcurrency || agents.length,
sharedContext: {
system: `Delad kontext för: ${sharedGoal}`,
history: [{ role: 'assistant', content: plan.successful[0]?.result || '' }]
},
onProgress: (event) => {
if (event.type === 'start') console.log(` 🚀 ${event.provider} startar task ${event.task}`);
if (event.type === 'complete') console.log(` ✅ Task ${event.task} klar (${event.duration}ms)`);
if (event.type === 'error') console.log(` ❌ Task ${event.task} misslyckades: ${event.error}`);
}
});
// Fas 3: Sammanställning
const synthesis = await swarmExecute([{
type: 'synthesis',
model: MODELS.KIMI_K2_6,
message: `Sammanställ resultaten för: ${sharedGoal}\n\n${results.successful.map(r => `## ${r.task}\n${r.result}`).join('\n\n')}`,
maxTokens: 4096,
}], { sharedContext: { system: 'Du är en expert på att syntetisera resultat från flera källor.' } });
return {
plan: plan.successful[0]?.result,
results,
synthesis: synthesis.successful[0]?.result,
};
}
export default { swarmExecute, coordinateAgents };