ForcePilot/backend/package/yuxi/channels/application/context/inbound_context.py
Kris eb80382da0 feat(wechat-woc): 新增SSE流式推送支持,优化日志与幂等性
1.  新增WeChatWocStreamConnectorAdapter,实现SSE长连接接收消息,支持热更新配置
2.  升级wechat_woc插件依赖bridge版本至1.5.0,开启both传输模式
3.  新增SSE相关常量与配置项,完善woc_bridge_client SSE实现
4.  重构RouteStage,复用会话缓存避免重复查询
5.  新增入站/出站全链路日志打点,优化异常场景日志输出
6.  实现入站幂等记录状态回写机制,独立事务避免死锁
7.  新增TransportManager重启恢复逻辑,自动恢复在线账号传输任务
8.  修复inbound_pipeline移除冗余persistence_port参数,注入idempotency仓储
9.  新增InboundContext.idempotency_record_id字段,传递幂等记录主键
2026-07-08 00:17:39 +08:00

168 lines
7.3 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.

"""入站管道上下文。
定义入站管道的可变局部上下文 ``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
# 入站消息幂等记录主键(可选)。由 inbound-idempotency 阶段在创建
# in_progress 记录后填充,供 InboundMessageService 在管道成功/失败后
# 更新为 completed/failed 状态C-5 状态回写,独立于管道事务)。
idempotency_record_id: int | 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
# 话题 IDFR-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