fix(provider): treat missing/null finish_reason as stop instead of other - #2174
fix(provider): treat missing/null finish_reason as stop instead of other#2174anandlo wants to merge 2 commits into
Conversation
EsanRAHIMI
left a comment
There was a problem hiding this comment.
The missing-finish-reason fallback should account for tool calls before defaulting to stop. This gateway is described as omitting finish_reason entirely, so a streamed response containing delta.tool_calls will also keep the new initial unified: "stop" value. The transform still emits the tool calls in flush(), but the final finish part now says the model stopped normally rather than tool-calls; consumers that use the finish reason to decide whether to continue the agent/tool loop can terminate early. Could flush() set the fallback to tool-calls when toolCalls.length > 0 (and no explicit reason was received), with a streaming regression test for a tool-call response that omits finish_reason?
Some gateways (e.g. muse-spark-1.2-contributor via opencode.ai/zen/go/v1) never send a finish_reason chunk in streaming and return null in non-streaming. mapOpenAICompatibleFinishReason fell through to the default branch returning "other", which made classify.ts flag every such response as degraded / think-only. - add null/undefined guard in mapOpenAICompatibleFinishReason returning "stop" - change streaming initial finishReason.unified default from "other" to "stop" - add tests covering null/undefined plus regression cases Fixes XiaomiMiMo#2173
…_reason with tool calls The flush() handler now checks if no explicit finish_reason was received (raw == null) and tool calls are present, defaulting to tool-calls instead of stop. This prevents the agent loop from terminating early when a gateway (e.g. muse-spark via zen/go) omits finish_reason but sends tool call deltas. Also adds a streaming regression test for a tool-call response that omits finish_reason, verifying the finish event says 'tool-calls'.
3a13643 to
08f6101
Compare
|
The CI failure in Evidence:
The MCP test failures appear to be a broken CI issue on main that predates this PR. |
Summary
Some gateways served by the OpenCode Go gateway (
opencode.ai/zen/go/v1) do not emit afinish_reasonin streaming responses (and returnnullin non-streaming). The mapping then fell through todefault: return "other", which madeclassify.tsflag every such response as degraded / think-only even though the response was delivered normally.Affected model:
muse-spark-1.2-contributor.Evidence (live gateway streaming captures)
finish_reasondeepseek-v4-pro['stop']✓glm-5['stop']✓muse-spark-1.2-contributorChanges
map-openai-compatible-finish-reason.ts: add anull/undefinedguard before theswitchthat returns"stop".openai-compatible-chat-language-model.ts: change the streaming initialfinishReason.unifieddefault from"other"to"stop"(models that send a properfinish_reasonstill override it).test/provider/map-openai-compatible-finish-reason.test.tscoveringnull/undefinedplus regression cases (stop,length,tool_calls,other,content_filter,"").Verification
bun typecheckfrompackages/opencode/passes.bun test test/providerpasses: 482 pass / 0 fail (8 new tests included).Fixes #2173
Test plan
muse-spark-1.2-contributorand confirmfinishis reported asstop, notother.deepseek-v4-pro/glm-5still reportstopas before (no regression).