"""渠道用例服务聚合与请求级 factory。 本模块是编排层的用例装配点,负责将请求级被驱动适配器、 应用级单例(注册中心等)与领域服务装配为 ``ChannelUseCases`` 聚合 (含 6 个用例服务实例与 19 个类型化领域端口绑定),对齐 external_systems 的 ``UseCases`` + ``create_use_cases_from_db(db)`` 模式。 装配顺序: 1. ``create_driven_adapters(db)`` 创建被驱动适配器聚合 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 from yuxi.channels.adapters import DrivenAdapters, create_driven_adapters from yuxi.channels.adapters.default_content_moderation_adapter import ( DefaultContentModerationAdapter, ) from yuxi.channels.adapters.inmemory_realtime_metrics_adapter import ( InmemoryRealtimeMetricsAdapter, ) from yuxi.channels.adapters.report_repository_adapter import ( SqlAlchemyReportRepositoryAdapter, ) 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.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.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.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.report_repository_port import ( ReportRepositoryPort, ) 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.report_management_port import ( ReportManagementPort, ) 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_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 # 调度器(worker 进程装配与一次性报告任务调度) from yuxi.scheduler.infrastructure.container import create_scheduler_service __all__ = [ "ChannelUseCases", "create_channel_use_cases", ] @dataclass class ChannelUseCases: """渠道用例服务聚合。 串联 ``create_driven_adapters(db)`` → 领域服务 → 管道 → 用例服务。 请求级创建,共享同一 ``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),绑定到 ``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 聚合,只读无副作用。 report_management: 报告管理用例(实现 ReportManagementPort),覆盖 一次性报告创建 / 查询 / 列表 / 下载(RPT-05 / RPT-06 / RPT-ONEOFF-01 / RPT-ONEOFF-02),绑定到 ``ChannelControlService`` 同一实例(第 18 个类型化端口)。 analytics_view: 分析视图用例(实现 AnalyticsViewPort),覆盖消息深度 分析 / 消息类型分布 / 会话分析 / 投递链路分析 / 投递延迟分布 / 投递漏斗分析(ANL-01 / ANL-02 / ANL-04 ~ ANL-07),绑定到 ``ChannelControlService`` 同一实例(第 19 个类型化端口),经控制 面管道五阶段处理。 """ 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 report_management: ReportManagementPort analytics_view: AnalyticsViewPort 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)`` 创建被驱动适配器聚合 2. 从 DI 容器获取应用级单例(注册中心等) 3. 创建领域服务(按依赖图拓扑顺序) 4. 通过 ``Pipeline.create()`` 创建管道 5. 实例化用例服务并注入依赖 Args: db: SQLAlchemy 异步会话(请求级),被驱动适配器共享此会话。 di_container: 依赖注入容器,提供应用级单例。 Returns: 装配完成的 ``ChannelUseCases`` 实例(6 个独立用例服务实例 + 19 个类型化领域端口绑定,详见 ``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,事件由应用层发布)。 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) adapters: DrivenAdapters = create_driven_adapters( db, outbox_config=outbox_config, redis_client=redis_client, arq_pool=arq_pool, execution_port=execution_port, ) # 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) review_repository: ContentReviewRepositoryPort = di_container.resolve(ContentReviewRepositoryPort) # PluginLoader 应用级单例(P1 PLG-INSTALL/UNINSTALL 文件操作),由 # create_host_bootstrap 注册到 DI 容器,注入 DispatchStage。 plugin_loader: PluginLoader = di_container.resolve(PluginLoader) # 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) # 实时指标采集器(单例,数据面管道采集 + 控制面 dashboard 查询共享) realtime_metrics = InmemoryRealtimeMetricsAdapter() # 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, logger=adapters.logger, ) # 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, ) # 4.6 AdminMessageService 需先于 ControlPlanePipeline 构造 # (ControlPlanePipeline 的 dispatch 阶段依赖 AdminMessagePort) # 非控制面管道路径:限流(cache_port)与审计(audit_log_repo)由用例 # 服务自行实现,不依赖 ControlPlanePipeline 的 RateLimitStage / AuditStage。 admin_message_service = AdminMessageService( outbound_pipeline=outbound_pipeline, idempotency_repo=adapters.persistence, session_repo=adapters.persistence, audit_log_repo=adapters.persistence, 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.3 安装向导领域服务(FR-16) # 协调 WizardAdapter 与 ConfigPort,编排向导步骤查询、校验、应用、 # 配置聚合与 OAuth 回调。向导状态持久化到 ConfigPort 的 CHANNEL 作用域。 wizard_service = WizardService( wizard_adapter_registry=wizard_adapter_registry, config_port=adapters.config, config_manager=config_manager, logger=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.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, ) # 报告域依赖(RPT-05~RPT-ONEOFF-02): # - report_repository:报告记录仓储,注入 DispatchStage 供 reports/* 读写 # - scheduler_service:调度器服务,注入 DispatchStage 供 reports/create_oneoff # 创建一次性任务(schedule_kind="at");api 进程仅创建任务记录,worker # 进程执行时通过 ChannelReportHandler 生成报告内容 report_repository = SqlAlchemyReportRepositoryAdapter(db, adapters.logger) scheduler_service = create_scheduler_service(db, arq_pool=arq_pool) # 渠道主动探测器(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, 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, report_repository=report_repository, scheduler_service=scheduler_service, 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, ) # 5. 用例服务(请求级,注入管道与适配器) # PluginLifecycleManager / HealthAggregator 为应用级单例,从 DI 容器 # resolve 后注入用例服务,类型安全,不使用 Any。 # AuditContextBuilder 集中审计日志构造逻辑(D5),供 ChannelControlService # 在管道失败时通过独立事务记录失败审计日志(AC-32)。audit_log_repo 取 # 自 persistence 聚合适名(继承 AuditLogRepositoryPort)。 audit_context_builder = AuditContextBuilder( audit_log_repo=adapters.persistence, logger=adapters.logger, masking_port=adapters.masking, ) 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, 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, ), 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 同时实现以下 19 个类型化领域端口,组合根将 # 同一实例绑定到各字段(窄端口依赖)。 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, report_management=channel_control, analytics_view=channel_control, ) def create_channel_report_handler_dependencies( session_factory: Any, ) -> dict[str, Any]: """构造 ChannelReportHandler 依赖字典(worker 进程装配用)。 由 ``infrastructure/scheduler.py`` 的 ``register_scheduler_handlers`` 调用,传入 worker 进程级 ``session_factory``,返回 ``ChannelReportHandler.__init__`` 所需的依赖字典。 **端口装配说明**:``AnalyticsViewPort``(18 号文档)与 ``DashboardViewPort`` (16 号文档)已在 api 进程装配(见 ``create_channel_use_cases``),但 worker 进程由于不持有 DI 容器与请求级 DB 会话,当前注入 ``None``。 ``ChannelReportHandler._generateReportContent`` 对 None 端口抛 ``NotImplementedError``,报告状态变 ``failed``。待 worker 进程装配 端口实例后即可激活异步报告生成。 依赖方向合规(INV-1):``report_repo_factory`` 在 infrastructure 层 装配具体适配器 ``SqlAlchemyReportRepositoryAdapter``,应用层 handler 仅依赖 ``ReportRepositoryPort`` 抽象,不直接 import 适配器实现。 Args: session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂, 通常为 ``pg_manager.get_async_session_context``。 Returns: 依赖字典,key 与 ``ChannelReportHandler.__init__`` 参数名一致: ``{"session_factory": ..., "report_repo_factory": ..., "analytics_view_port": None, "dashboard_view_port": None, "logger": ...}`` """ # StructuredLoggerAdapter 包装默认 loguru logger 以满足 LoggerPort 协议 # (对齐 create_driven_adapters 中 _logger_adapter 的装配模式,注入 # MaskingAdapter 以满足 LoggerPort 协议的脱敏要求) logger_port = _create_worker_logger_port() # 报告仓储工厂:infrastructure 层装配具体适配器,handler 仅依赖端口抽象。 # 每次执行通过 session_factory 创建独立 db 会话后调用本工厂得到端口实例, # 保证会话隔离(避免 worker 进程长生命周期会话问题)。 def report_repo_factory(db: AsyncSession) -> ReportRepositoryPort: return SqlAlchemyReportRepositoryAdapter(db, logger_port) return { "session_factory": session_factory, "report_repo_factory": report_repo_factory, # AnalyticsViewPort / DashboardViewPort 已在 api 进程装配, # worker 进程因不持有 DI 容器与请求级 DB 会话,暂注入 None。 # ChannelReportHandler 对 None 端口抛 NotImplementedError, # 报告状态变 failed。待 worker 装配端口实例后激活。 "analytics_view_port": None, "dashboard_view_port": None, "logger": logger_port, } 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()) 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, ) -> dict[str, Any]: """构造 ChannelSessionInactiveCleanupHandler 依赖字典(worker 进程装配用)。 由 ``infrastructure/scheduler.py`` 的 ``register_scheduler_handlers`` 调用,传入 worker 进程级 ``session_factory``,返回 ``ChannelSessionInactiveCleanupHandler.__init__`` 所需的依赖字典。 依赖方向合规(INV-1):``session_repo_factory`` 在 infrastructure 层 装配具体适配器 ``ChannelPersistenceAdapter``(fat adapter,实现 ``ChannelSessionRepositoryPort``),应用层 handler 仅依赖端口抽象, 不直接 import 适配器实现。 Args: session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂, 通常为 ``pg_manager.get_async_session_context``。 Returns: 依赖字典,key 与 ``ChannelSessionInactiveCleanupHandler.__init__`` 参数名一致:``{"session_factory": ..., "session_repo_factory": ..., "logger": ...}`` """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() def session_repo_factory(db: AsyncSession) -> ChannelSessionRepositoryPort: return ChannelPersistenceAdapter(db, outbox_config=outbox_config, logger=logger_port) return { "session_factory": session_factory, "session_repo_factory": session_repo_factory, "logger": logger_port, } def create_channel_outbox_terminal_cleanup_handler_dependencies( session_factory: Any, ) -> dict[str, Any]: """构造 ChannelOutboxTerminalCleanupHandler 依赖字典(worker 进程装配用)。 ``event_publisher`` 注入 ``None``(worker 进程未注入事件发布端口, handler 内 best-effort 发布 ``OutboxEntryPurgedEvent``,发布失败仅记录 WARN 不影响清理主流程,对齐 ``ChannelReportHandler`` 的 ``analytics_view_port=None`` 模式)。 Args: session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂。 Returns: 依赖字典,key 与 ``ChannelOutboxTerminalCleanupHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() def outbox_repo_factory(db: AsyncSession) -> OutboxRepositoryPort: return ChannelPersistenceAdapter(db, outbox_config=outbox_config, logger=logger_port) return { "session_factory": session_factory, "outbox_repo_factory": outbox_repo_factory, "event_publisher": None, # worker 进程未注入事件发布端口,best-effort "logger": logger_port, } def create_channel_pairing_terminal_cleanup_handler_dependencies( session_factory: Any, ) -> dict[str, Any]: """构造 ChannelPairingTerminalCleanupHandler 依赖字典(worker 进程装配用)。 Args: session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂。 Returns: 依赖字典,key 与 ``ChannelPairingTerminalCleanupHandler.__init__`` 参数名一致。 """ from yuxi.channels.adapters.channel_persistence_adapter import ( ChannelPersistenceAdapter, ) logger_port = _create_worker_logger_port() outbox_config = _create_outbox_config() def pairing_repo_factory(db: AsyncSession) -> PairingRepositoryPort: return ChannelPersistenceAdapter(db, outbox_config=outbox_config, logger=logger_port) return { "session_factory": session_factory, "pairing_repo_factory": pairing_repo_factory, "logger": logger_port, } def create_channel_report_cleanup_handler_dependencies( session_factory: Any, ) -> dict[str, Any]: """构造 ChannelReportCleanupHandler 依赖字典(worker 进程装配用)。 复用 ``create_channel_report_handler_dependencies`` 的 ``report_repo_factory`` 装配模式(``SqlAlchemyReportRepositoryAdapter``),仅在 logger 构造上 统一为 ``_create_worker_logger_port``(注入 ``masking_port``)。 Args: session_factory: 调用返回 ``AsyncSession`` 的异步上下文管理器工厂。 Returns: 依赖字典,key 与 ``ChannelReportCleanupHandler.__init__`` 参数名一致。 """ logger_port = _create_worker_logger_port() def report_repo_factory(db: AsyncSession) -> ReportRepositoryPort: return SqlAlchemyReportRepositoryAdapter(db, logger_port) return { "session_factory": session_factory, "report_repo_factory": report_repo_factory, "logger": logger_port, }