fix(agent): enable reliable cross-platform card interactions

This commit is contained in:
fdc310
2026-10-27 16:03:11 +08:00
parent 71b5b70633
commit de565d0bcc
11 changed files with 271 additions and 39 deletions
@@ -191,26 +191,27 @@ def test_qqofficial_interaction_keyboard_contains_only_host_token_and_index():
@pytest.mark.asyncio
async def test_qqofficial_interaction_delivery_and_callback_event():
adapter = make_adapter()
result = await adapter.call_platform_api(
'interaction.request',
{
'callback_token': 'callback-token',
'reply_target': {
'target_type': 'group',
'target_id': 'group-openid',
'message_id': 'msg-1',
},
'request': {
'interaction_id': 'form-1',
'title': 'Approve?',
'actions': [{'id': 'approve', 'label': 'Approve'}],
'fallback_text': 'Reply approve.',
},
params = {
'callback_token': 'callback-token',
'reply_target': {
'target_type': 'group',
'target_id': 'group-openid',
'message_id': 'msg-1',
},
)
'request': {
'interaction_id': 'form-1',
'title': 'Approve?',
'actions': [{'id': 'approve', 'label': 'Approve'}],
'fallback_text': 'Reply approve.',
},
}
result = await adapter.call_platform_api('interaction.request', params)
await adapter.call_platform_api('interaction.request', params)
assert result == {'ok': True, 'message_id': 'keyboard-message', 'rich': True}
assert adapter.bot.send_markdown_keyboard.await_args.kwargs['msg_id'] == 'msg-1'
calls = adapter.bot.send_markdown_keyboard.await_args_list
assert [call.kwargs['msg_id'] for call in calls] == ['msg-1', 'msg-1']
assert [call.kwargs['msg_seq'] for call in calls] == [1, 2]
event = interaction_event_from_payload(
{
@@ -226,6 +227,34 @@ async def test_qqofficial_interaction_delivery_and_callback_event():
assert event.data['actor_id'] == 'user-openid'
@pytest.mark.asyncio
async def test_qqofficial_interaction_omits_synthetic_negative_message_id():
adapter = make_adapter()
await adapter.call_platform_api(
'interaction.request',
{
'callback_token': 'callback-token',
'reply_target': {
'target_type': 'person',
'target_id': 'user-openid',
'message_id': -1,
},
'request': {
'interaction_id': 'form-1',
'title': 'Approve?',
'actions': [{'id': 'approve', 'label': 'Approve'}],
'fallback_text': 'Reply approve.',
},
},
)
call = adapter.bot.send_markdown_keyboard.await_args
assert call.kwargs['msg_id'] is None
assert call.kwargs['event_id'] is None
assert call.kwargs['msg_seq'] == 1
@pytest.mark.asyncio
async def test_qqofficial_message_converter_maps_common_components_to_send_payloads():
payload = await QQOfficialMessageConverter.yiri2target(
@@ -605,6 +605,19 @@ class TestInteractionResumeRouting:
assert submission['action_ref'] == 1
assert submission['interaction_id'] is None
@pytest.mark.asyncio
async def test_replayed_callback_is_an_idempotent_noop(self):
from langbot.pkg.agent.runner.interaction_store import InteractionAlreadySubmittedError
bot = self._make_bot(self._record('pipeline'))
manager = bot.ap.agent_run_orchestrator.interaction_manager
manager.consume_callback.side_effect = InteractionAlreadySubmittedError('Interaction was already submitted')
await bot._handle_interaction_submission(self._event(), SimpleNamespace())
manager.acknowledge_submission.assert_not_awaited()
bot.ap.msg_aggregator.add_message.assert_not_awaited()
@pytest.mark.asyncio
async def test_pipeline_callback_rejects_changed_runner(self):
bot = self._make_bot(self._record('pipeline'))