Skip to content

Conversation

@mchenco
Copy link
Contributor

@mchenco mchenco commented Jan 30, 2026

Summary

Fixes a critical bug in the streaming implementation where was always hardcoded to "stop" regardless of the actual completion reason from Workers AI.

Problem

The streaming code in streaming.ts line 104 always returned:

finishReason: { unified: "stop", raw: "stop" }  // ❌ Hardcoded!

This caused:

  • ❌ Tool calling scenarios to incorrectly report "stop" instead of "tool-calls"
  • ❌ Multi-turn tool conversations to fail because AI SDK couldn't detect when tools were requested
  • ❌ Length limit scenarios to show "stop" instead of "length"
  • ❌ Error scenarios to show "stop" instead of "error"

Solution

Extract the actual finish_reason from streaming chunks and use the existing mapWorkersAIFinishReason() function:

// Extract finish_reason from chunk (only update if non-null to avoid overwriting)
const choiceFinishReason = chunk?.choices?.[0]?.finish_reason;
const directFinishReason = chunk?.finish_reason;

if (choiceFinishReason != null) {
  finishReason = mapWorkersAIFinishReason(choiceFinishReason);
} else if (directFinishReason != null) {
  finishReason = mapWorkersAIFinishReason(directFinishReason);
}

Then use the tracked value:

finishReason: finishReason ?? { unified: "stop", raw: "stop" }  // ✅ Actual value!

Testing

Unit Tests

  • ✅ Added 8 comprehensive test cases for all finish reason types
  • ✅ Tests for: stop, tool-calls, length, model_length, error, null handling, direct property, multiple chunks
  • ✅ All existing tests continue to pass (7/7 test files)

Integration Testing

  • ✅ Tested with GLM-4.7-Flash in production gadgets environment
  • ✅ Multi-turn tool calling now works correctly
  • ✅ Finish reasons properly reported: "stop" for text, "tool-calls" for tools

Impact

Before:

  • Multi-turn tool calling broken
  • All streaming completions reported as "stop"

After:

  • ✅ Multi-turn tool calling works
  • ✅ Accurate finish reason reporting
  • ✅ AI SDK can properly detect tool execution requests

Files Changed

  • packages/workers-ai-provider/src/streaming.ts (+13 lines, 3 modified)
  • packages/workers-ai-provider/test/stream-text.test.ts (+325 test lines)
  • .changeset/fix-streaming-finish-reason.md (changeset)

Related

  • Follows the same pattern as non-streaming doGenerate which already uses mapWorkersAIFinishReason() correctly
  • Consistent with OpenAI and Anthropic provider implementations
  • Addresses a root cause issue affecting Workers AI model reliability

@changeset-bot
Copy link

changeset-bot bot commented Jan 30, 2026

🦋 Changeset detected

Latest commit: 41b92a3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
workers-ai-provider Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 30, 2026

Open in StackBlitz

npx https://pkg.pr.new/cloudflare/ai/ai-gateway-provider@390
npx https://pkg.pr.new/cloudflare/ai/workers-ai-provider@390

commit: 41b92a3

@threepointone
Copy link
Collaborator

thank you for the tests 🙏

@threepointone threepointone merged commit f8d9ee3 into cloudflare:main Jan 31, 2026
3 checks passed
@github-actions github-actions bot mentioned this pull request Jan 31, 2026
usage: usage,
});
controller.enqueue({
finishReason: finishReason ?? { unified: "stop", raw: "stop" },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🇫🇮

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.

2 participants