Repository navigation
fix: keep ids ascending across clock steps and never end Gemini requests on a model turn - #55515
Open
piercypixel wants to merge 1 commit into
Open
piercypixel wants to merge 1 commit into
piercypixel wants to merge 1 commit into
Conversation
…sts on a model turn Identifier.create derived IDs from Date.now() with no guard against the wall clock stepping backward (NTP corrections, VM or WSL2 resume). Parts are replayed in ID order, so a tool part minted after a backward step sorted before its own step-start; convertToModelMessages then split that step's reasoning into a trailing assistant block and Gemini rejected the request with 400 "Requests ending with a model turn are not supported." - Identifier.create: keep wall-clock IDs strictly ascending through a backward step. Explicit timestamps are minted as given. - ProviderTransform.message: for @ai-sdk/google and @ai-sdk/google-vertex, drop a trailing reasoning-only assistant message and prime a user turn behind any other assistant tail. Outbound only, so sessions that already hold a misordered step and continued turns recover without touching the stored transcript.
Contributor
|
The following comment was made by an LLM, it may be inaccurate: |
This was referenced Oct 14, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue for this PR
Closes #55514 (same user-visible error as #45359 / #47034; complements #55382)
Type of change
What does this PR do?
Gemini rejects any request whose
contentsend on amodelturn. #55514 shows how v1 produces that shape without any prefill:Identifier.createmints IDs fromDate.now()and only guards against two IDs in the same millisecond, parts are replayed in ID order, so when the wall clock steps backward inside a step (NTP correction, VM resume, WSL2) the tool part sorts before its ownstep-start.convertToModelMessagesthen opens a new block at thatstep-startand the step's reasoning ends up as a trailing assistant message.Two changes:
Identifier.createkeeps alastfloor for wall-clock IDs and bumps any value that would not sort after it. Same-millisecond IDs come out exactly as before, explicit timestamps are minted as given and never touch the floor (truncation.test.tsdepends on that), and descending IDs stay descending because the bump happens before the bit inversion. This stops new steps from being stored out of order.ProviderTransform.message, for@ai-sdk/googleand@ai-sdk/google-vertexonly, drops a trailing reasoning-only assistant message (thought text is not something the model can continue from; the thought signature lives on the tool call, which keeps its result) and then primes auser"Continue." turn behind any other assistant tail, the same move as fix(provider): keep Gemini requests from ending with a model turn #55382 and the existing synthetic "Done." turn innormalizeMessages. Outbound only, so sessions that already contain a misordered step, and the compaction-continuation case from Gemini 400 "Requests ending with a model turn are not supported" when a step is stored out of order: Identifier.create is not monotonic across backward clock steps #55514, recover without rewriting stored history.Not touched: message order still uses
time_created, so a backward step can still swap two whole messages; each still ends on a tool result, which Gemini accepts.How did you verify your code works?
From
packages/opencode/:bun test ./test/id/id.test.ts: on pristinev1the two backward-step cases fail; with the fix all 4 pass.bun test ./test/id/id.test.ts ./test/provider/transform.test.ts ./test/tool/truncation.test.ts: 614 pass, 0 fail.bun run typecheck: 0 errors before and after. Rootbun turbo typecheckran in the pre-push hook and passed. Prettier clean on the four files.gemini-3.8-flashthrough@ai-sdk/googlewith the exact shape from the failing session:[user, assistant(tool-call), tool(result)]200; plus trailingassistant(reasoning)400 "Requests ending with a model turn are not supported."; same input throughProviderTransform.message200. A text-only assistant tail: 400 unguarded, 200 with the primed turn.Screenshots / recordings
Not a UI change.
Checklist