feat(tools): 落成 executor() 与派生分发器;公共数据类一律只收关键字参数
两个自行调研后决定的问题,各自的证据写进了 design doc: 一、handler 返回 str 而不是带截断计数的小结构(0008 决策三,文末新增一节)。三条实据: 两个真实消费者的执行函数今天就返回纯字符串(GovDoc 的 handler 是 Coroutine[..., str], dissect 的环境 execute 是 -> str);dissect 的 observation_truncated_chars 唯一的生产写入点 硬编码 0 且全仓零读取点,存在的是名字不是需求;reference/pi 是唯一把截断做完整的,它记的是 totalBytes/outputBytes/maxBytes 这组绝对量而不是一个差值——现在补 truncated_chars 补的 大概率是错形状,正是 scope.md 说的「猜出来的接缝比没有接缝更难拆」。 二、新增 design 0009:src/polyloop/ 下每个数据类都加 kw_only=True,另加一条扫描测试守它。 实验室七个仓库 223 个 dataclass 里 kw_only 出现零次,但那是默认行为不是选择。真正的证据是 PolyGateway:它的 LLMResponse 前 11 个字段顺序被三个下游的测试替身按位置构造锁死,模块 docstring 写着「字段顺序即公共承诺」,还得专门写一条 test_eleven_legacy_fields_positional 守着,从此再也插不进字段。那个约束不是它选的是它继承的,而本库还没有下游装上。 扫描测试查的是构造签名不是那个装饰器参数——要守的承诺是「按位置构造不了」。 executor() 在派生那一刻全查一遍实现,缺一个就报错,不拖到分发时才炸。RegistryExecutor 是 具体类而不是闭包,因为 RunRequest 要用 isinstance 认它。CancelledError 不被那个 except Exception 接住(它继承 BaseException),有测试守着。
This commit is contained in:
@@ -37,7 +37,7 @@ from polyloop.types import (
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen=True, slots=True, kw_only=True)
|
||||
class ModelCall:
|
||||
"""交给模型调用接缝的一次调用。"""
|
||||
|
||||
@@ -55,7 +55,7 @@ class ModelCall:
|
||||
binding: Mapping[str, str]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen=True, slots=True, kw_only=True)
|
||||
class ToolCall:
|
||||
"""一次工具调用的名字与参数。"""
|
||||
|
||||
@@ -63,7 +63,7 @@ class ToolCall:
|
||||
arguments: Mapping[str, object]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen=True, slots=True, kw_only=True)
|
||||
class Action:
|
||||
"""决策解释出的动作。"""
|
||||
|
||||
@@ -74,14 +74,14 @@ class Action:
|
||||
tool_call: ToolCall | None
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen=True, slots=True, kw_only=True)
|
||||
class FinalAnswer:
|
||||
"""模型给出的最终回答。这一支不碰环境。"""
|
||||
|
||||
text: str
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen=True, slots=True, kw_only=True)
|
||||
class InvalidDecision:
|
||||
"""解释不出有效动作。"""
|
||||
|
||||
@@ -94,7 +94,7 @@ class InvalidDecision:
|
||||
Decision = Action | FinalAnswer | InvalidDecision
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen=True, slots=True, kw_only=True)
|
||||
class ParsedReply:
|
||||
"""决策解释接缝的返回。"""
|
||||
|
||||
@@ -105,7 +105,7 @@ class ParsedReply:
|
||||
decision: Decision
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen=True, slots=True, kw_only=True)
|
||||
class RunLog:
|
||||
"""一份读回来的完整日志。恢复判定读它。
|
||||
|
||||
@@ -119,7 +119,7 @@ class RunLog:
|
||||
finished: RunFinished | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen=True, slots=True, kw_only=True)
|
||||
class Event:
|
||||
"""从事件出口发出去的一条事件。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user