Feat: Brain-Rolle (hermes) als erstklassige, dauer-warme Hirn-Rolle

- ROLE_IDS (llamaswap, sources) + UI-Rollenlisten (ModelBadges, Discover,
  ModelBrowse, Cockpit-Slot-Grid) um `hermes` erweitert: gemma erscheint als
  „Hirn", nicht mehr als scout.
- Neuer set_ttl-Helper; set_agent_brain erzwingt ttl:0 (neu + idempotent beim
  Re-Setzen) und liefert eine weiche Budget-Warnung (kein Hard-Block) bei OOM.
- brain_status/brain_model_name: zeigen das echte Hirn (Rolle hermes / Hermes
  model.default) statt hart `fast` (Bugfix Health-/Ready-Check).
- POST /api/models/{id}/role delegiert die Rolle `hermes` an den warm-bewussten
  Flow (Alias + brains-Gruppe + ttl 0 + Hermes-Config + Gateway-Restart).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-30 17:01:26 +02:00
parent 087eb2259d
commit dd99401f3e
11 changed files with 360 additions and 284 deletions
@@ -1,8 +1,9 @@
import { type Fit } from "@/lib/api"
import { cn } from "@/lib/utils"
// Die 5 kanonischen Serving-Rollen (identisch zu Backend sources.py/llamaswap.ROLE_IDS).
export const ROLES = ["fast", "heavy", "coder", "vision", "scout"]
// Die kanonischen Serving-Rollen (identisch zu Backend sources.py/llamaswap.ROLE_IDS).
// `hermes` = Lucys Agent-Hirn (warm + ko-resident); UI-Label „Hirn".
export const ROLES = ["fast", "heavy", "coder", "vision", "hermes", "scout"]
// Rolle → Farbton. EINE Quelle der Wahrheit für alle Rollen-Badges (Cockpit, ModelsCard,
// …). `hermes` = Agent-Hirn (taucht als geladenes Modell auf).
+6 -3
View File
@@ -6,7 +6,7 @@ import { useDialog } from "@/lib/useDialog"
import { CapsChips } from "@/components/CapsChips"
import { cn } from "@/lib/utils"
import { fmtSize, fmtCtx } from "@/lib/format"
import { getBrandInfo, roleTone } from "@/components/models/ModelBadges"
import { getBrandInfo, roleTone, ROLES } from "@/components/models/ModelBadges"
import { SpecDraftModal } from "@/components/models/SpecDraftModal"
import { LaneEditor } from "@/components/models/LaneEditor"
@@ -107,11 +107,14 @@ export function Cockpit() {
async function handleRoleChange(role: string, modelName: string) {
try {
await api(`/api/models/${encodeURIComponent(modelName)}/role`, {
// Bei der Hirn-Rolle (hermes) läuft serverseitig der warm-bewusste Flow (Alias + brains-
// Gruppe + ttl 0 + Hermes-Config + Gateway-Restart) und liefert ggf. eine Budget-Warnung.
const res = await api<{ warning?: string | null }>(`/api/models/${encodeURIComponent(modelName)}/role`, {
method: "POST",
body: JSON.stringify({ role: role || null }),
})
reload()
if (res?.warning) showAlert("Hirn gesetzt — Hinweis", res.warning)
} catch (e: any) {
showAlert("Fehler", `Fehler beim Zuweisen der Rolle: ${e.message || e}`)
}
@@ -311,7 +314,7 @@ export function Cockpit() {
Gateway Steckplatz-Belegung (Slot-Zuweisung)
</div>
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
{["fast", "heavy", "coder", "vision", "scout"].map((role) => {
{ROLES.map((role) => {
const m = models.find((x) => x.role === role)
const isWarm = m ? running.includes(m.name) : false
+7 -2
View File
@@ -1,5 +1,5 @@
import { useState } from "react"
import { Download, Star, Layers, Check, Zap, Eye, Code, Brain, Compass, ChevronDown, ChevronUp } from "lucide-react"
import { Download, Star, Layers, Check, Zap, Eye, Code, Brain, BrainCircuit, Compass, ChevronDown, ChevronUp } from "lucide-react"
import { api } from "@/lib/api"
import { useModels, useUpdates, useDiscover } from "@/lib/queries"
import { cn } from "@/lib/utils"
@@ -7,7 +7,7 @@ import { fmtBytes } from "@/lib/format"
import { FitBadge } from "@/components/models/ModelBadges"
import { ModelBrowse } from "./ModelBrowse"
// Die 5 kanonischen Rollen (identisch zu sources.py / ModelBadges.ROLES).
// Die kanonischen Rollen (identisch zu sources.py / ModelBadges.ROLES).
const ROLE_METADATA: Record<string, { title: string; desc: string; icon: any }> = {
fast: {
title: "Schnelles Alltags-Hirn",
@@ -29,6 +29,11 @@ const ROLE_METADATA: Record<string, { title: string; desc: string; icon: any }>
desc: "Verarbeitet Bilder, Screenshots und visuelle Diagramme in multimodalen Chats.",
icon: Eye
},
hermes: {
title: "Lucys Hirn (Agent)",
desc: "Lucys dauer-warmes Agent-Hirn mit Tool-Calling — bleibt ko-resident, lädt nie kalt nach.",
icon: BrainCircuit
},
scout: {
title: "Multimodal-Allrounder",
desc: "Multimodaler Allrounder für schnelle Antworten, Übersetzungen und Alltag.",
+1 -1
View File
@@ -13,7 +13,7 @@ const CHIPS: { key: string; label: string; q: string }[] = [
{ key: "reasoning", label: "Reasoning", q: "reasoning" },
{ key: "small", label: "Klein (≤4B)", q: "3B" },
]
const ROLE_OPTS = ["fast", "heavy", "coder", "vision", "scout"]
const ROLE_OPTS = ["fast", "heavy", "coder", "vision", "hermes", "scout"]
const _nf = new Intl.NumberFormat(undefined, { notation: "compact", maximumFractionDigits: 1 })
function fmtN(n: number): string {