feat: add IM channels for Feishu, Slack, and Telegram (#1010)

* feat: add IM channels system for Feishu, Slack, and Telegram integration

Bridge external messaging platforms to DeerFlow via LangGraph Server with
async message bus, thread management, and per-channel configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address review comments on IM channels system

Fix topic_id handling in store remove/list_entries and manager commands,
correct Telegram reply threading, remove unused imports/variables, update
docstrings and docs to match implementation, and prevent config mutation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* update skill creator

* fix im reply text

* fix comments

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
DanielWalnut
2026-03-08 15:21:18 +08:00
committed by GitHub
parent d664ae5a4b
commit 75b7302000
49 changed files with 8354 additions and 367 deletions

View File

@@ -5,22 +5,22 @@ from src.gateway.routers import suggestions
def test_strip_markdown_code_fence_removes_wrapping():
text = "```json\n[\"a\"]\n```"
assert suggestions._strip_markdown_code_fence(text) == "[\"a\"]"
text = '```json\n["a"]\n```'
assert suggestions._strip_markdown_code_fence(text) == '["a"]'
def test_strip_markdown_code_fence_no_fence_keeps_content():
text = " [\"a\"] "
assert suggestions._strip_markdown_code_fence(text) == "[\"a\"]"
text = ' ["a"] '
assert suggestions._strip_markdown_code_fence(text) == '["a"]'
def test_parse_json_string_list_filters_invalid_items():
text = "```json\n[\"a\", \" \", 1, \"b\"]\n```"
text = '```json\n["a", " ", 1, "b"]\n```'
assert suggestions._parse_json_string_list(text) == ["a", "b"]
def test_parse_json_string_list_rejects_non_list():
text = "{\"a\": 1}"
text = '{"a": 1}'
assert suggestions._parse_json_string_list(text) is None
@@ -43,7 +43,7 @@ def test_generate_suggestions_parses_and_limits(monkeypatch):
model_name=None,
)
fake_model = MagicMock()
fake_model.invoke.return_value = MagicMock(content="```json\n[\"Q1\", \"Q2\", \"Q3\", \"Q4\"]\n```")
fake_model.invoke.return_value = MagicMock(content='```json\n["Q1", "Q2", "Q3", "Q4"]\n```')
monkeypatch.setattr(suggestions, "create_chat_model", lambda **kwargs: fake_model)
result = asyncio.run(suggestions.generate_suggestions("t1", req))
@@ -63,4 +63,4 @@ def test_generate_suggestions_returns_empty_on_model_error(monkeypatch):
result = asyncio.run(suggestions.generate_suggestions("t1", req))
assert result.suggestions == []
assert result.suggestions == []