Skip to content

feat(discord): sync thread titles with session titles - #35420

Closed
poom wants to merge 8 commits into
NousResearch:mainfrom
poom:feat/discord-title-sync
Closed

feat(discord): sync thread titles with session titles#35420
poom wants to merge 8 commits into
NousResearch:mainfrom
poom:feat/discord-title-sync

Conversation

@poom

@poom poom commented May 30, 2026

Copy link
Copy Markdown

What does this PR do?

Adds minimal Discord thread-title synchronization for Hermes sessions.

When Hermes generates a session title for a Discord thread, the gateway now attempts to rename the Discord thread to that generated title, but only when the thread still appears to have its initial/default name, the same session is still bound to that Discord thread, and the generated title is useful. Low-information auto-titles such as Hermes are ignored so they do not replace a better message-derived thread name.

It also syncs Discord thread renames back into the Hermes session title so /title, /history, /resume, and session search stay aligned with the visible Discord thread name.

Manual /title <name> remains explicit user intent and can rename the Discord thread even when the original initial thread name is unavailable. Explicit title renames use Discord's full 100-character thread-name limit.

Auto-thread naming is configurable via discord.auto_thread_name_mode / DISCORD_AUTO_THREAD_NAME_MODE:

  • summary (default): rename auto-created Discord threads to the generated Hermes session title after the first response.
  • message: keep the initial message-derived Discord thread name.

