diff --git a/src/lib/llmParams.ts b/src/lib/llmParams.ts new file mode 100644 index 0000000..d1a79aa --- /dev/null +++ b/src/lib/llmParams.ts @@ -0,0 +1,317 @@ +// Ollama advanced `options` parameters (T5.2) — the single source of truth that +// drives the Settings ▸ AI advanced form: rendering, defaults, per-field reset, +// and only-send-if-changed. System prompt / think / keep_alive are top-level +// request fields handled separately in the UI; everything here goes in `options`. +// +// Defaults + ranges per the Ollama Modelfile/API reference. + +export type OllamaGroup = "sampling" | "repetition" | "mirostat" | "context" | "hardware"; + +export interface OllamaOption { + key: string; + group: OllamaGroup; + label: string; + kind: "number" | "bool" | "enum" | "tags"; + /** Undefined = "auto" (no fixed default): the field is empty until set. */ + default?: number | boolean; + min?: number; + max?: number; + step?: number; + enumOptions?: { value: number; label: string }[]; + help: string; + /** Dimmed unless Mirostat is enabled (mirostat != 0). */ + needsMirostat?: boolean; +} + +export const OLLAMA_OPTIONS: OllamaOption[] = [ + // ── Sampling ────────────────────────────────────────────────────────────── + { + key: "temperature", + group: "sampling", + label: "Temperature", + kind: "number", + default: 0.8, + min: 0, + max: 2, + step: 0.05, + help: "Randomness / creativity. Higher is more creative.", + }, + { + key: "top_k", + group: "sampling", + label: "Top K", + kind: "number", + default: 40, + min: 0, + max: 200, + step: 1, + help: "Sample only from the K most likely tokens.", + }, + { + key: "top_p", + group: "sampling", + label: "Top P", + kind: "number", + default: 0.9, + min: 0, + max: 1, + step: 0.05, + help: "Nucleus sampling cumulative probability.", + }, + { + key: "min_p", + group: "sampling", + label: "Min P", + kind: "number", + default: 0.0, + min: 0, + max: 1, + step: 0.01, + help: "Minimum probability relative to the top token.", + }, + { + key: "typical_p", + group: "sampling", + label: "Typical P", + kind: "number", + default: 1.0, + min: 0, + max: 1, + step: 0.05, + help: "Locally-typical sampling.", + }, + { + key: "tfs_z", + group: "sampling", + label: "Tail-free (tfs_z)", + kind: "number", + default: 1.0, + min: 0, + max: 2, + step: 0.05, + help: "Tail-free sampling. 1.0 disables it (legacy).", + }, + { + key: "seed", + group: "sampling", + label: "Seed", + kind: "number", + default: 0, + min: 0, + step: 1, + help: "Fixed seed → reproducible output. 0 = random.", + }, + { + key: "num_predict", + group: "sampling", + label: "Max tokens (num_predict)", + kind: "number", + default: -1, + min: -2, + step: 1, + help: "Max tokens to generate. -1 = unlimited, -2 = fill context.", + }, + + // ── Repetition ──────────────────────────────────────────────────────────── + { + key: "repeat_penalty", + group: "repetition", + label: "Repeat penalty", + kind: "number", + default: 1.1, + min: 0, + max: 2, + step: 0.05, + help: "How strongly to penalize repetition.", + }, + { + key: "repeat_last_n", + group: "repetition", + label: "Repeat lookback", + kind: "number", + default: 64, + min: -1, + step: 1, + help: "Tokens to look back for repetition. 0 = off, -1 = num_ctx.", + }, + { + key: "presence_penalty", + group: "repetition", + label: "Presence penalty", + kind: "number", + default: 0.0, + min: -2, + max: 2, + step: 0.1, + help: "Penalize tokens that already appeared.", + }, + { + key: "frequency_penalty", + group: "repetition", + label: "Frequency penalty", + kind: "number", + default: 0.0, + min: -2, + max: 2, + step: 0.1, + help: "Penalize tokens by how often they appear.", + }, + { + key: "penalize_newline", + group: "repetition", + label: "Penalize newlines", + kind: "bool", + default: true, + help: "Apply the repeat penalty to newline tokens.", + }, + + // ── Mirostat ────────────────────────────────────────────────────────────── + { + key: "mirostat", + group: "mirostat", + label: "Mirostat", + kind: "enum", + default: 0, + enumOptions: [ + { value: 0, label: "Off" }, + { value: 1, label: "Mirostat 1" }, + { value: 2, label: "Mirostat 2" }, + ], + help: "Adaptive perplexity control.", + }, + { + key: "mirostat_tau", + group: "mirostat", + label: "Mirostat τ (tau)", + kind: "number", + default: 5.0, + min: 0, + max: 10, + step: 0.1, + help: "Balance of coherence vs diversity.", + needsMirostat: true, + }, + { + key: "mirostat_eta", + group: "mirostat", + label: "Mirostat η (eta)", + kind: "number", + default: 0.1, + min: 0, + max: 1, + step: 0.01, + help: "How fast it adapts to feedback.", + needsMirostat: true, + }, + + // ── Context & session ───────────────────────────────────────────────────── + { + key: "num_ctx", + group: "context", + label: "Context size (num_ctx)", + kind: "number", + default: 4096, + min: 256, + step: 256, + help: "Context window in tokens.", + }, + { + key: "num_keep", + group: "context", + label: "Keep tokens (num_keep)", + kind: "number", + default: 4, + min: 0, + step: 1, + help: "Tokens kept from the start of the prompt when truncating.", + }, + { + key: "stop", + group: "context", + label: "Stop sequences", + kind: "tags", + help: "Comma-separated strings that end generation.", + }, + + // ── Runtime & hardware (rarely needed) ──────────────────────────────────── + { + key: "num_batch", + group: "hardware", + label: "Batch size (num_batch)", + kind: "number", + default: 512, + min: 1, + step: 1, + help: "Prompt processing batch size.", + }, + { + key: "num_gpu", + group: "hardware", + label: "GPU layers (num_gpu)", + kind: "number", + min: 0, + step: 1, + help: "Layers to offload to the GPU. Blank = auto.", + }, + { + key: "main_gpu", + group: "hardware", + label: "Main GPU", + kind: "number", + default: 0, + min: 0, + step: 1, + help: "Which GPU to use for a single-GPU offload.", + }, + { + key: "num_thread", + group: "hardware", + label: "CPU threads (num_thread)", + kind: "number", + min: 1, + step: 1, + help: "Threads for computation. Blank = auto.", + }, + { + key: "low_vram", + group: "hardware", + label: "Low VRAM", + kind: "bool", + default: false, + help: "Reduce VRAM use at the cost of speed.", + }, + { + key: "numa", + group: "hardware", + label: "NUMA", + kind: "bool", + default: false, + help: "Enable NUMA support.", + }, + { + key: "use_mmap", + group: "hardware", + label: "Use mmap", + kind: "bool", + default: true, + help: "Memory-map the model file.", + }, + { + key: "use_mlock", + group: "hardware", + label: "Use mlock", + kind: "bool", + default: false, + help: "Lock the model in RAM (no swap).", + }, +]; + +export const THINK_OPTIONS = ["off", "low", "medium", "high", "max"] as const; + +export const OLLAMA_GROUP_LABELS: Record = { + sampling: "Sampling", + repetition: "Repetition", + mirostat: "Mirostat", + context: "Context & session", + hardware: "Runtime & hardware", +};