- Check process_running and ready state before making inference request
- Emit descriptive error messages for each failure scenario
- Handle local vs remote connection modes appropriately
- Validation score: 100 (was 0)
Result: {"status":"keep","validation_score":100,"response_time_ms":500}
86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
import { useCallback, useRef, useState } from "react";
|
|
import type { RuntimeModelFile } from "../features/runtime/types";
|
|
import { resolveAlias } from "../lib/modelAlias";
|
|
import { useToast } from "../components/Toast";
|
|
|
|
interface Options {
|
|
preferredModel: string;
|
|
onSwitchToCooper: (cooperPath: string) => void;
|
|
localModels: RuntimeModelFile[];
|
|
}
|
|
|
|
interface SessionModelController {
|
|
effectiveModel: string;
|
|
overrideSource: 'auto' | 'user';
|
|
setUserOverride: (modelPath: string) => void;
|
|
clearOverride: () => void;
|
|
onDegradationDetected: () => void;
|
|
degradationPromptShown: boolean;
|
|
}
|
|
|
|
export function useSessionModelController({
|
|
preferredModel,
|
|
onSwitchToCooper,
|
|
localModels,
|
|
}: Options): SessionModelController {
|
|
const { showToast } = useToast();
|
|
const [effectiveModel, setEffectiveModel] = useState<string>(preferredModel);
|
|
const [overrideSource, setOverrideSource] = useState<'auto' | 'user'>('auto');
|
|
const [degradationPromptShown, setDegradationPromptShown] = useState(false);
|
|
|
|
// Keep effectiveModel in sync when preferredModel changes externally (e.g. startup auto-select)
|
|
// but only if the user hasn't manually overridden
|
|
const prevPreferredRef = useRef(preferredModel);
|
|
if (preferredModel !== prevPreferredRef.current) {
|
|
prevPreferredRef.current = preferredModel;
|
|
if (overrideSource === 'auto') {
|
|
setEffectiveModel(preferredModel);
|
|
}
|
|
}
|
|
|
|
const setUserOverride = useCallback((modelPath: string) => {
|
|
setEffectiveModel(modelPath);
|
|
setOverrideSource('user');
|
|
}, []);
|
|
|
|
const clearOverride = useCallback(() => {
|
|
setEffectiveModel(preferredModel);
|
|
setOverrideSource('auto');
|
|
}, [preferredModel]);
|
|
|
|
const onDegradationDetected = useCallback(() => {
|
|
// Don't show if user already chose manually or already shown
|
|
if (overrideSource === 'user' || degradationPromptShown) return;
|
|
|
|
// Find Copper's path from localModels
|
|
const copperModel = localModels.find((m) => resolveAlias(m.path) === 'Copper');
|
|
if (!copperModel) return; // Copper not available, can't suggest
|
|
|
|
setDegradationPromptShown(true);
|
|
|
|
showToast({
|
|
id: 'tps-degradation',
|
|
variant: 'warning',
|
|
message: 'Performance degraded',
|
|
detail: 'TPS dropped below 30 for 5s. Switch to Copper (0.8B) for faster responses?',
|
|
action: {
|
|
label: 'Switch to Copper',
|
|
onClick: () => {
|
|
setUserOverride(copperModel.path);
|
|
onSwitchToCooper(copperModel.path);
|
|
},
|
|
},
|
|
duration: 0, // persistent until dismissed
|
|
});
|
|
}, [overrideSource, degradationPromptShown, localModels, showToast, setUserOverride, onSwitchToCooper]);
|
|
|
|
return {
|
|
effectiveModel,
|
|
overrideSource,
|
|
setUserOverride,
|
|
clearOverride,
|
|
onDegradationDetected,
|
|
degradationPromptShown,
|
|
};
|
|
}
|