"""渠道用例服务聚合与请求级 factory。 本模块是编排层的用例装配点,负责将请求级被驱动适配器、 应用级单例(注册中心等)与领域服务装配为 ``ChannelUseCases`` 聚合 (含 6 个用例服务实例与 18 个类型化领域端口绑定),对齐 external_systems 的 ``UseCases`` + ``create_use_cases_from_db(db)`` 模式。 装配顺序: 1. ``create_driven_adapters(db, session_factory, ...)`` 创建被驱动适配器聚合 2. 从 DI 容器获取应用级单例(注册中心等) 3. 按依赖图拓扑顺序构造领域服务 4. 通过 ``Pipeline.create()`` 创建管道 5. 实例化用例服务并注入依赖 """ # ruff: noqa: I001 # 本文件为组合根,200+ 行导入按装配语义分组(管道/用例/DTO/适配器/注册表/领域服务/DI), # 与 isort 的字母序合并规则冲突,故豁免 I001 以保留可读性。 from __future__ import annotations from collections.abc import Iterable from dataclasses import dataclass from typing import Any from arq import ArqRedis from redis.asyncio import Redis from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from yuxi.channels.adapters import DrivenAdapters, create_driven_adapters from yuxi.channels.adapters.default_content_moderation_adapter import ( DefaultContentModerationAdapter, ) from yuxi.channels.application.circuit_breaker.channel_circuit_breaker import ( ChannelCircuitBreaker, ) from yuxi.channels.application.executor.channel_tool_executor import ChannelToolExecutor from yuxi.channels.application.executor.message_operation_executor import ( MessageOperationExecutor, ) from yuxi.channels.application.health.channel_probe import ChannelProbe from yuxi.channels.application.health.health_aggregator import HealthAggregator from yuxi.channels.application.lifecycle.plugin_lifecycle_manager import ( PluginLifecycleManager, ) from yuxi.channels.application.lifecycle.plugin_loader import PluginLoader from yuxi.channels.application.lifecycle.config_scope_registry import ( ConfigScopeRegistry, ) from yuxi.channels.application.lifecycle.sensitive_field_registry import ( SensitiveFieldRegistry, ) from yuxi.channels.application.pipeline.control_plane.audit_context_builder import ( AuditContextBuilder, ) from yuxi.channels.application.pipeline.control_plane.control_plane_pipeline import ( ControlPlanePipeline, ) # 管道 from yuxi.channels.application.pipeline.inbound.inbound_pipeline import InboundPipeline from yuxi.channels.application.pipeline.outbound.outbound_pipeline import ( OutboundPipeline, ) # framework 层应用级单例(健康聚合器、插件生命周期管理器) from yuxi.channels.application.executor.pre_tool_call_trusted_injector import ( PreToolCallTrustedInjector, ) # 用例服务实现(唯一允许 import 用例实现类的地方) from yuxi.channels.application.usecase.admin_message_service import AdminMessageService from yuxi.channels.application.usecase.channel_control_service import ( ChannelControlService, ) from yuxi.channels.application.usecase.content_review_query_service import ( ContentReviewQueryService, ) from yuxi.channels.application.usecase.health_check_service import HealthCheckService from yuxi.channels.application.usecase.inbound_message_service import ( InboundMessageService, ) from yuxi.channels.application.usecase.plugin_lifecycle_service import ( PluginLifecycleService, ) # DTO from yuxi.channels.contract.dtos.channel import ChannelType from yuxi.channels.contract.dtos.outbox import OutboxConfig, OutboxConfigHolder # 错误类型(装配期冲突校验,INV-7 错误显式化) from yuxi.channels.contract.errors import RuleViolationError # 适配器协议(管道注册表键类型) from yuxi.channels.contract.plugin.adapters.attachment_upload_adapter import ( AttachmentUploadAdapter, ) from yuxi.channels.contract.plugin.adapters.command_adapter import CommandAdapter from yuxi.channels.contract.plugin.adapters.content_moderation_adapter import ( ContentModerationAdapter, ) from yuxi.channels.contract.plugin.adapters.directory_adapter import DirectoryAdapter from yuxi.channels.contract.plugin.adapters.doctor_adapter import DoctorAdapter from yuxi.channels.contract.plugin.adapters.inbound_adapter import InboundAdapter from yuxi.channels.contract.plugin.adapters.lifecycle_adapter import ( LifecycleAdapter, ) from yuxi.channels.contract.plugin.adapters.login_adapter import LoginAdapter from yuxi.channels.contract.plugin.adapters.mention_adapter import MentionAdapter from yuxi.channels.contract.plugin.adapters.message_ops_adapter import MessageOpsAdapter from yuxi.channels.contract.plugin.adapters.outbound_adapter import OutboundAdapter from yuxi.channels.contract.plugin.adapters.rich_message_adapter import RichMessageAdapter from yuxi.channels.contract.plugin.adapters.session_adapter import SessionAdapter from yuxi.channels.contract.plugin.adapters.status_adapter import StatusAdapter from yuxi.channels.contract.plugin.adapters.streaming_adapter import ( StreamingAdapter, ) from yuxi.channels.contract.plugin.adapters.tools_adapter import ToolsAdapter from yuxi.channels.contract.plugin.adapters.webhook_test_adapter import WebhookTestAdapter from yuxi.channels.contract.plugin.adapters.whitelist_adapter import WhitelistAdapter from yuxi.channels.contract.plugin.adapters.wizard_adapter import WizardAdapter from yuxi.channels.adapters import MessageOpsPortAdapter # 适配器类型(管道注册表值类型) from yuxi.channels.contract.ports.driven.agent_run_execution_port import ( AgentRunExecutionPort, ) from yuxi.channels.contract.ports.driven.cache_port import CachePort from yuxi.channels.contract.ports.driven.channel_context_provider_port import ( ChannelContextProviderPort, ) from yuxi.channels.contract.ports.driven.channel_session_repository_port import ( ChannelSessionRepositoryPort, ) from yuxi.channels.contract.ports.driven.channel_tool_executor_port import ( ChannelToolExecutorPort, ) from yuxi.channels.contract.ports.driven.content_review_repository_port import ( ContentReviewRepositoryPort, ) # EventPublisherPort(应用层通过此端口契约依赖事件发布能力,组合根绑定到 EventBus) from yuxi.channels.contract.ports.driven.audit_log_repository_port import ( AuditLogRepositoryPort, ) from yuxi.channels.contract.ports.driven.idempotency_repository_port import ( IdempotencyRepositoryPort, ) from yuxi.channels.contract.ports.driven.event_publisher_port import EventPublisherPort from yuxi.channels.contract.ports.driven.outbox_repository_port import ( OutboxRepositoryPort, ) from yuxi.channels.contract.ports.driven.pairing_repository_port import ( PairingRepositoryPort, ) from yuxi.channels.contract.ports.driven.queue_port import QueuePort from yuxi.channels.contract.ports.driven.realtime_metrics_port import ( RealtimeMetricsPort, ) from yuxi.channels.contract.ports.driving.account_management_port import ( AccountManagementPort, ) from yuxi.channels.contract.ports.driving.admin_message_port import AdminMessagePort from yuxi.channels.contract.ports.driving.analytics_view_port import ( AnalyticsViewPort, ) from yuxi.channels.contract.ports.driving.audit_query_port import AuditQueryPort from yuxi.channels.contract.ports.driving.capability_query_port import ( CapabilityQueryPort, ) from yuxi.channels.contract.ports.driving.channel_login_port import ( ChannelLoginPort, ) from yuxi.channels.contract.ports.driving.config_management_port import ( ConfigManagementPort, ) from yuxi.channels.contract.ports.driving.content_review_port import ContentReviewPort from yuxi.channels.contract.ports.driving.content_review_query_port import ( ContentReviewQueryPort, ) from yuxi.channels.contract.ports.driving.dashboard_view_port import ( DashboardViewPort, ) from yuxi.channels.contract.ports.driving.directory_port import DirectoryPort from yuxi.channels.contract.ports.driving.doctor_port import DoctorPort from yuxi.channels.contract.ports.driving.health_check_port import HealthCheckPort from yuxi.channels.contract.ports.driving.inbound_message_port import ( InboundMessagePort, ) from yuxi.channels.contract.ports.driving.message_management_port import ( MessageManagementPort, ) from yuxi.channels.contract.ports.driving.outbox_management_port import ( OutboxManagementPort, ) from yuxi.channels.contract.ports.driving.pairing_management_port import ( PairingManagementPort, ) from yuxi.channels.contract.ports.driving.plugin_lifecycle_port import ( PluginLifecyclePort, ) from yuxi.channels.contract.ports.driving.plugin_management_port import ( PluginManagementPort, ) from yuxi.channels.contract.ports.driving.route_binding_management_port import ( RouteBindingManagementPort, ) from yuxi.channels.contract.ports.driving.session_management_port import ( SessionManagementPort, ) from yuxi.channels.contract.ports.driving.user_binding_port import ( UserBindingPort, ) from yuxi.channels.contract.ports.driving.whitelist_management_port import ( WhitelistManagementPort, ) from yuxi.channels.contract.ports.driving.wizard_port import WizardPort # 注册表(应用级单例) from yuxi.channels.core.registry.capability_registry import CapabilityRegistry from yuxi.channels.core.registry.command_registry import CommandRegistryTable from yuxi.channels.core.registry.identity_resolver_registry import ( IdentityResolverRegistry, ) from yuxi.channels.core.registry.plugin_registry import PluginRegistry from yuxi.channels.core.registry.route_match_registry import RouteMatchRegistry from yuxi.channels.core.registry.whitelist_registry import WhitelistRegistry # 领域服务 from yuxi.channels.core.service.account_creation_service import ( AccountCreationService, ) from yuxi.channels.core.service.account_lifecycle_service import ( AccountLifecycleService, ) from yuxi.channels.core.service.ack_decision_maker import AckDecisionMaker from yuxi.channels.core.service.bot_loop_budget_guard import BotLoopBudgetGuard from yuxi.channels.core.service.capability_verifier import CapabilityVerifier from yuxi.channels.core.service.command_registry import CommandRegistry from yuxi.channels.core.service.common_command_adapter import CommonCommandAdapter from yuxi.channels.core.service.config_manager import ConfigManager from yuxi.channels.core.service.credential_service import CredentialService from yuxi.channels.core.service.degradation_manager import DegradationManager from yuxi.channels.core.service.dm_security_guard import DmSecurityGuard from yuxi.channels.core.service.doctor_service import DoctorService from yuxi.channels.core.service.fence_guard import FenceGuard from yuxi.channels.core.service.identity_resolver import IdentityResolver from yuxi.channels.core.service.mention_evaluator import MentionEvaluator from yuxi.channels.core.service.qr_login_service import QrLoginService from yuxi.channels.core.service.route_resolver import RouteResolver from yuxi.channels.core.service.session_merger import SessionMerger from yuxi.channels.core.service.status_writeback_handler import StatusWritebackHandler from yuxi.channels.core.service.truncation_detector import TruncationDetector from yuxi.channels.core.service.trusted_message_guard import TrustedMessageGuard from yuxi.channels.core.service.wizard_service import WizardService # DI 容器 from yuxi.channels.infrastructure.dependency_injection import ( DependencyInjectionContainer, ) # 全局配置(组合根读取配置源,构造 OutboxConfig 注入应用层,§6.1) from yuxi.config.app import config as app_config __all__ = [ "ChannelUseCases", "create_channel_use_cases", ] @dataclass class ChannelUseCases: """渠道用例服务聚合。 串联 ``create_driven_adapters(db, session_factory, ...)`` → 领域服务 → 管道 → 用例服务。 请求级创建,共享同一 ``db`` session。 对齐 external_systems 的 ``UseCases`` dataclass 模式。字段类型使用驱动 端口 Protocol(非实现类),保证调用方只依赖端口。 字段: inbound_message: 入站消息用例(实现 InboundMessagePort)。 admin_message: 管理员消息用例(实现 AdminMessagePort)。 plugin_lifecycle: 插件生命周期用例(实现 PluginLifecyclePort)。 health_check: 健康检查用例(实现 HealthCheckPort)。 channel_tool_executor: 渠道工具执行器(实现 ChannelToolExecutorPort), 由 Agent 后端通过依赖注入显式获取,调用 ``executeChannelTool`` 路由到对应插件的 ``executeTool``(FR-11)。 wizard: 安装向导用例(实现 WizardPort),覆盖向导步骤查询 / 校验 / 应用 / 完成与 OAuth 回调(FR-16)。 doctor: 配置诊断用例(实现 DoctorPort),覆盖诊断检查项查询 / 全量 与单项检查 / 自动修复(FR-17)。 whitelist_management: 白名单管理用例(实现 WhitelistManagementPort), 覆盖白名单查询 / 添加 / 移除(FR-18)。 directory: 目录查询用例(实现 DirectoryPort),覆盖用户与群组 搜索 / 资料与成员查询(FR-14)。 pairing_management: 配对审批管理用例(实现 PairingManagementPort), 覆盖配对记录查询 / 批准 / 拒绝 / 撤销(FR-33)。 config_management: 配置热更新管理用例(实现 ConfigManagementPort), 覆盖配置查询 / 更新 / 回滚 / 版本历史(FR-37)。 session_management: 会话管理用例(实现 SessionManagementPort),覆盖 会话合并、所有者转移、关闭与统计(FR-07 / FR-26)。 user_binding: 用户绑定用例(实现 UserBindingPort),覆盖渠道会话 统一身份的绑定 / 解绑 / 状态查询(P3 渐进式绑定,不走控制面管道)。 audit_query: 审计查询用例(实现 AuditQueryPort),覆盖审计日志查询 (FR-34)。 account_management: 账户生命周期管理用例(实现 AccountManagementPort), 覆盖账户创建 / 更新 / 删除 / 启用 / 禁用 / 查询 / 列表(AL-01~AL-04)。 login: 扫码登录用例(实现 ChannelLoginPort),覆盖二维码生成 / 状态 轮询 / 登录确认回调 / 登录态查询(QR-03~QR-05 + 运维排查)。 message_management: 消息管理用例(实现 MessageManagementPort),覆盖 会话消息查询、全文搜索、状态查询与消息运维操作(撤回 / 重发 / 附件上传,运维排查 / 审计用例)。 plugin_management: 插件生命周期管理用例(实现 PluginManagementPort), 覆盖插件加载 / 启动 / 暂停 / 恢复 / 停止 / 卸载 / 重载(FR-32), 通过控制面管道统一执行认证 / 权限 / 限流 / 分派 / 审计五阶段。 outbox_management: 发件箱管理用例(实现 OutboxManagementPort),覆盖 outbox 条目查询 / 统计 / 重投 / 死信管理与重试策略查询(OBX-01~OBX-08)。 capability_query: 能力查询用例(实现 CapabilityQueryPort),覆盖渠道 能力列表、单渠道能力详情与渠道能力画像矩阵查询 (CAP-01 / CAP-02 / CAP-03),绑定到 ``ChannelControlService`` 同一实例(第 15 个类型化端口),聚合 PluginRegistry 中插件的 manifest.capabilities 声明与运行时可用性。 content_review: 内容审核用例(实现 ContentReviewPort),覆盖管理员 主动触发的 dry-run 预审核(CR-01),绑定到 ``ChannelControlService`` 同一实例(第 16 个类型化端口),经控制面管道执行 ``content_review/preview`` 操作。 content_review_query: 内容审核历史查询用例(实现 ContentReviewQueryPort), 覆盖审核历史列表与详情查询(CR-02 / CR-03),由独立的 ``ContentReviewQueryService`` 实现,不经控制面管道(数据面语义)。 dashboard_view: 聚合视图用例(实现 DashboardViewPort),覆盖全局总览 / 账户总览 / 消息总览 / 会话总览 / 投递总览 / 实时监控指标查询 (DSB-01~DSB-04 / DSB-DELIVERY / DSB-REALTIME),绑定到 ``ChannelControlService`` 同一实例(第 17 个类型化端口),跨子域 KPI 聚合,只读无副作用。 analytics_view: 分析视图用例(实现 AnalyticsViewPort),覆盖消息深度 分析 / 消息类型分布 / 会话分析 / 投递链路分析 / 投递延迟分布 / 投递漏斗分析(ANL-01 / ANL-02 / ANL-04 ~ ANL-07),绑定到 ``ChannelControlService`` 同一实例(第 19 个类型化端口),经控制 面管道五阶段处理。 route_binding_management: 路由绑定管理用例(实现 RouteBindingManagementPort),覆盖路由绑定规则列表 / 创建 / 更新 / 删除 / 解析测试(route_binding/list / create / update / delete / resolve),绑定到 ``ChannelControlService`` 同一实例 (第 20 个类型化端口),经控制面管道执行路由绑定管理操作。 """ inbound_message: InboundMessagePort admin_message: AdminMessagePort plugin_lifecycle: PluginLifecyclePort health_check: HealthCheckPort channel_tool_executor: ChannelToolExecutorPort # 控制面健康子集端口(ChannelControlService 实现 HealthCheckPort 的 # getSingleHealth / probeChannelDeep 控制面方法,组合根将同一实例 # 绑定到此字段,与数据面 health_check 字段分离以避免模板混淆)。 health_check_control: HealthCheckPort # 类型化领域端口(ChannelControlService 同时实现这些端口,组合根将同一 # 实例绑定到各字段,调用方按窄端口依赖) wizard: WizardPort doctor: DoctorPort whitelist_management: WhitelistManagementPort directory: DirectoryPort pairing_management: PairingManagementPort config_management: ConfigManagementPort session_management: SessionManagementPort user_binding: UserBindingPort audit_query: AuditQueryPort account_management: AccountManagementPort login: ChannelLoginPort message_management: MessageManagementPort plugin_management: PluginManagementPort outbox_management: OutboxManagementPort capability_query: CapabilityQueryPort content_review: ContentReviewPort content_review_query: ContentReviewQueryPort dashboard_view: DashboardViewPort analytics_view: AnalyticsViewPort route_binding_management: RouteBindingManagementPort def _fill_adapter_registry[T]( registry: dict[ChannelType, T], adapters: Iterable[T], channel_type: ChannelType, *, duplicate_rule: str | None = None, ) -> None: """将插件适配器收集到注册表,最后注册者覆盖。 每类适配器每个 ChannelType 仅允许一个实例。``duplicate_rule`` 设置时, 重复注册抛 ``RuleViolationError``(INV-7 错误显式化,不静默兜底)。 Args: registry: 目标注册表(按 ChannelType 索引)。 adapters: 插件注册的适配器列表。 channel_type: 当前渠道类型。 duplicate_rule: 若设置,重复注册时抛错,rule 为 ``{duplicate_rule}:{channel_type}``。 """ for adapter in adapters: if duplicate_rule is not None and channel_type in registry: raise RuleViolationError( rule=f"{duplicate_rule}:{channel_type}", ) registry[channel_type] = adapter def create_channel_use_cases( db: AsyncSession, di_container: DependencyInjectionContainer, ) -> ChannelUseCases: """请求级 factory,创建用例服务聚合。 装配顺序(对齐 external_systems 的 ``create_use_cases_from_db`` 模式): 1. ``create_driven_adapters(db, session_factory, ...)`` 创建被驱动适配器聚合 2. 从 DI 容器获取应用级单例(注册中心等) 3. 创建领域服务(按依赖图拓扑顺序) 4. 通过 ``Pipeline.create()`` 创建管道 5. 实例化用例服务并注入依赖 Args: db: SQLAlchemy 异步会话(请求级),被驱动适配器共享此会话。 di_container: 依赖注入容器,提供应用级单例。 Returns: 装配完成的 ``ChannelUseCases`` 实例(6 个独立用例服务实例 + 18 个类型化领域端口绑定,详见 ``ChannelUseCases`` 字段文档)。 """ # 组合根从配置源构造 OutboxConfig 注入应用层,消除应用层对 yuxi.config.app # 的直接依赖(§6.1 应用服务层禁止依赖具体技术适配器)。 # 同时构造 OutboxConfigHolder 支持 updateRetryPolicy 热更新(S2 修复): # holder 在本次请求范围内共享给 OutboxHandler,使 updateRetryPolicy 的 # 内存更新对 retry_policy 查询立即生效;ConfigPort 持久化保证跨请求最终 # 一致性。 outbox_config = OutboxConfig( ttl_seconds=app_config.channel_outbox_ttl_seconds, retry_backoff_schedule=tuple(app_config.channel_outbox_retry_backoff_schedule), max_retry=app_config.channel_outbox_max_retry, ) outbox_config_holder = OutboxConfigHolder(outbox_config) # 1. 被驱动适配器(请求级,共享 db) # Redis 客户端、ARQ 连接池、AgentRunExecutionPort 从 DI 容器解析 # (由 create_host_bootstrap 注册为单例),注入到对应适配器构造函数 # (构造注入,INV-5 / ADP-001 / ADP-005 / ADP-022)。 # EventPublisherPort 同样从 DI 容器解析,注入到 ConfigManager 用于 # 配置变更后发布领域事件(CON-030 / ADP-029,事件由应用层发布)。 # F-02:ConfigScopeRegistry 从 DI 容器解析,提取 key_to_scope_map # 注入到请求级 RedisConfigAdapter 供 _build_key 校验作用域一致性。 # session_factory(async_sessionmaker)从 DI 容器解析,注入到 # ChannelPersistenceAdapter 供 _session_scope(tx) 按需创建独立 session # (无状态适配器不持有请求级 db)。 redis_client: Redis = di_container.resolve(Redis) arq_pool: ArqRedis = di_container.resolve(ArqRedis) execution_port: AgentRunExecutionPort = di_container.resolve(AgentRunExecutionPort) event_publisher: EventPublisherPort = di_container.resolve(EventPublisherPort) queue_port: QueuePort = di_container.resolve(QueuePort) config_scope_registry: ConfigScopeRegistry = di_container.resolve(ConfigScopeRegistry) session_factory: async_sessionmaker = di_container.resolve(async_sessionmaker) adapters: DrivenAdapters = create_driven_adapters( db, session_factory=session_factory, outbox_config=outbox_config, redis_client=redis_client, arq_pool=arq_pool, execution_port=execution_port, key_to_scope_map=config_scope_registry.key_to_scope_map, ) # 2. 应用级单例(从 DI 容器获取) plugin_registry: PluginRegistry = di_container.resolve(PluginRegistry) capability_registry: CapabilityRegistry = di_container.resolve(CapabilityRegistry) command_registry_table: CommandRegistryTable = di_container.resolve(CommandRegistryTable) identity_resolver_registry: IdentityResolverRegistry = di_container.resolve(IdentityResolverRegistry) route_match_registry: RouteMatchRegistry = di_container.resolve(RouteMatchRegistry) whitelist_registry: WhitelistRegistry = di_container.resolve(WhitelistRegistry) plugin_lifecycle_manager: PluginLifecycleManager = di_container.resolve(PluginLifecycleManager) health_aggregator: HealthAggregator = di_container.resolve(HealthAggregator) channel_circuit_breaker: ChannelCircuitBreaker = di_container.resolve(ChannelCircuitBreaker) # 内容审核域应用级单例(由 create_host_bootstrap 注册到 DI 容器): # - DefaultContentModerationAdapter:未注册插件渠道时的兜底审核适配器, # 注入 DispatchStage 供 content_review/preview 选择适配器。 # - ContentReviewRepositoryPort:审核历史仓储端口绑定,注入 DispatchStage # (写路径)与 ContentReviewQueryService(读路径)。 default_moderation_adapter: DefaultContentModerationAdapter = di_container.resolve(DefaultContentModerationAdapter) # ContentReviewRepositoryPort 从 DI 容器解析(无状态单例,由 # create_host_bootstrap 注册)。适配器通过 _session_scope(tx) 按需获取 # session:tx 非空时复用应用层主事务 session,tx 为 None 时自主创建并提交。 review_repository: ContentReviewRepositoryPort = di_container.resolve(ContentReviewRepositoryPort) # PluginLoader 应用级单例(P1 PLG-INSTALL/UNINSTALL 文件操作),由 # create_host_bootstrap 注册到 DI 容器,注入 DispatchStage。 plugin_loader: PluginLoader = di_container.resolve(PluginLoader) # F-01:敏感字段注册表应用级单例,由 create_host_bootstrap 在 # _loadPlugins discover 后调用 register(manifests) 合并插件声明的 # 敏感字段。注入到 ControlPlanePipeline.create(config/export 过滤) # 与独立 AuditContextBuilder(params_summary 脱敏)。 sensitive_registry: SensitiveFieldRegistry = di_container.resolve(SensitiveFieldRegistry) # 3. 领域服务(按依赖图拓扑顺序构造) # 3.1 纯函数服务(无端口依赖) mention_evaluator = MentionEvaluator() truncation_detector = TruncationDetector() # 3.2 单端口服务 fence_guard = FenceGuard( cache_port=adapters.cache, config_port=adapters.config, logger=adapters.logger, ) trusted_message_guard = TrustedMessageGuard( conversation_port=adapters.conversation, logger=adapters.logger, ) config_manager = ConfigManager( config_port=adapters.config, event_publisher=event_publisher, logger=adapters.logger, ) ack_decision_maker = AckDecisionMaker( config_port=adapters.config, cache_port=adapters.cache, logger=adapters.logger, ) # 3.3 端口 + 注册中心 capability_verifier = CapabilityVerifier( cache_port=adapters.cache, registry=capability_registry, logger=adapters.logger, ) degradation_manager = DegradationManager( cache_port=adapters.cache, plugin_registry=plugin_registry, logger=adapters.logger, ) # 通用命令与内置身份解析器由 bootstrap 一次性注册到应用级单例注册表 # (见 ``create_host_bootstrap``),此处仅构造领域服务封装。 command_registry = CommandRegistry(registry=command_registry_table) route_resolver = RouteResolver( registry=route_match_registry, config_port=adapters.config, cache_port=adapters.cache, logger=adapters.logger, ) # 3.4 嵌套依赖(关键:BotLoopBudgetGuard 必须先于 DmSecurityGuard 构造) bot_loop_budget_guard = BotLoopBudgetGuard( cache_port=adapters.cache, config_port=adapters.config, logger=adapters.logger, ) dm_security_guard = DmSecurityGuard( persistence_port=adapters.persistence, whitelist_registry=whitelist_registry, bot_loop_guard=bot_loop_budget_guard, logger=adapters.logger, ) identity_resolver = IdentityResolver( registry=identity_resolver_registry, config_port=adapters.config, cache_port=adapters.cache, logger=adapters.logger, ) session_merger = SessionMerger( conversation_port=adapters.conversation, persistence_port=adapters.persistence, logger=adapters.logger, ) # 状态回写处理器(FR-09):协调 ConversationPort 与 PersistencePort # 完成渠道侧状态事件回写,含"已发未确认"推进与持久化记录反查。 status_writeback_handler = StatusWritebackHandler( conversation_port=adapters.conversation, persistence_port=adapters.persistence, logger=adapters.logger, ) # 4. 管道(请求级,注入适配器与领域服务) # 4.1 适配器注册表(从 PluginRegistry 读取插件注册的适配器填充) # 约束:每类适配器每个 ChannelType 仅允许一个实例(最后注册者覆盖)。 # 插件注册时由 PluginRegistry 保证唯一性,此处取最后值填充注册表。 status_adapter_registry: dict[ChannelType, StatusAdapter] = {} session_adapter_registry: dict[ChannelType, SessionAdapter] = {} inbound_adapter_registry: dict[ChannelType, InboundAdapter] = {} mention_adapter_registry: dict[ChannelType, MentionAdapter] = {} streaming_adapter_registry: dict[ChannelType, StreamingAdapter] = {} outbound_adapter_registry: dict[ChannelType, OutboundAdapter] = {} rich_message_adapter_registry: dict[ChannelType, RichMessageAdapter] = {} channel_context_provider_registry: dict[ChannelType, ChannelContextProviderPort] = {} command_adapter_registry: dict[ChannelType, CommandAdapter] = {} tools_adapter_registry: dict[ChannelType, ToolsAdapter] = {} message_ops_adapter_registry: dict[ChannelType, MessageOpsAdapter] = {} directory_adapter_registry: dict[ChannelType, DirectoryAdapter] = {} wizard_adapter_registry: dict[ChannelType, WizardAdapter] = {} doctor_adapter_registry: dict[ChannelType, DoctorAdapter] = {} whitelist_adapter_registry: dict[ChannelType, WhitelistAdapter] = {} lifecycle_adapter_registry: dict[ChannelType, LifecycleAdapter] = {} login_adapter_registry: dict[ChannelType, LoginAdapter] = {} content_moderation_adapter_registry: dict[ChannelType, ContentModerationAdapter] = {} webhook_test_adapter_registry: dict[ChannelType, WebhookTestAdapter] = {} attachment_upload_adapter_registry: dict[ChannelType, AttachmentUploadAdapter] = {} for channel_type, plugin_da in plugin_registry.listPluginAdapters(): _fill_adapter_registry(status_adapter_registry, plugin_da.status_adapters, channel_type) _fill_adapter_registry(session_adapter_registry, plugin_da.session_adapters, channel_type) _fill_adapter_registry(inbound_adapter_registry, plugin_da.inbound_adapters, channel_type) _fill_adapter_registry(mention_adapter_registry, plugin_da.mention_adapters, channel_type) _fill_adapter_registry(streaming_adapter_registry, plugin_da.streaming_adapters, channel_type) _fill_adapter_registry(outbound_adapter_registry, plugin_da.outbound_adapters, channel_type) _fill_adapter_registry(rich_message_adapter_registry, plugin_da.rich_message_adapters, channel_type) _fill_adapter_registry(channel_context_provider_registry, plugin_da.channel_context_providers, channel_type) _fill_adapter_registry(command_adapter_registry, plugin_da.command_adapters, channel_type) _fill_adapter_registry(tools_adapter_registry, plugin_da.tools_adapters, channel_type) _fill_adapter_registry(message_ops_adapter_registry, plugin_da.message_ops_adapters, channel_type) _fill_adapter_registry(directory_adapter_registry, plugin_da.directory_adapters, channel_type) _fill_adapter_registry(wizard_adapter_registry, plugin_da.wizard_adapters, channel_type) _fill_adapter_registry(doctor_adapter_registry, plugin_da.doctor_adapters, channel_type) _fill_adapter_registry(whitelist_adapter_registry, plugin_da.whitelist_adapters, channel_type) _fill_adapter_registry(lifecycle_adapter_registry, plugin_da.lifecycle_adapters, channel_type) _fill_adapter_registry(login_adapter_registry, plugin_da.login_adapters, channel_type) _fill_adapter_registry( content_moderation_adapter_registry, plugin_da.content_moderation_adapters, channel_type, duplicate_rule="content_moderation_adapter_duplicate", ) _fill_adapter_registry(webhook_test_adapter_registry, plugin_da.webhook_test_adapters, channel_type) _fill_adapter_registry(attachment_upload_adapter_registry, plugin_da.attachment_upload_adapters, channel_type) # 4.2 通用命令适配器(内置,跨渠道可用,FR-15) # whitelist_command_port 延迟回填:ChannelControlService 同时实现 # WhitelistManagementPort 与 WhitelistCommandPort,在 ControlPlanePipeline # 之后构造。此处先注入 logger,待 ChannelControlService 构造后通过 # setWhitelistCommandPort 回填(与 ChannelToolExecutor.setMessageOperationExecutor # 同模式)。 common_command_adapter = CommonCommandAdapter(logger=adapters.logger) # 实时指标采集器(进程级单例,由 create_host_bootstrap 按 # app_config.realtime_metrics_backend 选择 inmemory/redis 实现并注册到 DI, # 数据面管道采集 + 控制面 dashboard 查询共享同一实例) realtime_metrics: RealtimeMetricsPort = di_container.resolve(RealtimeMetricsPort) # 4.3 入站管道 # 服务账号端口单例:由 create_driven_adapters 创建,共享注入到入站管道 # ServiceAccountResolveStage、控制面管道 AccountHandler 与 AgentRunAdapter。 service_account_port = adapters.service_account # Agent 渠道访问配置端口单例:共享注入到入站管道 agent-run-enqueue 阶段 agent_access_config_port = adapters.agent_access_config inbound_pipeline = InboundPipeline.create( status_adapter_registry=status_adapter_registry, session_adapter_registry=session_adapter_registry, inbound_adapter_registry=inbound_adapter_registry, mention_adapter_registry=mention_adapter_registry, dm_security_guard=dm_security_guard, bot_loop_budget_guard=bot_loop_budget_guard, mention_evaluator=mention_evaluator, command_registry=command_registry, identity_resolver=identity_resolver, route_resolver=route_resolver, ack_decision_maker=ack_decision_maker, fence_guard=fence_guard, plugin_registry=plugin_registry, config_port=adapters.config, persistence_port=adapters.persistence, conversation_port=adapters.conversation, cache_port=adapters.cache, agent_run_port=adapters.agent_run, service_account_port=service_account_port, agent_access_config_port=agent_access_config_port, command_adapter_registry=command_adapter_registry, common_command_adapter=common_command_adapter, status_writeback_handler=status_writeback_handler, channel_context_provider_registry=channel_context_provider_registry, tools_adapter_registry=tools_adapter_registry, message_ops_adapter_registry=message_ops_adapter_registry, realtime_metrics=realtime_metrics, event_publisher=event_publisher, masking_port=adapters.masking, logger=adapters.logger, tracer_port=adapters.tracer, ) # 4.4 构造渠道工具执行器,作为 ``ChannelUseCases.channel_tool_executor`` # 字段返回,供 Agent 后端(``resolve_configured_runtime_tools``)通过 # 依赖注入显式获取并调用插件 executeTool(FR-11)。执行器持有 # tools_adapter_registry,按渠道类型路由到对应插件方法。同时注入 # MessageOperationExecutor 用于路由 ``渠道操作_`` 前缀工具调用(FR-12)。 # 由于 MessageOperationExecutor 依赖 message_ops_adapter_registry 与 # PreToolCallTrustedInjector(依赖 trusted_message_guard),需在 # 执行器构造后通过 setMessageOperationExecutor 回填引用,避免循环依赖。 # 不再通过模块级全局状态注册,符合 INV-3(契约显式化)与 §9.1 # (不得隐式全局注入)。 channel_tool_executor = ChannelToolExecutor(tools_adapter_registry) pre_tool_call_trusted_injector = PreToolCallTrustedInjector( trusted_message_guard=trusted_message_guard, logger=adapters.logger, ) message_operation_executor = MessageOperationExecutor( message_ops_adapter_registry=message_ops_adapter_registry, pre_tool_call_trusted_injector=pre_tool_call_trusted_injector, conversation_port=adapters.conversation, logger=adapters.logger, ) channel_tool_executor.setMessageOperationExecutor(message_operation_executor) # 4.5 出站管道 outbound_pipeline = OutboundPipeline.create( agent_run_port=adapters.agent_run, fence_guard=fence_guard, conversation_port=adapters.conversation, capability_verifier=capability_verifier, plugin_registry=plugin_registry, trusted_message_guard=trusted_message_guard, streaming_adapter_registry=streaming_adapter_registry, rich_message_adapter_registry=rich_message_adapter_registry, truncation_detector=truncation_detector, persistence_port=adapters.persistence, outbound_adapter_registry=outbound_adapter_registry, bot_loop_budget_guard=bot_loop_budget_guard, transaction_port=adapters.transaction, config_port=adapters.config, whitelist_registry=whitelist_registry, event_publisher=event_publisher, outbox_config=outbox_config, realtime_metrics=realtime_metrics, logger=adapters.logger, tracer_port=adapters.tracer, ) # 4.6 AuditContextBuilder 集中审计日志构造逻辑(D5),供 # AdminMessageService(非控制面管道路径,H-16 统一 fail-closed 语义) # 与 ChannelControlService(管道失败审计,AC-32)共用。需先于 # AdminMessageService 构造(注入其 _writeAuditLog 统一路径)。 audit_context_builder = AuditContextBuilder( audit_log_repo=adapters.persistence, logger=adapters.logger, masking_port=adapters.masking, # F-01:敏感字段注册表,审计日志 params_summary 脱敏。 sensitive_registry=sensitive_registry, ) # 4.7 AdminMessageService 需先于 ControlPlanePipeline 构造 # (ControlPlanePipeline 的 dispatch 阶段依赖 AdminMessagePort) # 非控制面管道路径:限流(cache_port)由用例服务自行实现,审计委托 # AuditContextBuilder 统一路径(H-16),不依赖 ControlPlanePipeline 的 # RateLimitStage / AuditStage。 admin_message_service = AdminMessageService( outbound_pipeline=outbound_pipeline, idempotency_repo=adapters.persistence, session_repo=adapters.persistence, account_repository=adapters.persistence, conversation_port=adapters.conversation, audit_context_builder=audit_context_builder, cache_port=adapters.cache, logger=adapters.logger, config_port=adapters.config, plugin_registry=plugin_registry, ) # 4.7.1 扫码登录领域服务(QR-03~QR-05) # 协调 LoginAdapter,编排二维码生成 / 状态轮询 / 登录确认回调。 # 登录态持久化到 ConfigPort 的 ACCOUNT 作用域(key=login_status), # 由 CredentialService 通过 setLoginStatus 写入。 # 注入到 ControlPlanePipeline 的 login_service 阶段。 # 注意:需先于 CredentialService / WizardService 构造(依赖关系)。 qr_login_service = QrLoginService( login_adapter_registry=login_adapter_registry, logger=adapters.logger, config_port=adapters.config, config_manager=config_manager, ) # 4.7.2 凭证编排服务(Task 11 DI 装配) # 渠道账号凭证的唯一落库入口,依赖 QrLoginService(QR 凭证获取)+ # ConfigPort(加密存储)+ CachePort(缓存失效)+ PersistencePort # (P1 聚合根持久化)+ LoggerPort。必须在 QrLoginService 之后构造 # (强依赖),经 ControlPlanePipeline.create 注入到 AccountHandler # (P1 enable/disable 链路 OFFLINE→ONLINE 凭证存在性校验)。 # WizardService 的 P2 finalize 凭证落库为未来规划,当前未消费。 credential_service = CredentialService( config_port=adapters.config, config_manager=config_manager, persistence_port=adapters.persistence, qr_login_service=qr_login_service, cache_port=adapters.cache, logger_port=adapters.logger, ) # 4.7.4 配置诊断领域服务(FR-17) # 协调 DoctorAdapter 与 ConfigPort,编排诊断检查项查询、单项检查、 # 全量检查与自动修复。已应用迁移列表从 CHANNEL 作用域读取(AC-64), # 单项检查异常隔离不中断整体诊断报告。 doctor_service = DoctorService( doctor_adapter_registry=doctor_adapter_registry, config_port=adapters.config, logger=adapters.logger, whitelist_registry=whitelist_registry, ) # 4.7.5 账户生命周期领域服务(AL-01~AL-04) # 协调 LifecycleAdapter,编排账户 ID 解析、配置规范化与生命周期回调 # (afterAccountConfigWritten / beforeAccountDelete / onAccountEnabled / # onAccountDisabled)。注入到 ControlPlanePipeline 的 lifecycle_service # 阶段。 account_lifecycle_service = AccountLifecycleService( lifecycle_adapter_registry=lifecycle_adapter_registry, logger=adapters.logger, ) # 4.7.6 账户创建领域服务(Task 6 装配) # 装配顺序:account_lifecycle_service → account_creation_service → # wizard_service → ControlPlanePipeline.create,避免循环依赖。 # 复用 lifecycle_service 的账户 ID 解析 / 配置规范化 / 回调能力, # 叠加 persistence_port 与 service_account_port 完成账户幂等创建, # 供 AccountHandler 与 WizardService.finalize 复用。 account_creation_service = AccountCreationService( lifecycle_service=account_lifecycle_service, persistence_port=adapters.persistence, service_account_port=service_account_port, event_publisher=event_publisher, logger=adapters.logger, ) # 4.7.3 安装向导领域服务(FR-16) # 协调 WizardAdapter 与 ConfigPort,编排向导步骤查询、校验、应用、 # 配置聚合与 OAuth 回调。向导状态持久化到 ConfigPort 的 CHANNEL 作用域。 # finalize 在写入 channel_config 后调用 AccountCreationService.create_account # 创建渠道账户(Task 6),并按 CredentialStrategy 通过 CredentialService # 将凭证写入 ACCOUNT 作用域,供运行时客户端读取并更新登录态。 credential_strategy_registry = { manifest.manifest.channel_type: manifest.manifest.credential_strategy for manifest in plugin_registry.listPlugins() if manifest.manifest.credential_strategy is not None } wizard_service = WizardService( wizard_adapter_registry=wizard_adapter_registry, login_adapter_registry=login_adapter_registry, config_port=adapters.config, logger=adapters.logger, account_creation_service=account_creation_service, credential_service=credential_service, credential_strategy_registry=credential_strategy_registry, ) # 4.8 控制面管道 # DispatchStage 不再依赖 AdminMessagePort / HealthAggregatorPort —— 前者 # 由 AdminMessageService 独立装配(见 4.6),后者由 HealthCheckService # 独立持有(见 5. HealthCheckService 装配),控制面 dispatch 阶段不涉及 # 这两类职责。 # 消息操作被驱动适配器(MSG-05 撤回用例):复用 4.1 收集的 # message_ops_adapter_registry,按 channel_type 路由到对应插件适配器, # 通过 ControlPlanePipeline.create 透传至 DispatchStage。 message_ops_port_adapter = MessageOpsPortAdapter( message_ops_adapter_registry=message_ops_adapter_registry, logger=adapters.logger, ) # 4.7.5 内容审核域装配(CR-01~CR-03) # content_moderation_adapter_registry 在 4.1 收集循环中已构建, # 同 channel_type 注册多个实现时抛 RuleViolationError(INV-7 错误 # 显式化,不静默兜底)。未注册时为空 dict,使用兜底适配器。 # ContentReviewQueryService 装配(数据面,不经控制面管道): # 直接读取 review_repository(ContentReviewRepositoryPort),覆盖 CR-02 # 历史列表与 CR-03 历史详情两个查询端点。查询无副作用,不写审计日志。 content_review_query_service = ContentReviewQueryService( review_repository=review_repository, logger=adapters.logger, ) # 渠道主动探测器(FR-35):供 account/runtime_status 聚合探测状态使用。 # 依赖均为请求级端口,随请求构造以保证端口引用与当前 db session 一致。 channel_probe = ChannelProbe( plugin_registry=plugin_registry, persistence_port=adapters.persistence, cache_port=adapters.cache, queue_port=queue_port, logger=adapters.logger, ) control_plane_pipeline = ControlPlanePipeline.create( persistence_port=adapters.persistence, config_manager=config_manager, config_port=adapters.config, session_merger=session_merger, degradation_manager=degradation_manager, whitelist_registry=whitelist_registry, cache_port=adapters.cache, event_publisher=event_publisher, plugin_registry=plugin_registry, wizard_service=wizard_service, directory_adapter_registry=directory_adapter_registry, doctor_service=doctor_service, whitelist_adapter_registry=whitelist_adapter_registry, logger=adapters.logger, lifecycle_service=account_lifecycle_service, login_service=qr_login_service, conversation_port=adapters.conversation, lifecycle_manager=plugin_lifecycle_manager, circuit_breaker=channel_circuit_breaker, message_ops_port=message_ops_port_adapter, outbox_repository=adapters.persistence, outbox_config=outbox_config, outbox_config_holder=outbox_config_holder, queue_port=queue_port, content_moderation_adapters=content_moderation_adapter_registry, default_moderation_adapter=default_moderation_adapter, review_repository=review_repository, masking_port=adapters.masking, transaction_port=adapters.transaction, plugin_loader=plugin_loader, webhook_test_adapters=webhook_test_adapter_registry, attachment_upload_adapters=attachment_upload_adapter_registry, channel_probe=channel_probe, realtime_metrics=realtime_metrics, service_account_port=service_account_port, # Task 11: 凭证编排服务,供 AccountHandler P1 enable/disable 链路 # 凭证存在性校验(OFFLINE→ONLINE 时 getCredentials)。 credential_service=credential_service, # Task 6: 账户创建服务,供 AccountHandler 与 WizardService.finalize # 复用,完成渠道账户幂等创建(resolveAccountId → saveChannelAccount)。 account_creation_service=account_creation_service, # F-01:敏感字段注册表,注入到 ConfigHandler(config/export 过滤) # 与管道内 AuditContextBuilder(params_summary 脱敏)。 sensitive_registry=sensitive_registry, # Task 13: 路由绑定管理依赖,注入到 RouteBindingHandler # (route_binding/* 系列操作)。route_binding_repository 复用 # persistence 适配器(实现 RouteBindingRepositoryPort)。 route_binding_repository=adapters.persistence, route_resolver=route_resolver, route_match_registry=route_match_registry, # Task 11: 管理员消息续投端口,注入到 MessageHandler 供 # admin-message/retry-failed 操作调用 retryFailedTargets。 admin_message_port=admin_message_service, tracer_port=adapters.tracer, ) # 5. 用例服务(请求级,注入管道与适配器) # PluginLifecycleManager / HealthAggregator 为应用级单例,从 DI 容器 # resolve 后注入用例服务,类型安全,不使用 Any。 # audit_context_builder 已在 4.6 构造(先于 AdminMessageService), # 此处复用同一实例注入 ChannelControlService(管道失败审计,AC-32)。 channel_control = ChannelControlService( control_plane_pipeline=control_plane_pipeline, transaction_port=adapters.transaction, audit_context_builder=audit_context_builder, logger=adapters.logger, user_identity_repository=adapters.persistence, session_repository=adapters.persistence, config_port=adapters.config, service_account_port=adapters.service_account, session_merger=session_merger, ) # 5.1 注入 ChannelControlService 作为 WhitelistCommandPort 实现(FR-15 / FR-18) # ChannelControlService 同时实现 WhitelistManagementPort 与 # WhitelistCommandPort:后者将 /allowlist 命令按 action 分派到 # listWhitelist / addWhitelistEntry / removeWhitelistEntry 类型化方法。 # CommonCommandAdapter 先于 ChannelControlService 构造,通过 setter # 注入解决装配顺序(与 ChannelToolExecutor.setMessageOperationExecutor # 同模式)。 common_command_adapter.setWhitelistCommandPort(channel_control) return ChannelUseCases( inbound_message=InboundMessageService( inbound_pipeline=inbound_pipeline, outbound_pipeline=outbound_pipeline, config_port=adapters.config, cache_port=adapters.cache, logger=adapters.logger, tracer=adapters.tracer, transaction_port=adapters.transaction, account_repository=adapters.persistence, ack_decision_maker=ack_decision_maker, inbound_adapter_registry=inbound_adapter_registry, idempotency_repository=adapters.persistence, ), admin_message=admin_message_service, plugin_lifecycle=PluginLifecycleService( lifecycle_manager=plugin_lifecycle_manager, logger=adapters.logger, ), health_check=HealthCheckService( health_aggregator=health_aggregator, cache_port=adapters.cache, logger=adapters.logger, tracer_port=adapters.tracer, account_repository=adapters.persistence, audit_log_repo=adapters.persistence, ), channel_tool_executor=channel_tool_executor, # ChannelControlService 实现 HealthCheckPort 的控制面子集 # (getSingleHealth / probeChannelDeep),绑定同一实例。 health_check_control=channel_control, # ChannelControlService 同时实现以下 18 个类型化领域端口,组合根将 # 同一实例绑定到各字段(窄端口依赖)。 wizard=channel_control, doctor=channel_control, whitelist_management=channel_control, directory=channel_control, pairing_management=channel_control, config_management=channel_control, session_management=channel_control, user_binding=channel_control, audit_query=channel_control, account_management=channel_control, login=channel_control, message_management=channel_control, plugin_management=channel_control, outbox_management=channel_control, capability_query=channel_control, # ChannelControlService 同时实现 ContentReviewPort(第 16 个类型化 # 端口),组合根将同一实例绑定到 content_review 字段。 content_review=channel_control, # ContentReviewQueryService 为独立用例服务(数据面,不经控制面管道), # 直接读取 review_repository 实现 CR-02 / CR-03 查询。 content_review_query=content_review_query_service, dashboard_view=channel_control, analytics_view=channel_control, route_binding_management=channel_control, ) def _create_worker_logger_port() -> Any: """构造 worker 进程级 LoggerPort 实例。 复用无状态 ``MaskingAdapter`` + ``StructuredLoggerAdapter`` 装配模式, 对齐 ``adapters/__init__.py`` 中 ``_logger_adapter`` 的构造方式 (注入 ``masking_port`` 以满足 ``LoggerPort`` 协议的脱敏要求)。 """ from yuxi.channels.adapters.masking_adapter import MaskingAdapter from yuxi.channels.adapters.structured_logger_adapter import ( StructuredLoggerAdapter, ) return StructuredLoggerAdapter(masking_port=MaskingAdapter()) async def create_worker_cache_port() -> CachePort: """构造 worker 进程级 CachePort 实例(分布式锁装配)。 通过 ``run_queue_service.get_redis_client`` 获取 worker 进程级 Redis 客户端(与 ARQ 队列共用同一连接池),构造 ``RedisCacheAdapter`` 供 scheduler handler 的分布式锁使用。对齐 ``adapters/__init__.py`` 中 ``RedisCacheAdapter`` 的构造方式。 Returns: ``RedisCacheAdapter`` 实例,实现 ``CachePort`` 协议。 """ from yuxi.channels.adapters.redis_cache_adapter import RedisCacheAdapter from yuxi.services.run_queue_service import get_redis_client redis_client = await get_redis_client() logger_port = _create_worker_logger_port() return RedisCacheAdapter(redis_client=redis_client, logger=logger_port) def _create_outbox_config() -> OutboxConfig: """从全局配置源构造 OutboxConfig(供 ChannelPersistenceAdapter 构造使用)。 对齐 ``create_channel_use_cases`` 中 OutboxConfig 的构造方式,消除应用层 对 ``yuxi.config.app`` 的直接依赖(§6.1 应用服务层禁止依赖具体技术适配器)。 """ return OutboxConfig( ttl_seconds=app_config.channel_outbox_ttl_seconds, retry_backoff_schedule=tuple(app_config.channel_outbox_retry_backoff_schedule), max_retry=app_config.channel_outbox_max_retry, ) def create_channel_session_inactive_cleanup_handler_dependencies( session_factory: Any, cache_port: Any, ) -> dict[str, Any]: """构造 ChannelSessionInactiveCleanupHandler 依赖字典(worker 进程装配用)。 由 ``infrastructure/scheduler.py`` 的 ``register_scheduler_handlers`` 调用,传入 worker 进程级 ``session_factory`` 与 ``cache_port``,返回 ``ChannelSessionInactiveCleanupHandler.__init__`` 所需的依赖字典。 依赖方向合规(INV-1):``session_repo`` 在 infrastructure 层装配具体 适配器 ``ChannelPersistenceAdapter``(fat adapter,实现 ``ChannelSessionRepositoryPort``),应用层 handler 仅依赖端口抽象, 不直接 import 适配器实现。 适配器无状态(注入 ``session_factory``,不持有 session 实例),通过 ``_session_scope(tx)`` 按需获取 session,可安全在 handler 长生命周期内复用。 Args: session_factory: 可调用对象,调用返回 ``AsyncSession`` 实例, 通常为 ``pg_manager.AsyncSession``。 cache_port: worker 进程级 CachePort 实例(RedisCacheAdapter), 供 handler 分布式锁使用。 Returns: 依赖字典,key 与 ``ChannelSessionInactiveCleanupHandler.__init__`` 参数名一致:``{"session_repo": ..., "cache_port": ..., "logger": ...}`` """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() session_repo: ChannelSessionRepositoryPort = ChannelPersistenceAdapter( session_factory, outbox_config=outbox_config, logger=logger_port ) return { "session_repo": session_repo, "cache_port": cache_port, "logger": logger_port, } def create_channel_outbox_terminal_cleanup_handler_dependencies( session_factory: Any, cache_port: Any, ) -> dict[str, Any]: """构造 ChannelOutboxTerminalCleanupHandler 依赖字典(worker 进程装配用)。 ``event_publisher`` 注入 ``None``(worker 进程未注入事件发布端口, handler 内 best-effort 发布 ``OutboxEntryPurgedEvent``,发布失败仅记录 WARN 不影响清理主流程)。 Args: session_factory: 可调用对象,调用返回 ``AsyncSession`` 实例, 通常为 ``pg_manager.AsyncSession``。 cache_port: worker 进程级 CachePort 实例(RedisCacheAdapter), 供 handler 分布式锁使用。 Returns: 依赖字典,key 与 ``ChannelOutboxTerminalCleanupHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() outbox_repo: OutboxRepositoryPort = ChannelPersistenceAdapter( session_factory, outbox_config=outbox_config, logger=logger_port ) return { "outbox_repo": outbox_repo, "event_publisher": None, # worker 进程未注入事件发布端口,best-effort "cache_port": cache_port, "logger": logger_port, } def create_channel_pairing_terminal_cleanup_handler_dependencies( session_factory: Any, cache_port: Any, ) -> dict[str, Any]: """构造 ChannelPairingTerminalCleanupHandler 依赖字典(worker 进程装配用)。 Args: session_factory: 可调用对象,调用返回 ``AsyncSession`` 实例, 通常为 ``pg_manager.AsyncSession``。 cache_port: worker 进程级 CachePort 实例(RedisCacheAdapter), 供 handler 分布式锁使用。 Returns: 依赖字典,key 与 ``ChannelPairingTerminalCleanupHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() pairing_repo: PairingRepositoryPort = ChannelPersistenceAdapter( session_factory, outbox_config=outbox_config, logger=logger_port ) return { "pairing_repo": pairing_repo, "cache_port": cache_port, "logger": logger_port, } def create_channel_outbox_recovery_handler_dependencies( session_factory: Any, arq_pool: ArqRedis, cache_port: Any, ) -> dict[str, Any]: """构造 ChannelOutboxRecoveryHandler 依赖字典(worker 进程装配用)。 依赖方向合规(INV-1):``outbox_repo`` / ``audit_log_repo`` 在 infrastructure 层装配具体适配器 ``ChannelPersistenceAdapter``(fat adapter,分别实现 ``OutboxRepositoryPort`` / ``AuditLogRepositoryPort``),应用层 handler 仅依赖端口抽象,不直接 import 适配器实现。 适配器无状态(注入 ``session_factory``,不持有 session 实例),通过 ``_session_scope(tx)`` 按需获取 session。恢复扫描中每条 entry 的 ``updateOutboxEntry`` / ``saveAuditLog`` 各自独立提交,单条失败不影响其他 条目(与原共享 session 模式相比,避免了 session 异常状态污染后续操作)。 Args: session_factory: 可调用对象,调用返回 ``AsyncSession`` 实例, 通常为 ``pg_manager.AsyncSession``。 arq_pool: worker 进程级 ARQ 连接池,由 ``run_worker.py`` 的 ``_worker_startup`` 提前初始化后传入,用于构造 ``ARQQueueAdapter``。 cache_port: worker 进程级 CachePort 实例(RedisCacheAdapter), 供 handler 分布式锁使用。 Returns: 依赖字典,key 与 ``ChannelOutboxRecoveryHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.arq_queue_adapter import ARQQueueAdapter from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() outbox_repo: OutboxRepositoryPort = ChannelPersistenceAdapter( session_factory, outbox_config=outbox_config, logger=logger_port ) audit_log_repo: AuditLogRepositoryPort = ChannelPersistenceAdapter( session_factory, outbox_config=outbox_config, logger=logger_port ) queue_port = ARQQueueAdapter(arq_pool, logger_port) return { "outbox_repo": outbox_repo, "audit_log_repo": audit_log_repo, "queue_port": queue_port, "outbox_config": outbox_config, "cache_port": cache_port, "logger": logger_port, } def create_channel_pairing_expiration_handler_dependencies( session_factory: Any, cache_port: Any, ) -> dict[str, Any]: """构造 ChannelPairingExpirationHandler 依赖字典(worker 进程装配用)。 依赖方向合规(INV-1):``pairing_repo`` 在 infrastructure 层装配具体 适配器 ``ChannelPersistenceAdapter``(fat adapter,实现 ``PairingRepositoryPort``),应用层 handler 仅依赖端口抽象,不直接 import 适配器实现。 适配器无状态(注入 ``session_factory``,不持有 session 实例),通过 ``_session_scope(tx)`` 按需获取 session。 Args: session_factory: 可调用对象,调用返回 ``AsyncSession`` 实例, 通常为 ``pg_manager.AsyncSession``。 cache_port: worker 进程级 CachePort 实例(RedisCacheAdapter), 供 handler 分布式锁使用。 Returns: 依赖字典,key 与 ``ChannelPairingExpirationHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() pairing_repo: PairingRepositoryPort = ChannelPersistenceAdapter( session_factory, outbox_config=outbox_config, logger=logger_port ) return { "pairing_repo": pairing_repo, "cache_port": cache_port, "logger": logger_port, } def create_channel_audit_log_retention_handler_dependencies( session_factory: Any, cache_port: Any, ) -> dict[str, Any]: """构造 ChannelAuditLogRetentionHandler 依赖字典(worker 进程装配用)。 依赖方向合规(INV-1):``audit_log_repo`` 在 infrastructure 层装配具体 适配器 ``ChannelPersistenceAdapter``(fat adapter,实现 ``AuditLogRepositoryPort``),应用层 handler 仅依赖端口抽象,不直接 import 适配器实现。 适配器无状态(注入 ``session_factory``,不持有 session 实例),通过 ``_session_scope(tx)`` 按需获取 session。 Args: session_factory: 可调用对象,调用返回 ``AsyncSession`` 实例, 通常为 ``pg_manager.AsyncSession``。 cache_port: worker 进程级 CachePort 实例(RedisCacheAdapter), 供 handler 分布式锁使用。 Returns: 依赖字典,key 与 ``ChannelAuditLogRetentionHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() audit_log_repo: AuditLogRepositoryPort = ChannelPersistenceAdapter( session_factory, outbox_config=outbox_config, logger=logger_port ) return { "audit_log_repo": audit_log_repo, "cache_port": cache_port, "logger": logger_port, } def create_channel_content_review_retention_handler_dependencies( session_factory: Any, cache_port: Any, ) -> dict[str, Any]: """构造 ChannelContentReviewRetentionHandler 依赖字典(worker 进程装配用)。 依赖方向合规(INV-1):``content_review_repo`` 在 infrastructure 层装配具体适配器 ``ContentReviewRepositoryAdapter``,应用层 handler 仅依赖 ``ContentReviewRepositoryPort`` 端口抽象,不直接 import 适配器实现。 适配器无状态(注入 ``session_factory``,不持有 session 实例),通过 ``_session_scope(tx)`` 按需获取 session。 Args: session_factory: 可调用对象,调用返回 ``AsyncSession`` 实例, 通常为 ``pg_manager.AsyncSession``。 cache_port: worker 进程级 CachePort 实例(RedisCacheAdapter), 供 handler 分布式锁使用。 Returns: 依赖字典,key 与 ``ChannelContentReviewRetentionHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.content_review_repository_adapter import ( ContentReviewRepositoryAdapter, ) logger_port = _create_worker_logger_port() content_review_repo: ContentReviewRepositoryPort = ContentReviewRepositoryAdapter( session_factory, logger=logger_port ) return { "content_review_repo": content_review_repo, "cache_port": cache_port, "logger": logger_port, } def create_channel_idempotency_cleanup_handler_dependencies( session_factory: Any, cache_port: Any, ) -> dict[str, Any]: """构造 ChannelIdempotencyCleanupHandler 依赖字典(worker 进程装配用)。 依赖方向合规(INV-1):``idempotency_repo`` 在 infrastructure 层 装配具体适配器 ``ChannelPersistenceAdapter``(fat adapter,实现 ``IdempotencyRepositoryPort``),应用层 handler 仅依赖端口抽象,不直接 import 适配器实现。 适配器无状态(注入 ``session_factory``,不持有 session 实例),通过 ``_session_scope(tx)`` 按需获取 session。 Args: session_factory: 可调用对象,调用返回 ``AsyncSession`` 实例, 通常为 ``pg_manager.AsyncSession``。 cache_port: worker 进程级 CachePort 实例(RedisCacheAdapter), 供 handler 分布式锁使用。 Returns: 依赖字典,key 与 ``ChannelIdempotencyCleanupHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() idempotency_repo: IdempotencyRepositoryPort = ChannelPersistenceAdapter( session_factory, outbox_config=outbox_config, logger=logger_port ) return { "idempotency_repo": idempotency_repo, "cache_port": cache_port, "logger": logger_port, }