fix(openai): drop non-chunk summary event message to avoid content duplication#2367
Merged
Merged
Conversation
…plication
Some OpenAI-compatible providers (e.g. MiniMax-M3) emit an extra non-chunk
chat.completion summary event at the end of a stream whose message restates
the entire message. The incremental deltas already accumulated the full
content, so accumulating the summary message again doubles reasoning_content
and concatenates tool_call arguments into {...}{...} (invalid JSON), which
the model rejects on the next round and halts the agent.
Strip the summary event's message at the transport layer in
OpenAIClient.stream(), keeping the choice (finish_reason) and usage (real
token counts only appear in the summary). Provider-agnostic, alongside the
existing [DONE] filtering.
Closes agentscope-ai#2366
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Contributor
Author
jujn
approved these changes
Jul 24, 2026
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.
AgentScope-Java Version
2.0.1-SNAPSHOT
Description
Fixes #2366.
Some OpenAI-compatible providers (confirmed with MiniMax-M3) terminate a streaming response with an extra non-chunk
chat.completionsummary event whosemessagerestates the full message (reasoning text + complete tool-call arguments) that the incrementaldeltachunks already delivered.OpenAIResponse.isChunk()returnsfalsefor this summary, soOpenAIResponseParser.parseResponseroutes it toparseCompletionResponse, extracting the fullmessageintoContentBlocks identical to what the deltas already produced.ReasoningContextthen accumulates them on top of the existing content:reasoning_contentis doubled (delta-accumulated full text + summary full text)tool_call.argumentsare concatenated into{...}{...}(invalid JSON), which survives loose JSON validation, is sent back on the next round, and the model rejects it (returns emptychoices:[]), halting the agent.Changes
OpenAIClient.stream(): after the error check and before emitting, if the response is not a chunk (i.e. a summary event), clear itschoice.messagewhile keeping thechoice(sofinish_reasonis preserved) andusage(real token counts only appear in the summary event). Provider-agnostic, lives at the protocol-normalization layer alongside the existing[DONE]filtering and error detection.How to test
Regression test
MinimaxDoubledSummaryReplayTestreplays a 6-event SSE trace captured from a real MiniMax-M3 stream (5 incrementalchat.completion.chunkdeltas + 1 non-chunkchat.completionsummary) through the realOpenAIClient.stream()(driven by a stubHttpTransport), then feeds the parsedOpenAIResponses throughOpenAIResponseParserandReasoningContext:summaryEventMessageClearedByTransportLayer— asserts the summary event'schoice.messageis cleared whilefinish_reasonis preserved (the fix point).reasoningAndToolArgsNotDoubled— asserts accumulated reasoning containsLet me start by loadingonce (not twice) and tool args containAIHOT_marketplaceonce (not{...}{...}).Both tests fail without the fix (message non-null; reasoning/args counted twice) and pass with it.
Checklist
mvn spotless:applymvn test)