hermes-agent/tests/gateway
Teknium 2edebedc9e
feat(steer): /steer <prompt> injects a mid-run note after the next tool call (#12116)
* feat(steer): /steer <prompt> injects a mid-run note after the next tool call

Adds a new slash command that sits between /queue (turn boundary) and
interrupt. /steer <text> stashes the message on the running agent and
the agent loop appends it to the LAST tool result's content once the
current tool batch finishes. The model sees it as part of the tool
output on its next iteration.

No interrupt is fired, no new user turn is inserted, and no prompt
cache invalidation happens beyond the normal per-turn tool-result
churn. Message-role alternation is preserved — we only modify an
existing role:"tool" message's content.

Wiring
------
- hermes_cli/commands.py: register /steer + add to ACTIVE_SESSION_BYPASS_COMMANDS.
- run_agent.py: add _pending_steer state, AIAgent.steer(), _drain_pending_steer(),
  _apply_pending_steer_to_tool_results(); drain at end of both parallel and
  sequential tool executors; clear on interrupt; return leftover as
  result['pending_steer'] if the agent exits before another tool batch.
- cli.py: /steer handler — route to agent.steer() when running, fall back to
  the regular queue otherwise; deliver result['pending_steer'] as next turn.
- gateway/run.py: running-agent intercept calls running_agent.steer(); idle-agent
  path strips the prefix and forwards as a regular user message.
- tui_gateway/server.py: new session.steer JSON-RPC method.
- ui-tui: SessionSteerResponse type + local /steer slash command that calls
  session.steer when ui.busy, otherwise enqueues for the next turn.

Fallbacks
---------
- Agent exits mid-steer → surfaces in run_conversation result as pending_steer
  so CLI/gateway deliver it as the next user turn instead of silently dropping it.
- All tools skipped after interrupt → re-stashes pending_steer for the caller.
- No active agent → /steer reduces to sending the text as a normal message.

Tests
-----
- tests/run_agent/test_steer.py — accept/reject, concatenation, drain,
  last-tool-result injection, multimodal list content, thread safety,
  cleared-on-interrupt, registry membership, bypass-set membership.
- tests/gateway/test_steer_command.py — running agent, pending sentinel,
  missing steer() method, rejected payload, empty payload.
- tests/gateway/test_command_bypass_active_session.py — /steer bypasses
  the Level-1 base adapter guard.
- tests/test_tui_gateway_server.py — session.steer RPC paths.

72/72 targeted tests pass under scripts/run_tests.sh.

* feat(steer): register /steer in Discord's native slash tree

Discord's app_commands tree is a curated subset of slash commands (not
derived from COMMAND_REGISTRY like Telegram/Slack). /steer already
works there as plain text (routes through handle_message → base
adapter bypass → runner), but registering it here adds Discord's
native autocomplete + argument hint UI so users can discover and
type it like any other first-class command.
2026-04-18 04:17:18 -07:00
..
__init__.py test: reorganize test structure and add missing unit tests 2026-02-26 03:20:08 +03:00
conftest.py fix(tests): resolve 12 CI failures + 10 errors across 6 root causes (#11040) 2026-04-16 06:49:36 -07:00
restart_test_helpers.py fix: notify active sessions on gateway shutdown + update health check 2026-04-14 14:21:57 -07:00
test_agent_cache.py fix(gateway): bound _agent_cache with LRU cap + idle TTL eviction (#11565) 2026-04-17 06:36:34 -07:00
test_allowlist_startup_check.py feat(gateway): add WeCom (Enterprise WeChat) platform support (#3847) 2026-03-29 21:29:13 -07:00
test_api_server.py fix: preserve session_id across previous_response_id chains in /v1/responses (#10059) 2026-04-14 21:06:32 -07:00
test_api_server_bind_guard.py fix(security): enforce API_SERVER_KEY for non-loopback binding 2026-04-10 16:51:44 -07:00
test_api_server_jobs.py fix(gateway): wrap cron helpers with staticmethod to prevent self-binding 2026-04-05 12:31:10 -07:00
test_api_server_normalize.py fix(api_server): normalize array-based content parts in chat completions 2026-04-12 18:03:16 -07:00
test_api_server_toolset.py refactor: remove browser_close tool — auto-cleanup handles it (#5792) 2026-04-07 03:28:44 -07:00
test_approve_deny_commands.py test(gateway): isolate blocking approval env 2026-04-11 02:03:20 -07:00
test_async_memory_flush.py fix(gateway): persist memory flush state to prevent redundant re-flushes on restart (#4481) 2026-04-01 12:05:02 -07:00
test_auto_continue.py feat: auto-continue interrupted agent work after gateway restart (#4493) 2026-04-14 16:56:49 -07:00
test_background_command.py fix(gateway): close temporary agents after one-off tasks 2026-04-16 06:31:23 -07:00
test_background_process_notifications.py fix(gateway): don't treat group session user_id as thread_id in shutdown notifications (#10546) 2026-04-15 15:09:23 -07:00
test_base_topic_sessions.py fix(gateway): avoid false failure reactions on restart cancellation 2026-04-10 03:52:00 -07:00
test_bluebubbles.py test: remove 169 change-detector tests across 21 files (#11472) 2026-04-17 01:05:09 -07:00
test_busy_session_ack.py fix: interrupt agent immediately when user messages during active run (#10068) 2026-04-14 22:07:28 -07:00
test_channel_directory.py feat(discord): support forum channels 2026-04-17 20:25:48 -07:00
test_clean_shutdown_marker.py fix: prevent unwanted session auto-reset after graceful gateway restarts (#8299) 2026-04-12 03:03:07 -07:00
test_command_bypass_active_session.py feat(steer): /steer <prompt> injects a mid-run note after the next tool call (#12116) 2026-04-18 04:17:18 -07:00
test_compress_command.py fix(gateway): close temporary agents after one-off tasks 2026-04-16 06:31:23 -07:00
test_compress_focus.py feat: /compress <focus> — guided compression with focus topic (#8017) 2026-04-11 19:23:29 -07:00
test_config.py test(dingtalk): cover get_connected_platforms + null platform_toolsets 2026-04-17 06:26:18 -07:00
test_config_cwd_bridge.py fix: enforce config.yaml as sole CWD source + deprecate .env CWD vars + add hermes memory reset (#11029) 2026-04-16 06:48:33 -07:00
test_delivery.py fix: update 6 test files broken by dead code removal 2026-04-10 03:44:43 -07:00
test_dingtalk.py feat(dingtalk): AI Cards streaming, emoji reactions, and media handling 2026-04-17 19:26:53 -07:00
test_discord_allowed_mentions.py fix(discord): default allowed_mentions to block @everyone and role pings 2026-04-17 04:08:42 -07:00
test_discord_attachment_download.py fix(discord): route attachment downloads through authenticated bot session (#11568) 2026-04-17 04:59:03 -07:00
test_discord_bot_auth_bypass.py fix(discord): harden DISCORD_ALLOWED_ROLES and cover gateway layer 2026-04-17 05:48:26 -07:00
test_discord_bot_filter.py feat(discord): add DISCORD_ALLOW_BOTS config for bot message filtering (inspired by openclaw) 2026-03-09 02:20:57 -07:00
test_discord_channel_controls.py test: disable text batching in existing adapter tests 2026-04-09 23:25:27 -07:00
test_discord_channel_prompts.py fix: discord mock setup and AUTHOR_MAP for channel_prompts tests 2026-04-15 16:31:28 -07:00
test_discord_channel_skills.py test(discord): add tests for channel_skill_bindings resolution 2026-04-10 05:19:26 -07:00
test_discord_connect.py fix(discord): default allowed_mentions to block @everyone and role pings 2026-04-17 04:08:42 -07:00
test_discord_document_handling.py fix(discord): accept .log attachments and raise document size limit 2026-04-09 02:26:33 -07:00
test_discord_free_response.py fix(discord): skip auto-threading reply messages 2026-04-17 06:46:52 -07:00
test_discord_imports.py fix: defer discord adapter annotations 2026-03-14 09:32:05 -07:00
test_discord_media_metadata.py feat(discord): add /thread command, auto_thread config, and media metadata fix (#1178) 2026-03-13 08:52:54 -07:00
test_discord_opus.py fix: add macOS Homebrew Opus fallback and fix shutdown dict iteration 2026-03-14 14:27:21 +03:00
test_discord_reactions.py fix(gateway): avoid false failure reactions on restart cancellation 2026-04-10 03:52:00 -07:00
test_discord_reply_mode.py test(discord): update reply_mode fixture for new to_reference() wrapping 2026-04-17 04:17:56 -07:00
test_discord_send.py fix(discord): forum channel media + polish 2026-04-17 20:25:48 -07:00
test_discord_slash_commands.py fix(discord): strip mention syntax from auto-thread names 2026-04-17 06:46:52 -07:00
test_discord_system_messages.py fix(discord): ignore system messages in on_message handler (#2618) 2026-03-23 06:50:09 -07:00
test_discord_thread_persistence.py refactor: extract shared helpers to deduplicate repeated code patterns (#7917) 2026-04-11 13:59:52 -07:00
test_display_config.py fix(gateway): fix regression causing display.streaming to override root streaming key 2026-04-14 10:52:23 -07:00
test_dm_topics.py test+docs: add group_topics tests and documentation 2026-04-03 18:20:50 -07:00
test_document_cache.py feat: add .zip document support and auto-mount cache dirs into remote backends (#4846) 2026-04-03 13:16:26 -07:00
test_duplicate_reply_suppression.py test: add cancellation handler delivery confirmation tests 2026-04-16 05:53:18 -07:00
test_email.py test: remove 169 change-detector tests across 21 files (#11472) 2026-04-17 01:05:09 -07:00
test_extract_local_files.py feat: auto-detect local file paths in gateway responses for native media delivery (#1640) 2026-03-17 01:47:34 -07:00
test_fallback_eviction.py fix: don't evict cached agent on failed runs — prevents MCP restart loop (#7539) 2026-04-10 21:16:56 -07:00
test_fast_command.py fix: add _session_model_overrides to test runner fixture 2026-04-10 05:54:56 -07:00
test_feishu.py fix(feishu-comment): use get_hermes_home(); drop dead asyncio wrapper; AUTHOR_MAP 2026-04-17 19:04:11 -07:00
test_feishu_approval_buttons.py fix(feishu): keep approval clicks synchronized with callback card state 2026-04-14 14:22:11 -07:00
test_feishu_comment.py feat: add Feishu document comment intelligent reply with 3-tier access control 2026-04-17 19:04:11 -07:00
test_feishu_comment_rules.py feat: add Feishu document comment intelligent reply with 3-tier access control 2026-04-17 19:04:11 -07:00
test_feishu_onboard.py fix: salvage follow-ups for Feishu QR onboarding (#7706) 2026-04-12 13:05:56 -07:00
test_flush_memory_stale_guard.py fix(gateway): close temporary agents after one-off tasks 2026-04-16 06:31:23 -07:00
test_gateway_inactivity_timeout.py fix(gateway): add staged inactivity warning before timeout escalation 2026-04-08 20:01:06 -07:00
test_gateway_shutdown.py fix(gateway): address restart review feedback 2026-04-10 21:18:34 -07:00
test_homeassistant.py test: remove 169 change-detector tests across 21 files (#11472) 2026-04-17 01:05:09 -07:00
test_hooks.py fix(tests): resolve 10 CI failures across hooks, tiktoken, plugins (#3848) 2026-03-29 20:05:59 -07:00
test_insights_unicode_flags.py fix(model-switch): normalize Unicode dashes from Telegram/iOS input 2026-04-15 17:54:16 -07:00
test_internal_event_bypass_pairing.py fix(gateway): route synthetic background events by session 2026-04-15 11:16:01 -07:00
test_interrupt_key_match.py test(gateway): cover photo burst interrupt regressions 2026-03-15 03:50:45 -07:00
test_matrix.py test: remove 169 change-detector tests across 21 files (#11472) 2026-04-17 01:05:09 -07:00
test_matrix_mention.py fix(matrix): E2EE and migration bugfixes (#10860) 2026-04-17 04:03:02 +05:30
test_matrix_voice.py fix(ci): resolve 4 pre-existing main failures (docs lint + 3 stale tests) (#11373) 2026-04-16 20:43:41 -07:00
test_mattermost.py test: remove 169 change-detector tests across 21 files (#11472) 2026-04-17 01:05:09 -07:00
test_media_download_retry.py fix: make safe_url_for_log public, add SSRF redirect guards to base.py cache helpers 2026-04-10 05:04:28 -07:00
test_media_extraction.py fix(gateway): prevent TTS voice messages from accumulating across turns 2026-02-28 03:38:27 -05:00
test_message_deduplicator.py fix: enforce TTL in MessageDeduplicator + use yaml for gateway --config (#10306, #10216) (#10509) 2026-04-15 13:35:40 -07:00
test_mirror.py fix(gateway): isolate telegram forum topic sessions 2026-03-11 09:15:34 +01:00
test_model_command_custom_providers.py fix: extract custom_provider_slug() helper, harden gateway test 2026-04-10 03:07:00 -07:00
test_model_switch_persistence.py fix(gateway): apply /model session overrides so switch persists across messages 2026-04-10 02:58:42 -07:00
test_pairing.py test: strengthen assertions across 7 test files (batch 1) 2026-03-05 18:39:37 -08:00
test_pending_event_none.py fix(gateway): guard pending_event.channel_prompt against None in recursive _run_agent 2026-04-16 07:45:27 -07:00
test_pii_redaction.py fix: remove 115 verified dead code symbols across 46 production files 2026-04-10 03:44:43 -07:00
test_plan_command.py fix: save /plan output in workspace (#1381) 2026-03-14 21:28:51 -07:00
test_platform_base.py fix(telegram): use UTF-16 code units for message length splitting (#8725) 2026-04-12 19:06:20 -07:00
test_platform_reconnect.py fix: repair 57 failing CI tests across 14 files (#5823) 2026-04-07 09:58:45 -07:00
test_proxy_mode.py feat: gateway proxy mode — forward messages to remote API server 2026-04-14 10:49:48 -07:00
test_qqbot.py fix(qqbot): add back-compat for env var rename; drop qrcode core dep 2026-04-17 15:31:14 -07:00
test_queue_consumption.py fix(gateway): preserve queued voice events for STT 2026-04-11 14:43:53 -07:00
test_reasoning_command.py fix: unify reasoning_effort to config.yaml only, remove HERMES_REASONING_EFFORT env var 2026-04-08 03:36:44 -07:00
test_restart_drain.py feat: auto-continue interrupted agent work after gateway restart (#4493) 2026-04-14 16:56:49 -07:00
test_restart_notification.py fix(gateway): /restart uses service restart under systemd instead of detached subprocess 2026-04-12 22:32:19 -07:00
test_restart_redelivery_dedup.py fix(gateway): ignore redelivered /restart after PTB offset ACK fails (#11940) 2026-04-17 21:17:33 -07:00
test_resume_command.py fix: honor session-scoped gateway model overrides 2026-04-11 03:11:34 -07:00
test_retry_replacement.py test: lock retry replacement semantics 2026-03-14 21:19:22 -07:00
test_retry_response.py test(gateway): add regression test for /retry response fix 2026-03-10 23:34:52 -07:00
test_run_progress_topics.py fix(gateway): defer background review notifications until after main reply 2026-04-15 17:23:15 -07:00
test_runner_fatal_adapter.py fix(gateway): exit with failure when all platforms fail with retryable errors (#3592) 2026-03-28 14:25:12 -07:00
test_runner_startup_failures.py fix(gateway): detect legacy hermes.service + mark --replace SIGTERM as planned (#11909) 2026-04-17 19:27:58 -07:00
test_send_image_file.py feat(telegram): auto-discover fallback IPs via DoH when api.telegram.org is unreachable (#3376) 2026-03-27 04:03:13 -07:00
test_send_retry.py fix(telegram): prevent duplicate message delivery on send timeout (#5153) 2026-04-04 19:05:34 -07:00
test_session.py fix(gateway): use profile-aware Hermes paths in runtime hints 2026-04-15 17:52:03 -07:00
test_session_boundary_hooks.py fix(gateway): drain in-flight work before restart 2026-04-10 21:18:34 -07:00
test_session_dm_thread_seeding.py fix(gateway): remove DM thread session seeding to prevent cross-thread contamination (#7084) 2026-04-10 03:01:59 -07:00
test_session_env.py fix(tests): resolve remaining CI failures — commit_memory_session, already_sent, timezone leak, session env (#10785) 2026-04-16 02:26:14 -07:00
test_session_hygiene.py fix(gateway): close temporary agents after one-off tasks 2026-04-16 06:31:23 -07:00
test_session_info.py feat(gateway): surface session config on /new, /reset, and auto-reset (#3321) 2026-03-26 19:27:58 -07:00
test_session_model_override_routing.py fix: honor session-scoped gateway model overrides 2026-04-11 03:11:34 -07:00
test_session_model_reset.py fix: clear session-scoped model overrides during session reset 2026-04-06 13:20:01 -07:00
test_session_race_guard.py fix(gateway): bypass active-session guard for gateway-handled slash commands 2026-04-17 18:58:03 -07:00
test_session_reset_notify.py feat(gateway): notify users when session auto-resets (#2519) 2026-03-22 09:33:39 -07:00
test_session_state_cleanup.py fix(gateway): consolidate per-session cleanup; close SessionDB on shutdown (#11800) 2026-04-17 15:18:23 -07:00
test_session_store_prune.py fix(gateway): prune stale SessionStore entries to bound memory + disk (#11789) 2026-04-17 13:48:49 -07:00
test_setup_feishu.py fix: salvage follow-ups for Feishu QR onboarding (#7706) 2026-04-12 13:05:56 -07:00
test_signal.py fix(signal): back off sendTyping spam for unreachable recipients (#12118) 2026-04-18 04:13:32 -07:00
test_slack.py fix(slack): per-thread sessions for DMs by default 2026-04-16 04:22:33 -07:00
test_slack_approval_buttons.py feat(slack): thread engagement — auto-respond in bot-started and mentioned threads (#5897) 2026-04-07 11:12:08 -07:00
test_slack_mention.py feat(slack): add require_mention and free_response_channels config support 2026-04-09 14:07:32 -07:00
test_sms.py test: remove 169 change-detector tests across 21 files (#11472) 2026-04-17 01:05:09 -07:00
test_sse_agent_cancel.py fix(api-server): cancel orphaned agent + true interrupt on SSE disconnect (salvage #3399) (#3427) 2026-03-27 11:33:19 -07:00
test_ssl_certs.py fix(gateway): SSL certificate auto-detection for NixOS and non-standard systems 2026-03-15 23:04:34 -07:00
test_status.py fix(gateway): detect legacy hermes.service + mark --replace SIGTERM as planned (#11909) 2026-04-17 19:27:58 -07:00
test_status_command.py Merge branch 'main' of github.com:NousResearch/hermes-agent into feat/ink-refactor 2026-04-16 08:23:20 -05:00
test_steer_command.py feat(steer): /steer <prompt> injects a mid-run note after the next tool call (#12116) 2026-04-18 04:17:18 -07:00
test_step_callback_compat.py fix(gateway): normalize step_callback prev_tools for backward compat 2026-04-02 20:54:27 -07:00
test_sticker_cache.py test: add unit tests for 8 untested modules (batch 3) (#191) 2026-03-01 05:28:12 -08:00
test_stream_consumer.py feat(dingtalk): AI Cards streaming, emoji reactions, and media handling 2026-04-17 19:26:53 -07:00
test_stt_config.py fix(gateway): preserve queued voice events for STT 2026-04-11 14:43:53 -07:00
test_stuck_loop.py fix: break stuck session resume loops after repeated restarts (#7536) 2026-04-14 17:08:35 -07:00
test_telegram_approval_buttons.py feat(telegram): add config option to disable link previews 2026-04-15 17:54:43 -07:00
test_telegram_caption_merge.py fix(telegram): replace substring caption check with exact line-by-line match 2026-04-07 14:08:59 -07:00
test_telegram_conflict.py refactor: extract shared helpers to deduplicate repeated code patterns (#7917) 2026-04-11 13:59:52 -07:00
test_telegram_documents.py feat: add .zip document support and auto-mount cache dirs into remote backends (#4846) 2026-04-03 13:16:26 -07:00
test_telegram_format.py feat(telegram): auto-wrap markdown tables in code blocks (#11794) 2026-04-17 14:27:26 -07:00
test_telegram_group_gating.py feat(gateway): add ignored_threads config for Telegram 2026-04-14 01:40:32 -07:00
test_telegram_network.py fix(tests): resolve 12 CI failures + 10 errors across 6 root causes (#11040) 2026-04-16 06:49:36 -07:00
test_telegram_network_reconnect.py feat(telegram): auto-discover fallback IPs via DoH when api.telegram.org is unreachable (#3376) 2026-03-27 04:03:13 -07:00
test_telegram_photo_interrupts.py fix(tests): fix 78 CI test failures and remove dead test (#9036) 2026-04-13 10:50:24 -07:00
test_telegram_reactions.py fix(telegram): use valid reaction emojis for processing completion (#7175) 2026-04-10 05:34:33 -07:00
test_telegram_reply_mode.py fix(telegram): use UTF-16 code units for message length splitting (#8725) 2026-04-12 19:06:20 -07:00
test_telegram_text_batching.py fix(telegram): aggregate split text messages before dispatching (#1674) 2026-03-17 02:49:57 -07:00
test_telegram_thread_fallback.py fix(telegram): restore typing indicator and thread routing for forum General topic 2026-04-15 22:35:19 -07:00
test_text_batching.py test: add text batching tests for Discord, Matrix, WeCom, Telegram, Feishu 2026-04-09 23:25:27 -07:00
test_title_command.py fix(test): add missing _voice_mode attr to GatewayRunner test stubs 2026-03-14 14:27:20 +03:00
test_transcript_offset.py fix(gateway): use filtered history length for transcript message extraction 2026-03-04 21:34:40 +03:00
test_unauthorized_dm_behavior.py fix(gateway): honor QQ_GROUP_ALLOWED_USERS in runner auth 2026-04-17 04:22:40 -07:00
test_unknown_command.py fix(gateway): surface unknown /commands instead of leaking them to the LLM 2026-04-05 11:59:28 -07:00
test_update_command.py feat(gateway): live-stream /update output + interactive prompt buttons (#5180) 2026-04-05 00:28:58 -07:00
test_update_streaming.py fix: prevent duplicate update prompt spam in gateway watcher (#8343) 2026-04-12 04:52:59 -07:00
test_usage_command.py fix(gateway): /usage now shows rate limits, cost, and token details between turns (#7038) 2026-04-10 02:33:01 -07:00
test_verbose_command.py feat: per-platform display verbosity configuration (#8006) 2026-04-11 17:20:34 -07:00
test_voice_command.py test: update stale tests to match current code (#11963) 2026-04-17 21:35:30 -07:00
test_weak_credential_guard.py fix(gateway): reject known-weak placeholder credentials at startup 2026-04-12 18:05:41 -07:00
test_webhook_adapter.py fix(gateway/webhook): don't pop delivery_info on send 2026-04-07 17:27:09 -07:00
test_webhook_dynamic_routes.py feat(webhook): hermes webhook CLI + skill for event-driven subscriptions (#3578) 2026-03-28 14:33:35 -07:00
test_webhook_integration.py fix(gateway/webhook): don't pop delivery_info on send 2026-04-07 17:27:09 -07:00
test_wecom.py fix(wecom): bound req_id cache, revert undocumented is_group change, add tests 2026-04-17 19:03:29 -07:00
test_wecom_callback.py feat(gateway): add WeCom callback-mode adapter for self-built apps 2026-04-11 15:22:49 -07:00
test_weixin.py Fix Weixin media uploads and refresh lockfile 2026-04-17 06:50:36 -07:00
test_whatsapp_connect.py fix(whatsapp): reuse persistent aiohttp session across requests (#3818) 2026-03-29 16:25:20 -07:00
test_whatsapp_formatting.py fix: improve WhatsApp UX — chunking, formatting, streaming (#8723) 2026-04-12 19:20:13 -07:00
test_whatsapp_group_gating.py fix(whatsapp): add free_response_chats, mention stripping, and interactive message unwrapping 2026-04-03 01:16:39 -07:00
test_whatsapp_reply_prefix.py feat: OpenAI-compatible API server + WhatsApp configurable reply prefix (#1756) 2026-03-17 10:44:37 -07:00
test_ws_auth_retry.py fix: resolve CI test failures — add missing functions, fix stale tests (#9483) 2026-04-14 01:43:45 -07:00
test_yolo_command.py refactor: remove dead code — 1,784 lines across 77 files (#9180) 2026-04-13 16:32:04 -07:00