revert: remove Hugging Face model integration

This commit is contained in:
Hermes Agent
2026-08-28 19:30:35 +10:00
parent bc47cf8152
commit 309947d353
7 changed files with 9 additions and 423 deletions
+5 -43
View File
@@ -126,10 +126,9 @@
}
function ModelCard(props) {
var model = props.model, installed = props.installed, busy = props.busy, action = props.action, onHuggingFace = props.onHuggingFace;
var model = props.model, installed = props.installed, busy = props.busy, action = props.action;
var openState = React.useState(false), open = openState[0], setOpen = openState[1];
var badges = [];
if (model.source === "huggingface") badges.push(h(Badge, { key: "huggingface", tone: "popular" }, "Hugging Face"));
if (installed && model.loaded) badges.push(h(Badge, { key: "loaded", tone: "live" }, "loaded"));
if (installed) badges.push(h(Badge, { key: "installed", tone: "installed" }, "installed"));
if (!installed) badges.push(h(Badge, { key: "available", tone: "download" }, "available"));
@@ -142,9 +141,7 @@
h("div", { className: "ollama-card-actions" },
installed && h(Button, { disabled: !!busy, onClick: function () { action("redownload", model.name); } }, busy === model.name + ":redownload" ? "Updating…" : "Update / re-download"),
installed && h(Button, { disabled: !!busy, className: "ollama-button danger", onClick: function () { action("delete", model.name); } }, busy === model.name + ":delete" ? "Removing…" : "Remove"),
!installed && model.source === "huggingface" && model.hf_url && h("a", { className: "ollama-button secondary", href: model.hf_url, target: "_blank", rel: "noreferrer" }, "Open on Hugging Face"),
!installed && model.source === "huggingface" && onHuggingFace && h(Button, { disabled: !!busy, onClick: function () { onHuggingFace(model); } }, "Download GGUF"),
!installed && model.source !== "huggingface" && h(Button, { disabled: !!busy, onClick: function () { action("pull", model.name); } }, busy === model.name + ":pull" ? "Downloading…" : "Download")
!installed && h(Button, { disabled: !!busy, onClick: function () { action("pull", model.name); } }, busy === model.name + ":pull" ? "Downloading…" : "Download")
)
),
h("div", { className: "ollama-model-summary" },
@@ -153,7 +150,7 @@
h("div", null, h("small", null, "Type"), h("strong", null, model.architecture || "Unknown")),
h("div", null, h("small", null, "Parameters"), h("strong", null, model.parameter_size || "Unknown"), model.activated_parameter_size && h("small", { className: "ollama-activated-parameters" }, model.activated_parameter_size, " activated"))
),
h("div", { className: "ollama-card-meta" }, h("span", null, (model.quantization || "Unknown") + " · " + (model.format || "Unknown")), model.hf_downloads != null && h("span", null, Number(model.hf_downloads).toLocaleString() + " downloads"), model.hf_likes != null && h("span", null, Number(model.hf_likes).toLocaleString() + " likes"), model.context_length && h("span", null, "Context " + Number(model.context_length).toLocaleString()), model.modified_at ? h("span", null, "Last updated " + fmtDate(model.modified_at)) : h("span", { className: "ollama-date-unavailable" }, "Last updated unavailable")),
h("div", { className: "ollama-card-meta" }, h("span", null, (model.quantization || "Unknown") + " · " + (model.format || "Unknown")), model.context_length && h("span", null, "Context " + Number(model.context_length).toLocaleString()), model.modified_at ? h("span", null, "Last updated " + fmtDate(model.modified_at)) : h("span", { className: "ollama-date-unavailable" }, "Last updated unavailable")),
h("div", { className: "ollama-strengths" }, h("strong", null, "Excels at: "), (model.strengths || []).join(" · ")),
installed && h(VariantTable, { model: model, action: action, busy: busy }),
h(Button, { className: "ollama-details-toggle", onClick: function () { setOpen(!open); } }, open ? "Hide capability breakdown" : "Show capability breakdown"),
@@ -162,7 +159,6 @@
h("h4", null, "Runtime estimate"),
h("p", null, model.expected_ram_basis || "No estimate basis available.", " Actual memory varies with context length, KV cache, GPU offload, and concurrent requests."),
h("div", { className: "ollama-detail-grid" },
h("span", null, "Source: ", h("strong", null, model.source_label || model.source || "Ollama")),
h("span", null, "Family: ", h("strong", null, model.family || "unknown")),
h("span", null, "Digest: ", h("strong", null, model.digest ? model.digest.slice(0, 16) + "…" : "unknown")),
h("span", null, "Embedding: ", h("strong", null, model.embedding_length || "unknown")),
@@ -511,30 +507,13 @@
var busyState = React.useState(""), busy = busyState[0], setBusy = busyState[1];
var noticeState = React.useState(null), notice = noticeState[0], setNotice = noticeState[1];
var targetDialogState = React.useState(null), targetDialog = targetDialogState[0], setTargetDialog = targetDialogState[1];
var hfFileDialogState = React.useState(null), hfFileDialog = hfFileDialogState[0], setHfFileDialog = hfFileDialogState[1];
var hfSearchState = React.useState(false), includeHuggingFace = hfSearchState[0], setIncludeHuggingFace = hfSearchState[1];
var loadingState = React.useState(true), loading = loadingState[0], setLoading = loadingState[1];
var externalSearchState = React.useState([]), externalSearch = externalSearchState[0], setExternalSearch = externalSearchState[1];
var externalSearchBusyState = React.useState(false), externalSearchBusy = externalSearchBusyState[0], setExternalSearchBusy = externalSearchBusyState[1];
var loadSequence = React.useRef(0);
var searchSequence = React.useRef(0);
function load() {
var sequence = ++loadSequence.current;
return fetchJSON(API + "/status").then(function (value) { if (sequence !== loadSequence.current) return value; setData(value); setLoading(false); return value; }).catch(function (err) { if (sequence === loadSequence.current) { setNotice({ error: err.message || String(err) }); setLoading(false); } });
}
React.useEffect(function () { load(); var timer = setInterval(load, 5000); return function () { clearInterval(timer); }; }, []);
React.useEffect(function () {
var term = query.trim();
var sequence = ++searchSequence.current;
if (term.length < 2 || !includeHuggingFace) { setExternalSearch([]); setExternalSearchBusy(false); return; }
setExternalSearchBusy(true);
var timer = setTimeout(function () {
fetchJSON(API + "/catalog/search?q=" + encodeURIComponent(term) + "&limit=30&include_huggingface=true").then(function (value) {
if (sequence === searchSequence.current) setExternalSearch(value.huggingface_results || []);
}).catch(function () { if (sequence === searchSequence.current) setExternalSearch([]); }).finally(function () { if (sequence === searchSequence.current) setExternalSearchBusy(false); });
}, 250);
return function () { clearTimeout(timer); };
}, [query, includeHuggingFace]);
function action(kind, name, selectedTarget) {
if (kind === "delete" && !window.confirm("Remove " + name + " from Ollama?")) return;
if ((kind === "pull" || kind === "redownload") && !selectedTarget) {
@@ -547,16 +526,6 @@
fetchJSON(API + (kind === "delete" ? "/model" : "/" + kind), { method: kind === "delete" ? "DELETE" : "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: name, target: selectedTarget || "local" }) }).then(function (result) { setNotice({ ok: result.message || "Action started." }); load(); }).catch(function (err) { setNotice({ error: err.message || String(err) }); }).finally(function () { setBusy(""); });
}
function refreshCatalog() { setBusy("catalog"); setNotice(null); fetchJSON(API + "/catalog/refresh", { method: "POST" }).then(function (result) { setNotice({ ok: "Catalog refreshed: " + result.count + " models." }); load(); }).catch(function (err) { setNotice({ error: err.message || String(err) }); }).finally(function () { setBusy(""); }); }
function openHuggingFaceFiles(model) {
if (!model || !model.name) return;
setBusy("hf-files"); setNotice(null); setHfFileDialog({ model: model, files: null, import_supported: false });
fetchJSON(API + "/huggingface/files?repo_id=" + encodeURIComponent(model.name)).then(function (value) { setHfFileDialog({ model: model, files: value.files || [], import_supported: !!value.import_supported }); }).catch(function (err) { setHfFileDialog(null); setNotice({ error: err.message || String(err) }); }).finally(function () { setBusy(""); });
}
function downloadHuggingFaceFile(model, file) {
if (!model || !file || !file.filename) return;
setBusy("hf-download"); setNotice(null);
fetchJSON(API + "/huggingface/download", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ repo_id: model.name, filename: file.filename }) }).then(function (result) { setHfFileDialog(null); setNotice({ ok: result.message || "Hugging Face GGUF download started." }); load(); }).catch(function (err) { setNotice({ error: err.message || String(err) }); }).finally(function () { setBusy(""); });
}
var baseModels = data ? (tab === "installed" ? data.models || [] : tab === "popular" ? data.popular || [] : tab === "catalog" ? (showOversized ? data.catalog_all || data.catalog || [] : data.catalog || []) : []) : [];
var models = baseModels;
if (tab === "catalog") {
@@ -574,10 +543,6 @@
if (catalogSort === "name") return String(a.name).localeCompare(String(b.name));
return (Number(a.popularity_rank) || 999999) - (Number(b.popularity_rank) || 999999);
});
if (query.trim().length >= 2 && externalSearch.length) {
var existingNames = new Set(models.map(function (model) { return model.name; }));
models = models.concat(externalSearch.filter(function (model) { return !existingNames.has(model.name); }));
}
}
var needle = query.toLowerCase().trim(); if (needle) models = models.filter(function (model) { return (model.name + " " + model.family + " " + (model.strengths || []).join(" ") + " " + (model.capabilities || []).join(" ")).toLowerCase().indexOf(needle) >= 0; });
var catalogCapabilities = data && data.catalog_filter_options ? data.catalog_filter_options.capabilities || [] : [];
@@ -603,20 +568,17 @@
h("label", { className: "ollama-catalog-checkbox ollama-catalog-memory-bypass", title: "This only bypasses the catalog display filter; loading remains protected by the 95% RAM safety guard." }, h("input", { type: "checkbox", checked: showOversized, onChange: function (event) { setShowOversized(event.target.checked); } }), h("span", null, "Show models above estimated RAM"))
);
var browseToolbar = tab !== "chat" && h("div", { className: "ollama-browse-row" },
h("input", { className: "ollama-search", value: query, placeholder: includeHuggingFace ? "Search Ollama + Hugging Face models…" : "Search Ollama models…", onChange: function (event) { setQuery(event.target.value); } }),
tab === "catalog" && h("label", { className: "ollama-catalog-checkbox ollama-huggingface-checkbox", title: "Search the public Hugging Face Hub in addition to Ollama." }, h("input", { type: "checkbox", checked: includeHuggingFace, onChange: function (event) { setIncludeHuggingFace(event.target.checked); } }), h("span", null, "Search Hugging Face")),
externalSearchBusy && h("small", { className: "ollama-search-status" }, "Searching Hugging Face…"),
h("input", { className: "ollama-search", value: query, placeholder: "Search models, capabilities, or strengths…", onChange: function (event) { setQuery(event.target.value); } }),
catalogControls
);
return h("main", { className: "ollama-page" }, h("header", { className: "ollama-hero" }, h("div", null, h("div", { className: "ollama-eyebrow" }, "LOCAL MODEL OPERATIONS"), h("h1", null, "Ollama Models"), h("p", null, "Inspect, chat with, download, update, and remove models from the local Ollama runtime.")), h("div", { className: "ollama-health" }, h(Badge, { tone: data && data.ollama && data.ollama.available ? "live" : "danger" }, data && data.ollama && data.ollama.available ? "Ollama online" : "Ollama unavailable"), data && data.ollama && h("span", null, "v" + (data.ollama.version || "unknown")), h(Button, { disabled: busy === "catalog", onClick: refreshCatalog }, busy === "catalog" ? "Refreshing…" : "Refresh catalog")), h(ConnectionPanel, { data: data, reload: load })),
targetDialog && h("div", { className: "ollama-target-modal" }, h("div", { className: "ollama-target-card" }, h("h3", null, "Where should " + targetDialog.name + " be downloaded?"), h("p", null, "Both local and remote Ollama instances are online. Choose the destination for this model."), targetDialog.targets.map(function (item) { return h(Button, { key: item.kind, onClick: function () { var chosen = targetDialog; setTargetDialog(null); action(chosen.kind, chosen.name, item.kind); } }, (item.kind || "local").toUpperCase(), " · ", item.url, " · v", item.version, " · ", item.models, " models"); }), h(Button, { className: "secondary", onClick: function () { setTargetDialog(null); } }, "Cancel"))),
hfFileDialog && h("div", { className: "ollama-target-modal" }, h("div", { className: "ollama-target-card ollama-huggingface-file-card" }, h("h3", null, "Download GGUF from ", hfFileDialog.model.name), h("p", null, hfFileDialog.import_supported ? "Choose a GGUF file. It will be downloaded and imported into the local Ollama runtime." : "Choose a GGUF file. It will be downloaded to Hermes storage; automatic Ollama import is unavailable in this deployment."), hfFileDialog.files === null ? h("p", null, "Loading repository files…") : hfFileDialog.files.length ? hfFileDialog.files.map(function (file) { return h("div", { className: "ollama-huggingface-file-row", key: file.filename }, h("span", null, h("strong", null, file.filename), h("small", null, (file.size_label || "Unknown size") + (file.split ? " · complete " + file.file_count + "-shard set" : ""))), h(Button, { disabled: !!busy, onClick: function () { downloadHuggingFaceFile(hfFileDialog.model, file); } }, busy === "hf-download" ? "Starting…" : (file.split ? "Download set" : "Download"))); }) : h("p", null, "This repository has no compatible GGUF files. Open the repository to inspect Transformers, safetensors, or other formats."), h("div", { className: "ollama-huggingface-file-actions" }, h("a", { className: "ollama-button secondary", href: hfFileDialog.model.hf_url, target: "_blank", rel: "noreferrer" }, "Open repository"), h(Button, { className: "secondary", onClick: function () { setHfFileDialog(null); } }, "Cancel")))),
notice && h("div", { className: "ollama-notice " + (notice.error ? "error" : notice.warning ? "warning" : "ok") }, notice.error || notice.warning || notice.ok),
h("section", { className: "ollama-toolbar" }, h("div", { className: "ollama-nav-row" }, navTabs, h("div", { className: "ollama-toolbar-disk" }, h("span", null, "Disk"), h("strong", null, disk.used_percent == null ? "n/a" : Number(disk.used_percent).toFixed(1) + "%"), h("small", null, disk.available ? fmtBytes(disk.free_bytes) + " free" : "Unavailable"))), browseToolbar),
tab !== "chat" && h("div", { className: "ollama-info-strip" }, h("span", null, data && data.models ? data.models.filter(function (m) { return m.loaded; }).length + " currently loaded" : "Loading runtime state…"), h("span", null, "Catalog checked " + (data && data.catalog_updated_at ? fmtDate(data.catalog_updated_at) : "not yet")), h("span", null, "Next daily check " + (data && data.next_catalog_refresh ? fmtDate(data.next_catalog_refresh) : "01:00 Melbourne time") + " (1:00 AM Melbourne time)")),
tab === "chat" && h(ChatPanel, { models: data && data.models ? data.models : [], refresh: load }),
tab === "popular" && h("p", { className: "ollama-popular-note" }, "Popular is limited to models with known size and RAM estimates at or below the detected system RAM (" + (data && data.popular_filter && data.popular_filter.max_expected_ram_gib ? data.popular_filter.max_expected_ram_gib + " GiB" : "detecting…") + "). Oversized families are represented by a smaller fitting variant when available."), jobs.length > 0 && h("section", { className: "ollama-jobs" }, jobs.map(function (job) { return h("div", { key: job.id }, h("strong", null, job.action + " · " + job.name + " · " + (job.target || "local") + (job.endpoint ? " · " + job.endpoint : "")), h("span", null, job.percent == null ? job.status : job.percent + "%")); })),
tab !== "chat" && loading && h(Empty, null, "Loading local Ollama inventory…"), tab !== "chat" && !loading && !models.length && h(Empty, null, tab === "installed" ? "No local models found." : tab === "popular" ? "No popular catalog entries available." : query.trim().length >= 2 ? "No Ollama or Hugging Face models matched this search." : "No catalog entries available. Try Refresh catalog."), tab !== "chat" && h("section", { className: "ollama-grid" }, models.map(function (model) { return h(ModelCard, { key: model.source + ":" + model.name, model: model, installed: tab === "installed" || !!model.installed, busy: busy, action: action, onHuggingFace: openHuggingFaceFiles }); }))
tab !== "chat" && loading && h(Empty, null, "Loading local Ollama inventory…"), tab !== "chat" && !loading && !models.length && h(Empty, null, tab === "installed" ? "No local models found." : tab === "popular" ? "No popular catalog entries available." : "No catalog entries available. Try Refresh catalog."), tab !== "chat" && h("section", { className: "ollama-grid" }, models.map(function (model) { return h(ModelCard, { key: model.name, model: model, installed: tab === "installed" || !!model.installed, busy: busy, action: action }); }))
);
}
registry.register("ollama-manager", Page);
+1 -1
View File
@@ -8,7 +8,7 @@
@media(max-width:600px){.ollama-runtime-grid{grid-template-columns:1fr}.ollama-chat-model{display:block}.ollama-chat-model select{width:100%;margin-bottom:8px}.ollama-message.user{margin-left:0}.ollama-message.assistant{margin-right:0}}.ollama-connection-panel{min-width:0;max-width:620px;width:100%;box-sizing:border-box;container-type:inline-size;margin-top:14px;padding:12px;border:1px solid rgba(164,211,199,.2);border-radius:10px;background:rgba(10,31,28,.72);box-shadow:0 8px 24px rgba(0,0,0,.12)}.ollama-connection-heading{display:flex;justify-content:space-between;gap:10px;color:#d7ebe5}.ollama-connection-heading strong{font-size:12px}.ollama-connection-heading small{display:block;margin-top:3px;color:#8fa9a4;font-size:10px}.ollama-connection-form{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;gap:6px;align-items:stretch;margin-top:9px}.ollama-connection-role,.ollama-connection-input{box-sizing:border-box;min-width:0;width:100%;height:36px;border:1px solid rgba(155,205,194,.28);border-radius:6px;background:#102d29;color:#e8f2ef;padding:7px;font:inherit;font-size:11px}.ollama-connection-input{overflow:hidden;text-overflow:ellipsis}.ollama-connection-form .ollama-button{height:36px;min-width:0;padding:7px 9px;white-space:nowrap}.ollama-connection-result{margin-top:7px;font-size:10px}.ollama-connection-result.ok{color:#9af1c7}.ollama-connection-result.error{color:#ffb1b1}.ollama-connection-list{display:grid;gap:5px;margin-top:8px}.ollama-connection-row{display:flex;align-items:center;gap:7px;width:100%;border:0;border-top:1px solid rgba(164,211,199,.1);padding:7px 0;background:none;color:#c5ddd7;text-align:left;cursor:pointer;font:inherit}.ollama-connection-row span:nth-child(2){display:flex;flex-direction:column;gap:2px;min-width:0}.ollama-connection-row strong{font-size:10px}.ollama-connection-row small{color:#8fa9a4;font-size:9px;overflow-wrap:anywhere}.ollama-connection-dot{width:7px;height:7px;border-radius:50%;background:#b36d6d;flex:0 0 auto}.ollama-connection-dot.online{background:#75d2b7;box-shadow:0 0 8px rgba(117,210,183,.55)}.ollama-connection-row-main{display:flex;align-items:center;gap:7px;flex:1;min-width:0;border:0;padding:0;background:none;color:inherit;text-align:left;cursor:pointer;font:inherit}.ollama-connection-remove{flex:0 0 auto;padding:5px 7px;font-size:9px}.ollama-connection-row-main>span:nth-child(2){display:flex;flex-direction:column;gap:2px;min-width:0}.ollama-connection-row-main strong{font-size:10px}.ollama-connection-row-main small{color:#8fa9a4;font-size:9px;overflow-wrap:anywhere}
@container (max-width: 460px){.ollama-connection-form{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.ollama-connection-role,.ollama-connection-input{grid-column:span 1}.ollama-connection-form .ollama-button{width:100%}}
.ollama-target-modal{position:fixed;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;padding:20px;background:rgba(4,15,14,.72)}.ollama-target-card{display:grid;gap:10px;max-width:560px;width:100%;padding:20px;border:1px solid rgba(141,210,193,.38);border-radius:12px;background:#102d29;box-shadow:0 14px 50px rgba(0,0,0,.35)}.ollama-target-card h3{margin:0;color:#effcf8}.ollama-target-card p{margin:0;color:#a5bfba;font-size:12px}.ollama-target-card .ollama-button{text-align:left}.ollama-huggingface-file-card{max-height:min(720px,90vh);overflow:auto}.ollama-huggingface-file-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 0;border-top:1px solid rgba(164,211,199,.14)}.ollama-huggingface-file-row span{display:grid;gap:3px;min-width:0}.ollama-huggingface-file-row strong{overflow-wrap:anywhere;font-size:12px}.ollama-huggingface-file-row small,.ollama-search-status{color:#8fa9a4;font-size:11px}.ollama-huggingface-file-actions{display:flex;gap:8px;flex-wrap:wrap}@media(max-width:900px){.ollama-connection-panel{min-width:0;max-width:none}.ollama-connection-form{flex-wrap:wrap}.ollama-connection-input{min-width:160px}}
.ollama-target-modal{position:fixed;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;padding:20px;background:rgba(4,15,14,.72)}.ollama-target-card{display:grid;gap:10px;max-width:560px;width:100%;padding:20px;border:1px solid rgba(141,210,193,.38);border-radius:12px;background:#102d29;box-shadow:0 14px 50px rgba(0,0,0,.35)}.ollama-target-card h3{margin:0;color:#effcf8}.ollama-target-card p{margin:0;color:#a5bfba;font-size:12px}.ollama-target-card .ollama-button{text-align:left}@media(max-width:900px){.ollama-connection-panel{min-width:0;max-width:none}.ollama-connection-form{flex-wrap:wrap}.ollama-connection-input{min-width:160px}}
.ollama-catalog-controls{display:grid;grid-template-columns:repeat(3,minmax(130px,1fr));gap:8px;align-items:end;margin-top:0;padding:10px;border:1px solid rgba(164,211,199,.16);border-radius:10px;background:rgba(10,31,28,.55)}.ollama-catalog-controls label{display:flex;flex-direction:column;gap:5px;color:#a5bfba;font-size:10px;text-transform:uppercase;letter-spacing:.06em}.ollama-catalog-checkbox{display:flex!important;flex-direction:row!important;align-items:center;gap:8px;grid-column:1 / -1;padding:8px 4px;color:#b8ead9!important;text-transform:none!important;letter-spacing:normal!important;cursor:pointer}.ollama-catalog-checkbox input{width:15px;height:15px;margin:0;accent-color:#75d2b7}.ollama-catalog-checkbox span{font-size:11px}.ollama-catalog-memory-bypass{color:#ffd89a!important;background:rgba(142,90,25,.12);border-radius:7px}.ollama-catalog-select{min-width:145px;border:1px solid rgba(155,205,194,.28);border-radius:7px;background:#102d29;color:#e8f2ef;padding:8px;font:inherit;font-size:11px;text-transform:none;letter-spacing:normal}
@media(max-width:1000px){.ollama-nav-row{display:grid;grid-template-columns:1fr}.ollama-toolbar-disk{justify-self:end}.ollama-browse-row{grid-template-columns:1fr}.ollama-catalog-controls{margin-top:0}}
@media(max-width:760px){.ollama-tabs{grid-template-columns:repeat(2,minmax(0,1fr))}.ollama-nav-row{gap:8px}.ollama-toolbar-disk{justify-self:stretch;grid-template-columns:auto auto;min-width:0}.ollama-browse-row{gap:8px}.ollama-catalog-controls{grid-template-columns:1fr;align-items:stretch}.ollama-catalog-select{width:100%}}.ollama-harness-primary,.ollama-harness-validators{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.ollama-harness-primary{min-width:260px}.ollama-harness-primary label{display:flex;align-items:center;gap:8px;color:#a5bfba;font-size:11px}.ollama-harness-primary select{border:1px solid rgba(155,205,194,.28);border-radius:7px;background:#102d29;color:#e8f2ef;padding:8px;font:inherit;font-size:11px;max-width:260px}.ollama-harness-validators{flex-basis:100%;padding-top:8px;border-top:1px solid rgba(164,211,199,.14)}.ollama-harness-validators>strong{color:#d5e8e2;font-size:11px}.ollama-harness-ready,.ollama-harness-warning{flex-basis:100%;font-size:10px}.ollama-harness-ready{color:#9af1c7}.ollama-harness-warning{color:#ffd89a}.ollama-validation-evidence{margin-top:10px;padding:10px 12px;border:1px solid rgba(141,210,193,.22);border-radius:8px;background:rgba(10,31,28,.5);color:#a5bfba;font-size:11px}.ollama-validation-evidence summary{cursor:pointer;color:#b8ead9;font-weight:700}.ollama-validation-report{margin-top:10px;padding-top:8px;border-top:1px solid rgba(164,211,199,.12)}.ollama-validation-report strong{color:#effcf8;font-size:11px}.ollama-validation-report p{margin:4px 0 0;white-space:pre-wrap;line-height:1.45}.ollama-storage-panel{margin-top:14px;padding:14px 16px;border:1px solid rgba(141,210,193,.22);border-radius:10px;background:rgba(10,31,28,.5)}.ollama-storage-copy{display:flex;flex-direction:column;gap:4px;margin-top:10px}.ollama-storage-copy strong{color:#effcf8;font-size:12px}.ollama-storage-copy small,.ollama-storage-note{color:#a5bfba;font-size:10px}.ollama-storage-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}.ollama-storage-note{display:block;margin-top:10px}