mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(mesh): make recommended agent model actionable
Preserve user token controls through the shared-compute spawn path and preselect the hardware-ranked Gemma recommendation for first-time sharing.\n\nCo-authored-by: Bartok9 <danielrpike9@gmail.com>\nCo-authored-by: Taksh <takshkothari09@gmail.com> Signed-off-by: Michael Neale <michael.neale@gmail.com>
This commit is contained in:
@@ -44,13 +44,42 @@ pub fn apply_relay_mesh_env(
|
||||
);
|
||||
// Keep the requested response inside smaller local-model context windows,
|
||||
// and spend that budget on an answer/tool call instead of hidden reasoning.
|
||||
// Without both settings Qwen3 either fails the router's fit check at the
|
||||
// agent default (32K) or can consume a tight cap before serializing a tool.
|
||||
env.insert(
|
||||
"BUZZ_AGENT_MAX_OUTPUT_TOKENS".to_string(),
|
||||
"4096".to_string(),
|
||||
);
|
||||
env.insert("BUZZ_AGENT_THINKING_EFFORT".to_string(), "none".to_string());
|
||||
// These are defaults, not policy: the effective agent/persona/global env
|
||||
// may deliberately choose a smaller cap or enable thinking. This function
|
||||
// runs after those layers during readiness, so never clobber their values.
|
||||
insert_default_if_unset(env, "BUZZ_AGENT_MAX_OUTPUT_TOKENS", "4096");
|
||||
insert_default_if_unset(env, "BUZZ_AGENT_THINKING_EFFORT", "none");
|
||||
}
|
||||
|
||||
#[cfg(feature = "mesh-llm")]
|
||||
fn insert_default_if_unset(
|
||||
env: &mut std::collections::BTreeMap<String, String>,
|
||||
key: &str,
|
||||
value: &str,
|
||||
) {
|
||||
if env.get(key).is_none_or(|current| current.trim().is_empty()) {
|
||||
env.insert(key.to_string(), value.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the final Mesh-specific process overrides from the already-resolved
|
||||
/// harness environment. Only user-owned generation controls are seeded: the
|
||||
/// derived provider/base URL/model values remain authoritative, and unrelated
|
||||
/// credentials (notably `OPENAI_API_KEY`) must not be copied back after the
|
||||
/// spawn path removes them.
|
||||
#[cfg(feature = "mesh-llm")]
|
||||
pub fn relay_mesh_process_env(
|
||||
effective_env: &std::collections::BTreeMap<String, String>,
|
||||
model: &str,
|
||||
) -> std::collections::BTreeMap<String, String> {
|
||||
let mut env = std::collections::BTreeMap::new();
|
||||
for key in ["BUZZ_AGENT_MAX_OUTPUT_TOKENS", "BUZZ_AGENT_THINKING_EFFORT"] {
|
||||
if let Some(value) = effective_env.get(key) {
|
||||
env.insert(key.to_string(), value.clone());
|
||||
}
|
||||
}
|
||||
apply_relay_mesh_env(&mut env, Some(RELAY_MESH_PROVIDER_ID), Some(model));
|
||||
env
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "mesh-llm"))]
|
||||
@@ -82,4 +111,52 @@ mod tests {
|
||||
Some("1")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn native_provider_preserves_explicit_generation_controls() {
|
||||
let mut env = BTreeMap::from([
|
||||
(
|
||||
"BUZZ_AGENT_MAX_OUTPUT_TOKENS".to_string(),
|
||||
"2048".to_string(),
|
||||
),
|
||||
("BUZZ_AGENT_THINKING_EFFORT".to_string(), "low".to_string()),
|
||||
]);
|
||||
apply_relay_mesh_env(
|
||||
&mut env,
|
||||
Some(RELAY_MESH_PROVIDER_ID),
|
||||
Some(RELAY_MESH_AUTO_MODEL_ID),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
env.get("BUZZ_AGENT_MAX_OUTPUT_TOKENS").map(String::as_str),
|
||||
Some("2048")
|
||||
);
|
||||
assert_eq!(
|
||||
env.get("BUZZ_AGENT_THINKING_EFFORT").map(String::as_str),
|
||||
Some("low")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn process_env_seeds_controls_without_restoring_unrelated_credentials() {
|
||||
let effective_env = BTreeMap::from([
|
||||
(
|
||||
"BUZZ_AGENT_MAX_OUTPUT_TOKENS".to_string(),
|
||||
"1024".to_string(),
|
||||
),
|
||||
("OPENAI_API_KEY".to_string(), "must-not-leak".to_string()),
|
||||
]);
|
||||
|
||||
let env = relay_mesh_process_env(&effective_env, "Gemma-4");
|
||||
|
||||
assert_eq!(
|
||||
env.get("BUZZ_AGENT_MAX_OUTPUT_TOKENS").map(String::as_str),
|
||||
Some("1024")
|
||||
);
|
||||
assert_eq!(
|
||||
env.get("OPENAI_COMPAT_MODEL").map(String::as_str),
|
||||
Some("Gemma-4")
|
||||
);
|
||||
assert!(!env.contains_key("OPENAI_API_KEY"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -869,12 +869,7 @@ pub fn spawn_agent_child(
|
||||
// uses the same trim semantics as the preflight callers.
|
||||
#[cfg(feature = "mesh-llm")]
|
||||
if let Some(ref mesh_model_id) = mesh_model_id {
|
||||
let mut mesh_env = std::collections::BTreeMap::new();
|
||||
super::apply_relay_mesh_env(
|
||||
&mut mesh_env,
|
||||
Some(super::RELAY_MESH_PROVIDER_ID),
|
||||
Some(mesh_model_id.as_str()),
|
||||
);
|
||||
let mesh_env = super::relay_mesh_process_env(&descriptor.env, mesh_model_id);
|
||||
command.env_remove("OPENAI_API_KEY");
|
||||
for (key, value) in mesh_env {
|
||||
command.env(key, value);
|
||||
|
||||
@@ -107,7 +107,9 @@ export function MeshComputeSettingsCard() {
|
||||
|
||||
// One-shot hardware-aware catalog fetch. Purely additive: when it fails
|
||||
// (stub build, survey error) the card falls back to the free-text field.
|
||||
// Keep an empty draft empty so the UI can explicitly ask the member to choose.
|
||||
// When there is no saved choice, make the curated recommendation the actual
|
||||
// default so a new member can turn Share Compute on directly. An explicit
|
||||
// saved draft always wins.
|
||||
React.useEffect(() => {
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
@@ -115,6 +117,11 @@ export function MeshComputeSettingsCard() {
|
||||
const value = await meshModelCatalog();
|
||||
if (cancelled) return;
|
||||
setCatalog(value);
|
||||
setModelInput((current) => {
|
||||
if (current.trim() !== "" || !value.recommended) return current;
|
||||
writeDraft(MODEL_DRAFT_STORAGE_KEY, value.recommended);
|
||||
return value.recommended;
|
||||
});
|
||||
} catch {
|
||||
// Non-fatal — picker just doesn't render.
|
||||
}
|
||||
|
||||
@@ -2887,9 +2887,7 @@ const mockMeshState: {
|
||||
servingUsage: MockServingUsage;
|
||||
} = {
|
||||
admitted: true,
|
||||
models: [
|
||||
{ id: "hf://demo/SmolLM2-135M-Instruct-GGUF:Q4_K_M", name: "SmolLM2 135M" },
|
||||
],
|
||||
models: [{ id: "Gemma-4-E4B-it-Q4_K_M", name: "Gemma 4 E4B" }],
|
||||
denyReason: "not a relay member",
|
||||
nodeState: "off",
|
||||
nodeMode: null,
|
||||
@@ -2898,9 +2896,7 @@ const mockMeshState: {
|
||||
|
||||
function resetMockMesh() {
|
||||
mockMeshState.admitted = true;
|
||||
mockMeshState.models = [
|
||||
{ id: "hf://demo/SmolLM2-135M-Instruct-GGUF:Q4_K_M", name: "SmolLM2 135M" },
|
||||
];
|
||||
mockMeshState.models = [{ id: "Gemma-4-E4B-it-Q4_K_M", name: "Gemma 4 E4B" }];
|
||||
mockMeshState.denyReason = "not a relay member";
|
||||
mockMeshState.nodeState = "off";
|
||||
mockMeshState.nodeMode = null;
|
||||
@@ -9736,6 +9732,25 @@ export function maybeInstallE2eTauriMocks() {
|
||||
}
|
||||
case "mesh_installed_models":
|
||||
return mockMeshState.models;
|
||||
case "mesh_model_catalog":
|
||||
return {
|
||||
gpuName: "Mock Apple GPU",
|
||||
vramDisplay: "32 GB",
|
||||
vramGb: 32,
|
||||
recommended: "Gemma-4-E4B-it-Q4_K_M",
|
||||
entries: [
|
||||
{
|
||||
name: "Gemma-4-E4B-it-Q4_K_M",
|
||||
size: "3.5GB",
|
||||
sizeGb: 3.5,
|
||||
description: "Buzz-curated local agent model",
|
||||
fit: "comfortable",
|
||||
installed: true,
|
||||
recommended: true,
|
||||
curated: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
case "mesh_node_status":
|
||||
return meshNodeStatus(mockMeshState.nodeState, mockMeshState.nodeMode);
|
||||
case "mesh_serving_usage":
|
||||
|
||||
@@ -15,7 +15,7 @@ type E2eWindow = Window & {
|
||||
}) => void;
|
||||
};
|
||||
|
||||
test("Share compute has a clear empty state and starts and stops sharing", async ({
|
||||
test("Share compute selects the curated default and starts and stops sharing", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page);
|
||||
@@ -30,22 +30,32 @@ test("Share compute has a clear empty state and starts and stops sharing", async
|
||||
await expect(card).toContainText(
|
||||
"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(model).toHaveValue("Gemma-4-E4B-it-Q4_K_M");
|
||||
await expect(toggle).toBeEnabled();
|
||||
await expect(card).toContainText(
|
||||
"Buzz downloads remote models when sharing starts",
|
||||
);
|
||||
await expect(toggle).toBeEnabled();
|
||||
|
||||
await toggle.click();
|
||||
await expect(toggle).toBeChecked();
|
||||
await expect(card).toContainText("Sharing SmolLM2 135M with relay members");
|
||||
await expect(card).toContainText("Sharing Gemma 4 E4B with relay members");
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(() => (window as E2eWindow).__BUZZ_E2E_COMMANDS__ ?? []),
|
||||
)
|
||||
.toContain("mesh_start_node");
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.evaluate(
|
||||
() => (window as E2eWindow).__BUZZ_E2E_COMMAND_PAYLOADS__ ?? [],
|
||||
),
|
||||
)
|
||||
.toContainEqual({
|
||||
command: "mesh_start_node",
|
||||
payload: {
|
||||
request: { mode: "serve", modelId: "Gemma-4-E4B-it-Q4_K_M" },
|
||||
},
|
||||
});
|
||||
|
||||
await toggle.click();
|
||||
await expect(toggle).not.toBeChecked();
|
||||
|
||||
Reference in New Issue
Block a user