feat(discord): opt-in toolsets + ID injection + split + feishu wiring (salvage #15457, #15458) - #15610
Merged
Conversation
teknium1
force-pushed
the
hermes/hermes-b2a07e89
branch
from
April 25, 2026 11:50
d80c5e6 to
7c776ab
Compare
Groundwork for injecting raw platform identifiers into the agent's system prompt. Currently only `thread_id` is exposed as a raw ID — callers in a Discord thread had to guess `channel_id == thread_id` (which happens to work because threads are channels in Discord's REST API) and had no way to reference the parent channel, guild, or the triggering message. Adds three optional fields: - `guild_id` — Discord guild / Slack workspace / Matrix server scope - `parent_chat_id` — parent channel when chat_id refers to a thread - `message_id` — ID of the triggering message (pin/reply/react) Extends `BasePlatformAdapter.build_source()` to accept + forward them and teaches `to_dict`/`from_dict` to serialize them. Behaviourally a no-op: nothing reads the fields yet and they default to None.
…onSource Discord knows all four identifiers for every inbound message — guild, channel (or thread), parent channel when in a thread, and the triggering message. Pass them into ``SessionSource`` via the new ``build_source()`` kwargs so downstream code (context-prompt builder, delivery, logging) can use them without re-resolving from discord.py objects. For auto-threaded messages, remember the original channel as the parent before swapping ``chat_id`` to the freshly created thread. Behavioural: still a no-op — nothing consumes these fields yet.
The Discord platform note in the session context prompt claimed the agent has no server-management APIs — pre-dating the discord tool. With a bot token configured the agent actually has fetch_messages, search_members, create_thread, and optionally the discord_admin tool; telling the model otherwise causes it to refuse or apologise for calls it is fully able to make. Gate the disclaimer on DISCORD_BOT_TOKEN being unset, matching the tool's own ``check_fn``. Without a token the note still appears and remains accurate; with a token the model is no longer gaslit into refusing valid tool calls.
When DISCORD_BOT_TOKEN is set — meaning the discord tool actually loads — emit a dedicated IDs block in the session context prompt so the agent can call ``fetch_messages``, ``pin_message``, etc. with real identifiers instead of probing. Currently only ``thread_id`` was exposed as a raw ID (via the ``description`` string). The agent in a Discord thread had to guess that the thread ID doubles as a channel ID for the REST API (it does), and it had no way to reference the parent channel, the guild, or the triggering message at all. The block adapts to context: - Thread: guild / parent channel / thread / message - Channel: guild / channel / message - (DM has no guild/channel IDs worth listing; only message) Discord isn't in _PII_SAFE_PLATFORMS, so IDs ship unredacted.
Both discord (read/participate) and discord_admin (server admin) are now
configurable via `hermes tools` with default-OFF. Previously the core
discord tool (fetch_messages, search_members, create_thread) auto-loaded
on every Discord install with DISCORD_BOT_TOKEN set — 19 tools the user
never opted into.
Adds a platform-scoping mechanism (_TOOLSET_PLATFORM_RESTRICTIONS) so
the discord toolsets only show up in the Discord platform's checklist,
not on CLI/Telegram/Slack/etc. Applied at four gates:
- _prompt_toolset_checklist: checklist filter
- _get_platform_tools: resolution filter (both branches)
- _save_platform_tools: save-time filter (covers 'Configure all
platforms' and hand-edited config.yaml)
- tools_disable_enable_command: rejects `hermes tools enable discord`
on non-Discord platforms with a clear error
build_session_context_prompt now injects the Discord IDs block only
when both conditions hold: the discord/discord_admin toolset is
enabled AND DISCORD_BOT_TOKEN is set. Toolset alone isn't enough —
the tool's check_fn gates on the token at registry time, so opting
in without a token yields no tools and the IDs block would lie.
Otherwise keep the stale-API disclaimer.
teknium1
force-pushed
the
hermes/hermes-b2a07e89
branch
from
April 25, 2026 11:51
7c776ab to
fb7b2b5
Compare
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Discord server tools are now user-toggleable (default OFF) and scoped to the Discord platform only. Salvage of #15457 + #15458 with a follow-up that stops the discord toolset from auto-bloating every Discord install with 19 tools.
Credits to @alt-glitch — commits preserved via rebase-merge.
Changes
From #15457 (@alt-glitch):
discord/feishu_doc/feishu_drivebeing silently dropped when user saves viahermes tools)discord_serverintodiscord(fetch_messages, search_members, create_thread) anddiscord_admin(list channels/roles, pin, assign roles)feishu_doc/feishu_driveinto thehermes-feishucompositeFrom #15458 (@alt-glitch):
guild_id,parent_chat_id,message_idtoSessionSource; populate from Discord adapterFollow-up (us):
discordadded toCONFIGURABLE_TOOLSETS+_DEFAULT_OFF_TOOLSETSalongsidediscord_admin— both opt-in viahermes tools_TOOLSET_PLATFORM_RESTRICTIONSsidecar map: platform-scoped toolsets only appear in their platform's checklist and are stripped everywhere else_get_platform_toolsresolution (both branches),_save_platform_tools, andtools_disable_enable_commanddiscord/discord_adminenabled ANDDISCORD_BOT_TOKENset (toolset alone isn't enough — tool'scheck_fngates on token at registry time)Validation
Truth table (token × toolset-enabled, E2E against real imports with isolated HERMES_HOME):
Platform scoping (E2E):
discordanddiscord_adminboth OFFdiscordon Telegram: stripped at save timehermes tools enable discord -p telegram: rejected with clear errorTest suite:
tests/hermes_cli/ tests/gateway/test_session.py tests/test_toolsets.py tests/tools/test_discord_tool.py— 2976 passed, 2 pre-existing failures on main unrelated to this PR (custom_provider_model_switch signature change, test_web_server single-field-category check).Closes #15457
Closes #15458