mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
feat(mesh): mesh capacity framing, honest usage signal, clickable card
Card now leads with pool capacity ("115 GB · 1 device") rather than this
machine's participation, and drops the model name — it belongs in the detail
view, not a 256px card.
Fixes an inverted usage signal: routing_metrics is incremented only by this
node's own OpenAI ingress, so remote/endpoint attempts mean this machine is
CONSUMING, not being consumed. The old activeConsumers check read them as
"someone is using your compute" — exactly backwards. mesh-llm exposes no
inbound counter, so participation copy now uses inflight ("working now") and
request_count ("N requests this session") and never claims work was served
for other members. A test pins that wording.
Headline text block is now a button for the forthcoming mesh detail view.
Signed-off-by: Michael Neale <michael.neale@gmail.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
describeMeshCapacity,
|
||||
describeParticipation,
|
||||
describeReadyModels,
|
||||
deriveMeshCardModel,
|
||||
formatCapacityGb,
|
||||
@@ -68,7 +69,8 @@ function derive(overrides = {}) {
|
||||
toggle: OFF_TOGGLE,
|
||||
pendingAction: null,
|
||||
canShare: true,
|
||||
activeConsumers: false,
|
||||
busyNow: false,
|
||||
requestsRouted: 0,
|
||||
...overrides,
|
||||
});
|
||||
}
|
||||
@@ -78,13 +80,13 @@ test("capacity headline counts devices and sums reported memory", () => {
|
||||
describeMeshCapacity(
|
||||
snapshot({ sharingDeviceCount: 3, sharedCapacityGb: 42.3 }),
|
||||
),
|
||||
"3 devices sharing · 42 GB",
|
||||
"42 GB · 3 devices",
|
||||
);
|
||||
assert.equal(
|
||||
describeMeshCapacity(
|
||||
snapshot({ sharingDeviceCount: 1, sharedCapacityGb: 18 }),
|
||||
),
|
||||
"1 device sharing · 18 GB",
|
||||
"18 GB · 1 device",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -92,7 +94,7 @@ test("unknown capacity degrades to a device count, never 0 GB", () => {
|
||||
const text = describeMeshCapacity(
|
||||
snapshot({ sharingDeviceCount: 3, sharedCapacityGb: null }),
|
||||
);
|
||||
assert.equal(text, "3 devices sharing");
|
||||
assert.equal(text, "Mesh capacity · 3 devices");
|
||||
assert.ok(!text.includes("0 GB"), "must not claim zero capacity");
|
||||
});
|
||||
|
||||
@@ -101,9 +103,9 @@ test("an empty mesh reads as an honest empty state", () => {
|
||||
describeMeshCapacity(
|
||||
snapshot({ sharingDeviceCount: 0, sharedCapacityGb: null }),
|
||||
),
|
||||
"No compute shared yet",
|
||||
"No mesh capacity yet",
|
||||
);
|
||||
assert.equal(describeMeshCapacity(null), "No compute shared yet");
|
||||
assert.equal(describeMeshCapacity(null), "No mesh capacity yet");
|
||||
});
|
||||
|
||||
test("capacity formatting keeps small figures meaningful", () => {
|
||||
@@ -145,7 +147,7 @@ test("consuming never renders as sharing", () => {
|
||||
assert.equal(model.switchDisabled, false);
|
||||
});
|
||||
|
||||
test("sharing states name the model and the community capacity", () => {
|
||||
test("sharing leads with mesh capacity and omits the model name", () => {
|
||||
const model = derive({
|
||||
toggle: SHARING_TOGGLE,
|
||||
status: {
|
||||
@@ -158,16 +160,20 @@ test("sharing states name the model and the community capacity", () => {
|
||||
consoleUrl: null,
|
||||
},
|
||||
snapshot: snapshot({
|
||||
sharingDeviceCount: 1,
|
||||
sharedCapacityGb: 115,
|
||||
devices: [device({ isSelf: true })],
|
||||
includesSelf: true,
|
||||
}),
|
||||
});
|
||||
assert.equal(model.tone, "sharing");
|
||||
assert.equal(model.switchOn, true);
|
||||
assert.match(model.detail, /Gemma 4 26B A4B/);
|
||||
assert.equal(model.headline, "115 GB · 1 device");
|
||||
// The model belongs in the detail view, not on a 256px card.
|
||||
assert.ok(!/Gemma/i.test(model.detail ?? ""), "card must not name the model");
|
||||
});
|
||||
|
||||
test("active consumers are called out in the headline", () => {
|
||||
test("inflight work reads as working, never as 'someone is using you'", () => {
|
||||
const model = derive({
|
||||
toggle: SHARING_TOGGLE,
|
||||
status: {
|
||||
@@ -179,9 +185,54 @@ test("active consumers are called out in the headline", () => {
|
||||
apiBaseUrl: null,
|
||||
consoleUrl: null,
|
||||
},
|
||||
activeConsumers: true,
|
||||
busyNow: true,
|
||||
});
|
||||
assert.match(model.headline, /in use now/);
|
||||
assert.match(model.detail, /working now/);
|
||||
});
|
||||
|
||||
test("routed requests are a subtle used-ness signal, not a served claim", () => {
|
||||
const model = derive({
|
||||
toggle: SHARING_TOGGLE,
|
||||
status: {
|
||||
state: "running",
|
||||
mode: "serve",
|
||||
health: { status: "ok", reason: null },
|
||||
modelId: "m",
|
||||
modelName: null,
|
||||
apiBaseUrl: null,
|
||||
consoleUrl: null,
|
||||
},
|
||||
requestsRouted: 7,
|
||||
});
|
||||
assert.match(model.detail, /7 requests this session/);
|
||||
});
|
||||
|
||||
test("participation copy never claims work was served for other members", () => {
|
||||
// mesh-llm exposes no inbound counter, so no wording here may imply that
|
||||
// another member consumed this machine's compute.
|
||||
const claims = [
|
||||
describeParticipation({ busyNow: false, requestsRouted: 0 }),
|
||||
describeParticipation({ busyNow: true, requestsRouted: 3 }),
|
||||
describeParticipation({ busyNow: false, requestsRouted: 3 }),
|
||||
];
|
||||
assert.deepEqual(claims, [
|
||||
"Sharing · ready",
|
||||
"Sharing · working now",
|
||||
"Sharing · 3 requests this session",
|
||||
]);
|
||||
for (const claim of claims) {
|
||||
assert.ok(
|
||||
!/served|for (others|members|someone)|consumed/i.test(claim),
|
||||
`must not claim served-for-others: ${claim}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("one routed request is singular", () => {
|
||||
assert.equal(
|
||||
describeParticipation({ busyNow: false, requestsRouted: 1 }),
|
||||
"Sharing · 1 request this session",
|
||||
);
|
||||
});
|
||||
|
||||
test("a serve node with no advertised model is warming up, not serving", () => {
|
||||
@@ -227,7 +278,7 @@ test("the idle invitation leads with what the community already has", () => {
|
||||
snapshot: snapshot({ sharingDeviceCount: 2, sharedCapacityGb: 54 }),
|
||||
});
|
||||
assert.equal(model.tone, "idle");
|
||||
assert.equal(model.headline, "2 devices sharing · 54 GB");
|
||||
assert.equal(model.headline, "54 GB · 2 devices");
|
||||
});
|
||||
|
||||
test("the switch is disabled until a model can be resolved", () => {
|
||||
|
||||
@@ -65,7 +65,11 @@ function plural(n: number, one: string, many = `${one}s`): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* The community headline: how much compute is actually available right now.
|
||||
* The community headline: how much compute is actually reachable right now.
|
||||
*
|
||||
* Named "Mesh capacity" rather than "sharing" because the figure describes the
|
||||
* pool, not this machine's participation — the switch already says whether you
|
||||
* are in it.
|
||||
*
|
||||
* Counts only devices advertising a routable model — the same standard routing
|
||||
* uses — so the number never promises capacity that cannot be reached. Never
|
||||
@@ -73,12 +77,14 @@ function plural(n: number, one: string, many = `${one}s`): string {
|
||||
*/
|
||||
export function describeMeshCapacity(snapshot: MeshSnapshot | null): string {
|
||||
if (!snapshot || snapshot.sharingDeviceCount === 0) {
|
||||
return "No compute shared yet";
|
||||
return "No mesh capacity yet";
|
||||
}
|
||||
const { sharingDeviceCount: count, sharedCapacityGb: gb } = snapshot;
|
||||
const devices = `${count} ${plural(count, "device")} sharing`;
|
||||
const devices = `${count} ${plural(count, "device")}`;
|
||||
// Unknown capacity degrades to the device count rather than printing 0 GB.
|
||||
return gb === null ? devices : `${devices} · ${formatCapacityGb(gb)}`;
|
||||
return gb === null
|
||||
? `Mesh capacity · ${devices}`
|
||||
: `${formatCapacityGb(gb)} · ${devices}`;
|
||||
}
|
||||
|
||||
/** Short label for what is ready to run, or null when nothing is. */
|
||||
@@ -95,6 +101,30 @@ export function describeReadyModels(
|
||||
return `${models.length} models ready`;
|
||||
}
|
||||
|
||||
/**
|
||||
* The sharing detail line: proof this machine is participating, and that the
|
||||
* mesh has actually been used.
|
||||
*
|
||||
* Scrupulously avoids claiming someone else consumed this machine's compute —
|
||||
* mesh-llm exposes no inbound counter, so "requests routed" is the strongest
|
||||
* true statement available. Worded as "requests" without "served for others".
|
||||
*/
|
||||
export function describeParticipation({
|
||||
busyNow,
|
||||
requestsRouted,
|
||||
}: {
|
||||
busyNow: boolean;
|
||||
requestsRouted: number;
|
||||
}): string {
|
||||
if (busyNow) {
|
||||
return "Sharing · working now";
|
||||
}
|
||||
if (requestsRouted > 0) {
|
||||
return `Sharing · ${requestsRouted} ${plural(requestsRouted, "request")} this session`;
|
||||
}
|
||||
return "Sharing · ready";
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim a model reference down to something that fits a 256px sidebar.
|
||||
* `unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q4_K_M` → `Gemma 4 26B A4B`.
|
||||
@@ -125,7 +155,8 @@ export function deriveMeshCardModel({
|
||||
toggle,
|
||||
pendingAction,
|
||||
canShare,
|
||||
activeConsumers,
|
||||
busyNow,
|
||||
requestsRouted,
|
||||
}: {
|
||||
snapshot: MeshSnapshot | null;
|
||||
status: MeshNodeStatus | null;
|
||||
@@ -133,8 +164,21 @@ export function deriveMeshCardModel({
|
||||
pendingAction: "start" | "stop" | null;
|
||||
/** False when no model can be resolved yet (catalog still loading). */
|
||||
canShare: boolean;
|
||||
/** Another member is actively using this machine's compute right now. */
|
||||
activeConsumers: boolean;
|
||||
/**
|
||||
* This node has inference in flight (`inflight > 0`).
|
||||
*
|
||||
* Honest but coarse: mesh-llm's inflight counter does not say whether the
|
||||
* work is for a local agent or a remote member, so this only ever claims
|
||||
* "working", never "someone is using your compute".
|
||||
*/
|
||||
busyNow: boolean;
|
||||
/**
|
||||
* Requests this node's ingress has routed this session (`request_count`).
|
||||
*
|
||||
* Outbound routing, NOT work served for others — mesh-llm exposes no inbound
|
||||
* counter. Used only as a subtle "this has been used" signal.
|
||||
*/
|
||||
requestsRouted: number;
|
||||
}): MeshCardModel {
|
||||
const devices = snapshot?.devices ?? [];
|
||||
const participantCount = devices.length;
|
||||
@@ -219,14 +263,13 @@ export function deriveMeshCardModel({
|
||||
showSoloHint: false,
|
||||
};
|
||||
}
|
||||
const model = status?.modelName ?? status?.modelId;
|
||||
// Model name is deliberately absent: it belongs in the detail view, not on
|
||||
// a 256px card whose job is "am I in the mesh, and is it alive".
|
||||
return {
|
||||
...base,
|
||||
tone: "sharing",
|
||||
headline: activeConsumers
|
||||
? "Sharing · in use now"
|
||||
: "Sharing this computer",
|
||||
detail: model ? `${shortModelLabel(model)} · ${capacity}` : capacity,
|
||||
headline: capacity,
|
||||
detail: describeParticipation({ busyNow, requestsRouted }),
|
||||
showSoloHint: isSolo,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,9 +62,12 @@ const TONE_RING_CLASS: Record<MeshCardTone, string> = {
|
||||
export function SidebarMeshComputeCard({
|
||||
className,
|
||||
onOpenComputeSettings,
|
||||
onOpenDetail,
|
||||
}: {
|
||||
className?: string;
|
||||
onOpenComputeSettings?: () => void;
|
||||
/** Open the full mesh view (topology, capacity, per-device detail). */
|
||||
onOpenDetail?: () => void;
|
||||
}) {
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
const { status, refresh: refreshStatus } = useMeshNodeStatus();
|
||||
@@ -82,9 +85,15 @@ export function SidebarMeshComputeCard({
|
||||
});
|
||||
|
||||
const toggle = deriveMeshShareToggle(status);
|
||||
const usage = useMeshServingUsage(toggle.isSharing);
|
||||
const activeConsumers =
|
||||
(usage?.remoteAttempts ?? 0) > 0 || (usage?.endpointAttempts ?? 0) > 0;
|
||||
// Poll whenever a runtime slot is occupied, not just when sharing: a
|
||||
// consuming node also has inflight work worth showing.
|
||||
const usage = useMeshServingUsage(toggle.isSharing || toggle.isConsuming);
|
||||
// `inflight` is the only honest "working" signal: mesh-llm's routing metrics
|
||||
// are all OUTBOUND (incremented by this node's own ingress), so a remote/
|
||||
// endpoint attempt means this machine is CONSUMING, not being consumed.
|
||||
// Reading them as "someone is using my compute" is exactly backwards.
|
||||
const busyNow = (usage?.inflight ?? 0) > 0;
|
||||
const requestsRouted = usage?.requestsServed ?? 0;
|
||||
|
||||
// One-shot catalog fetch: the card needs the hardware-appropriate
|
||||
// recommendation so the switch can start sharing without a model picker.
|
||||
@@ -116,7 +125,8 @@ export function SidebarMeshComputeCard({
|
||||
toggle,
|
||||
pendingAction,
|
||||
canShare: Boolean(recommended),
|
||||
activeConsumers,
|
||||
busyNow,
|
||||
requestsRouted,
|
||||
});
|
||||
|
||||
async function handleToggle(next: boolean) {
|
||||
@@ -146,7 +156,7 @@ export function SidebarMeshComputeCard({
|
||||
}
|
||||
|
||||
// A transport failure is worth showing; an empty mesh is not an error and is
|
||||
// already expressed by the headline ("No compute shared yet").
|
||||
// already expressed by the headline ("No mesh capacity yet").
|
||||
const errorText = actionError ?? snapshotError;
|
||||
|
||||
return (
|
||||
@@ -178,7 +188,17 @@ export function SidebarMeshComputeCard({
|
||||
{TONE_ICON[model.tone]}
|
||||
</span>
|
||||
|
||||
<div className="min-w-0 flex-1">
|
||||
{/*
|
||||
Clickable region is the text block, not the whole card: wrapping the
|
||||
Switch in a button would nest interactive elements.
|
||||
*/}
|
||||
<button
|
||||
className="min-w-0 flex-1 rounded-md text-left focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-default"
|
||||
data-testid="mesh-card-open-detail"
|
||||
disabled={!onOpenDetail}
|
||||
onClick={onOpenDetail}
|
||||
type="button"
|
||||
>
|
||||
<p
|
||||
className="truncate text-sm font-semibold leading-tight"
|
||||
data-testid="mesh-card-headline"
|
||||
@@ -193,7 +213,7 @@ export function SidebarMeshComputeCard({
|
||||
{model.detail}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<Switch
|
||||
aria-label={model.switchLabel}
|
||||
|
||||
@@ -53,9 +53,25 @@ export async function meshNodeStatus(): Promise<MeshNodeStatus> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Host-side usage of the compute this machine is sharing. The
|
||||
* local/remote/endpoint attempt split distinguishes this machine's own agents
|
||||
* (local) from another member consuming this machine's compute (remote/endpoint).
|
||||
* This machine's own routing activity — **outbound**, not work done for others.
|
||||
*
|
||||
* Every counter here comes from mesh-llm's `routing_metrics`, which is
|
||||
* incremented only by the local OpenAI ingress (`network/openai/transport.rs`)
|
||||
* when *this* node dispatches a request. The inbound peer-serving path
|
||||
* (`mesh/stage_transport.rs`) never touches it — it only observes inflight.
|
||||
*
|
||||
* So the attempt split means where MY requests went, not who asked me:
|
||||
* - `localAttempts` — I ran it on my own GPU
|
||||
* - `remoteAttempts` — I sent it to a peer (i.e. I am CONSUMING)
|
||||
* - `endpointAttempts` — I sent it to an endpoint
|
||||
*
|
||||
* `tokensServed` is likewise `completion_tokens_observed`: tokens I received,
|
||||
* not tokens I produced for someone else.
|
||||
*
|
||||
* mesh-llm exposes no inbound "requests I served for others" counter today, so
|
||||
* never label any field here as proof that this machine's compute was used by
|
||||
* another member. `inflight` is the one honest "busy right now" signal, and it
|
||||
* does not distinguish who the work is for.
|
||||
*/
|
||||
export type MeshServingUsage = {
|
||||
inflight: number;
|
||||
|
||||
Reference in New Issue
Block a user