Skip to content

fix(desktop): downscale large avatars for agent-share PNG body - #6260

Merged
wesbillman merged 3 commits into
mainfrom
wpfleger/agent-snapshot-avatar-downscale
Aug 18, 2026
Merged

fix(desktop): downscale large avatars for agent-share PNG body#6260
wesbillman merged 3 commits into
mainfrom
wpfleger/agent-snapshot-avatar-downscale

Conversation

@wpfleger96

Copy link
Copy Markdown
Member

Sharing an agent encodes a .agent.png snapshot with the avatar as the PNG image body. Non-PNG avatars were transcoded at full resolution and already-PNG avatars were carried through unchanged, so a large source avatar could produce a PNG that exceeds the 10 MiB MAX_SNAPSHOT_PNG_BYTES cap and fail the send. A 2764×4096 webp avatar encoded to ~26 MB — over 2.5× the ceiling — which is why sharing that agent hung for a few seconds (fetching and transcoding the image) and then failed.

The share dialog compounded the problem: on failure it discarded the pipeline's real error (Snapshot exceeds the 10 MiB size limit…) and toasted a generic Couldn't send … Try again., hiding the actual cause.

Changes

  • Downscale the avatar for the snapshot PNG body. The body is only a card thumbnail, so raster avatars are now downscaled to a 512px longest edge (MAX_PNG_BODY_EDGE) before PNG re-encoding, mirroring the frontend SVG rasterizer's 512×512 cap in snapshotAvatarPng.ts. Already-PNG avatars over the dimension cap route through the same downscaling transcode path instead of a straight tEXt-chunk injection. The manifest's avatar_url/avatar_data_url source reference is untouched — only the PNG image body is downscaled.
  • Surface the real error in the share dialog. PersonaShareDialog (used by SnapshotShareDialog/TeamShareDialog) and AgentCardViewerDialog now toast the send controller's actual error message, falling back to the generic string only when it is empty. A getCurrentError() accessor reads the error through a ref because the render-captured state.error is stale in the closure immediately after beginSend resolves.

A unit test pins the invariant: an oversize (2764×4096) avatar produces a snapshot that stays far under the cap with body dimensions clamped to 512px.

Duncan and others added 2 commits August 18, 2026 14:39
Sharing an agent encodes a .agent.png with the avatar as the image body.
Non-PNG avatars were transcoded at full resolution, so a large avatar (e.g.
a 2764×4096 webp) produced a PNG over the 10 MiB MAX_SNAPSHOT_PNG_BYTES cap
and the share failed. Downscale the PNG body to a 512px longest edge — the
body is only a card thumbnail and the manifest keeps the untouched source
avatar reference. Oversize already-PNG avatars now route through the same
downscaling path instead of a verbatim tEXt-chunk injection.

Also surface the pipeline's real error in the share-dialog toast instead of
the generic "Couldn't send. Try again." via a synchronous getCurrentError()
accessor (the render-captured state is stale right after beginSend resolves).

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…ot-avatar-downscale

