feat(agent): local-model room agent (Ollama -> GroupMind, offline-capable)#39
Conversation
… failover) Puts an on-device (Ollama) model into a GroupMind room: polls the room, and on an @mention prompts the local model and posts the reply back — so a local model becomes a first-class room participant. Reads/writes cloud GroupMind when the net is up and the LAN GroupMind Local relay when it isn't, so point mm + mb agents at the same relay, flip the net off, and the local pair keeps talking. Zero deps. History-skip on first poll, never replies to itself, mention-gated by default. 5 unit tests (mention/self/history/respond-all + Ollama call). Suite 155 green. Verified live: qwen3.5:9b on the M4 Mini (16.6 tps) introduced itself in the room. Note: a 27B is too big for 24GB here (GGUF 4.9 tps + RAM-tight, MLX won't load). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b10ea3eeab
ℹ️ 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".
|
|
||
| async function postMessage(ep, room, body) { | ||
| const res = await fetch(`${ep.baseUrl.replace(/\/$/, '')}/messages`, | ||
| { method: 'POST', headers: headersFor(ep), body: JSON.stringify({ room, body }), signal: AbortSignal.timeout(8000) }); |
There was a problem hiding this comment.
Preserve the sender when posting relay replies
In offline/relay mode with respondTo: 'all', this POST omits from: cfg.handle, so scripts/local-relay.mjs stores the agent's own replies as from: "unknown"; on the next poll they no longer match sameHandle(m.from, cfg.handle) and the agent replies to its own previous relay message indefinitely. Include the configured handle when posting to the local relay so the self guard still works.
Useful? React with 👍 / 👎.
The fleet's local models are reasoning models (the Mini runs qwen3.6:35b-a3b MoE at UD-Q2_K_XL, load-tested at 31.7 tps on the M4), so generateReply now strips <think>...</think> so room replies read clean. Default OLLAMA_MODEL updated to the MoE tag. +1 test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Q3_K_M is the Mini pick: clean output (fixes Q2's untagged reasoning-leak), 22.6 tps, fits 24GB (tight). Added a keep_alive (default 5m) so the 17GB model unloads when idle instead of pinning RAM the Mini's other services need. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
scripts/local-agent.mjs— puts a local Ollama model into a GroupMind room. It polls the room and, on an@mentionof its handle, prompts the local model over Ollama's HTTP API and posts the reply back, so an on-device model is a first-class room participant.It reads/writes cloud GroupMind when the net is up and the LAN GroupMind Local relay when it isn't — point mm + mb agents at the same relay, flip the net off, and the local pair keeps talking. That's the offline-fleet demo.
Details
npm run agent.respondTo:'all'optional).Verified live
qwen3.5:9b on the M4 Mini (16.6 tps) introduced itself in the room. Model note: a 27B is not viable on 24GB — GGUF 4.9 tps + RAM-tight, and the MLX build won't load (needs 18.4GB, 17.3 free). So the Mini runs a right-sized fast model; the 128GB MacBook carries the big SOTA one.
Not in this PR
Cross-review welcome @codexmb / @claudemb.
🤖 Generated with Claude Code