aps-agent/server/contracts.py

152 lines
10 KiB
Python
Raw Permalink 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.

# ============================================================
# 跨层契约的 pydantic 运行时形态(moduleId: server-contracts, 可重生 ✅)
# 与 shared/schemas/*.json 保持一一对应(JSON Schema 为源,py/ts 为镜像)
# 任何跨层数据必须经过这里的模型校验后才能流转(plan.md §12 规范 6)
# ============================================================
from __future__ import annotations # 允许前向类型引用
from typing import Any, Literal, Optional # 类型标注工具
from pydantic import BaseModel, Field # 契约校验基座
INTERFACE_VERSION = "1.0"
# ---------------- 视口命令(shared/viewport_command.schema.json) ----------------
class ViewportCommand(BaseModel):
"""视口命令:驱动右侧可视化的结构化指令(§6.3)。权力等级:P0(纯视图状态)。"""
# 命令名:viewport.* 改视口状态;world.refresh 通知前端重拉世界数据
cmd: Literal[
"viewport.mode", "viewport.filter", "viewport.focus",
"viewport.highlight", "viewport.timescale", "viewport.reset",
"world.refresh",
]
# 目标对象 ID(如聚焦的产线 ID),无目标时为 None
target: Optional[str] = None
# 命令参数(按 cmd 而异,前端按约定读取)
params: dict[str, Any] = Field(default_factory=dict)
# 发起方:LLM 解析产出 / 用户手点 / 系统自动
issuedBy: Literal["LLM", "USER", "SYSTEM"] = "SYSTEM"
interfaceVersion: Literal["1.0"] = INTERFACE_VERSION
# ---------------- UI 块(shared/ui_block.schema.json) ----------------
class UIAction(BaseModel):
"""UI 块内的可触发动作:用户点击后回传后端(§6.2)。"""
actionId: str # 动作 ID(后端据此路由)
label: str # 按钮文案
power: Literal["P0", "P1", "P2", "P3"] # 权力等级(P2/P3 必须过门禁)
payload: dict[str, Any] = Field(default_factory=dict) # 携带参数
class UIBlock(BaseModel):
"""UI 块:后端与前端之间的渲染契约(§6.2)。M3 新增 report(报告预览 §9.10)。"""
blockId: str # 块唯一 ID
type: Literal["text", "confirm-card", "evidence", "scenario-cards", "report",
"flex-schedule", "flex-capacity", "flex-due", "flex-compare",
"plan-trace", "conflict-center",
"kpi-dashboard", "compare-table", "guidance",
"readiness", "clarify", "wizard", "folder-pack", "project-analyze", "drawing-analysis"]
props: dict[str, Any] = Field(default_factory=dict) # 数据载荷
actions: list[UIAction] = Field(default_factory=list) # 块内动作
evidenceRefs: list[str] = Field(default_factory=list) # 关联证据 ID
interfaceVersion: Literal["1.0"] = INTERFACE_VERSION
# ---------------- 结构化工具请求(shared/intent.schema.json) ----------------
# 工具名的封闭枚举:Pi Agent 只能调用此集合内的已登记工具,超出即拒绝。
IntentName = Literal[
"schedule.run", "schedule.publish",
"order.upsert", "order.cancel", "order.complete", "order.delete", "order.clear", # M4:订单管理(P2)
"order.submit", "order.approve", "order.reject", # OR-03:订单池审核
"order.pool", # OR-03:订单池摘要(P0)
"rush.evaluate", "rush.apply", # OR-04:紧急插单快评 / 采用
"forecast.query", "forecast.upsert", "forecast.delete", "forecast.convert", # OR-05
"plan.buckets", # PL-01:时间分桶计划
"plan.rccp", # PL-02:有限/无限粗能力对照
"plan.feasibility", # PL-03:交期可行性
"plan.inventory", # PL-04:库存投影
"plan.leveling", # PL-05:产能平衡/削峰
"plan.supply", # PL-06:产供方向决策
"order.decompose", "mrp.release", # M4:订单分解 MRP(P1)/ 建议单下达(P2)
"plan.trace", # M4:计划追溯 SO→主数据→分解→PO/WO→负荷/库存
"master.material.upsert", # 对话新建/编辑物料(P2)
"master.changeover.upsert", # MD-06:换型矩阵写入(P2)
"master.clear", # 一键清理主数据板块(P2)
"master.query", # 自然语言检索订单/物料/BOM/工艺(P0)
"changeover.query", # MD-06:换型矩阵只读
"campaign.preview", # SC-08:战役合并预览
"params.update", # OR-02:排产参数更新(P2)
"params.query", # OR-02:排产参数查询(P0)
"constraint.profile.query", # SC-04:约束剖面查询(P0)
"constraint.profile.save", # SC-04:约束剖面保存(P2)
"data.import", # 自然语言批量导入订单/物料(P2)
"import.commit", # Excel/CSV 导入入库(P2)
"folder.analyze", # 工程目录深度解析(P0)
"folder.schedule", # 导入工程目录并试排(P2)
"flex.site.load", # 现场完整生产路线 → 替换 flex*(P2)
"flex.schedule", "flex.reschedule", "flex.swap", "flex.capacity", "flex.simulate_due",
"flex.compare", "flex.rush", "flex.fault", "flex.resource.patch", "flex.conflict.resolve",
"conflict.list", "flex.adjust.preview", "flex.adjust.commit",
"schedule.adjust.preview", "schedule.adjust.commit",
"sap.status", "sap.sync.inbound", "sap.sync.outbound",
"mes.status", "mes.dispatch", "mes.report",
"scenario.compare", # M2:多策略沙盒对比(Explore 通道 §5.1)
"scenario.sensitivity", # SC-06:敏感性分析 Tornado
"sop.compile", "sop.apply", # IND-02:SOP→约束编译 / 应用
"checkpoint.create", "checkpoint.rollback", # M2:成对快照与回滚(§4.3)
"knowledge.query", # M3:知识库检索(带出处 §8.2)
"knowledge.import", # RAG:导入知识文档(P2)
"skill.list", "skill.health", # 外部算法 skill 清单/健康检查(P0)
"skill.register", "skill.enable", # 登记/启停 skill(P2)
"readiness.query", # M-B:数据齐备度检查(P0)
"data.analyze", # 分析项目/文件数据与排产缺口(P0)
"assistant.reply", # 通用排产助理作答(P0,带项目上下文)
"flex.time.update", # M-B:工时维护(P2)
"schedule.wizard", # M-F:引导式排产向导
"guidance.next", # AG-07:主动引导下一步建议
"report.generate", # M3:报告生成(日报/版本对比 §9.10)
"viewport.mode", "viewport.filter", "viewport.focus",
"viewport.highlight", "viewport.timescale", "viewport.reset",
"query.kpi", "data.reset", "help", "unknown",
]
class IntentResult(BaseModel):
"""Pi Agent 的结构化工具请求(不是自然语言意图识别结果)。"""
intent: IntentName # 工具名(封闭枚举)
params: dict[str, Any] = Field(default_factory=dict) # 槽位参数(策略/模式/客户名…)
confidence: float = Field(ge=0, le=1) # 请求置信度(保留字段,工具执行以登记与门禁为准)
source: Literal["RULE_FAST", "LLM"] = "LLM" # 产生来源;RULE_FAST 仅为历史审计兼容
interfaceVersion: Literal["1.0"] = INTERFACE_VERSION
# ---------------- 排产结果摘要(shared/schedule_result.schema.json) ----------------
class ScheduleResult(BaseModel):
"""排产结果摘要:引擎 solve() 的标准输出(§9.1),回复/审计/KPI 共用。"""
versionId: int # 版本 ID
versionNo: str # 版本号(V+日期+序号)
engineType: Literal["RULE", "CP", "GA", "HYBRID", "EXTERNAL", "OPTIMIZE"] # 引擎类型
strategy: str # 策略模板
status: Literal["DRAFT", "PUBLISHED", "ARCHIVED"] = "DRAFT" # 版本状态
orderCount: int # 参与排产的订单项数
poCount: int # 生成生产订单数
woCount: int # 生成工单数
conflictCount: int # 冲突数
totalTardiness: float # 总延迟(小时)
avgUtilization: float # 平均利用率 0-1
totalCost: float = 0 # 预估成本
evidenceRefs: list[str] = Field(default_factory=list) # 证据引用(run-id)
# SC-03:求解器元信息(RULE 可空;CP 填 status/gap/耗时)
solveStatus: str | None = None # OPTIMAL / FEASIBLE / INFEASIBLE / MODEL_INVALID / …
solveTimeSec: float | None = None # 墙钟秒
optimalityGap: float | None = None # |(obj-bound)/obj|;最优时约 0
# ---------------- 智能体回复(SSE 载荷的聚合形态,仅后端内部使用) ----------------
class AgentReply(BaseModel):
"""一轮对话的完整产出:文本 + 视口命令 + UI 块(gateway 将其拆成 SSE 事件流)。"""
text: str # 回复正文(前端流式渲染)
commands: list[ViewportCommand] = Field(default_factory=list) # 要执行的视口命令
blocks: list[UIBlock] = Field(default_factory=list) # 附加 UI 块(如确认卡)
intent: Optional[IntentResult] = None # 本轮结构化工具请求(协议证据)