Skip to content

[CUDA] Support right-padded prefill chunks in GroupQueryAttention - #33503

Merged
Tianlei Wu (tianleiwu) merged 11 commits into
mainfrom
tlwu/qga_right_padded_prefill_chunk_slide_window
Nov 3, 2026
Merged

Tianlei Wu (tianleiwu) merged 11 commits into
mainfrom
tlwu/qga_right_padded_prefill_chunk_slide_window

Conversation

@tianleiwu

@tianleiwu Tianlei Wu (tianleiwu) commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Description

Add an optional query_seqlens input (index 16) to com.microsoft::GroupQueryAttention and implement it
in the CUDA execution provider. It carries the number of valid, non-padded tokens of a right-padded
query/key/value chunk per batch entry, so fixed-shape chunked prefill works with FlashAttention,
MemoryEfficientAttention and unfused attention, with a full-length or a windowed KV cache.

This replaces the right_padded_query attribute that earlier revisions of this PR introduced. The attribute
and the CPU heuristic in #33505 are superseded by one input that is part of the operator contract, so every
execution provider can implement identical semantics. The attribute was never in a release, so no released
schema changes.

Stack: this PR is the base of a two-PR stack. #33505 (draft) adds the CPU implementation. Its base is the branch
of this PR, so it shows only the CPU changes, and it is retargeted to main once this PR merges. ORT's build, test
and CodeQL workflows run only for pull requests that target main or rel-* (the lint workflow runs for any base),
so #33505 gets them after that retarget. This branch is rebased onto the current main.

Contract

For batch entry b: S is the padded sequence_length, T = seqlens_k[b] + 1 is the number of tokens in
the cache after the step, Q = query_seqlens[b] is the number of valid rows, and P = T - Q is the number
of tokens cached before the chunk.

  • Rows [0, Q) of query/key/value are valid and rows [Q, S) are right padding.
  • Only the valid rows are appended to the cache, at [P, T). Query row s sits at absolute position P + s
    for causal masking, local_window_size and implicit rotary positions. Output rows [Q, S) and cache rows at
    or beyond T are unspecified.
  • total_sequence_length is only an upper bound of T (for example the cache capacity). It no longer has to be
    P + S and is not used to tell a first prompt from a later chunk.
  • Requirements: causal=1, kv_sequence_length == S, past present, 1 <= Q <= min(S, T), T <= total_sequence_length, S > 1 requires batch_size == 1, and Q == 1 when S == 1. A cache that is not
    windowed also needs P + S <= C (C is the sequence dimension of present_key) and its P cached tokens in
    past_key/past_value. Those buffers may be shorter than present_key, so a cache can grow between steps.
  • Omitting the input keeps the existing behavior, so callers that pass the cache capacity as
    total_sequence_length are unaffected.

Key changes

  • Schema/docs: new input 16, the right_padded_query attribute is removed, and a "Right-padded query chunks"
    section is added to the operator description. docs/ContribOperators.md and docs/contrib_ops/cuda/gqa.md
    are updated.
  • Shared validation (group_query_attention_helper.h): CheckQuerySeqlens validates shape, type and, when
    the tensors are host resident, the per-entry values. With the input present, CheckInputs no longer classifies
    the step by comparing S with total_sequence_length, and it skips the legacy check that ties a growing cache to
    past + S == total_sequence_length, which rejected valid calls such as past rows 10, S = 8, Q = 3,
    total_sequence_length = 32.
  • CUDA: GetSequenceLengths takes Q from the input, clamped to [1, min(S, T)], and derives P = T - Q
    from seqlens_k instead of total_sequence_length - S. Padded rows never enter the cache and the unfused
    causal mask is anchored at P. cuDNN SDPA is skipped for padded chunks because it assumes unpadded subsequent
    queries. S == 1 ignores the input so XQA and flash decode stay enabled. query_seqlens with causal=0 is
    rejected. Device-resident values cannot be checked on the host, so out-of-contract values give unspecified but
    memory-safe results.
  • CUDA quantized KV cache: an ordinary first prompt attends to the float K/V of the chunk, while later chunks
    read the quantized cache. With the input the host cannot tell them apart, so a chunk is handled as a later one,
    and an entry with no past and more than one valid row is then re-attended to the float K/V to match the unpadded
    first prompt. An entry with one valid row behaves like a single-token step and keeps reading the quantized cache,
    and a call that omits the input keeps the previous classification.
  • CPU: temporarily rejects the input with INVALID_ARGUMENT so it is never silently misinterpreted.
    [CPU] Support right-padded prefill chunks in GroupQueryAttention #33505 replaces the rejection with the implementation.
  • Other EPs (WebGPU, JS, DML, WebNN, OpenVINO, MIGraphX): reject or decline nodes that set input 16. These
    edits are small, but they were not compiled locally because those EPs are not part of this build, so CI is
    the first compile of them. The OpenVINO check also applies to the com.microsoft domain.
  • Latent bug fix (group_query_attention_pre_norm_fusion.cc, group_query_attention_fusion.cc): both fusions
    rebuilt the node input list with a fixed number of slots and dropped any later input, which would have silently
    removed query_seqlens. They now keep all inputs, with unit tests.

Testing

CUDA 13.0 and cuDNN 9, H200 (sm_90), Release build, FlashAttention and MemoryEfficientAttention enabled, on the
head of this branch.

  • onnxruntime_provider_test --gtest_filter='*GroupQueryAttention*:*GQA*': 138 passed, 18 skipped, 0 failed.
    The skipped tests need WebGPU. New goldens compare padded chunks with the same call on an unpadded chunk for
    Flash, MEA and unfused in fp16/bf16, with and without packed QKV, for full-length and windowed caches, and for a
    cache that grows between steps. New negative tests cover a bidirectional node, a missing past, a batched chunk
    and a wrong shape.
  • onnxruntime_test_all --gtest_filter='*GroupQueryAttentionPreNormFusion*:*GroupQueryAttentionFusion*':
    33 passed, 4 skipped (WebGPU). Reverting the input-count fix makes the new test fail.
  • test_gqa.py, the whole file on this build: 1003 tests, 8 skipped, 2 failures. The failures,
    TestFlashGQA.test_gqa_decode_bidirectional and
    TestGQAAttentionBias.test_windowed_cache_attention_bias_is_rejected, also occur on an independent build of
    main and are not related to this change. The right-padded tests cover fp16 and int8-quantized KV (including a
    chunk with one valid row and a call that omits the input), the cuDNN fallback, capacity-bound caches,
    rotary/softcap/head_sink/attention_bias/packed QKV, and S == 1 decode.
  • compute-sanitizer --tool memcheck: 0 errors on the head of this branch for the quantized-KV tests
    (TestQuerySeqlensQuantizedCache, 16 tests), the padded windowed-cache tests (7) and the right-padded CUDA
    gtests. An earlier revision also ran on the Flash, MEA and unfused paths for in-contract and out-of-contract
    inputs (Q of 0, negative, above S or T; T above total_sequence_length; negative seqlens_k; P + S
    above the cache) with exact-size buffers separated by spacers, and a deliberately shortened cache is flagged by the
    same harness. That harness was not repeated after the later review fixes.
  • lintrunner -m origin/main: clean.

Notes for reviewers:

  • docs/ContribOperators.md was refreshed from the schema source with a script that mirrors
    gen_contrib_doc.py for the GQA entry, because my local build is lite-protobuf and strips operator
    descriptions. It matches the generator's output format; the full-protobuf CI docs check is authoritative. The
    DML row of docs/OperatorKernels.md follows the generator's format by hand, because DML cannot be built on Linux.

Motivation and Context

Static-shape (for example compiled or graph-captured) prefill uses a fixed query chunk even when only a few rows
are real tokens. Previously, subsequent chunks derived the past offset and the eviction count from the padded
length, which corrupted the KV cache and shifted causal and RoPE alignment. Inferring the padding from
total_sequence_length cannot work in general, because existing callers pass the cache capacity there. An
explicit per-entry valid length removes the ambiguity, needs no heuristic, and gives the CPU and CUDA
implementations the same contract.

Copilot AI balanced review requested due to automatic review settings October 20, 2026 23:37

Copilot AI 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.

🟡 Changes recommended

The padding heuristic misclassifies existing fixed-bound callers, shifting cache offsets and discarding valid tokens.

1 open issue
What changed in this PR

Adds right-padded chunked prefill support to CUDA GroupQueryAttention across FlashAttention, memory-efficient, and unfused backends.

Changes:

  • Adjusts sequence lengths, cache eviction, and causal alignment for padding.
  • Zeros padded K/V entries.
  • Adds padded-prefill coverage, including quantized caches.
File Description
onnxruntime/​test/​python/​transformers/​test_gqa.py Adds padded-step parity tests across backends.
onnxruntime/​test/​contrib_ops/​group_query_attention_op_test.cc Corrects test lengths and covers padded windowed chunks.
onnxruntime/​contrib_ops/​cuda/​bert/​unfused_attention.h Adds optional per-batch past lengths.
onnxruntime/​contrib_ops/​cuda/​bert/​unfused_attention.cu Uses explicit past offsets for masking.
onnxruntime/​contrib_ops/​cuda/​bert/​group_query_attention_qkv.cuh Zeros padded cache entries and adjusts RoPE assertions.
onnxruntime/​contrib_ops/​cuda/​bert/​group_query_attention_impl.cu Updates padding-aware lengths and backend wiring.

Review effort: Balanced

Copilot AI 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.

🟡 Changes recommended

Shared-KV calls retain memory-safety and causal-alignment regressions, and the forced-Flash test fails in quick builds.

3 open issues
1 resolved since last review

Review effort: Balanced

Copilot AI 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.

