Skip to content

fix(llm): keep the SSE keep-alive fallback for thinking-disabled MiniMax M3 streams - #18015

Merged
furionw merged 3 commits into
ai-dynamo:mainfrom
glamr-agent:dyn-5298-minimax-m3-http-keepalive-prompt-aware-deferral-5cf2447c92b5
Nov 5, 2026
Merged

furionw merged 3 commits into
ai-dynamo:mainfrom
glamr-agent:dyn-5298-minimax-m3-http-keepalive-prompt-aware-deferral-5cf2447c92b5

Conversation

@glamr-agent

@glamr-agent glamr-agent commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Failure behavior

A MiniMax M3 stream can send nothing for a long time and be cut off by an idle timeout. The reported setup is the public M3.1 Flash template, a streaming request with reasoning_effort: "none" and force_nonempty_content: true, no DYN_HTTP_SSE_KEEP_ALIVE_INTERVAL_MS, and about 90 seconds of reasoning. No frame goes on the wire during that time.

Since #17120, the M3 reasoning parser still runs for a thinking-disabled request when the rendered prompt leaves reasoning open. This template ignores thinking_mode, so it does. With force_nonempty_content, the stream then holds back every data frame while the model reasons. The HTTP handlers choose the 15-second fallback keep-alive before the prompt is rendered. They still use the request-only check, which says this request holds nothing back, so they send no keep-alive. The defect is in Dynamo.

Reproduction Without the fix With the fix Note
Exact failure on the reported setup Not run — Needs the MiniMax M3.1 Flash weights served with its public template and a long reasoning stream. Those weights do not fit the single A100 80 GB the coding run had.
Exact failure on a similar setup Not run — Needs a live deployment that runs the M3 reasoning parser. The mock worker cannot set a reasoning parser, and a small vLLM model does not render an M3 prompt.
Exact error in a test ❌ Exact error ✅ Passed The new predicate test and the changed Responses wrapper test ran on CPU. Before the fix, both returned false for an M3 force_nonempty_content request with thinking disabled, so the stream got no fallback keep-alive. With the fix, both return true.

Proposed fix

