Skip to content

[None][feat] Add DeepSeek DSpark speculative decoding#15808

Open
longlee0622 wants to merge 2 commits into
NVIDIA:mainfrom
longlee0622:dev/dspark-spec-dec-pr
Open

[None][feat] Add DeepSeek DSpark speculative decoding#15808
longlee0622 wants to merge 2 commits into
NVIDIA:mainfrom
longlee0622:dev/dspark-spec-dec-pr

Conversation

@longlee0622

@longlee0622 longlee0622 commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds DeepSeek DSpark speculative decoding (the DeepSeek-V4-Pro-DSpark draft) to the PyTorch backend.

DSpark extends the MTP one-model family with three full DeepSeek-V4 draft blocks under the mtp.* namespace. One backbone forward proposes a block of tokens, a lightweight sequential Markov head refines the proposal, and a per-position confidence head can truncate it. Acceptance still uses standard target verification, so greedy correctness is preserved independently of draft quality.

The implementation runs end-to-end on 8×B300 as a one-engine drafter, and the generation draft path can be captured into the target CUDA graph.

What is added

  • Draft model: DSparkBlock, DSparkDraftModel, and DSparkForCausalLM, including mtp.{stage}.* to mtp_layers.{stage}.* weight remapping and FP8 UE8M0 / MXFP4 expert loading.
  • Draft components: Markov/confidence heads, draft input/output handling, and scalar plus batched captured-context attention.
  • Runtime integration: DSpark worker and metadata, SpeculativeDecodingMode.DSPARK, DSparkDecodingConfig, one-engine wiring, and DSpark-gated target hidden-state capture.
  • Tests: hardware-agnostic unit coverage, CUDA-graph capture/replay coverage, 8-GPU end-to-end coverage, and a full GSM8K LLM API accuracy gate.

CUDA-graph safety

The default generation draft path is batched and avoids host synchronization and data-dependent shapes. It uses per-request start-position tensors, RoPE gathered from a fixed table, slot-indexed rolling windows, and fixed-width masked top-k. The batched path is numerically checked against the scalar reference path.

No DSpark-specific CUDA-graph flag is required.

Validated LLM API configuration

The new full-accuracy LLM API test uses the following topology and backend:

from tensorrt_llm import LLM
from tensorrt_llm.llmapi import (
    DSparkDecodingConfig,
    KvCacheConfig,
    MoeConfig,
)

model_path = "/path/to/DeepSeek-V4-Pro-DSpark"

llm = LLM(
    model_path,
    attn_backend="TRTLLM",
    tensor_parallel_size=8,
    moe_expert_parallel_size=8,
    enable_attention_dp=True,
    moe_config=MoeConfig(backend="MEGAMOE_DEEPGEMM"),
    max_seq_len=4096,
    max_num_tokens=4096,
    kv_cache_config=KvCacheConfig(
        enable_block_reuse=False,
        free_gpu_memory_fraction=0.5,
    ),
    enable_chunked_prefill=False,
    disable_overlap_scheduler=True,
    custom_tokenizer="deepseek_v4",
    speculative_config=DSparkDecodingConfig(
        max_draft_len=5,
        speculative_model=model_path,
    ),
)

The draft inherits the target MoE backend. The validated high-acceptance path is DEP8 + MegaMoE DeepGEMM. CUTLASS remains a compatible fallback; TRTLLM-Gen blockScaleMoe cannot route this checkpoint's 384-expert / 8-group layout.

Correctness and accuracy

  • Hardware-agnostic unit tests: heads, draft I/O, weight schema, attention, batched-versus-scalar equivalence, worker, and metadata.
  • Numerical faithfulness: DeepSpec-reference attention cosine similarity is approximately 0.999994, with full-chain and live-capture goldens.
  • 8-GPU end-to-end test: eager and CUDA-graph modes generate coherent greedy output and assert a positive accepted-draft count.
  • Full GSM8K LLM API test: test_gsm8k_dep8_megamoe_deepgemm runs all 1,319 samples with TP8, EP8, attention DP, and MegaMoE DeepGEMM. The measured score is 96.475%; the committed reference floor is 96.0% to allow normal run-to-run variation.

The 8-GPU MoE path is not bit-reproducible across independent runs because of non-associative FP atomics, so the end-to-end test does not require token-for-token equality with a separate no-spec run. The verification invariant is covered by unit tests and numerical goldens.

Acceptance length: DL1-DL7 sweep

Measured offline on 8×B300 with the same TP8 + EP8 + attention DP + MegaMoE DeepGEMM configuration as the LLM API test. The sweep used greedy decoding, 12 prompts per dataset / thinking mode / draft length, up to 512 new tokens, with chunked prefill and CUDA graph disabled.

AL is avg_decoded_tokens_per_iter: committed tokens per target step, including the one guaranteed target token. DL is max_draft_len, so AL is in [1, DL+1]. Each dataset cell below is Thinking-OFF / Thinking-ON.

DL GSM8K HumanEval MATH500 Six-regime average
1 1.877 / 1.908 1.896 / 1.911 1.909 / 1.927 1.905
2 2.653 / 2.704 2.672 / 2.669 2.698 / 2.703 2.683
3 3.200 / 3.411 3.285 / 3.370 3.231 / 3.448 3.324
4 3.914 / 3.905 3.769 / 3.826 4.001 / 4.054 3.912
5 4.142 / 4.208 4.008 / 4.244 4.315 / 4.520 4.240
6 4.286 / 4.875 4.350 / 4.648 4.800 / 4.764 4.621
7 4.687 / 4.958 4.264 / 4.401 4.682 / 4.809 4.634

Key observations:

  • The aggregate AL rises monotonically from 1.905 at DL1 to 4.634 at DL7.
  • DL6 and DL7 are effectively a plateau in this N=12 sample: DL7 improves the six-regime average by only 0.013.
  • Best GSM8K AL is at DL7 (4.687 / 4.958); HumanEval peaks at DL6 (4.350 / 4.648); MATH500 peaks at DL6 for Thinking-OFF (4.800) and DL7 for Thinking-ON (4.809).
  • Against a matched CUTLASS / no-attention-DP baseline using the same harness, source, wheel, node, and prompts, the combined configuration improves average AL by 10.3%, 22.6%, 36.8%, 51.5%, 64.4%, 86.1%, and 104.1% for DL1 through DL7.
  • Because both attention DP and the MoE backend changed together, the result establishes the benefit of the combined production configuration but does not attribute the gain to either knob independently.
  • This sweep measures acceptance length, not throughput. It is not sufficient on its own to change the default draft length.

All 42 reported AL values were validated against the raw log, all seven draft-length runs exited successfully, and the sweep completed successfully.

Notes and limitations

  • Acceptance remains workload- and thinking-mode-dependent; max_draft_len should be tuned together with end-to-end throughput for the intended workload.
  • Confidence-based dynamic drafting is not enabled in this PR.

PR checklist

  • The description explains the implementation, validated configuration, accuracy gate, and acceptance results.
  • Unit, CUDA-graph, 8-GPU end-to-end, and full GSM8K LLM API tests cover the new paths.
  • The change follows the TensorRT-LLM coding and contribution guidelines to the best of the author's knowledge.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a new DSpark speculative decoding mode across the TensorRT-LLM _torch stack: pure-torch captured-context attention kernels, Markov/confidence draft heads, a staged draft model with checkpoint remapping, a worker managing rolling KV windows, target-model capture hooks, and LLM API config/validation, plus extensive unit and e2e tests. Unrelated fixes tighten DeepSeek-V4 config validation and an mHC head reshape.

Changes

DSpark Speculative Decoding

Layer / File(s) Summary
Speculative mode dispatch
tensorrt_llm/_torch/speculative/interface.py, tensorrt_llm/_torch/speculative/utils.py, tensorrt_llm/_torch/models/modeling_speculative.py
Adds DSPARK enum member and is_dspark(), wires get_spec_metadata/get_spec_worker/get_draft_model/load_draft_weights to dispatch to DSpark implementations.
Captured-context attention kernels
tensorrt_llm/_torch/speculative/dspark_attention.py, tests/unittest/_torch/speculative/hw_agnostic/test_dspark_attention.py, tests/unittest/_torch/speculative/hw_agnostic/test_dspark_cuda_graph.py
Adds RoPE, top-k index selection, sparse attention with sink, and scalar/batched forward attention functions, with CPU correctness and CUDA-graph capture/replay tests.
Draft heads and proposal
tensorrt_llm/_torch/speculative/dspark_heads.py, tensorrt_llm/_torch/speculative/dspark_draft.py, tests/unittest/_torch/speculative/hw_agnostic/test_dspark_heads.py, tests/unittest/_torch/speculative/hw_agnostic/test_dspark_draft.py
Adds Markov-bias heads (vanilla/gated/RNN), confidence head, capture projection, and dspark_propose full-block token proposal with confidence-based truncation, with unit tests.
Staged draft model and checkpoint loading
tensorrt_llm/_torch/models/modeling_dspark.py, tests/unittest/_torch/speculative/hw_agnostic/test_dspark_weight_schema.py
Adds checkpoint key remapping, DSparkBlock, DSparkDraftModel (forward/forward_batched/context windows), DSparkForCausalLM weight-loading wrapper, and weight-schema consistency tests.
Worker and rolling KV windows
tensorrt_llm/_torch/speculative/dspark.py, tests/unittest/_torch/speculative/hw_agnostic/test_dspark_worker.py
Adds DSparkSpecMetadata capture hooks and DSparkWorker slot/window management with eager and batched draft generation plus acceptance/forward orchestration.
Target model capture and mHC head fix
tensorrt_llm/_torch/models/modeling_deepseekv4.py, tensorrt_llm/_torch/modules/mhc/hyper_connection.py
Extends decoder layer forward/forward_MoE to support DSpark hidden-state capture; fixes HCHead.forward to preserve leading dimensions across reshape.
LLM API config and DeepSeek-V4 guards
tensorrt_llm/llmapi/llm_args.py, tensorrt_llm/llmapi/__init__.py, tensorrt_llm/_torch/model_config.py, tests/unittest/_torch/test_model_config.py, tests/unittest/api_stability/references_committed/llm.yaml
Adds DSparkDecodingConfig and backend validation, tightens num_nextn_predict_layers/compress_ratios handling for DeepSeek-V4 with a fail-fast error and regression test.
End-to-end test
tests/unittest/_torch/speculative/hw_agnostic/test_dspark.py
Adds an 8-GPU e2e pytest generating text with DSpark decoding and validating non-degenerate acceptance rate.

