feat: Modell pro Chat waehlen — und sehen, welches gerade laeuft

Nach einem Sicherheitsfilter-Treffer fuhr ein Projekt still auf dem
Ausweich-Modell weiter, und nirgends war zu sehen, auf welchem. Zurueck ging
nur ueber "Liste leeren" im Filter-Panel, und das gleich fuer alle Chats.

Jetzt drei Ebenen (aria-brain/context_model.py):
  Einstellung (brainModel) < pro Chat < Ausweich (Sicherheitsfilter)

- Pro Chat: Hauptchat und jedes Projekt koennen ein eigenes Modell haben, in
  /shared/config/context_models.json. Bewusst kein Feld im Projekt-Manifest —
  der Hauptchat ist kein Projekt und waere sonst aussen vor.
- "↩ zurueck" pro Chat: loescht nur die Filter-Vermerke DIESES Chats. Blockt
  der Filter erneut, weicht das Brain eben wieder aus.
- Angezeigt wird, was wirklich laeuft: chat() gibt das Modell aus modelUsage
  der CLI zurueck (aufgeloeste Version statt Alias) samt Grund; Brain → Bridge
  → chat_backup + Live-Payload → App und Diagnostic. Als Grundeinstellung
  zaehlt das Modell, mit dem das Brain laeuft, nicht der Dateiwert — so faellt
  ein ausstehender Neustart nach brainModel-Aenderung auf.

Diagnostic: 🧠-Auswahl neben "+ Projekt" fuer den fokussierten Chat, Modell im
Untertitel jeder Kontext-Karte, Modell statt "Claude" am Bubble-Badge (orange
mit ↪ bei Ausweich).

App: hinter der Quell-Anzeige (Einstellungen, Default aus — Kopfzeile bleibt
fuer Mama unveraendert) ein Modell-Chip in der Kopfzeile; Tippen oeffnet die
Auswahl fuer diesen Chat inkl. "Zurueck". Laeuft ueber den vorhandenen
brain_request-Kanal, also keine neuen RVS-Typen.

Tests: 47/47 (12 neue fuer die Aufloesungsreihenfolge gegen agent.chat()),
tsc ohne Fehler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 13:39:30 +02:00
co-authored by Claude Opus 5.5
parent d221c1a320
commit 6d978d72b3
9 changed files with 596 additions and 19 deletions
+56
View File
@@ -260,6 +260,43 @@ export interface Trigger {
// ── Memory CRUD ──────────────────────────────────────────────────────
// ── Modell pro Chat ──────────────────────────────────────────────────
// reason: 'einstellung' (brainModel) | 'pro-chat' (fuer diesen Chat gewaehlt)
// | 'ausweich' (Sicherheitsfilter hat das gewaehlte Modell blockiert)
export interface ContextModelRow {
context_id: string;
name: string;
override: string; // '' = folgt der Einstellung
selected: string; // gewaehlt (Einstellung oder pro Chat)
effective: string; // was der naechste Turn tatsaechlich nutzt
reason: 'einstellung' | 'pro-chat' | 'ausweich' | string;
blocked: string[];
}
export interface ContextModelChoice {
id: string;
name: string;
section: 'tier' | 'main' | 'overflow' | string;
}
export interface ContextModels {
default: string;
rows: ContextModelRow[];
choices: ContextModelChoice[];
names: Record<string, string>;
}
/** "claude-sonnet-5-5" → "Sonnet 5.5". Katalog-Namen (names) haben Vorrang;
* Datums-Suffixe ("-20251001") gehoeren nicht zur Version. Gleiche Logik wie
* prettyModel() in der Diagnostic. */
export function prettyModel(id: string, names?: Record<string, string>): string {
if (!id) return '';
if (names && names[id]) return names[id];
const m = /^claude-([a-z]+)-(\d+)(?:-(\d{1,2}))?(?:-|$)/.exec(id);
if (m) return m[1][0].toUpperCase() + m[1].slice(1) + ' ' + m[2] + (m[3] ? '.' + m[3] : '');
return id.charAt(0).toUpperCase() + id.slice(1);
}
export const brainApi = {
/** Einzelne Memory holen (mit allen Feldern inkl. Anhaenge) */
getMemory(id: string): Promise<Memory> {
@@ -682,6 +719,25 @@ export const brainApi = {
getProjectQueueStatus(): Promise<ProjectQueueStatus> {
return _send('/projects/queue-status');
},
/** Modelle aller Chats: gewaehlt, effektiv, Grund + Auswahl-Liste. */
getContextModels(): Promise<ContextModels> {
return _send('/context-model/list');
},
/** Modell fuer einen Chat setzen ('' als Modell = wieder die Einstellung). */
setContextModel(contextId: string, model: string): Promise<ContextModels> {
return _send('/context-model/set', {
method: 'POST',
body: { context_id: contextId || '', model: model || '' },
});
},
/** Ausweich-Modell beenden: zurueck aufs gewaehlte Modell dieses Chats. */
contextModelBack(contextId: string): Promise<ContextModels> {
return _send('/context-model/back-to-selected', {
method: 'POST',
body: { context_id: contextId || '' },
});
},
};
export default brainApi;