8000 fix(completions): 推理块关闭后到达的 reasoning_details 不再丢失 by ix64 · Pull Request #122 · felinics/twilight · GitHub
[go: up one dir, main page]

Skip to content

fix(completions): 推理块关闭后到达的 reasoning_details 不再丢失 - #122

Open
ix64 wants to merge 1 commit into
felinics:mainfrom
ix64:fix/reasoning-details-late
Open

ix64 wants to merge 1 commit into
felinics:mainfrom
ix64:fix/reasoning-details-late

Conversation

@ix64
@ix64 ix64 commented Oct 13, 2026
Copy link
Copy Markdown
Member

概要

OpenRouter 有时在推理块被正文或工具调用关闭之后,才发来 reasoning_details 片段。流式处理原来只在第一次(!reasoningBlockSeen)为不带文本的片段打开推理块。之后到达的片段虽然并进了 sp.reasoningDetails,却再没有 ReasoningEndPart 把它带出去,所以 ReasoningPart 的元数据里没有它,下一轮回传也缺这一项。

  • 迟到的片段重新打开推理块:带 reasoning_details 的 delta 总会调用 startReasoning(chunkID)。块已关闭时,按同一 ID 重新打开它,块下一次结束时带上完整的累积数组。sdk 的 reasoningAccumulator 按 ID 把它并回原来的 ReasoningPart,不会多出第二个推理块。推理文本续上时本来就这样重开推理块,这次让只带细节的片段也一样。DeepSeek 的空 reasoning_content 标记仍不会重开已关闭的块。
  • 实际场景:Gemini 经 OpenRouter 时,正文的思考签名(只带 signature 的 reasoning.text)在正文之后才发。前面没有推理文本时,由签名打开第一个块,没有问题。前面有推理文本时,块已经被正文关闭,签名就丢了。
  • 文档:docs/providers.md 里「按 index 合并」的说明在 fix(completions): preserve streamed reasoning detail order #118 之后已经不对,改成按线上顺序合并,并补上迟到片段的说明。

关联

验证

  • 新增 reasoning_details_test.go,使用 2026-10-13 从 OpenRouter 录下的流式分片,不透明值只保留前 24 个字符。测试先流式接收,再用 WithReasoningReplay(sdk.ReasoningReplay{Field: sdk.ReasoningReplayDetails}) 回传,核对 ReasoningPart 上保留的和请求里回传的 reasoning_details:
    • Gemini 调用工具:推理文本,加上同在 index 0 的 reasoning.encrypted(思考签名,id 是工具调用的 id)
    • GPT 调用工具:摘要,加上 index 1 的 reasoning.encrypted
    • Claude 8000 调用工具:推理文本,签名是同一项的后续片段
    • Gemini 直接回答:签名在正文之后
    • Gemini 先给推理文本、正文之后才发签名:用上面录下的分片拼成(把推理分片换到正文那次的生成 id 下)。修改前的代码上只有这一条失败。前四条在 fix(completions): preserve streamed reasoning detail order #118 之后已经通过,作为真实分片的回归测试保留。
  • 本地按 CI 流程跑过:go build ./...、go vet ./...、go vet -tags integration ./...、go test ./... -short -count=1 -race、internal/sdkdiff 的测试,go mod tidy 无变化。
  • golangci-lint:仓库锁定的 2.11.3 在 Go 1.27 下会 panic,所以改用 2.14.0。改动的文件没有报告;其余报告(goconst 等)在 main 上同样存在。
  • 真实接口:fork 上的同类修复用探针对 OpenRouter 实测过回传,Gemini、GPT、Claude 都返回 200。正文之后迟到的签名没有在真实接口上验证过,本分支也没有再对真实接口跑。

行为变化

  • 流式输出中,推理块关闭后到达的 reasoning_details 片段会再触发一对 ReasoningStartPart/ReasoningEndPart,ID 与原块相同。按 ID 聚合的调用方(包括 sdk 自己的 ModelResult)得到的仍是一个推理块;只看事件顺序的调用方,会在正文或工具调用之后看到它。

- 不带文本的 reasoning_details 片段在推理块已被正文或工具调用关闭后到达时,
  按同一 ID 重新打开推理块,由块的下一次结束带上它,和续上的推理文本一样。
  此前只有第一个片段会打开推理块,之后的片段并进累积数组,却没有块结束来带走,
  回传时缺失。Gemini 经 OpenRouter 在正文之后才发正文的思考签名,前面有推理
  文本时签名就丢了
- 新增测试,用 2026-10-13 从 OpenRouter 录下的分片:Gemini(推理文本与加密的
  思考签名)、GPT(摘要与加密推理)、Claude(带签名的思考)各一个调工具的
  回合,Gemini 在正文后发签名的回合,以及由录下的分片拼成的、先有推理文本的
  同类回合;流式后回传,核对保留与回传的 reasoning_details
- 文档:按 index 合并的旧说明改为按线上顺序合并,并说明迟到的片段
ix64 added a commit to ix64/twilight that referenced this pull request Oct 13, 2026
…e stream"

This reverts commit 9821109.

Upstream felinics#118 merges reasoning_details in wire order and supersedes the
type+index merge here; the late-piece fix is proposed separately in felinics#122.
This branch goes back to the errorformat and openai models fixes only.
ix64 added a commit to ix64/twilight that referenced this pull request Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0