Sequence Diagram(s)

sequenceDiagram
  participant TargetModel as DeepseekV4DecoderLayer
  participant SpecMetadata as DSparkSpecMetadata
  participant DSparkWorker
  participant DraftModel as DSparkDraftModel

  TargetModel->>SpecMetadata: maybe_capture_hidden_states(resolved_residual)
  DSparkWorker->>SpecMetadata: prepare(request_ids)
  DSparkWorker->>SpecMetadata: get_hidden_states()
  DSparkWorker->>DSparkWorker: write_context_windows / back-fill accepted tokens
  DSparkWorker->>DraftModel: forward_batched(main_hidden, bonus_token_ids, kv_windows, slots)
  DraftModel->>DraftModel: _forward_stage (attention + MoE) per stage
  DraftModel->>DraftModel: forward_head (dspark_propose)
  DraftModel-->>DSparkWorker: draft tokens, num_proposed
  DSparkWorker-->>TargetModel: next_draft_tokens
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • NVIDIA/TensorRT-LLM#12794: Extends the same SpeculativeDecodingMode/is_parallel_draft interface and get_draft_model dispatch to add a new draft mode (DFlash), mirroring the DSpark integration points in this PR.

Suggested reviewers

  • arysef
  • nv-guomingz
  • jieli-matrix
  • 2ez4bz
  • JunyiXu-nv
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding DeepSeek DSpark speculative decoding.
Description check ✅ Passed The description is detailed and largely matches the template, covering summary, validation, tests, and checklist items.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
tests/unittest/_torch/speculative/hw_agnostic/test_dspark_worker.py (1)

151-210: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Coverage is insufficient for confidence-based truncation in the worker.

These tests only cover slot/window bookkeeping. They never stub draft_model.forward() / forward_batched() to return num_proposed < block_size, so the worker contract that should honor DSpark truncation is still untested. Please add that regression in tests/unittest/_torch/speculative/hw_agnostic/test_dspark_worker.py (and, if you want end-to-end coverage, follow up in tests/unittest/_torch/speculative/hw_agnostic/test_dspark.py).

