Status: NOT in this commit. The kobbler kob-gpu-gate already
registers an LLM heavy service with unload_path: "/v1/admin/unload" +
drain_path: "/v1/admin/drain", and acquire_for_avatar already does the
drain → wait-for-in-flight → unload dance against those paths. So as soon as
this fork ships the endpoints, the avatar↔LLM coexistence story works without
any further kobbler-side change.
Today: koblem-llama is docker.oldug.com/koblem-llama:latest (the
TurboQuant fork). The Avatar render path silently no-ops when the LLM is
unregistered or when the endpoints aren't there — fine for v0 since the box
the agent verified on doesn't currently run llama-server. But ship this for
real two-heavies coexistence.
Per GO-LIVE-PLAN §3.4.b:
- Env-gated
LLAMA_WORKER_ISOLATION=1. When set, on the first chat request,fork()a child that holds the CUDA context + the GGUF + the spec-mtp draft + mmproj. The parent stays CUDA-free and owns the HTTP port + the in-flight counter. POST /v1/admin/unload— SIGKILL the child. Kernel exit tears down the CUDA context → ALL VRAM reclaimed. Idempotent: an idle parent returns 200 with{status: "idle"}.POST /v1/admin/drain— set a flag that 503's new/v1/chat/completions/v1/completionsrequests. Existing in-flight streams run to[DONE]naturally. Clearing the flag happens viaPOST /v1/admin/load(or automatically on next acquire-for-llm, but explicit-clear is cleaner).
POST /v1/admin/load— optional pre-warm. If the child is dead, fork + load eagerly so the next chat request doesn't pay the cold reload tax.GET /health— augment the existing response with{loaded, busy, draining, in_flight}so the kob-gpu-gateservice_states()shape and the koblem/api/v1/gpu/servicesUI can show LLM state.
-
SSE relay across the IPC boundary. Chat completions stream
text/event-stream— the parent has to forward the child's SSE frames out the inbound HTTP socket without re-encoding. Two approaches:- dup'd-fd / SCM_RIGHTS — child sends its write-end fd to the parent over a Unix-domain socket; parent splices fd → response socket. Lowest overhead.
- Per-request named pipe — parent opens a FIFO before sending the request blob to the child; reads SSE frames from the FIFO, writes to the response. Simpler, marginally slower.
-
Drain semantics under streams.
/v1/admin/drainblocks new requests only. The currently-streaming response runs to its[DONE]event. Keep-alive connections that haven't sent a request yet stay open (their next request gets the 503). -
Cold-reload latency. ~5 s warm-page-cache, < 2 s if
/modelsis already paged. First chat after an avatar render eats this — acceptable (the kid pressing Avatar then immediately resuming chat is the expected flow, and 5 s is invisible compared to the avatar wall they just sat through).
-
~/dev/qwen3-tts.cpp/src/server.cpp(THE blueprint):- L552 —
fork()on first request whenQWEN3_TTS_WORKER_ISOLATION=1. - L856–880 — request marshalling to child over a Unix-domain socket.
- L1152–1158 —
POST /v1/admin/unloadhandler.
- L552 —
-
~/dev/siglip2.cpp/src/{siglip2_server.cpp, worker_ipc.cpp, worker_session.cpp}— second worker-isolation reference, slightly different IPC shape. -
~/dev/parakeet.cpp/examples/server/server.cpp— third reference; useful for the "/unloadreturns clean even when no model is loaded" idempotency pattern (compose's healthcheck depends on this).
The server entry is at examples/server/server.cpp (or the standard
llama.cpp server path — check the latest sync point from upstream). Add a
top-of-main fork helper + an IPC channel module + the three admin route
handlers. Bind the existing chat-completion handler behind a
forward_to_child(request, response) shim.
The llama-server-dev profile (docker/llama-server-dev/ + LLAMA_SRC= $HOME/dev/llama.cpp-turboquant) builds against the local source tree on
port 8093. End-to-end test:
docker compose --profile llama-dev up -d llama-server-dev- Send a chat completion, watch VRAM go up (~6.5 GB).
POST localhost:8093/v1/admin/drain, fire another chat → expect 503.POST localhost:8093/v1/admin/unload, watch VRAM return to 149 MiB.- Send another chat — expect cold load (~5 s) then normal streaming.
Run the avatar render concurrently to verify the full
acquire_for_avatar drain dance (kobbler must point LLAMA_SERVER_URL at
port 8093 for this test).
- Owner triggers a registry rebuild of
docker.oldug.com/koblem-llama:latest. docker compose pull llama-server && docker compose up -d llama-serveron this box.kob-gpu-gatetestavatar_drains_then_unloads_llm(already landed) becomes load-bearing — the drain dance will fire in prod.- The
is_avatar_busy503-on-chat path becomes the prod failure mode.
This is port the qwen3-tts.cpp shape, not "design a new IPC". The shape works; the cost of inventing something different is real and the ROI is zero.