Skip to content

fix(discord): retry standalone REST sends on 429 - #88154

Closed
eyeonall wants to merge 1 commit into
NousResearch:mainfrom
eyeonall:fix/discord-rest-retry-backoff
Closed

fix(discord): retry standalone REST sends on 429#88154
eyeonall wants to merge 1 commit into
NousResearch:mainfrom
eyeonall:fix/discord-rest-retry-backoff

Conversation

@eyeonall

@eyeonall eyeonall commented Aug 17, 2026

Copy link
Copy Markdown

What does this PR do?

Adds bounded retry/backoff for Discord standalone REST POSTs so transient 429 rate limits do not immediately abort hermes send / cron delivery.

This is the same failure mode described in #44468: standalone Discord delivery returns an error on the first 429, and the caller's chunk loop stops there, dropping remaining chunks. The retry now lives inside the Discord standalone adapter, preserving the existing send_message_tool.py chunk-loop contract: a transient 429 on chunk N can retry and then the loop continues to chunk N+1.

Duplicate check note: #44488 is the earlier canonical open PR for #44468. This branch is a current-main implementation and broadens the helper across standalone Discord REST POST sites, including text messages, forum thread creation, caption fallback, and per-file media uploads. If #44488 lands first, this PR can be closed or rebased as a follow-up.

Related Issue

Partially addresses #44468

Related / duplicate context: #44488, #44542, #44558

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/discord/adapter.py: add _standalone_post_with_retry() for bounded Discord REST 429 retries.
  • plugins/platforms/discord/adapter.py: honor Discord retry_after from JSON first, then Retry-After / X-RateLimit-Reset-After headers, then exponential fallback.
  • plugins/platforms/discord/adapter.py: cap long retry waits at 10 seconds so the blocking standalone send path fails fast on long/global limits.
  • plugins/platforms/discord/adapter.py: route standalone text sends, forum JSON thread creation, forum multipart thread creation, caption fallback sends, and per-file media uploads through the helper.
  • tests/tools/test_send_message_tool.py: add focused Discord 429 retry coverage, including body/header retry_after parsing, fallback backoff, exhausted attempts, fail-fast cap, non-429 behavior, and multipart form rebuild.

How to Test

  1. uv run pytest tests/tools/test_send_message_tool.py::TestSendDiscord429Retry -q
  2. uv run pytest tests/tools/test_send_message_tool.py -q
  3. uv run python -m py_compile plugins/platforms/discord/adapter.py tests/tools/test_send_message_tool.py
  4. uv run ruff check plugins/platforms/discord/adapter.py tests/tools/test_send_message_tool.py

Validated locally on Windows and in the isolated hermes-staging Linux account. No production Hermes profile or service was modified.

Live Discord smoke validation was also run from hermes-staging against the configured test channel discord:1538734203737477131.

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
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Windows 11 local checkout; Linux staging user on Fedora-family host

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
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • 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

Screenshots / Logs

Local:

tests/tools/test_send_message_tool.py::TestSendDiscord429Retry
7 passed in 10.83s

tests/tools/test_send_message_tool.py
55 passed in 21.01s

Staging:

tests/tools/test_send_message_tool.py::TestSendDiscord429Retry
7 passed in 1.51s

tests/tools/test_send_message_tool.py
55 passed in 4.53s

Live Discord smoke:

HERMES_HOME=/home/hermes-staging/.hermes hermes send --json --to discord:1538734203737477131 "Hermes PR A Discord standalone REST smoke test ..."
{
  "success": true,
  "platform": "discord",
  "chat_id": "1538734203737477131",
  "message_id": "1538772078952583239"
}

HERMES_HOME=/home/hermes-staging/.hermes hermes send --json --to discord:1538734203737477131 --file /tmp/pr-a-discord-smoke.txt
{
  "success": true,
  "platform": "discord",
  "chat_id": "1538734203737477131",
  "message_id": "1538772261346222090"
}

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins platform/discord Discord bot adapter duplicate This issue or pull request already exists labels Aug 17, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #44488, which already implements the same retry_after-aware bounded 429 retry helper for the standalone Discord REST send path.

@eyeonall

Copy link
Copy Markdown
Author

Closing in favor of #44488 as the canonical earlier PR for #44468. This branch also tested the current-main/staging path and media upload retry coverage; happy to revisit that as a follow-up if needed after #44488 lands.

@eyeonall eyeonall closed this Aug 17, 2026
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 duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have platform/discord Discord bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants