diff --git a/README.md b/README.md index 29f6b66..3541072 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,11 @@ The Available downloads controls support: Popularity and date ordering use upstream metadata only; the plugin does not invent popularity, dates, RAM requirements, or token metrics. -## Live model-loading telemetry +## Ollama capacity warnings +When Ollama accepts a load request but evicts one model while starting another, the dashboard displays an amber capacity warning rather than a red plugin error. On the verified host, Ollama logged that a 27.9 GiB runner would exceed available device memory with approximately 2.5 GiB GPU memory free. The T600 has 4 GiB VRAM, so two large multimodal models cannot be guaranteed resident simultaneously by the plugin. The actual resident set remains authoritative through `/api/ps`. + +## Live model-loading telemetry While Ollama is starting a runner, the highlighted runtime chart displays an animated **Loading into Ollama memory** state with the selected model names, current stage, and elapsed time. The runtime panel separately reports Ollama resident model-weight bytes and the estimated target weight bytes. This is separate from host `MemAvailable`: CPU-mapped model files may appear as Linux file cache rather than ordinary process RAM usage. ## Multi-model loading and resident state diff --git a/dashboard/dist/index.js b/dashboard/dist/index.js index 621df97..19f995a 100644 --- a/dashboard/dist/index.js +++ b/dashboard/dist/index.js @@ -321,7 +321,7 @@ if (endpoint === "/models/load") { var resident = Array.isArray(result.resident) ? result.resident : ((result.runtime && result.runtime.model_memory) || []).map(function (item) { return item.name; }); var missing = Array.isArray(result.not_resident) ? result.not_resident : requested.filter(function (name) { return resident.indexOf(name) < 0; }); - setNotice(missing.length ? { error: "Ollama resident check: " + resident.join(", ") + ". Not resident: " + missing.join(", ") + ". Ollama may have evicted models because of its scheduler or available memory." } : { ok: "Loaded and resident: " + resident.join(", ") }); + setNotice(missing.length ? { warning: "Ollama kept resident: " + resident.join(", ") + ". Not resident: " + missing.join(", ") + ". This is an Ollama scheduler/capacity warning, not a plugin error." } : { ok: "Loaded and resident: " + resident.join(", ") }); } else { setNotice({ ok: label + ": " + requested.join(", ") }); } @@ -377,7 +377,7 @@ metrics && metrics.length > 0 && h("div", { className: "ollama-metrics-detail" }, (metrics.slice(-3)).map(function (item, index) { return h("span", { key: index }, item.model || "model", " · TTFT ", item.time_to_first_token_ms == null ? "n/a" : item.time_to_first_token_ms + " ms", " · ", item.eval_count == null ? "n/a" : item.eval_count + " output tokens", " · ", item.eval_tokens_per_second == null ? "n/a" : item.eval_tokens_per_second + " tok/s"); })) ), h(ModelPoolPanel, { models: models, loadedModels: loadedModels, selectedModels: selectedModels, poolSelection: poolSelection, busy: busy, onTogglePool: togglePoolModel, onToggleChat: toggleChatModel, onLoad: loadModel, onUnload: unloadModels }), - notice && h("div", { className: "ollama-notice " + (notice.error ? "error" : "ok") }, notice.error || notice.ok), + notice && h("div", { className: "ollama-notice " + (notice.error ? "error" : notice.warning ? "warning" : "ok") }, notice.error || notice.warning || notice.ok), thinking && h(ThinkingStatus, { stage: thinkingDetails && thinkingDetails.stage ? thinkingDetails.stage : (thinkingElapsed < 1 ? thinking.stage : "Ollama is generating the response"), elapsed: thinkingDetails && thinkingDetails.elapsed != null ? thinkingDetails.elapsed : thinkingElapsed, details: thinkingDetails, expanded: thinkingOpen, onToggle: function () { setThinkingOpen(!thinkingOpen); }, onStop: stop }), h(RuntimePanel, { runtime: runtime, samples: samples }), h("div", { className: "ollama-chat-layout" }, @@ -438,7 +438,7 @@ var jobs = data && data.jobs ? data.jobs.filter(function (job) { return job.state === "running"; }) : []; 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"))), - notice && h("div", { className: "ollama-notice " + (notice.error ? "error" : "ok") }, notice.error || notice.ok), + 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-tabs" }, h(Button, { className: tab === "chat" ? "selected" : "", onClick: function () { setTab("chat"); } }, "Ollama Chat"), h(Button, { className: tab === "installed" ? "selected" : "", onClick: function () { setTab("installed"); } }, "Installed (" + ((data && data.models) || []).length + ")"), h(Button, { className: tab === "popular" ? "selected" : "", onClick: function () { setTab("popular"); } }, "Top 20 popular (" + ((data && data.popular) || []).length + ")"), h(Button, { className: tab === "catalog" ? "selected" : "", onClick: function () { setTab("catalog"); } }, "Available downloads (" + ((data && data.catalog) || []).length + ")")), tab !== "chat" && h("input", { className: "ollama-search", value: query, placeholder: "Search models, capabilities, or strengths…", onChange: function (event) { setQuery(event.target.value); } }), tab === "catalog" && h("div", { className: "ollama-catalog-controls" }, h("label", null, "Type", h("select", { className: "ollama-catalog-select", value: catalogType, onChange: function (event) { setCatalogType(event.target.value); } }, h("option", { value: "all" }, "All types"), h("option", { value: "moe" }, "MoE only"), h("option", { value: "dense" }, "Dense only"))), h("label", null, "Ability", h("select", { className: "ollama-catalog-select", value: catalogCapability, onChange: function (event) { setCatalogCapability(event.target.value); } }, h("option", { value: "all" }, "All abilities"), catalogCapabilities.map(function (capability) { return h("option", { key: capability, value: capability }, capability); }))), h("label", null, "Organize", h("select", { className: "ollama-catalog-select", value: catalogSort, onChange: function (event) { setCatalogSort(event.target.value); } }, h("option", { value: "popularity" }, "Popularity"), h("option", { value: "newest" }, "Newest"), h("option", { value: "size_asc" }, "Size: smallest first"), h("option", { value: "size_desc" }, "Size: largest first"), h("option", { value: "name" }, "Name"))))), 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 }), diff --git a/dashboard/dist/style.css b/dashboard/dist/style.css index b902d76..f428f76 100644 --- a/dashboard/dist/style.css +++ b/dashboard/dist/style.css @@ -1,4 +1,4 @@ -.ollama-page{min-height:100%;padding:28px 32px 56px;color:#e8f2ef;background:linear-gradient(135deg,rgba(17,42,39,.92),rgba(10,24,23,.98));font-family:inherit}.ollama-hero{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;border-bottom:1px solid rgba(164,211,199,.16);padding-bottom:22px}.ollama-eyebrow{font-size:10px;letter-spacing:.18em;color:#8ec8bb;font-weight:700}.ollama-hero h1{margin:7px 0 6px;font-size:30px;letter-spacing:.02em}.ollama-hero p{margin:0;color:#a5bfba;max-width:680px}.ollama-health{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end;color:#9bb6b0;font-size:12px}.ollama-badge-row{display:flex;gap:6px;flex-wrap:wrap;margin-top:7px}.ollama-badge{display:inline-flex;align-items:center;border:1px solid rgba(152,204,192,.24);border-radius:999px;padding:4px 8px;color:#b4d1ca;font-size:10px;letter-spacing:.06em;text-transform:uppercase;background:rgba(80,125,115,.12)}.ollama-badge.live{color:#9af1c7;border-color:rgba(72,218,147,.4);background:rgba(35,137,91,.2)}.ollama-badge.installed{color:#bce1ff;border-color:rgba(89,168,231,.35);background:rgba(30,96,145,.2)}.ollama-badge.download{color:#f6d18f;border-color:rgba(244,182,80,.35);background:rgba(142,90,25,.18)}.ollama-badge.moe{color:#e2b4ff;border-color:rgba(197,107,255,.35);background:rgba(105,44,139,.2)}.ollama-badge.danger{color:#ffb1b1;border-color:rgba(255,100,100,.45);background:rgba(160,40,40,.18)}.ollama-button{border:1px solid rgba(155,205,194,.24);border-radius:7px;background:rgba(70,117,108,.18);color:#dbebe7;padding:8px 11px;cursor:pointer;font:inherit;font-size:11px;transition:background .15s,border-color .15s}.ollama-button:hover:not(:disabled){background:rgba(91,161,144,.3);border-color:rgba(155,230,210,.55)}.ollama-button:disabled{opacity:.45;cursor:not-allowed}.ollama-button.selected{background:#3e8073;border-color:#8dd2c1}.ollama-button.danger{color:#ffb8b8;border-color:rgba(255,110,110,.3)}.ollama-toolbar{display:flex;justify-content:space-between;gap:16px;margin:22px 0 12px;align-items:center}.ollama-tabs{display:flex;gap:8px;flex-wrap:wrap}.ollama-search{min-width:280px;max-width:410px;width:100%;background:rgba(7,20,19,.65);border:1px solid rgba(155,205,194,.24);border-radius:7px;color:#e8f2ef;padding:10px 12px;font:inherit;font-size:12px}.ollama-search::placeholder{color:#78958e}.ollama-info-strip{display:flex;gap:18px;flex-wrap:wrap;color:#88aaa2;font-size:11px;padding:10px 0 18px}.ollama-notice{padding:10px 12px;margin-top:15px;border-radius:7px;font-size:12px}.ollama-notice.ok{background:rgba(42,141,98,.18);border:1px solid rgba(84,222,159,.32);color:#a9f1cf}.ollama-notice.error{background:rgba(156,45,45,.18);border:1px solid rgba(255,116,116,.35);color:#ffc1c1}.ollama-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(390px,1fr));gap:15px}.ollama-model-card{border:1px solid rgba(155,205,194,.18);border-radius:11px;background:rgba(12,31,29,.78);padding:17px;box-shadow:0 12px 30px rgba(0,0,0,.12)}.ollama-card-top{display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.ollama-model-title h3{margin:0;font-size:17px;word-break:break-word}.ollama-card-actions{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}.ollama-model-summary{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:17px 0 10px}.ollama-model-summary div{padding:9px;background:rgba(87,137,126,.09);border-radius:7px;min-width:0}.ollama-model-summary small{display:block;color:#779d95;font-size:9px;text-transform:uppercase;letter-spacing:.08em;margin-bottom:4px}.ollama-model-summary strong{display:block;color:#d8ebe6;font-size:12px;overflow-wrap:anywhere}.ollama-card-meta{display:flex;gap:12px;flex-wrap:wrap;color:#8eada6;font-size:10px}.ollama-strengths{margin:13px 0;color:#b1c9c3;font-size:12px;line-height:1.5}.ollama-strengths strong{color:#dfede9}.ollama-details-toggle{padding:6px 0;border:0;background:transparent;color:#8fd1bf}.ollama-details{border-top:1px solid rgba(155,205,194,.14);margin-top:10px;padding-top:13px;color:#a9c4bd;font-size:11px}.ollama-details h4{margin:0 0 8px;color:#d8ebe6;font-size:11px;text-transform:uppercase;letter-spacing:.08em}.ollama-details p{line-height:1.5}.ollama-capabilities{display:grid;gap:7px}.ollama-capability{display:flex;align-items:center;gap:8px}.ollama-capability span{color:#9cbab3}.ollama-detail-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:7px;color:#8eada6}.ollama-detail-grid strong{color:#d2e7e1}.ollama-jobs{display:grid;gap:7px;margin:0 0 15px}.ollama-jobs>div{display:flex;justify-content:space-between;padding:10px 12px;border-radius:7px;background:rgba(50,113,99,.2);border:1px solid rgba(112,213,187,.23);font-size:11px;color:#b6dcd2}.ollama-empty{padding:48px 14px;text-align:center;color:#8aa8a1;font-size:13px}.ollama-jobs span{color:#a7e7d0}.ollama-badge.current{color:#a9f0d1;border-color:rgba(84,222,159,.42);background:rgba(35,137,91,.22)}.ollama-badge.popular{color:#f5d18c;border-color:rgba(244,182,80,.4);background:rgba(142,90,25,.2)}.ollama-variants{margin:15px 0 5px;border:1px solid rgba(155,205,194,.17);border-radius:8px;background:rgba(5,18,17,.34);overflow:hidden}.ollama-variants-heading{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:11px 12px;border-bottom:1px solid rgba(155,205,194,.14)}.ollama-variants-heading h4{margin:0;color:#d8ebe6;font-size:11px;text-transform:uppercase;letter-spacing:.08em}.ollama-variants-heading span{color:#7fa69d;font-size:10px}.ollama-variant-table-wrap{overflow-x:auto}.ollama-variant-table{border-collapse:collapse;width:100%;font-size:11px;min-width:650px}.ollama-variant-table th{padding:9px 10px;text-align:left;color:#7fa69d;background:rgba(87,137,126,.08);font-size:9px;text-transform:uppercase;letter-spacing:.08em;font-weight:600}.ollama-variant-table td{padding:10px;border-top:1px solid rgba(155,205,194,.1);color:#a9c4bd;vertical-align:middle;white-space:nowrap}.ollama-variant-table tr.current{background:rgba(42,141,98,.12)}.ollama-variant-table td strong{color:#dcece8;display:block}.ollama-variant-table td small{display:block;color:#7fa69d;font-size:9px;margin-top:3px}.ollama-variant-table td .ollama-badge{margin-left:7px;vertical-align:middle}.ollama-current-label{color:#8fe1bf;font-size:10px}.ollama-variant-table .ollama-button{padding:6px 9px;font-size:10px} +.ollama-page{min-height:100%;padding:28px 32px 56px;color:#e8f2ef;background:linear-gradient(135deg,rgba(17,42,39,.92),rgba(10,24,23,.98));font-family:inherit}.ollama-hero{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;border-bottom:1px solid rgba(164,211,199,.16);padding-bottom:22px}.ollama-eyebrow{font-size:10px;letter-spacing:.18em;color:#8ec8bb;font-weight:700}.ollama-hero h1{margin:7px 0 6px;font-size:30px;letter-spacing:.02em}.ollama-hero p{margin:0;color:#a5bfba;max-width:680px}.ollama-health{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end;color:#9bb6b0;font-size:12px}.ollama-badge-row{display:flex;gap:6px;flex-wrap:wrap;margin-top:7px}.ollama-badge{display:inline-flex;align-items:center;border:1px solid rgba(152,204,192,.24);border-radius:999px;padding:4px 8px;color:#b4d1ca;font-size:10px;letter-spacing:.06em;text-transform:uppercase;background:rgba(80,125,115,.12)}.ollama-badge.live{color:#9af1c7;border-color:rgba(72,218,147,.4);background:rgba(35,137,91,.2)}.ollama-badge.installed{color:#bce1ff;border-color:rgba(89,168,231,.35);background:rgba(30,96,145,.2)}.ollama-badge.download{color:#f6d18f;border-color:rgba(244,182,80,.35);background:rgba(142,90,25,.18)}.ollama-badge.moe{color:#e2b4ff;border-color:rgba(197,107,255,.35);background:rgba(105,44,139,.2)}.ollama-badge.danger{color:#ffb1b1;border-color:rgba(255,100,100,.45);background:rgba(160,40,40,.18)}.ollama-button{border:1px solid rgba(155,205,194,.24);border-radius:7px;background:rgba(70,117,108,.18);color:#dbebe7;padding:8px 11px;cursor:pointer;font:inherit;font-size:11px;transition:background .15s,border-color .15s}.ollama-button:hover:not(:disabled){background:rgba(91,161,144,.3);border-color:rgba(155,230,210,.55)}.ollama-button:disabled{opacity:.45;cursor:not-allowed}.ollama-button.selected{background:#3e8073;border-color:#8dd2c1}.ollama-button.danger{color:#ffb8b8;border-color:rgba(255,110,110,.3)}.ollama-toolbar{display:flex;justify-content:space-between;gap:16px;margin:22px 0 12px;align-items:center}.ollama-tabs{display:flex;gap:8px;flex-wrap:wrap}.ollama-search{min-width:280px;max-width:410px;width:100%;background:rgba(7,20,19,.65);border:1px solid rgba(155,205,194,.24);border-radius:7px;color:#e8f2ef;padding:10px 12px;font:inherit;font-size:12px}.ollama-search::placeholder{color:#78958e}.ollama-info-strip{display:flex;gap:18px;flex-wrap:wrap;color:#88aaa2;font-size:11px;padding:10px 0 18px}.ollama-notice{padding:10px 12px;margin-top:15px;border-radius:7px;font-size:12px}.ollama-notice.ok{background:rgba(42,141,98,.18);border:1px solid rgba(84,222,159,.32);color:#a9f1cf}.ollama-notice.warning{background:rgba(156,112,45,.2);border:1px solid rgba(255,193,86,.5);color:#ffe0a0}.ollama-notice.error{background:rgba(156,45,45,.18);border:1px solid rgba(255,116,116,.35);color:#ffc1c1}.ollama-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(390px,1fr));gap:15px}.ollama-model-card{border:1px solid rgba(155,205,194,.18);border-radius:11px;background:rgba(12,31,29,.78);padding:17px;box-shadow:0 12px 30px rgba(0,0,0,.12)}.ollama-card-top{display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.ollama-model-title h3{margin:0;font-size:17px;word-break:break-word}.ollama-card-actions{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}.ollama-model-summary{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:17px 0 10px}.ollama-model-summary div{padding:9px;background:rgba(87,137,126,.09);border-radius:7px;min-width:0}.ollama-model-summary small{display:block;color:#779d95;font-size:9px;text-transform:uppercase;letter-spacing:.08em;margin-bottom:4px}.ollama-model-summary strong{display:block;color:#d8ebe6;font-size:12px;overflow-wrap:anywhere}.ollama-card-meta{display:flex;gap:12px;flex-wrap:wrap;color:#8eada6;font-size:10px}.ollama-strengths{margin:13px 0;color:#b1c9c3;font-size:12px;line-height:1.5}.ollama-strengths strong{color:#dfede9}.ollama-details-toggle{padding:6px 0;border:0;background:transparent;color:#8fd1bf}.ollama-details{border-top:1px solid rgba(155,205,194,.14);margin-top:10px;padding-top:13px;color:#a9c4bd;font-size:11px}.ollama-details h4{margin:0 0 8px;color:#d8ebe6;font-size:11px;text-transform:uppercase;letter-spacing:.08em}.ollama-details p{line-height:1.5}.ollama-capabilities{display:grid;gap:7px}.ollama-capability{display:flex;align-items:center;gap:8px}.ollama-capability span{color:#9cbab3}.ollama-detail-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:7px;color:#8eada6}.ollama-detail-grid strong{color:#d2e7e1}.ollama-jobs{display:grid;gap:7px;margin:0 0 15px}.ollama-jobs>div{display:flex;justify-content:space-between;padding:10px 12px;border-radius:7px;background:rgba(50,113,99,.2);border:1px solid rgba(112,213,187,.23);font-size:11px;color:#b6dcd2}.ollama-empty{padding:48px 14px;text-align:center;color:#8aa8a1;font-size:13px}.ollama-jobs span{color:#a7e7d0}.ollama-badge.current{color:#a9f0d1;border-color:rgba(84,222,159,.42);background:rgba(35,137,91,.22)}.ollama-badge.popular{color:#f5d18c;border-color:rgba(244,182,80,.4);background:rgba(142,90,25,.2)}.ollama-variants{margin:15px 0 5px;border:1px solid rgba(155,205,194,.17);border-radius:8px;background:rgba(5,18,17,.34);overflow:hidden}.ollama-variants-heading{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:11px 12px;border-bottom:1px solid rgba(155,205,194,.14)}.ollama-variants-heading h4{margin:0;color:#d8ebe6;font-size:11px;text-transform:uppercase;letter-spacing:.08em}.ollama-variants-heading span{color:#7fa69d;font-size:10px}.ollama-variant-table-wrap{overflow-x:auto}.ollama-variant-table{border-collapse:collapse;width:100%;font-size:11px;min-width:650px}.ollama-variant-table th{padding:9px 10px;text-align:left;color:#7fa69d;background:rgba(87,137,126,.08);font-size:9px;text-transform:uppercase;letter-spacing:.08em;font-weight:600}.ollama-variant-table td{padding:10px;border-top:1px solid rgba(155,205,194,.1);color:#a9c4bd;vertical-align:middle;white-space:nowrap}.ollama-variant-table tr.current{background:rgba(42,141,98,.12)}.ollama-variant-table td strong{color:#dcece8;display:block}.ollama-variant-table td small{display:block;color:#7fa69d;font-size:9px;margin-top:3px}.ollama-variant-table td .ollama-badge{margin-left:7px;vertical-align:middle}.ollama-current-label{color:#8fe1bf;font-size:10px}.ollama-variant-table .ollama-button{padding:6px 9px;font-size:10px} @media(max-width:760px){.ollama-page{padding:20px 16px 40px}.ollama-hero,.ollama-toolbar{display:block}.ollama-health{justify-content:flex-start;margin-top:15px}.ollama-search{margin-top:12px;max-width:none}.ollama-grid{grid-template-columns:1fr}.ollama-card-top{display:block}.ollama-card-actions{justify-content:flex-start;margin-top:12px}.ollama-model-summary{grid-template-columns:repeat(2,1fr)}} .ollama-popular-note{margin:14px 0;color:#a5bfba;font-size:12px;line-height:1.5} .ollama-model-pool{margin-top:14px;padding:16px;border:1px solid rgba(164,211,199,.16);border-radius:12px;background:rgba(10,31,28,.7)}.ollama-pool-heading{display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.ollama-pool-heading h3{margin:0 0 3px}.ollama-pool-heading p{margin:0;color:#8fa9a4;font-size:11px}.ollama-pool-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:8px;margin-top:12px}.ollama-pool-item,.ollama-chat-model-selection label{display:flex;gap:8px;align-items:flex-start;padding:9px;border:1px solid rgba(155,205,194,.16);border-radius:7px;background:rgba(71,117,108,.1);color:#c5ddd7;font-size:11px;cursor:pointer}.ollama-pool-item.loaded{border-color:rgba(117,210,183,.75);background:linear-gradient(135deg,rgba(48,113,96,.48),rgba(35,82,73,.42));box-shadow:0 0 0 1px rgba(117,210,183,.18),0 0 18px rgba(117,210,183,.12)}.ollama-pool-item.loaded strong{color:#effff9}.ollama-pool-item.loaded small{color:#a8ead8}.ollama-pool-item.selected{outline:1px solid rgba(117,210,183,.45)}.ollama-pool-item input,.ollama-chat-model-selection input{margin-top:2px;accent-color:#75d2b7}.ollama-pool-item span{display:flex;flex-direction:column;gap:3px}.ollama-pool-item small,.ollama-chat-model-selection small{color:#8fa9a4;font-size:10px}.ollama-chat-model-selection label.loaded{border-color:rgba(117,210,183,.48);background:rgba(48,113,96,.28);color:#effff9}.ollama-pool-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}.ollama-chat-model-selection{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:14px;padding-top:12px;border-top:1px solid rgba(164,211,199,.14);color:#d5e8e2}.ollama-chat-model-selection>strong{margin-right:4px}.ollama-chat-model-selection>small{margin-right:8px}.ollama-chat-model-selection label{align-items:center;padding:6px 8px}.ollama-loaded-capabilities{flex-basis:100%;color:#b8ead9;font-size:10px}.ollama-permanent-label{color:#9af1c7;font-size:10px} diff --git a/dashboard/manifest.json b/dashboard/manifest.json index 09f317f..0e17f92 100644 --- a/dashboard/manifest.json +++ b/dashboard/manifest.json @@ -3,7 +3,7 @@ "label": "Ollama Models", "description": "Inspect, manage, and chat with local Ollama models, including shared persistent conversations, performance metrics, images, PDFs, URLs, and live memory telemetry.", "icon": "Cpu", - "version": "1.5.13", + "version": "1.5.14", "tab": {"path": "/ollama-manager", "position": "after:models"}, "entry": "dist/index.js", "css": "dist/style.css", diff --git a/plugin.yaml b/plugin.yaml index 3aaa916..1de4c69 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,5 +1,5 @@ name: ollama-manager -version: 1.5.13 +version: 1.5.14 description: Native dashboard manager and chat interface for local Ollama models, attachments, URLs, shared persistent conversations, performance metrics, and live runtime telemetry. auto_install_dependencies: true python_dependencies: