Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion java_codebase_rag/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1799,7 +1799,19 @@ def run_install(
return e.code

# Stage 2: Embedding model
resolved_model = resolve_model(model, non_interactive=non_interactive)
from java_codebase_rag.pipeline import vector_stack_installed

if not vector_stack_installed():
# Graph-only install (macOS Intel): no torch/lancedb, so there is no vector
# index to embed into — the embedding-model choice is inert here. Skip the
# prompt and let init build the graph (vectors phase auto-skipped).
print(
"Skipping embedding model selection: vector stack not installed on this "
"platform (graph-only mode)."
)
resolved_model = "auto"
else:
resolved_model = resolve_model(model, non_interactive=non_interactive)

# Stage 3-4: Agent host + scope + surface selection
prior_surface = _prior_surface_from_marker(cwd)
Expand Down
14 changes: 14 additions & 0 deletions java_codebase_rag/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import annotations

import asyncio
import importlib.util
import os
import shutil
import subprocess
Expand Down Expand Up @@ -200,6 +201,19 @@ def is_graph_preflight_blocker(proc: subprocess.CompletedProcess[str]) -> bool:
return bool(proc.returncode in (126, 127) and len(getattr(proc, "args", ()) or ()) <= 1)


def vector_stack_installed() -> bool:
"""True when the optional vector stack (cocoindex/lancedb/sentence-transformers) is importable.

False on graph-only installs (macOS Intel), where PEP 508 markers exclude the trio.
Used to skip vector-only wizard steps (e.g. embedding-model selection) and to preflight
branching without spawning cocoindex. Probes all three since they are gated together.
"""
return all(
importlib.util.find_spec(m) is not None
for m in ("cocoindex", "lancedb", "sentence_transformers")
)


def _run_cocoindex_update_impl(
env: dict[str, str],
*,
Expand Down
22 changes: 22 additions & 0 deletions tests/test_graph_only_boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,25 @@ def test_preflight_blocker_detects_graph_only_install() -> None:
# non-zero exit is a failure, not a skip.
assert is_cocoindex_preflight_blocker(_completed(1, (exe, "update", "t", "-f"))) is False
assert is_cocoindex_preflight_blocker(_completed(0, (exe, "update", "t", "-f"))) is False


def test_vector_stack_installed_reports_absent_when_blocked() -> None:
# The installer wizard gates its embedding-model step on vector_stack_installed().
# Deterministic across platforms: blocking the modules in a fresh subprocess must
# report False (this is the macOS Intel reality).
proc = subprocess.run(
[
sys.executable,
"-c",
"import sys\n"
"for m in ('lancedb','pylance','torch','sentence_transformers','cocoindex'):\n"
" sys.modules[m] = None\n"
"from java_codebase_rag.pipeline import vector_stack_installed\n"
"print('INSTALLED:' + str(vector_stack_installed()))",
],
capture_output=True,
text=True,
timeout=60,
)
assert proc.returncode == 0, proc.stderr
assert "INSTALLED:False" in proc.stdout
Loading