Orchestrator-Skill: Werkstatt zum Fliessband verallgemeinert (zerlegen -> delegieren -> Zwei-Kritiker-Gate -> Vorschlag)
- deploy/worker.sh: Ein-Schuss-Arbeitsauftrag an ein Worker-Modell (Gegenstueck zu fremdblick.sh), Fence-Strip + Aufruf-Log (Delegations-Nachweis); v1 nur Coder-Next (heavy stirbt neben dem Warm-Set). - deploy/skills/orchestrator/SKILL.md: Manager-Drehbuch, propose-only, Warm-Set-Schutz, Delegations-Pflicht + Evidenz, stage-vor-Diff, Zwei-Kritiker-Gate (Coder-Next Kompetenz + GLM Fremd-Blick). - deploy/deploy.sh: worker.sh + orchestrator-Skill mit ausrollen. E2E gegen die Box verifiziert (worker.log-belegte Delegation, Self-Gate + Zwei-Kritiker-Gate, propose-only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+6
-1
@@ -77,10 +77,15 @@ cp "$SRC/deploy/selbstkritik-feed.sh" "$HOME/.hermes/scripts/selbstkritik-feed.s
|
|||||||
cp "$SRC/deploy/dreaming-feed.sh" "$HOME/.hermes/scripts/dreaming-feed.sh"
|
cp "$SRC/deploy/dreaming-feed.sh" "$HOME/.hermes/scripts/dreaming-feed.sh"
|
||||||
# Fremdblick-Helfer: Ein-Schuss-Zweitmeinung von einem anderen Modell (umgeht 64K-Delegations-Floor).
|
# Fremdblick-Helfer: Ein-Schuss-Zweitmeinung von einem anderen Modell (umgeht 64K-Delegations-Floor).
|
||||||
cp "$SRC/deploy/fremdblick.sh" "$HOME/.hermes/scripts/fremdblick.sh"
|
cp "$SRC/deploy/fremdblick.sh" "$HOME/.hermes/scripts/fremdblick.sh"
|
||||||
chmod +x "$HOME/.hermes/scripts/fremdblick.sh" "$HOME/.hermes/scripts/dreaming-feed.sh"
|
# Worker-Helfer (Orchestrator): Ein-Schuss-Arbeitsauftrag an ein Worker-Modell (Gegenstück zu fremdblick).
|
||||||
|
cp "$SRC/deploy/worker.sh" "$HOME/.hermes/scripts/worker.sh"
|
||||||
|
chmod +x "$HOME/.hermes/scripts/fremdblick.sh" "$HOME/.hermes/scripts/dreaming-feed.sh" "$HOME/.hermes/scripts/worker.sh"
|
||||||
# Werkstatt-Skill (Autonomie E6): Selbstwartungs-Kreislauf für Hermes.
|
# Werkstatt-Skill (Autonomie E6): Selbstwartungs-Kreislauf für Hermes.
|
||||||
mkdir -p "$HOME/.hermes/skills/wartung"
|
mkdir -p "$HOME/.hermes/skills/wartung"
|
||||||
cp "$SRC/deploy/skills/wartung/SKILL.md" "$HOME/.hermes/skills/wartung/SKILL.md"
|
cp "$SRC/deploy/skills/wartung/SKILL.md" "$HOME/.hermes/skills/wartung/SKILL.md"
|
||||||
|
# Orchestrator-Skill (Autonomie): Werkstatt verallgemeinert — zerlegen → an Worker delegieren → gaten.
|
||||||
|
mkdir -p "$HOME/.hermes/skills/orchestrator"
|
||||||
|
cp "$SRC/deploy/skills/orchestrator/SKILL.md" "$HOME/.hermes/skills/orchestrator/SKILL.md"
|
||||||
systemctl --user daemon-reload
|
systemctl --user daemon-reload
|
||||||
systemctl --user enable mission-control-2 >/dev/null 2>&1 || true
|
systemctl --user enable mission-control-2 >/dev/null 2>&1 || true
|
||||||
systemctl --user enable hermes-terminal >/dev/null 2>&1 || true
|
systemctl --user enable hermes-terminal >/dev/null 2>&1 || true
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
---
|
||||||
|
name: orchestrator
|
||||||
|
description: "Orchestrieren wie ein Manager: einen groesseren Auftrag in Teil-Tasks zerlegen, jeden SERIELL an das passende Worker-Modell delegieren (worker.sh, Ein-Schuss via llama-swap), die Ergebnisse einsammeln + zusammensetzen, per Fremd-Kritiker gaten und als Telegram-Vorschlag zurueckgeben. NIE selbst mergen/deployen — der Commander ist das Gate."
|
||||||
|
version: 1.0.0
|
||||||
|
author: MC2 (Autonomie — Orchestrator)
|
||||||
|
platforms: [linux]
|
||||||
|
metadata:
|
||||||
|
hermes:
|
||||||
|
tags: [orchestrator, delegation, werkstatt, mc2, fliessband]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Orchestrator — du managst, du fuehrst nicht alles selbst aus
|
||||||
|
|
||||||
|
Nutze diesen Skill, wenn ein Auftrag zu gross fuer EINEN Rutsch ist, sich aber in wenige klar
|
||||||
|
abgegrenzte Teil-Tasks zerlegen laesst (ueberwiegend Code-Bau). Du bist der **Manager**: du
|
||||||
|
zerlegst, verteilst die Teile SERIELL an Worker-Modelle (die arbeiten), fuegst die Ergebnisse
|
||||||
|
zusammen und lieferst am Ende einen **Vorschlag** — der Commander entscheidet.
|
||||||
|
|
||||||
|
Das ist die Verallgemeinerung der **Werkstatt** (`wartung`): dort delegierst du EINEN Schritt
|
||||||
|
(Code-Review) an ein Fremdmodell. Hier delegierst du MEHRERE Bau-Schritte an Worker und behaeltst
|
||||||
|
die Integration + das Gate.
|
||||||
|
|
||||||
|
## Warum seriell (und warum das ok ist)
|
||||||
|
Mehrere grosse Modelle GLEICHZEITIG passen nicht in den Speicher. llama-swap ist **seriell** — ein
|
||||||
|
Modell laden → arbeiten → tauschen → naechstes. Orchestrierung ist ein **Fliessband, kein Schwarm.**
|
||||||
|
Langsamer (Swap-Latenz + einer nach dem anderen: Minuten), aber bei Hintergrund-/Telegram-Jobs egal.
|
||||||
|
|
||||||
|
## Scope-Check zuerst (klein anfangen)
|
||||||
|
Passt: ein Auftrag, der in **2–4 abgegrenzte Teil-Tasks** zerfaellt, jeder ein 1–2-Datei-Bau-Schritt
|
||||||
|
(neues kleines Modul + Test, kleine neue Funktion + Verdrahtung, zusammenhaengender Refactor in
|
||||||
|
wenigen Dateien). Zu gross (viele Module, echte Architektur-Entscheidungen, breite API-Aenderung):
|
||||||
|
dann NUR einen **Plan** als Text im Telegram-Vorschlag liefern, KEINEN Code — der Commander schneidet
|
||||||
|
dann kleiner.
|
||||||
|
|
||||||
|
## Leitplanken (nicht verhandelbar)
|
||||||
|
- **Du delegierst, du baust NICHT selbst.** Jedes Bau-Artefakt MUSS aus einem `worker.sh`-Aufruf
|
||||||
|
stammen. Schreibst du den Code selbst (auch wenn der Teil-Task „einfach genug" wirkt), statt ihn
|
||||||
|
vom Worker zu holen, ist der Lauf GESCHEITERT — sag das ehrlich, statt Eigenbau als Orchestrierung
|
||||||
|
auszugeben. Belege jeden Teil-Task im Vorschlag mit dem `worker.sh`-Aufruf UND den ersten Zeilen
|
||||||
|
seiner Roh-Ausgabe. (Warum so streng: das Manager-Modell kann kleine Tasks selbst — genau dann
|
||||||
|
faellt Delegation aus Bequemlichkeit weg; das ist der haeufigste Orchestrierungs-Fehler.)
|
||||||
|
- **Die Helfer EXISTIEREN.** `~/.hermes/scripts/worker.sh` und `~/.hermes/scripts/fremdblick.sh`
|
||||||
|
sind installiert, aber NICHT auf deinem PATH → immer mit vollem Pfad aufrufen (nie bloss `worker.sh`).
|
||||||
|
Glaubst du, sie fehlen, IRRST du dich: erst `ls -la ~/.hermes/scripts/worker.sh` ausfuehren und den
|
||||||
|
Pfad lesen, dann nutzen. „Skript fehlt" ist KEIN gueltiger Grund, den Schritt selbst zu machen.
|
||||||
|
- **Propose-only.** Am Ende steht IMMER ein Telegram-Vorschlag; die Entscheidung trifft der Commander.
|
||||||
|
NIEMALS auf `main` committen, NIEMALS mergen, NIEMALS deployen oder Dienste neu starten.
|
||||||
|
- **Nur im Worktree arbeiten.** Die Live-Instanz `~/mission-control-v2` bleibt unberuehrt.
|
||||||
|
- **Warm-Set-Schutz (harte Speicher-Falle).** Worker nur ueber **`worker.sh`** und nur Modelle, die
|
||||||
|
KLEIN neben dem Warm-Set laden — v1 = **`Qwen3-Coder-Next`** (Default in worker.sh). **NIEMALS
|
||||||
|
`heavy`/`gpt-oss-120b` als Worker** (60 GB → stirbt neben dem VL-30B-Warm-Set, gefaehrdet Lucys
|
||||||
|
~1-s-Sprech-Latenz). Planung/Zerlegung/Integration machst DU (Hermes, schon warm) selbst.
|
||||||
|
- **Fremd-Kritiker ist Pflicht-Gate.** Der zusammengesetzte Diff MUSS von `fremdblick.sh` (anderes
|
||||||
|
Modell) gegengelesen werden, bevor du vorschlaegst. Ein Manager, der Worker-Output blind
|
||||||
|
zusammenklebt, produziert leisen Muell.
|
||||||
|
- **Security-Config ist TABU:** keine Tokens, approvals, ufw, sudoers, ssh-Keys anfassen.
|
||||||
|
- Gate rot oder Kritiker dagegen → trotzdem ehrlich melden (Branch bleibt liegen), nichts beschoenigen.
|
||||||
|
|
||||||
|
## Ablauf
|
||||||
|
|
||||||
|
### 1. Zerlegen (der Manager denkt)
|
||||||
|
Brich den Auftrag in eine **geordnete, nummerierte Liste von Teil-Tasks**. Fuer jeden Teil-Task
|
||||||
|
entscheide: (a) was ist das Artefakt (welche Datei, was tut sie), (b) welches Worker-Modell +
|
||||||
|
welche Rolle (`build`/`refactor`), (c) welchen Kontext braucht der Worker (siehe Abschnitt
|
||||||
|
„Kontext-Uebergabe"). Halte die Liste kurz. Reihe die Teile so, dass spaetere auf fertige
|
||||||
|
fruehere aufbauen koennen.
|
||||||
|
|
||||||
|
### 2. Worktree anlegen (Slug = kurzer Kebab-Case-Name des Auftrags)
|
||||||
|
```
|
||||||
|
cd ~/mission-control-v2 && git fetch -q origin \
|
||||||
|
&& git worktree add /tmp/orch-<slug> -b orchestrator/<slug> origin/main
|
||||||
|
mkdir -p /tmp/orch-<slug>-work # Ablage fuer rohe Worker-Ausgaben
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Routen — je Teil-Task ein Worker-Ein-Schuss (seriell)
|
||||||
|
Fuer jeden Bau-Teil-Task:
|
||||||
|
1. Baue die Eingabe: **genau der noetige Kontext** + der praezise Auftrag (siehe unten). Bereits
|
||||||
|
fertige Artefakte aus frueheren Schritten als Kontext mitgeben, wenn der Worker sie braucht.
|
||||||
|
2. Ruf den Worker auf und fang die Ausgabe roh ab:
|
||||||
|
```
|
||||||
|
printf '%s' "$eingabe" | WORKER_ROLE=build ~/.hermes/scripts/worker.sh > /tmp/orch-<slug>-work/<n>.out
|
||||||
|
```
|
||||||
|
(Default-Modell ist `Qwen3-Coder-Next`. Fuer einen bewusst anderen Worker `WORKER_MODEL=<echte-id>`.)
|
||||||
|
3. **Pruefe die Ausgabe, bevor du sie verwendest:** Beginnt sie mit `FEHLT:`, hast du zu wenig
|
||||||
|
Kontext gegeben → nachliefern und erneut rufen. Hat der Worker versehentlich einen ```-Codezaun
|
||||||
|
oder Prosa drumherum gesetzt, entferne ihn. Dann schreibe das saubere Artefakt mit deinen
|
||||||
|
Datei-Tools an seinen Platz im Worktree (`/tmp/orch-<slug>/...`). Der Worker hat KEINE
|
||||||
|
Datei-Haende — das Schreiben machst DU.
|
||||||
|
|
||||||
|
### 4. Integrieren + Self-Gate (nach jedem Schritt bzw. am Ende)
|
||||||
|
Die Worker liefern Bausteine — DU sorgst dafuer, dass sie zusammenpassen (Imports, Verdrahtung,
|
||||||
|
Namen). Dann das Selbst-Gate, was zutrifft:
|
||||||
|
- Python geaendert → `python3 -m py_compile <dateien>` (und wenn ein Test dabei ist und ohne
|
||||||
|
schwere Deps laeuft: den Test im Worktree ausfuehren).
|
||||||
|
- Shell geaendert → `bash -n <dateien>`
|
||||||
|
- Frontend (`frontend/src/...`) → auf der Box gibt es KEIN Node. Im Vorschlag ausweisen:
|
||||||
|
„Gate eingeschraenkt: tsc/Build laeuft erst beim Merge auf dem PC."
|
||||||
|
- **Live-Checkout unberuehrt (PFLICHT, zwei Beweise):**
|
||||||
|
- `git -C ~/mission-control-v2 status --porcelain -uno` **muss LEER sein** (Beweis, dass du
|
||||||
|
wirklich nur im Worktree gearbeitet hast — ein gruener Health-curl allein reicht NICHT, weil
|
||||||
|
der laufende Dienst den alten Code im RAM haelt und eine schmutzige Datei auf der Platte nicht
|
||||||
|
bemerkt).
|
||||||
|
- `curl -sf http://127.0.0.1:9001/api/health` muss gruen bleiben.
|
||||||
|
- Ist `git status` NICHT leer: die fremden Aenderungen im Live-Checkout mit
|
||||||
|
`git -C ~/mission-control-v2 checkout -- <datei>` zuruecknehmen (deine Arbeit liegt sicher im
|
||||||
|
Worktree) und im Vorschlag ehrlich erwaehnen.
|
||||||
|
|
||||||
|
### 5. Zwei-Kritiker-Gate ueber den GESAMTEN Diff (Pflicht)
|
||||||
|
Zwei Zweitgutachter mit je anderer Staerke lesen den zusammengesetzten Diff gegen — aus demselben
|
||||||
|
Grund wie in der Werkstatt („wer seine eigenen Hausaufgaben benotet, stimmt sich selbst zu"). **NICHT
|
||||||
|
`delegate_task`** (laeuft ueber `heavy` → 64K-Floor + Warm-Set-Kollision).
|
||||||
|
|
||||||
|
**Zuerst ALLES stagen** — sonst fehlen NEUE Dateien im Diff (haeufigste Falle: `git diff` ignoriert
|
||||||
|
untracked Dateien, die Kritiker bekaemen einen LEEREN Diff und wuerden alles blind ablehnen):
|
||||||
|
```
|
||||||
|
git -C /tmp/orch-<slug> add -A
|
||||||
|
```
|
||||||
|
Dann die Eingabe EINMAL bauen (mit `--cached`, damit die neuen Dateien drin sind):
|
||||||
|
```
|
||||||
|
EINGABE="AUFTRAG (im Wortlaut):
|
||||||
|
<der urspruengliche Auftrag>
|
||||||
|
|
||||||
|
ZERLEGUNG (deine Teil-Tasks, je 1 Zeile):
|
||||||
|
<1..n>
|
||||||
|
|
||||||
|
GIT-DIFF des Worktrees:
|
||||||
|
$(git -C /tmp/orch-<slug> diff --cached origin/main)"
|
||||||
|
```
|
||||||
|
Ist dieser Diff LEER, hast du nicht gestaged (oder nichts gebaut) → NICHT weiter, erst beheben.
|
||||||
|
**Kritik A — Kompetenz** (`Qwen3-Coder-Next`, starker Coder, vom Bauen noch geladen → KEIN Swap):
|
||||||
|
```
|
||||||
|
printf '%s' "$EINGABE" | FREMDBLICK_MODE=code ~/.hermes/scripts/fremdblick.sh
|
||||||
|
```
|
||||||
|
**Kritik B — Fremd-Blick** (`GLM-4.6V-Flash`, andere Modellfamilie, andere blinde Flecken):
|
||||||
|
```
|
||||||
|
printf '%s' "$EINGABE" | FREMDBLICK_MODE=code FREMDBLICK_MODEL=GLM-4.6V-Flash FREMDBLICK_MAXTOK=3000 ~/.hermes/scripts/fremdblick.sh
|
||||||
|
```
|
||||||
|
Reihenfolge bewusst: erst A (Coder-Next ist noch warm), dann B (ein Swap zu GLM). Beide beginnen mit
|
||||||
|
`URTEIL: <ABGELEHNT | FREIGABE-MIT-VORBEHALT | FREIGABE>`. **Warte auf beide.**
|
||||||
|
|
||||||
|
**Gate-Regel (streng):** Sagt AUCH NUR EINER `ABGELEHNT` → nachbessern (max. 2 Runden: den
|
||||||
|
betroffenen Teil-Task neu an den Worker, integrieren, BEIDE Kritiker erneut). `FREIGABE-MIT-VORBEHALT`
|
||||||
|
→ die Vorbehalte adressieren oder im Vorschlag ehrlich ausweisen (NICHT wegdiskutieren). Nur wenn
|
||||||
|
BEIDE tragen → Vorschlag. Beide Urteile KONKRET in den Vorschlag (welcher Kritiker was sagte). Faellt
|
||||||
|
ein Kritiker technisch aus (`FEHLGESCHLAGEN`/`ABGESCHNITTEN`) → einmal wiederholen, sonst „⚠ Kritik X
|
||||||
|
fiel aus" vermerken (NICHT als Freigabe zaehlen).
|
||||||
|
|
||||||
|
> Der schwere **Chef-Gutachter (`gpt-oss`)** laeuft NICHT in diesem heissen Pfad — er muesste 60 GB
|
||||||
|
> kalt laden und Lucys Warm-Set stoeren. Er prueft separat NACHTS im Leerlauf ueber die offenen
|
||||||
|
> Orchestrator-Vorschlaege (eigener Cron), wo Ladezeit + Warm-Set-Umbau verkraftbar sind.
|
||||||
|
- `ABGELEHNT` / berechtigte `FREIGABE-MIT-VORBEHALT` → nachbessern (max. 2 Runden: den betroffenen
|
||||||
|
Teil-Task neu an den Worker geben, integrieren, erneut gaten). Bleibt es kritisch: Kritik in den
|
||||||
|
Vorschlag schreiben, Branch bleibt liegen, Entscheidung dem Commander.
|
||||||
|
- `FREMDBLICK FEHLGESCHLAGEN`/`ABGESCHNITTEN` → einmal wiederholen; sonst im Vorschlag ehrlich
|
||||||
|
„⚠ Fremd-Review fiel aus — UNGEPRUEFT" vermerken (NICHT als Freigabe behandeln).
|
||||||
|
|
||||||
|
### 6. Telegram-Vorschlag (in LUCYS Stimme)
|
||||||
|
`bash ~/mission-control-v2/deploy/notify.sh -s "[Orchestrator]" "<text>"` — an den Commander, nicht
|
||||||
|
als anonymer Job: erst 1–2 Saetze, was gebaut wurde und was er jetzt entscheiden soll; dann knapp:
|
||||||
|
- die **Zerlegung** (welcher Teil-Task an welches Worker-Modell ging),
|
||||||
|
- geaenderte/neue Dateien · Kern des Diffs,
|
||||||
|
- Self-Gate-Ergebnis · Kritiker-Urteil KONKRET ausgeschrieben (nicht nur „ok"),
|
||||||
|
- Branch-Name · Frage „merge oder verwerfen?"
|
||||||
|
|
||||||
|
### 7. Nichts loeschen
|
||||||
|
Worktree + Branch + rohe Worker-Ausgaben bleiben liegen, bis der Commander entschieden hat.
|
||||||
|
|
||||||
|
## Kontext-Uebergabe — hier geht Orchestrierung am ehesten schief
|
||||||
|
Jeder Worker startet **frisch und zustandslos**: kein Gedaechtnis der bisherigen Schritte, kein
|
||||||
|
Zugriff aufs Repo. Er sieht NUR, was du ihm auf stdin gibst. Deshalb:
|
||||||
|
- Gib ihm den **relevanten Ausschnitt** mit — die betroffene Datei (oder den betroffenen Block),
|
||||||
|
benachbarte Muster zum Nachahmen, die genaue Signatur/den Namen, den er treffen muss, und bei
|
||||||
|
Folge-Schritten die bereits fertigen Artefakte, auf die er aufbaut.
|
||||||
|
- Sei praezise beim Zielartefakt: „Gib den VOLLSTAENDIGEN Inhalt der neuen Datei `X` aus" bzw. „Gib
|
||||||
|
einen unified Diff gegen den folgenden Stand von `Y` aus".
|
||||||
|
- Zu wenig Kontext → der Worker raet oder meldet `FEHLT:`. Zu viel unnoetiger Kontext → er verliert
|
||||||
|
den Fokus. Ziel: das kleinste, das den Teil-Task eindeutig macht.
|
||||||
|
|
||||||
|
## Nach dem Commander-Entscheid (kommt als neuer Auftrag)
|
||||||
|
- „verwerfen" → `git worktree remove /tmp/orch-<slug> --force && git branch -D orchestrator/<slug>`
|
||||||
|
(+ `rm -rf /tmp/orch-<slug>-work`; Remote-Branch loeschen, falls gepusht).
|
||||||
|
- „merge" → das Mergen nach main + Deploy macht der PC/Claude (Frontend-Builds gibt es nur dort).
|
||||||
|
Du pushst NIE nach main.
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Worker — Ein-Schuss-Arbeitsauftrag an ein bestimmtes Worker-Modell (llama-swap, SERIELL).
|
||||||
|
# Das Gegenstueck zu fremdblick.sh: fremdblick KRITISIERT, worker ARBEITET. Beide sind eine
|
||||||
|
# EINZELNE Completion an eine ECHTE llama-swap-Modell-ID (kein Gateway-Alias, kein delegate_task)
|
||||||
|
# → umgeht Hermes' 64K-Delegations-Floor (MINIMUM_CONTEXT_LENGTH) und das Laden grosser Modelle
|
||||||
|
# neben dem Warm-Set liegt bewusst in DEINER Hand.
|
||||||
|
#
|
||||||
|
# WICHTIG (harte Speicher-Falle): Waehle nur Worker, die KLEIN neben dem Warm-Set laden.
|
||||||
|
# v1-Palette = Qwen3-Coder-Next (128k, code-stark, laedt klein). NIEMALS "heavy"/gpt-oss-120b
|
||||||
|
# als Worker: 60 GB stirbt beim Laden neben dem VL-30B-Warm-Set (Health-Check-Timeout) und
|
||||||
|
# gefaehrdet Lucys ~1-s-Sprech-Latenz.
|
||||||
|
#
|
||||||
|
# Der Worker ist ZUSTANDSLOS: kein Gedaechtnis, keine Datei-Haende. Er bekommt GENAU den Kontext,
|
||||||
|
# den du ihm auf stdin gibst, und liefert TEXT zurueck (Datei-Inhalt / Diff / Plan). Das SCHREIBEN
|
||||||
|
# in Dateien macht der Manager (Hermes) danach mit seinen eigenen Tools.
|
||||||
|
#
|
||||||
|
# Nutzung: printf '%s' "$teiltask_mit_kontext" | WORKER_ROLE=build worker.sh > /tmp/out.py
|
||||||
|
# printf '%s' "$spec" | WORKER_MODEL=Qwen3-Coder-Next WORKER_ROLE=build worker.sh
|
||||||
|
#
|
||||||
|
# Env-Overrides:
|
||||||
|
# WORKER_MODEL echte llama-swap-ID (Default: Qwen3-Coder-Next). NICHT gpt-oss/heavy (siehe oben).
|
||||||
|
# WORKER_ROLE build (Default) | refactor | plan | prose — waehlt das System-Raster.
|
||||||
|
# WORKER_SYS eigenes System-Raster (uebersteuert WORKER_ROLE).
|
||||||
|
# WORKER_MAXTOK max_tokens (Default 4000 — Code braucht Platz).
|
||||||
|
# WORKER_TEMP temperature (Default 0.1 — deterministisch fuer Code).
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
# Achtung: llama-swap listet unter /v1/models die ECHTEN Modell-IDs, nicht die Gateway-Aliase
|
||||||
|
# (kein "heavy"/"coder"/"scout" hier — die echte ID nehmen).
|
||||||
|
ENDPOINT="${WORKER_ENDPOINT:-http://127.0.0.1:8080/v1/chat/completions}"
|
||||||
|
MODEL="${WORKER_MODEL:-Qwen3-Coder-Next}"
|
||||||
|
ROLE="${WORKER_ROLE:-build}"
|
||||||
|
MAXTOK="${WORKER_MAXTOK:-4000}"
|
||||||
|
TEMP="${WORKER_TEMP:-0.1}"
|
||||||
|
TASK="$(cat)"
|
||||||
|
|
||||||
|
if [ -z "${TASK// /}" ]; then
|
||||||
|
echo "=== WORKER: nichts zu tun (leere Eingabe) ===" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Aufruf-Protokoll: Nachweis, dass wirklich delegiert wurde (der Manager kann sich das nicht
|
||||||
|
# ausdenken) + Beobachtbarkeit eines Orchestrator-Laufs. Best-effort, blockiert nie.
|
||||||
|
LOGF="${WORKER_LOG:-$HOME/.hermes/logs/worker.log}"
|
||||||
|
mkdir -p "$(dirname "$LOGF")" 2>/dev/null || true
|
||||||
|
printf '%s\tmodel=%s\trole=%s\tbytes=%s\tfirst=%s\n' \
|
||||||
|
"$(date +%Y-%m-%dT%H:%M:%S)" "$MODEL" "$ROLE" "${#TASK}" \
|
||||||
|
"$(printf '%s' "$TASK" | tr '\n\t' ' ' | cut -c1-90)" >> "$LOGF" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Bau-Raster: liefert NUR das Artefakt, keine Prosa, kein Markdown-Zaun (Manager schreibt es 1:1 in eine Datei).
|
||||||
|
BUILD_SYS='Du bist ein fokussierter Umsetzungs-Worker in einem Fliessband. Du bekommst EINEN abgegrenzten Teil-Auftrag mit allem noetigen Kontext. Erledige GENAU diesen Teil — nicht mehr, nicht weniger. Du bist ZUSTANDSLOS: nutze NUR den mitgelieferten Kontext, erfinde keine Datei-Inhalte, keine Pfade und keine APIs dazu; fehlt dir etwas Entscheidendes, schreibe als EINZIGE Ausgabe eine Zeile "FEHLT: <was genau>" statt zu raten. Uebernimm den Stil des umgebenden Codes (Sprache der Kommentare, bestehende Muster, Einrueckung). Gib NUR das geforderte Artefakt aus (den vollstaendigen Datei-Inhalt bzw. den unified Diff), OHNE Vorrede, OHNE ```-Codezaun, OHNE Erklaerung danach.'
|
||||||
|
# Refactor: wie build, aber betont Verhalten-erhalten.
|
||||||
|
REFACTOR_SYS='Du bist ein fokussierter Refactor-Worker. Du bekommst bestehenden Code und einen klaren Umbau-Auftrag. Erhalte das beobachtbare Verhalten exakt; aendere nur, was der Auftrag verlangt. Du bist ZUSTANDSLOS: nutze NUR den mitgelieferten Kontext; fehlt Entscheidendes, gib nur "FEHLT: <was>" aus. Gib NUR den vollstaendigen neuen Datei-Inhalt bzw. den Diff aus, OHNE Prosa, OHNE ```-Codezaun.'
|
||||||
|
# Plan-Raster: knappe, umsetzbare Schrittliste (kein Code). In v1 plant meist der Manager selbst; optional.
|
||||||
|
PLAN_SYS='Du bist ein knapper Umsetzungs-Planer. Zerlege den Auftrag in eine kurze, nummerierte Liste konkreter Schritte — je 1 Zeile: welche Datei, was passiert. Keine Prosa drumherum, KEIN Code, keine Alternativen-Diskussion.'
|
||||||
|
# Prosa-Raster: Text-/Recherche-Teiltask.
|
||||||
|
PROSE_SYS='Du bist ein fokussierter Text-Worker. Erledige den Schreib-/Recherche-Teilauftrag knapp und sachlich auf Deutsch, ausschliesslich mit dem mitgelieferten Kontext. Keine Ausschmueckung, keine erfundenen Fakten.'
|
||||||
|
|
||||||
|
case "$ROLE" in
|
||||||
|
build) SYS="${WORKER_SYS:-$BUILD_SYS}" ;;
|
||||||
|
refactor) SYS="${WORKER_SYS:-$REFACTOR_SYS}" ;;
|
||||||
|
plan) SYS="${WORKER_SYS:-$PLAN_SYS}" ;;
|
||||||
|
prose) SYS="${WORKER_SYS:-$PROSE_SYS}" ;;
|
||||||
|
*) SYS="${WORKER_SYS:-$BUILD_SYS}" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
RESP="$(jq -n --arg m "$MODEL" --arg s "$SYS" --arg u "$TASK" --argjson t "$MAXTOK" --argjson temp "$TEMP" \
|
||||||
|
'{model:$m, temperature:$temp, max_tokens:$t, messages:[{role:"system",content:$s},{role:"user",content:$u}]}' \
|
||||||
|
| curl -s --max-time 300 "$ENDPOINT" -H 'Content-Type: application/json' -d @- 2>/dev/null)"
|
||||||
|
|
||||||
|
OUT="$(printf '%s' "$RESP" | jq -r '.choices[0].message.content // empty' 2>/dev/null)"
|
||||||
|
FIN="$(printf '%s' "$RESP" | jq -r '.choices[0].finish_reason // empty' 2>/dev/null)"
|
||||||
|
|
||||||
|
# Code-Modelle wickeln die Ausgabe trotz Anweisung gern in einen ```-Codezaun. stdout soll aber ein
|
||||||
|
# DIREKT schreibbares Artefakt sein → einen umschliessenden Zaun entfernen (nur wenn die erste UND
|
||||||
|
# die letzte nicht-leere Zeile ein Zaun ist — der uebliche Wrap-Fall; interne Zaeune bleiben unberuehrt).
|
||||||
|
OUT="$(printf '%s' "$OUT" | awk '
|
||||||
|
{ l[NR]=$0 }
|
||||||
|
END {
|
||||||
|
f=0; last=0
|
||||||
|
for (i=1;i<=NR;i++) if (l[i] ~ /[^[:space:]]/) { if (!f) f=i; last=i }
|
||||||
|
if (f && l[f] ~ /^[[:space:]]*```/ && l[last] ~ /^[[:space:]]*```[[:space:]]*$/ && f!=last)
|
||||||
|
{ for (i=f+1;i<last;i++) print l[i] }
|
||||||
|
else
|
||||||
|
{ for (i=1;i<=NR;i++) print l[i] }
|
||||||
|
}')"
|
||||||
|
|
||||||
|
if [ -n "$OUT" ]; then
|
||||||
|
printf '%s\n' "$OUT"
|
||||||
|
# Abschneide-Warnung auf stderr (stdout bleibt sauberes Artefakt).
|
||||||
|
[ "$FIN" = "length" ] && echo "=== WORKER-HINWEIS: Ausgabe bei max_tokens ($MAXTOK) ABGESCHNITTEN — WORKER_MAXTOK erhoehen ODER den Teil-Task kleiner schneiden. ===" >&2
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "=== WORKER FEHLGESCHLAGEN (Modell $MODEL, finish=${FIN:-keins}) — kein Ergebnis. Endpoint/Modell-ID pruefen (echte /v1/models-ID, kein Alias). ===" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user