Felipe97/llama-cpp-compiled
01.2k
1/**2 * ParameterSyncService - Syncs sampling parameters with the server3 *4 * Decides for each sampling parameter whether the user's setting is an5 * override of the server default, and normalizes floating-point values.6 * No reactive state; consumed by settingsStore.7 */8 9import { SETTINGS_KEYS, SETTINGS_REGISTRY } from '$lib/constants';10import { ParameterSource, SyncableParameterType } from '$lib/enums';11import type { ParameterInfo, ParameterRecord, ParameterValue, SyncableParameter } from '$lib/types';12import { normalizeFloatingPoint } from '$lib/utils';13 14/** Mapping of UI setting keys to server parameter keys, derived from the registry. */15export const SYNCABLE_PARAMETERS: SyncableParameter[] = SETTINGS_REGISTRY.flatMap(16 (section) => section.settings17)18 .filter((s) => s.sync !== undefined)19 .map((s) => ({20 canSync: true,21 key: s.key,22 serverKey: s.sync!.serverKey,23 type: s.sync!.paramType24 }));25 26export class ParameterSyncService {27 /**28 * Check if a parameter can be synced from server.29 *30 * @param key - The parameter key to check31 * @returns True if the parameter is in the syncable parameters list32 */33 static canSyncParameter(key: string): boolean {34 return SYNCABLE_PARAMETERS.some((param) => param.key === key && param.canSync);35 }36 37 /**38 * Create a diff between current settings and server defaults.39 * Shows which parameters differ from server values, useful for debugging40 * and for the "Reset to defaults" functionality.41 *42 * @param currentSettings - Current parameter values in the settings store43 * @param serverDefaults - Default values extracted from server props44 * @returns Record of parameter diffs with current value, server value, and whether they differ45 */46 static createParameterDiff(47 currentSettings: ParameterRecord,48 serverDefaults: ParameterRecord49 ): Record<string, { current: ParameterValue; server: ParameterValue; differs: boolean }> {50 const diff: Record<51 string,52 { current: ParameterValue; server: ParameterValue; differs: boolean }53 > = {};54 55 for (const key of this.getSyncableParameterKeys()) {56 const currentValue = currentSettings[key];57 const serverValue = serverDefaults[key];58 59 if (serverValue !== undefined) {60 diff[key] = {61 current: currentValue,62 differs: currentValue !== serverValue,63 server: serverValue64 };65 }66 }67 68 return diff;69 }70 71 /**72 * Extract server default parameters that can be synced from `/props` response.73 * Handles both generation settings parameters and UI-specific settings.74 * Converts samplers array to semicolon-delimited string for UI display.75 *76 * @param serverParams - Raw generation settings from server `/props` endpoint77 * @returns Record of extracted parameter key-value pairs with normalized precision78 */79 static extractServerDefaults(80 serverParams: ApiLlamaCppServerProps['default_generation_settings']['params'] | null81 ): ParameterRecord {82 const extracted: ParameterRecord = {};83 84 if (serverParams) {85 for (const param of SYNCABLE_PARAMETERS) {86 if (param.canSync && param.serverKey in serverParams) {87 const value = (serverParams as unknown as Record<string, ParameterValue>)[88 param.serverKey89 ];90 91 if (value !== undefined) {92 // Apply precision rounding to avoid JavaScript floating-point issues93 extracted[param.key] = this.roundFloatingPoint(value);94 }95 }96 }97 98 // Handle samplers array conversion to string99 if (serverParams.samplers && Array.isArray(serverParams.samplers)) {100 extracted[SETTINGS_KEYS.SAMPLERS] = serverParams.samplers.join(';');101 }102 }103 104 return extracted;105 }106 107 /**108 * Get parameter information including source and values.109 * Used by SettingsChatParameterSourceIndicator to display the correct badge110 * (Custom vs Default) for each parameter in the settings UI.111 *112 * @param key - The parameter key to get info for113 * @param currentValue - The current value of the parameter114 * @param propsDefaults - Server default values from `/props`115 * @param userOverrides - Set of parameter keys explicitly overridden by the user116 * @returns Parameter info with source, server default, and user override values117 */118 static getParameterInfo(119 key: string,120 currentValue: ParameterValue,121 propsDefaults: ParameterRecord,122 userOverrides: Set<string>123 ): ParameterInfo {124 const hasPropsDefault = propsDefaults[key] !== undefined;125 const isUserOverride = userOverrides.has(key);126 // Simple logic: either using default (from props) or custom (user override)127 const source = isUserOverride ? ParameterSource.CUSTOM : ParameterSource.DEFAULT;128 129 return {130 serverDefault: hasPropsDefault ? propsDefaults[key] : undefined, // Keep same field name for compatibility131 source,132 userOverride: isUserOverride ? currentValue : undefined,133 value: currentValue134 };135 }136 137 /**138 * Get all syncable parameter keys.139 *140 * @returns Array of parameter keys that can be synced from server141 */142 static getSyncableParameterKeys(): string[] {143 return SYNCABLE_PARAMETERS.filter((param) => param.canSync).map((param) => param.key);144 }145 146 /**147 * Merge server defaults with current user settings.148 * User overrides always take priority — only parameters not in `userOverrides`149 * set will be updated from server defaults.150 *151 * @param currentSettings - Current parameter values in the settings store152 * @param serverDefaults - Default values extracted from server props153 * @param userOverrides - Set of parameter keys explicitly overridden by the user154 * @returns Merged parameter record with user overrides preserved155 */156 static mergeWithServerDefaults(157 currentSettings: ParameterRecord,158 serverDefaults: ParameterRecord,159 userOverrides: Set<string> = new Set()160 ): ParameterRecord {161 const merged = { ...currentSettings };162 163 for (const [key, serverValue] of Object.entries(serverDefaults)) {164 // Only update if user hasn't explicitly overridden this parameter165 if (!userOverrides.has(key)) {166 merged[key] = this.roundFloatingPoint(serverValue);167 }168 }169 170 return merged;171 }172 173 /**174 * Validate a server parameter value against its expected type.175 *176 * @param key - The parameter key to validate177 * @param value - The value to validate178 * @returns True if value matches the expected type for this parameter179 */180 static validateServerParameter(key: string, value: ParameterValue): boolean {181 const param = SYNCABLE_PARAMETERS.find((p) => p.key === key);182 183 if (!param) return false;184 185 switch (param.type) {186 case SyncableParameterType.NUMBER:187 return typeof value === 'number' && !isNaN(value);188 case SyncableParameterType.STRING:189 return typeof value === 'string';190 case SyncableParameterType.BOOLEAN:191 return typeof value === 'boolean';192 default:193 return false;194 }195 }196 197 /**198 * Round floating-point numbers to avoid JavaScript precision issues.199 * E.g., 0.1 + 0.2 = 0.30000000000000004 → 0.3200 *201 * @param value - Parameter value to normalize202 * @returns Precision-normalized value203 */204 private static roundFloatingPoint(value: ParameterValue): ParameterValue {205 return normalizeFloatingPoint(value) as ParameterValue;206 }207}208 