Skip to content

fix: prevent empty tool-call deltas from fragmenting OpenAI-compatible reasoning streams - #20253

Merged
gr2m merged 3 commits into
mainfrom
bugfix-20203-20260902214819827381
Sep 3, 2026
Merged

gr2m merged 3 commits into
mainfrom
bugfix-20203-20260902214819827381

Conversation

@ai-sdk-factory

@ai-sdk-factory ai-sdk-factory Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Background

OpenAI-compatible gateways that attach tool_calls: [] to reasoning deltas caused one logical reasoning span to be emitted as multiple user-visible reasoning blocks.

Root Cause

The stream transform treated any non-null tool_calls array as active tool output. The immutable reproduction and regression test confirmed that empty arrays closed reasoning after each delta, producing two start/end cycles instead of one.

Summary

Reasoning now ends for tool calls only when the streamed tool_calls array contains entries. Added a patch changeset and removed reproduction-only artifacts.

Testing

Added a regression test verifying consecutive reasoning deltas with empty tool-call arrays remain within one reasoning lifecycle.

End-to-end Validation

  • pnpm -C packages/openai-compatible build completed successfully.
  • Immutable reproduction replay completed successfully with one contiguous reasoning block and no original failure signal.

Related Issues

Fixes #20203

Closes #20251

ai-sdk-factory and others added 3 commits September 2, 2026 22:29
Co-authored-by: Gregor Martynus <[email protected]>
Co-authored-by: WuJunkai2004 <[email protected]>
Co-authored-by: WuJunkai2004 <[email protected]>
@ai-sdk-factory

ai-sdk-factory Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Bugfix review

Outcome: approved

Reproduction replay

Status: no-longer-reproduces

The exact original reproduction completed successfully and the original bug signal did not appear.

Fixes issue

Status: fully-addresses

The implementation ignores empty tool-call arrays for reasoning lifecycle transitions while preserving handling for non-empty tool-call deltas, directly correcting the reported root cause.

Side effects

Risk: low

The only production behavior change is that an empty tool-call array no longer ends reasoning; actual text and non-empty tool-call deltas retain their existing transition behavior.

Performance

Risk: none

The added constant-time array-length check introduces no meaningful overhead and prevents unnecessary reasoning lifecycle events.

Backwards compatibility

Risk: none

No persistence code or stored-data format is touched, so existing stored data requires no migration or reinterpretation.

Breaking changes

Risk: none

No public APIs, types, exports, accepted inputs, defaults, configuration, errors, or persisted formats change; only the erroneous streamed event sequence for empty tool-call arrays is corrected.

Architecture

Risk: none

The fix remains localized to the OpenAI-compatible stream adapter that owns this behavior and introduces no dependencies, cross-package source imports, shared abstractions, or boundary violations.

Change scope

Status: minimal

The merge-base diff contains one production condition change, one focused regression test, and the required patch changeset.

Security

Risk: none

The change does not alter URL handling, credentials, parsing, validation, authorization, or other security-sensitive behavior.

Testing

Status: appropriate

The regression test covers consecutive reasoning deltas carrying empty tool-call arrays, while existing tests continue to cover non-empty tool-call streaming; the exact reproduction replay also passed.

Verification

Reviewed the complete three-file merge-base diff and surrounding reasoning, text, tool-call, and schema logic. The OpenAI-compatible package's Node and Edge suites each passed with 262 tests, and package type-checking, build, and diff validation passed.

@gr2m
gr2m merged commit e5a22f0 into main Sep 3, 2026
70 checks passed
@gr2m
gr2m deleted the bugfix-20203-20260902214819827381 branch September 3, 2026 19:28
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

🚀 Published in:

Package Version
ai 7.0.93 github npm
@ai-sdk/amazon-bedrock 5.0.75 github npm
@ai-sdk/angular 3.0.93 github npm
@ai-sdk/azure 4.0.62 github npm
@ai-sdk/baseten 2.1.22 github npm
@ai-sdk/cerebras 3.0.44 github npm
@ai-sdk/code-mode 1.0.50 github npm
@ai-sdk/deepinfra 3.0.44 github npm
@ai-sdk/fireworks 3.0.47 github npm
@ai-sdk/gateway 4.0.75 github npm
@ai-sdk/gmicloud 3.0.15 github npm
@ai-sdk/google 4.0.64 github npm
@ai-sdk/google-vertex 5.0.76 github npm
@ai-sdk/harness 1.0.102 github npm
@ai-sdk/harness-acp 1.0.40 github npm
@ai-sdk/harness-claude-code 1.0.106 github npm
@ai-sdk/harness-cline 1.0.29 github npm
@ai-sdk/harness-codex 1.0.104 github npm
@ai-sdk/harness-cursor 1.0.15 github npm
@ai-sdk/harness-deepagents 1.0.102 github npm
@ai-sdk/harness-fx 1.0.15 github npm
@ai-sdk/harness-grok-build 1.0.39 github npm
@ai-sdk/harness-opencode 1.0.104 github npm
@ai-sdk/harness-pi 1.0.104 github npm
@ai-sdk/huggingface 2.0.44 github npm
@ai-sdk/langchain 3.0.93 github npm
@ai-sdk/llamaindex 3.0.93 github npm
@ai-sdk/mcp 2.0.45 github npm
@ai-sdk/open-responses 2.0.39 github npm
@ai-sdk/openai 4.0.59 github npm
@ai-sdk/openai-compatible 3.0.44 github npm
@ai-sdk/otel 1.0.93 github npm
@ai-sdk/policy-opa 1.0.93 github npm
@ai-sdk/react 4.0.96 github npm
@ai-sdk/rsc 3.0.93 github npm
@ai-sdk/sandbox-just-bash 1.0.102 github npm
@ai-sdk/sandbox-vercel 1.0.102 github npm
@ai-sdk/svelte 5.0.93 github npm
@ai-sdk/togetherai 3.0.45 github npm
@ai-sdk/tui 1.0.94 github npm
@ai-sdk/vue 4.0.93 github npm
@ai-sdk/workflow 2.0.24 github npm
@ai-sdk/workflow-harness 1.0.102 github npm
@ai-sdk/zai 3.0.6 github npm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: openai-compatible: empty tool_calls: [] array in every delta fragments reasoning into one reasoning-start/end cycle per chunk

2 participants