{#if field.type === SettingsFieldType.INPUT}
- {@const paramInfo = getParameterSourceInfo(field.key)}
{@const currentValue = String(localConfig[field.key] ?? '')}
- {@const propsDefault = paramInfo?.serverDefault}
+ {@const serverDefault = sp[field.key]}
{@const isCustomRealTime = (() => {
- if (!paramInfo || propsDefault === undefined) return false;
+ if (serverDefault == null) return false;
+ if (currentValue === '') return false;
- // Apply same rounding logic for real-time comparison
- const inputValue = currentValue;
- const numericInput = parseFloat(inputValue);
+ const numericInput = parseFloat(currentValue);
const normalizedInput = !isNaN(numericInput)
? Math.round(numericInput * 1000000) / 1000000
- : inputValue;
+ : currentValue;
const normalizedDefault =
- typeof propsDefault === 'number'
- ? Math.round(propsDefault * 1000000) / 1000000
- : propsDefault;
+ typeof serverDefault === 'number'
+ ? Math.round(serverDefault * 1000000) / 1000000
+ : serverDefault;
return normalizedInput !== normalizedDefault;
})()}
@@ -74,7 +78,9 @@
// Update local config immediately for real-time badge feedback
onConfigChange(field.key, e.currentTarget.value);
}}
- placeholder={`Default: ${SETTING_CONFIG_DEFAULT[field.key] ?? 'none'}`}
+ placeholder={sp[field.key] != null
+ ? `Default: ${normalizeFloatingPoint(sp[field.key])}`
+ : ''}
class="w-full {isCustomRealTime ? 'pr-8' : ''}"
/>
{#if isCustomRealTime}
@@ -82,9 +88,7 @@
type="button"
onclick={() => {
settingsStore.resetParameterToServerDefault(field.key);
- // Trigger UI update by calling onConfigChange with the default value
- const defaultValue = propsDefault ?? SETTING_CONFIG_DEFAULT[field.key];
- onConfigChange(field.key, String(defaultValue));
+ onConfigChange(field.key, '');
}}
class="absolute top-1/2 right-2 inline-flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded transition-colors hover:bg-muted"
aria-label="Reset to default"
@@ -112,7 +116,7 @@
id={field.key}
value={String(localConfig[field.key] ?? '')}
onchange={(e) => onConfigChange(field.key, e.currentTarget.value)}
- placeholder={`Default: ${SETTING_CONFIG_DEFAULT[field.key] ?? 'none'}`}
+ placeholder=""
class="min-h-[10rem] w-full md:max-w-2xl"
/>
@@ -140,14 +144,12 @@
(opt: { value: string; label: string; icon?: Component }) =>
opt.value === localConfig[field.key]
)}
- {@const paramInfo = getParameterSourceInfo(field.key)}
{@const currentValue = localConfig[field.key]}
- {@const propsDefault = paramInfo?.serverDefault}
+ {@const serverDefault = sp[field.key]}
{@const isCustomRealTime = (() => {
- if (!paramInfo || propsDefault === undefined) return false;
-
- // For select fields, do direct comparison (no rounding needed)
- return currentValue !== propsDefault;
+ if (serverDefault == null) return false;
+ if (currentValue === '' || currentValue === undefined) return false;
+ return currentValue !== serverDefault;
})()}
@@ -190,9 +192,7 @@
type="button"
onclick={() => {
settingsStore.resetParameterToServerDefault(field.key);
- // Trigger UI update by calling onConfigChange with the default value
- const defaultValue = propsDefault ?? SETTING_CONFIG_DEFAULT[field.key];
- onConfigChange(field.key, String(defaultValue));
+ onConfigChange(field.key, '');
}}
class="absolute top-1/2 right-8 inline-flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded transition-colors hover:bg-muted"
aria-label="Reset to default"
diff --git a/tools/server/webui/src/lib/constants/settings-config.ts b/tools/server/webui/src/lib/constants/settings-config.ts
index e76fa89e9a..e1ff5f30eb 100644
--- a/tools/server/webui/src/lib/constants/settings-config.ts
+++ b/tools/server/webui/src/lib/constants/settings-config.ts
@@ -30,27 +30,30 @@ export const SETTING_CONFIG_DEFAULT: Record =
agenticMaxToolPreviewLines: 25,
showToolCallInProgress: false,
alwaysShowAgenticTurns: false,
- // make sure these default values are in sync with `common.h`
- samplers: 'top_k;typ_p;top_p;min_p;temperature',
+ // sampling params: empty means "use server default"
+ // the server / preset is the source of truth
+ // empty values are shown as placeholders from /props in the UI
+ // and are NOT sent in API requests, letting the server decide
+ samplers: '',
backend_sampling: false,
- temperature: 0.8,
- dynatemp_range: 0.0,
- dynatemp_exponent: 1.0,
- top_k: 40,
- top_p: 0.95,
- min_p: 0.05,
- xtc_probability: 0.0,
- xtc_threshold: 0.1,
- typ_p: 1.0,
- repeat_last_n: 64,
- repeat_penalty: 1.0,
- presence_penalty: 0.0,
- frequency_penalty: 0.0,
- dry_multiplier: 0.0,
- dry_base: 1.75,
- dry_allowed_length: 2,
- dry_penalty_last_n: -1,
- max_tokens: -1,
+ temperature: '',
+ dynatemp_range: '',
+ dynatemp_exponent: '',
+ top_k: '',
+ top_p: '',
+ min_p: '',
+ xtc_probability: '',
+ xtc_threshold: '',
+ typ_p: '',
+ repeat_last_n: '',
+ repeat_penalty: '',
+ presence_penalty: '',
+ frequency_penalty: '',
+ dry_multiplier: '',
+ dry_base: '',
+ dry_allowed_length: '',
+ dry_penalty_last_n: '',
+ max_tokens: '',
custom: '', // custom json-stringified object
// experimental features
pyInterpreterEnabled: false,
diff --git a/tools/server/webui/src/lib/stores/settings.svelte.ts b/tools/server/webui/src/lib/stores/settings.svelte.ts
index 8ab817c071..2fbff8312f 100644
--- a/tools/server/webui/src/lib/stores/settings.svelte.ts
+++ b/tools/server/webui/src/lib/stores/settings.svelte.ts
@@ -289,16 +289,10 @@ class SettingsStore {
const serverDefaults = this.getServerDefaults();
if (serverDefaults[key] !== undefined) {
- const value = normalizeFloatingPoint(serverDefaults[key]);
-
- this.config[key as keyof SettingsConfigType] =
- value as SettingsConfigType[keyof SettingsConfigType];
- } else {
- if (key in SETTING_CONFIG_DEFAULT) {
- const defaultValue = getConfigValue(SETTING_CONFIG_DEFAULT, key);
-
- setConfigValue(this.config, key, defaultValue);
- }
+ // sampling param known by server: clear it, let server decide
+ setConfigValue(this.config, key, '');
+ } else if (key in SETTING_CONFIG_DEFAULT) {
+ setConfigValue(this.config, key, getConfigValue(SETTING_CONFIG_DEFAULT, key));
}
this.userOverrides.delete(key);
@@ -319,12 +313,7 @@ class SettingsStore {
*/
syncWithServerDefaults(): void {
const propsDefaults = this.getServerDefaults();
-
- if (Object.keys(propsDefaults).length === 0) {
- console.warn('No server defaults available for initialization');
-
- return;
- }
+ if (Object.keys(propsDefaults).length === 0) return;
for (const [key, propsValue] of Object.entries(propsDefaults)) {
const currentValue = getConfigValue(this.config, key);
@@ -332,17 +321,14 @@ class SettingsStore {
const normalizedCurrent = normalizeFloatingPoint(currentValue);
const normalizedDefault = normalizeFloatingPoint(propsValue);
+ // if user value matches server, it's not a real override
if (normalizedCurrent === normalizedDefault) {
this.userOverrides.delete(key);
- setConfigValue(this.config, key, propsValue);
- } else if (!this.userOverrides.has(key)) {
- setConfigValue(this.config, key, propsValue);
}
}
this.saveConfig();
- console.log('Settings initialized with props defaults:', propsDefaults);
- console.log('Current user overrides after sync:', Array.from(this.userOverrides));
+ console.log('User overrides after sync:', Array.from(this.userOverrides));
}
/**
@@ -352,19 +338,11 @@ class SettingsStore {
*/
forceSyncWithServerDefaults(): void {
const propsDefaults = this.getServerDefaults();
- const syncableKeys = ParameterSyncService.getSyncableParameterKeys();
-
- for (const key of syncableKeys) {
+ for (const key of ParameterSyncService.getSyncableParameterKeys()) {
if (propsDefaults[key] !== undefined) {
- const normalizedValue = normalizeFloatingPoint(propsDefaults[key]);
-
- setConfigValue(this.config, key, normalizedValue);
- } else {
- if (key in SETTING_CONFIG_DEFAULT) {
- const defaultValue = getConfigValue(SETTING_CONFIG_DEFAULT, key);
-
- setConfigValue(this.config, key, defaultValue);
- }
+ setConfigValue(this.config, key, '');
+ } else if (key in SETTING_CONFIG_DEFAULT) {
+ setConfigValue(this.config, key, getConfigValue(SETTING_CONFIG_DEFAULT, key));
}
this.userOverrides.delete(key);