Skip to content

feat(mesh): upgrade to v0.74 and make shared agents reply reliably - #3467

Closed
micspiral wants to merge 8 commits into
mainfrom
micspiral/mesh-0-74-gemma
Closed

feat(mesh): upgrade to v0.74 and make shared agents reply reliably#3467
micspiral wants to merge 8 commits into
mainfrom
micspiral/mesh-0-74-gemma

Conversation

@micspiral

@micspiral micspiral commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Upgrade embedded Mesh to v0.74 and use canonical Gemma model IDs.
  • Keep shared compute serving through member joins, roster changes, app recovery, and community switching (no crashy!).
  • Wait for actual model readiness and avoid resuming incomplete downloads after quit.
  • mesh only scoped tweaks: improvements with buzz agent using mesh with thinking modes (corrected so they don't interfere) a reply tool (so it can talk back) and a failsafe to scoop up responses if that fails for small models (and scoped to mesh/shared compute only, no other providers affected).

Live validation

Tested across two Macs: a production Buzz 0.73.1 client joined and messaged an agent while this development build hosted Mesh v0.74. The host stayed in serving mode, Gemma completed both turns, and the agent log confirmed both replies were published back to the channel.

Also tested a build https://github.com/michaelneale/buzz-testing/releases/tag/v0.5.1-test1 across 2 unrelated machines and it sustained a connection, shared compute reliably.

Testing

Focused ACP, desktop Mesh, and harness checks pass locally. Full CI is running on this PR.

@michaelneale
michaelneale force-pushed the micspiral/mesh-0-74-gemma branch from f79a72c to 59eb49c Compare July 29, 2026 13:11
@micspiral micspiral changed the title feat(mesh): upgrade to v0.74 and validate Buzz replies feat(mesh): upgrade to v0.74 and make shared agents reply reliably Jul 29, 2026
@micspiral
micspiral marked this pull request as ready for review July 29, 2026 13:12
@micspiral
micspiral requested a review from a team as a code owner July 29, 2026 13:12
Pin mesh-llm to the v0.74.0 tag instead of a commit rev, and carry the
desktop-side changes that upgrade needs: catalog/coordinator/recovery
updates, the relay-mesh agent preset, and restart behaviour that survives
community boundary changes and roster churn.

Also promote reasoning to text in the OpenAI-compat parser when `content`
is empty and there are no tool calls. Local models served through mesh
sometimes return the entire answer as reasoning; with no tool calls there
is nothing else to surface, so reporting an empty turn loses the reply.

Signed-off-by: Michael Neale <michael.neale@gmail.com>
Publishing a reply required composing a `buzz messages send ...` string
inside a `shell` call. That indirection is reliable for frontier models
and unreliable for the small local models shared compute exists to serve:
against the real ~3.2k-token Buzz system prompt and the real dev-mcp
toolset, Gemma 4 E4B delivered a reply in only 2 of 8 samples, answering
in prose the rest of the time — and sometimes emitting the literal
command text as assistant content. Assistant text is never published, so
those replies were silently dropped while the turn reported success.

Exposing the publish action as its own typed tool removes the
indirection: the model selects a tool by name and fills one string field.
Measured on the same prompt and toolset, delivery went 2/8 -> 8/8 on
gemma-4-E4B and 6/6 on gemma-4-26B-A4B, and the real ACP path (buzz-acp +
buzz-agent + live relay) replied correctly 3 for 3.

The tool duplicates no process machinery — it builds an argv, quotes it,
and delegates to shell::run, inheriting its timeout, output capping,
cancellation and process-group kill. Channel ids are normalized (the
`[Context]` block renders `general (#uuid)`, so models pass `#uuid`) and
validated to bare ids, and content is single-quoted, so model output
cannot reach the shell as metacharacters.

Signed-off-by: Michael Neale <michael.neale@gmail.com>
P5 could never pass: install_fake_shell returned the bin directory, but
resolve_bash requires BUZZ_SHELL to name a file, so it silently fell back
to real bash and the marker was never written. The fake shell also matched
`-lc` while shell_flag() emits `-c` on Unix. Return the executable, accept
both flags, and append rather than overwrite so a probing model does not
erase the recorded send.

P5 stops at the shell boundary, so it cannot show a reply ever lands. Add
P6: the agent runs the genuine `buzz messages send` (dev-mcp's multicall
shim, real buzz-cli) against a running relay, and the harness then queries
the relay itself — the agent's prose is not evidence. Infra-gated on
BUZZ_E2E_RELAY_URL / _PRIVATE_KEY / _CHANNEL; skipped when unset so
P1-P5 still run without Postgres and Redis.

Also drive the agent with the real base_prompt.md instead of a terse
hand-written string. A short prompt is not a proxy for production: tool
adherence in small models depends on it, so testing with 56 characters
where Buzz injects ~3.2k tokens measures the harness, not Buzz.

Signed-off-by: Michael Neale <michael.neale@gmail.com>
The relay-mesh preset defaulted BUZZ_AGENT_THINKING_EFFORT to "none" to
spend the output budget on an answer instead of hidden reasoning. On local
models that also switches tool calling off: llama.cpp's Gemma grammar is
lazy under `tool_choice: auto`, and `reasoning_effort: "none"` keeps the
model on its prose completion path so it never emits the tool-call token.
The agent then answers in plain content, which is never published, and the
turn reports success with nothing in the channel.

Isolated by replaying a captured production request against a local mesh
node and varying one field: with the real prompt and toolset,
gemma-4-E4B emitted a tool call 0/8 times at "none", 3/4 at "minimal",
and 4/4 at "low" (4/4 with the field omitted entirely). Default to "low",
which buys enough deliberation to select a tool without spending the
budget on hidden reasoning. Still a default, so explicit
agent/persona/global values are preserved.

The mesh e2e harness claims to supply exactly what apply_relay_mesh_env()
does, so update it in lockstep — pinning "none" there would test a config
the product no longer ships and hide the regression P5/P6 exist to catch.

Signed-off-by: Michael Neale <michael.neale@gmail.com>
@michaelneale
michaelneale force-pushed the micspiral/mesh-0-74-gemma branch from 0136bef to 0ad81c3 Compare July 29, 2026 20:03
Shared compute pinned BUZZ_AGENT_THINKING_EFFORT. That is not a sampling
hint: mesh translates `reasoning_effort` into the chat template's
`enable_thinking` flag, so any value Buzz sends overrides the default the
model authors shipped — and the right value is model-specific.

Measured against a request captured from the real agent (full ~43k-token
system prompt, real dev-mcp toolset, tool_choice=auto):

  effort   gemma-4-E4B   Qwen3-8B   Qwen3-8B output tokens
  none         0/8          8/8               ~121
  low          4/4          7/8               ~470
  unset        6/6          8/8               ~500

`none` (the previous default, chosen when shared compute was Qwen3-only)
stops gemma tool-calling outright, so its replies were never published.
Enabling thinking instead makes Qwen3 spend ~4x the output budget, which
risks the 4096 cap this preset sets.

Omitting the field leaves `enable_thinking` as None, so mesh passes no
override and each model uses its own template default: 3/3 delivery on
gemma-4-E4B, gemma-4-26B-A4B, gemma-4-31B and Qwen3-8B, and 3/3 replies
through the real buzz-acp + buzz-agent path against a live relay.

Thinking levels are unaffected: an explicit agent/persona/global value is
still preserved and applied.

Signed-off-by: Michael Neale <michael.neale@gmail.com>
buzz-agent's contract is that output is tool calls: streamed assistant text
is observability only and never published. Capable models honour that and
call `send_message`. Small local models served over shared compute do not
always — on multi-step turns they run their tools, then write the answer as
prose and end the turn, so the turn reports success with nothing in the
channel.

Retain the turn's streamed text in AcpClient (bounded at 8 KiB) alongside a
flag for whether a publish tool call was seen, and on EndTurn publish that
text as a threaded channel reply when the agent published nothing itself.
Gated on EndTurn only: MaxTokens / MaxTurnRequests mean the turn was
truncated, so the text is not a deliberate answer. Bare acknowledgements
("OK", "Done") are filtered, and taking the buffer clears it so the same
text can never post twice.

Off by default via --deliver-plain-replies / BUZZ_ACP_DELIVER_PLAIN_REPLIES:
for cloud models, which reliably publish their own replies, posting streamed
text would double-post. The desktop shared-compute preset opts in, so this
stays scoped to the case that needs it.

Verified end to end against a live relay with stub ACP agents that pin each
branch deterministically: a prose-only agent gets its answer delivered, and
an agent that calls send_message while also streaming prose posts exactly
once with the fallback silent.

Signed-off-by: Michael Neale <michael.neale@gmail.com>
cargo fmt --all skips desktop/src-tauri (separate workspace), so this line
only failed under just desktop-tauri-fmt-check in CI's Rust Lint job.

Signed-off-by: Michael Neale <michael.neale@gmail.com>
@micspiral

Copy link
Copy Markdown
Collaborator Author

ok - yes this is working quite well now - even for a small model. The other fixes for sharing seem ok too. This did require a reply tool added, and a mesh scoped change to scoop up missed replies so it returns to buz, but that seems to work well. Shouldn't impact other models outside of mesh.

It also needed some tweaks to ensure thinking modes are used appropriately (very sensitive to those).

The typed `send_message` reply tool was registered unconditionally, so every
ACP agent's toolset grew from seven tools to eight. That changes the prompt
each agent sees, and the delivery benefit was only ever measured on a small
local model served over shared compute (3/8 -> 8/8 on gemma-4-E4B). Cloud
models already publish their own replies by composing a `buzz messages send`
shell command, so they were absorbing a behavioural change for no gain.

Gate the tool on BUZZ_ACP_SEND_MESSAGE_TOOL, off by default. buzz-acp forwards
it to the MCP server as BUZZ_MCP_SEND_MESSAGE_TOOL — via the ServerSpec env,
since spawn_one clears the environment and only passes a whitelist — and
dev-mcp drops the route when unset. Agents without it publish replies through
the shell tool exactly as they did before the tool existed.

This gets its own flag rather than reusing --deliver-plain-replies: one
controls which tools exist, the other whether the harness publishes on the
agent's behalf, and conflating them would make both harder to reason about.
The desktop shared-compute preset sets both.

Verified over a real MCP handshake on two machines: tools/list returns seven
tools with the variable unset and eight with it set, on both the build host
and a second Mac running the bundled app.

Signed-off-by: Michael Neale <michael.neale@gmail.com>
@micspiral

Copy link
Copy Markdown
Collaborator Author
image finally! end to end.

@tlongwell-block

Copy link
Copy Markdown
Collaborator

Split requested by Tyler: the mesh-scoped commits from this PR (mesh v0.74 upgrade + shared-compute hardening + thinking-effort defaults) are now separately mergeable as #3741, with authorship preserved. The agent/ACP reply-behavior work (send_message tool, plain-reply delivery, e2e P5/P6, and the llm.rs reasoning→text parser change from 2cd640b) remains here as part 2 — details in #3741's description.

tlongwell-block added a commit that referenced this pull request Jul 30, 2026
…(split 1/2 of #3467) (#3741)

## Summary

This is **part 1 of 2** split out from #3467 (per Tyler's request),
carrying only the mesh-scoped changes. The agent/ACP response-behavior
changes and the new `send_message` tool stay in #3467 as part 2. All
commits are @michaelneale's work, cherry-picked with authorship
preserved.

- Upgrade embedded Mesh to v0.74.0 (tag-pinned instead of commit rev)
and use canonical Gemma model IDs.
- Keep shared compute serving through member joins, roster changes, app
recovery, and community switching.
- Wait for actual model readiness and avoid resuming incomplete
downloads after quit.
- Leave `BUZZ_AGENT_THINKING_EFFORT` unset by default so each model's
chat template picks its own thinking default (`none` suppressed Gemma
tool-calling entirely; pinning `low` made Qwen3 burn ~4x output budget).
Explicit agent/persona/global values still win.

## Relationship to #3467

Contains the mesh commits from #3467 (`2cd640b23`, `0ad81c341`,
`ad13ed841`) rebased onto current main, with one deliberate exclusion:
the `crates/buzz-agent/src/llm.rs` reasoning→text parser change from
`2cd640b23` is **not** here. That change unconditionally affects every
OpenAI-compat/Responses provider, so it belongs with the reply-behavior
work in part 2, where it can be reviewed as what it is.

Not included (remaining in #3467 / part 2):
- typed `send_message` tool in dev-mcp + `BUZZ_ACP_SEND_MESSAGE_TOOL`
gating
- plain-reply delivery fallback in buzz-acp
(`BUZZ_ACP_DELIVER_PLAIN_REPLIES`)
- the mesh_agent_e2e P5/P6 rewrite (exists to prove the reply path)
- the two `env.insert` preset opt-ins in `relay_mesh.rs` for the flags
above
- the llm.rs parser change

This PR is independently mergeable; part 2's flags are all off by
default so it can land before or after.

## Testing

- `cargo test -p buzz-relay --locked` — 780 passed (one telemetry test
is order-sensitive under parallel default settings; passes in the
pre-push suite and standalone, unrelated to this diff — files untouched
here).
- `just desktop-tauri-test` (default features) — 1877 passed.
- `cargo test --locked --features mesh-llm` in `desktop/src-tauri` —
1961 passed, including the new relay-mesh preset and
coordinator/recovery tests.
- Both `Cargo.lock`s resolve with `--locked` against the v0.74.0 tag.
- Full pre-push hook suite green (rust-tests, desktop-check/test, tauri
checks).

Live validation of the mesh v0.74 upgrade itself is documented on #3467
(two-Mac cross-version test).

---------

Signed-off-by: Michael Neale <michael.neale@gmail.com>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Co-authored-by: Michael Neale <michael.neale@gmail.com>
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
@tlongwell-block

Copy link
Copy Markdown
Collaborator

Closing per Tyler — this PR has been split, and the mesh half now lives in #3741.

What #3741 carries (rebased onto current main, Mic kept as author on all commits): the mesh v0.74 upgrade + shared-compute hardening (2cd640b23 minus the llm.rs parser change) and both thinking-effort commits (0ad81c341, ad13ed841). It has been independently verified and redteamed at head a360bf82a — CI fully green, live serve→join→inference proven on hardware — and is awaiting human approval to merge.

What still needs a new PR (part 2) — the agent/ACP reply-behavior work from this branch:

  • the typed send_message tool in dev-mcp (7b7b56f89) + its BUZZ_ACP_SEND_MESSAGE_TOOL gating (239542e83)
  • the plain-reply delivery fallback in buzz-acp behind BUZZ_ACP_DELIVER_PLAIN_REPLIES (bb4af4189, a11e7b85e)
  • the mesh_agent_e2e P5/P6 rewrite (bf735e235)
  • the crates/buzz-agent/src/llm.rs reasoning→text promotion from 2cd640b23 — deliberately excluded from feat(mesh): upgrade embedded mesh to v0.74 and harden shared compute (split 1/2 of #3467) #3741 because it unconditionally affects every OpenAI-compat/Responses provider, so it deserves review as the behavior change it is
  • the two relay_mesh.rs opt-in env lines for the flags above

None of that work is lost — it's all on micspiral/mesh-0-74-gemma and can be cherry-picked onto main once #3741 lands (the only overlap is relay_mesh.rs and the e2e example, both trivial).

Thanks Mic — the commit hygiene on this branch is what made the split clean.

auto-merge was automatically disabled July 30, 2026 15:38

Pull request was closed

wpfleger96 added a commit that referenced this pull request Jul 30, 2026
…chive

* origin/main: (22 commits)
  feat(catalog): resolve publisher display name in catalog detail pane (#3640)
  feat(mesh): upgrade embedded mesh to v0.74 and harden shared compute (split 1/2 of #3467) (#3741)
  docs(nips): specify kind:30621 multi-repo projects (NIP-MP) (#3163)
  Refine agent sharing dialog (#3699)
  desktop: enable getUserMedia in the Linux WebKitGTK webview (#3607)
  fix: align responsive agent views (#3688)
  Add macOS agent menu-bar menu (#3565)
  Fix pending message feedback (#3543)
  fix(desktop): remove remaining Projects panel fills (#3742)
  feat(mobile): desktop-parity emoji and thread experience (#3485)
  desktop: restore direct community member adds (#3634)
  fix(desktop): explain open agent access (#2561)
  fix(cli): resolve agents from owner records (#3178)
  fix(desktop): remove Projects overview card fills (#3416)
  feat(replica): portable heartbeat-token fence with snapshot-local reader routing (#3268)
  fix(git): channel binding tooling + author remediation for unbound repos (#3626)
  feat: configure S3 URL addressing style (#3400)
  feat: add first-class OpenRouter provider support (#1975)
  feat(agent,acp): wire provider total_tokens through NIP-AM publish chain (#3593)
  chore(release): release Buzz Desktop version 0.5.2 (#3624)
  ...

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 pushed a commit that referenced this pull request Jul 30, 2026
…g-pipeline

* origin/main:
  feat(catalog): resolve publisher display name in catalog detail pane (#3640)
  feat(mesh): upgrade embedded mesh to v0.74 and harden shared compute (split 1/2 of #3467) (#3741)
  docs(nips): specify kind:30621 multi-repo projects (NIP-MP) (#3163)

Signed-off-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
joahg added a commit to joahg/buzz-dev-mode that referenced this pull request Jul 30, 2026
…-style

* origin/main:
  fix(acp): preserve truncated thread context (block#3340)
  feat(catalog): resolve publisher display name in catalog detail pane (block#3640)
  feat(mesh): upgrade embedded mesh to v0.74 and harden shared compute (split 1/2 of block#3467) (block#3741)
  docs(nips): specify kind:30621 multi-repo projects (NIP-MP) (block#3163)
  Refine agent sharing dialog (block#3699)
  desktop: enable getUserMedia in the Linux WebKitGTK webview (block#3607)
  fix: align responsive agent views (block#3688)
  Add macOS agent menu-bar menu (block#3565)
  Fix pending message feedback (block#3543)
  fix(desktop): remove remaining Projects panel fills (block#3742)
  feat(mobile): desktop-parity emoji and thread experience (block#3485)
  desktop: restore direct community member adds (block#3634)
  fix(desktop): explain open agent access (block#2561)
  fix(cli): resolve agents from owner records (block#3178)
  fix(desktop): remove Projects overview card fills (block#3416)
  feat(replica): portable heartbeat-token fence with snapshot-local reader routing (block#3268)

Signed-off-by: Joah Gerstenberg <joah@squareup.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants