fix: preserve cross-provider model selection across conversation turns
Two-part fix for the model selector jumping back to the profile default after the first message when a cross-provider model (e.g. a custom relay like custom:glm-free-relay) is selected. Backend (api/routes.py): - _catalog_has_provider() now matches compound provider IDs (e.g. custom:zenmux-relay) whose normalized form (custom) is a raw catalog provider_id. Previously the three existing checks missed normalized-vs-raw comparison for compound hints, causing the catalog lookup to fail and the fallback branch to silently revert the model to the profile default on every non-explicit turn. Frontend (static/messages.js): - The explicit_model_pick marker was consumed after the first send(), so subsequent sends lost the signal and the server repaired the model back to the profile default (#3737 regression). - Now, when the session has a non-default model from a different provider than the profile's active provider, every send() sends explicit_model_pick=true so the server honors the user's choice across the entire conversation. - The pending onchange marker is still consumed after the first send (unchanged behavior); only the explicit_pick inference is broadened.
This commit is contained in:
1 parent
c6ac31b71e
commit
96265f6ae4
2 files changed
+28
-2
No files matched your search
@@ -3196,6 +3196,18 @@ def _catalog_has_provider(
|
||||
provider_raw in raw_provider_ids
|
||||
or (provider_normalized and provider_normalized in raw_provider_ids)
|
||||
or (provider_normalized and provider_normalized in normalized_provider_ids)
|
||||
# Compound provider IDs like "custom:zenmux-relay" normalize to
|
||||
# "custom" which is a raw catalog provider_id. The three checks
|
||||
# above compare raw-vs-raw and normalized-vs-normalized but miss
|
||||
# normalized-vs-raw for compound hints. Without this, a
|
||||
# @custom:relay-name:model selection is silently reverted to the
|
||||
# profile default on every non-explicit turn because the catalog
|
||||
# lookup fails and the fallback branch at line ~3932 fires.
|
||||
or (
|
||||
provider_normalized
|
||||
and ":" in provider_raw
|
||||
and provider_normalized in raw_provider_ids
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
+16
-2
@@ -1267,15 +1267,29 @@ async function send(){
|
||||
const _pendingPick=(typeof _readPendingSessionModel==='function')
|
||||
? _readPendingSessionModel(activeSid)
|
||||
: null;
|
||||
const _explicitPick=_pendingPick
|
||||
const _pendingPickMatch=_pendingPick
|
||||
&& _pendingPick.model===_modelState.model
|
||||
&& String(_pendingPick.model_provider||'')===String(_modelState.model_provider||'');
|
||||
// ── Persisted cross-provider pick (#3737 follow-up) ──
|
||||
// The onchange marker is consumed after the first send, so subsequent sends
|
||||
// lose explicit_model_pick and the server "repairs" the model back to the
|
||||
// profile default. When the session has a non-default model from a different
|
||||
// provider than the profile's active provider, treat every send as explicit
|
||||
// so the server honors the user's choice across the entire conversation.
|
||||
const _defaultModel=(typeof window!=='undefined' && window._defaultModel)||'';
|
||||
const _activeProvider=(typeof window!=='undefined' && window._activeProvider)||null;
|
||||
const _isCrossProviderPick = _modelState.model
|
||||
&& _modelState.model_provider
|
||||
&& _defaultModel
|
||||
&& _modelState.model !== _defaultModel
|
||||
&& String(_modelState.model_provider||'') !== String(_activeProvider||'');
|
||||
const _explicitPick = _pendingPickMatch || _isCrossProviderPick;
|
||||
// Consume the pending explicit-pick marker for THIS send only. The marker is
|
||||
// recorded on modelSelect.onchange and intentionally kept (not cleared on
|
||||
// session-update) so it survives the normal pick→update→send flow; clear it here
|
||||
// once read so a later send of an unchanged dropdown isn't treated as an explicit
|
||||
// pick. (#3739/#3737, Codex catch)
|
||||
if(_explicitPick && typeof _clearPendingSessionModel==='function') _clearPendingSessionModel(activeSid);
|
||||
if(_pendingPickMatch && typeof _clearPendingSessionModel==='function') _clearPendingSessionModel(activeSid);
|
||||
explicitPickForPostStart=_explicitPick;
|
||||
const startData=await api('/api/chat/start',{method:'POST',body:JSON.stringify({
|
||||
session_id:activeSid,message:msgText,
|
||||
|
||||
Reference in new issue
Block a user