Make the codex/GGUF auto-pick symmetric in both directions
The correction effect only steered away from codex when the model stopped being GGUF; it never steered back toward codex if the model became GGUF *after* a non-GGUF-gated fallback had already picked something else (e.g. codex is the only detected CLI, a transformers model is loaded so the selection correctly falls back to the claude default, then the user loads a GGUF model while the panel stays mounted -- codex never gets reconsidered). Consolidate into one effect that re-derives the preferred detected agent from scratch whenever detectedAgents or activeGgufVariant changes, in either direction, instead of only reacting to the codex-specific downgrade case. The fetch effect now only populates detectedAgents/availableAgents; this effect is the single source of truth for what gets auto-picked from that list. Never overrides a manual choice. Verified both transition directions plus the manual-pick-survives and initial-detection cases with a standalone port of the derivation logic.
This commit is contained in:
parent
00e4d77423
commit
d988f52a00
1 changed files with 17 additions and 24 deletions
|
|
@ -500,6 +500,10 @@ export function UsageExamples({ apiKey }: { apiKey?: string | null }) {
|
||||||
void fetchDeviceType({ force: true });
|
void fetchDeviceType({ force: true });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Fetching is the only job of this effect: populate availableAgents/
|
||||||
|
// detectedAgents (or clear them). Which agent gets auto-picked from that
|
||||||
|
// list is derived separately below, so it can react to the loaded model
|
||||||
|
// changing too, not just a fresh fetch.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// shutil.which runs on the Studio backend, so "detected" only means
|
// shutil.which runs on the Studio backend, so "detected" only means
|
||||||
// something for the browser's own machine when the base this panel
|
// something for the browser's own machine when the base this panel
|
||||||
|
|
@ -520,20 +524,6 @@ export function UsageExamples({ apiKey }: { apiKey?: string | null }) {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
setAvailableAgents(info.agents);
|
setAvailableAgents(info.agents);
|
||||||
setDetectedAgents(info.detected);
|
setDetectedAgents(info.detected);
|
||||||
// Prefer an agent that's actually installed over the hardcoded
|
|
||||||
// "claude" starting point, but never override a choice the user
|
|
||||||
// already made -- including one made while this request was in
|
|
||||||
// flight, which a value comparison against "claude" alone would miss.
|
|
||||||
// `codex` additionally refuses to launch against a non-GGUF model
|
|
||||||
// (unsloth_cli's _require_gguf_for_codex exits for transformers-backed
|
|
||||||
// models), so skip it unless the loaded model actually qualifies.
|
|
||||||
if (!agentPickedByUserRef.current && info.detected.length > 0) {
|
|
||||||
const isGguf = Boolean(
|
|
||||||
useChatRuntimeStore.getState().activeGgufVariant,
|
|
||||||
);
|
|
||||||
const preferred = info.detected.find((a) => a !== "codex" || isGguf);
|
|
||||||
if (preferred) setAgent(preferred);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
// Best-effort: keep the default agent list and let the user pick manually.
|
// Best-effort: keep the default agent list and let the user pick manually.
|
||||||
|
|
@ -543,19 +533,22 @@ export function UsageExamples({ apiKey }: { apiKey?: string | null }) {
|
||||||
};
|
};
|
||||||
}, [isLoopbackBase]);
|
}, [isLoopbackBase]);
|
||||||
|
|
||||||
// The effect above only re-evaluates codex's GGUF requirement at the
|
// Single source of truth for the auto-picked agent, re-derived whenever
|
||||||
// moment detection resolves; if the user swaps to a non-GGUF model while
|
// the detected list or the loaded model's GGUF-ness changes -- in either
|
||||||
// this panel stays mounted, steer the auto-pick away from codex instead of
|
// direction. `codex` needs a GGUF model (unsloth_cli's
|
||||||
// leaving a command that unsloth_cli's _require_gguf_for_codex will now
|
// _require_gguf_for_codex exits otherwise), so it's only preferred once
|
||||||
// reject. No network call here -- it only re-derives from state already in
|
// the loaded model actually qualifies; loading a GGUF model *after* a
|
||||||
// hand, and it never overrides a choice the user made by hand.
|
// non-GGUF-gated fallback picked something else re-steers back to codex
|
||||||
|
// just as loading a non-GGUF model steers away from it. Never overrides a
|
||||||
|
// choice the user made by hand.
|
||||||
const activeGgufVariant = useChatRuntimeStore((s) => s.activeGgufVariant);
|
const activeGgufVariant = useChatRuntimeStore((s) => s.activeGgufVariant);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (agentPickedByUserRef.current) return;
|
if (agentPickedByUserRef.current) return;
|
||||||
if (agent !== "codex" || activeGgufVariant) return;
|
if (detectedAgents.length === 0) return;
|
||||||
const fallback = detectedAgents.find((id) => id !== "codex");
|
const isGguf = Boolean(activeGgufVariant);
|
||||||
if (fallback) setAgent(fallback);
|
const preferred = detectedAgents.find((a) => a !== "codex" || isGguf);
|
||||||
}, [agent, activeGgufVariant, detectedAgents]);
|
if (preferred) setAgent(preferred);
|
||||||
|
}, [detectedAgents, activeGgufVariant]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue