feat(channels): enable tool hints by default

This commit is contained in:
chengyongru
2026-07-26 21:22:12 +08:00
committed by chengyongru
parent ee93725e83
commit d576804f23
8 changed files with 27 additions and 16 deletions
+2 -2
View File
@@ -618,7 +618,7 @@ async def send(self, msg: OutboundMessage) -> None:
await self._send_message(msg.chat_id, msg.content, media=msg.media)
```
Tool hints are off by default for most channels. Users can enable them globally or per channel:
Tool hints are on by default. Users can disable them globally or per channel:
```json
{
@@ -626,7 +626,7 @@ Tool hints are off by default for most channels. Users can enable them globally
"sendToolHints": true,
"webhook": {
"enabled": true,
"sendToolHints": true
"sendToolHints": false
}
}
}
+5 -4
View File
@@ -1555,7 +1555,7 @@ Global settings that apply to all channels. Configure under the `channels` secti
{
"channels": {
"sendProgress": true,
"sendToolHints": false,
"sendToolHints": true,
"extractDocumentText": true,
"sendMaxRetries": 3,
"telegram": {
@@ -1568,7 +1568,7 @@ Global settings that apply to all channels. Configure under the `channels` secti
| Setting | Default | Description |
|---------|---------|-------------|
| `sendProgress` | `true` | Stream agent's text progress to the channel |
| `sendToolHints` | `false` | Stream tool-call hints (e.g. `read_file("…")`) |
| `sendToolHints` | `true` | Stream tool-call hints (e.g. `read_file("…")`) |
| `showReasoning` | `true` | Allow channels to surface model reasoning/thinking content (DeepSeek-R1 `reasoning_content`, Anthropic `thinking_blocks`, inline `<think>` tags). Reasoning flows as a dedicated stream with `_reasoning_delta` / `_reasoning_end` markers — channels override `send_reasoning_delta` / `send_reasoning_end` to render in-place updates. Even with `true`, channels without those overrides stay no-op silently. Currently surfaced on CLI and WebSocket/WebUI (italic shimmer header, auto-collapses after the stream ends); Telegram / Slack / Discord / Feishu / WeChat / Matrix / Mattermost keep the base no-op until their bubble UI is adapted. Independent of `sendProgress`. |
| `extractDocumentText` | `true` | Extract supported document/text attachments into the model prompt. PDF, DOCX, XLSX, and PPTX readers are included in the standard installation. Set to `false` to keep document content out of the prompt and include attachment path references instead. |
| `sendMaxRetries` | `3` | Max delivery attempts per outbound message, including the initial send (0-10 configured, minimum 1 actual attempt) |
@@ -1581,10 +1581,11 @@ Global settings that apply to all channels. Configure under the `channels` secti
{
"channels": {
"sendProgress": true,
"sendToolHints": false,
"sendToolHints": true,
"telegram": {
"enabled": true,
"sendProgress": false
"sendProgress": false,
"sendToolHints": false
},
"websocket": {
"enabled": true,
+1 -1
View File
@@ -29,7 +29,7 @@ class BaseChannel(ABC):
name: str = "base"
display_name: str = "Base"
send_progress: bool = True
send_tool_hints: bool = False
send_tool_hints: bool = True
show_reasoning: bool = True
def __init__(self, config: Any, bus: MessageBus):
+1 -1
View File
@@ -56,7 +56,7 @@ class MattermostConfig(Base):
react_emoji: str = "eyes"
done_emoji: str = "white_check_mark"
send_progress: bool = True
send_tool_hints: bool = False
send_tool_hints: bool = True
dm: MattermostDMConfig = Field(default_factory=MattermostDMConfig)
@@ -119,6 +119,7 @@ def test_config_defaults():
assert config.token == ""
assert config.streaming is True
assert config.streaming_max_chars == 16000
assert config.send_tool_hints is True
assert config.dm.enabled is True
assert config.dm.policy == "open"
assert config.reply_in_thread is True
@@ -131,6 +132,7 @@ def test_config_camelcase_aliases():
"allowFromMatchMode": "username",
"streamingMaxChars": 8000,
"replyInThread": False,
"sendToolHints": False,
}
config = MattermostConfig.model_validate(raw)
assert config.server_url == "https://mm.example.com"
@@ -138,11 +140,13 @@ def test_config_camelcase_aliases():
assert config.allow_from_match_mode == "username"
assert config.streaming_max_chars == 8000
assert config.reply_in_thread is False
assert config.send_tool_hints is False
def test_config_default_config_classmethod():
d = MattermostChannel.default_config()
assert d["enabled"] is False
assert d["sendToolHints"] is True
assert d["serverUrl"] == ""
assert d["token"] == ""
+1 -1
View File
@@ -30,7 +30,7 @@ class ChannelsConfig(Base):
model_config = ConfigDict(extra="allow")
send_progress: bool = True # stream agent's text progress to the channel
send_tool_hints: bool = False # stream tool-call hints (e.g. read_file("…"))
send_tool_hints: bool = True # stream tool-call hints (e.g. read_file("…"))
show_reasoning: bool = True # surface model reasoning when channel implements it
extract_document_text: bool = True # extract text from document attachments before sending to the model
send_max_retries: int = Field(default=3, ge=0, le=10) # Max delivery attempts (initial send included)
@@ -74,7 +74,7 @@ def bus():
@pytest.fixture
def manager(config, bus):
manager = ChannelManager(config, bus)
manager.channels["mock"] = MockChannel({}, bus)
manager.channels["mock"] = manager._build_channel("mock", MockChannel, {})
return manager
@@ -284,14 +284,17 @@ class TestProgressFiltering:
def test_progress_visibility_uses_global_defaults(self, manager):
assert manager._should_send_progress("mock", tool_hint=False) is True
assert manager._should_send_progress("mock", tool_hint=True) is False
assert manager._should_send_progress("mock", tool_hint=True) is True
def test_progress_visibility_uses_channel_overrides(self, manager):
manager.channels["mock"].send_progress = False
manager.channels["mock"].send_tool_hints = True
def test_progress_visibility_uses_channel_overrides(self, manager, bus):
manager.channels["mock"] = manager._build_channel(
"mock",
MockChannel,
{"sendProgress": False, "sendToolHints": False},
)
assert manager._should_send_progress("mock", tool_hint=False) is False
assert manager._should_send_progress("mock", tool_hint=True) is True
assert manager._should_send_progress("mock", tool_hint=True) is False
def test_progress_visibility_returns_false_for_missing_channel(self, manager):
assert manager._should_send_progress("nonexistent", tool_hint=False) is False
+4 -1
View File
@@ -269,9 +269,12 @@ def test_channels_config_has_no_per_channel_fields():
cfg = ChannelsConfig()
assert not hasattr(cfg, "telegram")
assert cfg.send_progress is True
assert cfg.send_tool_hints is False
assert cfg.send_tool_hints is True
assert cfg.extract_document_text is True
opted_out = ChannelsConfig.model_validate({"sendToolHints": False})
assert opted_out.send_tool_hints is False
def test_channels_config_extract_document_text_accepts_camel_alias():
cfg = ChannelsConfig.model_validate({"extractDocumentText": False})