fix: address completion verdict review findings

- fidelity cacheability also requires a non-empty projected body, so
  think-tag-only answers are no longer cached
- a no-argument tool sent with arguments null only is a deterministic
  dialect: ResultInvalid tool_arguments_null instead of retried
- text mode treats choice index null as 0 and no longer lets False pose
  as 0
- null-only tool_calls elements no longer produce an empty tool_calls
  list; non-stream fidelity checks role before the verdict; warning
  paths are length-bounded
- docs: ARCHITECTURE 7.8 field counts, README cache/watchdog wording,
  CHANGELOG notes, review record in the design, hook note in the plan

Red: 8 new tests failed before this change (e.g.
test_openai_cacheable_requires_projected_body,
test_null_arguments_tool_is_result_invalid_stream,
test_text_mode_choice_index_null_is_zero[None-True]).
This commit is contained in:
2026-10-15 00:22:07 -04:00
parent 31942f55f1
commit abcdf6930e
12 changed files with 179 additions and 27 deletions
+19
View File
@@ -244,3 +244,22 @@ def test_stream_end_exported():
import polygateway
assert "StreamEnd" in polygateway.__all__
def test_openai_cacheable_requires_projected_body():
"""审查 I1: think 标签剥离后投影为空,即使原文非空也不可缓存。"""
think_only = _completion(content="<think>x</think>")
assert not _is_cacheable(
mode="openai", content="", finish_reason="stop", stream_end="done", completion=think_only
)
def test_null_arguments_only_tool_is_result_invalid():
"""审查 I2: 无参函数 arguments 全程 null(其余齐全)→ 确定性方言,ResultInvalid。"""
tool = {"id": "t1", "type": "function", "function": {"name": "f", "arguments": None}}
summary = _summarize_message({"role": "assistant", "tool_calls": [tool]}, "")
assert summary.null_arguments and not summary.tools_ok
verdict = _judge_outcome(mode="openai", summary=summary, finish="natural")
assert (verdict.error_kind, verdict.code) == ("result_invalid", "tool_arguments_null")
broken = {"id": "t1", "type": "function", "function": {"arguments": None}}
assert not _summarize_message({"role": "assistant", "tool_calls": [broken]}, "").null_arguments