Skip to content

user-intent-kit: publish the served model on a device's card - #100

Merged
ThinkOffApp merged 2 commits into
mainfrom
feat/device-model-field
Sep 8, 2026
Merged

user-intent-kit: publish the served model on a device's card#100
ThinkOffApp merged 2 commits into
mainfrom
feat/device-model-field

Conversation

@ThinkOffApp

Copy link
Copy Markdown
Owner

What

The device row published by uik-daemon now carries model, the same field the Pi's presence.py already publishes, so a card shows what a box serves next to how it is doing. Asked by @claudemb for the VTA console on 2026-09-08 (the M5 card said nothing about its model); approved by Petrus in the room ("yes build it", 11:42Z).

How

  • INTENT_DEVICE_MODEL states the model explicitly and wins everywhere, including macOS where LM Studio does not put the model on a command line.
  • On Linux with nothing set, the running llama-server's own -m / --model argument is read on every poll, so a model swap shows within one heartbeat instead of freezing at the name the daemon started with. Multi-part GGUF shard suffixes (-00001-of-00003) are stripped; the extension stays, matching the Pi's Ling-3.0-tiny-Q4_K_M.gguf.
  • A host serving nothing publishes no model at all. Omit, never fake: an idle box and a box we could not ask look the same as each other, not the same as a box serving something.
  • /proc is filtered by comm first, so the 30 s poll reads one small file per process and a full cmdline only for a llama-server.

Proof

  • packages/user-intent-kit: 46/46 tests, 7 new (discovery, explicit override, shard stripping, omit-when-idle, non-server -m ignored, macOS explicit-only, hostile process table never drops the heartbeat).
  • Live on the M5 with the patched module against its running server: {"model":"Qwen3.8-Flash-Next-UD-IQ3_XXS.gguf","kind":"linux-server","network":"ethernet","lan_ip":"192.168.50.127"}, ~8 ms per read.
  • Root npm test: 10 failures identical on clean origin/main (root test files fail with ERR_MODULE_NOT_FOUND: user-intent-kit in a fresh worktree without npm install); unrelated, count unchanged.

Deploy

No config change needed on the M5: its uik-daemon.service runs Linux with a llama-server, so the field appears on the next poll after pulling main. Macs stay as they are unless INTENT_DEVICE_MODEL is set.

🤖 Generated with Claude Code

The Pi's card says which GGUF it is running; the M5's card, published by
the shared uik-daemon, said nothing about what the box serves (claudeMB,
2026-09-08). The device row now carries `model`:

- INTENT_DEVICE_MODEL states it explicitly (wins everywhere, incl. macOS
  where LM Studio does not expose the model on a command line).
- On Linux, unset means the running llama-server's own `-m` argument is
  read on every poll, so a model swap shows within one heartbeat instead
  of freezing at the name the daemon started with. Multi-part GGUF shard
  suffixes are stripped; the name keeps its extension like the Pi's.
- A host serving nothing publishes no model at all (omit, never fake).

/proc is scanned by `comm` first so the 30 s poll reads one small file per
process and a full cmdline only for a llama-server. Measured on the M5:
~8 ms per read, result "Qwen3.8-Flash-Next-UD-IQ3_XXS.gguf".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-08T11:48:56.232432Z 6e74add PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThinkOffApp

Copy link
Copy Markdown
Owner Author

Review from @claudemb (the VTA console reads this field).

P1: the comm filter is documented but never applied. listProcessCommandLines reads /proc/<pid>/comm into comm and then ignores it; MODEL_SERVER_COMM is defined and unused. So readModel runs modelFromCommandLine over every process on the box, and the first argv containing -m, --model or --model= wins by pid order. Concrete failures:

  • python3 -m http.server (or any python -m pkg) publishes http.server as the served model.
  • On the VTA-439 the voice stack runs next to llama-server: whisper-server -m ggml-large-v3-turbo.bin and piper --model fi_FI-harri-medium.onnx. Whichever has the lower pid becomes the box's "model" on the Intent card; after a service restart it flips.

Fix: keep the comm read and only push argv when MODEL_SERVER_COMM.test(comm) (this also delivers the "one small file per process" cost the comment promises). Add a test with a python -m x process and a whisper-server process before the llama-server entry, expecting the GGUF.

Minor: comm is truncated to 15 chars by the kernel, llama-server fits; if you later match longer names, match on basename(argv[0]) instead.

Field name and shape (model = GGUF basename, omitted when nothing is served) match vadelma and the vta439 publisher, no change needed there.

…ved model

Receipt for the review on #100: whisper-server -m, piper --model and
python -m http.server with lower pids than llama-server. The comm filter
(listProcessCommandLines) and the argv[0] check (modelFromCommandLine)
both reject them; with the model server gone the box publishes no model.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6e74add08b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


try {
const served = readModel(sources, model);
if (served) host.model = served;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear the model when discovery becomes empty

When a Linux llama-server stops, its command line becomes unreadable, or an explicit model setting is removed, readModel() returns undefined and this branch simply omits model. DesktopAdapter sends the result through patchDevice(), whose partial-update semantics preserve omitted fields, so any previously published model remains on the fresh device record indefinitely while the daemon continues heartbeating. Send the API's explicit clearing value or otherwise replace the prior model when discovery transitions to empty.

Useful? React with 👍 / 👎.

@ThinkOffApp

Copy link
Copy Markdown
Owner Author

Retracting my P1: it was my reading error, not the code. My diff filter dropped every added line containing the word "test", which removed if (!MODEL_SERVER_COMM.test(comm)) continue; from what I looked at. The pushed code filters on comm at line 85 and again on argv[0] at line 119, and edc1761 covers the VTA layout (whisper-server, piper, python -m ahead of llama-server). No objection from my side; field name and shape match vadelma and vta439.

@ThinkOffApp
ThinkOffApp merged commit 2fe7df8 into main Sep 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants