# ============================================================ # 跨层契约的 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 # 契约校验基座 # ---------------- 视口命令(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" # ---------------- 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"] props: dict[str, Any] = Field(default_factory=dict) # 数据载荷 actions: list[UIAction] = Field(default_factory=list) # 块内动作 evidenceRefs: list[str] = Field(default_factory=list) # 关联证据 ID # ---------------- 意图结果(shared/intent.schema.json) ---------------- # 意图名的封闭枚举:LLM 输出超出此集合即判非法并降级(M3 新增知识查询与报告) 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): """意图识别结果:两级管线(规则快路/LLM)的统一输出(§9.6)。""" intent: IntentName # 意图名(封闭枚举) params: dict[str, Any] = Field(default_factory=dict) # 槽位参数(策略/模式/客户名…) confidence: float = Field(ge=0, le=1) # 置信度:<0.5 拒识,0.5-0.85 澄清,>0.85 执行 source: Literal["RULE_FAST", "LLM"] = "RULE_FAST" # 产生来源(审计与调试用) # ---------------- 排产结果摘要(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"] # 引擎类型 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 # 本轮识别出的意图(协议证据,前端可展开)