feat(session): 参数快照补上配方指纹与注入通道,并写定执行器抛异常的契约
四件事,都来自第一个下游的 issue。 **RunRequest 新增 fingerprints。** 上下文与注入内容刻意不进快照(它们是数据不是参数), 而这条规则把生成它们的提示词模板也一起挡在外面了。具体的失败场景:换一份模板续跑不报错, 前几步用 A 模板、后几步用 B,那次运行的数据已经废了却没有任何提示。键形状 request.fingerprint.<name>,和 model_binding 那个坐标分开——一个是「这次运行属于哪一格」, 一个是「用的配方是哪一版」,混在一个字段里事后分不开。默认空映射时一个键都不写,所以已有 配置算出来的快照逐字节不变。 **注入的通道维度不再拍平。** 一通道一键,于是「声明了通道但一条都没选中」和「压根没有这个 通道」分得开:前者是值为空串的键,后者是键不存在。有一档实验要比较的正是这两种情形。 **ActionExecutor 的 docstring 写定抛异常时会怎样**:环境故障走 ENV_ERROR 返回值,实现方真 抛了库不接管、异常原样穿出。理由在 design 0016;简言之库替它编一个结算结果就是在编造,而 副作用状态在那一刻是未知的。 **三个映射字段在构造期冻成只读。** 对抗审查发现 frozen=True 不禁止改字段里那个 dict,于是 构造期那道「快照取值必须是字符串」的校验能被绕过去:构造完往 fingerprints 里塞一个整数, 它一路进日志,要到续跑读日志时才炸——而那时这次运行已经完整跑过一遍。复用 tools 里已有的 _frozen,没另写一套。
This commit is contained in:
@@ -154,14 +154,45 @@ def test_channels_are_ordered_by_name_not_by_mapping_order() -> None:
|
||||
assert [block.text for m in injection_messages(entries) for block in m.content] == ["A", "Z"]
|
||||
|
||||
|
||||
def test_entry_ids_come_back_in_the_same_order_as_the_messages() -> None:
|
||||
"""轨迹里记的是条目标识,正文不进——正文可能很大,而「这次贴了哪几条」事后要查得到。"""
|
||||
def test_entry_ids_keep_the_channel_they_came_from() -> None:
|
||||
"""参数快照里记的是条目标识,正文不进——正文可能很大,而「这次贴了哪几条」事后要查得到。
|
||||
|
||||
通道维度保留:拍平之后「声明了这个通道但一条都没选中」和「压根没有这个通道」是同一个
|
||||
结果,而有下游要比较的正是这两种情形。
|
||||
"""
|
||||
entries = {
|
||||
"zeta": (Injection(entry_id="z", content="Z"),),
|
||||
"alpha": (Injection(entry_id="a", content="A"),),
|
||||
"alpha": (Injection(entry_id="a", content="A"), Injection(entry_id="b", content="B")),
|
||||
}
|
||||
|
||||
assert injected_entry_ids(entries) == ("a", "z")
|
||||
assert injected_entry_ids(entries) == {"alpha": ("a", "b"), "zeta": ("z",)}
|
||||
|
||||
|
||||
def test_a_declared_but_empty_channel_is_not_the_same_as_a_missing_one() -> None:
|
||||
"""一个是值为空元组的项,另一个是这个项不存在。两者拼进快照才分得开。"""
|
||||
assert injected_entry_ids({"skill": ()}) == {"skill": ()}
|
||||
assert injected_entry_ids({}) == {}
|
||||
|
||||
|
||||
def test_entry_ids_come_back_in_the_same_order_as_the_messages() -> None:
|
||||
"""两个函数的顺序必须一致,它们同住一个模块就是为了守住这一点。
|
||||
|
||||
对不上的话,快照记的贴入顺序和模型真正看到的顺序是两回事,而续跑守卫照样全绿。
|
||||
"""
|
||||
entries = {
|
||||
"zeta": (Injection(entry_id="z", content="Z"),),
|
||||
"alpha": (Injection(entry_id="a", content="A"), Injection(entry_id="b", content="B")),
|
||||
}
|
||||
by_content = {"A": "a", "B": "b", "Z": "z"}
|
||||
|
||||
flattened = [
|
||||
entry_id for entry_ids in injected_entry_ids(entries).values() for entry_id in entry_ids
|
||||
]
|
||||
from_messages = [
|
||||
by_content[block.text] for m in injection_messages(entries) for block in m.content
|
||||
]
|
||||
|
||||
assert flattened == from_messages
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user