fix(channels): preserve global progress defaults

This commit is contained in:
chengyongru 2026-08-07 17:07:41 +08:00 committed by chengyongru
parent 332c159b93
commit bd8d3ad5b6
4 changed files with 47 additions and 9 deletions

View File

@ -101,6 +101,14 @@ class BaseChannel(ABC):
""" """
pass pass
def progress_transport_defaults(self) -> tuple[bool, bool] | None:
"""Return channel-owned defaults for progress and tool-hint messages.
``None`` keeps the global channel policy. Channels should override this
only when their transport requires different defaults.
"""
return None
def should_retry_send_error(self, error: Exception) -> bool: def should_retry_send_error(self, error: Exception) -> bool:
"""Return whether the channel manager may retry a failed delivery. """Return whether the channel manager may retry a failed delivery.

View File

@ -187,15 +187,9 @@ class ChannelManager:
channel = cls(section, self.bus, **kwargs) channel = cls(section, self.bus, **kwargs)
if runtime_name and runtime_name != channel.name: if runtime_name and runtime_name != channel.name:
channel.name = runtime_name channel.name = runtime_name
# Channel-owned config models may deliberately choose safer transport progress_default, tool_hints_default = channel.progress_transport_defaults() or (
# defaults than the global channel policy (for example, a quota-limited self.config.channels.send_progress,
# platform can disable progress messages). Preserve those defaults self.config.channels.send_tool_hints,
# while still letting an explicit per-channel value win below.
progress_default = getattr(
channel.config, "send_progress", self.config.channels.send_progress,
)
tool_hints_default = getattr(
channel.config, "send_tool_hints", self.config.channels.send_tool_hints,
) )
channel.send_progress = self._resolve_bool_override( channel.send_progress = self._resolve_bool_override(
section, "send_progress", progress_default, section, "send_progress", progress_default,

View File

@ -339,6 +339,9 @@ class WeixinChannel(BaseChannel):
self._reply_run_ids: dict[str, str] = {} self._reply_run_ids: dict[str, str] = {}
self._reply_progress_counts: dict[str, int] = {} self._reply_progress_counts: dict[str, int] = {}
def progress_transport_defaults(self) -> tuple[bool, bool]:
return self.config.send_progress, self.config.send_tool_hints
def should_retry_send_error(self, error: Exception) -> bool: def should_retry_send_error(self, error: Exception) -> bool:
if isinstance(error, WeixinAPIError): if isinstance(error, WeixinAPIError):
return error.retryable return error.retryable

View File

@ -17,6 +17,7 @@ from nanobot.bus.outbound_events import (
from nanobot.bus.queue import MessageBus from nanobot.bus.queue import MessageBus
from nanobot.channels.base import BaseChannel from nanobot.channels.base import BaseChannel
from nanobot.channels.manager import ChannelManager from nanobot.channels.manager import ChannelManager
from nanobot.channels.mattermost.runtime import MattermostChannel
from nanobot.config.schema import Config from nanobot.config.schema import Config
@ -311,6 +312,38 @@ class TestProgressFiltering:
assert manager._should_send_progress("mock", tool_hint=False) is False assert manager._should_send_progress("mock", tool_hint=False) is False
assert manager._should_send_progress("mock", tool_hint=True) is False assert manager._should_send_progress("mock", tool_hint=True) is False
def test_channel_config_defaults_do_not_override_global_policy(self, bus):
manager = ChannelManager.__new__(ChannelManager)
manager.config = Config.model_validate({
"channels": {
"sendProgress": False,
"sendToolHints": False,
},
})
manager.bus = bus
channel = manager._build_channel(
"mattermost",
MattermostChannel,
{"enabled": True},
)
assert channel.send_progress is False
assert channel.send_tool_hints is False
opted_in = manager._build_channel(
"mattermost",
MattermostChannel,
{
"enabled": True,
"sendProgress": True,
"sendToolHints": True,
},
)
assert opted_in.send_progress is True
assert opted_in.send_tool_hints is True
def test_progress_visibility_returns_false_for_missing_channel(self, manager): def test_progress_visibility_returns_false_for_missing_channel(self, manager):
assert manager._should_send_progress("nonexistent", tool_hint=False) is False assert manager._should_send_progress("nonexistent", tool_hint=False) is False
assert manager._should_send_progress("nonexistent", tool_hint=True) is False assert manager._should_send_progress("nonexistent", tool_hint=True) is False