mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-23 17:05:28 +08:00
Apply group response rules before busy-session steering. Initialize usable private-message and group-mention routes for new bots, including Wizard-created pipelines, and preserve member-configured rules across saves and retries. Fix empty pipeline configuration, refresh the processor sidebar after automatic creation, and show creation feedback. Align routing regressions and use Node 24 for the browser CI job. Correct the task's erroneous agent attribution while preserving every code tree and the original human contribution. Co-authored-by: multica-agent <[email protected]>
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
import asyncio
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock
|
|
|
|
from langbot.pkg.api.http.service.bot import BotService
|
|
|
|
|
|
async def test_concurrent_first_bots_share_one_default_pipeline():
|
|
pipelines = []
|
|
|
|
async def create(context, data, default=False):
|
|
await asyncio.sleep(0)
|
|
assert default
|
|
pipelines.append({'uuid': 'p', 'is_default': True})
|
|
return 'p'
|
|
|
|
ap = SimpleNamespace(
|
|
pipeline_service=SimpleNamespace(
|
|
get_pipelines=AsyncMock(side_effect=lambda context: list(pipelines)),
|
|
create_pipeline=AsyncMock(side_effect=create),
|
|
)
|
|
)
|
|
service = BotService(ap)
|
|
first, second = await asyncio.gather(
|
|
service._build_default_event_bindings('workspace'),
|
|
service._build_default_event_bindings('workspace'),
|
|
)
|
|
ap.pipeline_service.create_pipeline.assert_awaited_once()
|
|
for bindings in (first, second):
|
|
assert len(bindings) == 2
|
|
assert all(binding['target_uuid'] == 'p' for binding in bindings)
|
|
assert bindings[0]['filters'] == [{'field': 'chat_type', 'operator': 'eq', 'value': 'person'}]
|
|
assert bindings[1]['filters'][-1] == {'field': 'is_at_bot', 'operator': 'eq', 'value': True}
|
|
|
|
|
|
async def test_existing_default_pipeline_preferred_without_creating_another():
|
|
ap = SimpleNamespace(
|
|
pipeline_service=SimpleNamespace(
|
|
get_pipelines=AsyncMock(
|
|
return_value=[
|
|
{'uuid': 'recent'},
|
|
{'uuid': 'default', 'is_default': True},
|
|
]
|
|
),
|
|
create_pipeline=AsyncMock(),
|
|
)
|
|
)
|
|
routes = await BotService(ap)._build_default_event_bindings('workspace')
|
|
assert all(route['target_uuid'] == 'default' for route in routes)
|
|
ap.pipeline_service.create_pipeline.assert_not_awaited()
|
|
|
|
|
|
async def test_explicit_manual_route_does_not_create_or_replace_defaults():
|
|
ap = SimpleNamespace(
|
|
instance_config=SimpleNamespace(data={}),
|
|
persistence_mgr=SimpleNamespace(execute_async=AsyncMock()),
|
|
pipeline_service=SimpleNamespace(get_pipelines=AsyncMock(), create_pipeline=AsyncMock()),
|
|
)
|
|
service = BotService(ap)
|
|
service.get_bot = AsyncMock(return_value={'enable': False})
|
|
route = {
|
|
'id': 'manual-route',
|
|
'event_pattern': 'message.received',
|
|
'target_type': 'discard',
|
|
'target_uuid': '',
|
|
'filters': [{'field': 'chat_id', 'operator': 'eq', 'value': 'manual-group'}],
|
|
'priority': 10,
|
|
'enabled': False,
|
|
'description': 'Keep this manual rule',
|
|
'order': 0,
|
|
}
|
|
await service.create_bot(
|
|
'workspace',
|
|
{
|
|
'name': 'Manual',
|
|
'adapter': 'onebot-v11',
|
|
'adapter_config': {},
|
|
'event_bindings': [route],
|
|
},
|
|
)
|
|
inserted = ap.persistence_mgr.execute_async.await_args_list[0].args[0].compile().params
|
|
assert inserted['event_bindings'] == [route]
|
|
ap.pipeline_service.get_pipelines.assert_not_awaited()
|
|
ap.pipeline_service.create_pipeline.assert_not_awaited()
|