fix: infer tool-calls finishReason when finish_reason is unknown (#420)#430
fix: infer tool-calls finishReason when finish_reason is unknown (#420)#430robert-j-y wants to merge 3 commits intomainfrom
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
The usage fallback in flush() was dead code — both usage and openrouterUsage are always populated from the same value.usage block in transform(), so the condition could never be true. Removed the fallback and its misleading test. PR now focuses solely on #420 (finishReason inference). Co-Authored-By: Robert Yeakel <robert.yeakel@openrouter.ai>
Addressing "Items for human review"1. FinishReason inference: infers
|
Description
Fixes #420 — Some providers (e.g. Kimi K2.5) return unknown or null
finish_reasonvalues even when tool calls are present. The SDK maps these to'other', which breaks agentic loops since the AI SDK doesn't know to continue. This PR adds an inference step: iffinishReasonis'other'but tool calls were made, override to'tool-calls'. Applied in bothdoGenerateanddoStreampaths.Updates since last revision
flush()fallback for populatingusagefromopenrouterUsagewas unreachable — both are always populated from the samevalue.usageblock intransform(). Removed the dead code and its misleading test. Issue Standard usage object empty when usage data is in providerMetadata #419 will need to be investigated separately.Key areas for review
flush()(lines ~1041-1055 insrc/chat/index.ts): The existing encrypted-reasoning override runs first, then the new'other'→'tool-calls'override. Verify the ordering is correct and no unintended interaction.doGenerate(mappedFinishReason→effectiveFinishReason): The existing encrypted-reasoning override and the new'other'override are now applied sequentially. Confirm no edge case where both fire incorrectly.finishReason === 'tool-calls'if the model actually returns tool calls. If the model doesn't comply, the test passes vacuously.Checklist
pnpm stylecheckandpnpm typecheckpnpm testand all tests pass (246 tests)Changeset
pnpm changesetto create a changeset fileLink to Devin Session: https://app.devin.ai/sessions/05ec3186bbc44181810cf240b9bccdc4
Requested by: @robert-j-y