Polish Share Compute settings (#3735)

## Summary
- Refresh Share Compute with the shared agent-style model controls.
- Reveal sharing details and advanced options only while sharing.
- Remove the preview-only mesh API path.

## Validation
- `pnpm check`
- `pnpm test`
- `pnpm exec playwright test tests/e2e/mesh-compute.spec.ts`

Snapshots are attached in a follow-up comment.

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
klopez4212
2026-08-03 22:12:21 +01:00
committed by GitHub
parent 7981597848
commit 027a74a61c
4 changed files with 367 additions and 261 deletions

View File

@@ -1,9 +1,19 @@
import * as React from "react";
import { ChevronDown, Cpu } from "lucide-react";
import { ChevronDown } from "lucide-react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import { Input } from "@/shared/ui/input";
import { Switch } from "@/shared/ui/switch";
import { cn } from "@/shared/lib/cn";
import {
AgentConfigTextInput,
AgentDropdownSelect,
type AgentDropdownOption,
} from "@/features/agents/ui/agentConfigControls";
import {
CUSTOM_MODEL_DROPDOWN_VALUE,
PERSONA_FIELD_CONTROL_CLASS,
PERSONA_FIELD_SHELL_CLASS,
} from "@/features/agents/ui/agentConfigOptions";
import {
meshStartNode,
@@ -17,10 +27,6 @@ import type {
MeshModelOption,
MeshNodeStatus,
} from "@/shared/api/tauriMesh";
import {
SettingsOptionGroup,
SettingsOptionRow,
} from "@/features/settings/ui/SettingsOptionGroup";
import { SettingsSectionHeader } from "@/features/settings/ui/SettingsSectionHeader";
import { classifyModelRef } from "../classifyModelRef";
import {
@@ -36,6 +42,20 @@ import { deriveServingIndicator } from "../servingUsage";
const MODEL_DRAFT_STORAGE_KEY = "buzz.mesh-compute.share.model.v1";
const MAX_VRAM_DRAFT_STORAGE_KEY = "buzz.mesh-compute.share.max-vram-gb.v1";
// Keep the Share compute controls visually and behaviorally aligned with the
// agent configuration fields. This is intentionally the same shell used by
// AgentDefaultsEditor rather than a local approximation of a select.
const MESH_SELECT_TRIGGER_CLASS = cn(
PERSONA_FIELD_CONTROL_CLASS,
PERSONA_FIELD_SHELL_CLASS,
"h-11 px-3 py-2 leading-6 hover:bg-muted/40 focus:bg-muted/40 [&>svg]:text-muted-foreground/60",
);
const SHARE_COMPUTE_REVEAL_TRANSITION = {
duration: 0.22,
ease: [0.23, 1, 0.32, 1],
} as const;
function readDraft(key: string): string {
try {
return window.localStorage.getItem(key) ?? "";
@@ -64,6 +84,7 @@ function writeDraft(key: string, value: string): void {
* exposing implementation protocols or raw mesh controls.
*/
export function MeshComputeSettingsCard() {
const shouldReduceMotion = useReducedMotion();
const { status, error, refresh } = useMeshNodeStatus();
const [installedModels, setInstalledModels] = React.useState<
MeshModelOption[]
@@ -75,6 +96,7 @@ export function MeshComputeSettingsCard() {
const [maxVramGb, setMaxVramGb] = React.useState<string>(() =>
readDraft(MAX_VRAM_DRAFT_STORAGE_KEY),
);
const [isCustomModelEditing, setIsCustomModelEditing] = React.useState(false);
const [advancedOpen, setAdvancedOpen] = React.useState(false);
const [actionInFlight, setActionInFlight] = React.useState(false);
const [pendingAction, setPendingAction] = React.useState<
@@ -163,6 +185,7 @@ export function MeshComputeSettingsCard() {
const controlsDisabled = actionInFlight || (slotOccupied && !isConsuming);
const refClass = classifyModelRef(modelInput);
const canStart = refClass.kind !== "unknown" && !actionInFlight;
const showSharingControls = isSharing || pendingAction === "start";
async function handleToggle(next: boolean) {
// Never let the Share switch tear down a consume session. The switch is
@@ -204,12 +227,7 @@ export function MeshComputeSettingsCard() {
<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.
</>
}
description="Share this machine with members of this relay so they can run agents here."
/>
{error ? (
@@ -226,8 +244,8 @@ export function MeshComputeSettingsCard() {
<DownloadProgressBar progress={downloadProgress} />
) : null}
<SettingsOptionGroup>
<SettingsOptionRow>
<div className="space-y-5">
<div className="flex min-w-0 items-start justify-between gap-6">
<div className="min-w-0">
<label
className="text-sm font-medium"
@@ -235,29 +253,12 @@ export function MeshComputeSettingsCard() {
>
Share this machine
</label>
<StatusLine
isConsuming={isConsuming}
pendingAction={pendingAction}
status={status}
/>
{servingIndicator.show ? (
<p
className={
servingIndicator.hasRemoteConsumers
? "mt-0.5 text-2xs text-emerald-600 dark:text-emerald-400"
: "mt-0.5 text-2xs text-muted-foreground"
}
data-testid="mesh-serving-usage"
title={servingIndicator.detail ?? undefined}
>
{servingIndicator.label}
{servingIndicator.detail ? (
<span className="text-muted-foreground">
{" "}
· {servingIndicator.detail}
</span>
) : null}
</p>
{!isSharing ? (
<StatusLine
isConsuming={isConsuming}
pendingAction={pendingAction}
status={status}
/>
) : null}
</div>
<Switch
@@ -277,126 +278,125 @@ export function MeshComputeSettingsCard() {
id="mesh-share-compute-toggle"
onCheckedChange={handleToggle}
/>
</SettingsOptionRow>
<div className="px-4 pb-4 pt-5">
<label
className="mb-3 flex items-center gap-2 text-sm font-medium"
htmlFor="mesh-share-compute-model"
>
<Cpu className="h-4 w-4 text-muted-foreground" />
Model
</label>
<div className="flex flex-col gap-2">
<Input
data-testid="mesh-share-compute-model"
disabled={controlsDisabled}
id="mesh-share-compute-model"
onChange={(e) => {
const next = e.target.value;
setModelInput(next);
writeDraft(MODEL_DRAFT_STORAGE_KEY, next);
}}
placeholder="Qwen3-8B-Q4_K_M or hf://meshllm/qwen3-8b@main"
value={modelInput}
/>
<p className="text-sm font-normal text-muted-foreground">
Choose a suggested model below, or enter a model reference or
local file. Buzz downloads remote models when sharing starts.
</p>
{catalog && catalog.entries.length > 0 ? (
<CatalogPicker
catalog={catalog}
disabled={controlsDisabled}
onPick={(name) => {
setModelInput(name);
writeDraft(MODEL_DRAFT_STORAGE_KEY, name);
}}
selected={modelInput.trim()}
/>
) : null}
{installedModels.length > 0 ? (
<div className="mt-1">
<p className="text-sm font-normal text-muted-foreground">
Already installed on this machine:
</p>
<ul
className="mt-1 flex flex-wrap gap-1.5"
data-testid="mesh-share-compute-installed-list"
>
{installedModels.map((m) => (
<li key={m.id}>
<button
className="rounded border border-border/60 bg-muted/20 px-2 py-0.5 text-sm hover:bg-muted/40 disabled:cursor-not-allowed disabled:opacity-50"
disabled={controlsDisabled}
onClick={() => {
setModelInput(m.id);
writeDraft(MODEL_DRAFT_STORAGE_KEY, m.id);
}}
type="button"
>
{m.name ?? m.id}
</button>
</li>
))}
</ul>
</div>
) : null}
</div>
</div>
<details
className="px-4 py-3"
onToggle={(e) =>
setAdvancedOpen((e.target as HTMLDetailsElement).open)
}
open={advancedOpen}
>
<summary className="flex cursor-pointer items-center gap-1.5 text-sm font-medium text-foreground">
<MeshModelPicker
catalog={catalog}
disabled={controlsDisabled}
installedModels={installedModels}
isCustomModelEditing={isCustomModelEditing}
model={modelInput}
onCustomModelEditingChange={setIsCustomModelEditing}
onModelChange={(next) => {
setModelInput(next);
writeDraft(MODEL_DRAFT_STORAGE_KEY, next);
}}
/>
<div className="pt-3">
<button
aria-expanded={advancedOpen}
className="inline-flex h-9 items-center gap-1.5 text-sm font-medium text-foreground transition-colors hover:text-foreground/80 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
data-testid="mesh-share-compute-advanced-toggle"
onClick={() => setAdvancedOpen((current) => !current)}
type="button"
>
<span>Advanced</span>
<ChevronDown
className={cn(
"h-4 w-4 text-muted-foreground transition-transform",
advancedOpen ? "rotate-0" : "-rotate-90",
"h-4 w-4 text-muted-foreground transition-transform duration-150 ease-out",
advancedOpen && "rotate-180",
)}
/>
Advanced
</summary>
<div className="mt-3 flex flex-col gap-2">
<label className="text-sm font-medium" htmlFor="mesh-vram">
Max VRAM (GB)
</label>
<Input
data-testid="mesh-share-compute-vram"
id="mesh-vram"
inputMode="decimal"
onChange={(e) => {
const next = e.target.value;
setMaxVramGb(next);
writeDraft(MAX_VRAM_DRAFT_STORAGE_KEY, next);
}}
placeholder="No limit"
value={maxVramGb}
/>
{status?.consoleUrl ? (
<p className="text-sm font-normal text-muted-foreground">
Debug console:{" "}
<a
className="underline"
href={status.consoleUrl}
rel="noreferrer"
target="_blank"
>
{status.consoleUrl}
</a>
</p>
) : null}
</div>
</details>
</SettingsOptionGroup>
</button>
{advancedOpen ? (
<div className="mt-3 space-y-1.5">
<label className="text-sm font-medium" htmlFor="mesh-vram">
Max VRAM (GB)
</label>
<AgentConfigTextInput
data-testid="mesh-share-compute-vram"
disabled={controlsDisabled}
id="mesh-vram"
inputMode="decimal"
onChange={(e) => {
const next = e.target.value;
setMaxVramGb(next);
writeDraft(MAX_VRAM_DRAFT_STORAGE_KEY, next);
}}
placeholder="No limit"
usePersonaInputStyle
value={maxVramGb}
/>
{status?.consoleUrl ? (
<p className="text-sm font-normal text-muted-foreground">
Debug console:{" "}
<a
className="underline"
href={status.consoleUrl}
rel="noreferrer"
target="_blank"
>
{status.consoleUrl}
</a>
</p>
) : null}
</div>
) : null}
</div>
<p className="mt-3 rounded-lg bg-muted/30 px-3 py-2 text-sm font-normal text-muted-foreground">
Only members of this relay can use this machine's shared compute.
</p>
<AnimatePresence initial={false}>
{showSharingControls ? (
<motion.div
animate={{ height: "auto", opacity: 1 }}
className="overflow-hidden"
data-testid="mesh-share-compute-options-motion"
exit={{ height: 0, opacity: 0 }}
initial={{ height: 0, opacity: 0 }}
key="mesh-share-compute-options"
transition={
shouldReduceMotion
? { duration: 0 }
: SHARE_COMPUTE_REVEAL_TRANSITION
}
>
<section
className="space-y-1"
data-testid="mesh-share-compute-sharing-status"
>
<h3 className="text-sm font-medium">Sharing</h3>
<div className="space-y-1 rounded-lg bg-muted/30 px-3 py-2">
<StatusLine
isConsuming={isConsuming}
omitSharingVerb
pendingAction={pendingAction}
status={status}
/>
{servingIndicator.show ? (
<p
className={
servingIndicator.hasRemoteConsumers
? "text-2xs text-emerald-600 dark:text-emerald-400"
: "text-2xs text-muted-foreground"
}
data-testid="mesh-serving-usage"
title={servingIndicator.detail ?? undefined}
>
{servingIndicator.label}
{servingIndicator.detail ? (
<span className="text-muted-foreground">
{" "}
· {servingIndicator.detail}
</span>
) : null}
</p>
) : null}
</div>
</section>
</motion.div>
) : null}
</AnimatePresence>
</div>
</section>
);
}
@@ -465,100 +465,159 @@ const FIT_CLASS: Record<MeshCatalogEntry["fit"], string> = {
};
/**
* Hardware-ranked curated model list (mesh-console's diagnose pattern).
* Click a row to fill the model field. Models too large for this machine are
* listed but disabled — honest about why, instead of hiding them.
* Share Compute's models use the agent configuration picker instead of a
* second, hand-rolled option system. The catalog remains hardware-aware, but
* its recommendations, installed models, and advanced choices now appear in
* the same searchable dropdown used when customizing an agent.
*/
function CatalogPicker({
function MeshModelPicker({
catalog,
disabled,
onPick,
selected,
installedModels,
isCustomModelEditing,
model,
onCustomModelEditingChange,
onModelChange,
}: {
catalog: MeshModelCatalog;
catalog: MeshModelCatalog | null;
disabled: boolean;
onPick: (name: string) => void;
selected: string;
installedModels: readonly MeshModelOption[];
isCustomModelEditing: boolean;
model: string;
onCustomModelEditingChange: (editing: boolean) => void;
onModelChange: (model: string) => void;
}) {
const [expanded, setExpanded] = React.useState(false);
// Above the fold: the Buzz-curated picks (models known to work well with
// agents on shared compute). Below: everything else, as advanced options.
const curated = catalog.entries.filter((e) => e.curated);
const advanced = catalog.entries.filter((e) => !e.curated);
const visible = expanded ? catalog.entries : curated;
const options = React.useMemo<AgentDropdownOption[]>(() => {
const seen = new Set<string>();
const catalogOptions = (catalog?.entries ?? []).map((entry) => {
seen.add(entry.name);
return {
disabled: entry.fit === "too_large",
label: <MeshModelOptionLabel entry={entry} />,
value: entry.name,
};
});
const localOptions = installedModels.flatMap((installed) => {
if (seen.has(installed.id)) return [];
return [
{
label: (
<div className="flex min-w-0 items-center justify-between gap-3">
<span className="min-w-0 truncate">
{installed.name ?? installed.id}
</span>
<span className="shrink-0 text-2xs text-muted-foreground">
Installed
</span>
</div>
),
value: installed.id,
},
];
});
return [
...catalogOptions,
...localOptions,
{ label: "Custom model…", value: CUSTOM_MODEL_DROPDOWN_VALUE },
];
}, [catalog?.entries, installedModels]);
const knownModel = options.some((option) => option.value === model.trim());
const showCustomModelInput =
isCustomModelEditing || (model.trim().length > 0 && !knownModel);
const selectedValue = showCustomModelInput
? CUSTOM_MODEL_DROPDOWN_VALUE
: model.trim();
function handleModelChange(next: string) {
if (next === CUSTOM_MODEL_DROPDOWN_VALUE) {
onCustomModelEditingChange(true);
return;
}
onCustomModelEditingChange(false);
onModelChange(next);
}
return (
<div className="mt-1" data-testid="mesh-share-compute-catalog">
<div className="space-y-1.5" data-testid="mesh-share-compute-catalog">
<label className="text-sm font-medium" htmlFor="mesh-share-compute-model">
Model
</label>
<AgentDropdownSelect
className={MESH_SELECT_TRIGGER_CLASS}
disabled={disabled}
id="mesh-share-compute-model"
onValueChange={handleModelChange}
options={options}
placeholder="Select a model"
placeholderClassName="text-muted-foreground/55"
searchable
testId="mesh-share-compute-model"
value={selectedValue}
/>
{showCustomModelInput ? (
<AgentConfigTextInput
aria-label="Custom model reference"
autoCorrect="off"
disabled={disabled}
onChange={(event) => {
// A stored custom ref starts out inferred rather than explicitly
// selected. Mark it as an active custom edit before applying a
// cleared value so the field stays mounted while it is replaced.
onCustomModelEditingChange(true);
onModelChange(event.target.value);
}}
placeholder="Qwen3-8B-Q4_K_M or hf://meshllm/qwen3-8b@main"
usePersonaInputStyle
value={model}
/>
) : null}
<p className="text-sm font-normal text-muted-foreground">
Recommended for this machine
{catalog.gpuName ? ` (${catalog.gpuName}, ` : " ("}
{catalog.vramDisplay} AI memory):
{catalog
? `Recommended for this machine${catalog.gpuName ? ` (${catalog.gpuName}, ${catalog.vramDisplay} AI memory)` : ""}.`
: "Choose a model or enter a model reference or local file."}{" "}
Buzz downloads remote models when sharing starts.
</p>
<ul className="mt-1.5 flex max-h-56 flex-col gap-1 overflow-y-auto">
{visible.map((entry) => {
const isSelected = entry.name === selected;
const tooLarge = entry.fit === "too_large";
return (
<li key={entry.name}>
<button
className={cn(
"flex w-full items-baseline gap-2 rounded border px-2 py-1 text-left text-sm",
isSelected
? "border-primary/60 bg-primary/10"
: "border-border/60 bg-muted/20 hover:bg-muted/40",
"disabled:cursor-not-allowed disabled:opacity-50",
)}
data-testid={`mesh-catalog-${entry.name}`}
disabled={disabled || tooLarge}
onClick={() => onPick(entry.name)}
title={entry.description}
type="button"
>
<span className="min-w-0 truncate font-medium">
{entry.name}
</span>
<span className="shrink-0 text-muted-foreground">
{entry.size}
</span>
<span className={cn("shrink-0", FIT_CLASS[entry.fit])}>
{FIT_LABEL[entry.fit]}
</span>
{entry.recommended ? (
<span className="shrink-0 rounded bg-primary/15 px-1.5 text-2xs font-medium text-primary">
Recommended
</span>
) : null}
{entry.installed ? (
<span className="shrink-0 text-2xs text-muted-foreground">
Installed
</span>
) : null}
</button>
</li>
);
})}
</ul>
{advanced.length > 0 ? (
<button
className="mt-1 text-sm text-muted-foreground underline hover:text-foreground"
data-testid="mesh-catalog-advanced-toggle"
onClick={() => setExpanded((v) => !v)}
type="button"
>
{expanded
? "Hide advanced models"
: `Advanced: ${advanced.length} more models`}
</button>
</div>
);
}
function MeshModelOptionLabel({ entry }: { entry: MeshCatalogEntry }) {
return (
<div className="flex min-w-0 items-center gap-2">
<span className="min-w-0 flex-1 truncate font-medium">{entry.name}</span>
<span className="shrink-0 text-muted-foreground">{entry.size}</span>
<span className={cn("shrink-0", FIT_CLASS[entry.fit])}>
{FIT_LABEL[entry.fit]}
</span>
{entry.recommended ? (
<span className="shrink-0 rounded bg-primary/15 px-1.5 text-2xs font-medium text-primary">
Recommended
</span>
) : null}
{entry.installed ? (
<span className="shrink-0 text-2xs text-muted-foreground">
Installed
</span>
) : null}
{!entry.curated ? (
<span className="shrink-0 text-2xs text-muted-foreground">
Advanced
</span>
) : null}
</div>
);
}
function StatusLine({
displayModel,
isConsuming,
omitSharingVerb = false,
pendingAction,
status,
}: {
displayModel?: string;
isConsuming: boolean;
omitSharingVerb?: boolean;
pendingAction: "start" | "stop" | null;
status: MeshNodeStatus | null;
}) {
@@ -583,12 +642,10 @@ function StatusLine({
return <p className="text-sm text-muted-foreground">Checking status…</p>;
}
const { state, health, modelId, modelName } = status;
const modelLabel = modelName ?? modelId ?? "";
const modelLabel = displayModel ?? modelName ?? modelId ?? "";
if (state === "off") {
return (
<p className="text-sm text-muted-foreground">Not sharing right now.</p>
);
return null;
}
if (state === "starting") {
const reason =
@@ -614,7 +671,9 @@ function StatusLine({
}
return (
<p className="text-sm text-muted-foreground">
Sharing{modelLabel ? ` ${modelLabel}` : ""} with relay members.
{omitSharingVerb ? "" : "Sharing"}
{modelLabel ? `${omitSharingVerb ? "" : " "}${modelLabel}` : ""} with
relay members.
</p>
);
}

View File

@@ -2950,6 +2950,7 @@ const ZERO_SERVING_USAGE: MockServingUsage = {
const mockMeshState: {
admitted: boolean;
models: Array<{ id: string; name: string | null }>;
activeModel: { id: string; name: string | null } | null;
denyReason: string;
nodeState: "off" | "running";
nodeMode: "serve" | "client" | null;
@@ -2957,6 +2958,7 @@ const mockMeshState: {
} = {
admitted: true,
models: [{ id: "Gemma-4-E4B-it-Q4_K_M", name: "Gemma 4 E4B" }],
activeModel: null,
denyReason: "not a relay member",
nodeState: "off",
nodeMode: null,
@@ -2966,6 +2968,7 @@ const mockMeshState: {
function resetMockMesh() {
mockMeshState.admitted = true;
mockMeshState.models = [{ id: "Gemma-4-E4B-it-Q4_K_M", name: "Gemma 4 E4B" }];
mockMeshState.activeModel = null;
mockMeshState.denyReason = "not a relay member";
mockMeshState.nodeState = "off";
mockMeshState.nodeMode = null;
@@ -9908,22 +9911,32 @@ export function maybeInstallE2eTauriMocks() {
window.__BUZZ_E2E_SEED_OBSERVER_EVENTS__ = ({ agentPubkey, events }) => {
injectObserverEventsForE2E(agentPubkey, events);
};
const meshModelName = (modelId: string) => {
const basename = modelId.split("/").at(-1) ?? modelId;
return basename
.replace(/-(?:Instruct|GGUF)(?:-|:|$).*/, "")
.replace(/:.*/, "")
.replaceAll("-", " ");
};
const meshNodeStatus = (
state: "off" | "running",
mode: "serve" | "client" | null,
) => ({
state,
mode,
health: { status: "ok" as const, reason: null },
apiBaseUrl: state === "running" ? "http://127.0.0.1:9337/v1" : null,
consoleUrl: null,
modelId: mockMeshState.models[0]?.id ?? null,
modelName: mockMeshState.models[0]?.name ?? null,
inviteToken: state === "running" ? "mock-endpoint-addr" : null,
endpointId: state === "running" ? "mock-endpoint-id" : null,
deviceId: state === "running" ? "mock-endpoint-id" : null,
deviceName: state === "running" ? "Mock desktop" : null,
});
) => {
const model = mockMeshState.activeModel ?? mockMeshState.models[0] ?? null;
return {
state,
mode,
health: { status: "ok" as const, reason: null },
apiBaseUrl: state === "running" ? "http://127.0.0.1:9337/v1" : null,
consoleUrl: null,
modelId: model?.id ?? null,
modelName: model?.name ?? null,
inviteToken: state === "running" ? "mock-endpoint-addr" : null,
endpointId: state === "running" ? "mock-endpoint-id" : null,
deviceId: state === "running" ? "mock-endpoint-id" : null,
deviceName: state === "running" ? "Mock desktop" : null,
};
};
let mockImportedVoices: Array<{
key: string;
displayName: string;
@@ -10300,10 +10313,15 @@ export function maybeInstallE2eTauriMocks() {
return mockMeshState.servingUsage;
case "mesh_start_node": {
const req = (
payload as { request?: { mode?: "serve" | "client" } } | null
payload as {
request?: { mode?: "serve" | "client"; modelId?: string };
} | null
)?.request;
mockMeshState.nodeState = "running";
mockMeshState.nodeMode = req?.mode ?? "serve";
mockMeshState.activeModel = req?.modelId
? { id: req.modelId, name: meshModelName(req.modelId) }
: (mockMeshState.models[0] ?? null);
return meshNodeStatus(mockMeshState.nodeState, mockMeshState.nodeMode);
}
case "mesh_stop_node":
@@ -10317,6 +10335,7 @@ export function maybeInstallE2eTauriMocks() {
}
mockMeshState.nodeState = "off";
mockMeshState.nodeMode = null;
mockMeshState.activeModel = null;
return meshNodeStatus("off", null);
case "get_identity": {
const isLost =

View File

@@ -226,6 +226,7 @@ test.describe("global agent config screenshots", () => {
await page
.getByTestId("global-agent-default-harness-option-claude")
.click();
await waitForAnimations(page);
await expect(page.getByTestId("global-agent-model")).toHaveText(
/Default model/,
);

View File

@@ -15,9 +15,8 @@ type E2eWindow = Window & {
}) => void;
};
test("Share compute selects the curated default and starts and stops sharing", async ({
page,
}) => {
test("Share compute chooses a model before sharing", async ({ page }) => {
const modelRef = "hf://demo/SmolLM2-135M-Instruct-GGUF:Q4_K_M";
await installMockBridge(page);
await page.goto("/");
await openSettings(page, "compute");
@@ -26,19 +25,34 @@ test("Share compute selects the curated default and starts and stops sharing", a
const toggle = page.getByTestId("mesh-share-compute-toggle");
const model = page.getByTestId("mesh-share-compute-model");
await expect(card).toContainText("Not sharing right now");
await expect(card).toContainText(
"Choose a suggested model below, or enter a model reference or local file",
);
await expect(model).toHaveValue("Gemma-4-E4B-it-Q4_K_M");
await expect(card).not.toContainText("Not sharing right now");
await expect(
page.getByTestId("mesh-share-compute-options-motion"),
).toHaveCount(0);
await expect(
page.getByTestId("mesh-share-compute-sharing-status"),
).toHaveCount(0);
await expect(model).toBeVisible();
await expect(toggle).toBeEnabled();
await model.click();
await page.getByRole("option", { name: "Custom model…" }).click();
await page.getByLabel("Custom model reference").fill(modelRef);
await toggle.click();
await expect(
page.getByTestId("mesh-share-compute-options-motion"),
).toBeVisible();
await expect(
page.getByTestId("mesh-share-compute-sharing-status"),
).toBeVisible();
await expect(model).toBeVisible();
await expect(card).toContainText(
"Buzz downloads remote models when sharing starts",
);
await toggle.click();
await expect(toggle).toBeChecked();
await expect(card).toContainText("Sharing Gemma 4 E4B with relay members");
await expect(
page.getByTestId("mesh-share-compute-sharing-status"),
).toContainText("SmolLM2 135M with relay members");
await expect
.poll(() =>
page.evaluate(() => (window as E2eWindow).__BUZZ_E2E_COMMANDS__ ?? []),
@@ -53,13 +67,20 @@ test("Share compute selects the curated default and starts and stops sharing", a
.toContainEqual({
command: "mesh_start_node",
payload: {
request: { mode: "serve", modelId: "Gemma-4-E4B-it-Q4_K_M" },
request: { mode: "serve", modelId: modelRef },
},
});
await toggle.click();
await expect(toggle).not.toBeChecked();
await expect(card).toContainText("Not sharing right now");
await expect(card).not.toContainText("Not sharing right now");
await expect(
page.getByTestId("mesh-share-compute-options-motion"),
).toHaveCount(0);
await expect(
page.getByTestId("mesh-share-compute-sharing-status"),
).toHaveCount(0);
await expect(model).toBeVisible();
await expect
.poll(() =>
page.evaluate(() => (window as E2eWindow).__BUZZ_E2E_COMMANDS__ ?? []),
@@ -97,16 +118,20 @@ test("a consuming client can switch to sharing its saved local model", async ({
const card = page.getByTestId("settings-mesh-share-compute");
const toggle = page.getByTestId("mesh-share-compute-toggle");
const model = page.getByTestId("mesh-share-compute-model");
await expect(card).toContainText(
"This machine is currently using another member's shared compute",
);
await expect(card).toContainText("Buzz may briefly restart");
await expect(toggle).not.toBeChecked();
await expect(model).toBeEnabled();
await expect(model).toHaveValue(localModel);
await expect(
page.getByTestId("mesh-share-compute-options-motion"),
).toHaveCount(0);
await expect(toggle).toBeEnabled();
const customModel = page.getByLabel("Custom model reference");
await expect(customModel).toHaveValue(localModel);
await customModel.fill("");
await expect(customModel).toBeVisible();
await customModel.fill("hf://demo/replacement-model:Q4_K_M");
await toggle.click();
await expect(toggle).toBeChecked();
@@ -117,6 +142,8 @@ test("a consuming client can switch to sharing its saved local model", async ({
expect(commands.names).not.toContain("mesh_stop_node");
expect(commands.payloads).toContainEqual({
command: "mesh_start_node",
payload: { request: { mode: "serve", modelId: localModel } },
payload: {
request: { mode: "serve", modelId: "hf://demo/replacement-model:Q4_K_M" },
},
});
});