Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/linux-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ jobs:
./scripts/bundle-sidecars.sh

- name: Build Linux Tauri app
# Intentionally without --features mesh-llm: release-linux matches this
# (CI mesh builds use Metal). Settings → Compute shows a build-unavailable
# empty state via mesh_feature_enabled instead of a dead-end toggle (#3841).
run: cd desktop && pnpm tauri build --ci --bundles deb,appimage --config src-tauri/tauri.canary.conf.json
env:
CMAKE_POLICY_VERSION_MINIMUM: "3.5"
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,9 @@ jobs:
BUZZ_UPDATER_ENDPOINT: https://github.com/block/buzz/releases/download/buzz-desktop-latest/latest.json

- name: Build Linux Tauri app
# No --features mesh-llm (macOS release is the only official package that
# enables Share Compute today; CI llama builds target Metal). The desktop
# Settings → Compute card gates on mesh_feature_enabled (#3841).
run: cd desktop && pnpm tauri build --verbose --ci --bundles deb,appimage --config src-tauri/tauri.release.conf.json
env:
BUZZ_UPDATER_PUBLIC_KEY: ${{ secrets.BUZZ_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
Expand Down
6 changes: 6 additions & 0 deletions desktop/src-tauri/src/commands/mesh_llm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,12 @@ pub async fn mesh_model_catalog() -> CmdResult<mesh_llm::MeshModelCatalog> {
.map_err(|error| format!("mesh catalog task failed: {error}"))
}

/// Build-time probe: Share Compute / mesh-llm is compiled into this binary.
#[tauri::command]
pub fn mesh_feature_enabled() -> bool {
true
}

#[cfg(all(test, feature = "mesh-llm"))]
#[path = "mesh_llm_tests.rs"]
mod tests;
1 change: 1 addition & 0 deletions desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ pub fn run() {
mesh_serving_usage,
mesh_installed_models,
mesh_model_catalog,
mesh_feature_enabled,
update_managed_agent,
discover_backend_providers,
probe_backend_provider,
Expand Down
20 changes: 14 additions & 6 deletions desktop/src-tauri/src/mesh_llm_stubs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,49 @@ use crate::app_state::AppState;

type CmdResult<T> = Result<T, String>;

const MESH_FEATURE_DISABLED: &str = "Share Compute is not included in this build (mesh-llm feature off — typical for Linux/Windows release packages; macOS releases enable it).";

/// Build-time probe: Share Compute / mesh-llm is compiled into this binary.
#[tauri::command]
pub fn mesh_feature_enabled() -> bool {
false
}

#[tauri::command]
pub async fn mesh_start_node(
_app: tauri::AppHandle,
_state: State<'_, AppState>,
_request: serde_json::Value,
) -> CmdResult<serde_json::Value> {
Err("mesh-llm feature not enabled".to_string())
Err(MESH_FEATURE_DISABLED.to_string())
}

#[tauri::command]
pub async fn mesh_stop_node(
_app: tauri::AppHandle,
_state: State<'_, AppState>,
) -> CmdResult<serde_json::Value> {
Err("mesh-llm feature not enabled".to_string())
Err(MESH_FEATURE_DISABLED.to_string())
}

#[tauri::command]
pub async fn mesh_node_status(_state: State<'_, AppState>) -> CmdResult<serde_json::Value> {
Err("mesh-llm feature not enabled".to_string())
Err(MESH_FEATURE_DISABLED.to_string())
}

#[tauri::command]
pub async fn mesh_serving_usage(_state: State<'_, AppState>) -> CmdResult<serde_json::Value> {
Err("mesh-llm feature not enabled".to_string())
Err(MESH_FEATURE_DISABLED.to_string())
}

#[tauri::command]
pub async fn mesh_installed_models(
_state: State<'_, AppState>,
) -> CmdResult<Vec<serde_json::Value>> {
Err("mesh-llm feature not enabled".to_string())
Err(MESH_FEATURE_DISABLED.to_string())
}

#[tauri::command]
pub async fn mesh_model_catalog() -> CmdResult<serde_json::Value> {
Err("mesh-llm feature not enabled".to_string())
Err(MESH_FEATURE_DISABLED.to_string())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from "react";

import { meshFeatureEnabled } from "@/shared/api/tauriMesh";

/**
* Resolves whether Share Compute was compiled into this desktop binary.
* `null` while the probe is in flight.
*/
export function useMeshFeatureEnabled(): boolean | null {
const [enabled, setEnabled] = React.useState<boolean | null>(null);

React.useEffect(() => {
let cancelled = false;
(async () => {
try {
const value = await meshFeatureEnabled();
if (!cancelled) setEnabled(value);
} catch {
// Older sidecars without the probe still surface stub errors on status.
if (!cancelled) setEnabled(null);
}
})();
return () => {
cancelled = true;
};
}, []);

return enabled;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";

import { isMeshFeatureDisabledError } from "./isMeshFeatureDisabledError.ts";

describe("isMeshFeatureDisabledError", () => {
it("matches the stub error and the clearer packaging copy", () => {
assert.equal(
isMeshFeatureDisabledError("mesh-llm feature not enabled"),
true,
);
assert.equal(
isMeshFeatureDisabledError(
"Share Compute is not included in this build (mesh-llm feature off — typical for Linux/Windows release packages; macOS releases enable it).",
),
true,
);
});

it("ignores unrelated failures", () => {
assert.equal(isMeshFeatureDisabledError(null), false);
assert.equal(isMeshFeatureDisabledError("download failed"), false);
});
});
12 changes: 12 additions & 0 deletions desktop/src/features/mesh-compute/isMeshFeatureDisabledError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Classify Share Compute backend errors so the settings card can show a
* build-unavailable state instead of a dead-end toggle (#3841).
*/
export function isMeshFeatureDisabledError(message: string | null | undefined): boolean {
if (!message) return false;
const lower = message.toLowerCase();
return (
lower.includes("mesh-llm feature") ||
lower.includes("not included in this build")
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import {
} from "@/features/settings/ui/SettingsOptionGroup";
import { SettingsSectionHeader } from "@/features/settings/ui/SettingsSectionHeader";
import { classifyModelRef } from "../classifyModelRef";
import { isMeshFeatureDisabledError } from "../isMeshFeatureDisabledError";
import {
downloadPercent,
formatDownloadBytes,
useMeshDownloadProgress,
} from "../hooks/useMeshDownloadProgress";
import { useMeshFeatureEnabled } from "../hooks/useMeshFeatureEnabled";
import { useMeshNodeStatus } from "../hooks/useMeshNodeStatus";
import { useMeshServingUsage } from "../hooks/useMeshServingUsage";
import { deriveMeshShareToggle } from "../shareToggleState";
Expand Down Expand Up @@ -64,6 +66,7 @@ function writeDraft(key: string, value: string): void {
* exposing implementation protocols or raw mesh controls.
*/
export function MeshComputeSettingsCard() {
const featureEnabled = useMeshFeatureEnabled();
const { status, error, refresh } = useMeshNodeStatus();
const [installedModels, setInstalledModels] = React.useState<
MeshModelOption[]
Expand All @@ -84,6 +87,35 @@ export function MeshComputeSettingsCard() {
const { progress: downloadProgress, reset: resetDownloadProgress } =
useMeshDownloadProgress();

const buildUnavailable =
featureEnabled === false || isMeshFeatureDisabledError(error);

if (buildUnavailable) {
return (
<section className="min-w-0" data-testid="settings-mesh-share-compute">
<SettingsSectionHeader
title="Share compute"
description={
<>
Share this machine with your relay. When on, other members can run
their agents here.
</>
}
/>
<p
className="mt-4 text-sm text-muted-foreground"
data-testid="settings-mesh-share-unavailable"
>
Share Compute is not included in this desktop build. Official Linux
and Windows packages currently ship without the mesh-llm feature;
macOS release builds enable it. Build from source with{" "}
<code className="text-xs">--features mesh-llm</code> to turn it on
locally.
</p>
</section>
);
}

// Fetch installed models. Called on mount and whenever the running state
// changes (a fresh start may have downloaded a new model). Stale-tolerant —
// the picklist is a convenience, not load-bearing.
Expand Down
9 changes: 9 additions & 0 deletions desktop/src/shared/api/tauriMesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,12 @@ export type MeshModelCatalog = {
export async function meshModelCatalog(): Promise<MeshModelCatalog> {
return await invokeTauri<MeshModelCatalog>("mesh_model_catalog");
}

/**
* Whether this desktop binary was compiled with `--features mesh-llm`.
* Linux/Windows release packages currently ship without it (#3841); macOS
* release/canary builds enable it. Prefer this over catching stub errors.
*/
export async function meshFeatureEnabled(): Promise<boolean> {
return await invokeTauri<boolean>("mesh_feature_enabled");
}
2 changes: 2 additions & 0 deletions desktop/src/testing/e2eBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10012,6 +10012,8 @@ export function maybeInstallE2eTauriMocks() {
}
case "mesh_installed_models":
return mockMeshState.models;
case "mesh_feature_enabled":
return true;
case "mesh_model_catalog":
return {
gpuName: "Mock Apple GPU",
Expand Down
12 changes: 12 additions & 0 deletions docs/buzz-shared-compute-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ stop printing build progress.
Using plain `just dev` is not sufficient: the Compute UI and embedded MeshLLM
runtime are behind the `mesh-llm` feature.

### Official packages and the Settings → Compute card

Release/canary packaging only passes `--features mesh-llm` on macOS today
(see `.github/workflows/release.yml` and the Linux/Windows canary jobs). Official
`.deb` / AppImage / Windows installers therefore compile the stub backend:
Share Compute commands return a build-unavailable error, and Settings → Compute
shows an explanatory empty state instead of a dead-end toggle (`#3841`).

To exercise Share Compute locally on any OS, use `just mesh=1 dev` (or otherwise
build the desktop with `--features mesh-llm`). The `mesh_feature_enabled` Tauri
command reports whether the running binary includes the feature.

## 2. Share this machine

1. Open **Settings**.
Expand Down