Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions gateway/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,12 @@ def load_gateway_config() -> GatewayConfig:
if entry.apply_yaml_config_fn is None:
continue
platform_cfg = yaml_cfg.get(entry.name)
if not isinstance(platform_cfg, dict) and isinstance(yaml_platforms, dict):
candidate_platform = yaml_platforms.get(entry.name)
if isinstance(candidate_platform, dict):
candidate_extra = candidate_platform.get("extra")
if isinstance(candidate_extra, dict):
platform_cfg = candidate_extra
if not isinstance(platform_cfg, dict):
continue
try:
Expand Down
37 changes: 27 additions & 10 deletions plugins/platforms/discord/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6093,16 +6093,17 @@ def _apply_yaml_config(yaml_cfg: dict, discord_cfg: dict) -> dict | None:
``gateway/config.py::load_gateway_config()`` before this migration.

The DiscordAdapter reads its runtime configuration via ``os.getenv()``
throughout the connect / handle code paths (``DISCORD_REQUIRE_MENTION``,
``DISCORD_FREE_RESPONSE_CHANNELS``, ``DISCORD_AUTO_THREAD``,
``DISCORD_REACTIONS``, ``DISCORD_IGNORED_CHANNELS``,
``DISCORD_ALLOWED_CHANNELS``, ``DISCORD_NO_THREAD_CHANNELS``,
``DISCORD_HISTORY_BACKFILL``, ``DISCORD_HISTORY_BACKFILL_LIMIT``,
``DISCORD_ALLOW_MENTION_*``, ``DISCORD_REPLY_TO_MODE``,
``DISCORD_THREAD_REQUIRE_MENTION``). Rather than rewrite ~50 call sites
inside the adapter to read from ``PlatformConfig.extra`` instead, this
hook keeps the existing env-driven model and merely owns the
YAML→env translation here, next to the adapter that consumes it.
throughout the connect / handle code paths (``DISCORD_ALLOWED_USERS``,
``DISCORD_REQUIRE_MENTION``, ``DISCORD_FREE_RESPONSE_CHANNELS``,
``DISCORD_AUTO_THREAD``, ``DISCORD_REACTIONS``,
``DISCORD_IGNORED_CHANNELS``, ``DISCORD_ALLOWED_CHANNELS``,
``DISCORD_NO_THREAD_CHANNELS``, ``DISCORD_HISTORY_BACKFILL``,
``DISCORD_HISTORY_BACKFILL_LIMIT``, ``DISCORD_ALLOW_MENTION_*``,
``DISCORD_REPLY_TO_MODE``, ``DISCORD_THREAD_REQUIRE_MENTION``).
Rather than rewrite ~50 call sites inside the adapter to read from
``PlatformConfig.extra`` instead, this hook keeps the existing
env-driven model and merely owns the YAML→env translation here, next to
the adapter that consumes it.

Env vars take precedence over YAML — every assignment is guarded by
``not os.getenv(...)`` so explicit env vars survive a config.yaml
Expand All @@ -6113,6 +6114,22 @@ def _apply_yaml_config(yaml_cfg: dict, discord_cfg: dict) -> dict | None:
os.environ["DISCORD_REQUIRE_MENTION"] = str(discord_cfg["require_mention"]).lower()
if "thread_require_mention" in discord_cfg and not os.getenv("DISCORD_THREAD_REQUIRE_MENTION"):
os.environ["DISCORD_THREAD_REQUIRE_MENTION"] = str(discord_cfg["thread_require_mention"]).lower()
platforms_cfg = yaml_cfg.get("platforms")
platform_extra_cfg = {}
if isinstance(platforms_cfg, dict):
discord_platform_cfg = platforms_cfg.get("discord")
if isinstance(discord_platform_cfg, dict):
candidate_extra = discord_platform_cfg.get("extra")
if isinstance(candidate_extra, dict):
platform_extra_cfg = candidate_extra
allowed_users_cfg = (
discord_cfg["allow_from"] if "allow_from" in discord_cfg
else platform_extra_cfg.get("allow_from")
)
if allowed_users_cfg is not None and not os.getenv("DISCORD_ALLOWED_USERS"):
if isinstance(allowed_users_cfg, list):
allowed_users_cfg = ",".join(str(v) for v in allowed_users_cfg)
os.environ["DISCORD_ALLOWED_USERS"] = str(allowed_users_cfg)
frc = discord_cfg.get("free_response_channels")
if frc is not None and not os.getenv("DISCORD_FREE_RESPONSE_CHANNELS"):
if isinstance(frc, list):
Expand Down
1 change: 1 addition & 0 deletions scripts/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"openhands@all-hands.dev": "YLChen-007",
"3153586+xzessmedia@users.noreply.github.com": "xzessmedia",
"AdamPlatin123@outlook.com": "AdamPlatin123",
"byquenox@gmail.com": "quen0xi",
"32711803+waefrebeorn@users.noreply.github.com": "waefrebeorn",
"32869278+dusterbloom@users.noreply.github.com": "dusterbloom",
"liuhao1024@users.noreply.github.com": "liuhao1024",
Expand Down
50 changes: 50 additions & 0 deletions tests/gateway/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,56 @@ def test_thread_require_mention_yaml_does_not_overwrite_env(self, tmp_path, monk
# Env value preserved, not clobbered by yaml.
assert os.environ.get("DISCORD_THREAD_REQUIRE_MENTION") == "true"

def test_bridges_discord_allow_from_from_config_yaml(self, tmp_path, monkeypatch):
"""discord.allow_from should populate DISCORD_ALLOWED_USERS for auth."""
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()
config_path = hermes_home / "config.yaml"
config_path.write_text(
"discord:\n"
" allow_from:\n"
" - \"123456789012345678\"\n"
" - \"999888777666555444\"\n",
encoding="utf-8",
)

monkeypatch.setenv("HERMES_HOME", str(hermes_home))
monkeypatch.delenv("DISCORD_ALLOWED_USERS", raising=False)

config = load_gateway_config()

assert config.platforms[Platform.DISCORD].extra["allow_from"] == [
"123456789012345678",
"999888777666555444",
]
assert os.environ.get("DISCORD_ALLOWED_USERS") == (
"123456789012345678,999888777666555444"
)

def test_bridges_discord_platform_extra_allow_from_to_env(self, tmp_path, monkeypatch):
"""platforms.discord.extra.allow_from should reach DISCORD_ALLOWED_USERS too."""
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()
config_path = hermes_home / "config.yaml"
config_path.write_text(
"platforms:\n"
" discord:\n"
" extra:\n"
" allow_from:\n"
" - \"123456789012345678\"\n",
encoding="utf-8",
)

monkeypatch.setenv("HERMES_HOME", str(hermes_home))
monkeypatch.delenv("DISCORD_ALLOWED_USERS", raising=False)

config = load_gateway_config()

assert config.platforms[Platform.DISCORD].extra["allow_from"] == [
"123456789012345678",
]
assert os.environ.get("DISCORD_ALLOWED_USERS") == "123456789012345678"

def test_bridges_quoted_false_platform_enabled_from_config_yaml(self, tmp_path, monkeypatch):
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()
Expand Down
Loading