Kaikki 6 agenttia osallistuvat pipeline-projektiin

Pipeline-vaiheet:
1. Data-agentti: models.py (tietokanta-asiantuntija)
2. Koodari: schemas.py, main.py (ohjelmistokehittäjä)
3. Koodari: pyproject.toml
4. DevOps: koodikatselmointi (importit, nimeämiset, virheet)
5. Koodari: korjaukset (jos DevOps löysi ongelmia)
6. QA: pytest-testit (test_main.py lisätään projektiin)
7. Tarkkailija: riskianalyysi (arkkitehtuuri, tietoturva)

Data-agentti valitaan automaattisesti models.py/database.py -tiedostoille.
Jokainen vaihe highlightaa oikean avatarin.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaakko Vanhala
2026-04-10 07:26:57 +03:00
parent 43f0aebf54
commit 5498eb6cbb

View File

@@ -735,8 +735,14 @@ OUTPUT FORMAT:
if (!fileDef) continue; if (!fileDef) continue;
const step = i + 1; const step = i + 1;
termLog(`\n<span style="color:#3fb950;font-weight:bold">[${step}/${template.order.length}] ${esc(cdr.name)}</span> — ${esc(fileName)}`); // Valitaan oikea agentti tiedostotyypin mukaan
highlightAgent('coder'); const isDbFile = fileName === 'models.py' || fileName === 'database.py';
const dataAgent = agents.data || Object.values(agents)[2];
const fileAgent = isDbFile && dataAgent ? dataAgent : cdr;
const fileAgentKey = isDbFile && dataAgent ? 'data' : 'coder';
termLog(`\n<span style="color:#3fb950;font-weight:bold">[${step}/${template.order.length}] ${esc(fileAgent.name)}</span> — ${esc(fileName)}`);
highlightAgent(fileAgentKey);
// Opettava selitys: miksi tämä tiedosto, mitä se sisältää // Opettava selitys: miksi tämä tiedosto, mitä se sisältää
explainStep(fileName, fileDef.instructions); explainStep(fileName, fileDef.instructions);
@@ -744,8 +750,8 @@ OUTPUT FORMAT:
// Rakennetaan prompti: esimerkki + konteksti + ohje // Rakennetaan prompti: esimerkki + konteksti + ohje
let prompt = ''; let prompt = '';
// Agentin system prompt // Agentin system prompt (data-agentti models.py:lle, koodari muille)
if (cdr.prompt) prompt += cdr.prompt + '\n\n'; if (fileAgent.prompt) prompt += fileAgent.prompt + '\n\n';
// Esimerkki (few-shot) // Esimerkki (few-shot)
prompt += `EXAMPLE of ${fileName} (for a different project, adapt to this one):\n`; prompt += `EXAMPLE of ${fileName} (for a different project, adapt to this one):\n`;
@@ -765,7 +771,7 @@ OUTPUT FORMAT:
prompt += fileDef.instructions + '\n'; prompt += fileDef.instructions + '\n';
prompt += 'Adapt the example to match the project description. Import from already written files. Write ONLY the code, no explanations.'; prompt += 'Adapt the example to match the project description. Import from already written files. Write ONLY the code, no explanations.';
const code = await kpnRun(cdr.model, prompt); const code = await kpnRun(fileAgent.model, prompt);
if (!code) { if (!code) {
termLog(` ✗ Keskeytyi (${fileName})`, '#f85149'); termLog(` ✗ Keskeytyi (${fileName})`, '#f85149');
return; return;
@@ -773,24 +779,52 @@ OUTPUT FORMAT:
files[fileName] = code; files[fileName] = code;
} }
// Review
const allCode = Object.entries(files).map(([n,c]) => `--- ${n} ---\n${c}`).join('\n\n'); const allCode = Object.entries(files).map(([n,c]) => `--- ${n} ---\n${c}`).join('\n\n');
termLog(`\n<span style="color:var(--accent);font-weight:bold">[${template.order.length + 1}] ${esc(tst.name)}</span> — review`); let stepN = template.order.length + 1;
// DevOps/Testaaja: koodikatselmointi
const tst = agents.tester || Object.values(agents)[4];
termLog(`\n<span style="color:var(--accent);font-weight:bold">[${stepN}] ${esc(tst.name)}</span> — koodikatselmointi`);
highlightAgent('tester'); highlightAgent('tester');
explainStep('Koodikatselmointi', 'Testaaja tarkistaa importit, nimeämiset, puuttuvat virheenkäsittelyt ja tiedostojen yhteensopivuuden.'); explainStep('Koodikatselmointi', `${tst.name} tarkistaa importit, nimeämiset, virheenkäsittelyn ja tiedostojen yhteensopivuuden.`);
const tstPrompt = (tst.prompt ? tst.prompt+'\n\n' : '') + `Review this project:\n\n${allCode}`;
const tstPrompt = (tst.prompt ? tst.prompt+'\n\n' : '') +
`Review this project. Check:\n1. All imports are correct (files import from each other)\n2. Pydantic schema names don't conflict with SQLAlchemy models\n3. All CRUD endpoints exist\n4. Error handling is present\nIf everything is correct, say "LGTM". Otherwise list specific issues.\n\n${allCode}`;
const review = await kpnRun(tst.model, tstPrompt); const review = await kpnRun(tst.model, tstPrompt);
stepN++;
// Korjausluuppi (jos tarpeen)
if (review && !review.toLowerCase().includes('lgtm')) { if (review && !review.toLowerCase().includes('lgtm')) {
termLog(`\n<span style="color:#d29922;font-weight:bold">[${template.order.length + 2}] ${esc(cdr.name)}</span> — korjaukset`); termLog(`\n<span style="color:#d29922;font-weight:bold">[${stepN}] ${esc(cdr.name)}</span> — korjaukset`);
highlightAgent('coder'); highlightAgent('coder');
explainStep('Korjausluuppi', 'Testaaja löysi ongelmia. Koodari saa palautteen ja korjaa koodin.'); explainStep('Korjausluuppi', `${tst.name} löysi ongelmia. ${cdr.name} saa palautteen ja korjaa koodin.`);
await kpnRun(cdr.model, `${cdr.prompt ? cdr.prompt+'\n\n' : ''}Fix these issues:\n${review}\n\nCurrent code:\n${allCode}\n\nWrite the corrected files.`); await kpnRun(cdr.model, `${cdr.prompt ? cdr.prompt+'\n\n' : ''}Fix these issues:\n${review}\n\nCurrent code:\n${allCode}\n\nWrite the corrected files.`);
stepN++;
} }
// Pipeline valmis — poistetaan highlight // QA: testit
const qaAgent = agents.qa || Object.values(agents)[3];
if (qaAgent) {
termLog(`\n<span style="color:#d2a8ff;font-weight:bold">[${stepN}] ${esc(qaAgent.name)}</span> — testit`);
highlightAgent('qa');
explainStep('Testit', `${qaAgent.name} kirjoittaa pytest-testit kaikille endpointeille.`);
const qaPrompt = (qaAgent.prompt ? qaAgent.prompt+'\n\n' : '') + `Write pytest tests for this project:\n\n${allCode}\n\nWrite a complete test_main.py file with TestClient.`;
const tests = await kpnRun(qaAgent.model, qaPrompt);
if (tests) files['test_main.py'] = tests;
stepN++;
}
// Tarkkailija: riskianalyysi
const obs = agents.observer || Object.values(agents)[5];
if (obs) {
termLog(`\n<span style="color:#8b949e;font-weight:bold">[${stepN}] ${esc(obs.name)}</span> — riskianalyysi`);
highlightAgent('observer');
explainStep('Riskianalyysi', `${obs.name} arvioi arkkitehtuurin, tietoturvan ja ylläpidettävyyden.`);
const finalCode = Object.entries(files).map(([n,c]) => `--- ${n} ---\n${c}`).join('\n\n');
const obsPrompt = (obs.prompt ? obs.prompt+'\n\n' : '') + `Evaluate this project:\n\n${finalCode}`;
await kpnRun(obs.model, obsPrompt);
stepN++;
}
// Pipeline valmis
highlightAgent(null); highlightAgent(null);
termLog(`\n<span style="color:var(--purple);font-weight:bold">━━━ Valmis (${Object.keys(files).length} tiedostoa) ━━━</span>`); termLog(`\n<span style="color:var(--purple);font-weight:bold">━━━ Valmis (${Object.keys(files).length} tiedostoa) ━━━</span>`);