# Kipinä Agentic Network PoC

Hajautettu AI-laskentaverkko selaimessa ja natiivina. Käyttäjät tarjoavat GPU/CPU-laskentatehoa avaamalla verkkosivun tai ajamalla natiivi-noden.

**Tuotanto:** https://kipina.studio | **Admin:** https://kipina.studio/admin

## Arkkitehtuuri

```
                          ┌─────────────────┐
                          │    Hub (Axum)    │
                          │  :3000 / Caddy   │
                          │  SQLite, WS BC   │
                          └────────┬────────┘
                     WebSocket     │     WebSocket
              ┌────────────────────┼────────────────────┐
              ▼                    ▼                     ▼
     ┌────────────────┐  ┌────────────────┐   ┌─────────────────┐
     │ Selainsolmu    │  │ Selainsolmu    │   │  Native Node    │
     │ Wasm + Burn    │  │ Wasm + Candle  │   │  Rust + Candle  │
     │ WebGPU/NdArray │  │ SmolLM/Qwen    │   │  CPU/CUDA       │
     └────────────────┘  └────────────────┘   └─────────────────┘
```

**Hub** broadcastaa tehtäviä (tokenisointiparit, LLM-promptit) kaikille solmuille WebSocketin kautta. Solmut käsittelevät vain oman tehtävätyyppinsä mukaiset viestit.

## Cratet

| Crate | Polku | Kuvaus |
|---|---|---|
| `hub` | `hub/` | Axum WebSocket -palvelin, tehtävien jakelu, admin-API, SQLite |
| `node` | `node/` | Wasm-selainsolmu: Burn (tensorit), Candle (LLM), tokenizer |
| `native-node` | `native-node/` | Natiivi Rust-solmu: Candle LLM, NVML/wgpu GPU-tunnistus, sysinfo |

### Hub (`hub/src/`)

- `main.rs` — WebSocket-reititin, tehtäväjakelu (10s intervalli), origin-tarkistus, IP-rajoitus, admin HTML
- `db.rs` — SQLite: `node_sessions` + `pair_results` taulut, skeemaversiointi

### Node (`node/src/`)

- `lib.rs` — Wasm-entrypoint, tehtävävalinta (`SELECTED_TASK`), WebSocket-handler, GPU/CPU-valinta
- `storage.rs` — IndexedDB read/write (tokenizer, mallin painot)
- `sampling.rs` — Top-k sampling EOS-penaltilla (kiertää Candlen softmax Wasm-bugin)
- `smollm.rs` — SmolLM 135M Candle-inferenssi (Llama-arkkitehtuuri)
- `qwen.rs` — Qwen2.5 0.5B Candle-inferenssi (Qwen2-arkkitehtuuri)
- `qwen_coder.rs` — Qwen2.5-Coder 0.5B/3B koodigenerointi (sama arkkitehtuuri, koodikoulutettu)
- `phi3.rs` — Phi-3 placeholder (liian iso selaimelle)

### Native Node (`native-node/src/`)

- `main.rs` — GPU-tunnistus (wgpu + NVML + sysfs + Apple), HF Hub -lataus, WS-yhteys
- `inference.rs` — Qwen2.5-0.5B Candle-inferenssi, CUDA/CPU, KV-cache reset per prompti, mmap-lataus

## Kehitysympäristö

```bash
# Vaatimukset
rustup target add wasm32-unknown-unknown
cargo install wasm-pack

# Kehitys (Docker — Wasm buildataan automaattisesti)
docker compose up

# Kehitys (ilman Dockeria)
cd node && wasm-pack build --dev --target web --out-dir ../static/pkg && cd ..
cargo run -p hub
# → http://localhost:3000

# Native node (erillinen terminaali)
CARGO_TARGET_DIR=target-native HUB_URL=ws://localhost:3000/ws cargo run --release -p native-node
```

## Viestityyypit (WebSocket JSON)

Hub → solmut:
| Tyyppi | Kuvaus |
|---|---|
| `pair_task` | `{en, fi}` — tokenisointipari |
| `llm_prompt` | `{prompt, model}` — LLM-tehtävä |
| `stats` | `{nodes, vram_gb, tasks, version}` |
| `node_joined` | `{node_id}` |

Solmu → hub:
| Tyyppi | Kuvaus |
|---|---|
| `auth` | Laitetiedot, `selected_task`, `allocated_gb` |
| `pair_done` | Tokenisointitulos: `{en, fi, overhead_pct, duration_ms}` |
| `llm_done` | LLM-tulos: `{response, tokens_generated, tokens_per_sec}` |
| `llm_chunk` | Streaming-token |
| `download_progress` | Mallin latauksen edistyminen |
| `user_text` | Käyttäjän oma teksti: `{text, task_type}` |

## API-endpointit

| Polku | Kuvaus |
|---|---|
| `GET /` | Dashboard (staattinen HTML) |
| `GET /ws` | WebSocket-yhteys |
| `GET /admin` | Admin-dashboard |
| `GET /api/sessions` | Node-sessiot (JSON) |
| `GET /api/pairs` | Tokenisointitulokset (JSON) |
| `GET /api/stats` | Yhteenvetotilastot (JSON) |

## Tietoturva

- **Origin-tarkistus** — vain `https://kipina.studio` ja `localhost:3000`
- **IP-rajoitus** — max 4 WS-yhteyttä per IP, X-Forwarded-For -tuki
- **Viestivalidointi** — pakollinen `type`, sallitut tyypit, kenttäkohtaiset rajat
- **Viestikoko** — max 16 KB per WebSocket-viesti
- **Admin Basic Auth** — `/admin` ja `/api/*` salasanan takana (`ADMIN_PASSWORD` env, oletus: `kipina`)
- **Caddy** — automaattinen TLS (Let's Encrypt)

## Tuotanto-deploy

```bash
# Buildaa lokaalisti, siirrä palvelimelle, käynnistä
./deploy.sh

# Manuaalisesti palvelimella
docker compose -f docker-compose.prod.yml down && docker compose -f docker-compose.prod.yml up -d
```

## Tiedossa olevat rajoitukset

- LLM-inferenssi käyttää **top-k samplingia** (k=10, EOS-penaltti) — ei täyttä temperature/top-p -tukea Wasmissa
- Qwen selaimessa: ~0.4 tok/s CPU — käyttökelpoinen demona mutta ei tuotantoon
- Native node + CUDA: ~50-100 tok/s (RTX 4090)
- Hub broadcastaa kaikki viestit kaikille — ei kohdennettu reititystä
- 3B Coder-malli vaatii ~12 GB RAM selaimessa (Wasm)

## Lisenssi

Kipinä Technologies Oy — sisäinen projekti.
