本次提交包含多项核心改进: 1. 新增微信公众号插件拉取传输模式配置,完善manifest与manifest加载逻辑 2. 新增运行态状态机与幂等冲突错误体系,补充错误映射与领域错误导出 3. 优化出站与入站上下文,新增幂等键、流式中断标记等字段 4. 完善发件箱仓储与模型,新增失败条目查询、投递原子语义字段 5. 修复签名验证阶段异常捕获逻辑,防御性处理内置NotImplementedError 6. 新增出站预算释放方法,完善机器人循环预算管控 7. 优化出站管道格式阶段,新增消息长度校验逻辑 8. 完善出站打字指示器阶段,新增重复启动防御与状态同步 9. 重构出站标记失败阶段,按源状态分支处理状态转换 10. 新增入站幂等过滤阶段,修复入站路由阶段空指针问题 11. 优化出站恢复扫描器,修复状态机调用与聚合根重建逻辑 12. 完善微信公众号适配器,新增类型校验与异常包装 13. 修复数据库事务回滚逻辑,简化不必要的显式回滚操作
164 lines
7.0 KiB
Python
164 lines
7.0 KiB
Python
"""入站管道上下文。
|
||
|
||
定义入站管道的可变局部上下文 ``InboundContext``,携带请求从 receive 到 reply
|
||
各阶段产生的状态。上下文为 ``@dataclass``(不 frozen),阶段直接修改字段以
|
||
推进管道状态。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from collections.abc import Awaitable, Callable
|
||
from dataclasses import dataclass, field
|
||
from typing import TYPE_CHECKING, Any
|
||
|
||
from yuxi.channels.contract.dtos.ack import AckPolicy
|
||
from yuxi.channels.contract.dtos.agent_run import (
|
||
AgentRoutingDecision,
|
||
ChannelContextNote,
|
||
ChannelFormatSpec,
|
||
)
|
||
from yuxi.channels.contract.dtos.channel import (
|
||
ChannelSession,
|
||
ChannelType,
|
||
UserIdentity,
|
||
)
|
||
from yuxi.channels.contract.dtos.command import CommandResult
|
||
from yuxi.channels.contract.dtos.common import (
|
||
MessageContent,
|
||
RawEvent,
|
||
)
|
||
from yuxi.channels.contract.dtos.mention import (
|
||
InboundMentionFact,
|
||
MentionContext,
|
||
MentionDecision,
|
||
)
|
||
from yuxi.channels.contract.dtos.pairing import DmDecision
|
||
from yuxi.channels.contract.dtos.route import RouteBinding
|
||
from yuxi.channels.contract.dtos.service_account import ServiceAccount
|
||
from yuxi.channels.contract.dtos.status import EventType
|
||
from yuxi.channels.contract.errors import Error
|
||
|
||
if TYPE_CHECKING:
|
||
from yuxi.channels.contract.ports.driven.transaction_port import TransactionContext
|
||
|
||
|
||
@dataclass
|
||
class InboundContext:
|
||
"""入站管道可变局部上下文。
|
||
|
||
携带入站请求从 receive 到 reply 各阶段产生的状态,阶段按顺序填充字段。
|
||
字段按阶段分组,便于追溯状态来源。
|
||
|
||
事务边界(§10.1):``tx`` 字段由 ``InboundMessageService`` 在管道
|
||
执行前通过 ``TransactionPort.begin()`` 开启,session-resolve 阶段的
|
||
``resolveConversation`` 与 ``saveChannelSession`` 写操作共享此事务
|
||
上下文,确保会话解析与渠道会话保存原子提交。
|
||
|
||
命名等价说明(6-P2-01):``trace_id`` 与 Agent 层 ``turn_id`` 为同一
|
||
概念的不同命名,均标识一次请求/会话回合的链路追踪 ID。本上下文
|
||
``trace_id`` 字段即等价于 ``turn_id``。
|
||
"""
|
||
|
||
# ---- 基础字段(receive 阶段) ----
|
||
trace_id: str
|
||
request_id: str
|
||
channel_type: ChannelType
|
||
account_id: str
|
||
raw_event: RawEvent
|
||
# 运行来源(如 "channel" / "admin"),用于 Agent 上下文注入区分来源(FR-10)
|
||
source: str = "channel"
|
||
# 渠道插件清单 ID,由 receive 阶段填充
|
||
plugin_id: str | None = None
|
||
# 入站消息幂等键(可选)。由 receive 阶段基于渠道类型 + 账户 ID + 原始事件
|
||
# 负载哈希派生,跨重试稳定,供幂等检查阶段去重,避免重复创建 agent_run。
|
||
idempotency_key: str | None = None
|
||
|
||
# ---- signature-verify 阶段字段 ----
|
||
# Webhook 签名是否已验证通过,由 signature-verify 阶段填充。
|
||
# 适配器未实现验签时保持 False(跳过验签),验签通过时置 True。
|
||
signature_verified: bool = False
|
||
|
||
# ---- 事务上下文(由 InboundMessageService 注入,session_resolve_stage 共享)----
|
||
tx: TransactionContext | None = None
|
||
# 事务提交后执行的副作用 hooks,由各阶段注册、InboundMessageService 统一执行。
|
||
post_commit_hooks: list[Callable[[], Awaitable[None]]] = field(default_factory=list)
|
||
|
||
# ---- classify 阶段字段 ----
|
||
event_type: EventType | None = None
|
||
ref_channel_msg_id: str | None = None
|
||
status_payload: dict[str, Any] | None = None
|
||
peer_id: str | None = None
|
||
chat_type: str | None = None
|
||
# 话题 ID(FR-10),由 classify 阶段从原始事件提取,不支持话题的渠道为 None
|
||
topic_id: str | None = None
|
||
message_content: MessageContent | None = None
|
||
mention_context: MentionContext | None = None
|
||
mention_fact: InboundMentionFact | None = None
|
||
# Agent 路由决策(FR-AgentCollab),由 classify 阶段从 mention_context
|
||
# 构造,供下游 RouteStage 决定路由目标。None 表示无 Agent 提及。
|
||
agent_routing_decision: AgentRoutingDecision | None = None
|
||
|
||
# ---- security 阶段字段 ----
|
||
dm_decision: DmDecision | None = None
|
||
pairing_id: str | None = None
|
||
# 是否为管理员用户(FR-15),由 security 阶段根据账户级 admin_users 配置
|
||
# 判定,供 command-check 阶段校验 ADMIN 权限命令(/allowlist、/approve 等)。
|
||
is_admin: bool = False
|
||
# 是否为渠道访客 channel_guest 身份,由 identity-resolve 阶段判定,标识当前
|
||
# 请求来自未绑定服务账号的访客,供下游阶段决策鉴权与降级策略。
|
||
is_guest: bool = False
|
||
|
||
# ---- command-check 阶段字段 ----
|
||
command: CommandResult | None = None
|
||
is_silent: bool = False
|
||
mention_decision: MentionDecision | None = None
|
||
|
||
# ---- identity-resolve 阶段字段 ----
|
||
unified_identity: UserIdentity | None = None
|
||
# 渠道账户绑定的服务账号,由 service-account-resolve 阶段填充,携带服务账号
|
||
# uid 作为 Agent 执行的鉴权主体,满足会话归属与用户存在性校验。
|
||
service_account: ServiceAccount | None = None
|
||
|
||
# ---- session-resolve 阶段字段 ----
|
||
channel_session: ChannelSession | None = None
|
||
conversation_id: str | None = None
|
||
|
||
# ---- fence 代际字段(agent-run-enqueue 阶段写入,FR-23) ----
|
||
fence_generation: int | None = None
|
||
|
||
# ---- route 阶段字段 ----
|
||
route_binding: RouteBinding | None = None
|
||
current_uid: str | None = None
|
||
|
||
# ---- agent-run-enqueue 阶段字段 ----
|
||
agent_run_id: str | None = None
|
||
|
||
# ---- reply 阶段字段(FR-24 分阶段 ACK) ----
|
||
# ACK 决策结果:ack | nack | pending
|
||
ack_decision: str = "pending"
|
||
# 解析后的 ACK 策略(reply 阶段解析:插件声明 → 配置 → 默认值)
|
||
ack_policy: AckPolicy | None = None
|
||
# 幂等键(基于渠道类型 + 账户 ID + 原始事件负载哈希,跨重试稳定)
|
||
ack_idempotency_key: str | None = None
|
||
# 是否已 ACK(幂等检查标记,避免重复 ACK 副作用)
|
||
acked: bool = False
|
||
# 是否已 NACK(与 ACK 互斥,避免 ACK/NACK 同时生效)
|
||
nacked: bool = False
|
||
|
||
# ---- 出站投递错误字段 ----
|
||
# 出站消息投递失败时的错误信息(FR-24)。reply 阶段向渠道侧投递出站
|
||
# 消息失败时填充,用于上层决策重试或降级;投递成功或未触发投递时为 None。
|
||
outbound_error: str | None = None
|
||
|
||
# ---- 降级标志字段 ----
|
||
degraded: bool = False
|
||
degraded_reason: Error | None = None
|
||
|
||
# ---- 可观测性字段(BP-10) ----
|
||
# 渠道格式规范(包含 supported_formats),由上下文富化逻辑写入,供管道
|
||
# 日志(_logStageExecution)输出可观测性信息。
|
||
channel_format_spec: ChannelFormatSpec | None = None
|
||
# 渠道上下文注记(来自 channel_context_provider),由上下文富化逻辑写入,
|
||
# 供管道日志(_logStageExecution)输出可观测性信息。
|
||
channel_context_note: ChannelContextNote | None = None
|