Summary-generated thread titles use discord.auto_thread_summary_max_chars / DISCORD_AUTO_THREAD_SUMMARY_MAX_CHARS (default 70, capped at Discord's 100-character thread-name limit).

Related Issue

Fixes #

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/session.py

    • Stores thread_initial_name on SessionSource so the gateway can tell whether a Discord thread still has its initial/default name.
  • gateway/platforms/base.py

    • Adds optional thread-title-change handler support to platform adapters.
  • plugins/platforms/discord/adapter.py

    • Captures the initial Discord thread name when creating SessionSource.
    • Adds rename_thread(...) support with an optional expected-current-name guard.
    • Fetches the Discord thread fresh before checking expected_current_name, so cached stale thread names cannot bypass the guard.
    • Emits thread rename events back to the gateway so user/manual Discord thread renames update the session title.
    • Bridges discord.auto_thread_name_mode and discord.auto_thread_summary_max_chars from config.yaml to environment variables.
  • agent/title_generator.py and hermes_state.py

    • Adds SessionDB.set_session_title_if_empty(...) and uses it for auto-generated titles.
    • Prevents auto-generated titles from overwriting titles set while generation was in flight.
    • Fires the thread-rename callback only if the conditional title write succeeds.
  • gateway/run.py

    • Schedules Discord thread rename after auto-title generation.
    • Only auto-renames when the Discord thread still matches its initial name.
    • Skips low-information generated auto-titles such as Hermes so they do not overwrite better initial thread names.
    • Verifies the thread is still bound to the same Hermes session before renaming.
    • Verifies the session DB title is still the scheduled title before sending a bot rename.
    • Tracks bot-initiated Discord rename echoes as a small per-thread queue so multiple in-flight bot renames cannot overwrite newer user/workflow titles.
    • Ignores stale bot rename echoes, including after thread rebinds and out-of-order auto-title → /title delivery.
    • Respects auto_thread_name_mode: summary | message and configurable summary title length.
    • Handles explicit /title <name> as user intent and schedules a Discord thread rename without the initial-name guard.
    • Syncs Discord platform thread-title-change events back into the session database.
    • Keeps rename failures non-fatal.
  • Website docs

    • Documents discord.auto_thread_name_mode, DISCORD_AUTO_THREAD_NAME_MODE, discord.auto_thread_summary_max_chars, and DISCORD_AUTO_THREAD_SUMMARY_MAX_CHARS near the existing auto_thread / DISCORD_AUTO_THREAD entries.
    • Updates the Chinese i18n copies with the same config references.
  • Tests

    • Adds/updates coverage for auto-renaming, manual rename wins, low-information title skips, stale session binding skips, stale DB title skips, explicit /title full-length and truncation behavior, fresh Discord fetch for the rename guard, bot rename echo suppression, interleaved bot rename echoes, rebound-session stale echo suppression, config bridging, and thread-title sync-back.

How to Test

  1. Run focused title-sync tests:

    pytest tests/agent/test_title_generator.py tests/gateway/test_discord_thread_rename.py tests/gateway/test_discord_free_response.py::test_discord_summary_rename_skips_when_thread_name_changed tests/gateway/test_discord_free_response.py::test_discord_summary_rename_uses_fresh_thread_name_for_guard -q
  2. Run gateway/agent related tests:

    scripts/run_tests.sh tests/gateway tests/agent/test_title_generator.py
  3. Run the full test suite using the repository’s preferred CONTRIBUTING.md-compatible wrapper:

    scripts/run_tests.sh
  4. Run review/lint sanity checks:

    git diff --check
    git diff origin/main --name-only | sort

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 the full test suite via the repository’s preferred scripts/run_tests.sh wrapper 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: Ubuntu/Linux

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A (Discord plugin config docs are in website docs/reference)
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A; CONTRIBUTING.md is not touched by this PR
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Review Notes

Claude reviewer feedback led to additional hardening for title-sync races:

  • Generated titles now use an atomic set-if-empty DB write.
  • Auto/bot renames are skipped if the Discord thread is no longer bound to the same session.
  • Auto/bot renames are skipped if the DB title changed after scheduling.
  • Discord expected_current_name checks fetch fresh thread state before comparing.
  • Bot-initiated Discord rename echoes are tracked per thread as a bounded queue, so interleaved auto-title and /title echoes cannot cause an older echo to overwrite a newer title.
  • Stale bot rename echoes are ignored, including after thread rebinds and out-of-order delivery.

Additional local reviewer loop:

  • Codex review: NO BLOCKING ISSUES
  • Claude Opus xhigh review after echo-queue fix: NO BLOCKING ISSUES

Screenshots / Logs

Focused post-echo-queue-fix title-sync tests:

pytest tests/agent/test_title_generator.py tests/gateway/test_discord_thread_rename.py tests/gateway/test_discord_free_response.py::test_discord_summary_rename_skips_when_thread_name_changed tests/gateway/test_discord_free_response.py::test_discord_summary_rename_uses_fresh_thread_name_for_guard -q
...........................................                              [100%]
43 passed in 1.42s

Post-echo-queue-fix gateway/agent related tests:

scripts/run_tests.sh tests/gateway tests/agent/test_title_generator.py

=== Summary: 278 files, 6133 tests passed, 0 failed (100% complete) in 35.5s (32 workers) ===

Full suite before final echo-queue follow-up, after all earlier code fixes:

scripts/run_tests.sh

=== Summary: 1279 files, 27607 tests passed, 0 failed (100% complete) in 273.5s (32 workers) ===

Reviewer loop:

Codex: NO BLOCKING ISSUES
Claude Opus xhigh: NO BLOCKING ISSUES

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have platform/discord Discord bot adapter comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins labels May 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #26477 (same feature, same tracking issue #18430). Also competes with #15757 and #33862. Maintainers should pick one PR to move forward with.

@poom
poom force-pushed the feat/discord-title-sync branch 3 times, most recently from f8e72d3 to 5a84e1b Compare May 30, 2026 18:23
@andyylin

andyylin commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Found the attachment/document retitle edge case from live gateway logs and added a regression test commit, but GitHub rejected pushing directly to the contributor branch from my account despite maintainerCanModify=true.

Branch/commit with the test:

Failure mode: Discord creates the thread from the raw starter text, but the agent prompt can be prefixed with attachment metadata like [The user sent a document: ...]. If the manual-rename guard derives its expected current name from that enriched prompt, it falsely decides the user renamed the thread and skips the generated title.

This PR's thread_initial_name approach is the right fix shape; the test locks that behavior down for document prompts.

poom and others added 8 commits July 5, 2026 21:35
What changed:
- Start Discord auto-created threads with the normal message-based title instead of a forced placeholder.
- Rename Discord threads after Hermes generates a session summary title.
- Only auto-rename when the thread name is still the original auto-created name, preserving workflow or user titles like `sample-repo ExampleOrg#1000001`.
- Sync explicit `/title ...` changes from Hermes sessions to Discord thread titles.
- Sync Discord thread rename events back to Hermes session titles for existing sessions.
- Add session lookup by platform thread ID for platform-side title update events.
- Add tests for generated summary title renaming, preserving manual or workflow-renamed threads, explicit `/title` syncing, Discord rename syncing, slash-command auto-thread routing, and initial auto-thread name capture.

Verified:
- `scripts/run_tests.sh` (27,394 tests passed, 0 failed)
- `pytest -q tests/gateway/test_discord_thread_rename.py tests/gateway/test_discord_free_response.py tests/gateway/test_session.py tests/gateway/test_discord_slash_commands.py -q`
- `pytest -q tests/gateway/test_discord_slash_commands.py::test_auto_thread_creates_thread_and_redirects -q`
- `pytest -q tests/gateway/test_discord_free_response.py::test_discord_summary_rename_skips_when_thread_name_changed -q`
- `python -m py_compile ...`
- `python scripts/check-windows-footguns.py --diff origin/main`
- `git diff --check`
- Static added-line security scan found no hardcoded secret, shell injection, eval/exec, pickle, or SQL injection patterns.
- Independent review checked the diff against CONTRIBUTING.md.
@teknium1

teknium1 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Fixed via #60187 (salvage of #56792 by @rungmc357). Your PR was the earliest implementation of this feature - thanks for kicking off the direction. The merged fix follows the Telegram title_callback pattern that landed on main after your branch was cut, and config lives in config.yaml rather than env vars per current policy.

@teknium1 teknium1 closed this Jul 7, 2026
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 platform/discord Discord bot adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants