接续 88dd570,保存 W20–W24 已实现的共享接口、业务入口、迁移、工作台、测试与文档。 W20/W22/W23 保持 in_progress,W21/W24 保持 verified;此提交不宣称方法或规则正式启用、多轮返修、真实角色评测完成。 W25 新增实验、标定、逐调用交付与角色执行及其迁移/测试/索引留在实施工作树,原有私人和旧实现保留项不纳入。 验证:离线 571、前端 33 通过;PG 469 项通过、2 项浏览器未启用,2 项误带入的 W25 用例已移出本提交;最终任务与交付边界 37 项通过。make 检查、最终类型、84 项资源及 diff 检查通过。未重跑浏览器或 Pi 宿主,不以合成调用认证外部模型效果。 独立整体审查四维通过;证据保存在 R2-20260909/提交W20-W24。
104 lines
4.2 KiB
Python
104 lines
4.2 KiB
Python
"""材料按必读优先与 UTF-8 字节预算取舍;省略有原因,不补造材料。
|
||
|
||
边界:纯函数,不访问数据库、模型、文件或网络,也不承担来源授权。
|
||
字节数为材料渲染后的 UTF-8 字节(含 ``\\n\\n`` 分隔符),不是 tokenizer 或计费估算。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from collections.abc import Mapping
|
||
|
||
from muse.上下文.模型 import 上下文错误, 材料装配结果
|
||
|
||
分隔符 = "\n\n"
|
||
|
||
|
||
def 装配材料(
|
||
材料: Mapping[str, str],
|
||
必读: tuple[str, ...],
|
||
*,
|
||
字节上限: int,
|
||
) -> 材料装配结果:
|
||
"""按必读优先、输入顺序整项加入可选,返回实际入选与省略条目。
|
||
|
||
必读按声明顺序先放入;缺失或空白必读拒绝,任一必读放不下即整体拒绝,不返回部分材料。
|
||
可选材料按输入顺序整项加入,空白与超预算分别记入省略原因;不截断中文字节,保留原文空白。
|
||
字节上限必须是真正的 int:True 是 bool 不是预算,与零、负数、浮点一并拒绝。
|
||
"""
|
||
if isinstance(字节上限, bool) or not isinstance(字节上限, int) or 字节上限 <= 0:
|
||
raise 上下文错误("CONTEXT_INPUT_INVALID", f"字节上限必须是正整数,收到 {字节上限!r}")
|
||
if len(set(必读)) != len(必读):
|
||
raise 上下文错误("CONTEXT_INPUT_INVALID", f"必读来源身份重复:{tuple(必读)}")
|
||
|
||
分隔字节 = len(分隔符.encode("utf-8"))
|
||
片段: list[str] = []
|
||
入选: list[str] = []
|
||
字节数 = 0
|
||
for 来源 in 必读:
|
||
文本 = 材料.get(来源)
|
||
if 文本 is None or not 文本.strip():
|
||
raise 上下文错误("CONTEXT_REQUIRED_MISSING", f"必读来源缺失或为空:{来源}")
|
||
必读总字节 = 字节数 + len(文本.encode("utf-8")) + (分隔字节 if 片段 else 0)
|
||
if 必读总字节 > 字节上限:
|
||
raise 上下文错误(
|
||
"CONTEXT_BUDGET_EXCEEDED",
|
||
f"必读材料需要 {必读总字节} 字节,超出上限 {字节上限}",
|
||
)
|
||
片段.append(文本)
|
||
入选.append(来源)
|
||
字节数 = 必读总字节
|
||
|
||
省略: list[tuple[str, str]] = []
|
||
for 来源, 文本 in 材料.items():
|
||
if 来源 in 入选:
|
||
continue
|
||
if not 文本.strip():
|
||
省略.append((来源, "EMPTY"))
|
||
continue
|
||
增量 = len(文本.encode("utf-8")) + (分隔字节 if 片段 else 0)
|
||
if 字节数 + 增量 > 字节上限:
|
||
省略.append((来源, "BUDGET_EXCEEDED"))
|
||
continue
|
||
片段.append(文本)
|
||
入选.append(来源)
|
||
字节数 += 增量
|
||
|
||
区间 = []
|
||
起点 = 0
|
||
for 来源, 文本 in zip(入选, 片段, strict=True):
|
||
终点 = 起点 + len(文本)
|
||
区间.append((来源, 起点, 终点))
|
||
起点 = 终点 + len(分隔符)
|
||
return 材料装配结果(
|
||
入选来源=tuple(入选),
|
||
文本=分隔符.join(片段),
|
||
字节数=字节数,
|
||
省略=tuple(省略),
|
||
材料区间=tuple(区间),
|
||
)
|
||
|
||
|
||
def 按键读取材料(装配: 材料装配结果) -> dict[str, str]:
|
||
"""按精确字符区间回读;区间须按入选顺序覆盖全文与固定分隔符。"""
|
||
if tuple(项[0] for 项 in 装配.材料区间) != 装配.入选来源:
|
||
raise 上下文错误("CONTEXT_INPUT_INVALID", "材料区间与入选来源不一致")
|
||
结果 = {}
|
||
起点 = 0
|
||
for 键, 开始, 结束 in 装配.材料区间:
|
||
if (
|
||
type(开始) is not int
|
||
or type(结束) is not int
|
||
or not (开始 == 起点 and 开始 <= 结束 <= len(装配.文本))
|
||
):
|
||
raise 上下文错误("CONTEXT_INPUT_INVALID", "材料区间越界或不连续")
|
||
if 结果 and 装配.文本[开始 - len(分隔符) : 开始] != 分隔符:
|
||
raise 上下文错误("CONTEXT_INPUT_INVALID", "材料分隔符不一致")
|
||
结果[键] = 装配.文本[开始:结束]
|
||
起点 = 结束 + len(分隔符)
|
||
if 结果 and 起点 - len(分隔符) != len(装配.文本):
|
||
raise 上下文错误("CONTEXT_INPUT_INVALID", "材料区间未覆盖全文")
|
||
return 结果
|
||
|
||
|
||
__all__ = ["装配材料", "按键读取材料"]
|