Commit Graph
43 Commits
Author SHA1 Message Date
elton 1f99b73161 Docker-Image, Compose-Demo mit ./data-Mount
Alle Laufzeitdateien (config, ACLs, keys, state, aa-cache, log) gehen über
den Mount ./data:/data, weil logDir und ACLs relativ zum CONFIG_PATH
aufgelöst werden. Ohne Keys startet der Router trotzdem, /health bleibt
bedienbar.
2026-09-08 09:48:13 +02:00
elton 3c0a8ead85 openrouter-auswahl.ts vendored, Importpfade umgestellt
Der Router verlaesst 42i/agents: die gemeinsame Modellauswahl wandert als
eigenstaendige Kopie nach src/ (die llmlite-Fassung bleibt dort fuer den
Tier-Updater). Referenz-Stellen zu LiteLLM-Durchreiche und Parallelbetrieb
korrigiert (entfallen mit der Abschaltung 2026-09-07).
2026-09-08 09:48:13 +02:00
elton bf7bc2c0b9 Ausweich auch für Schwelle-Aliasse und bei 429/5xx
auto/mass:fast war als Endstation ohne Rückfall: ling-3.0-flash fiel
am 2026-09-07 nachts aus (5x 502 nach ~270 s hängendem Upstream,
117x 429), und der bisherige Ausweich griff nur bei fetch-Fehlern und
nur für fest-Ziele. Jetzt darf auch ein Schwelle-Alias ausweichen,
und der Ausweich löst bei 429/5xx aus — bevor das erste Byte an den
Client geht, also gefahrlos wiederholbar, weiterhin nur einmal.

auto/mass:fast weicht auf auto/coding:junior aus (ling erfüllt deren
Schwellen strukturell nie, der Rückfall landet also garantiert auf
einem tauglichen Modell). Die Container-Personas bekommen die
Kettenziele in die ACL — ohne sie schlägt der Fallback in
zielBestimmen still fehl und der ursprüngliche Fehler geht durch.

Verifiziert im lokalen End-to-End-Test gegen Schein-Upstreams:
Ausweich bei 429 (200 vom Ersatzmodell, Log-Zeile alias->ausweich),
Durchreichung von 429 ohne ACL-Freigabe, fetch-catch-Pfad unverändert
funktionierend.

Refs 42i/intern#1252
2026-09-08 09:07:34 +02:00
eltonandClaude Opus 5 16a6b98c51 Ticketnummer bis ins Router-Log durchreichen (42i/intern#1291)
Der Log wusste bisher WER gerufen hat (Key, Rolle), aber nicht WORAN gearbeitet
wurde. Damit liess sich "was kostet ein Vorgang" gar nicht bilden -- die
Voraussetzung fuer die Frage, ob die teuren Tickets die sind, die ein Mensch
wollte.

- server.ts liest den Header x-42i-ticket und legt ihn in den Log-Eintrag
- log.ts: Feld `ticket` in JSONL und SQLite; die Spalte wird per ALTER
  nachgezogen (Bestandstabellen haben sie nicht), dazu ein Index darauf.
  Das INSERT nennt jetzt Spaltennamen statt Positionen -- sonst haette die
  neue Spalte die Reihenfolge zerschossen.
- opencode.json und der Container-Entrypoint schicken den Header aus
  {env:AGENT_TICKET}; job.sh exportiert die Variable ohnehin seit 2026-09-02.

Wer keines mitschickt (Chat, Handbetrieb), steht als null im Log -- auch das
ist eine Auskunft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 22:22:19 +02:00
eltonandClaude Opus 5 2355981c67 VERSUCH: role/worker auf ling (auto/mass:fast)
Andreas 2026-09-07: 'stellen wir die worker mal auf ling um und schauen was
passiert.' Bewusst gegen meine Empfehlung aus #1252 (ling Coding 50,6 /
Agentic 21,1 gegen glm 71,5 / 51,5) -- und bewusst als Versuch: der Rueckweg
ist diese eine Zeile.

Nur role/worker. engineer, qa und perf bleiben auf auto/coding:junior, damit
der Vergleich sauber bleibt.

Zu beobachten ist nicht der Preis (der faellt sicher), sondern ob die
Ergebnisse die Abnahme des Teamleiters bestehen -- und wie oft er neu
delegieren muss. Ein Worker, der in Schleifen haengt, braucht am Ende mehr
Zuege als er spart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 20:27:13 +02:00
eltonandClaude Opus 5 948ab84afe llmrouter: Slot an das Verbindungssignal binden (cancel feuert nicht)
Gegenprobe am Produktivrouter nach dem ersten Fix: Ein abgebrochener Stream
gab den Slot WEITERHIN nicht frei -- cancel() im TransformStream wird von Bun
beim Verbindungsabbruch nicht aufgerufen. Immerhin griff die zweite Haerte:
statt zwei Stunden Stille gab es nach 30 s ein 503 mit Grund.