@tianleiwu
Tianlei Wu (tianleiwu) force-pushed the tlwu/qga_right_padded_prefill_chunk_slide_window branch from 40bbbff to 6a2b0e6 Compare November 1, 2026 09:00

Copilot AI 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.

Support right-padded query chunks (including subsequent prefill chunks and
sliding_window_cache=1) in CUDA GroupQueryAttention across FlashAttention,
MemoryEfficientAttention, and Unfused attention paths:

- Derive past_len from max_total_sequence_length - sequence_length when a
  subsequent prefill chunk (sequence_length > 1) is right-padded, and compute
  windowed KV cache eviction and resident lengths from valid_q_len rather than
  the padded sequence_length.
- Populate padded_seq_lens as past_len + sequence_length (or cache_past_len +
  sequence_length when windowed) and pass it to causal FlashAttention and
  MemoryEfficientAttention so valid query rows stay aligned at their true past
  offset.
- Pass past_seq_lens to UnfusedAttentionParams so UnfusedSoftmaxKernel aligns
  queries at past_seq_lens[batch] + q_in_head instead of seqlens_k[batch] -
  q_sequence_length.
- Zero right-padded KV positions (cache_s >= valid_seq_lens[b]) in
  UnpackRoPEAppend so padding tokens never pollute the KV cache or leave
  uninitialized values in a windowed staging buffer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve capacity-valued length callers by making padded prefill interpretation opt-in. Keep ragged decode offsets per batch, exclude cuDNN's unpadded-query path, and verify every forced attention dispatch.

Add capacity-bound, padded global-attention, quantized first-prompt, ragged decode, and attribute-validation regressions, and document the contract.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the right_padded_query attribute with an optional query_seqlens input (index 16) so that a fixed-shape, right-padded query chunk carries its valid length per batch entry instead of deriving it from total_sequence_length - sequence_length. The input is part of the operator contract, so every execution provider can implement it with identical semantics.

CUDA: GetSequenceLengths takes the valid query length from the input (clamped to [1, min(S, T)]) and the present-cache capacity, appends only the valid rows at [T - Q, T), and disables cuDNN SDPA for padded chunks. The shared CheckInputs helper validates the input and no longer classifies the step by comparing S with total_sequence_length when the input is present. The CPU kernel and other EPs reject the input until they implement it.

Also keep trailing node inputs (such as query_seqlens) when the GroupQueryAttention pre-norm fusion rebuilds the input list, and cover that with a unit test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve borrowed-KV lengths and signed causal offsets. Initialize quantized
present buffers from past caches and keep floating-point KV for first-chunk
attention when query_seqlens supplies the valid lengths.

Retain optional inputs during GQA fusion, apply the OpenVINO rejection to the
contrib domain, guard BF16 coverage by device capability, and use quick-build
compatible Flash test shapes. Refresh generated GQA kernel documentation.

Validation: 137 provider tests and 33 fusion tests passed; 61 Python tests and
36 subtests passed. Reverting the fixes reproduces the new regression failures.
CUDA memcheck reports zero errors; lintrunner -a is clean. OpenVINO capability
coverage is included but skipped locally because the provider is unavailable.
With query_seqlens, total_sequence_length is only an upper bound, so a cache
that grows between steps is no longer tied to past_sequence_length +
kv_sequence_length. The legacy dynamic-cache equality rejected valid calls
such as past rows 10, S=8, Q=3, T=13 and total_sequence_length=32. Skip it when
query_seqlens is given and instead require that the P = T - Q cached tokens of
a non-windowed cache are held by past_key and past_value.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The forced Flash and memory-efficient assertions in test_gqa.py only hold when the
requested kernel is compiled into the CUDA provider, but they were gated on the GPU
architecture alone. Probe the dispatch once per kernel with the borrowed-KV model and
skip the exact-dispatch assertions when the kernel is unavailable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The quantized-cache fallback re-attends a right-padded first chunk to the float
RoPE'd K/V so that it matches an ordinary first prompt. The replay ran for every
S > 1 call. Callers that omit query_seqlens therefore changed from reading the
quantized cache to reading float K/V, and a chunk with a single valid row read
float K/V while the equivalent single-token step reads the quantized cache.

Carry has_query_seqlens in GroupQueryAttentionData, gate the replay on it, and
skip entries whose valid end is at most one token. Add INT8 regressions for the
Q=1 padded chunk and for the input-omitted first chunk.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CodeQL reports the OpenVINO import in the query_seqlens capability test as a
potentially uninitialized local, because it does not know that skipTest() never
returns. Move the GPU discovery into a helper that returns False when the Python
runtime is missing, so the test no longer uses the module after a failed import.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
HasCudaEnvironment comes from cuda_op_test_utils.h, which this test file includes only under USE_CUDA. The BF16 branch of QuerySeqlensRightPaddedChunk_CUDA called it unguarded, so non-CUDA builds of onnxruntime_provider_test failed to compile (gcc: 'not declared in this scope'; MSVC: C3861).

The test already returns early via GTEST_SKIP when no CUDA EP is available, so the guard changes only compilation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tianleiwu
Tianlei Wu (tianleiwu) force-pushed the tlwu/qga_right_padded_prefill_chunk_slide_window branch from b84d577 to 823a83b Compare November 2, 2026 04:49

@titaiwangms Ti-Tai Wang (titaiwangms) 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.

Full static review of 657cc52 -> 823a83b, including the stacked CPU implementation in #33505.

No concrete core correctness, memory-safety, or integration defect was established. I am withholding approval for the focused JSEP regression-coverage requirement below.

Required before approval

Missing focused JSEP rejection coverage -- onnxruntime/contrib_ops/js/bert/group_query_attention.h:28.

The constructor now rejects an existing query_seqlens input at slot 16. Please add focused JSEP tests showing that supplying the input fails with the intended error, while omitting it or supplying an empty optional slot preserves existing admission. The matching .github/instructions/jsep-deprecated.instructions.md explicitly requires focused regression coverage for accepted correctness fixes.

The native WebGPU rejection test added by #33505 is useful, but it does not exercise JSEP session construction. This is a coverage/policy gap, not an established runtime failure.

Nonblocking follow-ups

  • Avoid probing availability with the regression case itself -- onnxruntime/test/python/transformers/test_gqa.py:575. has_sdpa_kernel() probes S=8, T=3, C=9, which is also the negative-diagonal boundary tested by test_query_longer_than_borrowed_kv(). A regression that makes Flash/MEA ineligible specifically for T < S can therefore turn the test into a skip. Probe availability with an ordinary supported control, such as S=T=8, C=9, and assert boundary-case dispatch separately.
  • Clarify the quantized first-chunk reference -- onnxruntime/core/graph/contrib_ops/bert_defs.cc:1510 and onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.cu:1333-1337. For P=0, Q>1, the new-input path attends to float new K/V. Omitting input 16 while retaining a capacity-valued total_sequence_length preserves the legacy subsequent-chunk classification and quantized reads. Please specify whether the unpadded reference retains input 16 or uses the true total length. The added tests deliberately distinguish these paths; this is a documentation ambiguity, not a proven numerical bug.
  • Update the padded-length comment -- onnxruntime/contrib_ops/cuda/bert/attention_data.h:144-145. padded_seq_lens is no longer first-prompt-only: it also carries P+S for padded continuations and cache-relative bounded lengths for windowed calls.

One nonblocking hardening question remains at group_query_attention_impl.cu:698: the initial signed-int P+S expression can overflow for an extreme windowed absolute length (T=INT_MAX, Q=1, S=8), before that value is overwritten by cache-relative geometry. No observable failure was established. Consider calculating it only where consumed, with widened arithmetic and clamping before narrowing.

Integration and validation scope

The review found agreement on input 16's type/placement, unsupported-provider rejection, trailing-input preservation in both fusions, and windowed-cache alias/staging admission. The absolute RoPE versus cache-relative causal-mask coordinates are consistent in the reviewed stack.

This was a five-role static review. No local build, CUDA execution, memcheck, performance/concurrency qualification, or exhaustive Flash/MEA-internal proof was performed. The observed CI snapshot was 99 successful and 1 neutral check; CI and author-reported tests are not independent local reproduction. No Major/Critical finding was overruled.

@tianleiwu

Copy link
Copy Markdown
Contributor Author

Ti-Tai Wang (@titaiwangms) Addressed the feedback from your review summary in 21ff2d096a:

  • Focused JSEP coverage: Added and wired three browser unit tests exercising actual JSEP session construction with CPU fallback disabled. A present input 16 fails with the intended JS-specific error; an omitted input and an explicit empty optional slot are accepted. The suite is loaded only for JSEP builds. All three tests passed on software WebGPU using this PR head’s CI-built JSEP WASM from Web CI run 41390541574; the production JSEP guard is unchanged.
  • Availability probe: has_sdpa_kernel now probes the ordinary S=T=8, C=9 control. The T<S regression continues to assert its own dispatch, so it cannot hide a boundary regression by skipping on that case.
  • Quantized reference: The schema, generated ContribOperators documentation, and CUDA GQA notes now specify that the unpadded reference retains query_seqlens and the same scalar bound. They also document float versus quantized first-chunk reads and the legacy tight-bound singleton precision rule.
  • Length comment and hardening: Updated padded_seq_lens and past_seq_lens comments. Absolute P+S is now computed only for non-windowed calls, using widened arithmetic and clamping before narrowing. Added a windowed INT_MAX absolute-length regression checking both valid-row attention and the resident cache layout.

Local validation: CUDA 13.0 build with FlashAttention enabled; 43 focused Python tests passed, 6 non-CUDA variants skipped; 6 existing query_seqlens C++ tests passed; 3 actual JSEP browser tests passed; TypeScript, lint, and whitespace checks passed.

@titaiwangms Ti-Tai Wang (titaiwangms) 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.

Follow-up review of 823a83b -> 21ff2d0, building on the prior five-role full static review.

The blocking JSEP coverage gap is resolved: the new browser suite constructs actual sessions with CPU fallback disabled, tests present/omitted/empty input 16, asserts the JS-specific rejection error, and is wired only into JSEP builds. The production rejection guard is unchanged.

The remaining feedback is also addressed:

  • The SDPA availability probe now uses S=T=8 rather than the T<S regression case.
  • The schema/generated documentation and CUDA notes explicitly retain query_seqlens and the same scalar bound in the unpadded reference.
  • The singleton replay threshold correctly distinguishes the legacy tight-bound first prompt from capacity-bound quantized decode; the new tests cover packed/unpacked and windowed cases.
  • The length comments are updated. Absolute P+S is calculated only on the nonwindowed path, in int64_t, with capacity clamping before narrowing for explicit-length calls. The new INT_MAX windowed regression checks valid-row attention and resident cache layout.

No remaining code-review blocker was established in this follow-up. Approving the reviewed head.

Scope and validation limitations: this follow-up was direct static inspection of the complete revision delta and controlling code, not another five-role review or a local build/test run. The author's reported CUDA, C++, JSEP browser and lint results were not independently reproduced.

CI on this new head is not yet an all-green validation snapshot: the current PR check listing contains license/cla SUCCESS and Linux Android Emulator QNN CI Pipeline ACTION_REQUIRED. This approval does not waive required CI or authorize merging before required checks are satisfied.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tianleiwu
Tianlei Wu (tianleiwu) merged commit 734eea3 into main Nov 3, 2026
@tianleiwu
Tianlei Wu (tianleiwu) deleted the tlwu/qga_right_padded_prefill_chunk_slide_window branch November 3, 2026 01:39
Tianlei Wu (tianleiwu) added a commit that referenced this pull request Nov 3, 2026
)

### Description
<!-- Describe your changes. -->

Implement the optional `query_seqlens` input (index 16) of
`com.microsoft::GroupQueryAttention` in the CPU
execution provider. The input carries the number of valid, non-padded
rows of a right-padded query/key/value
chunk per batch entry, so fixed-shape chunked prefill works on CPU with
a full-length or a windowed KV cache
(`sliding_window_cache=1`), with float, fp16 and int8-quantized KV, on
both the MLAS flash and the unfused paths.

This PR is stacked on #33503, which adds the input to the schema, the
shared validation and the CUDA
implementation, and makes the CPU provider reject the input until this
PR lands. The input's semantics are
specified there and are only summarized below. This revision supersedes
the earlier one of this PR, which inferred
the valid length of a chunk from `total_sequence_length`
(`ResolveGQAStepLengths`). That heuristic is removed.

**Stack:** the base of this PR is the branch of #33503, so "Files
changed" shows only the CPU changes. Once #33503
merges, this PR is retargeted to `main` and rebased onto it. ORT's
build, test and CodeQL workflows run only for pull
requests that target `main` or `rel-*` (the lint workflow runs for any
base), so this PR gets them after that
retarget. The local results below were produced on the combined branch.

#### CPU behavior

For batch entry `b`: `S` is the padded `sequence_length`, `T =
seqlens_k[b] + 1`, `Q = query_seqlens[b]` and
`P = T - Q`.

- Only the `Q` valid rows are appended to the cache, for full-length and
windowed caches alike. Query row `s` sits
at absolute position `P + s` for causal masking, `local_window_size` and
the implicit rotary positions. The
padded rows of the implicit rotary positions get position 0, which is
always a valid rotary-cache index.
- Every contract violation is rejected with `INVALID_ARGUMENT` (CUDA
clamps device-side values instead): a shape
other than `(batch_size)`, `Q` outside `[1, min(S, T)]`, `T >
total_sequence_length`, a missing past, key/value
that are not a full chunk of `S` rows (including the shared-KV case
`kv_sequence_length == 0`), `S > 1` with
`batch_size > 1`, `P` above the sequence dimension of `past_key` (a
cache may grow between steps, so the past
buffers can be shorter than the present buffers), `P + S > C` for a
cache that is not windowed (`C` is the
sequence dimension of `present_key`), `causal=0`, and missing
`present_key`/`present_value` outputs. The outputs
are required for every step, also for `S == 1`, because the contract of
the input does not depend on the chunk
  length.
- `S == 1` treats the input as absent (it is still validated), so a
model can feed it at every step.
- With the input, an explicit `position_ids` is honored for every row,
also on the first chunk, as on any later
chunk. Without it, a first prompt reads only `position_ids[0]`. The
entries of padded rows must still be valid
  rotary-cache indices.
- A windowed cache accepts `C >= local_window_size` and `attention_bias`
together with padded chunks. CUDA is
  limited to `C == local_window_size` and no `attention_bias`.
- `output_qk`, when requested, keeps its shape `(batch_size, num_heads,
S, total_sequence_length)`. The columns
`[T, total_sequence_length)` of a batch entry are zero. They used to
hold uninitialized scratch memory, which
already happened for ragged batches without the new input, because the
kernel never writes them.
- Without the input the behavior is unchanged except for the `output_qk`
columns above: the helper below falls back
to the previous per-batch logic, and the one changed constant (the
padded-row rotary position) is unreachable then.

#### Key changes

- **`gqa_attention_base.h`**: the per-batch lengths of a step (total,
past rows to copy, causal past, new rows to
append) were open-coded at 8 sites. They now come from
`ResolveBatchStepLengths`, which takes an optional
per-batch past length and reproduces the previous logic when none is
given. `ConcatStateChunkGQA` and its
quantized variant append `valid_new_rows` instead of
`kv_sequence_length`, so padded rows never overwrite valid
entries or run past the capacity. The flash paths take their past length
per batch entry. `WriteOutputQKHeadChunk`
copies only the columns the kernel wrote and zero-fills the rest of the
`output_qk` row.
- **`group_query_attention.cc`**: reads input 16 and performs the checks
above. `PlanWindowedKvCache` sizes
eviction and the staging cache with `Q` instead of `S`, and also returns
the kept past length per entry, which is
passed down as `attention_past_seqlens`. The default rotary positions
use `Q`.
- **`group_query_attention_helper.h`**: the earlier
`ResolveGQAStepLengths` is removed. The file is identical to the
  #33503 branch, which holds the validation shared by CPU and CUDA.
- **Schema and docs**: input 16 is documented as honored by the CPU and
CUDA providers (other providers must reject
the node). `docs/ContribOperators.md` is regenerated and the
"Right-Padded Prefill Chunks" section of
`docs/contrib_ops/cpu/gqa.md` is rewritten for `query_seqlens`. Comments
in the MIGraphX, OpenVINO and JS
providers that said only CUDA implements the input now say CPU and CUDA.
- **Tests**:
- C++ (`group_query_attention_op_test.cc`):
`QuerySeqlensRightPaddedChunk_CPU` and
`QuerySeqlensRotaryRightPaddedChunkMatchesUnpadded_CPU` compare a padded
chunk with the same call on an
unpadded chunk (float and fp16, flash on and off, packed and unpacked
QKV, and the appended cache rows).
`WindowedCacheRightPaddedChunkMatchesUnpadded_CPU` does the same for a
windowed cache over many prefill and
valid lengths. Every rejection above has a negative test, including a
missing `present_key`/`present_value`
for `S == 1` and a growing cache whose past is longer than the bound
past buffers. A WebGPU-only test checks
that the WebGPU provider rejects a node with the input. It is compiled
only with `USE_WEBGPU`, which my build
    does not enable.
- Python (`TestGQAWindowedKvCacheCpu`, shared with the CUDA suite):
padded chunks run through `query_seqlens`
with a float and an int8 cache, flash and non-flash, `C == W` and `C ==
W + 8`, a capacity-valued
`total_sequence_length`, `head_sink`, `position_ids`, softcap and
`attention_bias`, and `S == 1` decode with the
input present. `TestQuerySeqlensQkOutputCpu` checks `output_qk` for a
padded chunk against the unpadded call,
    including the zeroed columns.

#### Testing

H200 host with a CUDA 13.0 Release build, so the gtest filter below also
runs the CUDA tests from #33503. The Python
classes below run on the CPU provider only. All results are from the
head of this branch.

- `onnxruntime_provider_test
--gtest_filter='*GroupQueryAttention*:*GQA*'`: **149 passed, 18 skipped,
0 failed**
(167 run). The skipped tests need an execution provider or hardware that
this build does not have.
- `test_gqa.py TestGQAWindowedKvCacheCpu`: **25 passed, 1 skipped** (the
CUDA-only cuDNN fallback test).
- `test_gqa.py TestQuerySeqlensQkOutputCpu` (`output_qk` of padded
chunks): **8 passed**.
- `test_gqa.py TestBorrowedKVCache` (cache inputs stay unchanged across
the refactored copy paths): **46 passed**.
- Mutation checks: four bugs were injected one at a time into a scratch
copy of the kernel (non-windowed past length
taken from `S` instead of `Q`, default rotary positions ignoring `Q`,
windowed planning ignoring `Q`, and padded
chunk handling disabled). Each is caught by both a C++ test and the
Python suite. The first round showed that no
C++ test covered the rotary one, which is why
`QuerySeqlensRotaryRightPaddedChunkMatchesUnpadded_CPU` exists. Two
more were checked for the later fixes: reverting the `output_qk`
zero-fill produces 24 failures, and limiting the
present-output requirement to `S > 1` fails exactly
`QuerySeqlensSingleTokenWithoutPresentOutputsRejected_CPU`.
- `lintrunner -m origin/main`: clean.
- The CUDA results, including the two unrelated failures that also fail
on a `main` build, are in #33503.

