Skip to content

fix(ai-sdk): omit UUID ids from Responses continuation input - #20414

Merged
kangfenmao merged 2 commits into
CherryHQ:mainfrom
gokay-ai:cursor/fix-responses-uuid-input-id-d814
Sep 22, 2026
Merged

kangfenmao merged 2 commits into
CherryHQ:mainfrom
gokay-ai:cursor/fix-responses-uuid-input-id-d814

Conversation

@gokay-ai

Copy link
Copy Markdown
Contributor

Branch strategy

  • Active development targets main.

What this PR does

Before this PR: a Responses continuation with store: false copied providerOptions.openai.itemId onto input[n].id. Relays and local history can store a UUID there. Upstream then rejected the request because response item IDs must begin with rs (reasoning) or msg (assistant message). Diagnostic ID 8bfdc98d-13ea-41b8-8825-8a339167ffe8.

After this PR: convertToOpenAIResponsesInput only serializes an item id when it already has the matching provider prefix (msg for messages, rs for reasoning). Valid provider-issued ids still round-trip. Function-call ids were already dropped in #20130; this is the same hygiene for message and reasoning items.

Fixes #20406

Why we need it and why it was done in this way

The following tradeoffs were made:

  • Prefix check (startsWith('msg') / startsWith('rs')) rather than dropping every id. Reasoning round-trip with store: false still needs a real rs_… id plus encrypted content.
  • The guard lives in the existing @ai-sdk/openai patch, next to the Ark assistant type/status hunk, so every Responses client path is covered. Gateway AiSdkToOpenAiResponsesSse synthesizes outbound rs_ ids on a different path and is unchanged.

The following alternatives were considered:

  • A Cherry middleware that strips itemId before the converter. That would miss any call that uses @ai-sdk/openai without the plugin.
  • Dropping all message/reasoning ids, matching function_call. That would break valid rs_ encrypted-reasoning replay.

Links to places where the discussion took place: #20406

Breaking changes

None.

Special notes for your reviewer

  • Commits are DCO-signed (Signed-off-by: GokayAI <[email protected]>) and SSH-signed.
  • Regression: src/main/ai/provider/__tests__/openaiResponsesItemId.test.ts. Related Responses patch tests still pass.
  • Test command: pnpm exec vitest run --project main src/main/ai/provider/__tests__/openaiResponsesItemId.test.ts src/main/ai/provider/__tests__/openaiResponsesFunctionCallId.test.ts src/main/ai/provider/__tests__/openaiResponsesAssistantStatusPatch.test.ts src/main/ai/provider/__tests__/openaiResponsesReasoningPatch.test.ts src/main/ai/provider/__tests__/openaiResponsesSamplingParamsPatch.test.ts src/main/ai/provider/__tests__/openaiResponsesAnnotationsPatch.test.ts

Checklist

This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR.
Approvers are expected to review this list.

Release note

[Chat] Fixed Responses continuations that sent a UUID as an input item id and were rejected because the id must begin with rs or msg.

@gokay-ai
gokay-ai requested a review from DeJeune as a code owner September 11, 2026 10:39
Copilot AI lite review requested due to automatic review settings September 11, 2026 10:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@cherry-ai-bot cherry-ai-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cherry Review · Passed

no findings

Local validation (advisory)

These results do not determine the code-review verdict. Repository CI checks retain their own merge requirements.

  • targeted-code-check: passed. Vitest preflight succeeded; all 1 frozen changed-test targets were supplied, with 1 test files collected and all 2 tests passing.

@cursor
cursor Bot force-pushed the cursor/fix-responses-uuid-input-id-d814 branch from b7617f2 to c4bc238 Compare September 15, 2026 15:19

@cherry-ai-bot cherry-ai-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cherry Review · Passed

no findings

Local validation (advisory)

These results do not determine the code-review verdict. Repository CI checks retain their own merge requirements.

  • targeted-code-check: passed. Vitest preflight succeeded; all 1 frozen changed-test targets were supplied, with 1 test files collected and all 2 tests passing.

store:false continuations copied local/relay UUIDs onto input[n].id.
The API requires a msg_ or rs_ prefix and 400s otherwise.

Co-authored-by: GokayAI <[email protected]>

Signed-off-by: GokayAI <[email protected]>
@cursor
cursor Bot force-pushed the cursor/fix-responses-uuid-input-id-d814 branch from c4bc238 to e3025b2 Compare September 18, 2026 15:05

@cherry-ai-bot cherry-ai-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cherry Review · Passed

no findings

Local validation (advisory)

These results do not determine the code-review verdict. Repository CI checks retain their own merge requirements.

  • targeted-code-check: passed. Vitest preflight succeeded; all 1 frozen changed-test targets were supplied, with 1 test files collected and all 2 tests passing.

@kangfenmao
kangfenmao merged commit 6337297 into CherryHQ:main Sep 22, 2026
19 of 20 checks passed
ShuaiHui added a commit to xigaomeicun/cherry-lite that referenced this pull request Oct 9, 2026
…Q#20414)

The continuation input replayed each message's `itemId` verbatim. An item id
the endpoint did not issue — a UUID carried over from another provider or from
a rewritten history — is rejected there, so a continued Responses conversation
400'd as soon as such an item was replayed.

Gate every replayed id on its Responses prefix: `toResponsesItemId(id, 'msg')`
for text items and `toResponsesItemId(id, 'rs')` for reasoning items now drop
anything that is not a real `msg_`/`rs_` id, letting the server mint a fresh
item instead of failing the request. Local zod validation is untouched.

Repository adaptation: the fork's patch file had drifted from upstream (an older
snapshot plus a hand-merged hunk for CherryHQ#21339). This commit replaces it with
upstream's exact file at the same point, so the file is now byte-identical to
upstream and later commits in this family cherry-pick without conflicts. The
`pnpm-lock.yaml` patch hash was recomputed (patch file sha256, all six
occurrences) and verified by `pnpm install --frozen-lockfile`.

(cherry picked from commit 6337297)
Signed-off-by: shuaihui <[email protected]>
ShuaiHui added a commit to xigaomeicun/cherry-lite that referenced this pull request Oct 9, 2026
CherryHQ#20762)

CherryHQ#20414 stopped replaying ids that lack a Responses prefix, but the text path
still forwarded whatever id the item carried. On a `store: false` request the
endpoint retained nothing, so an id it never issued — a UUID from another
provider, or one rewritten by a client — was rejected and the whole continued
conversation 400'd even though the request was locally well-formed.

Replay a text item's id only when the request is stored, or when the id itself
starts with `msg_`; otherwise omit it and let the server mint a fresh item.
Reasoning items keep their prefix guard through `toResponsesItemId(id, 'rs')`.

Repository adaptation: taken as upstream's exact patch file at this commit (the
file became byte-identical to upstream in the previous commit), with the
`pnpm-lock.yaml` hash recomputed for the new file and verified by
`pnpm install --frozen-lockfile`.

(cherry picked from commit 88f8d0b)
Signed-off-by: shuaihui <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Bug]: Responses API reuses a UUID input ID instead of an rs-prefixed ID

4 participants