The frontend now treats every M3 stream with force_nonempty_content as one that may hold back all output, even when the request disables thinking. This applies to chat completions, Responses, and Anthropic Messages. It matches the fix on the release branch (#17197). The result is conservative: when an M3 template does close the reasoning, the stream still gets comment frames. A configured DYN_HTTP_SSE_KEEP_ALIVE_INTERVAL_MS still wins.

Case Before After
M3, thinking disabled, force_nonempty_content: true No keep-alive; silent stream Comment frame every 15 s
M3, thinking disabled, no force_nonempty_content No keep-alive Unchanged
Other reasoning parsers with thinking disabled No keep-alive Unchanged

Open #17381 sends a keep-alive on every Anthropic stream. If it merges first, the Anthropic part of this fix is redundant but harmless.

Core change: about 3 lines (+2/−1). The logic is in 1 file, in reading order:

  • about 3 lines in preprocessor.rs: Makes the keep-alive check count a MiniMax M3 reasoning parser as possibly holding back output, whatever the request says about thinking.

The rest of the +71/−6 diff is a doc comment and unit tests.

Validation

This PR adds one unit test to lib/llm/src/preprocessor.rs and extends one unit test in lib/llm/src/http/service/openai.rs. Both run on CPU with cargo test -p dynamo-llm --lib, with no model and no GPU.

Behavior checked Checked by Without the fix With the fix
A thinking-disabled M3 stream that may hold back all output gets the fallback keep-alive, through both the predicate and the OpenAI handler wrapper New unit test minimax_m3_disabled_thinking_force_nonempty_stream_can_defer_all_output, and changed unit test responses_force_nonempty_request_requires_fallback_keep_alive, which had no M3 case before this PR; also the reproduction above ❌ Exact error ✅ Passed
An M3 stream with thinking unset or adaptive still gets the fallback New unit test Not run ✅ Passed
An M3 stream without force_nonempty_content gets no fallback New unit test Not run ✅ Passed
A non-M3 parser (kimi_k25) that disables thinking still gets no fallback New unit test Not run ✅ Passed

The before-fix run stopped at the new test's first assertion, so its later control assertions did not run without the fix.

Relates to #17120 and #17197.

Closes DYN-5298.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of streamed MiniMax M3 responses when non-empty output is required. Requests with reasoning disabled can now be treated as potentially deferring output, helping avoid premature assumptions about when response content will arrive.
    • Other reasoning parsers retain their existing behavior when reasoning is disabled.

…Max M3 streams

stream_can_defer_all_output used the request-only reasoning gate, so a
MiniMax M3 force_nonempty_content stream with thinking_mode=disabled (or
reasoning_effort=none) reported that it defers nothing. Since ai-dynamo#17120 the
stream builder keeps the M3 parser on when the rendered prompt leaves
reasoning open, so such a stream can withhold every data frame with no
keep-alive. Treat the M3 reasoning parser as possibly deferring, as the
release-branch fix in ai-dynamo#17197 does.

Refs DYN-5298

Signed-off-by: svc-glamr@nvidia.com <svc-glamr@nvidia.com>
@glamr-agent
glamr-agent requested a review from a team as a code owner November 4, 2026 05:28
@copy-pr-bot

copy-pr-bot Bot commented Nov 4, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@glamr-agent
glamr-agent temporarily deployed to external_collaborator November 4, 2026 05:28 — with GitHub Actions Inactive
@glamr-agent
glamr-agent temporarily deployed to external_collaborator November 4, 2026 05:28 — with GitHub Actions Inactive
@github-actions github-actions Bot added the fix label Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

👋 Hi glamr-agent! Thank you for contributing to ai-dynamo/dynamo.

Just a reminder: The NVIDIA Test Github Validation CI runs an essential subset of the testing framework to quickly catch errors.Your PR reviewers may elect to test the changes comprehensively before approving your changes.

🚀

@github-actions github-actions Bot added external-contribution Pull request is from an external contributor frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` labels Nov 4, 2026
@glamr-agent

Copy link
Copy Markdown
Collaborator Author

factory: Initial validation snapshot.

Validation status: complete

Check Result Scope or reason
Checks the changed Rust crates with cargo check and Clippy. Passed (exit 0) Workspace cargo check --all-targets, Python bindings cargo check, and workspace Clippy with -D warnings at a13eea9b03

No live MiniMax M3 stream ran: the weights do not fit the single GPU available. The unit tests cover the keep-alive decision for the reported request, not a real 90-second reasoning stream.

Detailed evidence — validation complete

Left out of the table because CI repeats them: none.

Evidence: 1/1 validated.

Advisory AI assessment: sound.

Validation result: pass. The new M3 keep-alive assertions fail on main's predicate and pass with the fix. Workspace check, workspace Clippy, sidecar tests, and dynamo-llm lib tests pass, except 19 GPT-OSS tests that fail identically on unchanged main because the Harmony vocab file cannot be downloaded in the validation environment. Evidence audit: complete, 1/1 validated; the command report comes from recorded runs.

Commands and results [1/1 validated]

Generated from the commands recorded during this run.

Check 1

Checks the changed Rust crates with cargo check and Clippy.

Result: Passed (exit 0)

Command:

Not shown because the exact command contained private run data.

@glamr-agent

Copy link
Copy Markdown
Collaborator Author

No description provided.

@glamr-agent

Copy link
Copy Markdown
Collaborator Author

factory: @dynamo-ops please run full CI for a13eea9

@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test a13eea9

@coderabbitai

coderabbitai Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The preprocessor now treats MiniMax M3 as able to defer all output when forced nonempty content is enabled, even if thinking is disabled. Tests cover both M3 parser aliases and confirm that other parsers retain their existing behavior.

Changes

MiniMax M3 deferred-output eligibility

Layer / File(s) Summary
Update eligibility rule and test coverage
lib/llm/src/preprocessor.rs, lib/llm/src/http/service/openai.rs
The preprocessor allows MiniMax M3 to defer output when force_nonempty_content is enabled, even if thinking is disabled. Tests cover both M3 aliases, multiple thinking modes, and unchanged behavior for other parsers.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: Minimal · up to a13ee

The M3 keep-alive change is mergeable after normal checks. An explicit zero interval may still produce fallback comments on deferred streams, but this narrow behavior does not block the change.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title clearly and concisely identifies the MiniMax M3 SSE keep-alive fallback fix.
Description check Passed The description is detailed and on-topic. It explains the failure behavior, proposed fix, validation, limitations, and related issues. It uses different headings from the template and omits the pull r…
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is detailed and on-topic. It explains the failure behavior, proposed fix, validation, limitations, and related issues. It uses different headings from the template and omits the pull request checklist, but the required technical content is largely present.

Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 1 files. (1 skipped: 1 too large.)

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 182039d and a13eea9.

Files selected for processing: 2
  • lib/llm/src/http/service/openai.rs
  • lib/llm/src/preprocessor.rs

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.

@devin-ai-integration

devin-ai-integration Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

✅ Dynamo PR CI passed — run 41898892806 (attempt 1) on 9eee0aafc7

Gate checks: ✅ backend-status-check · ✅ deploy-status-check · ✅ dynamo-status-check

Posted automatically by Devin for run 41898892806. Updated on every full-CI run of this PR.

Signed-off-by: GLAMR <svc-glamr@nvidia.com>
@glamr-agent
glamr-agent temporarily deployed to external_collaborator November 4, 2026 18:24 — with GitHub Actions Inactive
@glamr-agent

Copy link
Copy Markdown
Collaborator Author

nursery: Merged the base fix in commit e869932 to address Devin’s finding. In test_live_retune_frontend_config.py, the frontend and worker parser tests now use device-aware-weighted, which the parser accepts. Separate cases check that the removed power-of-two mode is rejected.

@glamr-agent

Copy link
Copy Markdown
Collaborator Author

nursery: @dynamo-ops please run full CI for e869932

@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test e869932

Signed-off-by: GLAMR <svc-glamr@nvidia.com>
@glamr-agent
glamr-agent temporarily deployed to external_collaborator November 4, 2026 19:37 — with GitHub Actions Inactive
@glamr-agent

Copy link
Copy Markdown
Collaborator Author

nursery: @dynamo-ops please run full CI for 9eee0aa

@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 9eee0aa

@furionw furionw 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.

Thank you

@furionw
furionw merged commit 54db08d into ai-dynamo:main Nov 5, 2026
119 checks passed

This branch was previously deployed

1 inactive deployment
external_collaborator — 9eee0aaf Deployed Nov 4, 2026 by glamr-agent via ok-to-test #45681
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contribution Pull request is from an external contributor fix frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants