• 1.3.10 Stable

    iomgaa released this 2026-10-15 13:18:12 +08:00 | 20 commits to main since this release

    #30/#31 同根修复: 1.3.9 以 [DONE] 存在、正文非空、字段白名单判定成功,上游的正常结局被当瞬时错误重试到耗尽(magpie/glm 不发 [DONE] 时单次调用挂 1216s;只有思考的 length 截断每次写满 max_tokens 后重抽)。本版改以上游 finish_reason 与传输完整性为准,流式/非流式/缓存读写共用一份判定。设计 research-wiki/designs/2026-10-14-issue30-31-completion-verdict-design.md。

    修复

    • 缺 [DONE] 但完整的流(#31,两种模式): finish_reason 已到、其同帧或之后收到实测 usage、连接干净关闭 → 完整交回,用量记 measured,stream_end="eof_after_finish"。文本模式默认 MISSING_DONE=retry 原本同样会重试到耗尽;该键现在只管真截断(无 finish 或 finish 后无实测 usage)。
    • 只有思考的 length 截断(#30): 保真模式原样交回(content 空、思考完整、finish_reason=length),不再重抽。
    • null 与未知字段(#30): 任意层 null 视为缺省(refusal: null、tool_calls: null 不再判失败,非流式同样修复);保真模式未知字段按 OpenAI 流式惯例无损合并(字符串拼接、对象递归、带 index 数组按 index 合并、index/type/id/format 同值幂等),Gemini extra_content 一类工具层扩展可原样回传。
    • reasoning 别名: vLLM/OpenRouter 的 reasoning 字段计入活性(此前只有思考的流会被 TTFT 看门狗误杀),文本模式无非空 reasoning_content 时投影为 thinking。
    • 截断结果不再写缓存: 文本 salvage 结果此前会被缓存并在 TTL 内反复回放。

    行为变更

    • 文本模式 length/过滤且无正文 → ResultInvalidError(原 TransientError 重试到耗尽): 不重试、不换源、熔断记成功不计窗口;不经 AllSourcesExhausted 包装,直接到调用方。原因码见异常消息(length_without_content / filtered_without_content)。文本模式"只有思考 + stop"维持瞬时(证据收集中)。
    • finish_reason 为 network_error/error(GLM 等上游自报失败)即使有正文也判瞬时。
    • 保真模式: 只有思考/拒答/空白 + 明确 finish(非上游错误)→ 原样交回;length 截断的半截工具(缺 id/name)→ ResultInvalidError tool_truncated;无参函数全程只发 arguments: null(其余字段齐全)→ ResultInvalidError tool_arguments_null(确定性方言,交付值不改写)。
    • 文本模式 choice.index: null 视为 0(此前整帧被丢弃);tool_calls 中全为 null 的元素按 tool_calls: null 处理,不产出会被上游拒收的空数组。
    • 缓存: 只有自然结束(stop/tool_calls/无 finish 的旧口径)且有正文的结果写入;length/过滤/未登记 finish 值、salvaged、空正文均交付但不缓存,读到此类条目按 miss。未登记 finish 值按源告警一次。
    • 活性口径增补: 未知字段的非空字符串片段(如 reasoning)算进展,index/type/id/format 等标签键不算;stall_ms 计量随之覆盖。

    新增

    • LLMResponse / TransportResult 末尾追加 finish_reason: str | None、stream_end: StreamEnd | None(done / eof_after_finish / salvaged;非流式、缓存命中为 None);包根导出 StreamEnd。
    • 遥测 llm_calls 末尾追加可空列 stream_end(INSERT 字段 38 → 39,物理列 39 → 40;旧行 NULL 不回填;auto 档幂等补列,manual 档裁剪写入并点名缺列,补列 SQL 由 telemetry_schema_sql() 自取)。

    破坏性(请先读)

    • TelemetryRecorder.record_llm_call 新增必填 keyword stream_end: 自建 recorder 未跟进会在装配期被形状闸拒绝(**fields 形态不受影响)。

    提醒

    • 保真模式交付 finish_reason=length 的工具调用时 arguments 可能是半截 JSON: 执行工具前先查 finish_reason。
    • 未知字段合并冲突时会删除该字段并按(源, 路径)告警一次: 结果可能缺字段,以告警为准。典型形态: 带 index 的数组(如 reasoning_details)后续帧元素缺 index 即判形态改变,整个字段被删。
    • 诚实边界: 中转在上游出错后主动正常关闭连接,与真完整在传输层不可区分;防线是"finish 必须存在、不属上游错误、且其后有实测 usage"。
    • 旧版本写入的 salvage/length 文本缓存无法辨认: 受影响集合须在升级后首次读写前更换 namespace/salt(同 1.3.9 提醒)。
    Downloads