文件最后提交记录最后更新时间
matrix: e2e test for cross-signing auto-bootstrap Self-contained docker-compose harness that exercises the new bootstrap branch against a real Continuwuity homeserver. Three tests: 1. fresh bot → bootstrap fires, /keys/query returns master + ssk with UNPADDED base64 keyids, current device is signed by the new SSK 2. second startup with same crypto store → bootstrap is skipped 3. MATRIX_RECOVERY_KEY set → existing verify_with_recovery_key path takes precedence, no new bootstrap Run via: docker compose -f tests/e2e/matrix_xsign_bootstrap/docker-compose.yml up -d python tests/e2e/matrix_xsign_bootstrap/test_bootstrap.py docker compose -f tests/e2e/matrix_xsign_bootstrap/docker-compose.yml down -v The test mirrors the bootstrap snippet from matrix.py inline so it can run without importing the full hermes gateway and its deps. Skipped automatically when mautrix isn't installed or the homeserver is unreachable. All three pass against ghcr.io/continuwuity/continuwuity:latest (Continuwuity 0.5.7). The unpadded-keyid assertion is the load-bearing one — it's exactly the property the PR's bootstrap path provides that the hand-rolled base64.b64encode().decode() scripts get wrong. 1 个月前
test(e2e): add telegram gateway e2e test infrastructure Fixtures and helpers for driving messages through the full async pipeline: adapter.handle_message → background task → GatewayRunner command dispatch → adapter.send (mocked). Uses the established _make_runner pattern (object.__new__) to skip filesystem side effects while exercising real command dispatch logic. 2 个月前
refactor(gateway): migrate Discord adapter to bundled plugin (full Teams parity) First migration of an existing built-in platform adapter to the plugin system established by IRC / Teams / LINE / Google Chat. Closes #24325; advances the umbrella refactor in #3823. Matches Teams' shape exactly — adapter under plugins/platforms/discord/ with the standard __init__.py / adapter.py / plugin.yaml shell, register(ctx) entry point, **no back-compat shim** at the old import path, and full parity for the four hooks Teams uses plus the apply_yaml_config_fn hook that landed in #25443 (the Discord plugin is the first consumer of that hook): * standalone_sender_fn — out-of-process cron delivery via REST API * setup_fn — interactive hermes setup gateway wizard * apply_yaml_config_fn — translate config.yaml discord: keys into DISCORD_* env vars (replaces the hardcoded block in gateway/config.py) * is_connected — declares connection state from DISCORD_BOT_TOKEN * check_fn — lazy-installs discord.py on demand * plus allowed_users_env, allow_all_env, cron_deliver_env_var, max_message_length, emoji, required_env, install_hint * gateway/platforms/discord.py (5,101 LOC) → plugins/platforms/discord/adapter.py (git rename, R090). * New plugins/platforms/discord/{__init__.py, plugin.yaml} with requires_env / optional_env declarations. * Append register(ctx) block + new hook implementations (_standalone_send, interactive_setup, _apply_yaml_config, _clean_discord_user_ids, _is_connected, _build_adapter, plus helpers _DISCORD_CHANNEL_TYPE_PROBE_CACHE etc.) to the adapter. * Replace the Platform.DISCORD elif branch in GatewayRunner._create_adapter() (−9 LOC) with a generic post-creation hook (+6 LOC) in the registry path: any plugin adapter that declares a gateway_runner attribute now gets it auto-injected. Webhook's built-in branch is unchanged (it doesn't go through the registry path). * Move _send_discord (190 LOC) and helpers (_DISCORD_CHANNEL_TYPE_PROBE_CACHE, _remember_channel_is_forum, _probe_is_forum_cached, _derive_forum_thread_name) from tools/send_message_tool.py into the plugin as _standalone_send. * Wire via standalone_sender_fn=_standalone_send (Teams pattern; same gap fixed in #21804 for other plugin platforms). * Replace the Discord elif in tools/send_message_tool.py _send_to_platform with a 10-line registry-hook dispatch. * Drop the DiscordAdapter import and the Platform.DISCORD: DiscordAdapter.MAX_MESSAGE_LENGTH _MAX_LENGTHS entry — the registry's max_message_length=2000 covers it. * Move _setup_discord and _clean_discord_user_ids (68 LOC) from hermes_cli/setup.py into the plugin as interactive_setup. * Wire via setup_fn=interactive_setup. CLI helpers (prompt, print_info, etc.) are lazy-imported so the plugin's module-load surface stays minimal. * Remove "discord": _s._setup_discord from hermes_cli/gateway.py::_builtin_setup_fn. * Remove the entire 32-line _PLATFORMS["discord"] static dict entry — Discord's setup metadata is now discovered dynamically via _all_platforms() from the registry entry. * Move the 59-line discord_cfg YAML→env bridge from gateway/config.py::load_gateway_config() into the plugin as _apply_yaml_config. Covers require_mention, thread_require_mention, free_response_channels, auto_thread, reactions, ignored_channels, allowed_channels, no_thread_channels, ``allow_mentions.{everyone,roles,users, replied_user}, and reply_to_mode`` (including the YAML 1.1 off-as-False coercion and the extra.reply_to_mode fallback). * Wire via apply_yaml_config_fn=_apply_yaml_config. * The hook runs BEFORE _apply_env_overrides and after the generic shared-key loop, exactly as documented in website/docs/developer-guide/adding-platform-adapters.md. * Behavior is preserved exactly — every assignment still uses not os.getenv(...) guards so env vars take precedence over YAML. All 78 references to the old import path are rewritten — no back-compat shim: * 51 from gateway.platforms.discord import Xfrom plugins.platforms.discord.adapter import X * 5 import gateway.platforms.discord as discord_platformimport plugins.platforms.discord.adapter as discord_platform * 1 from gateway.platforms import discord as discord_modfrom plugins.platforms.discord import adapter as discord_mod * 21 mock.patch("gateway.platforms.discord.X") strings → mock.patch("plugins.platforms.discord.adapter.X") * 1 docstring reference in hermes_cli/commands.py * 1 import in tools/send_message_tool.py (now removed entirely) The import-safety test in tests/gateway/test_discord_imports.py is updated to purge the new canonical module name from sys.modules. **38 files changed, +621 / −473** — net positive due to the YAML hook implementation (89 new LOC in the plugin trading for 59 deleted in core), but every line moved has a clear plugin home now. The git rename is detected at R090 because the adapter gained ~340 LOC of moved-in hook implementations (_standalone_send + interactive_setup + _apply_yaml_config + helpers). * All 568 Discord-specific tests pass across 25 test_discord_*.py files plus voice/send/text-batching/reload-skills/stream-consumer/ integration tests. * All 147 tests in the YAML-touching subset (test_discord_reply_mode, test_discord_free_response, test_discord_allowed_channels, test_discord_allowed_mentions, test_discord_channel_controls, test_discord_reactions, test_discord_thread_persistence, test_runtime_footer) pass — this is the strongest signal that the YAML→env hook behaves identically to the legacy block. * Broader gateway/cron/integration sweep (1297 tests) introduces zero new failures vs main. Pre-existing failures in tests/gateway/test_tts_media_routing.py and tests/e2e/test_platform_commands.py reproduce identically on the unchanged main revision. * Plugin discovery sanity check confirms Discord registers alongside the other four platform plugins: Registered platforms: ['discord', 'google_chat', 'irc', 'line', 'teams'] These Discord-shaped tendrils in core were **deliberately not moved** — they are generic platform-registry concerns affecting every platform, not Discord-specific: * gateway/config.py:1205 DISCORD_BOT_TOKEN → config.token env enablement — same shape Telegram has. The existing env_enablement_fn registry hook only seeds extra, not .token, so it can't replace this without an adapter refactor to read from extra["bot_token"]. * gateway/run.py voice-mode hooks (self.adapters.get(Platform.DISCORD) for start_voice_mode/stop_voice_mode), role-based auth, DISCORD_ALLOW_BOTS branch in _is_user_authorized, _UPDATE_ALLOWED_PLATFORMS frozenset, and the per-platform allowlist maps — generic platform-registry concerns. * Platform.DISCORD enum literal — stable identifier used as dict keys throughout the codebase; removing it is a separate refactor with no real benefit. * tools/discord_tool.py and tools/environments/local.py — first-class agent tools and env-passthrough config, neither is the gateway adapter. Each of these is worth its own scoping issue when the time comes. 13 天前
fix: follow-up for salvaged PRs #6293, #7387, #9091, #13131 - Fix duplicate 'timezone' import in e2e conftest - Fix test_text_before_command_not_detected asserting send() is awaited when no agent is present in mock setup (text messages don't produce command output) 1 个月前
fix(gateway): move quick-command dispatch before built-in handlers Quick commands of type "alias" that target built-in slash commands (e.g. /h -> /model) were processed too late in _handle_message — after the if-canonical=="model" checks. This meant alias expansion never reached the target handler and fell through to the LLM as raw text. Two fixes: 1. Move the quick_commands block before built-in dispatch so alias targets (like /model) hit the correct handler after expansion. 2. Extract bare command name from target_command via .split()[0] to feed _resolve_cmd() correctly (was using the full arg-string). 1 个月前