docs: LICENCE.md-Feature, .gitignore, Single-GPU-Doku
- pi-coder-judge-extension.ts: licenceMd() + writeLicenceMd() — erzeugt proprietäre LICENCE.md in der Doku-Phase (nur wenn noch nicht vorhanden) - tests: Guards und pure-logic-Tests für LICENCE.md ergänzt (38 Tests, alle grün) - .gitignore: Node, TypeScript-Artefakte, Backups, Editor-Dateien, OS-Metadaten - README.md + BEDIENUNGSANLEITUNG.md: vollständig auf Single-GPU-Architektur aktualisiert (ein Server, System-Prompt-Rollen, kein Quick-Judge, PASS WITH CONCERNS-Verhalten, LICENCE.md in /update_doku, start-single.sh) - SINGLE_SERVER_PLAN.md: entfernt (umgesetzt, kein Mehrwert mehr) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ba733fe684
commit
485ab30265
7 changed files with 297 additions and 357 deletions
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Node (aktuell keine Dependencies, aber falls welche hinzukommen)
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# TypeScript-/Build-Artefakte
|
||||||
|
*.tsbuildinfo
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Backup-Dateien (z. B. settings.json.bak aus dem Install-Skript)
|
||||||
|
*.bak
|
||||||
|
|
||||||
|
# Editor / IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# Bedienungsanleitung: pi_coder
|
# Bedienungsanleitung: pi_coder
|
||||||
|
|
||||||
pi_coder ist ein Werkzeug, das zwei lokale KI-Modelle als **Coder** und **Judge** einsetzt,
|
pi_coder ist ein Werkzeug, das ein lokales KI-Modell abwechselnd als **Coder** und **Judge**
|
||||||
um Software automatisch zu schreiben, zu prüfen und zu verbessern — alles gesteuert über
|
einsetzt, um Software automatisch zu schreiben, zu prüfen und zu verbessern — alles gesteuert
|
||||||
einfache Slash-Kommandos in der pi-Agent-Oberfläche.
|
über einfache Slash-Kommandos in der pi-Agent-Oberfläche.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -25,17 +25,22 @@ einfache Slash-Kommandos in der pi-Agent-Oberfläche.
|
||||||
|
|
||||||
## 1. Konzept: Coder und Judge
|
## 1. Konzept: Coder und Judge
|
||||||
|
|
||||||
pi_coder verwendet zwei Rollen:
|
pi_coder verwendet zwei Rollen — bedient von **einem einzigen Modell**, das je nach Aufgabe
|
||||||
|
eine andere Persona annimmt:
|
||||||
|
|
||||||
**Coder** (Port 8001): Schreibt und repariert Code. Liest die Aufgabe aus `TASK.md`,
|
**Coder-Persona**: Schreibt und repariert Code. Liest die Aufgabe aus `TASK.md`, implementiert
|
||||||
implementiert sie, führt Tests aus und erstellt Git-Commits.
|
sie, führt Tests aus und erstellt Git-Commits.
|
||||||
|
|
||||||
**Judge** (Port 8002): Überprüft den Code mit dem Blick eines skeptischen Senior-Entwicklers.
|
**Judge-Persona**: Überprüft den Code mit dem Blick eines skeptischen Senior-Entwicklers.
|
||||||
Prüft Korrektheit, Robustheit, Randfälle, Sicherheit und Produktionsreife. Gibt ein Urteil:
|
Prüft Korrektheit, Robustheit, Randfälle, Sicherheit und Produktionsreife. Gibt ein Urteil:
|
||||||
- `PASS` — Code ist in Ordnung
|
- `PASS` — Code ist in Ordnung
|
||||||
- `PASS WITH CONCERNS` — grundsätzlich akzeptabel, aber mit Anmerkungen
|
- `PASS WITH CONCERNS` — hat Anmerkungen, die behoben werden müssen (wird wie `FAIL` behandelt,
|
||||||
|
außer du verwendest `--approve-concerns`)
|
||||||
- `FAIL` — enthält Blocker, die behoben werden müssen
|
- `FAIL` — enthält Blocker, die behoben werden müssen
|
||||||
|
|
||||||
|
Die Umschaltung zwischen den Rollen erfolgt über unterschiedliche System-Prompts, die die
|
||||||
|
Extension automatisch vor jeder Inference einsetzt. Es läuft kein zweiter Server.
|
||||||
|
|
||||||
Der Grundgedanke: Coder und Judge haben keine „Höflichkeitsschranke" zueinander —
|
Der Grundgedanke: Coder und Judge haben keine „Höflichkeitsschranke" zueinander —
|
||||||
der Judge kritisiert direkt und konkret, der Coder repariert ohne Widerspruch.
|
der Judge kritisiert direkt und konkret, der Coder repariert ohne Widerspruch.
|
||||||
|
|
||||||
|
|
@ -47,14 +52,14 @@ der Judge kritisiert direkt und konkret, der Coder repariert ohne Widerspruch.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/pi_coder
|
cd ~/pi_coder
|
||||||
./start-servers.sh
|
./start-single.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Ausgabe bei Erfolg:
|
Ausgabe bei Erfolg:
|
||||||
```
|
```
|
||||||
[*] Starte beide Server parallel ...
|
[*] Verwende HF_HOME = /home/.../huggingface
|
||||||
[✓] Coder (:8001) bereit
|
[*] GPU device = 1
|
||||||
[✓] Judge (:8002) bereit
|
[✓] Single-Server (:8001) bereit
|
||||||
```
|
```
|
||||||
|
|
||||||
Dauer: bis zu 5 Minuten (Modell wird in GPU-VRAM geladen; neuere llama.cpp-Versionen
|
Dauer: bis zu 5 Minuten (Modell wird in GPU-VRAM geladen; neuere llama.cpp-Versionen
|
||||||
|
|
@ -68,8 +73,7 @@ prüfen beim Start die VRAM-Verfügbarkeit, was zusätzliche Zeit kostet).
|
||||||
|
|
||||||
```
|
```
|
||||||
=== LLaMA-Server Status ===
|
=== LLaMA-Server Status ===
|
||||||
qwen36-27b-coder (Port 8001): Container=RUNNING HTTP=OK
|
qwen36-27b-single (Port 8001): Container=RUNNING HTTP=OK
|
||||||
qwen36-27b-judge (Port 8002): Container=RUNNING HTTP=OK
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### pi agent öffnen
|
### pi agent öffnen
|
||||||
|
|
@ -86,53 +90,41 @@ pi
|
||||||
|
|
||||||
## 3. Server starten und stoppen
|
## 3. Server starten und stoppen
|
||||||
|
|
||||||
### GPU-Zuordnung (3-GPU-Setup)
|
### GPU-Zuordnung
|
||||||
|
|
||||||
Bei einem System mit drei GPUs sind die Rollen fest in den Startskripten verankert —
|
Der Server läuft standardmäßig auf **GPU 1** (überschreibbar):
|
||||||
**keine manuelle Konfiguration nötig:**
|
|
||||||
|
|
||||||
| GPU | Modell | Rolle |
|
```bash
|
||||||
|-----|--------|-------|
|
./start-single.sh # GPU 1 (Standard)
|
||||||
| GPU 0 (NVIDIA T600) | — | Display / Monitor — wird von den Skripten nicht angetastet |
|
GPU_DEVICE=0 ./start-single.sh # GPU 0
|
||||||
| GPU 1 (RTX 3090, 24 GB) | Qwen3.6-27B | **Coder** (Port 8001) |
|
```
|
||||||
| GPU 2 (RTX 3090, 24 GB) | Qwen3.6-27B | **Judge** (Port 8002) |
|
|
||||||
|
|
||||||
Jeder Server bekommt seine eigene GPU exklusiv — so gibt es keinen VRAM-Konflikt,
|
Auf einem System mit mehreren GPUs empfiehlt es sich, GPU 0 (Display) freizuhalten
|
||||||
auch wenn beide gleichzeitig laufen.
|
und GPU 1 für den KI-Server zu verwenden.
|
||||||
|
|
||||||
**Wichtig:** Andere GPU-Prozesse (z. B. TTS-Dienste, Ollama) auf GPU 1 oder GPU 2 können
|
**Wichtig:** Andere GPU-Prozesse (z. B. TTS-Dienste, Ollama) auf der verwendeten GPU
|
||||||
VRAM belegen und dazu führen, dass ein Server nicht startet. Im Zweifel prüfen:
|
können VRAM belegen und dazu führen, dass der Server nicht startet. Im Zweifel prüfen:
|
||||||
```bash
|
```bash
|
||||||
nvidia-smi --query-gpu=index,name,memory.used,memory.free --format=csv
|
nvidia-smi --query-gpu=index,name,memory.used,memory.free --format=csv
|
||||||
```
|
```
|
||||||
|
|
||||||
### Beide starten (empfohlen)
|
### Server starten
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/pi_coder
|
cd ~/pi_coder
|
||||||
./start-servers.sh
|
./start-single.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Erwartete Ausgabe:
|
Erwartete Ausgabe:
|
||||||
```
|
```
|
||||||
[*] Starte beide Server parallel ...
|
[*] Verwende HF_HOME = /home/.../huggingface
|
||||||
[✓] Coder (:8001) bereit
|
[*] GPU device = 1
|
||||||
[✓] Judge (:8002) bereit
|
[✓] Single-Server (:8001) bereit
|
||||||
```
|
```
|
||||||
|
|
||||||
Dauer: bis zu 5 Minuten. Danach sind beide Modelle im VRAM und sofort antwortbereit.
|
Dauer: bis zu 5 Minuten. Danach ist das Modell im VRAM und sofort antwortbereit.
|
||||||
|
|
||||||
### Einzelnen Server neu starten
|
### Server stoppen
|
||||||
|
|
||||||
Z.B. wenn nur der Judge-Server abgestürzt ist:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./start-judge.sh # Port 8002, GPU 2
|
|
||||||
# oder:
|
|
||||||
./start-coder.sh # Port 8001, GPU 1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Beide stoppen
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./stop-servers.sh
|
./stop-servers.sh
|
||||||
|
|
@ -149,7 +141,7 @@ Z.B. wenn nur der Judge-Server abgestürzt ist:
|
||||||
Falls die GGUF-Datei an einem anderen Ort liegt:
|
Falls die GGUF-Datei an einem anderen Ort liegt:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
HF_HOME=/mnt/daten/huggingface ./start-servers.sh
|
HF_HOME=/mnt/daten/huggingface ./start-single.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -235,7 +227,7 @@ Der Judge:
|
||||||
3. Führt Tests aus
|
3. Führt Tests aus
|
||||||
4. Gibt ein strukturiertes Urteil aus
|
4. Gibt ein strukturiertes Urteil aus
|
||||||
|
|
||||||
**Beispiel-Ausgabe PASS:**
|
**Beispiel-Ausgabe PASS WITH CONCERNS:**
|
||||||
```
|
```
|
||||||
Urteil: PASS WITH CONCERNS
|
Urteil: PASS WITH CONCERNS
|
||||||
|
|
||||||
|
|
@ -326,17 +318,22 @@ Empfohlene Sofortmaßnahmen: keine
|
||||||
- `--continue` — überspringt die Implementierungsphase und startet direkt mit dem
|
- `--continue` — überspringt die Implementierungsphase und startet direkt mit dem
|
||||||
Judge→Fix-Zyklus ab dem aktuellen Code-Stand. Nützlich wenn man bereits manuell
|
Judge→Fix-Zyklus ab dem aktuellen Code-Stand. Nützlich wenn man bereits manuell
|
||||||
`/coder`, `/judge` und `/fix` durchgeführt hat und den Rest automatisieren möchte.
|
`/coder`, `/judge` und `/fix` durchgeführt hat und den Rest automatisieren möchte.
|
||||||
Im `--continue`-Modus werden Coder- und Judge-Server gleichzeitig geprüft.
|
|
||||||
- `--interactive` — pausiert nach erstem PASS für einen menschlichen Checkpoint.
|
- `--interactive` — pausiert nach erstem PASS für einen menschlichen Checkpoint.
|
||||||
Details: siehe [Interactive-Modus](#interactive-modus) weiter unten.
|
Details: siehe [Interactive-Modus](#interactive-modus) weiter unten.
|
||||||
- `--no-tests` — überspringt die automatische Test-Erkennung. Sinnvoll wenn keine
|
- `--no-tests` — überspringt die automatische Test-Erkennung. Sinnvoll wenn keine
|
||||||
Test-Suite vorhanden ist oder Tests über externe Infrastruktur laufen.
|
Test-Suite vorhanden ist oder Tests über externe Infrastruktur laufen.
|
||||||
- `--approve-concerns` — behandelt „PASS WITH CONCERNS" wie „PASS": kein ShipIt-Call,
|
- `--approve-concerns` — behandelt „PASS WITH CONCERNS" wie „PASS": kein ShipIt-Call,
|
||||||
direktes SHIP. Für Projekte, bei denen du dem Judge-Urteil vertraust.
|
direktes SHIP. Standardmäßig löst PASS WITH CONCERNS immer einen Coder-Fix aus.
|
||||||
- `--test-cmd "befehl"` — überschreibt die automatische Test-Erkennung mit einem
|
- `--test-cmd "befehl"` — überschreibt die automatische Test-Erkennung mit einem
|
||||||
eigenen Befehl (z.B. `--test-cmd "pytest tests/ -x"`).
|
eigenen Befehl (z.B. `--test-cmd "pytest tests/ -x"`).
|
||||||
- `--test-timeout N` — maximale Laufzeit pro Test-Befehl in Sekunden (Standard: 120).
|
- `--test-timeout N` — maximale Laufzeit pro Test-Befehl in Sekunden (Standard: 120).
|
||||||
|
|
||||||
|
### PASS WITH CONCERNS — wichtig
|
||||||
|
|
||||||
|
Ohne `--approve-concerns` gilt `PASS WITH CONCERNS` **wie `FAIL`** — der Coder bekommt
|
||||||
|
einen Fix-Auftrag und der Loop geht weiter. Erst sauberes `PASS` beendet die Schleife.
|
||||||
|
Mit `--approve-concerns` gilt PASS WITH CONCERNS als bestanden.
|
||||||
|
|
||||||
### Beispiel: einfacher Auftrag
|
### Beispiel: einfacher Auftrag
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -346,31 +343,33 @@ Empfohlene Sofortmaßnahmen: keine
|
||||||
Was im Hintergrund passiert:
|
Was im Hintergrund passiert:
|
||||||
```
|
```
|
||||||
Phase 1: Coder implementiert...
|
Phase 1: Coder implementiert...
|
||||||
Phase 2: Runde 1/2: Quick-Check (kompakter Erstcheck)...
|
Phase 2: Runde 1/2: Judge — TASK.md + letzter Commit + Tests...
|
||||||
→ Urteil: FAIL (2 Blocker)
|
→ Urteil: FAIL (2 Blocker)
|
||||||
Phase 3: Runde 1/2: Coder fixt...
|
Phase 3: Runde 1/2: Coder fixt...
|
||||||
Phase 4: Runde 2/2: Judge — TASK.md + letzter Commit + Tests...
|
Phase 4: Runde 2/2: Judge — TASK.md + letzter Commit + Tests...
|
||||||
→ Urteil: PASS WITH CONCERNS
|
→ Urteil: PASS
|
||||||
✓ PASS WITH CONCERNS nach Runde 2
|
✓ PASS nach Runde 2 → SHIP
|
||||||
Finale ShipIt-Prüfung... (nur bei PASS WITH CONCERNS, nicht bei klarem PASS)
|
|
||||||
→ SHIP
|
|
||||||
[Dialog: Version → v0.1.0 (empfohlen)]
|
[Dialog: Version → v0.1.0 (empfohlen)]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Runde 1 = Quick-Check:** Kompakter Prompt ohne TASK.md-Analyse — erkennt offensichtliche
|
Bei `PASS WITH CONCERNS` (ohne --approve-concerns):
|
||||||
Fehler schnell. Erst ab Runde 2 (oder bei `--continue`) kommt der vollständige Judge-Prompt.
|
```
|
||||||
|
→ Urteil: PASS WITH CONCERNS (Major: fehlendes --help)
|
||||||
|
Phase 3: Runde 2/2: Coder fixt Concerns...
|
||||||
|
Phase 4: Runde 3/3: Judge...
|
||||||
|
→ Urteil: PASS
|
||||||
|
✓ PASS → SHIP
|
||||||
|
```
|
||||||
|
|
||||||
Bei klarem `PASS` entfällt die ShipIt-Runde — es wird direkt SHIP ausgelöst.
|
Bei klarem `PASS` entfällt die ShipIt-Runde — es wird direkt SHIP ausgelöst.
|
||||||
Mit `--approve-concerns` gilt das auch für `PASS WITH CONCERNS`.
|
|
||||||
|
|
||||||
Während des Ablaufs zeigt die Statuszeile die aktuelle Phase — mit laufendem Timer,
|
Während des Ablaufs zeigt die Statuszeile die aktuelle Phase — mit laufendem Timer:
|
||||||
der beweist, dass die LLM tatsächlich arbeitet (und nicht hängt):
|
|
||||||
|
|
||||||
```
|
```
|
||||||
◉ Coder implementiert: Login-Flow mit JWT [01:23]
|
◉ Coder implementiert: Login-Flow mit JWT [01:23]
|
||||||
◉○ Runde 1/2: Quick-Check [00:47]
|
◉○ Runde 1/2: Judge — TASK.md + letzter Commit + Tests [00:47]
|
||||||
●◉ Runde 2/2: Coder fixt — fehlendes Null-Check [01:05]
|
●◉ Runde 1/2: Coder fixt — fehlendes Null-Check [01:05]
|
||||||
●● ✓ PASS nach Runde 2/2 — ShipIt…
|
●● ✓ PASS nach Runde 2/2 — SHIP
|
||||||
🚀 SHIP – produktionsreif
|
🚀 SHIP – produktionsreif
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -392,6 +391,7 @@ Nach SHIP werden automatisch ausgeführt:
|
||||||
1. Code-Kommentare einfügen
|
1. Code-Kommentare einfügen
|
||||||
2. README.md schreiben
|
2. README.md schreiben
|
||||||
3. BEDIENUNGSANLEITUNG.md schreiben
|
3. BEDIENUNGSANLEITUNG.md schreiben
|
||||||
|
4. LICENCE.md anlegen (falls noch nicht vorhanden)
|
||||||
|
|
||||||
### Vom manuellen Workflow in den automatischen wechseln
|
### Vom manuellen Workflow in den automatischen wechseln
|
||||||
|
|
||||||
|
|
@ -415,7 +415,8 @@ Stand und der Fix-Zyklus läuft automatisch bis PASS oder max. N Runden.
|
||||||
|
|
||||||
### Loop-Erkennung
|
### Loop-Erkennung
|
||||||
|
|
||||||
Wenn zweimal hintereinander genau dieselben Blocker auftreten, bricht `/optimize` ab:
|
Wenn zweimal hintereinander genau dieselben Blocker oder Concerns auftreten, bricht
|
||||||
|
`/optimize` ab:
|
||||||
```
|
```
|
||||||
⚠ Derselbe Blocker tritt erneut auf – Schleife abgebrochen. Bitte manuell prüfen.
|
⚠ Derselbe Blocker tritt erneut auf – Schleife abgebrochen. Bitte manuell prüfen.
|
||||||
```
|
```
|
||||||
|
|
@ -563,11 +564,14 @@ Fix: Validierung in die Funktion generate_password() verschieben statt in parse_
|
||||||
## 8. Dokumentation generieren: /update_doku
|
## 8. Dokumentation generieren: /update_doku
|
||||||
|
|
||||||
Nach Abschluss der Entwicklung (nach `/shipit` oder `/optimize`) erstellt `/update_doku`
|
Nach Abschluss der Entwicklung (nach `/shipit` oder `/optimize`) erstellt `/update_doku`
|
||||||
drei Dinge automatisch:
|
vier Dinge automatisch:
|
||||||
|
|
||||||
1. **Code-Kommentare** — erklärt das WARUM in den Quelldateien (Deutsch)
|
1. **Code-Kommentare** — erklärt das WARUM in den Quelldateien (Deutsch)
|
||||||
2. **README.md** — Entwicklerperspektive: Installation, Build, Verwendung
|
2. **README.md** — Entwicklerperspektive: Installation, Build, Verwendung
|
||||||
3. **BEDIENUNGSANLEITUNG.md** — Endnutzerperspektive: einfach, ohne Jargon
|
3. **BEDIENUNGSANLEITUNG.md** — Endnutzerperspektive: einfach, ohne Jargon
|
||||||
|
4. **LICENCE.md** — proprietäre Lizenz mit aktuellem Jahr und Inhaber aus `git config user.name`
|
||||||
|
(wird nur angelegt wenn noch keine `LICENCE.md` vorhanden ist — existierende Lizenzen
|
||||||
|
werden nie überschrieben)
|
||||||
|
|
||||||
```
|
```
|
||||||
/update_doku
|
/update_doku
|
||||||
|
|
@ -582,6 +586,7 @@ Nur geänderte Quelldateien werden neu kommentiert — unveränderte bleiben una
|
||||||
Code-Kommentare: keine Änderungen seit letztem Lauf – übersprungen.
|
Code-Kommentare: keine Änderungen seit letztem Lauf – übersprungen.
|
||||||
README.md: 2 Datei(en) geändert – wird geprüft
|
README.md: 2 Datei(en) geändert – wird geprüft
|
||||||
BEDIENUNGSANLEITUNG.md: 2 Datei(en) geändert – wird geprüft
|
BEDIENUNGSANLEITUNG.md: 2 Datei(en) geändert – wird geprüft
|
||||||
|
LICENCE.md: bereits vorhanden – übersprungen.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Zusammen mit /optimize
|
### Zusammen mit /optimize
|
||||||
|
|
@ -772,7 +777,7 @@ Die Checkboxen werden automatisch abgehakt:
|
||||||
# Für Projekte wo "PASS WITH CONCERNS" ausreicht:
|
# Für Projekte wo "PASS WITH CONCERNS" ausreicht:
|
||||||
/optimize "Kleines Refactoring" --approve-concerns
|
/optimize "Kleines Refactoring" --approve-concerns
|
||||||
|
|
||||||
# Kombination: kein Test, kein ShipIt bei Concerns, 1 Runde
|
# Kombination: kein Test, PASS WITH CONCERNS akzeptieren, 1 Runde
|
||||||
/optimize "Typo-Fix in Fehlermeldungen" --rounds 1 --no-tests --approve-concerns
|
/optimize "Typo-Fix in Fehlermeldungen" --rounds 1 --no-tests --approve-concerns
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -851,7 +856,7 @@ Die Checkboxen werden automatisch abgehakt:
|
||||||
ls $HF_HOME/models/qwen3/
|
ls $HF_HOME/models/qwen3/
|
||||||
|
|
||||||
# Oder mit explizitem Pfad starten:
|
# Oder mit explizitem Pfad starten:
|
||||||
HF_HOME=/korrekter/pfad ./start-servers.sh
|
HF_HOME=/korrekter/pfad ./start-single.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Server startet nicht / HTTP nicht erreichbar
|
### Server startet nicht / HTTP nicht erreichbar
|
||||||
|
|
@ -864,26 +869,26 @@ HF_HOME=/korrekter/pfad ./start-servers.sh
|
||||||
|
|
||||||
1. Zu wenig VRAM — Container bricht beim Laden ab:
|
1. Zu wenig VRAM — Container bricht beim Laden ab:
|
||||||
```bash
|
```bash
|
||||||
docker logs qwen36-27b-coder | tail -50
|
docker logs qwen36-27b-single | tail -50
|
||||||
# Suche nach: "CUDA out of memory" oder "failed to allocate"
|
# Suche nach: "CUDA out of memory" oder "failed to allocate"
|
||||||
```
|
```
|
||||||
→ Kontext reduzieren: `-c 32768` statt `-c 131072`
|
→ Kontext reduzieren: `-c 65536` statt `-c 262144` in `start-single.sh`
|
||||||
|
|
||||||
2. GPU nicht verfügbar:
|
2. GPU nicht verfügbar:
|
||||||
```bash
|
```bash
|
||||||
nvidia-smi # alle drei GPUs sichtbar?
|
nvidia-smi # GPU sichtbar?
|
||||||
# GPU 1 (Coder) testen:
|
# GPU 1 testen:
|
||||||
docker run --gpus '"device=1"' --rm nvidia/cuda:12.0-base nvidia-smi
|
docker run --gpus '"device=1"' --rm nvidia/cuda:12.0-base nvidia-smi
|
||||||
# GPU 2 (Judge) testen:
|
# Andere GPU testen:
|
||||||
docker run --gpus '"device=2"' --rm nvidia/cuda:12.0-base nvidia-smi
|
GPU_DEVICE=0 ./start-single.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Port bereits belegt:
|
3. Port 8001 bereits belegt:
|
||||||
```bash
|
```bash
|
||||||
ss -tlnp | grep 800[12]
|
ss -tlnp | grep 8001
|
||||||
docker ps -a # alter Container noch vorhanden?
|
docker ps -a # alter Container noch vorhanden?
|
||||||
./stop-servers.sh
|
./stop-servers.sh
|
||||||
./start-servers.sh
|
./start-single.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### "Agent is already processing a prompt"
|
### "Agent is already processing a prompt"
|
||||||
|
|
@ -914,8 +919,8 @@ Lies die Datei neu ein und wende die Änderungen als unified diff mit apply_patc
|
||||||
⚠ Derselbe Blocker tritt erneut auf – Schleife abgebrochen.
|
⚠ Derselbe Blocker tritt erneut auf – Schleife abgebrochen.
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ursache:** Der Coder kann einen bestimmten Blocker nicht beheben — z.B. weil die
|
**Ursache:** Der Coder kann einen bestimmten Blocker oder Concern nicht beheben — z.B.
|
||||||
Aufgabe einen Widerspruch enthält oder ein externes System fehlt.
|
weil die Aufgabe einen Widerspruch enthält oder ein externes System fehlt.
|
||||||
|
|
||||||
**Lösung:** Manuell eingreifen:
|
**Lösung:** Manuell eingreifen:
|
||||||
```
|
```
|
||||||
|
|
@ -927,9 +932,14 @@ Dann den Blocker analysieren und entweder:
|
||||||
- Die Aufgabe in TASK.md präzisieren
|
- Die Aufgabe in TASK.md präzisieren
|
||||||
- Bei komplexen Aufgaben mit mehr Runden wiederholen: `/optimize --continue --rounds 5`
|
- Bei komplexen Aufgaben mit mehr Runden wiederholen: `/optimize --continue --rounds 5`
|
||||||
|
|
||||||
|
Falls der Judge wiederholt Concerns findet, die du akzeptierst:
|
||||||
|
```
|
||||||
|
/optimize --continue --approve-concerns
|
||||||
|
```
|
||||||
|
|
||||||
### Server läuft, aber pi wechselt nicht das Modell
|
### Server läuft, aber pi wechselt nicht das Modell
|
||||||
|
|
||||||
**Ursache:** `models.json` wurde nach einer Änderung nicht neu deployt.
|
**Ursache:** `models.json` oder `settings.json` wurde nach einer Änderung nicht neu deployt.
|
||||||
|
|
||||||
**Lösung:**
|
**Lösung:**
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
236
README.md
236
README.md
|
|
@ -1,8 +1,9 @@
|
||||||
# pi_coder — Automatisierter Coder/Judge-Workflow für pi agent
|
# pi_coder_2 — Automatisierter Coder/Judge-Workflow für pi agent
|
||||||
|
|
||||||
Dieses Repository enthält die Konfiguration und Skripte für einen automatisierten
|
Dieses Repository enthält die Konfiguration und Skripte für einen automatisierten
|
||||||
Coding-Workflow mit zwei lokalen LLaMA-Modellen: ein Coder-Modell und ein Judge-Modell,
|
Coding-Workflow mit einem lokalen LLaMA-Modell, das abwechselnd als Coder und Judge
|
||||||
gesteuert über [pi agent](https://github.com/earendil-works/pi).
|
agiert — gesteuert über Pi Agent. Er dreht solange Optimierungsschleifen, bis das
|
||||||
|
Programm Produktionsreife hat.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -12,37 +13,40 @@ gesteuert über [pi agent](https://github.com/earendil-works/pi).
|
||||||
Nutzer gibt Auftrag
|
Nutzer gibt Auftrag
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
/coder → qwen3.5-coder (:8001) → Implementierung + git commit
|
/coder → qwen3.5-single (:8001, Coder-Persona) → Implementierung + git commit
|
||||||
│
|
│
|
||||||
▼
|
▼
|
||||||
/judge → qwen3.5-judge (:8002) → Review: PASS / FAIL + Blocker
|
/judge → qwen3.5-single (:8001, Judge-Persona) → Review: PASS / FAIL + Blocker
|
||||||
│
|
│
|
||||||
FAIL? ▼
|
FAIL? ▼
|
||||||
/fix → qwen3.5-coder (:8001) → Fixes + git commit
|
/fix → qwen3.5-single (:8001, Coder-Persona) → Fixes + git commit
|
||||||
|
│
|
||||||
|
PASS WITH CONCERNS? ▼
|
||||||
|
│ (ohne --approve-concerns: wie FAIL → weiterer Fix-Zyklus)
|
||||||
│
|
│
|
||||||
PASS? ▼
|
PASS? ▼
|
||||||
/shipit → qwen3.5-judge (:8002) → Finale Freigabe: SHIP / NO-SHIP
|
/shipit → qwen3.5-single (:8001, Judge-Persona) → Finale Freigabe: SHIP / NO-SHIP
|
||||||
(nur bei "PASS WITH CONCERNS" — klares PASS → direkt SHIP)
|
(nur bei "PASS WITH CONCERNS" --approve-concerns; klares PASS → direkt SHIP)
|
||||||
|
|
||||||
/optimize = Coder→Judge→Fix-Schleife automatisch (bis PASS oder max. N Runden)
|
/optimize = Coder→Judge→Fix-Schleife automatisch (bis PASS oder max. N Runden)
|
||||||
--interactive: pausiert nach PASS für menschlichen Checkpoint + optionale Zusatzaufträge
|
--interactive: pausiert nach PASS für menschlichen Checkpoint + optionale Zusatzaufträge
|
||||||
```
|
```
|
||||||
|
|
||||||
Beide Modelle laufen als **separate llama.cpp-Docker-Container** und sprechen eine
|
Ein **einzelner** llama.cpp-Docker-Container bedient beide Rollen. Die Rollenumschaltung
|
||||||
OpenAI-kompatible API (`/v1/chat/completions`). pi agent wechselt automatisch zwischen
|
(Coder ↔ Judge) erfolgt über unterschiedliche System-Prompts, die der `before_agent_start`-Hook
|
||||||
den Endpunkten wenn du ein `/judge`-, `/fix`- oder `/coder`-Kommando aufrufst.
|
der Extension vor jeder Inference injiziert. pi agent wechselt keine Server mehr —
|
||||||
|
nur die Persona im System-Prompt ändert sich.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Modelle
|
## Modelle
|
||||||
|
|
||||||
| Rolle | Modell | Port | Container | Alias | GPU |
|
| Rolle | Modell | Port | Container | Alias | GPU |
|
||||||
|--------|---------------------------------------------------|------|------------------|----------------|----------|
|
|----------------|---------------------------------------------------|------|--------------------|----------------|----------|
|
||||||
| Coder | Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS | 8001 | qwen36-27b-coder | qwen3.5-coder | device=1 |
|
| Coder + Judge | Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS | 8001 | qwen36-27b-single | qwen3.5-single | device=1 |
|
||||||
| Judge | Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS | 8002 | qwen36-27b-judge | qwen3.5-judge | device=2 |
|
|
||||||
|
|
||||||
Beide Container verwenden dasselbe GGUF-Datei, aber mit unterschiedlichen
|
Coder- und Judge-Rollen werden durch verschiedene System-Prompts realisiert —
|
||||||
Serverparametern (Kontext, Temperatur, Parallelität).
|
dasselbe Modell, derselbe Container, unterschiedliche Persona.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -58,12 +62,12 @@ Serverparametern (Kontext, Temperatur, Parallelität).
|
||||||
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
|
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
|
||||||
sudo systemctl restart docker
|
sudo systemctl restart docker
|
||||||
```
|
```
|
||||||
- NVIDIA-GPUs: empfohlen 2 × RTX 3090 (je 24 GB VRAM) für Coder und Judge parallel.
|
- NVIDIA-GPU: empfohlen RTX 3090 (24 GB VRAM). Standard: GPU 1. Überschreibbar mit
|
||||||
Bei 3 GPUs: GPU 0 für Display reservieren, GPU 1 → Coder, GPU 2 → Judge.
|
`GPU_DEVICE=0 ./start-single.sh`. Bei 3 GPUs: GPU 0 für Display reservieren.
|
||||||
- GGUF-Modell vorhanden unter:
|
- GGUF-Modell vorhanden unter:
|
||||||
`$HF_HOME/models/qwen3/Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS.gguf`
|
`$HF_HOME/models/qwen3/Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS.gguf`
|
||||||
- Standard-Pfad: `HF_HOME=/home/dschlueter/nvme2n1p7_home/huggingface`
|
- Standard-Pfad: `HF_HOME=/home/dschlueter/nvme2n1p7_home/huggingface`
|
||||||
- Überschreibbar: `HF_HOME=/anderer/pfad ./start-servers.sh`
|
- Überschreibbar: `HF_HOME=/anderer/pfad ./start-single.sh`
|
||||||
- [pi agent](https://github.com/earendil-works/pi) installiert (`~/.pi/`)
|
- [pi agent](https://github.com/earendil-works/pi) installiert (`~/.pi/`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -75,16 +79,20 @@ Serverparametern (Kontext, Temperatur, Parallelität).
|
||||||
git clone https://kitux.de/forgejo/dschlueter/pi_coder.git ~/pi_coder
|
git clone https://kitux.de/forgejo/dschlueter/pi_coder.git ~/pi_coder
|
||||||
cd ~/pi_coder
|
cd ~/pi_coder
|
||||||
|
|
||||||
# 2. Extension und Modell-Config nach ~/.pi/agent/ deployen
|
# 2. Extension, Modell-Config und settings.json nach ~/.pi/agent/ deployen
|
||||||
./install_servers_and_pi_coder_extension.sh
|
./install_servers_and_pi_coder_extension.sh
|
||||||
|
|
||||||
# 3. pi agent neu laden (in der pi-Oberfläche)
|
# 3. pi agent neu laden (in der pi-Oberfläche)
|
||||||
# /reload
|
# /reload
|
||||||
|
|
||||||
# 4. Server starten
|
# 4. Server starten
|
||||||
./start-servers.sh
|
./start-single.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Das Install-Skript sichert eine vorhandene `~/.pi/agent/settings.json` als `.bak` und
|
||||||
|
kopiert dann `settings.json` aus dem Repo. Damit ist der korrekte Default-Provider
|
||||||
|
(`llama-cpp-single/qwen3.5-single`) automatisch konfiguriert.
|
||||||
|
|
||||||
Nach späteren Änderungen an `pi-coder-judge-extension.ts` oder `models.json`:
|
Nach späteren Änderungen an `pi-coder-judge-extension.ts` oder `models.json`:
|
||||||
```bash
|
```bash
|
||||||
./install_servers_and_pi_coder_extension.sh # kopiert nach ~/.pi/agent/
|
./install_servers_and_pi_coder_extension.sh # kopiert nach ~/.pi/agent/
|
||||||
|
|
@ -96,95 +104,71 @@ Nach späteren Änderungen an `pi-coder-judge-extension.ts` oder `models.json`:
|
||||||
## Server starten / stoppen / status
|
## Server starten / stoppen / status
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Beide Server parallel starten (empfohlen — dauert 1–3 Minuten)
|
# Server starten (empfohlen — dauert 1–3 Minuten)
|
||||||
./start-servers.sh
|
./start-single.sh
|
||||||
|
|
||||||
# Einzeln starten (z.B. nur einen neu starten)
|
# Server auf anderer GPU starten
|
||||||
./start-coder.sh # Port 8001
|
GPU_DEVICE=0 ./start-single.sh
|
||||||
./start-judge.sh # Port 8002
|
|
||||||
|
|
||||||
# Beide stoppen
|
# Stoppen
|
||||||
./stop-servers.sh
|
./stop-servers.sh
|
||||||
|
|
||||||
# Status beider Server prüfen
|
# Status prüfen
|
||||||
./status.sh
|
./status.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
`start-servers.sh` startet beide Container gleichzeitig und wartet bis beide
|
`start-single.sh` startet den Container und wartet bis HTTP-ready (max. 5 Minuten — die
|
||||||
HTTP-ready sind (max. 5 Minuten — die neue llama.cpp-Version prüft beim Start, ob
|
neue llama.cpp-Version prüft beim Start, ob Modell + KV-Cache in den VRAM passen, was
|
||||||
Modell + KV-Cache in den VRAM passen, was zusätzliche Zeit kostet). Logs werden
|
zusätzliche Zeit kostet).
|
||||||
getrennt gesammelt und nur bei Fehler ausgegeben.
|
|
||||||
|
|
||||||
Wenn Server bereits laufen und du `start-servers.sh` (oder ein Einzelskript)
|
Wenn der Server bereits läuft und du `start-single.sh` aufrufst, wird der laufende
|
||||||
aufrufst, werden die laufenden Container zuerst per `docker rm -f` gestoppt
|
Container zuerst per `docker rm -f` gestoppt und dann neu gestartet — ein laufender
|
||||||
und dann neu gestartet — ein laufender Inference-Request wird dabei abgebrochen.
|
Inference-Request wird dabei abgebrochen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## llama.cpp-Serverparameter im Detail
|
## llama.cpp-Serverparameter im Detail
|
||||||
|
|
||||||
### Gemeinsame Parameter
|
### Parameter des Single-Servers (Port 8001)
|
||||||
|
|
||||||
| Parameter | Wert | Bedeutung |
|
| Parameter | Wert | Bedeutung |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `--jinja` | — | Verwendet das im GGUF eingebettete Jinja-Chat-Template (Qwen-Format). Notwendig für korrekte `<\|im_start\|>`-Tokens. |
|
| `--jinja` | — | Verwendet das im GGUF eingebettete Jinja-Chat-Template (Qwen-Format). Notwendig für korrekte `<\|im_start\|>`-Tokens. |
|
||||||
| `--reasoning on` | — | Aktiviert das interne Thinking-Budget des Modells (Qwen3-spezifisch). Ersetzt das frühere `--chat-template-kwargs '{"enable_thinking":true}'`. |
|
| `--reasoning on` | — | Aktiviert das interne Thinking-Budget des Modells (Qwen3-spezifisch). |
|
||||||
| `--no-context-shift` | — | Kontextfenster wird **nicht** verschoben wenn es voll ist — stattdessen Fehler. Verhindert stille Datenverluste. |
|
| `--no-context-shift` | — | Kontextfenster wird **nicht** verschoben wenn es voll ist — stattdessen Fehler. Verhindert stille Datenverluste. |
|
||||||
| `--repeat-penalty 1.05` | — | Leichte Penalty für Wiederholungen. Wert > 1.0 unterdrückt Loops. |
|
| `--repeat-penalty 1.05` | — | Leichte Penalty für Wiederholungen. |
|
||||||
| `--top-k 20` | — | Nur die 20 wahrscheinlichsten nächsten Tokens werden berücksichtigt. |
|
| `--top-k 20` | — | Nur die 20 wahrscheinlichsten nächsten Tokens. |
|
||||||
| `--min-p 0.01` | — | Tokens mit Wahrscheinlichkeit < 1 % des wahrscheinlichsten Tokens werden ausgeschlossen. |
|
| `--min-p 0.01` | — | Tokens mit Wahrscheinlichkeit < 1 % des wahrscheinlichsten Tokens werden ausgeschlossen. |
|
||||||
| `-ngl 999` | — | Alle Layer auf die GPU laden (999 = „alle"). Bei zu wenig VRAM reduzieren. |
|
| `-ngl 999` | — | Alle Layer auf die GPU laden. |
|
||||||
| `-fa on` | — | Flash Attention — schnellere Attention-Berechnung, weniger VRAM für den Attention-Pass. |
|
| `-fa on` | — | Flash Attention. |
|
||||||
| `--kv-unified` | — | Einheitlicher KV-Cache über alle Schichten. Effizienter bei langen Kontexten. |
|
| `--kv-unified` | — | Einheitlicher KV-Cache über alle Schichten. |
|
||||||
| `--cache-type-k q4_0` | — | KV-Cache Keys in 4-Bit quantisiert. Spart ~75 % VRAM gegenüber fp16 — nötig für 256K Kontext auf einer 24-GB-GPU. |
|
| `--cache-type-k q4_0` | — | KV-Cache Keys 4-Bit quantisiert. Nötig für 256K Kontext auf einer 24-GB-GPU. |
|
||||||
| `--cache-type-v q4_0` | — | KV-Cache Values ebenfalls 4-Bit quantisiert. |
|
| `--cache-type-v q4_0` | — | KV-Cache Values ebenfalls 4-Bit quantisiert. |
|
||||||
| `--cont-batching` | — | Continuous Batching: neue Anfragen werden in laufende Batches eingefügt — höherer Durchsatz bei mehreren parallelen Anfragen. |
|
| `--cont-batching` | — | Continuous Batching. |
|
||||||
| `--main-gpu 0` | — | GPU-Index (0 = erste des Containers) für Nicht-Tensor-Operationen. |
|
| `-c 262144` | 256K | Großes Kontextfenster für langen Gesprächsverlauf im Optimize-Loop. |
|
||||||
| `--gpus '"device=1"'` (Coder) | — | Docker: nur GPU 1 dem Coder-Container zuweisen. |
|
| `-n 16384` | 16K | Maximale Ausgabelänge. |
|
||||||
| `--gpus '"device=2"'` (Judge) | — | Docker: nur GPU 2 dem Judge-Container zuweisen. |
|
| `--temp 0.2` | — | Deterministisch — Coder-Rolle. Der Judge-System-Prompt gleicht die etwas höhere Temperatur aus. |
|
||||||
|
| `--parallel 2` | — | 2 Slots, damit pi agent Folgeanfragen schnell hintereinander stellen kann. |
|
||||||
### Coder-Server (Port 8001) — optimiert für Coding-Aufgaben
|
| `--gpus '"device=1"'` | — | Standard: GPU 1. Überschreibbar: `GPU_DEVICE=0 ./start-single.sh`. |
|
||||||
|
|
||||||
| Parameter | Wert | Erklärung / Wirkung |
|
|
||||||
|---|---|---|
|
|
||||||
| `-c 262144` | 256K Tokens | Sehr großes Kontextfenster: gesamte Codebasis + langer Gesprächsverlauf passt rein. **Sehr hoher VRAM-Bedarf.** Reduziere auf `65536` wenn VRAM knapp. |
|
|
||||||
| `-n 16384` | 16K Tokens | Maximale Ausgabelänge pro Anfrage. Für Kommentieraufgaben (`/update_doku`) nötig. |
|
|
||||||
| `--temp 0.2` | — | Niedrige Temperatur: deterministisch, konsistenter Code. Erhöhe auf `0.4–0.6` für kreativere Lösungsansätze. |
|
|
||||||
| `--top-p 0.95` | — | Nucleus Sampling: 95 % der Wahrscheinlichkeitsmasse. Passend zu temp 0.2. |
|
|
||||||
| `--batch-size 1024` | — | Prompt-Verarbeitungs-Batch. Größer = schnelleres Einlesen langer Dateien. |
|
|
||||||
| `--ubatch-size 512` | — | Micro-Batch für GPU-Kernel. Muss ≤ batch-size sein. |
|
|
||||||
| `--parallel 2` | — | 2 gleichzeitige Request-Slots. Nützlich wenn pi agent schnell Folgeanfragen schickt. |
|
|
||||||
|
|
||||||
### Judge-Server (Port 8002) — optimiert für Reviews
|
|
||||||
|
|
||||||
| Parameter | Wert | Erklärung / Wirkung |
|
|
||||||
|---|---|---|
|
|
||||||
| `-c 262144` | 256K Tokens | Großes Kontextfenster: nötig bei langen /optimize-Runden, wo der Gesprächsverlauf stark anwächst. |
|
|
||||||
| `-n 16384` | 16K Tokens | Lange Reviews und Begründungen passen vollständig in die Ausgabe. |
|
|
||||||
| `--temp 0.1` | — | Sehr niedrige Temperatur: maximale Konsistenz und Reproduzierbarkeit der Urteile. |
|
|
||||||
| `--top-p 0.9` | — | Etwas enger als beim Coder — weniger Variation im Urteil gewünscht. |
|
|
||||||
| `--batch-size 512` | — | Kleiner als beim Coder — Judge bekommt selten sehr lange Prompts. |
|
|
||||||
| `--ubatch-size 256` | — | Entsprechend kleiner. |
|
|
||||||
| `--parallel 1` | — | Judge-Aufgaben sind immer sequenziell im Workflow, daher 1 Slot ausreichend. |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## GPU-Konfiguration und VRAM
|
## GPU-Konfiguration und VRAM
|
||||||
|
|
||||||
### Aktuelles Setup (1 GPU pro Server)
|
### Aktuelles Setup (1 GPU, 1 Server)
|
||||||
|
|
||||||
Jeder Server bekommt eine dedizierte GPU — dadurch kein VRAM-Konflikt:
|
Ein einzelner Container bedient beide Rollen sequenziell:
|
||||||
|
|
||||||
```
|
```
|
||||||
GPU 0 NVIDIA T600 → Display / Monitor (nicht für KI genutzt)
|
GPU 0 NVIDIA T600 → Display / Monitor (nicht für KI genutzt)
|
||||||
GPU 1 RTX 3090 (24 GB) → qwen36-27b-coder (Port 8001)
|
GPU 1 RTX 3090 (24 GB) → qwen36-27b-single (Port 8001, Coder + Judge)
|
||||||
GPU 2 RTX 3090 (24 GB) → qwen36-27b-judge (Port 8002)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Die Skripte verwenden `--gpus '"device=1"'` (Coder) bzw. `'"device=2"'` (Judge).
|
Da Coder und Judge nicht gleichzeitig inferieren, gibt es keinen VRAM-Konflikt.
|
||||||
Innerhalb des Containers ist dies stets `CUDA:0`, daher `--main-gpu 0` ohne `--tensor-split`.
|
Die Umschaltung zwischen den Rollen erfolgt ausschließlich über den System-Prompt —
|
||||||
|
der Container läuft ohne Unterbrechung durch.
|
||||||
|
|
||||||
### VRAM-Abschätzung für das 27B IQ4_XS-Modell (eine GPU)
|
### VRAM-Abschätzung für das 27B IQ4_XS-Modell
|
||||||
|
|
||||||
| Komponente | Größe (ca.) |
|
| Komponente | Größe (ca.) |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
|
@ -194,36 +178,28 @@ Innerhalb des Containers ist dies stets `CUDA:0`, daher `--main-gpu 0` ohne `--t
|
||||||
| KV-Cache bei 65 536 Tokens (q4_0) | ~2–3 GB |
|
| KV-Cache bei 65 536 Tokens (q4_0) | ~2–3 GB |
|
||||||
| **Summe (262k Kontext)** | **~22–24 GB** |
|
| **Summe (262k Kontext)** | **~22–24 GB** |
|
||||||
|
|
||||||
Bei einer **24-GB-GPU** ist 262k Kontext knapp kalkuliert. Wichtig: keine anderen Prozesse
|
Bei einer **24-GB-GPU** ist 262k Kontext knapp kalkuliert. Keine anderen Prozesse
|
||||||
dürfen nennenswert VRAM belegen (z. B. TTS-Dienste, Ollama). Prüfen mit:
|
dürfen nennenswert VRAM belegen (z. B. TTS-Dienste, Ollama). Prüfen mit:
|
||||||
```bash
|
```bash
|
||||||
nvidia-smi --query-gpu=index,memory.used,memory.free --format=csv
|
nvidia-smi --query-gpu=index,memory.used,memory.free --format=csv
|
||||||
```
|
```
|
||||||
|
|
||||||
Falls der VRAM nicht reicht: Kontext in den Startskripten auf `131072` oder `65536` reduzieren.
|
Falls der VRAM nicht reicht: Kontext in `start-single.sh` auf `131072` oder `65536` reduzieren.
|
||||||
|
|
||||||
### Anpassung für andere GPU-Konfigurationen
|
### Anpassung für andere GPU-Konfigurationen
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 2 GPUs (beide für KI, keine Display-GPU):
|
# Andere GPU verwenden:
|
||||||
--gpus '"device=0"' # Coder
|
GPU_DEVICE=0 ./start-single.sh
|
||||||
--gpus '"device=1"' # Judge
|
|
||||||
|
|
||||||
# 1 GPU (beide Server auf gleicher GPU — nicht empfohlen, VRAM-Konflikt):
|
# 2 GPUs für einen Server (sehr großer Kontext):
|
||||||
--gpus '"device=0"' # beide Server
|
# start-single.sh anpassen:
|
||||||
--tensor-split 0.5,0.5 # Modell hälftig aufteilen
|
|
||||||
-c 65536 # Kontext stark reduzieren
|
|
||||||
|
|
||||||
# 2 GPUs für einen Server (wenn sehr großer Kontext nötig):
|
|
||||||
--gpus '"device=0,1"' \
|
--gpus '"device=0,1"' \
|
||||||
--tensor-split 0.5,0.5 \
|
--tensor-split 0.5,0.5 \
|
||||||
--main-gpu 0 \
|
--main-gpu 0 \
|
||||||
-c 262144
|
-c 262144
|
||||||
```
|
```
|
||||||
|
|
||||||
Bei einer **16-GB-GPU** ist die Modellgröße allein schon grenzwertig.
|
|
||||||
Entweder ein kleineres Modell verwenden oder die Quantisierung erhöhen (IQ3_XS, Q4_K_M).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Parameter-Tuning-Guide
|
## Parameter-Tuning-Guide
|
||||||
|
|
@ -232,23 +208,18 @@ Entweder ein kleineres Modell verwenden oder die Quantisierung erhöhen (IQ3_XS,
|
||||||
|
|
||||||
| Wert | Eignung |
|
| Wert | Eignung |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `0.0–0.1` | Maximale Reproduzierbarkeit. Gut für Judge/Review. |
|
| `0.0–0.1` | Maximale Reproduzierbarkeit. |
|
||||||
| `0.1–0.3` | Guter Kompromiss für Coding. **Empfohlen für Coder.** |
|
| `0.1–0.3` | Guter Kompromiss für Coding. **Aktuell gesetzt: 0.2.** |
|
||||||
| `0.4–0.6` | Kreativere Lösungen, mehr Varianz. Sinnvoll für Prototyping. |
|
| `0.4–0.6` | Kreativere Lösungen. |
|
||||||
| `0.7–1.0` | Kreativschreiben, Brainstorming. Für Coding meist zu viel Rauschen. |
|
| `0.7–1.0` | Für Coding meist zu viel Rauschen. |
|
||||||
|
|
||||||
### Kontextgröße (`-c`)
|
### Kontextgröße (`-c`)
|
||||||
|
|
||||||
Je größer der Kontext, desto mehr VRAM braucht der KV-Cache.
|
|
||||||
Faustregel: KV-Cache ≈ `context_size × layers × head_dim × 2 × bytes_per_element`.
|
|
||||||
Bei q8_0 (1 Byte/Element) und Qwen3-27B (28 Schichten, 128 Head-Dim, 32 Heads):
|
|
||||||
KV-Cache ≈ `context_size × 28 × 128 × 32 × 2 × 1 Byte ≈ context_size × 0,23 MB`
|
|
||||||
|
|
||||||
| Kontext | KV-Cache (q4_0) | Empfehlung |
|
| Kontext | KV-Cache (q4_0) | Empfehlung |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 32 768 | ~1,9 GB | 1 × 16-GB-GPU |
|
| 32 768 | ~1,9 GB | 1 × 16-GB-GPU |
|
||||||
| 65 536 | ~3,7 GB | 1 × 24-GB-GPU |
|
| 65 536 | ~3,7 GB | 1 × 24-GB-GPU (konservativ) |
|
||||||
| 131 072 | ~7,5 GB | 2 × 16-GB-GPU |
|
| 131 072 | ~7,5 GB | 1 × 24-GB-GPU |
|
||||||
| 262 144 | ~8–10 GB | 1 × 24-GB-GPU (q4_0) — **aktuell gesetzt** |
|
| 262 144 | ~8–10 GB | 1 × 24-GB-GPU (q4_0) — **aktuell gesetzt** |
|
||||||
|
|
||||||
### KV-Cache-Quantisierung
|
### KV-Cache-Quantisierung
|
||||||
|
|
@ -257,31 +228,35 @@ KV-Cache ≈ `context_size × 28 × 128 × 32 × 2 × 1 Byte ≈ context_size ×
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `f16` | 100 % (Basis) | Referenz |
|
| `f16` | 100 % (Basis) | Referenz |
|
||||||
| `q8_0` | ~50 % | Kaum merklich schlechter |
|
| `q8_0` | ~50 % | Kaum merklich schlechter |
|
||||||
| `q4_0` | ~25 % | Merklicher Qualitätsverlust bei langen Kontexten — aber nötig für 256K Kontext auf 2× 24 GB. **Aktuell gesetzt.** |
|
| `q4_0` | ~25 % | Merklicher Qualitätsverlust bei langen Kontexten — aber nötig für 256K Kontext auf 24 GB. **Aktuell gesetzt.** |
|
||||||
|
|
||||||
### Parallelität (`--parallel`)
|
---
|
||||||
|
|
||||||
Mehr parallele Slots erhöhen den Durchsatz bei gleichzeitigen Anfragen, aber jeder Slot
|
## Tests ausführen
|
||||||
reserviert Speicher im KV-Cache. Im pi-coder-Workflow sind echte Parallelaufrufe selten,
|
|
||||||
daher ist `--parallel 1` für den Judge ausreichend. Coder `--parallel 2` bietet Puffer
|
```bash
|
||||||
wenn pi agent Folgeanfragen schnell hintereinander schickt.
|
./run-tests.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Keine npm-Installation nötig — nutzt den integrierten `node:test`-Runner und
|
||||||
|
`--experimental-strip-types` für TypeScript. Testet Parsing-Logik, Konfigurationskonsistenz
|
||||||
|
und Extension-Guards gegen Regressionen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Dateien
|
## Dateien
|
||||||
|
|
||||||
| Datei | Zweck |
|
| Datei / Verzeichnis | Zweck |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `pi-coder-judge-extension.ts` | pi agent Extension (Kommandos, Tools, Hooks) |
|
| `pi-coder-judge-extension.ts` | pi agent Extension (Kommandos, Tools, Hooks, Rollen-Logik) |
|
||||||
| `models.json` | Provider- und Modell-Konfiguration für pi agent |
|
| `models.json` | Provider- und Modell-Konfiguration für pi agent |
|
||||||
| `test-utils.ts` | Unit-Tests für Hilfsfunktionen der Extension |
|
| `settings.json` | pi-agent-Settings (Default-Modell, aktivierte Modelle) — wird von Install-Skript deployt |
|
||||||
| `run-tests.sh` | Unit-Tests ausführen (TypeScript-Stripping + node) |
|
| `run-tests.sh` | Tests ausführen |
|
||||||
| `start-servers.sh` | Beide Server parallel starten (empfohlen) |
|
| `tests/` | Testdateien (pure-logic, config, extension-guards, scripts) |
|
||||||
| `start-coder.sh` | Nur Coder-Container starten (Port 8001) |
|
| `start-single.sh` | Single-Server starten (Port 8001, Coder + Judge) |
|
||||||
| `start-judge.sh` | Nur Judge-Container starten (Port 8002) |
|
| `stop-servers.sh` | Container stoppen |
|
||||||
| `stop-servers.sh` | Beide Container stoppen |
|
| `status.sh` | Laufstatus anzeigen |
|
||||||
| `status.sh` | Laufstatus beider Server anzeigen |
|
| `install_servers_and_pi_coder_extension.sh` | Extension + models.json + settings.json nach `~/.pi/agent/` deployen |
|
||||||
| `install_servers_and_pi_coder_extension.sh` | Extension + models.json nach `~/.pi/agent/` kopieren |
|
|
||||||
| `examples/` | Demo-Projekte (Python, Rust, Go, C, Bash, HTML/JS) für Live-Demos |
|
| `examples/` | Demo-Projekte (Python, Rust, Go, C, Bash, HTML/JS) für Live-Demos |
|
||||||
| `examples/restore-all.sh` | Examples nach Demo-Lauf in Ausgangszustand zurücksetzen |
|
| `examples/restore-all.sh` | Examples nach Demo-Lauf in Ausgangszustand zurücksetzen |
|
||||||
|
|
||||||
|
|
@ -289,18 +264,18 @@ wenn pi agent Folgeanfragen schnell hintereinander schickt.
|
||||||
|
|
||||||
## pi-Kommandos (Kurzübersicht)
|
## pi-Kommandos (Kurzübersicht)
|
||||||
|
|
||||||
| Kommando | Modell | Beschreibung |
|
| Kommando | Persona | Beschreibung |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `/coder <auftrag>` | Coder | TASK.md anlegen, Implementierung starten |
|
| `/coder <auftrag>` | Coder | TASK.md anlegen, Implementierung starten |
|
||||||
| `/judge [fokus]` | Judge | Code-Review gegen TASK.md + letzten Commit |
|
| `/judge [fokus]` | Judge | Code-Review gegen TASK.md + letzten Commit |
|
||||||
| `/fix [hinweis]` | Coder | Judge-Kritik beheben, committen |
|
| `/fix [hinweis]` | Coder | Judge-Kritik beheben, committen |
|
||||||
| `/shipit` | Judge | Finale Freigabeprüfung |
|
| `/shipit` | Judge | Finale Freigabeprüfung |
|
||||||
| `/optimize <auftrag> [--rounds N] [--with-doku] [--continue] [--interactive]` | beide | Vollautomatische Schleife bis PASS (Standard: 2 Runden, Runde 1: Quick-Judge) |
|
| `/optimize <auftrag> [--rounds N] [--with-doku] [--continue] [--interactive]` | beide | Vollautomatische Schleife bis PASS (Standard: 2 Runden) |
|
||||||
| `/optimize ... [--no-tests] [--approve-concerns] [--test-cmd "cmd"] [--test-timeout N]` | beide | Test-Erkennung überspringen / PASS WITH CONCERNS direkt shippern |
|
| `/optimize ... [--no-tests] [--approve-concerns] [--test-cmd "cmd"] [--test-timeout N]` | beide | Test-Erkennung überspringen / PASS WITH CONCERNS akzeptieren |
|
||||||
| `/patch <änderung>` | Coder | Gezielte Minimaländerung ohne Review |
|
| `/patch <änderung>` | Coder | Gezielte Minimaländerung ohne Review |
|
||||||
| `/quick_check [was]` | Judge | Schnelle Prüfung der letzten Änderung |
|
| `/quick_check [was]` | Judge | Schnelle Prüfung der letzten Änderung |
|
||||||
| `/version` | — | Versionsnummer erhöhen (SemVer + Git-Tag) |
|
| `/version` | — | Versionsnummer erhöhen (SemVer + Git-Tag) |
|
||||||
| `/update_doku` | Coder | Code kommentieren + README + Bedienungsanleitung |
|
| `/update_doku` | Coder | Code kommentieren + README + Bedienungsanleitung + LICENCE.md |
|
||||||
| `/plan <auftrag>` | Coder | Implementierungsplan in PLAN.md (kein Code) |
|
| `/plan <auftrag>` | Coder | Implementierungsplan in PLAN.md (kein Code) |
|
||||||
| `/continue` | Coder | Unterbrochenen Prozess fortsetzen |
|
| `/continue` | Coder | Unterbrochenen Prozess fortsetzen |
|
||||||
| `/cancel` | — | Laufenden Loop nach aktuellem Schritt abbrechen |
|
| `/cancel` | — | Laufenden Loop nach aktuellem Schritt abbrechen |
|
||||||
|
|
@ -310,6 +285,15 @@ Ausführliche Beschreibung aller Kommandos mit Beispielen: siehe **BEDIENUNGSANL
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## PASS WITH CONCERNS — Verhalten
|
||||||
|
|
||||||
|
Im `/optimize`-Loop gilt `PASS WITH CONCERNS` **nicht** als bestanden — der Coder erhält
|
||||||
|
einen weiteren Fix-Auftrag, genau wie bei `FAIL`. Erst sauberes `PASS` beendet die Schleife.
|
||||||
|
|
||||||
|
Opt-out: `--approve-concerns` lässt `PASS WITH CONCERNS` als bestanden gelten.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Live-Aktivitätsstatus
|
## Live-Aktivitätsstatus
|
||||||
|
|
||||||
Während der Ausführung zeigt pi_coder in der Statuszeile, was gerade passiert —
|
Während der Ausführung zeigt pi_coder in der Statuszeile, was gerade passiert —
|
||||||
|
|
@ -320,11 +304,11 @@ inklusive eines laufenden `[MM:SS]`-Timers während jeder LLM-Inference-Phase:
|
||||||
| Coder implementiert | `◉ Coder implementiert: Login-Flow mit JWT [01:23]` |
|
| Coder implementiert | `◉ Coder implementiert: Login-Flow mit JWT [01:23]` |
|
||||||
| edit-Tool aktiv | `Editiere src/main.py…` |
|
| edit-Tool aktiv | `Editiere src/main.py…` |
|
||||||
| git commit | `Git-Commit…` |
|
| git commit | `Git-Commit…` |
|
||||||
| Judge (Quick-Check, Runde 1) | `◉○ Runde 1/2: Quick-Check [00:47]` |
|
| Judge (Runde 1) | `◉○ Runde 1/2: Judge — TASK.md + letzter Commit + Tests [00:47]` |
|
||||||
| Judge (voller Review, Runde 2) | `●◉ Runde 2/2: Judge — TASK.md + letzter Commit + Tests [02:15]` |
|
| Judge (Runde 2) | `●◉ Runde 2/2: Judge — TASK.md + letzter Commit + Tests [02:15]` |
|
||||||
| Tests laufen | `●○ Runde 1/2: Tests laufen (pytest, max. 120s)…` |
|
| Tests laufen | `●○ Runde 1/2: Tests laufen (pytest, max. 120s)…` |
|
||||||
| Fix-Phase | `●◉ Runde 2/2: Coder fixt — fehlendes Null-Check [01:05]` |
|
| Fix-Phase | `●◉ Runde 2/2: Coder fixt — fehlendes Null-Check [01:05]` |
|
||||||
| ShipIt | `●●◉ ShipIt — finale Freigabe [00:33]` |
|
| ShipIt | `●●◉ ShipIt — finale Freigabe [00:33]` |
|
||||||
| Interactive-Pause (--interactive) | `⏸ PASS – warte auf /continue…` |
|
| Interactive-Pause | `⏸ PASS – warte auf /continue…` |
|
||||||
|
|
||||||
Der Timer beweist, dass die LLM tatsächlich arbeitet. Steht er still, hängt der Prozess.
|
Der Timer beweist, dass die LLM tatsächlich arbeitet. Steht er still, hängt der Prozess.
|
||||||
|
|
|
||||||
|
|
@ -1,150 +0,0 @@
|
||||||
# Plan: pi_coder_v2 — Single-Server (Option B)
|
|
||||||
|
|
||||||
## Kontext
|
|
||||||
|
|
||||||
pi_coder verwendet zwei llama.cpp-Server für Coder (GPU 1) und Judge (GPU 2),
|
|
||||||
die aber dasselbe GGUF-Modell ausführen. Die Rollentrennung entsteht ausschließlich
|
|
||||||
durch System-Prompts. Wenn nur eine GPU verfügbar ist, kann ein einziger Server
|
|
||||||
beide Rollen übernehmen — Rollenwechsel per Prompt statt per Server-Neustart.
|
|
||||||
|
|
||||||
**pi_coder bleibt unverändert.** Die Umsetzung erfolgt im neuen Verzeichnis `~/pi_coder_v2`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Schritt 1: Verzeichnis anlegen und Dateien kopieren
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir ~/pi_coder_v2
|
|
||||||
cp ~/pi_coder/pi-coder-judge-extension.ts ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/models.json ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/start-coder.sh ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/start-judge.sh ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/start-servers.sh ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/stop-servers.sh ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/status.sh ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/install_servers_and_pi_coder_extension.sh ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/README.md ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/BEDIENUNGSANLEITUNG.md ~/pi_coder_v2/
|
|
||||||
cp ~/pi_coder/CLAUDE.md ~/pi_coder_v2/
|
|
||||||
# Plan-Datei ebenfalls kopieren
|
|
||||||
cp <dieser-plan> ~/pi_coder_v2/SINGLE_SERVER_PLAN.md
|
|
||||||
# git init
|
|
||||||
cd ~/pi_coder_v2 && git init && git add -A && git commit -m "init: kopiert aus pi_coder"
|
|
||||||
```
|
|
||||||
|
|
||||||
Nicht kopieren: `run-tests.sh`, `test-utils.ts`, `examples/` (nicht relevant für Kernfunktion).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Schritt 2: `start-single.sh` anlegen
|
|
||||||
|
|
||||||
Basiert auf `start-coder.sh` mit folgenden Änderungen:
|
|
||||||
|
|
||||||
| Parameter | Alt (coder) | Neu (single) |
|
|
||||||
|---|---|---|
|
|
||||||
| `CONTAINER_NAME` | `qwen36-27b-coder` | `qwen36-27b-single` |
|
|
||||||
| `HOST_PORT` | 8001 | 8001 |
|
|
||||||
| `MODEL_ALIAS` | `qwen3.5-coder` | `qwen3.5-single` |
|
|
||||||
| `--temp` | 0.6 | 0.65 (Kompromiss) |
|
|
||||||
| `--gpus` | `"device=1"` | `"device=1"` (oder konfigurierbar) |
|
|
||||||
|
|
||||||
Der Server registriert sich unter dem Alias `qwen3.5-single`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Schritt 3: `models.json` anpassen
|
|
||||||
|
|
||||||
Neuen Provider `llama-cpp-single` hinzufügen mit **beiden** Modell-IDs auf Port 8001:
|
|
||||||
|
|
||||||
```json
|
|
||||||
"llama-cpp-single": {
|
|
||||||
"baseUrl": "http://127.0.0.1:8001/v1",
|
|
||||||
"api": "openai-completions",
|
|
||||||
"apiKey": "none",
|
|
||||||
"compat": {
|
|
||||||
"supportsDeveloperRole": false,
|
|
||||||
"supportsReasoningEffort": false,
|
|
||||||
"maxTokensField": "max_tokens",
|
|
||||||
"thinkingFormat": "qwen-chat-template"
|
|
||||||
},
|
|
||||||
"models": [
|
|
||||||
{
|
|
||||||
"id": "qwen3.5-coder",
|
|
||||||
"name": "Qwen3.6 27B Single-Server Coder (llama.cpp :8001)",
|
|
||||||
"reasoning": true,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 262144,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "qwen3.5-judge",
|
|
||||||
"name": "Qwen3.6 27B Single-Server Judge (llama.cpp :8001)",
|
|
||||||
"reasoning": true,
|
|
||||||
"input": ["text"],
|
|
||||||
"contextWindow": 262144,
|
|
||||||
"maxTokens": 16384,
|
|
||||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Die bestehenden Provider `llama-cpp-coder` und `llama-cpp-judge` bleiben erhalten
|
|
||||||
(für Kompatibilität), werden aber nicht aktiv genutzt.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Schritt 4: `pi-coder-judge-extension.ts` — switchModel-Aufrufe
|
|
||||||
|
|
||||||
Alle Aufrufe von `switchModel(pi, ctx, "llama-cpp-coder", "qwen3.5-coder")`
|
|
||||||
und `switchModel(pi, ctx, "llama-cpp-judge", "qwen3.5-judge")` werden auf
|
|
||||||
`"llama-cpp-single"` umgestellt. Der Modell-ID-Parameter (`"qwen3.5-coder"` /
|
|
||||||
`"qwen3.5-judge"`) bleibt unverändert — so bleiben die Registry-Wechsel erhalten,
|
|
||||||
sind aber sofort (kein Server-Neustart).
|
|
||||||
|
|
||||||
Betroffene Stellen (ca. 8):
|
|
||||||
- `/coder` handler
|
|
||||||
- `/judge` handler
|
|
||||||
- `/fix` handler
|
|
||||||
- `/shipit` handler
|
|
||||||
- `/optimize` loop (Coder-Kickoff, Judge-Phase, Fix-Phase, ShipIt-Phase)
|
|
||||||
- `/patch` handler
|
|
||||||
- `/quick_check` handler
|
|
||||||
- `/plan` handler
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Schritt 5: `install_servers_and_pi_coder_extension.sh` anpassen
|
|
||||||
|
|
||||||
Pfade auf `pi_coder_v2` anpassen (falls nötig — Skript referenziert vermutlich `$REPO`
|
|
||||||
als relatives Verzeichnis, was automatisch korrekt ist).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Schritt 6: `waitUntilModelReady` im `--continue`-Modus
|
|
||||||
|
|
||||||
Im `--continue`-Modus prüft die Extension beide Server parallel:
|
|
||||||
```typescript
|
|
||||||
const [coderReady, judgeReady] = await Promise.all([
|
|
||||||
waitUntilModelReady(pi, ctx, 8001, "qwen3.5-coder"),
|
|
||||||
waitUntilModelReady(pi, ctx, 8002, "qwen3.5-judge"),
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Dies muss auf einen einzigen Check umgestellt werden:
|
|
||||||
```typescript
|
|
||||||
const ready = await waitUntilModelReady(pi, ctx, 8001, "qwen3.5-single");
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Verifikation
|
|
||||||
|
|
||||||
1. `cd ~/pi_coder_v2 && ./start-single.sh` → Server startet auf Port 8001
|
|
||||||
2. `nvidia-smi` → nur eine GPU belegt, ~20 GB VRAM
|
|
||||||
3. `./install_servers_and_pi_coder_extension.sh` → Extension in `~/.pi/agent/` deployen
|
|
||||||
4. In pi: `/reload` → Extension neu laden
|
|
||||||
5. `/optimize <kleiner Testauftrag>` → Loop läuft durch
|
|
||||||
6. In der Statuszeile: `switchModel` wechselt ohne spürbare Pause
|
|
||||||
7. Qualitätscheck: Judge-Urteil und Coder-Fix verhalten sich wie erwartet
|
|
||||||
|
|
@ -324,6 +324,45 @@ function planPrompt(task: string): string {
|
||||||
|
|
||||||
// ── Hilfsfunktionen ─────────────────────────────────────────────────────────
|
// ── Hilfsfunktionen ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
// Proprietäre Default-Lizenz ("Alle Rechte vorbehalten"), deutsch — passend zur übrigen Doku.
|
||||||
|
// Reine Template-Funktion (deterministisch): Lizenztext wird NIE vom LLM generiert.
|
||||||
|
function licenceMd(year: string, holder: string): string {
|
||||||
|
return [
|
||||||
|
"# Lizenz",
|
||||||
|
"",
|
||||||
|
`Copyright (c) ${year} ${holder}`,
|
||||||
|
"",
|
||||||
|
"Alle Rechte vorbehalten.",
|
||||||
|
"",
|
||||||
|
"Diese Software und der zugehörige Quellcode sind urheberrechtlich geschützt.",
|
||||||
|
"Kein Teil dieser Software darf ohne vorherige ausdrückliche schriftliche",
|
||||||
|
"Genehmigung des Rechteinhabers kopiert, verändert, weitergegeben, veröffentlicht,",
|
||||||
|
"unterlizenziert oder anderweitig genutzt werden.",
|
||||||
|
"",
|
||||||
|
"DIE SOFTWARE WIRD OHNE MÄNGELGEWÄHR UND OHNE JEGLICHE AUSDRÜCKLICHE ODER",
|
||||||
|
"KONKLUDENTE GEWÄHRLEISTUNG BEREITGESTELLT. DER RECHTEINHABER HAFTET NICHT FÜR",
|
||||||
|
"SCHÄDEN, DIE AUS DER NUTZUNG DIESER SOFTWARE ENTSTEHEN.",
|
||||||
|
""
|
||||||
|
].join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legt LICENCE.md mit der proprietären Default-Lizenz an — nur wenn noch keine existiert
|
||||||
|
// (eine vorhandene Lizenz wird nie überschrieben). Inhaber aus 'git config user.name',
|
||||||
|
// sonst Platzhalter; Jahr aus dem aktuellen Datum.
|
||||||
|
async function writeLicenceMd(pi: ExtensionAPI, ctx: ExtensionCommandContext): Promise<void> {
|
||||||
|
const check = await pi.exec("bash", ["-c", "test -f LICENCE.md && echo exists"], { cwd: ctx.cwd });
|
||||||
|
if (check.stdout.trim() === "exists") {
|
||||||
|
ctx.ui.notify("LICENCE.md existiert bereits — unverändert.", "info");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const who = await pi.exec("bash", ["-c", "git config user.name 2>/dev/null"], { cwd: ctx.cwd });
|
||||||
|
const holder = who.stdout.trim() || "[Rechteinhaber eintragen]";
|
||||||
|
const year = String(new Date().getFullYear());
|
||||||
|
// content als Argument ($1), nicht interpoliert — kein Shell-Escaping-Problem.
|
||||||
|
await pi.exec("bash", ["-c", `printf "%s" "$1" > LICENCE.md`, "_", licenceMd(year, holder)], { cwd: ctx.cwd });
|
||||||
|
ctx.ui.notify(`LICENCE.md angelegt (proprietär, © ${year} ${holder}).`, "info");
|
||||||
|
}
|
||||||
|
|
||||||
// Legt TASK.md neu an oder hängt einen Zusatzauftrag an.
|
// Legt TASK.md neu an oder hängt einen Zusatzauftrag an.
|
||||||
async function writeTaskMd(
|
async function writeTaskMd(
|
||||||
pi: ExtensionAPI,
|
pi: ExtensionAPI,
|
||||||
|
|
@ -703,10 +742,18 @@ async function runUpdateDoku(pi: ExtensionAPI, ctx: ExtensionCommandContext): Pr
|
||||||
ctx.ui.notify(`3/3 BEDIENUNGSANLEITUNG.md fehlgeschlagen: ${String(e?.message ?? e)}`, "error");
|
ctx.ui.notify(`3/3 BEDIENUNGSANLEITUNG.md fehlgeschlagen: ${String(e?.message ?? e)}`, "error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LICENCE.md: deterministisch anlegen (nur wenn nicht vorhanden) — kein LLM.
|
||||||
|
try {
|
||||||
|
ctx.ui.setStatus("update_doku", "LICENCE.md wird geprüft…");
|
||||||
|
await writeLicenceMd(pi, ctx);
|
||||||
|
} catch (e: any) {
|
||||||
|
ctx.ui.notify(`LICENCE.md fehlgeschlagen: ${String(e?.message ?? e)}`, "error");
|
||||||
|
}
|
||||||
|
|
||||||
// Abschließender Dokumentations-Commit (immer, auch bei Teilfehlern)
|
// Abschließender Dokumentations-Commit (immer, auch bei Teilfehlern)
|
||||||
await pi.exec(
|
await pi.exec(
|
||||||
"bash",
|
"bash",
|
||||||
["-c", "git add -A && git commit -m 'docs: update comments, README, BEDIENUNGSANLEITUNG' || true"],
|
["-c", "git add -A && git commit -m 'docs: update comments, README, BEDIENUNGSANLEITUNG, LICENCE' || true"],
|
||||||
{ cwd: ctx.cwd }
|
{ cwd: ctx.cwd }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1331,7 +1378,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
if (withDoku) {
|
if (withDoku) {
|
||||||
await runUpdateDoku(pi, ctx);
|
await runUpdateDoku(pi, ctx);
|
||||||
} else {
|
} else {
|
||||||
ctx.ui.notify("Nächster Schritt: /update_doku für Code-Kommentare, README.md und BEDIENUNGSANLEITUNG.md", "info");
|
ctx.ui.notify("Nächster Schritt: /update_doku für Code-Kommentare, README.md, BEDIENUNGSANLEITUNG.md und LICENCE.md", "info");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|
@ -1387,7 +1434,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
// ── Dokumentations-Phase ─────────────────────────────────────────────────
|
// ── Dokumentations-Phase ─────────────────────────────────────────────────
|
||||||
|
|
||||||
pi.registerCommand("update_doku", {
|
pi.registerCommand("update_doku", {
|
||||||
description: "Inkrementelle Code-Kommentare + README.md + BEDIENUNGSANLEITUNG.md via Git-Tags.",
|
description: "Inkrementelle Code-Kommentare + README.md + BEDIENUNGSANLEITUNG.md via Git-Tags; legt LICENCE.md an (proprietär, falls fehlend).",
|
||||||
handler: async function (_args: string, ctx: ExtensionCommandContext) {
|
handler: async function (_args: string, ctx: ExtensionCommandContext) {
|
||||||
await runUpdateDoku(pi, ctx);
|
await runUpdateDoku(pi, ctx);
|
||||||
}
|
}
|
||||||
|
|
@ -1484,7 +1531,7 @@ export default function (pi: ExtensionAPI) {
|
||||||
"/patch <änderung> Gezielte Minimaländerung → Coder",
|
"/patch <änderung> Gezielte Minimaländerung → Coder",
|
||||||
"/quick_check [was] Schnelle OK/PROBLEM-Prüfung → Judge",
|
"/quick_check [was] Schnelle OK/PROBLEM-Prüfung → Judge",
|
||||||
"/plan <auftrag> Implementierungsplan in PLAN.md → Coder",
|
"/plan <auftrag> Implementierungsplan in PLAN.md → Coder",
|
||||||
"/update_doku Code-Kommentare + README.md + BEDIENUNGSANLEITUNG.md",
|
"/update_doku Code-Kommentare + README.md + BEDIENUNGSANLEITUNG.md + LICENCE.md",
|
||||||
"/version Versionsnummer erhöhen (SemVer + Git-Tag)",
|
"/version Versionsnummer erhöhen (SemVer + Git-Tag)",
|
||||||
"/discard Verwirft PLAN.md",
|
"/discard Verwirft PLAN.md",
|
||||||
"/new_project <pfad> Projektverzeichnis + git init + .gitignore",
|
"/new_project <pfad> Projektverzeichnis + git init + .gitignore",
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,17 @@ test("Loop-Erkennung greift auch ohne Blocker-Abschnitt (Fallback auf Gesamttext
|
||||||
test("currentRole wird nach jedem optimize-Lauf auf 'coder' zurückgesetzt", () => {
|
test("currentRole wird nach jedem optimize-Lauf auf 'coder' zurückgesetzt", () => {
|
||||||
assert.match(extSource, /currentRole\s*=\s*"coder"/);
|
assert.match(extSource, /currentRole\s*=\s*"coder"/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("LICENCE.md: deterministisch in der Doku-Phase, nur wenn nicht vorhanden, proprietär", () => {
|
||||||
|
assert.match(extSource, /function licenceMd\b/);
|
||||||
|
assert.match(extSource, /async function writeLicenceMd\b/);
|
||||||
|
// wird in runUpdateDoku aufgerufen
|
||||||
|
assert.match(extSource, /await writeLicenceMd\(pi, ctx\)/);
|
||||||
|
// existierende Lizenz wird nicht überschrieben
|
||||||
|
assert.match(extSource, /test -f LICENCE\.md/);
|
||||||
|
// proprietärer Default
|
||||||
|
assert.match(extSource, /Alle Rechte vorbehalten/);
|
||||||
|
// Inhaber aus git config, Jahr aus aktuellem Datum
|
||||||
|
assert.match(extSource, /git config user\.name/);
|
||||||
|
assert.match(extSource, /new Date\(\)\.getFullYear\(\)/);
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { extractFn } from "./helpers.mjs";
|
||||||
const parseVerdict = extractFn("parseVerdict");
|
const parseVerdict = extractFn("parseVerdict");
|
||||||
const parseBlockers = extractFn("parseBlockers");
|
const parseBlockers = extractFn("parseBlockers");
|
||||||
const normalizeForComparison = extractFn("normalizeForComparison");
|
const normalizeForComparison = extractFn("normalizeForComparison");
|
||||||
|
const licenceMd = extractFn("licenceMd");
|
||||||
|
|
||||||
test("parseVerdict: klares PASS", () => {
|
test("parseVerdict: klares PASS", () => {
|
||||||
assert.equal(parseVerdict("Review fertig.\nUrteil: PASS\nKeine Blocker."), "PASS");
|
assert.equal(parseVerdict("Review fertig.\nUrteil: PASS\nKeine Blocker."), "PASS");
|
||||||
|
|
@ -64,3 +65,16 @@ test("normalizeForComparison: gleiche Blocker trotz Formatierungsunterschied →
|
||||||
normalizeForComparison(b)
|
normalizeForComparison(b)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("licenceMd: proprietärer Default mit eingesetztem Jahr und Inhaber", () => {
|
||||||
|
const txt = licenceMd("2026", "Dieter Schlüter");
|
||||||
|
assert.match(txt, /^# Lizenz/);
|
||||||
|
assert.match(txt, /Copyright \(c\) 2026 Dieter Schlüter/);
|
||||||
|
assert.match(txt, /Alle Rechte vorbehalten\./);
|
||||||
|
assert.match(txt, /ohne vorherige ausdrückliche schriftliche/);
|
||||||
|
assert.match(txt, /OHNE MÄNGELGEWÄHR/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("licenceMd: Platzhalter-Inhaber wird unverändert eingesetzt", () => {
|
||||||
|
assert.match(licenceMd("2030", "[Rechteinhaber eintragen]"), /Copyright \(c\) 2030 \[Rechteinhaber eintragen\]/);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue