Does finishReason "stop" always send for streamText?

HEAD
a29b934Version Packages (#12294)
This post might have stale content, as HEAD is 64 commits ahead.

does finishReason "stop" get sent always in the case of a successful generation? for streamText, i mean.

Avatar of anthropic/claude-opus-4.5
Claude Opus 4.5
commented

Now I have a complete picture. Let me summarize the findings:

##Summary: finishReason in streamText

No, finishReason: "stop" is NOT always sent for a successful generation. Here's how it works:

###Possible finishReason values:

From packages/ai/src/types/language-model.ts:

export type FinishReason =
  | 'stop'        // model stopped naturally (e.g., end of response)
  | 'length'      // model stopped due to max tokens
  | 'content-filter' // model stopped due to content filtering
  | 'tool-calls'  // model stopped to make tool calls
  | 'error'       // model stopped due to an error
  | 'other';      // model stopped for other reasons

###When you get each finishReason:

  1. "stop" - The model naturally completed its generation (most common for a simple successful text completion)

  2. "tool-calls" - The model stopped because it wants to call tools. This is a "successful" generation too, just one that requires tool execution. If you have multi-step tool loops, intermediate steps will have finishReason: "tool-calls" and only the final step will typically have "stop".

  3. "length" - The model hit the maximum token limit (maxTokens)

  4. "content-filter" - The provider's content filter triggered

  5. "error" - An error occurred during generation

  6. "other" - Default fallback when the provider doesn't specify a reason (see packages/openai/src/chat/map-openai-finish-reason.ts)

###Default behavior:

  • Providers initialize finishReason as { unified: 'other', raw: undefined } (line 443 in the OpenAI provider)
  • If no finish chunk comes from the provider with a reason, or the stream ends early, you may get 'other'
  • In stream-text.ts (line 974): const finishReason = recordedFinishReason ?? 'other'; — if no finish reason was recorded, it defaults to 'other'

###Key takeaway:

A "successful generation" with tool calling will often end with finishReason: "tool-calls" on intermediate steps. The "stop" reason indicates the model naturally finished generating text without needing to call tools or hitting any limits.


END OF POST

Does finishReason "stop" always send for streamText? — vercel/ai