mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-15 00:46:07 +00:00
0cde4c71cd
- Added support for select fields in Telegram adapter, including option extraction and callback handling. - Implemented form action processing for Telegram callbacks, improving user interaction feedback. - Introduced new helper functions for building keyboards and resolving select button actions in QQ Official adapter. - Enhanced DifyServiceAPIRunner to handle cumulative streaming responses and improve error handling during workflow resumes. - Added unit tests for new functionalities in Telegram and QQ Official adapters, ensuring robust behavior for select fields and form actions.
118 lines
3.9 KiB
Python
118 lines
3.9 KiB
Python
"""Tests for QQ Official keyboard payload helpers."""
|
|
|
|
import asyncio
|
|
import time
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from langbot.libs.qq_official_api.api import (
|
|
QQ_SELECT_ACTION_PREFIX,
|
|
build_keyboard_from_select_field,
|
|
get_select_field_options,
|
|
resolve_select_button_action,
|
|
)
|
|
|
|
|
|
def _select_form_data() -> dict:
|
|
return {
|
|
'_current_input_field': 'choice',
|
|
'input_defs': [
|
|
{
|
|
'output_variable_name': 'choice',
|
|
'type': 'select',
|
|
'option_source': {'type': 'constant', 'value': ['A', 'B', 'C']},
|
|
}
|
|
],
|
|
}
|
|
|
|
|
|
def test_qq_select_field_builds_callback_buttons():
|
|
keyboard = build_keyboard_from_select_field(_select_form_data(), buttons_per_row=2)
|
|
|
|
rows = keyboard['content']['rows']
|
|
assert [[button['render_data']['label'] for button in row['buttons']] for row in rows] == [
|
|
['A', 'B'],
|
|
['C'],
|
|
]
|
|
assert rows[0]['buttons'][0]['action']['data'] == f'{QQ_SELECT_ACTION_PREFIX}0'
|
|
assert rows[0]['buttons'][1]['action']['data'] == f'{QQ_SELECT_ACTION_PREFIX}1'
|
|
|
|
|
|
def test_qq_select_button_resolves_field_and_value():
|
|
form_data = _select_form_data()
|
|
|
|
assert get_select_field_options(form_data) == ('choice', ['A', 'B', 'C'])
|
|
assert resolve_select_button_action(form_data, f'{QQ_SELECT_ACTION_PREFIX}1') == ('choice', 'B')
|
|
assert resolve_select_button_action(form_data, f'{QQ_SELECT_ACTION_PREFIX}99') is None
|
|
|
|
|
|
def test_qq_select_keyboard_fits_twenty_five_options():
|
|
form_data = _select_form_data()
|
|
form_data['input_defs'][0]['option_source']['value'] = [f'Option {idx}' for idx in range(25)]
|
|
|
|
rows = build_keyboard_from_select_field(form_data)['content']['rows']
|
|
|
|
assert len(rows) == 5
|
|
assert all(len(row['buttons']) == 5 for row in rows)
|
|
|
|
|
|
def test_qq_non_select_field_does_not_build_keyboard():
|
|
form_data = {
|
|
'_current_input_field': 'comment',
|
|
'input_defs': [{'output_variable_name': 'comment', 'type': 'paragraph'}],
|
|
}
|
|
|
|
assert build_keyboard_from_select_field(form_data)['content']['rows'] == []
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_qq_select_click_enqueues_input_progress_query():
|
|
import langbot.pkg.core.app # noqa: F401
|
|
from langbot.pkg.platform.sources.qqofficial import QQOfficialAdapter
|
|
|
|
adapter = QQOfficialAdapter.model_construct()
|
|
adapter.logger = AsyncMock()
|
|
adapter.bot = MagicMock()
|
|
adapter.bot.ack_interaction = AsyncMock()
|
|
adapter.ap = MagicMock()
|
|
adapter.ap.platform_mgr.bots = []
|
|
adapter.ap.query_pool.add_query = AsyncMock()
|
|
adapter._pending_forms = {
|
|
'group_group-1': {
|
|
'form_data': {
|
|
**_select_form_data(),
|
|
'form_token': 'token-1',
|
|
'workflow_run_id': 'run-1',
|
|
'node_title': 'Review',
|
|
'actions': [{'id': 'approve', 'title': 'Approve'}],
|
|
},
|
|
'sender_id': 'initiator-1',
|
|
'posted_at': time.time(),
|
|
}
|
|
}
|
|
adapter._session_event_ids = {}
|
|
adapter._anchor_msg_seq = {}
|
|
|
|
await adapter._handle_interaction_create(
|
|
{
|
|
'id': 'interaction-1',
|
|
'chat_type': 1,
|
|
'group_openid': 'group-1',
|
|
'member_openid': 'reviewer-2',
|
|
'data': {'resolved': {'button_data': f'{QQ_SELECT_ACTION_PREFIX}1'}},
|
|
},
|
|
ws_event_id='event-1',
|
|
)
|
|
await asyncio.sleep(0)
|
|
|
|
call = adapter.ap.query_pool.add_query.await_args
|
|
form_action = call.kwargs['variables']['_dify_form_action']
|
|
assert call.kwargs['launcher_id'] == 'group-1'
|
|
assert call.kwargs['sender_id'] == 'reviewer-2'
|
|
assert form_action['action_id'] == ''
|
|
assert form_action['inputs'] == {'select': 'B'}
|
|
assert form_action['_current_input_field'] == 'choice'
|
|
assert form_action['_input_progress'] is True
|
|
adapter.bot.ack_interaction.assert_awaited_once_with('interaction-1', code=0)
|