Skip to content

fix(buzz): deliver local images through native upload - #74999

Open
riyaazd29 wants to merge 1 commit into
NousResearch:mainfrom
riyaazd29:fix/buzz-local-image-delivery
Open

fix(buzz): deliver local images through native upload#74999
riyaazd29 wants to merge 1 commit into
NousResearch:mainfrom
riyaazd29:fix/buzz-local-image-delivery

Conversation

@riyaazd29

Copy link
Copy Markdown

What does this PR do?

Fixes native delivery of local image attachments through the Buzz adapter.

The gateway's real local-image path calls BasePlatformAdapter.send_image_file() (including file:// items passed through send_multiple_images()). Buzz already uploads local files natively in send_image(), but it did not override send_image_file(), so the Base fallback sent a warning message instead of the attachment.

This adds the missing adapter-local bridge. Existing files use Buzz's current messages send --file path directly; missing or non-file paths retain the Base fallback so host filesystem paths are never echoed into chat. The direct path avoids a second file probe that could otherwise race into the text fallback if the file disappeared between checks.

Related Issue

N/A — small adapter-local regression found during live Buzz testing; no existing Buzz image-delivery issue or PR was found.

Related work:

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • plugins/platforms/buzz/adapter.py
    • Add BuzzAdapter.send_image_file().
    • Send existing local files through Buzz's native messages send --file path with the same result parsing, retry, and echo-suppression behavior as send_image().
    • Preserve upstream's current reply_to then metadata["thread_id"] precedence.
    • Preserve the Base no-path-leak fallback for missing/non-file paths.
  • tests/gateway/test_buzz_adapter.py
    • Prove the real Base send_multiple_images() file:// path reaches Buzz's native --file upload with its caption.
    • Prove a missing local path is not exposed in argv or message content.
    • Prove a file-probe race cannot fall through to text and expose the path.
    • Prove metadata-only thread context is forwarded using upstream's current semantics.

How to Test

  1. Run:

    scripts/run_tests.sh tests/gateway/test_buzz_adapter.py tests/gateway/test_buzz_websocket.py tests/gateway/test_send_multiple_images.py tests/gateway/test_send_image_file.py tests/gateway/test_media_metadata_contract.py -q
  2. Confirm all 49 tests pass.

  3. Run:

    ruff check plugins/platforms/buzz/adapter.py tests/gateway/test_buzz_adapter.py
    python -m py_compile plugins/platforms/buzz/adapter.py tests/gateway/test_buzz_adapter.py
    git diff --check origin/main...HEAD
  4. Confirm Ruff, compilation, and diff checks are clean.

Full-suite baseline note:

  • scripts/run_tests.sh tests/ -q is not currently clean on this macOS checkout: 23 unrelated test files failed.
  • Running those exact 23 files from a detached clean origin/main checkout reproduced the same failed-file set.
  • One parallel-run count differed by one; a direct rerun of the differing transcription file produced the same single failure on the patch branch and clean upstream.
  • Neither touched file failed. The focused and surrounding media suite above is clean.

RED evidence before implementation:

  • The Base file:// path test failed because no --file argument was emitted and the Base fallback warning was used.
  • The missing-path safety test failed because the path was echoed in message content instead of using the friendly Base fallback.
  • The sequential file-probe test failed because a second is_file() check could race into the text fallback and expose the path.
  • The metadata-only reply test failed because the new direct upload path initially omitted upstream's existing metadata fallback.

Private dogfood confirmed the equivalent adapter behavior on two Hermes installations. No private logs, hostnames, paths, channel IDs, event IDs, screenshots, or credentials are included here.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched existing open and closed PRs/issues for overlap
  • My PR contains only changes related to this fix
  • I've run the repository test wrapper and all affected tests pass
  • pytest tests/ -q is fully clean — see the baseline note above; the same 23 unrelated files fail on clean upstream
  • I've added behavioral tests for the fix and no-path-leak fallback
  • I've tested on macOS 26.5.1

Documentation & Housekeeping

  • Documentation update — N/A; no user-facing configuration or API change
  • cli-config.yaml.example — N/A; no config keys
  • CONTRIBUTING.md / AGENTS.md — N/A; no architecture or workflow change
  • Cross-platform impact considered; uses existing pathlib.Path and adapter/Base contracts
  • Tool descriptions/schemas — N/A

Screenshots / Logs

N/A. Automated behavioral evidence is included above; private dogfood artifacts are intentionally not published.

Independent review

Final fail-closed review passed with zero security concerns, logic errors, or scope violations. The reviewer also ran 49 targeted tests and six adversarial image-delivery probes.

AI assistance

AI assisted with implementation and test drafting. I reviewed the complete diff, ran the affected test suites and static checks, and verified that no credentials or setup-specific data are included.

@alt-glitch alt-glitch added type/bug Something isn't working comp/plugins Plugin system and bundled plugins tool/vision Vision analysis and image generation P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jul 30, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused Buzz adapter fix. The premise is confirmed: gateway/platforms/base.py:3927-3933 routes file:// images to send_image_file(), while current Buzz has native local upload only in send_image() (plugins/platforms/buzz/adapter.py:643-679) and therefore inherits the Base fallback at gateway/platforms/base.py:4286-4312.

The proposed override follows Buzz's existing messages send --file behavior, preserves thread metadata precedence, retains the no-path-leak fallback, and adds coverage for the real Base file:// route. No substantive problems found. This is an automated hermes-sweeper review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages tool/vision Vision analysis and image generation type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants