- {refHint}
+ {refHint}. If it is not installed, Buzz downloads it when
+ sharing starts.
) : (
- Catalog name, HuggingFace ref, or a local file path.
+ Choose a suggested model below, or enter a catalog name,
+ HuggingFace ref, or local file. Buzz downloads remote models
+ when sharing starts.
From 2cb4af4ee90ed95223c77f8cf07cc82e2bd6d915 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Fri, 10 Jul 2026 20:19:15 -0700
Subject: [PATCH 09/35] fix(mesh): translate inherited provider and simplify
compute copy
---
.../src/managed_agents/global_config/tests.rs | 36 +++++++++++++++++++
.../src-tauri/src/managed_agents/readiness.rs | 5 +++
.../src/managed_agents/relay_mesh.rs | 11 +++---
.../src-tauri/src/managed_agents/runtime.rs | 4 +--
.../mesh-compute/classifyModelRef.test.mjs | 18 +---------
.../features/mesh-compute/classifyModelRef.ts | 22 ++----------
.../ui/MeshComputeSettingsCard.tsx | 32 +++++------------
desktop/tests/e2e/mesh-compute.spec.ts | 4 +--
8 files changed, 62 insertions(+), 70 deletions(-)
diff --git a/desktop/src-tauri/src/managed_agents/global_config/tests.rs b/desktop/src-tauri/src/managed_agents/global_config/tests.rs
index 60ef0d79a6..41d6a6de46 100644
--- a/desktop/src-tauri/src/managed_agents/global_config/tests.rs
+++ b/desktop/src-tauri/src/managed_agents/global_config/tests.rs
@@ -469,6 +469,42 @@ fn resolve_global_fallback_when_record_and_persona_have_none() {
/// Tier 4 — no persona linked: record.persona_id is None, record has no
/// model/provider; global defaults must still fill in (persona lookup skipped).
+#[cfg(feature = "mesh-llm")]
+#[test]
+fn inherited_shared_compute_translates_to_supported_agent_transport() {
+ let record = bare_record();
+ let personas: Vec = vec![];
+ let global = GlobalAgentConfig {
+ model: Some("auto".to_string()),
+ provider: Some(super::super::RELAY_MESH_PROVIDER_ID.to_string()),
+ ..Default::default()
+ };
+ let runtime = super::super::known_acp_runtime("buzz-agent").expect("buzz-agent runtime");
+
+ let effective = super::super::readiness::resolve_effective_agent_env(
+ &record,
+ &personas,
+ Some(runtime),
+ &global,
+ );
+
+ assert_eq!(
+ effective.env.get("BUZZ_AGENT_PROVIDER").map(String::as_str),
+ Some("openai")
+ );
+ assert_eq!(
+ effective.env.get("BUZZ_AGENT_MODEL").map(String::as_str),
+ Some("auto")
+ );
+ assert_eq!(
+ effective
+ .env
+ .get("OPENAI_COMPAT_BASE_URL")
+ .map(String::as_str),
+ Some(super::super::RELAY_MESH_API_BASE_URL)
+ );
+}
+
#[test]
fn resolve_global_fallback_when_no_persona_linked() {
let record = bare_record(); // persona_id = None, model/provider = None
diff --git a/desktop/src-tauri/src/managed_agents/readiness.rs b/desktop/src-tauri/src/managed_agents/readiness.rs
index 600ac7a6cd..4fe447dce9 100644
--- a/desktop/src-tauri/src/managed_agents/readiness.rs
+++ b/desktop/src-tauri/src/managed_agents/readiness.rs
@@ -135,6 +135,11 @@ pub(crate) fn resolve_effective_agent_env(
);
env.extend(user_env);
+ // Buzz shared compute is a native Buzz provider. Translate it to buzz-agent's
+ // OpenAI-compatible transport only in the effective runtime environment.
+ #[cfg(feature = "mesh-llm")]
+ super::apply_relay_mesh_env(&mut env, effective_provider, effective_model);
+
EffectiveAgentEnv {
env,
config_file_path: runtime.and_then(|r| r.config_file_path),
diff --git a/desktop/src-tauri/src/managed_agents/relay_mesh.rs b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
index 403a2e9bdc..f5544fa111 100644
--- a/desktop/src-tauri/src/managed_agents/relay_mesh.rs
+++ b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
@@ -12,14 +12,13 @@ pub const RELAY_MESH_AUTO_MODEL_ID: &str = "auto";
#[cfg(feature = "mesh-llm")]
pub fn apply_relay_mesh_env(
env: &mut std::collections::BTreeMap,
- record: &ManagedAgentRecord,
+ provider: Option<&str>,
+ model: Option<&str>,
) {
- if record.provider.as_deref() != Some(RELAY_MESH_PROVIDER_ID) {
+ if provider.map(str::trim) != Some(RELAY_MESH_PROVIDER_ID) {
return;
}
- let model = record
- .model
- .as_deref()
+ let model = model
.map(str::trim)
.filter(|value| !value.is_empty())
.unwrap_or(RELAY_MESH_AUTO_MODEL_ID)
@@ -193,7 +192,7 @@ mod tests {
rec.model = Some(RELAY_MESH_AUTO_MODEL_ID.to_string());
let mut env = BTreeMap::new();
- apply_relay_mesh_env(&mut env, &rec);
+ apply_relay_mesh_env(&mut env, rec.provider.as_deref(), rec.model.as_deref());
assert_eq!(
env.get("BUZZ_AGENT_MAX_OUTPUT_TOKENS").map(String::as_str),
diff --git a/desktop/src-tauri/src/managed_agents/runtime.rs b/desktop/src-tauri/src/managed_agents/runtime.rs
index 7502807906..8b4884d97d 100644
--- a/desktop/src-tauri/src/managed_agents/runtime.rs
+++ b/desktop/src-tauri/src/managed_agents/runtime.rs
@@ -1844,9 +1844,9 @@ pub fn spawn_agent_child(
// Buzz shared compute is stored as a native provider; derive the OpenAI-compatible
// transport at spawn time and scrub any unrelated ambient OpenAI key.
#[cfg(feature = "mesh-llm")]
- if record.provider.as_deref() == Some(super::RELAY_MESH_PROVIDER_ID) {
+ if effective_provider == Some(super::RELAY_MESH_PROVIDER_ID) {
let mut mesh_env = std::collections::BTreeMap::new();
- super::apply_relay_mesh_env(&mut mesh_env, record);
+ super::apply_relay_mesh_env(&mut mesh_env, effective_provider, effective_model);
command.env_remove("OPENAI_API_KEY");
for (key, value) in mesh_env {
command.env(key, value);
diff --git a/desktop/src/features/mesh-compute/classifyModelRef.test.mjs b/desktop/src/features/mesh-compute/classifyModelRef.test.mjs
index aa7c2165e4..9876678c8a 100644
--- a/desktop/src/features/mesh-compute/classifyModelRef.test.mjs
+++ b/desktop/src/features/mesh-compute/classifyModelRef.test.mjs
@@ -1,7 +1,7 @@
import assert from "node:assert/strict";
import test from "node:test";
-import { classifyModelRef, modelRefHintLabel } from "./classifyModelRef.ts";
+import { classifyModelRef } from "./classifyModelRef.ts";
test("empty string → unknown", () => {
assert.deepEqual(classifyModelRef(""), { kind: "unknown" });
@@ -57,19 +57,3 @@ test("trims whitespace before classifying", () => {
name: "Qwen3-8B-Q4_K_M",
});
});
-
-test("hint labels are user-facing strings", () => {
- assert.equal(
- modelRefHintLabel({ kind: "catalog", name: "x" }),
- "Looks like a catalog name",
- );
- assert.equal(
- modelRefHintLabel({ kind: "huggingface", ref: "hf://x" }),
- "HuggingFace ref",
- );
- assert.equal(
- modelRefHintLabel({ kind: "local-path", path: "/x" }),
- "Local file",
- );
- assert.equal(modelRefHintLabel({ kind: "unknown" }), null);
-});
diff --git a/desktop/src/features/mesh-compute/classifyModelRef.ts b/desktop/src/features/mesh-compute/classifyModelRef.ts
index d01b63bfae..666c56b309 100644
--- a/desktop/src/features/mesh-compute/classifyModelRef.ts
+++ b/desktop/src/features/mesh-compute/classifyModelRef.ts
@@ -1,7 +1,6 @@
/**
* Classification of a free-text model ref entered into the serve card.
- * UI shows a hint inline ("Looks like a catalog name") for trust feedback.
- * Mirrors mesh's own resolve logic at `runtime/mod.rs:3390`.
+ * Mirrors mesh's own resolution categories for input validation.
*/
export type ModelRefKind =
| { kind: "catalog"; name: string }
@@ -18,9 +17,8 @@ export type ModelRefKind =
*
* Source: mesh runtime/mod.rs:3390 ("local file, catalog name, or HuggingFace URL").
*
- * This is presentational only — the canonical resolution still happens server-
- * side via `mesh_start_node`. UI uses this for the "Looks like a …" hint that
- * makes the free-text field feel honest instead of opaque.
+ * This is validation-only — canonical resolution happens server-side via
+ * `mesh_start_node`.
*/
export function classifyModelRef(raw: string): ModelRefKind {
const trimmed = raw.trim();
@@ -43,17 +41,3 @@ export function classifyModelRef(raw: string): ModelRefKind {
}
return { kind: "catalog", name: trimmed };
}
-
-/** Short label for the inline hint, e.g. "Looks like a catalog name". */
-export function modelRefHintLabel(kind: ModelRefKind): string | null {
- switch (kind.kind) {
- case "catalog":
- return "Looks like a catalog name";
- case "huggingface":
- return "HuggingFace ref";
- case "local-path":
- return "Local file";
- case "unknown":
- return null;
- }
-}
diff --git a/desktop/src/features/mesh-compute/ui/MeshComputeSettingsCard.tsx b/desktop/src/features/mesh-compute/ui/MeshComputeSettingsCard.tsx
index 46cc387c22..8bbd0ef00b 100644
--- a/desktop/src/features/mesh-compute/ui/MeshComputeSettingsCard.tsx
+++ b/desktop/src/features/mesh-compute/ui/MeshComputeSettingsCard.tsx
@@ -22,7 +22,7 @@ import {
SettingsOptionRow,
} from "@/features/settings/ui/SettingsOptionGroup";
import { SettingsSectionHeader } from "@/features/settings/ui/SettingsSectionHeader";
-import { classifyModelRef, modelRefHintLabel } from "../classifyModelRef";
+import { classifyModelRef } from "../classifyModelRef";
import {
downloadPercent,
formatDownloadBytes,
@@ -57,13 +57,8 @@ function writeDraft(key: string, value: string): void {
* Settings → Compute → Share compute.
*
* One toggle, one model field, an "Already installed" picklist, an Advanced
- * group. Honest copy throughout — no kind:30621, no "endpoint id", no raw
- * mesh knobs.
- *
- * The architectural-trust footer is load-bearing: it tells a privacy-aware
- * user that *not publishing* is enforced by the build, not by a default they
- * have to verify. (Source of the invariants this copy claims: Max's no-leak
- * builder defaults — publish=false, no Nostr relays, no auto-discovery.)
+ * group. User-facing copy describes the shared-compute behavior without
+ * exposing implementation protocols or raw mesh controls.
*/
export function MeshComputeSettingsCard() {
const { status, error, refresh } = useMeshNodeStatus();
@@ -138,7 +133,6 @@ export function MeshComputeSettingsCard() {
const isOn = status?.state === "running" || status?.state === "starting";
const controlsDisabled = isOn || actionInFlight;
const refClass = classifyModelRef(modelInput);
- const refHint = modelRefHintLabel(refClass);
const canStart =
refClass.kind !== "unknown" &&
!actionInFlight &&
@@ -240,18 +234,10 @@ export function MeshComputeSettingsCard() {
placeholder="Qwen3-8B-Q4_K_M or hf://meshllm/qwen3-8b@main"
value={modelInput}
/>
- {refHint ? (
-
- {refHint}. If it is not installed, Buzz downloads it when
- sharing starts.
-
- ) : (
-
- Choose a suggested model below, or enter a catalog name,
- HuggingFace ref, or local file. Buzz downloads remote models
- when sharing starts.
-
- )}
+
+ Choose a suggested model below, or enter a model reference or
+ local file. Buzz downloads remote models when sharing starts.
+
{catalog && catalog.entries.length > 0 ? (
- Buzz will not publish your machine to public Nostr relays, auto-discover
- other networks, or share your endpoint outside this relay's members.
- Only members of this relay can dial in.
+ Only members of this relay can use this machine's shared compute.
);
diff --git a/desktop/tests/e2e/mesh-compute.spec.ts b/desktop/tests/e2e/mesh-compute.spec.ts
index 85302a68b0..c33a53e340 100644
--- a/desktop/tests/e2e/mesh-compute.spec.ts
+++ b/desktop/tests/e2e/mesh-compute.spec.ts
@@ -23,13 +23,13 @@ test("Share compute has a clear empty state and starts and stops sharing", async
await expect(card).toContainText("Not sharing right now");
await expect(card).toContainText(
- "Choose a suggested model below, or enter a catalog name",
+ "Choose a suggested model below, or enter a model reference or local file",
);
await expect(toggle).toBeDisabled();
await model.fill("hf://demo/SmolLM2-135M-Instruct-GGUF:Q4_K_M");
await expect(card).toContainText(
- "If it is not installed, Buzz downloads it when sharing starts",
+ "Buzz downloads remote models when sharing starts",
);
await expect(toggle).toBeEnabled();
From 34dda02d58a6ef92dddb6ee1ebd02c3cb8d995a1 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 11:47:57 +1000
Subject: [PATCH 10/35] fix(mesh): repair tests after main rebase
---
.../src/managed_agents/discovery/tests.rs | 21 +++++++++++++++++--
.../src/managed_agents/global_config/tests.rs | 2 +-
.../src-tauri/src/managed_agents/readiness.rs | 5 +++--
.../src/managed_agents/relay_mesh.rs | 1 -
4 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/desktop/src-tauri/src/managed_agents/discovery/tests.rs b/desktop/src-tauri/src/managed_agents/discovery/tests.rs
index b8e5e20b58..86c602be47 100644
--- a/desktop/src-tauri/src/managed_agents/discovery/tests.rs
+++ b/desktop/src-tauri/src/managed_agents/discovery/tests.rs
@@ -4,8 +4,7 @@ use super::overrides::{divergent_agent_command_override, update_time_agent_comma
use super::{
apply_agent_command_update, classify_runtime, codex_adapter_availability,
codex_adapter_is_outdated, command_search_dirs, create_time_agent_command_override,
- default_agent_command,
- effective_agent_command, find_nvm_default_bin, find_via_login_shell,
+ default_agent_command, effective_agent_command, find_nvm_default_bin, find_via_login_shell,
is_login_shell_path_uninit, is_safe_nvm_tag, managed_agent_avatar_url, normalize_agent_args,
parse_semver_tag, probe_codex_acp_major_version, record_agent_command,
refresh_login_shell_path, BUZZ_AGENT_AVATAR_URL, CLAUDE_CODE_AVATAR_URL, CODEX_AVATAR_URL,
@@ -45,6 +44,24 @@ fn returns_none_for_unknown_commands() {
assert!(managed_agent_avatar_url("custom-agent").is_none());
}
+#[test]
+fn command_search_prefers_current_build_profile() {
+ let dirs = command_search_dirs();
+ let debug_index = dirs
+ .iter()
+ .position(|path| path.ends_with("target/debug"))
+ .expect("debug search directory");
+ let release_index = dirs
+ .iter()
+ .position(|path| path.ends_with("target/release"))
+ .expect("release search directory");
+ if cfg!(debug_assertions) {
+ assert!(debug_index < release_index);
+ } else {
+ assert!(release_index < debug_index);
+ }
+}
+
#[test]
fn default_agent_command_resolves_bundled_buzz_agent() {
// The create-path default must be the bundled buzz-agent, never the
diff --git a/desktop/src-tauri/src/managed_agents/global_config/tests.rs b/desktop/src-tauri/src/managed_agents/global_config/tests.rs
index 41d6a6de46..a48061b443 100644
--- a/desktop/src-tauri/src/managed_agents/global_config/tests.rs
+++ b/desktop/src-tauri/src/managed_agents/global_config/tests.rs
@@ -473,7 +473,7 @@ fn resolve_global_fallback_when_record_and_persona_have_none() {
#[test]
fn inherited_shared_compute_translates_to_supported_agent_transport() {
let record = bare_record();
- let personas: Vec = vec![];
+ let personas: Vec = vec![];
let global = GlobalAgentConfig {
model: Some("auto".to_string()),
provider: Some(super::super::RELAY_MESH_PROVIDER_ID.to_string()),
diff --git a/desktop/src-tauri/src/managed_agents/readiness.rs b/desktop/src-tauri/src/managed_agents/readiness.rs
index 4fe447dce9..2bcdf95773 100644
--- a/desktop/src-tauri/src/managed_agents/readiness.rs
+++ b/desktop/src-tauri/src/managed_agents/readiness.rs
@@ -38,8 +38,8 @@
//! it at startup. We do not evaluate it here; it is exposed for future
//! UI display only.
-use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
+use std::collections::BTreeMap;
use crate::managed_agents::{
agent_env::baked_build_env,
@@ -1021,7 +1021,8 @@ mod tests {
// → CliLogin{Available} (tooling installed, needs login).
let exe = present_binary_str();
let rt = make_cli_runtime(static_commands(vec![exe]), Some(exe));
- let reqs = cli_login::requirements(&[exe, "--buzz-probe-fail-xyz"], "run `tool login`", &rt);
+ let reqs =
+ cli_login::requirements(&[exe, "--buzz-probe-fail-xyz"], "run `tool login`", &rt);
assert!(
!reqs.is_empty(),
"non-zero probe must produce a CliLogin requirement (logged out)"
diff --git a/desktop/src-tauri/src/managed_agents/relay_mesh.rs b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
index f5544fa111..51d99815db 100644
--- a/desktop/src-tauri/src/managed_agents/relay_mesh.rs
+++ b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
@@ -160,7 +160,6 @@ mod tests {
source_team_persona_slug: None,
definition_respond_to: None,
definition_respond_to_allowlist: Vec::new(),
- definition_mcp_toolsets: None,
definition_parallelism: None,
relay_mesh: None,
}
From 393c7a47f4e486ec80b8a7b851024a36ea2d5ade Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 11:55:44 +1000
Subject: [PATCH 11/35] refactor(mesh): use native iroh transport with client
discovery
---
.../buzz-relay/src/mesh_status_publisher.rs | 33 -
desktop/src-tauri/src/commands/mesh_llm.rs | 123 +---
desktop/src-tauri/src/mesh_llm/coordinator.rs | 591 ++----------------
desktop/src-tauri/src/mesh_llm/discovery.rs | 15 +-
desktop/src-tauri/src/mesh_llm/mod.rs | 10 +-
desktop/src-tauri/src/mesh_llm/mod_tests.rs | 43 +-
6 files changed, 111 insertions(+), 704 deletions(-)
diff --git a/crates/buzz-relay/src/mesh_status_publisher.rs b/crates/buzz-relay/src/mesh_status_publisher.rs
index e6364d3f9d..4285e72211 100644
--- a/crates/buzz-relay/src/mesh_status_publisher.rs
+++ b/crates/buzz-relay/src/mesh_status_publisher.rs
@@ -53,12 +53,6 @@ pub struct BuzzMeshStatus {
/// Mesh identity, if mesh-llm has joined/created one.
#[serde(skip_serializing_if = "Option::is_none")]
pub mesh_id: Option,
- /// Reporter's mesh owner id (mesh-llm owner keypair identity). Serve
- /// nodes build their admission allowlist from the member owner ids in
- /// these notes, so a member's node is only dialable/joinable by nodes
- /// whose owner id appears in a relay-signed status note.
- #[serde(skip_serializing_if = "Option::is_none")]
- pub owner_id: Option,
/// Human mesh name, if configured.
#[serde(skip_serializing_if = "Option::is_none")]
pub mesh_name: Option,
@@ -115,7 +109,6 @@ pub fn sanitize_mesh_status(payload: &Value, now_unix: u64) -> BuzzMeshStatus {
let node_id = string_field(payload, "node_id");
let mesh_id = string_field(payload, "mesh_id");
let mesh_name = string_field(payload, "mesh_name");
- let owner_id = string_field(payload, "ownerId").or_else(|| string_field(payload, "owner_id"));
let my_vram_gb = payload.get("my_vram_gb").and_then(Value::as_f64);
let mut models = Vec::::new();
@@ -189,7 +182,6 @@ pub fn sanitize_mesh_status(payload: &Value, now_unix: u64) -> BuzzMeshStatus {
status_type: MESH_STATUS_TYPE.to_string(),
updated_at: now_unix,
mesh_id,
- owner_id,
mesh_name,
serve_targets,
models,
@@ -365,31 +357,6 @@ mod tests {
assert!(!serialized.contains("/secret"));
}
- #[test]
- fn sanitizer_carries_owner_id_for_admission_roster() {
- let payload = serde_json::json!({
- "token": "endpoint-token-a",
- "ownerId": "owner-abc123",
- "hosted_models": ["Qwen3-8B-Q4_K_M"],
- "peers": []
- });
- let status = sanitize_mesh_status(&payload, 123);
- assert_eq!(status.owner_id.as_deref(), Some("owner-abc123"));
-
- // snake_case variant also accepted; absent stays None (and is omitted
- // from the serialized note).
- let snake = serde_json::json!({ "token": "t", "owner_id": "owner-x", "peers": [] });
- assert_eq!(
- sanitize_mesh_status(&snake, 1).owner_id.as_deref(),
- Some("owner-x")
- );
- let none = serde_json::json!({ "token": "t", "peers": [] });
- let status = sanitize_mesh_status(&none, 1);
- assert_eq!(status.owner_id, None);
- let serialized = serde_json::to_string(&status).unwrap();
- assert!(!serialized.contains("ownerId"));
- }
-
#[test]
fn sanitizer_keeps_model_id_separate_from_label() {
let payload = serde_json::json!({
diff --git a/desktop/src-tauri/src/commands/mesh_llm.rs b/desktop/src-tauri/src/commands/mesh_llm.rs
index beb32eefe2..d7013c2d58 100644
--- a/desktop/src-tauri/src/commands/mesh_llm.rs
+++ b/desktop/src-tauri/src/commands/mesh_llm.rs
@@ -47,21 +47,21 @@ const RELAY_MESH_RUNTIME_NO_TARGET: &str =
pub type CmdResult = Result;
-/// Resolve the admission roster by intersecting relay-signed mesh status
+/// Resolve the admission roster by intersecting member-signed mesh status
/// reporters with the current NIP-43 direct-member list. Relays that publish no
/// membership list retain status-only backcompat. Returns `None` when the
/// combined query fails, so a transient outage does not lock out a working
/// mesh.
-pub(crate) async fn resolve_trusted_owner_ids(state: &AppState) -> Option> {
+pub(crate) async fn resolve_trusted_owner_ids(state: &AppState) -> Vec {
let filters = [
mesh_llm::mesh_status_filter(),
mesh_llm::relay_membership_filter(),
];
match relay::query_relay(state, &filters).await {
- Ok(events) => Some(mesh_llm::owner_ids_from_events(&events)),
+ Ok(events) => mesh_llm::owner_ids_from_events(&events),
Err(error) => {
- eprintln!("buzz-mesh: roster query failed; starting without allowlist: {error}");
- None
+ eprintln!("buzz-mesh: roster query failed; allowing only this node: {error}");
+ Vec::new()
}
}
}
@@ -82,7 +82,7 @@ pub(crate) async fn restore_mesh_sharing(app: &AppHandle, state: &AppState) -> C
model_id: Some(config.model_id),
max_vram_gb: config.max_vram_gb,
join_token: None,
- trusted_owner_ids: resolve_trusted_owner_ids(state).await,
+ trusted_owner_ids: Some(resolve_trusted_owner_ids(state).await),
};
let started = mesh_llm::DesktopMeshRuntime::start(request)
.await
@@ -112,7 +112,7 @@ pub async fn mesh_start_node(
// Frontend requests never carry a roster; resolve it here so every
// UI-started node enforces the member allowlist.
if request.trusted_owner_ids.is_none() {
- request.trusted_owner_ids = resolve_trusted_owner_ids(&state).await;
+ request.trusted_owner_ids = Some(resolve_trusted_owner_ids(&state).await);
}
let mut runtime = state.mesh_llm_runtime.lock().await;
if runtime.is_some() {
@@ -153,20 +153,6 @@ pub async fn mesh_ensure_client_node(
ensure_client_node_for_model(&state, request.model_id, request.endpoint_addr).await
}
-fn normalize_pubkey(value: Option<&str>) -> Option {
- let normalized = value?.trim().to_ascii_lowercase();
- if normalized.len() == 64 && normalized.chars().all(|c| c.is_ascii_hexdigit()) {
- Some(normalized)
- } else {
- None
- }
-}
-
-fn workspace_pubkey(state: &AppState) -> Result {
- let keys = state.keys.lock().map_err(|e| e.to_string())?;
- Ok(keys.public_key().to_hex())
-}
-
/// Mesh can bind its HTTP ingress and advertise a model shortly before the
/// router has installed a usable target. Probe the exact chat path agents use
/// so startup cannot race that gap (`single target None unavailable`).
@@ -208,54 +194,6 @@ async fn wait_for_mesh_inference(model_id: &str) -> CmdResult<()> {
))
}
-/// Join a peer by endpoint addr without naming a model. Used by the runtime
-/// coordinator's call-me-now responder and the initiator's same-attempt dial:
-/// the responder side of a hole-punch just needs both ends dialing, and the
-/// mesh-llm router resolves per-model routability per request afterward.
-///
-/// Dials into the running runtime if one exists; otherwise starts a client
-/// node with the addr as its join token. Model-agnostic on purpose.
-pub(crate) async fn ensure_client_node_for_model_dial_only(
- state: &AppState,
- endpoint_addr: &str,
-) -> CmdResult<()> {
- let addr = endpoint_addr.trim();
- if addr.is_empty() {
- return Err("endpoint_addr is required to dial".to_string());
- }
- {
- let runtime = state.mesh_llm_runtime.lock().await;
- if let Some(runtime) = runtime.as_ref() {
- return runtime
- .dial_endpoint_addr(addr)
- .await
- .map_err(|error| format!("mesh dial failed: {error}"));
- }
- }
- let start = mesh_llm::StartMeshNodeRequest {
- mode: mesh_llm::MeshNodeMode::Client,
- model_id: None,
- max_vram_gb: None,
- join_token: Some(addr.to_string()),
- trusted_owner_ids: resolve_trusted_owner_ids(state).await,
- };
- let mut runtime = state.mesh_llm_runtime.lock().await;
- if runtime.is_some() {
- // Lost a race; dial into the now-present runtime instead.
- if let Some(runtime) = runtime.as_ref() {
- return runtime
- .dial_endpoint_addr(addr)
- .await
- .map_err(|error| format!("mesh dial failed: {error}"));
- }
- }
- let started = mesh_llm::DesktopMeshRuntime::start(start)
- .await
- .map_err(|error| format!("mesh client failed to start: {error}"))?;
- *runtime = Some(started);
- Ok(())
-}
-
pub(crate) async fn ensure_client_node_for_model(
state: &AppState,
model_id: impl AsRef,
@@ -313,7 +251,7 @@ pub(crate) async fn ensure_client_node_for_model(
model_id: None,
max_vram_gb: None,
join_token: Some(join_token),
- trusted_owner_ids: resolve_trusted_owner_ids(state).await,
+ trusted_owner_ids: Some(resolve_trusted_owner_ids(state).await),
};
let mut runtime = state.mesh_llm_runtime.lock().await;
if runtime.is_some() {
@@ -333,7 +271,7 @@ pub(crate) async fn ensure_client_node_for_model(
/// Re-resolve a live serve target's dial pointer for a saved relay-mesh agent.
///
/// The serve target's `endpoint_addr` is live discovery state — it comes from
-/// the peer's replaceable kind:30621 status event and rotates when the peer's
+/// the peer's client-signed mesh status event and rotates when the peer's
/// iroh endpoint changes — so it is never persisted onto the agent record.
/// Instead, a saved agent re-resolves a current bootstrap target at start time
/// by matching its configured model against the targets the relay is gossiping
@@ -388,12 +326,10 @@ fn pick_serve_target_for_model(
///
/// Every start follows the same backend-owned path. If a local runtime exists,
/// wait until its inference router is actually ready. Otherwise re-resolve a
-/// current bootstrap target from the relay's gossiped targets,
-/// bring up the local client node, then publish a paired connect-request
-/// (kind:24621) through the runtime coordinator so the peer dials back — the
-/// hole-punch needs *both* ends dialing. This is the fix for saved agents
-/// flaking on restart: before, saved-start did a one-sided dial and never told
-/// the peer to dial back. The two failure modes get distinct, actionable copy:
+/// current bootstrap target from the members' client-signed discovery notes,
+/// then bring up the local MeshLLM client. The endpoint contains MeshLLM's
+/// encrypted iroh relay addresses, so no Buzz relay connection coordination is
+/// required. The two failure modes get distinct, actionable copy:
/// a relay query failure ("could not refresh targets") is not the same as a
/// relay that answered with no live target for this model ("peer offline").
/// Non relay-mesh records are a no-op.
@@ -427,38 +363,7 @@ pub(crate) async fn ensure_relay_mesh_for_record(
}
};
- // Bring up the local client node (and dial the peer). Its status carries
- // our own invite token — the addr we advertise to the peer in the 24621.
- let status =
- ensure_client_node_for_model(&state, &model_id, Some(target.endpoint_addr.clone())).await?;
-
- // Publish the paired connect-request so the peer dials *us* back. Needs the
- // target's reporter pubkey (whom to address) and our invite token (where to
- // dial). If either is missing we have already done the one-sided dial above
- // — no worse than the old behavior — so degrade rather than fail the start.
- if let (Some(target_pubkey), Some(self_addr)) = (
- normalize_pubkey(target.reporter_pubkey.as_deref()),
- status.invite_token.as_deref(),
- ) {
- if target_pubkey != workspace_pubkey(&state)? {
- if let Err(error) = crate::mesh_llm::start_client(
- app,
- crate::mesh_llm::RelayMeshConnectRequest {
- target_pubkey: &target_pubkey,
- peer_endpoint_addr: &target.endpoint_addr,
- self_endpoint_addr: self_addr,
- peer_endpoint_id: target.endpoint_id.as_deref(),
- self_endpoint_id: status.endpoint_id.as_deref(),
- },
- )
- .await
- {
- // Non-fatal: the one-sided dial may still punch on a favorable NAT.
- // Surface the reason without blocking the agent's spawn.
- eprintln!("buzz-mesh: saved-start connect-request failed: {error}");
- }
- }
- }
+ ensure_client_node_for_model(&state, &model_id, Some(target.endpoint_addr)).await?;
wait_for_mesh_inference(&model_id).await
}
diff --git a/desktop/src-tauri/src/mesh_llm/coordinator.rs b/desktop/src-tauri/src/mesh_llm/coordinator.rs
index 4b36468373..d76a7318af 100644
--- a/desktop/src-tauri/src/mesh_llm/coordinator.rs
+++ b/desktop/src-tauri/src/mesh_llm/coordinator.rs
@@ -1,166 +1,72 @@
-//! Rust-owned relay-mesh coordinator.
+//! Runtime-owned shared-compute coordinator.
//!
-//! Owns the control plane that used to live in React (`useMeshRelayOrchestrator`)
-//! and the TS start helper (`startRelayMeshClientForTarget`). One runtime-owned
-//! actor, started when the desktop's relay identity is set — independent of any
-//! UI mount or mesh activity. This is what kills the cold-launch race: the
-//! call-me-now listener's lifetime is tied to the runtime, not to a renderer
-//! mounting with a pubkey.
-//!
-//! Two responsibilities:
-//! 1. `spawn_listener` — a long-lived task that holds an authenticated WS to
-//! Buzz's relay (generalizing the proven `commands::pairing` NIP-42
-//! machinery), subscribes `kind:24622 #p=self`, and dials each paired
-//! call-me-now back into the local mesh runtime. Idempotent: one listener
-//! per process; re-entrant calls return the live handle.
-//! 2. `start_client` — publishes a `kind:24621` connect-request with a fresh
-//! attempt id and drives bounded publish+dial retry inside the relay's 60s
-//! call-me-now TTL. Both fresh-create and saved/restore start paths route
-//! through here, so there is no behavioral fork.
-//!
-//! `start_client` blocks on `listener_active` being `true` before publishing,
-//! so a 24621 can never be emitted before this desktop is able to receive its
-//! own paired 24622. The race is closed by construction, not convention.
+//! Buzz publishes a client-signed, replaceable discovery note containing the
+//! member's MeshLLM owner identity and current iroh endpoint. MeshLLM itself
+//! performs transport (direct QUIC or its encrypted iroh relays) and admission.
+//! The Buzz relay is only a generic Nostr store for membership and discovery;
+//! it does not coordinate connections or require mesh-specific handlers.
use std::time::Duration;
-use futures_util::{SinkExt, StreamExt};
-use nostr::JsonUtil;
-use serde_json::json;
+use nostr::Tag;
use tauri::{AppHandle, Manager};
-use tokio::sync::watch;
-use tokio_tungstenite::{connect_async, tungstenite::Message};
-
-use buzz_core_pkg::kind::{
- KIND_MESH_CALL_ME_NOW, KIND_MESH_CONNECT_REQUEST, KIND_MESH_STATUS_REPORT,
-};
use crate::app_state::AppState;
-/// Relay's call-me-now TTL. Retry deadline lives inside this window: once the
-/// paired 24622 expires, re-dialing the same attempt is pointless.
-const CALL_ME_NOW_TTL: Duration = Duration::from_secs(60);
-/// Backoff between connect-request attempts. Hole-punch is lossy; a single
-/// publish is flaky by construction even when both ends are correct.
-const RETRY_BACKOFF: Duration = Duration::from_secs(5);
-
-/// Cadence for the roster watcher. Membership changes are rare; a slow poll
-/// keeps relay load negligible while bounding how long an ex-member's owner
-/// id stays admitted (one poll interval + node restart).
+/// Client-owned parameterized-replaceable discovery note. Intentionally local
+/// to the desktop: relays handle it as an ordinary NIP-33 event.
+pub const KIND_BUZZ_MESH_MEMBER_STATUS: u16 = 30_321;
+const STATUS_D_TAG: &str = "buzz-mesh-member-status";
const ROSTER_POLL_INTERVAL: Duration = Duration::from_secs(60);
+const STATUS_PUBLISH_INTERVAL: Duration = Duration::from_secs(15);
-/// Handle to the runtime-owned mesh control plane. Stored on [`AppState`].
pub struct MeshCoordinator {
- /// `true` once the call-me-now listener holds a live, authenticated
- /// subscription. `start_client` awaits this before publishing a 24621.
- /// Observable so guardrail tests can assert listener-before-publish
- /// without depending on wall-clock timing.
- listener_active: watch::Receiver,
- _listener: tokio::task::JoinHandle<()>,
_status_publisher: tokio::task::JoinHandle<()>,
_roster_watcher: tokio::task::JoinHandle<()>,
}
-impl MeshCoordinator {
- /// Whether the call-me-now listener is currently live. Exposed for
- /// instrumentation and tests.
- pub fn listener_active(&self) -> bool {
- *self.listener_active.borrow()
- }
-
- /// Await the listener becoming active, bounded by `timeout`. Returns
- /// `Err` if it does not come up in time (relay unreachable / auth failed),
- /// so `start_client` fails loudly rather than publishing into the void.
- async fn await_listener(&self, timeout: Duration) -> Result<(), String> {
- if self.listener_active() {
- return Ok(());
- }
- let mut rx = self.listener_active.clone();
- tokio::time::timeout(timeout, async {
- while !*rx.borrow() {
- if rx.changed().await.is_err() {
- return Err("mesh listener task ended before becoming active".to_string());
- }
- }
- Ok(())
- })
- .await
- .map_err(|_| "timed out waiting for mesh call-me-now listener to come up".to_string())?
- }
-}
-
-/// Start the runtime-owned relay-mesh coordinator if it is not already running.
-/// Idempotent: a second call with a coordinator already present is a no-op.
-///
-/// Known limitation: the listener subscribes with the identity active at spawn
-/// time and is never restarted. If the workspace identity changes mid-session
-/// the subscription keeps filtering on the old pubkey; an app restart picks up
-/// the new one. Acceptable for now — identity changes are rare and already
-/// disruptive — but revisit if identity switching becomes a first-class flow.
-///
-/// Spawned at identity-set time from `lib.rs` setup, *before* any restore or
-/// create attempt can enqueue a connect-request. Holds the `AppHandle` and
-/// fetches `AppState` per session (the codebase manages `AppState` by value;
-/// long-lived tasks never hold an `Arc` across awaits).
+/// Start the runtime-owned status publisher and admission-roster watcher.
+/// Kept under the historical name to avoid a broad startup API churn.
pub async fn spawn_listener(app: AppHandle) {
{
let state = app.state::();
- let guard = state.mesh_coordinator.lock().await;
- if guard.is_some() {
+ if state.mesh_coordinator.lock().await.is_some() {
return;
}
}
- let (active_tx, active_rx) = watch::channel(false);
- let listener_app = app.clone();
- let listener = tokio::spawn(async move {
- listener_loop(listener_app, active_tx).await;
- });
+
let publisher_app = app.clone();
- let publisher = tokio::spawn(async move {
- status_publisher_loop(publisher_app).await;
+ let status_publisher = tokio::spawn(async move {
+ loop {
+ publish_current_status_once(&publisher_app, "periodic").await;
+ tokio::time::sleep(STATUS_PUBLISH_INTERVAL).await;
+ }
});
let roster_app = app.clone();
let roster_watcher = tokio::spawn(async move {
- roster_watcher_loop(roster_app).await;
+ loop {
+ tokio::time::sleep(ROSTER_POLL_INTERVAL).await;
+ let state = roster_app.state::();
+ if let Err(error) = reconcile_roster(&state).await {
+ eprintln!("buzz-mesh: roster reconcile failed: {error}");
+ }
+ }
});
+
let state = app.state::();
let mut guard = state.mesh_coordinator.lock().await;
if guard.is_none() {
*guard = Some(MeshCoordinator {
- listener_active: active_rx,
- _listener: listener,
- _status_publisher: publisher,
+ _status_publisher: status_publisher,
_roster_watcher: roster_watcher,
});
} else {
- // Lost a race: another caller installed a coordinator first. Drop ours.
- listener.abort();
- publisher.abort();
+ status_publisher.abort();
roster_watcher.abort();
}
}
-/// Watch the member roster and restart the mesh node when it drifts.
-///
-/// The SDK's trust store is fixed at node start, so an allowlist change
-/// (member joined or left the Buzz server) only takes effect through a node
-/// restart. The watcher polls the relay-signed status notes, compares the
-/// owner-id roster against the one the running node was started with, and on
-/// drift restarts the node with the fresh roster (same mode/model/limits).
-/// Nodes running without a roster (`trusted_owner_ids: None`) are left alone.
-async fn roster_watcher_loop(app: AppHandle) {
- loop {
- tokio::time::sleep(ROSTER_POLL_INTERVAL).await;
- let state = app.state::();
- if let Err(error) = reconcile_roster(&state).await {
- eprintln!("buzz-mesh: roster reconcile failed: {error}");
- }
- }
-}
-
async fn reconcile_roster(state: &AppState) -> Result<(), String> {
- // Snapshot the running node's request without holding the lock across
- // the relay query.
let current_request = {
let runtime = state.mesh_llm_runtime.lock().await;
match runtime.as_ref() {
@@ -168,64 +74,31 @@ async fn reconcile_roster(state: &AppState) -> Result<(), String> {
None => return Ok(()),
}
};
- // Only enforce drift on nodes that were started with a roster.
- if current_request.trusted_owner_ids.is_none() {
+ let Some(current_owners) = current_request.trusted_owner_ids.as_ref() else {
return Ok(());
- }
-
- let fresh = match crate::commands::mesh_llm::resolve_trusted_owner_ids(state).await {
- Some(ids) => ids,
- // Relay unreachable: keep the node as-is rather than churning it
- // during an outage.
- None => return Ok(()),
};
- if Some(&fresh) == current_request.trusted_owner_ids.as_ref() {
+ let fresh = crate::commands::mesh_llm::resolve_trusted_owner_ids(state).await;
+ if &fresh == current_owners {
return Ok(());
}
- // Roster drifted: restart the node with the fresh roster. Take the
- // runtime out under the lock, stop it, start the replacement, put it
- // back. A concurrent stop/start while we're mid-restart loses the node
- // it installed — acceptable: both paths converge on the fresh roster at
- // the next poll.
let mut request = current_request;
request.trusted_owner_ids = Some(fresh);
let mut guard = state.mesh_llm_runtime.lock().await;
let Some(running) = guard.take() else {
return Ok(());
};
- // Re-check under the lock: the node may have been swapped while we
- // queried. Restart only if the node we now hold still differs from the
- // fresh roster (a replacement started with the fresh roster passes
- // through untouched).
- if running.start_request().trusted_owner_ids != request.trusted_owner_ids {
- eprintln!(
- "buzz-mesh: membership roster changed; restarting mesh node with fresh allowlist"
- );
- if let Err(error) = running.stop().await {
- eprintln!("buzz-mesh: stopping mesh node for roster restart failed: {error}");
- }
- match crate::mesh_llm::DesktopMeshRuntime::start(request).await {
- Ok(replacement) => *guard = Some(replacement),
- Err(error) => {
- return Err(format!(
- "mesh node restart after roster change failed; node left stopped: {error}"
- ));
- }
- }
- } else {
- *guard = Some(running);
+ eprintln!("buzz-mesh: membership roster changed; restarting mesh node with fresh allowlist");
+ if let Err(error) = running.stop().await {
+ eprintln!("buzz-mesh: stopping mesh node for roster restart failed: {error}");
}
+ let replacement = crate::mesh_llm::DesktopMeshRuntime::start(request)
+ .await
+ .map_err(|error| format!("mesh node restart after roster change failed: {error}"))?;
+ *guard = Some(replacement);
Ok(())
}
-async fn status_publisher_loop(app: AppHandle) {
- loop {
- publish_current_status_once(&app, "periodic").await;
- tokio::time::sleep(Duration::from_secs(15)).await;
- }
-}
-
pub(crate) async fn publish_current_status_once(app: &AppHandle, reason: &str) {
let state = app.state::();
if let Err(error) = publish_current_status_for_state(&state).await {
@@ -267,394 +140,62 @@ async fn publish_stopped_status_for_state(state: &AppState) -> Result<(), String
fn stopped_status_payload(owner_id: &str) -> serde_json::Value {
serde_json::json!({
"ownerId": owner_id,
- "token": "",
- "hosted_models": [],
- "serving_models": [],
- "peers": [],
+ "serveTargets": [],
+ "models": [],
})
}
-/// The listener task body. Connects, authenticates as the Buzz identity,
-/// subscribes `24622 #p=self`, and dials each paired call-me-now. Reconnects
-/// with backoff on connection loss; flips `active` to `false` while down so
-/// `start_client` won't publish during an outage.
-async fn listener_loop(app: AppHandle, active: watch::Sender) {
- loop {
- if let Err(error) = listener_session(&app, &active).await {
- eprintln!("buzz-mesh: call-me-now listener session ended: {error}");
- }
- let _ = active.send(false);
- tokio::time::sleep(RETRY_BACKOFF).await;
- }
-}
-
-/// One authenticated listener session. Mirrors `commands::pairing`'s WS+NIP-42
-/// preamble, then runs a long-lived REQ on `24622 #p=self`.
-async fn listener_session(app: &AppHandle, active: &watch::Sender) -> Result<(), String> {
- let (relay_url, self_pk) = {
- let state = app.state::();
- let url = crate::relay::relay_ws_url_with_override(&state);
- let pk = {
- let keys = state.keys.lock().map_err(|e| e.to_string())?;
- keys.public_key().to_hex()
- };
- (url, pk)
- };
-
- let (ws, _) = connect_async(&relay_url)
- .await
- .map_err(|e| format!("mesh listener WS connect failed: {e}"))?;
- let (mut write, mut read) = ws.split();
-
- authenticate(app, &relay_url, &mut read, &mut write).await?;
-
- let sub = json!([
- "REQ", "mesh-call-me-now",
- { "kinds": [KIND_MESH_CALL_ME_NOW], "#p": [self_pk], "limit": 0 }
- ]);
- write
- .send(Message::Text(sub.to_string().into()))
- .await
- .map_err(|e| format!("mesh listener subscribe failed: {e}"))?;
-
- // Subscription accepted — we can now receive our own paired 24622. Signal
- // before processing events so `start_client` may proceed.
- let _ = active.send(true);
-
- while let Some(msg) = read.next().await {
- let msg = msg.map_err(|e| format!("mesh listener WS read error: {e}"))?;
- let Message::Text(text) = msg else { continue };
- let Some(event) = parse_relay_event(text.as_str(), "mesh-call-me-now") else {
- continue;
- };
- if let Some(addr) = call_me_now_peer_addr(&event) {
- // Dial the peer the relay paired us with. Errors are per-attempt;
- // the initiator's retry loop and the peer's own dial cover loss.
- let state = app.state::();
- if let Err(error) =
- crate::commands::ensure_client_node_for_model_dial_only(&state, &addr).await
- {
- eprintln!("buzz-mesh: call-me-now dial failed: {error}");
- }
- }
- }
- Ok(())
-}
-
-pub struct RelayMeshConnectRequest<'a> {
- pub target_pubkey: &'a str,
- pub peer_endpoint_addr: &'a str,
- pub self_endpoint_addr: &'a str,
- pub peer_endpoint_id: Option<&'a str>,
- pub self_endpoint_id: Option<&'a str>,
-}
-
-/// Publish a `kind:24621` connect-request and drive bounded publish+dial retry.
-/// Blocks until the listener is active so we never request a connection we
-/// cannot receive the pairing for. One `attempt_id` per call correlates the
-/// retries in logs and tests.
-pub async fn start_client(
- app: &AppHandle,
- request: RelayMeshConnectRequest<'_>,
-) -> Result {
- let attempt_id = uuid::Uuid::new_v4().to_string();
- {
- let state = app.state::();
- let guard = state.mesh_coordinator.lock().await;
- let coordinator = guard
- .as_ref()
- .ok_or("mesh coordinator not started; cannot request connection")?;
- coordinator.await_listener(Duration::from_secs(10)).await?;
- }
-
- let deadline = tokio::time::Instant::now() + CALL_ME_NOW_TTL;
- let mut last_error = String::new();
- while tokio::time::Instant::now() < deadline {
- let state = app.state::();
- match publish_connect_request(&state, &request, &attempt_id).await {
- Ok(()) => {
- // Dial in the same attempt: hole-punch needs both ends dialing.
- if let Err(error) = crate::commands::ensure_client_node_for_model_dial_only(
- &state,
- request.peer_endpoint_addr,
- )
- .await
- {
- last_error = format!("dial after connect-request failed: {error}");
- } else {
- return Ok(attempt_id);
- }
- }
- Err(error) => last_error = error,
- }
- tokio::time::sleep(RETRY_BACKOFF).await;
- }
- Err(format!(
- "mesh connect attempt {attempt_id} exhausted its window: {last_error}"
- ))
-}
-
-/// Build + sign + submit the kind:24621 connect-request as the Buzz identity.
-async fn publish_connect_request(
- state: &AppState,
- request: &RelayMeshConnectRequest<'_>,
- attempt_id: &str,
-) -> Result<(), String> {
- let builder = build_connect_request_event(request, attempt_id)?;
- crate::relay::submit_event(builder, state).await.map(|_| ())
-}
-
-fn build_connect_request_event(
- request: &RelayMeshConnectRequest<'_>,
- attempt_id: &str,
+pub(crate) fn build_status_report_event(
+ payload: serde_json::Value,
) -> Result {
- let mut content = json!({
- "v": 1,
- "self_endpoint_addr": request.self_endpoint_addr,
- "peer_endpoint_addr": request.peer_endpoint_addr,
- "attempt_id": attempt_id,
- });
- if let Some(endpoint_id) = request.self_endpoint_id {
- content["self_endpoint_id"] = serde_json::Value::String(endpoint_id.to_string());
- }
- if let Some(endpoint_id) = request.peer_endpoint_id {
- content["peer_endpoint_id"] = serde_json::Value::String(endpoint_id.to_string());
- }
- let target = nostr::PublicKey::from_hex(request.target_pubkey)
- .map_err(|e| format!("invalid target pubkey: {e}"))?;
+ let d = Tag::parse(["d", STATUS_D_TAG]).map_err(|error| error.to_string())?;
+ let k = Tag::parse(["k", "buzz-mesh-status"]).map_err(|error| error.to_string())?;
Ok(nostr::EventBuilder::new(
- nostr::Kind::Custom(KIND_MESH_CONNECT_REQUEST as u16),
- content.to_string(),
- )
- .tag(nostr::Tag::public_key(target)))
-}
-
-pub(crate) fn build_status_report_event(payload: serde_json::Value) -> nostr::EventBuilder {
- nostr::EventBuilder::new(
- nostr::Kind::Custom(KIND_MESH_STATUS_REPORT as u16),
+ nostr::Kind::Custom(KIND_BUZZ_MESH_MEMBER_STATUS),
payload.to_string(),
)
+ .tags([d, k]))
}
pub(crate) async fn publish_status_report(
state: &AppState,
payload: serde_json::Value,
) -> Result<(), String> {
- crate::relay::submit_event(build_status_report_event(payload), state)
+ crate::relay::submit_event(build_status_report_event(payload)?, state)
.await
.map(|_| ())
}
-/// Extract the peer endpoint addr from a paired call-me-now (24622) event,
-/// dropping expired ones.
-fn call_me_now_peer_addr(event: &nostr::Event) -> Option {
- let payload: serde_json::Value = serde_json::from_str(&event.content).ok()?;
- if payload.get("type")?.as_str()? != "buzz-iroh-call-me-now" {
- return None;
- }
- let now = chrono::Utc::now().timestamp().max(0) as u64;
- if let Some(expires_at) = payload.get("expires_at").and_then(|v| v.as_u64()) {
- if expires_at < now {
- return None;
- }
- }
- payload
- .get("peer_endpoint_addr")?
- .as_str()
- .map(str::to_string)
-}
-
-/// NIP-42 AUTH as the Buzz identity. Generalized from `commands::pairing`'s
-/// `handle_nip42_auth` — same flow, signs with `state.keys` instead of a
-/// pairing session. Returns `Ok(())` when the relay does not challenge.
-async fn authenticate(
- app: &AppHandle,
- relay_url: &str,
- read: &mut R,
- write: &mut W,
-) -> Result<(), String>
-where
- R: StreamExt> + Unpin,
- W: SinkExt + Unpin,
-{
- let challenge = match tokio::time::timeout(Duration::from_secs(3), async {
- loop {
- let msg = read
- .next()
- .await
- .ok_or_else(|| "relay closed during mesh auth".to_string())?
- .map_err(|e| format!("WS error during mesh auth: {e}"))?;
- if let Message::Text(text) = msg {
- if let Some(challenge) = parse_auth_challenge(text.as_str()) {
- return Ok::(challenge);
- }
- }
- }
- })
- .await
- {
- Ok(Ok(c)) => c,
- Ok(Err(e)) => return Err(e),
- Err(_) => return Ok(()), // no challenge: relay does not require AUTH
- };
-
- let relay_url_parsed =
- nostr::RelayUrl::parse(relay_url).map_err(|e| format!("invalid relay URL: {e}"))?;
- // Sign synchronously, drop the guard before awaiting (keep the future Send).
- let auth_json = {
- let state = app.state::();
- let keys = state.keys.lock().map_err(|e| e.to_string())?;
- let event = nostr::EventBuilder::auth(challenge, relay_url_parsed)
- .sign_with_keys(&keys)
- .map_err(|e| format!("sign mesh auth event: {e}"))?;
- format!("[\"AUTH\",{}]", event.as_json())
- };
- write
- .send(Message::Text(auth_json.into()))
- .await
- .map_err(|e| format!("send mesh auth: {e}"))?;
- Ok(())
-}
-
-fn parse_auth_challenge(text: &str) -> Option {
- let arr: serde_json::Value = serde_json::from_str(text).ok()?;
- let arr = arr.as_array()?;
- if arr.len() >= 2 && arr[0].as_str()? == "AUTH" {
- return arr[1].as_str().map(str::to_string);
- }
- None
-}
-
-fn parse_relay_event(text: &str, sub_id: &str) -> Option {
- let arr: serde_json::Value = serde_json::from_str(text).ok()?;
- let arr = arr.as_array()?;
- if arr.len() < 3 || arr[0].as_str()? != "EVENT" || arr[1].as_str()? != sub_id {
- return None;
- }
- serde_json::from_value(arr[2].clone()).ok()
-}
-
#[cfg(test)]
mod tests {
- use super::*;
+ use nostr::JsonUtil;
- #[test]
- fn connect_request_event_includes_optional_endpoint_ids() {
- let keys = nostr::Keys::generate();
- let request = RelayMeshConnectRequest {
- target_pubkey: &keys.public_key().to_hex(),
- peer_endpoint_addr: "peer-addr",
- self_endpoint_addr: "self-addr",
- peer_endpoint_id: Some("peer-id"),
- self_endpoint_id: Some("self-id"),
- };
- let event = build_connect_request_event(&request, "attempt-1")
- .expect("build event")
- .sign_with_keys(&keys)
- .expect("sign event");
- let content: serde_json::Value = serde_json::from_str(&event.content).unwrap();
- assert_eq!(content["self_endpoint_id"], "self-id");
- assert_eq!(content["peer_endpoint_id"], "peer-id");
- }
-
- #[test]
- fn connect_request_event_omits_absent_endpoint_ids() {
- let keys = nostr::Keys::generate();
- let request = RelayMeshConnectRequest {
- target_pubkey: &keys.public_key().to_hex(),
- peer_endpoint_addr: "peer-addr",
- self_endpoint_addr: "self-addr",
- peer_endpoint_id: None,
- self_endpoint_id: None,
- };
- let event = build_connect_request_event(&request, "attempt-1")
- .expect("build event")
- .sign_with_keys(&keys)
- .expect("sign event");
- let content: serde_json::Value = serde_json::from_str(&event.content).unwrap();
- assert!(content.get("self_endpoint_id").is_none());
- assert!(content.get("peer_endpoint_id").is_none());
- }
-
- #[test]
- fn status_report_event_uses_kind_and_exact_content() {
- let keys = nostr::Keys::generate();
- let payload = json!({"v": 1, "models": ["demo"]});
- let event = build_status_report_event(payload.clone())
- .sign_with_keys(&keys)
- .expect("sign event");
- assert_eq!(
- event.kind,
- nostr::Kind::Custom(KIND_MESH_STATUS_REPORT as u16)
- );
- assert_eq!(
- serde_json::from_str::(&event.content).unwrap(),
- payload
- );
- }
+ use super::*;
#[test]
- fn stopped_status_payload_advertises_identity_without_targets() {
+ fn stopped_status_advertises_identity_without_targets() {
assert_eq!(
stopped_status_payload("owner-test"),
- json!({
+ serde_json::json!({
"ownerId": "owner-test",
- "token": "",
- "hosted_models": [],
- "serving_models": [],
- "peers": [],
+ "serveTargets": [],
+ "models": [],
})
);
}
#[test]
- fn call_me_now_peer_addr_extracts_unexpired() {
- let future = chrono::Utc::now().timestamp() as u64 + 30;
- let event = test_event(&json!({
- "type": "buzz-iroh-call-me-now",
- "peer_endpoint_addr": "node-abc",
- "attempt_id": "a1",
- "expires_at": future,
- }));
- assert_eq!(call_me_now_peer_addr(&event).as_deref(), Some("node-abc"));
- }
-
- #[test]
- fn call_me_now_peer_addr_drops_expired() {
- let event = test_event(&json!({
- "type": "buzz-iroh-call-me-now",
- "peer_endpoint_addr": "node-abc",
- "attempt_id": "a1",
- "expires_at": 1u64,
- }));
- assert_eq!(call_me_now_peer_addr(&event), None);
- }
-
- #[test]
- fn call_me_now_peer_addr_rejects_wrong_type() {
- let event = test_event(&json!({
- "type": "something-else",
- "peer_endpoint_addr": "node-abc",
- }));
- assert_eq!(call_me_now_peer_addr(&event), None);
- }
-
- #[test]
- fn parse_auth_challenge_reads_nip42() {
+ fn status_is_an_ordinary_client_replaceable_event() {
+ let keys = nostr::Keys::generate();
+ let event = build_status_report_event(serde_json::json!({"ownerId":"owner"}))
+ .unwrap()
+ .sign_with_keys(&keys)
+ .unwrap();
assert_eq!(
- parse_auth_challenge(r#"["AUTH","chal-123"]"#).as_deref(),
- Some("chal-123")
+ event.kind,
+ nostr::Kind::Custom(KIND_BUZZ_MESH_MEMBER_STATUS)
);
- assert_eq!(parse_auth_challenge(r#"["EVENT","x"]"#), None);
- }
-
- fn test_event(content: &serde_json::Value) -> nostr::Event {
- let keys = nostr::Keys::generate();
- nostr::EventBuilder::new(
- nostr::Kind::Custom(KIND_MESH_CALL_ME_NOW as u16),
- content.to_string(),
- )
- .sign_with_keys(&keys)
- .expect("sign test event")
+ assert_eq!(event.pubkey, keys.public_key());
+ assert!(event.as_json().contains(STATUS_D_TAG));
}
}
diff --git a/desktop/src-tauri/src/mesh_llm/discovery.rs b/desktop/src-tauri/src/mesh_llm/discovery.rs
index 20210f59f3..4375472fbc 100644
--- a/desktop/src-tauri/src/mesh_llm/discovery.rs
+++ b/desktop/src-tauri/src/mesh_llm/discovery.rs
@@ -79,8 +79,7 @@ pub fn availability_from_events(events: Vec) -> MeshAvailability {
return MeshAvailability::unavailable("Buzz shared compute status is not published yet");
}
- // Relay status is now per reporter (d=buzz-relay-mesh:), so a
- // query returns multiple replaceable events. Aggregate them; do not pick the
+ // Status is replaceable per member pubkey, so a query returns multiple events. Aggregate them; do not pick the
// newest single event or one member's machines hide everyone else's.
let mut all_targets = Vec::::new();
let mut all_models = Vec::::new();
@@ -175,15 +174,9 @@ pub fn relay_membership_filter() -> serde_json::Value {
}
fn reporter_pubkey_from_status_event(event: &nostr::Event) -> Option {
- event.tags.iter().find_map(|tag| {
- let slice = tag.as_slice();
- let d = slice.get(1)?;
- if slice.first().is_some_and(|name| name == "d") {
- d.strip_prefix("buzz-relay-mesh:").map(ToString::to_string)
- } else {
- None
- }
- })
+ // Discovery notes are signed by the member that owns the MeshLLM identity.
+ // The generic relay only stores/queries them; it is not an identity oracle.
+ Some(event.pubkey.to_hex())
}
pub(super) fn enrich_status_payload_identity(
diff --git a/desktop/src-tauri/src/mesh_llm/mod.rs b/desktop/src-tauri/src/mesh_llm/mod.rs
index 2d03bb3d98..d60c3bf765 100644
--- a/desktop/src-tauri/src/mesh_llm/mod.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod.rs
@@ -1,10 +1,8 @@
use std::collections::BTreeMap;
mod coordinator;
-pub(crate) use coordinator::{
- publish_current_status_once, publish_stopped_status_once, RelayMeshConnectRequest,
-};
-pub use coordinator::{spawn_listener, start_client, MeshCoordinator};
+pub(crate) use coordinator::{publish_current_status_once, publish_stopped_status_once};
+pub use coordinator::{spawn_listener, MeshCoordinator, KIND_BUZZ_MESH_MEMBER_STATUS};
mod discovery;
pub use discovery::{
@@ -27,7 +25,7 @@ use std::time::Duration;
const DEFAULT_MESH_API_PORT: u16 = 9337;
const DEFAULT_MESH_CONSOLE_PORT: u16 = 3131;
-const MESH_STATUS_KIND: u64 = 30_621;
+const MESH_STATUS_KIND: u64 = KIND_BUZZ_MESH_MEMBER_STATUS as u64;
const MESH_API_PORT_ENV: &str = "BUZZ_MESH_API_PORT";
const MESH_CONSOLE_PORT_ENV: &str = "BUZZ_MESH_CONSOLE_PORT";
/// Iroh relay tunneling for symmetric-NAT peers. Unset/empty/"1"/"default" =
@@ -169,7 +167,7 @@ pub struct StartMeshNodeRequest {
#[serde(default)]
pub join_token: Option,
/// Mesh owner ids admitted to this node (the member roster from
- /// relay-signed status notes). `None` = caller did not resolve a roster
+ /// member-signed discovery notes). `None` = caller did not resolve a roster
/// (tests, direct invocations): the node runs without allowlist
/// enforcement, matching an open relay. `Some` = enforce
/// `TrustPolicy::Allowlist` over exactly these owners (self is always
diff --git a/desktop/src-tauri/src/mesh_llm/mod_tests.rs b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
index a9dda38ea1..1f5affadfc 100644
--- a/desktop/src-tauri/src/mesh_llm/mod_tests.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
@@ -118,22 +118,21 @@ fn normalized_roster_always_includes_self_and_dedupes() {
}
fn signed_status_event(content: serde_json::Value) -> nostr::Event {
- let keys = nostr::Keys::generate();
- nostr::EventBuilder::new(nostr::Kind::Custom(30_621), content.to_string())
- .sign_with_keys(&keys)
- .expect("test event signs")
-}
-
-fn signed_reporter_status(reporter: &str, owner_id: &str) -> nostr::Event {
let keys = nostr::Keys::generate();
nostr::EventBuilder::new(
- nostr::Kind::Custom(30_621),
- json!({ "ownerId": owner_id, "serveTargets": [] }).to_string(),
+ nostr::Kind::Custom(super::KIND_BUZZ_MESH_MEMBER_STATUS),
+ content.to_string(),
)
- .tag(
- nostr::Tag::parse(["d", &format!("buzz-relay-mesh:{reporter}")])
- .expect("valid reporter tag"),
+ .sign_with_keys(&keys)
+ .expect("test event signs")
+}
+
+fn signed_reporter_status(reporter_secret: &str, owner_id: &str) -> nostr::Event {
+ let keys = nostr::Keys::parse(reporter_secret).expect("valid reporter secret");
+ super::coordinator::build_status_report_event(
+ json!({ "ownerId": owner_id, "serveTargets": [] }),
)
+ .expect("status builder")
.sign_with_keys(&keys)
.expect("test event signs")
}
@@ -168,13 +167,17 @@ fn owner_ids_from_events_collects_sorted_deduped_roster() {
#[test]
fn owner_roster_intersects_status_reporters_with_current_members() {
- let current_member = "a".repeat(64);
- let removed_member = "b".repeat(64);
- let nonmember = "c".repeat(64);
+ let current_secret = "1".repeat(64);
+ let removed_secret = "2".repeat(64);
+ let nonmember_secret = "3".repeat(64);
+ let current_member = nostr::Keys::parse(¤t_secret)
+ .unwrap()
+ .public_key()
+ .to_hex();
let events = vec![
- signed_reporter_status(¤t_member, "owner-current"),
- signed_reporter_status(&removed_member, "owner-removed"),
- signed_reporter_status(&nonmember, "owner-nonmember"),
+ signed_reporter_status(¤t_secret, "owner-current"),
+ signed_reporter_status(&removed_secret, "owner-removed"),
+ signed_reporter_status(&nonmember_secret, "owner-nonmember"),
signed_membership_event(std::slice::from_ref(¤t_member)),
];
@@ -187,8 +190,8 @@ fn owner_roster_intersects_status_reporters_with_current_members() {
#[test]
fn owner_roster_without_membership_list_preserves_published_owners() {
let events = vec![
- signed_reporter_status(&"a".repeat(64), "owner-a"),
- signed_reporter_status(&"b".repeat(64), "owner-b"),
+ signed_reporter_status(&"1".repeat(64), "owner-a"),
+ signed_reporter_status(&"2".repeat(64), "owner-b"),
];
assert_eq!(
From aabcc891f1020a1343c53ced81d815307ea7730b Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 12:03:53 +1000
Subject: [PATCH 12/35] fix(desktop): align persona creation after main rebase
---
.../src/features/agents/ui/usePersonaActions.ts | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/desktop/src/features/agents/ui/usePersonaActions.ts b/desktop/src/features/agents/ui/usePersonaActions.ts
index d4685286ed..bc81145e3a 100644
--- a/desktop/src/features/agents/ui/usePersonaActions.ts
+++ b/desktop/src/features/agents/ui/usePersonaActions.ts
@@ -42,10 +42,8 @@ import {
import { resolveManagedAgentAvatarUrl } from "./managedAgentAvatar";
import {
buildInstanceInputForDefinition,
- mintDefinitionWithPreflight,
type BackendIntent,
} from "../lib/instanceInputForDefinition";
-import { meshPrepareRelayMeshClient } from "@/shared/api/tauriMesh";
type PersonaFeedbackSurface = "catalog" | "library";
@@ -207,15 +205,10 @@ export function usePersonaActions() {
undefined,
runtime.avatarUrl,
);
- const persona = await mintDefinitionWithPreflight(
- startIntent,
- meshPrepareRelayMeshClient,
- () =>
- createPersonaMutation.mutateAsync({
- ...input,
- avatarUrl,
- }),
- );
+ const persona = await createPersonaMutation.mutateAsync({
+ ...input,
+ avatarUrl,
+ });
if (resolveCreateIntent(intent) === "definition") {
setPersonaNoticeMessage(`Created ${persona.displayName}.`);
From f98d802bda7ebe3adecf99cc80191ed92df0271e Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 12:07:34 +1000
Subject: [PATCH 13/35] fix(mesh): publish client-owned serve targets
---
desktop/src-tauri/src/mesh_llm/mod.rs | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/desktop/src-tauri/src/mesh_llm/mod.rs b/desktop/src-tauri/src/mesh_llm/mod.rs
index d60c3bf765..b4d3178380 100644
--- a/desktop/src-tauri/src/mesh_llm/mod.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod.rs
@@ -410,6 +410,31 @@ impl DesktopMeshRuntime {
if let Ok(identity) = ensure_owner_identity() {
payload["ownerId"] = serde_json::Value::String(identity.owner_id);
}
+ let models = models_from_status_payload(Some(&payload));
+ payload["models"] = serde_json::to_value(&models)?;
+ let endpoint_addr = status.invite_token.unwrap_or_default();
+ let serve_targets = if self.mode == MeshNodeMode::Serve && !endpoint_addr.is_empty() {
+ models
+ .into_iter()
+ .map(|model| MeshServeTarget {
+ model_id: model.id,
+ model_name: model.name,
+ endpoint_addr: endpoint_addr.clone(),
+ node_name: payload
+ .get("node_id")
+ .and_then(serde_json::Value::as_str)
+ .map(str::to_string),
+ capacity: None,
+ reporter_pubkey: None,
+ endpoint_id: endpoint_id_from_status(&payload, Some(&endpoint_addr)),
+ device_id: None,
+ device_name: None,
+ })
+ .collect::>()
+ } else {
+ Vec::new()
+ };
+ payload["serveTargets"] = serde_json::to_value(serve_targets)?;
Ok(payload)
}
From 4cf63f382b30ff2beac155e6516d7b9a377f91df Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 12:14:24 +1000
Subject: [PATCH 14/35] fix(desktop): keep discovery tests within size guard
---
.../src/managed_agents/discovery/tests.rs | 22 ++-----------------
1 file changed, 2 insertions(+), 20 deletions(-)
diff --git a/desktop/src-tauri/src/managed_agents/discovery/tests.rs b/desktop/src-tauri/src/managed_agents/discovery/tests.rs
index 86c602be47..d1c1cc18d8 100644
--- a/desktop/src-tauri/src/managed_agents/discovery/tests.rs
+++ b/desktop/src-tauri/src/managed_agents/discovery/tests.rs
@@ -3,8 +3,8 @@ use std::path::PathBuf;
use super::overrides::{divergent_agent_command_override, update_time_agent_command_override};
use super::{
apply_agent_command_update, classify_runtime, codex_adapter_availability,
- codex_adapter_is_outdated, command_search_dirs, create_time_agent_command_override,
- default_agent_command, effective_agent_command, find_nvm_default_bin, find_via_login_shell,
+ codex_adapter_is_outdated, create_time_agent_command_override, default_agent_command,
+ effective_agent_command, find_nvm_default_bin, find_via_login_shell,
is_login_shell_path_uninit, is_safe_nvm_tag, managed_agent_avatar_url, normalize_agent_args,
parse_semver_tag, probe_codex_acp_major_version, record_agent_command,
refresh_login_shell_path, BUZZ_AGENT_AVATAR_URL, CLAUDE_CODE_AVATAR_URL, CODEX_AVATAR_URL,
@@ -44,24 +44,6 @@ fn returns_none_for_unknown_commands() {
assert!(managed_agent_avatar_url("custom-agent").is_none());
}
-#[test]
-fn command_search_prefers_current_build_profile() {
- let dirs = command_search_dirs();
- let debug_index = dirs
- .iter()
- .position(|path| path.ends_with("target/debug"))
- .expect("debug search directory");
- let release_index = dirs
- .iter()
- .position(|path| path.ends_with("target/release"))
- .expect("release search directory");
- if cfg!(debug_assertions) {
- assert!(debug_index < release_index);
- } else {
- assert!(release_index < debug_index);
- }
-}
-
#[test]
fn default_agent_command_resolves_bundled_buzz_agent() {
// The create-path default must be the bundled buzz-agent, never the
From 2c07e467a630bb3b8b22c895de4139ebc740f03d Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 12:20:13 +1000
Subject: [PATCH 15/35] fix(mesh): use relay-supported discovery kind and fail
closed
---
desktop/src-tauri/src/mesh_llm/coordinator.rs | 8 +++--
desktop/src-tauri/src/mesh_llm/discovery.rs | 19 ++++++------
desktop/src-tauri/src/mesh_llm/mod_tests.rs | 30 +++++++------------
3 files changed, 24 insertions(+), 33 deletions(-)
diff --git a/desktop/src-tauri/src/mesh_llm/coordinator.rs b/desktop/src-tauri/src/mesh_llm/coordinator.rs
index d76a7318af..e00a109a39 100644
--- a/desktop/src-tauri/src/mesh_llm/coordinator.rs
+++ b/desktop/src-tauri/src/mesh_llm/coordinator.rs
@@ -13,9 +13,11 @@ use tauri::{AppHandle, Manager};
use crate::app_state::AppState;
-/// Client-owned parameterized-replaceable discovery note. Intentionally local
-/// to the desktop: relays handle it as an ordinary NIP-33 event.
-pub const KIND_BUZZ_MESH_MEMBER_STATUS: u16 = 30_321;
+/// Client-owned parameterized-replaceable discovery note. We use the standard
+/// NIP-51 bookmark-set kind with a reserved d-tag so existing Buzz relays accept
+/// and store it through their generic user-state path. The relay needs no mesh
+/// handler or kind-registry change.
+pub const KIND_BUZZ_MESH_MEMBER_STATUS: u16 = buzz_core_pkg::kind::KIND_BOOKMARK_SET as u16;
const STATUS_D_TAG: &str = "buzz-mesh-member-status";
const ROSTER_POLL_INTERVAL: Duration = Duration::from_secs(60);
const STATUS_PUBLISH_INTERVAL: Duration = Duration::from_secs(15);
diff --git a/desktop/src-tauri/src/mesh_llm/discovery.rs b/desktop/src-tauri/src/mesh_llm/discovery.rs
index 4375472fbc..997c88a3e5 100644
--- a/desktop/src-tauri/src/mesh_llm/discovery.rs
+++ b/desktop/src-tauri/src/mesh_llm/discovery.rs
@@ -16,21 +16,20 @@ fn dedupe_targets(targets: Vec) -> Vec {
/// Resolve the mesh admission roster from relay status and membership events.
///
-/// When a NIP-43 membership list exists, only status notes attributed to a
-/// currently listed direct member contribute an owner id. This removes stale
-/// notes from former members and ignores notes from nonmembers. Relays without
-/// a membership list retain the legacy/open-relay behavior: every published
-/// owner id is admitted.
+/// Only status notes signed by a currently listed NIP-43 direct member
+/// contribute an owner id. This removes stale notes from former members and
+/// ignores notes from nonmembers. If the relay has no membership snapshot, the
+/// roster is empty and MeshLLM admission therefore remains self-only.
pub fn owner_ids_from_events(events: &[nostr::Event]) -> Vec {
- let members = latest_membership_list(events);
+ let Some(members) = latest_membership_list(events) else {
+ return Vec::new();
+ };
let mut ids: Vec = events
.iter()
.filter(|event| event.kind.as_u16() as u64 == MESH_STATUS_KIND)
.filter(|event| {
- members.as_ref().is_none_or(|members| {
- reporter_pubkey_from_status_event(event)
- .is_some_and(|reporter| members.contains(&reporter.to_ascii_lowercase()))
- })
+ reporter_pubkey_from_status_event(event)
+ .is_some_and(|reporter| members.contains(&reporter.to_ascii_lowercase()))
})
.filter_map(owner_id_from_status_event)
.collect();
diff --git a/desktop/src-tauri/src/mesh_llm/mod_tests.rs b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
index 1f5affadfc..0394fe3723 100644
--- a/desktop/src-tauri/src/mesh_llm/mod_tests.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
@@ -117,16 +117,6 @@ fn normalized_roster_always_includes_self_and_dedupes() {
);
}
-fn signed_status_event(content: serde_json::Value) -> nostr::Event {
- let keys = nostr::Keys::generate();
- nostr::EventBuilder::new(
- nostr::Kind::Custom(super::KIND_BUZZ_MESH_MEMBER_STATUS),
- content.to_string(),
- )
- .sign_with_keys(&keys)
- .expect("test event signs")
-}
-
fn signed_reporter_status(reporter_secret: &str, owner_id: &str) -> nostr::Event {
let keys = nostr::Keys::parse(reporter_secret).expect("valid reporter secret");
super::coordinator::build_status_report_event(
@@ -151,12 +141,15 @@ fn signed_membership_event(members: &[String]) -> nostr::Event {
#[test]
fn owner_ids_from_events_collects_sorted_deduped_roster() {
+ let secret_a = "1".repeat(64);
+ let secret_b = "2".repeat(64);
+ let member_a = nostr::Keys::parse(&secret_a).unwrap().public_key().to_hex();
+ let member_b = nostr::Keys::parse(&secret_b).unwrap().public_key().to_hex();
let events = vec![
- signed_status_event(json!({ "ownerId": "owner-b", "serveTargets": [] })),
- signed_status_event(json!({ "owner_id": "owner-a" })), // snake_case accepted
- signed_status_event(json!({ "ownerId": "owner-b" })), // duplicate
- signed_status_event(json!({ "serveTargets": [] })), // pre-upgrade note: no owner id
- signed_status_event(json!({ "ownerId": "" })), // empty filtered
+ signed_reporter_status(&secret_b, "owner-b"),
+ signed_reporter_status(&secret_a, "owner-a"),
+ signed_reporter_status(&secret_b, "owner-b"), // duplicate
+ signed_membership_event(&[member_a, member_b]),
];
assert_eq!(
super::owner_ids_from_events(&events),
@@ -188,14 +181,11 @@ fn owner_roster_intersects_status_reporters_with_current_members() {
}
#[test]
-fn owner_roster_without_membership_list_preserves_published_owners() {
+fn owner_roster_without_membership_list_fails_closed() {
let events = vec![
signed_reporter_status(&"1".repeat(64), "owner-a"),
signed_reporter_status(&"2".repeat(64), "owner-b"),
];
- assert_eq!(
- super::owner_ids_from_events(&events),
- vec!["owner-a".to_string(), "owner-b".to_string()]
- );
+ assert!(super::owner_ids_from_events(&events).is_empty());
}
From ef5fb2703f4bf80b8ec0cd06eeb3b21f66b4b956 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 12:25:12 +1000
Subject: [PATCH 16/35] fix(mesh): prove member ownership of admission
identities
---
desktop/src-tauri/Cargo.lock | 1 +
desktop/src-tauri/Cargo.toml | 1 +
desktop/src-tauri/src/mesh_llm/coordinator.rs | 48 ++++++++++++++-----
desktop/src-tauri/src/mesh_llm/discovery.rs | 31 +++++++++---
desktop/src-tauri/src/mesh_llm/identity.rs | 41 ++++++++++++----
desktop/src-tauri/src/mesh_llm/mod_tests.rs | 32 ++++++++-----
6 files changed, 115 insertions(+), 39 deletions(-)
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index 7404ea31d5..175a2db69b 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -969,6 +969,7 @@ dependencies = [
"ctrlc",
"dirs",
"earshot",
+ "ed25519-dalek",
"futures-util",
"hex",
"image",
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index da9fd85365..5f31b78617 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -66,6 +66,7 @@ tauri-plugin-updater = "2"
tauri-plugin-process = "2"
infer = "0.19"
hex = "0.4"
+ed25519-dalek = "=3.0.0-rc.0"
tokio = { version = "1", features = ["fs", "sync", "rt", "macros", "time"] }
tokio-tungstenite = { version = "0.29", features = ["rustls-tls-webpki-roots"] }
tokio-util = { version = "0.7", features = ["rt"] }
diff --git a/desktop/src-tauri/src/mesh_llm/coordinator.rs b/desktop/src-tauri/src/mesh_llm/coordinator.rs
index e00a109a39..3dd73c5e49 100644
--- a/desktop/src-tauri/src/mesh_llm/coordinator.rs
+++ b/desktop/src-tauri/src/mesh_llm/coordinator.rs
@@ -116,37 +116,55 @@ pub(crate) async fn publish_stopped_status_once(app: &AppHandle, reason: &str) {
}
async fn publish_current_status_for_state(state: &AppState) -> Result<(), String> {
- let owner_id = super::ensure_owner_identity()
- .map_err(|error| format!("failed to load mesh owner identity: {error}"))?
- .owner_id;
- let payload = {
+ let identity = super::ensure_owner_identity()
+ .map_err(|error| format!("failed to load mesh owner identity: {error}"))?;
+ let mut payload = {
let runtime = state.mesh_llm_runtime.lock().await;
match runtime.as_ref() {
Some(runtime) => runtime
.status_report_payload()
.await
.map_err(|error| error.to_string())?,
- None => stopped_status_payload(&owner_id),
+ None => stopped_status_payload(&identity),
}
};
+ bind_payload_to_member(state, &identity, &mut payload)?;
publish_status_report(state, payload).await
}
async fn publish_stopped_status_for_state(state: &AppState) -> Result<(), String> {
- let owner_id = super::ensure_owner_identity()
- .map_err(|error| format!("failed to load mesh owner identity: {error}"))?
- .owner_id;
- publish_status_report(state, stopped_status_payload(&owner_id)).await
+ let identity = super::ensure_owner_identity()
+ .map_err(|error| format!("failed to load mesh owner identity: {error}"))?;
+ let mut payload = stopped_status_payload(&identity);
+ bind_payload_to_member(state, &identity, &mut payload)?;
+ publish_status_report(state, payload).await
}
-fn stopped_status_payload(owner_id: &str) -> serde_json::Value {
+fn stopped_status_payload(identity: &super::identity::OwnerIdentity) -> serde_json::Value {
serde_json::json!({
- "ownerId": owner_id,
+ "ownerId": identity.owner_id,
+ "ownerVerifyingKey": identity.verifying_key_hex,
"serveTargets": [],
"models": [],
})
}
+fn bind_payload_to_member(
+ state: &AppState,
+ identity: &super::identity::OwnerIdentity,
+ payload: &mut serde_json::Value,
+) -> Result<(), String> {
+ let member_pubkey = state.signing_keys()?.public_key().to_hex();
+ payload["ownerId"] = serde_json::Value::String(identity.owner_id.clone());
+ payload["ownerVerifyingKey"] = serde_json::Value::String(identity.verifying_key_hex.clone());
+ payload["ownerBindingSig"] = serde_json::Value::String(
+ identity
+ .sign_member_binding(&member_pubkey)
+ .map_err(|error| error.to_string())?,
+ );
+ Ok(())
+}
+
pub(crate) fn build_status_report_event(
payload: serde_json::Value,
) -> Result {
@@ -176,10 +194,16 @@ mod tests {
#[test]
fn stopped_status_advertises_identity_without_targets() {
+ let identity = super::super::identity::OwnerIdentity {
+ keystore_path: "/tmp/unused".into(),
+ owner_id: "owner-test".into(),
+ verifying_key_hex: "verify-test".into(),
+ };
assert_eq!(
- stopped_status_payload("owner-test"),
+ stopped_status_payload(&identity),
serde_json::json!({
"ownerId": "owner-test",
+ "ownerVerifyingKey": "verify-test",
"serveTargets": [],
"models": [],
})
diff --git a/desktop/src-tauri/src/mesh_llm/discovery.rs b/desktop/src-tauri/src/mesh_llm/discovery.rs
index 997c88a3e5..e8f73279ea 100644
--- a/desktop/src-tauri/src/mesh_llm/discovery.rs
+++ b/desktop/src-tauri/src/mesh_llm/discovery.rs
@@ -1,6 +1,8 @@
use std::collections::{BTreeMap, BTreeSet};
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
+use ed25519_dalek::{Signature, Verifier, VerifyingKey};
+use sha2::{Digest, Sha256};
use super::{dedupe_models, MeshAvailability, MeshModelOption, MeshServeTarget, MESH_STATUS_KIND};
@@ -64,13 +66,30 @@ fn latest_membership_list(events: &[nostr::Event]) -> Option> {
fn owner_id_from_status_event(event: &nostr::Event) -> Option {
let content = serde_json::from_str::(&event.content).ok()?;
- content
+ let owner_id = content
.get("ownerId")
- .or_else(|| content.get("owner_id"))
- .and_then(serde_json::Value::as_str)
- .map(str::trim)
- .filter(|id| !id.is_empty())
- .map(ToString::to_string)
+ .or_else(|| content.get("owner_id"))?
+ .as_str()?
+ .trim();
+ let verifying_key_bytes: [u8; 32] =
+ hex::decode(content.get("ownerVerifyingKey")?.as_str()?.trim())
+ .ok()?
+ .try_into()
+ .ok()?;
+ let derived_owner = hex::encode(Sha256::digest(verifying_key_bytes));
+ if owner_id != derived_owner {
+ return None;
+ }
+ let signature_bytes = hex::decode(content.get("ownerBindingSig")?.as_str()?.trim()).ok()?;
+ let signature = Signature::from_slice(&signature_bytes).ok()?;
+ let verifying_key = VerifyingKey::from_bytes(&verifying_key_bytes).ok()?;
+ verifying_key
+ .verify(
+ &super::identity::member_binding_bytes(&event.pubkey.to_hex()),
+ &signature,
+ )
+ .ok()?;
+ Some(owner_id.to_string())
}
pub fn availability_from_events(events: Vec) -> MeshAvailability {
diff --git a/desktop/src-tauri/src/mesh_llm/identity.rs b/desktop/src-tauri/src/mesh_llm/identity.rs
index fcc0356f56..29a82ab160 100644
--- a/desktop/src-tauri/src/mesh_llm/identity.rs
+++ b/desktop/src-tauri/src/mesh_llm/identity.rs
@@ -18,6 +18,37 @@ use mesh_llm_host_runtime::crypto::{
pub struct OwnerIdentity {
pub keystore_path: PathBuf,
pub owner_id: String,
+ pub verifying_key_hex: String,
+}
+
+impl OwnerIdentity {
+ /// Sign a Buzz-to-MeshLLM ownership binding. The member's Nostr signature
+ /// authenticates the discovery event; this Ed25519 signature proves the
+ /// advertised owner id is backed by the MeshLLM owner key itself.
+ pub fn sign_member_binding(&self, member_pubkey: &str) -> anyhow::Result {
+ let keypair = load_keystore(&self.keystore_path, None).map_err(|error| {
+ anyhow::anyhow!("failed to load mesh owner keystore for binding: {error}")
+ })?;
+ Ok(hex::encode(
+ keypair.sign_bytes(&member_binding_bytes(member_pubkey)),
+ ))
+ }
+}
+
+pub fn member_binding_bytes(member_pubkey: &str) -> Vec {
+ format!(
+ "buzz-mesh-owner-binding-v1:{}",
+ member_pubkey.trim().to_ascii_lowercase()
+ )
+ .into_bytes()
+}
+
+fn owner_identity(path: PathBuf, keypair: &OwnerKeypair) -> OwnerIdentity {
+ OwnerIdentity {
+ owner_id: keypair.owner_id(),
+ verifying_key_hex: hex::encode(keypair.verifying_key().as_bytes()),
+ keystore_path: path,
+ }
}
/// Load-or-generate the machine's mesh owner identity. Cached for the process
@@ -40,10 +71,7 @@ fn ensure_owner_identity_uncached() -> anyhow::Result {
path.display()
)
})?;
- return Ok(OwnerIdentity {
- owner_id: keypair.owner_id(),
- keystore_path: path,
- });
+ return Ok(owner_identity(path, &keypair));
}
let keypair = OwnerKeypair::generate();
save_keystore(&path, &keypair, None, false).map_err(|error| {
@@ -52,8 +80,5 @@ fn ensure_owner_identity_uncached() -> anyhow::Result {
path.display()
)
})?;
- Ok(OwnerIdentity {
- owner_id: keypair.owner_id(),
- keystore_path: path,
- })
+ Ok(owner_identity(path, &keypair))
}
diff --git a/desktop/src-tauri/src/mesh_llm/mod_tests.rs b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
index 0394fe3723..b03a56664c 100644
--- a/desktop/src-tauri/src/mesh_llm/mod_tests.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
@@ -81,6 +81,7 @@ fn normalized_roster_none_means_no_enforcement() {
let identity = super::identity::OwnerIdentity {
keystore_path: std::path::PathBuf::from("/tmp/ks.json"),
owner_id: "owner-self".to_string(),
+ verifying_key_hex: String::new(),
};
assert_eq!(super::normalized_roster(&None, &identity), None);
}
@@ -90,6 +91,7 @@ fn normalized_roster_always_includes_self_and_dedupes() {
let identity = super::identity::OwnerIdentity {
keystore_path: std::path::PathBuf::from("/tmp/ks.json"),
owner_id: "owner-self".to_string(),
+ verifying_key_hex: String::new(),
};
// Empty roster (fresh relay, nobody published yet) still admits self —
// otherwise the first sharer locks themselves out.
@@ -117,11 +119,20 @@ fn normalized_roster_always_includes_self_and_dedupes() {
);
}
-fn signed_reporter_status(reporter_secret: &str, owner_id: &str) -> nostr::Event {
+fn signed_reporter_status(reporter_secret: &str, _label: &str) -> nostr::Event {
+ use mesh_llm_host_runtime::crypto::OwnerKeypair;
+
let keys = nostr::Keys::parse(reporter_secret).expect("valid reporter secret");
- super::coordinator::build_status_report_event(
- json!({ "ownerId": owner_id, "serveTargets": [] }),
- )
+ let owner = OwnerKeypair::generate();
+ let member_pubkey = keys.public_key().to_hex();
+ super::coordinator::build_status_report_event(json!({
+ "ownerId": owner.owner_id(),
+ "ownerVerifyingKey": hex::encode(owner.verifying_key().as_bytes()),
+ "ownerBindingSig": hex::encode(owner.sign_bytes(
+ &super::identity::member_binding_bytes(&member_pubkey)
+ )),
+ "serveTargets": []
+ }))
.expect("status builder")
.sign_with_keys(&keys)
.expect("test event signs")
@@ -148,13 +159,11 @@ fn owner_ids_from_events_collects_sorted_deduped_roster() {
let events = vec![
signed_reporter_status(&secret_b, "owner-b"),
signed_reporter_status(&secret_a, "owner-a"),
- signed_reporter_status(&secret_b, "owner-b"), // duplicate
signed_membership_event(&[member_a, member_b]),
];
- assert_eq!(
- super::owner_ids_from_events(&events),
- vec!["owner-a".to_string(), "owner-b".to_string()]
- );
+ let owners = super::owner_ids_from_events(&events);
+ assert_eq!(owners.len(), 2);
+ assert!(owners.windows(2).all(|pair| pair[0] < pair[1]));
assert_eq!(super::owner_ids_from_events(&[]), Vec::::new());
}
@@ -174,10 +183,7 @@ fn owner_roster_intersects_status_reporters_with_current_members() {
signed_membership_event(std::slice::from_ref(¤t_member)),
];
- assert_eq!(
- super::owner_ids_from_events(&events),
- vec!["owner-current".to_string()]
- );
+ assert_eq!(super::owner_ids_from_events(&events).len(), 1);
}
#[test]
From e9cd903bea20cee79e675a1212733b250495a4f3 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 12:54:00 +1000
Subject: [PATCH 17/35] fix(mesh): pin post-release admission enforcement patch
---
Cargo.lock | 156 ++++++++--------
crates/buzz-relay/Cargo.toml | 4 +-
.../examples/mesh_admission_smoke.rs | 4 +-
desktop/src-tauri/Cargo.lock | 174 +++++++++---------
desktop/src-tauri/Cargo.toml | 12 +-
5 files changed, 176 insertions(+), 174 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 0f6ba8a342..2e2c041db8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4331,8 +4331,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-client"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"hex",
"mesh-llm-client",
@@ -4341,8 +4341,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-server"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4352,13 +4352,13 @@ dependencies = [
[[package]]
name = "mesh-llm-build-info"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
[[package]]
name = "mesh-llm-client"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -4389,8 +4389,8 @@ dependencies = [
[[package]]
name = "mesh-llm-config"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"dirs",
@@ -4405,8 +4405,8 @@ dependencies = [
[[package]]
name = "mesh-llm-embedded-runtime"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"mesh-llm-host-runtime",
@@ -4415,8 +4415,8 @@ dependencies = [
[[package]]
name = "mesh-llm-events"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"clap",
@@ -4427,8 +4427,8 @@ dependencies = [
[[package]]
name = "mesh-llm-gpu-bench"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"cc",
@@ -4440,8 +4440,8 @@ dependencies = [
[[package]]
name = "mesh-llm-guardrails"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"serde",
"serde_json",
@@ -4449,16 +4449,16 @@ dependencies = [
[[package]]
name = "mesh-llm-hardware-profile"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"mesh-llm-native-runtime",
]
[[package]]
name = "mesh-llm-host-runtime"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"argon2",
@@ -4550,8 +4550,8 @@ dependencies = [
[[package]]
name = "mesh-llm-identity"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"argon2",
"base64",
@@ -4572,8 +4572,8 @@ dependencies = [
[[package]]
name = "mesh-llm-native-runtime"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"serde",
@@ -4583,8 +4583,8 @@ dependencies = [
[[package]]
name = "mesh-llm-node"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"mesh-llm-types",
@@ -4597,8 +4597,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -4614,8 +4614,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin-manager"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"dirs",
@@ -4632,8 +4632,8 @@ dependencies = [
[[package]]
name = "mesh-llm-protocol"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"hex",
@@ -4645,16 +4645,16 @@ dependencies = [
[[package]]
name = "mesh-llm-routing"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"iroh",
]
[[package]]
name = "mesh-llm-runtime-install"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"dirs",
@@ -4676,8 +4676,8 @@ dependencies = [
[[package]]
name = "mesh-llm-sdk"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4691,8 +4691,8 @@ dependencies = [
[[package]]
name = "mesh-llm-skills"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"dirs",
@@ -4702,8 +4702,8 @@ dependencies = [
[[package]]
name = "mesh-llm-system"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"chrono",
@@ -4725,8 +4725,8 @@ dependencies = [
[[package]]
name = "mesh-llm-types"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"hex",
"serde",
@@ -4736,13 +4736,13 @@ dependencies = [
[[package]]
name = "mesh-llm-ui"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
[[package]]
name = "mesh-mixture-of-agents"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"async-trait",
"mesh-llm-guardrails",
@@ -4858,8 +4858,8 @@ dependencies = [
[[package]]
name = "model-artifact"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -4869,8 +4869,8 @@ dependencies = [
[[package]]
name = "model-hf"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -4887,8 +4887,8 @@ dependencies = [
[[package]]
name = "model-package"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"bytes",
@@ -4907,16 +4907,16 @@ dependencies = [
[[package]]
name = "model-ref"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"serde",
]
[[package]]
name = "model-resolver"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"model-artifact",
@@ -5626,8 +5626,8 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openai-frontend"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"async-trait",
"axum",
@@ -7858,8 +7858,8 @@ checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b"
[[package]]
name = "skippy-cache"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"blake3",
@@ -7868,29 +7868,29 @@ dependencies = [
[[package]]
name = "skippy-coordinator"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "skippy-ffi"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"libloading",
]
[[package]]
name = "skippy-metrics"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
[[package]]
name = "skippy-protocol"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"prost",
"prost-build",
@@ -7900,8 +7900,8 @@ dependencies = [
[[package]]
name = "skippy-runtime"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"libc",
@@ -7914,8 +7914,8 @@ dependencies = [
[[package]]
name = "skippy-server"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -7942,8 +7942,8 @@ dependencies = [
[[package]]
name = "skippy-topology"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"serde",
"serde_json",
diff --git a/crates/buzz-relay/Cargo.toml b/crates/buzz-relay/Cargo.toml
index 8c502dffa3..1339d11a1a 100644
--- a/crates/buzz-relay/Cargo.toml
+++ b/crates/buzz-relay/Cargo.toml
@@ -77,8 +77,8 @@ metrics-exporter-prometheus = { workspace = true }
dev = ["buzz-auth/dev"]
[dev-dependencies]
-mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "c209d1775fec5fcf6ab314628826dfdb0615ea6a", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] }
-mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "c209d1775fec5fcf6ab314628826dfdb0615ea6a", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] }
+mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] }
+mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] }
buzz-core = { workspace = true, features = ["test-utils"] }
buzz-auth = { workspace = true, features = ["dev"] }
reqwest = { workspace = true }
diff --git a/crates/buzz-relay/examples/mesh_admission_smoke.rs b/crates/buzz-relay/examples/mesh_admission_smoke.rs
index 6f7b73a637..394f901139 100644
--- a/crates/buzz-relay/examples/mesh_admission_smoke.rs
+++ b/crates/buzz-relay/examples/mesh_admission_smoke.rs
@@ -187,7 +187,9 @@ fn orchestrate() -> anyhow::Result<()> {
// real HOME would share a node identity and clobber each other's
// attestations. The native runtime cache must still point at the real
// one (it resolves via HOME otherwise).
- let real_cache = dirs_cache_dir()?.join("mesh-llm/native-runtimes");
+ let real_cache = std::env::var_os("MESH_LLM_NATIVE_RUNTIME_CACHE_DIR")
+ .map(std::path::PathBuf::from)
+ .unwrap_or(dirs_cache_dir()?.join("mesh-llm/native-runtimes"));
let role_home = |name: &str| -> anyhow::Result {
let home = scratch.join(format!("{name}-home"));
std::fs::create_dir_all(&home)?;
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index 175a2db69b..a46b915cfa 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -1637,7 +1637,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "windows 0.62.2",
+ "windows 0.61.3",
]
[[package]]
@@ -2975,8 +2975,8 @@ dependencies = [
"libc",
"log",
"rustversion",
- "windows-link 0.2.1",
- "windows-result 0.4.1",
+ "windows-link 0.1.3",
+ "windows-result 0.3.4",
]
[[package]]
@@ -3711,7 +3711,7 @@ dependencies = [
"tokio",
"tower-service",
"tracing",
- "windows-registry 0.6.1",
+ "windows-registry 0.5.3",
]
[[package]]
@@ -3726,7 +3726,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.62.2",
+ "windows-core 0.61.2",
]
[[package]]
@@ -4761,8 +4761,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-client"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"hex",
"mesh-llm-client",
@@ -4771,8 +4771,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-server"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4782,13 +4782,13 @@ dependencies = [
[[package]]
name = "mesh-llm-build-info"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
[[package]]
name = "mesh-llm-client"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -4819,8 +4819,8 @@ dependencies = [
[[package]]
name = "mesh-llm-config"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"dirs",
@@ -4835,8 +4835,8 @@ dependencies = [
[[package]]
name = "mesh-llm-embedded-runtime"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"mesh-llm-host-runtime",
@@ -4845,8 +4845,8 @@ dependencies = [
[[package]]
name = "mesh-llm-events"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"clap",
@@ -4857,8 +4857,8 @@ dependencies = [
[[package]]
name = "mesh-llm-gpu-bench"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"cc",
@@ -4870,8 +4870,8 @@ dependencies = [
[[package]]
name = "mesh-llm-guardrails"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"serde",
"serde_json",
@@ -4879,16 +4879,16 @@ dependencies = [
[[package]]
name = "mesh-llm-hardware-profile"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"mesh-llm-native-runtime",
]
[[package]]
name = "mesh-llm-host-runtime"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"argon2",
@@ -4980,8 +4980,8 @@ dependencies = [
[[package]]
name = "mesh-llm-identity"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"argon2",
"base64 0.22.1",
@@ -5002,8 +5002,8 @@ dependencies = [
[[package]]
name = "mesh-llm-native-runtime"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"serde",
@@ -5013,8 +5013,8 @@ dependencies = [
[[package]]
name = "mesh-llm-node"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"mesh-llm-types",
@@ -5027,8 +5027,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -5044,8 +5044,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin-manager"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"dirs",
@@ -5062,8 +5062,8 @@ dependencies = [
[[package]]
name = "mesh-llm-protocol"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"hex",
@@ -5075,16 +5075,16 @@ dependencies = [
[[package]]
name = "mesh-llm-routing"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"iroh",
]
[[package]]
name = "mesh-llm-runtime-install"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"dirs",
@@ -5106,8 +5106,8 @@ dependencies = [
[[package]]
name = "mesh-llm-sdk"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -5121,8 +5121,8 @@ dependencies = [
[[package]]
name = "mesh-llm-skills"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"dirs",
@@ -5132,8 +5132,8 @@ dependencies = [
[[package]]
name = "mesh-llm-system"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"chrono",
@@ -5155,8 +5155,8 @@ dependencies = [
[[package]]
name = "mesh-llm-types"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"hex",
"serde",
@@ -5166,13 +5166,13 @@ dependencies = [
[[package]]
name = "mesh-llm-ui"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
[[package]]
name = "mesh-mixture-of-agents"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"async-trait",
"mesh-llm-guardrails",
@@ -5235,8 +5235,8 @@ dependencies = [
[[package]]
name = "model-artifact"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -5246,8 +5246,8 @@ dependencies = [
[[package]]
name = "model-hf"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -5264,8 +5264,8 @@ dependencies = [
[[package]]
name = "model-package"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"bytes",
@@ -5284,16 +5284,16 @@ dependencies = [
[[package]]
name = "model-ref"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"serde",
]
[[package]]
name = "model-resolver"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"model-artifact",
@@ -5923,7 +5923,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
dependencies = [
- "proc-macro-crate 3.5.0",
+ "proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.118",
@@ -6297,8 +6297,8 @@ dependencies = [
[[package]]
name = "openai-frontend"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"async-trait",
"axum",
@@ -7191,7 +7191,7 @@ version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
dependencies = [
- "heck 0.5.0",
+ "heck 0.4.1",
"itertools",
"log",
"multimap",
@@ -8751,8 +8751,8 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
[[package]]
name = "skippy-cache"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"blake3",
@@ -8761,29 +8761,29 @@ dependencies = [
[[package]]
name = "skippy-coordinator"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "skippy-ffi"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"libloading 0.8.9",
]
[[package]]
name = "skippy-metrics"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
[[package]]
name = "skippy-protocol"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"prost",
"prost-build",
@@ -8793,8 +8793,8 @@ dependencies = [
[[package]]
name = "skippy-runtime"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"libc",
@@ -8807,8 +8807,8 @@ dependencies = [
[[package]]
name = "skippy-server"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"anyhow",
"async-trait",
@@ -8835,8 +8835,8 @@ dependencies = [
[[package]]
name = "skippy-topology"
-version = "0.72.2"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=c209d1775fec5fcf6ab314628826dfdb0615ea6a#c209d1775fec5fcf6ab314628826dfdb0615ea6a"
+version = "0.72.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
dependencies = [
"serde",
"serde_json",
@@ -11980,8 +11980,8 @@ dependencies = [
"log",
"serde",
"thiserror 2.0.18",
- "windows 0.62.2",
- "windows-core 0.62.2",
+ "windows 0.61.3",
+ "windows-core 0.61.2",
]
[[package]]
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index 5f31b78617..edddf06877 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -86,14 +86,14 @@ buzz_core_pkg = { package = "buzz-core", path = "../../crates/buzz-core" }
buzz_persona_pkg = { package = "buzz-persona", path = "../../crates/buzz-persona" }
buzz_sdk_pkg = { package = "buzz-sdk", path = "../../crates/buzz-sdk" }
buzz_agent_pkg = { package = "buzz-agent", path = "../../crates/buzz-agent" }
-mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "c209d1775fec5fcf6ab314628826dfdb0615ea6a", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
-mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "c209d1775fec5fcf6ab314628826dfdb0615ea6a", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
+mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
+mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
# Model catalog + hardware survey for the Share-compute model picker (same
# diagnose pattern as mesh-console). Lib name of mesh-llm-client is mesh_client.
-mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "c209d1775fec5fcf6ab314628826dfdb0615ea6a", package = "mesh-llm-client", optional = true }
-mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "c209d1775fec5fcf6ab314628826dfdb0615ea6a", package = "mesh-llm-node", optional = true }
-mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "c209d1775fec5fcf6ab314628826dfdb0615ea6a", package = "mesh-llm-system", optional = true }
-mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "c209d1775fec5fcf6ab314628826dfdb0615ea6a", package = "mesh-llm-events", optional = true }
+mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-client", optional = true }
+mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-node", optional = true }
+mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-system", optional = true }
+mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-events", optional = true }
base64 = "0.22"
sha2 = "0.11"
tar = "0.4"
From 33a2ada9d77a9117f9881e2c77687b1ea6ace5c3 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 13:02:35 +1000
Subject: [PATCH 18/35] test(mesh): require stranger inference rejection
---
.../examples/mesh_admission_smoke.rs | 26 +++++++++++++++----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/crates/buzz-relay/examples/mesh_admission_smoke.rs b/crates/buzz-relay/examples/mesh_admission_smoke.rs
index 394f901139..a541f35bbc 100644
--- a/crates/buzz-relay/examples/mesh_admission_smoke.rs
+++ b/crates/buzz-relay/examples/mesh_admission_smoke.rs
@@ -272,12 +272,28 @@ fn orchestrate() -> anyhow::Result<()> {
window_secs: STRANGER_WINDOW_SECS,
},
)?;
- if stranger_out.seen.is_none() {
- eprintln!("[admission] PASS 3/3: non-member saw no model ({STRANGER_WINDOW_SECS}s window)");
- } else {
- eprintln!("[admission] non-member was not admitted to mesh membership");
+ match (
+ stranger_out.seen.as_deref(),
+ stranger_out.infer_ok.as_deref(),
+ stranger_out.infer_fail.as_deref(),
+ ) {
+ (None, None, _) => eprintln!(
+ "[admission] PASS 3/3: non-member saw no model ({STRANGER_WINDOW_SECS}s window)"
+ ),
+ (Some(model), None, Some(error)) => eprintln!(
+ "[admission] PASS 3/3: non-member saw gossip for {model} but inference was rejected: {error}"
+ ),
+ (Some(model), Some(content), _) => anyhow::bail!(
+ "ADMISSION FAIL: non-member reused the invite token and inferred through {model}: {content:?}"
+ ),
+ (Some(model), None, None) => anyhow::bail!(
+ "ADMISSION INCONCLUSIVE: non-member saw {model} but produced no inference verdict"
+ ),
+ (None, Some(content), _) => anyhow::bail!(
+ "ADMISSION FAIL: non-member inferred without model visibility: {content:?}"
+ ),
}
- eprintln!("[admission] PASS: owner allowlist gates mesh membership");
+ eprintln!("[admission] PASS: owner allowlist gates mesh membership and inference");
drop(serve_guard); // kills the serve child
let _ = serve_child.wait();
From a0182e5778a24e7a374f002a9267c2eac6b75b6d Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 13:05:57 +1000
Subject: [PATCH 19/35] test(mesh): reject spoofed member owner bindings
---
desktop/src-tauri/src/mesh_llm/mod_tests.rs | 36 +++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/desktop/src-tauri/src/mesh_llm/mod_tests.rs b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
index b03a56664c..a2ee7bbbca 100644
--- a/desktop/src-tauri/src/mesh_llm/mod_tests.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
@@ -186,6 +186,42 @@ fn owner_roster_intersects_status_reporters_with_current_members() {
assert_eq!(super::owner_ids_from_events(&events).len(), 1);
}
+#[test]
+fn owner_roster_rejects_spoofed_owner_id_and_cross_member_binding() {
+ use mesh_llm_host_runtime::crypto::OwnerKeypair;
+
+ let member_secret = "4".repeat(64);
+ let other_secret = "5".repeat(64);
+ let member_keys = nostr::Keys::parse(&member_secret).unwrap();
+ let other_keys = nostr::Keys::parse(&other_secret).unwrap();
+ let member_pubkey = member_keys.public_key().to_hex();
+ let owner = OwnerKeypair::generate();
+ let verifying_key = hex::encode(owner.verifying_key().as_bytes());
+
+ let sign_status = |owner_id: String, binding_pubkey: &str| {
+ super::coordinator::build_status_report_event(json!({
+ "ownerId": owner_id,
+ "ownerVerifyingKey": verifying_key,
+ "ownerBindingSig": hex::encode(owner.sign_bytes(
+ &super::identity::member_binding_bytes(binding_pubkey)
+ )),
+ "serveTargets": []
+ }))
+ .unwrap()
+ .sign_with_keys(&member_keys)
+ .unwrap()
+ };
+
+ let spoofed_owner = sign_status("0".repeat(64), &member_pubkey);
+ let cross_member_binding = sign_status(owner.owner_id(), &other_keys.public_key().to_hex());
+ let membership = signed_membership_event(std::slice::from_ref(&member_pubkey));
+
+ assert!(
+ super::owner_ids_from_events(&[spoofed_owner, cross_member_binding, membership]).is_empty(),
+ "a Buzz member must not be able to advertise an unproven MeshLLM owner identity"
+ );
+}
+
#[test]
fn owner_roster_without_membership_list_fails_closed() {
let events = vec![
From dde0090eff5f5c1bfbcace8c90c6ecb27c2a7399 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 13:09:24 +1000
Subject: [PATCH 20/35] fix(mesh): hide removed members from compute discovery
---
.../src-tauri/src/commands/agent_models.rs | 12 +++--
desktop/src-tauri/src/commands/mesh_llm.rs | 19 +++++++-
desktop/src-tauri/src/mesh_llm/discovery.rs | 15 +++++-
desktop/src-tauri/src/mesh_llm/mod_tests.rs | 47 +++++++++++++++++++
4 files changed, 86 insertions(+), 7 deletions(-)
diff --git a/desktop/src-tauri/src/commands/agent_models.rs b/desktop/src-tauri/src/commands/agent_models.rs
index 0de54c8637..97772b12a5 100644
--- a/desktop/src-tauri/src/commands/agent_models.rs
+++ b/desktop/src-tauri/src/commands/agent_models.rs
@@ -226,9 +226,15 @@ pub async fn discover_agent_models(
if input.provider.as_deref().map(str::trim)
== Some(crate::managed_agents::RELAY_MESH_PROVIDER_ID)
{
- let events = crate::relay::query_relay(&state, &[crate::mesh_llm::mesh_status_filter()])
- .await
- .map_err(|error| format!("Buzz shared compute model discovery failed: {error}"))?;
+ let events = crate::relay::query_relay(
+ &state,
+ &[
+ crate::mesh_llm::mesh_status_filter(),
+ crate::mesh_llm::relay_membership_filter(),
+ ],
+ )
+ .await
+ .map_err(|error| format!("Buzz shared compute model discovery failed: {error}"))?;
let availability = crate::mesh_llm::availability_from_events(events);
if availability.models.is_empty() {
return Err(availability.reason.unwrap_or_else(|| {
diff --git a/desktop/src-tauri/src/commands/mesh_llm.rs b/desktop/src-tauri/src/commands/mesh_llm.rs
index d7013c2d58..d3f5ca9cc5 100644
--- a/desktop/src-tauri/src/commands/mesh_llm.rs
+++ b/desktop/src-tauri/src/commands/mesh_llm.rs
@@ -97,7 +97,15 @@ pub(crate) async fn restore_mesh_sharing(app: &AppHandle, state: &AppState) -> C
pub async fn mesh_availability(
state: State<'_, AppState>,
) -> CmdResult {
- match relay::query_relay(&state, &[mesh_llm::mesh_status_filter()]).await {
+ match relay::query_relay(
+ &state,
+ &[
+ mesh_llm::mesh_status_filter(),
+ mesh_llm::relay_membership_filter(),
+ ],
+ )
+ .await
+ {
Ok(events) => Ok(mesh_llm::availability_from_events(events)),
Err(error) => Ok(mesh_llm::MeshAvailability::unavailable(error)),
}
@@ -291,7 +299,14 @@ pub(crate) async fn resolve_mesh_bootstrap_target(
if model_id.is_empty() {
return Ok(None);
}
- let events = relay::query_relay(state, &[mesh_llm::mesh_status_filter()]).await?;
+ let events = relay::query_relay(
+ state,
+ &[
+ mesh_llm::mesh_status_filter(),
+ mesh_llm::relay_membership_filter(),
+ ],
+ )
+ .await?;
Ok(pick_serve_target_for_model(
mesh_llm::availability_from_events(events).serve_targets,
model_id,
diff --git a/desktop/src-tauri/src/mesh_llm/discovery.rs b/desktop/src-tauri/src/mesh_llm/discovery.rs
index e8f73279ea..9b1472bb29 100644
--- a/desktop/src-tauri/src/mesh_llm/discovery.rs
+++ b/desktop/src-tauri/src/mesh_llm/discovery.rs
@@ -96,14 +96,25 @@ pub fn availability_from_events(events: Vec) -> MeshAvailability {
if events.is_empty() {
return MeshAvailability::unavailable("Buzz shared compute status is not published yet");
}
+ let Some(members) = latest_membership_list(&events) else {
+ return MeshAvailability::unavailable(
+ "Buzz shared compute is waiting for the current member roster",
+ );
+ };
- // Status is replaceable per member pubkey, so a query returns multiple events. Aggregate them; do not pick the
- // newest single event or one member's machines hide everyone else's.
+ // Status is replaceable per member pubkey, so a query returns multiple
+ // events. Aggregate only current members: a removed member's last status
+ // must not remain selectable after their admission is revoked.
let mut all_targets = Vec::::new();
let mut all_models = Vec::::new();
let mut saw_valid_status = false;
for event in events {
+ if event.kind.as_u16() as u64 != MESH_STATUS_KIND
+ || !members.contains(&event.pubkey.to_hex().to_ascii_lowercase())
+ {
+ continue;
+ }
let Ok(content) = serde_json::from_str::(&event.content) else {
continue;
};
diff --git a/desktop/src-tauri/src/mesh_llm/mod_tests.rs b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
index a2ee7bbbca..d22ab196cb 100644
--- a/desktop/src-tauri/src/mesh_llm/mod_tests.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
@@ -222,6 +222,53 @@ fn owner_roster_rejects_spoofed_owner_id_and_cross_member_binding() {
);
}
+#[test]
+fn availability_excludes_removed_member_status() {
+ let current_secret = "6".repeat(64);
+ let removed_secret = "7".repeat(64);
+ let current_member = nostr::Keys::parse(¤t_secret)
+ .unwrap()
+ .public_key()
+ .to_hex();
+ let events = vec![
+ signed_reporter_target(¤t_secret, "model-current", "addr-current"),
+ signed_reporter_target(&removed_secret, "model-removed", "addr-removed"),
+ signed_membership_event(std::slice::from_ref(¤t_member)),
+ ];
+
+ let availability = super::availability_from_events(events);
+ assert_eq!(availability.models.len(), 1);
+ assert_eq!(availability.models[0].id, "model-current");
+ assert_eq!(availability.serve_targets.len(), 1);
+ assert_eq!(availability.serve_targets[0].endpoint_addr, "addr-current");
+}
+
+fn signed_reporter_target(reporter_secret: &str, model: &str, endpoint: &str) -> nostr::Event {
+ use mesh_llm_host_runtime::crypto::OwnerKeypair;
+
+ let keys = nostr::Keys::parse(reporter_secret).unwrap();
+ let owner = OwnerKeypair::generate();
+ let member_pubkey = keys.public_key().to_hex();
+ super::coordinator::build_status_report_event(json!({
+ "ownerId": owner.owner_id(),
+ "ownerVerifyingKey": hex::encode(owner.verifying_key().as_bytes()),
+ "ownerBindingSig": hex::encode(owner.sign_bytes(
+ &super::identity::member_binding_bytes(&member_pubkey)
+ )),
+ "models": [{"id": model, "name": null}],
+ "serveTargets": [{
+ "modelId": model,
+ "modelName": null,
+ "endpointAddr": endpoint,
+ "nodeName": null,
+ "capacity": null
+ }]
+ }))
+ .unwrap()
+ .sign_with_keys(&keys)
+ .unwrap()
+}
+
#[test]
fn owner_roster_without_membership_list_fails_closed() {
let events = vec![
From f2a7009866bebc2a0dc3f98376d5fe95d5f03df0 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 13:32:15 +1000
Subject: [PATCH 21/35] docs(mesh): add local GUI Fizz verification runbook
---
docs/buzz-shared-compute-dev.md | 115 ++++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+)
create mode 100644 docs/buzz-shared-compute-dev.md
diff --git a/docs/buzz-shared-compute-dev.md b/docs/buzz-shared-compute-dev.md
new file mode 100644
index 0000000000..30acf4cc26
--- /dev/null
+++ b/docs/buzz-shared-compute-dev.md
@@ -0,0 +1,115 @@
+# Buzz shared compute: local GUI verification
+
+This runbook verifies the actual desktop path used by the built-in **Fizz** agent:
+
+`Buzz Desktop → buzz-acp → buzz-agent → MeshLLM SDK → local/remote compute`
+
+It does not use a substitute agent harness.
+
+## Before starting
+
+Run from the `block/buzz` repository root on the mesh-enabled branch.
+
+Free the development ports if a previous run was interrupted:
+
+```bash
+lsof -nP -iTCP:3000 -iTCP:8080 -iTCP:9102 -iTCP:9337 -iTCP:3131
+```
+
+Stop only stale Buzz/MeshLLM processes shown by that command. Do not leave a
+standalone `mesh-llm` process using `9337` or `3131`; the desktop owns those
+ports during this test.
+
+## 1. Launch the mesh-enabled desktop
+
+```bash
+. ./bin/activate-hermit
+just mesh=1 dev
+```
+
+Keep that terminal open. The first run may build/install the native runtime and
+take several minutes. Wait for the Buzz window to open and for the terminal to
+stop printing build progress.
+
+Using plain `just dev` is not sufficient: the Compute UI and embedded MeshLLM
+runtime are behind the `mesh-llm` feature.
+
+## 2. Share this machine
+
+1. Open **Settings**.
+2. Select **Compute**.
+3. Under **Share compute**, choose a suggested model.
+ - On a 16 GB Apple Silicon machine, use a suggested Qwen3.5 4B quantized
+ model when available.
+ - `unsloth/Qwen3.5-4B-GGUF:Q4_K_M` is the model used by the hardware proof.
+4. Turn on **Share this machine**.
+5. Wait until the card says it is sharing/running. Do not start Fizz while the
+ card says downloading, preparing, or starting.
+
+Buzz may download the model on first use. The model picker ranks models for the
+current hardware; avoid entering a model the card marks too large.
+
+## 3. Make shared compute the agent default
+
+1. Open **Agents** from the left sidebar.
+2. In **Agent defaults**, set **Default LLM provider** to
+ **Buzz shared compute**.
+3. Set **Default model** to **Default (auto)**.
+4. Click **Save defaults** and wait for **Saved**.
+
+Fizz has no pinned runtime/provider/model, so it inherits these defaults and
+resolves to the bundled `buzz-agent`. No API key is required.
+
+## 4. Start the real Fizz path
+
+1. Find the **Fizz** card on the Agents screen.
+2. Click its start/play control.
+3. Wait for its runtime indicator to become active.
+4. Add Fizz to a channel if it is not already a channel member.
+5. In that channel, send:
+
+ ```text
+ @Fizz Reply exactly: FIZZ_MESH_OK
+ ```
+
+6. Confirm that Fizz replies `FIZZ_MESH_OK` in the channel.
+
+That channel response is the end-to-end proof. A green Compute card alone proves
+only model serving; it does not prove the Fizz harness and provider inheritance.
+
+## 5. Optional diagnostics
+
+While Buzz is running:
+
+```bash
+# The desktop should own both ports.
+lsof -nP -iTCP:9337 -iTCP:3131
+
+# The embedded OpenAI-compatible ingress should advertise the model.
+curl -sS http://127.0.0.1:9337/v1/models | jq '.data[].id'
+
+# Fizz should resolve through the real managed-agent subprocesses.
+ps -eo pid,ppid,command | grep -E '[b]uzz-(desktop|acp|agent)'
+```
+
+If Fizz fails, open its runtime details from the Agents screen first. Common
+causes are:
+
+- launched with `just dev` instead of `just mesh=1 dev`;
+- a stale process owns `9337`/`3131`;
+- the model is still downloading or preparing;
+- Fizz is not a member of the channel;
+- defaults were changed but not saved;
+- no current Buzz membership snapshot is available (admission fails closed).
+
+## Security boundary
+
+Buzz publishes member-signed discovery notes through an ordinary relay-supported
+NIP-51 event. The note includes a MeshLLM-key signature binding the member to the
+advertised MeshLLM owner identity. Current Buzz membership controls which owner
+identities are admitted and which serving targets are selectable.
+
+MeshLLM—not the Buzz relay—carries inference over direct QUIC or its encrypted
+iroh relays and enforces the owner allowlist. The dependency is pinned to the
+post-v0.72.2 admission fix that prevents a non-member with a leaked invite token
+from using passive inference streams.
From 917d0f4519a2fe5bcd328e12cd6a6c6b2ae03c4d Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 16:44:27 +1000
Subject: [PATCH 22/35] fix(mesh): expire stale devices and preserve
multi-device compute
---
desktop/src-tauri/src/mesh_llm/coordinator.rs | 15 ++-
desktop/src-tauri/src/mesh_llm/discovery.rs | 28 +++++-
desktop/src-tauri/src/mesh_llm/mod_tests.rs | 98 +++++++++++++++++++
3 files changed, 137 insertions(+), 4 deletions(-)
diff --git a/desktop/src-tauri/src/mesh_llm/coordinator.rs b/desktop/src-tauri/src/mesh_llm/coordinator.rs
index 3dd73c5e49..b3646c570b 100644
--- a/desktop/src-tauri/src/mesh_llm/coordinator.rs
+++ b/desktop/src-tauri/src/mesh_llm/coordinator.rs
@@ -18,7 +18,7 @@ use crate::app_state::AppState;
/// and store it through their generic user-state path. The relay needs no mesh
/// handler or kind-registry change.
pub const KIND_BUZZ_MESH_MEMBER_STATUS: u16 = buzz_core_pkg::kind::KIND_BOOKMARK_SET as u16;
-const STATUS_D_TAG: &str = "buzz-mesh-member-status";
+const STATUS_D_TAG_PREFIX: &str = "buzz-mesh-member-status";
const ROSTER_POLL_INTERVAL: Duration = Duration::from_secs(60);
const STATUS_PUBLISH_INTERVAL: Duration = Duration::from_secs(15);
@@ -168,7 +168,14 @@ fn bind_payload_to_member(
pub(crate) fn build_status_report_event(
payload: serde_json::Value,
) -> Result {
- let d = Tag::parse(["d", STATUS_D_TAG]).map_err(|error| error.to_string())?;
+ let owner_id = payload
+ .get("ownerId")
+ .and_then(serde_json::Value::as_str)
+ .map(str::trim)
+ .filter(|value| !value.is_empty())
+ .ok_or_else(|| "mesh discovery status is missing ownerId".to_string())?;
+ let d_tag = format!("{STATUS_D_TAG_PREFIX}:{owner_id}");
+ let d = Tag::parse(["d", d_tag.as_str()]).map_err(|error| error.to_string())?;
let k = Tag::parse(["k", "buzz-mesh-status"]).map_err(|error| error.to_string())?;
Ok(nostr::EventBuilder::new(
nostr::Kind::Custom(KIND_BUZZ_MESH_MEMBER_STATUS),
@@ -222,6 +229,8 @@ mod tests {
nostr::Kind::Custom(KIND_BUZZ_MESH_MEMBER_STATUS)
);
assert_eq!(event.pubkey, keys.public_key());
- assert!(event.as_json().contains(STATUS_D_TAG));
+ assert!(event
+ .as_json()
+ .contains(&format!("{STATUS_D_TAG_PREFIX}:owner")));
}
}
diff --git a/desktop/src-tauri/src/mesh_llm/discovery.rs b/desktop/src-tauri/src/mesh_llm/discovery.rs
index 9b1472bb29..a199b458d3 100644
--- a/desktop/src-tauri/src/mesh_llm/discovery.rs
+++ b/desktop/src-tauri/src/mesh_llm/discovery.rs
@@ -6,6 +6,27 @@ use sha2::{Digest, Sha256};
use super::{dedupe_models, MeshAvailability, MeshModelOption, MeshServeTarget, MESH_STATUS_KIND};
+/// Status notes are refreshed every 15 seconds. Ignore notes older than two
+/// minutes so crashed/offline devices stop contributing compute or admission
+/// identities without requiring a relay-side cleanup job.
+const STATUS_FRESHNESS_SECS: u64 = 120;
+
+fn newest_event_timestamp(events: &[nostr::Event]) -> u64 {
+ events
+ .iter()
+ .map(|event| event.created_at.as_secs())
+ .max()
+ .unwrap_or_default()
+}
+
+fn status_is_fresh(event: &nostr::Event, now: u64) -> bool {
+ event
+ .created_at
+ .as_secs()
+ .saturating_add(STATUS_FRESHNESS_SECS)
+ >= now
+}
+
fn dedupe_targets(targets: Vec) -> Vec {
let mut by_endpoint = BTreeMap::::new();
for target in targets {
@@ -26,9 +47,12 @@ pub fn owner_ids_from_events(events: &[nostr::Event]) -> Vec {
let Some(members) = latest_membership_list(events) else {
return Vec::new();
};
+ let now = newest_event_timestamp(events);
let mut ids: Vec = events
.iter()
- .filter(|event| event.kind.as_u16() as u64 == MESH_STATUS_KIND)
+ .filter(|event| {
+ event.kind.as_u16() as u64 == MESH_STATUS_KIND && status_is_fresh(event, now)
+ })
.filter(|event| {
reporter_pubkey_from_status_event(event)
.is_some_and(|reporter| members.contains(&reporter.to_ascii_lowercase()))
@@ -109,8 +133,10 @@ pub fn availability_from_events(events: Vec) -> MeshAvailability {
let mut all_models = Vec::::new();
let mut saw_valid_status = false;
+ let now = newest_event_timestamp(&events);
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;
diff --git a/desktop/src-tauri/src/mesh_llm/mod_tests.rs b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
index d22ab196cb..71d9df987e 100644
--- a/desktop/src-tauri/src/mesh_llm/mod_tests.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod_tests.rs
@@ -269,6 +269,104 @@ fn signed_reporter_target(reporter_secret: &str, model: &str, endpoint: &str) ->
.unwrap()
}
+#[test]
+fn stale_status_is_excluded_from_admission_and_availability() {
+ let secret = "8".repeat(64);
+ let member = nostr::Keys::parse(&secret).unwrap().public_key().to_hex();
+ let stale = signed_reporter_target_at(&secret, "stale-model", "stale-addr", 1_000);
+ let membership = signed_membership_event_at(std::slice::from_ref(&member), 1_121);
+ let events = vec![stale, membership];
+
+ assert!(super::owner_ids_from_events(&events).is_empty());
+ let availability = super::availability_from_events(events);
+ assert!(!availability.available);
+ assert!(availability.serve_targets.is_empty());
+}
+
+#[test]
+fn same_member_can_publish_multiple_owner_scoped_devices() {
+ let secret = "9".repeat(64);
+ let member = nostr::Keys::parse(&secret).unwrap().public_key().to_hex();
+ let first = signed_reporter_target(&secret, "model-a", "addr-a");
+ let second = signed_reporter_target(&secret, "model-b", "addr-b");
+ let first_d = first
+ .tags
+ .iter()
+ .find_map(|tag| {
+ let values = tag.as_slice();
+ (values.first().map(String::as_str) == Some("d"))
+ .then(|| values.get(1).cloned())
+ .flatten()
+ })
+ .unwrap();
+ let second_d = second
+ .tags
+ .iter()
+ .find_map(|tag| {
+ let values = tag.as_slice();
+ (values.first().map(String::as_str) == Some("d"))
+ .then(|| values.get(1).cloned())
+ .flatten()
+ })
+ .unwrap();
+ assert_ne!(
+ first_d, second_d,
+ "device status coordinates must not overwrite"
+ );
+
+ let availability = super::availability_from_events(vec![
+ first,
+ second,
+ signed_membership_event(std::slice::from_ref(&member)),
+ ]);
+ assert_eq!(availability.serve_targets.len(), 2);
+}
+
+fn signed_reporter_target_at(
+ reporter_secret: &str,
+ model: &str,
+ endpoint: &str,
+ created_at: u64,
+) -> nostr::Event {
+ use mesh_llm_host_runtime::crypto::OwnerKeypair;
+
+ let keys = nostr::Keys::parse(reporter_secret).unwrap();
+ let owner = OwnerKeypair::generate();
+ let member_pubkey = keys.public_key().to_hex();
+ super::coordinator::build_status_report_event(json!({
+ "ownerId": owner.owner_id(),
+ "ownerVerifyingKey": hex::encode(owner.verifying_key().as_bytes()),
+ "ownerBindingSig": hex::encode(owner.sign_bytes(
+ &super::identity::member_binding_bytes(&member_pubkey)
+ )),
+ "models": [{"id": model, "name": null}],
+ "serveTargets": [{
+ "modelId": model,
+ "modelName": null,
+ "endpointAddr": endpoint,
+ "nodeName": null,
+ "capacity": null
+ }]
+ }))
+ .unwrap()
+ .custom_created_at(nostr::Timestamp::from(created_at))
+ .sign_with_keys(&keys)
+ .unwrap()
+}
+
+fn signed_membership_event_at(members: &[String], created_at: u64) -> nostr::Event {
+ let keys = nostr::Keys::generate();
+ let tags = members
+ .iter()
+ .map(|member| nostr::Tag::parse(["member", member]).unwrap())
+ .collect::>();
+ nostr::EventBuilder::new(nostr::Kind::Custom(13_534), "")
+ .tags(tags)
+ .custom_created_at(nostr::Timestamp::from(created_at))
+ .sign_with_keys(&keys)
+ .unwrap()
+}
+
#[test]
fn owner_roster_without_membership_list_fails_closed() {
let events = vec![
From 958e4a54ea7f06977b24eb9304b1177a551dad9e Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 17:26:33 +1000
Subject: [PATCH 23/35] docs(mesh): clarify shared compute GUI workflow
---
desktop/src-tauri/src/app_state.rs | 6 +++---
desktop/src-tauri/src/lib.rs | 8 ++++----
docs/buzz-shared-compute-dev.md | 14 +++++++++++++-
3 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/desktop/src-tauri/src/app_state.rs b/desktop/src-tauri/src/app_state.rs
index 7421caa66f..ca14dae6d6 100644
--- a/desktop/src-tauri/src/app_state.rs
+++ b/desktop/src-tauri/src/app_state.rs
@@ -76,9 +76,9 @@ pub struct AppState {
/// In-process mesh-llm node started by Buzz Desktop.
#[cfg(feature = "mesh-llm")]
pub mesh_llm_runtime: AsyncMutex
>,
- /// Runtime-owned relay-mesh control plane (call-me-now listener + connect
- /// request publish/retry). Installed once at identity-set time so the
- /// listener is up before any restore/create can request a connection.
+ /// Runtime-owned shared-compute coordinator. It publishes member-signed
+ /// discovery status and reconciles MeshLLM's admission roster; MeshLLM
+ /// itself owns direct QUIC/iroh connection establishment.
#[cfg(feature = "mesh-llm")]
pub mesh_coordinator: AsyncMutex
>,
}
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 382373d413..079a5a2acf 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -501,10 +501,10 @@ pub fn run() {
*guard = Some(app_handle.clone());
}
- // Bring up the runtime-owned relay-mesh call-me-now listener now,
- // before any saved agent restore can request a connection. Its
- // lifetime is tied to the runtime, not a UI mount — this is what
- // closes the cold-launch hole-punch race.
+ // Bring up the runtime-owned shared-compute coordinator before
+ // saved agents are restored. Its lifetime is tied to the app, not
+ // a UI mount; it publishes discovery and reconciles membership for
+ // MeshLLM's native admission and transport.
#[cfg(feature = "mesh-llm")]
{
// Route mesh-llm's download progress (model weights, runtime)
diff --git a/docs/buzz-shared-compute-dev.md b/docs/buzz-shared-compute-dev.md
index 30acf4cc26..aeb87446bc 100644
--- a/docs/buzz-shared-compute-dev.md
+++ b/docs/buzz-shared-compute-dev.md
@@ -63,7 +63,8 @@ resolves to the bundled `buzz-agent`. No API key is required.
## 4. Start the real Fizz path
1. Find the **Fizz** card on the Agents screen.
-2. Click its start/play control.
+2. If Fizz is stopped, click the small play badge over its avatar. If it is
+ running, the badge is a green status dot instead of a stop control.
3. Wait for its runtime indicator to become active.
4. Add Fizz to a channel if it is not already a channel member.
5. In that channel, send:
@@ -77,6 +78,17 @@ resolves to the bundled `buzz-agent`. No API key is required.
That channel response is the end-to-end proof. A green Compute card alone proves
only model serving; it does not prove the Fizz harness and provider inheritance.
+To stop a running agent, click the body/name of its card to open its profile,
+then click **Stop** near the top. The green avatar badge is status-only while the
+agent is running. Once stopped, the profile action becomes **Respawn** and the
+avatar badge becomes a play button.
+
+To create a separate test agent, choose **New agent → New agent**, use
+**buzz-agent** as the runtime, **Buzz shared compute** as the LLM provider,
+**Default (auto)** as the model, and **This computer** under **Run on**. Shared
+compute is an LLM provider; do not select a remote compute backend as the run
+location merely because its name mentions mesh.
+
## 5. Optional diagnostics
While Buzz is running:
From 6fd6b18a22794c645dcaf0bfe82ec432fd6662fc Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 18:28:26 +1000
Subject: [PATCH 24/35] fix(mesh): prevent reasoning-only silent turns
---
crates/buzz-agent/src/agent.rs | 33 +++++++
crates/buzz-agent/src/config.rs | 6 ++
crates/buzz-agent/src/llm.rs | 27 ++++-
crates/buzz-agent/tests/regressions.rs | 82 ++++++++++-----
crates/buzz-relay/examples/mesh_agent_e2e.rs | 99 ++++++++-----------
.../src/managed_agents/relay_mesh.rs | 18 ++--
6 files changed, 172 insertions(+), 93 deletions(-)
diff --git a/crates/buzz-agent/src/agent.rs b/crates/buzz-agent/src/agent.rs
index 730e87b2e8..2252eca3f6 100644
--- a/crates/buzz-agent/src/agent.rs
+++ b/crates/buzz-agent/src/agent.rs
@@ -21,6 +21,15 @@ use crate::wire::{self, WireSender};
const ERROR_REFLECTION_SUFFIX: &str =
"\n\n[Reflect] Before retrying, identify the cause and change your approach.";
+/// Maximum number of times a provider may claim a normal end-turn while
+/// returning neither user-visible text nor a tool call. Accepting that shape as
+/// success makes ACP turns disappear: the harness has nothing to publish or
+/// execute. One corrective round is enough to recover compatible local models
+/// without allowing an empty-response loop to run unboundedly.
+const MAX_EMPTY_END_TURN_RETRIES: u32 = 1;
+
+const EMPTY_END_TURN_RETRY_PROMPT: &str = "Your previous response ended without any visible text or tool call. Complete the current user request now. Return a user-visible answer, or use the required communication tool when the system instructions require one; do not return an empty response.";
+
pub struct RunCtx<'a> {
pub cfg: &'a Config,
/// Effective model for this session. Usually equals `cfg.model`; overridden
@@ -84,6 +93,7 @@ impl RunCtx<'_> {
// session) so a stubborn exchange can't permanently disable the stop
// guard for a long-lived session; `max_rounds` still caps the loop.
let mut stop_rejections = 0u32;
+ let mut empty_end_turn_retries = 0u32;
loop {
if self.cfg.max_rounds > 0 && round >= self.cfg.max_rounds {
return Ok(StopReason::MaxTurnRequests);
@@ -210,6 +220,29 @@ impl RunCtx<'_> {
"provider: stop=tool_use but zero tool_calls".into(),
));
}
+
+ // A provider may return a valid `finish_reason=stop` envelope
+ // containing only hidden/reasoning text. That is not a
+ // completed ACP turn: no user-visible message was emitted and
+ // no communication tool can publish one. Give the model one
+ // explicit corrective round, then fail loudly rather than
+ // reporting a silent success to the harness.
+ if response.stop == ProviderStop::EndTurn && response.text.trim().is_empty() {
+ self.history.push(HistoryItem::Assistant {
+ text: response.text,
+ tool_calls: Vec::new(),
+ });
+ if empty_end_turn_retries < MAX_EMPTY_END_TURN_RETRIES {
+ empty_end_turn_retries = empty_end_turn_retries.saturating_add(1);
+ self.history
+ .push(HistoryItem::User(EMPTY_END_TURN_RETRY_PROMPT.to_string()));
+ continue;
+ }
+ return Err(AgentError::Llm(
+ "provider ended the turn without visible text or a tool call".into(),
+ ));
+ }
+
self.history.push(HistoryItem::Assistant {
text: response.text,
tool_calls: Vec::new(),
diff --git a/crates/buzz-agent/src/config.rs b/crates/buzz-agent/src/config.rs
index f06849c7d1..8a76590071 100644
--- a/crates/buzz-agent/src/config.rs
+++ b/crates/buzz-agent/src/config.rs
@@ -730,6 +730,10 @@ pub struct Config {
/// Thinking/reasoning effort level. `None` = use provider default (no
/// thinking config sent). Set via `BUZZ_AGENT_THINKING_EFFORT`.
pub thinking_effort: Option,
+ /// Let an OpenAI-compatible server choose its generation limit instead of
+ /// sending `max_completion_tokens`. Useful for local/unknown models whose
+ /// output limit is discovered and enforced by the serving runtime.
+ pub openai_omit_max_tokens: bool,
}
impl Config {
@@ -824,6 +828,7 @@ impl Config {
hook_servers: parse_hook_servers_env("MCP_HOOK_SERVERS"),
hints_enabled: parse_env("BUZZ_AGENT_NO_HINTS", 0u8)? == 0,
thinking_effort: parse_thinking_effort(env("BUZZ_AGENT_THINKING_EFFORT").as_deref())?,
+ openai_omit_max_tokens: parse_env("OPENAI_COMPAT_OMIT_MAX_TOKENS", false)?,
};
cfg.validate()?;
Ok(cfg)
@@ -864,6 +869,7 @@ impl Config {
hook_servers: HookServers::None,
hints_enabled: false,
thinking_effort: None,
+ openai_omit_max_tokens: false,
}
}
diff --git a/crates/buzz-agent/src/llm.rs b/crates/buzz-agent/src/llm.rs
index 8a774fdf24..9bd02e0cce 100644
--- a/crates/buzz-agent/src/llm.rs
+++ b/crates/buzz-agent/src/llm.rs
@@ -539,8 +539,14 @@ fn openai_body(
"parameters": t.input_schema } })
})
.collect();
- let mut body = json!({ "model": effective_model, "stream": false,
- "max_completion_tokens": cfg.max_output_tokens, "messages": messages });
+ let mut body = json!({
+ "model": effective_model,
+ "stream": false,
+ "messages": messages,
+ });
+ if !cfg.openai_omit_max_tokens {
+ body["max_completion_tokens"] = json!(cfg.max_output_tokens);
+ }
if let Some(e) = effort {
body["reasoning_effort"] = json!(e.openai_effort_str());
}
@@ -1203,6 +1209,7 @@ mod tests {
openai_api: OpenAiApi::Chat,
hints_enabled: true,
thinking_effort: None,
+ openai_omit_max_tokens: false,
}
}
@@ -1782,6 +1789,22 @@ mod tests {
);
}
+ #[test]
+ fn openai_body_can_defer_generation_limit_to_compatible_server() {
+ let mut config = cfg(Provider::OpenAi);
+ config.openai_omit_max_tokens = true;
+ let body = openai_body(
+ &config,
+ "system",
+ &[HistoryItem::User("hi".into())],
+ &[],
+ "local-model",
+ None,
+ );
+ assert!(body.get("max_completion_tokens").is_none());
+ assert!(body.get("max_tokens").is_none());
+ }
+
#[test]
fn openai_body_omits_reasoning_effort_when_none() {
let body = openai_body(
diff --git a/crates/buzz-agent/tests/regressions.rs b/crates/buzz-agent/tests/regressions.rs
index 3c2237ac99..b87465455d 100644
--- a/crates/buzz-agent/tests/regressions.rs
+++ b/crates/buzz-agent/tests/regressions.rs
@@ -458,43 +458,79 @@ async fn cancel_leaves_history_valid_for_next_prompt() {
h.shutdown().await;
}
-/// Empty assistant content + no tool_calls must serialize as "" (not null)
-/// for OpenAI, so subsequent prompts don't get rejected. Round 7 fix 6.
+/// An empty normal completion is not a successful ACP turn. The agent must
+/// give the model one corrective round so a local reasoning model cannot end a
+/// Buzz mention after emitting only hidden thought text.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
-async fn empty_assistant_serializes_as_empty_string() {
- // First call returns content="" finish_reason=stop — agent records an
- // empty assistant turn. Second call's request body is what we inspect.
- let llm = spawn_capturing_llm(vec![openai_text(""), openai_text("done")]).await;
+async fn empty_end_turn_gets_one_corrective_round() {
+ let llm = spawn_capturing_llm(vec![openai_text(""), openai_text("visible answer")]).await;
let mut h = Harness::spawn(&llm.url).await;
let sid = init_session(&mut h, json!([])).await;
- let p1 = h
+ let prompt_id = h
.send(
"session/prompt",
json!({"sessionId": sid, "prompt": [{"type":"text","text":"a"}]}),
)
.await;
- let _ = h.recv_until(|v| v["id"] == json!(p1)).await;
- let p2 = h
+ let mut saw_visible_chunk = false;
+ let result = loop {
+ let value = h.recv().await;
+ if value["method"] == "session/update"
+ && value["params"]["update"]["sessionUpdate"] == "agent_message_chunk"
+ && value["params"]["update"]["content"]["text"] == "visible answer"
+ {
+ saw_visible_chunk = true;
+ }
+ if value["id"] == json!(prompt_id) {
+ break value;
+ }
+ };
+
+ assert_eq!(result["result"]["stopReason"], "end_turn");
+ assert!(
+ saw_visible_chunk,
+ "corrective answer was not emitted: {result}"
+ );
+
+ let captured = llm.captured.lock().await;
+ assert_eq!(captured.len(), 2, "expected exactly one corrective request");
+ let retry_messages = captured[1]["messages"].as_array().unwrap();
+ let empty_assistant = retry_messages
+ .iter()
+ .find(|message| message["role"] == "assistant")
+ .expect("empty assistant turn must be preserved for valid OpenAI history");
+ assert_eq!(empty_assistant["content"], json!(""));
+ assert!(retry_messages.iter().any(|message| {
+ message["role"] == "user"
+ && message["content"]
+ .as_str()
+ .is_some_and(|text| text.contains("ended without any visible text"))
+ }));
+ drop(captured);
+ h.shutdown().await;
+}
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+async fn repeated_empty_end_turn_fails_instead_of_silent_success() {
+ let llm = spawn_capturing_llm(vec![openai_text(""), openai_text("")]).await;
+ let mut h = Harness::spawn(&llm.url).await;
+ let sid = init_session(&mut h, json!([])).await;
+
+ let prompt_id = h
.send(
"session/prompt",
- json!({"sessionId": sid, "prompt": [{"type":"text","text":"b"}]}),
+ json!({"sessionId": sid, "prompt": [{"type":"text","text":"a"}]}),
)
.await;
- let _ = h.recv_until(|v| v["id"] == json!(p2)).await;
-
- let captured = llm.captured.lock().await;
- let msgs = captured[1]["messages"].as_array().unwrap();
- let empty_assistant = msgs
- .iter()
- .find(|m| m["role"] == "assistant" && m.get("tool_calls").is_none())
- .expect("no plain assistant turn");
- // Must be empty string, NOT null.
- assert_eq!(
- empty_assistant["content"],
- json!(""),
- "expected empty string content, got {empty_assistant}"
+ let result = h.recv_until(|value| value["id"] == json!(prompt_id)).await;
+ assert!(
+ result["error"]["message"]
+ .as_str()
+ .is_some_and(|message| message.contains("without visible text or a tool call")),
+ "unexpected result: {result}"
);
+ assert_eq!(llm.captured.lock().await.len(), 2);
h.shutdown().await;
}
diff --git a/crates/buzz-relay/examples/mesh_agent_e2e.rs b/crates/buzz-relay/examples/mesh_agent_e2e.rs
index f16387f5a9..3846d4339f 100644
--- a/crates/buzz-relay/examples/mesh_agent_e2e.rs
+++ b/crates/buzz-relay/examples/mesh_agent_e2e.rs
@@ -6,9 +6,8 @@
//! 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).
+//! P3 repeated ordinary chat — several normal prompts must each produce a
+//! user-visible ACP message, never reasoning-only silent success.
//! 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
@@ -33,6 +32,7 @@ use tokio::process::{Child, Command};
const DEFAULT_MODEL: &str = "unsloth/Qwen3-8B-GGUF:Q4_K_M";
const API_PORT: u16 = 19437;
const CONSOLE_PORT: u16 = 13231;
+const BUZZ_BASE_PROMPT: &str = include_str!("../../buzz-acp/src/base_prompt.md");
fn main() -> anyhow::Result<()> {
tokio::runtime::Builder::new_multi_thread()
@@ -94,15 +94,9 @@ async fn run() -> anyhow::Result<()> {
}
};
- // P1: explicit model id.
- let r = agent_chat(
- &base,
- &served_id,
- "1024",
- "Reply with exactly one word: PONG",
- &[],
- )
- .await;
+ // P1: explicit model id. Shared compute mirrors Goose for unknown local
+ // models and lets the serving runtime choose the generation limit.
+ let r = agent_chat(&base, &served_id, "Reply with exactly one word: PONG", &[]).await;
match r {
Ok(text) => record(
"P1 explicit-model chat",
@@ -113,14 +107,7 @@ async fn run() -> anyhow::Result<()> {
}
// P2: auto — router picks the model.
- let r = agent_chat(
- &base,
- "auto",
- "1024",
- "Reply with exactly one word: PONG",
- &[],
- )
- .await;
+ let r = agent_chat(&base, "auto", "Reply with exactly one word: PONG", &[]).await;
match r {
Ok(text) => record(
"P2 auto-model chat",
@@ -130,33 +117,26 @@ async fn run() -> anyhow::Result<()> {
Err(e) => record("P2 auto-model chat", false, e.to_string()),
}
- // 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.
- let r = agent_chat(
- &base,
- &served_id,
- "150000",
- "Reply with exactly one word: PONG",
- &[],
- )
- .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);
+ // P3: ordinary chat reliability with the real Buzz system prompt and MCP
+ // tool catalog. These prompts reproduce the GUI failure that exact-token,
+ // tiny-context smoke prompts missed. Each fresh ACP session must emit a
+ // visible message chunk; thought-only output is not an answer.
+ let dev_mcp = vec![("dev".to_string(), repo_bin("buzz-dev-mcp")?)];
+ for attempt in 1..=3 {
+ let r = agent_chat(
+ &base,
+ "auto",
+ "What can you do in Buzz? Answer in two short sentences. Do not call a tool for this test.",
+ &dev_mcp,
+ )
+ .await;
+ match r {
+ Ok(text) => record(
+ &format!("P3.{attempt} ordinary chat"),
+ !text.trim().is_empty(),
+ text,
+ ),
+ Err(e) => record(&format!("P3.{attempt} ordinary chat"), false, e.to_string()),
}
}
@@ -168,8 +148,7 @@ async fn run() -> anyhow::Result<()> {
"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."
);
let mcp = vec![("dev".to_string(), repo_bin("buzz-dev-mcp")?)];
- let (r, marker) =
- agent_chat_with_marker(&base, &served_id, "1024", &prompt, &mcp, &marker_name).await;
+ let (r, marker) = agent_chat_with_marker(&base, &served_id, &prompt, &mcp, &marker_name).await;
let file_ok = std::fs::read_to_string(&marker)
.map(|c| c.contains("BUZZ_OK"))
.unwrap_or(false);
@@ -212,32 +191,27 @@ fn repo_bin(name: &str) -> anyhow::Result {
async fn agent_chat(
base: &str,
model: &str,
- max_output_tokens: &str,
prompt: &str,
mcp_servers: &[(String, String)],
) -> anyhow::Result {
- let (result, _) =
- agent_chat_in_isolated_home(base, model, max_output_tokens, prompt, mcp_servers).await;
+ let (result, _) = agent_chat_in_isolated_home(base, model, prompt, mcp_servers).await;
result
}
async fn agent_chat_with_marker(
base: &str,
model: &str,
- max_output_tokens: &str,
prompt: &str,
mcp_servers: &[(String, String)],
marker_name: &str,
) -> (anyhow::Result, 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, prompt, mcp_servers).await;
(result, home.join(marker_name))
}
async fn agent_chat_in_isolated_home(
base: &str,
model: &str,
- max_output_tokens: &str,
prompt: &str,
mcp_servers: &[(String, String)],
) -> (anyhow::Result, std::path::PathBuf) {
@@ -262,7 +236,7 @@ async fn agent_chat_in_isolated_home(
.env("OPENAI_COMPAT_MODEL", model)
.env("OPENAI_COMPAT_API_KEY", "buzz-mesh-local")
.env("OPENAI_COMPAT_API", "chat")
- .env("BUZZ_AGENT_MAX_OUTPUT_TOKENS", max_output_tokens)
+ .env("OPENAI_COMPAT_OMIT_MAX_TOKENS", "true")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
@@ -317,7 +291,7 @@ async fn drive_acp(
"params": {
"cwd": cwd.to_string_lossy(),
"mcpServers": mcp_json,
- "systemPrompt": "You are a terse test agent. Follow instructions exactly."
+ "systemPrompt": BUZZ_BASE_PROMPT
}
}))
.as_bytes(),
@@ -336,9 +310,14 @@ async fn drive_acp(
let Ok(msg) = serde_json::from_str::(&line) else {
continue;
};
- // Collect any streamed agent text from session/update notifications.
+ // Only visible assistant output counts as an answer. Thought chunks
+ // are intentionally excluded: accepting them made reasoning-only turns
+ // look successful even though Buzz had nothing to publish to chat.
if msg.get("method").and_then(|m| m.as_str()) == Some("session/update") {
- collect_text(&msg["params"]["update"], &mut agent_text);
+ let update = &msg["params"]["update"];
+ if update["sessionUpdate"] == "agent_message_chunk" {
+ collect_text(update, &mut agent_text);
+ }
continue;
}
match msg.get("id").and_then(|i| i.as_i64()) {
diff --git a/desktop/src-tauri/src/managed_agents/relay_mesh.rs b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
index 51d99815db..999baf5485 100644
--- a/desktop/src-tauri/src/managed_agents/relay_mesh.rs
+++ b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
@@ -35,13 +35,14 @@ pub fn apply_relay_mesh_env(
RELAY_MESH_API_KEY_PLACEHOLDER.to_string(),
);
env.insert("OPENAI_COMPAT_API".to_string(), "chat".to_string());
- // Keep the combined prompt + response budget within small shared models.
- // The router reserves roughly 25% headroom, so 4K output can reject an 8K
- // model before the first turn once ACP/MCP context is included.
+ // Match Goose's OpenAI-compatible behavior for unknown local models: let
+ // MeshLLM enforce the selected model's discovered generation/context
+ // limits instead of imposing a harness-wide cap.
env.insert(
- "BUZZ_AGENT_MAX_OUTPUT_TOKENS".to_string(),
- "1024".to_string(),
+ "OPENAI_COMPAT_OMIT_MAX_TOKENS".to_string(),
+ "true".to_string(),
);
+ env.remove("BUZZ_AGENT_MAX_OUTPUT_TOKENS");
}
/// Resolve a record's relay-mesh config, typed field first.
@@ -185,7 +186,7 @@ mod tests {
}
#[test]
- fn native_provider_uses_a_small_model_safe_output_budget() {
+ fn native_provider_defers_output_limit_to_mesh_runtime() {
let mut rec = fixture();
rec.provider = Some(RELAY_MESH_PROVIDER_ID.to_string());
rec.model = Some(RELAY_MESH_AUTO_MODEL_ID.to_string());
@@ -194,9 +195,10 @@ mod tests {
apply_relay_mesh_env(&mut env, rec.provider.as_deref(), rec.model.as_deref());
assert_eq!(
- env.get("BUZZ_AGENT_MAX_OUTPUT_TOKENS").map(String::as_str),
- Some("1024")
+ env.get("OPENAI_COMPAT_OMIT_MAX_TOKENS").map(String::as_str),
+ Some("true")
);
+ assert!(!env.contains_key("BUZZ_AGENT_MAX_OUTPUT_TOKENS"));
}
#[test]
From 2c94b6464c9841551d99f163d0e67a55b37c2aeb Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Mon, 13 Jul 2026 19:37:20 +1000
Subject: [PATCH 25/35] fix(mesh): make Fizz reliable on local models
---
crates/buzz-acp/src/base_prompt.md | 2 +-
crates/buzz-dev-mcp/src/buzz_message.rs | 101 ++++++++++++
crates/buzz-dev-mcp/src/lib.rs | 12 ++
crates/buzz-relay/examples/mesh_agent_e2e.rs | 151 ++++++++++++++++--
.../src/managed_agents/fizz_system_prompt.md | 19 +++
.../src-tauri/src/managed_agents/personas.rs | 20 +--
.../src/managed_agents/relay_mesh.rs | 9 ++
desktop/src-tauri/src/mesh_llm/catalog.rs | 53 +++++-
docs/buzz-shared-compute-dev.md | 7 +-
9 files changed, 332 insertions(+), 42 deletions(-)
create mode 100644 crates/buzz-dev-mcp/src/buzz_message.rs
create mode 100644 desktop/src-tauri/src/managed_agents/fizz_system_prompt.md
diff --git a/crates/buzz-acp/src/base_prompt.md b/crates/buzz-acp/src/base_prompt.md
index fe2ea7107b..ff1eacdc16 100644
--- a/crates/buzz-acp/src/base_prompt.md
+++ b/crates/buzz-acp/src/base_prompt.md
@@ -47,7 +47,7 @@ All replies and delegations — including task assignments to other agents — g
### General
- Respond promptly to @mentions. Be direct — no preamble. Name what you did, what you found, or what you need.
-- **Every turn that processes a user message MUST end with `buzz messages send`.** Your reasoning and tool calls are invisible to users — if you didn't send a message, they saw nothing. A turn that ends without a sent message is a silent failure.
+- **Every turn that processes a user message MUST publish a reply.** Prefer the dedicated `buzz_send_message` tool when available; otherwise use `buzz messages send`. Your reasoning and other tool calls are invisible to users — if you didn't publish a message, they saw nothing. A turn that ends without a sent message is a silent failure.
- For work that requires follow-up tools, create an open todo **before** sending the pickup acknowledgment. Keep it open until the deliverable is verified and you have sent a completion or blocker message; never end a turn with open todo state unless you have posted that completion or blocker message.
- Use GitHub-flavored Markdown. Fenced code blocks with language tags for syntax highlighting.
- No push notifications — poll with `buzz messages get --channel --since `.
diff --git a/crates/buzz-dev-mcp/src/buzz_message.rs b/crates/buzz-dev-mcp/src/buzz_message.rs
new file mode 100644
index 0000000000..5589e2f888
--- /dev/null
+++ b/crates/buzz-dev-mcp/src/buzz_message.rs
@@ -0,0 +1,101 @@
+use crate::shell::SharedState;
+use rmcp::model::{CallToolResult, Content};
+use rmcp::ErrorData;
+use schemars::JsonSchema;
+use serde::Deserialize;
+use std::path::PathBuf;
+use std::process::Stdio;
+use tokio::process::Command;
+
+const MAX_CONTENT_BYTES: usize = 64 * 1024;
+
+#[derive(Debug, Deserialize, JsonSchema)]
+pub struct SendMessageParams {
+ /// Buzz channel UUID supplied in the turn's Context section.
+ pub channel: String,
+ /// Message body to publish.
+ pub content: String,
+ /// Optional event id to reply to when the Context section requires a threaded reply.
+ #[serde(default)]
+ pub reply_to: Option,
+}
+
+pub async fn run(
+ state: &SharedState,
+ params: SendMessageParams,
+) -> Result {
+ if params.content.trim().is_empty() {
+ return Err(ErrorData::invalid_params(
+ "content must not be empty".to_string(),
+ None,
+ ));
+ }
+ if params.content.len() > MAX_CONTENT_BYTES {
+ return Err(ErrorData::invalid_params(
+ format!("content exceeds {MAX_CONTENT_BYTES} bytes"),
+ None,
+ ));
+ }
+
+ let buzz = find_buzz(&state.shim.path_env).ok_or_else(|| {
+ ErrorData::internal_error("bundled Buzz CLI is unavailable".to_string(), None)
+ })?;
+ let mut command = Command::new(buzz);
+ command
+ .args([
+ "messages",
+ "send",
+ "--channel",
+ ¶ms.channel,
+ "--content",
+ ¶ms.content,
+ ])
+ .current_dir(&state.cwd)
+ .env("PATH", &state.shim.path_env)
+ .stdin(Stdio::null())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped());
+ if let Some(reply_to) = params.reply_to.as_deref() {
+ command.args(["--reply-to", reply_to]);
+ }
+
+ let output = command.output().await.map_err(|error| {
+ ErrorData::internal_error(format!("failed to run Buzz CLI: {error}"), None)
+ })?;
+ let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
+ let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
+ if output.status.success() {
+ let text = if stdout.is_empty() {
+ "Message published.".to_string()
+ } else {
+ stdout
+ };
+ Ok(CallToolResult::success(vec![Content::text(text)]))
+ } else {
+ let detail = if stderr.is_empty() { stdout } else { stderr };
+ Ok(CallToolResult::error(vec![Content::text(format!(
+ "Buzz message failed: {detail}"
+ ))]))
+ }
+}
+
+fn find_buzz(path: &str) -> Option {
+ std::env::split_paths(path)
+ .map(|entry| entry.join(if cfg!(windows) { "buzz.exe" } else { "buzz" }))
+ .find(|candidate| candidate.is_file())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn finds_bundled_buzz_on_path() {
+ let dir = tempfile::tempdir().unwrap();
+ let path = dir
+ .path()
+ .join(if cfg!(windows) { "buzz.exe" } else { "buzz" });
+ std::fs::write(&path, "test").unwrap();
+ assert_eq!(find_buzz(&dir.path().to_string_lossy()), Some(path));
+ }
+}
diff --git a/crates/buzz-dev-mcp/src/lib.rs b/crates/buzz-dev-mcp/src/lib.rs
index f9fced8e81..9ebd27aeab 100644
--- a/crates/buzz-dev-mcp/src/lib.rs
+++ b/crates/buzz-dev-mcp/src/lib.rs
@@ -10,6 +10,7 @@ use rmcp::{
use std::path::Path;
use std::sync::Arc;
+mod buzz_message;
mod paths;
mod read_file;
mod rg;
@@ -49,6 +50,17 @@ impl DevMcp {
shell::run(&self.state, p, context.ct).await
}
+ #[tool(
+ name = "buzz_send_message",
+ description = "Publish the user-visible reply for the current Buzz turn. Use the channel UUID and optional reply event id from the prompt's Context section. Prefer this typed tool over constructing `buzz messages send` in the shell. Every turn that processes a Buzz user message must call this before ending."
+ )]
+ async fn buzz_send_message(
+ &self,
+ Parameters(p): Parameters,
+ ) -> Result {
+ buzz_message::run(&self.state, p).await
+ }
+
#[tool(
name = "read_file",
description = "Read a text file and return its contents with line numbers. Returns lines in `{number}:{content}` format. Use `offset` (0-based) and `limit` (default 2000) to window into large files. Path resolved relative to workdir (defaults to server cwd). Prefer over cat/head/tail."
diff --git a/crates/buzz-relay/examples/mesh_agent_e2e.rs b/crates/buzz-relay/examples/mesh_agent_e2e.rs
index 3846d4339f..854a3c8aea 100644
--- a/crates/buzz-relay/examples/mesh_agent_e2e.rs
+++ b/crates/buzz-relay/examples/mesh_agent_e2e.rs
@@ -6,9 +6,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 repeated ordinary chat — several normal prompts must each produce a
-//! user-visible ACP message, never reasoning-only silent success.
-//! P4 agentic tool use — agent + buzz-dev-mcp writes a file on disk.
+//! P3 repeated ordinary chat — each turn emits user-visible ACP text.
+//! P4 repeated Fizz publish — real Fizz selects the typed Buzz publish tool.
+//! P5 agentic tool use — agent + buzz-dev-mcp writes a verified file.
//!
//! The serve node is the same `mesh_llm_sdk::serve` path Share-compute uses
//! (publish off, mdns, loopback). The agent legs spawn the real
@@ -22,6 +22,7 @@ use std::process::Stdio;
use std::time::Duration;
use mesh_llm_sdk::{serve, MeshDiscoveryMode};
+use nostr::{Keys, ToBech32};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::process::{Child, Command};
@@ -33,6 +34,9 @@ const DEFAULT_MODEL: &str = "unsloth/Qwen3-8B-GGUF:Q4_K_M";
const API_PORT: u16 = 19437;
const CONSOLE_PORT: u16 = 13231;
const BUZZ_BASE_PROMPT: &str = include_str!("../../buzz-acp/src/base_prompt.md");
+const FIZZ_SYSTEM_PROMPT: &str =
+ include_str!("../../../desktop/src-tauri/src/managed_agents/fizz_system_prompt.md");
+const FIZZ_TEST_CHANNEL: &str = "11111111-2222-4333-8444-555555555555";
fn main() -> anyhow::Result<()> {
tokio::runtime::Builder::new_multi_thread()
@@ -140,7 +144,42 @@ async fn run() -> anyhow::Result<()> {
}
}
- // P4: agentic tool use via buzz-dev-mcp — write a real file inside the
+ // P4: the actual Fizz/Buzz contract. Visible ACP prose is insufficient:
+ // Fizz must select the typed Buzz publish tool. Capturing ACP tool calls
+ // keeps this relay/keychain independent while exercising the real Fizz
+ // prompt, buzz-agent, and developer MCP.
+ for attempt in 1..=3 {
+ let (fizz_result, fizz_capture) = fizz_publish_turn(&base, "auto").await;
+ match fizz_result {
+ Ok(text) => {
+ let args = std::fs::read_to_string(&fizz_capture).unwrap_or_default();
+ let calls: Vec = serde_json::from_str(&args).unwrap_or_default();
+ let published = calls.iter().any(|call| {
+ call["title"] == "dev__buzz_send_message"
+ && call["rawInput"]["channel"] == FIZZ_TEST_CHANNEL
+ && call["rawInput"]["content"] == "FIZZ_MESH_CONTRACT_OK"
+ });
+ record(
+ &format!("P4.{attempt} Fizz selects typed Buzz publish tool"),
+ published,
+ if published {
+ format!("typed publish invocation captured; ACP text: {text}")
+ } else {
+ format!(
+ "no valid typed Buzz publish invocation; args={args:?}; ACP text={text}"
+ )
+ },
+ );
+ }
+ Err(error) => record(
+ &format!("P4.{attempt} Fizz selects typed Buzz publish tool"),
+ false,
+ error.to_string(),
+ ),
+ }
+ }
+
+ // P5: agentic tool use via buzz-dev-mcp — write a real file inside the
// isolated ACP working directory. The MCP sandbox intentionally rejects
// nonexistent absolute paths outside that root.
let marker_name = format!("mesh-e2e-{}.txt", std::process::id());
@@ -154,7 +193,7 @@ async fn run() -> anyhow::Result<()> {
.unwrap_or(false);
match r {
Ok(text) => record(
- "P4 agentic tool use",
+ "P5 agentic tool use",
file_ok,
if file_ok {
format!("file written; agent said: {text}")
@@ -162,7 +201,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("P5 agentic tool use", file_ok, format!("agent error: {e}")),
}
let _ = std::fs::remove_file(&marker);
@@ -175,6 +214,37 @@ async fn run() -> anyhow::Result<()> {
std::process::exit(0);
}
+async fn fizz_publish_turn(
+ base: &str,
+ model: &str,
+) -> (anyhow::Result, std::path::PathBuf) {
+ let root = std::env::temp_dir().join(format!("mesh-fizz-e2e-{}", std::process::id()));
+ let capture = root.join("tool-calls.json");
+ if let Err(error) = std::fs::create_dir_all(&root) {
+ return (Err(error.into()), capture);
+ }
+
+ let dev_mcp = match repo_bin("buzz-dev-mcp") {
+ Ok(path) => vec![("dev".to_string(), path)],
+ Err(error) => return (Err(error), capture),
+ };
+ let system_prompt = format!("{BUZZ_BASE_PROMPT}\n\n[System]\n{FIZZ_SYSTEM_PROMPT}");
+ let prompt = format!(
+ "[Context]\nChannel UUID: {FIZZ_TEST_CHANNEL}\nReply destination: top-level channel message.\n\n[Buzz event: message]\n@Fizz Reply exactly FIZZ_MESH_CONTRACT_OK. You must follow the Buzz communication contract and publish the reply to this channel."
+ );
+ let (result, _) = agent_chat_with_setup(
+ base,
+ model,
+ &prompt,
+ &dev_mcp,
+ &system_prompt,
+ None,
+ Some(&capture),
+ )
+ .await;
+ (result, capture)
+}
+
fn repo_bin(name: &str) -> anyhow::Result {
let path = std::env::current_dir()?.join("target/release").join(name);
anyhow::ensure!(
@@ -214,6 +284,27 @@ async fn agent_chat_in_isolated_home(
model: &str,
prompt: &str,
mcp_servers: &[(String, String)],
+) -> (anyhow::Result, std::path::PathBuf) {
+ agent_chat_with_setup(
+ base,
+ model,
+ prompt,
+ mcp_servers,
+ BUZZ_BASE_PROMPT,
+ None,
+ None,
+ )
+ .await
+}
+
+async fn agent_chat_with_setup(
+ base: &str,
+ model: &str,
+ prompt: &str,
+ mcp_servers: &[(String, String)],
+ system_prompt: &str,
+ path_prefix: Option<&std::path::Path>,
+ tool_call_capture: Option<&std::path::Path>,
) -> (anyhow::Result, std::path::PathBuf) {
let agent = match repo_bin("buzz-agent") {
Ok(agent) => agent,
@@ -225,9 +316,22 @@ async fn agent_chat_in_isolated_home(
return (Err(error.into()), home);
}
+ let test_nsec = match Keys::generate().secret_key().to_bech32() {
+ Ok(key) => key,
+ Err(error) => return (Err(error.into()), home),
+ };
+ let path = path_prefix
+ .map(|prefix| {
+ format!(
+ "{}:{}",
+ prefix.display(),
+ std::env::var("PATH").unwrap_or_default()
+ )
+ })
+ .unwrap_or_else(|| std::env::var("PATH").unwrap_or_default());
let mut child = match Command::new(&agent)
.env_clear()
- .env("PATH", std::env::var("PATH").unwrap_or_default())
+ .env("PATH", path)
.env("HOME", &home)
// Exactly the relay-mesh preset env (preset.rs).
.env("BUZZ_AGENT_PROVIDER", "openai")
@@ -237,6 +341,12 @@ async fn agent_chat_in_isolated_home(
.env("OPENAI_COMPAT_API_KEY", "buzz-mesh-local")
.env("OPENAI_COMPAT_API", "chat")
.env("OPENAI_COMPAT_OMIT_MAX_TOKENS", "true")
+ .env("BUZZ_AGENT_THINKING_EFFORT", "none")
+ // Real desktop launches inject these into the harness and MCP server.
+ // Hermetic placeholders satisfy the CLI preflight; the test-local
+ // `buzz` shim records the command without contacting a relay.
+ .env("BUZZ_RELAY_URL", "ws://127.0.0.1:1")
+ .env("BUZZ_PRIVATE_KEY", test_nsec)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
@@ -246,17 +356,30 @@ 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, system_prompt)
+ .await
+ .and_then(|turn| {
+ if let Some(path) = tool_call_capture {
+ std::fs::write(path, serde_json::to_vec_pretty(&turn.tool_calls)?)?;
+ }
+ Ok(turn.text)
+ });
let _ = child.kill().await;
(result, home)
}
+struct AcpTurnResult {
+ text: String,
+ tool_calls: Vec,
+}
+
async fn drive_acp(
child: &mut Child,
prompt: &str,
mcp_servers: &[(String, String)],
cwd: &std::path::Path,
-) -> anyhow::Result {
+ system_prompt: &str,
+) -> anyhow::Result {
let mut stdin = child
.stdin
.take()
@@ -291,7 +414,7 @@ async fn drive_acp(
"params": {
"cwd": cwd.to_string_lossy(),
"mcpServers": mcp_json,
- "systemPrompt": BUZZ_BASE_PROMPT
+ "systemPrompt": system_prompt
}
}))
.as_bytes(),
@@ -300,6 +423,7 @@ async fn drive_acp(
let mut session_id: Option = None;
let mut agent_text = String::new();
+ let mut tool_calls = Vec::new();
let deadline = tokio::time::Instant::now() + Duration::from_secs(600);
loop {
@@ -317,6 +441,8 @@ async fn drive_acp(
let update = &msg["params"]["update"];
if update["sessionUpdate"] == "agent_message_chunk" {
collect_text(update, &mut agent_text);
+ } else if update["sessionUpdate"] == "tool_call" {
+ tool_calls.push(update.clone());
}
continue;
}
@@ -348,7 +474,10 @@ async fn drive_acp(
if let Some(err) = msg.get("error") {
anyhow::bail!("session/prompt failed: {err}");
}
- return Ok(agent_text.trim().to_string());
+ return Ok(AcpTurnResult {
+ text: agent_text.trim().to_string(),
+ tool_calls,
+ });
}
_ => {}
}
diff --git a/desktop/src-tauri/src/managed_agents/fizz_system_prompt.md b/desktop/src-tauri/src/managed_agents/fizz_system_prompt.md
new file mode 100644
index 0000000000..82007d0b91
--- /dev/null
+++ b/desktop/src-tauri/src/managed_agents/fizz_system_prompt.md
@@ -0,0 +1,19 @@
+You are Fizz. You are a careful, direct engineering agent with a subtle bee theme: collaborative, industrious, and precise. Keep the bee motif light — no catchphrases, no cartoon impersonation, and no performative roleplay. Reliability beats performance theater.
+
+# Subagents and Peers
+
+Other agents are peers, not tools. Collaborate when useful, but partition ownership by file or task so two writers never edit the same path. Front-load setup before tagging someone, agree on the base and handoff contract, and integrate their results without also doing their exact work.
+
+Use subagents when:
+
+- You can decompose research into unrelated areas explored in parallel.
+- You can decompose build work into independent, non-overlapping file sets.
+- A task needs a long-running command while you continue other work.
+
+Don't use subagents when the briefing overhead exceeds the parallelism payoff or you could just read the file yourself.
+
+# Communication
+
+- Bee-themed emoji are okay, but use them sparingly — at most one when it genuinely adds warmth or clarity, and skip them entirely in serious, blocked, or failure updates.
+
+Your name is Fizz. You are friendly, helpful, and quietly industrious — more honeycomb than hornet.
diff --git a/desktop/src-tauri/src/managed_agents/personas.rs b/desktop/src-tauri/src/managed_agents/personas.rs
index 605148b197..d498183bc9 100644
--- a/desktop/src-tauri/src/managed_agents/personas.rs
+++ b/desktop/src-tauri/src/managed_agents/personas.rs
@@ -24,25 +24,7 @@ const WORK_COORDINATOR_AVATAR: &str = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0
const SUPPORT_GUIDE_AVATAR: &str = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cmVjdCB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgcng9IjMyIiBmaWxsPSIjNmE3MDMxIi8+PGNpcmNsZSBjeD0iOTYiIGN5PSIzMiIgcj0iMTYiIGZpbGw9IiNmMmY2ZDciIGZpbGwtb3BhY2l0eT0iLjI4Ii8+PHBhdGggZD0iTTI0IDk0YzE0LTI1IDI3LTM3IDQwLTM3czI2IDEyIDQwIDM3IiBmaWxsPSJub25lIiBzdHJva2U9IiNmMmY2ZDciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHRleHQgeD0iNjQiIHk9IjcyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iSW50ZXIsQXJpYWwsc2Fucy1zZXJpZiIgZm9udC1zaXplPSIzNCIgZm9udC13ZWlnaHQ9IjcwMCIgZmlsbD0iI2YyZjZkNyI+U0c8L3RleHQ+PC9zdmc+";
const EXPERIMENT_DESIGNER_AVATAR: &str = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cmVjdCB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgcng9IjMyIiBmaWxsPSIjOGIzZjVlIi8+PGNpcmNsZSBjeD0iOTYiIGN5PSIzMiIgcj0iMTYiIGZpbGw9IiNmZmU3ZjAiIGZpbGwtb3BhY2l0eT0iLjI4Ii8+PHBhdGggZD0iTTI0IDk0YzE0LTI1IDI3LTM3IDQwLTM3czI2IDEyIDQwIDM3IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmU3ZjAiIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHRleHQgeD0iNjQiIHk9IjcyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iSW50ZXIsQXJpYWwsc2Fucy1zZXJpZiIgZm9udC1zaXplPSIzNCIgZm9udC13ZWlnaHQ9IjcwMCIgZmlsbD0iI2ZmZTdmMCI+RUQ8L3RleHQ+PC9zdmc+";
-const FIZZ_SYSTEM_PROMPT: &str = r#"You are Fizz. You are a careful, direct engineering agent with a subtle bee theme: collaborative, industrious, and precise. Keep the bee motif light — no catchphrases, no cartoon impersonation, and no performative roleplay. Reliability beats performance theater.
-
-# Subagents and Peers
-
-Other agents are peers, not tools. Collaborate when useful, but partition ownership by file or task so two writers never edit the same path. Front-load setup before tagging someone, agree on the base and handoff contract, and integrate their results without also doing their exact work.
-
-Use subagents when:
-
-- You can decompose research into unrelated areas explored in parallel.
-- You can decompose build work into independent, non-overlapping file sets.
-- A task needs a long-running command while you continue other work.
-
-Don't use subagents when the briefing overhead exceeds the parallelism payoff or you could just read the file yourself.
-
-# Communication
-
-- Bee-themed emoji are okay, but use them sparingly — at most one when it genuinely adds warmth or clarity, and skip them entirely in serious, blocked, or failure updates.
-
-Your name is Fizz. You are friendly, helpful, and quietly industrious — more honeycomb than hornet."#;
+const FIZZ_SYSTEM_PROMPT: &str = include_str!("fizz_system_prompt.md");
const PRODUCT_STRATEGIST_SYSTEM_PROMPT: &str = r#"You are a product strategy agent. You help turn broad ideas into clear product and design direction.
diff --git a/desktop/src-tauri/src/managed_agents/relay_mesh.rs b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
index 999baf5485..9d989915fb 100644
--- a/desktop/src-tauri/src/managed_agents/relay_mesh.rs
+++ b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
@@ -35,6 +35,11 @@ pub fn apply_relay_mesh_env(
RELAY_MESH_API_KEY_PLACEHOLDER.to_string(),
);
env.insert("OPENAI_COMPAT_API".to_string(), "chat".to_string());
+ // Agent/tool turns require a visible answer or complete tool call. MeshLLM
+ // canonicalizes OpenAI's model-agnostic `reasoning_effort: none` into the
+ // selected runtime's thinking-disable control (for example Qwen's
+ // `chat_template_kwargs.enable_thinking=false`).
+ env.insert("BUZZ_AGENT_THINKING_EFFORT".to_string(), "none".to_string());
// Match Goose's OpenAI-compatible behavior for unknown local models: let
// MeshLLM enforce the selected model's discovered generation/context
// limits instead of imposing a harness-wide cap.
@@ -198,6 +203,10 @@ mod tests {
env.get("OPENAI_COMPAT_OMIT_MAX_TOKENS").map(String::as_str),
Some("true")
);
+ assert_eq!(
+ env.get("BUZZ_AGENT_THINKING_EFFORT").map(String::as_str),
+ Some("none")
+ );
assert!(!env.contains_key("BUZZ_AGENT_MAX_OUTPUT_TOKENS"));
}
diff --git a/desktop/src-tauri/src/mesh_llm/catalog.rs b/desktop/src-tauri/src/mesh_llm/catalog.rs
index 34de3faeb5..b668a36faa 100644
--- a/desktop/src-tauri/src/mesh_llm/catalog.rs
+++ b/desktop/src-tauri/src/mesh_llm/catalog.rs
@@ -36,6 +36,19 @@ fn fit_code(model_gb: f64, vram_gb: f64) -> ModelFit {
}
}
+fn agent_suitability(name: &str) -> u8 {
+ match name {
+ // Repeated real-hardware Fizz publication + ordinary chat + file-tool
+ // gates pass with the shared-compute request policy.
+ "Gemma-4-E4B-it-Q4_K_M" => 3,
+ "Qwen3-8B-Q4_K_M" => 2,
+ // MeshLLM's catalog explicitly identifies these as Goose defaults with
+ // good/strong agent tool calling. Keep below locally verified models.
+ "Hermes-2-Pro-Mistral-7B-Q4_K_M" | "Llama-3.2-3B-Instruct-Q4_K_M" => 1,
+ _ => 0,
+ }
+}
+
fn fit_rank(fit: ModelFit) -> u8 {
match fit {
ModelFit::Comfortable => 0,
@@ -188,11 +201,11 @@ fn build_catalog(
})
.collect();
- // Recommendation: prefer what's already on disk. The largest installed
- // general-purpose model that fits comfortably starts instantly — a far
- // better first-run than upstream's pack, which optimizes for a fresh
- // machine and would trigger a multi-GB download. Coder-specialized
- // models are skipped (a shared chat/agent model should be general).
+ // Recommendation: prefer an agent-suitable model that's already on disk.
+ // Fizz needs reliable structured tool use, not merely good chat prose, so
+ // models that pass the real hardware Fizz contract outrank unverified
+ // general models. Within the same suitability tier, prefer the larger
+ // comfortable model. Coder-specialized models are skipped.
// Fall back to upstream `auto_model_pack` when nothing suitable is
// installed.
let installed_pick = MODEL_CATALOG
@@ -204,7 +217,11 @@ fn build_catalog(
fit_code(size_gb, vram_gb) == ModelFit::Comfortable
&& !m.name.to_ascii_lowercase().contains("coder")
})
- .max_by(|a, b| parse_size_gb(&a.size).total_cmp(&parse_size_gb(&b.size)))
+ .max_by(|a, b| {
+ agent_suitability(&a.name)
+ .cmp(&agent_suitability(&b.name))
+ .then(parse_size_gb(&a.size).total_cmp(&parse_size_gb(&b.size)))
+ })
.map(|m| m.name.clone());
let recommended = installed_pick.or_else(|| auto_model_pack(vram_gb).into_iter().next());
for entry in &mut entries {
@@ -310,6 +327,25 @@ mod tests {
assert!(fresh.recommended.is_some());
}
+ #[test]
+ fn recommendation_prefers_verified_agent_model_over_larger_chat_model() {
+ let installed = vec![
+ (
+ "Qwen3-30B-A3B-Q4_K_M.gguf".to_string(),
+ "unsloth/Qwen3-30B-A3B-GGUF:Q4_K_M".to_string(),
+ ),
+ (
+ "gemma-4-E4B-it-Q4_K_M.gguf".to_string(),
+ "unsloth/gemma-4-E4B-it-GGUF:Q4_K_M".to_string(),
+ ),
+ ];
+ let catalog = build_catalog(None, 64_000_000_000, 64.0, &installed, &[]);
+ assert_eq!(
+ catalog.recommended.as_deref(),
+ Some("Gemma-4-E4B-it-Q4_K_M")
+ );
+ }
+
#[test]
fn recommendation_skips_incomplete_layer_packages() {
// Regression: Qwen3-30B-A3B's GGUF was cached but its meshllm layer
@@ -334,9 +370,10 @@ mod tests {
Some("Qwen3-8B-Q4_K_M"),
"incomplete layer package must not be the instant-start pick"
);
- // Same cache with the 30B package complete -> 30B wins again.
+ // Even when the larger package is complete, the verified Fizz-capable
+ // model remains the safer agent recommendation.
let catalog = build_catalog(None, 64_000_000_000, 64.0, &installed, &[]);
- assert_eq!(catalog.recommended.as_deref(), Some("Qwen3-30B-A3B-Q4_K_M"));
+ assert_eq!(catalog.recommended.as_deref(), Some("Qwen3-8B-Q4_K_M"));
}
#[test]
diff --git a/docs/buzz-shared-compute-dev.md b/docs/buzz-shared-compute-dev.md
index aeb87446bc..a12e6aa824 100644
--- a/docs/buzz-shared-compute-dev.md
+++ b/docs/buzz-shared-compute-dev.md
@@ -39,9 +39,10 @@ runtime are behind the `mesh-llm` feature.
1. Open **Settings**.
2. Select **Compute**.
3. Under **Share compute**, choose a suggested model.
- - On a 16 GB Apple Silicon machine, use a suggested Qwen3.5 4B quantized
- model when available.
- - `unsloth/Qwen3.5-4B-GGUF:Q4_K_M` is the model used by the hardware proof.
+ - Prefer `Gemma-4-E4B-it-Q4_K_M` when it is suggested; it passes repeated
+ real-hardware Fizz publication, ordinary chat, and file-tool checks.
+ - `Qwen3-8B-Q4_K_M` is the verified fallback. Models smaller than these may
+ chat successfully but are not recommended for Fizz's structured tool use.
4. Turn on **Share this machine**.
5. Wait until the card says it is sharing/running. Do not start Fizz while the
card says downloading, preparing, or starting.
From c549772c302bdc6dae676b8c195d00e5e8769f1d Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 08:38:39 +1000
Subject: [PATCH 26/35] Revert "fix(mesh): make Fizz reliable on local models"
This reverts commit ba7f836c8293d8092bd91d1f7a60d27a5b5aec9a.
---
crates/buzz-acp/src/base_prompt.md | 2 +-
crates/buzz-dev-mcp/src/buzz_message.rs | 101 ------------
crates/buzz-dev-mcp/src/lib.rs | 12 --
crates/buzz-relay/examples/mesh_agent_e2e.rs | 151 ++----------------
.../src/managed_agents/fizz_system_prompt.md | 19 ---
.../src-tauri/src/managed_agents/personas.rs | 20 ++-
.../src/managed_agents/relay_mesh.rs | 9 --
desktop/src-tauri/src/mesh_llm/catalog.rs | 53 +-----
docs/buzz-shared-compute-dev.md | 7 +-
9 files changed, 42 insertions(+), 332 deletions(-)
delete mode 100644 crates/buzz-dev-mcp/src/buzz_message.rs
delete mode 100644 desktop/src-tauri/src/managed_agents/fizz_system_prompt.md
diff --git a/crates/buzz-acp/src/base_prompt.md b/crates/buzz-acp/src/base_prompt.md
index ff1eacdc16..fe2ea7107b 100644
--- a/crates/buzz-acp/src/base_prompt.md
+++ b/crates/buzz-acp/src/base_prompt.md
@@ -47,7 +47,7 @@ All replies and delegations — including task assignments to other agents — g
### General
- Respond promptly to @mentions. Be direct — no preamble. Name what you did, what you found, or what you need.
-- **Every turn that processes a user message MUST publish a reply.** Prefer the dedicated `buzz_send_message` tool when available; otherwise use `buzz messages send`. Your reasoning and other tool calls are invisible to users — if you didn't publish a message, they saw nothing. A turn that ends without a sent message is a silent failure.
+- **Every turn that processes a user message MUST end with `buzz messages send`.** Your reasoning and tool calls are invisible to users — if you didn't send a message, they saw nothing. A turn that ends without a sent message is a silent failure.
- For work that requires follow-up tools, create an open todo **before** sending the pickup acknowledgment. Keep it open until the deliverable is verified and you have sent a completion or blocker message; never end a turn with open todo state unless you have posted that completion or blocker message.
- Use GitHub-flavored Markdown. Fenced code blocks with language tags for syntax highlighting.
- No push notifications — poll with `buzz messages get --channel --since `.
diff --git a/crates/buzz-dev-mcp/src/buzz_message.rs b/crates/buzz-dev-mcp/src/buzz_message.rs
deleted file mode 100644
index 5589e2f888..0000000000
--- a/crates/buzz-dev-mcp/src/buzz_message.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-use crate::shell::SharedState;
-use rmcp::model::{CallToolResult, Content};
-use rmcp::ErrorData;
-use schemars::JsonSchema;
-use serde::Deserialize;
-use std::path::PathBuf;
-use std::process::Stdio;
-use tokio::process::Command;
-
-const MAX_CONTENT_BYTES: usize = 64 * 1024;
-
-#[derive(Debug, Deserialize, JsonSchema)]
-pub struct SendMessageParams {
- /// Buzz channel UUID supplied in the turn's Context section.
- pub channel: String,
- /// Message body to publish.
- pub content: String,
- /// Optional event id to reply to when the Context section requires a threaded reply.
- #[serde(default)]
- pub reply_to: Option,
-}
-
-pub async fn run(
- state: &SharedState,
- params: SendMessageParams,
-) -> Result {
- if params.content.trim().is_empty() {
- return Err(ErrorData::invalid_params(
- "content must not be empty".to_string(),
- None,
- ));
- }
- if params.content.len() > MAX_CONTENT_BYTES {
- return Err(ErrorData::invalid_params(
- format!("content exceeds {MAX_CONTENT_BYTES} bytes"),
- None,
- ));
- }
-
- let buzz = find_buzz(&state.shim.path_env).ok_or_else(|| {
- ErrorData::internal_error("bundled Buzz CLI is unavailable".to_string(), None)
- })?;
- let mut command = Command::new(buzz);
- command
- .args([
- "messages",
- "send",
- "--channel",
- ¶ms.channel,
- "--content",
- ¶ms.content,
- ])
- .current_dir(&state.cwd)
- .env("PATH", &state.shim.path_env)
- .stdin(Stdio::null())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped());
- if let Some(reply_to) = params.reply_to.as_deref() {
- command.args(["--reply-to", reply_to]);
- }
-
- let output = command.output().await.map_err(|error| {
- ErrorData::internal_error(format!("failed to run Buzz CLI: {error}"), None)
- })?;
- let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
- let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
- if output.status.success() {
- let text = if stdout.is_empty() {
- "Message published.".to_string()
- } else {
- stdout
- };
- Ok(CallToolResult::success(vec![Content::text(text)]))
- } else {
- let detail = if stderr.is_empty() { stdout } else { stderr };
- Ok(CallToolResult::error(vec![Content::text(format!(
- "Buzz message failed: {detail}"
- ))]))
- }
-}
-
-fn find_buzz(path: &str) -> Option {
- std::env::split_paths(path)
- .map(|entry| entry.join(if cfg!(windows) { "buzz.exe" } else { "buzz" }))
- .find(|candidate| candidate.is_file())
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn finds_bundled_buzz_on_path() {
- let dir = tempfile::tempdir().unwrap();
- let path = dir
- .path()
- .join(if cfg!(windows) { "buzz.exe" } else { "buzz" });
- std::fs::write(&path, "test").unwrap();
- assert_eq!(find_buzz(&dir.path().to_string_lossy()), Some(path));
- }
-}
diff --git a/crates/buzz-dev-mcp/src/lib.rs b/crates/buzz-dev-mcp/src/lib.rs
index 9ebd27aeab..f9fced8e81 100644
--- a/crates/buzz-dev-mcp/src/lib.rs
+++ b/crates/buzz-dev-mcp/src/lib.rs
@@ -10,7 +10,6 @@ use rmcp::{
use std::path::Path;
use std::sync::Arc;
-mod buzz_message;
mod paths;
mod read_file;
mod rg;
@@ -50,17 +49,6 @@ impl DevMcp {
shell::run(&self.state, p, context.ct).await
}
- #[tool(
- name = "buzz_send_message",
- description = "Publish the user-visible reply for the current Buzz turn. Use the channel UUID and optional reply event id from the prompt's Context section. Prefer this typed tool over constructing `buzz messages send` in the shell. Every turn that processes a Buzz user message must call this before ending."
- )]
- async fn buzz_send_message(
- &self,
- Parameters(p): Parameters,
- ) -> Result {
- buzz_message::run(&self.state, p).await
- }
-
#[tool(
name = "read_file",
description = "Read a text file and return its contents with line numbers. Returns lines in `{number}:{content}` format. Use `offset` (0-based) and `limit` (default 2000) to window into large files. Path resolved relative to workdir (defaults to server cwd). Prefer over cat/head/tail."
diff --git a/crates/buzz-relay/examples/mesh_agent_e2e.rs b/crates/buzz-relay/examples/mesh_agent_e2e.rs
index 854a3c8aea..3846d4339f 100644
--- a/crates/buzz-relay/examples/mesh_agent_e2e.rs
+++ b/crates/buzz-relay/examples/mesh_agent_e2e.rs
@@ -6,9 +6,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 repeated ordinary chat — each turn emits user-visible ACP text.
-//! P4 repeated Fizz publish — real Fizz selects the typed Buzz publish tool.
-//! P5 agentic tool use — agent + buzz-dev-mcp writes a verified file.
+//! P3 repeated ordinary chat — several normal prompts must each produce a
+//! user-visible ACP message, never reasoning-only silent success.
+//! 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
//! (publish off, mdns, loopback). The agent legs spawn the real
@@ -22,7 +22,6 @@ use std::process::Stdio;
use std::time::Duration;
use mesh_llm_sdk::{serve, MeshDiscoveryMode};
-use nostr::{Keys, ToBech32};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::process::{Child, Command};
@@ -34,9 +33,6 @@ const DEFAULT_MODEL: &str = "unsloth/Qwen3-8B-GGUF:Q4_K_M";
const API_PORT: u16 = 19437;
const CONSOLE_PORT: u16 = 13231;
const BUZZ_BASE_PROMPT: &str = include_str!("../../buzz-acp/src/base_prompt.md");
-const FIZZ_SYSTEM_PROMPT: &str =
- include_str!("../../../desktop/src-tauri/src/managed_agents/fizz_system_prompt.md");
-const FIZZ_TEST_CHANNEL: &str = "11111111-2222-4333-8444-555555555555";
fn main() -> anyhow::Result<()> {
tokio::runtime::Builder::new_multi_thread()
@@ -144,42 +140,7 @@ async fn run() -> anyhow::Result<()> {
}
}
- // P4: the actual Fizz/Buzz contract. Visible ACP prose is insufficient:
- // Fizz must select the typed Buzz publish tool. Capturing ACP tool calls
- // keeps this relay/keychain independent while exercising the real Fizz
- // prompt, buzz-agent, and developer MCP.
- for attempt in 1..=3 {
- let (fizz_result, fizz_capture) = fizz_publish_turn(&base, "auto").await;
- match fizz_result {
- Ok(text) => {
- let args = std::fs::read_to_string(&fizz_capture).unwrap_or_default();
- let calls: Vec = serde_json::from_str(&args).unwrap_or_default();
- let published = calls.iter().any(|call| {
- call["title"] == "dev__buzz_send_message"
- && call["rawInput"]["channel"] == FIZZ_TEST_CHANNEL
- && call["rawInput"]["content"] == "FIZZ_MESH_CONTRACT_OK"
- });
- record(
- &format!("P4.{attempt} Fizz selects typed Buzz publish tool"),
- published,
- if published {
- format!("typed publish invocation captured; ACP text: {text}")
- } else {
- format!(
- "no valid typed Buzz publish invocation; args={args:?}; ACP text={text}"
- )
- },
- );
- }
- Err(error) => record(
- &format!("P4.{attempt} Fizz selects typed Buzz publish tool"),
- false,
- error.to_string(),
- ),
- }
- }
-
- // P5: agentic tool use via buzz-dev-mcp — write a real file inside the
+ // P4: agentic tool use via buzz-dev-mcp — write a real file inside the
// isolated ACP working directory. The MCP sandbox intentionally rejects
// nonexistent absolute paths outside that root.
let marker_name = format!("mesh-e2e-{}.txt", std::process::id());
@@ -193,7 +154,7 @@ async fn run() -> anyhow::Result<()> {
.unwrap_or(false);
match r {
Ok(text) => record(
- "P5 agentic tool use",
+ "P4 agentic tool use",
file_ok,
if file_ok {
format!("file written; agent said: {text}")
@@ -201,7 +162,7 @@ async fn run() -> anyhow::Result<()> {
format!("no file at {}; agent said: {text}", marker.display())
},
),
- Err(e) => record("P5 agentic tool use", file_ok, format!("agent error: {e}")),
+ Err(e) => record("P4 agentic tool use", file_ok, format!("agent error: {e}")),
}
let _ = std::fs::remove_file(&marker);
@@ -214,37 +175,6 @@ async fn run() -> anyhow::Result<()> {
std::process::exit(0);
}
-async fn fizz_publish_turn(
- base: &str,
- model: &str,
-) -> (anyhow::Result, std::path::PathBuf) {
- let root = std::env::temp_dir().join(format!("mesh-fizz-e2e-{}", std::process::id()));
- let capture = root.join("tool-calls.json");
- if let Err(error) = std::fs::create_dir_all(&root) {
- return (Err(error.into()), capture);
- }
-
- let dev_mcp = match repo_bin("buzz-dev-mcp") {
- Ok(path) => vec![("dev".to_string(), path)],
- Err(error) => return (Err(error), capture),
- };
- let system_prompt = format!("{BUZZ_BASE_PROMPT}\n\n[System]\n{FIZZ_SYSTEM_PROMPT}");
- let prompt = format!(
- "[Context]\nChannel UUID: {FIZZ_TEST_CHANNEL}\nReply destination: top-level channel message.\n\n[Buzz event: message]\n@Fizz Reply exactly FIZZ_MESH_CONTRACT_OK. You must follow the Buzz communication contract and publish the reply to this channel."
- );
- let (result, _) = agent_chat_with_setup(
- base,
- model,
- &prompt,
- &dev_mcp,
- &system_prompt,
- None,
- Some(&capture),
- )
- .await;
- (result, capture)
-}
-
fn repo_bin(name: &str) -> anyhow::Result {
let path = std::env::current_dir()?.join("target/release").join(name);
anyhow::ensure!(
@@ -284,27 +214,6 @@ async fn agent_chat_in_isolated_home(
model: &str,
prompt: &str,
mcp_servers: &[(String, String)],
-) -> (anyhow::Result, std::path::PathBuf) {
- agent_chat_with_setup(
- base,
- model,
- prompt,
- mcp_servers,
- BUZZ_BASE_PROMPT,
- None,
- None,
- )
- .await
-}
-
-async fn agent_chat_with_setup(
- base: &str,
- model: &str,
- prompt: &str,
- mcp_servers: &[(String, String)],
- system_prompt: &str,
- path_prefix: Option<&std::path::Path>,
- tool_call_capture: Option<&std::path::Path>,
) -> (anyhow::Result, std::path::PathBuf) {
let agent = match repo_bin("buzz-agent") {
Ok(agent) => agent,
@@ -316,22 +225,9 @@ async fn agent_chat_with_setup(
return (Err(error.into()), home);
}
- let test_nsec = match Keys::generate().secret_key().to_bech32() {
- Ok(key) => key,
- Err(error) => return (Err(error.into()), home),
- };
- let path = path_prefix
- .map(|prefix| {
- format!(
- "{}:{}",
- prefix.display(),
- std::env::var("PATH").unwrap_or_default()
- )
- })
- .unwrap_or_else(|| std::env::var("PATH").unwrap_or_default());
let mut child = match Command::new(&agent)
.env_clear()
- .env("PATH", path)
+ .env("PATH", std::env::var("PATH").unwrap_or_default())
.env("HOME", &home)
// Exactly the relay-mesh preset env (preset.rs).
.env("BUZZ_AGENT_PROVIDER", "openai")
@@ -341,12 +237,6 @@ async fn agent_chat_with_setup(
.env("OPENAI_COMPAT_API_KEY", "buzz-mesh-local")
.env("OPENAI_COMPAT_API", "chat")
.env("OPENAI_COMPAT_OMIT_MAX_TOKENS", "true")
- .env("BUZZ_AGENT_THINKING_EFFORT", "none")
- // Real desktop launches inject these into the harness and MCP server.
- // Hermetic placeholders satisfy the CLI preflight; the test-local
- // `buzz` shim records the command without contacting a relay.
- .env("BUZZ_RELAY_URL", "ws://127.0.0.1:1")
- .env("BUZZ_PRIVATE_KEY", test_nsec)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
@@ -356,30 +246,17 @@ async fn agent_chat_with_setup(
Err(error) => return (Err(error.into()), home),
};
- let result = drive_acp(&mut child, prompt, mcp_servers, &home, system_prompt)
- .await
- .and_then(|turn| {
- if let Some(path) = tool_call_capture {
- std::fs::write(path, serde_json::to_vec_pretty(&turn.tool_calls)?)?;
- }
- Ok(turn.text)
- });
+ let result = drive_acp(&mut child, prompt, mcp_servers, &home).await;
let _ = child.kill().await;
(result, home)
}
-struct AcpTurnResult {
- text: String,
- tool_calls: Vec,
-}
-
async fn drive_acp(
child: &mut Child,
prompt: &str,
mcp_servers: &[(String, String)],
cwd: &std::path::Path,
- system_prompt: &str,
-) -> anyhow::Result {
+) -> anyhow::Result {
let mut stdin = child
.stdin
.take()
@@ -414,7 +291,7 @@ async fn drive_acp(
"params": {
"cwd": cwd.to_string_lossy(),
"mcpServers": mcp_json,
- "systemPrompt": system_prompt
+ "systemPrompt": BUZZ_BASE_PROMPT
}
}))
.as_bytes(),
@@ -423,7 +300,6 @@ async fn drive_acp(
let mut session_id: Option = None;
let mut agent_text = String::new();
- let mut tool_calls = Vec::new();
let deadline = tokio::time::Instant::now() + Duration::from_secs(600);
loop {
@@ -441,8 +317,6 @@ async fn drive_acp(
let update = &msg["params"]["update"];
if update["sessionUpdate"] == "agent_message_chunk" {
collect_text(update, &mut agent_text);
- } else if update["sessionUpdate"] == "tool_call" {
- tool_calls.push(update.clone());
}
continue;
}
@@ -474,10 +348,7 @@ async fn drive_acp(
if let Some(err) = msg.get("error") {
anyhow::bail!("session/prompt failed: {err}");
}
- return Ok(AcpTurnResult {
- text: agent_text.trim().to_string(),
- tool_calls,
- });
+ return Ok(agent_text.trim().to_string());
}
_ => {}
}
diff --git a/desktop/src-tauri/src/managed_agents/fizz_system_prompt.md b/desktop/src-tauri/src/managed_agents/fizz_system_prompt.md
deleted file mode 100644
index 82007d0b91..0000000000
--- a/desktop/src-tauri/src/managed_agents/fizz_system_prompt.md
+++ /dev/null
@@ -1,19 +0,0 @@
-You are Fizz. You are a careful, direct engineering agent with a subtle bee theme: collaborative, industrious, and precise. Keep the bee motif light — no catchphrases, no cartoon impersonation, and no performative roleplay. Reliability beats performance theater.
-
-# Subagents and Peers
-
-Other agents are peers, not tools. Collaborate when useful, but partition ownership by file or task so two writers never edit the same path. Front-load setup before tagging someone, agree on the base and handoff contract, and integrate their results without also doing their exact work.
-
-Use subagents when:
-
-- You can decompose research into unrelated areas explored in parallel.
-- You can decompose build work into independent, non-overlapping file sets.
-- A task needs a long-running command while you continue other work.
-
-Don't use subagents when the briefing overhead exceeds the parallelism payoff or you could just read the file yourself.
-
-# Communication
-
-- Bee-themed emoji are okay, but use them sparingly — at most one when it genuinely adds warmth or clarity, and skip them entirely in serious, blocked, or failure updates.
-
-Your name is Fizz. You are friendly, helpful, and quietly industrious — more honeycomb than hornet.
diff --git a/desktop/src-tauri/src/managed_agents/personas.rs b/desktop/src-tauri/src/managed_agents/personas.rs
index d498183bc9..605148b197 100644
--- a/desktop/src-tauri/src/managed_agents/personas.rs
+++ b/desktop/src-tauri/src/managed_agents/personas.rs
@@ -24,7 +24,25 @@ const WORK_COORDINATOR_AVATAR: &str = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0
const SUPPORT_GUIDE_AVATAR: &str = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cmVjdCB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgcng9IjMyIiBmaWxsPSIjNmE3MDMxIi8+PGNpcmNsZSBjeD0iOTYiIGN5PSIzMiIgcj0iMTYiIGZpbGw9IiNmMmY2ZDciIGZpbGwtb3BhY2l0eT0iLjI4Ii8+PHBhdGggZD0iTTI0IDk0YzE0LTI1IDI3LTM3IDQwLTM3czI2IDEyIDQwIDM3IiBmaWxsPSJub25lIiBzdHJva2U9IiNmMmY2ZDciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHRleHQgeD0iNjQiIHk9IjcyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iSW50ZXIsQXJpYWwsc2Fucy1zZXJpZiIgZm9udC1zaXplPSIzNCIgZm9udC13ZWlnaHQ9IjcwMCIgZmlsbD0iI2YyZjZkNyI+U0c8L3RleHQ+PC9zdmc+";
const EXPERIMENT_DESIGNER_AVATAR: &str = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cmVjdCB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgcng9IjMyIiBmaWxsPSIjOGIzZjVlIi8+PGNpcmNsZSBjeD0iOTYiIGN5PSIzMiIgcj0iMTYiIGZpbGw9IiNmZmU3ZjAiIGZpbGwtb3BhY2l0eT0iLjI4Ii8+PHBhdGggZD0iTTI0IDk0YzE0LTI1IDI3LTM3IDQwLTM3czI2IDEyIDQwIDM3IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmU3ZjAiIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHRleHQgeD0iNjQiIHk9IjcyIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iSW50ZXIsQXJpYWwsc2Fucy1zZXJpZiIgZm9udC1zaXplPSIzNCIgZm9udC13ZWlnaHQ9IjcwMCIgZmlsbD0iI2ZmZTdmMCI+RUQ8L3RleHQ+PC9zdmc+";
-const FIZZ_SYSTEM_PROMPT: &str = include_str!("fizz_system_prompt.md");
+const FIZZ_SYSTEM_PROMPT: &str = r#"You are Fizz. You are a careful, direct engineering agent with a subtle bee theme: collaborative, industrious, and precise. Keep the bee motif light — no catchphrases, no cartoon impersonation, and no performative roleplay. Reliability beats performance theater.
+
+# Subagents and Peers
+
+Other agents are peers, not tools. Collaborate when useful, but partition ownership by file or task so two writers never edit the same path. Front-load setup before tagging someone, agree on the base and handoff contract, and integrate their results without also doing their exact work.
+
+Use subagents when:
+
+- You can decompose research into unrelated areas explored in parallel.
+- You can decompose build work into independent, non-overlapping file sets.
+- A task needs a long-running command while you continue other work.
+
+Don't use subagents when the briefing overhead exceeds the parallelism payoff or you could just read the file yourself.
+
+# Communication
+
+- Bee-themed emoji are okay, but use them sparingly — at most one when it genuinely adds warmth or clarity, and skip them entirely in serious, blocked, or failure updates.
+
+Your name is Fizz. You are friendly, helpful, and quietly industrious — more honeycomb than hornet."#;
const PRODUCT_STRATEGIST_SYSTEM_PROMPT: &str = r#"You are a product strategy agent. You help turn broad ideas into clear product and design direction.
diff --git a/desktop/src-tauri/src/managed_agents/relay_mesh.rs b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
index 9d989915fb..999baf5485 100644
--- a/desktop/src-tauri/src/managed_agents/relay_mesh.rs
+++ b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
@@ -35,11 +35,6 @@ pub fn apply_relay_mesh_env(
RELAY_MESH_API_KEY_PLACEHOLDER.to_string(),
);
env.insert("OPENAI_COMPAT_API".to_string(), "chat".to_string());
- // Agent/tool turns require a visible answer or complete tool call. MeshLLM
- // canonicalizes OpenAI's model-agnostic `reasoning_effort: none` into the
- // selected runtime's thinking-disable control (for example Qwen's
- // `chat_template_kwargs.enable_thinking=false`).
- env.insert("BUZZ_AGENT_THINKING_EFFORT".to_string(), "none".to_string());
// Match Goose's OpenAI-compatible behavior for unknown local models: let
// MeshLLM enforce the selected model's discovered generation/context
// limits instead of imposing a harness-wide cap.
@@ -203,10 +198,6 @@ mod tests {
env.get("OPENAI_COMPAT_OMIT_MAX_TOKENS").map(String::as_str),
Some("true")
);
- assert_eq!(
- env.get("BUZZ_AGENT_THINKING_EFFORT").map(String::as_str),
- Some("none")
- );
assert!(!env.contains_key("BUZZ_AGENT_MAX_OUTPUT_TOKENS"));
}
diff --git a/desktop/src-tauri/src/mesh_llm/catalog.rs b/desktop/src-tauri/src/mesh_llm/catalog.rs
index b668a36faa..34de3faeb5 100644
--- a/desktop/src-tauri/src/mesh_llm/catalog.rs
+++ b/desktop/src-tauri/src/mesh_llm/catalog.rs
@@ -36,19 +36,6 @@ fn fit_code(model_gb: f64, vram_gb: f64) -> ModelFit {
}
}
-fn agent_suitability(name: &str) -> u8 {
- match name {
- // Repeated real-hardware Fizz publication + ordinary chat + file-tool
- // gates pass with the shared-compute request policy.
- "Gemma-4-E4B-it-Q4_K_M" => 3,
- "Qwen3-8B-Q4_K_M" => 2,
- // MeshLLM's catalog explicitly identifies these as Goose defaults with
- // good/strong agent tool calling. Keep below locally verified models.
- "Hermes-2-Pro-Mistral-7B-Q4_K_M" | "Llama-3.2-3B-Instruct-Q4_K_M" => 1,
- _ => 0,
- }
-}
-
fn fit_rank(fit: ModelFit) -> u8 {
match fit {
ModelFit::Comfortable => 0,
@@ -201,11 +188,11 @@ fn build_catalog(
})
.collect();
- // Recommendation: prefer an agent-suitable model that's already on disk.
- // Fizz needs reliable structured tool use, not merely good chat prose, so
- // models that pass the real hardware Fizz contract outrank unverified
- // general models. Within the same suitability tier, prefer the larger
- // comfortable model. Coder-specialized models are skipped.
+ // Recommendation: prefer what's already on disk. The largest installed
+ // general-purpose model that fits comfortably starts instantly — a far
+ // better first-run than upstream's pack, which optimizes for a fresh
+ // machine and would trigger a multi-GB download. Coder-specialized
+ // models are skipped (a shared chat/agent model should be general).
// Fall back to upstream `auto_model_pack` when nothing suitable is
// installed.
let installed_pick = MODEL_CATALOG
@@ -217,11 +204,7 @@ fn build_catalog(
fit_code(size_gb, vram_gb) == ModelFit::Comfortable
&& !m.name.to_ascii_lowercase().contains("coder")
})
- .max_by(|a, b| {
- agent_suitability(&a.name)
- .cmp(&agent_suitability(&b.name))
- .then(parse_size_gb(&a.size).total_cmp(&parse_size_gb(&b.size)))
- })
+ .max_by(|a, b| parse_size_gb(&a.size).total_cmp(&parse_size_gb(&b.size)))
.map(|m| m.name.clone());
let recommended = installed_pick.or_else(|| auto_model_pack(vram_gb).into_iter().next());
for entry in &mut entries {
@@ -327,25 +310,6 @@ mod tests {
assert!(fresh.recommended.is_some());
}
- #[test]
- fn recommendation_prefers_verified_agent_model_over_larger_chat_model() {
- let installed = vec![
- (
- "Qwen3-30B-A3B-Q4_K_M.gguf".to_string(),
- "unsloth/Qwen3-30B-A3B-GGUF:Q4_K_M".to_string(),
- ),
- (
- "gemma-4-E4B-it-Q4_K_M.gguf".to_string(),
- "unsloth/gemma-4-E4B-it-GGUF:Q4_K_M".to_string(),
- ),
- ];
- let catalog = build_catalog(None, 64_000_000_000, 64.0, &installed, &[]);
- assert_eq!(
- catalog.recommended.as_deref(),
- Some("Gemma-4-E4B-it-Q4_K_M")
- );
- }
-
#[test]
fn recommendation_skips_incomplete_layer_packages() {
// Regression: Qwen3-30B-A3B's GGUF was cached but its meshllm layer
@@ -370,10 +334,9 @@ mod tests {
Some("Qwen3-8B-Q4_K_M"),
"incomplete layer package must not be the instant-start pick"
);
- // Even when the larger package is complete, the verified Fizz-capable
- // model remains the safer agent recommendation.
+ // Same cache with the 30B package complete -> 30B wins again.
let catalog = build_catalog(None, 64_000_000_000, 64.0, &installed, &[]);
- assert_eq!(catalog.recommended.as_deref(), Some("Qwen3-8B-Q4_K_M"));
+ assert_eq!(catalog.recommended.as_deref(), Some("Qwen3-30B-A3B-Q4_K_M"));
}
#[test]
diff --git a/docs/buzz-shared-compute-dev.md b/docs/buzz-shared-compute-dev.md
index a12e6aa824..aeb87446bc 100644
--- a/docs/buzz-shared-compute-dev.md
+++ b/docs/buzz-shared-compute-dev.md
@@ -39,10 +39,9 @@ runtime are behind the `mesh-llm` feature.
1. Open **Settings**.
2. Select **Compute**.
3. Under **Share compute**, choose a suggested model.
- - Prefer `Gemma-4-E4B-it-Q4_K_M` when it is suggested; it passes repeated
- real-hardware Fizz publication, ordinary chat, and file-tool checks.
- - `Qwen3-8B-Q4_K_M` is the verified fallback. Models smaller than these may
- chat successfully but are not recommended for Fizz's structured tool use.
+ - On a 16 GB Apple Silicon machine, use a suggested Qwen3.5 4B quantized
+ model when available.
+ - `unsloth/Qwen3.5-4B-GGUF:Q4_K_M` is the model used by the hardware proof.
4. Turn on **Share this machine**.
5. Wait until the card says it is sharing/running. Do not start Fizz while the
card says downloading, preparing, or starting.
From a2af94fd6fcdcd2793e6062b10c0fa38d86733e0 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 08:38:39 +1000
Subject: [PATCH 27/35] Revert "fix(mesh): prevent reasoning-only silent turns"
This reverts commit d2d5d929f545c8c115a1e77b24832edf35dc6fa6.
---
crates/buzz-agent/src/agent.rs | 33 -------
crates/buzz-agent/src/config.rs | 6 --
crates/buzz-agent/src/llm.rs | 27 +----
crates/buzz-agent/tests/regressions.rs | 82 +++++----------
crates/buzz-relay/examples/mesh_agent_e2e.rs | 99 +++++++++++--------
.../src/managed_agents/relay_mesh.rs | 18 ++--
6 files changed, 93 insertions(+), 172 deletions(-)
diff --git a/crates/buzz-agent/src/agent.rs b/crates/buzz-agent/src/agent.rs
index 2252eca3f6..730e87b2e8 100644
--- a/crates/buzz-agent/src/agent.rs
+++ b/crates/buzz-agent/src/agent.rs
@@ -21,15 +21,6 @@ use crate::wire::{self, WireSender};
const ERROR_REFLECTION_SUFFIX: &str =
"\n\n[Reflect] Before retrying, identify the cause and change your approach.";
-/// Maximum number of times a provider may claim a normal end-turn while
-/// returning neither user-visible text nor a tool call. Accepting that shape as
-/// success makes ACP turns disappear: the harness has nothing to publish or
-/// execute. One corrective round is enough to recover compatible local models
-/// without allowing an empty-response loop to run unboundedly.
-const MAX_EMPTY_END_TURN_RETRIES: u32 = 1;
-
-const EMPTY_END_TURN_RETRY_PROMPT: &str = "Your previous response ended without any visible text or tool call. Complete the current user request now. Return a user-visible answer, or use the required communication tool when the system instructions require one; do not return an empty response.";
-
pub struct RunCtx<'a> {
pub cfg: &'a Config,
/// Effective model for this session. Usually equals `cfg.model`; overridden
@@ -93,7 +84,6 @@ impl RunCtx<'_> {
// session) so a stubborn exchange can't permanently disable the stop
// guard for a long-lived session; `max_rounds` still caps the loop.
let mut stop_rejections = 0u32;
- let mut empty_end_turn_retries = 0u32;
loop {
if self.cfg.max_rounds > 0 && round >= self.cfg.max_rounds {
return Ok(StopReason::MaxTurnRequests);
@@ -220,29 +210,6 @@ impl RunCtx<'_> {
"provider: stop=tool_use but zero tool_calls".into(),
));
}
-
- // A provider may return a valid `finish_reason=stop` envelope
- // containing only hidden/reasoning text. That is not a
- // completed ACP turn: no user-visible message was emitted and
- // no communication tool can publish one. Give the model one
- // explicit corrective round, then fail loudly rather than
- // reporting a silent success to the harness.
- if response.stop == ProviderStop::EndTurn && response.text.trim().is_empty() {
- self.history.push(HistoryItem::Assistant {
- text: response.text,
- tool_calls: Vec::new(),
- });
- if empty_end_turn_retries < MAX_EMPTY_END_TURN_RETRIES {
- empty_end_turn_retries = empty_end_turn_retries.saturating_add(1);
- self.history
- .push(HistoryItem::User(EMPTY_END_TURN_RETRY_PROMPT.to_string()));
- continue;
- }
- return Err(AgentError::Llm(
- "provider ended the turn without visible text or a tool call".into(),
- ));
- }
-
self.history.push(HistoryItem::Assistant {
text: response.text,
tool_calls: Vec::new(),
diff --git a/crates/buzz-agent/src/config.rs b/crates/buzz-agent/src/config.rs
index 8a76590071..f06849c7d1 100644
--- a/crates/buzz-agent/src/config.rs
+++ b/crates/buzz-agent/src/config.rs
@@ -730,10 +730,6 @@ pub struct Config {
/// Thinking/reasoning effort level. `None` = use provider default (no
/// thinking config sent). Set via `BUZZ_AGENT_THINKING_EFFORT`.
pub thinking_effort: Option,
- /// Let an OpenAI-compatible server choose its generation limit instead of
- /// sending `max_completion_tokens`. Useful for local/unknown models whose
- /// output limit is discovered and enforced by the serving runtime.
- pub openai_omit_max_tokens: bool,
}
impl Config {
@@ -828,7 +824,6 @@ impl Config {
hook_servers: parse_hook_servers_env("MCP_HOOK_SERVERS"),
hints_enabled: parse_env("BUZZ_AGENT_NO_HINTS", 0u8)? == 0,
thinking_effort: parse_thinking_effort(env("BUZZ_AGENT_THINKING_EFFORT").as_deref())?,
- openai_omit_max_tokens: parse_env("OPENAI_COMPAT_OMIT_MAX_TOKENS", false)?,
};
cfg.validate()?;
Ok(cfg)
@@ -869,7 +864,6 @@ impl Config {
hook_servers: HookServers::None,
hints_enabled: false,
thinking_effort: None,
- openai_omit_max_tokens: false,
}
}
diff --git a/crates/buzz-agent/src/llm.rs b/crates/buzz-agent/src/llm.rs
index 9bd02e0cce..8a774fdf24 100644
--- a/crates/buzz-agent/src/llm.rs
+++ b/crates/buzz-agent/src/llm.rs
@@ -539,14 +539,8 @@ fn openai_body(
"parameters": t.input_schema } })
})
.collect();
- let mut body = json!({
- "model": effective_model,
- "stream": false,
- "messages": messages,
- });
- if !cfg.openai_omit_max_tokens {
- body["max_completion_tokens"] = json!(cfg.max_output_tokens);
- }
+ let mut body = json!({ "model": effective_model, "stream": false,
+ "max_completion_tokens": cfg.max_output_tokens, "messages": messages });
if let Some(e) = effort {
body["reasoning_effort"] = json!(e.openai_effort_str());
}
@@ -1209,7 +1203,6 @@ mod tests {
openai_api: OpenAiApi::Chat,
hints_enabled: true,
thinking_effort: None,
- openai_omit_max_tokens: false,
}
}
@@ -1789,22 +1782,6 @@ mod tests {
);
}
- #[test]
- fn openai_body_can_defer_generation_limit_to_compatible_server() {
- let mut config = cfg(Provider::OpenAi);
- config.openai_omit_max_tokens = true;
- let body = openai_body(
- &config,
- "system",
- &[HistoryItem::User("hi".into())],
- &[],
- "local-model",
- None,
- );
- assert!(body.get("max_completion_tokens").is_none());
- assert!(body.get("max_tokens").is_none());
- }
-
#[test]
fn openai_body_omits_reasoning_effort_when_none() {
let body = openai_body(
diff --git a/crates/buzz-agent/tests/regressions.rs b/crates/buzz-agent/tests/regressions.rs
index b87465455d..3c2237ac99 100644
--- a/crates/buzz-agent/tests/regressions.rs
+++ b/crates/buzz-agent/tests/regressions.rs
@@ -458,79 +458,43 @@ async fn cancel_leaves_history_valid_for_next_prompt() {
h.shutdown().await;
}
-/// An empty normal completion is not a successful ACP turn. The agent must
-/// give the model one corrective round so a local reasoning model cannot end a
-/// Buzz mention after emitting only hidden thought text.
+/// Empty assistant content + no tool_calls must serialize as "" (not null)
+/// for OpenAI, so subsequent prompts don't get rejected. Round 7 fix 6.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
-async fn empty_end_turn_gets_one_corrective_round() {
- let llm = spawn_capturing_llm(vec![openai_text(""), openai_text("visible answer")]).await;
+async fn empty_assistant_serializes_as_empty_string() {
+ // First call returns content="" finish_reason=stop — agent records an
+ // empty assistant turn. Second call's request body is what we inspect.
+ let llm = spawn_capturing_llm(vec![openai_text(""), openai_text("done")]).await;
let mut h = Harness::spawn(&llm.url).await;
let sid = init_session(&mut h, json!([])).await;
- let prompt_id = h
+ let p1 = h
.send(
"session/prompt",
json!({"sessionId": sid, "prompt": [{"type":"text","text":"a"}]}),
)
.await;
- let mut saw_visible_chunk = false;
- let result = loop {
- let value = h.recv().await;
- if value["method"] == "session/update"
- && value["params"]["update"]["sessionUpdate"] == "agent_message_chunk"
- && value["params"]["update"]["content"]["text"] == "visible answer"
- {
- saw_visible_chunk = true;
- }
- if value["id"] == json!(prompt_id) {
- break value;
- }
- };
-
- assert_eq!(result["result"]["stopReason"], "end_turn");
- assert!(
- saw_visible_chunk,
- "corrective answer was not emitted: {result}"
- );
-
- let captured = llm.captured.lock().await;
- assert_eq!(captured.len(), 2, "expected exactly one corrective request");
- let retry_messages = captured[1]["messages"].as_array().unwrap();
- let empty_assistant = retry_messages
- .iter()
- .find(|message| message["role"] == "assistant")
- .expect("empty assistant turn must be preserved for valid OpenAI history");
- assert_eq!(empty_assistant["content"], json!(""));
- assert!(retry_messages.iter().any(|message| {
- message["role"] == "user"
- && message["content"]
- .as_str()
- .is_some_and(|text| text.contains("ended without any visible text"))
- }));
- drop(captured);
- h.shutdown().await;
-}
-
-#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
-async fn repeated_empty_end_turn_fails_instead_of_silent_success() {
- let llm = spawn_capturing_llm(vec![openai_text(""), openai_text("")]).await;
- let mut h = Harness::spawn(&llm.url).await;
- let sid = init_session(&mut h, json!([])).await;
-
- let prompt_id = h
+ let _ = h.recv_until(|v| v["id"] == json!(p1)).await;
+ let p2 = h
.send(
"session/prompt",
- json!({"sessionId": sid, "prompt": [{"type":"text","text":"a"}]}),
+ json!({"sessionId": sid, "prompt": [{"type":"text","text":"b"}]}),
)
.await;
- let result = h.recv_until(|value| value["id"] == json!(prompt_id)).await;
- assert!(
- result["error"]["message"]
- .as_str()
- .is_some_and(|message| message.contains("without visible text or a tool call")),
- "unexpected result: {result}"
+ let _ = h.recv_until(|v| v["id"] == json!(p2)).await;
+
+ let captured = llm.captured.lock().await;
+ let msgs = captured[1]["messages"].as_array().unwrap();
+ let empty_assistant = msgs
+ .iter()
+ .find(|m| m["role"] == "assistant" && m.get("tool_calls").is_none())
+ .expect("no plain assistant turn");
+ // Must be empty string, NOT null.
+ assert_eq!(
+ empty_assistant["content"],
+ json!(""),
+ "expected empty string content, got {empty_assistant}"
);
- assert_eq!(llm.captured.lock().await.len(), 2);
h.shutdown().await;
}
diff --git a/crates/buzz-relay/examples/mesh_agent_e2e.rs b/crates/buzz-relay/examples/mesh_agent_e2e.rs
index 3846d4339f..f16387f5a9 100644
--- a/crates/buzz-relay/examples/mesh_agent_e2e.rs
+++ b/crates/buzz-relay/examples/mesh_agent_e2e.rs
@@ -6,8 +6,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 repeated ordinary chat — several normal prompts must each produce a
-//! user-visible ACP message, never reasoning-only silent success.
+//! 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).
//! 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
@@ -32,7 +33,6 @@ use tokio::process::{Child, Command};
const DEFAULT_MODEL: &str = "unsloth/Qwen3-8B-GGUF:Q4_K_M";
const API_PORT: u16 = 19437;
const CONSOLE_PORT: u16 = 13231;
-const BUZZ_BASE_PROMPT: &str = include_str!("../../buzz-acp/src/base_prompt.md");
fn main() -> anyhow::Result<()> {
tokio::runtime::Builder::new_multi_thread()
@@ -94,9 +94,15 @@ async fn run() -> anyhow::Result<()> {
}
};
- // P1: explicit model id. Shared compute mirrors Goose for unknown local
- // models and lets the serving runtime choose the generation limit.
- let r = agent_chat(&base, &served_id, "Reply with exactly one word: PONG", &[]).await;
+ // P1: explicit model id.
+ let r = agent_chat(
+ &base,
+ &served_id,
+ "1024",
+ "Reply with exactly one word: PONG",
+ &[],
+ )
+ .await;
match r {
Ok(text) => record(
"P1 explicit-model chat",
@@ -107,7 +113,14 @@ async fn run() -> anyhow::Result<()> {
}
// P2: auto — router picks the model.
- let r = agent_chat(&base, "auto", "Reply with exactly one word: PONG", &[]).await;
+ let r = agent_chat(
+ &base,
+ "auto",
+ "1024",
+ "Reply with exactly one word: PONG",
+ &[],
+ )
+ .await;
match r {
Ok(text) => record(
"P2 auto-model chat",
@@ -117,26 +130,33 @@ async fn run() -> anyhow::Result<()> {
Err(e) => record("P2 auto-model chat", false, e.to_string()),
}
- // P3: ordinary chat reliability with the real Buzz system prompt and MCP
- // tool catalog. These prompts reproduce the GUI failure that exact-token,
- // tiny-context smoke prompts missed. Each fresh ACP session must emit a
- // visible message chunk; thought-only output is not an answer.
- let dev_mcp = vec![("dev".to_string(), repo_bin("buzz-dev-mcp")?)];
- for attempt in 1..=3 {
- let r = agent_chat(
- &base,
- "auto",
- "What can you do in Buzz? Answer in two short sentences. Do not call a tool for this test.",
- &dev_mcp,
- )
- .await;
- match r {
- Ok(text) => record(
- &format!("P3.{attempt} ordinary chat"),
- !text.trim().is_empty(),
- text,
- ),
- Err(e) => record(&format!("P3.{attempt} ordinary chat"), false, e.to_string()),
+ // 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.
+ let r = agent_chat(
+ &base,
+ &served_id,
+ "150000",
+ "Reply with exactly one word: PONG",
+ &[],
+ )
+ .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);
}
}
@@ -148,7 +168,8 @@ async fn run() -> anyhow::Result<()> {
"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."
);
let mcp = vec![("dev".to_string(), repo_bin("buzz-dev-mcp")?)];
- let (r, marker) = agent_chat_with_marker(&base, &served_id, &prompt, &mcp, &marker_name).await;
+ let (r, marker) =
+ agent_chat_with_marker(&base, &served_id, "1024", &prompt, &mcp, &marker_name).await;
let file_ok = std::fs::read_to_string(&marker)
.map(|c| c.contains("BUZZ_OK"))
.unwrap_or(false);
@@ -191,27 +212,32 @@ fn repo_bin(name: &str) -> anyhow::Result {
async fn agent_chat(
base: &str,
model: &str,
+ max_output_tokens: &str,
prompt: &str,
mcp_servers: &[(String, String)],
) -> anyhow::Result {
- let (result, _) = agent_chat_in_isolated_home(base, model, prompt, mcp_servers).await;
+ let (result, _) =
+ agent_chat_in_isolated_home(base, model, max_output_tokens, prompt, mcp_servers).await;
result
}
async fn agent_chat_with_marker(
base: &str,
model: &str,
+ max_output_tokens: &str,
prompt: &str,
mcp_servers: &[(String, String)],
marker_name: &str,
) -> (anyhow::Result, std::path::PathBuf) {
- let (result, home) = agent_chat_in_isolated_home(base, model, prompt, mcp_servers).await;
+ let (result, home) =
+ agent_chat_in_isolated_home(base, model, max_output_tokens, prompt, mcp_servers).await;
(result, home.join(marker_name))
}
async fn agent_chat_in_isolated_home(
base: &str,
model: &str,
+ max_output_tokens: &str,
prompt: &str,
mcp_servers: &[(String, String)],
) -> (anyhow::Result, std::path::PathBuf) {
@@ -236,7 +262,7 @@ async fn agent_chat_in_isolated_home(
.env("OPENAI_COMPAT_MODEL", model)
.env("OPENAI_COMPAT_API_KEY", "buzz-mesh-local")
.env("OPENAI_COMPAT_API", "chat")
- .env("OPENAI_COMPAT_OMIT_MAX_TOKENS", "true")
+ .env("BUZZ_AGENT_MAX_OUTPUT_TOKENS", max_output_tokens)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::null())
@@ -291,7 +317,7 @@ async fn drive_acp(
"params": {
"cwd": cwd.to_string_lossy(),
"mcpServers": mcp_json,
- "systemPrompt": BUZZ_BASE_PROMPT
+ "systemPrompt": "You are a terse test agent. Follow instructions exactly."
}
}))
.as_bytes(),
@@ -310,14 +336,9 @@ async fn drive_acp(
let Ok(msg) = serde_json::from_str::(&line) else {
continue;
};
- // Only visible assistant output counts as an answer. Thought chunks
- // are intentionally excluded: accepting them made reasoning-only turns
- // look successful even though Buzz had nothing to publish to chat.
+ // Collect any streamed agent text from session/update notifications.
if msg.get("method").and_then(|m| m.as_str()) == Some("session/update") {
- let update = &msg["params"]["update"];
- if update["sessionUpdate"] == "agent_message_chunk" {
- collect_text(update, &mut agent_text);
- }
+ collect_text(&msg["params"]["update"], &mut agent_text);
continue;
}
match msg.get("id").and_then(|i| i.as_i64()) {
diff --git a/desktop/src-tauri/src/managed_agents/relay_mesh.rs b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
index 999baf5485..51d99815db 100644
--- a/desktop/src-tauri/src/managed_agents/relay_mesh.rs
+++ b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
@@ -35,14 +35,13 @@ pub fn apply_relay_mesh_env(
RELAY_MESH_API_KEY_PLACEHOLDER.to_string(),
);
env.insert("OPENAI_COMPAT_API".to_string(), "chat".to_string());
- // Match Goose's OpenAI-compatible behavior for unknown local models: let
- // MeshLLM enforce the selected model's discovered generation/context
- // limits instead of imposing a harness-wide cap.
+ // Keep the combined prompt + response budget within small shared models.
+ // The router reserves roughly 25% headroom, so 4K output can reject an 8K
+ // model before the first turn once ACP/MCP context is included.
env.insert(
- "OPENAI_COMPAT_OMIT_MAX_TOKENS".to_string(),
- "true".to_string(),
+ "BUZZ_AGENT_MAX_OUTPUT_TOKENS".to_string(),
+ "1024".to_string(),
);
- env.remove("BUZZ_AGENT_MAX_OUTPUT_TOKENS");
}
/// Resolve a record's relay-mesh config, typed field first.
@@ -186,7 +185,7 @@ mod tests {
}
#[test]
- fn native_provider_defers_output_limit_to_mesh_runtime() {
+ fn native_provider_uses_a_small_model_safe_output_budget() {
let mut rec = fixture();
rec.provider = Some(RELAY_MESH_PROVIDER_ID.to_string());
rec.model = Some(RELAY_MESH_AUTO_MODEL_ID.to_string());
@@ -195,10 +194,9 @@ mod tests {
apply_relay_mesh_env(&mut env, rec.provider.as_deref(), rec.model.as_deref());
assert_eq!(
- env.get("OPENAI_COMPAT_OMIT_MAX_TOKENS").map(String::as_str),
- Some("true")
+ env.get("BUZZ_AGENT_MAX_OUTPUT_TOKENS").map(String::as_str),
+ Some("1024")
);
- assert!(!env.contains_key("BUZZ_AGENT_MAX_OUTPUT_TOKENS"));
}
#[test]
From 7ee53257b3848d3210604c7cee62796fb8ff80d0 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 09:06:32 +1000
Subject: [PATCH 28/35] fix(mesh): use released model selection and runtime
---
Cargo.lock | 166 ++++++++---------
crates/buzz-relay/Cargo.toml | 4 +-
desktop/src-tauri/Cargo.lock | 174 +++++++++---------
desktop/src-tauri/Cargo.toml | 12 +-
.../src/managed_agents/relay_mesh.rs | 22 ---
desktop/src-tauri/src/mesh_llm/catalog.rs | 142 +-------------
6 files changed, 186 insertions(+), 334 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 2e2c041db8..5cc0be5a83 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2834,8 +2834,8 @@ dependencies = [
"libc",
"log",
"rustversion",
- "windows-link 0.1.3",
- "windows-result 0.3.4",
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
]
[[package]]
@@ -3425,7 +3425,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.61.2",
+ "windows-core 0.62.2",
]
[[package]]
@@ -4331,8 +4331,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-client"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"hex",
"mesh-llm-client",
@@ -4341,8 +4341,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-server"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4352,13 +4352,13 @@ dependencies = [
[[package]]
name = "mesh-llm-build-info"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
[[package]]
name = "mesh-llm-client"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -4389,8 +4389,8 @@ dependencies = [
[[package]]
name = "mesh-llm-config"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"dirs",
@@ -4405,8 +4405,8 @@ dependencies = [
[[package]]
name = "mesh-llm-embedded-runtime"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"mesh-llm-host-runtime",
@@ -4415,8 +4415,8 @@ dependencies = [
[[package]]
name = "mesh-llm-events"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"clap",
@@ -4427,8 +4427,8 @@ dependencies = [
[[package]]
name = "mesh-llm-gpu-bench"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"cc",
@@ -4440,8 +4440,8 @@ dependencies = [
[[package]]
name = "mesh-llm-guardrails"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"serde",
"serde_json",
@@ -4449,16 +4449,16 @@ dependencies = [
[[package]]
name = "mesh-llm-hardware-profile"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"mesh-llm-native-runtime",
]
[[package]]
name = "mesh-llm-host-runtime"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"argon2",
@@ -4550,8 +4550,8 @@ dependencies = [
[[package]]
name = "mesh-llm-identity"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"argon2",
"base64",
@@ -4572,8 +4572,8 @@ dependencies = [
[[package]]
name = "mesh-llm-native-runtime"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"serde",
@@ -4583,8 +4583,8 @@ dependencies = [
[[package]]
name = "mesh-llm-node"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"mesh-llm-types",
@@ -4597,8 +4597,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -4614,8 +4614,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin-manager"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"dirs",
@@ -4632,8 +4632,8 @@ dependencies = [
[[package]]
name = "mesh-llm-protocol"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"hex",
@@ -4645,16 +4645,16 @@ dependencies = [
[[package]]
name = "mesh-llm-routing"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"iroh",
]
[[package]]
name = "mesh-llm-runtime-install"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"dirs",
@@ -4676,8 +4676,8 @@ dependencies = [
[[package]]
name = "mesh-llm-sdk"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4691,8 +4691,8 @@ dependencies = [
[[package]]
name = "mesh-llm-skills"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"dirs",
@@ -4702,8 +4702,8 @@ dependencies = [
[[package]]
name = "mesh-llm-system"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"chrono",
@@ -4725,8 +4725,8 @@ dependencies = [
[[package]]
name = "mesh-llm-types"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"hex",
"serde",
@@ -4736,13 +4736,13 @@ dependencies = [
[[package]]
name = "mesh-llm-ui"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
[[package]]
name = "mesh-mixture-of-agents"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"async-trait",
"mesh-llm-guardrails",
@@ -4858,8 +4858,8 @@ dependencies = [
[[package]]
name = "model-artifact"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -4869,8 +4869,8 @@ dependencies = [
[[package]]
name = "model-hf"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -4887,8 +4887,8 @@ dependencies = [
[[package]]
name = "model-package"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"bytes",
@@ -4907,16 +4907,16 @@ dependencies = [
[[package]]
name = "model-ref"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"serde",
]
[[package]]
name = "model-resolver"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"model-artifact",
@@ -5626,8 +5626,8 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openai-frontend"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"async-trait",
"axum",
@@ -7858,8 +7858,8 @@ checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b"
[[package]]
name = "skippy-cache"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"blake3",
@@ -7868,29 +7868,29 @@ dependencies = [
[[package]]
name = "skippy-coordinator"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "skippy-ffi"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"libloading",
]
[[package]]
name = "skippy-metrics"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
[[package]]
name = "skippy-protocol"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"prost",
"prost-build",
@@ -7900,8 +7900,8 @@ dependencies = [
[[package]]
name = "skippy-runtime"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"libc",
@@ -7914,8 +7914,8 @@ dependencies = [
[[package]]
name = "skippy-server"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -7942,8 +7942,8 @@ dependencies = [
[[package]]
name = "skippy-topology"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"serde",
"serde_json",
@@ -10301,8 +10301,8 @@ dependencies = [
"log",
"serde",
"thiserror 2.0.18",
- "windows 0.61.3",
- "windows-core 0.61.2",
+ "windows 0.62.2",
+ "windows-core 0.62.2",
]
[[package]]
diff --git a/crates/buzz-relay/Cargo.toml b/crates/buzz-relay/Cargo.toml
index 1339d11a1a..f516b82d63 100644
--- a/crates/buzz-relay/Cargo.toml
+++ b/crates/buzz-relay/Cargo.toml
@@ -77,8 +77,8 @@ metrics-exporter-prometheus = { workspace = true }
dev = ["buzz-auth/dev"]
[dev-dependencies]
-mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] }
-mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] }
+mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] }
+mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] }
buzz-core = { workspace = true, features = ["test-utils"] }
buzz-auth = { workspace = true, features = ["dev"] }
reqwest = { workspace = true }
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index a46b915cfa..54e242a146 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -1637,7 +1637,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "windows 0.61.3",
+ "windows 0.62.2",
]
[[package]]
@@ -2975,8 +2975,8 @@ dependencies = [
"libc",
"log",
"rustversion",
- "windows-link 0.1.3",
- "windows-result 0.3.4",
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
]
[[package]]
@@ -3711,7 +3711,7 @@ dependencies = [
"tokio",
"tower-service",
"tracing",
- "windows-registry 0.5.3",
+ "windows-registry 0.6.1",
]
[[package]]
@@ -3726,7 +3726,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.61.2",
+ "windows-core 0.62.2",
]
[[package]]
@@ -4761,8 +4761,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-client"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"hex",
"mesh-llm-client",
@@ -4771,8 +4771,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-server"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4782,13 +4782,13 @@ dependencies = [
[[package]]
name = "mesh-llm-build-info"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
[[package]]
name = "mesh-llm-client"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -4819,8 +4819,8 @@ dependencies = [
[[package]]
name = "mesh-llm-config"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"dirs",
@@ -4835,8 +4835,8 @@ dependencies = [
[[package]]
name = "mesh-llm-embedded-runtime"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"mesh-llm-host-runtime",
@@ -4845,8 +4845,8 @@ dependencies = [
[[package]]
name = "mesh-llm-events"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"clap",
@@ -4857,8 +4857,8 @@ dependencies = [
[[package]]
name = "mesh-llm-gpu-bench"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"cc",
@@ -4870,8 +4870,8 @@ dependencies = [
[[package]]
name = "mesh-llm-guardrails"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"serde",
"serde_json",
@@ -4879,16 +4879,16 @@ dependencies = [
[[package]]
name = "mesh-llm-hardware-profile"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"mesh-llm-native-runtime",
]
[[package]]
name = "mesh-llm-host-runtime"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"argon2",
@@ -4980,8 +4980,8 @@ dependencies = [
[[package]]
name = "mesh-llm-identity"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"argon2",
"base64 0.22.1",
@@ -5002,8 +5002,8 @@ dependencies = [
[[package]]
name = "mesh-llm-native-runtime"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"serde",
@@ -5013,8 +5013,8 @@ dependencies = [
[[package]]
name = "mesh-llm-node"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"mesh-llm-types",
@@ -5027,8 +5027,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -5044,8 +5044,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin-manager"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"dirs",
@@ -5062,8 +5062,8 @@ dependencies = [
[[package]]
name = "mesh-llm-protocol"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"hex",
@@ -5075,16 +5075,16 @@ dependencies = [
[[package]]
name = "mesh-llm-routing"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"iroh",
]
[[package]]
name = "mesh-llm-runtime-install"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"dirs",
@@ -5106,8 +5106,8 @@ dependencies = [
[[package]]
name = "mesh-llm-sdk"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -5121,8 +5121,8 @@ dependencies = [
[[package]]
name = "mesh-llm-skills"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"dirs",
@@ -5132,8 +5132,8 @@ dependencies = [
[[package]]
name = "mesh-llm-system"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"chrono",
@@ -5155,8 +5155,8 @@ dependencies = [
[[package]]
name = "mesh-llm-types"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"hex",
"serde",
@@ -5166,13 +5166,13 @@ dependencies = [
[[package]]
name = "mesh-llm-ui"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
[[package]]
name = "mesh-mixture-of-agents"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"async-trait",
"mesh-llm-guardrails",
@@ -5235,8 +5235,8 @@ dependencies = [
[[package]]
name = "model-artifact"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -5246,8 +5246,8 @@ dependencies = [
[[package]]
name = "model-hf"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -5264,8 +5264,8 @@ dependencies = [
[[package]]
name = "model-package"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"bytes",
@@ -5284,16 +5284,16 @@ dependencies = [
[[package]]
name = "model-ref"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"serde",
]
[[package]]
name = "model-resolver"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"model-artifact",
@@ -5923,7 +5923,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
dependencies = [
- "proc-macro-crate 1.3.1",
+ "proc-macro-crate 2.0.2",
"proc-macro2",
"quote",
"syn 2.0.118",
@@ -6297,8 +6297,8 @@ dependencies = [
[[package]]
name = "openai-frontend"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"async-trait",
"axum",
@@ -7191,7 +7191,7 @@ version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
dependencies = [
- "heck 0.4.1",
+ "heck 0.5.0",
"itertools",
"log",
"multimap",
@@ -8751,8 +8751,8 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
[[package]]
name = "skippy-cache"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"blake3",
@@ -8761,29 +8761,29 @@ dependencies = [
[[package]]
name = "skippy-coordinator"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "skippy-ffi"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"libloading 0.8.9",
]
[[package]]
name = "skippy-metrics"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
[[package]]
name = "skippy-protocol"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"prost",
"prost-build",
@@ -8793,8 +8793,8 @@ dependencies = [
[[package]]
name = "skippy-runtime"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"libc",
@@ -8807,8 +8807,8 @@ dependencies = [
[[package]]
name = "skippy-server"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"anyhow",
"async-trait",
@@ -8835,8 +8835,8 @@ dependencies = [
[[package]]
name = "skippy-topology"
-version = "0.72.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=5acd902540efd966ea7ba205b7e35fb4f96aa673#5acd902540efd966ea7ba205b7e35fb4f96aa673"
+version = "0.73.0"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
dependencies = [
"serde",
"serde_json",
@@ -11980,8 +11980,8 @@ dependencies = [
"log",
"serde",
"thiserror 2.0.18",
- "windows 0.61.3",
- "windows-core 0.61.2",
+ "windows 0.62.2",
+ "windows-core 0.62.2",
]
[[package]]
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index edddf06877..92526f6ca6 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -86,14 +86,14 @@ buzz_core_pkg = { package = "buzz-core", path = "../../crates/buzz-core" }
buzz_persona_pkg = { package = "buzz-persona", path = "../../crates/buzz-persona" }
buzz_sdk_pkg = { package = "buzz-sdk", path = "../../crates/buzz-sdk" }
buzz_agent_pkg = { package = "buzz-agent", path = "../../crates/buzz-agent" }
-mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
-mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
+mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
+mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
# Model catalog + hardware survey for the Share-compute model picker (same
# diagnose pattern as mesh-console). Lib name of mesh-llm-client is mesh_client.
-mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-client", optional = true }
-mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-node", optional = true }
-mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-system", optional = true }
-mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "5acd902540efd966ea7ba205b7e35fb4f96aa673", package = "mesh-llm-events", optional = true }
+mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-client", optional = true }
+mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-node", optional = true }
+mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-system", optional = true }
+mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-events", optional = true }
base64 = "0.22"
sha2 = "0.11"
tar = "0.4"
diff --git a/desktop/src-tauri/src/managed_agents/relay_mesh.rs b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
index 51d99815db..d0160e318f 100644
--- a/desktop/src-tauri/src/managed_agents/relay_mesh.rs
+++ b/desktop/src-tauri/src/managed_agents/relay_mesh.rs
@@ -35,13 +35,6 @@ pub fn apply_relay_mesh_env(
RELAY_MESH_API_KEY_PLACEHOLDER.to_string(),
);
env.insert("OPENAI_COMPAT_API".to_string(), "chat".to_string());
- // Keep the combined prompt + response budget within small shared models.
- // The router reserves roughly 25% headroom, so 4K output can reject an 8K
- // model before the first turn once ACP/MCP context is included.
- env.insert(
- "BUZZ_AGENT_MAX_OUTPUT_TOKENS".to_string(),
- "1024".to_string(),
- );
}
/// Resolve a record's relay-mesh config, typed field first.
@@ -184,21 +177,6 @@ mod tests {
assert_eq!(relay_mesh_model_id(&rec).as_deref(), Some("Qwen3"));
}
- #[test]
- fn native_provider_uses_a_small_model_safe_output_budget() {
- let mut rec = fixture();
- rec.provider = Some(RELAY_MESH_PROVIDER_ID.to_string());
- rec.model = Some(RELAY_MESH_AUTO_MODEL_ID.to_string());
- let mut env = BTreeMap::new();
-
- apply_relay_mesh_env(&mut env, rec.provider.as_deref(), rec.model.as_deref());
-
- assert_eq!(
- env.get("BUZZ_AGENT_MAX_OUTPUT_TOKENS").map(String::as_str),
- Some("1024")
- );
- }
-
#[test]
fn relay_mesh_model_id_ignores_non_mesh_openai_env() {
let mut rec = fixture();
diff --git a/desktop/src-tauri/src/mesh_llm/catalog.rs b/desktop/src-tauri/src/mesh_llm/catalog.rs
index 34de3faeb5..d5fd91b905 100644
--- a/desktop/src-tauri/src/mesh_llm/catalog.rs
+++ b/desktop/src-tauri/src/mesh_llm/catalog.rs
@@ -84,7 +84,6 @@ pub fn model_catalog() -> MeshModelCatalog {
survey.vram_bytes,
vram_gb,
&installed_names(),
- &incomplete_layer_package_files(),
)
}
@@ -104,73 +103,17 @@ fn installed_names() -> Vec<(String, String)> {
.collect()
}
-/// Primary GGUF file names of models whose meshllm layer package on disk is
-/// *incomplete*. mesh-llm serves such models from the layer package and will
-/// resume a multi-GB download on first serve — so "the GGUF is cached" does
-/// not mean "starts instantly". mesh-llm's own `scan_installed_models` marks
-/// a package installed if any single layer file exists (no completeness
-/// check — upstream gap), so we verify against the package's own
-/// `model-package.json` manifest: every listed layer file must exist.
-fn incomplete_layer_package_files() -> Vec {
- let cache = default_huggingface_cache_dir();
- let mut incomplete = Vec::new();
- let Ok(repos) = std::fs::read_dir(&cache) else {
- return incomplete;
- };
- for repo in repos.flatten() {
- let name = repo.file_name().to_string_lossy().into_owned();
- if !(name.starts_with("models--meshllm--") && name.ends_with("-layers")) {
- continue;
- }
- let Ok(snapshots) = std::fs::read_dir(repo.path().join("snapshots")) else {
- continue;
- };
- for snapshot in snapshots.flatten() {
- let manifest_path = snapshot.path().join("model-package.json");
- let Ok(raw) = std::fs::read_to_string(&manifest_path) else {
- continue;
- };
- let Ok(manifest) = serde_json::from_str::(&raw) else {
- continue;
- };
- let Some(primary_file) = manifest["source_model"]["primary_file"].as_str() else {
- continue;
- };
- let layers = manifest["layers"].as_array().cloned().unwrap_or_default();
- let complete = !layers.is_empty()
- && layers.iter().all(|layer| {
- layer["path"]
- .as_str()
- .map(|p| snapshot.path().join(p).exists())
- .unwrap_or(false)
- });
- if !complete {
- incomplete.push(primary_file.to_string());
- }
- }
- }
- incomplete
-}
-
fn build_catalog(
gpu_name: Option,
vram_bytes: u64,
vram_gb: f64,
installed: &[(String, String)],
- incomplete_layer_files: &[String],
) -> MeshModelCatalog {
let is_installed = |file: &str, name: &str| {
installed
.iter()
.any(|(f, model_ref)| f == file || model_ref.contains(name))
};
- // "Installed" for recommendation purposes means *ready to serve now*:
- // if the model's layer package exists but is incomplete, first serve
- // resumes a multi-GB download — that's not an instant-start pick.
- let is_ready = |file: &str, name: &str| {
- is_installed(file, name) && !incomplete_layer_files.iter().any(|f| f == file)
- };
-
let mut entries: Vec = MODEL_CATALOG
.iter()
.filter(|m| !is_draft_only(&m.name))
@@ -188,25 +131,7 @@ fn build_catalog(
})
.collect();
- // Recommendation: prefer what's already on disk. The largest installed
- // general-purpose model that fits comfortably starts instantly — a far
- // better first-run than upstream's pack, which optimizes for a fresh
- // machine and would trigger a multi-GB download. Coder-specialized
- // models are skipped (a shared chat/agent model should be general).
- // Fall back to upstream `auto_model_pack` when nothing suitable is
- // installed.
- let installed_pick = MODEL_CATALOG
- .iter()
- .filter(|m| !is_draft_only(&m.name))
- .filter(|m| is_ready(&m.file, &m.name))
- .filter(|m| {
- let size_gb = parse_size_gb(&m.size);
- fit_code(size_gb, vram_gb) == ModelFit::Comfortable
- && !m.name.to_ascii_lowercase().contains("coder")
- })
- .max_by(|a, b| parse_size_gb(&a.size).total_cmp(&parse_size_gb(&b.size)))
- .map(|m| m.name.clone());
- let recommended = installed_pick.or_else(|| auto_model_pack(vram_gb).into_iter().next());
+ let recommended = auto_model_pack(vram_gb).into_iter().next();
for entry in &mut entries {
entry.recommended = recommended.as_deref() == Some(entry.name.as_str());
}
@@ -254,7 +179,7 @@ mod tests {
#[test]
fn catalog_ranks_recommended_first_then_fit() {
- let catalog = build_catalog(Some("Test GPU".into()), 24_000_000_000, 24.0, &[], &[]);
+ let catalog = build_catalog(Some("Test GPU".into()), 24_000_000_000, 24.0, &[]);
assert!(
!catalog.entries.is_empty(),
"curated catalog must not be empty"
@@ -280,63 +205,12 @@ mod tests {
}
#[test]
- fn recommendation_prefers_largest_installed_comfortable_general_model() {
- // M4 Max 64GB shape: Qwen3-30B-A3B (17GB) and Qwen2.5-3B cached.
- // The installed 30B MoE must win over upstream's download-something
- // pack, and over the smaller installed model. Coder models never
- // win even when installed and larger.
- let installed = vec![
- (
- "Qwen3-30B-A3B-Q4_K_M.gguf".to_string(),
- "unsloth/Qwen3-30B-A3B-GGUF:Q4_K_M".to_string(),
- ),
- (
- "qwen2.5-3b-instruct-q4_k_m.gguf".to_string(),
- "Qwen/Qwen2.5-3B-Instruct-GGUF:q4_k_m".to_string(),
- ),
- (
- "Qwen2.5-Coder-32B-Instruct-Q4_K_M.gguf".to_string(),
- "Qwen/Qwen2.5-Coder-32B-Instruct-GGUF:q4_k_m".to_string(),
- ),
- ];
- let catalog = build_catalog(None, 64_000_000_000, 64.0, &installed, &[]);
- assert_eq!(
- catalog.recommended.as_deref(),
- Some("Qwen3-30B-A3B-Q4_K_M"),
- "largest installed comfortable non-coder model must be recommended"
- );
- // Nothing installed -> upstream pack fallback still recommends.
- let fresh = build_catalog(None, 64_000_000_000, 64.0, &[], &[]);
- assert!(fresh.recommended.is_some());
- }
-
- #[test]
- fn recommendation_skips_incomplete_layer_packages() {
- // Regression: Qwen3-30B-A3B's GGUF was cached but its meshllm layer
- // package was 7/48 layers — recommending it meant a surprise ~7GB
- // download on first serve. An incomplete package must lose to a
- // smaller fully-ready model; it stays listed as installed, just not
- // recommended.
- let installed = vec![
- (
- "Qwen3-30B-A3B-Q4_K_M.gguf".to_string(),
- "unsloth/Qwen3-30B-A3B-GGUF:Q4_K_M".to_string(),
- ),
- (
- "Qwen3-8B-Q4_K_M.gguf".to_string(),
- "unsloth/Qwen3-8B-GGUF:Q4_K_M".to_string(),
- ),
- ];
- let incomplete = vec!["Qwen3-30B-A3B-Q4_K_M.gguf".to_string()];
- let catalog = build_catalog(None, 64_000_000_000, 64.0, &installed, &incomplete);
+ fn recommendation_uses_mesh_llm_auto_selection() {
+ let catalog = build_catalog(None, 62_000_000_000, 62.0, &[]);
assert_eq!(
- catalog.recommended.as_deref(),
- Some("Qwen3-8B-Q4_K_M"),
- "incomplete layer package must not be the instant-start pick"
+ catalog.recommended,
+ auto_model_pack(62.0).into_iter().next()
);
- // Same cache with the 30B package complete -> 30B wins again.
- let catalog = build_catalog(None, 64_000_000_000, 64.0, &installed, &[]);
- assert_eq!(catalog.recommended.as_deref(), Some("Qwen3-30B-A3B-Q4_K_M"));
}
#[test]
@@ -345,13 +219,13 @@ mod tests {
"Qwen3-8B-Q4_K_M.gguf".to_string(),
"unsloth/Qwen3-8B-GGUF:Q4_K_M".to_string(),
)];
- let catalog = build_catalog(None, 96_000_000_000, 96.0, &installed, &[]);
+ let catalog = build_catalog(None, 96_000_000_000, 96.0, &installed);
let qwen8b = catalog.entries.iter().find(|e| e.name == "Qwen3-8B-Q4_K_M");
if let Some(entry) = qwen8b {
assert!(entry.installed, "cached file must mark entry installed");
}
// A machine with nothing installed marks nothing installed.
- let empty = build_catalog(None, 96_000_000_000, 96.0, &[], &[]);
+ let empty = build_catalog(None, 96_000_000_000, 96.0, &[]);
assert!(empty.entries.iter().all(|e| !e.installed));
}
}
From 6aedc1ff0ac4108afdd556ff1c2fda463ce75b00 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 10:04:15 +1000
Subject: [PATCH 29/35] fix(agent): publish Buzz replies through typed tool
---
crates/buzz-acp/src/base_prompt.md | 2 +-
crates/buzz-dev-mcp/src/buzz_message.rs | 172 ++++++++++++++++++++++++
crates/buzz-dev-mcp/src/lib.rs | 12 ++
3 files changed, 185 insertions(+), 1 deletion(-)
create mode 100644 crates/buzz-dev-mcp/src/buzz_message.rs
diff --git a/crates/buzz-acp/src/base_prompt.md b/crates/buzz-acp/src/base_prompt.md
index fe2ea7107b..7d5cbd4136 100644
--- a/crates/buzz-acp/src/base_prompt.md
+++ b/crates/buzz-acp/src/base_prompt.md
@@ -47,7 +47,7 @@ All replies and delegations — including task assignments to other agents — g
### General
- Respond promptly to @mentions. Be direct — no preamble. Name what you did, what you found, or what you need.
-- **Every turn that processes a user message MUST end with `buzz messages send`.** Your reasoning and tool calls are invisible to users — if you didn't send a message, they saw nothing. A turn that ends without a sent message is a silent failure.
+- **Every turn that processes a user message MUST publish a reply.** Use the dedicated `buzz_send_message` tool when available; otherwise use `buzz messages send`. Your reasoning and other tool calls are invisible to users — if you didn't publish a message, they saw nothing. A turn that ends without a published message is a silent failure.
- For work that requires follow-up tools, create an open todo **before** sending the pickup acknowledgment. Keep it open until the deliverable is verified and you have sent a completion or blocker message; never end a turn with open todo state unless you have posted that completion or blocker message.
- Use GitHub-flavored Markdown. Fenced code blocks with language tags for syntax highlighting.
- No push notifications — poll with `buzz messages get --channel --since `.
diff --git a/crates/buzz-dev-mcp/src/buzz_message.rs b/crates/buzz-dev-mcp/src/buzz_message.rs
new file mode 100644
index 0000000000..c488f391fc
--- /dev/null
+++ b/crates/buzz-dev-mcp/src/buzz_message.rs
@@ -0,0 +1,172 @@
+use crate::shell::SharedState;
+use rmcp::model::{CallToolResult, Content};
+use rmcp::ErrorData;
+use schemars::JsonSchema;
+use serde::Deserialize;
+use std::path::PathBuf;
+use std::process::Stdio;
+use tokio::process::Command;
+
+const MAX_CONTENT_BYTES: usize = 64 * 1024;
+
+#[derive(Debug, Deserialize, JsonSchema)]
+pub struct SendMessageParams {
+ /// Buzz channel UUID supplied in the turn's Context section.
+ pub channel: String,
+ /// Message body to publish.
+ pub content: String,
+ /// Optional event id to reply to when the Context section requires a threaded reply.
+ #[serde(default)]
+ pub reply_to: Option,
+}
+
+pub async fn run(
+ state: &SharedState,
+ params: SendMessageParams,
+) -> Result {
+ if params.content.trim().is_empty() {
+ return Err(ErrorData::invalid_params(
+ "content must not be empty".to_string(),
+ None,
+ ));
+ }
+ if params.content.len() > MAX_CONTENT_BYTES {
+ return Err(ErrorData::invalid_params(
+ format!("content exceeds {MAX_CONTENT_BYTES} bytes"),
+ None,
+ ));
+ }
+
+ let buzz = find_buzz(&state.shim.path_env).ok_or_else(|| {
+ ErrorData::internal_error("bundled Buzz CLI is unavailable".to_string(), None)
+ })?;
+ let mut command = Command::new(buzz);
+ command
+ .args([
+ "messages",
+ "send",
+ "--channel",
+ ¶ms.channel,
+ "--content",
+ ¶ms.content,
+ ])
+ .current_dir(&state.cwd)
+ .env("PATH", &state.shim.path_env)
+ .stdin(Stdio::null())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped());
+ if let Some(reply_to) = params.reply_to.as_deref() {
+ command.args(["--reply-to", reply_to]);
+ }
+
+ let output = command.output().await.map_err(|error| {
+ ErrorData::internal_error(format!("failed to run Buzz CLI: {error}"), None)
+ })?;
+ let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
+ let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
+ if output.status.success() {
+ let text = if stdout.is_empty() {
+ "Message published.".to_string()
+ } else {
+ stdout
+ };
+ Ok(CallToolResult::success(vec![Content::text(text)]))
+ } else {
+ let detail = if stderr.is_empty() { stdout } else { stderr };
+ Ok(CallToolResult::error(vec![Content::text(format!(
+ "Buzz message failed: {detail}"
+ ))]))
+ }
+}
+
+fn find_buzz(path: &str) -> Option {
+ std::env::split_paths(path)
+ .map(|entry| entry.join(if cfg!(windows) { "buzz.exe" } else { "buzz" }))
+ .find(|candidate| candidate.is_file())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[cfg(unix)]
+ fn make_executable(path: &std::path::Path) {
+ use std::os::unix::fs::PermissionsExt;
+ let mut permissions = std::fs::metadata(path).unwrap().permissions();
+ permissions.set_mode(0o755);
+ std::fs::set_permissions(path, permissions).unwrap();
+ }
+
+ #[cfg(windows)]
+ fn make_executable(_path: &std::path::Path) {}
+
+ #[tokio::test]
+ async fn publishes_with_structured_cli_arguments() {
+ let dir = tempfile::tempdir().unwrap();
+ let buzz = dir
+ .path()
+ .join(if cfg!(windows) { "buzz.cmd" } else { "buzz" });
+ let args_file = dir.path().join("args.txt");
+ if cfg!(windows) {
+ std::fs::write(
+ &buzz,
+ format!(
+ "@echo off\r\n(for %%a in (%*) do @echo %%~a)>>\"{}\"\r\n",
+ args_file.display()
+ ),
+ )
+ .unwrap();
+ } else {
+ std::fs::write(
+ &buzz,
+ format!(
+ "#!/bin/sh\nprintf '%s\\n' \"$@\" > '{}'\n",
+ args_file.display()
+ ),
+ )
+ .unwrap();
+ }
+ make_executable(&buzz);
+ let mut state = SharedState::new(
+ dir.path().to_path_buf(),
+ crate::shim::Shim::install().unwrap(),
+ )
+ .unwrap();
+ state.shim.path_env = dir.path().to_string_lossy().into_owned();
+ let result = run(
+ &state,
+ SendMessageParams {
+ channel: "channel-id".into(),
+ content: "hello world".into(),
+ reply_to: Some("event-id".into()),
+ },
+ )
+ .await
+ .unwrap();
+ assert!(!result.is_error.unwrap_or(false));
+ let args = std::fs::read_to_string(args_file).unwrap();
+ assert_eq!(
+ args.lines().collect::>(),
+ [
+ "messages",
+ "send",
+ "--channel",
+ "channel-id",
+ "--content",
+ "hello world",
+ "--reply-to",
+ "event-id"
+ ]
+ );
+ }
+
+ #[test]
+ fn finds_bundled_buzz_on_path() {
+ let dir = tempfile::tempdir().unwrap();
+ let path = dir
+ .path()
+ .join(if cfg!(windows) { "buzz.exe" } else { "buzz" });
+ std::fs::write(&path, "test").unwrap();
+ assert_eq!(find_buzz(&dir.path().to_string_lossy()), Some(path));
+ }
+}
diff --git a/crates/buzz-dev-mcp/src/lib.rs b/crates/buzz-dev-mcp/src/lib.rs
index f9fced8e81..ec58d13e00 100644
--- a/crates/buzz-dev-mcp/src/lib.rs
+++ b/crates/buzz-dev-mcp/src/lib.rs
@@ -10,6 +10,7 @@ use rmcp::{
use std::path::Path;
use std::sync::Arc;
+mod buzz_message;
mod paths;
mod read_file;
mod rg;
@@ -49,6 +50,17 @@ impl DevMcp {
shell::run(&self.state, p, context.ct).await
}
+ #[tool(
+ name = "buzz_send_message",
+ description = "Publish the user-visible reply for the current Buzz turn. Use the channel UUID and optional reply event id from the prompt Context. Every Buzz turn must call this before ending; use shell-based buzz messages send only if this tool is unavailable."
+ )]
+ async fn buzz_send_message(
+ &self,
+ Parameters(p): Parameters,
+ ) -> Result {
+ buzz_message::run(&self.state, p).await
+ }
+
#[tool(
name = "read_file",
description = "Read a text file and return its contents with line numbers. Returns lines in `{number}:{content}` format. Use `offset` (0-based) and `limit` (default 2000) to window into large files. Path resolved relative to workdir (defaults to server cwd). Prefer over cat/head/tail."
From 051ac3bc5bd4e97240f39d97064a41fee90dc2fe Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 11:00:10 +1000
Subject: [PATCH 30/35] test(agent): gate shell fixture to unix
---
crates/buzz-dev-mcp/src/buzz_message.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/crates/buzz-dev-mcp/src/buzz_message.rs b/crates/buzz-dev-mcp/src/buzz_message.rs
index c488f391fc..cde70e9264 100644
--- a/crates/buzz-dev-mcp/src/buzz_message.rs
+++ b/crates/buzz-dev-mcp/src/buzz_message.rs
@@ -100,6 +100,7 @@ mod tests {
#[cfg(windows)]
fn make_executable(_path: &std::path::Path) {}
+ #[cfg(unix)]
#[tokio::test]
async fn publishes_with_structured_cli_arguments() {
let dir = tempfile::tempdir().unwrap();
From c4d7d9ce7c27d6e7c416f0884a03ce2e5b8945b1 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 11:16:31 +1000
Subject: [PATCH 31/35] fix(agent): keep Windows test target warning-free
---
crates/buzz-dev-mcp/src/buzz_message.rs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/crates/buzz-dev-mcp/src/buzz_message.rs b/crates/buzz-dev-mcp/src/buzz_message.rs
index cde70e9264..63a77c7940 100644
--- a/crates/buzz-dev-mcp/src/buzz_message.rs
+++ b/crates/buzz-dev-mcp/src/buzz_message.rs
@@ -97,9 +97,6 @@ mod tests {
std::fs::set_permissions(path, permissions).unwrap();
}
- #[cfg(windows)]
- fn make_executable(_path: &std::path::Path) {}
-
#[cfg(unix)]
#[tokio::test]
async fn publishes_with_structured_cli_arguments() {
From fd657f22194b0462aa2a13e303bfa4429d851d62 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 12:19:51 +1000
Subject: [PATCH 32/35] fix(mesh): install native runtime on first use
---
desktop/src-tauri/src/mesh_llm/mod.rs | 21 +++++----------------
1 file changed, 5 insertions(+), 16 deletions(-)
diff --git a/desktop/src-tauri/src/mesh_llm/mod.rs b/desktop/src-tauri/src/mesh_llm/mod.rs
index b4d3178380..dcb1ea2d57 100644
--- a/desktop/src-tauri/src/mesh_llm/mod.rs
+++ b/desktop/src-tauri/src/mesh_llm/mod.rs
@@ -233,24 +233,13 @@ pub struct DesktopMeshRuntime {
}
async fn initialize_mesh_native_runtime() -> anyhow::Result<()> {
- let cache = mesh_llm_sdk::native_runtime::native_runtime_cache(None)?;
- let installed = cache.installed()?;
- let current = mesh_llm_sdk::native_runtime::CURRENT_MESH_VERSION;
- if !installed
- .iter()
- .any(|runtime| runtime.mesh_version == current)
- {
- anyhow::bail!(
- "mesh native runtime for MeshLLM {current} is not installed; run `just mesh=1 staging` or `just mesh-e2e-hardware` to prepare it"
- );
- }
+ // The dynamic host runtime installs the recommended signed runtime on first
+ // use when no compatible version is cached. Keep that SDK-owned path intact
+ // so release builds work on clean machines without bundling llama.cpp or
+ // requiring a separate `mesh-llm runtime install` command.
mesh_llm_host_runtime::initialize_host_runtime()
.await
- .map_err(|error| {
- anyhow::anyhow!(
- "mesh native runtime failed to load; run `just mesh=1 staging` or `just mesh-e2e-hardware` to repair it: {error}"
- )
- })
+ .map_err(|error| anyhow::anyhow!("mesh native runtime failed to install or load: {error}"))
}
/// Tokio worker stack size for the runtime that polls mesh-llm futures.
From 22e389136e14d18f54df1c217dece8c16ee69488 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 14:54:28 +1000
Subject: [PATCH 33/35] fix(mesh): update runtime and exit cleanly on macOS
---
Cargo.lock | 166 ++++++++++++++++-----------------
crates/buzz-relay/Cargo.toml | 4 +-
desktop/src-tauri/Cargo.lock | 174 +++++++++++++++++------------------
desktop/src-tauri/Cargo.toml | 12 +--
desktop/src-tauri/src/lib.rs | 44 +++++++++
5 files changed, 222 insertions(+), 178 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 5cc0be5a83..6f3f6ebc50 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2834,8 +2834,8 @@ dependencies = [
"libc",
"log",
"rustversion",
- "windows-link 0.2.1",
- "windows-result 0.4.1",
+ "windows-link 0.1.3",
+ "windows-result 0.3.4",
]
[[package]]
@@ -3425,7 +3425,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.62.2",
+ "windows-core 0.61.2",
]
[[package]]
@@ -4331,8 +4331,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-client"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"hex",
"mesh-llm-client",
@@ -4341,8 +4341,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-server"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4352,13 +4352,13 @@ dependencies = [
[[package]]
name = "mesh-llm-build-info"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "mesh-llm-client"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4389,8 +4389,8 @@ dependencies = [
[[package]]
name = "mesh-llm-config"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4405,8 +4405,8 @@ dependencies = [
[[package]]
name = "mesh-llm-embedded-runtime"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-host-runtime",
@@ -4415,8 +4415,8 @@ dependencies = [
[[package]]
name = "mesh-llm-events"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"clap",
@@ -4427,8 +4427,8 @@ dependencies = [
[[package]]
name = "mesh-llm-gpu-bench"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"cc",
@@ -4440,8 +4440,8 @@ dependencies = [
[[package]]
name = "mesh-llm-guardrails"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
"serde_json",
@@ -4449,16 +4449,16 @@ dependencies = [
[[package]]
name = "mesh-llm-hardware-profile"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"mesh-llm-native-runtime",
]
[[package]]
name = "mesh-llm-host-runtime"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"argon2",
@@ -4550,8 +4550,8 @@ dependencies = [
[[package]]
name = "mesh-llm-identity"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"argon2",
"base64",
@@ -4572,8 +4572,8 @@ dependencies = [
[[package]]
name = "mesh-llm-native-runtime"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"serde",
@@ -4583,8 +4583,8 @@ dependencies = [
[[package]]
name = "mesh-llm-node"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-types",
@@ -4597,8 +4597,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4614,8 +4614,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin-manager"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4632,8 +4632,8 @@ dependencies = [
[[package]]
name = "mesh-llm-protocol"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"hex",
@@ -4645,16 +4645,16 @@ dependencies = [
[[package]]
name = "mesh-llm-routing"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"iroh",
]
[[package]]
name = "mesh-llm-runtime-install"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4676,8 +4676,8 @@ dependencies = [
[[package]]
name = "mesh-llm-sdk"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4691,8 +4691,8 @@ dependencies = [
[[package]]
name = "mesh-llm-skills"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4702,8 +4702,8 @@ dependencies = [
[[package]]
name = "mesh-llm-system"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"chrono",
@@ -4725,8 +4725,8 @@ dependencies = [
[[package]]
name = "mesh-llm-types"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"hex",
"serde",
@@ -4736,13 +4736,13 @@ dependencies = [
[[package]]
name = "mesh-llm-ui"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "mesh-mixture-of-agents"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"async-trait",
"mesh-llm-guardrails",
@@ -4858,8 +4858,8 @@ dependencies = [
[[package]]
name = "model-artifact"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4869,8 +4869,8 @@ dependencies = [
[[package]]
name = "model-hf"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4887,8 +4887,8 @@ dependencies = [
[[package]]
name = "model-package"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"bytes",
@@ -4907,16 +4907,16 @@ dependencies = [
[[package]]
name = "model-ref"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
]
[[package]]
name = "model-resolver"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"model-artifact",
@@ -5626,8 +5626,8 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openai-frontend"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"async-trait",
"axum",
@@ -7858,8 +7858,8 @@ checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b"
[[package]]
name = "skippy-cache"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"blake3",
@@ -7868,29 +7868,29 @@ dependencies = [
[[package]]
name = "skippy-coordinator"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "skippy-ffi"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"libloading",
]
[[package]]
name = "skippy-metrics"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "skippy-protocol"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"prost",
"prost-build",
@@ -7900,8 +7900,8 @@ dependencies = [
[[package]]
name = "skippy-runtime"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"libc",
@@ -7914,8 +7914,8 @@ dependencies = [
[[package]]
name = "skippy-server"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -7942,8 +7942,8 @@ dependencies = [
[[package]]
name = "skippy-topology"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
"serde_json",
@@ -10301,8 +10301,8 @@ dependencies = [
"log",
"serde",
"thiserror 2.0.18",
- "windows 0.62.2",
- "windows-core 0.62.2",
+ "windows 0.61.3",
+ "windows-core 0.61.2",
]
[[package]]
diff --git a/crates/buzz-relay/Cargo.toml b/crates/buzz-relay/Cargo.toml
index f516b82d63..5d5282b6b4 100644
--- a/crates/buzz-relay/Cargo.toml
+++ b/crates/buzz-relay/Cargo.toml
@@ -77,8 +77,8 @@ metrics-exporter-prometheus = { workspace = true }
dev = ["buzz-auth/dev"]
[dev-dependencies]
-mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] }
-mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] }
+mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] }
+mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] }
buzz-core = { workspace = true, features = ["test-utils"] }
buzz-auth = { workspace = true, features = ["dev"] }
reqwest = { workspace = true }
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index 54e242a146..87b8d79828 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -1637,7 +1637,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "windows 0.62.2",
+ "windows 0.61.3",
]
[[package]]
@@ -2975,8 +2975,8 @@ dependencies = [
"libc",
"log",
"rustversion",
- "windows-link 0.2.1",
- "windows-result 0.4.1",
+ "windows-link 0.1.3",
+ "windows-result 0.3.4",
]
[[package]]
@@ -3711,7 +3711,7 @@ dependencies = [
"tokio",
"tower-service",
"tracing",
- "windows-registry 0.6.1",
+ "windows-registry 0.5.3",
]
[[package]]
@@ -3726,7 +3726,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.62.2",
+ "windows-core 0.61.2",
]
[[package]]
@@ -4761,8 +4761,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-client"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"hex",
"mesh-llm-client",
@@ -4771,8 +4771,8 @@ dependencies = [
[[package]]
name = "mesh-llm-api-server"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4782,13 +4782,13 @@ dependencies = [
[[package]]
name = "mesh-llm-build-info"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "mesh-llm-client"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4819,8 +4819,8 @@ dependencies = [
[[package]]
name = "mesh-llm-config"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4835,8 +4835,8 @@ dependencies = [
[[package]]
name = "mesh-llm-embedded-runtime"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-host-runtime",
@@ -4845,8 +4845,8 @@ dependencies = [
[[package]]
name = "mesh-llm-events"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"clap",
@@ -4857,8 +4857,8 @@ dependencies = [
[[package]]
name = "mesh-llm-gpu-bench"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"cc",
@@ -4870,8 +4870,8 @@ dependencies = [
[[package]]
name = "mesh-llm-guardrails"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
"serde_json",
@@ -4879,16 +4879,16 @@ dependencies = [
[[package]]
name = "mesh-llm-hardware-profile"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"mesh-llm-native-runtime",
]
[[package]]
name = "mesh-llm-host-runtime"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"argon2",
@@ -4980,8 +4980,8 @@ dependencies = [
[[package]]
name = "mesh-llm-identity"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"argon2",
"base64 0.22.1",
@@ -5002,8 +5002,8 @@ dependencies = [
[[package]]
name = "mesh-llm-native-runtime"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"serde",
@@ -5013,8 +5013,8 @@ dependencies = [
[[package]]
name = "mesh-llm-node"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-types",
@@ -5027,8 +5027,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -5044,8 +5044,8 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin-manager"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -5062,8 +5062,8 @@ dependencies = [
[[package]]
name = "mesh-llm-protocol"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"hex",
@@ -5075,16 +5075,16 @@ dependencies = [
[[package]]
name = "mesh-llm-routing"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"iroh",
]
[[package]]
name = "mesh-llm-runtime-install"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -5106,8 +5106,8 @@ dependencies = [
[[package]]
name = "mesh-llm-sdk"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -5121,8 +5121,8 @@ dependencies = [
[[package]]
name = "mesh-llm-skills"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -5132,8 +5132,8 @@ dependencies = [
[[package]]
name = "mesh-llm-system"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"chrono",
@@ -5155,8 +5155,8 @@ dependencies = [
[[package]]
name = "mesh-llm-types"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"hex",
"serde",
@@ -5166,13 +5166,13 @@ dependencies = [
[[package]]
name = "mesh-llm-ui"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "mesh-mixture-of-agents"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"async-trait",
"mesh-llm-guardrails",
@@ -5235,8 +5235,8 @@ dependencies = [
[[package]]
name = "model-artifact"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -5246,8 +5246,8 @@ dependencies = [
[[package]]
name = "model-hf"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -5264,8 +5264,8 @@ dependencies = [
[[package]]
name = "model-package"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"bytes",
@@ -5284,16 +5284,16 @@ dependencies = [
[[package]]
name = "model-ref"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
]
[[package]]
name = "model-resolver"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"model-artifact",
@@ -5923,7 +5923,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
dependencies = [
- "proc-macro-crate 2.0.2",
+ "proc-macro-crate 1.3.1",
"proc-macro2",
"quote",
"syn 2.0.118",
@@ -6297,8 +6297,8 @@ dependencies = [
[[package]]
name = "openai-frontend"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"async-trait",
"axum",
@@ -7191,7 +7191,7 @@ version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
dependencies = [
- "heck 0.5.0",
+ "heck 0.4.1",
"itertools",
"log",
"multimap",
@@ -8751,8 +8751,8 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
[[package]]
name = "skippy-cache"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"blake3",
@@ -8761,29 +8761,29 @@ dependencies = [
[[package]]
name = "skippy-coordinator"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "skippy-ffi"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"libloading 0.8.9",
]
[[package]]
name = "skippy-metrics"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "skippy-protocol"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"prost",
"prost-build",
@@ -8793,8 +8793,8 @@ dependencies = [
[[package]]
name = "skippy-runtime"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"libc",
@@ -8807,8 +8807,8 @@ dependencies = [
[[package]]
name = "skippy-server"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -8835,8 +8835,8 @@ dependencies = [
[[package]]
name = "skippy-topology"
-version = "0.73.0"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=002f2d8abb0bce3dbed59dc4e0944a51621ab47f#002f2d8abb0bce3dbed59dc4e0944a51621ab47f"
+version = "0.73.1"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
"serde_json",
@@ -11980,8 +11980,8 @@ dependencies = [
"log",
"serde",
"thiserror 2.0.18",
- "windows 0.62.2",
- "windows-core 0.62.2",
+ "windows 0.61.3",
+ "windows-core 0.61.2",
]
[[package]]
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index 92526f6ca6..0835c83b82 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -86,14 +86,14 @@ buzz_core_pkg = { package = "buzz-core", path = "../../crates/buzz-core" }
buzz_persona_pkg = { package = "buzz-persona", path = "../../crates/buzz-persona" }
buzz_sdk_pkg = { package = "buzz-sdk", path = "../../crates/buzz-sdk" }
buzz_agent_pkg = { package = "buzz-agent", path = "../../crates/buzz-agent" }
-mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
-mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
+mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
+mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
# Model catalog + hardware survey for the Share-compute model picker (same
# diagnose pattern as mesh-console). Lib name of mesh-llm-client is mesh_client.
-mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-client", optional = true }
-mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-node", optional = true }
-mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-system", optional = true }
-mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "002f2d8abb0bce3dbed59dc4e0944a51621ab47f", package = "mesh-llm-events", optional = true }
+mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-client", optional = true }
+mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-node", optional = true }
+mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-system", optional = true }
+mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-events", optional = true }
base64 = "0.22"
sha2 = "0.11"
tar = "0.4"
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 079a5a2acf..082cd43b56 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -226,6 +226,35 @@ async fn wait_for_stable_initial_window_geometry(window: &tau
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
+#[cfg(all(feature = "mesh-llm", target_os = "macos"))]
+fn hard_exit_after_mesh_shutdown() -> ! {
+ // SAFETY: all Buzz-managed subprocesses and the embedded Mesh runtime have
+ // been stopped above. `_exit` intentionally skips only process-global C++
+ // destructors and buffered stdio; no Rust or application state remains to
+ // be observed after this point.
+ unsafe { libc::_exit(0) }
+}
+
+#[cfg(feature = "mesh-llm")]
+fn shutdown_mesh_runtime(app: &tauri::AppHandle) {
+ let app = app.clone();
+ let (tx, rx) = std::sync::mpsc::channel();
+ tauri::async_runtime::spawn(async move {
+ let state = app.state::();
+ let runtime = state.mesh_llm_runtime.lock().await.take();
+ let result = match runtime {
+ Some(runtime) => runtime.stop().await,
+ None => Ok(()),
+ };
+ let _ = tx.send(result);
+ });
+ match rx.recv_timeout(std::time::Duration::from_secs(5)) {
+ Ok(Ok(())) => {}
+ Ok(Err(error)) => eprintln!("buzz-desktop: failed to stop Mesh runtime: {error}"),
+ Err(error) => eprintln!("buzz-desktop: timed out stopping Mesh runtime: {error}"),
+ }
+}
+
pub fn run() {
// mesh-llm's async chains (model download, node start/join) overflow
// tokio's default 2 MiB worker stacks — a stack-guard SIGABRT, not a
@@ -948,7 +977,12 @@ pub fn run() {
signal_shutdown_started.store(true, Ordering::SeqCst);
if !signal_shutdown_done.swap(true, Ordering::SeqCst) {
let _ = shutdown_managed_agents(&signal_app);
+ #[cfg(feature = "mesh-llm")]
+ shutdown_mesh_runtime(&signal_app);
}
+ #[cfg(all(feature = "mesh-llm", target_os = "macos"))]
+ hard_exit_after_mesh_shutdown();
+ #[cfg(not(all(feature = "mesh-llm", target_os = "macos")))]
std::process::exit(0);
}) {
eprintln!("buzz-desktop: failed to register signal handler: {e}");
@@ -964,7 +998,17 @@ pub fn run() {
if let Err(error) = shutdown_managed_agents(app_handle) {
eprintln!("buzz-desktop: failed to stop managed agents: {error}");
}
+ #[cfg(feature = "mesh-llm")]
+ shutdown_mesh_runtime(app_handle);
}
+
+ // AppKit terminates through libc exit(), which runs C++ static
+ // destructors. The embedded ggml/Metal runtime currently aborts in
+ // that destructor phase even after its node has stopped cleanly.
+ // End the process only after Buzz and Mesh shutdown above, while
+ // deliberately skipping those native global destructors.
+ #[cfg(all(feature = "mesh-llm", target_os = "macos"))]
+ hard_exit_after_mesh_shutdown();
}
_ => {}
});
From 04c964a49cf18dc922630cf6e9ab234e9690e930 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 15:01:55 +1000
Subject: [PATCH 34/35] build(mesh): pin released runtime by tag
---
.github/workflows/ci.yml | 2 +-
.github/workflows/release.yml | 2 +-
Cargo.lock | 88 ++++++++++++++++----------------
crates/buzz-relay/Cargo.toml | 4 +-
desktop/src-tauri/Cargo.lock | 96 +++++++++++++++++------------------
desktop/src-tauri/Cargo.toml | 12 ++---
6 files changed, 102 insertions(+), 102 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e0e85ebfc1..18e9f1829e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -914,7 +914,7 @@ jobs:
id: mesh_rev
run: |
set -euo pipefail
- REV=$(grep -oE 'mesh-llm\.git\?rev=[0-9a-f]{40}' Cargo.lock | head -1 | grep -oE '[0-9a-f]{40}')
+ REV=$(python3 -c 'import tomllib; d=tomllib.load(open("Cargo.lock", "rb")); p=next(p for p in d["package"] if p["name"] == "mesh-llm-sdk"); print(p["source"].rsplit("#", 1)[1])')
[[ -n "$REV" ]] || { echo "::error::could not resolve mesh-llm rev from Cargo.lock"; exit 1; }
echo "rev=$REV" >> "$GITHUB_OUTPUT"
echo "short=${REV:0:7}" >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index cbe9fb1ea6..76a8bdcb8b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -137,7 +137,7 @@ jobs:
id: mesh_rev
run: |
set -euo pipefail
- REV=$(grep -oE 'mesh-llm\.git\?rev=[0-9a-f]{40}' Cargo.lock | head -1 | grep -oE '[0-9a-f]{40}')
+ REV=$(python3 -c 'import tomllib; d=tomllib.load(open("Cargo.lock", "rb")); p=next(p for p in d["package"] if p["name"] == "mesh-llm-sdk"); print(p["source"].rsplit("#", 1)[1])')
[[ -n "$REV" ]] || { echo "::error::could not resolve mesh-llm rev from Cargo.lock"; exit 1; }
echo "rev=$REV" >> "$GITHUB_OUTPUT"
echo "short=${REV:0:7}" >> "$GITHUB_OUTPUT"
diff --git a/Cargo.lock b/Cargo.lock
index 6f3f6ebc50..f9bba7c7fa 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2834,8 +2834,8 @@ dependencies = [
"libc",
"log",
"rustversion",
- "windows-link 0.1.3",
- "windows-result 0.3.4",
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
]
[[package]]
@@ -3425,7 +3425,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.61.2",
+ "windows-core 0.62.2",
]
[[package]]
@@ -4332,7 +4332,7 @@ dependencies = [
[[package]]
name = "mesh-llm-api-client"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"hex",
"mesh-llm-client",
@@ -4342,7 +4342,7 @@ dependencies = [
[[package]]
name = "mesh-llm-api-server"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4353,12 +4353,12 @@ dependencies = [
[[package]]
name = "mesh-llm-build-info"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "mesh-llm-client"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4390,7 +4390,7 @@ dependencies = [
[[package]]
name = "mesh-llm-config"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4406,7 +4406,7 @@ dependencies = [
[[package]]
name = "mesh-llm-embedded-runtime"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-host-runtime",
@@ -4416,7 +4416,7 @@ dependencies = [
[[package]]
name = "mesh-llm-events"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"clap",
@@ -4428,7 +4428,7 @@ dependencies = [
[[package]]
name = "mesh-llm-gpu-bench"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"cc",
@@ -4441,7 +4441,7 @@ dependencies = [
[[package]]
name = "mesh-llm-guardrails"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
"serde_json",
@@ -4450,7 +4450,7 @@ dependencies = [
[[package]]
name = "mesh-llm-hardware-profile"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"mesh-llm-native-runtime",
]
@@ -4458,7 +4458,7 @@ dependencies = [
[[package]]
name = "mesh-llm-host-runtime"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"argon2",
@@ -4551,7 +4551,7 @@ dependencies = [
[[package]]
name = "mesh-llm-identity"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"argon2",
"base64",
@@ -4573,7 +4573,7 @@ dependencies = [
[[package]]
name = "mesh-llm-native-runtime"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"serde",
@@ -4584,7 +4584,7 @@ dependencies = [
[[package]]
name = "mesh-llm-node"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-types",
@@ -4598,7 +4598,7 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4615,7 +4615,7 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin-manager"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4633,7 +4633,7 @@ dependencies = [
[[package]]
name = "mesh-llm-protocol"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"hex",
@@ -4646,7 +4646,7 @@ dependencies = [
[[package]]
name = "mesh-llm-routing"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"iroh",
]
@@ -4654,7 +4654,7 @@ dependencies = [
[[package]]
name = "mesh-llm-runtime-install"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4677,7 +4677,7 @@ dependencies = [
[[package]]
name = "mesh-llm-sdk"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4692,7 +4692,7 @@ dependencies = [
[[package]]
name = "mesh-llm-skills"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4703,7 +4703,7 @@ dependencies = [
[[package]]
name = "mesh-llm-system"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"chrono",
@@ -4726,7 +4726,7 @@ dependencies = [
[[package]]
name = "mesh-llm-types"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"hex",
"serde",
@@ -4737,12 +4737,12 @@ dependencies = [
[[package]]
name = "mesh-llm-ui"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "mesh-mixture-of-agents"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"async-trait",
"mesh-llm-guardrails",
@@ -4859,7 +4859,7 @@ dependencies = [
[[package]]
name = "model-artifact"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4870,7 +4870,7 @@ dependencies = [
[[package]]
name = "model-hf"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4888,7 +4888,7 @@ dependencies = [
[[package]]
name = "model-package"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"bytes",
@@ -4908,7 +4908,7 @@ dependencies = [
[[package]]
name = "model-ref"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
]
@@ -4916,7 +4916,7 @@ dependencies = [
[[package]]
name = "model-resolver"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"model-artifact",
@@ -5627,7 +5627,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openai-frontend"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"async-trait",
"axum",
@@ -7859,7 +7859,7 @@ checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b"
[[package]]
name = "skippy-cache"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"blake3",
@@ -7869,7 +7869,7 @@ dependencies = [
[[package]]
name = "skippy-coordinator"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"thiserror 2.0.18",
]
@@ -7877,7 +7877,7 @@ dependencies = [
[[package]]
name = "skippy-ffi"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"libloading",
]
@@ -7885,12 +7885,12 @@ dependencies = [
[[package]]
name = "skippy-metrics"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "skippy-protocol"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"prost",
"prost-build",
@@ -7901,7 +7901,7 @@ dependencies = [
[[package]]
name = "skippy-runtime"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"libc",
@@ -7915,7 +7915,7 @@ dependencies = [
[[package]]
name = "skippy-server"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -7943,7 +7943,7 @@ dependencies = [
[[package]]
name = "skippy-topology"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
"serde_json",
@@ -10301,8 +10301,8 @@ dependencies = [
"log",
"serde",
"thiserror 2.0.18",
- "windows 0.61.3",
- "windows-core 0.61.2",
+ "windows 0.62.2",
+ "windows-core 0.62.2",
]
[[package]]
diff --git a/crates/buzz-relay/Cargo.toml b/crates/buzz-relay/Cargo.toml
index 5d5282b6b4..10c5b05425 100644
--- a/crates/buzz-relay/Cargo.toml
+++ b/crates/buzz-relay/Cargo.toml
@@ -77,8 +77,8 @@ metrics-exporter-prometheus = { workspace = true }
dev = ["buzz-auth/dev"]
[dev-dependencies]
-mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] }
-mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] }
+mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.73.1", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] }
+mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.73.1", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] }
buzz-core = { workspace = true, features = ["test-utils"] }
buzz-auth = { workspace = true, features = ["dev"] }
reqwest = { workspace = true }
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index 87b8d79828..1428155fd1 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -1637,7 +1637,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "windows 0.61.3",
+ "windows 0.62.2",
]
[[package]]
@@ -2975,8 +2975,8 @@ dependencies = [
"libc",
"log",
"rustversion",
- "windows-link 0.1.3",
- "windows-result 0.3.4",
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
]
[[package]]
@@ -3711,7 +3711,7 @@ dependencies = [
"tokio",
"tower-service",
"tracing",
- "windows-registry 0.5.3",
+ "windows-registry 0.6.1",
]
[[package]]
@@ -3726,7 +3726,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.61.2",
+ "windows-core 0.62.2",
]
[[package]]
@@ -4762,7 +4762,7 @@ dependencies = [
[[package]]
name = "mesh-llm-api-client"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"hex",
"mesh-llm-client",
@@ -4772,7 +4772,7 @@ dependencies = [
[[package]]
name = "mesh-llm-api-server"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -4783,12 +4783,12 @@ dependencies = [
[[package]]
name = "mesh-llm-build-info"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "mesh-llm-client"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -4820,7 +4820,7 @@ dependencies = [
[[package]]
name = "mesh-llm-config"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -4836,7 +4836,7 @@ dependencies = [
[[package]]
name = "mesh-llm-embedded-runtime"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-host-runtime",
@@ -4846,7 +4846,7 @@ dependencies = [
[[package]]
name = "mesh-llm-events"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"clap",
@@ -4858,7 +4858,7 @@ dependencies = [
[[package]]
name = "mesh-llm-gpu-bench"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"cc",
@@ -4871,7 +4871,7 @@ dependencies = [
[[package]]
name = "mesh-llm-guardrails"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
"serde_json",
@@ -4880,7 +4880,7 @@ dependencies = [
[[package]]
name = "mesh-llm-hardware-profile"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"mesh-llm-native-runtime",
]
@@ -4888,7 +4888,7 @@ dependencies = [
[[package]]
name = "mesh-llm-host-runtime"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"argon2",
@@ -4981,7 +4981,7 @@ dependencies = [
[[package]]
name = "mesh-llm-identity"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"argon2",
"base64 0.22.1",
@@ -5003,7 +5003,7 @@ dependencies = [
[[package]]
name = "mesh-llm-native-runtime"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"serde",
@@ -5014,7 +5014,7 @@ dependencies = [
[[package]]
name = "mesh-llm-node"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-types",
@@ -5028,7 +5028,7 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -5045,7 +5045,7 @@ dependencies = [
[[package]]
name = "mesh-llm-plugin-manager"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -5063,7 +5063,7 @@ dependencies = [
[[package]]
name = "mesh-llm-protocol"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"hex",
@@ -5076,7 +5076,7 @@ dependencies = [
[[package]]
name = "mesh-llm-routing"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"iroh",
]
@@ -5084,7 +5084,7 @@ dependencies = [
[[package]]
name = "mesh-llm-runtime-install"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -5107,7 +5107,7 @@ dependencies = [
[[package]]
name = "mesh-llm-sdk"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"mesh-llm-api-client",
@@ -5122,7 +5122,7 @@ dependencies = [
[[package]]
name = "mesh-llm-skills"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"dirs",
@@ -5133,7 +5133,7 @@ dependencies = [
[[package]]
name = "mesh-llm-system"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"chrono",
@@ -5156,7 +5156,7 @@ dependencies = [
[[package]]
name = "mesh-llm-types"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"hex",
"serde",
@@ -5167,12 +5167,12 @@ dependencies = [
[[package]]
name = "mesh-llm-ui"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "mesh-mixture-of-agents"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"async-trait",
"mesh-llm-guardrails",
@@ -5236,7 +5236,7 @@ dependencies = [
[[package]]
name = "model-artifact"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -5247,7 +5247,7 @@ dependencies = [
[[package]]
name = "model-hf"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -5265,7 +5265,7 @@ dependencies = [
[[package]]
name = "model-package"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"bytes",
@@ -5285,7 +5285,7 @@ dependencies = [
[[package]]
name = "model-ref"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
]
@@ -5293,7 +5293,7 @@ dependencies = [
[[package]]
name = "model-resolver"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"model-artifact",
@@ -5923,7 +5923,7 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
dependencies = [
- "proc-macro-crate 1.3.1",
+ "proc-macro-crate 2.0.2",
"proc-macro2",
"quote",
"syn 2.0.118",
@@ -6298,7 +6298,7 @@ dependencies = [
[[package]]
name = "openai-frontend"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"async-trait",
"axum",
@@ -7191,7 +7191,7 @@ version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
dependencies = [
- "heck 0.4.1",
+ "heck 0.5.0",
"itertools",
"log",
"multimap",
@@ -8752,7 +8752,7 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
[[package]]
name = "skippy-cache"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"blake3",
@@ -8762,7 +8762,7 @@ dependencies = [
[[package]]
name = "skippy-coordinator"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"thiserror 2.0.18",
]
@@ -8770,7 +8770,7 @@ dependencies = [
[[package]]
name = "skippy-ffi"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"libloading 0.8.9",
]
@@ -8778,12 +8778,12 @@ dependencies = [
[[package]]
name = "skippy-metrics"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
[[package]]
name = "skippy-protocol"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"prost",
"prost-build",
@@ -8794,7 +8794,7 @@ dependencies = [
[[package]]
name = "skippy-runtime"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"libc",
@@ -8808,7 +8808,7 @@ dependencies = [
[[package]]
name = "skippy-server"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"anyhow",
"async-trait",
@@ -8836,7 +8836,7 @@ dependencies = [
[[package]]
name = "skippy-topology"
version = "0.73.1"
-source = "git+https://github.com/Mesh-LLM/mesh-llm.git?rev=43103c5c40292be688ac0261129bcbab0e7b9132#43103c5c40292be688ac0261129bcbab0e7b9132"
+source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.73.1#43103c5c40292be688ac0261129bcbab0e7b9132"
dependencies = [
"serde",
"serde_json",
@@ -11980,8 +11980,8 @@ dependencies = [
"log",
"serde",
"thiserror 2.0.18",
- "windows 0.61.3",
- "windows-core 0.61.2",
+ "windows 0.62.2",
+ "windows-core 0.62.2",
]
[[package]]
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index 0835c83b82..96c36f994e 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -86,14 +86,14 @@ buzz_core_pkg = { package = "buzz-core", path = "../../crates/buzz-core" }
buzz_persona_pkg = { package = "buzz-persona", path = "../../crates/buzz-persona" }
buzz_sdk_pkg = { package = "buzz-sdk", path = "../../crates/buzz-sdk" }
buzz_agent_pkg = { package = "buzz-agent", path = "../../crates/buzz-agent" }
-mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
-mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
+mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.73.1", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true }
+mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.73.1", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true }
# Model catalog + hardware survey for the Share-compute model picker (same
# diagnose pattern as mesh-console). Lib name of mesh-llm-client is mesh_client.
-mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-client", optional = true }
-mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-node", optional = true }
-mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-system", optional = true }
-mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", rev = "43103c5c40292be688ac0261129bcbab0e7b9132", package = "mesh-llm-events", optional = true }
+mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.73.1", package = "mesh-llm-client", optional = true }
+mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.73.1", package = "mesh-llm-node", optional = true }
+mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.73.1", package = "mesh-llm-system", optional = true }
+mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.73.1", package = "mesh-llm-events", optional = true }
base64 = "0.22"
sha2 = "0.11"
tar = "0.4"
From 483b67237a2dc34d251d48030fdcc568a123a368 Mon Sep 17 00:00:00 2001
From: Michael Neale
Date: Tue, 14 Jul 2026 15:08:54 +1000
Subject: [PATCH 35/35] refactor(mesh): keep shutdown logic scoped
---
desktop/src-tauri/src/lib.rs | 33 ++++---------------------------
desktop/src-tauri/src/shutdown.rs | 28 ++++++++++++++++++++++++++
2 files changed, 32 insertions(+), 29 deletions(-)
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 082cd43b56..45de10d8dd 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -47,7 +47,11 @@ use huddle::{
use managed_agents::{
backfill_persona_snapshots, ensure_nest, restore_managed_agents_on_launch, try_regenerate_nest,
};
+#[cfg(all(feature = "mesh-llm", target_os = "macos"))]
+use shutdown::hard_exit_after_mesh_shutdown;
use shutdown::shutdown_managed_agents;
+#[cfg(feature = "mesh-llm")]
+use shutdown::shutdown_mesh_runtime;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
@@ -226,35 +230,6 @@ async fn wait_for_stable_initial_window_geometry(window: &tau
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
-#[cfg(all(feature = "mesh-llm", target_os = "macos"))]
-fn hard_exit_after_mesh_shutdown() -> ! {
- // SAFETY: all Buzz-managed subprocesses and the embedded Mesh runtime have
- // been stopped above. `_exit` intentionally skips only process-global C++
- // destructors and buffered stdio; no Rust or application state remains to
- // be observed after this point.
- unsafe { libc::_exit(0) }
-}
-
-#[cfg(feature = "mesh-llm")]
-fn shutdown_mesh_runtime(app: &tauri::AppHandle) {
- let app = app.clone();
- let (tx, rx) = std::sync::mpsc::channel();
- tauri::async_runtime::spawn(async move {
- let state = app.state::();
- let runtime = state.mesh_llm_runtime.lock().await.take();
- let result = match runtime {
- Some(runtime) => runtime.stop().await,
- None => Ok(()),
- };
- let _ = tx.send(result);
- });
- match rx.recv_timeout(std::time::Duration::from_secs(5)) {
- Ok(Ok(())) => {}
- Ok(Err(error)) => eprintln!("buzz-desktop: failed to stop Mesh runtime: {error}"),
- Err(error) => eprintln!("buzz-desktop: timed out stopping Mesh runtime: {error}"),
- }
-}
-
pub fn run() {
// mesh-llm's async chains (model download, node start/join) overflow
// tokio's default 2 MiB worker stacks — a stack-guard SIGABRT, not a
diff --git a/desktop/src-tauri/src/shutdown.rs b/desktop/src-tauri/src/shutdown.rs
index 532e005f82..5e17c875be 100644
--- a/desktop/src-tauri/src/shutdown.rs
+++ b/desktop/src-tauri/src/shutdown.rs
@@ -7,6 +7,34 @@ use crate::managed_agents::{
};
use crate::util;
+#[cfg(all(feature = "mesh-llm", target_os = "macos"))]
+pub(crate) fn hard_exit_after_mesh_shutdown() -> ! {
+ // SAFETY: all Buzz-managed subprocesses and the embedded Mesh runtime have
+ // been stopped. `_exit` intentionally skips only process-global C++
+ // destructors and buffered stdio; no application state remains observable.
+ unsafe { libc::_exit(0) }
+}
+
+#[cfg(feature = "mesh-llm")]
+pub(crate) fn shutdown_mesh_runtime(app: &tauri::AppHandle) {
+ let app = app.clone();
+ let (tx, rx) = std::sync::mpsc::channel();
+ tauri::async_runtime::spawn(async move {
+ let state = app.state::();
+ let runtime = state.mesh_llm_runtime.lock().await.take();
+ let result = match runtime {
+ Some(runtime) => runtime.stop().await,
+ None => Ok(()),
+ };
+ let _ = tx.send(result);
+ });
+ match rx.recv_timeout(std::time::Duration::from_secs(5)) {
+ Ok(Ok(())) => {}
+ Ok(Err(error)) => eprintln!("buzz-desktop: failed to stop Mesh runtime: {error}"),
+ Err(error) => eprintln!("buzz-desktop: timed out stopping Mesh runtime: {error}"),
+ }
+}
+
pub(crate) fn shutdown_managed_agents(app: &tauri::AppHandle) -> Result<(), String> {
let state = app.state::();
let _store_guard = state