QA-korjaussilmukka: validointi delegoi ongelmat Coder-agentille

Aiemmin mekaaninen validateProjectCode() vain listasi ongelmat terminaaliin.
Nyt pipeline toimii näin:
1. QA-agentti ajaa mekaanisen validoinnin
2. Jos ongelmia → ryhmittelee ne tiedostoittain
3. Delegoi jokaisen tiedoston korjauksen oikealle agentille (Coder/Data/QA)
4. Agentti (LLM) palauttaa korjatun tiedoston
5. Validointi ajetaan uudelleen — max 2 korjauskierrosta
6. Lopullinen tulos näytetään vihreänä/punaisena
7. Tarkkailija arvioi lopullisen version

Kaikki korjausvaiheet tallentuvat promptLog:iin → näkyvät oppimispolussa.
This commit is contained in:
2026-04-13 14:09:10 +03:00
parent 59daebbd38
commit 670141c8c3

View File

@@ -1418,20 +1418,71 @@ Blog → Author: name,email,bio(Text|None) / Post: title, content(Text), author_
let stepN = fileOrder.length + 2;
// === Vaihe 4: Mekaaninen QA-validointi ===
// === Vaihe 4: Mekaaninen QA-validointi + korjaussilmukka ===
const qaAgent = agents.qa || Object.values(agents)[4];
termLog(`\n<span style="color:#d2a8ff;font-weight:bold">[${stepN}] ${esc(qaAgent.name)}</span> — validointi`);
highlightAgent('qa');
explainStep('Validointi', `${qaAgent.name} ajaa mekaanisen koodivalidoinnin.`);
const MAX_FIX_ROUNDS = 2;
let mechIssues = validateProjectCode(files);
let fixRound = 0;
const mechIssues = validateProjectCode(files);
if (mechIssues.length > 0) {
termLog(` <span style="color:#d29922">⚠ ${mechIssues.length} ongelmaa (template-bugeja — korjattava):</span>`);
while (mechIssues.length > 0 && fixRound < MAX_FIX_ROUNDS) {
fixRound++;
termLog(`\n<span style="color:#d2a8ff;font-weight:bold">[${stepN}] ${esc(qaAgent.name)}</span> — validointi (kierros ${fixRound})`);
highlightAgent('qa');
explainStep('Validointi', `${qaAgent.name} löysi ${mechIssues.length} ongelmaa — delegoidaan korjattavaksi.`);
termLog(` <span style="color:#d29922">⚠ ${mechIssues.length} ongelmaa:</span>`);
for (const issue of mechIssues) termLog(` <span style="color:#d29922">${esc(issue)}</span>`);
} else {
termLog(` <span style="color:#3fb950">✓ Kaikki tiedostot validoitu — 0 ongelmaa</span>`);
promptLog.push({ step: promptLog.length, agentKey: 'qa', agentName: qaAgent.name, model: 'mekaaninen', label: `validointi #${fixRound}`, systemPrompt: '(mekaaninen validointi)', userPrompt: 'validateProjectCode(files)', response: mechIssues.join('\n') });
stepN++;
// Ryhmitellään ongelmat tiedostoittain
const issuesByFile = {};
for (const issue of mechIssues) {
const m = issue.match(/^ISSUE:\s*(\S+?):/);
const fname = m ? m[1] : 'unknown';
if (!issuesByFile[fname]) issuesByFile[fname] = [];
issuesByFile[fname].push(issue);
}
promptLog.push({ step: promptLog.length, agentKey: 'qa', agentName: qaAgent.name, model: 'mekaaninen', label: 'validointi', systemPrompt: '(mekaaninen validointi — ei LLM:ää)', userPrompt: 'validateProjectCode(files)', response: mechIssues.length === 0 ? 'OK — 0 issues' : mechIssues.join('\n') });
// Delegoidaan korjaukset Coder-agentille tiedosto kerrallaan
for (const [fname, fIssues] of Object.entries(issuesByFile)) {
if (!files[fname]) continue;
const fixAgent = agents[agentMap[fname]] || cdr;
termLog(`\n<span style="color:#f0883e;font-weight:bold">[${stepN}] ${esc(fixAgent.name)}</span> — korjaa ${esc(fname)} (${fIssues.length} ongelmaa)`);
highlightAgent(agentMap[fname] || 'coder');
explainStep(`Korjaus: ${fname}`, `${fixAgent.name} korjaa validoinnin löytämät ongelmat.`);
const fixPrompt = `Fix the following issues in this Python file. Return ONLY the complete corrected file, no explanations.\n\nISSUES:\n${fIssues.join('\n')}\n\nCURRENT FILE (${fname}):\n\`\`\`python\n${files[fname]}\`\`\``;
const fixResult = await kpnRun(fixAgent.model, fixPrompt, false, { ...fixAgent, prompt: 'You are a Python code fixer. Return ONLY the corrected Python file. No markdown fences, no explanations — just valid Python code.' });
if (fixResult) {
// Poistetaan markdown-koodiblokit jos LLM palauttaa ne
let cleaned = fixResult.replace(/^```(?:python)?\s*\n?/m, '').replace(/\n?```\s*$/m, '').trim() + '\n';
files[fname] = cleaned;
termLog(` <span style="color:#3fb950">✓ ${esc(fname)} korjattu</span>`);
} else {
termLog(` <span style="color:#f85149">✗ ${esc(fname)} korjaus epäonnistui — pidetään alkuperäinen</span>`);
}
promptLog.push({ step: promptLog.length, agentKey: agentMap[fname] || 'coder', agentName: fixAgent.name, model: fixAgent.model, label: `korjaus: ${fname}`, systemPrompt: '(code fixer)', userPrompt: fixPrompt, response: fixResult || '(epäonnistui)' });
stepN++;
}
// Validoidaan uudelleen
mechIssues = validateProjectCode(files);
}
// Lopullinen validointitulos
termLog(`\n<span style="color:#d2a8ff;font-weight:bold">[${stepN}] ${esc(qaAgent.name)}</span> — lopullinen validointi`);
highlightAgent('qa');
if (mechIssues.length > 0) {
explainStep('Validointi', `${mechIssues.length} ongelmaa jäi korjaamatta ${MAX_FIX_ROUNDS} kierroksen jälkeen.`);
termLog(` <span style="color:#f85149">✗ ${mechIssues.length} ongelmaa jäljellä ${fixRound} korjauskierroksen jälkeen:</span>`);
for (const issue of mechIssues) termLog(` <span style="color:#f85149">${esc(issue)}</span>`);
} else {
const msg = fixRound > 0 ? `✓ Kaikki ongelmat korjattu (${fixRound} kierrosta)` : '✓ Kaikki tiedostot validoitu — 0 ongelmaa';
explainStep('Validointi', msg);
termLog(` <span style="color:#3fb950">${msg}</span>`);
}
promptLog.push({ step: promptLog.length, agentKey: 'qa', agentName: qaAgent.name, model: 'mekaaninen', label: 'lopullinen validointi', systemPrompt: '(mekaaninen validointi)', userPrompt: 'validateProjectCode(files)', response: mechIssues.length === 0 ? `OK — korjattu ${fixRound} kierroksessa` : mechIssues.join('\n') });
stepN++;
// Tarkkailija: yhteenveto + raportti + arvosana