hermes-agent/tests/tools
GodsBoy 93e25ceb13 feat(plugins): add standalone_sender_fn for out-of-process cron delivery
Plugin platforms (IRC, Teams, Google Chat) currently fail with
`No live adapter for platform '<name>'` when a `deliver=<plugin>` cron
job runs in a separate process from the gateway, even though the
platforms are eligible cron targets via `cron_deliver_env_var` (added
in #21306). Built-in platforms (Telegram, Discord, Slack, etc.) use
direct REST helpers in `tools/send_message_tool.py` so cron can deliver
without holding the gateway in the same process; plugin platforms
historically depended on `_gateway_runner_ref()` which returns `None`
out of process.

This change adds an optional `standalone_sender_fn` field to
`PlatformEntry` so plugins can register an ephemeral send path that
opens its own connection, sends, and closes without needing the live
adapter. The dispatch site in `_send_via_adapter` falls through to the
hook when the gateway runner is unavailable, with a descriptive error
when neither path applies. The hook is optional, so existing plugins
are unaffected.

Reference migrations land in the same change for IRC, Teams, and
Google Chat, exercising the hook across stdlib (asyncio + IRC protocol),
Bot Framework OAuth client_credentials, and Google service-account
flows respectively.

Security hardening on the new code paths:
* IRC: control-character stripping on chat_id and message body to
  block CRLF command injection; bounded nick-collision retries; JOIN
  before PRIVMSG so channels with the default `+n` mode accept the
  delivery.
* Teams: TEAMS_SERVICE_URL validated against an allowlist of known
  Bot Framework hosts (`smba.trafficmanager.net`,
  `smba.infra.gov.teams.microsoft.us`) to block SSRF; chat_id and
  tenant_id constrained to the documented Bot Framework character set;
  per-request timeouts so a slow STS endpoint cannot starve the
  activity POST.
* Google Chat: chat_id and thread_id validated against strict
  resource-name regexes; service-account refresh wrapped in
  `asyncio.wait_for` so a hung token endpoint cannot stall the
  scheduler.

Test coverage: 20 new tests covering happy path, missing-config errors,
network failure modes, and each defensive validation. Existing tests
unchanged. `bash scripts/run_tests.sh tests/tools/test_send_message_tool.py
tests/gateway/test_irc_adapter.py tests/gateway/test_teams.py
tests/gateway/test_google_chat.py` reports 341 passed, 0 regressions.

Documentation: new "Out-of-process cron delivery" section in
website/docs/developer-guide/adding-platform-adapters.md and an entry
in gateway/platforms/ADDING_A_PLATFORM.md naming the hook.
2026-05-09 02:56:29 -07:00
..
__init__.py
test_accretion_caps.py
test_ansi_strip.py
test_approval.py
test_approval_heartbeat.py test: remove 50 stale/broken tests to unblock CI (#22098) 2026-05-08 14:55:40 -07:00
test_approval_plugin_hooks.py test: remove 50 stale/broken tests to unblock CI (#22098) 2026-05-08 14:55:40 -07:00
test_base_environment.py fix(env): pass -- to cd for hyphen-prefixed workdirs 2026-05-04 04:45:03 -07:00
test_browser_camofox.py
test_browser_camofox_persistence.py
test_browser_camofox_state.py
test_browser_cdp_override.py
test_browser_cdp_tool.py
test_browser_chromium_check.py test: remove 50 stale/broken tests to unblock CI (#22098) 2026-05-08 14:55:40 -07:00
test_browser_cleanup.py
test_browser_cloud_fallback.py
test_browser_console.py
test_browser_content_none_guard.py
test_browser_hardening.py
test_browser_homebrew_paths.py feat(windows): close remaining POSIX-only landmines — TUI crash, kanban waitpid, AF_UNIX sandbox, /bin/bash, npm .cmd shims, cwd tracking, detach flags 2026-05-08 14:27:40 -07:00
test_browser_hybrid_routing.py
test_browser_lightpanda.py fix(browser): tighten Lightpanda fallback edge cases 2026-05-06 03:41:21 -07:00
test_browser_orphan_reaper.py test: migrate stale os.kill monkeypatches to gateway.status._pid_exists 2026-05-08 14:27:40 -07:00
test_browser_secret_exfil.py
test_browser_ssrf_local.py fix(browser): enforce cloud-metadata SSRF floor in hybrid routing (#16234) (#21228) 2026-05-07 05:38:05 -07:00
test_browser_supervisor.py
test_browser_supervisor_healthcheck.py
test_budget_config.py
test_checkpoint_manager.py feat(checkpoints): v2 single-store rewrite with real pruning + disk guardrails (#20709) 2026-05-06 05:44:35 -07:00
test_clarify_tool.py
test_clipboard.py
test_code_execution.py fix(windows): enable execute_code — stale AF_UNIX gate was blocking the tool 2026-05-08 14:27:40 -07:00
test_code_execution_modes.py tests: skip POSIX-venv-layout tests on Windows 2026-05-08 14:27:40 -07:00
test_code_execution_windows_env.py execute_code: set PYTHONIOENCODING=utf-8 + PYTHONUTF8=1 in child env 2026-05-08 14:27:40 -07:00
test_command_guards.py test: remove 50 stale/broken tests to unblock CI (#22098) 2026-05-08 14:55:40 -07:00
test_computer_use.py feat(computer-use): cua-driver backend, universal any-model schema 2026-05-08 11:07:38 -07:00
test_config_null_guard.py
test_credential_files.py
test_credential_pool_env_fallback.py test: remove 50 stale/broken tests to unblock CI (#22098) 2026-05-08 14:55:40 -07:00
test_cron_approval_mode.py fix(approval): cron jobs must not be treated as gateway context 2026-05-08 07:30:14 -07:00
test_cron_prompt_injection.py
test_cronjob_tools.py fix(cron): normalize partial job records 2026-05-09 01:11:41 -07:00
test_daytona_environment.py test: remove 50 stale/broken tests to unblock CI (#22098) 2026-05-08 14:55:40 -07:00
test_debug_helpers.py
test_delegate.py fix(delegate): accept JSON string batch tasks 2026-05-09 02:18:57 -07:00
test_delegate_composite_toolsets.py fix(delegate): expand composite toolsets before intersection in delegate_task 2026-05-07 06:41:42 -07:00
test_delegate_subagent_timeout_diagnostic.py
test_delegate_toolset_scope.py
test_discord_tool.py feat: add Discord message deletion action 2026-05-07 05:11:09 -07:00
test_docker_environment.py
test_docker_find.py
test_dockerfile_node_modules_perms.py fix(docker): chown runtime node_modules trees to hermes user (#18800) 2026-05-07 06:17:49 -07:00
test_dockerfile_pid1_reaping.py test(docker): align Dockerfile contract tests with simplified TUI flow 2026-05-07 04:53:10 -07:00
test_env_passthrough.py
test_feishu_tools.py
test_file_operations.py fix(file-ops): allow file search in hidden roots 2026-05-04 12:37:09 -07:00
test_file_operations_edge_cases.py feat(file_tools): post-write delta lint on write_file + patch, add JSON/YAML/TOML/Python in-process linters (#20191) 2026-05-05 04:54:17 -07:00
test_file_ops_cwd_tracking.py
test_file_read_guards.py
test_file_staleness.py
test_file_state_registry.py
test_file_sync.py
test_file_sync_back.py
test_file_sync_perf.py
test_file_tools.py test(patch-tool): collapse 9 schema-shape tests into 2 invariants 2026-05-08 16:59:24 -07:00
test_file_tools_container_config.py
test_file_tools_live.py
test_file_write_safety.py
test_force_dangerous_override.py
test_fuzzy_match.py
test_hardline_blocklist.py
test_heartbeat_stale_thresholds.py test: add unit tests for heartbeat stale threshold increase 2026-05-04 05:08:51 -07:00
test_hidden_dir_filter.py
test_homeassistant_tool.py
test_image_generation.py
test_image_generation_env.py
test_image_generation_plugin_dispatch.py
test_init_session_cwd_respect.py
test_interrupt.py
test_kanban_tools.py test(kanban): cover kanban_comment author hardening + cross-task policy 2026-05-09 02:32:16 -07:00
test_llm_content_none_guard.py
test_local_background_child_hang.py
test_local_env_blocklist.py
test_local_env_cwd_recovery.py fix(local): test root as ancestor candidate; use real pipe for fake stdout 2026-05-04 15:31:47 -07:00
test_local_interrupt_cleanup.py
test_local_shell_init.py
test_local_tempdir.py
test_managed_browserbase_and_modal.py
test_managed_media_gateways.py
test_managed_modal_environment.py
test_managed_server_tool_support.py
test_managed_tool_gateway.py
test_mcp_cancelled_error_propagation.py fix(mcp): re-raise CancelledError explicitly in MCPServerTask.run (#21318) 2026-05-07 07:04:38 -07:00
test_mcp_circuit_breaker.py
test_mcp_dynamic_discovery.py
test_mcp_empty_error_message.py fix(mcp): include exception type in error messages when str(exc) is empty 2026-05-07 06:33:57 -07:00
test_mcp_image_content.py fix(mcp): surface image tool results as MEDIA tags instead of dropping them (#21328) 2026-05-07 07:14:16 -07:00
test_mcp_oauth.py fix(security): close TOCTOU window when saving MCP OAuth credentials 2026-05-07 04:56:13 -07:00
test_mcp_oauth_bidirectional.py
test_mcp_oauth_cold_load_expiry.py
test_mcp_oauth_integration.py
test_mcp_oauth_manager.py
test_mcp_oauth_metadata.py fix(mcp-oauth): persist OAuth server metadata across process restarts (#21226) 2026-05-07 05:35:33 -07:00
test_mcp_probe.py
test_mcp_reconnect_signal.py
test_mcp_sse_transport.py fix(mcp): forward OAuth auth and bump sse_read_timeout on SSE transport (#21323) 2026-05-07 07:08:04 -07:00
test_mcp_stability.py test: migrate stale os.kill monkeypatches to gateway.status._pid_exists 2026-05-08 14:27:40 -07:00
test_mcp_structured_content.py
test_mcp_tool.py fix(mcp): report configured timeout in MCP call errors 2026-05-07 06:28:11 -07:00
test_mcp_tool_401_handling.py
test_mcp_tool_issue_948.py
test_mcp_tool_session_expired.py fix(mcp): retry stale pipe transport failures 2026-05-07 06:32:45 -07:00
test_mcp_utility_capability_gating.py fix(mcp): gate utility stubs on server-advertised capabilities (#21347) 2026-05-07 07:39:50 -07:00
test_memory_tool.py
test_memory_tool_import_fallback.py
test_memory_tool_schema.py fix(memory): remove dead allOf schema block at the source 2026-05-07 07:03:21 -07:00
test_microsoft_graph_auth.py test(msgraph): cover concurrent token cache reuse 2026-05-08 09:27:26 -07:00
test_microsoft_graph_client.py fix(msgraph): stream download_to_file body instead of buffering 2026-05-08 09:27:26 -07:00
test_mixture_of_agents_tool.py
test_modal_bulk_upload.py
test_modal_sandbox_fixes.py
test_modal_snapshot_isolation.py
test_notify_on_complete.py
test_osv_check.py
test_parse_env_var.py
test_patch_parser.py
test_process_registry.py test: migrate stale os.kill monkeypatches to gateway.status._pid_exists 2026-05-08 14:27:40 -07:00
test_read_loop_detection.py
test_registry.py fix(computer-use): harden image-rejection fallback + AUTHOR_MAP 2026-05-08 11:07:38 -07:00
test_resolve_path.py
test_rl_training_tool.py
test_schema_sanitizer.py fix: strip Codex-hostile top-level schema combinators 2026-05-07 07:03:21 -07:00
test_search_hidden_dirs.py
test_send_message_missing_platforms.py
test_send_message_tool.py feat(plugins): add standalone_sender_fn for out-of-process cron delivery 2026-05-09 02:56:29 -07:00
test_session_search.py fix(session-search): report source from resolved parent, not FTS5 child session (#15909) 2026-05-04 05:07:40 -07:00
test_shared_container_task_id.py
test_signal_media.py
test_singularity_preflight.py
test_skill_env_passthrough.py
test_skill_improvements.py
test_skill_manager_tool.py fix(skills): pin protects against deletion only, not edits (#20220) 2026-05-05 05:43:10 -07:00
test_skill_provenance.py test: remove 50 stale/broken tests to unblock CI (#22098) 2026-05-08 14:55:40 -07:00
test_skill_size_limits.py
test_skill_usage.py fix(skills): lock usage telemetry updates 2026-05-07 06:13:37 -07:00
test_skill_view_path_check.py
test_skill_view_traversal.py
test_skills_guard.py
test_skills_hub.py test(skills): add bytes-vs-str equivalence and on-disk hash parity tests 2026-05-04 01:28:12 -07:00
test_skills_hub_clawhub.py
test_skills_sync.py
test_skills_tool.py
test_slash_confirm.py
test_spotify_client.py
test_ssh_bulk_upload.py
test_ssh_environment.py
test_symlink_prefix_confusion.py
test_sync_back_backends.py
test_terminal_compound_background.py
test_terminal_config_env_sync.py
test_terminal_exit_semantics.py
test_terminal_foreground_timeout_cap.py
test_terminal_none_command_guard.py
test_terminal_output_transform_hook.py
test_terminal_requirements.py
test_terminal_timeout_output.py
test_terminal_tool.py fix(terminal): skip sudo prompt when local NOPASSWD sudo works 2026-04-30 20:38:09 -07:00
test_terminal_tool_pty_fallback.py
test_terminal_tool_requirements.py
test_threaded_process_handle.py
test_tirith_security.py
test_todo_tool.py
test_tool_backend_helpers.py
test_tool_call_parsers.py
test_tool_output_limits.py
test_tool_result_storage.py fix(file-tools): cap read_file result size to prevent context window overflow 2026-05-04 03:14:59 -07:00
test_transcription.py
test_transcription_dotenv_fallback.py
test_transcription_tools.py fix(test): add skip marker for transcription tests requiring faster_whisper 2026-05-04 04:41:36 -07:00
test_tts_command_providers.py
test_tts_dotenv_fallback.py
test_tts_gemini.py
test_tts_kittentts.py
test_tts_max_text_length.py
test_tts_mistral.py
test_tts_piper.py
test_tts_speed.py fix(tts): update MiniMax API endpoint to v1/text_to_speech 2026-05-04 12:36:09 -07:00
test_url_safety.py fix(browser): enforce cloud-metadata SSRF floor in hybrid routing (#16234) (#21228) 2026-05-07 05:38:05 -07:00
test_vercel_sandbox_environment.py test: remove 50 stale/broken tests to unblock CI (#22098) 2026-05-08 14:55:40 -07:00
test_video_analyze.py feat: add video_analyze tool for native video understanding (#19301) 2026-05-04 00:04:36 +05:30
test_vision_tools.py
test_voice_cli_integration.py fix(cli): avoid voice TTS restart race 2026-05-04 01:36:07 -07:00
test_voice_mode.py
test_watch_patterns.py
test_web_providers.py refactor(web): per-capability backend selection for search/extract split 2026-05-06 09:16:25 -07:00
test_web_providers_brave_free.py feat(web): add Brave Search (free tier) and DDGS search providers 2026-05-07 09:59:17 -07:00
test_web_providers_ddgs.py feat(web): add Brave Search (free tier) and DDGS search providers 2026-05-07 09:59:17 -07:00
test_web_providers_searxng.py feat(web): add SearXNG as a native search-only backend 2026-05-06 10:05:29 -07:00
test_web_tools_config.py
test_web_tools_tavily.py
test_website_policy.py
test_windows_compat.py
test_windows_native_support.py test: migrate stale os.kill monkeypatches to gateway.status._pid_exists 2026-05-08 14:27:40 -07:00
test_write_deny.py
test_yolo_mode.py
test_zombie_process_cleanup.py