diff --git a/network-poc/frontend/src/components/StatusBar.astro b/network-poc/frontend/src/components/StatusBar.astro index 6755938..cda5791 100644 --- a/network-poc/frontend/src/components/StatusBar.astro +++ b/network-poc/frontend/src/components/StatusBar.astro @@ -41,7 +41,7 @@
2. Käynnistä Kipinä-node
curl -sSL "https://kipina.studio/kipina-node?v=$(date +%s)" -o kipina-node && chmod +x kipina-node && ./kipina-node - +
Lataa kielimallin (~2GB) automaattisesti ensimmäisellä kerralla. Ctrl+C pysäyttää.
diff --git a/network-poc/frontend/src/pages/index.astro b/network-poc/frontend/src/pages/index.astro index 49476ea..52226ad 100644 --- a/network-poc/frontend/src/pages/index.astro +++ b/network-poc/frontend/src/pages/index.astro @@ -71,7 +71,25 @@ import Settings from "../components/Settings.astro"; // === Globaalit tilat === const defaultAgents = { - manager: { name: 'Manageri', avatar: '/avatars/karhunpentu.webp', model: 'qwen-coder', order: 0, + client: { name: 'Asiakas', avatar: '/avatars/kettu_notext.webp', model: 'qwen-coder', order: 0, + temperature: 0.6, topK: 40, repeatPenalty: 1.15, maxTokens: 512, + prompt: `You are a product owner who turns vague ideas into clear, actionable software requirements. + +GIVEN a short project description from the user, produce a structured brief: + +1. PROJECT NAME: a short, descriptive name +2. GOAL: one sentence explaining what the software does and who it's for +3. CORE FEATURES: numbered list of 3-5 concrete features (not vague wishes) +4. DATA MODEL: list the main entities and their key fields +5. API ENDPOINTS: list the essential REST endpoints (method + path + purpose) +6. CONSTRAINTS: any technical constraints (e.g. "must use SQLite", "no auth needed for MVP") + +RULES: +- Be specific: "User can filter todos by status" not "todo management" +- Keep scope small — MVP only, no nice-to-haves +- Use plain English, no code +- Maximum 200 words total` }, + manager: { name: 'Manageri', avatar: '/avatars/karhunpentu.webp', model: 'qwen-coder', order: 1, temperature: 0.5, topK: 40, repeatPenalty: 1.15, maxTokens: 512, prompt: `You are a senior project manager and software architect. Your job is to plan the file structure of a software project. @@ -88,7 +106,7 @@ models.py: SQLAlchemy database models and engine setup schemas.py: Pydantic request/response schemas main.py: FastAPI application with CRUD endpoints pyproject.toml: project dependencies` }, - coder: { name: 'Koodari', avatar: '/avatars/kipina_notext.webp', model: 'qwen-coder', order: 1, + coder: { name: 'Koodari', avatar: '/avatars/kipina_notext.webp', model: 'qwen-coder', order: 2, temperature: 0.7, topK: 40, repeatPenalty: 1.15, maxTokens: 1024, prompt: `You are an expert Python developer. Write complete, production-ready code. @@ -109,7 +127,7 @@ NEVER: - Forget to import from other project files - Use requirements.txt or Poetry — always use pyproject.toml with [project] format (PEP 621) - Use pip install — use uv (e.g. uv run uvicorn main:app --reload)` }, - data: { name: 'Data', avatar: '/avatars/pesukarhu_notext.webp', model: 'qwen-coder', order: 2, + data: { name: 'Data', avatar: '/avatars/pesukarhu_notext.webp', model: 'qwen-coder', order: 3, temperature: 0.5, topK: 40, repeatPenalty: 1.15, maxTokens: 1024, prompt: `You are a database architect specializing in SQLAlchemy and relational databases. @@ -126,7 +144,7 @@ ALWAYS INCLUDE: - from sqlalchemy.ext.declarative import declarative_base - from sqlalchemy.orm import sessionmaker - DATABASE_URL, engine, SessionLocal, Base` }, - qa: { name: 'QA', avatar: '/avatars/susi_notext.webp', model: 'qwen-coder', order: 3, + qa: { name: 'QA', avatar: '/avatars/susi_notext.webp', model: 'qwen-coder', order: 4, temperature: 0.4, topK: 40, repeatPenalty: 1.15, maxTokens: 1024, prompt: `You are a QA engineer writing automated tests. @@ -143,7 +161,7 @@ TEST STRUCTURE: 5. test_delete: DELETE → 204, verify GET returns 404 after ALWAYS: from fastapi.testclient import TestClient` }, - tester: { name: 'DevOps', avatar: '/avatars/laiskiainen_notext.webp', model: 'qwen-coder', order: 4, + tester: { name: 'DevOps', avatar: '/avatars/laiskiainen_notext.webp', model: 'qwen-coder', order: 5, temperature: 0.3, topK: 40, repeatPenalty: 1.1, maxTokens: 512, prompt: `You are a strict code reviewer and static analysis expert. Analyze the code line by line. @@ -162,7 +180,7 @@ RESPOND: - If all checks pass: "LGTM" - If issues found: list each as "ISSUE: filename.py: description" - Be specific and actionable, not vague` }, - observer: { name: 'Tarkkailija', avatar: '/avatars/aikuinen_susi.webp', model: 'qwen-coder', order: 5, + observer: { name: 'Tarkkailija', avatar: '/avatars/aikuinen_susi.webp', model: 'qwen-coder', order: 6, temperature: 0.6, topK: 40, repeatPenalty: 1.15, maxTokens: 512, prompt: `You are an independent technical observer and risk analyst. @@ -178,7 +196,7 @@ OUTPUT FORMAT: - End with overall assessment: "SHIP IT" or "NEEDS WORK: reason"` }, }; // Versio: kasvata kun oletuspromptit muuttuvat - const AGENTS_VERSION = 2; + const AGENTS_VERSION = 3; let agents; const savedVersion = parseInt(localStorage.getItem('kpn-agents-version') || '0'); if (savedVersion < AGENTS_VERSION && localStorage.getItem('kpn-agents')) { @@ -750,7 +768,8 @@ OUTPUT FORMAT: } async function kpnProject(task) { - const cdr = agents.coder || Object.values(agents)[1]; + const cli = agents.client || Object.values(agents)[0]; + const cdr = agents.coder || Object.values(agents)[2]; // Etsitään sopivin mallipohja const template = Object.values(templates)[0]; // Toistaiseksi vain FastAPI CRUD @@ -760,6 +779,15 @@ OUTPUT FORMAT: } termLog(`━━━ ${esc(template.name)} — ${esc(task)} ━━━`); + + // Asiakas: jalostaa vaatimukset + termLog(`\n[0] ${esc(cli.name)} — vaatimusmäärittely`); + highlightAgent('client'); + explainStep('Vaatimusmäärittely', `${cli.name} muotoilee idean selkeiksi vaatimuksiksi: ominaisuudet, datamallit, rajapinnat.`); + const brief = await kpnRun(cli.model, `${task}`, false, cli); + if (!brief) { termLog(' ✗ Vaatimusmäärittely epäonnistui', '#f85149'); return; } + termLog(` Vaatimukset valmiit → Manageri`); + explainStep('Mallipohja', `Käytetään "${template.name}" -mallipohjaa jossa ${template.order.length} tiedostoa: ${template.order.join(', ')}. Jokainen tiedosto generoidaan järjestyksessä, ja aiemmat tiedostot annetaan kontekstina seuraavalle.`); const files = {}; @@ -772,7 +800,7 @@ OUTPUT FORMAT: const step = i + 1; // Valitaan oikea agentti tiedostotyypin mukaan const isDbFile = fileName === 'models.py' || fileName === 'database.py'; - const dataAgent = agents.data || Object.values(agents)[2]; + const dataAgent = agents.data || Object.values(agents)[3]; const fileAgent = isDbFile && dataAgent ? dataAgent : cdr; const fileAgentKey = isDbFile && dataAgent ? 'data' : 'coder'; @@ -801,6 +829,9 @@ OUTPUT FORMAT: } } + // Asiakkaan vaatimusmäärittely + prompt += `PROJECT REQUIREMENTS (from product owner):\n${brief}\n\n`; + // Tehtävä prompt += `NOW write "${fileName}" for THIS project: ${task}\n`; prompt += fileDef.instructions + '\n'; @@ -818,7 +849,7 @@ OUTPUT FORMAT: let stepN = template.order.length + 1; // Review-korjausluuppi: max 2 kierrosta - const tst = agents.tester || Object.values(agents)[4]; + const tst = agents.tester || Object.values(agents)[5]; const MAX_REVIEW_ROUNDS = 3; for (let round = 0; round < MAX_REVIEW_ROUNDS; round++) { @@ -866,7 +897,7 @@ OUTPUT FORMAT: const updatedCode = Object.entries(files).map(([n,c]) => `--- ${n} ---\n${c}`).join('\n\n'); // QA: testit (saa korjatut tiedostot) - const qaAgent = agents.qa || Object.values(agents)[3]; + const qaAgent = agents.qa || Object.values(agents)[4]; if (qaAgent) { termLog(`\n[${stepN}] ${esc(qaAgent.name)} — testit`); highlightAgent('qa'); @@ -897,7 +928,7 @@ OUTPUT FORMAT: stepN++; // Tarkkailija: yhteenveto + raportti + arvosana - const obs = agents.observer || Object.values(agents)[5]; + const obs = agents.observer || Object.values(agents)[6]; if (obs) { termLog(`\n[${stepN}] ${esc(obs.name)} — projektin yhteenveto`); highlightAgent('observer'); @@ -958,15 +989,24 @@ OUTPUT FORMAT: } async function kpnPipelineSimple(task) { + const cli = agents.client || Object.values(agents)[0]; termLog(`━━━ Pipeline ━━━`); - termLog(`\n[1/3] Manageri`); - const plan = await kpnRun('qwen-coder', `Analyse briefly, write a spec:\n${task}`); + termLog(`\n[1/4] ${esc(cli.name)} — vaatimukset`); + highlightAgent('client'); + const brief = await kpnRun(cli.model, `${task}`, false, cli); + if (!brief) return; + termLog(`\n[2/4] Manageri`); + highlightAgent('manager'); + const plan = await kpnRun('qwen-coder', `Requirements:\n${brief}\n\nAnalyse briefly, write a spec:\n${task}`); if (!plan) return; - termLog(`\n[2/3] Koodari`); + termLog(`\n[3/4] Koodari`); + highlightAgent('coder'); const code = await kpnRun('qwen-coder', `${plan}\n\nWrite the code.`); if (!code) return; - termLog(`\n[3/3] Testaaja`); + termLog(`\n[4/4] Testaaja`); + highlightAgent('tester'); await kpnRun('qwen-coder', `Review briefly:\n${code}`); + highlightAgent(null); termLog(`\n━━━ Valmis ━━━`); } diff --git a/network-poc/hub-local.log b/network-poc/hub-local.log index dba8b1c..7d62265 100644 --- a/network-poc/hub-local.log +++ b/network-poc/hub-local.log @@ -1,7 +1,34 @@ - Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.14s + Compiling hub v0.3.1 (/Users/jaakko/code/kipina-codes/playground/agentic-studio/network-poc/hub) + Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.95s Running `target/debug/hub` -2026-04-12T03:21:35.058711Z  INFO hub: Tietokanta alustettu -2026-04-12T03:21:35.061635Z  INFO hub: Kipinä Agent Hub v0.3.1 käynnistyy osoitteessa http://localhost:3000 -2026-04-12T03:21:49.577628Z  INFO hub: Solmu 1 yhdistyi osoitteesta 127.0.0.1 -2026-04-12T03:21:49.600021Z  INFO hub: Solmu 1 (natiivi) | 127.0.0.1 | Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM | varaus: 4 GB -2026-04-12T03:21:49.600099Z  INFO hub: GPU 0: Apple M2 Max | VRAM: 0/24576 MB | 0°C | 0% +2026-04-12T04:56:09.723604Z  INFO hub: Tietokanta alustettu +2026-04-12T04:56:09.725088Z  INFO hub: Kipinä Agent Hub v0.3.1 käynnistyy osoitteessa http://localhost:3000 +2026-04-12T04:56:18.997935Z  INFO hub: Solmu 1 yhdistyi osoitteesta 127.0.0.1 +2026-04-12T04:56:19.027478Z  INFO hub: Solmu 1 (natiivi) | 127.0.0.1 | Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM | varaus: 4 GB +2026-04-12T04:56:19.029931Z  INFO hub: GPU 0: Apple M2 Max | VRAM: 0/24576 MB | 0°C | 0% +2026-04-12T04:56:31.260470Z  INFO hub: Solmu 2 yhdistyi osoitteesta 127.0.0.1 +2026-04-12T04:56:31.281759Z  INFO hub: Solmu 2 (selain) | 127.0.0.1 | MacIntel | 11 ydintä | ~8 GB RAM | GPU: ei GPU:ta | tehtävä: viewer | varaus: 0 GB +2026-04-12T04:56:31.283313Z  INFO hub: Reititettiin API-pyyntö solmulle 1 (Malli: qwen-coder) + +━━━ Solmu 1 ━━━ qwen2.5-coder:7b-instruct-q4_K_M (Ollama) ━━━ + Prompt: "ping" + Vastaus: Pong! How can I assist you today? + 11 tokenia | 4502ms | 56.3 tok/s +2026-04-12T04:56:36.419646Z  INFO hub: Solmu 2 (127.0.0.1) poistui verkosta. +2026-04-12T04:56:36.433155Z  INFO hub: Solmu 3 yhdistyi osoitteesta 127.0.0.1 +2026-04-12T04:56:36.445127Z  INFO hub: Solmu 3 (selain) | 127.0.0.1 | MacIntel | 11 ydintä | ~8 GB RAM | GPU: ei GPU:ta | tehtävä: viewer | varaus: 0 GB +2026-04-12T04:56:36.445818Z  INFO hub: Reititettiin API-pyyntö solmulle 1 (Malli: qwen-coder) + +━━━ Solmu 1 ━━━ qwen2.5-coder:7b-instruct-q4_K_M (Ollama) ━━━ + Prompt: "ping" + Vastaus: Pong! How can I assist you today? If you have any questions or need information on a specific topic, feel free to let me know. + 31 tokenia | 679ms | 57.5 tok/s +2026-04-12T04:56:39.466711Z  INFO hub: Solmu 3 (127.0.0.1) poistui verkosta. +2026-04-12T04:56:43.881216Z  INFO hub: Solmu 4 yhdistyi osoitteesta 127.0.0.1 +2026-04-12T04:56:43.894385Z  INFO hub: Solmu 4 (selain) | 127.0.0.1 | MacIntel | 3 ydintä | ~16 GB RAM | GPU: ei GPU:ta | tehtävä: viewer | varaus: 0 GB +2026-04-12T04:56:43.894960Z  INFO hub: Reititettiin API-pyyntö solmulle 1 (Malli: qwen-coder) + +━━━ Solmu 1 ━━━ qwen2.5-coder:7b-instruct-q4_K_M (Ollama) ━━━ + Prompt: "ping" + Vastaus: Pong! How can I assist you today? + 11 tokenia | 333ms | 58.7 tok/s diff --git a/network-poc/nodes.db b/network-poc/nodes.db index 8a24237..4739a4a 100644 Binary files a/network-poc/nodes.db and b/network-poc/nodes.db differ