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
10 changes: 8 additions & 2 deletions stacklets/ai/hooks/on_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
# third-party tap until that tap is trusted, so the trust step in
# `_install_omlx_formula` is what stands between a working `stack up ai`
# and an install that dies at the first brew command.
# Homebrew 7 asks before an install that brings dependencies, and the
# question is buried in `stack up ai`'s output, where a script or an agent
# waits on it for good. The admin already said yes to setting up AI. Older
# Homebrew ignores the variable, where it would refuse `--yes`.
BREW_INSTALL = "HOMEBREW_NO_ASK=1 brew install"

OMLX_TAP = "jundot/omlx"
OMLX_TAP_URL = "https://github.com/jundot/omlx"
WHISPER_MODEL = "ggml-large-v3-turbo.bin"
Expand Down Expand Up @@ -99,7 +105,7 @@ def _install_omlx_formula(ctx) -> None:
except RuntimeError:
dim(" (this Homebrew has no trust gate — nothing to do)")

ctx.shell_live("brew install omlx --with-grammar")
ctx.shell_live(f"{BREW_INSTALL} omlx --with-grammar")


def install_omlx(ctx, state_dir: Path):
Expand Down Expand Up @@ -183,7 +189,7 @@ def _install_whisper(ctx, data_dir: Path, state_dir: Path):

if missing:
ctx.step(f"Installing build dependencies: {' '.join(missing)}...")
ctx.shell_live(f"brew install {' '.join(missing)}")
ctx.shell_live(f"{BREW_INSTALL} {' '.join(missing)}")
done("Dependencies ready")

# Clone source
Expand Down
15 changes: 12 additions & 3 deletions tests/unit/stacklets/test_ai_omlx_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def test_the_tap_is_trusted_before_the_install_runs(self):
trust_at = next(i for i, c in enumerate(ctx.commands)
if c.startswith("brew trust"))
install_at = next(i for i, c in enumerate(ctx.commands)
if c.startswith("brew install omlx"))
if "brew install omlx" in c)
assert trust_at < install_at, "trusting after installing is too late"

def test_the_tap_is_added_before_it_is_trusted(self):
Expand All @@ -90,7 +90,16 @@ def test_grammar_is_requested_so_json_mode_works(self):
# formula installs a build whose JSON mode is broken.
ctx = FakeCtx()
_install_omlx_formula(ctx)
assert any(c == "brew install omlx --with-grammar" for c in ctx.commands)
assert any(c.endswith("brew install omlx --with-grammar") for c in ctx.commands)

def test_homebrew_does_not_stop_to_ask(self):
"""Homebrew 7 asks before an install that brings dependencies. Deep
in `stack up ai` nobody expects that question, and a script or an
agent running it waits on it for good."""
ctx = FakeCtx()
_install_omlx_formula(ctx)
(install,) = [c for c in ctx.commands if "brew install" in c]
assert install.startswith("HOMEBREW_NO_ASK=1 ")

def test_steps_are_separate_commands_not_one_chained_string(self):
"""Chained with `&&`, any failure reported the whole string, so a
Expand All @@ -105,4 +114,4 @@ def test_a_homebrew_without_a_trust_gate_still_installs(self):
nothing to clear, so its absence is success, not a failed install."""
ctx = FakeCtx(no_trust_subcommand=True)
_install_omlx_formula(ctx) # must not raise
assert any(c.startswith("brew install omlx") for c in ctx.commands)
assert any("brew install omlx" in c for c in ctx.commands)
2 changes: 1 addition & 1 deletion tests/unit/stacklets/test_ai_start_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def test_a_missing_engine_is_installed(self, monkeypatch):

on_start.run(ctx)

assert "brew install omlx --with-grammar" in ctx.shell_calls
assert any(c.endswith("brew install omlx --with-grammar") for c in ctx.shell_calls)

def test_an_installed_engine_starts_normally(self, monkeypatch):
monkeypatch.setattr(on_start.shutil, "which",
Expand Down
Loading