实现侧: - 上下文:任务范围拆分为 范围校验/范围授权;索引按可发现口径重建、索引新鲜度改对称差;依赖校验统一快照漂移说明。 - 知识方法:方法与材料读取口径统一;超限方法材料按可选省略,核对路径不再二次计费;删除无合同的读时重算。 - 任务运行:新增 context.usage/tool.denied 事件类型;连接池常驻并在装配生命周期内开关;调用结算与核对分列。 - 效果评测/审校修订/交付连载/作者经验/作品规划:凭据冻结、标定消费、导出补证、事实引文核对等收尾修复。 - 资源加载:能力正文不再夹带索引用的导航注记(该注记此前进入角色与技能的模型提示)。 - 元数据:受保护骨架与代码保护属性对齐;字段校验与内置结构口径同步。 - 基础设施:环境预检进入装配生命周期;数据库连接运行期字段不参与相等比较;索引指纹归一化 jsonb 浮点。 - 删除被替代实现:7 份旧提示词模板与空壳 资料来源 读取器。 用例侧: - 用例身份与导航元信息迁移;夹具补生命周期、同库暴露与模板封存; - 本轮定向修复:方法材料省略、事实引文、迁移回执、额度与暂停用例、慢用例超时预算等。
155 lines
6.6 KiB
Python
155 lines
6.6 KiB
Python
"""材料装配的必读优先、UTF-8 字节预算与省略原因;离线纯函数合同。
|
||
|
||
字节期望值按 UTF-8 逐字写死,不由被测函数自身推算,避免同源计算自证。
|
||
"""
|
||
|
||
import dataclasses
|
||
|
||
import pytest
|
||
|
||
from muse.上下文.接口 import 上下文错误, 装配材料
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-ctx-budget-priority",
|
||
environment="离线纯函数",
|
||
given="必读来源与多个可选材料的有序映射",
|
||
when="按 64 字节上限装配材料",
|
||
then=[
|
||
"必读最先入选,可选按输入顺序整项加入并以两个换行分隔",
|
||
"字节数按 UTF-8 写死核算,结果不可变",
|
||
],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md",
|
||
)
|
||
def test_必读优先且可选按原顺序整项加入__1c4a9e() -> None:
|
||
材料 = {"可选甲": "甲文", "必读": "必读文", "可选乙": "乙文"}
|
||
结果 = 装配材料(材料, ("必读",), 字节上限=64)
|
||
assert 结果.入选来源 == ("必读", "可选甲", "可选乙")
|
||
assert 结果.文本 == "必读文\n\n甲文\n\n乙文"
|
||
assert 结果.字节数 == 25 # 三个片段 9+6+6 字节加两处分隔符
|
||
assert 结果.省略 == ()
|
||
with pytest.raises(dataclasses.FrozenInstanceError):
|
||
结果.文本 = "改写"
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-ctx-budget-utf8",
|
||
environment="离线纯函数",
|
||
given="含四字节 emoji 与组合字符的中文材料",
|
||
when="分别在恰好容纳与差一字节的上限下装配",
|
||
then=[
|
||
"中文与 emoji 逐字按 UTF-8 计数且含分隔符",
|
||
"差一字节时可选整项省略并给出 BUDGET_EXCEEDED,不截断中文",
|
||
],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md",
|
||
)
|
||
def test_中文与emoji按utf8字节计数含分隔符__5d1c47() -> None:
|
||
原文 = "第1章:雨。🌧"
|
||
仅必读 = 装配材料({"历史": 原文}, ("历史",), 字节上限=20)
|
||
assert 仅必读.文本 == 原文
|
||
assert 仅必读.字节数 == 20 # 含四字节 emoji
|
||
|
||
材料 = {"历史": 原文, "旁观": "他站着"}
|
||
齐 = 装配材料(材料, ("历史",), 字节上限=31)
|
||
assert 齐.入选来源 == ("历史", "旁观")
|
||
assert 齐.字节数 == 31 # 20 + 分隔符 2 + 9
|
||
assert 齐.文本 == f"{原文}\n\n他站着"
|
||
|
||
缺一字节 = 装配材料(材料, ("历史",), 字节上限=30)
|
||
assert 缺一字节.入选来源 == ("历史",)
|
||
assert 缺一字节.文本 == 原文
|
||
assert 缺一字节.省略 == (("旁观", "BUDGET_EXCEEDED"),)
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-ctx-budget-required-missing",
|
||
environment="离线纯函数",
|
||
given="必读来源不在材料映射或只有空白",
|
||
when="装配材料",
|
||
then=["整体拒绝并返回 CONTEXT_REQUIRED_MISSING,说明点名缺失的具体来源身份"],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md",
|
||
)
|
||
@pytest.mark.parametrize(
|
||
("材料", "必读"),
|
||
[({}, ("孤本第三章",)), ({"孤本第三章": " \n "}, ("孤本第三章",))],
|
||
ids=["missing", "blank"],
|
||
)
|
||
def test_必读缺失或空白拒绝__a7e903(材料: dict[str, str], 必读: tuple[str, ...]) -> None:
|
||
with pytest.raises(上下文错误) as 异常:
|
||
装配材料(材料, 必读, 字节上限=64)
|
||
assert 异常.value.错误码 == "CONTEXT_REQUIRED_MISSING"
|
||
assert "孤本第三章" in 异常.value.说明
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-ctx-budget-required-over",
|
||
environment="离线纯函数",
|
||
given="两份必读合计 20 字节、上限 19 与恰好 20 两种",
|
||
when="装配材料",
|
||
then=[
|
||
"必读放不下整体拒绝并返回 CONTEXT_BUDGET_EXCEEDED 与实际需要字节数",
|
||
"恰好等于上限时必读全部入选,可选按 BUDGET_EXCEEDED 省略",
|
||
],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md",
|
||
)
|
||
def test_必读整体超预算拒绝__c9e51f() -> None:
|
||
材料 = {"甲": "必读甲", "乙": "必读乙", "可选": "可选丙"}
|
||
with pytest.raises(上下文错误) as 异常:
|
||
装配材料(材料, ("甲", "乙"), 字节上限=19)
|
||
assert 异常.value.错误码 == "CONTEXT_BUDGET_EXCEEDED"
|
||
assert "20" in 异常.value.说明
|
||
|
||
恰好 = 装配材料(材料, ("甲", "乙"), 字节上限=20) # 9 + 分隔符 2 + 9
|
||
assert 恰好.入选来源 == ("甲", "乙")
|
||
assert 恰好.字节数 == 20
|
||
assert 恰好.省略 == (("可选", "BUDGET_EXCEEDED"),)
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-ctx-budget-omission",
|
||
environment="离线纯函数",
|
||
given="必读、空白可选、超长可选与可入选可选并存",
|
||
when="按紧预算装配",
|
||
then=["省略条目按输入顺序分别给出 EMPTY 与 BUDGET_EXCEEDED 原因"],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md",
|
||
)
|
||
def test_可选空白与超预算分别给出省略原因__4f8ab2() -> None:
|
||
材料 = {"必读": "必读文", "空白": " ", "太长": "长" * 40, "入选": "短文"}
|
||
结果 = 装配材料(材料, ("必读",), 字节上限=17) # 9 + 分隔符 2 + 6
|
||
assert 结果.入选来源 == ("必读", "入选")
|
||
assert 结果.省略 == (("空白", "EMPTY"), ("太长", "BUDGET_EXCEEDED"))
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-ctx-budget-invalid-input",
|
||
environment="离线纯函数",
|
||
given="字节上限为零、负数、True 或必读身份重复",
|
||
when="装配材料",
|
||
then=["一律返回 CONTEXT_INPUT_INVALID;True 是 bool 不被当作正整数预算"],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md",
|
||
)
|
||
@pytest.mark.parametrize(
|
||
("字节上限", "必读"),
|
||
[(0, ("必读",)), (-3, ("必读",)), (True, ("必读",)), (64, ("必读", "必读"))],
|
||
ids=["zero", "negative", "boolean", "duplicate"],
|
||
)
|
||
def test_非法预算或重复必读身份拒绝__e2168c(字节上限: int, 必读: tuple[str, ...]) -> None:
|
||
with pytest.raises(上下文错误) as 异常:
|
||
装配材料({"必读": "必读文"}, 必读, 字节上限=字节上限)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-ctx-budget-verbatim",
|
||
environment="离线纯函数",
|
||
given="首尾空白、制表符与换行并存的材料原文",
|
||
when="装配材料",
|
||
then=["入选文本与原文逐字一致,不 trim、不截断,字节数按原文 UTF-8 核算"],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md",
|
||
)
|
||
def test_原文不裁剪空白且按原字节保留__b4d7a1() -> None:
|
||
原文 = " 第1章 \n雨还在下。\t\n"
|
||
结果 = 装配材料({"历史": 原文}, ("历史",), 字节上限=29)
|
||
assert 结果.文本 == 原文
|
||
assert 结果.字节数 == 29
|