Compare commits
2 Commits
6e2f85daa8
...
094b183c17
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
094b183c17 | ||
|
|
a91b9539b3 |
@@ -1 +1 @@
|
||||
403f35efdcdf6317309f2e6b450c0ea257550b6a
|
||||
5f005820535910a5052a33cfcfc0bd6909d11c25
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -41,7 +41,7 @@
|
||||
<div style="color:#e6edf3;font-weight:600;margin-bottom:6px">2. Käynnistä Kipinä-node</div>
|
||||
<div style="display:flex;gap:6px;align-items:center;margin-bottom:6px">
|
||||
<code style="flex:1;background:#010409;padding:8px 12px;border-radius:4px;color:var(--green);font-family:'Courier New',monospace;font-size:13px;user-select:all">curl -sSL "https://kipina.studio/kipina-node?v=$(date +%s)" -o kipina-node && chmod +x kipina-node && ./kipina-node</code>
|
||||
<button onclick="navigator.clipboard.writeText('curl -sSL \"https://kipina.studio/kipina-node?v=$(date +%s)\" -o kipina-node && chmod +x kipina-node && ./kipina-node');this.textContent='✓';setTimeout(()=>this.textContent='Kopioi',1500)" class="btn btn-green" style="padding:6px 10px">Kopioi</button>
|
||||
<button onclick="navigator.clipboard.writeText('curl -sSL "https://kipina.studio/kipina-node?v=$(date +%s)" -o kipina-node && chmod +x kipina-node && ./kipina-node');this.textContent='✓';setTimeout(()=>this.textContent='Kopioi',1500)" class="btn btn-green" style="padding:6px 10px">Kopioi</button>
|
||||
</div>
|
||||
<div style="color:#8b949e;font-size:12px">Lataa kielimallin (~2GB) automaattisesti ensimmäisellä kerralla. Ctrl+C pysäyttää.</div>
|
||||
</div>
|
||||
|
||||
@@ -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(`<span style="color:var(--purple);font-weight:bold">━━━ ${esc(template.name)} — ${esc(task)} ━━━</span>`);
|
||||
|
||||
// Asiakas: jalostaa vaatimukset
|
||||
termLog(`\n<span style="color:#f0883e;font-weight:bold">[0] ${esc(cli.name)}</span> — 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(` <span style="color:#8b949e">Vaatimukset valmiit → Manageri</span>`);
|
||||
|
||||
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<span style="color:#d2a8ff;font-weight:bold">[${stepN}] ${esc(qaAgent.name)}</span> — 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<span style="color:#8b949e;font-weight:bold">[${stepN}] ${esc(obs.name)}</span> — projektin yhteenveto`);
|
||||
highlightAgent('observer');
|
||||
@@ -958,15 +989,24 @@ OUTPUT FORMAT:
|
||||
}
|
||||
|
||||
async function kpnPipelineSimple(task) {
|
||||
const cli = agents.client || Object.values(agents)[0];
|
||||
termLog(`<span style="color:var(--purple);font-weight:bold">━━━ Pipeline ━━━</span>`);
|
||||
termLog(`\n<span style="color:#d29922;font-weight:bold">[1/3] Manageri</span>`);
|
||||
const plan = await kpnRun('qwen-coder', `Analyse briefly, write a spec:\n${task}`);
|
||||
termLog(`\n<span style="color:#f0883e;font-weight:bold">[1/4] ${esc(cli.name)}</span> — vaatimukset`);
|
||||
highlightAgent('client');
|
||||
const brief = await kpnRun(cli.model, `${task}`, false, cli);
|
||||
if (!brief) return;
|
||||
termLog(`\n<span style="color:#d29922;font-weight:bold">[2/4] Manageri</span>`);
|
||||
highlightAgent('manager');
|
||||
const plan = await kpnRun('qwen-coder', `Requirements:\n${brief}\n\nAnalyse briefly, write a spec:\n${task}`);
|
||||
if (!plan) return;
|
||||
termLog(`\n<span style="color:#3fb950;font-weight:bold">[2/3] Koodari</span>`);
|
||||
termLog(`\n<span style="color:#3fb950;font-weight:bold">[3/4] Koodari</span>`);
|
||||
highlightAgent('coder');
|
||||
const code = await kpnRun('qwen-coder', `${plan}\n\nWrite the code.`);
|
||||
if (!code) return;
|
||||
termLog(`\n<span style="color:var(--accent);font-weight:bold">[3/3] Testaaja</span>`);
|
||||
termLog(`\n<span style="color:var(--accent);font-weight:bold">[4/4] Testaaja</span>`);
|
||||
highlightAgent('tester');
|
||||
await kpnRun('qwen-coder', `Review briefly:\n${code}`);
|
||||
highlightAgent(null);
|
||||
termLog(`\n<span style="color:var(--purple);font-weight:bold">━━━ Valmis ━━━</span>`);
|
||||
}
|
||||
|
||||
|
||||
@@ -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`
|
||||
[2m2026-04-12T03:21:35.058711Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Tietokanta alustettu
|
||||
[2m2026-04-12T03:21:35.061635Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Kipinä Agent Hub v0.3.1 käynnistyy osoitteessa http://localhost:3000
|
||||
[2m2026-04-12T03:21:49.577628Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 1 yhdistyi osoitteesta 127.0.0.1
|
||||
[2m2026-04-12T03:21:49.600021Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 1 (natiivi) | 127.0.0.1 | Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM | varaus: 4 GB
|
||||
[2m2026-04-12T03:21:49.600099Z[0m [32m INFO[0m [2mhub[0m[2m:[0m GPU 0: Apple M2 Max | VRAM: 0/24576 MB | 0°C | 0%
|
||||
[2m2026-04-12T04:56:09.723604Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Tietokanta alustettu
|
||||
[2m2026-04-12T04:56:09.725088Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Kipinä Agent Hub v0.3.1 käynnistyy osoitteessa http://localhost:3000
|
||||
[2m2026-04-12T04:56:18.997935Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 1 yhdistyi osoitteesta 127.0.0.1
|
||||
[2m2026-04-12T04:56:19.027478Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 1 (natiivi) | 127.0.0.1 | Mac | Darwin 26.3.1 | 12 ydintä | 32768 MB RAM | varaus: 4 GB
|
||||
[2m2026-04-12T04:56:19.029931Z[0m [32m INFO[0m [2mhub[0m[2m:[0m GPU 0: Apple M2 Max | VRAM: 0/24576 MB | 0°C | 0%
|
||||
[2m2026-04-12T04:56:31.260470Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 2 yhdistyi osoitteesta 127.0.0.1
|
||||
[2m2026-04-12T04:56:31.281759Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 2 (selain) | 127.0.0.1 | MacIntel | 11 ydintä | ~8 GB RAM | GPU: ei GPU:ta | tehtävä: viewer | varaus: 0 GB
|
||||
[2m2026-04-12T04:56:31.283313Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Reititettiin API-pyyntö solmulle 1 (Malli: qwen-coder)
|
||||
|
||||
[35m━━━ Solmu 1 ━━━ qwen2.5-coder:7b-instruct-q4_K_M (Ollama) ━━━[0m
|
||||
Prompt: [33m"ping"[0m
|
||||
Vastaus: [32mPong! How can I assist you today?[0m
|
||||
11 tokenia | 4502ms | [36m56.3 tok/s[0m
|
||||
[2m2026-04-12T04:56:36.419646Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 2 (127.0.0.1) poistui verkosta.
|
||||
[2m2026-04-12T04:56:36.433155Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 3 yhdistyi osoitteesta 127.0.0.1
|
||||
[2m2026-04-12T04:56:36.445127Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 3 (selain) | 127.0.0.1 | MacIntel | 11 ydintä | ~8 GB RAM | GPU: ei GPU:ta | tehtävä: viewer | varaus: 0 GB
|
||||
[2m2026-04-12T04:56:36.445818Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Reititettiin API-pyyntö solmulle 1 (Malli: qwen-coder)
|
||||
|
||||
[35m━━━ Solmu 1 ━━━ qwen2.5-coder:7b-instruct-q4_K_M (Ollama) ━━━[0m
|
||||
Prompt: [33m"ping"[0m
|
||||
Vastaus: [32mPong! How can I assist you today? If you have any questions or need information on a specific topic, feel free to let me know.[0m
|
||||
31 tokenia | 679ms | [36m57.5 tok/s[0m
|
||||
[2m2026-04-12T04:56:39.466711Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 3 (127.0.0.1) poistui verkosta.
|
||||
[2m2026-04-12T04:56:43.881216Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 4 yhdistyi osoitteesta 127.0.0.1
|
||||
[2m2026-04-12T04:56:43.894385Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Solmu 4 (selain) | 127.0.0.1 | MacIntel | 3 ydintä | ~16 GB RAM | GPU: ei GPU:ta | tehtävä: viewer | varaus: 0 GB
|
||||
[2m2026-04-12T04:56:43.894960Z[0m [32m INFO[0m [2mhub[0m[2m:[0m Reititettiin API-pyyntö solmulle 1 (Malli: qwen-coder)
|
||||
|
||||
[35m━━━ Solmu 1 ━━━ qwen2.5-coder:7b-instruct-q4_K_M (Ollama) ━━━[0m
|
||||
Prompt: [33m"ping"[0m
|
||||
Vastaus: [32mPong! How can I assist you today?[0m
|
||||
11 tokenia | 333ms | [36m58.7 tok/s[0m
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user