Cookbook/Launch: pre-flight backend install check, deep-link to Dependencies

Before the quickrun (Run) button fires /api/model/serve, ask the deps
API whether the chosen backend (vllm / sglang / llama_cpp) is actually
installed on the target server. If not:

- Toast: '<backend> not installed on <host>. Opening Dependencies …'
- Route the user into the Dependencies tab via the existing
  _openCookbookDependencies helper (now exported as
  openCookbookDependencies)
- Auto-expand the recipe panel for that backend
- Pre-select the user's model in the panel's picker so the right
  recipe is highlighted out of the box

The serve task is suppressed; the Run button is re-enabled. Once the
install task finishes in Running, the user clicks Run again.

cookbook-diagnosis.js: openCookbookDependencies takes an opts object
that, when expandRecipe is set, finds the row's caret and clicks it,
then matches a recipe label by model (currently only MiniMax has a
specific entry; the generic fallback stays selected otherwise).
This commit is contained in:
pewdiepie-archdaemon
2026-06-14 22:35:56 +09:00
parent 600fa6be8a
commit 25dd94234c
2 changed files with 247 additions and 1 deletions
+27 -1
View File
@@ -65,7 +65,13 @@ import spinnerModule from './spinner.js';
// ── Error diagnosis ──
function _openCookbookDependencies(pkgName = '') {
// Re-exported so callers (Launch-tab pre-flight) can deep-link into the
// Dependencies tab + auto-expand a specific backend's recipe panel and
// pre-select the model they were trying to launch.
export function openCookbookDependencies(pkgName = '', opts = {}) {
_openCookbookDependencies(pkgName, opts);
}
function _openCookbookDependencies(pkgName = '', opts = {}) {
const cookbook = window.cookbookModule;
if (cookbook && typeof cookbook.open === 'function') {
cookbook.open({ tab: 'Dependencies' });
@@ -94,6 +100,26 @@ function _openCookbookDependencies(pkgName = '') {
row.scrollIntoView({ block: 'center' });
row.classList.add('cookbook-pkg-flash');
setTimeout(() => row.classList.remove('cookbook-pkg-flash'), 1800);
// Pre-flight deep link: auto-expand the recipe panel + pre-select
// the model the user was trying to launch.
if (opts.expandRecipe) {
const caret = row.querySelector('[data-dep-recipe-toggle]');
if (caret && caret.getAttribute('aria-expanded') !== 'true') caret.click();
if (opts.model) {
const sel = document.querySelector(`[data-dep-recipe-pick="${CSS.escape(opts.expandRecipe)}"]`);
if (sel) {
// Find first matching recipe; if none, leave on default.
for (let i = 0; i < sel.options.length; i++) {
const label = (sel.options[i].textContent || '').toLowerCase();
if (/minimax/i.test(opts.model) && /minimax/i.test(label)) {
sel.value = String(i);
sel.dispatchEvent(new Event('change'));
break;
}
}
}
}
}
}
};
tryHighlight();