diff --git a/crates/genie-core/tests/tool_dispatch_test.rs b/crates/genie-core/tests/tool_dispatch_test.rs index fa90729d..1f8755c9 100644 --- a/crates/genie-core/tests/tool_dispatch_test.rs +++ b/crates/genie-core/tests/tool_dispatch_test.rs @@ -264,6 +264,24 @@ fn start_all_uses_configured_llm_backend() { contents.contains("is_warmup_unit") && contents.contains("start --no-block"), "start_all should queue warmup units without blocking the lifecycle script" ); + let units = contents + .split("UNITS=(") + .nth(1) + .and_then(|s| s.split(")").next()) + .expect("start_all should declare ordered units"); + let llm_pos = units + .find("\"$configured_llm_unit\"") + .expect("start_all should include the configured LLM unit"); + let homeassistant_pos = units + .find("homeassistant.service") + .expect("start_all should include Home Assistant"); + let whisper_pos = units + .find("genie-whisper.service") + .expect("start_all should include Whisper"); + assert!( + llm_pos < homeassistant_pos && llm_pos < whisper_pos, + "start_all should start the configured LLM before memory-heavy services" + ); } /// Verify genie-ai-runtime service preserves warm GGUF pages across restarts. @@ -285,8 +303,14 @@ fn genie_ai_runtime_service_preserves_model_page_cache() { "genie-ai-runtime.service should use INT8 KV to fit enough context under memory pressure" ); assert!( - contents.contains("GENIEPOD_AI_RUNTIME_CONTEXT=2048"), - "genie-ai-runtime.service should request the GenieClaw web-chat context size" + contents.contains("GENIEPOD_AI_RUNTIME_CONTEXT=8192"), + "genie-ai-runtime.service should request the Jetson-tested 8k context size" + ); + assert!( + contents.contains( + "Before=genie-whisper.service genie-whisper-warmup.service homeassistant.service genie-core.service" + ), + "genie-ai-runtime.service should reserve KV cache before memory-heavy services" ); } diff --git a/deploy/scripts/start_all.sh b/deploy/scripts/start_all.sh index eac7371a..607dc7a6 100644 --- a/deploy/scripts/start_all.sh +++ b/deploy/scripts/start_all.sh @@ -118,12 +118,12 @@ configured_llm_unit="$(normalize_unit "$raw_llm_unit")" configured_warmup_unit="$(warmup_unit_for "$configured_llm_unit")" UNITS=( - homeassistant.service genie-audio.service - genie-whisper.service - genie-whisper-warmup.service "$configured_llm_unit" "$configured_warmup_unit" + homeassistant.service + genie-whisper.service + genie-whisper-warmup.service genie-core.service genie-governor.service genie-health.service diff --git a/deploy/systemd/genie-ai-runtime.service b/deploy/systemd/genie-ai-runtime.service index 8adf5f84..b3c36915 100644 --- a/deploy/systemd/genie-ai-runtime.service +++ b/deploy/systemd/genie-ai-runtime.service @@ -2,6 +2,11 @@ Description=GeniePod AI Runtime (Jetson-tuned LLM, OpenAI-compatible) Documentation=https://github.com/GeniePod/genie-ai-runtime After=network.target +# Claim the LLM KV cache before memory-heavy voice/container services start. +# Jetson testing for issue #75 showed the same `-c 4096` request fitting only +# ~1.7k ctx after the full stack was resident, but fitting 4k/6k/8k ctx when +# genie-ai-runtime loaded first. +Before=genie-whisper.service genie-whisper-warmup.service homeassistant.service genie-core.service ConditionPathExists=/opt/geniepod/bin/jetson-llm-server # Conflicts with genie-llm.service: both bind :8080. systemd will refuse # to start the second one while the first is running, so a misconfigured @@ -12,17 +17,16 @@ Conflicts=genie-llm.service Type=simple # Keep the GGUF in page cache across restarts when the kernel can. Clearing # VM caches here made every runtime restart cold-load Qwen3 again (issue #69). -# Use INT8 KV so the Jetson service reliably gets enough context for -# GenieClaw's web prompt even under memory pressure. `-c` is still clamped -# by runtime memory budget, but INT8 KV roughly doubles the fitted context -# versus the server's FP16 default. +# Use INT8 KV so the Jetson service can reserve an 8k context on Orin Nano +# when systemd starts it before memory-heavy services. `-c` is still clamped +# by runtime memory budget, so boot/start ordering matters. ExecStart=/opt/geniepod/bin/jetson-llm-server \ -m ${GENIEPOD_LLM_MODEL} \ -p 8080 \ -c ${GENIEPOD_AI_RUNTIME_CONTEXT} \ --int8-kv Environment=GENIEPOD_LLM_MODEL=/opt/geniepod/models/Qwen3-4B-Q4_K_M.gguf -Environment=GENIEPOD_AI_RUNTIME_CONTEXT=2048 +Environment=GENIEPOD_AI_RUNTIME_CONTEXT=8192 Restart=on-failure RestartSec=5 TimeoutStartSec=120