* origin/main:
  feat(managed-agents): close five Claude Code agent-config gaps (#4557)
  chore(hooks): keep mobile analysis out of pre-commit (#6236)
  fix(shared-ui): delay hover disclosures by default (#5821)
  fix(desktop-chrome): preserve balanced layout when sidebar collapses (#6000)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
@wpfleger96
wpfleger96 requested a review from a team as a code owner August 18, 2026 20:55
The error-surfacing fix toasts the controller's real message instead of
the generic "Couldn't send agent. Try again." fallback, so the two people-
sharing e2e tests that asserted the generic string no longer matched. Assert
the specific eligibility messages, which verifies the new behavior end-to-end.

Also back the oversized-avatar unit test's manifest claim with an assertion:
the manifest keeps the untouched source avatar_url reference while only the
PNG body is downscaled.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mordecai, an automated reviewer, commenting via Wes’s GitHub account.

Reviewed source at ad20a1ea0fc453aa41582d263164ebd39349b58d. No blocking findings.

  • Oversize and non-PNG avatars enter the decode/downscale/re-encode path; already-PNG bodies at or below 512px retain the existing inexpensive chunk-injection path.
  • DynamicImage::resize(512, 512, Lanczos3) preserves aspect ratio while bounding both dimensions. The complete materialized PNG still passes through the existing 10 MiB validation, so large manifest payloads remain fail-closed.
  • The manifest is constructed from the original avatar source independently of PNG-body encoding. The regression now verifies both the 512px body cap and preservation of avatar_url without inlining the oversized source.
  • The synchronous error accessor is coherent: every send-state transition uses commitState, which updates the ref before React state, and both share-dialog call sites read it immediately after beginSend returns false. Team sharing delegates to the same SnapshotShareDialog.
  • Updated E2E expectations assert the specific eligibility failures surfaced by this change.

Source-only review; I did not run tests or harnesses. Current GitHub checks are green.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Princess Donut, an automated reviewer, commenting via Wes's GitHub account.

Reviewed exact head ad20a1ea0fc453aa41582d263164ebd39349b58d with the avatar decode/resize boundary, manifest preservation, and stale React state paths as the primary lens.

CLEAR. I found no material correctness, security, or user-trust defect in the change.

Evidence:

  • Oversize and non-PNG bodies converge on one decode → aspect-preserving 512px resize → PNG encode path; already-small PNGs retain the existing injection path (agent_snapshot.rs:336-349, :464-503).
  • The manifest is built independently from the PNG body and still applies the existing 2 MiB inline/reference policy (agent_snapshot.rs:249-283); the regression test now verifies both the 512px body cap and preserved source URL.
  • Every send-pipeline state transition now updates the ref before React state (useSnapshotSendController.ts:399-406, :424-449), so the post-await beginSend toast reads the failure that actually occurred rather than a stale render or generic fallback.
  • The changed branch has green Desktop Core, desktop smoke/integration, macOS build, Windows Rust, and DCO checks in the current PR status.

One non-blocking observation: image decoding still materializes the source before resizing, so this improves output size rather than peak decode memory. That behavior predates this patch on the transcode path and the source bytes already pass existing media boundaries; it is not a regression here.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Consolidated Royal Court review at exact head ad20a1ea0fc453aa41582d263164ebd39349b58d.

No blocking findings. Oversized PNGs and non-PNG raster avatars converge on an aspect-preserving 512 px resize before PNG encoding, while small PNGs retain the existing direct path. The final 10 MiB snapshot guard remains in the shared materialization path. The manifest is built independently from the original avatar bytes/reference, and the regression now verifies both the body dimension cap and preservation of the source URL.

The ref-backed error accessor is coherent: all controller transitions update the ref synchronously before React state, so callers reading immediately after beginSend receive the current eligibility/encode/upload/send failure. Updated E2E expectations verify the user-visible eligibility messages.

I also checked malformed-image fallback, locked/plain shared encoding, output-size enforcement, and source/body separation. git diff --check is clean, and all applicable GitHub checks are green; path-filtered jobs are skipped as expected. I did not rerun CI-equivalent suites locally.

@wesbillman
wesbillman merged commit e2ade93 into main Aug 18, 2026
44 of 46 checks passed
@wesbillman
wesbillman deleted the wpfleger/agent-snapshot-avatar-downscale branch August 18, 2026 22:18
jedwards27 pushed a commit to jedwards27/buzz that referenced this pull request Aug 18, 2026
* origin/main: (43 commits)
  perf(desktop): parallelize relay agent directory rebuild (block#6258)
  Refine the mobile emoji picker (block#5853)
  fix(desktop): exclude archived agents from nest, order regeneration (block#5905)
  Add font size and conversation density preferences (block#5644)
  fix(desktop): emit camelCase config-write payload fields (block#6062)
  fix(desktop): downscale large avatars for agent-share PNG body (block#6260)
  fix(desktop): preserve early relay auth challenges (block#3320)
  Polish mobile message actions (block#5873)
  Refine mobile pairing confirmation (block#6018)
  chore(scripts): add buzz-adopt-prod-agents.sh (block#6250)
  feat(managed-agents): close five Claude Code agent-config gaps (block#4557)
  chore(hooks): keep mobile analysis out of pre-commit (block#6236)
  fix(shared-ui): delay hover disclosures by default (block#5821)
  fix(desktop-chrome): preserve balanced layout when sidebar collapses (block#6000)
  Polish mobile timeline navigation (block#5874)
  chore(release): release Buzz Desktop version 0.5.17 (block#6234)
  fix(prompt): simplify pickup follow-through (block#6186)
  fix(mcp): scope todo usage (block#6216)
  fix(desktop): bound remote agent mention authorization (block#6224)
  fix: bump h2 for RUSTSEC-2026-0258 (block#6222)
  ...

Signed-off-by: Princess Donut <3cb959c7eb65d61f634e61df318e450f18f82fa0e01849e7010b82666ead0587@buzz.block.builderlab.xyz>

# Conflicts:
#	desktop/src/main.tsx
#	mobile/ios/Podfile.lock
wpfleger96 pushed a commit that referenced this pull request Aug 19, 2026
…-in-thread

* origin/main: (32 commits)
  Revert "fix(acp): gate relay-signed workflow messages on their attributed author" (#6311)
  fix(desktop): morph the drawer panel icon instead of sliding it (#6306)
  feat(desktop): refine repository-aware project workspaces (#6003)
  Fix mobile Activity thread navigation (#5850)
  perf(desktop): parallelize relay agent directory rebuild (#6258)
  Refine the mobile emoji picker (#5853)
  fix(desktop): exclude archived agents from nest, order regeneration (#5905)
  Add font size and conversation density preferences (#5644)
  fix(desktop): emit camelCase config-write payload fields (#6062)
  fix(desktop): downscale large avatars for agent-share PNG body (#6260)
  fix(desktop): preserve early relay auth challenges (#3320)
  Polish mobile message actions (#5873)
  Refine mobile pairing confirmation (#6018)
  chore(scripts): add buzz-adopt-prod-agents.sh (#6250)
  feat(managed-agents): close five Claude Code agent-config gaps (#4557)
  chore(hooks): keep mobile analysis out of pre-commit (#6236)
  fix(shared-ui): delay hover disclosures by default (#5821)
  fix(desktop-chrome): preserve balanced layout when sidebar collapses (#6000)
  Polish mobile timeline navigation (#5874)
  chore(release): release Buzz Desktop version 0.5.17 (#6234)
  ...

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96 pushed a commit that referenced this pull request Aug 19, 2026
…c-agent-commit-identity

* origin/main:
  Revert "fix(acp): gate relay-signed workflow messages on their attributed author" (#6311)
  fix(desktop): morph the drawer panel icon instead of sliding it (#6306)
  feat(desktop): refine repository-aware project workspaces (#6003)
  Fix mobile Activity thread navigation (#5850)
  perf(desktop): parallelize relay agent directory rebuild (#6258)
  Refine the mobile emoji picker (#5853)
  fix(desktop): exclude archived agents from nest, order regeneration (#5905)
  Add font size and conversation density preferences (#5644)
  fix(desktop): emit camelCase config-write payload fields (#6062)
  fix(desktop): downscale large avatars for agent-share PNG body (#6260)
  fix(desktop): preserve early relay auth challenges (#3320)
  Polish mobile message actions (#5873)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96 pushed a commit that referenced this pull request Aug 19, 2026
…ntion-phase1

* origin/main: (71 commits)
  Revert "fix(acp): gate relay-signed workflow messages on their attributed author" (#6311)
  fix(desktop): morph the drawer panel icon instead of sliding it (#6306)
  feat(desktop): refine repository-aware project workspaces (#6003)
  Fix mobile Activity thread navigation (#5850)
  perf(desktop): parallelize relay agent directory rebuild (#6258)
  Refine the mobile emoji picker (#5853)
  fix(desktop): exclude archived agents from nest, order regeneration (#5905)
  Add font size and conversation density preferences (#5644)
  fix(desktop): emit camelCase config-write payload fields (#6062)
  fix(desktop): downscale large avatars for agent-share PNG body (#6260)
  fix(desktop): preserve early relay auth challenges (#3320)
  Polish mobile message actions (#5873)
  Refine mobile pairing confirmation (#6018)
  chore(scripts): add buzz-adopt-prod-agents.sh (#6250)
  feat(managed-agents): close five Claude Code agent-config gaps (#4557)
  chore(hooks): keep mobile analysis out of pre-commit (#6236)
  fix(shared-ui): delay hover disclosures by default (#5821)
  fix(desktop-chrome): preserve balanced layout when sidebar collapses (#6000)
  Polish mobile timeline navigation (#5874)
  chore(release): release Buzz Desktop version 0.5.17 (#6234)
  ...

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
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.

2 participants