mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-23 00:45:25 +08:00
fix(pipeline): preserve form callbacks and verify all group response rules
Allow routed Dify form callbacks to resume without another mention or prefix while keeping ordinary messages subject to group response rules. Cover mention, prefix, regex, random probability, and combined rules.
This commit is contained in:
@@ -167,13 +167,118 @@ async def test_routed_group_messages_still_obey_response_rules(mock_app, sample_
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_interaction_submission_does_not_require_another_mention(mock_app, sample_query):
|
||||
@pytest.mark.parametrize('routed', [False, True])
|
||||
@pytest.mark.parametrize(
|
||||
'overrides,text,mention,draw,matches,expected_text',
|
||||
[
|
||||
pytest.param({'regexp': ['^hello$']}, 'hello', False, 0.9, True, 'hello', id='regexp-match'),
|
||||
pytest.param({'regexp': ['^hello$']}, 'bye', False, 0.9, False, 'bye', id='regexp-miss'),
|
||||
pytest.param({'regexp': ['^bye$', '^hello$']}, 'hello', False, 0.9, True, 'hello', id='second-regexp'),
|
||||
pytest.param({'regexp': ['[']}, 'hello', False, 0.9, False, 'hello', id='invalid-regexp'),
|
||||
pytest.param({'random': 0}, 'hello', False, 0.0, False, 'hello', id='random-disabled'),
|
||||
pytest.param({'random': 1}, 'hello', False, 0.999, True, 'hello', id='random-always'),
|
||||
pytest.param({'random': 0.25}, 'hello', False, 0.249, True, 'hello', id='random-hit'),
|
||||
pytest.param({'random': 0.25}, 'hello', False, 0.25, False, 'hello', id='random-boundary'),
|
||||
pytest.param({}, 'hello', True, 0.0, False, 'hello', id='mention-disabled'),
|
||||
pytest.param({}, '!bot hello', False, 0.0, False, '!bot hello', id='prefix-disabled'),
|
||||
pytest.param({'prefix': ['!other ', '!bot ']}, '!bot hello', False, 0.9, True, 'hello', id='second-prefix'),
|
||||
pytest.param(
|
||||
{'at': True, 'prefix': ['!bot '], 'regexp': ['^hello$'], 'random': 0.25},
|
||||
'hello',
|
||||
False,
|
||||
0.9,
|
||||
True,
|
||||
'hello',
|
||||
id='combined-regexp-match',
|
||||
),
|
||||
pytest.param(
|
||||
{'at': True, 'prefix': ['!bot '], 'regexp': ['^bye$'], 'random': 0.25},
|
||||
'hello',
|
||||
False,
|
||||
0.1,
|
||||
True,
|
||||
'hello',
|
||||
id='combined-random-fallback',
|
||||
),
|
||||
pytest.param(
|
||||
{'at': True, 'prefix': ['!bot '], 'regexp': ['^bye$'], 'random': 0.25},
|
||||
'hello',
|
||||
False,
|
||||
0.9,
|
||||
False,
|
||||
'hello',
|
||||
id='combined-all-miss',
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_group_response_rule_configuration(
|
||||
mock_app, sample_query, monkeypatch, routed, overrides, text, mention, draw, matches, expected_text
|
||||
):
|
||||
resprule, entities, _, _ = get_modules()
|
||||
random_rule = import_module('langbot.pkg.pipeline.resprule.rules.random')
|
||||
monkeypatch.setattr(random_rule.random, 'random', lambda: draw)
|
||||
sample_query.launcher_type = provider_session.LauncherTypes.GROUP
|
||||
sample_query.adapter.bot_account_id = '999'
|
||||
sample_query.variables = {'_routed_by_rule': routed}
|
||||
sample_query.pipeline_config = {
|
||||
'trigger': {'group-respond-rules': {'at': False, 'prefix': [], 'regexp': [], 'random': 0, **overrides}}
|
||||
}
|
||||
parts = [platform_message.Plain(text=text)]
|
||||
if mention:
|
||||
parts.insert(0, platform_message.At(target='999'))
|
||||
sample_query.message_chain = platform_message.MessageChain(parts)
|
||||
stage = resprule.GroupRespondRuleCheckStage(mock_app)
|
||||
await stage.initialize(sample_query.pipeline_config)
|
||||
|
||||
result = await stage.process(sample_query, 'GroupRespondRuleCheckStage')
|
||||
|
||||
assert result.result_type == (entities.ResultType.CONTINUE if matches else entities.ResultType.INTERRUPT)
|
||||
assert str(result.new_query.message_chain) == expected_text
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('callback_key', ['_interaction_submission', '_dify_form_action'])
|
||||
async def test_interaction_callbacks_do_not_require_another_mention(mock_app, sample_query, callback_key):
|
||||
resprule, entities, _, _ = get_modules()
|
||||
sample_query.launcher_type = provider_session.LauncherTypes.GROUP
|
||||
sample_query.variables = {'_routed_by_rule': True, '_interaction_submission': {'interaction_id': 'form-1'}}
|
||||
sample_query.adapter.bot_account_id = '999'
|
||||
submission = {'action_id': 'approve'}
|
||||
sample_query.variables = {'_routed_by_rule': True, callback_key: submission}
|
||||
sample_query.message_chain = platform_message.MessageChain([platform_message.Plain(text='[Form Action: Approve]')])
|
||||
sample_query.pipeline_config = {
|
||||
'trigger': {'group-respond-rules': {'at': True, 'prefix': ['!bot '], 'regexp': [], 'random': 0}}
|
||||
}
|
||||
stage = resprule.GroupRespondRuleCheckStage(mock_app)
|
||||
stage.rule_matchers = []
|
||||
await stage.initialize(sample_query.pipeline_config)
|
||||
|
||||
result = await stage.process(sample_query, 'GroupRespondRuleCheckStage')
|
||||
|
||||
assert result.result_type == entities.ResultType.CONTINUE
|
||||
assert str(result.new_query.message_chain) == '[Form Action: Approve]'
|
||||
assert result.new_query.variables[callback_key] == submission
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
'variables',
|
||||
[
|
||||
{'_routed_by_rule': True, '_dify_form_action': None},
|
||||
{'_routed_by_rule': True, '_dify_form_action': {}},
|
||||
{'_routed_by_rule': False, '_dify_form_action': {'action_id': 'approve'}},
|
||||
],
|
||||
)
|
||||
async def test_incomplete_form_callback_does_not_bypass_response_rules(mock_app, sample_query, variables):
|
||||
resprule, entities, _, _ = get_modules()
|
||||
sample_query.launcher_type = provider_session.LauncherTypes.GROUP
|
||||
sample_query.adapter.bot_account_id = '999'
|
||||
sample_query.variables = variables
|
||||
sample_query.message_chain = platform_message.MessageChain([platform_message.Plain(text='[Form Action: Approve]')])
|
||||
sample_query.pipeline_config = {
|
||||
'trigger': {'group-respond-rules': {'at': True, 'prefix': ['!bot '], 'regexp': [], 'random': 0}}
|
||||
}
|
||||
stage = resprule.GroupRespondRuleCheckStage(mock_app)
|
||||
await stage.initialize(sample_query.pipeline_config)
|
||||
|
||||
result = await stage.process(sample_query, 'GroupRespondRuleCheckStage')
|
||||
|
||||
assert result.result_type == entities.ResultType.INTERRUPT
|
||||
|
||||
Reference in New Issue
Block a user