ForcePilot/backend/package/yuxi/channels/contract/plugin/entry.py
Kris 742299cb07 chore: 批量清理报告相关代码并完成多项功能迭代
本次提交包含多维度代码优化与功能增强:
1.  移除报告模块冗余导入与枚举,清理报表相关代码
2.  新增扫码登录支持方法与飞书适配器适配
3.  完善异常日志与健康检查信息
4.  扩展目录、配对管理、能力查询等接口
5.  优化出站管道与事务提交后钩子逻辑
6.  修复飞书消息解析与响应空值问题
7.  重构配置更新与服务账号创建逻辑
8.  统一传输错误分类契约与错误基类扩展
2026-07-06 20:49:35 +08:00

336 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""插件入口契约。
定义插件宿主 Protocol``PluginHost``)与插件入口类型别名
``CHANNEL_ENTRY``)。插件通过 ``CHANNEL_ENTRY`` 函数注册,由宿主在
loaded 阶段调用,返回 ``PluginManifest``。
"""
from __future__ import annotations
from collections.abc import Callable
from typing import Any, Protocol, runtime_checkable
from yuxi.channels.contract.dtos.plugin import DomainEvent
from yuxi.channels.contract.dtos.route import MatchTier
from yuxi.channels.contract.plugin.capability import CapabilityProver
from yuxi.channels.contract.plugin.extension_point import (
ConfigSource,
EventSubscription,
StageSlot,
)
from yuxi.channels.contract.plugin.manifest import (
ChannelManifest,
PluginManifest,
)
from yuxi.channels.contract.ports.driven import (
AgentRunPort,
AuditLogRepositoryPort,
CachePort,
ChannelAccountRepositoryPort,
ChannelSessionRepositoryPort,
ConfigPort,
ConversationPort,
IdempotencyRepositoryPort,
IdentityResolverPort,
LoggerPort,
OutboxRepositoryPort,
PairingRepositoryPort,
PersistenceHealthPort,
PersistencePort,
QueuePort,
TracerPort,
UserIdentityRepositoryPort,
)
class PluginAdapter(Protocol):
"""插件适配器标记 Protocol。
标识 ``PluginHost.registerAdapter`` 接受的适配器实例类型。渠道插件
可注册的适配器包括 ``contract.plugin.adapters`` 中定义的 23 类适配器
协议InboundAdapter / OutboundAdapter / SessionAdapter / RichMessageAdapter
/ StreamingAdapter / DirectoryAdapter / CommandAdapter / WizardAdapter
/ DoctorAdapter / WhitelistAdapter / ToolsAdapter / MessageOpsAdapter
/ StatusAdapter / MentionAdapter / IdentityResolverAdapter / LifecycleAdapter
/ LoginAdapter / ProbeableAdapter / ContentModerationAdapter / PullerAdapter
/ StreamConnectorAdapter / AttachmentUploadAdapter / WebhookTestAdapter
渠道上下文提供者端口ChannelContextProviderPort它们各自定义独立
的处理方法,无公共方法基类,故本 Protocol 作为类型边界用于静态检查
与文档化,不含公共方法声明。
"""
...
#: 路由匹配器类型别名。
#:
#: 接收绑定上下文,返回匹配的路由绑定或 ``None``。插件通过
#: ``registerMatcher`` 注入自定义匹配函数,供 ``RouteResolver`` 遍历
#: 层级时调用执行匹配逻辑。使用 ``Any`` 避免运行时解析
#: ``BindingContext``TYPE_CHECKING 导入,见 ``TierMatcher``)。
Matcher = Callable[..., Any]
@runtime_checkable
class PluginHost(Protocol):
"""插件宿主 Protocol。
由宿主实现,向插件提供被驱动端口获取、扩展点注册、能力边界声明与
事件发布能力。使用 ``@runtime_checkable`` 装饰以支持 ``isinstance``
检查。
资源访问约束INV-I7 / FF-ADAPTER-01 / FR-32
- 插件 **不得** 直接访问宿主的 ``settings``、``logger``、数据库连接池、
Redis 客户端,**必须** 通过 ``PluginHost`` 提供的端口获取方法获取依赖。
- 插件 **不得** 修改宿主的中间件链、路由表、事件订阅器,**只能** 通过
扩展点注册方法注入自身逻辑。
- 插件能力声明 **必须** 通过 ``CapabilityProver`` 验证,验证失败 **不得**
启动插件。
插件必须通过 ``PluginHost`` 完成以下三类操作:
1. 端口获取:通过 ``getXxxPort()`` 方法获取被驱动端口,访问配置、日志、
持久化、缓存、追踪、队列、会话、Agent 运行与身份解析能力。
2. 扩展点注册:通过 ``registerXxx()`` 方法注册适配器、阶段槽位、事件订阅、
配置源与能力证明者,向宿主注入自身逻辑。
3. 能力边界声明:通过 ``declareXxx()`` 方法声明可访问端口、可注入管道与
资源配额,由宿主强制约束。
"""
def getConfigPort(self) -> ConfigPort:
"""获取配置端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getLoggerPort(self) -> LoggerPort:
"""获取日志端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getPersistencePort(self) -> PersistencePort:
"""获取持久化端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getCachePort(self) -> CachePort:
"""获取缓存端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getTracerPort(self) -> TracerPort:
"""获取追踪端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getQueuePort(self) -> QueuePort:
"""获取队列端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getConversationPort(self) -> ConversationPort:
"""获取会话端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getAgentRunPort(self) -> AgentRunPort:
"""获取 Agent 运行端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getIdentityResolverPort(self) -> IdentityResolverPort:
"""获取身份解析端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getChannelAccountRepositoryPort(self) -> ChannelAccountRepositoryPort:
"""获取渠道账户仓储端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getChannelSessionRepositoryPort(self) -> ChannelSessionRepositoryPort:
"""获取渠道会话仓储端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getPairingRepositoryPort(self) -> PairingRepositoryPort:
"""获取配对仓储端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getAuditLogRepositoryPort(self) -> AuditLogRepositoryPort:
"""获取审计日志仓储端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getOutboxRepositoryPort(self) -> OutboxRepositoryPort:
"""获取发件箱仓储端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getUserIdentityRepositoryPort(self) -> UserIdentityRepositoryPort:
"""获取用户身份仓储端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getIdempotencyRepositoryPort(self) -> IdempotencyRepositoryPort:
"""获取幂等性仓储端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def getPersistenceHealthPort(self) -> PersistenceHealthPort:
"""获取持久化健康端口。
@consistency: 无状态stateless返回注入的端口实例。
"""
...
def registerAdapter(self, adapter_type: str, adapter: PluginAdapter) -> None:
"""注册适配器。
参数:
adapter_type: 适配器类型。
adapter: 适配器实例。
@consistency: 无状态stateless仅写入注册表。
@idempotent: False — 重复注册相同 adapter_type 会覆盖前一次的实例.
"""
...
def registerStageSlot(self, slot: StageSlot) -> None:
"""注册管道阶段槽位。
参数:
slot: 阶段槽位实例。
@consistency: 无状态stateless仅写入注册表。
@idempotent: False — 重复注册相同锚点 + 优先级的 slot 会触发冲突策略.
"""
...
def registerEventSubscription(self, subscription: EventSubscription) -> None:
"""注册事件订阅。
参数:
subscription: 事件订阅实例。
@consistency: 无状态stateless仅写入注册表。
@idempotent: False — 重复注册会创建多个订阅,同一事件被多次处理.
"""
...
def registerConfigSource(self, source: ConfigSource) -> None:
"""注册配置源。
参数:
source: 配置源实例。
@consistency: 无状态stateless仅写入注册表。
@idempotent: False — 重复注册相同 key 会覆盖前一次的源.
"""
...
def registerCapabilityProver(self, prover: CapabilityProver) -> None:
"""注册能力证明者FR-08 增强)。
注册 ``CapabilityProver`` 实例,供宿主对插件清单声明的静态能力
进行运行时证明。宿主在 ``initialized`` 阶段调用 ``proveCapability``
对每项能力进行证明,证明失败的插件 **不得** 启动FR-32
参数:
prover: 能力证明 Protocol 实例。
@consistency: 无状态stateless仅写入注册表。
@idempotent: False — 重复注册会覆盖前一次的 prover 实例.
"""
...
def registerMatchTier(self, tier: MatchTier) -> None:
"""注册路由匹配层级FR-04
参数:
tier: 匹配层级配置。
@consistency: 无状态stateless仅写入注册表。
@idempotent: False — 重复注册相同层级名会覆盖前一次的配置.
"""
...
def registerMatcher(self, name: str, matcher: Matcher) -> None:
"""注册匹配层级的匹配器FR-04
为已注册的层级绑定匹配函数,供 ``RouteResolver`` 在遍历层级时调用
执行匹配逻辑。插件通过本方法注入自定义匹配规则。
参数:
name: 层级名称(必须已通过 ``registerMatchTier`` 注册)。
matcher: 匹配器函数,接收绑定上下文,返回路由绑定或 None。
@consistency: 无状态stateless仅写入注册表。
@idempotent: False — 重复注册相同 name 会覆盖前一次的 matcher.
"""
...
async def publishEvent(self, event: DomainEvent) -> None:
"""发布领域事件。
宿主负责将事件分发到订阅者。支持的事件类型:
PluginDiscovered/PluginLoaded/PluginStarted/PluginPaused/
PluginResumed/PluginStopped/PluginUnloaded/PluginFailed/
PairingApproved/PairingRevoked/ConfigChanged/ChannelDegraded/ChannelRecovered。
参数:
event: 领域事件。
@consistency: 最终一致eventual订阅者按各自策略处理。
@idempotent: True — 重复发布相同事件产生等价结果(订阅者需自行幂等).
"""
...
#: 插件入口类型别名。
#:
#: 每个渠道插件 **必须** 通过 ``CHANNEL_ENTRY`` 契约注册,**不得** 隐式全局
#: 注入FR-32。由宿主在 loaded 阶段调用,返回 ``PluginManifest``,包含
#: 元数据、适配器、阶段、事件订阅等。
#:
#: 签名 ``(host, manifest) -> PluginManifest``:宿主传入 discover 阶段从
#: ``manifest.json`` 解析的 ``ChannelManifest``,插件直接复用为返回清单的
#: ``manifest`` 字段,**不得** 在 entry.py 内重新构造声明性字段
#: capabilities / config_schema / env_vars / accessible_ports /
#: resource_quota / lifecycle / credential_strategy 等),避免双真相源
#: F-03。插件仅负责适配器实例化、client 实例化、LifecycleHandler
#: 构造与 ``registerAdapter`` 调用。宿主在加载期校验返回清单的
#: ``manifest.id`` 与入参 ``manifest.id`` 一致。
CHANNEL_ENTRY = Callable[[PluginHost, ChannelManifest], PluginManifest]