feat(streaming): per-platform streaming defaults (Telegram on, Discord off) + dashboard toggles (#37303)
Streaming quality differs sharply by platform: Telegram has native animated
draft streaming (sendMessageDraft) which is smooth, while Discord/Slack only
have edit-based streaming (repeated editMessage) which visibly flickers. Ship
defaults that match reality instead of one global flag.
- hermes_cli/config.py: DEFAULT_CONFIG display.platforms now ships
telegram.streaming=true and discord.streaming=false (was empty {}). These
are gap-fillers — config deep-merge has user values win, so anyone who
explicitly sets discord.streaming=true keeps it. The global
streaming.enabled master switch still gates everything; these per-platform
flags only take effect once streaming is on.
- Dashboard exposure comes for free: the web settings schema is generated
from DEFAULT_CONFIG, so display.platforms.telegram.streaming and
.discord.streaming now surface as editable boolean toggles in the UI with
no frontend change. (Previously the per-platform tree was {} and invisible.)
- tests: pin the defaults, the resolver outcome (telegram on / discord off /
unlisted platforms follow global), user-override-wins, and dashboard schema
exposure.
No _config_version bump: deep-merge fills the gap for existing installs; no
value migration needed.
This commit is contained in:
@ -1345,7 +1345,27 @@ DEFAULT_CONFIG = {
|
||||
# responses and content messages are never touched. Default 0
|
||||
# (disabled) preserves prior behavior.
|
||||
"ephemeral_system_ttl": 0,
|
||||
"platforms": {}, # Per-platform display overrides: {"telegram": {"tool_progress": "all"}, "slack": {"tool_progress": "off"}}
|
||||
# Per-platform display/streaming overrides. Each key is a gateway
|
||||
# platform ("telegram", "discord", "slack", …) mapping to a dict of
|
||||
# display settings that override the global value for that platform
|
||||
# only. A setting left unset here falls through to the global default.
|
||||
#
|
||||
# Shipped defaults encode the streaming experience that works best
|
||||
# per platform:
|
||||
# - Telegram has native animated draft streaming (sendMessageDraft),
|
||||
# which is smooth, so streaming is on by default there.
|
||||
# - Discord/Slack/etc. only have edit-based streaming (repeated
|
||||
# editMessage), which flickers and is noticeably jankier, so
|
||||
# streaming is off by default there.
|
||||
# These are gap-fillers: a user who explicitly sets, e.g.,
|
||||
# display.platforms.discord.streaming: true keeps their value
|
||||
# (config deep-merge has user values win over defaults). The global
|
||||
# streaming.enabled master switch still gates everything — these
|
||||
# per-platform flags only take effect once streaming is enabled.
|
||||
"platforms": {
|
||||
"telegram": {"streaming": True},
|
||||
"discord": {"streaming": False},
|
||||
},
|
||||
# Gateway runtime-metadata footer appended to the FINAL message of a turn
|
||||
# (disabled by default to keep replies minimal). When enabled, renders
|
||||
# e.g. `model · 68% · ~/projects/hermes`. Per-platform overrides go under
|
||||
|
||||
65
tests/gateway/test_per_platform_streaming_defaults.py
Normal file
65
tests/gateway/test_per_platform_streaming_defaults.py
Normal file
@ -0,0 +1,65 @@
|
||||
"""Per-platform streaming defaults + dashboard exposure.
|
||||
|
||||
Streaming is smooth on Telegram (native sendMessageDraft) but flickers on
|
||||
edit-only platforms like Discord. The shipped defaults encode that:
|
||||
display.platforms.telegram.streaming=true, .discord.streaming=false. These are
|
||||
gap-fillers (user values win via deep-merge) and, because the dashboard schema
|
||||
is generated from DEFAULT_CONFIG, they automatically appear as editable toggles
|
||||
in the web UI.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def test_default_per_platform_streaming_flags():
|
||||
from hermes_cli.config import DEFAULT_CONFIG
|
||||
plats = DEFAULT_CONFIG["display"]["platforms"]
|
||||
assert plats["telegram"]["streaming"] is True
|
||||
assert plats["discord"]["streaming"] is False
|
||||
|
||||
|
||||
def test_resolver_telegram_on_discord_off_when_global_enabled():
|
||||
"""With global streaming on, the per-platform defaults make Telegram stream
|
||||
and Discord not — matching the platforms' actual streaming quality."""
|
||||
from hermes_cli.config import DEFAULT_CONFIG
|
||||
from gateway.display_config import resolve_display_setting
|
||||
|
||||
cfg = dict(DEFAULT_CONFIG)
|
||||
cfg["streaming"] = {"enabled": True, "transport": "auto"}
|
||||
|
||||
def streams(plat):
|
||||
ov = resolve_display_setting(cfg, plat, "streaming")
|
||||
# global enabled; None override = follow global (True)
|
||||
return True if ov is None else bool(ov)
|
||||
|
||||
assert streams("telegram") is True
|
||||
assert streams("discord") is False
|
||||
# A platform with no default entry follows the global switch.
|
||||
assert streams("slack") is True
|
||||
|
||||
|
||||
def test_user_override_wins_over_default():
|
||||
"""A user who explicitly enables Discord streaming keeps their value — the
|
||||
default false must not clobber it (config deep-merge: user wins)."""
|
||||
from hermes_cli.config import DEFAULT_CONFIG, _deep_merge
|
||||
|
||||
user = {"display": {"platforms": {"discord": {"streaming": True}}}}
|
||||
merged = _deep_merge(dict(DEFAULT_CONFIG), user)
|
||||
assert merged["display"]["platforms"]["discord"]["streaming"] is True
|
||||
# Partial override must not wipe the sibling telegram default.
|
||||
assert merged["display"]["platforms"]["telegram"]["streaming"] is True
|
||||
|
||||
|
||||
def test_dashboard_schema_exposes_per_platform_streaming():
|
||||
"""Because the web settings schema is built from DEFAULT_CONFIG, the
|
||||
per-platform streaming toggles surface in the dashboard automatically."""
|
||||
import pytest
|
||||
pytest.importorskip("fastapi") # web_server requires fastapi/uvicorn
|
||||
from hermes_cli.web_server import CONFIG_SCHEMA
|
||||
|
||||
assert "display.platforms.telegram.streaming" in CONFIG_SCHEMA
|
||||
assert "display.platforms.discord.streaming" in CONFIG_SCHEMA
|
||||
assert CONFIG_SCHEMA["display.platforms.discord.streaming"]["type"] == "boolean"
|
||||
# Global streaming controls are exposed too.
|
||||
assert "streaming.enabled" in CONFIG_SCHEMA
|
||||
assert "streaming.transport" in CONFIG_SCHEMA
|
||||
Reference in New Issue
Block a user