Demand-based model wants: unified gossiped demand map - #6
Merged
Conversation
Replace three separate concepts (requested_models, mesh_wanted, request_rates)
with a single model_demand map that gets gossiped across the mesh.
Key changes:
- ModelDemand { last_active, request_count } struct gossiped in PeerAnnouncement
- Demand entries created by: --model flags, API requests (including misses/503s)
- Merged across peers via max(last_active, request_count) — propagates infectiously
- Entries decay after DEMAND_TTL_SECS (2 hours) unless pinned by a live --model node
- pick_model_assignment() now prioritizes by demand (hottest unserved first)
- Nostr 'wanted' derived from active demand instead of requested_models
- Backward compatible: old nodes still send requested_models/request_rates,
new nodes synthesize demand entries from those fields
This fixes the core issue where model wants disappeared when the declaring
node left the mesh. Now demand signals reverberate across all nodes via
gossip and persist as long as they're recent or actively requested.
…emand in API - gc_demand(): prune expired demand entries in heartbeat loop to prevent unbounded map growth over long-running meshes - check_unserved_model(): gate rebalancing on last_active recency (60 min) before using request_count/servers ratio — fixes spurious promotions from stale cumulative counts - /api/status: expose request_count and last_active_secs_ago per model so external tools can see mesh demand signals - Remove dead mesh_wanted_models() wrapper - Fix DEMAND_DESIGN.md: remove pinned field that was never in the struct
- Remove DEMAND_DESIGN.md (internals now in code comments) - README: update demand-aware rebalancing description - docs site: update feature blurb - TODO: tick off demand in /api/status and demand-based Nostr listings No parameter changes — fully transparent upgrade, backward compatible.
This was referenced Aug 11, 2026
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a node declares
--model GLMand later leaves the mesh, the "want" for GLM disappears entirely. The mesh forgets it ever wanted GLM. New nodes joining see no demand and go standby, even if they have GLM on disk and spare VRAM.This happened because model wants were tracked in three disconnected ways:
requested_models— per-node, gossiped, dies when the node leavesmesh_wanted— local in-memory accumulator, never gossiped, dies on restartrequest_rates— per-node request counts, not used for want discoverySolution
Replace all three with a single
model_demandmap that gets gossiped infectiously across the mesh:How it works
--modelflags seed demand entries at startuplast_activeand incrementrequest_countlast_active = max(ours, theirs),request_count = max(ours, theirs)DEMAND_TTL_SECS) are ignored unless pinned by a live--modelnodepick_model_assignment()prioritizes by demand (hottest unserved model first)What this fixes
model_demandreplacesrequested_models+mesh_wanted+request_rateswantedlist derived from active demand instead of per-noderequested_modelsBackward compatible
model_demandfield (serde skips unknown fields)requested_models+request_ratesrequested_modelsandrequest_ratesstill gossiped for old node compatTests
7 new unit tests covering merge logic, TTL filtering, backward compat synthesis, and serialization.