As per path instructions, coverage here is insufficient and the feedback should name the target test files explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/_torch/speculative/hw_agnostic/test_dspark_worker.py` around
lines 151 - 210, The current tests only verify slot/window bookkeeping and do
not cover the confidence-based truncation path in the worker. Add a regression
test in test_dspark_worker that stubs draft_model.forward() or forward_batched()
to return num_proposed less than block_size, then assert the worker honors
DSpark truncation behavior; use _lazy_init, prepare, and the draft model call
path to locate the right spot. If you want broader coverage, add a matching
end-to-end test in test_dspark as well.

Source: Path instructions

tests/unittest/_torch/test_model_config.py (1)

173-198: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

DSpark config coverage is still missing.

This regression closes the compress_ratios=None gap, but none of the new DSpark validation in tensorrt_llm/llmapi/llm_args.py is covered here. Please add focused cases in tests/unittest/_torch/test_model_config.py or a new tests/unittest/llmapi/test_llm_args.py for same-checkpoint speculative_model handling and rejecting block_size != max_draft_len, so the first signal is not the 8-GPU e2e.

As per path instructions, "tests/**: Act as a QA engineer reviewing test changes and coverage for TensorRT-LLM. Keep feedback actionable: suggest concrete list file names and whether coverage is sufficient, insufficient, or needs follow-up outside the PR."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/_torch/test_model_config.py` around lines 173 - 198, Coverage
is insufficient for the new DSpark validation in llm_args.py. Add focused tests
in tests/unittest/_torch/test_model_config.py or a new
tests/unittest/llmapi/test_llm_args.py that exercise the speculative_model
same-checkpoint path and verify block_size is rejected when it differs from
max_draft_len. Use the relevant entry points ModelConfig.from_pretrained and the
llm_args validation logic so the failure is caught in unit tests instead of only
in e2e.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_torch/models/modeling_dspark.py`:
- Around line 367-377: The DSpark confidence path is always enabling
`with_markov` even when `build_markov_head()` returns `None`, which later makes
`DSparkConfidenceHead.forward()` assert on missing `prev_embeddings`. Update the
initialization in `DSparkModel` so `with_markov` is derived from whether
`self.markov_head` actually exists (or from `self.markov_rank > 0`), and pass
that value into `DSparkConfidenceHead` instead of hardcoding `True`. This should
keep `dspark_propose()` and `DSparkConfidenceHead` aligned when
`dspark_markov_rank=0`.

In `@tensorrt_llm/_torch/speculative/dspark.py`:
- Around line 339-347: `num_proposed` is being computed by
`draft_model.forward*()` but then discarded, so speculative scheduling still
always queues a full `block_size` block. Update the DSpark flow in `dspark.py`
to capture the second return value from both draft paths and thread it through
`next_draft_tokens` / the verifier so the scheduled draft length is truncated
according to `confidence_threshold`. Use the existing `draft_model.forward*()`,
`next_draft_tokens`, and speculative verification logic to ensure the count
affects runtime behavior, then add a regression test covering truncated draft
blocks.

In `@tensorrt_llm/llmapi/llm_args.py`:
- Around line 5137-5179: Move the DSpark validation into this
`DSparkDecodingConfig` handling block in `llm_args.py` so misconfigurations fail
early: explicitly reject `speculative_model=None` when `speculative_config` is
`DSparkDecodingConfig`, and validate that the resolved `block_size` matches
`max_draft_len` after loading any draft config overrides. Keep the checks close
to the existing `spec_cfg` resolution logic and use the `DSparkDecodingConfig` /
`speculative_model` / `max_draft_len` symbols so the invariant is enforced
before downstream DSpark model construction.
- Around line 2479-2484: The confidence_threshold field in llm_args.py is
currently unconstrained, so it can accept values outside the valid probability
range and cause DSpark truncation misconfiguration. Update the
confidence_threshold definition in the relevant args/model to enforce a [0, 1]
bound using Pydantic field constraints, and keep the existing default and
description intact. Use the confidence_threshold symbol to locate the field and
ensure the validation is declarative rather than handled by a custom validator.

In `@tests/unittest/_torch/speculative/hw_agnostic/test_dspark_cuda_graph.py`:
- Around line 214-252: The CUDA graph test only captures the non-persistent
branch, so it misses the production write-through path in
dspark_attention_forward_batched. Update
test_batched_attention_cuda_graph_capture_replay to also exercise persist=True
with a separate cache buffer, using the same CUDA graph capture/replay pattern.
Add an assertion that verifies the expected rolling KV window mutation after
replay, alongside the existing output comparison.

In `@tests/unittest/_torch/speculative/hw_agnostic/test_dspark.py`:
- Around line 107-114: Wrap the DSpark speculative decoding section in a
try/finally so the 8-GPU LLM created in spec_llm is always shut down even if
generate() or the output extraction for
spec_out/spec_texts/spec_ids/avg_accepted fails. Keep the existing spec_config,
spec_llm.generate, and shutdown logic, but move spec_llm.shutdown() into the
finally block to prevent leaked model/process-group state.

---

Nitpick comments:
In `@tests/unittest/_torch/speculative/hw_agnostic/test_dspark_worker.py`:
- Around line 151-210: The current tests only verify slot/window bookkeeping and
do not cover the confidence-based truncation path in the worker. Add a
regression test in test_dspark_worker that stubs draft_model.forward() or
forward_batched() to return num_proposed less than block_size, then assert the
worker honors DSpark truncation behavior; use _lazy_init, prepare, and the draft
model call path to locate the right spot. If you want broader coverage, add a
matching end-to-end test in test_dspark as well.

In `@tests/unittest/_torch/test_model_config.py`:
- Around line 173-198: Coverage is insufficient for the new DSpark validation in
llm_args.py. Add focused tests in tests/unittest/_torch/test_model_config.py or
a new tests/unittest/llmapi/test_llm_args.py that exercise the speculative_model
same-checkpoint path and verify block_size is rejected when it differs from
max_draft_len. Use the relevant entry points ModelConfig.from_pretrained and the
llm_args validation logic so the failure is caught in unit tests instead of only
in e2e.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: fec2a059-f520-48da-ac10-e69c8dd54c96

📥 Commits

Reviewing files that changed from the base of the PR and between 9a26938 and 533cd80.

📒 Files selected for processing (22)
  • tensorrt_llm/_torch/model_config.py
  • tensorrt_llm/_torch/models/modeling_deepseekv4.py
  • tensorrt_llm/_torch/models/modeling_dspark.py
  • tensorrt_llm/_torch/models/modeling_speculative.py
  • tensorrt_llm/_torch/modules/mhc/hyper_connection.py
  • tensorrt_llm/_torch/speculative/dspark.py
  • tensorrt_llm/_torch/speculative/dspark_attention.py
  • tensorrt_llm/_torch/speculative/dspark_draft.py
  • tensorrt_llm/_torch/speculative/dspark_heads.py
  • tensorrt_llm/_torch/speculative/interface.py
  • tensorrt_llm/_torch/speculative/utils.py
  • tensorrt_llm/llmapi/__init__.py
  • tensorrt_llm/llmapi/llm_args.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_dspark.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_dspark_attention.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_dspark_cuda_graph.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_dspark_draft.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_dspark_heads.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_dspark_weight_schema.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_dspark_worker.py
  • tests/unittest/_torch/test_model_config.py
  • tests/unittest/api_stability/references_committed/llm.yaml

Comment on lines +367 to +377
self.markov_head = build_markov_head(
markov_head_type=getattr(config, "dspark_markov_head_type", "vanilla"),
vocab_size=config.vocab_size,
markov_rank=self.markov_rank,
hidden_size=config.hidden_size,
)
self.confidence_head = DSparkConfidenceHead(
hidden_size=config.hidden_size,
markov_rank=self.markov_rank,
with_markov=True,
)

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Gate with_markov on whether a Markov head actually exists.

build_markov_head() can return None when markov_rank <= 0, but this still constructs DSparkConfidenceHead(..., with_markov=True). Later, dspark_propose() only passes prev_embeddings when markov_head is present, so any confidence_threshold > 0 run with dspark_markov_rank=0 trips the assert prev_embeddings is not None in DSparkConfidenceHead.forward().

Suggested fix
             self.confidence_head = DSparkConfidenceHead(
                 hidden_size=config.hidden_size,
                 markov_rank=self.markov_rank,
-                with_markov=True,
+                with_markov=self.markov_rank > 0,
             )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self.markov_head = build_markov_head(
markov_head_type=getattr(config, "dspark_markov_head_type", "vanilla"),
vocab_size=config.vocab_size,
markov_rank=self.markov_rank,
hidden_size=config.hidden_size,
)
self.confidence_head = DSparkConfidenceHead(
hidden_size=config.hidden_size,
markov_rank=self.markov_rank,
with_markov=True,
)
self.confidence_head = DSparkConfidenceHead(
hidden_size=config.hidden_size,
markov_rank=self.markov_rank,
with_markov=self.markov_rank > 0,
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/models/modeling_dspark.py` around lines 367 - 377, The
DSpark confidence path is always enabling `with_markov` even when
`build_markov_head()` returns `None`, which later makes
`DSparkConfidenceHead.forward()` assert on missing `prev_embeddings`. Update the
initialization in `DSparkModel` so `with_markov` is derived from whether
`self.markov_head` actually exists (or from `self.markov_rank > 0`), and pass
that value into `DSparkConfidenceHead` instead of hardcoding `True`. This should
keep `dspark_propose()` and `DSparkConfidenceHead` aligned when
`dspark_markov_rank=0`.