Jetzt haengt der Slot an req.signal, das beim Abbruch zuverlaessig feuert, plus
einem Sicherheitsnetz von 660 s (laenger als der Upstream-Timeout darf kein
Slot gehalten werden). Die Freigabe ist gegen Doppelaufruf gesichert, ein
spaeteres flush() schadet also nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 20:23:36 +02:00
eltonandClaude Opus 5 ff62e751ed llmrouter: Slot-Leak beheben (42i/intern#1283)
Ein abgebrochener Streaming-Aufruf gegen das lokale Qwen (maxParallel 1) hat
den einzigen Slot dauerhaft gefressen: die Freigabe hing allein im flush() des
TransformStreams, und der laeuft bei cancel() nie. Danach reihte sich jeder
weitere Aufruf UNBEGRENZT in die Warteschlange ein, statt zu scheitern --
auto/mass, role/ops (Buzz) und das small_model aller Container-Personas hingen
zwei Stunden, ohne dass irgendwo etwas rot wurde. Diagnose von Elton im
Selbstheilungslauf, dreimal in Folge belegt.

Drei Haerten:
- Die Freigabe ist gegen Doppelaufruf gesichert (Flag). Erst dadurch darf sie
  an mehreren Stellen stehen, ohne Slots zu erfinden.
- cancel() gibt jetzt frei, nicht nur flush(). Das ist der eigentliche Fehler:
  bricht der Client ab, laeuft flush() nie.
- Wer laenger als 30 s auf einen Slot wartet, bekommt 503 mit Grund. Ein
  Fehler, an dem der Aufrufer etwas aendern kann, ist besser als Stille.

Ausgeloest habe ich den Fall selbst: zwei eigene Testaufrufe gegen role/ops
liefen gegen 18:05 ins Timeout und wurden abgebrochen -- genau die Handlung,
die den Slot frisst. Der Fehler im Code ist aelter, der Ausloeser war meiner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 20:20:56 +02:00
eltonandClaude Opus 5 ae0c4ca4a6 Korrektur: Qwen MIT Denkstufe holt den Skill selbst -- Einbacken fuer buzz unnoetig
Andreas fragte nach ("bist du dir sicher? so ganz sicher?" / "versuch sonst mal
qwen mit reasoning") -- zu Recht. Ich hatte die Aussage "Qwen laedt den Skill
nicht" aus der Doku uebernommen, statt sie zu messen.

Gemessen 2026-09-07 an agent-buzz auf auto/mass (qwen36:35b, enable_thinking):
Er ruft context_get_context von selbst und nennt seinen Arbeitsweg korrekt
(Runbooks und geschlossene Tickets zuerst, Wissen sichern, Routinen woertlich).

Der alte Befund (klara 0/9, live/live#1171) galt fuer 42i/marvin-core:none --
Qwen OHNE Denkstufe. Der Unterschied ist die Denkstufe, nicht das Modell.
AGENT_SKILL_EINBACKEN bleibt als Notnagel im Entrypoint, ist fuer buzz aber
nicht gesetzt.

Belastbarkeit: ein Lauf, kein Dutzend. Fuer eine Regel reicht das nicht -- fuer
die Entscheidung, den Vorspann nicht vorsorglich zu verdoppeln, schon.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 17:41:09 +02:00
eltonandClaude Opus 5 6c3d73584d buzz auf das lokale Qwen (role/ops -> auto/mass), Skill fuer ihn eingebacken
Andreas 2026-09-07: "lass buzz auf 42i/mass laufen. Der macht nicht so viel,
das muss ein qwen koennen." Buzz ist der einzige ops-Agent, deshalb bleibt die
Rolle der richtige Ort statt eines Modellnamens im Container.

Dazu gehoert zwingend AGENT_SKILL_EINBACKEN=1 fuer buzz: Qwen holt den
Persona-Skill nicht von selbst (klara 0/9 Laeufe, live/live#1171) -- genau der
Fall, fuer den der Schalter heute gebaut wurde. Der Vorspann steigt fuer ihn
also wieder, dafuer kostet sein Modell nichts.

Ausserdem: start-buzz-web.sh haengt den Werkzeug-Hinweis nach seinem
`cat > AGENTS.md` wieder an. Buzz war der einzige Container ohne den Hinweis --
sein warmer Web-Server ueberschreibt die Datei, die der Entrypoint schreibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 17:37:47 +02:00
eltonandClaude Opus 5 0ecf90e152 Altnamen wirksam machen und die XO-Runde drosseln
ALTNAMEN (Schadensbehebung): Bei der Umstellung heute Mittag starben fuenf
laufende Teamlaeufe, weil sie ihren Modellnamen aus der Session mittrugen und
der Router ihn nicht mehr kannte (Aktennotiz des XO an 42i/intern#1251). Das
Feld "altnamen" war seit jeher deklariert und validiert, aber im Server NIE
angewendet. Jetzt uebersetzt der Router alte Namen VOR ACL-Pruefung und
Aufloesung; 20 Eintraege fuer die 2608-Reihe und die praefixlosen LiteLLM-Namen.

DROSSELUNG der Runde (Andreas: Verbrauch senken). Gemessen am 07.09.: 32 Runden,
75-220 Zuege je Runde, 82k Kontext je Zug, 208 Mio. Token an einem Tag.
- Ereignis-Paket 4 -> 2: der Aufwand waechst quadratisch mit der Zuglaenge,
  zwei Runden mit je 110 Zuegen kosten rund ein Viertel einer mit 220. Keine
  Zeitgrenze, nichts wird abgebrochen (Andreas 2026-09-03).
- Prompt: die Rueckgabeformate von tool.sh stehen jetzt als Tabelle im Prompt --
  mehrere Zuege gingen dafuer drauf, sie zu erraten. Dazu die Regel, Kommandos
  zu buendeln (214 der 1359 Bash-Aufrufe waren reine cd) und keine breiten
  Verzeichnis-Dumps (groesstes Ergebnis des Tages: ein ls -la mit 14k Zeichen).

Nicht umgesetzt: die Vermutung, der XO fuehre delegierbare Arbeit selbst aus.
Die Messung widerlegt sie -- die Bash-Aufrufe sind ueberwiegend tool.sh-Aufrufe
(Tickets lesen, kommentieren, CI pruefen), also seine eigentliche Aufgabe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 14:05:35 +02:00
eltonandClaude Opus 5 32c54439c8 llmrouter: Messwerkzeug fuer Telefon-Latenz (Erstbyte mit Inkas Zuschnitt)
Anbieterstatistiken messen den Erstbyte ueber alle Nutzer und Prompts. Am
Telefon zaehlt die Zeit bis zum ersten gesprochenen Wort, mit unserem grossen
Systemprompt und ueber mehrere Zuege -- ein Modell mit Zwangs-Reasoning verliert
dort Sekunden, die in keiner Statistik stehen (42i/intern#1252).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:35:30 +02:00
elton 77c29266c9 llmrouter-README: Namensraum auto/ und die Rollen-Vorbelegung nachgezogen 2026-09-07 13:24:24 +02:00
eltonandClaude Opus 5 1513ca63d6 key-acls aufgeraeumt: nightjob und persona-inka-mx entfernt
nightjob hatte kein Token, keinen Konsumenten und keine Nutzung in den letzten
14 Tagen -- der Name stand nur noch in den ACL-Dateien. persona-inka-mx war ein
LiteLLM-key_alias; beide Inka-Tokens (Shim und Telefon-Front-End) laufen im
Router unter persona-inka. Der Alias in OpenBao (agents/inka/litellm) ist
mitkorrigiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:23:50 +02:00
eltonandClaude Opus 5 7fea5c82c4 Router: Namensraum auto/ mit acht Profilen auf drei Achsen (42i/intern#1252)
Der Preisfinder waehlte bisher ueber EINE Zahl. Ein Modell kann generalistisch
gut aussehen und agentisch durchfallen -- gemini-3.8-flash hat Coding 76,3 und
Agentic 41,2 und traegt den Werkzeug-Rundlauf nicht.

- openrouter-auswahl: billigsterUeberSchwelle reicht minCoding/minAgentic an
  klasseFiltern durch (nahm es bereits entgegen, wurde nur nie gefuettert)
- config: art "schwelle" hat jetzt index, coding und agentic, jede optional;
  "fest" kennt ausweich
- resolver: Beschreibung nennt die geforderten Achsen
- server: ein festes Ziel weicht bei Upstream-Ausfall EINMAL auf den
  konfigurierten Alias aus. Ohne das haengt mit dem lokalen Knoten jede
  Titelzeile jedes Agenten, weil auto/mass ueberall als small_model haengt.
- acht Profile, Rollen darauf umgehaengt, 42i/marvin-2609:* bleiben als Namen

Aufgeloest (ohne Last-Probe, alle Ziele laufen bereits ueber bestehende
Aliasse): coding:junior und leader:junior -> glm-5.3-flash, coding:senior ->
grok-4.6:high, leader:senior -> glm-5.3:max (15,66 statt 26 gewichtet -- die
Regel findet etwas Billigeres als die Schaetzung im Ticket), mass:fast -> ling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:20:10 +02:00
eltonandClaude Opus 5 a95c525a2c LiteLLM-Abschaltung: Fallback raus, alter Port 4000 zeigt auf den Router
- config.json: fallback und der litellm-Upstream entfernt. Unbekannte Namen
  sind ab jetzt ein Fehler statt einer stillen Weiterleitung -- mit totem
  LiteLLM waere daraus ein Timeout ohne Hinweis geworden, und mit Caddy auf
  :4000 sogar eine Schleife auf den Router selbst.
- Caddyfile: :4000 -> localhost:4010. Der Port war ueberall hart verdrahtet
  (Container-Images, spark-desktop, aeltere Skripte); ihn umzubiegen ist
  sicherer, als jeden Aufrufer einzeln zu finden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:06:38 +02:00
eltonandClaude Opus 5 f5eae167f4 Container: Persona fragt ihre Rolle, small_model auf das lokale Qwen, Port 4010
- entrypoint: Zuordnung Persona -> Rolle (spark engineer, buzz ops, jessie
  assistant, klara service); AGENT_MODEL bleibt als Ueberschreibung
- small_model getrennt von model (AGENT_SMALL_MODEL, Default lokales Qwen) --
  Titel und Zusammenfassungen muessen nichts kosten (42i/intern#1252)
- baseURL 4000 -> 4010: die Container sprachen bisher LiteLLM direkt an, am
  Router und am Caddy vorbei
- key-acls: core:none fuer spark/buzz/klara, sonst laeuft small_model in 401
- compose: AGENT_MODEL bei klara entfernt, die Rolle kommt aus dem Entrypoint

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:04:38 +02:00
eltonandClaude Opus 5 a023deb1be Leiter komplett auf Rollen: architect guenstig, alle opencode-Agenten, logbuch weg von Claude
Andreas 2026-09-07: das Max-Abo laeuft aus, es wird direkt umgestellt statt am
Mittwoch. Damit steht KEINE Rolle mehr auf der teuren Stufe.

- llmrouter: architect von :high auf :medium (= allround:junior)
- opencode.json: baseURL auf 4010 (Router statt LiteLLM), alle zehn Agenten auf
  role/*, model und small_model ebenso; Modelldeklarationen sind jetzt die
  Rollen statt der 2608-Namen
- engines.json: xo-chat und logbuch von engine=claude auf opencode; masse von
  42i/marvin-2608-mass:medium (kein Router-Gegenstueck) auf :low
- logbuch-eintrag.sh: opencode-Zweig, Entwurf aus dem JSONL-Strom; der
  claude-Zweig bleibt als Rueckweg erhalten

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:03:49 +02:00
eltonandClaude Opus 5 087dd91ad7 xo: von Claude Code aufs opencode-Gespann, Modell role/xo statt Max-Abo
Der XO war der letzte grosse Posten ausserhalb des Routers: engine=claude mit
claude-opus-5 ueber das Abo, damit ohne Kostenzeile und ohne Metering. Er laeuft
jetzt wie die Teams auf opencode und fragt die Rolle role/xo.

role/xo zeigt dazu auf 42i/marvin-2609:medium (= leader:junior nach
42i/intern#1252, heute glm-5.3-flash) statt :high. Ausdruecklich als Versuch
(Andreas): reicht das Urteil nicht, ist Hochstufen eine Zeile in config.json.
Der Gegenpol bleibt notiert - der Hinweis vom 2026-08-20 (Fall t1678) steht.

Kontextgrenze der Modelldeklaration bewusst auf 262144, die garantierte
Mindestschwelle der medium-Stufe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 12:56:57 +02:00
eltonandClaude Opus 5 da47c1b3ed router: teamleader und lead auf die guenstige Stufe (Andreas 2026-09-07)
Beide standen auf 42i/marvin-2609:high (= grok-4.6 fuer 26 $/1M gewichtet).
Nach 42i/intern#1252 entspricht das leader:junior; damit bleibt nur xo auf der
teuren Stufe, architect ueber allround:senior.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 12:50:49 +02:00
eltonandClaude Opus 5 707a60bc0d Clients auf Router-Namen ziehen: matrix-MCP und Paperless-Verschlagwortung
Beide riefen ueber Port 4000 (LiteLLM) und mit LiteLLM-eigenen Modellnamen
(marvin-tts, marvin-stt, standard, 42i/marvin-2608-core:none). Der Router kennt
diese Namen nicht und reicht sie heute still an LiteLLM durch - mit dessen
Abschaltung waeren sie tot (42i/intern#1252).

- matrix-MCP: TTS/STT auf llm.lan:4010 und 42i/marvin-tts bzw. 42i/marvin-stt
- Paperless: llm.lan:4010, Modell 42i/marvin-2609-core:none statt "standard"
  bzw. dem 2608-Namen; nach #1252 gehoert diese Massenarbeit auf auto/mass
- key-acls: persona-jessie darf das lokale Qwen (fuer genau diese Laeufe)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 12:45:12 +02:00