Initial ForgeLM import

This commit is contained in:
Evandro Fonseca Junior committed 2026-03-29 19:10:57 -03:00
commit a392b9dc60
4296 files changed
+1212675

No files matched your search

@@ -0,0 +1,962 @@
import { useEffect, useMemo, useRef, useState } from "react";
import {
getModelLibraryState,
pickRuntimeModelFiles,
pickRuntimeModelsDir,
queryRuntimeGpu,
scanRuntimeModels,
searchHuggingFaceModels,
} from "../api";
import {
chooseModel,
createRuntimeConfigPatch,
dedupeModels,
getLocalRuntimeStartReason,
pathName,
resolveDraftModelSelection,
toModelFile,
} from "../runtime-settings-form";
import {
createRuntimeDraftFieldState,
type ModelLibraryState,
type HuggingFaceModelResult,
type RuntimeConfig,
type RuntimeDraftFieldKey,
type RuntimeDraftFieldMeta,
type RuntimeDraftFieldState,
type RuntimeGpuInfo,
type RuntimeLifecycleResult,
type RuntimeModelFile,
type RuntimeSnapshot,
} from "../types";
import "./RuntimeSettingsDrawer.css";
const CTX_PRESETS = [2048, 4096, 8192, 16384, 32768, 65536];
const REMOTE_PRESET_TEMPLATES = [
{ id: "openai", label: "OpenAI", provider: "open_ai", baseUrl: "https://api.openai.com/v1" },
{ id: "openrouter", label: "OpenRouter", provider: "open_router", baseUrl: "https://openrouter.ai/api/v1" },
{ id: "anthropic", label: "Anthropic", provider: "anthropic", baseUrl: "https://api.anthropic.com/v1" },
] as const;
interface Props {
open: boolean;
snapshot: RuntimeSnapshot;
busy: boolean;
activeLifecycleCommand?: RuntimeSnapshot["active_command"];
lastLifecycleResult?: RuntimeLifecycleResult;
lifecycleBusy?: boolean;
applyImpact?: "immediate" | "restart_required" | "save_before_apply";
onClose: () => void;
onSave: (patch: Partial<RuntimeConfig>) => Promise<RuntimeSnapshot>;
onStart: () => Promise<unknown>;
onStop: () => Promise<unknown>;
draftConfig?: RuntimeConfig;
savedBaseline?: RuntimeConfig;
draftDirty?: boolean;
draftFields?: RuntimeDraftFieldState;
onUpdateDraft?: (patch: Partial<RuntimeConfig>) => void;
onUpdateDraftFieldMeta?: (field: RuntimeDraftFieldKey, patch: Partial<RuntimeDraftFieldMeta>) => void;
onResetDraft?: () => void;
}
function valuesEqual(left: unknown, right: unknown): boolean {
return JSON.stringify(left) === JSON.stringify(right);
}
function maskSecret(value: string): string {
if (!value.trim()) return "Not configured";
return `${"*".repeat(Math.max(4, Math.min(12, value.trim().length)))} (${value.trim().length} chars)`;
}
function formatReferenceValue(field: keyof RuntimeConfig, value: RuntimeConfig[keyof RuntimeConfig]): string {
switch (field) {
case "connection_mode":
return value === "remote" ? "Remote API" : "Local API";
case "start_policy":
return value === "on_app_launch" ? "Start on app launch" : "Start manually";
case "server_url":
return String(value || "Not configured");
case "api_key":
return maskSecret(String(value || ""));
case "model_path":
return value ? pathName(String(value)) : "No model selected";
case "models_dir":
return String(value || "No folder selected");
case "addr":
return `http://${String(value || "127.0.0.1:8080")}`;
case "gpu_layers":
return `${String(value)} GPU layers`;
case "ctx_size":
return `${String(value)} context tokens`;
case "selected_model_id":
return String(value || "No managed model selected");
case "hugging_face_token":
return maskSecret(String(value || ""));
default:
return Array.isArray(value) ? `${value.length} configured` : String(value || "-");
}
}
export default function RuntimeSettingsDrawer({
open,
snapshot,
busy,
activeLifecycleCommand = snapshot.active_command,
lastLifecycleResult = snapshot.last_command_result,
lifecycleBusy = false,
applyImpact = "immediate",
onClose,
onSave,
onStart,
onStop,
draftConfig: controlledDraftConfig,
savedBaseline: controlledSavedBaseline,
draftDirty: controlledDraftDirty,
draftFields: controlledDraftFields,
onUpdateDraft,
onUpdateDraftFieldMeta,
onResetDraft,
}: Props) {
const draftConfig = controlledDraftConfig ?? snapshot.config;
const savedBaseline = controlledSavedBaseline ?? snapshot.config;
const draftFields = controlledDraftFields ?? createRuntimeDraftFieldState();
const draftDirty = controlledDraftDirty ?? !valuesEqual(draftConfig, savedBaseline);
const draftConfigRef = useRef(draftConfig);
const requestIdsRef = useRef<Record<string, number>>({});
const [scannedModels, setScannedModels] = useState<RuntimeModelFile[]>([]);
const [gpuInfo, setGpuInfo] = useState<RuntimeGpuInfo | null>(null);
const [gpuError, setGpuError] = useState("");
const [localError, setLocalError] = useState("");
const [scanning, setScanning] = useState(false);
const [hfQuery, setHfQuery] = useState("");
const [hfResults, setHfResults] = useState<HuggingFaceModelResult[]>([]);
const [hfLoading, setHfLoading] = useState(false);
const [libraryState, setLibraryState] = useState<ModelLibraryState>({ entries: [], managed_dir: "" });
const [confirmDiscard, setConfirmDiscard] = useState(false);
useEffect(() => {
draftConfigRef.current = draftConfig;
}, [draftConfig]);
const updateDraft = (patch: Partial<RuntimeConfig>) => {
onUpdateDraft?.(patch);
};
const updateDraftFieldMeta = (field: RuntimeDraftFieldKey, patch: Partial<RuntimeDraftFieldMeta>) => {
onUpdateDraftFieldMeta?.(field, patch);
};
const beginRequest = (key: string) => {
const nextId = (requestIdsRef.current[key] ?? 0) + 1;
requestIdsRef.current[key] = nextId;
return nextId;
};
const isLatestRequest = (key: string, requestId: number) => requestIdsRef.current[key] === requestId;
const extraModels = useMemo(
() => draftConfig.extra_model_paths.map(toModelFile),
[draftConfig.extra_model_paths],
);
const allModels = useMemo(() => {
const merged = dedupeModels([...scannedModels, ...extraModels]);
if (draftConfig.model_path && !merged.some((model) => model.path === draftConfig.model_path)) {
return [toModelFile(draftConfig.model_path), ...merged];
}
return merged;
}, [draftConfig.model_path, extraModels, scannedModels]);
const dirtyFieldCount = useMemo(() => {
const trackedFields: Array<keyof RuntimeConfig> = [
"connection_mode",
"server_url",
"api_key",
"models_dir",
"model_path",
"addr",
"ctx_size",
"gpu_layers",
"start_policy",
"hugging_face_token",
];
return trackedFields.filter((field) => !valuesEqual(draftConfig[field], savedBaseline[field])).length;
}, [draftConfig, savedBaseline]);
const hasInvalidDraft = Object.values(draftFields).some((meta) => meta?.invalid);
const hasPendingDraft = Object.values(draftFields).some((meta) => meta?.pending);
const hasBlockingDraftState = hasInvalidDraft || hasPendingDraft;
const hasPendingModeChange = draftConfig.connection_mode !== savedBaseline.connection_mode;
const restartRequiredWhileRunning =
draftDirty && draftConfig.connection_mode === "local" && snapshot.process_running && applyImpact === "restart_required";
const maxLayers = gpuInfo?.recommended_layers ?? 200;
const startReason = getLocalRuntimeStartReason({
mode: draftConfig.connection_mode,
binaryPath: snapshot.binary_path,
selectedModel: draftConfig.model_path || "",
});
const isFieldDirty = (field: keyof RuntimeConfig) => !valuesEqual(draftConfig[field], savedBaseline[field]);
const fieldMeta = (field: RuntimeDraftFieldKey) => draftFields[field] ?? { invalid: false, pending: false, message: null };
const showLifecycleResult = lastLifecycleResult.command !== "idle" && !lifecycleBusy;
const applyGuidance = !draftDirty || draftConfig.connection_mode !== "local"
? null
: hasPendingModeChange || applyImpact === "save_before_apply"
? "Stop the local API or save first before applying this change."
: applyImpact === "restart_required"
? "Restart required to apply saved changes."
: "Applies immediately after save.";
const saveLabel = activeLifecycleCommand === "save" ? "Saving changes..." : "Save changes";
const tertiaryLabel = hasPendingModeChange
? "Save mode before applying"
: activeLifecycleCommand === "start"
? "Starting local API..."
: activeLifecycleCommand === "stop"
? "Stopping local API..."
: restartRequiredWhileRunning
? "Restart required to apply saved changes"
: snapshot.process_running
? "Stop local API"
: "Save and start local API";
const renderFieldState = (field: RuntimeDraftFieldKey) => {
const meta = fieldMeta(field);
const dirty = isFieldDirty(field);
if (!dirty && !meta.invalid && !meta.pending) {
return null;
}
return (
<div className={`runtime-field-state${dirty ? " is-draft" : ""}${meta.invalid ? " is-invalid" : ""}`}>
<div className="runtime-field-state-row">
{dirty && <span className="runtime-field-badge">Draft</span>}
{meta.invalid && <span className="runtime-field-badge runtime-field-badge-danger">Invalid</span>}
{meta.pending && <span className="runtime-field-badge runtime-field-badge-pending">Pending</span>}
{dirty && (
<>
<span className="runtime-field-state-label">Live now</span>
<span className="runtime-field-state-value">{formatReferenceValue(field, savedBaseline[field])}</span>
</>
)}
</div>
{meta.message && <div className="runtime-field-error-text">{meta.message}</div>}
</div>
);
};
const applyResolvedModelState = (models: RuntimeModelFile[]) => {
const currentDraft = draftConfigRef.current;
const resolved = resolveDraftModelSelection(currentDraft.model_path || "", models, currentDraft.extra_model_paths.map(toModelFile));
updateDraft({
model_path: resolved.nextModel || null,
selected_model_id:
resolved.invalid || resolved.nextModel === currentDraft.model_path
? currentDraft.selected_model_id
: null,
});
updateDraftFieldMeta("model_path", {
invalid: resolved.invalid,
pending: false,
message: resolved.message,
});
};
const loadModelLibrary = async () => {
const requestId = beginRequest("library");
try {
const state = await getModelLibraryState();
if (!isLatestRequest("library", requestId)) return;
setLibraryState(state);
} catch (error) {
if (!isLatestRequest("library", requestId)) return;
setLocalError(String(error));
}
};
const loadGpuInfo = async () => {
const requestId = beginRequest("gpu");
try {
const info = await queryRuntimeGpu();
if (!isLatestRequest("gpu", requestId)) return;
setGpuInfo(info);
setGpuError("");
if (info && draftConfigRef.current.gpu_layers === 0) {
updateDraft({ gpu_layers: info.recommended_layers });
}
} catch (error) {
if (!isLatestRequest("gpu", requestId)) return;
setGpuError(String(error));
}
};
const handleRescan = async (dir = draftConfigRef.current.models_dir || "") => {
if (!dir.trim()) return;
const requestId = beginRequest("model-selection");
setScanning(true);
setLocalError("");
updateDraftFieldMeta("models_dir", { pending: true, invalid: false, message: null });
updateDraftFieldMeta("model_path", { pending: true });
try {
const models = await scanRuntimeModels(dir.trim());
if (!isLatestRequest("model-selection", requestId)) return;
setScannedModels(models);
applyResolvedModelState(models);
updateDraftFieldMeta("models_dir", { pending: false, invalid: false, message: null });
} catch (error) {
if (!isLatestRequest("model-selection", requestId)) return;
setLocalError(String(error));
setScannedModels([]);
updateDraftFieldMeta("models_dir", { pending: false });
updateDraftFieldMeta("model_path", { pending: false });
} finally {
if (isLatestRequest("model-selection", requestId)) {
setScanning(false);
}
}
};
const handlePickDir = async () => {
const requestId = beginRequest("model-selection");
setLocalError("");
updateDraftFieldMeta("models_dir", { pending: true, invalid: false, message: null });
updateDraftFieldMeta("model_path", { pending: true });
try {
const result = await pickRuntimeModelsDir();
if (!isLatestRequest("model-selection", requestId) || !result) return;
updateDraft({ models_dir: result.dir });
setScannedModels(result.models);
applyResolvedModelState(result.models);
updateDraftFieldMeta("models_dir", { pending: false, invalid: false, message: null });
} catch (error) {
if (!isLatestRequest("model-selection", requestId)) return;
setLocalError(String(error));
updateDraftFieldMeta("models_dir", { pending: false });
updateDraftFieldMeta("model_path", { pending: false });
}
};
const handlePickFiles = async () => {
const requestId = beginRequest("model-selection");
setLocalError("");
updateDraftFieldMeta("model_path", { pending: true });
try {
const picked = await pickRuntimeModelFiles();
if (!isLatestRequest("model-selection", requestId) || picked.length === 0) {
updateDraftFieldMeta("model_path", { pending: false });
return;
}
const currentDraft = draftConfigRef.current;
const nextExtra = dedupeModels([...currentDraft.extra_model_paths.map(toModelFile), ...picked]);
const nextModel = currentDraft.model_path || nextExtra[0]?.path || "";
updateDraft({
extra_model_paths: nextExtra.map((model) => model.path),
model_path: nextModel || null,
selected_model_id: currentDraft.model_path ? currentDraft.selected_model_id : null,
});
updateDraftFieldMeta("model_path", { pending: false, invalid: false, message: null });
} catch (error) {
if (!isLatestRequest("model-selection", requestId)) return;
setLocalError(String(error));
updateDraftFieldMeta("model_path", { pending: false });
}
};
const handleHubSearch = async () => {
if (!hfQuery.trim()) {
setHfResults([]);
return;
}
const requestId = beginRequest("hf-search");
setLocalError("");
setHfLoading(true);
try {
const results = await searchHuggingFaceModels(hfQuery.trim(), draftConfig.hugging_face_token.trim());
if (!isLatestRequest("hf-search", requestId)) return;
setHfResults(results);
} catch (error) {
if (!isLatestRequest("hf-search", requestId)) return;
setLocalError(String(error));
setHfResults([]);
} finally {
if (isLatestRequest("hf-search", requestId)) {
setHfLoading(false);
}
}
};
const handleSave = async () => {
setLocalError("");
try {
await onSave(buildPatch());
setConfirmDiscard(false);
} catch (error) {
setLocalError(String(error));
}
};
const handleSaveAndStart = async () => {
setLocalError("");
if (snapshot.process_running) {
try {
await onStop();
} catch (error) {
setLocalError(String(error));
}
return;
}
try {
const next = await onSave(buildPatch());
if (next.config.connection_mode !== "local") return;
if (!next.config.model_path?.trim()) return;
if (next.last_error?.code === "restart_required") return;
await onStart();
} catch (error) {
setLocalError(String(error));
}
};
useEffect(() => {
if (!open) return;
setConfirmDiscard(false);
setLocalError("");
setHfResults([]);
void loadModelLibrary();
void loadGpuInfo();
if (draftConfig.connection_mode === "local" && draftConfig.models_dir?.trim()) {
void handleRescan(draftConfig.models_dir);
}
}, [open]);
if (!open) return null;
const buildPatch = (): RuntimeConfig => ({
...createRuntimeConfigPatch(
savedBaseline,
{
mode: draftConfig.connection_mode,
startPolicy: draftConfig.start_policy,
serverUrl: draftConfig.server_url,
apiKey: draftConfig.api_key,
modelsDir: draftConfig.models_dir || "",
selectedModel: draftConfig.model_path || "",
selectedModelId: draftConfig.selected_model_id,
addr: draftConfig.addr,
gpuLayers: draftConfig.gpu_layers,
ctxSize: draftConfig.ctx_size,
extraModels,
},
maxLayers,
),
hugging_face_token: draftConfig.hugging_face_token.trim(),
remote_presets: draftConfig.remote_presets?.length
? draftConfig.remote_presets
: REMOTE_PRESET_TEMPLATES.map((preset) => ({
id: preset.id,
label: preset.label,
provider: preset.provider,
base_url: preset.baseUrl,
default_model: "",
})),
});
return (
<div className="runtime-drawer-shell" role="dialog" aria-modal="true" aria-label="Draft settings">
<button
className="runtime-drawer-backdrop"
onClick={() => {
setConfirmDiscard(false);
onClose();
}}
aria-label="Close runtime settings"
/>
<aside className="runtime-drawer">
<div className="runtime-drawer-header runtime-drawer-header-sticky">
<div>
<div className="runtime-drawer-kicker">Draft settings</div>
<h2>Draft settings</h2>
<div className="runtime-drawer-summary-row">
<span className={`runtime-drawer-summary-badge${draftDirty ? " is-dirty" : ""}`}>
{draftDirty ? `${dirtyFieldCount} unsaved ${dirtyFieldCount === 1 ? "change" : "changes"}` : "No draft changes yet"}
</span>
<span className="runtime-live-chip">Live now</span>
<span className="runtime-live-chip-value">
{snapshot.status === "ready"
? "Local API ready"
: snapshot.config.connection_mode === "remote"
? "Remote API mode"
: "Local API setup"}
</span>
</div>
<p className="runtime-drawer-copy">
Edit runtime settings as a draft. Close keeps this draft in-session until you save or discard it.
</p>
</div>
<button
className="runtime-drawer-close"
onClick={() => {
setConfirmDiscard(false);
onClose();
}}
type="button"
aria-label="Close runtime settings"
>
×
</button>
</div>
<div className="runtime-drawer-body">
<section className="runtime-overview-card">
<div>
<div className="runtime-overview-label">Current status</div>
<div className="runtime-overview-value">
{snapshot.status === "ready"
? "Local API ready"
: snapshot.config.connection_mode === "remote"
? "Remote API mode"
: "Local API setup"}
</div>
</div>
<div>
<div className="runtime-overview-label">Endpoint</div>
<div className="runtime-overview-value runtime-overview-mono">
{snapshot.config.connection_mode === "remote"
? snapshot.config.server_url || "Not configured"
: `http://${snapshot.config.addr}`}
</div>
</div>
<div>
<div className="runtime-overview-label">Saved model</div>
<div className="runtime-overview-value">
{savedBaseline.model_path ? pathName(savedBaseline.model_path) : "No model saved"}
</div>
</div>
</section>
<section className="runtime-drawer-section">
<div className="runtime-drawer-section-title">Connection mode</div>
<div className="runtime-segmented" role="tablist" aria-label="Connection mode">
<button
className={`runtime-segmented-btn${draftConfig.connection_mode === "local" ? " active" : ""}${isFieldDirty("connection_mode") ? " is-draft" : ""}`}
onClick={() => updateDraft({ connection_mode: "local" })}
type="button"
>
Local API
</button>
<button
className={`runtime-segmented-btn${draftConfig.connection_mode === "remote" ? " active" : ""}${isFieldDirty("connection_mode") ? " is-draft" : ""}`}
onClick={() => updateDraft({ connection_mode: "remote" })}
type="button"
>
Remote API
</button>
</div>
{isFieldDirty("connection_mode") && (
<div className="runtime-field-state is-draft">
<div className="runtime-field-state-row">
<span className="runtime-field-badge">Draft</span>
<span className="runtime-field-state-label">Live now</span>
<span className="runtime-field-state-value">
{formatReferenceValue("connection_mode", savedBaseline.connection_mode)}
</span>
</div>
</div>
)}
</section>
{draftConfig.connection_mode === "remote" ? (
<section className="runtime-drawer-section runtime-section-card">
<div className="runtime-field-label">Provider presets</div>
<div className="runtime-preset-row runtime-preset-row-first">
{REMOTE_PRESET_TEMPLATES.map((preset) => (
<button
key={preset.id}
className={`runtime-preset${draftConfig.server_url.trim() === preset.baseUrl ? " active" : ""}`}
onClick={() => updateDraft({ server_url: preset.baseUrl })}
type="button"
>
{preset.label}
</button>
))}
</div>
<label className="runtime-field-label" htmlFor="runtime-remote-url">Remote server URL</label>
<input
id="runtime-remote-url"
className={`runtime-field-input${isFieldDirty("server_url") ? " is-draft" : ""}${fieldMeta("server_url").invalid ? " is-invalid" : ""}`}
value={draftConfig.server_url}
onChange={(event) => updateDraft({ server_url: event.target.value })}
placeholder="https://api.example.com"
type="text"
/>
{renderFieldState("server_url")}
<label className="runtime-field-label" htmlFor="runtime-api-key">API key</label>
<input
id="runtime-api-key"
className={`runtime-field-input${isFieldDirty("api_key") ? " is-draft" : ""}${fieldMeta("api_key").invalid ? " is-invalid" : ""}`}
value={draftConfig.api_key}
onChange={(event) => updateDraft({ api_key: event.target.value })}
placeholder="sk-..."
type="password"
/>
{renderFieldState("api_key")}
</section>
) : (
<>
<section className="runtime-drawer-section runtime-section-card runtime-grid-two">
<div>
<div className="runtime-field-label">Managed endpoint</div>
<div className="runtime-static-value runtime-static-value-mono">http://{draftConfig.addr.trim() || snapshot.config.addr}</div>
</div>
<div>
<div className="runtime-field-label">Binary discovery</div>
<div className="runtime-static-value runtime-static-value-path">{snapshot.binary_path || "Binary not found yet"}</div>
</div>
</section>
<section className="runtime-drawer-section runtime-section-card">
<div className="runtime-field-row runtime-field-row-top">
<div>
<div className="runtime-field-label">Managed library</div>
<div className="runtime-field-support">
App-managed downloads live outside your scanned folders so they survive app updates.
</div>
</div>
</div>
<div className="runtime-static-value runtime-static-value-path">
{libraryState.managed_dir || "Loading managed storage path..."}
</div>
{libraryState.entries.length > 0 ? (
<div className="runtime-chip-list">
{libraryState.entries.map((entry) => (
<button
key={entry.id}
className={`runtime-chip runtime-chip-selectable${draftConfig.selected_model_id === entry.id ? " active" : ""}${isFieldDirty("model_path") ? " is-draft" : ""}`}
onClick={() => updateDraft({ model_path: entry.path, selected_model_id: entry.id })}
type="button"
title={entry.path}
>
{entry.label}
</button>
))}
</div>
) : (
<div className="runtime-field-support">No managed downloads yet.</div>
)}
</section>
<section className="runtime-drawer-section runtime-section-card">
<div className="runtime-field-row">
<div>
<div className="runtime-field-label">Models folder</div>
<div className={`runtime-static-value runtime-static-value-path${isFieldDirty("models_dir") ? " is-draft" : ""}${fieldMeta("models_dir").invalid ? " is-invalid" : ""}`}>
{draftConfig.models_dir || "Choose a folder or add individual files"}
</div>
</div>
<div className="runtime-inline-actions">
<button className="runtime-inline-btn" onClick={handlePickDir} type="button">Browse</button>
<button className="runtime-inline-btn" onClick={() => { void handleRescan(); }} type="button" disabled={!draftConfig.models_dir?.trim() || scanning}>
{scanning ? "Scanning..." : "Rescan"}
</button>
<button className="runtime-inline-btn" onClick={handlePickFiles} type="button">Add files</button>
</div>
</div>
{renderFieldState("models_dir")}
<label className="runtime-field-label" htmlFor="runtime-model-select">Selected model</label>
<select
id="runtime-model-select"
className={`runtime-field-input runtime-field-select${isFieldDirty("model_path") ? " is-draft" : ""}${fieldMeta("model_path").invalid ? " is-invalid" : ""}`}
value={draftConfig.model_path || ""}
onChange={(event) =>
updateDraft({
model_path: event.target.value || null,
selected_model_id: null,
})
}
>
<option value="">Choose a model</option>
{allModels.map((model) => (
<option key={model.path} value={model.path}>{model.name}</option>
))}
</select>
{renderFieldState("model_path")}
{extraModels.length > 0 && (
<div className="runtime-chip-list">
{extraModels.map((model) => (
<button
key={model.path}
className="runtime-chip"
onClick={() => {
const next = extraModels.filter((entry) => entry.path !== model.path);
updateDraft({
extra_model_paths: next.map((entry) => entry.path),
model_path:
draftConfig.model_path === model.path
? chooseModel("", scannedModels, next)
: draftConfig.model_path,
selected_model_id: draftConfig.model_path === model.path ? null : draftConfig.selected_model_id,
});
}}
type="button"
title={`Remove ${model.name}`}
>
{model.name}
<span>×</span>
</button>
))}
</div>
)}
</section>
<section className="runtime-drawer-section runtime-section-card">
<div className="runtime-field-row runtime-field-row-top">
<div>
<div className="runtime-field-label">Discover from Hugging Face</div>
<div className="runtime-field-support">
Search public GGUF repos, preview verified files, and keep your local library as the primary runtime source.
</div>
</div>
</div>
<label className="runtime-field-label" htmlFor="runtime-hf-token">Optional Hugging Face token</label>
<input
id="runtime-hf-token"
className={`runtime-field-input${isFieldDirty("hugging_face_token") ? " is-draft" : ""}`}
value={draftConfig.hugging_face_token}
onChange={(event) => updateDraft({ hugging_face_token: event.target.value })}
placeholder="hf_..."
type="password"
/>
<div className="runtime-field-row runtime-field-row-top">
<div className="runtime-search-grow">
<label className="runtime-field-label" htmlFor="runtime-hf-search">Search public GGUF repos</label>
<input
id="runtime-hf-search"
className="runtime-field-input"
value={hfQuery}
onChange={(event) => setHfQuery(event.target.value)}
onInput={(event) => setHfQuery((event.target as HTMLInputElement).value)}
placeholder="phi-4, mistral, qwen..."
type="text"
/>
</div>
<button className="runtime-inline-btn" onClick={() => { void handleHubSearch(); }} type="button" disabled={hfLoading}>
{hfLoading ? "Searching..." : "Search Hub"}
</button>
</div>
{hfResults.length > 0 ? (
<div className="runtime-search-results" aria-label="Hugging Face search results">
{hfResults.map((result) => (
<article key={result.repo_id} className="runtime-search-card">
<div className="runtime-search-title">{result.repo_id}</div>
<div className="runtime-field-support">{result.author || "Unknown author"}</div>
<div className="runtime-verified-file-list">
{result.verified_files.map((file) => (
<div key={`${result.repo_id}:${file.path}`} className="runtime-verified-file">
<span>{file.path}</span>
<span className="runtime-verified-file-meta">
{file.quantization || "gguf"}
{file.size ? ` · ${Math.round(file.size / (1024 * 1024))} MiB` : ""}
</span>
</div>
))}
</div>
</article>
))}
</div>
) : (
<div className="runtime-field-support">
{hfLoading ? "Looking up verified GGUF files..." : "Search for a model family to preview compatible local installs."}
</div>
)}
</section>
<section className="runtime-drawer-section runtime-section-card runtime-grid-two">
<div>
<label className="runtime-field-label" htmlFor="runtime-addr">Listen address</label>
<input
id="runtime-addr"
className={`runtime-field-input${isFieldDirty("addr") ? " is-draft" : ""}`}
value={draftConfig.addr}
onChange={(event) => updateDraft({ addr: event.target.value })}
placeholder="127.0.0.1:8080"
type="text"
/>
</div>
<div>
<label className="runtime-field-label" htmlFor="runtime-context">Context size</label>
<input
id="runtime-context"
className={`runtime-field-input${isFieldDirty("ctx_size") ? " is-draft" : ""}`}
min={512}
step={512}
value={draftConfig.ctx_size}
onChange={(event) => updateDraft({ ctx_size: Math.max(512, parseInt(event.target.value, 10) || 4096) })}
type="number"
/>
</div>
</section>
<section className="runtime-drawer-section runtime-section-card">
<div className="runtime-field-row runtime-field-row-top">
<div>
<div className="runtime-field-label">GPU layers</div>
<div className="runtime-field-support">
{gpuInfo ? `${gpuInfo.name} · recommended ${gpuInfo.recommended_layers}` : gpuError || "GPU detection unavailable"}
</div>
</div>
{gpuInfo && (
<button className="runtime-inline-btn" onClick={() => updateDraft({ gpu_layers: gpuInfo.recommended_layers })} type="button">
Use recommended
</button>
)}
</div>
<input
className={`runtime-field-input${isFieldDirty("gpu_layers") ? " is-draft" : ""}`}
min={0}
max={maxLayers}
value={draftConfig.gpu_layers}
onChange={(event) => updateDraft({ gpu_layers: Math.max(0, Math.min(maxLayers, parseInt(event.target.value, 10) || 0)) })}
type="number"
/>
<div className="runtime-preset-row">
{CTX_PRESETS.map((preset) => (
<button
key={preset}
className={`runtime-preset${draftConfig.ctx_size === preset ? " active" : ""}`}
onClick={() => updateDraft({ ctx_size: preset })}
type="button"
>
{preset >= 1024 ? `${preset / 1024}k` : preset}
</button>
))}
</div>
</section>
<section className="runtime-drawer-section runtime-section-card">
<label className="runtime-checkbox-row">
<input
checked={draftConfig.start_policy === "on_app_launch"}
onChange={(event) => updateDraft({ start_policy: event.target.checked ? "on_app_launch" : "manual" })}
type="checkbox"
/>
<span>Start the local API automatically when the desktop app opens</span>
</label>
</section>
</>
)}
{(localError || snapshot.last_error) && (
<section className="runtime-drawer-section">
<div className="runtime-error-banner">
{localError || snapshot.last_error?.message || "Couldn't save your draft. Review the highlighted fields and try again — your unsaved changes are still here."}
</div>
</section>
)}
{showLifecycleResult && (
<section className="runtime-drawer-section">
<div
className={`runtime-apply-guidance runtime-apply-guidance-${lastLifecycleResult.outcome}`}
role="status"
aria-live="polite"
>
{lastLifecycleResult.message}
</div>
</section>
)}
{applyGuidance && (
<section className="runtime-drawer-section">
<div
className={`runtime-apply-guidance${applyImpact !== "immediate" ? " is-warning" : ""}`}
role="status"
>
{applyGuidance}
</div>
</section>
)}
{!snapshot.process_running && draftConfig.connection_mode === "local" && startReason && (
<section className="runtime-drawer-section">
<div className="runtime-warning-banner">{startReason}</div>
</section>
)}
</div>
<div className="runtime-drawer-footer runtime-drawer-footer-sticky">
<div className="runtime-footer-main-actions">
<button
className="runtime-footer-btn runtime-footer-btn-secondary"
onClick={() => setConfirmDiscard(true)}
type="button"
disabled={busy || lifecycleBusy || !draftDirty}
>
Discard changes
</button>
<button
className="runtime-footer-btn runtime-footer-btn-primary"
onClick={() => { void handleSave(); }}
type="button"
disabled={busy || lifecycleBusy || !draftDirty || hasBlockingDraftState}
>
{saveLabel}
</button>
</div>
{draftConfig.connection_mode === "local" && (
<button
className="runtime-footer-btn runtime-footer-btn-tertiary"
onClick={() => { void handleSaveAndStart(); }}
type="button"
disabled={
busy ||
lifecycleBusy ||
hasBlockingDraftState ||
hasPendingModeChange ||
restartRequiredWhileRunning ||
(!snapshot.process_running && Boolean(startReason))
}
>
{tertiaryLabel}
</button>
)}
</div>
{confirmDiscard && (
<div className="runtime-discard-confirmation">
<div className="runtime-discard-copy">Revert to saved: Replace all unsaved edits with the last saved values.</div>
<div className="runtime-inline-actions">
<button className="runtime-inline-btn" onClick={() => setConfirmDiscard(false)} type="button">
Keep editing
</button>
<button
className="runtime-inline-btn runtime-inline-btn-danger"
onClick={() => {
onResetDraft?.();
setConfirmDiscard(false);
}}
type="button"
>
Revert to saved
</button>
</div>
</div>
)}
</aside>
</div>
);
}