Summary
Fixes #545 (immediate guardrail portion)
When a workflow stream is resumed/replayed, entire assistant messages can be duplicated with blank reasoning parts that carry the same rs_* item IDs as earlier messages. OpenAI requires item IDs to be unique across input history, so these duplicates cause follow-up turns to fail.
Problem
The existing dedupeMessageReasoning only deduplicates within a single message. But the replay bug produces cross-message duplicates — a new assistant message containing only blank reasoning parts with IDs that already appeared in a previous message.
Changes
dedupe-message-reasoning.ts
- Added
dedupeCrossMessageReasoning()— processes the full message array and:- Tracks
rs_*item IDs across all messages in order - Removes blank reasoning-only assistant messages whose IDs were already seen (replay artifacts)
- Strips individual blank-text reasoning parts from mixed messages
- Preserves non-blank multi-summary segments (same ID, different text)
- Returns the same array reference when no dedup is needed
- Tracks
chat.ts (workflow)
convertMessagesnow applies cross-message dedup as a second pass after the existing per-message dedup
dedupe-message-reasoning.test.ts
- 10 new test cases covering: replay removal, new ID preservation, blank part stripping, multi-summary preservation, empty message removal, Azure metadata, immutability
Test results
17 pass, 0 fail (dedupe-message-reasoning.test.ts)
28 pass, 0 fail (chat.test.ts)All existing tests continue to pass.
Scope
This PR addresses the immediate guardrail from #545 — preventing poisoned messages from reaching the OpenAI API. The root fix (chunk-index-aware workflow resume with startIndex) is a larger change that should be handled separately.
@JasonOA888 is attempting to deploy a commit to the Vercel Labs Team on Vercel.
A member of the Team first needs to authorize it.