Skip to content

feat(gateway): publish native remote turn activity - #80217

Open
cmyk wants to merge 2 commits into
NousResearch:mainfrom
Peakhunter:feat/buzz-native-activity
Open

feat(gateway): publish native remote turn activity#80217
cmyk wants to merge 2 commits into
NousResearch:mainfrom
Peakhunter:feat/buzz-native-activity

Conversation

@cmyk

@cmyk cmyk commented Aug 6, 2026

Copy link
Copy Markdown

What does this PR do?

Publishes structured remote turn activity from the Hermes Gateway to Buzz so users can distinguish an actively working agent from a stalled or completed turn.

The Gateway emits a neutral TurnLifecycleEvent contract for turn start, session resolution, progress, tool execution, completion, failure, and interruption. Buzz translates those events into allowlisted, owner-encrypted NIP-44 v2 observer frames without coupling Gateway core logic to Buzz wire semantics.

Terminal outcomes are latched at the agent-execution boundary, before later delivery, TTS, cache-refresh, or queued-follow-up work can rewrite the result. Buzz retains terminal frames until positive relay acknowledgement, performs one bounded delayed same-generation retry after rejection or send failure, and preserves exhausted terminals for replay after the next authenticated WebSocket generation.

The transport remains fail-open for Gateway execution and fail-safe for the Buzz UI: Activity requires WebSocket transport, polling fallback does not publish a false started state, stale-generation frames are not sent, retry cannot hot-loop, and cancellation during reset cannot leave disconnect() hanging while the WebSocket loop reconnects.

Activity payloads are privacy allowlisted. They exclude prompts, tool arguments, tool outputs, credentials, and model response content. Tool identifiers are bounded and opaque, and internal retry metadata is removed before encryption.

Related Issue

Fixes #76678

Related Buzz consumer/relay tracking: block/buzz#4964

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

  • gateway/turn_observer.py
    • Adds the neutral GatewayTurnObserver and closed lifecycle-event contract.
    • Latches terminal outcomes and emits privacy-safe, bounded tool metadata.
  • gateway/run.py
    • Wraps normal, proxy, early-failure, and follow-up execution paths with the observer.
    • Preserves existing tool callbacks while adding structured lifecycle callbacks.
  • gateway/platforms/base.py
    • Adds the platform-neutral lifecycle adapter hook.
  • plugins/platforms/buzz/adapter.py
    • Translates lifecycle events into Buzz Activity frames.
    • Publishes signed, NIP-44-encrypted observer events over the authenticated WebSocket.
    • Correlates relay acknowledgements and retains terminal frames until positive acknowledgement.
    • Adds bounded delayed retry for negative relay acknowledgements and same-socket send failures.
    • Replays retained terminals after reconnect without stale-generation delivery or hot retry loops.
    • Uses cooperative sender shutdown while propagating cancellation so Gateway teardown cannot hang.
  • plugins/platforms/buzz/nostr_auth.py
    • Adds NIP-44 v2 encryption and observer-event construction.
  • tests/gateway/test_turn_observer.py
    • Covers lifecycle ordering, outcome latching, interruption/failure handling, privacy, and tool identifier bounds.
  • tests/gateway/test_buzz_activity_bridge.py
    • Covers Gateway-to-platform lifecycle translation, proxy/early-failure paths, callback preservation, and transport fallback behavior.
  • tests/gateway/test_buzz_websocket.py
    • Covers encrypted Activity publication, official NIP-44 vectors, acknowledgement retention, bounded retries, queue/reset behavior, cancellation propagation, and production-shaped disconnect/reconnect replay.
  • website/docs/integrations/buzz.md
    • Links the native Activity configuration and behavior documentation.
  • website/docs/user-guide/messaging/buzz.md
    • Documents activity_owner_pubkey, WebSocket requirements, encryption, retry/reconnect behavior, and terminal deduplication expectations.

How to Test

  1. Configure Buzz with authenticated WebSocket transport and an activity_owner_pubkey, start the Gateway, and send a turn that invokes a tool. Confirm Buzz receives ordered started, progress/tool, and terminal Activity frames without prompt, argument, output, or credential content.

  2. Reject a terminal event with ['OK', event_id, false, 'rate-limited: slow down'], and separately fail the first terminal WebSocket send while keeping the socket live. Confirm one delayed retry occurs, no hot loop occurs, and the terminal remains retained after retry exhaustion.

  3. Disconnect before terminal acknowledgement and reconnect. Confirm the retained terminal is replayed on the new authenticated generation, while stale-generation frames are never sent. Cancel/disconnect while transport reset is awaiting the sender and confirm teardown completes without reconnecting.

  4. Run the focused repository-prescribed suite:

    HERMES_PYTHON=<pytest-capable-python> scripts/run_tests.sh \
      tests/gateway/test_turn_observer.py \
      tests/gateway/test_buzz_activity_bridge.py \
      tests/gateway/test_buzz_websocket.py -q
    

    Expected result: 59 passed, 0 failed.

  5. Run the full Gateway suite:

    HERMES_PYTHON=<pytest-capable-python> scripts/run_tests.sh tests/gateway/ -q
    

    Observed result: 4,879 passed, 2 failed. Both failures are pre-existing optional WeCom XML tests where ET is None; the same 4 passed / 2 failed file result was reproduced against a clean baseline checkout.

  6. Run static checks:

    python -m ruff check plugins/platforms/buzz/adapter.py tests/gateway/test_buzz_websocket.py
    python -m compileall -q plugins/platforms/buzz/adapter.py tests/gateway/test_buzz_websocket.py
    git diff --check
    

    All passed.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
    • The repository requires scripts/run_tests.sh instead of direct pytest. The focused suite passes 59/59; the full Gateway suite passes 4,879 tests with two baseline-confirmed optional WeCom XML failures.
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Linux 7.0.0-28-generic x86_64

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
    • N/A: this is a Buzz plugin extra setting documented in both Buzz documentation surfaces, not a new top-level CLI configuration key.
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
    • N/A: no contributor workflow or repository policy changed.
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A
    • N/A: no model tool or tool schema changed.

Screenshots / Logs

No Dashboard or ordinary message UI is changed by this contribution. The production-shaped WebSocket test exercises authentication, generation assignment, subscription, Activity replay, disconnect/reset, reconnect, replay on the new socket, and cancellation teardown through the real _websocket_loop() ordering.

Verification summary:

Focused lifecycle/bridge/transport: 59 passed, 0 failed
Complete Buzz WebSocket coverage: 28 passed, 0 failed
Full Gateway suite: 4,879 passed, 2 baseline-confirmed optional WeCom failures
Ruff: passed
compileall: passed
git diff --check: passed

The terminal retry, reconnect, and cancellation remediation received an independent APPROVE review after targeted dynamic verification of the production code paths.

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Aug 6, 2026
@LuisFreeWill

Copy link
Copy Markdown

Operator +1 from a Windows Path 3 install (hermes gateway run, not ACP).

This is the missing piece for Activity/working status without dumping tools into the channel. I can smoke-test once it is reviewable.

@cmyk

cmyk commented Aug 14, 2026

Copy link
Copy Markdown
Author

Operator +1 from a Windows Path 3 install (hermes gateway run, not ACP).

This is the missing piece for Activity/working status without dumping tools into the channel. I can smoke-test once it is reviewable.

Don't hold your breath. Not going to chase this upstream.
They have 5k+ PRs. This is like a needle in the haystack. Lol.

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

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(buzz): Gateway path — NIP-AO Activity (kind 24200) + composer working/typing parity with ACP

4 participants