- src/muse 新版全模块(装配/共享/上下文/任务运行/作品规划/故事世界/正文写作/审校修订/知识方法/作者经验/效果评测/交付连载/资料研究/正式变更/元数据/接入/基础设施/编排)+ 测试树(单元/契约/集成/架构/迁移/端到端/夹具) - 129 项功能全部实现与自动验证(功能覆盖.json/矩阵),含 W31 补齐的规则与代价/节奏安排/伏笔与承诺 - 旧实现按处置清单退出(702 条中 324 删,保护合同与未迁移条目留存有据);web/app.py 旧工作台退役,新工作台为唯一写入口 - 数据库/旧库迁移:真实旧库内容批次迁移链(端点守卫/PG作品正文映射/质量资产缺省投影) - 运行手册 docs/运行手册.md;W30 本机服务阶段一已运行(infra PG 为正式内容权威) - R2 执行证据与私有运行材料在 .agents.local/改造/R2-20260909/(不入库)
422 lines
17 KiB
Python
422 lines
17 KiB
Python
"""选择并注入数据库、宿主、模块和流程实现。
|
||
|
||
合同依据:文件设计/后端-装配与接入.md。
|
||
|
||
- 环境实现的选择集中在此唯一装配位置;更换宿主或连接实现不改业务规则。
|
||
- 只配置和注入模块、宿主、连接、资源与流程;不承载创作规则。
|
||
- 数据库工厂随配置与用途注入,取得连接时才访问外部;模型与角色循环读取任务已绑定配置。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass, field
|
||
from pathlib import Path
|
||
from typing import Any, Protocol
|
||
|
||
import psycopg
|
||
|
||
from muse.上下文.接口 import 上下文服务
|
||
from muse.交付连载.接口 import 交付服务, 登记交付参与者
|
||
from muse.任务运行.接口 import (
|
||
任务服务,
|
||
原文服务,
|
||
只读工具集,
|
||
执行上下文,
|
||
未知计价,
|
||
模型执行器,
|
||
登记任务参与者,
|
||
角色策略目录,
|
||
证据服务,
|
||
调用计价,
|
||
配置版本管理,
|
||
预算管理,
|
||
领取凭证,
|
||
)
|
||
from muse.作品规划.接口 import 作品服务, 创作进度服务, 探索服务, 登记作品参与者, 规划服务
|
||
from muse.作者经验.接口 import 作者经验服务, 登记经验参与者
|
||
from muse.共享.时间 import 时钟, 真实时钟
|
||
from muse.共享.错误 import Muse错误, 配置错误
|
||
from muse.基础设施.受控文件 import 受控文件
|
||
from muse.基础设施.宿主.Pi import Pi宿主
|
||
from muse.基础设施.宿主.直接调用 import 直接宿主, 直接角色循环
|
||
from muse.基础设施.数据库.连接 import 数据库工厂
|
||
from muse.基础设施.模型.HTTP传输 import HTTP传输
|
||
from muse.审校修订.接口 import (
|
||
审校服务,
|
||
登记修订参与者,
|
||
登记声音参与者,
|
||
登记案例参与者,
|
||
登记规则参与者,
|
||
)
|
||
from muse.接入.只读工具 import 领取只读工具
|
||
from muse.故事世界.接口 import 故事服务, 登记故事参与者, 解析本书规划引用
|
||
from muse.效果评测.接口 import 评测服务
|
||
from muse.正式变更.接口 import 参与者目录, 正式变更服务
|
||
from muse.正文写作.接口 import 正文服务, 登记正文参与者
|
||
from muse.知识方法.接口 import 登记方法参与者, 知识方法服务
|
||
from muse.编排.接口 import 流程登记
|
||
from muse.资料研究.接口 import 登记分析参与者, 资料服务
|
||
from muse.配置 import 应用配置
|
||
|
||
|
||
class 数据库实现(Protocol):
|
||
"""取得按装配用途绑定的数据库连接。"""
|
||
|
||
def 连接(self, *, 只读: bool = False, autocommit: bool = False) -> psycopg.Connection: ...
|
||
|
||
def 检查连接(self) -> None: ...
|
||
|
||
|
||
class 装配未完成(Muse错误):
|
||
"""所需实现尚未注入;启动如实失败而不是静默降级。"""
|
||
|
||
错误码 = "MUSE_ASSEMBLY_INCOMPLETE"
|
||
|
||
|
||
@dataclass(slots=True)
|
||
class 应用装配:
|
||
"""已注入的实现集合;业务模块只依赖这里的成员。"""
|
||
|
||
配置: 应用配置
|
||
时钟: 时钟
|
||
数据库: 数据库实现 | None = None
|
||
任务运行: 任务服务 | None = None
|
||
原文: 原文服务 | None = None
|
||
默认计价: 调用计价 | None = None
|
||
作品: 作品服务 | None = None
|
||
正文: 正文服务 | None = None
|
||
作品进度: 创作进度服务 | None = None
|
||
故事世界: 故事服务 | None = None
|
||
规划: 规划服务 | None = None
|
||
上下文: 上下文服务 | None = None
|
||
知识方法: 知识方法服务 | None = None
|
||
流程登记: 流程登记 | None = None
|
||
资料: 资料服务 = field(default_factory=资料服务)
|
||
审校: 审校服务 | None = None
|
||
作者经验: 作者经验服务 | None = None
|
||
交付: 交付服务 | None = None
|
||
|
||
def 要求交付(self) -> 交付服务:
|
||
if self.交付 is None:
|
||
raise 装配未完成("交付服务未注入")
|
||
return self.交付
|
||
|
||
def 要求作者经验(self) -> 作者经验服务:
|
||
if self.作者经验 is None:
|
||
raise 装配未完成("作者经验服务未注入")
|
||
return self.作者经验
|
||
|
||
def 要求评测(self) -> 评测服务:
|
||
return 评测服务(数据库工厂(self.配置.数据库, self.配置.运行用途), self.任务运行)
|
||
|
||
def 要求审校(self) -> 审校服务:
|
||
if self.审校 is None:
|
||
raise 装配未完成("审校服务未注入")
|
||
return self.审校
|
||
|
||
def 要求上下文(self) -> 上下文服务:
|
||
if self.上下文 is None:
|
||
raise 装配未完成("上下文服务未注入")
|
||
return self.上下文
|
||
|
||
def 要求只读工具(self, 领取: 领取凭证) -> 只读工具集:
|
||
"""工具范围完全取自已保存任务;接入层不重新解释作者、作品或截止。"""
|
||
if self.任务运行 is None:
|
||
raise 装配未完成("任务运行服务未注入")
|
||
return 领取只读工具(self.要求上下文(), self.任务运行, 领取)
|
||
|
||
def 要求规划(self) -> 规划服务:
|
||
if self.规划 is None:
|
||
raise 装配未完成("规划服务未注入")
|
||
return self.规划
|
||
|
||
def 要求知识方法(self) -> 知识方法服务:
|
||
if self.知识方法 is None:
|
||
raise 装配未完成("知识方法服务未注入")
|
||
return self.知识方法
|
||
|
||
def 要求探索(self) -> 探索服务:
|
||
if self.配置.探索草稿 is None:
|
||
raise 配置错误("私人探索需要在作者配置中明确探索草稿目录")
|
||
return 探索服务(Path(self.配置.探索草稿))
|
||
|
||
def 要求故事世界(self) -> 故事服务:
|
||
if self.故事世界 is None:
|
||
raise 装配未完成("故事世界服务未注入")
|
||
return self.故事世界
|
||
|
||
def 要求作品进度(self) -> 创作进度服务:
|
||
if self.作品进度 is None:
|
||
raise 装配未完成("创作进度查询未注入")
|
||
return self.作品进度
|
||
|
||
def 要求作品(self) -> 作品服务:
|
||
if self.作品 is None:
|
||
raise 装配未完成("作品服务未注入")
|
||
return self.作品
|
||
|
||
def 要求正文(self) -> 正文服务:
|
||
if self.正文 is None:
|
||
raise 装配未完成("正文服务未注入")
|
||
return self.正文
|
||
|
||
def 要求资料(self) -> 资料服务:
|
||
"""注入资料公开用例;基础资料连接由调用方事务提供。"""
|
||
return self.资料
|
||
|
||
def 要求证据(self) -> 证据服务:
|
||
return 证据服务(数据库工厂(self.配置.数据库, self.配置.运行用途))
|
||
|
||
def 要求原文(self) -> 原文服务:
|
||
if self.原文 is None:
|
||
self.原文 = 原文服务(
|
||
数据库工厂(self.配置.数据库, self.配置.运行用途),
|
||
受控文件(Path(self.配置.原文暂存)) if self.配置.原文暂存 else None,
|
||
self.时钟,
|
||
)
|
||
return self.原文
|
||
|
||
def 要求数据库(self) -> 数据库实现:
|
||
if self.数据库 is None:
|
||
raise 装配未完成(
|
||
"数据库实现未注入(W03 提供);当前构建拒绝启动业务入口",
|
||
上下文={"缺少": "数据库"},
|
||
)
|
||
return self.数据库
|
||
|
||
def 要求模型执行器(self, 上下文: 执行上下文, 计价: 调用计价 | None) -> 模型执行器:
|
||
数据库 = 数据库工厂(self.配置.数据库, self.配置.运行用途)
|
||
版本 = 配置版本管理(数据库).读取任务绑定(上下文.领取.任务ID)
|
||
内容 = 版本.内容
|
||
if 内容.资源发布身份 != self.配置.资源发布身份:
|
||
raise 配置错误("任务运行配置与当前安装资源不一致")
|
||
if self.任务运行 is None:
|
||
raise 装配未完成("任务运行服务未注入")
|
||
当前 = self.任务运行.读取任务(上下文.领取.任务ID)
|
||
步骤 = next(s for s in 当前.流程.步骤 if s.步骤ID == 上下文.领取.步骤ID)
|
||
策略 = 角色策略目录.从发布包()
|
||
角色 = 策略.定义.get("aliases", {}).get(步骤.角色, 步骤.角色)
|
||
if 角色 not in 内容.角色配置:
|
||
raise 配置错误("任务角色没有对应的固定运行配置")
|
||
声明 = 内容.角色配置[角色]
|
||
提供方 = next(p for p in 内容.提供方 if p.身份 == 声明["provider"])
|
||
凭据 = next(r for r in 内容.凭据 if r.名称 == 提供方.凭据名称)
|
||
实际计价 = 计价 or 未知计价(内容.计价版本)
|
||
return 模型执行器(
|
||
self.任务运行,
|
||
预算管理(数据库, 内容.预算策略引用),
|
||
self.要求原文(),
|
||
self.要求证据(),
|
||
策略,
|
||
直接宿主(HTTP传输(提供方.地址, 凭据.来源, 凭据.位置, 提供方.协议)),
|
||
实际计价,
|
||
固定配置=版本,
|
||
)
|
||
|
||
def 要求角色循环(self, 任务ID: str) -> 直接角色循环 | Pi宿主:
|
||
版本 = 配置版本管理(数据库工厂(self.配置.数据库, self.配置.运行用途)).读取任务绑定(任务ID)
|
||
内容 = 版本.内容
|
||
if 内容.宿主 == "pi":
|
||
assert 内容.Node路径 is not None and 内容.Pi包目录 is not None
|
||
return Pi宿主(Path(内容.Node路径), Path(内容.Pi包目录), 内容.宿主版本)
|
||
if 内容.宿主版本 != "1":
|
||
raise 配置错误("未支持的直接宿主合同版本")
|
||
return 直接角色循环()
|
||
|
||
|
||
def 构建(配置: 应用配置, *, 时钟: 时钟 | None = None, 流程: 流程登记 | None = None) -> 应用装配:
|
||
"""注入按用途绑定的数据库工厂;装配与自检不建立连接。"""
|
||
数据库 = 数据库工厂(配置.数据库, 配置.运行用途)
|
||
目录 = 参与者目录()
|
||
登记作品参与者(目录, 探索服务(Path(配置.探索草稿)) if 配置.探索草稿 else None, 解析本书规划引用)
|
||
登记正文参与者(目录)
|
||
登记交付参与者(目录)
|
||
登记故事参与者(目录)
|
||
登记方法参与者(目录)
|
||
登记分析参与者(目录)
|
||
登记声音参与者(目录)
|
||
登记修订参与者(目录)
|
||
登记规则参与者(目录)
|
||
正式 = 正式变更服务(数据库, 目录)
|
||
登记案例参与者(目录, 正式.读取回执于)
|
||
作品 = 作品服务(数据库, 正式)
|
||
正文 = 正文服务(数据库, 正式)
|
||
登记 = 流程 or 流程登记()
|
||
任务 = 任务服务(数据库, 登记)
|
||
登记任务参与者(目录, 任务)
|
||
登记经验参与者(目录, 任务)
|
||
app = 应用装配(
|
||
配置=配置,
|
||
时钟=时钟 or 真实时钟(),
|
||
数据库=数据库,
|
||
任务运行=任务,
|
||
流程登记=登记,
|
||
作品=作品,
|
||
正文=正文,
|
||
作品进度=创作进度服务(作品, 正文, 任务),
|
||
故事世界=故事服务(数据库, 正式),
|
||
规划=规划服务(数据库, 正式, 解析本书规划引用),
|
||
上下文=上下文服务(数据库, 任务, 解析本书规划引用),
|
||
知识方法=知识方法服务(数据库, 正式),
|
||
资料=资料服务(正式),
|
||
审校=审校服务(数据库, 正式),
|
||
作者经验=作者经验服务(数据库, 正式),
|
||
交付=交付服务(数据库, 正式),
|
||
)
|
||
from muse.编排.定稿交付 import 登记定稿交付
|
||
from muse.编排.数据维护 import 登记数据维护
|
||
|
||
登记定稿交付(app)
|
||
登记数据维护(app)
|
||
return app
|
||
|
||
|
||
def 构建默认运行(
|
||
配置: 应用配置,
|
||
*,
|
||
时钟: 时钟 | None = None,
|
||
计价: 调用计价 | None = None,
|
||
分析配置ID: str | None = None,
|
||
抽取配置ID: str | None = None,
|
||
) -> 应用装配:
|
||
"""唯一默认运行入口:构建完整作者处理器,不连库或发布计划。"""
|
||
|
||
from muse.编排.运行装配 import _登记默认运行
|
||
|
||
装配 = 构建(配置, 时钟=时钟)
|
||
装配.默认计价 = 计价
|
||
return _登记默认运行(
|
||
装配,
|
||
计价=计价,
|
||
分析配置ID=分析配置ID,
|
||
抽取配置ID=抽取配置ID,
|
||
)
|
||
|
||
|
||
def 装配章后处理(
|
||
装配: 应用装配,
|
||
计价,
|
||
模板路径: Path | None = None,
|
||
*,
|
||
抽取配置ID: str | None = None,
|
||
) -> None:
|
||
"""登记并发布章后处理流程;抽取配置由部署装配声明,作者配置仍走验证启用链。"""
|
||
|
||
from muse.编排.接口 import 流程服务
|
||
from muse.编排.章后处理 import 登记章后处理
|
||
from muse.编排.载入模板 import 载入流程定义
|
||
|
||
登记 = 装配.流程登记
|
||
if 登记 is None or 装配.任务运行 is None:
|
||
raise 装配未完成("任务运行与流程登记未注入")
|
||
登记章后处理(登记, 装配, 计价, 抽取配置ID=抽取配置ID)
|
||
定义 = 载入流程定义(模板路径 or Path("配置/流程模板/章后处理.yaml"))
|
||
流程服务(装配.任务运行, 登记).发布(定义)
|
||
|
||
|
||
def 装配研究拆书(
|
||
装配: 应用装配, 计价, 模板路径: Path | None = None, *, 分析配置ID: str | None = None
|
||
) -> None:
|
||
"""登记并发布研究拆书流程;分析配置由部署装配声明,作者配置仍走验证启用链。"""
|
||
|
||
from muse.编排.接口 import 流程服务
|
||
from muse.编排.研究拆书 import 登记研究拆书
|
||
from muse.编排.载入模板 import 载入流程定义
|
||
|
||
登记 = 装配.流程登记
|
||
if 登记 is None or 装配.任务运行 is None:
|
||
raise 装配未完成("任务运行与流程登记未注入")
|
||
登记研究拆书(登记, 装配, 计价, 分析配置ID=分析配置ID)
|
||
定义 = 载入流程定义(模板路径 or Path("配置/流程模板/研究拆书.yaml"))
|
||
流程服务(装配.任务运行, 登记).发布(定义)
|
||
|
||
|
||
def 装配生成正文(装配: 应用装配, 计价, 模板路径: Path | None = None) -> None:
|
||
"""登记并发布生成正文流程;计价由调用方注入,模板默认取仓内可审配置。"""
|
||
|
||
from muse.编排.接口 import 流程服务
|
||
from muse.编排.生成正文 import 登记生成正文
|
||
from muse.编排.载入模板 import 载入流程定义
|
||
|
||
登记 = 装配.流程登记
|
||
if 登记 is None or 装配.任务运行 is None:
|
||
raise 装配未完成("任务运行与流程登记未注入")
|
||
登记生成正文(登记, 装配, 计价)
|
||
定义 = 载入流程定义(模板路径 or Path("配置/流程模板/生成正文.yaml"))
|
||
流程服务(装配.任务运行, 登记).发布(定义)
|
||
|
||
|
||
def 装配完整审校(装配: 应用装配, 计价, 模板路径: Path | None = None) -> None:
|
||
"""登记本书正文完整审校;调用方选择已验证judge配置并另行批准预算。"""
|
||
from muse.编排.完整审校 import 登记完整审校
|
||
from muse.编排.接口 import 流程服务
|
||
from muse.编排.载入模板 import 载入流程定义
|
||
|
||
登记 = 装配.流程登记
|
||
if 登记 is None or 装配.任务运行 is None:
|
||
raise 装配未完成("任务运行与流程登记未注入")
|
||
登记完整审校(登记, 装配, 计价)
|
||
流程服务(装配.任务运行, 登记).发布(
|
||
载入流程定义(模板路径 or Path("配置/流程模板/完整审校.yaml"))
|
||
)
|
||
|
||
|
||
def 装配审校修订(装配: 应用装配, 计价, 模板路径: Path | None = None) -> None:
|
||
from muse.编排.审校修订 import 登记审校修订
|
||
from muse.编排.接口 import 流程服务
|
||
from muse.编排.载入模板 import 载入流程定义
|
||
|
||
登记 = 装配.流程登记
|
||
if 登记 is None or 装配.任务运行 is None:
|
||
raise 装配未完成("修订任务装配缺失")
|
||
登记审校修订(登记, 装配, 计价)
|
||
流程服务(装配.任务运行, 登记).发布(
|
||
载入流程定义(模板路径 or Path("配置/流程模板/审校修订.yaml"))
|
||
)
|
||
|
||
|
||
def 装配生成规划(装配: 应用装配, 计价, 模板路径: Path | None = None) -> None:
|
||
"""登记并发布受控规划;配置和额度仍由 S02 验证及绑定。"""
|
||
from muse.编排.接口 import 流程服务
|
||
from muse.编排.生成规划 import 登记生成规划
|
||
from muse.编排.载入模板 import 载入流程定义
|
||
|
||
登记 = 装配.流程登记
|
||
if 登记 is None or 装配.任务运行 is None:
|
||
raise 装配未完成("任务运行与流程登记未注入")
|
||
登记生成规划(登记, 装配, 计价)
|
||
流程服务(装配.任务运行, 登记).发布(
|
||
载入流程定义(模板路径 or Path("配置/流程模板/生成规划.yaml"))
|
||
)
|
||
|
||
|
||
def 自检(装配: 应用装配) -> dict[str, Any]:
|
||
"""进程内自检:报告已注入实现与缺口;不连接任何外部服务。"""
|
||
return {
|
||
"包版本": __import__("muse").__version__,
|
||
"资源发布身份": 装配.配置.资源发布身份,
|
||
"数据库": "已注入" if 装配.数据库 is not None else "未注入(W03)",
|
||
"宿主": "按任务已绑定配置装配",
|
||
}
|
||
|
||
|
||
__all__ = [
|
||
"应用装配",
|
||
"构建",
|
||
"构建默认运行",
|
||
"自检",
|
||
"装配未完成",
|
||
"数据库实现",
|
||
]
|
||
|
||
|
||
def 装配效果评测(装配: 应用装配, 计价=None) -> None:
|
||
"""按评测用途装配固定发布资源;未装配计价时保留未知,不推定免费。"""
|
||
from muse.共享.调用身份 import 用途
|
||
from muse.效果评测.接口 import 评测用途越权
|
||
from muse.编排.执行评测 import 登记评测执行
|
||
|
||
if 装配.配置.运行用途 is not 用途.评测:
|
||
raise 评测用途越权("效果评测流程只允许evaluation配置")
|
||
登记评测执行(装配, 计价 if 计价 is not None else 装配.默认计价)
|