Refine shared compute setup experience

Reapply the full remaining diff from #7014 on current main, retaining the shared-compute UX, smoke coverage, and mesh agent E2E updates. Mic Neale's foundation from #6189 is already present in main.

Co-authored-by: Michael Neale <michael.neale@gmail.com>
Signed-off-by: Alessandro Joabar <sandro@squareup.com>
This commit is contained in:
Alessandro Joabar
2026-09-16 16:19:58 -04:00
parent 891208914e
commit 5b7cd830f2
25 changed files with 3123 additions and 200 deletions

View File

@@ -5,10 +5,9 @@
//!
//! Permutations:
//! P1 explicit-model chat — agent pinned to the served model id replies.
//! P2 auto-model chat — agent sends `model: "auto"`; mesh router picks.
//! P3 context-fit regression — an oversized output budget (150k tokens)
//! must FAIL with the router's context error (proves the router's fit
//! gate — the failure mode the 1024 preset cap protects against).
//! P2 virtual-mesh chat — one served model exercises single-model fallback.
//! P3 generous output ceiling succeeds (Mesh #1350); oversized input still
//! fails context admission via the real HTTP router, before inference.
//! P4 agentic tool use — agent + buzz-dev-mcp writes a file on disk.
//!
//! The serve node is the same `mesh_llm_sdk::serve` path Share-compute uses
@@ -136,13 +135,11 @@ async fn run() -> anyhow::Result<()> {
),
}
// P3: regression — an output budget no served model's context can hold
// must be rejected by the router with the context-fit error (the failure
// mode that broke relay-mesh agents when buzz-agent's default 32768
// budget met a 32k-context model). 150k output: passes buzz-agent's own
// config validation (must stay under its 200k max_context_tokens) but
// with the router's +25% margin overflows even 128k-context models like
// GLM-4.7-Flash.
// Mesh v0.76.0-rc9 (9f192c9), routing_rank.rs:43-58 reserves
// min(completion ceiling, 512) decode headroom, NOT the entire ceiling
// (#1350). buzz-agent llm.rs sends max_completion_tokens on the chat API.
// Keep the 150k ceiling as a positive regression, plus a negative input
// fit probe below. Do not accept generic service failures as context errors.
let r = agent_chat(
&base,
"mesh",
@@ -152,18 +149,13 @@ async fn run() -> anyhow::Result<()> {
)
.await;
match r {
Ok(text) => record(
"P3 oversized-budget must fail",
false,
format!("unexpectedly succeeded: {text}"),
),
Err(e) => {
let msg = e.to_string();
let is_context_503 = msg.contains("503")
|| msg.contains("service_unavailable")
|| msg.contains("context-compatible");
record("P3 oversized-budget must fail", is_context_503, msg);
}
Ok(text) => record("P3a generous output ceiling", text.trim() == "PONG", text),
Err(e) => record("P3a generous output ceiling", false, e.to_string()),
}
let r = oversized_input_probe(&http, &base, &served_id).await;
match r {
Ok(detail) => record("P3b oversized input rejected", true, detail),
Err(e) => record("P3b oversized input rejected", false, e.to_string()),
}
// P4: agentic tool use via buzz-dev-mcp — write a real file inside the
@@ -171,13 +163,13 @@ async fn run() -> anyhow::Result<()> {
// nonexistent absolute paths outside that root.
let marker_name = format!("mesh-e2e-{}.txt", std::process::id());
let prompt = format!(
"Use your developer tools to create {marker_name} in the current working directory containing exactly the text BUZZ_OK (no quotes, no newline commentary). Then confirm."
"Call dev__shell exactly once with command `{}` and no workdir override. This is the only authorized operation. Then confirm in text; do not run any other tools.", marker_command(&marker_name)
);
let mcp = vec![("dev".to_string(), repo_bin("buzz-dev-mcp")?)];
let (r, marker) =
agent_chat_with_marker(&base, "mesh", None, &prompt, &mcp, &marker_name).await;
let file_ok = std::fs::read_to_string(&marker)
.map(|c| c.contains("BUZZ_OK"))
.map(|c| c == "BUZZ_OK")
.unwrap_or(false);
match r {
Ok(text) => record(
@@ -189,7 +181,7 @@ async fn run() -> anyhow::Result<()> {
format!("no file at {}; agent said: {text}", marker.display())
},
),
Err(e) => record("P4 agentic tool use", file_ok, format!("agent error: {e}")),
Err(e) => record("P4 agentic tool use", false, format!("agent error: {e}")),
}
let _ = std::fs::remove_file(&marker);
@@ -237,7 +229,8 @@ async fn agent_chat(
mcp_servers: &[(String, String)],
) -> anyhow::Result<String> {
let (result, _) =
agent_chat_in_isolated_home(base, model, max_output_tokens, prompt, mcp_servers).await;
agent_chat_in_isolated_home(base, model, max_output_tokens, prompt, mcp_servers, None)
.await;
result
}
@@ -249,8 +242,15 @@ async fn agent_chat_with_marker(
mcp_servers: &[(String, String)],
marker_name: &str,
) -> (anyhow::Result<String>, std::path::PathBuf) {
let (result, home) =
agent_chat_in_isolated_home(base, model, max_output_tokens, prompt, mcp_servers).await;
let (result, home) = agent_chat_in_isolated_home(
base,
model,
max_output_tokens,
prompt,
mcp_servers,
Some(marker_name),
)
.await;
(result, home.join(marker_name))
}
@@ -260,19 +260,25 @@ async fn agent_chat_in_isolated_home(
max_output_tokens: Option<&str>,
prompt: &str,
mcp_servers: &[(String, String)],
marker_name: Option<&str>,
) -> (anyhow::Result<String>, std::path::PathBuf) {
let agent = match repo_bin("buzz-agent") {
Ok(agent) => agent,
Err(error) => return (Err(error), std::path::PathBuf::new()),
};
// Isolated HOME: no skills, no AGENTS.md chain, no keychain, tiny prompt.
let home = std::env::temp_dir().join(format!("mesh-e2e-home-{}", std::process::id()));
if let Err(error) = std::fs::create_dir_all(&home) {
return (Err(error.into()), home);
}
// Fresh per leg: stale markers and prior agent state can never pass P4.
// Retain the directory for diagnostics (also when P4 fails).
let home = match tempfile::Builder::new().prefix("mesh-e2e-home-").tempdir() {
Ok(dir) => dir.keep(),
Err(error) => return (Err(error.into()), std::path::PathBuf::new()),
};
eprintln!("[e2e] isolated home: {}", home.display());
let mut command = Command::new(&agent);
command
.current_dir(&home)
.kill_on_drop(true)
.env_clear()
.env("PATH", std::env::var("PATH").unwrap_or_default())
.env("HOME", &home)
@@ -291,10 +297,8 @@ async fn agent_chat_in_isolated_home(
// Pinning a value here would test a config the product does not ship.
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null());
// P3 deliberately overrides the production default to exercise the
// router's context-fit rejection. Normal and tool turns leave it unset,
// matching the desktop provider path.
.stderr(Stdio::inherit());
// P3a exercises a generous ceiling, not an admission reservation.
if let Some(value) = max_output_tokens {
command.env("BUZZ_AGENT_MAX_OUTPUT_TOKENS", value);
}
@@ -303,7 +307,7 @@ async fn agent_chat_in_isolated_home(
Err(error) => return (Err(error.into()), home),
};
let result = drive_acp(&mut child, prompt, mcp_servers, &home).await;
let result = drive_acp(&mut child, prompt, mcp_servers, &home, marker_name).await;
let _ = child.kill().await;
(result, home)
}
@@ -313,6 +317,7 @@ async fn drive_acp(
prompt: &str,
mcp_servers: &[(String, String)],
cwd: &std::path::Path,
marker_name: Option<&str>,
) -> anyhow::Result<String> {
let mut stdin = child
.stdin
@@ -341,7 +346,68 @@ async fn drive_acp(
.as_bytes(),
)
.await?;
stdin
let mut session_id: Option<String> = None;
let mut agent_text = String::new();
let mut marker_approved = false;
let deadline = tokio::time::Instant::now() + Duration::from_secs(600);
loop {
let line = tokio::time::timeout_at(deadline, lines.next_line())
.await
.map_err(|_| anyhow::anyhow!("agent timed out; text so far: {agent_text}"))??
.ok_or_else(|| anyhow::anyhow!("agent closed stdout; text so far: {agent_text}"))?;
let Ok(msg) = serde_json::from_str::<serde_json::Value>(&line) else {
continue;
};
// Requests have their own id namespace; handle before response ids.
if msg["method"] == "session/request_permission" {
let response = permission_response(
&msg,
session_id.as_deref(),
marker_name,
&mut marker_approved,
);
eprintln!(
"[e2e] permission: {} -> {}",
msg["params"]["toolCall"], response["result"]
);
stdin.write_all(send(response).as_bytes()).await?;
continue;
}
if msg.get("method").is_some() && msg.get("id").is_some() {
stdin
.write_all(
send(serde_json::json!({
"jsonrpc": "2.0", "id": msg["id"],
"error": {"code": -32601, "message": "Unsupported harness method"}
}))
.as_bytes(),
)
.await?;
continue;
}
// Collect any streamed agent text from session/update notifications.
if msg.get("method").and_then(|m| m.as_str()) == Some("session/update") {
if msg["params"]["sessionId"].as_str() == session_id.as_deref() {
let update = &msg["params"]["update"];
if matches!(
update["sessionUpdate"].as_str(),
Some("tool_call" | "tool_call_update")
) {
eprintln!("[e2e] tool update: {update}");
}
collect_text(update, &mut agent_text);
}
continue;
}
match msg.get("id").and_then(|i| i.as_i64()) {
Some(1) => {
anyhow::ensure!(msg.get("error").is_none(), "initialize failed: {msg}");
anyhow::ensure!(
msg["result"]["protocolVersion"] == 1,
"expected ACP v1: {msg}"
);
stdin
.write_all(
send(serde_json::json!({
"jsonrpc": "2.0", "id": 2, "method": "session/new",
@@ -354,25 +420,7 @@ async fn drive_acp(
.as_bytes(),
)
.await?;
let mut session_id: Option<String> = None;
let mut agent_text = String::new();
let deadline = tokio::time::Instant::now() + Duration::from_secs(600);
loop {
let line = tokio::time::timeout_at(deadline, lines.next_line())
.await
.map_err(|_| anyhow::anyhow!("agent timed out; text so far: {agent_text}"))??
.ok_or_else(|| anyhow::anyhow!("agent closed stdout; text so far: {agent_text}"))?;
let Ok(msg) = serde_json::from_str::<serde_json::Value>(&line) else {
continue;
};
// Collect any streamed agent text from session/update notifications.
if msg.get("method").and_then(|m| m.as_str()) == Some("session/update") {
collect_text(&msg["params"]["update"], &mut agent_text);
continue;
}
match msg.get("id").and_then(|i| i.as_i64()) {
}
Some(2) => {
if let Some(err) = msg.get("error") {
anyhow::bail!("session/new failed: {err}");
@@ -400,6 +448,14 @@ async fn drive_acp(
if let Some(err) = msg.get("error") {
anyhow::bail!("session/prompt failed: {err}");
}
anyhow::ensure!(
msg["result"]["stopReason"] == "end_turn",
"unexpected prompt stop: {msg}; text: {agent_text}"
);
anyhow::ensure!(
marker_name.is_none() || marker_approved,
"marker permission was never approved; text: {agent_text}"
);
return Ok(agent_text.trim().to_string());
}
_ => {}
@@ -407,25 +463,116 @@ async fn drive_acp(
}
}
/// Recursively harvest "text" string fields out of a session/update payload.
/// Only user-visible assistant chunks count, never reasoning or tool content.
fn collect_text(value: &serde_json::Value, out: &mut String) {
match value {
serde_json::Value::Object(map) => {
for (k, v) in map {
if k == "text" {
if let Some(s) = v.as_str() {
out.push_str(s);
}
} else {
collect_text(v, out);
}
}
if value["sessionUpdate"] == "agent_message_chunk" && value["content"]["type"] == "text" {
if let Some(text) = value["content"]["text"].as_str() {
out.push_str(text);
}
serde_json::Value::Array(items) => {
for item in items {
collect_text(item, out);
}
}
_ => {}
}
}
fn marker_command(name: &str) -> String {
format!("printf %s BUZZ_OK > {name}")
}
/// Test-client-only grant: one exact shell invocation, in a fresh cwd.
/// No command parsing, prefix matches, persistent grants, or alternate tools.
fn permission_response(
request: &serde_json::Value,
session: Option<&str>,
marker: Option<&str>,
approved: &mut bool,
) -> serde_json::Value {
let p = &request["params"];
let tool = &p["toolCall"]; // We negotiate v1 only; fail closed on other shapes.
let input = &tool["rawInput"];
let safe_marker = marker.filter(|name| {
!name.is_empty()
&& name
.bytes()
.all(|b| b.is_ascii_alphanumeric() || b == b'-' || b == b'.')
});
let exact_input = safe_marker.is_some_and(|name| {
input.as_object().is_some_and(|o| {
o.keys()
.all(|k| k == "command" || k == "timeout_ms" || k == "workdir")
// MCP treats absent/null workdir as its default cwd; no overrides.
&& (input.get("workdir").is_none() || input["workdir"].is_null())
&& input["command"] == marker_command(name)
&& (input.get("timeout_ms").is_none()
|| input["timeout_ms"]
.as_u64()
.is_some_and(|n| n > 0 && n <= 120_000))
})
});
let allow = !*approved
&& session.is_some()
&& p["sessionId"].as_str() == session
&& tool["title"] == "dev__shell"
&& exact_input;
let option = p["options"]
.as_array()
.and_then(|options| options.iter().find(|o| o["kind"] == "allow_once"))
.and_then(|o| o["optionId"].as_str());
let outcome = if let Some(id) = option.filter(|_| allow) {
*approved = true;
serde_json::json!({"outcome": "selected", "optionId": id})
} else {
serde_json::json!({"outcome": "cancelled"})
};
serde_json::json!({"jsonrpc": "2.0", "id": request["id"], "result": {"outcome": outcome}})
}
async fn oversized_input_probe(
http: &reqwest::Client,
base: &str,
model: &str,
) -> anyhow::Result<String> {
// Use advertised runtime capacity, not native model capacity. Explicit
// model routing avoids conflating MoA selection failure with context fit.
let models: serde_json::Value = http
.get(format!("{base}/models"))
.send()
.await?
.error_for_status()?
.json()
.await?;
let entry = models["data"]
.as_array()
.and_then(|a| a.iter().find(|m| m["id"] == model))
.ok_or_else(|| anyhow::anyhow!("served model absent: {models}"))?;
let metadata = &entry["metadata"];
let context = metadata["max_context_length"]
.as_u64()
.or_else(|| metadata["context_length"].as_u64())
.ok_or_else(|| anyhow::anyhow!("no advertised runtime context: {entry}"))?;
// Bound allocation/request size; fail rather than guess for huge models.
anyhow::ensure!(
context > 0 && context <= 262_144,
"unsupported smoke context: {context}"
);
// rc9 estimates serialized input bytes / 4, retains ALL prompt tokens.
let body = serde_json::json!({"model": model, "stream": false,
"max_completion_tokens": 1,
"messages": [{"role": "user", "content": "x".repeat((context as usize + 1024) * 4)}]});
let response = http
.post(format!("{base}/chat/completions"))
.timeout(Duration::from_secs(30))
.json(&body)
.send()
.await?;
let status = response.status();
let text = response.text().await?;
anyhow::ensure!(
status == reqwest::StatusCode::SERVICE_UNAVAILABLE
&& text.contains("no context-compatible target"),
"expected context-fit 503 for runtime context {context}, got {status}: {}",
text.chars().take(2048).collect::<String>()
);
Ok(format!("runtime context {context}; {status}: {text}"))
}
#[cfg(test)]
#[path = "mesh_agent_e2e/tests.rs"]
mod tests;

View File

@@ -0,0 +1,185 @@
use super::*;
use serde_json::{json, Value};
fn request() -> Value {
json!({"jsonrpc":"2.0", "id":3, "method":"session/request_permission",
"params":{"sessionId":"s", "toolCall":{"title":"dev__shell",
"rawInput":{"command":marker_command("marker.txt")}},
"options":[{"kind":"allow_always","optionId":"persistent"},
{"kind":"allow_once","optionId":"one-shot"}]}})
}
#[test]
fn exact_marker_grants_offered_once_option_and_preserves_id() {
let mut approved = false;
let response = permission_response(&request(), Some("s"), Some("marker.txt"), &mut approved);
assert!(approved);
assert_eq!(response["id"], 3);
assert_eq!(
response["result"]["outcome"],
json!({"outcome":"selected","optionId":"one-shot"})
);
assert_eq!(
permission_response(&request(), Some("s"), Some("marker.txt"), &mut approved)["result"]
["outcome"]["outcome"],
"cancelled"
);
}
#[test]
fn hardware_payload_allows_null_workdir_but_rejects_non_null_values() {
let mut r = request();
r["params"]["toolCall"]["rawInput"] = json!({
"command": "printf %s BUZZ_OK > marker.txt",
"timeout_ms": 120000,
"workdir": null
});
let mut approved = false;
let response = permission_response(&r, Some("s"), Some("marker.txt"), &mut approved);
assert!(approved);
assert_eq!(response["id"], 3);
assert_eq!(
response["result"]["outcome"],
json!({"outcome":"selected","optionId":"one-shot"})
);
assert_eq!(
permission_response(&r, Some("s"), Some("marker.txt"), &mut approved)["result"]["outcome"]
["outcome"],
"cancelled"
);
for workdir in [
json!(""),
json!("/tmp"),
json!("."),
json!(false),
json!(0),
json!([]),
json!({}),
] {
r["params"]["toolCall"]["rawInput"]["workdir"] = workdir;
let mut approved = false;
let response = permission_response(&r, Some("s"), Some("marker.txt"), &mut approved);
assert_eq!(response["result"]["outcome"]["outcome"], "cancelled", "{r}");
assert!(!approved);
}
}
#[test]
fn permission_fails_closed_on_scope_command_options_and_protocol() {
let mut mutations = Vec::new();
for command in [
"printf %s BUZZ_OK > other.txt",
"printf %s BUZZ_OK > marker.txt; pwd",
"printf %s BUZZ_OK > ../marker.txt",
"echo BUZZ_OK > marker.txt",
] {
let mut r = request();
r["params"]["toolCall"]["rawInput"]["command"] = json!(command);
mutations.push(r);
}
for (pointer, value) in [
("/params/sessionId", json!("other")),
("/params/toolCall/title", json!("other__shell")),
(
"/params/toolCall/rawInput",
json!({"command":marker_command("marker.txt"),"workdir":"/tmp"}),
),
(
"/params/toolCall/rawInput",
json!({"command":marker_command("marker.txt"),"timeout_ms":999999}),
),
(
"/params/options",
json!([{"kind":"allow_always","optionId":"always"}]),
),
("/params/toolCall", Value::Null),
] {
let mut r = request();
*r.pointer_mut(pointer).unwrap() = value;
mutations.push(r);
}
for r in mutations {
let mut approved = false;
let response = permission_response(&r, Some("s"), Some("marker.txt"), &mut approved);
assert_eq!(response["result"]["outcome"]["outcome"], "cancelled", "{r}");
assert!(!approved);
}
for (session, marker) in [
(None, Some("marker.txt")),
(Some("s"), None),
(Some("s"), Some("../marker.txt")),
] {
assert_eq!(
permission_response(&request(), session, marker, &mut false)["result"]["outcome"]
["outcome"],
"cancelled"
);
}
}
#[test]
fn collector_excludes_thoughts_tool_results_and_nontext_content() {
let mut text = String::new();
for update in [
"agent_thought_chunk",
"tool_call",
"tool_call_update",
"user_message_chunk",
] {
collect_text(
&json!({"sessionUpdate":update,"content":{"type":"text","text":"PONG"}}),
&mut text,
);
}
collect_text(
&json!({"sessionUpdate":"agent_message_chunk","content":{"type":"image","text":"PONG"}}),
&mut text,
);
assert!(text.is_empty());
for chunk in ["PO", "NG"] {
collect_text(
&json!({"sessionUpdate":"agent_message_chunk","content":{"type":"text","text":chunk}}),
&mut text,
);
}
assert_eq!(text, "PONG");
}
/// Real stdio framing through drive_acp, no model, MCP or native runtime.
/// The permission request intentionally collides with our prompt response id.
#[tokio::test]
async fn acp_permission_request_is_not_mistaken_for_prompt_response() {
let script = r#"
import json, sys
def read(): return json.loads(sys.stdin.readline())
def send(v): print(json.dumps(v), flush=True)
assert read()['method'] == 'initialize'
send({'id':1,'result':{'protocolVersion':1}})
assert read()['method'] == 'session/new'
send({'id':2,'result':{'sessionId':'s'}})
assert read()['method'] == 'session/prompt'
send({'id':3,'method':'session/request_permission','params':{'sessionId':'s','toolCall':{'title':'dev__shell','rawInput':{'command':'printf %s BUZZ_OK > marker.txt','timeout_ms':120000,'workdir':None}},'options':[{'kind':'allow_once','optionId':'yes'}]}})
r = read()
assert r['id'] == 3 and r['result']['outcome'] == {'outcome':'selected','optionId':'yes'}
for kind,text in [('agent_thought_chunk','NOT VISIBLE'),('agent_message_chunk','PONG')]:
send({'method':'session/update','params':{'sessionId':'s','update':{'sessionUpdate':kind,'content':{'type':'text','text':text}}}})
send({'id':3,'result':{'stopReason':'end_turn'}})
"#;
let mut child = Command::new("python3")
.args(["-c", script])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.kill_on_drop(true)
.spawn()
.unwrap();
let home = tempfile::tempdir().unwrap();
let result = tokio::time::timeout(
Duration::from_secs(10),
drive_acp(&mut child, "test", &[], home.path(), Some("marker.txt")),
)
.await
.unwrap();
assert_eq!(result.unwrap(), "PONG");
assert!(child.wait().await.unwrap().success());
}

View File

@@ -176,7 +176,7 @@ fn advance_mesh_status_cursor(
Ok(cursor)
}
async fn query_mesh_discovery_events_at(
pub(super) async fn query_mesh_discovery_events_at(
state: &AppState,
relay_url: &str,
) -> Result<Vec<nostr::Event>, String> {
@@ -484,7 +484,7 @@ pub async fn mesh_start_node(
let started = mesh_llm::DesktopMeshRuntime::start(request)
.await
.map_err(|error| format!("{error:#}"))?;
let status = match started.status().await {
let mut status = match started.status().await {
Ok(status) => status,
Err(error) => {
let cleanup = started.stop().await;
@@ -520,11 +520,23 @@ pub async fn mesh_start_node(
// (leaves a warming node alone) can loop a slow-but-alive node, and an
// unstartable config fails earlier in `start()`. Probe is informational.
save_mesh_sharing_config(&app, config)?;
if let Err(error) = wait_for_mesh_inference(&config.model_id).await {
eprintln!(
"buzz-mesh: node started but inference is not ready yet ({error}); \
leaving it to warm up (Share Compute stays armed for next launch)"
);
match wait_for_mesh_inference(&config.model_id).await {
Ok(()) => {
// The status captured immediately after runtime installation can
// still say `starting`. Re-read after the readiness probe so the
// command response reflects the successful boot the user waited
// for instead of pinning the UI's transition indicator.
let runtime = state.mesh_llm_runtime.lock().await;
if let Some(running) = runtime.as_ref() {
status = running.status().await.map_err(|error| error.to_string())?;
}
}
Err(error) => {
eprintln!(
"buzz-mesh: node started but inference is not ready yet ({error}); \
leaving it to warm up (Share Compute stays armed for next launch)"
);
}
}
}
mesh_llm::publish_current_status_once(&app, "start").await;

View File

@@ -0,0 +1,45 @@
//! `mesh_snapshot` — community-wide shared-compute snapshot for the UI.
//!
//! Separate file from `commands/mesh_llm.rs` deliberately: that module is at
//! the 1000-line file ceiling enforced by `desktop/scripts/check-file-sizes.mjs`.
//!
//! Read-only. Queries the same member-status + membership filters routing uses,
//! then projects them through [`mesh_llm::snapshot_from_events`], which applies
//! the membership/binding/freshness rules. This never selects a serve target —
//! routing stays with `availability_from_events`.
use tauri::State;
use crate::app_state::AppState;
use crate::mesh_llm;
type CmdResult<T> = Result<T, String>;
/// Snapshot of who is sharing compute in this community right now.
///
/// An empty mesh is a normal state, not an error: the snapshot carries a
/// `reason` string instead of failing, so the card can render an honest empty
/// state. A genuine relay/transport failure still returns `Err`.
#[tauri::command]
pub async fn mesh_snapshot(state: State<'_, AppState>) -> CmdResult<mesh_llm::MeshSnapshot> {
// Reuse discovery's author-scoped, composite-cursor pagination. A direct
// two-filter query stops at the status filter's 100-event page size and
// silently undercounts larger communities.
let relay_url = crate::relay::relay_ws_url_with_override(&state);
let events = super::mesh_llm::query_mesh_discovery_events_at(&state, &relay_url)
.await
.map_err(|error| format!("Shared compute status query failed: {error}"))?;
// Identify this member's own device so the card can say "including yours".
// A missing/locked identity is not fatal here — the snapshot is still
// useful, just without self-attribution.
let self_pubkey = state
.signing_keys()
.ok()
.map(|keys| keys.public_key().to_hex());
Ok(mesh_llm::snapshot_from_events(
events,
self_pubkey.as_deref(),
))
}

View File

@@ -43,6 +43,8 @@ mod media_voice_note;
pub(crate) mod mesh_llm;
#[cfg(feature = "mesh-llm")]
pub(crate) mod mesh_readiness;
#[cfg(feature = "mesh-llm")]
mod mesh_snapshot;
mod messages;
mod notifications;
mod observer_archive;
@@ -106,6 +108,8 @@ pub use media_fetch_cancellation::*;
pub use media_raw::*;
#[cfg(feature = "mesh-llm")]
pub use mesh_llm::*;
#[cfg(feature = "mesh-llm")]
pub use mesh_snapshot::*;
pub use messages::*;
pub use notifications::*;
pub use observer_archive::*;

View File

@@ -728,6 +728,7 @@ pub fn run() {
mesh_serving_usage,
mesh_installed_models,
mesh_model_catalog,
mesh_snapshot,
update_managed_agent,
discover_backend_providers,
probe_backend_provider,

View File

@@ -12,7 +12,7 @@ use super::{dedupe_models, MeshAvailability, MeshModelOption, MeshServeTarget, M
pub(super) const STATUS_FRESHNESS_SECS: u64 = 120;
pub(crate) const MESH_STATUS_PAGE_SIZE: usize = 100;
fn status_is_fresh(event: &nostr::Event, now: u64) -> bool {
pub(super) fn status_is_fresh(event: &nostr::Event, now: u64) -> bool {
event
.created_at
.as_secs()
@@ -63,7 +63,7 @@ pub fn owner_ids_from_events(events: &[nostr::Event]) -> Vec<String> {
ids
}
fn latest_membership_list(events: &[nostr::Event]) -> Option<BTreeSet<String>> {
pub(super) fn latest_membership_list(events: &[nostr::Event]) -> Option<BTreeSet<String>> {
events
.iter()
.filter(|event| event.kind.as_u16() == 13_534)
@@ -108,7 +108,7 @@ pub(crate) fn has_membership_snapshot(events: &[nostr::Event]) -> bool {
events.iter().any(|event| event.kind.as_u16() == 13_534)
}
fn owner_id_from_status_event(event: &nostr::Event) -> Option<String> {
pub(super) fn owner_id_from_status_event(event: &nostr::Event) -> Option<String> {
let content = serde_json::from_str::<serde_json::Value>(&event.content).ok()?;
let owner_id = content
.get("ownerId")
@@ -136,7 +136,7 @@ fn owner_id_from_status_event(event: &nostr::Event) -> Option<String> {
Some(owner_id.to_string())
}
fn endpoint_binding_is_valid(event: &nostr::Event, content: &serde_json::Value) -> bool {
pub(super) fn endpoint_binding_is_valid(event: &nostr::Event, content: &serde_json::Value) -> bool {
let Some(endpoint_tokens) = super::identity::advertised_endpoint_tokens(content) else {
return false;
};

View File

@@ -13,6 +13,9 @@ pub(crate) use discovery::{
};
use discovery::{device_name_from_status, endpoint_id_from_status, enrich_status_payload_identity};
mod snapshot;
pub use snapshot::{snapshot_from_events, MeshSnapshot};
mod catalog;
pub(crate) use catalog::canonical_curated_model_id;
pub use catalog::{model_catalog, MeshModelCatalog};

View File

@@ -0,0 +1,352 @@
//! Community-wide mesh snapshot — an **allowlisted** projection of the member
//! status notes already on the relay.
//!
//! Every sharing member already publishes its whole SDK status payload as
//! kind:30003 content (see `mod.rs::status_report_payload`), but
//! `availability_from_events` reads only `serveTargets`/`models` and discards
//! the rest. This module projects the few extra fields the Share-compute UI
//! needs — per-device shared capacity, a coarse state, and a stable label —
//! and **nothing else**.
//!
//! Deliberately narrow, for two reasons:
//! 1. Routing must keep using [`super::availability_from_events`]. This
//! snapshot is presentation-only and must never select a serve target.
//! 2. The published payload also carries a hardware fingerprint, peer
//! topology, and operational counters. Naming each field we surface keeps
//! the UI from quietly growing into the rest of it.
//!
//! Capacity uses the payload's `my_vram_gb`, which mesh-llm derives from a
//! `vram_bytes` already clamped to the member's own `--max-vram` cap. Raw
//! `gpus[].vram_bytes` is *not* capped, so summing GPUs would advertise more
//! than the member agreed to share.
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use super::discovery::{
device_name_from_status, endpoint_binding_is_valid, endpoint_id_from_status,
latest_membership_list, owner_id_from_status_event, status_is_fresh, STATUS_FRESHNESS_SECS,
};
use super::{MeshServeTarget, MESH_STATUS_KIND};
/// Coarse per-device state. Intentionally not the SDK's `NodeState`: the UI
/// only needs "is this device giving compute, warming up, or just consuming?"
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum MeshDeviceState {
/// Advertising at least one routable model.
Serving,
/// Serve-mode, model not ready yet.
Loading,
/// Serve-mode participant with no model work (contributes capacity only).
Standby,
/// Client-mode: consuming someone else's compute, not sharing.
Consuming,
}
/// One device visible on the mesh.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct MeshSnapshotDevice {
/// Stable endpoint/device id, when the note carries one.
pub device_id: Option<String>,
/// Human label: hostname when published, else a short endpoint id.
pub label: String,
/// Shared AI memory in GB, honoring the member's own cap. `None` when the
/// member is not currently running a node (a stopped member publishes only
/// its owner binding).
pub capacity_gb: Option<f64>,
/// Models this device is advertising right now.
pub models: Vec<String>,
pub state: MeshDeviceState,
/// Whether this is the local member's own device.
pub is_self: bool,
/// Community member who signed this status note. Safe for profile lookup;
/// endpoint tokens, owner signatures, and raw hardware remain excluded.
pub member_pubkey: Option<String>,
/// Relay event creation time, in Unix seconds.
pub reported_at: Option<u64>,
/// Approximate hosted-model footprint reported by MeshLLM, when available.
pub model_size_gb: Option<f64>,
}
/// What the community's shared compute looks like right now.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct MeshSnapshot {
/// Devices advertising at least one routable model.
pub sharing_device_count: usize,
/// Unique current members with at least one ready serving device.
pub contributor_member_count: usize,
/// Summed shared capacity across sharing devices. `None` when no sharing
/// device published a figure — the UI then shows a count with no GB, never
/// a misleading `0 GB`.
pub shared_capacity_gb: Option<f64>,
/// Summed model footprint only when every sharing device reports it.
/// `None` preserves mixed-version honesty instead of presenting a partial sum.
pub allocated_capacity_gb: Option<f64>,
/// Distinct models ready to use, deduped across devices.
pub models: Vec<String>,
/// Per-device rows, for the topology view. Sharing devices first.
pub devices: Vec<MeshSnapshotDevice>,
/// True when the local member's own device is among the sharing devices.
pub includes_self: bool,
/// Members in the community right now (NIP-43 roster size).
///
/// The denominator for "N of M sharing". Deliberately NOT used to estimate
/// unshared capacity: a member who never starts a node publishes no status
/// note, so their hardware is unknown by design — they never consented to
/// disclose it. Ghost nodes in the topology are a count, never GB.
pub member_count: usize,
/// When this projection was evaluated, in Unix seconds.
pub observed_at: u64,
/// Maximum age of a relay-reported serving status.
pub freshness_seconds: u64,
/// Why the snapshot is empty, when it is. Never a hard error: an empty
/// mesh is a normal, expected state.
pub reason: Option<String>,
}
impl MeshSnapshot {
fn empty(reason: impl Into<String>) -> Self {
Self {
observed_at: nostr::Timestamp::now().as_secs(),
freshness_seconds: STATUS_FRESHNESS_SECS,
reason: Some(reason.into()),
..Default::default()
}
}
}
fn f64_field(content: &serde_json::Value, key: &str) -> Option<f64> {
content
.get(key)
.and_then(serde_json::Value::as_f64)
.filter(|value| value.is_finite() && *value > 0.0)
}
/// Coarse state from the published `node_state`, falling back to whether the
/// note actually advertises routable targets.
fn device_state(content: &serde_json::Value, has_targets: bool) -> MeshDeviceState {
let raw = content
.get("node_state")
.and_then(serde_json::Value::as_str)
.map(str::trim)
.unwrap_or_default()
.to_ascii_lowercase();
match raw.as_str() {
"serving" => MeshDeviceState::Serving,
"loading" => MeshDeviceState::Loading,
"client" => MeshDeviceState::Consuming,
"standby" => MeshDeviceState::Standby,
// Unknown/absent: trust the routable evidence rather than guessing.
_ if has_targets => MeshDeviceState::Serving,
_ => MeshDeviceState::Standby,
}
}
/// Project validated member status notes into a presentation snapshot.
///
/// Applies the same trust rules as routing — current NIP-43 membership, owner
/// binding, endpoint binding, and [`status_is_fresh`] — so a stale or
/// non-member note can never inflate the headline. Pure and total so it can be
/// unit-tested without a relay.
pub fn snapshot_from_events(
events: Vec<nostr::Event>,
self_member_pubkey: Option<&str>,
) -> MeshSnapshot {
if events.is_empty() {
return MeshSnapshot::empty("No shared compute has been published yet");
}
let Some(members) = latest_membership_list(&events) else {
return MeshSnapshot::empty("Waiting for the current member roster");
};
let self_pubkey = self_member_pubkey.map(str::to_ascii_lowercase);
let now = nostr::Timestamp::now().as_secs();
// Status notes are replaceable per owner id, so key on that: two devices
// signed in as the same member each publish their own note.
let mut by_owner = BTreeMap::<String, MeshSnapshotDevice>::new();
for event in events {
if event.kind.as_u16() as u64 != MESH_STATUS_KIND
|| !status_is_fresh(&event, now)
|| !members.contains(&event.pubkey.to_hex().to_ascii_lowercase())
{
continue;
}
let Ok(content) = serde_json::from_str::<serde_json::Value>(&event.content) else {
continue;
};
let Some(owner_id) = owner_id_from_status_event(&event) else {
continue;
};
if !endpoint_binding_is_valid(&event, &content) {
continue;
}
// Reuse the routing-side target parse so "sharing" here means exactly
// what it means to the router: a validated, advertisable endpoint.
let targets = content
.get("serveTargets")
.or_else(|| content.get("serve_targets"))
.cloned()
.and_then(|value| serde_json::from_value::<Vec<MeshServeTarget>>(value).ok())
.unwrap_or_default()
.into_iter()
.filter(|target| {
super::transport_policy::validate_advertised_endpoint(&target.endpoint_addr).is_ok()
})
.collect::<Vec<_>>();
let mut models = targets
.iter()
.map(|target| target.model_id.clone())
.collect::<Vec<_>>();
models.sort();
models.dedup();
let endpoint_id = endpoint_id_from_status(&content, None);
let is_self = self_pubkey
.as_deref()
.is_some_and(|pubkey| event.pubkey.to_hex().to_ascii_lowercase() == pubkey);
by_owner.insert(
owner_id,
MeshSnapshotDevice {
label: device_name_from_status(&content, endpoint_id.as_deref())
.unwrap_or_else(|| "Unknown device".to_string()),
device_id: endpoint_id,
capacity_gb: f64_field(&content, "my_vram_gb"),
state: device_state(&content, !models.is_empty()),
models,
is_self,
member_pubkey: Some(event.pubkey.to_hex()),
reported_at: Some(event.created_at.as_secs()),
model_size_gb: f64_field(&content, "model_size_gb"),
},
);
}
let mut devices = by_owner.into_values().collect::<Vec<_>>();
// Sharing devices first, then the local device, then by label so the list
// is stable across polls (no jitter in the topology view).
devices.sort_by(|a, b| {
let sharing = |d: &MeshSnapshotDevice| d.state == MeshDeviceState::Serving;
sharing(b)
.cmp(&sharing(a))
.then_with(|| b.is_self.cmp(&a.is_self))
.then_with(|| a.label.cmp(&b.label))
});
let sharing = devices
.iter()
.filter(|device| device.state == MeshDeviceState::Serving)
.collect::<Vec<_>>();
let sharing_device_count = sharing.len();
let contributor_member_count = sharing
.iter()
.filter_map(|device| device.member_pubkey.as_ref())
.collect::<std::collections::BTreeSet<_>>()
.len();
let includes_self = sharing.iter().any(|device| device.is_self);
// Sum only reported figures; keep `None` when nobody reported one so the
// UI can drop the number instead of printing `0 GB`.
let shared_capacity_gb = sharing
.iter()
.filter_map(|device| device.capacity_gb)
.fold(None::<f64>, |acc, gb| Some(acc.unwrap_or(0.0) + gb));
let allocated_capacity_gb = (!sharing.is_empty()
&& sharing.iter().all(|device| device.model_size_gb.is_some()))
.then(|| {
sharing
.iter()
.filter_map(|device| device.model_size_gb)
.sum()
});
let mut models = sharing
.iter()
.flat_map(|device| device.models.iter().cloned())
.collect::<Vec<_>>();
models.sort();
models.dedup();
let reason = if sharing_device_count == 0 {
Some("No one is sharing compute yet".to_string())
} else {
None
};
MeshSnapshot {
member_count: members.len(),
contributor_member_count,
sharing_device_count,
shared_capacity_gb,
allocated_capacity_gb,
models,
devices,
includes_self,
observed_at: now,
freshness_seconds: STATUS_FRESHNESS_SECS,
reason,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_events_report_a_reason_not_an_error() {
let snapshot = snapshot_from_events(Vec::new(), None);
assert_eq!(snapshot.sharing_device_count, 0);
assert_eq!(snapshot.shared_capacity_gb, None);
assert!(snapshot.reason.is_some());
assert_eq!(snapshot.freshness_seconds, STATUS_FRESHNESS_SECS);
assert!(snapshot.observed_at > 0);
}
#[test]
fn missing_membership_snapshot_is_not_treated_as_an_empty_mesh() {
// A relay gap must not read as "nobody is sharing".
let event = nostr::EventBuilder::new(nostr::Kind::Custom(30003), "{}")
.sign_with_keys(&nostr::Keys::generate())
.expect("test event signs");
let snapshot = snapshot_from_events(vec![event], None);
assert_eq!(
snapshot.reason.as_deref(),
Some("Waiting for the current member roster")
);
}
#[test]
fn unknown_node_state_falls_back_to_routable_evidence() {
assert_eq!(
device_state(&serde_json::json!({}), true),
MeshDeviceState::Serving
);
assert_eq!(
device_state(&serde_json::json!({}), false),
MeshDeviceState::Standby
);
assert_eq!(
device_state(&serde_json::json!({"node_state": "client"}), false),
MeshDeviceState::Consuming
);
}
#[test]
fn capacity_ignores_zero_and_nonfinite_reports() {
// A node that has not surveyed yet publishes 0.0; that must not count
// as a real reported capacity.
assert_eq!(
f64_field(&serde_json::json!({"my_vram_gb": 0.0}), "my_vram_gb"),
None
);
assert_eq!(
f64_field(&serde_json::json!({"my_vram_gb": 36.5}), "my_vram_gb"),
Some(36.5)
);
}
}

View File

@@ -42,3 +42,8 @@ pub async fn mesh_installed_models(
pub async fn mesh_model_catalog() -> CmdResult<serde_json::Value> {
Err("mesh-llm feature not enabled".to_string())
}
#[tauri::command]
pub async fn mesh_snapshot(_state: State<'_, AppState>) -> CmdResult<serde_json::Value> {
Err("mesh-llm feature not enabled".to_string())
}

View File

@@ -381,6 +381,8 @@ buzz messages send --channel <channel-id> --reply-to <thread-root-id> \
- Rust: `definition_validation` and inbound persona tests pin the shared
Unicode/control-character policy at local, import, publish, and sync gates.
16. **Community-mesh agent creation uses the normal create dialog with a named preset.** The Compute settings CTA requests the `community-mesh` create preset; the app-level create-dialog owner resolves it to Buzz Agent with the `relay-mesh` provider and `auto` model, then passes those values through `AgentDialog`. Keep this as a preset of the canonical create flow—never add a second mesh-specific form or bypass normal runtime catalog validation and persistence.
## Keep this file true
**If you change how agent configuration is modeled, rendered, persisted,

View File

@@ -3,6 +3,7 @@ const OPEN_CREATE_AGENT_EVENT = "buzz:open-create-agent";
export type OpenCreateAgentOptions = {
channelId?: string;
channelName?: string;
preset?: "community-mesh";
};
let pendingOpenCreateAgent: OpenCreateAgentOptions | null = null;

View File

@@ -5,6 +5,7 @@ import {
subscribeOpenCreateAgent,
type OpenCreateAgentOptions,
} from "@/features/agents/openCreateAgentEvent";
import type { CreatePersonaInput } from "@/shared/api/types";
import { AgentDialog } from "./AgentDialog";
import { usePersonaActions } from "./usePersonaActions";
@@ -16,9 +17,23 @@ export function RequestedAgentCreateDialogs() {
name: string;
} | null>(null);
const [isOpen, setIsOpen] = React.useState(false);
const [initialValues, setInitialValues] =
React.useState<CreatePersonaInput | null>(null);
const openCreate = React.useEffectEvent((options: OpenCreateAgentOptions) => {
personas.prepareCreate();
setInitialValues(
options.preset === "community-mesh"
? {
displayName: "Community agent",
avatarUrl: "",
systemPrompt: "",
runtime: "buzz-agent",
provider: "relay-mesh",
model: "auto",
}
: null,
);
setTargetChannel(
options.channelId && options.channelName
? { id: options.channelId, name: options.channelName }
@@ -42,12 +57,14 @@ export function RequestedAgentCreateDialogs() {
? personas.createPersonaMutation.error
: null
}
initialValues={initialValues}
isDefinitionPending={personas.isPending}
mode="definition"
onOpenChange={(open) => {
if (!open) {
setIsOpen(false);
setTargetChannel(null);
setInitialValues(null);
}
}}
onSubmitDefinition={(input, intent, backendIntent) =>

View File

@@ -0,0 +1,234 @@
import type {
CommunityComputeDeviceInput,
CommunityComputeSnapshotInput,
} from "./communityComputeMapModel";
export type CommunityComputeTutorialFixtureId =
| "empty"
| "single-device"
| "small-company"
| "large-dense-500";
export type CommunityComputeTutorialFixture = {
id: CommunityComputeTutorialFixtureId;
title: string;
description: string;
snapshot: CommunityComputeSnapshotInput;
};
const MODEL_REFS = [
"unsloth/gemma-4-26B-A4B-it-GGUF:UD-Q4_K_M",
"Qwen/Qwen3.5-35B-A3B-GGUF:Q4_K_M",
"mistralai/Ministral-3-14B-Instruct-GGUF:Q4_K_M",
"bartowski/Llama-3.3-70B-Instruct-GGUF:Q4_K_M",
] as const;
export const EMPTY_COMMUNITY_COMPUTE_FIXTURE: CommunityComputeTutorialFixture =
{
id: "empty",
title: "New community",
description: "No member has shared compute yet.",
snapshot: {
sharingDeviceCount: 0,
contributorMemberCount: 0,
sharedCapacityGb: null,
allocatedCapacityGb: null,
models: [],
devices: [],
includesSelf: false,
memberCount: 8,
reason: "No sharing devices found",
},
};
export const SINGLE_DEVICE_COMMUNITY_COMPUTE_FIXTURE: CommunityComputeTutorialFixture =
{
id: "single-device",
title: "First deployment",
description: "One member is sharing a single workstation.",
snapshot: snapshotFromDevices(
[
device({
index: 0,
id: "studio-workstation",
label: "Morgan’s Studio",
capacityGb: 24,
modelSizeGb: 18,
isSelf: true,
}),
],
1,
),
};
export const SMALL_COMPANY_COMMUNITY_COMPUTE_FIXTURE: CommunityComputeTutorialFixture =
{
id: "small-company",
title: "Small company",
description: "A mixed fleet across a small distributed team.",
snapshot: snapshotFromDevices(
[
...[
{ capacityGb: 24, modelSizeGb: 18 },
{ capacityGb: 24, modelSizeGb: 18 },
{ capacityGb: 36, modelSizeGb: 28 },
{ capacityGb: 36, modelSizeGb: 28 },
{ capacityGb: 48, modelSizeGb: 36 },
{ capacityGb: 48, modelSizeGb: 36 },
{ capacityGb: 64, modelSizeGb: 48 },
{ capacityGb: 64, modelSizeGb: 48 },
{ capacityGb: 96, modelSizeGb: 72 },
{ capacityGb: 96, modelSizeGb: 72 },
].map(({ capacityGb, modelSizeGb }, index) =>
device({
index,
id: `team-macbook-${String(index + 1).padStart(2, "0")}`,
label: `Team MacBook ${String(index + 1).padStart(2, "0")}`,
capacityGb,
modelSizeGb,
isSelf: index === 0,
}),
),
device({
index: 10,
id: "intensive-model-host-a",
label: "Intensive model host A",
capacityGb: 768,
modelRef: "unsloth/Kimi-K2-Thinking-GGUF:UD-Q4_K_XL",
modelSizeGb: 646,
}),
device({
index: 11,
id: "intensive-model-host-b",
label: "Intensive model host B",
capacityGb: 1_440,
modelRef: "unsloth/DeepSeek-V3.2-GGUF:UD-Q4_K_XL",
modelSizeGb: 1_000,
}),
],
24,
),
};
/** Deterministic stress fixture using only the production snapshot contract. */
export const LARGE_DENSE_COMMUNITY_COMPUTE_FIXTURE: CommunityComputeTutorialFixture =
{
id: "large-dense-500",
title: "Large company",
description:
"Five hundred deterministic reporting devices for density testing.",
snapshot: createLargeDenseSnapshot(500),
};
export const COMMUNITY_COMPUTE_TUTORIAL_FIXTURES: Readonly<
Record<CommunityComputeTutorialFixtureId, CommunityComputeTutorialFixture>
> = {
empty: EMPTY_COMMUNITY_COMPUTE_FIXTURE,
"single-device": SINGLE_DEVICE_COMMUNITY_COMPUTE_FIXTURE,
"small-company": SMALL_COMPANY_COMMUNITY_COMPUTE_FIXTURE,
"large-dense-500": LARGE_DENSE_COMMUNITY_COMPUTE_FIXTURE,
};
export function createLargeDenseSnapshot(
deviceCount = 500,
): CommunityComputeSnapshotInput {
const count = Math.max(0, Math.floor(deviceCount));
const capacities = [8, 16, 24, 32, 48, 64, 96, 128] as const;
const devices = Array.from({ length: count }, (_, index) => {
const capacityGb = capacities[index % capacities.length];
const state =
index % 41 === 0 ? "loading" : index % 17 === 0 ? "standby" : "serving";
const largeIndex = [49, 149, 249, 349, 449, 499].indexOf(index);
const largeSizes = [170, 230, 350, 480, 700, 1_000] as const;
const largeCapacities = [192, 256, 384, 512, 768, 1_440] as const;
const modelSizeGb =
largeIndex >= 0
? largeSizes[largeIndex]
: roundCapacity(capacityGb * 0.72);
return device({
index,
id: `dense-device-${String(index + 1).padStart(4, "0")}`,
label:
largeIndex >= 0
? `${largeCapacities[largeIndex]} GB model host`
: `Compute ${String(index + 1).padStart(4, "0")}`,
capacityGb: largeIndex >= 0 ? largeCapacities[largeIndex] : capacityGb,
modelRef:
largeIndex >= 0
? `community/Large-${modelSizeGb}GB-Instruct:FP8`
: undefined,
modelSizeGb,
state,
models: state === "serving" ? undefined : [],
isSelf: index === 0,
});
});
return snapshotFromDevices(devices, Math.ceil(count * 1.37));
}
type DeviceOptions = {
index: number;
id: string;
label: string;
capacityGb: number;
modelRef?: string;
modelSizeGb?: number;
models?: string[];
state?: CommunityComputeDeviceInput["state"];
isSelf?: boolean;
};
function device(options: DeviceOptions): CommunityComputeDeviceInput {
const model =
options.modelRef ?? MODEL_REFS[options.index % MODEL_REFS.length];
return {
deviceId: options.id,
label: options.label,
capacityGb: options.capacityGb,
models: options.models ?? [model],
state: options.state ?? "serving",
isSelf: options.isSelf ?? false,
memberPubkey: `tutorial-member-${String(options.index + 1).padStart(4, "0")}`,
reportedAt: 1_786_032_000,
modelSizeGb: options.modelSizeGb ?? null,
};
}
function roundCapacity(value: number): number {
return Math.round(value * 10) / 10;
}
function snapshotFromDevices(
devices: CommunityComputeDeviceInput[],
memberCount: number,
): CommunityComputeSnapshotInput {
const serving = devices.filter(
(item) => item.state === "serving" && item.models.length > 0,
);
const models = [...new Set(serving.flatMap((item) => item.models))].sort();
const sharedCapacityGb = completeSum(serving.map((item) => item.capacityGb));
const allocatedCapacityGb = completeSum(
serving.map((item) => item.modelSizeGb ?? null),
);
return {
sharingDeviceCount: serving.length,
contributorMemberCount: new Set(
serving.map((item) => item.memberPubkey ?? item.deviceId),
).size,
sharedCapacityGb,
allocatedCapacityGb,
models,
devices,
includesSelf: serving.some((item) => item.isSelf),
memberCount,
observedAt: 1_786_032_000,
freshnessSeconds: 120,
reason: serving.length === 0 ? "No sharing devices found" : null,
};
}
function completeSum(values: readonly (number | null)[]): number | null {
return values.length > 0 && values.every((value) => value !== null)
? values.reduce<number>((total, value) => total + (value ?? 0), 0)
: null;
}

View File

@@ -0,0 +1,358 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
hexCoordinateKey,
hexDistance,
hexNeighbours,
hexTerritoryBoundaryEdges,
hexTerritoryInteriorEdges,
isContiguousHexTerritory,
layoutCommunityComputeHexTerritories,
} from "./communityComputeHexLayout.ts";
import { LARGE_DENSE_COMMUNITY_COMPUTE_FIXTURE } from "./communityComputeFixtures.ts";
import { deriveCommunityComputeMapModel } from "./communityComputeMapModel.ts";
function assertStructuralInvariants(layout) {
const occupied = new Set(layout.cells.map(hexCoordinateKey));
assert.equal(occupied.size, layout.cells.length, "cells must not overlap");
assert.ok(
layout.territories.every((territory) =>
isContiguousHexTerritory(territory.cells),
),
"every territory must be contiguous",
);
if (layout.cells.length > 0) {
const reached = new Set([hexCoordinateKey(layout.cells[0])]);
const queue = [layout.cells[0]];
for (let cursor = 0; cursor < queue.length; cursor += 1) {
for (const neighbour of hexNeighbours(queue[cursor])) {
const key = hexCoordinateKey(neighbour);
if (occupied.has(key) && !reached.has(key)) {
reached.add(key);
queue.push(neighbour);
}
}
}
assert.equal(
reached.size,
occupied.size,
"occupied mesh must be connected",
);
}
}
function organicGaps(layout) {
const occupied = new Set(layout.cells.map(hexCoordinateKey));
const empty = new Map();
for (const cell of layout.cells) {
for (const neighbour of hexNeighbours(cell)) {
const key = hexCoordinateKey(neighbour);
if (!occupied.has(key)) empty.set(key, neighbour);
}
}
return [...empty.values()].filter(
(cell) =>
hexNeighbours(cell).filter((neighbour) =>
occupied.has(hexCoordinateKey(neighbour)),
).length >= 2,
);
}
function assertBalancedSparseFrontier(layout, deploymentCount) {
const points = layout.cells.map((cell) => ({
x: Math.sqrt(3) * (cell.q + cell.r / 2),
y: 1.5 * cell.r,
}));
const width =
Math.max(...points.map(({ x }) => x)) -
Math.min(...points.map(({ x }) => x)) +
Math.sqrt(3);
const height =
Math.max(...points.map(({ y }) => y)) -
Math.min(...points.map(({ y }) => y)) +
2;
const aspectRatio = width / height;
assert.ok(
aspectRatio >= 0.8 && aspectRatio <= 1.3,
`${deploymentCount} deployments have unbalanced aspect ratio ${aspectRatio}`,
);
const radius = Math.max(
...layout.cells.map((cell) => hexDistance(cell, { q: 0, r: 0 })),
);
const directionalRadii = Array(6).fill(0);
for (const cell of layout.cells) {
const projections = [
cell.q,
-cell.r,
-cell.q - cell.r,
-cell.q,
cell.r,
cell.q + cell.r,
];
for (const [index, projection] of projections.entries()) {
directionalRadii[index] = Math.max(directionalRadii[index], projection);
}
}
assert.ok(
Math.max(...directionalRadii) - Math.min(...directionalRadii) <= 2,
`${deploymentCount} deployments must reach every side evenly`,
);
const outerOccupancy =
layout.cells.filter((cell) => hexDistance(cell, { q: 0, r: 0 }) === radius)
.length /
(6 * radius);
assert.ok(
outerOccupancy >= 0.1 && outerOccupancy <= 0.55,
`${deploymentCount} deployments need a sparse, notched outer edge (${outerOccupancy})`,
);
}
function deployments(count) {
const buckets = [1, 2, 4, 7];
return Array.from({ length: count }, (_, index) => ({
id: `deployment-${String(index + 1).padStart(4, "0")}`,
cellCount: buckets[index % buckets.length],
}));
}
test("layout is deterministic and independent of input order", () => {
const input = deployments(80);
const first = layoutCommunityComputeHexTerritories(input);
const second = layoutCommunityComputeHexTerritories([...input].reverse());
assert.deepEqual(first, second);
});
test("growing layouts stay balanced with sparse outer frontiers", () => {
for (const count of [24, 250, 1_000]) {
const layout = layoutCommunityComputeHexTerritories(deployments(count));
assertStructuralInvariants(layout);
assertBalancedSparseFrontier(layout, count);
assert.ok(
organicGaps(layout).length > 0,
`${count} deployments should leave deterministic pockets or edge gaps`,
);
}
});
test("canonical territory order remains stable when previous placement is reused", () => {
const input = deployments(60);
const initial = layoutCommunityComputeHexTerritories(input);
const next = layoutCommunityComputeHexTerritories([...input].reverse(), {
previous: initial,
});
assert.deepEqual(
next.territories.map(({ deploymentId }) => deploymentId),
initial.territories.map(({ deploymentId }) => deploymentId),
);
});
test("payload changes preserve positions because IDs own the slots", () => {
const initial = deployments(40);
const changed = initial.map((deployment) => ({
...deployment,
label: `Changed ${deployment.id}`,
health: "degraded",
}));
assert.deepEqual(
layoutCommunityComputeHexTerritories(initial),
layoutCommunityComputeHexTerritories(changed),
);
});
test("surviving IDs keep positions as deployments are added and removed", () => {
const initialInput = deployments(40);
const initial = layoutCommunityComputeHexTerritories(initialInput);
const nextInput = [
...initialInput.filter((_, index) => index % 4 !== 0),
...deployments(6).map((item, index) => ({
...item,
id: `new-deployment-${index}`,
})),
];
const next = layoutCommunityComputeHexTerritories(nextInput, {
previous: initial,
});
const initialCenters = new Map(
initial.territories.map((territory) => [
territory.deploymentId,
territory.center,
]),
);
for (const territory of next.territories) {
const oldCenter = initialCenters.get(territory.deploymentId);
if (oldCenter !== undefined) {
assert.deepEqual(territory.center, oldCenter);
}
}
assert.equal(
new Set(next.cells.map(hexCoordinateKey)).size,
next.cells.length,
);
});
test("every supported territory shape is contiguous", () => {
const layout = layoutCommunityComputeHexTerritories([
{ id: "one", cellCount: 1 },
{ id: "two", cellCount: 2 },
{ id: "four", cellCount: 4 },
{ id: "seven", cellCount: 7 },
]);
const expected = new Map([
["one", 1],
["two", 2],
["four", 4],
["seven", 7],
]);
for (const territory of layout.territories) {
assert.equal(territory.cells.length, expected.get(territory.deploymentId));
assert.ok(
isContiguousHexTerritory(territory.cells),
`${territory.deploymentId} must be contiguous`,
);
}
});
test("fused boundaries omit interior edges for 1, 2, 4, and 7 cells", () => {
const shapes = [
[{ q: 0, r: 0 }],
[
{ q: 0, r: 0 },
{ q: 1, r: 0 },
],
[
{ q: 0, r: 0 },
{ q: 1, r: 0 },
{ q: 1, r: -1 },
{ q: 0, r: -1 },
],
[{ q: 0, r: 0 }, ...hexNeighbours({ q: 0, r: 0 })],
];
for (const [index, cells] of shapes.entries()) {
const sharedPairs =
cells.reduce(
(total, cell) =>
total +
hexNeighbours(cell).filter((neighbour) =>
cells.some(
(candidate) =>
hexCoordinateKey(candidate) === hexCoordinateKey(neighbour),
),
).length,
0,
) / 2;
const boundary = hexTerritoryBoundaryEdges(cells);
assert.equal(boundary.length, 6 * cells.length - 2 * sharedPairs);
const endpointDegree = new Map();
for (const edge of boundary) {
assert.notDeepEqual(edge.start, edge.end);
for (const point of [edge.start, edge.end]) {
const key = `${point.x.toFixed(8)},${point.y.toFixed(8)}`;
endpointDegree.set(key, (endpointDegree.get(key) ?? 0) + 1);
}
}
assert.ok(
[...endpointDegree.values()].every((degree) => degree === 2),
`shape ${index} boundary must form closed loops without dangling edges`,
);
}
const edgeKey = (edge) =>
[edge.start, edge.end]
.map((point) => `${point.x.toFixed(8)},${point.y.toFixed(8)}`)
.sort()
.join("|");
assert.deepEqual(
hexTerritoryBoundaryEdges(shapes[3]).map(edgeKey).sort(),
hexTerritoryBoundaryEdges([...shapes[3]].reverse())
.map(edgeKey)
.sort(),
"edge membership must not depend on cell order",
);
});
test("interior edges contain each shared device boundary exactly once", () => {
const cells = [{ q: 0, r: 0 }, ...hexNeighbours({ q: 0, r: 0 })];
const interior = hexTerritoryInteriorEdges(cells);
const edgeKey = (edge) =>
[edge.start, edge.end]
.map((point) => `${point.x.toFixed(8)},${point.y.toFixed(8)}`)
.sort()
.join("|");
assert.equal(interior.length, 12);
assert.equal(new Set(interior.map(edgeKey)).size, interior.length);
assert.deepEqual(
interior.map(edgeKey).sort(),
hexTerritoryInteriorEdges([...cells].reverse())
.map(edgeKey)
.sort(),
"shared edge membership must not depend on cell order",
);
assert.deepEqual(hexTerritoryInteriorEdges([{ q: 0, r: 0 }]), []);
});
test("territories never emit duplicate occupied cells", () => {
const layout = layoutCommunityComputeHexTerritories(deployments(250));
const coordinates = layout.cells.map(hexCoordinateKey);
assert.equal(new Set(coordinates).size, coordinates.length);
assert.equal(
new Set(layout.cells.map((cell) => cell.id)).size,
layout.cells.length,
);
});
test("duplicate deployment IDs are rejected rather than overlapped", () => {
assert.throws(
() =>
layoutCommunityComputeHexTerritories([
{ id: "same", cellCount: 1 },
{ id: "same", cellCount: 7 },
]),
/Duplicate community compute deployment ID: same/,
);
});
test("empty layout has no fabricated bounds", () => {
assert.deepEqual(layoutCommunityComputeHexTerritories([]), {
territories: [],
cells: [],
bounds: null,
});
});
test("500-deployment fixture lays out uniquely and contiguously", () => {
const model = deriveCommunityComputeMapModel(
LARGE_DENSE_COMMUNITY_COMPUTE_FIXTURE.snapshot,
);
const input = model.deployments.map(({ id, cellCount }) => ({
id,
cellCount,
}));
const layout = layoutCommunityComputeHexTerritories(input);
assert.equal(layout.territories.length, model.deployments.length);
assert.equal(
layout.cells.length,
model.deployments.reduce(
(total, deployment) => total + deployment.cellCount,
0,
),
);
assert.equal(
new Set(layout.cells.map(hexCoordinateKey)).size,
layout.cells.length,
);
assert.ok(
layout.territories.every((territory) =>
isContiguousHexTerritory(territory.cells),
),
);
assert.ok(layout.bounds !== null);
});

View File

@@ -0,0 +1,448 @@
import type { HexCellCount } from "./communityComputeMapModel";
/** Axial coordinates for a pointy-top hex grid. */
export type HexCoordinate = {
q: number;
r: number;
};
/** Cartesian point in pointy-top hex geometry. */
export type HexPoint = {
x: number;
y: number;
};
/** One exposed side of a fused hex territory boundary. */
export type HexBoundaryEdge = {
start: HexPoint;
end: HexPoint;
};
export type CommunityComputeLayoutInput = {
id: string;
cellCount: HexCellCount;
};
export type CommunityComputeHexCell = HexCoordinate & {
id: string;
deploymentId: string;
index: number;
};
export type CommunityComputeHexTerritory = {
deploymentId: string;
center: HexCoordinate;
cells: readonly CommunityComputeHexCell[];
};
export type CommunityComputeHexBounds = {
minQ: number;
maxQ: number;
minR: number;
maxR: number;
};
export type CommunityComputeHexLayout = {
territories: readonly CommunityComputeHexTerritory[];
cells: readonly CommunityComputeHexCell[];
bounds: CommunityComputeHexBounds | null;
};
export type CommunityComputeHexLayoutOptions = {
/**
* Reuse centres for IDs that are still present. Supplying the last layout
* keeps a live map steady while deployments arrive, leave, or change size.
*/
previous?: CommunityComputeHexLayout | null;
};
const HEX_DIRECTIONS: readonly HexCoordinate[] = [
{ q: 1, r: 0 },
{ q: 1, r: -1 },
{ q: 0, r: -1 },
{ q: -1, r: 0 },
{ q: -1, r: 1 },
{ q: 0, r: 1 },
];
/**
* Lay deployments out as one organic, edge-connected honeycomb.
*
* Input order never affects the result. Stable hashes choose territory
* orientation, while a deterministic low-discrepancy permutation spreads each
* ring's placements around the whole current frontier. Completed inner rings
* remain dense; only the growing outer layers carry deliberate notches. With a
* previous layout, collision-free surviving shapes retain their exact cells;
* new shapes take the first non-overlapping frontier position that shares an
* edge with the occupied mesh.
*/
export function layoutCommunityComputeHexTerritories(
deployments: readonly CommunityComputeLayoutInput[],
options: CommunityComputeHexLayoutOptions = {},
): CommunityComputeHexLayout {
const seenIds = new Set<string>();
for (const deployment of deployments) {
if (seenIds.has(deployment.id)) {
throw new Error(
`Duplicate community compute deployment ID: ${deployment.id}`,
);
}
seenIds.add(deployment.id);
}
const ordered = [...deployments].sort(
(left, right) =>
stableHash(left.id) - stableHash(right.id) ||
left.id.localeCompare(right.id),
);
// Previous cells are retained only when they remain collision-free. New
// territories search the compact spiral for the first candidate that both
// fits and touches the occupied frontier.
const previousById = new Map(
(options.previous?.territories ?? []).map((territory) => [
territory.deploymentId,
territory,
]),
);
const retainableIds = connectedRetainedTerritoryIds(ordered, previousById);
const occupied = new Set<string>();
const territories: CommunityComputeHexTerritory[] = [];
const placementOrder = [...ordered].sort(
(left, right) =>
Number(retainableIds.has(right.id)) -
Number(retainableIds.has(left.id)) ||
ordered.indexOf(left) - ordered.indexOf(right),
);
for (const deployment of placementOrder) {
const previous = retainableIds.has(deployment.id)
? previousById.get(deployment.id)
: undefined;
const retained =
previous?.cells.length === deployment.cellCount
? previous.cells.map(({ q, r }) => ({ q, r }))
: null;
const retainedFits = retained?.every(
(cell) => !occupied.has(hexCoordinateKey(cell)),
);
const orientation = stableHash(`${deployment.id}:orientation`) % 6;
let center = retainedFits ? previous?.center : undefined;
let coordinates = retainedFits ? retained : null;
if (!coordinates || !center) {
for (let slot = 0; ; slot += 1) {
const candidate = balancedSpiralCoordinate(slot);
const offsets = territoryOffsets(deployment.cellCount, orientation);
const candidateCells = offsets.map((offset) => ({
q: candidate.q + offset.q,
r: candidate.r + offset.r,
}));
const fits = candidateCells.every(
(cell) => !occupied.has(hexCoordinateKey(cell)),
);
const touches =
occupied.size === 0 ||
candidateCells.some((cell) =>
hexNeighbours(cell).some((neighbour) =>
occupied.has(hexCoordinateKey(neighbour)),
),
);
if (fits && touches) {
center = candidate;
coordinates = candidateCells;
break;
}
}
}
const cells = coordinates.map(({ q, r }, index) => {
occupied.add(hexCoordinateKey({ q, r }));
return {
id: `${deployment.id}@${q},${r}`,
deploymentId: deployment.id,
index,
q,
r,
};
});
territories.push({ deploymentId: deployment.id, center, cells });
}
territories.sort(
(left, right) =>
ordered.findIndex((item) => item.id === left.deploymentId) -
ordered.findIndex((item) => item.id === right.deploymentId),
);
const cells = territories.flatMap((territory) => territory.cells);
return { territories, cells, bounds: findBounds(cells) };
}
/** The six axial neighbours of a cell, in stable clockwise order. */
export function hexNeighbours(coordinate: HexCoordinate): HexCoordinate[] {
return HEX_DIRECTIONS.map((direction) => ({
q: coordinate.q + direction.q,
r: coordinate.r + direction.r,
}));
}
/**
* Return only the exposed unit-hex sides of a territory.
*
* Coordinates use pointy-top axial geometry. Shared sides are omitted, so the
* result can be stroked as one fused territory rather than as overlapping
* individual hexagons. Edge direction is stable and follows each cell's
* perimeter; callers may chain matching endpoints when an ordered path is
* required.
*/
export function hexTerritoryBoundaryEdges(
cells: readonly HexCoordinate[],
): HexBoundaryEdge[] {
const occupied = new Set(cells.map(hexCoordinateKey));
const edges: HexBoundaryEdge[] = [];
for (const cell of cells) {
for (let direction = 0; direction < HEX_DIRECTIONS.length; direction += 1) {
const neighbour = {
q: cell.q + HEX_DIRECTIONS[direction].q,
r: cell.r + HEX_DIRECTIONS[direction].r,
};
if (!occupied.has(hexCoordinateKey(neighbour))) {
edges.push(hexEdge(cell, direction));
}
}
}
return edges;
}
/**
* Return each side shared by two cells in a territory exactly once.
*
* Fused model territories do not render these edges. Split deployments use
* them to show the device boundaries without drawing inset outlines around
* every cell or accidentally doubling a shared stroke.
*/
export function hexTerritoryInteriorEdges(
cells: readonly HexCoordinate[],
): HexBoundaryEdge[] {
const occupied = new Set(cells.map(hexCoordinateKey));
const edges: HexBoundaryEdge[] = [];
for (const cell of cells) {
const cellKey = hexCoordinateKey(cell);
for (let direction = 0; direction < HEX_DIRECTIONS.length; direction += 1) {
const neighbour = {
q: cell.q + HEX_DIRECTIONS[direction].q,
r: cell.r + HEX_DIRECTIONS[direction].r,
};
const neighbourKey = hexCoordinateKey(neighbour);
if (occupied.has(neighbourKey) && cellKey < neighbourKey) {
edges.push(hexEdge(cell, direction));
}
}
}
return edges;
}
function hexEdge(cell: HexCoordinate, direction: number): HexBoundaryEdge {
const center = {
x: Math.sqrt(3) * (cell.q + cell.r / 2),
y: 1.5 * cell.r,
};
const corners = Array.from({ length: 6 }, (_, index) => {
const angle = ((-30 + index * 60) * Math.PI) / 180;
return {
x: normalizeHexPointComponent(center.x + Math.cos(angle)),
y: normalizeHexPointComponent(center.y + Math.sin(angle)),
};
});
return {
start: corners[(6 - direction) % 6],
end: corners[(7 - direction) % 6],
};
}
function normalizeHexPointComponent(value: number): number {
return Math.abs(value) < Number.EPSILON * 8 ? 0 : value;
}
/** Axial hex distance, useful to consumers for borders and transitions. */
export function hexDistance(left: HexCoordinate, right: HexCoordinate): number {
const dq = left.q - right.q;
const dr = left.r - right.r;
return Math.max(Math.abs(dq), Math.abs(dr), Math.abs(dq + dr));
}
/** True when every cell can be reached from every other through shared edges. */
export function isContiguousHexTerritory(
cells: readonly HexCoordinate[],
): boolean {
if (cells.length === 0) {
return false;
}
const remaining = new Set(cells.map(hexCoordinateKey));
const queue: HexCoordinate[] = [cells[0]];
remaining.delete(hexCoordinateKey(cells[0]));
for (let cursor = 0; cursor < queue.length; cursor += 1) {
for (const neighbour of hexNeighbours(queue[cursor])) {
const key = hexCoordinateKey(neighbour);
if (remaining.delete(key)) {
queue.push(neighbour);
}
}
}
return remaining.size === 0;
}
export function hexCoordinateKey(coordinate: HexCoordinate): string {
return `${coordinate.q},${coordinate.r}`;
}
/** Keep only the edge-connected component of valid surviving territories. */
function connectedRetainedTerritoryIds(
ordered: readonly CommunityComputeLayoutInput[],
previousById: ReadonlyMap<string, CommunityComputeHexTerritory>,
): Set<string> {
const valid = ordered
.map((deployment) => previousById.get(deployment.id))
.filter(
(territory): territory is CommunityComputeHexTerritory =>
territory !== undefined &&
territory.cells.length ===
ordered.find((item) => item.id === territory.deploymentId)?.cellCount,
);
if (valid.length === 0) return new Set();
const owner = new Map<string, string>();
for (const territory of valid) {
for (const cell of territory.cells) {
const key = hexCoordinateKey(cell);
if (owner.has(key)) return new Set();
owner.set(key, territory.deploymentId);
}
}
const retained = new Set([valid[0].deploymentId]);
const queue = [valid[0].deploymentId];
const byId = new Map(
valid.map((territory) => [territory.deploymentId, territory]),
);
for (let cursor = 0; cursor < queue.length; cursor += 1) {
const territory = byId.get(queue[cursor]);
if (!territory) continue;
for (const cell of territory.cells) {
for (const neighbour of hexNeighbours(cell)) {
const neighbourOwner = owner.get(hexCoordinateKey(neighbour));
if (neighbourOwner && !retained.has(neighbourOwner)) {
retained.add(neighbourOwner);
queue.push(neighbourOwner);
}
}
}
}
return retained;
}
function territoryOffsets(
count: HexCellCount,
orientation: number,
): HexCoordinate[] {
const center = { q: 0, r: 0 };
if (count === 1) {
return [center];
}
if (count === 2) {
return [center, HEX_DIRECTIONS[orientation]];
}
if (count === 4) {
return [
center,
HEX_DIRECTIONS[orientation],
HEX_DIRECTIONS[(orientation + 1) % 6],
HEX_DIRECTIONS[(orientation + 2) % 6],
];
}
return [center, ...HEX_DIRECTIONS];
}
/**
* Zero-based spiral slot: origin, then complete radius-one, radius-two, … rings.
* Runtime is O(radius), which is O(sqrt(n)); even at dense fixture sizes the
* largest radius remains small.
*/
function balancedSpiralCoordinate(index: number): HexCoordinate {
if (index === 0) {
return { q: 0, r: 0 };
}
let radius = 1;
let ringStart = 1;
while (index >= ringStart + 6 * radius) {
ringStart += 6 * radius;
radius += 1;
}
const ringLength = 6 * radius;
const ringIndex = index - ringStart;
// Multiplication by a number coprime with the ring length is a permutation,
// not sampling: every slot is eventually visited. A step near half a ring
// alternates opposite sides, preventing a partially filled layer from
// producing the one-sided growth of a clockwise spiral.
let step = Math.max(1, Math.floor(ringLength / 2) - 1);
while (greatestCommonDivisor(step, ringLength) !== 1) step -= 1;
const offsetSeed = stableHash(`ring:${radius}`) % ringLength;
let offset = (offsetSeed + ringIndex * step) % ringLength;
let coordinate = { q: -radius, r: radius };
for (const direction of HEX_DIRECTIONS) {
const steps = Math.min(radius, offset);
coordinate = {
q: coordinate.q + direction.q * steps,
r: coordinate.r + direction.r * steps,
};
offset -= steps;
if (offset === 0) {
break;
}
}
return coordinate;
}
function greatestCommonDivisor(left: number, right: number): number {
let a = left;
let b = right;
while (b !== 0) {
const remainder = a % b;
a = b;
b = remainder;
}
return a;
}
function findBounds(
cells: readonly HexCoordinate[],
): CommunityComputeHexBounds | null {
if (cells.length === 0) {
return null;
}
let minQ = cells[0].q;
let maxQ = cells[0].q;
let minR = cells[0].r;
let maxR = cells[0].r;
for (const cell of cells.slice(1)) {
minQ = Math.min(minQ, cell.q);
maxQ = Math.max(maxQ, cell.q);
minR = Math.min(minR, cell.r);
maxR = Math.max(maxR, cell.r);
}
return { minQ, maxQ, minR, maxR };
}
/** FNV-1a over UTF-16 code units; deterministic on every JS runtime. */
function stableHash(value: string): number {
let hash = 0x811c9dc5;
for (let index = 0; index < value.length; index += 1) {
hash ^= value.charCodeAt(index);
hash = Math.imul(hash, 0x01000193);
}
return hash >>> 0;
}

View File

@@ -0,0 +1,206 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
bucketHexCellCount,
capacityGbToHexCellCount,
deriveCommunityComputeMapModel,
} from "./communityComputeMapModel.ts";
import {
COMMUNITY_COMPUTE_TUTORIAL_FIXTURES,
LARGE_DENSE_COMMUNITY_COMPUTE_FIXTURE,
createLargeDenseSnapshot,
} from "./communityComputeFixtures.ts";
function device(overrides = {}) {
return {
deviceId: "device-1",
label: "Studio",
capacityGb: 32,
models: ["gemma"],
state: "serving",
isSelf: false,
memberPubkey: "member-1",
reportedAt: 1_786_032_000,
modelSizeGb: 18,
...overrides,
};
}
function snapshot(overrides = {}) {
return {
sharingDeviceCount: 1,
contributorMemberCount: 1,
sharedCapacityGb: 32,
allocatedCapacityGb: 18,
models: ["gemma"],
devices: [device()],
includesSelf: false,
memberCount: 4,
reason: null,
...overrides,
};
}
test("cell buckets are exactly 1, 2, 4, and 7", () => {
assert.deepEqual(
[-1, 1, 1.1, 2, 2.1, 4, 4.1, 999, Number.NaN].map(bucketHexCellCount),
[1, 1, 2, 2, 4, 4, 7, 7, 1],
);
assert.deepEqual(
[null, 128, 128.1, 256, 256.1, 512, 512.1, 1000].map(
capacityGbToHexCellCount,
),
[1, 1, 2, 2, 4, 4, 7, 7],
);
});
test("only ready serving models become deployments", () => {
const model = deriveCommunityComputeMapModel(
snapshot({
sharingDeviceCount: 1,
devices: [
device({ deviceId: "a", models: ["gemma", "qwen"] }),
device({ deviceId: "b", state: "loading", models: [] }),
device({ deviceId: "c", state: "standby", models: [] }),
device({ deviceId: "d", state: "consuming", models: [] }),
],
}),
);
assert.equal(model.status, "ready");
assert.deepEqual(
model.deployments.map((deployment) => deployment.modelId),
["gemma", "qwen"],
);
assert.equal(model.kpis.deploymentCount, 2);
assert.equal(model.kpis.contributorMemberCount, 1);
assert.equal(model.health.counts.healthy, 1);
assert.equal(model.health.counts.warming, 1);
assert.equal(model.health.counts.idle, 1);
});
test("one territory is produced per model and per device replica", () => {
const model = deriveCommunityComputeMapModel(
snapshot({
devices: [
device({ deviceId: "a", models: ["qwen", "gemma"] }),
device({ deviceId: "b", memberPubkey: "member-2", models: ["gemma"] }),
],
}),
);
assert.equal(model.deployments.length, 3);
assert.equal(
model.deployments.filter((deployment) => deployment.modelId === "gemma")
.length,
2,
);
assert.equal(new Set(model.deployments.map(({ id }) => id)).size, 3);
});
test("reported model footprint controls area without fixture overrides", () => {
const model = deriveCommunityComputeMapModel(
snapshot({ devices: [device({ capacityGb: 768, modelSizeGb: 96 })] }),
);
assert.equal(model.deployments[0].cellCount, 1);
const large = deriveCommunityComputeMapModel(
snapshot({ devices: [device({ capacityGb: 768, modelSizeGb: 646 })] }),
);
assert.equal(large.deployments[0].cellCount, 7);
});
test("loading, consumer-only, and empty snapshots render no territories", () => {
for (const state of ["loading", "standby", "consuming"]) {
const model = deriveCommunityComputeMapModel(
snapshot({ devices: [device({ state, models: [] })] }),
);
assert.equal(model.status, "empty");
assert.equal(model.deployments.length, 0);
}
assert.equal(deriveCommunityComputeMapModel(null).status, "loading");
assert.equal(
deriveCommunityComputeMapModel(
COMMUNITY_COMPUTE_TUTORIAL_FIXTURES.empty.snapshot,
).status,
"empty",
);
});
test("projection is deterministic and independent of device/model order", () => {
const devices = [
device({ deviceId: "z", label: "Zulu", models: ["qwen", "gemma"] }),
device({ deviceId: "a", label: "Alpha", models: ["mistral"] }),
];
const forward = deriveCommunityComputeMapModel(snapshot({ devices }));
const reverse = deriveCommunityComputeMapModel(
snapshot({
devices: [...devices]
.reverse()
.map((item) => ({ ...item, models: [...item.models].reverse() })),
}),
);
assert.deepEqual(forward, reverse);
});
test("tutorial fixtures use only production fields and production sizing", () => {
assert.deepEqual(Object.keys(COMMUNITY_COMPUTE_TUTORIAL_FIXTURES).sort(), [
"empty",
"large-dense-500",
"single-device",
"small-company",
]);
const allowed = new Set([
"deviceId",
"label",
"capacityGb",
"models",
"state",
"isSelf",
"memberPubkey",
"reportedAt",
"modelSizeGb",
]);
for (const fixture of Object.values(COMMUNITY_COMPUTE_TUTORIAL_FIXTURES)) {
for (const item of fixture.snapshot.devices) {
assert.deepEqual(
Object.keys(item).filter((key) => !allowed.has(key)),
[],
);
}
}
const small = deriveCommunityComputeMapModel(
COMMUNITY_COMPUTE_TUTORIAL_FIXTURES["small-company"].snapshot,
);
assert.equal(small.deployments.length, 12);
assert.equal(
small.deployments.filter(({ deviceLabel }) =>
deviceLabel.startsWith("Team MacBook"),
).length,
10,
);
assert.equal(
small.deployments.filter(({ cellCount }) => cellCount === 1).length,
10,
);
assert.equal(
small.deployments.filter(({ cellCount }) => cellCount === 7).length,
2,
);
});
test("large dense fixture is deterministic and excludes non-serving rows", () => {
const fixture = LARGE_DENSE_COMMUNITY_COMPUTE_FIXTURE.snapshot;
assert.deepEqual(fixture, createLargeDenseSnapshot(500));
assert.equal(fixture.devices.length, 500);
const servingCount = fixture.devices.filter(
(item) => item.state === "serving" && item.models.length > 0,
).length;
const model = deriveCommunityComputeMapModel(fixture);
assert.equal(model.deployments.length, servingCount);
assert.equal(model.kpis.deploymentCount, servingCount);
assert.equal(
new Set(model.deployments.map(({ id }) => id)).size,
servingCount,
);
});

View File

@@ -0,0 +1,365 @@
import type {
MeshDeviceState,
MeshSnapshot,
MeshSnapshotDevice,
} from "@/shared/api/tauriMesh";
/** The only territory sizes rendered by the community compute map. */
export const HEX_CELL_BUCKETS = [1, 2, 4, 7] as const;
export type HexCellCount = (typeof HEX_CELL_BUCKETS)[number];
/**
* The Community view intentionally consumes only fields in the production
* snapshot contract. Tutorial fixtures use this same shape so examples cannot
* quietly grow capabilities that live Compute does not have.
*/
export type CommunityComputeDeviceInput = MeshSnapshotDevice;
/** A readonly, structurally compatible form of the current mesh snapshot. */
export type CommunityComputeSnapshotInput<
TDevice extends MeshSnapshotDevice = CommunityComputeDeviceInput,
> = Omit<MeshSnapshot, "devices"> & {
readonly devices: readonly TDevice[];
};
export type CommunityComputeDeploymentHealth =
| "healthy"
| "warming"
| "idle"
| "degraded"
| "offline"
| "unknown";
export type CommunityComputeMapHealth =
| "healthy"
| "attention"
| "critical"
| "empty"
| "unknown";
export type CommunityComputeDeployment<
TDevice extends MeshSnapshotDevice = CommunityComputeDeviceInput,
> = {
/** Stable map identity. Never derived from the device's array position. */
id: string;
/** Model shown as the territory's primary identity. */
label: string;
modelId: string;
deviceLabel: string;
capacityGb: number | null;
models: readonly string[];
state: MeshDeviceState;
isSelf: boolean;
health: CommunityComputeDeploymentHealth;
healthReason: string | null;
cellCount: HexCellCount;
/** Preserves additive backend data for a future detail projection. */
source: Readonly<TDevice>;
};
export type CommunityComputeKpis = {
memberCount: number;
contributorMemberCount: number;
deploymentCount: number;
activeDeploymentCount: number;
sharedCapacityGb: number | null;
allocatedCapacityGb: number | null;
allocatedPercent: number | null;
modelCount: number;
};
export type CommunityComputeHealthSummary = {
status: CommunityComputeMapHealth;
label: string;
reason: string | null;
counts: Record<CommunityComputeDeploymentHealth, number>;
};
export type CommunityComputeMapModel<
TDevice extends MeshSnapshotDevice = CommunityComputeDeviceInput,
> = {
status: "loading" | "ready" | "empty";
kpis: CommunityComputeKpis;
health: CommunityComputeHealthSummary;
deployments: readonly CommunityComputeDeployment<TDevice>[];
};
/**
* Round a desired territory footprint up to one of the four supported shapes.
* Invalid and non-positive weights still get one cell so a deployment cannot
* disappear from the map.
*/
export function bucketHexCellCount(
weight: number | null | undefined,
): HexCellCount {
if (weight === null || weight === undefined || !Number.isFinite(weight)) {
return 1;
}
const normalized = Math.max(1, Math.ceil(weight));
return HEX_CELL_BUCKETS.find((bucket) => normalized <= bucket) ?? 7;
}
/**
* Turn model memory into a deliberately coarse footprint.
*
* A 128 GB Mac is the common mesh workhorse, so every model that fits on one is
* one cell. Multi-cell territories are reserved for genuinely multi-GPU scale
* deployments; this avoids making ordinary local models look fragmented.
*/
export function capacityGbToHexCellCount(
capacityGb: number | null | undefined,
): HexCellCount {
if (capacityGb === null || capacityGb === undefined || capacityGb <= 128) {
return 1;
}
if (capacityGb <= 256) {
return 2;
}
if (capacityGb <= 512) {
return 4;
}
return 7;
}
const EMPTY_HEALTH_COUNTS: Record<CommunityComputeDeploymentHealth, number> = {
healthy: 0,
warming: 0,
idle: 0,
degraded: 0,
offline: 0,
unknown: 0,
};
/** Project a backend snapshot into the complete, render-agnostic map model. */
export function deriveCommunityComputeMapModel<
TDevice extends MeshSnapshotDevice = CommunityComputeDeviceInput,
>(
snapshot: CommunityComputeSnapshotInput<TDevice> | null,
): CommunityComputeMapModel<TDevice> {
if (snapshot === null) {
return {
status: "loading",
kpis: {
memberCount: 0,
contributorMemberCount: 0,
deploymentCount: 0,
activeDeploymentCount: 0,
sharedCapacityGb: null,
allocatedCapacityGb: null,
allocatedPercent: null,
modelCount: 0,
},
health: {
status: "unknown",
label: "Checking community compute",
reason: null,
counts: { ...EMPTY_HEALTH_COUNTS },
},
deployments: [],
};
}
const deployments = projectDeployments(snapshot.devices);
const healthStates = snapshot.devices
.filter((device) => device.state !== "consuming")
.map((device) => healthFromState(device.state));
const counts = countHealth(healthStates);
const models = new Set(snapshot.models);
for (const deployment of deployments) {
for (const model of deployment.models) {
models.add(model);
}
}
const contributorMemberCount =
snapshot.contributorMemberCount ??
new Set(
deployments
.filter((deployment) => deployment.state === "serving")
.map(
(deployment) =>
deployment.source.memberPubkey?.trim() || deployment.id,
),
).size;
const sharedCapacityGb = finiteNonNegative(snapshot.sharedCapacityGb);
const reportedAllocated = finiteNonNegative(snapshot.allocatedCapacityGb);
const servingDeployments = deployments.filter(
(deployment) => deployment.state === "serving",
);
const inferredAllocations = servingDeployments.map((deployment) =>
finiteNonNegative(deployment.source.modelSizeGb),
);
const allocatedCapacityGb =
reportedAllocated ??
(inferredAllocations.length > 0 &&
inferredAllocations.every((value) => value !== null)
? inferredAllocations.reduce((total, value) => total + (value ?? 0), 0)
: null);
return {
status: deployments.length === 0 ? "empty" : "ready",
kpis: {
memberCount: nonNegativeInteger(snapshot.memberCount),
contributorMemberCount,
deploymentCount: deployments.length,
activeDeploymentCount: counts.healthy + counts.warming,
sharedCapacityGb,
allocatedCapacityGb,
allocatedPercent:
allocatedCapacityGb !== null &&
sharedCapacityGb !== null &&
sharedCapacityGb > 0
? Math.min(100, (allocatedCapacityGb / sharedCapacityGb) * 100)
: null,
modelCount: models.size,
},
health: summarizeHealth(counts, healthStates, snapshot.reason),
deployments,
};
}
function projectDeployments<TDevice extends MeshSnapshotDevice>(
devices: readonly TDevice[],
): CommunityComputeDeployment<TDevice>[] {
const canonical = devices
.filter((device) => device.state === "serving" && device.models.length > 0)
.flatMap((device) =>
[...new Set(device.models)].map((model) => ({
device: { ...device, models: [model] } as TDevice,
identity: deploymentIdentity(device, model),
})),
)
.sort(
(left, right) =>
left.identity.localeCompare(right.identity) ||
deviceFingerprint(left.device).localeCompare(
deviceFingerprint(right.device),
),
);
const occurrences = new Map<string, number>();
return canonical.map(({ device, identity }) => {
const occurrence = occurrences.get(identity) ?? 0;
occurrences.set(identity, occurrence + 1);
const models = [...new Set(device.models)].sort();
return {
id: occurrence === 0 ? identity : `${identity}#${occurrence + 1}`,
label: models[0] ?? device.label,
modelId: models[0] ?? "Model not reported",
deviceLabel: device.label,
capacityGb: finiteNonNegative(device.capacityGb),
models,
state: device.state,
isSelf: device.isSelf,
health: healthFromState(device.state),
healthReason: null,
cellCount: capacityGbToHexCellCount(
device.modelSizeGb ?? device.capacityGb,
),
source: device,
};
});
}
function deploymentIdentity(
device: MeshSnapshotDevice,
modelId: string,
): string {
const deviceId = cleanOptionalText(device.deviceId);
const model = encodeURIComponent(modelId);
return deviceId === null
? `derived:${encodeURIComponent(deviceFingerprint(device))}:${model}`
: `deployment:${encodeURIComponent(deviceId)}:${model}`;
}
function deviceFingerprint(device: MeshSnapshotDevice): string {
return JSON.stringify([
device.label,
device.capacityGb,
[...device.models].sort(),
device.state,
device.isSelf,
]);
}
function healthFromState(
state: MeshDeviceState,
): CommunityComputeDeploymentHealth {
switch (state) {
case "serving":
case "consuming":
return "healthy";
case "loading":
return "warming";
case "standby":
return "idle";
}
}
function countHealth(
states: readonly CommunityComputeDeploymentHealth[],
): Record<CommunityComputeDeploymentHealth, number> {
const counts = { ...EMPTY_HEALTH_COUNTS };
for (const state of states) {
counts[state] += 1;
}
return counts;
}
function summarizeHealth(
counts: Record<CommunityComputeDeploymentHealth, number>,
states: readonly CommunityComputeDeploymentHealth[],
snapshotReason: string | null,
): CommunityComputeHealthSummary {
if (states.length === 0) {
return {
status: "empty",
label: "No deployments",
reason: cleanOptionalText(snapshotReason),
counts,
};
}
const unavailable = counts.offline + counts.degraded;
const reason = null;
if (counts.offline === states.length) {
return { status: "critical", label: "Compute unavailable", reason, counts };
}
if (unavailable > 0) {
return {
status: "attention",
label: `${unavailable} deployment${unavailable === 1 ? "" : "s"} need attention`,
reason,
counts,
};
}
if (counts.unknown === states.length) {
return { status: "unknown", label: "Health unknown", reason: null, counts };
}
return {
status: "healthy",
label: "No reported issues",
reason: null,
counts,
};
}
function finiteNonNegative(value: number | null | undefined): number | null {
return value !== null &&
value !== undefined &&
Number.isFinite(value) &&
value >= 0
? value
: null;
}
function nonNegativeInteger(value: number): number {
return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
}
function cleanOptionalText(value: string | null | undefined): string | null {
const cleaned = value?.trim();
return cleaned ? cleaned : null;
}

View File

@@ -17,42 +17,54 @@ export function useMeshNodeStatus(): {
status: MeshNodeStatus | null;
error: string | null;
refresh: () => void;
update: (status: MeshNodeStatus) => void;
} {
const [status, setStatus] = React.useState<MeshNodeStatus | null>(null);
const [error, setError] = React.useState<string | null>(null);
const requestSequence = React.useRef(0);
const fetchOnce = React.useCallback(() => {
let cancelled = false;
(async () => {
const sequence = ++requestSequence.current;
void (async () => {
try {
const value = await meshNodeStatus();
if (!cancelled) {
if (sequence === requestSequence.current) {
setStatus(value);
setError(null);
}
} catch (err) {
if (!cancelled) {
if (sequence === requestSequence.current) {
setError(err instanceof Error ? err.message : String(err));
}
}
})();
return () => {
cancelled = true;
};
}, []);
React.useEffect(() => fetchOnce(), [fetchOnce]);
const update = React.useCallback((value: MeshNodeStatus) => {
// Invalidate any slower request started before this authoritative command
// result so it cannot restore the preceding lifecycle state.
requestSequence.current += 1;
setStatus(value);
setError(null);
}, []);
React.useEffect(() => {
fetchOnce();
}, [fetchOnce]);
// Fast poll while in a transitioning state; slow poll while steady or off.
React.useEffect(() => {
const transitioning =
status?.state === "starting" || status?.state === "stopping";
const interval = transitioning ? 750 : 4000;
// Keep reconciling aggressively while a start command is still waiting on
// model readiness. The command can take minutes and its eventual response
// is not the only signal that the runtime crossed to running.
const interval = transitioning ? 500 : 4000;
const handle = window.setInterval(() => {
fetchOnce();
}, interval);
return () => window.clearInterval(handle);
}, [status?.state, fetchOnce]);
return { status, error, refresh: fetchOnce };
return { status, error, refresh: fetchOnce, update };
}

View File

@@ -0,0 +1,62 @@
import * as React from "react";
import { meshSnapshot } from "@/shared/api/tauriMesh";
import type { MeshSnapshot } from "@/shared/api/tauriMesh";
/**
* Poll the community shared-compute snapshot.
*
* Deliberately slow compared to `useMeshNodeStatus` (750ms/4000ms): that hook
* watches a LOCAL lifecycle that must feel responsive, while this one reads
* RELAY state that only changes as fast as the 45s member heartbeat, with a
* 120s freshness window. Polling faster would just add relay queries without
* adding information.
*
* An empty mesh is not an error — the snapshot carries its own `reason`. `error`
* here means the query itself failed (offline relay, stub build).
*/
const SNAPSHOT_POLL_INTERVAL_MS = 30_000;
export function useMeshSnapshot(options?: { refreshKey?: number }): {
snapshot: MeshSnapshot | null;
error: string | null;
refresh: () => void;
} {
const [snapshot, setSnapshot] = React.useState<MeshSnapshot | null>(null);
const [error, setError] = React.useState<string | null>(null);
const refreshKey = options?.refreshKey ?? 0;
// Guards against a slow in-flight response overwriting a newer one.
const requestSeq = React.useRef(0);
const fetchOnce = React.useCallback(() => {
const seq = ++requestSeq.current;
(async () => {
try {
const value = await meshSnapshot();
if (seq === requestSeq.current) {
setSnapshot(value);
setError(null);
}
} catch (err) {
if (seq === requestSeq.current) {
setError(err instanceof Error ? err.message : String(err));
}
}
})();
}, []);
// Re-fetch immediately when the local node transitions (refreshKey), so
// turning sharing on updates the community view without waiting for a poll.
// biome-ignore lint/correctness/useExhaustiveDependencies: refreshKey is an intentional trigger, not a value read in the body — bumping it re-queries the community snapshot right after a local node transition instead of waiting out the 30s poll
React.useEffect(() => {
fetchOnce();
}, [fetchOnce, refreshKey]);
React.useEffect(() => {
const handle = window.setInterval(fetchOnce, SNAPSHOT_POLL_INTERVAL_MS);
return () => window.clearInterval(handle);
}, [fetchOnce]);
return { snapshot, error, refresh: fetchOnce };
}

View File

@@ -0,0 +1,342 @@
import * as React from "react";
import { cn } from "@/shared/lib/cn";
import {
hexTerritoryBoundaryEdges,
layoutCommunityComputeHexTerritories,
type CommunityComputeHexCell,
} from "../communityComputeHexLayout";
import type {
CommunityComputeDeployment,
CommunityComputeMapModel,
} from "../communityComputeMapModel";
export type CommunityComputeTerritoryMapProps = {
model: CommunityComputeMapModel;
className?: string;
};
type Point = { x: number; y: number };
type ViewBox = {
x: number;
y: number;
width: number;
height: number;
};
// Deliberately overlap polygons, then trim their outside with the territory
// edge. This avoids SVG antialias seams inside one model footprint.
const FUSED_TILE_RADIUS = 1.025;
const TILE_EDGE_WIDTH = 0.1;
const SQRT_THREE = Math.sqrt(3);
/**
* Responsive SVG territory map. Each deployment owns one stable, contiguous
* cluster of discrete hexes; health changes never move that cluster.
*/
export function CommunityComputeTerritoryMap({
model,
className,
}: CommunityComputeTerritoryMapProps) {
const deploymentById = React.useMemo(
() =>
new Map(
model.deployments.map((deployment) => [deployment.id, deployment]),
),
[model.deployments],
);
const previousLayoutRef = React.useRef<ReturnType<
typeof layoutCommunityComputeHexTerritories
> | null>(null);
const layout = React.useMemo(
() =>
layoutCommunityComputeHexTerritories(
model.deployments.map(({ id, cellCount }) => ({ id, cellCount })),
{ previous: previousLayoutRef.current },
),
[model.deployments],
);
React.useEffect(() => {
previousLayoutRef.current = layout;
}, [layout]);
const viewBox = computeViewBox(layout.cells);
const [hoveredId, setHoveredId] = React.useState<string | null>(null);
const lowerTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(
null,
);
const hoveredDeployment = hoveredId
? (deploymentById.get(hoveredId) ?? null)
: null;
const isDenseMap = model.deployments.length >= 50;
React.useEffect(
() => () => {
if (lowerTimerRef.current) clearTimeout(lowerTimerRef.current);
},
[],
);
function raiseTerritory(deploymentId: string, territoryElement: SVGGElement) {
if (lowerTimerRef.current) clearTimeout(lowerTimerRef.current);
// SVG paints in DOM order. Move the existing node instead of rebuilding
// children so hover stays smooth as territories scale.
territoryElement.parentNode?.appendChild(territoryElement);
setHoveredId(deploymentId);
}
function lowerTerritory() {
if (lowerTimerRef.current) clearTimeout(lowerTimerRef.current);
// Let the detail card linger briefly while the territory settles.
lowerTimerRef.current = setTimeout(() => setHoveredId(null), 280);
}
if (model.status === "loading") {
return (
<section
aria-busy="true"
aria-label="Community compute map"
className={cn(
"rounded-xl border border-border/70 bg-muted/10 p-4",
className,
)}
data-testid="community-compute-map-loading"
>
<div className="h-48 animate-pulse rounded-lg bg-muted/50 motion-reduce:animate-none" />
<p className="mt-3 text-sm text-muted-foreground">
Mapping community compute…
</p>
</section>
);
}
if (model.status === "empty" || viewBox === null) {
return (
<section
aria-label="Community compute map"
className={cn(
"flex min-h-48 flex-col items-center justify-center rounded-xl border border-dashed border-border px-5 py-8 text-center",
className,
)}
data-testid="community-compute-map-empty"
>
<EmptyHexes />
<p className="mt-3 text-sm font-medium">No compute territories yet</p>
<p className="mt-1 max-w-sm text-xs leading-relaxed text-muted-foreground">
Shared compute appears here when members make it available to the
community.
</p>
</section>
);
}
return (
<section
aria-label="Community compute map"
className={cn(
"min-w-0 space-y-4 rounded-xl border border-border/70 bg-muted/10 p-3",
className,
)}
data-testid="community-compute-territory-map"
>
<div className="relative flex min-h-72 min-w-0 flex-col items-center justify-center gap-4 overflow-hidden rounded-lg border border-border/50 bg-background/70 p-3 sm:min-h-96">
<svg
aria-label={`${model.deployments.length} community compute territories. Focus or hover a territory for details.`}
className="h-auto max-h-[28rem] w-full overflow-visible"
data-testid="community-compute-map-svg"
preserveAspectRatio="xMidYMid meet"
role="img"
viewBox={`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`}
>
{layout.territories.map((territory) => {
const deployment = deploymentById.get(territory.deploymentId);
if (!deployment) return null;
return (
// SVG groups have no semantic element for hover/focus detail disclosure.
// biome-ignore lint/a11y/noStaticElementInteractions: keyboard focus mirrors hover without making the territory an action.
<g
aria-label={territoryAccessibleLabel(deployment)}
className="origin-center outline-hidden [transform-box:fill-box] transition-[opacity,transform] duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] hover:scale-[var(--mesh-hover-scale)] focus-visible:scale-[var(--mesh-hover-scale)] focus-visible:opacity-90 motion-reduce:transition-none"
data-deployment-id={deployment.id}
data-cell-count={deployment.cellCount}
data-testid={`community-compute-territory-${testId(deployment.id)}`}
key={deployment.id}
onBlur={lowerTerritory}
onFocus={(event) =>
raiseTerritory(deployment.id, event.currentTarget)
}
onMouseEnter={(event) =>
raiseTerritory(deployment.id, event.currentTarget)
}
onMouseLeave={lowerTerritory}
style={territoryHoverStyle(
territory.cells,
viewBox,
isDenseMap,
)}
tabIndex={0}
>
<title>{territoryAccessibleLabel(deployment)}</title>
<TerritoryShape cells={territory.cells} />
</g>
);
})}
</svg>
{hoveredDeployment ? (
<div
className="pointer-events-none absolute bottom-3 left-3 max-w-64 rounded-xl border border-border/70 bg-popover/95 px-3 py-2 shadow-lg backdrop-blur-sm"
data-testid="community-compute-hover-details"
>
<p
className="truncate text-xs font-semibold"
title={hoveredDeployment.modelId}
>
{shortModelName(hoveredDeployment.modelId)}
</p>
<p className="mt-0.5 truncate text-2xs text-muted-foreground">
{hoveredDeployment.deviceLabel} ·{" "}
{formatCapacity(hoveredDeployment.capacityGb)}
</p>
<p className="mt-1 text-2xs text-muted-foreground">
Available to the community
</p>
</div>
) : null}
</div>
</section>
);
}
function TerritoryShape({
cells,
}: {
cells: readonly CommunityComputeHexCell[];
}) {
const boundary = hexTerritoryBoundaryEdges(cells);
return (
<g>
{cells.map((cell) => {
const center = axialToPoint(cell.q, cell.r);
return (
<polygon
className="fill-foreground stroke-transparent"
data-testid="community-compute-tile"
key={cell.id}
points={hexPoints(center, FUSED_TILE_RADIUS)}
/>
);
})}
<path
className="fill-none stroke-background"
d={edgesToPath(boundary)}
data-testid="community-compute-territory-boundary"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={TILE_EDGE_WIDTH}
/>
</g>
);
}
function territoryHoverStyle(
cells: readonly CommunityComputeHexCell[],
viewBox: ViewBox,
dense: boolean,
): React.CSSProperties {
const centers = cells.map((cell) => axialToPoint(cell.q, cell.r));
const minX = Math.min(...centers.map(({ x }) => x)) - 1;
const maxX = Math.max(...centers.map(({ x }) => x)) + 1;
const minY = Math.min(...centers.map(({ y }) => y)) - 1;
const maxY = Math.max(...centers.map(({ y }) => y)) + 1;
const territorySpan = Math.max(maxX - minX, maxY - minY);
const mapSpan = Math.min(viewBox.width, viewBox.height);
// Normalize every hovered territory toward the same visual footprint. Dense
// maps therefore expand dramatically while already-large sparse territories
// receive only a restrained lift.
const targetSpan = mapSpan * (dense ? 0.18 : 0.16);
const scale = Math.max(1.06, Math.min(8, targetSpan / territorySpan));
return { "--mesh-hover-scale": scale } as React.CSSProperties;
}
function edgesToPath(
edges: ReturnType<typeof hexTerritoryBoundaryEdges>,
): string {
return edges
.map(
(edge) =>
`M ${edge.start.x} ${edge.start.y} L ${edge.end.x} ${edge.end.y}`,
)
.join(" ");
}
function EmptyHexes() {
const centers = [
{ x: 2, y: 1.75 },
{ x: 3.58, y: 2.65 },
{ x: 2, y: 3.55 },
{ x: 0.42, y: 2.65 },
];
return (
<svg aria-hidden="true" className="h-14 w-20" viewBox="-0.7 0.5 5.4 4.3">
{centers.map((center) => (
<polygon
className="fill-muted/40 stroke-muted-foreground/40"
key={`${center.x}:${center.y}`}
points={hexPoints(center, 0.82)}
strokeDasharray="2 2"
strokeWidth="0.08"
/>
))}
</svg>
);
}
function axialToPoint(q: number, r: number): Point {
return { x: SQRT_THREE * (q + r / 2), y: 1.5 * r };
}
function hexPoints(center: Point, radius: number): string {
return Array.from({ length: 6 }, (_, index) => {
const angle = ((60 * index - 30) * Math.PI) / 180;
return `${center.x + radius * Math.cos(angle)},${center.y + radius * Math.sin(angle)}`;
}).join(" ");
}
function computeViewBox(
cells: readonly CommunityComputeHexCell[],
): ViewBox | null {
if (cells.length === 0) return null;
const centers = cells.map((cell) => axialToPoint(cell.q, cell.r));
const minX = Math.min(...centers.map(({ x }) => x)) - 1.4;
const maxX = Math.max(...centers.map(({ x }) => x)) + 1.4;
const minY = Math.min(...centers.map(({ y }) => y)) - 1.4;
const maxY = Math.max(...centers.map(({ y }) => y)) + 1.4;
return {
x: minX,
y: minY,
width: Math.max(2.8, maxX - minX),
height: Math.max(2.8, maxY - minY),
};
}
function shortModelName(modelId: string): string {
const tail = modelId.split("/").at(-1) ?? modelId;
return tail.length > 34 ? `${tail.slice(0, 31)}…` : tail;
}
function territoryAccessibleLabel(
deployment: CommunityComputeDeployment,
): string {
const capacity = formatCapacity(deployment.capacityGb);
return `${deployment.modelId} on ${deployment.deviceLabel}, ${capacity}`;
}
function formatCapacity(value: number | null): string {
return value === null
? "Capacity not reported"
: `${Math.round(value)} GB shared`;
}
function testId(value: string): string {
return encodeURIComponent(value).replaceAll("%", "-");
}

View File

@@ -1,6 +1,5 @@
import * as React from "react";
import { ChevronDown } from "lucide-react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import { ChevronDown, Hexagon, Sparkles } from "lucide-react";
import { Switch } from "@/shared/ui/switch";
import { cn } from "@/shared/lib/cn";
@@ -29,6 +28,12 @@ import type {
} from "@/shared/api/tauriMesh";
import { SettingsOptionGroup } from "@/features/settings/ui/SettingsOptionGroup";
import { SettingsSectionHeader } from "@/features/settings/ui/SettingsSectionHeader";
import { requestOpenCreateAgent } from "@/features/agents/openCreateAgentEvent";
import { useCommunities } from "@/features/communities/useCommunities";
import { Button } from "@/shared/ui/button";
import { useMeshSnapshot } from "../hooks/useMeshSnapshot";
import { deriveCommunityComputeMapModel } from "../communityComputeMapModel";
import { CommunityComputeTerritoryMap } from "./CommunityComputeTerritoryMap";
import { classifyModelRef } from "../classifyModelRef";
import {
downloadPercent,
@@ -52,11 +57,6 @@ const MESH_SELECT_TRIGGER_CLASS = cn(
"h-11 px-3 py-2 leading-6 hover:bg-muted/40 focus:bg-muted/40 [&>svg]:text-muted-foreground/60",
);
const SHARE_COMPUTE_REVEAL_TRANSITION = {
duration: 0.22,
ease: [0.23, 1, 0.32, 1],
} as const;
function readDraft(key: string): string {
try {
return window.localStorage.getItem(key) ?? "";
@@ -85,8 +85,11 @@ function writeDraft(key: string, value: string): void {
* exposing implementation protocols or raw mesh controls.
*/
export function MeshComputeSettingsCard() {
const shouldReduceMotion = useReducedMotion();
const { status, error, refresh } = useMeshNodeStatus();
const { activeCommunity } = useCommunities();
const communityName = activeCommunity?.name ?? "this community";
const { status, error, refresh, update } = useMeshNodeStatus();
const [snapshotRefreshKey, setSnapshotRefreshKey] = React.useState(0);
const { snapshot } = useMeshSnapshot({ refreshKey: snapshotRefreshKey });
const [installedModels, setInstalledModels] = React.useState<
MeshModelOption[]
>([]);
@@ -187,6 +190,17 @@ export function MeshComputeSettingsCard() {
const refClass = classifyModelRef(modelInput);
const canStart = refClass.kind !== "unknown" && !actionInFlight;
const showSharingControls = isSharing || pendingAction === "start";
// Live runtime state wins over the still-pending command promise. Starting a
// node waits on an additional inference-readiness probe, so the command can
// remain in flight after status already proves this machine is running. Do
// not leave the visual state spinning during that window.
const isSuccessfullySharing =
status?.mode === "serve" && status.state === "running";
const isTransitioning =
!isSuccessfullySharing &&
(pendingAction !== null ||
status?.state === "starting" ||
status?.state === "stopping");
async function handleToggle(next: boolean) {
// Never let the Share switch tear down a consume session. The switch is
@@ -203,7 +217,7 @@ export function MeshComputeSettingsCard() {
if (next) {
const maxVram =
maxVramGb.trim() === "" ? undefined : Number.parseFloat(maxVramGb);
await meshStartNode({
const nextStatus = await meshStartNode({
mode: "serve",
modelId: modelInput.trim() || undefined,
maxVramGb:
@@ -211,10 +225,13 @@ export function MeshComputeSettingsCard() {
? maxVram
: undefined,
});
update(nextStatus);
} else {
await meshStopNode();
const nextStatus = await meshStopNode();
update(nextStatus);
}
refresh();
setSnapshotRefreshKey((current) => current + 1);
} catch (err) {
setActionError(err instanceof Error ? err.message : String(err));
} finally {
@@ -227,8 +244,8 @@ export function MeshComputeSettingsCard() {
return (
<section className="min-w-0" data-testid="settings-mesh-share-compute">
<SettingsSectionHeader
title="Share compute"
description="Share this machine with members of this relay so they can run agents here."
title="Compute"
description="Sharing helps your community run faster, more capable agents without sending prompts to an outside provider—and every contributor makes that shared resource more useful for everyone."
/>
{error ? (
@@ -248,20 +265,68 @@ export function MeshComputeSettingsCard() {
<SettingsOptionGroup title="Sharing">
<div className="space-y-5 px-4 py-3">
<div className="flex min-w-0 items-start justify-between gap-6">
<div className="min-w-0">
<label
className="text-sm font-medium"
htmlFor="mesh-share-compute-toggle"
<div className="flex min-w-0 items-start gap-3">
<span
aria-hidden="true"
className={cn(
"relative mt-0.5 flex size-7 shrink-0 items-center justify-center text-muted-foreground",
isSuccessfullySharing && "text-emerald-500",
isTransitioning && "text-foreground",
)}
>
Share this machine
</label>
{!isSharing ? (
<StatusLine
isConsuming={isConsuming}
pendingAction={pendingAction}
status={status}
/>
) : null}
{isSuccessfullySharing ? (
<span className="absolute inset-0 animate-ping text-emerald-400 opacity-30 motion-reduce:animate-none">
<Hexagon className="size-7 fill-current" />
</span>
) : null}
{isTransitioning ? (
<svg className="size-7" viewBox="0 0 32 32">
<title>Preparing shared compute</title>
<polygon
className="fill-none stroke-current opacity-20"
points="16,2 28,9 28,23 16,30 4,23 4,9"
strokeWidth="2"
/>
<polygon
className="mesh-compute-hex-trace fill-none stroke-current motion-reduce:[animation:none]"
pathLength="100"
points="16,2 28,9 28,23 16,30 4,23 4,9"
strokeDasharray="18 82"
strokeLinecap="round"
strokeWidth="2.5"
/>
</svg>
) : (
<Hexagon
className={cn(
"size-6",
isSuccessfullySharing && "fill-current",
)}
/>
)}
</span>
<div className="min-w-0">
<label
className="text-sm font-medium"
htmlFor="mesh-share-compute-toggle"
>
{isSuccessfullySharing
? "You’re sharing compute"
: "Share your machine"}
</label>
{!isSuccessfullySharing ? (
<StatusLine
isConsuming={isConsuming}
pendingAction={pendingAction}
status={status}
/>
) : (
<p className="mt-1 text-sm text-emerald-600 dark:text-emerald-400">
This machine is actively sharing compute on {communityName}
’s mesh.
</p>
)}
</div>
</div>
<Switch
checked={isSharing}
@@ -330,6 +395,33 @@ export function MeshComputeSettingsCard() {
usePersonaInputStyle
value={maxVramGb}
/>
{showSharingControls ? (
<section
className="mt-3 space-y-1"
data-testid="mesh-share-compute-sharing-status"
>
<h3 className="text-sm font-medium">Status</h3>
<div className="space-y-1 rounded-lg bg-muted/30 px-3 py-2">
<StatusLine
isConsuming={isConsuming}
omitSharingVerb
pendingAction={pendingAction}
status={status}
/>
{servingIndicator.show ? (
<p
className="text-2xs text-muted-foreground"
data-testid="mesh-serving-usage"
>
{servingIndicator.label}
{servingIndicator.detail
? ` · ${servingIndicator.detail}`
: null}
</p>
) : null}
</div>
</section>
) : null}
{status?.consoleUrl ? (
<p className="text-sm font-normal text-muted-foreground">
Debug console:{" "}
@@ -347,59 +439,47 @@ export function MeshComputeSettingsCard() {
) : null}
</div>
<AnimatePresence initial={false}>
{showSharingControls ? (
<motion.div
animate={{ height: "auto", opacity: 1 }}
className="overflow-hidden"
data-testid="mesh-share-compute-options-motion"
exit={{ height: 0, opacity: 0 }}
initial={{ height: 0, opacity: 0 }}
key="mesh-share-compute-options"
transition={
shouldReduceMotion
? { duration: 0 }
: SHARE_COMPUTE_REVEAL_TRANSITION
}
>
<section
className="space-y-1"
data-testid="mesh-share-compute-sharing-status"
>
<h3 className="text-sm font-medium">Status</h3>
<div className="space-y-1 rounded-lg bg-muted/30 px-3 py-2">
<StatusLine
isConsuming={isConsuming}
omitSharingVerb
pendingAction={pendingAction}
status={status}
/>
{servingIndicator.show ? (
<p
className={
servingIndicator.hasRemoteConsumers
? "text-2xs text-emerald-600 dark:text-emerald-400"
: "text-2xs text-muted-foreground"
}
data-testid="mesh-serving-usage"
title={servingIndicator.detail ?? undefined}
>
{servingIndicator.label}
{servingIndicator.detail ? (
<span className="text-muted-foreground">
{" "}
· {servingIndicator.detail}
</span>
) : null}
</p>
) : null}
</div>
</section>
</motion.div>
) : null}
</AnimatePresence>
{(snapshot?.contributorMemberCount ?? 0) >= 6 ? (
<section className="space-y-2" data-testid="community-compute-view">
<div>
<h3 className="text-base font-semibold">Community mesh</h3>
<p className="text-xs text-muted-foreground">
{snapshot?.contributorMemberCount} people are contributing
compute.
</p>
</div>
<CommunityComputeTerritoryMap
model={deriveCommunityComputeMapModel(snapshot)}
/>
</section>
) : null}
</div>
</SettingsOptionGroup>
<section
className="mt-5 rounded-xl border border-border/70 bg-muted/15 p-4"
data-testid="mesh-community-agent-card"
>
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div>
<h2 className="text-base font-semibold">
Put the community mesh to work
</h2>
<p className="mt-1 text-sm text-muted-foreground">
Anyone can use compute shared by the community—even if this
machine can’t contribute. Name your agent and customize its
instructions; we’ll handle the compute setup.
</p>
</div>
<Button
className="shrink-0"
onClick={() => requestOpenCreateAgent({ preset: "community-mesh" })}
type="button"
>
<Sparkles /> Create community agent
</Button>
</div>
</section>
</section>
);
}
@@ -496,7 +576,9 @@ function MeshModelPicker({
seen.add(entry.name);
return {
disabled: entry.fit === "too_large",
label: <MeshModelOptionLabel entry={entry} />,
label: (
<MeshModelOptionLabel entry={entry} hardware={catalog?.gpuName} />
),
value: entry.name,
};
});
@@ -523,7 +605,7 @@ function MeshModelPicker({
...localOptions,
{ label: "Custom model…", value: CUSTOM_MODEL_DROPDOWN_VALUE },
];
}, [catalog?.entries, installedModels]);
}, [catalog?.entries, catalog?.gpuName, installedModels]);
const knownModel = options.some((option) => option.value === model.trim());
const showCustomModelInput =
isCustomModelEditing || (model.trim().length > 0 && !knownModel);
@@ -578,16 +660,19 @@ function MeshModelPicker({
className="text-sm font-normal text-muted-foreground/70"
data-settings-subcopy
>
{catalog
? `Recommended for this machine${catalog.gpuName ? ` (${catalog.gpuName}, ${catalog.vramDisplay} AI memory)` : ""}.`
: "Choose a model or enter a model reference or local file."}{" "}
Buzz downloads remote models when sharing starts.
Buzz downloads the selected model when sharing starts.
</p>
</div>
);
}
function MeshModelOptionLabel({ entry }: { entry: MeshCatalogEntry }) {
function MeshModelOptionLabel({
entry,
hardware,
}: {
entry: MeshCatalogEntry;
hardware?: string | null;
}) {
return (
<div className="flex min-w-0 items-center gap-2">
<span className="min-w-0 flex-1 truncate font-medium">{entry.name}</span>
@@ -596,8 +681,8 @@ function MeshModelOptionLabel({ entry }: { entry: MeshCatalogEntry }) {
{FIT_LABEL[entry.fit]}
</span>
{entry.recommended ? (
<span className="shrink-0 rounded bg-primary/15 px-1.5 text-2xs font-medium text-primary">
Recommended
<span className="shrink-0 text-2xs text-muted-foreground">
Recommended for {hardware ?? "this machine"}
</span>
) : null}
{entry.installed ? (

View File

@@ -112,3 +112,35 @@ export type MeshModelCatalog = {
export async function meshModelCatalog(): Promise<MeshModelCatalog> {
return await invokeTauri<MeshModelCatalog>("mesh_model_catalog");
}
export type MeshDeviceState = "serving" | "loading" | "standby" | "consuming";
export type MeshSnapshotDevice = {
deviceId: string | null;
label: string;
capacityGb: number | null;
models: string[];
state: MeshDeviceState;
isSelf: boolean;
memberPubkey?: string | null;
reportedAt?: number | null;
modelSizeGb?: number | null;
};
export type MeshSnapshot = {
sharingDeviceCount: number;
contributorMemberCount?: number;
sharedCapacityGb: number | null;
allocatedCapacityGb?: number | null;
models: string[];
devices: MeshSnapshotDevice[];
includesSelf: boolean;
observedAt?: number;
freshnessSeconds?: number;
memberCount: number;
reason: string | null;
};
export async function meshSnapshot(): Promise<MeshSnapshot> {
return await invokeTauri<MeshSnapshot>("mesh_snapshot");
}

View File

@@ -930,3 +930,14 @@
animation: none;
}
}
/* The shape stays fixed while a short dark stroke travels around its edge. */
@keyframes mesh-compute-hex-trace {
to {
stroke-dashoffset: -100;
}
}
.mesh-compute-hex-trace {
animation: mesh-compute-hex-trace 1.1s linear infinite;
}

View File

@@ -26,9 +26,6 @@ test("Share compute chooses a model before sharing", async ({ page }) => {
const model = page.getByTestId("mesh-share-compute-model");
await expect(card).not.toContainText("Not sharing right now");
await expect(
page.getByTestId("mesh-share-compute-options-motion"),
).toHaveCount(0);
await expect(
page.getByTestId("mesh-share-compute-sharing-status"),
).toHaveCount(0);
@@ -39,17 +36,20 @@ test("Share compute chooses a model before sharing", async ({ page }) => {
await page.getByLabel("Custom model reference").fill(modelRef);
await toggle.click();
await expect(
page.getByTestId("mesh-share-compute-options-motion"),
).toBeVisible();
await expect(toggle).toBeChecked();
await expect(card).toContainText("You’re sharing compute");
await expect(card).toContainText("This machine is actively sharing compute");
await expect(model).toBeVisible();
await expect(card).toContainText(
"Buzz downloads the selected model when sharing starts",
);
// Runtime/model details are intentionally secondary to the successful
// sharing state and remain available under Advanced.
await page.getByTestId("mesh-share-compute-advanced-toggle").click();
await expect(
page.getByTestId("mesh-share-compute-sharing-status"),
).toBeVisible();
await expect(model).toBeVisible();
await expect(card).toContainText(
"Buzz downloads remote models when sharing starts",
);
await expect(toggle).toBeChecked();
await expect(
page.getByTestId("mesh-share-compute-sharing-status"),
).toContainText("SmolLM2 135M with relay members");
@@ -74,9 +74,6 @@ test("Share compute chooses a model before sharing", async ({ page }) => {
await toggle.click();
await expect(toggle).not.toBeChecked();
await expect(card).not.toContainText("Not sharing right now");
await expect(
page.getByTestId("mesh-share-compute-options-motion"),
).toHaveCount(0);
await expect(
page.getByTestId("mesh-share-compute-sharing-status"),
).toHaveCount(0);
@@ -123,9 +120,6 @@ test("a consuming client can switch to sharing its saved local model", async ({
);
await expect(card).toContainText("Buzz may briefly restart");
await expect(toggle).not.toBeChecked();
await expect(
page.getByTestId("mesh-share-compute-options-motion"),
).toHaveCount(0);
await expect(toggle).toBeEnabled();
const customModel = page.getByLabel("Custom model reference");
await expect(customModel).toHaveValue(localModel);