mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-25 05:46:13 +00:00
fix(wecomcs): implement proactive text sends (#2300)
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
import typing
|
import typing
|
||||||
import asyncio
|
import asyncio
|
||||||
import traceback
|
import traceback
|
||||||
|
import uuid
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import pydantic
|
import pydantic
|
||||||
@@ -182,7 +183,28 @@ class WecomCSAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def send_message(self, target_type: str, target_id: str, message: platform_message.MessageChain):
|
async def send_message(self, target_type: str, target_id: str, message: platform_message.MessageChain):
|
||||||
pass
|
if target_type != 'person':
|
||||||
|
raise ValueError('WeCom customer service only supports sending messages to person targets')
|
||||||
|
|
||||||
|
open_kfid = self.bot_account_id
|
||||||
|
external_userid = target_id
|
||||||
|
if '|' in target_id:
|
||||||
|
open_kfid, external_userid = target_id.split('|', 1)
|
||||||
|
if external_userid.startswith('u'):
|
||||||
|
external_userid = external_userid[1:]
|
||||||
|
if not open_kfid:
|
||||||
|
raise ValueError('WeCom customer service open_kfid is required before sending messages')
|
||||||
|
|
||||||
|
content_list = await WecomMessageConverter.yiri2target(message, self.bot)
|
||||||
|
for content in content_list:
|
||||||
|
msgid = f'langbot_{uuid.uuid4().hex}'
|
||||||
|
if content['type'] == 'text':
|
||||||
|
await self.bot.send_text_msg(
|
||||||
|
open_kfid=open_kfid,
|
||||||
|
external_userid=external_userid,
|
||||||
|
msgid=msgid,
|
||||||
|
content=content['content'],
|
||||||
|
)
|
||||||
|
|
||||||
def set_bot_uuid(self, bot_uuid: str):
|
def set_bot_uuid(self, bot_uuid: str):
|
||||||
"""设置 bot UUID(用于生成 webhook URL)"""
|
"""设置 bot UUID(用于生成 webhook URL)"""
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
from types import SimpleNamespace
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import langbot_plugin.api.definition.abstract.platform.event_logger as abstract_platform_logger
|
||||||
|
import langbot_plugin.api.entities.builtin.platform.message as platform_message
|
||||||
|
from langbot.pkg.platform.sources.wecomcs import WecomCSAdapter
|
||||||
|
|
||||||
|
|
||||||
|
class DummyLogger(abstract_platform_logger.AbstractEventLogger):
|
||||||
|
async def info(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def debug(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def warning(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def error(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def make_adapter():
|
||||||
|
return WecomCSAdapter(
|
||||||
|
config={
|
||||||
|
'corpid': 'corp-id',
|
||||||
|
'secret': 'secret',
|
||||||
|
'token': 'token',
|
||||||
|
'EncodingAESKey': 'encoding-key',
|
||||||
|
},
|
||||||
|
logger=DummyLogger(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_message_sends_text_to_customer_service_user():
|
||||||
|
adapter = make_adapter()
|
||||||
|
adapter.bot_account_id = 'kf-test'
|
||||||
|
adapter.bot = SimpleNamespace(send_text_msg=AsyncMock())
|
||||||
|
|
||||||
|
message = platform_message.MessageChain([platform_message.Plain(text='hello')])
|
||||||
|
|
||||||
|
await adapter.send_message('person', 'uexternal-user', message)
|
||||||
|
|
||||||
|
adapter.bot.send_text_msg.assert_awaited_once()
|
||||||
|
kwargs = adapter.bot.send_text_msg.await_args.kwargs
|
||||||
|
assert kwargs['open_kfid'] == 'kf-test'
|
||||||
|
assert kwargs['external_userid'] == 'external-user'
|
||||||
|
assert kwargs['content'] == 'hello'
|
||||||
|
assert kwargs['msgid'].startswith('langbot_')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_message_allows_explicit_open_kfid_in_target_id():
|
||||||
|
adapter = make_adapter()
|
||||||
|
adapter.bot = SimpleNamespace(send_text_msg=AsyncMock())
|
||||||
|
|
||||||
|
message = platform_message.MessageChain([platform_message.Plain(text='hello')])
|
||||||
|
|
||||||
|
await adapter.send_message('person', 'kf-explicit|uexternal-user', message)
|
||||||
|
|
||||||
|
kwargs = adapter.bot.send_text_msg.await_args.kwargs
|
||||||
|
assert kwargs['open_kfid'] == 'kf-explicit'
|
||||||
|
assert kwargs['external_userid'] == 'external-user'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_message_requires_open_kfid():
|
||||||
|
adapter = make_adapter()
|
||||||
|
adapter.bot = SimpleNamespace(send_text_msg=AsyncMock())
|
||||||
|
message = platform_message.MessageChain([platform_message.Plain(text='hello')])
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match='open_kfid is required'):
|
||||||
|
await adapter.send_message('person', 'uexternal-user', message)
|
||||||
|
|
||||||
|
adapter.bot.send_text_msg.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_message_rejects_group_targets():
|
||||||
|
adapter = make_adapter()
|
||||||
|
adapter.bot_account_id = 'kf-test'
|
||||||
|
adapter.bot = SimpleNamespace(send_text_msg=AsyncMock())
|
||||||
|
message = platform_message.MessageChain([platform_message.Plain(text='hello')])
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match='only supports sending messages to person'):
|
||||||
|
await adapter.send_message('group', 'group-id', message)
|
||||||
|
|
||||||
|
adapter.bot.send_text_msg.assert_not_called()
|
||||||
Reference in New Issue
Block a user