frank-large: swap halogen Quadlet for ik_llama.cpp (3090 + Strix Halo CPU path)

This commit is contained in:
Frank
2026-09-15 23:20:19 -07:00
parent 4183e31fd1
commit fe3fc62c41
7 changed files with 274 additions and 76 deletions
+37 -69
View File
@@ -912,85 +912,53 @@ deploy_anubis() {
wait_container_healthy anubis 60 || return 1
}
# frank-large runs as a rootless Quadlet unit since 2026-09-11 (halogen-flash-
# server replaced the llama.cpp/kingjones runtime). Unlike the sibling LLM
# services it is therefore NOT a root unit: no relink_unit, no `systemctl
# enable` (this host's quadlet generator produces units that cannot be
# enabled — boot persistence comes from [Install] WantedBy=default.target in
# the .container file plus linger).
# frank-large runs as a ROOT unit again since 2026-09-15: ik_llama.cpp
# (qwen4exp support merged upstream) replaced the halogen-flash-server
# rootless Quadlet, and the ik server is a native binary — CUDA on the RTX
# 3090 for dense/attention/KV, the Strix Halo CPU path for the MoE experts.
# There is no container image to pull and no generated unit to avoid:
# relink_unit points /etc/systemd/system/frank-large.service at the repo
# file, and boot persistence is the unit's [Install] section.
#
# The llama.cpp-era ROOT unit is retired first. Its unit file is a symlink
# into this checkout (the old relink_unit did `ln -sfn scripts/frank-large.
# service /etc/systemd/system/`), so leaving it behind after the repo file
# moves to the trash would leave systemd holding a dangling unit that can
# still claim port 7770. Stop it, drop its enable symlinks, move the unit file
# into the home trash (never rm), then reload the root manager.
#
# FIRST START: the container fetches ~127 GB of weights before it can serve,
# so /health is legitimately down for the whole fetch. wait_for_health would
# burn its budget and report a failure that is not one. The gate below
# recognises the bootstrap (checkpoint absent) and waits for the checkpoint
# instead, falling through to the normal health gate once it lands.
LLM_LARGE_CHECKPOINT="${LLM_LARGE_CHECKPOINT:-/home/dank/models/halogen/qwen38-flash-next-w4b.hgn}"
# The halogen Quadlet is retired first. Both managers must never know this
# unit name at once (they would race for port 7770): stop the user unit,
# poll until it is really gone, move the installed .container into the home
# trash (never rm), then reload the user manager.
LLM_LARGE_CHECKPOINT="${LLM_LARGE_CHECKPOINT:-/home/dank/models/mradermacher-Qwen3.8-Flash-Next-Uncensored-i1-Q4_K_M/Qwen3.8-Flash-Next-Uncensored.i1-Q4_K_M.gguf}"
retire_root_llm_large() {
local trash="$HOME/.AGENTTRASH/20260911-halogen-swap/host-units"
run_privileged systemctl stop frank-default-large 2>/dev/null || true
run_privileged systemctl disable frank-default-large 2>/dev/null || true
run_privileged systemctl stop frank-large.service 2>/dev/null || true
# On this host `disable` has been observed to delete the unit file itself
# (2026-08-26 incident, see AGENTS.md); tolerate either behaviour and keep
# whatever remains by moving it to the trash.
run_privileged systemctl disable frank-large.service 2>/dev/null || true
if [[ -e /etc/systemd/system/frank-large.service || -L /etc/systemd/system/frank-large.service ]]; then
retire_quadlet_llm_large() {
local trash="$HOME/.AGENTTRASH/20260915-ik-swap/halogen-quadlet"
systemctl --user stop frank-large.service 2>/dev/null || true
# A stopping quadlet runs podman stop (SIGTERM, then SIGKILL at the
# timeout); llama-family engines never preempt an in-flight generation.
# Poll until the user unit is really inactive before removing its file.
local i
for ((i = 0; i < 30; i++)); do
systemctl --user is-active --quiet frank-large.service 2>/dev/null || break
sleep 2
done
if [[ -e "$HOME/.config/containers/systemd/frank-large.container" || -L "$HOME/.config/containers/systemd/frank-large.container" ]]; then
mkdir -p "$trash"
run_privileged mv -- /etc/systemd/system/frank-large.service \
"$trash/frank-large.service"
echo "retired root unit frank-large.service -> $trash"
mv -- "$HOME/.config/containers/systemd/frank-large.container" \
"$trash/frank-large.container"
echo "retired halogen quadlet -> $trash"
fi
run_privileged systemctl daemon-reload
systemctl --user daemon-reload
}
deploy_llm_large() {
retire_root_llm_large
# Pull once, then run the localhost/-aliased tag: this host's quadlet path
# cannot resolve registry-prefixed refs from local storage at create time
# (same workaround as anubis/hermes).
local image="ghcr.io/peonist-ai/halogen-flash-server:0.5.8"
local alias="localhost/peonist-ai/halogen-flash-server:0.5.8"
podman pull "$image"
podman tag "$image" "$alias"
# The weights volume: read-write, because the container downloads into it.
mkdir -p /home/dank/models/halogen
install_quadlet frank-large dankclaw/frank-large/quadlet frank-large
systemctl --user restart frank-large.service
wait_for_llm_large_ready
retire_quadlet_llm_large
if [[ ! -f "$LLM_LARGE_CHECKPOINT" ]]; then
echo "ERROR: checkpoint absent at $LLM_LARGE_CHECKPOINT" >&2
echo "frank-large: download the mradermacher i1-Q4_K_M GGUF first; refusing to start a unit that cannot load." >&2
return 1
fi
relink_unit frank-large
run_privileged systemctl enable frank-large.service
run_privileged systemctl restart frank-large.service
wait_for_health frank-large http://127.0.0.1:7770/health 1200
}
# wait_for_llm_large_ready — bootstrap-aware gate. If the checkpoint is absent
# the container is downloading it; wait for the file (resumable, and the unit
# restarts it on failure) rather than gating on a /health that cannot answer
# yet. Reports success either way, so the first deploy does not look like a
# failure while the engine does exactly what it was told to.
wait_for_llm_large_ready() {
[[ -f "$LLM_LARGE_CHECKPOINT" ]] && return 0
echo "frank-large: checkpoint absent at $LLM_LARGE_CHECKPOINT"
echo "frank-large: first start — the container is downloading ~127 GB from"
echo "frank-large: peonist-ai/halogen-qwen3.8-flash-next (resumes if interrupted)."
local i
for ((i = 1; i <= 1200; i++)); do
if [[ -f "$LLM_LARGE_CHECKPOINT" ]]; then
echo "frank-large: weights landed after approximately $((i * 2))s; gating on /health"
return 0
fi
sleep 2
done
echo "WARN: frank-large download still in progress after 40m — NOT a failure."
echo "WARN: the unit keeps fetching; re-run this deploy (or re-check /health) later." >&2
return 0
}
# deploy_llm_medium — frank-medium runs as a rootless Quadlet since the
# 2026-09-15 runtime swap to the vllm-radiance MXFP4 stack. It began the day
# as a root llama.cpp unit (the ROCmFPX/Q8_0_ROCMFPX_AGENT deployment from