Skip to content

[v2] 接受无新增内容的重复终态 usage 块 - #232

Merged
EricWvi merged 1 commit into
ora-space:mainfrom
ElephantGit:fix/774-openrouter-terminal-usage
Oct 30, 2026
Merged

EricWvi merged 1 commit into
ora-space:mainfrom
ElephantGit:fix/774-openrouter-terminal-usage

Conversation

@ElephantGit

@ElephantGit ElephantGit commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

OpenRouter 兼容流可能先发送正常文本和 stop,随后在 usage 块里重复一个空的 stop choice,再发送 [DONE]。此前第二个 choice 被一律拒绝,导致已经收齐的答案以 model_response_invalid 失败。

现在仅允许带完整基础 usage 计数、单个 index:0、与既有 stop 相同且没有新增内容的终态元数据 choice。delta 可缺省、null 或为空,role 可缺省、null、空字符串或 assistant。新正文、推理、工具、拒绝、音频、annotations、变化的终态、多 choice、错误 envelope、缺 DONE 和同次收到的 DONE 后数据仍失败;没有 usage 的普通重复空 choice 不会被放行。reasoning_details 在普通 chunk 中仍被忽略且不进入答案;终态元数据中仅缺省/null/空数组可通过。

独立 PR 验证:Go 1.27.1 / Linux,gofmt、go vet ./...、设置真实 PostgreSQL TEST_DATABASE_URL 的 go test -race -count=1 ./...、git diff --check 全部通过。真实 httptest TLS + RemoteProvider 重放脱敏响应:18 字节答案、两个 stop choice、33/37/70 token usage 和 reasoning/cache 明细;回归覆盖空 delta 形式及新增正文、工具、拒绝、推理详情、类型错误、变化终态、缺失 usage 等坏变体。上述自动化回归使用本地 TLS,不需模型密钥。最终 head d6f44d4 的 v2 CI server、frontend、e2e 全部通过。

另完成组合验收:本修复合入集成分支 c52500e 后,在原生 Linux 运行 race 编译的 TestConfiguredProviderServicePostgresRestart(internal/executionruntime/configured_provider_test.go,-test.run=^TestConfiguredProviderServicePostgresRestart$ -test.v -test.timeout=12m),以 V2_REAL_PROVIDER_TEST=1、OpenRouter https://openrouter.ai/api/v1 和 nvidia/nemotron-3-ultra-550b-a55b:free 验证真实模型直连,再通过真实 Node/OpenCode 执行工具并检查 marker;End 后重建 PostgreSQL 连接池与 Service,读回结果一致。组合测试 49.67 秒通过,确认重复终态 usage 不再把完整模型答案误判为失败。此证据包含集成分支的公共 Service、驱动与测试,并非本 PR 单独交付这些组件。

本 PR 严格只有三个交付文件:internal/modelturn/response.go、terminal_usage_test.go、README.md;不新增 Service、Node 驱动或页面。

v2,不涉及 specs。

Refs ora-space/circus#774

@wanglongan587

Copy link
Copy Markdown
Collaborator

独立只读审查(成员,非本运行 reviewer)

审过 commit d6f44d4894f796a57d386ff77197f443fe6dd487。结论:未发现阻塞问题,从正确性上可以合入。

核对点:

  • 终态后的重复 choice 只在 w.finished、hasCounters、finish_reason 与既有 stop 一致且 stopReason == "stop" 时放行;随后再要求 content 为空、reasoning / reasoning_content / reasoning_details 为空才返回 nil。新增正文、推理、工具、拒绝、改变终态、多 choice,以及缺 usage / partial usage 仍有拒绝路径,和 README 的表述一致。
  • usage 在 choices 之前解析,终态块里的完整基础计数会更新先前值;计数不一致时按既有规则清空 usage(normalizeUsage 返回 hasCounters=true、值为 nil),不会把坏计数留给上层。
  • 测试覆盖 6 种 delta 形态的正例和 19 种坏变体,另有「终态前出现的 reasoning_details 不进入答案」「缺 DONE / 错误 envelope / DONE 后数据仍失败」两组用例;go test ./internal/modelturn 在本机(Go 1.27.1)也通过,CI 在 head 上全绿(run 41034055449)。
  • 与集成分支 c52500ed 比对,本 PR 三个文件逐字一致,作者的组合验收确实用的是这份修复。

一个非阻塞边界:终态块里 reasoning_details: {}(对象而非数组)会被 emptyReasoningDetails 判为坏变体拒绝,空数组和 null 才通过。目前观察到的 provider 形状是空数组;如果后续真实 provider 在终态 usage 块里发 {},会再次失败,到时按实际形状放宽即可。

@EricWvi
EricWvi merged commit fe60df2 into ora-space:main Oct 30, 2026
3 checks passed
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.

3 participants