Comment on lines +339 to +347
toks, _ = draft_model.forward(
main_hidden,
bonus,
start_pos,
kv_windows=win_slice,
temperature=0.0,
confidence_threshold=conf_thr,
)
out_tokens[i] = toks[0].to(torch.int32)

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.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

num_proposed is dropped before the next speculative step is scheduled.

Both draft paths discard the second value returned by draft_model.forward*() and always enqueue the full block_size tokens into next_draft_tokens. That makes confidence_threshold a no-op at runtime: the confidence head computes num_proposed, but the verifier still sees K draft tokens every step, so DSpark's advertised block truncation never takes effect.

This needs to be plumbed through the speculative scheduling/verification path, not just computed in the draft model. Please also add a regression once this is wired.

Also applies to: 422-431

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/speculative/dspark.py` around lines 339 - 347,
`num_proposed` is being computed by `draft_model.forward*()` but then discarded,
so speculative scheduling still always queues a full `block_size` block. Update
the DSpark flow in `dspark.py` to capture the second return value from both
draft paths and thread it through `next_draft_tokens` / the verifier so the
scheduled draft length is truncated according to `confidence_threshold`. Use the
existing `draft_model.forward*()`, `next_draft_tokens`, and speculative
verification logic to ensure the count affects runtime behavior, then add a
regression test covering truncated draft blocks.

Comment on lines +2479 to +2484
confidence_threshold: float = Field(
default=0.0,
description=
"Static confidence threshold for proposal-length truncation. A draft "
"position k is dropped when sigmoid(confidence_k) < threshold. 0.0 "
"disables truncation (propose the full block).")

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Bound confidence_threshold to [0, 1].

sigmoid(confidence_k) is a probability. Values outside [0, 1] silently turn DSpark truncation into “always keep” or “always drop,” which is a bad user-facing misconfiguration surface.

As per coding guidelines, "Prefer PositiveInt, NonNegativeInt, NonNegativeFloat, PositiveFloat, or Field(gt=0) for numeric constraints in Pydantic fields instead of custom validators."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/llmapi/llm_args.py` around lines 2479 - 2484, The
confidence_threshold field in llm_args.py is currently unconstrained, so it can
accept values outside the valid probability range and cause DSpark truncation
misconfiguration. Update the confidence_threshold definition in the relevant
args/model to enforce a [0, 1] bound using Pydantic field constraints, and keep
the existing default and description intact. Use the confidence_threshold symbol
to locate the field and ensure the validation is declarative rather than handled
by a custom validator.

Source: Coding guidelines

Comment thread tensorrt_llm/llmapi/llm_args.py
Comment on lines +214 to +252
@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA graph capture needs a GPU")
def test_batched_attention_cuda_graph_capture_replay():
"""The batched attention captures + replays and matches eager output.

Proves the path is free of capture-illegal ops (host syncs, dynamic shapes).
"""
g = _make_batched_inputs(seed=0)
dev = "cuda"
G = g["G"]
start_pos = torch.tensor(g["start_positions"], dtype=torch.long, device=dev)
slots = torch.arange(G, dtype=torch.long, device=dev)
# Static input tensors the graph reads/writes.
x = g["x"].to(dev)
main_x = g["main_x"].to(dev)
cache = g["kv_cache"].to(dev)
kw = {k: (v.to(dev) if torch.is_tensor(v) else v) for k, v in _attn_kwargs(g).items()}

def run(persist):
return dspark_attention_forward_batched(
x, main_x, start_pos, cache, slots, persist=persist, **kw
)

eager = run(persist=False)

# Warmup (PyTorch CUDA-graph semantics) then capture on a non-persist call so
# the comparison isn't perturbed by the window write-through.
s = torch.cuda.Stream()
s.wait_stream(torch.cuda.current_stream())
with torch.cuda.stream(s):
for _ in range(3):
run(persist=False)
torch.cuda.current_stream().wait_stream(s)

graph = torch.cuda.CUDAGraph()
with torch.cuda.graph(graph):
out = run(persist=False)
graph.replay()
torch.cuda.synchronize()
torch.testing.assert_close(out, eager, rtol=2e-2, atol=2e-2)

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Capture the persist=True CUDA-graph path too.

Line 248 captures run(persist=False), but the production DSpark path calls dspark_attention_forward_batched(..., persist=True) when it updates the rolling KV windows. That means tests/unittest/_torch/speculative/hw_agnostic/test_dspark_cuda_graph.py never exercises the indexed write-through branch that actually runs under CUDA graphs, so a capture-only regression there can ship unnoticed. Please add a replay assertion for persist=True on a dedicated cache buffer and verify the expected window-row mutation. As per path instructions, "Act as a QA engineer reviewing test changes and coverage for TensorRT-LLM."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/_torch/speculative/hw_agnostic/test_dspark_cuda_graph.py`
around lines 214 - 252, The CUDA graph test only captures the non-persistent
branch, so it misses the production write-through path in
dspark_attention_forward_batched. Update
test_batched_attention_cuda_graph_capture_replay to also exercise persist=True
with a separate cache buffer, using the same CUDA graph capture/replay pattern.
Add an assertion that verifies the expected rolling KV window mutation after
replay, alongside the existing output comparison.

Source: Path instructions

Comment on lines +107 to +114
# DSpark speculative decoding (draft = same checkpoint's mtp.* stages).
spec_config = DSparkDecodingConfig(max_draft_len=5, speculative_model=model_dir)
spec_llm = LLM(speculative_config=spec_config, **common)
spec_out = spec_llm.generate(PROMPTS, sampling)
spec_texts = [o.outputs[0].text for o in spec_out]
spec_ids = [list(o.outputs[0].token_ids) for o in spec_out]
avg_accepted = [o.avg_decoded_tokens_per_iter - 1 for o in spec_out]
spec_llm.shutdown()

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Always shut down the 8-GPU LLM in a finally block.

If generate() or output extraction raises, this test exits before shutdown() and can leave the model/process group alive, which tends to poison the rest of the suite on shared CI nodes.

Suggested fix
-    spec_llm = LLM(speculative_config=spec_config, **common)
-    spec_out = spec_llm.generate(PROMPTS, sampling)
-    spec_texts = [o.outputs[0].text for o in spec_out]
-    spec_ids = [list(o.outputs[0].token_ids) for o in spec_out]
-    avg_accepted = [o.avg_decoded_tokens_per_iter - 1 for o in spec_out]
-    spec_llm.shutdown()
+    spec_llm = LLM(speculative_config=spec_config, **common)
+    try:
+        spec_out = spec_llm.generate(PROMPTS, sampling)
+        spec_texts = [o.outputs[0].text for o in spec_out]
+        spec_ids = [list(o.outputs[0].token_ids) for o in spec_out]
+        avg_accepted = [o.avg_decoded_tokens_per_iter - 1 for o in spec_out]
+    finally:
+        spec_llm.shutdown()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# DSpark speculative decoding (draft = same checkpoint's mtp.* stages).
spec_config = DSparkDecodingConfig(max_draft_len=5, speculative_model=model_dir)
spec_llm = LLM(speculative_config=spec_config, **common)
spec_out = spec_llm.generate(PROMPTS, sampling)
spec_texts = [o.outputs[0].text for o in spec_out]
spec_ids = [list(o.outputs[0].token_ids) for o in spec_out]
avg_accepted = [o.avg_decoded_tokens_per_iter - 1 for o in spec_out]
spec_llm.shutdown()
# DSpark speculative decoding (draft = same checkpoint's mtp.* stages).
spec_config = DSparkDecodingConfig(max_draft_len=5, speculative_model=model_dir)
spec_llm = LLM(speculative_config=spec_config, **common)
try:
spec_out = spec_llm.generate(PROMPTS, sampling)
spec_texts = [o.outputs[0].text for o in spec_out]
spec_ids = [list(o.outputs[0].token_ids) for o in spec_out]
avg_accepted = [o.avg_decoded_tokens_per_iter - 1 for o in spec_out]
finally:
spec_llm.shutdown()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unittest/_torch/speculative/hw_agnostic/test_dspark.py` around lines
107 - 114, Wrap the DSpark speculative decoding section in a try/finally so the
8-GPU LLM created in spec_llm is always shut down even if generate() or the
output extraction for spec_out/spec_texts/spec_ids/avg_accepted fails. Keep the
existing spec_config, spec_llm.generate, and shutdown logic, but move
spec_llm.shutdown() into the finally block to prevent leaked model/process-group
state.

@longlee0622
longlee0622 requested a review from a team as a code owner July 2, 2026 08:53
@longlee0622
longlee0622 force-pushed the dev/dspark-spec-dec-pr branch 3 times, most recently from 5e177ce to c8fcd3d Compare July 3, 2026 05:07
@longlee0622

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57370 [ run ] triggered by Bot. Commit: 15169d5 Link to invocation

@longlee0622 longlee0622 added the api-compatible Accepted LLM API contract change that is backwards-compatible label Jul 3, 2026
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57370 [ run ] completed with state FAILURE. Commit: 15169d5
/LLM/main/L0_MergeRequest_PR pipeline #46121 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@longlee0622

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57435 [ run ] triggered by Bot. Commit: 15169d5 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57435 [ run ] completed with state SUCCESS. Commit: 15169d5
/LLM/main/L0_MergeRequest_PR pipeline #46174 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@longlee0622
longlee0622 force-pushed the dev/dspark-spec-dec-pr branch from 15169d5 to fa6461a Compare July 3, 2026 18:22
@longlee0622

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57501 [ run ] triggered by Bot. Commit: fa6461a Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57501 [ run ] completed with state ABORTED. Commit: fa6461a

Link to invocation

)
# Pad entries hold BAD_PAGE_INDEX (-1); clamp before _compute_slot_mappings
# dereferences them (mirrors base class).
self.indexer_k_cache_block_offsets.clamp_(min=0)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Don't really understand the comment here - in what case can they be negative?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

updated comment to include the background of doing this.

@@ -0,0 +1,462 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I did not review the modeling part carefully, but we should make sure we are reusing components from DSV4 where possible

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for pointing this out.

DSpark already reuses the DeepSeek-V4 decoder layer, attention/MoE/mHC modules, weight loader, embeddings, and LM head. The remaining custom attention execution implements DSpark-specific captured-context rolling windows, non-causal block attention, attention sinks, inverse RoPE, and CUDA-graph-safe batched indexing, so reusing the standard DSV4 attention forward directly would change DSpark semantics.

I did find duplicated checkpoint remapping logic. In 1c951bb016, I factored the common attention/FFN key remapping, routed-MoE scale detection, and MXFP4 tensor conversion into shared DeepSeek-V4 helpers, and updated DSpark to reuse them while retaining only its stage-specific namespace and head mappings.

I also verified the refactor against the previous implementation for FP8 and MXFP4 checkpoints, including compressor fusion, shared/routed experts, MTP keys, and DSpark stage filtering.

Comment thread tensorrt_llm/_torch/modules/mla.py Outdated
Comment on lines +401 to +402
# Keep every MLA reachable when one-model speculative decoding
# reuses local attention layer indices in a shared registry.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we add some more elaboration on this comment?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Sure. I expanded the comment to document the distinction and naming rule of layer ids.

Comment on lines +2505 to +2506
# Per-rank generation-request counts. External drafters (DSpark) run the
# draft only over generation requests, so num_seqs (which includes

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why do we only run on generation requests?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

As I understand it, DSpark requires the bonus token from main model and the main model hidden states generated from that token as input. prefill request doesn't have the latter.

I've updated the comment to make it clear. BTW, it seems DFlash is doing similar things for gen-only

with self.draft_kv_cache_context(attn_metadata, draft_kv_cache_manager):
hidden_states_out = draft_model.dflash_forward(
noise_embedding=inputs["noise_embedding"],
query_positions=inputs["query_positions"],
num_ctx_per_req=inputs["num_ctx_per_req"],
ctx_k_cache=inputs["ctx_k_cache"],
ctx_v_cache=inputs["ctx_v_cache"],
ctx_cache_batch_idx=inputs["ctx_cache_batch_idx"],
)
# Gather K logits per gen request from mask positions (1..K).
# hidden_states_out is flat: [num_gens * block_size, hidden_dim]
block_size = self._resolved_block_size
request_bases = torch.arange(num_gens, dtype=torch.long, device="cuda") * block_size
offsets = torch.arange(K, dtype=torch.long, device="cuda")
# Masks are at positions 1..K in each request's block_size output
gen_gather_ids = (request_bases.unsqueeze(1) + 1 + offsets.unsqueeze(0)).flatten()
gen_gather_ids = gen_gather_ids.clamp(max=hidden_states_out.shape[0] - 1)
gen_logits = draft_model.logits_processor(
hidden_states_out[gen_gather_ids], draft_model.lm_head, attn_metadata, True
)
vocab_size = gen_logits.shape[-1]
gen_logits = gen_logits.reshape(num_gens, K, vocab_size)
d2t = getattr(draft_model.model, "d2t", None)
gen_draft_tokens = torch.argmax(gen_logits, dim=-1, keepdim=False).long()
if d2t is not None:
gen_draft_tokens = d2t[gen_draft_tokens] + gen_draft_tokens
gen_draft_tokens = gen_draft_tokens.type(torch.int32)
else:
gen_draft_tokens = torch.empty((0, K), dtype=torch.int32, device="cuda")
if num_contexts > 0 and num_gens > 0:
ctx_draft_tokens = torch.zeros((num_contexts, K), dtype=torch.int32, device="cuda")
next_draft_tokens = torch.cat([ctx_draft_tokens, gen_draft_tokens], dim=0)
elif num_contexts > 0:
next_draft_tokens = torch.zeros((num_contexts, K), dtype=torch.int32, device="cuda")
else:
next_draft_tokens = gen_draft_tokens

@longlee0622
longlee0622 force-pushed the dev/dspark-spec-dec-pr branch from 8a67c7f to 24ff931 Compare July 15, 2026 05:13
longlee0622 added a commit to longlee0622/TensorRT-LLM that referenced this pull request Jul 15, 2026
Addresses review feedback from mikeiovine on PR NVIDIA#15808:

- Remove the DSPARK_FIX_WO_A_ENV gate around the wo_a dequant. The
  real-MLA path already proved the dequant is correct (cos 1.0 vs the
  reference), so always dequantize instead of keeping the historical
  buggy raw fp8-cast-to-bf16 path around.
- DSparkDecodingConfig.markov_head_type was never consulted by the
  model (which read dspark_markov_head_type straight off the HF draft
  config); wire it through DSparkBlock/DSparkDraftModel as a user
  override that falls back to the draft checkpoint value, matching the
  resolution pattern already used for target_layer_ids/block_size/
  markov_rank.
- DSparkDecodingConfig.enable_confidence_head was unused; it now gates
  confidence-based draft-length truncation in DSparkWorker.
- DSparkDecodingConfig.mask_token_id was resolved from the draft
  config but never consumed by the model; wire it through the same
  way as markov_head_type.

Signed-off-by: Jonas Li <6110159+longlee0622@users.noreply.github.com>
longlee0622 added a commit to longlee0622/TensorRT-LLM that referenced this pull request Jul 15, 2026
Addresses review feedback from mikeiovine on PR NVIDIA#15808:

- Remove the DSPARK_FIX_WO_A_ENV gate around the wo_a dequant. The
  real-MLA path already proved the dequant is correct (cos 1.0 vs the
  reference), so always dequantize instead of keeping the historical
  buggy raw fp8-cast-to-bf16 path around.
- DSparkDecodingConfig.markov_head_type was never consulted by the
  model (which read dspark_markov_head_type straight off the HF draft
  config); wire it through DSparkBlock/DSparkDraftModel as a user
  override that falls back to the draft checkpoint value, matching the
  resolution pattern already used for target_layer_ids/block_size/
  markov_rank.
- DSparkDecodingConfig.enable_confidence_head was unused; it now gates
  confidence-based draft-length truncation in DSparkWorker.
- DSparkDecodingConfig.mask_token_id was resolved from the draft
  config but never consumed by the model; wire it through the same
  way as markov_head_type.

Signed-off-by: Jonas Li <6110159+longlee0622@users.noreply.github.com>
@longlee0622
longlee0622 force-pushed the dev/dspark-spec-dec-pr branch 3 times, most recently from 0e6c264 to 3c296d9 Compare July 15, 2026 07:29
@longlee0622

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59391 [ run ] triggered by Bot. Commit: 3c296d9 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59391 [ run ] completed with state SUCCESS. Commit: 3c296d9
/LLM/main/L0_MergeRequest_PR pipeline #47865 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@longlee0622

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59433 [ run ] triggered by Bot. Commit: 3c296d9 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59433 [ run ] completed with state SUCCESS. Commit: 3c296d9
/LLM/main/L0_MergeRequest_PR pipeline #47902 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@longlee0622

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59556 [ run ] triggered by Bot. Commit: 3c296d9 Link to invocation

@chienchunhung chienchunhung left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Curious: Is there a way to ensure spec_config.target_layer_ids matches the draft checkpoint’s dspark_target_layer_ids? An explicit override could make these shapes incompatible and fail at runtime.

Signed-off-by: Jonas Li <6110159+longlee0622@users.noreply.github.com>
Make the checkpoint's dspark_target_layer_ids authoritative for DSpark
speculative decoding. When target_layer_ids is unset it is copied from
the checkpoint verbatim (order preserved, since main_proj columns are
order-dependent). An explicit override that does not exactly match the
checkpoint list is now rejected during config validation instead of
failing later with a projection shape mismatch (different count) or
silently degrading acceptance (same count, different/reordered layers).

Add unit coverage for defaulting, matching override, mismatched count,
same-count-different-layers, and order-mismatch cases.

Signed-off-by: Jonas Li <6110159+longlee0622@users.noreply.github.com>
@longlee0622
longlee0622 force-pushed the dev/dspark-spec-dec-pr branch from 9581c66 to 1df8a86 Compare July 16, 2026 09:30
@longlee0622

Copy link
Copy Markdown
Collaborator Author

Curious: Is there a way to ensure spec_config.target_layer_ids matches the draft checkpoint’s dspark_target_layer_ids? An explicit override could make these shapes incompatible and fail at runtime.

Does this help? 1df8a86

@longlee0622

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59689 [ run ] triggered by Bot. Commit: 1df8a86 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59556 [ run ] completed with state ABORTED. Commit: 3c296d9

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59689 [ run ] completed with state SUCCESS. Commit: 1df8a86
/LLM/main/L0_MergeRequest_PR pipeline #48122 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-compatible Accepted LLM API contract change that is backwards-compatible

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants