refactor: consolidate bot event routing

This commit is contained in:
Junyan Qin
2026-07-01 21:04:21 +08:00
committed by huanghuoguoguo
parent 662627142e
commit 7fb393b85b
26 changed files with 408 additions and 365 deletions
@@ -3,7 +3,7 @@
All user-facing URLs are keyed by **bot_uuid** (not pipeline_uuid) so that All user-facing URLs are keyed by **bot_uuid** (not pipeline_uuid) so that
internal pipeline identifiers are never exposed to end-users. Each handler internal pipeline identifiers are never exposed to end-users. Each handler
resolves the bot_uuid to the owning ``web_page_bot`` RuntimeBot and extracts resolves the bot_uuid to the owning ``web_page_bot`` RuntimeBot and extracts
the bound pipeline_uuid for internal routing. the message event route's Pipeline target for internal routing.
""" """
import asyncio import asyncio
@@ -62,16 +62,17 @@ class EmbedRouterGroup(group.RouterGroup):
"""Resolve *bot_uuid* to ``(runtime_bot, pipeline_uuid)``. """Resolve *bot_uuid* to ``(runtime_bot, pipeline_uuid)``.
Returns ``(None, None)`` when the bot does not exist, is not a Returns ``(None, None)`` when the bot does not exist, is not a
``web_page_bot``, is disabled, or has no pipeline bound. ``web_page_bot``, is disabled, or has no Pipeline target for messages.
""" """
for bot in self.ap.platform_mgr.bots: for bot in self.ap.platform_mgr.bots:
pipeline_uuid = bot.get_pipeline_target_for_event_type('message.received')
if ( if (
bot.bot_entity.uuid == bot_uuid bot.bot_entity.uuid == bot_uuid
and bot.bot_entity.adapter == 'web_page_bot' and bot.bot_entity.adapter == 'web_page_bot'
and bot.bot_entity.enable and bot.bot_entity.enable
and bot.bot_entity.use_pipeline_uuid and pipeline_uuid
): ):
return bot, bot.bot_entity.use_pipeline_uuid return bot, pipeline_uuid
return None, None return None, None
def _get_bot_config(self, bot_uuid: str) -> dict: def _get_bot_config(self, bot_uuid: str) -> dict:
+1 -1
View File
@@ -17,7 +17,7 @@ AGENT_DEFAULT_EVENT_PATTERNS = ['*']
class AgentService: class AgentService:
"""Unified product surface for Agent orchestration instances and Pipelines.""" """Unified product surface for Agent processors and Pipelines."""
ap: app.Application ap: app.Application
+23 -12
View File
@@ -15,6 +15,15 @@ class BotService:
"""Bot service""" """Bot service"""
ap: app.Application ap: app.Application
BOT_FIELDS = {
'uuid',
'name',
'description',
'adapter',
'adapter_config',
'enable',
'event_bindings',
}
def __init__(self, ap: app.Application) -> None: def __init__(self, ap: app.Application) -> None:
self.ap = ap self.ap = ap
@@ -115,6 +124,17 @@ class BotService:
return normalized return normalized
async def _prepare_bot_data(self, bot_data: dict, *, include_uuid: bool) -> dict:
"""Normalize Bot write payloads to the current event-routing model."""
update_data = bot_data.copy()
if not include_uuid:
update_data.pop('uuid', None)
update_data = {key: value for key, value in update_data.items() if key in self.BOT_FIELDS}
if 'event_bindings' in update_data:
update_data['event_bindings'] = await self._normalize_event_bindings(update_data.get('event_bindings'))
return update_data
async def get_bots(self, include_secret: bool = True) -> list[dict]: async def get_bots(self, include_secret: bool = True) -> list[dict]:
"""获取所有机器人""" """获取所有机器人"""
result = await self.ap.persistence_mgr.execute_async(sqlalchemy.select(persistence_bot.Bot)) result = await self.ap.persistence_mgr.execute_async(sqlalchemy.select(persistence_bot.Bot))
@@ -188,7 +208,9 @@ class BotService:
raise ValueError(f'Maximum number of bots ({max_bots}) reached') raise ValueError(f'Maximum number of bots ({max_bots}) reached')
# TODO: 检查配置信息格式 # TODO: 检查配置信息格式
bot_data = await self._prepare_bot_data(bot_data, include_uuid=True)
bot_data['uuid'] = str(uuid.uuid4()) bot_data['uuid'] = str(uuid.uuid4())
bot_data.setdefault('event_bindings', [])
await self.ap.persistence_mgr.execute_async(sqlalchemy.insert(persistence_bot.Bot).values(bot_data)) await self.ap.persistence_mgr.execute_async(sqlalchemy.insert(persistence_bot.Bot).values(bot_data))
@@ -200,18 +222,7 @@ class BotService:
async def update_bot(self, bot_uuid: str, bot_data: dict) -> None: async def update_bot(self, bot_uuid: str, bot_data: dict) -> None:
"""Update bot""" """Update bot"""
update_data = bot_data.copy() update_data = await self._prepare_bot_data(bot_data, include_uuid=False)
if 'uuid' in update_data:
del update_data['uuid']
if 'event_bindings' in update_data:
update_data['event_bindings'] = await self._normalize_event_bindings(update_data.get('event_bindings'))
# clear legacy routing fields — routing is now fully managed via event_bindings
update_data.pop('use_pipeline_uuid', None)
update_data.pop('use_pipeline_name', None)
update_data.pop('pipeline_routing_rules', None)
await self.ap.persistence_mgr.execute_async( await self.ap.persistence_mgr.execute_async(
sqlalchemy.update(persistence_bot.Bot).values(update_data).where(persistence_bot.Bot.uuid == bot_uuid) sqlalchemy.update(persistence_bot.Bot).values(update_data).where(persistence_bot.Bot.uuid == bot_uuid)
@@ -218,19 +218,6 @@ class PipelineService:
pipeline = await self.get_pipeline(pipeline_uuid) pipeline = await self.get_pipeline(pipeline_uuid)
if 'name' in pipeline_data:
from ....entity.persistence import bot as persistence_bot
result = await self.ap.persistence_mgr.execute_async(
sqlalchemy.select(persistence_bot.Bot).where(persistence_bot.Bot.use_pipeline_uuid == pipeline_uuid)
)
bots = result.all()
for bot in bots:
bot_data = {'use_pipeline_name': pipeline_data['name']}
await self.ap.bot_service.update_bot(bot.uuid, bot_data)
await self.ap.pipeline_mgr.remove_pipeline(pipeline_uuid) await self.ap.pipeline_mgr.remove_pipeline(pipeline_uuid)
await self.ap.pipeline_mgr.load_pipeline(pipeline) await self.ap.pipeline_mgr.load_pipeline(pipeline)
+4 -4
View File
@@ -142,7 +142,7 @@ class LangBotMCPServer:
return _dump({'ok': True}) return _dump({'ok': True})
# ----- Agents -------------------------------------------------- # # ----- Agents -------------------------------------------------- #
@mcp.tool(description='List product-level Agents, including Agent orchestrations and Pipelines.') @mcp.tool(description='List product-level processors, including Agents and Pipelines.')
async def list_agents() -> str: async def list_agents() -> str:
return _dump(await ap.agent_service.get_agents()) return _dump(await ap.agent_service.get_agents())
@@ -152,19 +152,19 @@ class LangBotMCPServer:
@mcp.tool( @mcp.tool(
description=( description=(
'Create an Agent orchestration or Pipeline. `agent_data` matches ' 'Create an Agent processor or Pipeline. `agent_data` matches '
'POST /api/v1/agents; set kind to `agent` or `pipeline`. Returns the new UUID and kind.' 'POST /api/v1/agents; set kind to `agent` or `pipeline`. Returns the new UUID and kind.'
) )
) )
async def create_agent(agent_data: dict) -> str: async def create_agent(agent_data: dict) -> str:
return _dump(await ap.agent_service.create_agent(agent_data)) return _dump(await ap.agent_service.create_agent(agent_data))
@mcp.tool(description='Update an Agent orchestration or Pipeline by UUID.') @mcp.tool(description='Update an Agent processor or Pipeline by UUID.')
async def update_agent(agent_uuid: str, agent_data: dict) -> str: async def update_agent(agent_uuid: str, agent_data: dict) -> str:
await ap.agent_service.update_agent(agent_uuid, agent_data) await ap.agent_service.update_agent(agent_uuid, agent_data)
return _dump({'ok': True}) return _dump({'ok': True})
@mcp.tool(description='Delete an Agent orchestration or Pipeline by UUID.') @mcp.tool(description='Delete an Agent processor or Pipeline by UUID.')
async def delete_agent(agent_uuid: str) -> str: async def delete_agent(agent_uuid: str) -> str:
await ap.agent_service.delete_agent(agent_uuid) await ap.agent_service.delete_agent(agent_uuid)
return _dump({'ok': True}) return _dump({'ok': True})
+1 -1
View File
@@ -4,7 +4,7 @@ from .base import Base
class Agent(Base): class Agent(Base):
"""Product-level Agent orchestration instance.""" """Product-level Agent processor."""
__tablename__ = 'agents' __tablename__ = 'agents'
@@ -28,9 +28,6 @@ class Bot(Base):
adapter = sqlalchemy.Column(sqlalchemy.String(255), nullable=False) adapter = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
adapter_config = sqlalchemy.Column(sqlalchemy.JSON, nullable=False) adapter_config = sqlalchemy.Column(sqlalchemy.JSON, nullable=False)
enable = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False) enable = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False)
use_pipeline_name = sqlalchemy.Column(sqlalchemy.String(255), nullable=True)
use_pipeline_uuid = sqlalchemy.Column(sqlalchemy.String(255), nullable=True)
pipeline_routing_rules = sqlalchemy.Column(sqlalchemy.JSON, nullable=False, server_default='[]')
event_bindings = sqlalchemy.Column(sqlalchemy.JSON, nullable=False, server_default='[]') event_bindings = sqlalchemy.Column(sqlalchemy.JSON, nullable=False, server_default='[]')
created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now()) created_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, server_default=sqlalchemy.func.now())
updated_at = sqlalchemy.Column( updated_at = sqlalchemy.Column(
@@ -16,6 +16,16 @@ down_revision = '0008_agent_product_surface'
depends_on = None depends_on = None
def _table_exists(table_name: str) -> bool:
return table_name in sa.inspect(op.get_bind()).get_table_names()
def _column_exists(table_name: str, column_name: str) -> bool:
if not _table_exists(table_name):
return False
return column_name in {column['name'] for column in sa.inspect(op.get_bind()).get_columns(table_name)}
def _rule_to_filters(rule: dict) -> list[dict] | None: def _rule_to_filters(rule: dict) -> list[dict] | None:
"""Convert a pipeline_routing_rule to event_binding filters (best effort). """Convert a pipeline_routing_rule to event_binding filters (best effort).
@@ -38,6 +48,11 @@ def _rule_to_filters(rule: dict) -> list[dict] | None:
def upgrade() -> None: def upgrade() -> None:
if not _table_exists('bots') or not _column_exists('bots', 'event_bindings'):
return
if not _column_exists('bots', 'use_pipeline_uuid') or not _column_exists('bots', 'pipeline_routing_rules'):
return
bind = op.get_bind() bind = op.get_bind()
rows = bind.execute( rows = bind.execute(
sa.text('SELECT uuid, use_pipeline_uuid, pipeline_routing_rules, event_bindings FROM bots') sa.text('SELECT uuid, use_pipeline_uuid, pipeline_routing_rules, event_bindings FROM bots')
@@ -0,0 +1,55 @@
"""drop legacy bot pipeline routing columns
Revision ID: 0011_drop_legacy_bot_routing
Revises: 0010_merge_mcp_resource_agent_heads
Create Date: 2026-07-01
"""
from alembic import op
import sqlalchemy as sa
revision = '0011_drop_legacy_bot_routing'
down_revision = '0010_merge_mcp_resource_agent_heads'
branch_labels = None
depends_on = None
def _table_exists(table_name: str) -> bool:
return table_name in sa.inspect(op.get_bind()).get_table_names()
def _column_exists(table_name: str, column_name: str) -> bool:
if not _table_exists(table_name):
return False
return column_name in {column['name'] for column in sa.inspect(op.get_bind()).get_columns(table_name)}
def upgrade() -> None:
if not _table_exists('bots'):
return
existing_columns = {column['name'] for column in sa.inspect(op.get_bind()).get_columns('bots')}
columns_to_drop = [
column_name
for column_name in ('use_pipeline_name', 'use_pipeline_uuid', 'pipeline_routing_rules')
if column_name in existing_columns
]
if not columns_to_drop:
return
with op.batch_alter_table('bots', schema=None) as batch_op:
for column_name in columns_to_drop:
batch_op.drop_column(column_name)
def downgrade() -> None:
if not _table_exists('bots'):
return
with op.batch_alter_table('bots', schema=None) as batch_op:
if not _column_exists('bots', 'use_pipeline_name'):
batch_op.add_column(sa.Column('use_pipeline_name', sa.String(255), nullable=True))
if not _column_exists('bots', 'use_pipeline_uuid'):
batch_op.add_column(sa.Column('use_pipeline_uuid', sa.String(255), nullable=True))
if not _column_exists('bots', 'pipeline_routing_rules'):
batch_op.add_column(sa.Column('pipeline_routing_rules', sa.JSON(), nullable=False, server_default='[]'))
+118 -125
View File
@@ -14,8 +14,6 @@ from ..core import app, entities as core_entities, taskmgr
from ..discover import engine from ..discover import engine
from ..entity.persistence import bot as persistence_bot from ..entity.persistence import bot as persistence_bot
from ..entity.persistence import pipeline as persistence_pipeline
from ..entity.errors import platform as platform_errors from ..entity.errors import platform as platform_errors
from ..agent.runner.host_models import ( from ..agent.runner.host_models import (
AgentBinding, AgentBinding,
@@ -32,6 +30,7 @@ import langbot_plugin.api.entities.builtin.provider.session as provider_session
import langbot_plugin.api.entities.builtin.provider.message as provider_message import langbot_plugin.api.entities.builtin.provider.message as provider_message
import langbot_plugin.api.entities.events as plugin_events import langbot_plugin.api.entities.events as plugin_events
import langbot_plugin.api.entities.builtin.platform.events as platform_events import langbot_plugin.api.entities.builtin.platform.events as platform_events
import langbot_plugin.api.entities.builtin.platform.entities as platform_entities
import langbot_plugin.api.entities.builtin.platform.message as platform_message import langbot_plugin.api.entities.builtin.platform.message as platform_message
import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter import langbot_plugin.api.definition.abstract.platform.adapter as abstract_platform_adapter
from langbot_plugin.api.entities.builtin.agent_runner.event import ( from langbot_plugin.api.entities.builtin.agent_runner.event import (
@@ -74,26 +73,6 @@ class RuntimeBot:
self.task_context = taskmgr.TaskContext() self.task_context = taskmgr.TaskContext()
self.logger = logger self.logger = logger
@staticmethod
def _match_operator(actual: str, operator: str, expected: str) -> bool:
"""Evaluate a single operator condition."""
if operator == 'eq':
return actual == expected
elif operator == 'neq':
return actual != expected
elif operator == 'contains':
return expected in actual
elif operator == 'not_contains':
return expected not in actual
elif operator == 'starts_with':
return actual.startswith(expected)
elif operator == 'regex':
try:
return bool(re.search(expected, actual))
except re.error:
return False
return False
PIPELINE_DISCARD = '__discard__' PIPELINE_DISCARD = '__discard__'
PIPELINE_DISCARD_DISPLAY_NAME = 'Discarded' PIPELINE_DISCARD_DISPLAY_NAME = 'Discarded'
EVENT_DATA_MAX_STRING_BYTES = 512 EVENT_DATA_MAX_STRING_BYTES = 512
@@ -229,12 +208,7 @@ class RuntimeBot:
if isinstance(event_filter, dict) if isinstance(event_filter, dict)
) )
def _resolve_eba_event_binding( def _get_event_bindings(self) -> list[dict[str, typing.Any]]:
self,
event: platform_events.EBAEvent,
event_type: str,
) -> dict[str, typing.Any] | None:
"""Resolve the highest priority Bot event binding for a platform event."""
raw_bindings = self.bot_entity.event_bindings or [] raw_bindings = self.bot_entity.event_bindings or []
if isinstance(raw_bindings, str): if isinstance(raw_bindings, str):
try: try:
@@ -242,11 +216,18 @@ class RuntimeBot:
except json.JSONDecodeError: except json.JSONDecodeError:
raw_bindings = [] raw_bindings = []
if not isinstance(raw_bindings, list): if not isinstance(raw_bindings, list):
return None return []
return [binding for binding in raw_bindings if isinstance(binding, dict)]
def _resolve_eba_event_binding(
self,
event: platform_events.EBAEvent,
event_type: str,
) -> dict[str, typing.Any] | None:
"""Resolve the highest priority Bot event binding for a platform event."""
matched: list[tuple[int, int, dict[str, typing.Any]]] = [] matched: list[tuple[int, int, dict[str, typing.Any]]] = []
for index, binding in enumerate(raw_bindings): for index, binding in enumerate(self._get_event_bindings()):
if not isinstance(binding, dict) or not binding.get('enabled', True): if not binding.get('enabled', True):
continue continue
event_pattern = str(binding.get('event_pattern') or '') event_pattern = str(binding.get('event_pattern') or '')
@@ -265,6 +246,29 @@ class RuntimeBot:
matched.sort(key=lambda item: (item[0], item[1]), reverse=True) matched.sort(key=lambda item: (item[0], item[1]), reverse=True)
return matched[0][2] return matched[0][2]
def get_pipeline_target_for_event_type(self, event_type: str = 'message.received') -> str | None:
"""Return the first Pipeline target configured for an event type."""
matched: list[tuple[int, int, str]] = []
for index, binding in enumerate(self._get_event_bindings()):
if not binding.get('enabled', True):
continue
if binding.get('target_type') != 'pipeline':
continue
target_uuid = str(binding.get('target_uuid') or '')
if not target_uuid:
continue
if not self._match_event_pattern(event_type, str(binding.get('event_pattern') or '')):
continue
priority = int(binding.get('priority') or 0)
order = int(binding.get('order', index))
matched.append((priority, -order, target_uuid))
if not matched:
return None
matched.sort(key=lambda item: (item[0], item[1]), reverse=True)
return matched[0][2]
@staticmethod @staticmethod
def _safe_model_dump(model: typing.Any) -> dict[str, typing.Any]: def _safe_model_dump(model: typing.Any) -> dict[str, typing.Any]:
if model is None: if model is None:
@@ -451,6 +455,56 @@ class RuntimeBot:
return None, None, metadata return None, None, metadata
@staticmethod
def _extract_message_id(message_chain: platform_message.MessageChain) -> str:
for component in message_chain:
if isinstance(component, platform_message.Source):
value = getattr(component, 'id', '')
return str(value) if value is not None else ''
return ''
def _legacy_message_to_eba_event(
self,
event: platform_events.FriendMessage | platform_events.GroupMessage,
adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter,
) -> platform_events.MessageReceivedEvent:
if isinstance(event, platform_events.GroupMessage):
group = platform_entities.UserGroup(
id=event.group.id,
name=event.group.name,
)
return platform_events.MessageReceivedEvent(
message_id=self._extract_message_id(event.message_chain),
message_chain=event.message_chain,
sender=platform_entities.User(
id=event.sender.id,
nickname=event.sender.member_name,
),
chat_type=platform_entities.ChatType.GROUP,
chat_id=event.group.id,
group=group,
timestamp=event.time or time.time(),
bot_uuid=self.bot_entity.uuid,
adapter_name=adapter.__class__.__name__,
source_platform_object=event.source_platform_object,
)
return platform_events.MessageReceivedEvent(
message_id=self._extract_message_id(event.message_chain),
message_chain=event.message_chain,
sender=platform_entities.User(
id=event.sender.id,
nickname=event.sender.nickname,
remark=event.sender.remark,
),
chat_type=platform_entities.ChatType.PRIVATE,
chat_id=event.sender.id,
timestamp=event.time or time.time(),
bot_uuid=self.bot_entity.uuid,
adapter_name=adapter.__class__.__name__,
source_platform_object=event.source_platform_object,
)
@classmethod @classmethod
def _build_agent_input(cls, event: platform_events.EBAEvent) -> AgentInput: def _build_agent_input(cls, event: platform_events.EBAEvent) -> AgentInput:
text = None text = None
@@ -635,6 +689,22 @@ class RuntimeBot:
platform_message.MessageChain([platform_message.Plain(text=final_text)]), platform_message.MessageChain([platform_message.Plain(text=final_text)]),
) )
async def _handle_platform_event(
self,
event: platform_events.EBAEvent,
adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter,
) -> None:
event.bot_uuid = self.bot_entity.uuid
plugin_event = self._eba_event_to_plugin_event(event)
if plugin_event is not None:
try:
await self.ap.plugin_connector.emit_event(plugin_event)
except Exception:
await self.logger.error(f'Failed to dispatch platform event to plugins: {traceback.format_exc()}')
await self._dispatch_eba_event_to_agent(event, adapter)
async def _dispatch_eba_event_to_agent( async def _dispatch_eba_event_to_agent(
self, self,
event: platform_events.EBAEvent, event: platform_events.EBAEvent,
@@ -644,8 +714,7 @@ class RuntimeBot:
event_binding = self._resolve_eba_event_binding(event, event_type) event_binding = self._resolve_eba_event_binding(event, event_type)
if event_binding is None: if event_binding is None:
if isinstance(event, platform_events.MessageReceivedEvent): await self.logger.info(f'Platform event {event_type} ignored: no event route matched')
await self._dispatch_eba_message_to_pipeline(event, adapter)
return return
target_type = event_binding.get('target_type') target_type = event_binding.get('target_type')
@@ -708,64 +777,6 @@ class RuntimeBot:
f'Failed to deliver Agent output for EBA event {event_type}: {traceback.format_exc()}' f'Failed to deliver Agent output for EBA event {event_type}: {traceback.format_exc()}'
) )
def resolve_pipeline_uuid(
self,
launcher_type: str,
launcher_id: str,
message_text: str,
message_element_types: list[str] | None = None,
) -> tuple[str | None, bool]:
"""Resolve pipeline UUID based on routing rules.
Rules are evaluated in order; first match wins.
Falls back to use_pipeline_uuid if no rule matches.
Rule types:
- launcher_type: session type ("person" / "group")
- launcher_id: session / group id
- message_content: message text content
- message_has_element: message contains element of given type
(Image, Voice, File, Forward, Face, At, AtAll, Quote)
Operators: eq (has), neq (doesn't have)
Operators: eq, neq, contains, not_contains, starts_with, regex
When pipeline_uuid is ``__discard__``, the message should be
silently dropped by the caller.
Returns:
tuple: (pipeline_uuid, routed_by_rule) - routed_by_rule is True
when a routing rule matched, False when falling back to default.
"""
rules = self.bot_entity.pipeline_routing_rules or []
element_type_set = set(message_element_types or [])
for rule in rules:
rule_type = rule.get('type')
operator = rule.get('operator', 'eq')
rule_value = rule.get('value', '')
target_uuid = rule.get('pipeline_uuid')
if not rule_type or not target_uuid:
continue
if rule_type == 'launcher_type':
if self._match_operator(launcher_type, operator, rule_value):
return target_uuid, True
elif rule_type == 'launcher_id':
if self._match_operator(str(launcher_id), operator, str(rule_value)):
return target_uuid, True
elif rule_type == 'message_content':
if self._match_operator(message_text, operator, rule_value):
return target_uuid, True
elif rule_type == 'message_has_element':
has_element = rule_value in element_type_set
if operator == 'eq' and has_element:
return target_uuid, True
elif operator == 'neq' and not has_element:
return target_uuid, True
return self.bot_entity.use_pipeline_uuid, False
async def _record_discarded_message( async def _record_discarded_message(
self, self,
launcher_type: provider_session.LauncherTypes, launcher_type: provider_session.LauncherTypes,
@@ -932,21 +943,21 @@ class RuntimeBot:
event: platform_events.FriendMessage, event: platform_events.FriendMessage,
adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter, adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter,
): ):
await self._handle_legacy_message_event( pipeline_uuid = websocket_pipeline_uuid(event, adapter)
event, if pipeline_uuid:
adapter, await self._handle_legacy_message_event(event, adapter, pipeline_uuid_override=pipeline_uuid)
pipeline_uuid_override=websocket_pipeline_uuid(event, adapter), return
) await self._handle_platform_event(self._legacy_message_to_eba_event(event, adapter), adapter)
async def on_group_message( async def on_group_message(
event: platform_events.GroupMessage, event: platform_events.GroupMessage,
adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter, adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter,
): ):
await self._handle_legacy_message_event( pipeline_uuid = websocket_pipeline_uuid(event, adapter)
event, if pipeline_uuid:
adapter, await self._handle_legacy_message_event(event, adapter, pipeline_uuid_override=pipeline_uuid)
pipeline_uuid_override=websocket_pipeline_uuid(event, adapter), return
) await self._handle_platform_event(self._legacy_message_to_eba_event(event, adapter), adapter)
self.adapter.register_listener(platform_events.FriendMessage, on_friend_message) self.adapter.register_listener(platform_events.FriendMessage, on_friend_message)
self.adapter.register_listener(platform_events.GroupMessage, on_group_message) self.adapter.register_listener(platform_events.GroupMessage, on_group_message)
@@ -957,20 +968,11 @@ class RuntimeBot:
adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter, adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter,
): ):
try: try:
# Resolve pipeline name pipeline_id = self.get_pipeline_target_for_event_type('message.received') or ''
pipeline_name = '' pipeline_name = ''
if self.bot_entity.use_pipeline_uuid: if pipeline_id:
try: pipeline = await self.ap.pipeline_service.get_pipeline(pipeline_id)
pipeline_result = await self.ap.persistence_mgr.execute_async( pipeline_name = pipeline.get('name', '') if pipeline else ''
sqlalchemy.select(persistence_pipeline.LegacyPipeline.name).where(
persistence_pipeline.LegacyPipeline.uuid == self.bot_entity.use_pipeline_uuid
)
)
pipeline_row = pipeline_result.first()
if pipeline_row:
pipeline_name = pipeline_row[0]
except Exception:
pass
await self.ap.monitoring_service.record_feedback( await self.ap.monitoring_service.record_feedback(
feedback_id=event.feedback_id, feedback_id=event.feedback_id,
@@ -979,7 +981,7 @@ class RuntimeBot:
inaccurate_reasons=event.inaccurate_reasons, inaccurate_reasons=event.inaccurate_reasons,
bot_id=self.bot_entity.uuid, bot_id=self.bot_entity.uuid,
bot_name=self.bot_entity.name, bot_name=self.bot_entity.name,
pipeline_id=self.bot_entity.use_pipeline_uuid or '', pipeline_id=pipeline_id,
pipeline_name=pipeline_name, pipeline_name=pipeline_name,
session_id=event.session_id, session_id=event.session_id,
message_id=event.message_id, message_id=event.message_id,
@@ -999,16 +1001,7 @@ class RuntimeBot:
event: platform_events.EBAEvent, event: platform_events.EBAEvent,
adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter, adapter: abstract_platform_adapter.AbstractMessagePlatformAdapter,
): ):
event.bot_uuid = self.bot_entity.uuid await self._handle_platform_event(event, adapter)
plugin_event = self._eba_event_to_plugin_event(event)
if plugin_event is not None:
try:
await self.ap.plugin_connector.emit_event(plugin_event)
except Exception:
await self.logger.error(f'Failed to dispatch EBA event to plugins: {traceback.format_exc()}')
await self._dispatch_eba_event_to_agent(event, adapter)
self.adapter.register_listener(platform_events.EBAEvent, on_eba_event) self.adapter.register_listener(platform_events.EBAEvent, on_eba_event)
@@ -508,11 +508,6 @@ class WebSocketAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter)
object.__setattr__(event, '_langbot_pipeline_uuid', pipeline_uuid) object.__setattr__(event, '_langbot_pipeline_uuid', pipeline_uuid)
# 设置流水线UUID (proxy bot always needs it for reply_message routing)
self.ap.platform_mgr.websocket_proxy_bot.bot_entity.use_pipeline_uuid = pipeline_uuid
if owner_bot is not None:
owner_bot.bot_entity.use_pipeline_uuid = pipeline_uuid
# 异步触发事件处理 # 异步触发事件处理
# Use owner_bot's listeners if available, otherwise fall back to proxy bot # Use owner_bot's listeners if available, otherwise fall back to proxy bot
listeners = ( listeners = (
@@ -84,8 +84,8 @@ export default function AgentCreateContent({
{ {
kind: 'agent', kind: 'agent',
icon: Bot, icon: Bot,
title: t('agents.agentOrchestration'), title: t('agents.agentType'),
description: t('agents.agentOrchestrationDescription'), description: t('agents.agentTypeDescription'),
badge: t('agents.allEvents'), badge: t('agents.allEvents'),
}, },
{ {
@@ -148,7 +148,7 @@ export default function AgentFormComponent({
const sections: SectionItem[] = [ const sections: SectionItem[] = [
{ label: t('agents.basicInfo'), name: 'basic', icon: Info }, { label: t('agents.basicInfo'), name: 'basic', icon: Info },
{ label: t('agents.runnerSettings'), name: 'runner', icon: Brain }, { label: t('agents.runnerSettings'), name: 'runner', icon: Brain },
{ label: t('agents.eventCapability'), name: 'events', icon: FileJson2 }, { label: t('agents.advanced'), name: 'events', icon: FileJson2 },
]; ];
const currentRunner = (form.watch('runner') as Record<string, any>)?.id; const currentRunner = (form.watch('runner') as Record<string, any>)?.id;
@@ -450,9 +450,9 @@ export default function AgentFormComponent({
{activeSection === 'events' && ( {activeSection === 'events' && (
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>{t('agents.eventCapability')}</CardTitle> <CardTitle>{t('agents.bindableEvents')}</CardTitle>
<CardDescription> <CardDescription>
{t('agents.eventCapabilityDescription')} {t('agents.bindableEventsDescription')}
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -448,13 +448,13 @@ export default function BotForm({
</CardContent> </CardContent>
</Card> </Card>
{/* Card 2: Event Orchestration (edit mode only) */} {/* Card 2: Event Routing (edit mode only) */}
{initBotId && ( {initBotId && (
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>{t('bots.eventOrchestration')}</CardTitle> <CardTitle>{t('bots.eventRouting')}</CardTitle>
<CardDescription> <CardDescription>
{t('bots.eventOrchestrationDescription')} {t('bots.eventRoutingDescription')}
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@@ -59,7 +59,7 @@ import {
} from '@dnd-kit/sortable'; } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities'; import { CSS } from '@dnd-kit/utilities';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { EventBinding, Agent, AgentKind } from '@/app/infra/entities/api'; import { EventBinding, Agent } from '@/app/infra/entities/api';
export const PIPELINE_DISCARD = '__discard__'; export const PIPELINE_DISCARD = '__discard__';
@@ -496,18 +496,6 @@ function BindingCardContent({
const isExpanded = expandedIds.has(id); const isExpanded = expandedIds.has(id);
const filterCount = (binding.filters as FilterRow[] | undefined)?.length ?? 0; const filterCount = (binding.filters as FilterRow[] | undefined)?.length ?? 0;
const pipelineAllowed = isMessageEventPattern(binding.event_pattern); const pipelineAllowed = isMessageEventPattern(binding.event_pattern);
const targetType = binding.target_type || 'agent';
function getTargetOptions(kind: AgentKind): Agent[] {
return agentOptions.filter((agent) => {
if (agent.kind !== kind) return false;
if (kind === 'pipeline')
return isMessageEventPattern(binding.event_pattern);
if (kind === 'agent')
return agentSupportsEventPattern(agent, binding.event_pattern);
return true;
});
}
return ( return (
<div className="rounded-lg border bg-card"> <div className="rounded-lg border bg-card">
@@ -29,7 +29,7 @@ export interface SidebarEntityItem {
debug?: boolean; debug?: boolean;
// Set when this item appears in the unified extensions list // Set when this item appears in the unified extensions list
extensionType?: 'plugin' | 'mcp' | 'skill'; extensionType?: 'plugin' | 'mcp' | 'skill';
// Agent-specific: distinguishes Agent orchestration from legacy Pipeline // Agent-specific: distinguishes Agent processors from Pipelines
kind?: 'agent' | 'pipeline'; kind?: 'agent' | 'pipeline';
} }
-22
View File
@@ -228,34 +228,12 @@ export interface Bot {
enable?: boolean; enable?: boolean;
adapter: string; adapter: string;
adapter_config: object; adapter_config: object;
use_pipeline_name?: string;
use_pipeline_uuid?: string;
pipeline_routing_rules?: PipelineRoutingRule[];
event_bindings?: EventBinding[]; event_bindings?: EventBinding[];
created_at?: string; created_at?: string;
updated_at?: string; updated_at?: string;
adapter_runtime_values?: object; adapter_runtime_values?: object;
} }
export type RoutingRuleOperator =
| 'eq'
| 'neq'
| 'contains'
| 'not_contains'
| 'starts_with'
| 'regex';
export interface PipelineRoutingRule {
type:
| 'launcher_type'
| 'launcher_id'
| 'message_content'
| 'message_has_element';
operator: RoutingRuleOperator;
value: string;
pipeline_uuid: string;
}
export interface EventBinding { export interface EventBinding {
id?: string; id?: string;
event_pattern: string; event_pattern: string;
+11 -1
View File
@@ -486,7 +486,17 @@ export default function WizardPage() {
adapter: existingBot.adapter, adapter: existingBot.adapter,
adapter_config: existingBot.adapter_config, adapter_config: existingBot.adapter_config,
enable: existingBot.enable, enable: existingBot.enable,
use_pipeline_uuid: pipelineResp.uuid, event_bindings: [
{
event_pattern: 'message.received',
target_type: 'pipeline',
target_uuid: pipelineResp.uuid,
filters: [],
priority: 0,
enabled: true,
description: '',
},
],
}); });
setCurrentStep(3); setCurrentStep(3);
+26 -28
View File
@@ -331,8 +331,7 @@ const enUS = {
getBotConfigError: 'Failed to get bot configuration: ', getBotConfigError: 'Failed to get bot configuration: ',
saveSuccess: 'Saved successfully', saveSuccess: 'Saved successfully',
saveError: 'Save failed: ', saveError: 'Save failed: ',
createSuccess: createSuccess: 'Created successfully. Please configure event routing',
'Created successfully. Please enable or modify the bound pipeline',
createError: 'Creation failed: ', createError: 'Creation failed: ',
deleteSuccess: 'Deleted successfully', deleteSuccess: 'Deleted successfully',
deleteError: 'Delete failed: ', deleteError: 'Delete failed: ',
@@ -363,25 +362,25 @@ const enUS = {
routingConnection: 'Routing & Connection', routingConnection: 'Routing & Connection',
routingConnectionDescription: routingConnectionDescription:
'Bind the pipeline that processes messages for this bot', 'Bind the pipeline that processes messages for this bot',
eventOrchestration: 'Event Orchestration', eventRouting: 'Event Routing',
eventOrchestrationDescription: eventRoutingDescription:
'Bind different handling logic to different bot events. Pipelines only support message events.', 'Choose which processor handles each event received by this bot. Edit the processing logic on the Agent page. Pipelines only support message events.',
eventBindings: 'Event Bindings', eventBindings: 'Event Routes',
addEventBinding: 'Add Event Binding', addEventBinding: 'Add Route',
eventPattern: 'Event', eventPattern: 'Event',
eventPatternPlaceholder: 'Select event', eventPatternPlaceholder: 'Select event',
targetType: 'Target Type', targetType: 'Target Type',
target: 'Handling Logic', target: 'Processor',
targetAgent: 'Agent Orchestration', targetAgent: 'Agent',
targetPipeline: 'Pipeline', targetPipeline: 'Pipeline',
targetDiscard: 'Discard', targetDiscard: 'Discard',
selectTarget: 'Select handling logic', selectTarget: 'Select processor',
searchTarget: 'Search…', searchTarget: 'Search processors…',
noTargetFound: 'No results found', noTargetFound: 'No compatible processors found',
priority: 'Priority', priority: 'Priority',
enabled: 'Enabled', enabled: 'Enabled',
eventBindingDescriptionPlaceholder: 'Rule description', eventBindingDescriptionPlaceholder: 'Rule description',
noEventBindings: 'No event bindings', noEventBindings: 'No event routes',
unsupportedPipelineEvent: 'Pipelines can only be used for message.* events', unsupportedPipelineEvent: 'Pipelines can only be used for message.* events',
disable: 'Disable', disable: 'Disable',
enable: 'Enable', enable: 'Enable',
@@ -529,14 +528,13 @@ const enUS = {
}, },
agents: { agents: {
title: 'Agent', title: 'Agent',
description: description: 'Create reusable processors and use them in bot event routing',
'Manage Agent orchestrations and Pipelines, then bind them to bot events', create: 'Create Processor',
create: 'Create Agent', editAgent: 'Edit Agent',
editAgent: 'Edit Agent Orchestration',
selectFromSidebar: 'Select an Agent or Pipeline from the sidebar', selectFromSidebar: 'Select an Agent or Pipeline from the sidebar',
agentOrchestration: 'Agent Orchestration', agentType: 'Agent',
agentOrchestrationDescription: agentTypeDescription:
'Event-first handling logic for messages, group members, friends, feedback, and other platform events.', 'Use a runner to handle messages, group members, friends, feedback, and other platform events.',
pipelineType: 'Pipeline', pipelineType: 'Pipeline',
kindBadgeAgent: 'Agent', kindBadgeAgent: 'Agent',
kindBadgePipeline: 'Pipeline', kindBadgePipeline: 'Pipeline',
@@ -549,12 +547,13 @@ const enUS = {
basicInfo: 'Basic Information', basicInfo: 'Basic Information',
basicInfoDescription: 'Set the name, icon, description and enabled state', basicInfoDescription: 'Set the name, icon, description and enabled state',
runnerSettings: 'Runner', runnerSettings: 'Runner',
eventCapability: 'Event Capability', advanced: 'Advanced',
eventCapabilityDescription: bindableEvents: 'Bindable Event Range',
'Declare which events this Agent orchestration can be bound to. Use one event pattern per line; * and namespace.* are supported.', bindableEventsDescription:
supportedEvents: 'Supported Events', 'Limit which bot event routes can select this Agent. The default is suitable for most cases.',
supportedEvents: 'Event Range',
supportedEventsDescription: supportedEventsDescription:
'Examples: *, message.received, group.*. Pipelines are fixed to message.*.', 'Use one event pattern per line, for example *, message.received, group.*. Pipelines are fixed to message.*.',
enabled: 'Enable Agent', enabled: 'Enable Agent',
enabledDescription: enabledDescription:
'When disabled, this Agent should not be selected by event routing.', 'When disabled, this Agent should not be selected by event routing.',
@@ -566,11 +565,10 @@ const enUS = {
saveError: 'Save failed: ', saveError: 'Save failed: ',
deleteSuccess: 'Deleted successfully', deleteSuccess: 'Deleted successfully',
deleteError: 'Delete failed: ', deleteError: 'Delete failed: ',
deleteConfirmation: deleteConfirmation: 'Are you sure you want to delete this Agent?',
'Are you sure you want to delete this Agent orchestration?',
dangerZone: 'Danger Zone', dangerZone: 'Danger Zone',
dangerZoneDescription: 'Irreversible and destructive actions', dangerZoneDescription: 'Irreversible and destructive actions',
deleteAgentAction: 'Delete this Agent orchestration', deleteAgentAction: 'Delete this Agent',
deleteAgentHint: deleteAgentHint:
'Once deleted, events bound to it can no longer be executed.', 'Once deleted, events bound to it can no longer be executed.',
noRunnerMetadata: 'No AgentRunner metadata is currently available.', noRunnerMetadata: 'No AgentRunner metadata is currently available.',
+18 -16
View File
@@ -342,8 +342,7 @@ const esES = {
getBotConfigError: 'Error al obtener la configuración del Bot: ', getBotConfigError: 'Error al obtener la configuración del Bot: ',
saveSuccess: 'Guardado correctamente', saveSuccess: 'Guardado correctamente',
saveError: 'Error al guardar: ', saveError: 'Error al guardar: ',
createSuccess: createSuccess: 'Creado correctamente. Configura el enrutamiento de eventos',
'Creado correctamente. Por favor, activa o modifica el Pipeline vinculado',
createError: 'Error al crear: ', createError: 'Error al crear: ',
deleteSuccess: 'Eliminado correctamente', deleteSuccess: 'Eliminado correctamente',
deleteError: 'Error al eliminar: ', deleteError: 'Error al eliminar: ',
@@ -374,6 +373,9 @@ const esES = {
routingConnection: 'Enrutamiento y conexión', routingConnection: 'Enrutamiento y conexión',
routingConnectionDescription: routingConnectionDescription:
'Vincula el Pipeline que procesa los mensajes de este Bot', 'Vincula el Pipeline que procesa los mensajes de este Bot',
eventRouting: 'Enrutamiento de eventos',
eventRoutingDescription:
'Elige qué procesador maneja cada evento recibido por este Bot. Edita la lógica de procesamiento en la página Agent. Los Pipelines solo admiten eventos de mensaje.',
routingRules: 'Reglas de enrutamiento condicional', routingRules: 'Reglas de enrutamiento condicional',
routingRulesDescription: routingRulesDescription:
'Las reglas se evalúan en orden; la primera coincidencia enruta a su pipeline. Si ninguna coincide, se usa el pipeline predeterminado.', 'Las reglas se evalúan en orden; la primera coincidencia enruta a su pipeline. Si ninguna coincide, se usa el pipeline predeterminado.',
@@ -484,13 +486,13 @@ const esES = {
agents: { agents: {
title: 'Agent', title: 'Agent',
description: description:
'Gestiona orquestaciones de Agent y Pipelines, y vincúlalos a eventos de bot', 'Crea procesadores reutilizables y úsalos en el enrutamiento de eventos del bot',
create: 'Crear Agent', create: 'Crear procesador',
editAgent: 'Editar orquestación de Agent', editAgent: 'Editar Agent',
selectFromSidebar: 'Selecciona un Agent o Pipeline desde la barra lateral', selectFromSidebar: 'Selecciona un Agent o Pipeline desde la barra lateral',
agentOrchestration: 'Orquestación de Agent', agentType: 'Agent',
agentOrchestrationDescription: agentTypeDescription:
'Lógica de procesamiento orientada a eventos para mensajes, miembros de grupo, amigos, retroalimentación y otros eventos de plataforma.', 'Usa un runner para procesar mensajes, miembros de grupo, amigos, retroalimentación y otros eventos de plataforma.',
pipelineType: 'Pipeline', pipelineType: 'Pipeline',
kindBadgeAgent: 'Agent', kindBadgeAgent: 'Agent',
kindBadgePipeline: 'Pipeline', kindBadgePipeline: 'Pipeline',
@@ -504,12 +506,13 @@ const esES = {
basicInfoDescription: basicInfoDescription:
'Establece el nombre, icono, descripción y estado de habilitación', 'Establece el nombre, icono, descripción y estado de habilitación',
runnerSettings: 'Runner', runnerSettings: 'Runner',
eventCapability: 'Capacidad de eventos', advanced: 'Avanzado',
eventCapabilityDescription: bindableEvents: 'Rango de eventos vinculables',
'Declara a qué eventos puede vincularse esta orquestación de Agent. Un patrón de evento por línea; se admiten * y namespace.*.', bindableEventsDescription:
supportedEvents: 'Eventos admitidos', 'Limita qué rutas de eventos del bot pueden seleccionar este Agent. El valor predeterminado sirve para la mayoría de los casos.',
supportedEvents: 'Rango de eventos',
supportedEventsDescription: supportedEventsDescription:
'Ejemplos: *, message.received, group.*. Los Pipelines están fijos en message.*.', 'Usa un patrón de evento por línea, por ejemplo *, message.received, group.*. Los Pipelines están fijos en message.*.',
enabled: 'Habilitar Agent', enabled: 'Habilitar Agent',
enabledDescription: enabledDescription:
'Cuando está deshabilitado, este Agent no debe ser seleccionado por el enrutamiento de eventos.', 'Cuando está deshabilitado, este Agent no debe ser seleccionado por el enrutamiento de eventos.',
@@ -521,11 +524,10 @@ const esES = {
saveError: 'Error al guardar: ', saveError: 'Error al guardar: ',
deleteSuccess: 'Eliminado correctamente', deleteSuccess: 'Eliminado correctamente',
deleteError: 'Error al eliminar: ', deleteError: 'Error al eliminar: ',
deleteConfirmation: deleteConfirmation: '¿Estás seguro de que deseas eliminar este Agent?',
'¿Estás seguro de que deseas eliminar esta orquestación de Agent?',
dangerZone: 'Zona de peligro', dangerZone: 'Zona de peligro',
dangerZoneDescription: 'Acciones irreversibles y destructivas', dangerZoneDescription: 'Acciones irreversibles y destructivas',
deleteAgentAction: 'Eliminar esta orquestación de Agent', deleteAgentAction: 'Eliminar este Agent',
deleteAgentHint: deleteAgentHint:
'Una vez eliminado, los eventos vinculados a él ya no podrán ejecutarse.', 'Una vez eliminado, los eventos vinculados a él ya no podrán ejecutarse.',
noRunnerMetadata: noRunnerMetadata:
+25 -24
View File
@@ -337,8 +337,7 @@ const jaJP = {
getBotConfigError: 'ボット設定の取得に失敗しました:', getBotConfigError: 'ボット設定の取得に失敗しました:',
saveSuccess: '保存に成功しました', saveSuccess: '保存に成功しました',
saveError: '保存に失敗しました:', saveError: '保存に失敗しました:',
createSuccess: createSuccess: '作成が完了しました。イベントルーティングを設定してください',
'作成が完了しました。有効化するか、パイプラインの設定を行ってください',
createError: '作成に失敗しました:', createError: '作成に失敗しました:',
deleteSuccess: '削除に成功しました', deleteSuccess: '削除に成功しました',
deleteError: '削除に失敗しました:', deleteError: '削除に失敗しました:',
@@ -369,23 +368,23 @@ const jaJP = {
routingConnection: 'ルーティングと接続', routingConnection: 'ルーティングと接続',
routingConnectionDescription: routingConnectionDescription:
'このボットのメッセージを処理するパイプラインを紐付け', 'このボットのメッセージを処理するパイプラインを紐付け',
eventOrchestration: 'イベント編成', eventRouting: 'イベントルーティング',
eventOrchestrationDescription: eventRoutingDescription:
'このボットのイベントごとに異なる処理ロジックを紐付けます。Pipeline はメッセージイベントのみ対応します。', 'このボットが受信した各イベントをどのプロセッサーに渡すかを選択します。処理ロジックは Agent ページで編集します。Pipeline はメッセージイベントのみ対応します。',
eventBindings: 'イベントバインディング', eventBindings: 'イベントルート',
addEventBinding: 'イベントバインディングを追加', addEventBinding: 'ルートを追加',
eventPattern: 'イベント', eventPattern: 'イベント',
eventPatternPlaceholder: 'イベントを選択', eventPatternPlaceholder: 'イベントを選択',
targetType: 'ターゲットタイプ', targetType: 'ターゲットタイプ',
target: '処理ロジック', target: 'プロセッサー',
targetAgent: 'Agent 編成', targetAgent: 'Agent',
targetPipeline: 'Pipeline', targetPipeline: 'Pipeline',
targetDiscard: '破棄', targetDiscard: '破棄',
selectTarget: '処理ロジックを選択', selectTarget: 'プロセッサーを選択',
priority: '優先度', priority: '優先度',
enabled: '有効', enabled: '有効',
eventBindingDescriptionPlaceholder: 'ルール説明', eventBindingDescriptionPlaceholder: 'ルール説明',
noEventBindings: 'イベントバインディングはありません', noEventBindings: 'イベントルートはありません',
unsupportedPipelineEvent: unsupportedPipelineEvent:
'Pipeline は message.* イベントにのみ使用できます', 'Pipeline は message.* イベントにのみ使用できます',
eventCustom: 'カスタムイベント', eventCustom: 'カスタムイベント',
@@ -516,14 +515,15 @@ const jaJP = {
}, },
agents: { agents: {
title: 'Agent', title: 'Agent',
description: 'Agent 編成と Pipeline を管理し、ボットのイベントに紐付けます', description:
create: 'Agent を作成', '再利用可能なプロセッサーを作成し、ボットのイベントルーティングで使用します',
editAgent: 'Agent 編成を編集', create: 'プロセッサーを作成',
editAgent: 'Agent を編集',
selectFromSidebar: selectFromSidebar:
'サイドバーから Agent または Pipeline を選択してください', 'サイドバーから Agent または Pipeline を選択してください',
agentOrchestration: 'Agent 編成', agentType: 'Agent',
agentOrchestrationDescription: agentTypeDescription:
'メッセージ、グループメンバー、友だち、フィードバックなどのプラットフォームイベント向けの処理ロジックです。', 'Runner を使ってメッセージ、グループメンバー、友だち、フィードバックなどのプラットフォームイベントを処理します。',
pipelineType: 'Pipeline', pipelineType: 'Pipeline',
kindBadgeAgent: 'Agent', kindBadgeAgent: 'Agent',
kindBadgePipeline: 'パイプライン', kindBadgePipeline: 'パイプライン',
@@ -536,12 +536,13 @@ const jaJP = {
basicInfo: '基本情報', basicInfo: '基本情報',
basicInfoDescription: '名前、アイコン、説明、有効状態を設定します', basicInfoDescription: '名前、アイコン、説明、有効状態を設定します',
runnerSettings: 'Runner', runnerSettings: 'Runner',
eventCapability: 'イベント能力', advanced: '詳細',
eventCapabilityDescription: bindableEvents: '紐付け可能なイベント範囲',
'この Agent 編成をどのイベントに紐付けられるかを宣言します。1 行に 1 つのイベントパターンを指定し、* と namespace.* を利用できます。', bindableEventsDescription:
supportedEvents: '対応イベント', 'この Agent を選択できるボットイベントルートの範囲を制限します。通常は既定値のままで問題ありません。',
supportedEvents: 'イベント範囲',
supportedEventsDescription: supportedEventsDescription:
'例: *、message.received、group.*。Pipeline は message.* 固定です。', '1 行に 1 つのイベントパターンを指定します。例: *、message.received、group.*。Pipeline は message.* 固定です。',
enabled: 'Agent を有効化', enabled: 'Agent を有効化',
enabledDescription: enabledDescription:
'無効化すると、この Agent はイベントルーティングで選択されません。', '無効化すると、この Agent はイベントルーティングで選択されません。',
@@ -553,10 +554,10 @@ const jaJP = {
saveError: '保存に失敗しました:', saveError: '保存に失敗しました:',
deleteSuccess: '削除に成功しました', deleteSuccess: '削除に成功しました',
deleteError: '削除に失敗しました:', deleteError: '削除に失敗しました:',
deleteConfirmation: 'この Agent 編成を削除してもよろしいですか?', deleteConfirmation: 'この Agent を削除してもよろしいですか?',
dangerZone: '危険ゾーン', dangerZone: '危険ゾーン',
dangerZoneDescription: '元に戻せない操作', dangerZoneDescription: '元に戻せない操作',
deleteAgentAction: 'この Agent 編成を削除', deleteAgentAction: 'この Agent を削除',
deleteAgentHint: '削除すると、紐付けられたイベントは実行できなくなります。', deleteAgentHint: '削除すると、紐付けられたイベントは実行できなくなります。',
noRunnerMetadata: '現在利用可能な AgentRunner メタデータはありません。', noRunnerMetadata: '現在利用可能な AgentRunner メタデータはありません。',
}, },
+18 -15
View File
@@ -341,8 +341,7 @@ const ruRU = {
getBotConfigError: 'Не удалось получить конфигурацию бота: ', getBotConfigError: 'Не удалось получить конфигурацию бота: ',
saveSuccess: 'Успешно сохранено', saveSuccess: 'Успешно сохранено',
saveError: 'Ошибка сохранения: ', saveError: 'Ошибка сохранения: ',
createSuccess: createSuccess: 'Успешно создано. Настройте маршрутизацию событий',
'Успешно создано. Пожалуйста, включите или измените привязанный конвейер',
createError: 'Ошибка создания: ', createError: 'Ошибка создания: ',
deleteSuccess: 'Успешно удалено', deleteSuccess: 'Успешно удалено',
deleteError: 'Ошибка удаления: ', deleteError: 'Ошибка удаления: ',
@@ -373,6 +372,9 @@ const ruRU = {
routingConnection: 'Маршрутизация и подключение', routingConnection: 'Маршрутизация и подключение',
routingConnectionDescription: routingConnectionDescription:
'Привяжите конвейер, обрабатывающий сообщения для этого бота', 'Привяжите конвейер, обрабатывающий сообщения для этого бота',
eventRouting: 'Маршрутизация событий',
eventRoutingDescription:
'Выберите, какой обработчик будет получать каждое событие этого бота. Логика обработки редактируется на странице Agent. Pipeline поддерживает только события сообщений.',
routingRules: 'Правила условной маршрутизации', routingRules: 'Правила условной маршрутизации',
routingRulesDescription: routingRulesDescription:
'Правила проверяются по порядку; первое совпадение направляет в соответствующий конвейер. При отсутствии совпадений используется конвейер по умолчанию.', 'Правила проверяются по порядку; первое совпадение направляет в соответствующий конвейер. При отсутствии совпадений используется конвейер по умолчанию.',
@@ -482,13 +484,13 @@ const ruRU = {
agents: { agents: {
title: 'Agent', title: 'Agent',
description: description:
'Управляйте оркестровками Agent и Pipeline, привязывая их к событиям бота', 'Создавайте переиспользуемые обработчики и используйте их в маршрутизации событий бота',
create: 'Создать Agent', create: 'Создать обработчик',
editAgent: 'Редактировать оркестровку Agent', editAgent: 'Редактировать Agent',
selectFromSidebar: 'Выберите Agent или Pipeline на боковой панели', selectFromSidebar: 'Выберите Agent или Pipeline на боковой панели',
agentOrchestration: 'Оркестровка Agent', agentType: 'Agent',
agentOrchestrationDescription: agentTypeDescription:
'Логика обработки сообщений, участников групп, друзей, обратной связи и других событий платформы.', 'Используйте runner для обработки сообщений, участников групп, друзей, обратной связи и других событий платформы.',
pipelineType: 'Pipeline', pipelineType: 'Pipeline',
kindBadgeAgent: 'Agent', kindBadgeAgent: 'Agent',
kindBadgePipeline: 'Pipeline', kindBadgePipeline: 'Pipeline',
@@ -501,12 +503,13 @@ const ruRU = {
basicInfo: 'Основная информация', basicInfo: 'Основная информация',
basicInfoDescription: 'Задайте имя, иконку, описание и статус активации', basicInfoDescription: 'Задайте имя, иконку, описание и статус активации',
runnerSettings: 'Runner', runnerSettings: 'Runner',
eventCapability: 'Возможности событий', advanced: 'Дополнительно',
eventCapabilityDescription: bindableEvents: 'Диапазон привязываемых событий',
'Объявите, к каким событиям может быть привязана эта оркестровка Agent. Один шаблон события в строке; поддерживаются * и namespace.*.', bindableEventsDescription:
supportedEvents: 'Поддерживаемые события', 'Ограничьте, какие маршруты событий бота могут выбирать этот Agent. Обычно достаточно значения по умолчанию.',
supportedEvents: 'Диапазон событий',
supportedEventsDescription: supportedEventsDescription:
'Примеры: *, message.received, group.*. Pipeline фиксирован на message.*.', 'Один шаблон события в строке, например *, message.received, group.*. Pipeline фиксирован на message.*.',
enabled: 'Включить Agent', enabled: 'Включить Agent',
enabledDescription: enabledDescription:
'При отключении этот Agent не должен выбираться маршрутизацией событий.', 'При отключении этот Agent не должен выбираться маршрутизацией событий.',
@@ -518,10 +521,10 @@ const ruRU = {
saveError: 'Ошибка сохранения: ', saveError: 'Ошибка сохранения: ',
deleteSuccess: 'Успешно удалено', deleteSuccess: 'Успешно удалено',
deleteError: 'Ошибка удаления: ', deleteError: 'Ошибка удаления: ',
deleteConfirmation: 'Вы уверены, что хотите удалить эту оркестровку Agent?', deleteConfirmation: 'Вы уверены, что хотите удалить этот Agent?',
dangerZone: 'Опасная зона', dangerZone: 'Опасная зона',
dangerZoneDescription: 'Необратимые и деструктивные действия', dangerZoneDescription: 'Необратимые и деструктивные действия',
deleteAgentAction: 'Удалить эту оркестровку Agent', deleteAgentAction: 'Удалить этот Agent',
deleteAgentHint: deleteAgentHint:
'После удаления события, привязанные к ней, больше не смогут выполняться.', 'После удаления события, привязанные к ней, больше не смогут выполняться.',
noRunnerMetadata: 'Метаданные AgentRunner в данный момент недоступны.', noRunnerMetadata: 'Метаданные AgentRunner в данный момент недоступны.',
+18 -15
View File
@@ -328,7 +328,7 @@ const thTH = {
getBotConfigError: 'ไม่สามารถดึงการกำหนดค่า Bot ได้: ', getBotConfigError: 'ไม่สามารถดึงการกำหนดค่า Bot ได้: ',
saveSuccess: 'บันทึกสำเร็จ', saveSuccess: 'บันทึกสำเร็จ',
saveError: 'บันทึกล้มเหลว: ', saveError: 'บันทึกล้มเหลว: ',
createSuccess: 'สร้างสำเร็จ กรุณาเปิดใช้งานหรือแก้ไข Pipeline ที่ผูกไว้', createSuccess: 'สร้างสำเร็จ กรุณากำหนดเส้นทางเหตุการณ์',
createError: 'สร้างล้มเหลว: ', createError: 'สร้างล้มเหลว: ',
deleteSuccess: 'ลบสำเร็จ', deleteSuccess: 'ลบสำเร็จ',
deleteError: 'ลบล้มเหลว: ', deleteError: 'ลบล้มเหลว: ',
@@ -359,6 +359,9 @@ const thTH = {
routingConnection: 'การกำหนดเส้นทางและการเชื่อมต่อ', routingConnection: 'การกำหนดเส้นทางและการเชื่อมต่อ',
routingConnectionDescription: routingConnectionDescription:
'ผูก Pipeline ที่ประมวลผลข้อความสำหรับ Bot นี้', 'ผูก Pipeline ที่ประมวลผลข้อความสำหรับ Bot นี้',
eventRouting: 'การกำหนดเส้นทางเหตุการณ์',
eventRoutingDescription:
'เลือกตัวประมวลผลที่จะจัดการแต่ละเหตุการณ์ที่ Bot นี้ได้รับ แก้ไขตรรกะการประมวลผลในหน้า Agent และ Pipeline รองรับเฉพาะเหตุการณ์ข้อความ',
routingRules: 'กฎการกำหนดเส้นทางตามเงื่อนไข', routingRules: 'กฎการกำหนดเส้นทางตามเงื่อนไข',
routingRulesDescription: routingRulesDescription:
'กฎจะถูกประเมินตามลำดับ การจับคู่แรกจะกำหนดเส้นทางไปยัง Pipeline ที่เกี่ยวข้อง หากไม่ตรงกันจะใช้ Pipeline เริ่มต้นด้านบน', 'กฎจะถูกประเมินตามลำดับ การจับคู่แรกจะกำหนดเส้นทางไปยัง Pipeline ที่เกี่ยวข้อง หากไม่ตรงกันจะใช้ Pipeline เริ่มต้นด้านบน',
@@ -467,14 +470,13 @@ const thTH = {
}, },
agents: { agents: {
title: 'Agent', title: 'Agent',
description: description: 'สร้างตัวประมวลผลที่ใช้ซ้ำได้และใช้ในเส้นทางเหตุการณ์ของบอท',
'จัดการการประสาน Agent และ Pipeline แล้วเชื่อมกับเหตุการณ์ของบอท', create: 'สร้างตัวประมวลผล',
create: 'สร้าง Agent', editAgent: 'แก้ไข Agent',
editAgent: 'แก้ไขการประสาน Agent',
selectFromSidebar: 'เลือก Agent หรือ Pipeline จากแถบด้านข้าง', selectFromSidebar: 'เลือก Agent หรือ Pipeline จากแถบด้านข้าง',
agentOrchestration: 'การประสาน Agent', agentType: 'Agent',
agentOrchestrationDescription: agentTypeDescription:
'ตรรกะการประมวลผลที่เน้นเหตุการณ์สำหรับข้อความ สมาชิกกลุ่ม เพื่อน ฟีดแบ็ก และเหตุการณ์แพลตฟอร์มอื่นๆ', 'ใช้ runner เพื่อประมวลผลข้อความ สมาชิกกลุ่ม เพื่อน ฟีดแบ็ก และเหตุการณ์แพลตฟอร์มอื่นๆ',
pipelineType: 'Pipeline', pipelineType: 'Pipeline',
kindBadgeAgent: 'Agent', kindBadgeAgent: 'Agent',
kindBadgePipeline: 'Pipeline', kindBadgePipeline: 'Pipeline',
@@ -487,12 +489,13 @@ const thTH = {
basicInfo: 'ข้อมูลพื้นฐาน', basicInfo: 'ข้อมูลพื้นฐาน',
basicInfoDescription: 'ตั้งชื่อ ไอคอน คำอธิบาย และสถานะการเปิดใช้งาน', basicInfoDescription: 'ตั้งชื่อ ไอคอน คำอธิบาย และสถานะการเปิดใช้งาน',
runnerSettings: 'Runner', runnerSettings: 'Runner',
eventCapability: 'ความสามารถด้านเหตุการณ์', advanced: 'ขั้นสูง',
eventCapabilityDescription: bindableEvents: 'ช่วงเหตุการณ์ที่ผูกได้',
'ประกาศว่าการประสาน Agent นี้สามารถเชื่อมกับเหตุการณ์ใดได้บ้าง หนึ่งรูปแบบเหตุการณ์ต่อบรรทัด รองรับ * และ namespace.*', bindableEventsDescription:
supportedEvents: 'เหตุการณ์ที่รองรับ', 'จำกัดว่าเส้นทางเหตุการณ์ของบอทใดสามารถเลือก Agent นี้ได้ ค่าเริ่มต้นเหมาะกับกรณีส่วนใหญ่',
supportedEvents: 'ช่วงเหตุการณ์',
supportedEventsDescription: supportedEventsDescription:
'ตัวอย่าง: *, message.received, group.* Pipeline ถูกกำหนดไว้ที่ message.*', 'หนึ่งรูปแบบเหตุการณ์ต่อบรรทัด เช่น *, message.received, group.* Pipeline ถูกกำหนดไว้ที่ message.*',
enabled: 'เปิดใช้งาน Agent', enabled: 'เปิดใช้งาน Agent',
enabledDescription: enabledDescription:
'เมื่อปิดใช้งาน Agent นี้จะไม่ถูกเลือกโดยการกำหนดเส้นทางเหตุการณ์', 'เมื่อปิดใช้งาน Agent นี้จะไม่ถูกเลือกโดยการกำหนดเส้นทางเหตุการณ์',
@@ -504,10 +507,10 @@ const thTH = {
saveError: 'บันทึกล้มเหลว: ', saveError: 'บันทึกล้มเหลว: ',
deleteSuccess: 'ลบสำเร็จ', deleteSuccess: 'ลบสำเร็จ',
deleteError: 'ลบล้มเหลว: ', deleteError: 'ลบล้มเหลว: ',
deleteConfirmation: 'คุณแน่ใจหรือว่าต้องการลบการประสาน Agent นี้?', deleteConfirmation: 'คุณแน่ใจหรือว่าต้องการลบ Agent นี้?',
dangerZone: 'โซนอันตราย', dangerZone: 'โซนอันตราย',
dangerZoneDescription: 'การดำเนินการที่ไม่สามารถย้อนกลับและทำลายข้อมูล', dangerZoneDescription: 'การดำเนินการที่ไม่สามารถย้อนกลับและทำลายข้อมูล',
deleteAgentAction: 'ลบการประสาน Agent นี้', deleteAgentAction: 'ลบ Agent นี้',
deleteAgentHint: deleteAgentHint:
'เมื่อลบแล้ว เหตุการณ์ที่เชื่อมกับมันจะไม่สามารถดำเนินการต่อได้', 'เมื่อลบแล้ว เหตุการณ์ที่เชื่อมกับมันจะไม่สามารถดำเนินการต่อได้',
noRunnerMetadata: 'ขณะนี้ไม่มีข้อมูลเมตา AgentRunner ที่พร้อมใช้งาน', noRunnerMetadata: 'ขณะนี้ไม่มีข้อมูลเมตา AgentRunner ที่พร้อมใช้งาน',
+18 -15
View File
@@ -337,8 +337,7 @@ const viVN = {
getBotConfigError: 'Lấy cấu hình Bot thất bại: ', getBotConfigError: 'Lấy cấu hình Bot thất bại: ',
saveSuccess: 'Lưu thành công', saveSuccess: 'Lưu thành công',
saveError: 'Lưu thất bại: ', saveError: 'Lưu thất bại: ',
createSuccess: createSuccess: 'Tạo thành công. Vui lòng cấu hình định tuyến sự kiện',
'Tạo thành công. Vui lòng bật hoặc sửa đổi Pipeline đã liên kết',
createError: 'Tạo thất bại: ', createError: 'Tạo thất bại: ',
deleteSuccess: 'Xóa thành công', deleteSuccess: 'Xóa thành công',
deleteError: 'Xóa thất bại: ', deleteError: 'Xóa thất bại: ',
@@ -369,6 +368,9 @@ const viVN = {
routingConnection: 'Định tuyến & Kết nối', routingConnection: 'Định tuyến & Kết nối',
routingConnectionDescription: routingConnectionDescription:
'Liên kết Pipeline xử lý tin nhắn cho Bot này', 'Liên kết Pipeline xử lý tin nhắn cho Bot này',
eventRouting: 'Định tuyến sự kiện',
eventRoutingDescription:
'Chọn bộ xử lý sẽ nhận từng sự kiện của Bot này. Chỉnh sửa logic xử lý trong trang Agent. Pipeline chỉ hỗ trợ sự kiện tin nhắn.',
routingRules: 'Quy tắc định tuyến có điều kiện', routingRules: 'Quy tắc định tuyến có điều kiện',
routingRulesDescription: routingRulesDescription:
'Các quy tắc được đánh giá theo thứ tự; kết quả khớp đầu tiên sẽ định tuyến đến pipeline tương ứng. Nếu không khớp, pipeline mặc định ở trên sẽ được sử dụng.', 'Các quy tắc được đánh giá theo thứ tự; kết quả khớp đầu tiên sẽ định tuyến đến pipeline tương ứng. Nếu không khớp, pipeline mặc định ở trên sẽ được sử dụng.',
@@ -478,13 +480,13 @@ const viVN = {
agents: { agents: {
title: 'Agent', title: 'Agent',
description: description:
'Quản lý dàn dng Agent và Pipeline, sau đó gắn chúng vào sự kiện của bot', 'Tạo bộ xử lý có thể tái sử dng và dùng chúng trong định tuyến sự kiện của bot',
create: 'Tạo Agent', create: 'Tạo bộ xử lý',
editAgent: 'Chỉnh sửa dàn dựng Agent', editAgent: 'Chỉnh sửa Agent',
selectFromSidebar: 'Chọn một Agent hoặc Pipeline từ thanh bên', selectFromSidebar: 'Chọn một Agent hoặc Pipeline từ thanh bên',
agentOrchestration: 'Dàn dựng Agent', agentType: 'Agent',
agentOrchestrationDescription: agentTypeDescription:
'Logic xử lý hướng sự kiện cho tin nhắn, thành viên nhóm, bạn bè, phản hồi và các sự kiện nền tảng khác.', 'Dùng runner để xử lý tin nhắn, thành viên nhóm, bạn bè, phản hồi và các sự kiện nền tảng khác.',
pipelineType: 'Pipeline', pipelineType: 'Pipeline',
kindBadgeAgent: 'Agent', kindBadgeAgent: 'Agent',
kindBadgePipeline: 'Pipeline', kindBadgePipeline: 'Pipeline',
@@ -497,12 +499,13 @@ const viVN = {
basicInfo: 'Thông tin cơ bản', basicInfo: 'Thông tin cơ bản',
basicInfoDescription: 'Đặt tên, biểu tượng, mô tả và trạng thái kích hoạt', basicInfoDescription: 'Đặt tên, biểu tượng, mô tả và trạng thái kích hoạt',
runnerSettings: 'Runner', runnerSettings: 'Runner',
eventCapability: 'Khả năng sự kiện', advanced: 'Nâng cao',
eventCapabilityDescription: bindableEvents: 'Phạm vi sự kiện có thể gắn',
'Khai báo những sự kiện mà dàn dựng Agent này có thể được gắn vào. Mỗi dòng một mẫu sự kiện; hỗ trợ * và namespace.*.', bindableEventsDescription:
supportedEvents: 'Sự kiện được hỗ trợ', 'Giới hạn những tuyến sự kiện bot có thể chọn Agent này. Mặc định phù hợp với hầu hết trường hợp.',
supportedEvents: 'Phạm vi sự kiện',
supportedEventsDescription: supportedEventsDescription:
'Ví dụ: *, message.received, group.*. Pipeline cố định ở message.*.', 'Mỗi dòng một mẫu sự kiện, ví dụ *, message.received, group.*. Pipeline cố định ở message.*.',
enabled: 'Kích hoạt Agent', enabled: 'Kích hoạt Agent',
enabledDescription: enabledDescription:
'Khi bị tắt, Agent này sẽ không được định tuyến sự kiện chọn.', 'Khi bị tắt, Agent này sẽ không được định tuyến sự kiện chọn.',
@@ -514,10 +517,10 @@ const viVN = {
saveError: 'Lưu thất bại: ', saveError: 'Lưu thất bại: ',
deleteSuccess: 'Xóa thành công', deleteSuccess: 'Xóa thành công',
deleteError: 'Xóa thất bại: ', deleteError: 'Xóa thất bại: ',
deleteConfirmation: 'Bạn có chắc muốn xóa dàn dựng Agent này không?', deleteConfirmation: 'Bạn có chắc muốn xóa Agent này không?',
dangerZone: 'Vùng nguy hiểm', dangerZone: 'Vùng nguy hiểm',
dangerZoneDescription: 'Hành động không thể hoàn tác và mang tính phá hủy', dangerZoneDescription: 'Hành động không thể hoàn tác và mang tính phá hủy',
deleteAgentAction: 'Xóa dàn dựng Agent này', deleteAgentAction: 'Xóa Agent này',
deleteAgentHint: deleteAgentHint:
'Sau khi xóa, các sự kiện đã gắn vào nó sẽ không thể thực thi được nữa.', 'Sau khi xóa, các sự kiện đã gắn vào nó sẽ không thể thực thi được nữa.',
noRunnerMetadata: 'Hiện chưa có siêu dữ liệu AgentRunner khả dụng.', noRunnerMetadata: 'Hiện chưa có siêu dữ liệu AgentRunner khả dụng.',
+25 -25
View File
@@ -317,7 +317,7 @@ const zhHans = {
getBotConfigError: '获取机器人配置失败:', getBotConfigError: '获取机器人配置失败:',
saveSuccess: '保存成功', saveSuccess: '保存成功',
saveError: '保存失败:', saveError: '保存失败:',
createSuccess: '创建成功 请启用或修改绑定流水线', createSuccess: '创建成功,请配置事件路由',
createError: '创建失败:', createError: '创建失败:',
deleteSuccess: '删除成功', deleteSuccess: '删除成功',
deleteError: '删除失败:', deleteError: '删除失败:',
@@ -347,25 +347,25 @@ const zhHans = {
basicInfoDescription: '设置机器人名称和描述', basicInfoDescription: '设置机器人名称和描述',
routingConnection: '路由与连接', routingConnection: '路由与连接',
routingConnectionDescription: '绑定处理此机器人消息的流水线', routingConnectionDescription: '绑定处理此机器人消息的流水线',
eventOrchestration: '事件编排', eventRouting: '事件路由',
eventOrchestrationDescription: eventRoutingDescription:
'此机器人不同事件绑定不同处理逻辑。Pipeline 仅支持消息事件。', '选择此机器人收到不同事件时交给哪个处理器。具体处理逻辑在 Agent 页面编辑,Pipeline 仅支持消息事件。',
eventBindings: '事件绑定', eventBindings: '事件路由',
addEventBinding: '添加事件绑定', addEventBinding: '添加路由',
eventPattern: '事件', eventPattern: '事件',
eventPatternPlaceholder: '选择事件', eventPatternPlaceholder: '选择事件',
targetType: '目标类型', targetType: '目标类型',
target: '处理逻辑', target: '处理',
targetAgent: 'Agent 编排', targetAgent: 'Agent',
targetPipeline: 'Pipeline', targetPipeline: 'Pipeline',
targetDiscard: '丢弃', targetDiscard: '丢弃',
selectTarget: '选择处理逻辑', selectTarget: '选择处理',
searchTarget: '搜索处理逻辑…', searchTarget: '搜索处理…',
noTargetFound: '未找到匹配项', noTargetFound: '未找到兼容处理器',
priority: '优先级', priority: '优先级',
enabled: '启用', enabled: '启用',
eventBindingDescriptionPlaceholder: '规则说明', eventBindingDescriptionPlaceholder: '规则说明',
noEventBindings: '暂无事件绑定', noEventBindings: '暂无事件路由',
unsupportedPipelineEvent: 'Pipeline 仅可用于 message.* 事件', unsupportedPipelineEvent: 'Pipeline 仅可用于 message.* 事件',
disable: '禁用', disable: '禁用',
enable: '启用', enable: '启用',
@@ -509,13 +509,12 @@ const zhHans = {
}, },
agents: { agents: {
title: 'Agent', title: 'Agent',
description: '管理 Agent 编排与 Pipeline,并将它们绑定到机器人事件', description: '创建可复用的处理器,并在机器人事件路由中使用',
create: '创建 Agent', create: '创建处理器',
editAgent: '编辑 Agent 编排', editAgent: '编辑 Agent',
selectFromSidebar: '从侧边栏选择一个 Agent 或 Pipeline', selectFromSidebar: '从侧边栏选择一个 Agent 或 Pipeline',
agentOrchestration: 'Agent 编排', agentType: 'Agent',
agentOrchestrationDescription: agentTypeDescription: '通过运行器处理消息、群成员、好友、反馈等平台事件。',
'面向平台事件的处理逻辑,可用于消息、群成员、好友、反馈等事件。',
pipelineType: 'Pipeline', pipelineType: 'Pipeline',
kindBadgeAgent: 'Agent', kindBadgeAgent: 'Agent',
kindBadgePipeline: '流水线', kindBadgePipeline: '流水线',
@@ -528,12 +527,13 @@ const zhHans = {
basicInfo: '基础信息', basicInfo: '基础信息',
basicInfoDescription: '设置名称、图标、描述和启用状态', basicInfoDescription: '设置名称、图标、描述和启用状态',
runnerSettings: '运行器', runnerSettings: '运行器',
eventCapability: '事件能力', advanced: '高级',
eventCapabilityDescription: bindableEvents: '可绑定事件范围',
'声明此 Agent 编排可被绑定到哪些事件。每行一个事件模式,支持 * 与 namespace.*。', bindableEventsDescription:
supportedEvents: '支持的事件', '限制此 Agent 可被机器人事件路由选择的事件范围。通常保持默认即可。',
supportedEvents: '事件范围',
supportedEventsDescription: supportedEventsDescription:
'例如 *、message.received、group.*。Pipeline 固定仅支持 message.*。', '每行一个事件模式,例如 *、message.received、group.*。Pipeline 固定仅支持 message.*。',
enabled: '启用 Agent', enabled: '启用 Agent',
enabledDescription: '禁用后,此 Agent 不应被事件路由选中。', enabledDescription: '禁用后,此 Agent 不应被事件路由选中。',
nameRequired: '名称不能为空', nameRequired: '名称不能为空',
@@ -544,10 +544,10 @@ const zhHans = {
saveError: '保存失败:', saveError: '保存失败:',
deleteSuccess: '删除成功', deleteSuccess: '删除成功',
deleteError: '删除失败:', deleteError: '删除失败:',
deleteConfirmation: '你确定要删除这个 Agent 编排吗?', deleteConfirmation: '你确定要删除这个 Agent 吗?',
dangerZone: '危险区域', dangerZone: '危险区域',
dangerZoneDescription: '不可逆的操作', dangerZoneDescription: '不可逆的操作',
deleteAgentAction: '删除此 Agent 编排', deleteAgentAction: '删除此 Agent',
deleteAgentHint: '删除后,绑定到它的事件将无法继续执行。', deleteAgentHint: '删除后,绑定到它的事件将无法继续执行。',
noRunnerMetadata: '当前没有可用的 AgentRunner 元数据。', noRunnerMetadata: '当前没有可用的 AgentRunner 元数据。',
}, },
+17 -14
View File
@@ -317,7 +317,7 @@ const zhHant = {
getBotConfigError: '取得機器人設定失敗:', getBotConfigError: '取得機器人設定失敗:',
saveSuccess: '儲存成功', saveSuccess: '儲存成功',
saveError: '儲存失敗:', saveError: '儲存失敗:',
createSuccess: '建立成功 請啟用或修改綁定流程線', createSuccess: '建立成功,請設定事件路由',
createError: '建立失敗:', createError: '建立失敗:',
deleteSuccess: '刪除成功', deleteSuccess: '刪除成功',
deleteError: '刪除失敗:', deleteError: '刪除失敗:',
@@ -347,6 +347,9 @@ const zhHant = {
basicInfoDescription: '設定機器人名稱和描述', basicInfoDescription: '設定機器人名稱和描述',
routingConnection: '路由與連接', routingConnection: '路由與連接',
routingConnectionDescription: '綁定處理此機器人訊息的流程線', routingConnectionDescription: '綁定處理此機器人訊息的流程線',
eventRouting: '事件路由',
eventRoutingDescription:
'選擇此機器人收到不同事件時交給哪個處理器。具體處理邏輯在 Agent 頁面編輯,Pipeline 僅支援訊息事件。',
routingRules: '條件路由規則', routingRules: '條件路由規則',
routingRulesDescription: routingRulesDescription:
'按順序匹配,命中第一條規則後路由到對應流程線;都不匹配時使用上方預設流程線', '按順序匹配,命中第一條規則後路由到對應流程線;都不匹配時使用上方預設流程線',
@@ -452,13 +455,12 @@ const zhHant = {
}, },
agents: { agents: {
title: 'Agent', title: 'Agent',
description: '管理 Agent 編排與 Pipeline,並將它們綁定到機器人事件', description: '建立可重用的處理器,並在機器人事件路由中使用',
create: '建立 Agent', create: '建立處理器',
editAgent: '編輯 Agent 編排', editAgent: '編輯 Agent',
selectFromSidebar: '從側邊欄選擇一個 Agent 或 Pipeline', selectFromSidebar: '從側邊欄選擇一個 Agent 或 Pipeline',
agentOrchestration: 'Agent 編排', agentType: 'Agent',
agentOrchestrationDescription: agentTypeDescription: '透過執行器處理訊息、群成員、好友、回饋等平台事件。',
'面向平台事件的處理邏輯,可用於訊息、群成員、好友、回饋等事件。',
pipelineType: 'Pipeline', pipelineType: 'Pipeline',
kindBadgeAgent: 'Agent', kindBadgeAgent: 'Agent',
kindBadgePipeline: '流水線', kindBadgePipeline: '流水線',
@@ -471,12 +473,13 @@ const zhHant = {
basicInfo: '基本資訊', basicInfo: '基本資訊',
basicInfoDescription: '設定名稱、圖示、描述和啟用狀態', basicInfoDescription: '設定名稱、圖示、描述和啟用狀態',
runnerSettings: '執行器', runnerSettings: '執行器',
eventCapability: '事件能力', advanced: '進階',
eventCapabilityDescription: bindableEvents: '可綁定事件範圍',
'宣告此 Agent 編排可被綁定到哪些事件。每行一個事件模式,支援 * 與 namespace.*。', bindableEventsDescription:
supportedEvents: '支援的事件', '限制此 Agent 可被機器人事件路由選擇的事件範圍。通常保持預設即可。',
supportedEvents: '事件範圍',
supportedEventsDescription: supportedEventsDescription:
'例如 *、message.received、group.*。Pipeline 固定僅支援 message.*。', '每行一個事件模式,例如 *、message.received、group.*。Pipeline 固定僅支援 message.*。',
enabled: '啟用 Agent', enabled: '啟用 Agent',
enabledDescription: '停用後,此 Agent 不應被事件路由選中。', enabledDescription: '停用後,此 Agent 不應被事件路由選中。',
nameRequired: '名稱不能為空', nameRequired: '名稱不能為空',
@@ -487,10 +490,10 @@ const zhHant = {
saveError: '儲存失敗:', saveError: '儲存失敗:',
deleteSuccess: '刪除成功', deleteSuccess: '刪除成功',
deleteError: '刪除失敗:', deleteError: '刪除失敗:',
deleteConfirmation: '你確定要刪除這個 Agent 編排嗎?', deleteConfirmation: '你確定要刪除這個 Agent 嗎?',
dangerZone: '危險區域', dangerZone: '危險區域',
dangerZoneDescription: '不可逆的操作', dangerZoneDescription: '不可逆的操作',
deleteAgentAction: '刪除此 Agent 編排', deleteAgentAction: '刪除此 Agent',
deleteAgentHint: '刪除後,綁定到它的事件將無法繼續執行。', deleteAgentHint: '刪除後,綁定到它的事件將無法繼續執行。',
noRunnerMetadata: '目前沒有可用的 AgentRunner 中繼資料。', noRunnerMetadata: '目前沒有可用的 AgentRunner 中繼資料。',
}, },