Repository navigation
Conversation
When powermetrics is unavailable the collectors published usage: 0, power.draw: 0 and systemDraw: 0 while the poll still counted as successful, so a non-root Mac dragged fleet watts and Wh/token down as if measured. Publish null for unread GPU usage/power and CPU usage/draw, keep the metricAvailability flags, and make fleet energy require available, finite readings rather than a non-zero vram.total. Keep the agent's own unavailable list on RAM and unified memory. Validate the Mac agent URL/host/port where it is saved (not only in the collector constructor), compare the runtime control token with hmac.compare_digest, and pin the powermetrics sudoers rule to the exact argv the collector runs. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The control proxy checked the agent's address policy and then let the fetch resolve the hostname again, so the authorized target and the connected socket were two separate DNS answers. Resolve once, hand the checked addresses to the connection, and read the response body while that pinned dispatcher is still open.
The rebase kept main's host-only RAM condition while keeping the comment that promised RAM when a Mac's unified pool is unknown, so an agent without memory readings showed neither panel. Restore the PR's Mac branch of that condition.
The agent's nullable cpu/gpu temperature landed after main's kiosk page was written, and the kiosk still compared those fields as plain numbers, so an unread reading typed as a number and could be treated as 0. Leave the figure unknown and cover both the card and the fleet maximum.
The Mac agent could collect telemetry but not switch models safely. Add a private current-user runner that owns the single heavy-model slot: validate binaries and cached paths before stopping the current engine, wait for its processes and listeners to disappear, detach the selected profile, and verify its exact API model ID, with optional warmup. A failed launch reports an error and cleans its own tree instead of restoring a different model. Profile-specific `start` argv and `health` checks let a target serve several models, and an ambiguous command is refused rather than guessed. Control actions return HTTP202 and poll a read-only operation snapshot, so closing the dashboard connection does not imply the engine stopped; output stays bounded and the token file is served without ever reaching the browser. Agent-backed Macs get the Models panel catalog and the output viewer; SSH hosts keep the script path. Tests cover the runner, control serialization, operation polling, token file safety and the viewer.
|
The agent's defaults are careful: loopback bind ( (Review notes prepared with Claude Code on behalf of the maintainer.) |
|
@MiaAI-Lab autoreview is clean on This is stacked on #277, so merging it lands #277's commits as well; #277 can be closed as superseded once this goes in. I can do the John deployment right after the merge lands. |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Stacked on #277 — @MiaAI-Lab, this branch is
589606b(#277's head) plus one commit,8f74993. Review that commit; #277 needs to merge first.What it adds
The Mac agent could collect telemetry but not switch models. This adds a private current-user runner that owns the single heavy-model slot: it validates binaries and cached paths before stopping the current engine, waits for its processes and listeners to disappear, detaches the selected profile, verifies the exact API model ID, and runs an optional warmup. A failed launch reports its error and cleans its own tree instead of restoring a different model.
Profiles carry their own
startargv and optional health check, so a target can serve several models; an ambiguous command is refused rather than guessed. Control actions return HTTP202 and poll a read-only operation snapshot, so a closed dashboard connection never implies the engine stopped, and polling never replays an action. The control token comes from the environment or an owner-only file, never reaches the browser, and status reads execute nothing.Agent-backed Macs get the Models panel catalog and a bounded-output viewer; SSH hosts keep the script path. Documentation is in
agents/macos/README.md.#277's guarantees are intact: the agent fetch and the
/controlproxy each resolve once and pin the connection to those checked addresses, and the strict inventory probes and authorized status reads are unchanged.Verification
npm run test:server: 1467 pass / 44 fail / 16 skipped, with the same failure names as untouched589606b(gpuclock systemd/sudo/cron, BSDtail --pid, missinguv).tsc --noEmitclean, i18n check passes.python3 -m unittest discover -s agents/macos/tests: 96 tests, 8 failures intest_privileged_service_lifecycle(launchctl/sudo on this non-macOS host, identical at baseline).python3 tests/test_profile_runner.py: 49 pass.Risk
Runtime actions are privileged, so this sits in the same sign-off queue as #277. Merging installs nothing: the runner is a current-user process, the agent stays optional, and root collectors remain read-only.