Skip to content

Commit 91806d5

Browse files
committed
fix(build): cap parallel compilation threads to prevent CPU lockup
1 parent 8c94322 commit 91806d5

5 files changed

Lines changed: 42 additions & 6 deletions

File tree

routes/cookbook_helpers.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,20 @@ def _user_shell_path_bootstrap() -> list[str]:
359359
return [
360360
'ODYSSEUS_USER_SHELL="${SHELL:-}"',
361361
'if [ -n "$ODYSSEUS_USER_SHELL" ] && [ -x "$ODYSSEUS_USER_SHELL" ]; then',
362-
' ODYSSEUS_USER_PATH="$("$ODYSSEUS_USER_SHELL" -ic \'printf "__ODYSSEUS_PATH__%s\\n" "$PATH"\' 2>/dev/null | sed -n \'s/^__ODYSSEUS_PATH__//p\' | tail -n 1 || true)"',
362+
' case "$ODYSSEUS_USER_SHELL" in',
363+
' *fish*) ODYSSEUS_USER_PATH="$("$ODYSSEUS_USER_SHELL" -c \'printf "__ODYSSEUS_PATH__%s\\n" "$PATH"\' 2>/dev/null | sed -n \'s/^__ODYSSEUS_PATH__//p\' | tail -n 1 || true)" ;;',
364+
' *) ODYSSEUS_USER_PATH="$("$ODYSSEUS_USER_SHELL" -lc \'printf "__ODYSSEUS_PATH__%s\\n" "$PATH"\' 2>/dev/null | sed -n \'s/^__ODYSSEUS_PATH__//p\' | tail -n 1 || true)" ;;',
365+
' esac',
363366
' if [ -n "$ODYSSEUS_USER_PATH" ]; then export PATH="$ODYSSEUS_USER_PATH:$PATH"; fi',
364367
'fi',
368+
'if command -v nproc >/dev/null 2>&1; then',
369+
' _n="$(nproc)"',
370+
' export CMAKE_BUILD_PARALLEL_LEVEL="$(( _n > 2 ? _n - 2 : 1 ))"',
371+
' export NPROC="$(( _n > 2 ? _n - 2 : 1 ))"',
372+
'else',
373+
' export CMAKE_BUILD_PARALLEL_LEVEL=2',
374+
' export NPROC=2',
375+
'fi',
365376
# Windows can expose python3 as a Microsoft Store App Execution Alias
366377
# under WindowsApps. Git Bash sees that stub as present, but it exits
367378
# before running Python. A Windows venv usually has python.exe, not
@@ -378,6 +389,7 @@ def _cached_model_scan_script(model_dirs: list[str] | None = None, add_hf_cache:
378389
"""
379390
lines = [
380391
"import json, os, re, shutil, subprocess, urllib.request",
392+
f"model_dirs = {model_dirs or []!r}",
381393
"models = []",
382394
"seen = set()",
383395
"BLOCKED_ROOTS = ('/sys', '/proc', '/dev', '/run', '/var/run')",
@@ -469,6 +481,12 @@ def _cached_model_scan_script(model_dirs: list[str] | None = None, add_hf_cache:
469481
" # Docker images mount ./data/huggingface at /app/.cache/huggingface.",
470482
" # When HOME is /root, expanduser() misses that persisted cache.",
471483
" add('/app/.cache/huggingface/hub')",
484+
" for p in model_dirs:",
485+
" try:",
486+
" ep = os.path.expanduser(p)",
487+
" if os.path.isdir(ep) and any(d.startswith('models--') for d in os.listdir(ep)):",
488+
" add(p)",
489+
" except Exception: pass",
472490
f" add({add_hf_cache!r})" if add_hf_cache else "",
473491
" return candidates",
474492
"def scan_dir(p):",
@@ -537,12 +555,11 @@ def _cached_model_scan_script(model_dirs: list[str] | None = None, add_hf_cache:
537555
" models.append({'repo_id':name,'size_bytes':size_bytes,'nb_files':1,'has_incomplete':False,'path':'ollama','backend':'ollama','is_ollama':True})",
538556
" return",
539557
"for _hf_cache in hf_cache_paths(): scan_hf(_hf_cache)",
558+
"for _md in model_dirs: scan_dir(os.path.expanduser(_md))",
540559
"scan_ollama_api()",
541560
"scan_ollama()",
561+
"print(json.dumps(models))",
542562
]
543-
for model_dir in model_dirs or []:
544-
lines.append(f"scan_dir(os.path.expanduser({model_dir!r}))")
545-
lines.append("print(json.dumps(models))")
546563
return "\n".join(lines) + "\n"
547564

548565

routes/cookbook_routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1751,7 +1751,7 @@ async def model_serve(request: Request, req: ServeRequest):
17511751
# else a plain CPU build. nproc is Linux-only — fall back to
17521752
# `sysctl hw.ncpu` on macOS. (Tip: `brew install llama.cpp` ships
17531753
# a prebuilt llama-server and skips this whole source build.)
1754-
runner_lines.append(' NPROC="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)"')
1754+
runner_lines.append(' _n="$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)"; NPROC="$(( _n > 2 ? _n - 2 : 1 ))"')
17551755
runner_lines.append(' if [ "$(uname -s)" = "Darwin" ]; then')
17561756
runner_lines.append(' command -v cmake >/dev/null 2>&1 || echo "WARNING: cmake not found — install it with: brew install cmake (or: brew install llama.cpp for a prebuilt llama-server)."')
17571757
# Start from a clean cache: a prior failed configure (e.g. a CUDA

src/llm_core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2264,6 +2264,11 @@ def _format_routed_content(parts: List[Tuple[str, bool]]) -> List[str]:
22642264
if data.strip():
22652265
if data.startswith("{"):
22662266
j = json.loads(data)
2267+
if "error" in j:
2268+
err = j["error"] or {}
2269+
text = err.get("message") if isinstance(err, dict) else str(err)
2270+
yield f'event: error\ndata: {json.dumps({"status": 400, "text": text})}\n\n'
2271+
return
22672272
chunk_model = j.get("model")
22682273
if isinstance(chunk_model, str) and chunk_model.strip():
22692274
_actual_model = chunk_model.strip()

src/model_context.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,10 +460,10 @@ def _query_context_length(endpoint_url: str, model: str) -> Tuple[int, bool]:
460460
except Exception as e:
461461
logger.debug(f"Failed to query context length for {model}: {e}")
462462

463+
_is_local = is_local_endpoint(endpoint_url)
463464
# For local/self-hosted endpoints, trust the API value (user set --max-model-len)
464465
# For cloud APIs, use the larger value (API can report low defaults)
465466
if api_ctx and known:
466-
_is_local = is_local_endpoint(endpoint_url)
467467
if _is_local and api_ctx < known:
468468
logger.info(f"Local endpoint reports {api_ctx} for {model} (known max: {known}) — using API value")
469469
return api_ctx, True
@@ -474,9 +474,21 @@ def _query_context_length(endpoint_url: str, model: str) -> Tuple[int, bool]:
474474
if api_ctx:
475475
return api_ctx, True
476476
if known:
477+
if _is_local:
478+
import os as _os
479+
env_val = _os.environ.get("ODYSSEUS_LOCAL_CONTEXT")
480+
try:
481+
limit = int(env_val) if env_val else 4096
482+
except (ValueError, TypeError):
483+
limit = 4096
484+
val = min(known, limit)
485+
logger.info(f"Using capped known context window for local endpoint {model}: {val} (known max: {known}, cap: {limit})")
486+
return val, True
477487
logger.info(f"Using known context window for {model}: {known}")
478488
return known, True
479489

490+
if _is_local:
491+
return 4096, False
480492
return DEFAULT_CONTEXT, False
481493

482494

static/js/cookbook-hwfit.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,6 +2037,8 @@ export function _hwfitInit() {
20372037
const selectors = [
20382038
document.getElementById('hwfit-server-select'),
20392039
document.getElementById('hwfit-dl-server'),
2040+
document.getElementById('hwfit-cache-server'),
2041+
document.getElementById('hwfit-deps-server'),
20402042
];
20412043
for (const sel of selectors) {
20422044
if (!sel) continue;

0 commit comments

Comments
 (0)