mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-24 01:15:24 +08:00
fix: bot routing setup and busy-session response checks (#2728)
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]>
This commit is contained in:
co-authored by
multica-agent
parent
f8e32ef14f
commit
d13ae56ea5
@@ -232,3 +232,35 @@ class BotsRouterGroup(group.RouterGroup):
|
||||
async def _(bot_uuid: str, admin_id: int, request_context: RequestContext) -> str:
|
||||
await self.ap.bot_service.delete_bot_admin(request_context, bot_uuid, admin_id)
|
||||
return self.success()
|
||||
|
||||
@self.route(
|
||||
'/<bot_uuid>/group-filter-migration',
|
||||
methods=['GET'],
|
||||
auth_type=group.AuthType.USER_TOKEN_OR_API_KEY,
|
||||
permission=Permission.RESOURCE_VIEW,
|
||||
)
|
||||
async def _(bot_uuid: str, request_context: RequestContext) -> str:
|
||||
try:
|
||||
result = await self.ap.bot_service.preview_group_filter_migration(request_context, bot_uuid)
|
||||
except ValueError as exc:
|
||||
return self.http_status(400, -1, str(exc))
|
||||
return self.success(data=result)
|
||||
|
||||
@self.route(
|
||||
'/<bot_uuid>/group-filter-migration',
|
||||
methods=['POST'],
|
||||
auth_type=group.AuthType.USER_TOKEN_OR_API_KEY,
|
||||
permission=Permission.RESOURCE_MANAGE,
|
||||
)
|
||||
async def _(bot_uuid: str, request_context: RequestContext) -> str:
|
||||
json_data = await quart.request.get_json(silent=True) or {}
|
||||
disable_pipeline_at_bot = bool(json_data.get('disable_pipeline_at_bot', True))
|
||||
try:
|
||||
result = await self.ap.bot_service.apply_group_filter_migration(
|
||||
request_context, bot_uuid, disable_pipeline_at_bot=disable_pipeline_at_bot
|
||||
)
|
||||
except BotApplyError as exc:
|
||||
return self._apply_error_response(exc)
|
||||
except ValueError as exc:
|
||||
return self.http_status(400, -1, str(exc))
|
||||
return self.success(data=result)
|
||||
|
||||
@@ -437,7 +437,6 @@ class AgentService:
|
||||
'name': agent_data.get('name') or t('New Pipeline'),
|
||||
'description': agent_data.get('description') or '',
|
||||
'emoji': agent_data.get('emoji') or '⚙️',
|
||||
'config': {},
|
||||
},
|
||||
)
|
||||
return {'uuid': pipeline_uuid, 'kind': AGENT_KIND_PIPELINE}
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import uuid
|
||||
import typing
|
||||
import json
|
||||
import asyncio
|
||||
import sqlalchemy
|
||||
|
||||
from ....core import app
|
||||
@@ -18,6 +19,7 @@ from ....platform.sources import http_bot_signing
|
||||
from ....platform.adapter_names import canonical_adapter_name
|
||||
from ....cloud.plan_policy import require_workspace_platform
|
||||
from ....agent.runner.errors import RunnerNotFoundError
|
||||
from ....i18n import t
|
||||
|
||||
|
||||
class BotService:
|
||||
@@ -43,6 +45,7 @@ class BotService:
|
||||
|
||||
def __init__(self, ap: app.Application) -> None:
|
||||
self.ap = ap
|
||||
self._default_pipeline_lock = asyncio.Lock()
|
||||
|
||||
def _get_adapter_component(self, adapter_name: str) -> engine.Component | None:
|
||||
"""Return the discovered platform adapter component for an adapter name."""
|
||||
@@ -202,6 +205,22 @@ class BotService:
|
||||
'diagnostic_details': diagnostic_steps or [],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _extract_dry_run_bot_account_id(
|
||||
context: typing.Any,
|
||||
event_data: typing.Any,
|
||||
) -> str | None:
|
||||
"""Extract bot_account_id from dry-run context for is_at_bot filter support."""
|
||||
if isinstance(context, dict):
|
||||
val = context.get('bot_account_id')
|
||||
if val is not None:
|
||||
return str(val)
|
||||
if isinstance(event_data, dict):
|
||||
val = event_data.get('bot_account_id')
|
||||
if val is not None:
|
||||
return str(val)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _build_dry_run_event(event_type: str, event_data: typing.Any, context: typing.Any) -> dict[str, typing.Any]:
|
||||
event: dict[str, typing.Any] = {}
|
||||
@@ -354,6 +373,7 @@ class BotService:
|
||||
bindings,
|
||||
event,
|
||||
event_type,
|
||||
bot_account_id=self._extract_dry_run_bot_account_id(context, event_data),
|
||||
)
|
||||
if selected_binding is None:
|
||||
return self._diagnostic_result(
|
||||
@@ -490,6 +510,60 @@ class BotService:
|
||||
],
|
||||
)
|
||||
|
||||
async def _build_default_event_bindings(self, context: TenantContext) -> list[dict]:
|
||||
"""Build the default event bindings for a new bot.
|
||||
|
||||
Two bindings route message.received to the first available pipeline:
|
||||
- private chat: always respond
|
||||
- group chat: require an @mention of the bot (is_at_bot=true)
|
||||
|
||||
The group @mention check runs at the routing layer, so messages that
|
||||
do not match never create a pipeline task. Existing bots keep their
|
||||
current bindings; this only applies to bots created without any.
|
||||
"""
|
||||
# Serialize first-bot setup without retaining an unbounded lock per Workspace.
|
||||
async with self._default_pipeline_lock:
|
||||
pipelines = await self.ap.pipeline_service.get_pipelines(context)
|
||||
if pipelines:
|
||||
selected = next((item for item in pipelines if item.get('is_default')), pipelines[0])
|
||||
pipeline_uuid = selected.get('uuid')
|
||||
else:
|
||||
pipeline_uuid = await self.ap.pipeline_service.create_pipeline(
|
||||
context, {'name': t('New Pipeline'), 'description': '', 'emoji': '⚙️'}, default=True
|
||||
)
|
||||
if not pipeline_uuid:
|
||||
return []
|
||||
|
||||
return [
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'event_pattern': 'message.received',
|
||||
'target_type': 'pipeline',
|
||||
'target_uuid': pipeline_uuid,
|
||||
'filters': [
|
||||
{'field': 'chat_type', 'operator': 'eq', 'value': 'person'},
|
||||
],
|
||||
'priority': 0,
|
||||
'enabled': True,
|
||||
'description': 'Private chat: respond directly',
|
||||
'order': 0,
|
||||
},
|
||||
{
|
||||
'id': str(uuid.uuid4()),
|
||||
'event_pattern': 'message.received',
|
||||
'target_type': 'pipeline',
|
||||
'target_uuid': pipeline_uuid,
|
||||
'filters': [
|
||||
{'field': 'chat_type', 'operator': 'eq', 'value': 'group'},
|
||||
{'field': 'is_at_bot', 'operator': 'eq', 'value': True},
|
||||
],
|
||||
'priority': 0,
|
||||
'enabled': True,
|
||||
'description': 'Group chat: respond only when the bot is @mentioned',
|
||||
'order': 1,
|
||||
},
|
||||
]
|
||||
|
||||
async def _normalize_event_bindings(self, context: TenantContext, bindings: list[dict] | None) -> list[dict]:
|
||||
"""Validate and normalize Bot event bindings."""
|
||||
if not bindings:
|
||||
@@ -700,7 +774,10 @@ class BotService:
|
||||
await require_workspace_platform(self.ap, workspace_uuid, bot_data['adapter'])
|
||||
bot_data['uuid'] = str(uuid.uuid4())
|
||||
bot_data['workspace_uuid'] = workspace_uuid
|
||||
bot_data.setdefault('event_bindings', [])
|
||||
if not bot_data.get('event_bindings'):
|
||||
bot_data['event_bindings'] = await self._build_default_event_bindings(context)
|
||||
else:
|
||||
bot_data['event_bindings'] = await self._normalize_event_bindings(context, bot_data['event_bindings'])
|
||||
bot_data.setdefault('plugin_processors', [])
|
||||
|
||||
await self.ap.persistence_mgr.execute_async(sqlalchemy.insert(persistence_bot.Bot).values(bot_data))
|
||||
@@ -860,6 +937,169 @@ class BotService:
|
||||
'stale_routes': stale_routes,
|
||||
}
|
||||
|
||||
async def preview_group_filter_migration(self, context: TenantContext, bot_uuid: str) -> dict[str, typing.Any]:
|
||||
"""Preview the effect of promoting the pipeline at-bot rule to a routing-layer filter.
|
||||
|
||||
Detects bots whose pipeline trigger still requires at-bot, and whose event
|
||||
bindings do not already filter group messages by is_at_bot. Returns the
|
||||
proposed binding changes plus a per-pipeline summary. Does not persist.
|
||||
"""
|
||||
from ....platform.botmgr import RuntimeBot
|
||||
|
||||
bot = await self.get_bot(context, bot_uuid, include_secret=False)
|
||||
if bot is None:
|
||||
raise WorkspaceNotFoundError('Bot not found')
|
||||
|
||||
bindings = RuntimeBot._get_event_bindings_from_value(bot.get('event_bindings') or [])
|
||||
pipeline_uuids = {
|
||||
str(b.get('target_uuid')) for b in bindings if b.get('target_type') == 'pipeline' and b.get('target_uuid')
|
||||
}
|
||||
|
||||
# Load each pipeline's trigger config to detect at-bot still enabled.
|
||||
pipeline_flags: dict[str, dict[str, typing.Any]] = {}
|
||||
for pipeline_uuid in pipeline_uuids:
|
||||
pipeline = await self.ap.pipeline_service.get_pipeline(context, pipeline_uuid)
|
||||
trigger = (pipeline or {}).get('config', {}).get('trigger', {}) if pipeline else {}
|
||||
group_rules = trigger.get('group-respond-rules', {}) if isinstance(trigger, dict) else {}
|
||||
pipeline_flags[pipeline_uuid] = {
|
||||
'at_bot_enabled': bool(group_rules.get('at')) if isinstance(group_rules, dict) else False,
|
||||
'prefix': group_rules.get('prefix', []) if isinstance(group_rules, dict) else [],
|
||||
'regexp': group_rules.get('regexp', []) if isinstance(group_rules, dict) else [],
|
||||
'random': group_rules.get('random', 0.0) if isinstance(group_rules, dict) else 0.0,
|
||||
}
|
||||
|
||||
# A binding "already has the at-bot filter" if it filters chat_type=group
|
||||
# AND requires is_at_bot=true (or non-false).
|
||||
def _has_group_at_filter(binding: dict) -> bool:
|
||||
filters = binding.get('filters') or []
|
||||
if not isinstance(filters, list):
|
||||
return False
|
||||
has_group = any(
|
||||
isinstance(f, dict)
|
||||
and f.get('field') == 'chat_type'
|
||||
and f.get('operator', 'eq') == 'eq'
|
||||
and f.get('value') == 'group'
|
||||
for f in filters
|
||||
)
|
||||
has_at = any(
|
||||
isinstance(f, dict)
|
||||
and f.get('field') == 'is_at_bot'
|
||||
and f.get('operator', 'eq') == 'eq'
|
||||
and f.get('value') is True
|
||||
for f in filters
|
||||
)
|
||||
return has_group and has_at
|
||||
|
||||
needs_migration = [pipeline_uuid for pipeline_uuid, flags in pipeline_flags.items() if flags['at_bot_enabled']]
|
||||
bindings_with_at_filter = [b for b in bindings if _has_group_at_filter(b)]
|
||||
bindings_missing_at_filter = [
|
||||
b
|
||||
for b in bindings
|
||||
if b.get('target_type') == 'pipeline'
|
||||
and str(b.get('target_uuid') or '') in needs_migration
|
||||
and not _has_group_at_filter(b)
|
||||
]
|
||||
|
||||
proposed_bindings: list[dict[str, typing.Any]] = []
|
||||
for binding in bindings_missing_at_filter:
|
||||
new_binding = json.loads(json.dumps(binding))
|
||||
filters = list(new_binding.get('filters') or [])
|
||||
if not any(
|
||||
isinstance(f, dict) and f.get('field') == 'chat_type' and f.get('value') == 'group' for f in filters
|
||||
):
|
||||
filters.append({'field': 'chat_type', 'operator': 'eq', 'value': 'group'})
|
||||
if not any(isinstance(f, dict) and f.get('field') == 'is_at_bot' for f in filters):
|
||||
filters.append({'field': 'is_at_bot', 'operator': 'eq', 'value': True})
|
||||
new_binding['filters'] = filters
|
||||
proposed_bindings.append(new_binding)
|
||||
|
||||
return {
|
||||
'bot_uuid': bot_uuid,
|
||||
'needs_migration': bool(bindings_missing_at_filter),
|
||||
'pipelines_with_at_bot': sorted(needs_migration),
|
||||
'pipeline_flags': pipeline_flags,
|
||||
'bindings_already_filtered': [b.get('id') for b in bindings_with_at_filter],
|
||||
'bindings_to_update': [
|
||||
{
|
||||
'binding_id': b.get('id'),
|
||||
'event_pattern': b.get('event_pattern'),
|
||||
'target_type': b.get('target_type'),
|
||||
'target_uuid': b.get('target_uuid'),
|
||||
'current_filters': b.get('filters') or [],
|
||||
'proposed_filters': next(
|
||||
(p.get('filters') for p in proposed_bindings if p.get('id') == b.get('id')),
|
||||
b.get('filters') or [],
|
||||
),
|
||||
}
|
||||
for b in bindings_missing_at_filter
|
||||
],
|
||||
}
|
||||
|
||||
async def apply_group_filter_migration(
|
||||
self,
|
||||
context: TenantContext,
|
||||
bot_uuid: str,
|
||||
*,
|
||||
disable_pipeline_at_bot: bool = True,
|
||||
) -> dict[str, typing.Any]:
|
||||
"""Apply the group filter migration previewed by preview_group_filter_migration.
|
||||
|
||||
Updates the bot's event_bindings to add is_at_bot=true filter on group
|
||||
bindings whose pipeline still has at-bot enabled. Optionally disables the
|
||||
pipeline's at-bot trigger rule so the filter is not checked twice. Existing
|
||||
prefix/regexp/random rules remain untouched. Idempotent.
|
||||
"""
|
||||
from ....platform.botmgr import RuntimeBot
|
||||
|
||||
preview = await self.preview_group_filter_migration(context, bot_uuid)
|
||||
if not preview['needs_migration']:
|
||||
return {'bot_uuid': bot_uuid, 'applied': False, 'reason': 'no_migration_needed'}
|
||||
|
||||
bot = await self.get_bot(context, bot_uuid, include_secret=False)
|
||||
if bot is None:
|
||||
raise WorkspaceNotFoundError('Bot not found')
|
||||
|
||||
bindings = RuntimeBot._get_event_bindings_from_value(bot.get('event_bindings') or [])
|
||||
bindings_by_id = {b.get('id'): b for b in bindings if b.get('id')}
|
||||
for item in preview['bindings_to_update']:
|
||||
binding_id = item['binding_id']
|
||||
existing = bindings_by_id.get(binding_id)
|
||||
if existing is None:
|
||||
continue
|
||||
existing['filters'] = item['proposed_filters']
|
||||
|
||||
update_payload = {
|
||||
'event_bindings': await self._normalize_event_bindings(context, bindings),
|
||||
}
|
||||
await self.update_bot(context, bot_uuid, update_payload)
|
||||
|
||||
updated_pipelines: list[str] = []
|
||||
if disable_pipeline_at_bot:
|
||||
for pipeline_uuid in preview['pipelines_with_at_bot']:
|
||||
pipeline = await self.ap.pipeline_service.get_pipeline(context, pipeline_uuid, include_secret=True)
|
||||
if not pipeline:
|
||||
continue
|
||||
config = pipeline.get('config') or {}
|
||||
trigger = config.get('trigger') or {}
|
||||
group_rules = trigger.get('group-respond-rules') or {}
|
||||
if not isinstance(group_rules, dict) or not group_rules.get('at'):
|
||||
continue
|
||||
new_config = json.loads(json.dumps(config))
|
||||
new_config.setdefault('trigger', {}).setdefault('group-respond-rules', {})['at'] = False
|
||||
await self.ap.pipeline_service.update_pipeline(
|
||||
context,
|
||||
pipeline_uuid,
|
||||
{'config': new_config},
|
||||
)
|
||||
updated_pipelines.append(pipeline_uuid)
|
||||
|
||||
return {
|
||||
'bot_uuid': bot_uuid,
|
||||
'applied': True,
|
||||
'updated_bindings': [item['binding_id'] for item in preview['bindings_to_update']],
|
||||
'disabled_pipeline_at_bot': updated_pipelines,
|
||||
}
|
||||
|
||||
async def send_http_bot_test_message(
|
||||
self,
|
||||
context: TenantContext,
|
||||
|
||||
@@ -189,7 +189,7 @@ class PipelineService:
|
||||
pipeline_data['stages'] = default_stage_order.copy()
|
||||
pipeline_data['is_default'] = default
|
||||
|
||||
if 'config' not in pipeline_data:
|
||||
if 'config' not in pipeline_data or pipeline_data['config'] == {}:
|
||||
pipeline_data['config'] = await self.get_default_pipeline_config(context)
|
||||
RunnerConfigResolver.validate_pipeline_config(pipeline_data['config'])
|
||||
|
||||
|
||||
@@ -387,6 +387,35 @@ class LangBotMCPServer:
|
||||
async def list_bot_event_route_statuses(bot_uuid: str) -> str:
|
||||
return _dump(await ap.bot_service.list_event_route_statuses(bot_uuid))
|
||||
|
||||
@mcp.tool(
|
||||
description=(
|
||||
'Preview promoting the pipeline at-bot trigger rule to a routing-layer '
|
||||
'is_at_bot filter. Reports which bindings and pipelines need migration '
|
||||
'without persisting changes.'
|
||||
)
|
||||
)
|
||||
async def preview_bot_group_filter_migration(bot_uuid: str) -> str:
|
||||
context = _authorized(Permission.RESOURCE_VIEW)
|
||||
return _dump(await ap.bot_service.preview_group_filter_migration(context, bot_uuid))
|
||||
|
||||
@mcp.tool(
|
||||
description=(
|
||||
'Apply the group filter migration previewed by '
|
||||
'preview_bot_group_filter_migration. Adds is_at_bot=true filter to group '
|
||||
'message bindings and, when disable_pipeline_at_bot is true (default), '
|
||||
'turns off the pipeline trigger at-bot rule. Idempotent.'
|
||||
)
|
||||
)
|
||||
async def apply_bot_group_filter_migration(bot_uuid: str, disable_pipeline_at_bot: bool = True) -> str:
|
||||
context = _authorized(Permission.RESOURCE_MANAGE)
|
||||
return _dump(
|
||||
await ap.bot_service.apply_group_filter_migration(
|
||||
context,
|
||||
bot_uuid,
|
||||
disable_pipeline_at_bot=disable_pipeline_at_bot,
|
||||
)
|
||||
)
|
||||
|
||||
# ----- Pipelines ----------------------------------------------- #
|
||||
@mcp.tool(description='List all pipelines.')
|
||||
async def list_pipelines() -> str:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import copy
|
||||
import traceback
|
||||
|
||||
from ..core import app
|
||||
@@ -59,6 +60,22 @@ class Controller:
|
||||
query.pipeline_config = pipeline.pipeline_entity.config
|
||||
query.variables['_pipeline_bound_plugins'] = pipeline.bound_plugins
|
||||
query.variables['_pipeline_bound_mcp_servers'] = pipeline.bound_mcp_servers
|
||||
if getattr(getattr(query, 'launcher_type', None), 'value', None) == 'group':
|
||||
from .resprule.resprule import GroupRespondRuleCheckStage
|
||||
from .entities import ResultType
|
||||
|
||||
candidate = copy.copy(query)
|
||||
candidate.message_chain = query.message_chain.model_copy(deep=True)
|
||||
candidate.variables = dict(query.variables)
|
||||
gate = GroupRespondRuleCheckStage(self.ap)
|
||||
await gate.initialize(query.pipeline_config)
|
||||
result = await gate.process(candidate, 'GroupRespondRuleCheckStage')
|
||||
random_key = '_group_response_random_draw'
|
||||
if random_key in candidate.variables:
|
||||
query.variables[random_key] = candidate.variables[random_key]
|
||||
if result.result_type == ResultType.INTERRUPT:
|
||||
return False
|
||||
query = candidate
|
||||
return await self.ap.agent_run_orchestrator.try_claim_steering_from_query(query)
|
||||
except Exception as exc:
|
||||
self.ap.logger.warning(
|
||||
|
||||
@@ -18,4 +18,7 @@ class RandomRespRule(rule_model.GroupRespondRule):
|
||||
) -> entities.RuleJudgeResult:
|
||||
random_rate = rule_dict['random']
|
||||
|
||||
return entities.RuleJudgeResult(matching=random.random() < random_rate, replacement=message_chain)
|
||||
key = '_group_response_random_draw'
|
||||
if key not in query.variables:
|
||||
query.variables[key] = random.random()
|
||||
return entities.RuleJudgeResult(matching=query.variables[key] < random_rate, replacement=message_chain)
|
||||
|
||||
@@ -229,6 +229,7 @@ class RuntimeBot:
|
||||
def _augment_event_data(
|
||||
cls,
|
||||
event_data: dict[str, typing.Any],
|
||||
bot_account_id: str | None = None,
|
||||
) -> dict[str, typing.Any]:
|
||||
"""Inject virtual computed fields to simplify common filter patterns."""
|
||||
message_chain = event_data.get('message_chain')
|
||||
@@ -240,6 +241,13 @@ class RuntimeBot:
|
||||
event_data['message_element_types'] = [
|
||||
comp.get('type', '') for comp in message_chain if isinstance(comp, dict)
|
||||
]
|
||||
if bot_account_id:
|
||||
event_data['is_at_bot'] = any(
|
||||
isinstance(comp, dict)
|
||||
and comp.get('type') == 'At'
|
||||
and str(comp.get('target', '')) == str(bot_account_id)
|
||||
for comp in message_chain
|
||||
)
|
||||
if 'group' in event_data:
|
||||
event_data['chat_type'] = 'group' if event_data.get('group') is not None else 'person'
|
||||
return event_data
|
||||
@@ -249,13 +257,14 @@ class RuntimeBot:
|
||||
cls,
|
||||
event: platform_events.EBAEvent,
|
||||
filters: typing.Any,
|
||||
bot_account_id: str | None = None,
|
||||
) -> bool:
|
||||
if not filters:
|
||||
return True
|
||||
if not isinstance(filters, list):
|
||||
return False
|
||||
|
||||
event_data = cls._augment_event_data(cls._safe_model_dump(event))
|
||||
event_data = cls._augment_event_data(cls._safe_model_dump(event), bot_account_id=bot_account_id)
|
||||
return all(
|
||||
cls._match_event_filter(event_data, event_filter)
|
||||
for event_filter in filters
|
||||
@@ -283,6 +292,7 @@ class RuntimeBot:
|
||||
bindings: list[dict[str, typing.Any]],
|
||||
event: platform_events.EBAEvent,
|
||||
event_type: str,
|
||||
bot_account_id: str | None = None,
|
||||
) -> tuple[dict[str, typing.Any] | None, list[dict[str, typing.Any]]]:
|
||||
"""Evaluate Bot event bindings with the same precedence used at runtime."""
|
||||
matched: list[tuple[int, int, dict[str, typing.Any], dict[str, typing.Any]]] = []
|
||||
@@ -325,7 +335,7 @@ class RuntimeBot:
|
||||
diagnostic_steps.append(step)
|
||||
continue
|
||||
|
||||
if not cls._match_event_filters(event, binding.get('filters')):
|
||||
if not cls._match_event_filters(event, binding.get('filters'), bot_account_id=bot_account_id):
|
||||
step['failure_code'] = 'filters_mismatch'
|
||||
step['reason'] = 'Event data does not satisfy binding filters'
|
||||
diagnostic_steps.append(step)
|
||||
@@ -356,7 +366,10 @@ class RuntimeBot:
|
||||
event_type: str,
|
||||
) -> dict[str, typing.Any] | None:
|
||||
"""Resolve the highest priority Bot event binding for a platform event."""
|
||||
selected, _ = self._evaluate_eba_event_bindings(self._get_event_bindings(), event, event_type)
|
||||
bot_account_id = getattr(getattr(self, 'adapter', None), 'bot_account_id', None) or None
|
||||
selected, _ = self._evaluate_eba_event_bindings(
|
||||
self._get_event_bindings(), event, event_type, bot_account_id=bot_account_id
|
||||
)
|
||||
return selected
|
||||
|
||||
def diagnose_eba_event_binding(
|
||||
@@ -365,7 +378,10 @@ class RuntimeBot:
|
||||
event_type: str,
|
||||
) -> tuple[dict[str, typing.Any] | None, list[dict[str, typing.Any]]]:
|
||||
"""Return the selected event binding plus per-binding diagnostic steps."""
|
||||
return self._evaluate_eba_event_bindings(self._get_event_bindings(), event, event_type)
|
||||
bot_account_id = getattr(getattr(self, 'adapter', None), 'bot_account_id', None) or None
|
||||
return self._evaluate_eba_event_bindings(
|
||||
self._get_event_bindings(), event, event_type, bot_account_id=bot_account_id
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _route_ref(
|
||||
|
||||
Reference in New Issue
Block a user