feat(ai): expose inputMessages and partialText in onAbort callback#14141
feat(ai): expose inputMessages and partialText in onAbort callback#14141Hovo-Dev wants to merge 9 commits into
Conversation
When a streamText call is aborted, the onAbort callback now receives usage (current step) and totalUsage (all steps combined) containing whatever real token data the provider had reported before the abort. If the provider had not yet sent a usage chunk, the values are undefined — no estimation is used. The OpenAI provider is updated to emit its finish chunk (which carries real usage) as soon as usage data arrives in the stream, rather than waiting for the stream to fully close. This ensures usage is available even when an abort fires before natural completion. Fixes vercel#7628 Fixes vercel#7805
The finish chunk was unreachable — OpenAI sends usage in a chunk with empty choices[], so choice?.delta == null triggered an early return before the emission block. Move the check before the delta guard.
2dfe4e0 to
de7c3a3
Compare
|
Hi @gr2m, Took a look at this and managed to get it working cleanly — happy to share the approach. The SDK was already holding the token data we needed, it just wasn't being handed off when a stream was aborted. We also noticed that usage from OpenAI arrives mid-stream but was only forwarded at natural close, so we made sure it gets captured as soon as it arrives. That way, whether the stream finishes or gets cut short, the data is there. Looking forward to your feedback! |
|
@lgrammel - Could you please take a look? |
|
can someone explain is token usage returend by the model on abort or is like usage or token info avaible mid stream ?? currently having problem with abortsignal getting no usage at all with gemini model |
|
@reactsaas Hey good to see you here! Actually, abort signal neither returns usage nor any data (history or partial generated text) to count the tokens manually, that's why you have to merge the generated stream data on fly with OnChunk method and then count the tokens accordingly. Given that, my current PR is especially designed to return the conversation list and partially generated text, so the client can at least count the tokens with ease without merging the mid-generated stream data on the fly and get rid of boilerplate code. Example of a usage with the new release. |
Hey thanks for the answer. I took your aproach now counting the tokens. 🍪 |
|
@reactsaas Glad to hear that, but I believe you can use it once this PR is merged. |
Background
When a
streamTextcall is aborted — viaAbortSignal, the user stopping generation, or a dropped connection — theonAbortcallback fires but receives no usage data.onFinishnever fires on abort at all. This makes it impossible to track token consumption for billing or quota purposes when streams don't complete naturally.Summary
packages/ai/src/generate-text/stream-text.tsusage?: LanguageModelUsageandtotalUsage?: LanguageModelUsagetoStreamTextOnAbortCallbackinputMessages: ModelMessage[]— the full message list passed to the model for the aborted step (initial messages + completed prior step toolcall/result pairs)
partialText?: string— the text actively being streamed at abort time;undefinedif no text was generated; resets at each step boundarycurrentStepUsage,completedStepsUsage,currentStepInputMessages, andpullLevelTextContentas outer-scope tracking variablesabort()function — if the provider had not yet sent usage data before the abort,usageisundefined(honest, noestimation)
packages/openai/src/chat/openai-chat-language-model.tsflush(), which never runs on aborttransform(), with afinishSentguard to prevent double-emission inflush()content/docs/07-reference/01-ai-sdk-core/02-stream-text.mdxUusage,totalUsage,inputMessages, andpartialTextfields in theonAbortcallback parameterscontent/docs/03-ai-sdk-core/50-error-handling.mdxonAbortsection to describe all four new fieldsUsage
Manual Verification
Verified via automated tests that exercise the full stream processing pipeline:
All 2200+ existing tests continue to pass.
Checklist
Related Issues
Fixes #7628
Fixes #7805