From d70eb99a0d996d016868a90fdd1f74c8e6544fe4 Mon Sep 17 00:00:00 2001 From: pewdiepie-archdaemon Date: Sun, 14 Jun 2026 22:45:12 +0900 Subject: [PATCH] Cookbook/Dependencies recipes: install into configured venv, drop 'uv venv' Recipes now hold ONLY the install command(s). The rendered
prepends a 'source /bin/activate' line so the user sees a
paste-ready sequence; Run uses env_prefix (same path the Install
button uses) to activate the configured venv before the install
command, so the install lands in the existing environment rather
than a fresh .venv in whatever CWD the tmux task happens to start in.

- cookbook-deps-recipes.js: trim each recipe to its single pip command
- cookbook.js: _recipeDisplayText() prepends the activate context for
  display; pre's data-dep-recipe-install holds the raw install-only
  command list so Run knows what to send; Run builds env_prefix the
  same way _installDep does.
---
 static/js/cookbook-deps-recipes.js | 13 ++++------
 static/js/cookbook.js              | 41 ++++++++++++++++++++++++++----
 2 files changed, 41 insertions(+), 13 deletions(-)

diff --git a/static/js/cookbook-deps-recipes.js b/static/js/cookbook-deps-recipes.js
index 86d4f6f07..36ecf5bbd 100644
--- a/static/js/cookbook-deps-recipes.js
+++ b/static/js/cookbook-deps-recipes.js
@@ -5,6 +5,11 @@
 // Entries are matched first-hit; put the more specific patterns ABOVE the
 // generic fallback for that backend.
 
+// Recipes hold ONLY the install command(s). The renderer prepends a
+// `source /bin/activate` line for context using the active server's
+// configured envPath; the Run button reuses env_prefix to activate that
+// same venv before executing, so the install lands in your existing
+// environment rather than a fresh `.venv` in some random CWD.
 const _RECIPES = [
   // ── vllm ──────────────────────────────────────────────────────────────
   // MiniMax M2/M2.7 — same generic vllm install for now; kept as its own
@@ -15,8 +20,6 @@ const _RECIPES = [
     label: 'MiniMax M2 / M2.7',
     match: (m) => /minimax[-_]?m\s?2(\.7)?/i.test(m || ''),
     commands: [
-      'uv venv',
-      'source .venv/bin/activate',
       'uv pip install -U vllm --torch-backend auto',
     ],
   },
@@ -27,8 +30,6 @@ const _RECIPES = [
     label: 'Any vLLM model',
     match: () => true,
     commands: [
-      'uv venv',
-      'source .venv/bin/activate',
       'uv pip install -U vllm --torch-backend auto',
     ],
   },
@@ -39,8 +40,6 @@ const _RECIPES = [
     label: 'Any SGLang model',
     match: () => true,
     commands: [
-      'uv venv',
-      'source .venv/bin/activate',
       'uv pip install -U "sglang[all]" --torch-backend auto',
     ],
   },
@@ -53,8 +52,6 @@ const _RECIPES = [
     label: 'Any GGUF model',
     match: () => true,
     commands: [
-      'uv venv',
-      'source .venv/bin/activate',
       'CMAKE_ARGS="-DGGML_CUDA=on" uv pip install -U "llama-cpp-python[server]"',
     ],
   },
diff --git a/static/js/cookbook.js b/static/js/cookbook.js
index a5b1ff5b6..584ec2ff0 100644
--- a/static/js/cookbook.js
+++ b/static/js/cookbook.js
@@ -834,6 +834,17 @@ async function _fetchDependencies() {
         + recipePanel;
     };
 
+    // Prepend the configured venv's activate line (when one is set) so the
+    // user sees the full sequence they'd need to paste, while Run keeps
+    // using env_prefix to activate the same venv before the pip command.
+    function _recipeDisplayText(commands) {
+      const envPath = (_envState.envPath || '').replace(/\/+$/, '');
+      const activate = envPath
+        ? `source ${envPath}${envPath.endsWith('/bin/activate') ? '' : '/bin/activate'}`
+        : '# (activate your venv first)';
+      return [activate, ...commands].join('\n');
+    }
+
     // Per-backend recipe panel (model picker + commands + Copy/Run).
     // Lives directly below the row it expands and starts collapsed.
     // The model picker lists every downloaded model from _cachedModelIds
@@ -858,7 +869,7 @@ async function _fetchDependencies() {
             Serving which model?
             
           
-          
${esc(initial.commands.join('\n'))}
+
${esc(_recipeDisplayText(initial.commands))}
@@ -988,13 +999,18 @@ async function _fetchDependencies() { }); // Model select: pickRecipe matches the model id against the catalog // (e.g. minimax-m2.7 → MiniMax recipe; anything else → generic). + // Visible text gets the activate-line prefix; the actual install + // command stays on data-dep-recipe-install so Run knows what to send. list.querySelectorAll('[data-dep-recipe-pick]').forEach(sel => { sel.addEventListener('change', () => { const backend = sel.dataset.depRecipePick; const recipe = pickRecipe(backend, sel.value || ''); if (!recipe) return; const pre = list.querySelector(`[data-dep-recipe-cmds="${CSS.escape(backend)}"]`); - if (pre) pre.textContent = recipe.commands.join('\n'); + if (pre) { + pre.textContent = _recipeDisplayText(recipe.commands); + pre.dataset.depRecipeInstall = recipe.commands.join('\n'); + } }); }); // Copy: drop the visible command block on the clipboard. @@ -1015,23 +1031,38 @@ async function _fetchDependencies() { } }); }); - // Run: launch the joined `cmd1 && cmd2 && …` as a tmux task on the - // currently-selected deps server, same plumbing as Install. + // Run: launch the install command(s) as a tmux task on the currently- + // selected deps server. Activation comes from env_prefix (same plumbing + // the Install button uses) so the install lands in the configured venv + // instead of a fresh .venv in some random CWD. list.querySelectorAll('[data-dep-recipe-run]').forEach(btn => { btn.addEventListener('click', async (e) => { e.stopPropagation(); const backend = btn.dataset.depRecipeRun; const pre = list.querySelector(`[data-dep-recipe-cmds="${CSS.escape(backend)}"]`); if (!pre) return; - const cmd = pre.textContent.split('\n').map(s => s.trim()).filter(Boolean).join(' && '); + // Use the install-only command list (no activate line) — the + // displayed source line is for the user's reading; env_prefix + // handles it for the actual run. + const installRaw = pre.dataset.depRecipeInstall || pre.textContent; + const cmd = installRaw.split('\n').map(s => s.trim()).filter(Boolean).join(' && '); const depsSel = document.getElementById('hwfit-deps-server'); if (depsSel) _applyServerSelection(depsSel.value); const targetHost = _envState.remoteHost || 'local'; + // Build env_prefix from the configured envPath (matches _installDep). + let envPrefix = ''; + if (_envState.env === 'venv' && _envState.envPath) { + const p = _envState.envPath; + envPrefix = 'source ' + _shellQuote(p.endsWith('/bin/activate') ? p : p + '/bin/activate'); + } else if (_envState.env === 'conda' && _envState.envPath) { + envPrefix = 'eval "$(conda shell.bash hook)" && conda activate ' + _shellQuote(_envState.envPath); + } const reqBody = { repo_id: `${backend} setup`, cmd: cmd, remote_host: _envState.remoteHost || undefined, ssh_port: _getPort(_envState.remoteHost) || undefined, + env_prefix: envPrefix || undefined, platform: _envState.platform || undefined, }; try {