Repository navigation
feat(metal-agent): start without llama-server when --runtime selects another engine - #2529
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…another engine A missing llama-server is fatal only when --runtime selects llama.cpp. With another runtime the agent logs a warning and registers no llama.cpp executor. /usr/bin/llama-server is searched after the Homebrew paths, and the install hint names brew only on macOS. An InferenceService whose resolved runtime has no executor is refused before its Model is fetched or a running engine is stopped, through refuseStart with a new RuntimeNotAvailable reason, so its status and a Warning Event say why. The reason is in MetalAgentRefusalReasons so the controller keeps it. For llama.cpp the message says llama-server was not found and how to fix it. This applies to any runtime whose binary was not configured, not only llama.cpp. stopManagedProcess returns an error instead of calling a nil executor, including for an adopted process without a PID. The AllowUnsafeExtraArgs and currentBackend comments and the --allow-unsafe-extra-args help say "host" instead of "Mac". Fixes defilantech#2516 Signed-off-by: Christian Nuss <cnuss@users.noreply.github.com>
fade45f to
477ceb9
Compare
|
Addressed the review finding in the squashed commit (477ceb9):
|
Defilan
left a comment
There was a problem hiding this comment.
I checked every lookup of the llama.cpp executor for a nil: s3SizeProbe falls back to a stand-in, warnIfDaemonExposed checks presence, and stopManagedProcess now errors instead of calling a nil executor. An explicit --llama-server path is returned as-is, so a typo there still builds the executor rather than silently degrading. Moving the refusal ahead of fetchModelThenStopStale is the right order, and it sits after the eviction, scale-to-zero and matching-hash checks, so none of those change.
A few small things, none blocking:
- The description (and the commit message) says
stopManagedProcessused to callStopProcesson a nil executor. On main the llama.cpp executor is always registered, so outside unit tests it fell back to that executor and calledStopProcessfor a process of a runtime it doesn't own. Worth correcting in the description for the record. - The
starting metal agentlog line still printsllamaServerBinas an empty string when it wasn't found; drop the key or say it's absent, as you did for the "found" line. - No test covers the generic (non-llama.cpp) refusal message, e.g.
spec.runtime: mlx-serveron an agent started without--mlx-server-bin. docs/site/guides/macos-metal.mdhas a troubleshooting entry per refusal reason (ModelDownloadTooLarge,SourceSecretNotAllowed, ...);RuntimeNotAvailableshould get one there too, not only in the README.llmkube metal joinstill says the agent "cannot start without" llama-server. Fine to leave here; could you file the follow-up?
|
Thanks. The description now has the correct account of
|
What
The metal-agent no longer exits at startup when
llama-serveris missing, as long as--runtimeselects another engine (ollama,omlx,mlx-server,vllm-swift,tensorfold). It logs a warning and registers no llama.cpp executor. An InferenceService that resolves tollamacppis then refused with the newRuntimeNotAvailablereason, before its Model is fetched or a running engine is stopped, so itsstatus.schedulingStatusand a Warning Event say llama-server was not found and how to fix it. With--runtime llama-server(the default) a missing binary is still fatal.Also:
/usr/bin/llama-serveris added to the search paths after the two Homebrew ones.brew install llama.cpponly on macOS; elsewhere it points at the distribution package or a source build.mlx-serverwithout its binary). Before, such a service only logged "no executor registered" on every reconcile, after its running engine had already been stopped.RuntimeNotAvailableis inMetalAgentRefusalReasons, so the controller keeps the refusal.stopManagedProcessreturns an error when no executor is registered for the process's runtime. (Corrected after merge:) onmainthe llama.cpp executor was always registered, so outside unit tests this path fell back to it and calledStopProcessfor a process of a runtime that executor doesn't own. With the llama.cpp executor now optional, that fallback can be nil, so the missing executor is an error instead, including for an adopted process with PID 0.A Mac with
llama-serverinstalled behaves as before.Why
A host that only runs Ollama or oMLX had to install llama.cpp anyway. On Linux the error was a Homebrew hint. With this change a Linux host gets as far as the Metal check and exits with "Metal support not detected"; the Linux platform check is #2520.
Fixes #2516
How
cmd/metal-agent/main.go: newresolveDefaultLlamaServerBinwrapsresolveLlamaServerBin. When the binary is missing, it returns nil (and logs a warning) whenIsMetalOnlyRuntime(cfg.Runtime), otherwise the error. The startup log line "llama-server binary found" is printed only when a path resolved.llamaServerInstallHint(goos)supplies the hint.pkg/agent/agent.go: the llama.cpp executor setup moves intobuildLlamaCPPExecutor, whichbuildExecutorscalls only whenLlamaServerBin != "".s3SizeProbealready falls back to a stand-in executor when none is registered, so it needs no change.stopManagedProcesschecks for a nil executor after the Ollama, oMLX and adopted-with-PID branches, which handle nil safely.reconcileProcesslooks up the executor for the resolved runtime beforefetchModelThenStopStaleand refuses throughrefuseStartwhen there is none.runtimeNotAvailableMessageinpkg/agent/refusal.gowrites the llama.cpp-specific and the generic message.deployment/macos/README.md: the llama.cpp prerequisite says it can be skipped with another--runtime, "Choosing a Runtime per InferenceService" lists the search paths and the refusal, andRuntimeNotAvailableis in the refusal and Events lists and has a Troubleshooting entry.llmkube metal joinstill refuses to run withoutllama-server. I left it unchanged here.Tests:
cmd/metal-agent/main_test.go: a table over runtime (llama-server, llamacpp, ollama, omlx, mlx-server) by binary present or missing by override, the/usr/binpath, and the install hint per OS.pkg/agent/llama_executor_test.go:buildExecutorsregisters neither llama.cpp key without a binary and both with one.stopManagedProcessreturns an error, and does not panic, for a spawned llama.cpp process and for an adopted process without a PID when no executor is registered.TestEnsureProcessRefusesLlamaCPPWithoutLlamaServer(both runtime names) checks there is no start,status.schedulingStatusisRuntimeNotAvailable, the message names the fix, and there is exactly one Warning Event.TestEnsureProcessRuntimeNotAvailableKeepsRunningEnginechecks that a healthy engine with an older spec is not stopped.RuntimeNotAvailable.Checks I ran on macOS (arm64):
make gate BASE_REF=origin/mainon the final commit: every step passed.GOOS=linux bin/golangci-lint run ./...andGOOS=darwin bin/golangci-lint run ./...: 0 issues each.make lint-deadcode, and the same config withGOOS=linux: 0 issues.GOOS=linux go vet ./cmd/metal-agent/ ./pkg/agent/: clean.Assisted-by: Claude Code (Claude Opus 5.5) split this out of #2482, wrote the description and ran the checks above in my session.
Miscellaneous fixes
Shared code that assumed the host is a Mac now says "host": the
AllowUnsafeExtraArgsandcurrentBackendcomments inagent.go, and the--allow-unsafe-extra-argshelp ("for hosts whose InferenceService authors are fully trusted").Checklist
make testpasses locallymake lintpasses locallygit commit -s) per DCO