mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-08-05 02:45:28 +00:00
feat(chat): apply defaults on model switch
This commit is contained in:
parent
201d466adb
commit
cb3c4888c4
3 changed files with 141 additions and 8 deletions
|
|
@ -2027,6 +2027,16 @@ function initializeEventListeners() {
|
|||
try { window.__odysseusModelControlDefaults = { ...modelControlDefaults }; } catch (_) {}
|
||||
}
|
||||
|
||||
async function refreshModelControlDefaults() {
|
||||
try {
|
||||
const res = await fetch('/api/auth/settings', { credentials: 'same-origin' });
|
||||
if (!res.ok) return { ...modelControlDefaults };
|
||||
const settings = await res.json();
|
||||
if (settings) setModelControlDefaults(settings);
|
||||
} catch (_) {}
|
||||
return { ...modelControlDefaults };
|
||||
}
|
||||
|
||||
const isThinkingModel = model => {
|
||||
const m = String(model || '').toLowerCase();
|
||||
return ['qwen3', 'qwq', 'deepseek-r1', 'deepseek-reasoner', 'minimax', 'm2-reap', 'gemma']
|
||||
|
|
@ -2108,8 +2118,8 @@ function initializeEventListeners() {
|
|||
return { supported: false, allowed: new Set(['auto']), reason: '' };
|
||||
}
|
||||
|
||||
async function persistSessionControl(key, value) {
|
||||
const sid = sessionModule && sessionModule.getCurrentSessionId ? sessionModule.getCurrentSessionId() : null;
|
||||
async function persistSessionControl(key, value, sessionId = null) {
|
||||
const sid = sessionId || (sessionModule && sessionModule.getCurrentSessionId ? sessionModule.getCurrentSessionId() : null);
|
||||
if (!sid) return;
|
||||
const fd = new FormData();
|
||||
fd.append(key, value || 'auto');
|
||||
|
|
@ -2145,6 +2155,52 @@ function initializeEventListeners() {
|
|||
Object.values(registry).forEach(api => api.refreshCapability(override));
|
||||
}
|
||||
|
||||
function resolveControlForContext(key, value, contextOverride = null) {
|
||||
const config = controls.find(item => item.key === key);
|
||||
if (!config) return 'auto';
|
||||
const capability = capabilitiesFor(key, contextOverride);
|
||||
const normalized = normalizeDefaultControl(key, value);
|
||||
return capability.allowed.has(normalized) ? normalized : 'auto';
|
||||
}
|
||||
|
||||
function resolveDefaultsForContext(contextOverride = null) {
|
||||
return {
|
||||
reasoning_effort: resolveControlForContext(
|
||||
'reasoning_effort',
|
||||
modelControlDefaults.reasoning_effort,
|
||||
contextOverride,
|
||||
),
|
||||
verbosity: resolveControlForContext(
|
||||
'verbosity',
|
||||
modelControlDefaults.verbosity,
|
||||
contextOverride,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
async function applyDefaultsForContext(contextOverride = null, options = {}) {
|
||||
if (options.refresh !== false) {
|
||||
await refreshModelControlDefaults();
|
||||
}
|
||||
const resolved = resolveDefaultsForContext(contextOverride);
|
||||
if (registry.reasoning_effort) {
|
||||
registry.reasoning_effort.setValue(resolved.reasoning_effort, {
|
||||
persist: options.persist !== false,
|
||||
contextOverride,
|
||||
sessionId: options.sessionId || null,
|
||||
});
|
||||
}
|
||||
if (registry.verbosity) {
|
||||
registry.verbosity.setValue(resolved.verbosity, {
|
||||
persist: options.persist !== false,
|
||||
contextOverride,
|
||||
sessionId: options.sessionId || null,
|
||||
});
|
||||
}
|
||||
refreshCapabilities(contextOverride);
|
||||
return resolved;
|
||||
}
|
||||
|
||||
controls.forEach(config => {
|
||||
const btn = el(config.btnId);
|
||||
const menu = el(config.menuId);
|
||||
|
|
@ -2172,7 +2228,7 @@ function initializeEventListeners() {
|
|||
opt.classList.toggle('active', opt.dataset.value === normalized);
|
||||
});
|
||||
if (optionsArg.persist !== false) {
|
||||
persistSessionControl(config.key, normalized);
|
||||
persistSessionControl(config.key, normalized, optionsArg.sessionId || null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2266,9 +2322,12 @@ function initializeEventListeners() {
|
|||
getDefaults() {
|
||||
return { ...modelControlDefaults };
|
||||
},
|
||||
resolveDefaultsForContext,
|
||||
applyDefaultsForContext,
|
||||
setDefaults(values = {}) {
|
||||
setModelControlDefaults(values);
|
||||
},
|
||||
refreshDefaults: refreshModelControlDefaults,
|
||||
refreshCapabilities,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -272,6 +272,20 @@ function _initModelPickerDropdown() {
|
|||
} catch (_) { /* leave stale data; picker still works */ }
|
||||
}
|
||||
|
||||
async function _applyModelControlDefaults(m, persist, sessionId) {
|
||||
if (!m || !window.odysseusModelControls || typeof window.odysseusModelControls.applyDefaultsForContext !== 'function') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await window.odysseusModelControls.applyDefaultsForContext(
|
||||
{ model: m.mid || '', endpointUrl: m.url || '' },
|
||||
{ persist: !!persist, sessionId: sessionId || null },
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn('Model picker: failed to apply model control defaults', e);
|
||||
}
|
||||
}
|
||||
|
||||
function _getAllModels() {
|
||||
const items = (window.modelsModule && window.modelsModule.getCachedItems) ? window.modelsModule.getCachedItems() : [];
|
||||
const result = [];
|
||||
|
|
@ -683,6 +697,7 @@ async function _pick(m) {
|
|||
if (!currentSessionId && _pendingChat) {
|
||||
// Already have a deferred session — just update the model
|
||||
_deps.setPendingChat({ url: m.url, modelId: m.mid, endpointId: m.endpointId, source: 'manual' });
|
||||
await _applyModelControlDefaults(m, false);
|
||||
// Header stays as session name — model switch only updates picker
|
||||
updateModelPicker();
|
||||
uiModule.showToast(`Using ${m.display}`);
|
||||
|
|
@ -692,6 +707,7 @@ async function _pick(m) {
|
|||
// No session yet — create one with this model
|
||||
try {
|
||||
await _deps.createDirectChat(m.url, m.mid, m.endpointId);
|
||||
await _applyModelControlDefaults(m, false);
|
||||
} catch (e) {
|
||||
uiModule.showError('Failed to start chat: ' + e);
|
||||
finishSwitch();
|
||||
|
|
@ -714,6 +730,7 @@ async function _pick(m) {
|
|||
finishSwitch();
|
||||
return;
|
||||
}
|
||||
await _applyModelControlDefaults(m, true, currentSessionId);
|
||||
// Header stays as session name — model info shown in picker only
|
||||
} catch (e) {
|
||||
uiModule.showError('Failed to set model: ' + e);
|
||||
|
|
|
|||
|
|
@ -2192,12 +2192,56 @@ async function _getPreferredDefaultChat() {
|
|||
return null;
|
||||
}
|
||||
|
||||
function _normalizePendingReasoning(value) {
|
||||
let v = String(value || '').trim().toLowerCase().replace(/-/g, '_');
|
||||
if (v === 'x_high') v = 'xhigh';
|
||||
if (v === 'none') v = 'off';
|
||||
return ['off', 'on', 'minimal', 'low', 'medium', 'high', 'xhigh'].includes(v) ? v : '';
|
||||
}
|
||||
|
||||
function _normalizePendingVerbosity(value) {
|
||||
const v = String(value || '').trim().toLowerCase();
|
||||
return ['low', 'medium', 'high'].includes(v) ? v : '';
|
||||
}
|
||||
|
||||
function _resolveInitialModelControls(modelControls) {
|
||||
const defaults = (window.odysseusModelControls && window.odysseusModelControls.getDefaults)
|
||||
? window.odysseusModelControls.getDefaults()
|
||||
: (window.__odysseusModelControlDefaults || {});
|
||||
const source = modelControls || defaults || {};
|
||||
return {
|
||||
reasoning_effort: _normalizePendingReasoning(source.reasoning_effort || source.default_reasoning_effort || ''),
|
||||
verbosity: _normalizePendingVerbosity(source.verbosity || source.default_verbosity || ''),
|
||||
};
|
||||
}
|
||||
|
||||
function _hasExplicitModelControls(modelControls) {
|
||||
if (!modelControls) return false;
|
||||
return Object.prototype.hasOwnProperty.call(modelControls, 'reasoning_effort')
|
||||
|| Object.prototype.hasOwnProperty.call(modelControls, 'default_reasoning_effort')
|
||||
|| Object.prototype.hasOwnProperty.call(modelControls, 'verbosity')
|
||||
|| Object.prototype.hasOwnProperty.call(modelControls, 'default_verbosity');
|
||||
}
|
||||
|
||||
function _defaultsForPendingModel(pending) {
|
||||
if (
|
||||
window.odysseusModelControls
|
||||
&& typeof window.odysseusModelControls.resolveDefaultsForContext === 'function'
|
||||
) {
|
||||
return window.odysseusModelControls.resolveDefaultsForContext({
|
||||
model: (pending && pending.modelId) || '',
|
||||
endpointUrl: (pending && pending.url) || '',
|
||||
});
|
||||
}
|
||||
return _resolveInitialModelControls(null);
|
||||
}
|
||||
|
||||
export function createDirectChat(url, modelId, endpointId, opts = {}) {
|
||||
const incomingSource = opts.source || 'manual';
|
||||
const initialControls = {
|
||||
reasoning_effort: opts.reasoning_effort || opts.default_reasoning_effort || '',
|
||||
verbosity: opts.verbosity || opts.default_verbosity || '',
|
||||
};
|
||||
const defaults = _defaultsForPendingModel({ url, modelId, endpointId });
|
||||
const initialControls = _resolveInitialModelControls(
|
||||
_hasExplicitModelControls(opts) ? opts : defaults,
|
||||
);
|
||||
if (
|
||||
_pendingChat &&
|
||||
_pendingChat.modelId &&
|
||||
|
|
@ -2822,7 +2866,20 @@ function _initAllDropdowns() {
|
|||
getCurrentSessionId: () => currentSessionId,
|
||||
getSessions: () => sessions,
|
||||
getPendingChat: () => _pendingChat,
|
||||
setPendingChat: (v) => { _pendingChat = v; },
|
||||
setPendingChat: (v) => {
|
||||
const controls = _hasExplicitModelControls(v)
|
||||
? _resolveInitialModelControls(v)
|
||||
: _resolveInitialModelControls(_defaultsForPendingModel(v));
|
||||
_pendingChat = v ? { ...v, ...controls } : v;
|
||||
if (_pendingChat && window.odysseusModelControls && window.odysseusModelControls.applySession) {
|
||||
window.odysseusModelControls.applySession({
|
||||
model: _pendingChat.modelId || '',
|
||||
endpoint_url: _pendingChat.url || '',
|
||||
reasoning_effort: _pendingChat.reasoning_effort || null,
|
||||
verbosity: _pendingChat.verbosity || null,
|
||||
});
|
||||
}
|
||||
},
|
||||
createDirectChat,
|
||||
});
|
||||
_initDropdownDismiss();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue