hermes-bsd/gateway
Teknium 7a131f7f40
fix(api-server): stop silently promising async delivery on stateless HTTP path (#50319)
* fix(api-server): stop silently promising async delivery on stateless HTTP path

terminal(notify_on_complete=True / watch_patterns) and delegate_task(background=True)
silently no-op'd on the API server / WebUI path (#10760): the watcher / detached
child registered, but every API-server route (OpenAI-spec /v1/chat/completions
and /v1/responses, plus the proprietary /v1/runs SSE stream) tears down its
channel when the turn ends, and APIServerAdapter.send() is a no-op stub. A
completion that fires after the response closed had nowhere to go — from the
agent side, indistinguishable from a hang.

There is no spec-compliant surface to wake the agent later on a stateless HTTP
client, so make the no-op honest instead of silent:

- Add a per-adapter capability flag supports_async_delivery (default True;
  APIServerAdapter = False), propagated into a HERMES_SESSION_ASYNC_DELIVERY
  contextvar via async_delivery_supported(). Toggle on the adapter, not a
  hardcoded platform string — a future stateless adapter is correct-by-default.
- terminal: when delivery is unsupported, skip watcher registration, force
  notify_on_complete off, and return a notify_unsupported note telling the
  agent to process(action='poll').
- delegate_task: when delivery is unsupported, fall back to SYNCHRONOUS
  execution (work runs and returns in the same response) with a note, instead
  of handing out a handle that never resolves.

CLI (in-process completion_queue) and the real gateway platforms are unchanged.

Fixes #10760

* refactor(api-server): route session binding through a single no-delivery chokepoint

Add APIServerAdapter._bind_api_server_session() and route both agent-entry
paths (_run_agent for /v1/chat/completions + /v1/responses, and the /v1/runs
_run_sync path) through it. The helper hardwires platform="api_server" and
async_delivery=False with no async_delivery parameter to pass, so a future
route added to the API server physically cannot reintroduce the silent
no-op (#10760) by forgetting to mark the channel as non-delivering.

The binding stays request-scoped (cleared per turn), so a session resumed
later on a delivering interface (CLI / gateway platform) re-binds fresh and
is NOT blocked — the no-delivery decision tracks the interface handling the
current turn, never the session.
2026-06-21 12:15:14 -07:00
..
assets
builtin_hooks
platforms fix(api-server): stop silently promising async delivery on stateless HTTP path (#50319) 2026-06-21 12:15:14 -07:00
relay fix(relay): make hosted gateways actually connect AND complete the inbound/outbound round-trip (#48828) 2026-06-19 16:30:24 +10:00
__init__.py
authz_mixin.py fix(gateway): preserve WeCom per-group sender allowlists 2026-06-13 07:18:54 -07:00
channel_directory.py fix: harden WhatsApp target alias salvage 2026-06-15 05:51:47 -07:00
config.py refactor(gateway): migrate slack/dingtalk/whatsapp/matrix/feishu/telegram/wecom/email/sms adapters to bundled plugins 2026-06-20 10:26:45 -07:00
delivery.py fix(gateway): drop outbound silence-narration messages pre-send 2026-05-29 19:06:05 -07:00
display_config.py feat(gateway): rename to tool_progress_grouping, add config/docs/tests 2026-06-16 05:49:24 -07:00
hooks.py feat(hooks): expose thread_id and chat_type in agent:start/end context (#41672) 2026-06-07 19:16:36 -07:00
kanban_watchers.py fix: open dispatcher lock file with explicit utf-8 encoding 2026-06-19 07:35:33 -07:00
memory_monitor.py
message_timestamps.py feat(gateway): inject stable human-readable message timestamps 2026-06-16 15:49:59 -07:00
mirror.py
pairing.py
platform_registry.py
response_filters.py fix(gateway): suppress exact silence tokens without mutating history 2026-06-14 03:25:08 -07:00
restart.py
rich_sent_store.py fix(telegram): resolve replies to rich (sendRichMessage) messages 2026-06-16 13:04:20 -07:00
run.py fix(api-server): stop silently promising async delivery on stateless HTTP path (#50319) 2026-06-21 12:15:14 -07:00
runtime_footer.py
session.py feat(gateway): multiplex phase 1 — HTTP-inbound /p/<profile>/ routing (webhook) 2026-06-19 07:34:15 -07:00
session_context.py fix(api-server): stop silently promising async delivery on stateless HTTP path (#50319) 2026-06-21 12:15:14 -07:00
shutdown_forensics.py
slash_access.py
slash_commands.py fix(cli): log instead of swallow preflight-warning errors; consistent TUI warning field 2026-06-21 16:31:56 +05:30
status.py refactor(gateway): route all active_agents coercion through parse_active_agents; harden drain-timeout fallback 2026-06-21 17:22:52 +05:30
sticker_cache.py
stream_consumer.py fix(mattermost): harden delivery hygiene 2026-06-16 06:34:54 -07:00
stream_dispatch.py feat(gateway): structured stream-event protocol + Telegram draft formatting parity (#37250) 2026-06-02 00:33:50 -07:00
stream_events.py feat(gateway): structured stream-event protocol + Telegram draft formatting parity (#37250) 2026-06-02 00:33:50 -07:00
whatsapp_identity.py