Repository navigation
Conversation
DeepSeek V4.1 Flash emits <||DSML|| calls> with a doubled bar and a shorter calls envelope. The existing recovery only matched single-bar function_calls, so the markup leaked into the content channel and was shown as the final answer. Accept both bar widths and both envelope names, with a regression test using the exact leaked block.
Final synthesis runs with ToolChoice=none so the OpenAI adapter deliberately skips DSML recovery. DeepSeek can still emit a DSML block there, which was streamed as the final answer after the iteration cap. Detect the markup, replace the streamed attempt, and return an honest partial-answer notice; also tell the synthesis prompt that tools are disabled.
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.
Description
Fixes two related failure modes that made DeepSeek tool-call markup visible as the final answer.
1. Doubled-bar
callsDSML was not recoveredFollow-up to #4851. DeepSeek V4.1 Flash can emit a DSML block in
contentwithfinish_reason=stop, using a doubled bar and a shorter envelope:The adapter previously matched
<|DSML|/<|DSML|and only thefunction_callsenvelope, so this block was treated as a normal answer and the tool never ran.This change accepts one or two bars and both
calls/function_callsenvelopes, while keeping the existing conservative rules: only complete trailing blocks with declared tools and valid parameters are recovered.2. Final synthesis bypassed DSML handling
The leaked block in the report happened after the agent hit its iteration cap.
handleMaxIterationssynthesizes a final answer withToolChoice=none, and the OpenAI adapter intentionally skips DSML recovery in that mode. When the model ignored the tool-free instruction and emitted DSML, the markup was streamed and persisted as the final answer.This change:
The underlying iteration cap is unchanged; a user can continue the run after the partial-answer notice.
Type of Change
Related Issue
Follow-up to #4851. Related: #2798.
Testing
go test ./internal/models/api/openaicompletions -run 'TestDSML|TestExtractDSML|TestChatDSML' -count=1go test ./internal/models/api/openaicompletions -count=1go test ./internal/agent -run 'TestStreamFinalAnswer|TestHandleMaxIterations|TestMaxIterations' -count=1go vet ./internal/models/api/openaicompletions ./internal/agentgit diff --check origin/main...HEADgofmt -lon changed files is cleanRegression tests use the exact leaked block for both non-streaming extraction and byte-by-byte streaming, plus a final-synthesis test that returns DSML with tools disabled and asserts the persisted answer is the partial-answer notice. Full-repository checks were not run; the changes are confined to the OpenAI-compatible adapter and final synthesis.
Checklist
git diff --check origin/main...HEADpassesgolangci-lintis not installed in this environment;go vetpasses)