Changeset 0.37.5 (#217)

Co-authored-by: gobha <jasafpro@gmail.com>
Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
2026-03-21 13:41:25 +00:00
committed by xcaliber
parent 05b5affdac
commit 74f3cb84e9
27 changed files with 2211 additions and 667 deletions

View File

@@ -0,0 +1,130 @@
/**
* GeneralSection — chat defaults: model, system prompt, max tokens, temperature, thinking
*/
const { html } = window;
const { useState, useEffect, useCallback, useRef } = hooks;
export function GeneralSection() {
const [models, setModels] = useState([]);
const [settings, setSettings] = useState({});
const [saving, setSaving] = useState(false);
const [maxHint, setMaxHint] = useState('');
const tempRef = useRef(null);
// Load settings + models
useEffect(() => {
(async () => {
try {
const [s, m] = await Promise.all([
sw.api.profile.settings(),
sw.api.models.enabled(),
]);
const sObj = s || {};
setSettings({
model: sObj.model || '',
system_prompt: sObj.system_prompt || '',
max_tokens: sObj.max_tokens || 0,
temperature: sObj.temperature ?? 0.7,
show_thinking: sObj.show_thinking || false,
});
const modelList = (m?.data || m || []).filter(x => !x.hidden);
setModels(modelList);
// Set initial max hint
const active = modelList.find(x => x.id === sObj.model);
if (active?.capabilities?.max_output_tokens > 0) {
setMaxHint(`(model max: ${(active.capabilities.max_output_tokens / 1000).toFixed(0)}K)`);
}
} catch (e) {
console.warn('[settings/general] Load failed:', e.message);
}
})();
}, []);
const onModelChange = useCallback((e) => {
const id = e.target.value;
setSettings(s => ({ ...s, model: id }));
const m = models.find(x => x.id === id);
const cap = m?.capabilities || {};
setMaxHint(cap.max_output_tokens > 0
? `(model max: ${(cap.max_output_tokens / 1000).toFixed(0)}K)` : '');
}, [models]);
const onTempInput = useCallback((e) => {
setSettings(s => ({ ...s, temperature: parseFloat(e.target.value) }));
}, []);
const save = useCallback(async () => {
setSaving(true);
try {
await sw.api.profile.updateSettings({
model: settings.model,
system_prompt: settings.system_prompt,
max_tokens: settings.max_tokens,
temperature: settings.temperature,
show_thinking: settings.show_thinking,
});
sw.emit('toast', { message: 'Settings saved', variant: 'success' });
} catch (e) {
sw.emit('toast', { message: e.message, variant: 'error' });
} finally {
setSaving(false);
}
}, [settings]);
return html`
<div class="settings-section">
<h3>Chat Defaults</h3>
<div class="form-group">
<label>Default Model</label>
<select value=${settings.model} onChange=${onModelChange}>
${models.map(m => html`
<option value=${m.id}>
${m.name || m.id}${m.provider ? ` (${m.provider})` : ''}
</option>
`)}
</select>
</div>
<div class="form-group">
<label>System Prompt</label>
<textarea rows="3" placeholder="Optional system prompt\u2026"
style="max-width:100%;"
value=${settings.system_prompt}
onInput=${e => setSettings(s => ({ ...s, system_prompt: e.target.value }))} />
</div>
<div style="display:flex;gap:16px;">
<div class="form-group" style="flex:1;">
<label>Max Tokens${' '}
<span style="font-weight:400;color:var(--text-3);">${maxHint}</span>
</label>
<input type="number" placeholder="default"
value=${settings.max_tokens || ''}
onInput=${e => setSettings(s => ({ ...s, max_tokens: parseInt(e.target.value) || 0 }))} />
</div>
<div class="form-group" style="flex:1;">
<label>Temperature</label>
<div style="display:flex;align-items:center;gap:8px;">
<input type="range" min="0" max="2" step="0.1"
ref=${tempRef}
value=${settings.temperature}
onInput=${onTempInput}
style="flex:1;" />
<span style="font-size:12px;color:var(--text-2);font-family:var(--mono);">
${settings.temperature}
</span>
</div>
</div>
</div>
<label style="display:flex;align-items:center;gap:8px;font-size:13px;color:var(--text-2);cursor:pointer;margin-top:4px;">
<input type="checkbox"
checked=${settings.show_thinking}
onChange=${e => setSettings(s => ({ ...s, show_thinking: e.target.checked }))} />
Show thinking blocks
</label>
</div>
<button class="btn-md btn-primary" style="margin-top:12px;"
disabled=${saving} onClick=${save}>
${saving ? 'Saving\u2026' : 'Save'}
</button>
`;
}