Feat: "Auto"-Button beim Kontext setzen - setzt den setup-bewussten Optimalwert

Beim manuellen ctx-Eintrag (Modellkarte »Ctx«) gab es nur ein leeres Eingabefeld.
Jetzt:
- Backend: GET /api/models/{id}/ctx/auto liefert den setup-bewussten Optimal-ctx fuer
  ein bestehendes Modell (Rolle/Params/Quant + aktuelles Setup) inkl. Budget-Herleitung.
  budget.py: params_of_model() + setup_aware_ctx_for_model() (DRY mit footprint_gb).
- Dialog (CustomDialog/useDialog): optionaler Auto-Button im Prompt, der den Wert eintraegt.
- Cockpit: »Ctx« holt den Optimalwert, zeigt ihn + Budget (GTT/reserviert/frei) in der
  Meldung und bietet »Auto (Nk)« zum direkten Uebernehmen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-06-27 14:32:14 +02:00
parent 6d529e3f79
commit 1e011714dd
7 changed files with 153 additions and 91 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>Mission Control 2.0</title>
<script type="module" crossorigin src="/assets/index-DGRyEXwM.js"></script>
<script type="module" crossorigin src="/assets/index-eaeyLEVq.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CqYu-pXY.css">
</head>
<body>
+27 -13
View File
@@ -6,11 +6,13 @@ export interface CustomDialogProps {
title: string
message: string
defaultValue?: string
autoValue?: string
autoLabel?: string
onConfirm: (val?: string) => void
onCancel?: () => void
}
export function CustomDialog({ type, title, message, defaultValue, onConfirm, onCancel }: CustomDialogProps) {
export function CustomDialog({ type, title, message, defaultValue, autoValue, autoLabel, onConfirm, onCancel }: CustomDialogProps) {
const inputRef = useRef<HTMLInputElement>(null)
return (
<div className="fixed inset-0 z-[99] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
@@ -27,18 +29,30 @@ export function CustomDialog({ type, title, message, defaultValue, onConfirm, on
<p className="text-xs text-muted-foreground leading-relaxed">{message}</p>
{type === "prompt" && (
<input
ref={inputRef}
type="text"
defaultValue={defaultValue}
className="w-full h-9 px-3 text-xs bg-background/40 border border-border/60 rounded-lg outline-none focus:border-primary transition-colors text-foreground"
autoFocus
onKeyDown={(e) => {
if (e.key === "Enter") {
onConfirm(inputRef.current?.value)
}
}}
/>
<div className="flex gap-2">
<input
ref={inputRef}
type="text"
defaultValue={defaultValue}
className="flex-1 h-9 px-3 text-xs bg-background/40 border border-border/60 rounded-lg outline-none focus:border-primary transition-colors text-foreground"
autoFocus
onKeyDown={(e) => {
if (e.key === "Enter") {
onConfirm(inputRef.current?.value)
}
}}
/>
{autoValue !== undefined && (
<button
type="button"
onClick={() => { if (inputRef.current) inputRef.current.value = autoValue }}
title="Setup-bewussten Optimalwert eintragen"
className="h-9 px-3 shrink-0 text-xs font-semibold text-primary border border-primary/50 bg-primary/10 hover:bg-primary/20 rounded-lg transition-colors cursor-pointer"
>
{autoLabel || "Auto"}
</button>
)}
</div>
)}
<div className="flex justify-end gap-3 pt-2">
+5 -1
View File
@@ -15,6 +15,8 @@ interface DialogState {
title: string
message: string
defaultValue?: string
autoValue?: string
autoLabel?: string
onConfirm: (val?: string) => void
onCancel?: () => void
}
@@ -41,9 +43,11 @@ export function useDialog() {
const showPrompt = useCallback(
(title: string, message: string, defaultValue: string,
onConfirm: (val?: string) => void, onCancel?: () => void) => {
onConfirm: (val?: string) => void, onCancel?: () => void,
opts?: { autoValue?: string; autoLabel?: string }) => {
setDialog({
type: "prompt", title, message, defaultValue,
autoValue: opts?.autoValue, autoLabel: opts?.autoLabel,
onConfirm: (val) => { setDialog(null); onConfirm(val) },
onCancel: () => { setDialog(null); onCancel?.() },
})
+17 -3
View File
@@ -132,22 +132,36 @@ export function Cockpit() {
}
async function handleSetCtx(name: string, cur: number | null) {
// Setup-bewussten Optimalwert holen (Rolle/Params/Quant + aktuelles Setup).
let auto: { ctx: number; gtt_gb: number; reserved_gb: number; budget_gb: number; mode: string } | null = null
try {
auto = await api(`/api/models/${encodeURIComponent(name)}/ctx/auto`)
} catch { /* Auto optional — Prompt funktioniert auch ohne */ }
const hint = auto
? `Optimal für dein Setup: ${(auto.ctx / 1024).toFixed(0)}k (${auto.ctx}) — ` +
`GTT ${auto.gtt_gb} GB reserviert ${auto.reserved_gb} GB (${auto.mode}) → ${auto.budget_gb} GB frei. ` +
`»Auto« trägt diesen Wert ein.`
: "Gib die gewünschte Kontextlänge in Tokens an:"
showPrompt(
"Kontextlänge anpassen",
"Gib die gewünschte Kontextlänge in Tokens an:",
hint,
String(cur || 32768),
async (v) => {
if (!v) return
try {
await api(`/api/models/${encodeURIComponent(name)}/ctx`, {
method: "POST",
method: "POST",
body: JSON.stringify({ ctx: parseInt(v, 10) }),
})
reload()
} catch (e: any) {
showAlert("Fehler", `Fehler beim Setzen des Kontexts: ${e.message || e}`)
}
}
},
undefined,
auto ? { autoValue: String(auto.ctx), autoLabel: `Auto (${(auto.ctx / 1024).toFixed(0)}k)` } : undefined,
)
}