Notes for reviewers:

- `docs/ContribOperators.md` is refreshed the same way as in #33503,
with a script that mirrors `gen_contrib_doc.py`
because my local build is lite-protobuf. The full-protobuf CI docs check
is authoritative.
- The new WebGPU rejection test and the three comment edits in the
MIGraphX, OpenVINO and JS providers are not
  compiled locally, because those providers are not part of my build.
- Padded output rows are unspecified. A padded row that sees no key (a
local window combined with heavy padding) may
  hold NaN. The contract allows that, but no test exercises it.
- This PR gets only the lint workflow while it is stacked (see above).
Once #33503 merges, I will retarget it to
  `main` and rebase.

### Motivation and Context
<!-- - Why is this change required? What problem does it solve?
- If it fixes an open issue, please link to the issue here. -->

Static-shape (compiled or graph-captured) prefill uses a fixed query
chunk even when only a few rows are real
tokens, for example the last chunk of a prompt padded to `S = 512`. Then
`sequence_length` is the padded size while
`seqlens_k[b] = P + Q - 1` reflects the real length. On the CPU provider
this:

- rejected a subsequent step with `seqlens_k + 1 < sequence_length`,
- derived the past length and the number of rows to evict from the
padded length, which dropped valid cache rows,
- appended all `S` rows to the cache, which could overwrite valid
entries or write past the capacity when
  `C > local_window_size`, and
- anchored the default rotary positions and the causal mask at `T - S`
instead of `P`.

Inferring the valid length from `total_sequence_length` cannot work in
general, because existing callers pass the
cache capacity there. An explicit per-entry valid length removes the
ambiguity, needs no heuristic, and gives the
CPU and CUDA implementations the same contract.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Shoryamishra61 added a commit to Shoryamishra61/onnxruntime that referenced this pull request Nov 3, 2026
- Resolve conflicts against upstream main in group_query_attention.cc and group_query_attention_helper.h with query_seqlens (input 16) from microsoft#33503 / microsoft#33505.
- Preserve explicit CPU-only opt-in (allow_8_aligned_rotary = true) in CPU GQA.
- Maintain conservative legacy 16-aligned validation by default (allow_8_aligned_rotary = false) for CUDA GQA, WebGPU GQA, and PagedAttention (CUDA & WebGPU).
- Retain head_size / 2 bound to prevent integer truncation for head_size = 8.
Dante (KafKafrnZ) added a commit to KafKafrnZ/onnxruntime that referenced this pull request Nov 3, 2026
…cept MATH

- New CudaCudnnSdpaRejectedRaggedBidirectionalPromptMasksPerBatch: when the
  probe rejects cuDNN for a right-padded causal=0 first prompt, the kernel that
  runs instead must mask each batch at its valid KV length, as cuDNN does. The
  test runs the fallback with FlashAttention, memory-efficient attention and the
  unfused kernel and checks every valid output row against the per-batch mean.
  On the previous base the Flash fallback failed it (batch 0: 0.5078 instead of
  0.2578); main's microsoft#33503 fixed Flash and MEA, and all three pass now.
- CudaCudnnSdpaRejectedGraphFallsBack also accepts SdpaKernel=MATH, for builds
  or settings without Flash and memory-efficient attention.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tianlei Wu (tianleiwu) added a commit that referenced this pull request Nov 5, 2026
## Description

Support batched right-padded GQA chunks and populated idle entries
(`query_seqlens[b] = 0`) on CPU and CUDA, including single-token steps.
Skip padded preprocessing and attention work while preserving physical
tensor strides and the sliding-window history needed by the first valid
query in each chunk.

This follows #33503 and #33505, both already merged. Other execution
providers continue to reject `query_seqlens`; the legacy
multi-token/past-context batch restriction remains when the input is
absent.

## Summary of Changes

### Length semantics and correctness

- Accept `0 <= Q[b] <= min(S, T[b])` with `T[b] >= 1`. An idle entry
keeps its absolute total and cache unchanged. Initially empty idle
entries remain unsupported.
- Honor explicit lengths at `S = 1`, rather than treating every entry as
active.
- Fix CPU flash dispatch for equal resident totals but different past
lengths: the causal offset cannot be shared in that case.
- Preserve staging/eviction behavior: eviction must not discard the
preceding `W - 1` positions needed by the first token of a chunk.
- Clarify that `total_sequence_length` bounds absolute totals, not
windowed cache capacity.

### CPU

- Bound unpack/transpose, RoPE, FP16 conversion, naive QK/softmax/SV and
MLAS flash query work by the valid row count.
- Keep padded physical strides for head, batch, output and bias
addressing.
- Skip idle attention while preserving required past-cache copies for
separately allocated outputs.
- Cover FP32/FP16 inputs and INT8/INT4 caches; retain default MLAS
behavior when valid query counts are not supplied.

### CUDA

- Guard padding before Q/K/V loads, QK-Norm, RoPE, quantization and
cache append.
- Skip idle aliased-cache staging seed/copy-back and unused
ungroup/dequantization rows.
- Bound FlashAttention/MEA query tiles and output stores by device-side
valid lengths.
- Skip padded unfused softmax/output rows and use masked V scratch to
avoid `0 * NaN` contamination from unused cache rows. Include that
scratch in runtime and bounded workspace calculations.
- Bypass XQA, fast Flash decode and cuDNN SDPA with explicit query
lengths because those paths do not represent idle query entries. No host
synchronization is added to inspect query lengths.

**Remaining work:** unfused CUDA cuBLAS QK/SV GEMMs still use dense
physical query dimensions. Partially filled fused tiles retain
tile-granular arithmetic. Scratch allocations and upstream Q/K/V
projection nodes are not made ragged by this change.

### Regression coverage and documentation

- Replay prompts `[513, 1025]` with `S = W = 512`, CPU cache capacity
1023 and CUDA capacity 512:

  | Chunk | Valid queries | Absolute totals |
  |---|---|---|
  | 1 | `[512, 512]` | `[512, 512]` |
  | 2 | `[1, 512]` | `[513, 1024]` |
  | 3 | `[0, 1]` | `[513, 1025]` |

- Compare valid outputs and resident caches with independent unpadded
single-entry full-cache calls. Include all-idle chunks, idle decode,
resumed decode, mixed first/continuation entries, additional eviction,
and equal-total/different-past cases.
- Poison padded Q/K/V and unused floating-cache rows with NaNs. Prebind
sentinel outputs and verify padded rows are not written. The sentinel
check is an optimization regression, not a new public padding-output
guarantee.
- Exercise packed/unpacked inputs, RoPE, FP16/BF16 CUDA, FP32/FP16 CPU,
and INT8/INT4 caches.
- Assert native FlashAttention/MEA/math dispatch without CPU fallback,
exercise MEA large-head accumulation, and replay CUDA graphs while
changing device query lengths.
- Update operator schema, generated operator documentation and CPU/CUDA
guides.

## Testing

Validated locally on H200 with CUDA 13 using the existing incremental
build and feature-source overlays:

- Rebuilt Python runtime, CPU/MLAS, CUDA provider and provider-test
targets, including dependent FlashAttention/MEA translation units.
Verified compiled feature-source and staged-provider parity.
- GQA C++ suite: **123 passed, 14 skipped** (137 tests).
- Focused MEA/unfused workspace GTests: **23 passed**. Both changed
workspace test files compile; additional standalone layout/bounds checks
passed. The main build has CUDA EP internal tests disabled, so the
complete estimator/internal-test suite was not run.
- Targeted Python query-length/windowed suites: **112 passed, 2
skipped**, plus **148 passing subtests**.
- Final new optimization suite rerun: **36 passed**, plus **48 passing
subtests**, including all three CUDA-graph backends.
- Independent NumPy-oracle replay: **96 CPU calls and 156 CUDA calls
passed**; CUDA dispatch verified for FlashAttention, MEA, math and
automatic selection.
- All configured lintrunner checks and `git diff --check` passed.

The CPU output-sentinel test was also run before optimization and
reproduced padded output writes for both flash settings and both
cache-alias modes.

## Checklist

- [x] CPU and CUDA changes included
- [x] Regression tests added/updated
- [x] Existing no-input behavior and other-EP rejection retained
- [x] Documentation and backend limitations updated

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
yzhou51 (yzhou51) pushed a commit to yzhou51/openvino that referenced this pull request Nov 12, 2026
…chunks Support (openvinotoolkit#39495)

## Description

Implements the optional `query_seqlens` input (index 16) of
`com.microsoft.GroupQueryAttention`, added by ONNX Runtime in
microsoft/onnxruntime#33505 (CPU) on top of
microsoft/onnxruntime#33503 (schema, CUDA). The
input gives the number of valid rows of a right-padded query chunk, so
static-shape chunked prefill can pad its last chunk to the fixed chunk
length. Before this change the ONNX frontend rejected any
GroupQueryAttention node with 17 inputs.

With `S` the padded chunk length, `T = seqlens_k + 1` and `Q =
query_seqlens`, the past length becomes `P = T - Q` instead of `T - S`:
query row `s` sits at absolute position `P + s` for the causal mask, the
sliding window and the implicit rotary positions, and only the `Q` valid
rows are new tokens. Following
microsoft/onnxruntime#33832, batched chunks are
supported, the input is honored at `sequence_length == 1`, and `Q = 0`
marks an idle entry whose cache is unchanged. Models without the input
are unaffected.

ONNX Runtime references:
- **Spec:**
https://github.com/microsoft/onnxruntime/blob/main/docs/ContribOperators.md#com.microsoft.GroupQueryAttention
- **CPU kernel:**
https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/contrib_ops/cpu/bert/group_query_attention.cc
- **CPU attention / cache write:**
https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/contrib_ops/cpu/bert/gqa_attention_base.h
- **Input checks:**
https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/contrib_ops/cpu/bert/group_query_attention_helper.h

## Approach

- **Op:** `ov::op::internal::GroupQueryAttention` gets a `QUERY_SEQLENS`
input with `has_query_seqlens()`. Validation matches ONNX Runtime: rank
1 with `batch_size` elements, past required (a typed-empty rank-4
Constant counts as past layout, matching an empty Parameter),
`causal=1`, no shared KV, key/value length equal to the query's.
- **ONNX FE:** accepts 17 inputs and forwards `query_seqlens` only when
it is wired, so existing models keep a 16-input op and their IR is
unchanged.
- **Decomposition:** when `has_query_seqlens()`, `P = T - Q` (per batch
entry) drives the mask, the KV write offset and the implicit rotary
positions. The KV write keeps its static S-row shape at `[P, P + S)`:
the cache stays left-aligned with every valid row in `[0, T)`, and the
padded tail lands at or beyond `T`, where no valid query reads it and
the next step overwrites it (ONNX Runtime requires `P + S <= capacity`).
Writing only the `Q` valid rows would make the update shape
data-dependent, which static-shape devices cannot compile. The public
present buffer is separately sized to ONNX Runtime's `max(past_rows,
total_sequence_length)` capacity contract
(`group_query_attention_helper.h`), since `total_sequence_length` can
pre-allocate headroom past this step's write; attention itself still
runs over the tight `[P, P + S)` buffer. The windowed-cache staging path
writes back only the valid rows, so eviction follows `T`. An idle entry
(`Q = 0`, `P = T`) writes only at or beyond `T`, so its valid cache is
unchanged; an idle windowed decode takes the staging path for the same
reason. Padded K/V rows are zeroed with one `Select` each, since masking
alone lets NaN filler reach valid rows through the scores and `0 * V`
(ONNX Runtime CPU/CUDA never read them); single-token steps skip it, as
their padded entries are idle. Padded rotary rows are capped at
`seqlens_k` with one `Minimum`, which keeps them in range; their outputs
are unspecified, as in ONNX Runtime. Graphs without the input lower
exactly as before.
- **GPU:** `StatelessKV` gets `P + S` as its present length, so the S
rows land at `P` and SDPA's lower-right causal alignment gives row `s`
the keys `<= P + s`, with no extra mask or copy. A windowed cache with a
padded chunk uses the generic staging path, because `StatelessKV` evicts
by its present length; decode keeps the `StatelessKV` sliding-window
path.

## Scope

In scope: CPU (common decomposition) and GPU for full-length,
static-capacity and windowed caches, implicit and explicit rotary
positions, float and int8-quantized KV, single and batched graphs. Out
of scope: NPU compilers, which do not handle the input yet;
`StatelessKV` honoring `total_sequence_length` headroom beyond `P + S`
on GPU, and keeping a padded windowed chunk on the GPU `StatelessKV`
sliding-window path (both planned as a follow-up).

## Validation

- type_prop tests for the new input, batched and single-token
acceptance, and every rejection.
- ONNX FE tests with expected values from the ONNX Runtime CPU kernel:
static cache with rotary, growing cache (batched path), windowed cache,
single-token step with the input wired, explicit `position_ids`, int8
quantized cache, plus the
microsoft/onnxruntime#33832 cases: batched chunk
with an idle entry and NaN-poisoned padding, equal totals with different
pasts, idle single-token step, windowed idle and active single-token
steps. Padded output rows and cache rows at or beyond the valid length
are unspecified, so the models compare only the valid region. The GPU
run of the static-capacity cases is skipped because a static-capacity
present output consumed by a non-Result op fails at runtime on GPU,
which also happens without this change.
- A growing-cache regression evaluates the unsliced present output
directly against `total_sequence_length` (not `P + S`), checking both
the resulting shape and that the write window and unwritten past prefix
land correctly, matching the ONNX Runtime CPU/CUDA capacity contract
(`group_query_attention_helper.h`).
- A padded prefill chunk with 32 heads, 8 KV heads, head size 128, `S =
512`, `Q = 300` and `P = 1000` matches the ONNX Runtime CPU kernel on
CPU (output max abs diff 1.2e-6, present KV bit-exact) for a static and
a windowed cache, and its latency with the input matches the same chunk
without it.

### FYI
- microsoft/onnxruntime#33832 (merged after this
PR was opened) extended the `query_seqlens` contract on CPU/CUDA:
batched chunks, `Q = 0` idle entries and honoring the input at
`sequence_length == 1`. This PR follows that contract; expected values
come from the ONNX Runtime CPU kernel at that commit.

### Tickets:
 - CVS-199056

### AI Assistance:
 - AI assistance used: yes
 - AI helped analyze, implement, test the optimal changes
Franklin Moormann (ooples) pushed a commit to ooples/AiDotNet that referenced this pull request Nov 13, 2026
Updated
[Microsoft.AspNetCore.Mvc.Testing](https://github.com/dotnet/dotnet)
from 10.0.14 to 10.0.15.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.AspNetCore.Mvc.Testing's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [Microsoft.Data.Sqlite](https://github.com/dotnet/dotnet) from
10.0.14 to 10.0.15.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Data.Sqlite's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.ML.OnnxRuntime](https://github.com/Microsoft/onnxruntime)
from 1.31.1 to 1.32.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.ML.OnnxRuntime's
releases](https://github.com/Microsoft/onnxruntime/releases)._

## 1.32.0

ONNX Runtime 1.32.0 reintegrates ONNX 1.23.2 with opset 28 support,
introduces CPU/GPU hybrid MoE offloading and shared-layout CPU QMoE
kernels, expands device-memory, weightless-compilation, and Python
model-package APIs, dramatically accelerates session initialization on
large graphs, and strengthens runtime and optimizer reliability. These
notes cover changes since ONNX Runtime 1.31.1. CUDA and WebGPU kernel
updates are summarized here; detailed provider notes are covered by
their separate plugin EP releases.

## Highlights

- Reintegrated **ONNX 1.23.2** with **opset 28** operator support
(`SpaceToDepth`, `Mod`, signed `BitShift`, and `BFloat16` extensions)
and updated **DLPack to v1.3** across all implemented ORT numeric and
boolean tensor types
([#​33134](microsoft/onnxruntime#33134),
[#​32362](microsoft/onnxruntime#32362),
[#​33848](microsoft/onnxruntime#33848)).
- Added a session-scoped **CPU/GPU hybrid MoE offload** planner and
execution backend for quantized `QMoE` (NVFP4, INT4, INT3, and INT2) and
block-packed `MoEPacked` models, backed by shared-layout AVX-512/AVX2
CPU `QMoE` kernels and memory-mapped expert storage
([#​33450](microsoft/onnxruntime#33450),
[#​33451](microsoft/onnxruntime#33451),
[#​33452](microsoft/onnxruntime#33452),
[#​33973](microsoft/onnxruntime#33973)).
- Expanded core APIs with `OrtApi::EpDevice_GetMemoryCapacity`, explicit
multi-mode weightless compilation
(`ModelCompilationOptions_SetWeightlessMode` and
`ep.enable_weightless_mode`), Python bindings for the Model Package
APIs, and zero-copy CPU buffer borrowing in `AddExternalInitializers`
([#​33447](microsoft/onnxruntime#33447),
[#​32899](microsoft/onnxruntime#32899),
[#​33640](microsoft/onnxruntime#33640),
[#​33877](microsoft/onnxruntime#33877)).
- Eliminated superlinear bottlenecks in allocation planning, constant
sharing, graph I/O mapping, and topological sorting—reducing session
initialization on 100k-node constant-heavy graphs from minutes to
seconds—and added pipelined pinned-memory staging for external GPU
weight loading
([#​33407](microsoft/onnxruntime#33407),
[#​33939](microsoft/onnxruntime#33939),
[#​34009](microsoft/onnxruntime#34009),
[#​33839](microsoft/onnxruntime#33839)).
- Expanded shared generative AI and quantized contrib operators,
including Kimi Delta Attention (`GatedDeltaNet` per-key-dimension
decay), right-padded chunked prefill in `GroupQueryAttention`, native
GGUF/block-packed operators (`GatherPacked`, `MatMulPacked`,
`MoEPacked`), and sparse-attention index sharing
([#​33817](microsoft/onnxruntime#33817),
[#​33503](microsoft/onnxruntime#33503),
[#​33953](microsoft/onnxruntime#33953),
[#​33224](microsoft/onnxruntime#33224)).

## Announcements & Compatibility

- **CUDA Plugin EP v0.4.0** and **WebGPU Plugin EP v0.6.0** are matched
with ONNX Runtime 1.32.0
([#​33214](microsoft/onnxruntime#33214)). For
**contrib-op compatibility**, core and the plugin must use the same
contributed-operator schemas; building both from the **same ONNX Runtime
revision** is recommended. Schema mismatches can cause incorrect
execution or crashes and may not be detected during plugin registration.
- **ACL EP removed:** Following its deprecation in 1.31.0, the Arm
Compute Library (`ACLExecutionProvider`) execution provider, its build
options, and its standalone C registration API have been removed.
Python's `get_all_providers()` no longer lists `ACLExecutionProvider`;
applications should remove it from explicit provider lists
([#​33851](microsoft/onnxruntime#33851)).
- **Legacy provider-bridge `NvTensorRTRTXExecutionProvider` removed:**
In-tree provider-bridge `NvTensorRTRTXExecutionProvider` sources have
been removed in favor of the standalone NVIDIA TensorRT RTX plugin EP
registered via `OrtApi::RegisterExecutionProviderLibrary`.
`NvTensorRtRtxProviderOptions` is retained as a deprecated declaration
for source compatibility, and legacy `AppendExecutionProvider` calls now
report a deprecation error directing callers to the plugin EP
([#​32276](microsoft/onnxruntime#32276)).
- **ONNX 1.23.2 integration:** ONNX has been upgraded to **1.23.2**,
raising supported opset ceilings to **28** and restoring
`ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT6E2M3` and
`ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT6E3M2` public element-type mappings
and `Cast` conversions
([#​33134](microsoft/onnxruntime#33134)).
- **DLPack v1.3 boolean contract change:** DLPack has been upgraded to
**v1.3** with native `kDLBool` metadata and bidirectional support for
all implemented ORT numeric and boolean types, including all five
`float8` formats, packed `float4`, `int4`/`uint4`, and `int2`/`uint2`
(`float6` remains unsupported in DLPack). The low-level `is_bool_tensor`
override was removed, and `uint8` DLPack metadata now always imports as
`uint8`
([#​33848](microsoft/onnxruntime#33848)).
- **Weightless compilation API migration:**
`OrtCompileApi::ModelCompilationOptions_SetWeightlessEnabled` and the
`ep.enable_weightless` / `ep.enable_weightless_ep_context_nodes` session
options are deprecated in favor of
`ModelCompilationOptions_SetWeightlessMode` and
`ep.enable_weightless_mode` (`"0"` = `NONE`, `"1"` = `EXTERNAL_ONLY`,
`"2"` = `ALL`). EPs can now advertise multi-mode capability via
`OrtWeightlessSupport_ALL_OR_EXTERNAL_ONLY` and
`weightless_supported_modes`
([#​32899](microsoft/onnxruntime#32899)).
- **Training CI retirement:** Training build and test lanes were retired
from active GitHub Actions CI workflows while retaining inference build
coverage
([#​33836](microsoft/onnxruntime#33836)).
- This is the last release for [CocoaPods](https://cocoapods.org/), and
we will switch to [Swift Package
Manager](https://docs.swift.org/latest/documentation/packagemanagerdocs/).
- We will use combo onnxruntime-gpu python package to reduce storage
size from next release. You can test it
[here](https://aiinfra.visualstudio.com/PublicPackages/_artifacts/feed/ORT-Nightly/PyPI/onnxruntime-gpu/overview)

## New Features

### Core APIs & Runtime

- Added `OrtApi::EpDevice_GetMemoryCapacity` (C++
`EpDevice::GetMemoryCapacity()`) and
`OrtEpFactory::GetDeviceMemoryCapacity` to query device-global total
memory and estimated currently available memory (`DEFAULT` or
`HOST_ACCESSIBLE`), with built-in and plugin CUDA EP support
([#​33447](microsoft/onnxruntime#33447)).
- Expanded the app–EP weightless contract so EPs advertise all supported
weightless modes (`weightless_supported_modes`), applications request an
explicit mode (`ModelCompilationOptions_SetWeightlessMode` /
`ep.enable_weightless_mode`), and compiled EPContext models record
`weightless_mode` and `external_dependencies` (`source_model`,
`external_weights`, `ep_context_binary`) in model metadata
([#​32899](microsoft/onnxruntime#32899)).
- Extended `session.use_external_initializer_file_buffers_directly="1"`
to `AddExternalInitializers` for zero-copy borrowing of naturally
aligned CPU buffers larger than 127 bytes on little-endian hosts, and
documented the read-only guarantee for external initializers added via
`OrtModelEditorApi::AddInitializerToGraph` with `data_is_external=true`
([#​33877](microsoft/onnxruntime#33877),
[#​33717](microsoft/onnxruntime#33717)).
- Added lock-free multi-worker pinned-memory staging
(`session.external_data_loader.*`) to accelerate external initializer
loading into GPU memory across built-in and plugin CUDA EPs
([#​33839](microsoft/onnxruntime#33839)).
- Added a session-scoped MoE/QMoE CPU/GPU offload planner and
memory-budget ledger (`session.moe.offload.*`), generic
`session.kernel_dispatch_policy` (`auto`, `latency`, `memory`, `safe`)
configuration plumbing, Level-1 workspace/prepack memory accounting
fallback for nodes absent from memory-profile CSVs, and internal
capability-planning protocol types
([#​33451](microsoft/onnxruntime#33451),
[#​33042](microsoft/onnxruntime#33042),
[#​33311](microsoft/onnxruntime#33311),
[#​33841](microsoft/onnxruntime#33841)).
- Enabled cross-thread reuse of idle device streams when graph capture
is disabled and providers register device-selection callbacks, and
enabled compile-session profiling (`<profile_file>_compile`) in
`onnxruntime_perf_test` when `-p` is used with `--compile_ep_context`
([#​33053](microsoft/onnxruntime#33053),
[#​33694](microsoft/onnxruntime#33694)).
- Made `onnxruntime_DISABLE_EXCEPTIONS` (`--disable_exceptions`) usable
without `onnxruntime_MINIMAL_BUILD` and added the
`onnxruntime_DISABLE_STREAM=ON` CMake option to disable device-stream
support in non-minimal builds
([#​33120](microsoft/onnxruntime#33120),
[#​33482](microsoft/onnxruntime#33482)).

### ONNX Opset 28 & Shared Contrib Operators

These updates affect core ONNX and contributed operator schemas and
cross-provider behavior, not only the separately released GPU plugins.

- Added ONNX opset 28 operator support: native `SpaceToDepth` (`DCR` and
`CRD`) on CPU and CUDA with version-split registrations across DML, JS,
WebGPU, and QNN; opset-28 floating floor-modulus `Mod` on CPU, CUDA, and
DML; opset-28 `BFloat16` support for `Compress`, `OneHot`,
`ReverseSequence`, `Unique`, `Celu`, and `Einsum` on CPU (plus
`Compress`, `OneHot`, and `ReverseSequence` on CUDA); and `BFloat16`
`Pad` (opsets 21–25) on CPU and CUDA
([#​32362](microsoft/onnxruntime#32362),
[#​32369](microsoft/onnxruntime#32369),
[#​32378](microsoft/onnxruntime#32378),
[#​34062](microsoft/onnxruntime#34062)).
- Extended `GatedDeltaNet` with Kimi Delta Attention (KDA)
per-key-dimension decay across CPU, CUDA, and WebGPU, and extended
`GatedDeltaNet` and `CausalConvWithState` state/gate handling for
multi-token speculative decoding
([#​33817](microsoft/onnxruntime#33817),
[#​33471](microsoft/onnxruntime#33471)).
- Added an optional `query_seqlens` input to `GroupQueryAttention` to
skip right-padded prefill tokens and idle batch entries
(`query_seqlens[b] = 0`) on CPU and CUDA, and added `q_norm_epsilon` /
`k_norm_epsilon` attributes to preserve distinct Q and K normalization
epsilons during GQA pre-norm fusion
([#​33503](microsoft/onnxruntime#33503),
[#​33505](microsoft/onnxruntime#33505),
[#​33832](microsoft/onnxruntime#33832),
[#​33363](microsoft/onnxruntime#33363)).
- Defined the INT3 `QMoE` v1 packed-code contract, added opt-in
post-SiLU clipping (`swiglu_limit_after_activation`) and tanh-`GEGLU`
(`activation_type="geglu"`) support to MoE/QMoE schemas, and added
`GatherPacked` (CPU/CUDA), `MatMulPacked` (CUDA, including native Bolt
`global_scale`), and `MoEPacked` (CUDA) to consume native
GGUF/block-packed quantized weights directly
([#​33394](microsoft/onnxruntime#33394),
[#​33954](microsoft/onnxruntime#33954),
[#​33633](microsoft/onnxruntime#33633),
[#​33953](microsoft/onnxruntime#33953),
[#​33962](microsoft/onnxruntime#33962)).
- Added `PackedSparseAttentionIndexerMerge` for multi-token prediction
index sharing and optional `state_status` / mid-state outputs on
`PackedSparseAttentionIndexer` across CUDA and WebGPU; extended
`GatedAdd` with an optional projected `gate_weight` across CPU, CUDA,
and WebGPU; and supported empty unpacked weights in CPU and WebGPU
`MatMulNBits`
([#​33224](microsoft/onnxruntime#33224),
[#​33383](microsoft/onnxruntime#33383),
[#​33472](microsoft/onnxruntime#33472),
[#​33470](microsoft/onnxruntime#33470),
[#​33559](microsoft/onnxruntime#33559)).
- Registered core contrib schemas for provider-targeted LLM and
speculative-decoding operators, including `SwiGLU`, `RMSNormRotary`,
`HyperConnectionLowRankMix`, `RouterGateUpProj`,
`SpeculativePrefixCommit`, `GatedDeltaNetStateReplay`,
`ConvStateReplay`, and `MatMulNBitsQLoRA`
([#​32126](microsoft/onnxruntime#32126),
[#​33469](microsoft/onnxruntime#33469),
[#​33384](microsoft/onnxruntime#33384),
[#​33650](microsoft/onnxruntime#33650),
[#​33474](microsoft/onnxruntime#33474),
[#​33213](microsoft/onnxruntime#33213),
[#​33493](microsoft/onnxruntime#33493),
[#​33370](microsoft/onnxruntime#33370)).

### Plugin Execution Provider Infrastructure

- Fixed an `OrtMemoryInfo` ABI mismatch across the ORT/plugin EP
boundary by converting `OrtMemoryInfo` instances exclusively through the
C API ([#​33571](microsoft/onnxruntime#33571)).
- Zero-initialized `OrtEpFactory` structs in provider-bridge EP
factories so unimplemented optional callbacks are null, and prevented
double DLL initialization and handle leaks when probing and registering
plugin EP libraries
([#​33117](microsoft/onnxruntime#33117),
[#​33701](microsoft/onnxruntime#33701)).
- Hardened portable model-package EP recreation, custom-domain
preservation, UTF-8 path handling, and `shared_assets` path confinement
and symlink validation
([#​32790](microsoft/onnxruntime#32790),
[#​33826](microsoft/onnxruntime#33826)).
 ... (truncated)

Commits viewable in [compare
view](microsoft/onnxruntime@v1.31.1...v1.32.0).
</details>

Updated
[Microsoft.ML.OnnxRuntime.Managed](https://github.com/microsoft/onnxruntime)
from 1.31.1 to 1.32.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.ML.OnnxRuntime.Managed's
releases](https://github.com/microsoft/onnxruntime/releases)._

## 1.32.0

ONNX Runtime 1.32.0 reintegrates ONNX 1.23.2 with opset 28 support,
introduces CPU/GPU hybrid MoE offloading and shared-layout CPU QMoE
kernels, expands device-memory, weightless-compilation, and Python
model-package APIs, dramatically accelerates session initialization on
large graphs, and strengthens runtime and optimizer reliability. These
notes cover changes since ONNX Runtime 1.31.1. CUDA and WebGPU kernel
updates are summarized here; detailed provider notes are covered by
their separate plugin EP releases.

## Highlights

- Reintegrated **ONNX 1.23.2** with **opset 28** operator support
(`SpaceToDepth`, `Mod`, signed `BitShift`, and `BFloat16` extensions)
and updated **DLPack to v1.3** across all implemented ORT numeric and
boolean tensor types
([#​33134](microsoft/onnxruntime#33134),
[#​32362](microsoft/onnxruntime#32362),
[#​33848](microsoft/onnxruntime#33848)).
- Added a session-scoped **CPU/GPU hybrid MoE offload** planner and
execution backend for quantized `QMoE` (NVFP4, INT4, INT3, and INT2) and
block-packed `MoEPacked` models, backed by shared-layout AVX-512/AVX2
CPU `QMoE` kernels and memory-mapped expert storage
([#​33450](microsoft/onnxruntime#33450),
[#​33451](microsoft/onnxruntime#33451),
[#​33452](microsoft/onnxruntime#33452),
[#​33973](microsoft/onnxruntime#33973)).
- Expanded core APIs with `OrtApi::EpDevice_GetMemoryCapacity`, explicit
multi-mode weightless compilation
(`ModelCompilationOptions_SetWeightlessMode` and
`ep.enable_weightless_mode`), Python bindings for the Model Package
APIs, and zero-copy CPU buffer borrowing in `AddExternalInitializers`
([#​33447](microsoft/onnxruntime#33447),
[#​32899](microsoft/onnxruntime#32899),
[#​33640](microsoft/onnxruntime#33640),
[#​33877](microsoft/onnxruntime#33877)).
- Eliminated superlinear bottlenecks in allocation planning, constant
sharing, graph I/O mapping, and topological sorting—reducing session
initialization on 100k-node constant-heavy graphs from minutes to
seconds—and added pipelined pinned-memory staging for external GPU
weight loading
([#​33407](microsoft/onnxruntime#33407),
[#​33939](microsoft/onnxruntime#33939),
[#​34009](microsoft/onnxruntime#34009),
[#​33839](microsoft/onnxruntime#33839)).
- Expanded shared generative AI and quantized contrib operators,
including Kimi Delta Attention (`GatedDeltaNet` per-key-dimension
decay), right-padded chunked prefill in `GroupQueryAttention`, native
GGUF/block-packed operators (`GatherPacked`, `MatMulPacked`,
`MoEPacked`), and sparse-attention index sharing
([#​33817](microsoft/onnxruntime#33817),
[#​33503](microsoft/onnxruntime#33503),
[#​33953](microsoft/onnxruntime#33953),
[#​33224](microsoft/onnxruntime#33224)).

## Announcements & Compatibility

- **CUDA Plugin EP v0.4.0** and **WebGPU Plugin EP v0.6.0** are matched
with ONNX Runtime 1.32.0
([#​33214](microsoft/onnxruntime#33214)). For
**contrib-op compatibility**, core and the plugin must use the same
contributed-operator schemas; building both from the **same ONNX Runtime
revision** is recommended. Schema mismatches can cause incorrect
execution or crashes and may not be detected during plugin registration.
- **ACL EP removed:** Following its deprecation in 1.31.0, the Arm
Compute Library (`ACLExecutionProvider`) execution provider, its build
options, and its standalone C registration API have been removed.
Python's `get_all_providers()` no longer lists `ACLExecutionProvider`;
applications should remove it from explicit provider lists
([#​33851](microsoft/onnxruntime#33851)).
- **Legacy provider-bridge `NvTensorRTRTXExecutionProvider` removed:**
In-tree provider-bridge `NvTensorRTRTXExecutionProvider` sources have
been removed in favor of the standalone NVIDIA TensorRT RTX plugin EP
registered via `OrtApi::RegisterExecutionProviderLibrary`.
`NvTensorRtRtxProviderOptions` is retained as a deprecated declaration
for source compatibility, and legacy `AppendExecutionProvider` calls now
report a deprecation error directing callers to the plugin EP
([#​32276](microsoft/onnxruntime#32276)).
- **ONNX 1.23.2 integration:** ONNX has been upgraded to **1.23.2**,
raising supported opset ceilings to **28** and restoring
`ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT6E2M3` and
`ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT6E3M2` public element-type mappings
and `Cast` conversions
([#​33134](microsoft/onnxruntime#33134)).
- **DLPack v1.3 boolean contract change:** DLPack has been upgraded to
**v1.3** with native `kDLBool` metadata and bidirectional support for
all implemented ORT numeric and boolean types, including all five
`float8` formats, packed `float4`, `int4`/`uint4`, and `int2`/`uint2`
(`float6` remains unsupported in DLPack). The low-level `is_bool_tensor`
override was removed, and `uint8` DLPack metadata now always imports as
`uint8`
([#​33848](microsoft/onnxruntime#33848)).
- **Weightless compilation API migration:**
`OrtCompileApi::ModelCompilationOptions_SetWeightlessEnabled` and the
`ep.enable_weightless` / `ep.enable_weightless_ep_context_nodes` session
options are deprecated in favor of
`ModelCompilationOptions_SetWeightlessMode` and
`ep.enable_weightless_mode` (`"0"` = `NONE`, `"1"` = `EXTERNAL_ONLY`,
`"2"` = `ALL`). EPs can now advertise multi-mode capability via
`OrtWeightlessSupport_ALL_OR_EXTERNAL_ONLY` and
`weightless_supported_modes`
([#​32899](microsoft/onnxruntime#32899)).
- **Training CI retirement:** Training build and test lanes were retired
from active GitHub Actions CI workflows while retaining inference build
coverage
([#​33836](microsoft/onnxruntime#33836)).
- This is the last release for [CocoaPods](https://cocoapods.org/), and
we will switch to [Swift Package
Manager](https://docs.swift.org/latest/documentation/packagemanagerdocs/).
- We will use combo onnxruntime-gpu python package to reduce storage
size from next release. You can test it
[here](https://aiinfra.visualstudio.com/PublicPackages/_artifacts/feed/ORT-Nightly/PyPI/onnxruntime-gpu/overview)

## New Features

### Core APIs & Runtime

- Added `OrtApi::EpDevice_GetMemoryCapacity` (C++
`EpDevice::GetMemoryCapacity()`) and
`OrtEpFactory::GetDeviceMemoryCapacity` to query device-global total
memory and estimated currently available memory (`DEFAULT` or
`HOST_ACCESSIBLE`), with built-in and plugin CUDA EP support
([#​33447](microsoft/onnxruntime#33447)).
- Expanded the app–EP weightless contract so EPs advertise all supported
weightless modes (`weightless_supported_modes`), applications request an
explicit mode (`ModelCompilationOptions_SetWeightlessMode` /
`ep.enable_weightless_mode`), and compiled EPContext models record
`weightless_mode` and `external_dependencies` (`source_model`,
`external_weights`, `ep_context_binary`) in model metadata
([#​32899](microsoft/onnxruntime#32899)).
- Extended `session.use_external_initializer_file_buffers_directly="1"`
to `AddExternalInitializers` for zero-copy borrowing of naturally
aligned CPU buffers larger than 127 bytes on little-endian hosts, and
documented the read-only guarantee for external initializers added via
`OrtModelEditorApi::AddInitializerToGraph` with `data_is_external=true`
([#​33877](microsoft/onnxruntime#33877),
[#​33717](microsoft/onnxruntime#33717)).
- Added lock-free multi-worker pinned-memory staging
(`session.external_data_loader.*`) to accelerate external initializer
loading into GPU memory across built-in and plugin CUDA EPs
([#​33839](microsoft/onnxruntime#33839)).
- Added a session-scoped MoE/QMoE CPU/GPU offload planner and
memory-budget ledger (`session.moe.offload.*`), generic
`session.kernel_dispatch_policy` (`auto`, `latency`, `memory`, `safe`)
configuration plumbing, Level-1 workspace/prepack memory accounting
fallback for nodes absent from memory-profile CSVs, and internal
capability-planning protocol types
([#​33451](microsoft/onnxruntime#33451),
[#​33042](microsoft/onnxruntime#33042),
[#​33311](microsoft/onnxruntime#33311),
[#​33841](microsoft/onnxruntime#33841)).
- Enabled cross-thread reuse of idle device streams when graph capture
is disabled and providers register device-selection callbacks, and
enabled compile-session profiling (`<profile_file>_compile`) in
`onnxruntime_perf_test` when `-p` is used with `--compile_ep_context`
([#​33053](microsoft/onnxruntime#33053),
[#​33694](microsoft/onnxruntime#33694)).
- Made `onnxruntime_DISABLE_EXCEPTIONS` (`--disable_exceptions`) usable
without `onnxruntime_MINIMAL_BUILD` and added the
`onnxruntime_DISABLE_STREAM=ON` CMake option to disable device-stream
support in non-minimal builds
([#​33120](microsoft/onnxruntime#33120),
[#​33482](microsoft/onnxruntime#33482)).

### ONNX Opset 28 & Shared Contrib Operators

These updates affect core ONNX and contributed operator schemas and
cross-provider behavior, not only the separately released GPU plugins.

- Added ONNX opset 28 operator support: native `SpaceToDepth` (`DCR` and
`CRD`) on CPU and CUDA with version-split registrations across DML, JS,
WebGPU, and QNN; opset-28 floating floor-modulus `Mod` on CPU, CUDA, and
DML; opset-28 `BFloat16` support for `Compress`, `OneHot`,
`ReverseSequence`, `Unique`, `Celu`, and `Einsum` on CPU (plus
`Compress`, `OneHot`, and `ReverseSequence` on CUDA); and `BFloat16`
`Pad` (opsets 21–25) on CPU and CUDA
([#​32362](microsoft/onnxruntime#32362),
[#​32369](microsoft/onnxruntime#32369),
[#​32378](microsoft/onnxruntime#32378),
[#​34062](microsoft/onnxruntime#34062)).
- Extended `GatedDeltaNet` with Kimi Delta Attention (KDA)
per-key-dimension decay across CPU, CUDA, and WebGPU, and extended
`GatedDeltaNet` and `CausalConvWithState` state/gate handling for
multi-token speculative decoding
([#​33817](microsoft/onnxruntime#33817),
[#​33471](microsoft/onnxruntime#33471)).
- Added an optional `query_seqlens` input to `GroupQueryAttention` to
skip right-padded prefill tokens and idle batch entries
(`query_seqlens[b] = 0`) on CPU and CUDA, and added `q_norm_epsilon` /
`k_norm_epsilon` attributes to preserve distinct Q and K normalization
epsilons during GQA pre-norm fusion
([#​33503](microsoft/onnxruntime#33503),
[#​33505](microsoft/onnxruntime#33505),
[#​33832](microsoft/onnxruntime#33832),
[#​33363](microsoft/onnxruntime#33363)).
- Defined the INT3 `QMoE` v1 packed-code contract, added opt-in
post-SiLU clipping (`swiglu_limit_after_activation`) and tanh-`GEGLU`
(`activation_type="geglu"`) support to MoE/QMoE schemas, and added
`GatherPacked` (CPU/CUDA), `MatMulPacked` (CUDA, including native Bolt
`global_scale`), and `MoEPacked` (CUDA) to consume native
GGUF/block-packed quantized weights directly
([#​33394](microsoft/onnxruntime#33394),
[#​33954](microsoft/onnxruntime#33954),
[#​33633](microsoft/onnxruntime#33633),
[#​33953](microsoft/onnxruntime#33953),
[#​33962](microsoft/onnxruntime#33962)).
- Added `PackedSparseAttentionIndexerMerge` for multi-token prediction
index sharing and optional `state_status` / mid-state outputs on
`PackedSparseAttentionIndexer` across CUDA and WebGPU; extended
`GatedAdd` with an optional projected `gate_weight` across CPU, CUDA,
and WebGPU; and supported empty unpacked weights in CPU and WebGPU
`MatMulNBits`
([#​33224](microsoft/onnxruntime#33224),
[#​33383](microsoft/onnxruntime#33383),
[#​33472](microsoft/onnxruntime#33472),
[#​33470](microsoft/onnxruntime#33470),
[#​33559](microsoft/onnxruntime#33559)).
- Registered core contrib schemas for provider-targeted LLM and
speculative-decoding operators, including `SwiGLU`, `RMSNormRotary`,
`HyperConnectionLowRankMix`, `RouterGateUpProj`,
`SpeculativePrefixCommit`, `GatedDeltaNetStateReplay`,
`ConvStateReplay`, and `MatMulNBitsQLoRA`
([#​32126](microsoft/onnxruntime#32126),
[#​33469](microsoft/onnxruntime#33469),
[#​33384](microsoft/onnxruntime#33384),
[#​33650](microsoft/onnxruntime#33650),
[#​33474](microsoft/onnxruntime#33474),
[#​33213](microsoft/onnxruntime#33213),
[#​33493](microsoft/onnxruntime#33493),
[#​33370](microsoft/onnxruntime#33370)).

### Plugin Execution Provider Infrastructure

- Fixed an `OrtMemoryInfo` ABI mismatch across the ORT/plugin EP
boundary by converting `OrtMemoryInfo` instances exclusively through the
C API ([#​33571](microsoft/onnxruntime#33571)).
- Zero-initialized `OrtEpFactory` structs in provider-bridge EP
factories so unimplemented optional callbacks are null, and prevented
double DLL initialization and handle leaks when probing and registering
plugin EP libraries
([#​33117](microsoft/onnxruntime#33117),
[#​33701](microsoft/onnxruntime#33701)).
- Hardened portable model-package EP recreation, custom-domain
preservation, UTF-8 path handling, and `shared_assets` path confinement
and symlink validation
([#​32790](microsoft/onnxruntime#32790),
[#​33826](microsoft/onnxruntime#33826)).
 ... (truncated)

Commits viewable in [compare
view](microsoft/onnxruntime@v1.31.1...v1.32.0).
</details>

Updated [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest)
from 18.11.0 to 18.12.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.NET.Test.Sdk's
releases](https://github.com/microsoft/vstest/releases)._

## 18.12.0

## Security fix

This release includes the fix for CVE-2026-105544, an elevation of
privilege vulnerability in the VSTest artifact post-processor. The
post-processor could consume a forged `executionComplete.json` written
by another local user, and then run attacker-controlled output handling.

Affected: `Microsoft.TestPlatform.CLI` 18.11.0 and earlier. Every
version from 18.11.1 on is fixed, including 18.12.0.

`Microsoft.TestPlatform.CLI` is the VSTest build that we ship into the
.NET SDK. The recommended way to get this fix is to update your .NET SDK
to the latest patched version, see the advisory for the SDK versions.

The fix is also released in the `Microsoft.TestPlatform.CLI` package,
for completeness. That package is rarely used directly. It is not a
dependency of `Microsoft.NET.Test.Sdk` or `Microsoft.TestPlatform`, so
those packages do not bring it in.

Details: microsoft/vstest#16654 and
dotnet/announcements#517

Using custom Docker images or Nano Server? See
microsoft/vstest#16652

## What's Changed
* Fix TestCaseStart/Stop events dropped for data-driven tests with
shared TestCase.Id by @​nohwnd in
microsoft/vstest#16033
* Stop the discovery manager factory from shadowing discoveryCriteria by
@​nohwnd in microsoft/vstest#16391
* Gate the HTTP link checker on a fingerprint of the broken links by
@​nohwnd in microsoft/vstest#16413
* Quote boolean conditions in shipped Microsoft.TestPlatform.targets by
@​nohwnd in microsoft/vstest#16404
* Obsolete API hygiene: the compatibility-safe changes by @​azat-msft in
microsoft/vstest#16420
* Add xxHash128 test ids, available but not default by @​azat-msft in
microsoft/vstest#16378
* Isolate attachment manager test temporary files by @​mmitche in
microsoft/vstest#16463
* Test ids report logger by @​azat-msft in
microsoft/vstest#16443
* Isolate code coverage files in published output by @​azat-msft in
microsoft/vstest#16483
* Preserve OutputType for Android test projects by @​jonathanpeppers in
microsoft/vstest#16496
* Fix dotnet host resolution under proot (ARM64/Termux) by @​azat-msft
in microsoft/vstest#16462
* Mark the xxHash128 test id API as experimental by @​azat-msft in
microsoft/vstest#16465
* Ship Microsoft.Diagnostics.NETCore.Client in Microsoft.TestPlatform
and Portable packages by @​nohwnd in
microsoft/vstest#16633
* Fix localized resource paths in CLI source-build/non-Windows packages
by @​nohwnd in microsoft/vstest#16644


**Full Changelog**:
microsoft/vstest@v18.11.0...v18.12.0



## 18.11.1

## Security fix

This release fixes CVE-2026-105544, an elevation of privilege
vulnerability in the VSTest artifact post-processor. The post-processor
could consume a forged `executionComplete.json` written by another local
user, and then run attacker-controlled output handling.

Affected: `Microsoft.TestPlatform.CLI` 18.11.0.
Fixed in: `Microsoft.TestPlatform.CLI` 18.11.1.

`Microsoft.TestPlatform.CLI` is the VSTest build that we ship into the
.NET SDK. The recommended way to get this fix is to update your .NET SDK
to the latest patched version, see the advisory for the SDK versions.

The fix is also released in the `Microsoft.TestPlatform.CLI` package,
for completeness. That package is rarely used directly. It is not a
dependency of `Microsoft.NET.Test.Sdk` or `Microsoft.TestPlatform`, so
those packages do not bring it in.

Details: microsoft/vstest#16654 and
dotnet/announcements#517

Using custom Docker images or Nano Server? See
microsoft/vstest#16652

## What's Changed
* Security fix for CVE-2026-105544, see
microsoft/vstest#16654
* Ship Microsoft.Diagnostics.NETCore.Client in Microsoft.TestPlatform
and Portable packages by @​nohwnd in
microsoft/vstest#16632
* Fix localized resource paths in CLI source-build packages by @​nohwnd
in microsoft/vstest#16643

**Full Changelog**:
microsoft/vstest@v18.11.0...v18.11.1

Commits viewable in [compare
view](microsoft/vstest@v18.11.0...v18.12.0).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants