Skip to content

[SDKv2] Migrate WinML EP downloads to WinML 2.x (reg-free runtime)#788

Merged
bmehta001 merged 37 commits into
mainfrom
bhamehta/flcore/winml-2-ep-downloads
Jun 17, 2026
Merged

[SDKv2] Migrate WinML EP downloads to WinML 2.x (reg-free runtime)#788
bmehta001 merged 37 commits into
mainfrom
bhamehta/flcore/winml-2-ep-downloads

Conversation

@bmehta001

@bmehta001 bmehta001 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates WinML EP-download path from Microsoft.WindowsAppSDK.ML 1.8.2192 (WinML 1.x, requires the Windows App SDK bootstrap and Win11 24H2+) to Microsoft.Windows.AI.MachineLearning 2.1.70 (WinML 2.x, registration-free, Win10 19H1+)

Highlights

  • Remove WinAppSDK Bootstrap plumbing across all SDKs, as is any code that existed only to support Bootstrapping.
  • Unify ORT to 1.25.1 and OnnxRuntimeGenAI to 0.13.2 for both flavors
  • Drop the WebGPU-EP skip on WinML builds (both flavors now satisfy ORT API ≥ 24).
  • Drop the IsWindows11_24H2OrLater() runtime guard in winml_ep_bootstrapper.cc, since LoadLibraryW is a sufficient probe.
  • Gate find_package(WinMLEpCatalog) behind FOUNDRY_LOCAL_USE_WINML so non-WinML builds don't silently link the catalog DLL.
  • CMake: update DLL path runtimes-framework/<rid>/native/runtimes/<rid>/native/ and bump default WINML_EP_CATALOG_VERSION to 2.1.70.
  • Pipelines: bump cppWinmlVersion to 2.1.70, drop cppOrtVersionWinml and the entire Microsoft.WindowsAppSDK.Foundation resolution + Bootstrap.dll staging in steps-prefetch-nuget.yml / steps-build-windows.yml.
  • NuGet pack: replace Microsoft.WindowsAppRuntime.Bootstrap.dll with Microsoft.Windows.AI.MachineLearning.dll in OPTIONAL_SIBLINGS.
  • Bump gtest DISCOVERY_TIMEOUT to 60 s for foundry_local_tests and cache_only_tests — the WinML build's delay-loaded DLL resolution + static initializers can exceed the 5 s default.
  • C# WinML SKU TFM relaxation: drops the net9.0-windows10.0.26100.0 lock and targets net8.0;net9.0 instead. The WinML 2.x OS floor (Win10 19H1+) is enforced at runtime by winml_ep_bootstrapper.cc and by the EP catalog NuGet, not by the C# csproj, so consumers no longer need the Win11 24H2 SDK to build against Microsoft.AI.Foundry.Local.WinML. netstandard2.0 is intentionally not added to the WinML SKU — the standard SKU keeps it (and the net462 test lane) for .NET Framework consumers; the WinML SKU's audience is Win11-era + modern .NET, so the net462 test lane is gated off for the WinML test matrix.

WinML 2.x EP semantics (informational)

  • Per-EP downloads happen one at a time today. 2.x exposes WinMLEpEnsureReadyAsync(WinMLAsyncBlock*), but the OS-side MSIX/BITS work is largely serialized anyway. Left as a future optimization.
  • Catalog (WinMLEpCatalogHandle) is only created during EnsureReady at the beginning. The 2.x C API has no Refresh/Invalidate, so if new EPs are released mid-process, they will only be visible after process restart.
  • Foundry's AzureModelCatalog cache is correctly invalidated in Manager::DownloadAndRegisterEps (manager.cc:547) after a successful register, so model-filter results reflect the new EP set immediately.

Maybe the extra error-checking in @sdk_v2/cpp/src/ep_detection/winml_ep_bootstrapper.cc is unnecessary, but I have added it for diagnostics.

@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
foundry-local Ready Ready Preview, Comment Jun 17, 2026 5:19pm

Request Review

@bmehta001 bmehta001 changed the title Migrate WinML EP downloads to WinML 2.x (reg-free runtime) [SDKv2] Migrate WinML EP downloads to WinML 2.x (reg-free runtime) Jun 9, 2026
@bmehta001 bmehta001 force-pushed the bhamehta/flcore/winml-2-ep-downloads branch from 44fb8d1 to ae5ad90 Compare June 9, 2026 06:04
@bmehta001 bmehta001 force-pushed the bhamehta/flcore/winml-2-ep-downloads branch from ae5ad90 to c240a00 Compare June 9, 2026 07:10
@bmehta001 bmehta001 self-assigned this Jun 10, 2026
@bmehta001 bmehta001 marked this pull request as ready for review June 10, 2026 14:34
Copilot AI review requested due to automatic review settings June 10, 2026 14:34

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.

Pull request overview

This PR migrates the WinML EP download/discovery path from WinML 1.x (Windows App SDK bootstrap required) to WinML 2.x (Microsoft.Windows.AI.MachineLearning, reg-free runtime), and unifies ORT/GenAI pins across WinML and non-WinML flavors to simplify build + packaging across C++, C#, JS, Python, and CI.

Changes:

  • Removes Windows App SDK bootstrap plumbing (Bootstrap additionalSettings, bootstrap DLL staging, and native bootstrap helper) across all SDK bindings.
  • Switches WinML EP catalog acquisition to Microsoft.Windows.AI.MachineLearning (NuGet + first-party CMake config) and updates packaging/staging to ship the reg-free runtime DLL where needed.
  • Unifies ORT/GenAI version pins (deletes WinML-specific deps JSON and removes WinML branching in CMake and the Python v2 build backend).

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
sdk_v2/python/test/integration/test_configuration_native.py Updates integration test to stop using the removed Bootstrap additional setting.
sdk_v2/python/README.md Removes WinML-only Bootstrap=false example from docs.
sdk_v2/python/pyproject.toml Updates comments to reflect single deps JSON source for both wheel flavors.
sdk_v2/python/_build_backend/init.py Drops WinML-specific deps JSON selection; always rewrites from deps_versions.json.
sdk_v2/js/test/bootstrap-autodetect.test.ts Deletes tests for bootstrap auto-detect (no longer relevant with WinML 2.x reg-free runtime).
sdk_v2/js/src/foundryLocalManager.ts Removes bootstrap auto-detect logic from manager initialization.
sdk_v2/js/script/copy-native.mjs Stops copying Bootstrap.dll; now copies Microsoft.Windows.AI.MachineLearning.dll.
sdk_v2/deps_versions_winml.json Removes WinML-specific ORT pin file (pins are unified).
sdk_v2/cs/src/Microsoft.AI.Foundry.Local.csproj Lowers WinML package TFM to Windows 10 19H1-era baseline.
sdk_v2/cs/src/FoundryLocalManager.cs Removes WinML bootstrap default injection into AdditionalSettings.
sdk_v2/cpp/test/sdk_api/ep_detection_test.cc Updates WinML EP test comment to reflect Win10 19H1+ support.
sdk_v2/cpp/test/CMakeLists.txt Increases gtest discovery timeout to accommodate WinML build startup costs.
sdk_v2/cpp/src/winml_bootstrap.h Deletes WinAppSDK bootstrap helper header.
sdk_v2/cpp/src/winml_bootstrap.cc Deletes WinAppSDK bootstrap helper implementation.
sdk_v2/cpp/src/manager.cc Removes bootstrap lifecycle; enables WebGPU EP path for WinML builds now that ORT is unified.
sdk_v2/cpp/src/ep_detection/winml_ep_bootstrapper.cc Removes OS-version gating; improves diagnostics when the WinML runtime DLL is absent.
sdk_v2/cpp/src/ep_detection/cuda_ep_bootstrapper.cc Collapses CUDA EP download to a single ORT-aligned payload (no WinML branching).
sdk_v2/cpp/nuget/pack.py Packages Microsoft.Windows.AI.MachineLearning.dll as the optional WinML sibling DLL.
sdk_v2/cpp/docs/MigrationPlan_20260410.md Updates migration plan documentation for WinML 2.x acquisition and behavior.
sdk_v2/cpp/docs/EpDetectionPlan.md Updates EP detection plan to WinML 2.x reg-free runtime and new package layout.
sdk_v2/cpp/docs/CppPortGuide.md Updates port guide WinML requirements note to Win10 19H1+ reg-free runtime.
sdk_v2/cpp/CMakeLists.txt Gates find_package(WinMLEpCatalog) behind FOUNDRY_LOCAL_USE_WINML; removes bootstrap linking/copy; ensures WinML DLL copy uses catalog DLL dir.
sdk_v2/cpp/cmake/FindWinMLEpCatalog.cmake Switches acquisition to Microsoft.Windows.AI.MachineLearning and uses the package’s first-party CMake config to define targets and DLL dir.
sdk_v2/cpp/cmake/FindOnnxRuntimeGenAI.cmake Removes WinML-vs-standard package branching; uses a single GenAI package.
sdk_v2/cpp/cmake/FindOnnxRuntime.cmake Removes WinML-specific deps file selection; uses unified ORT pin.
sdk_v2/cpp/build.py Updates --use_winml messaging and changes override define to WINML_EP_CATALOG_VERSION.
.pipelines/v2/templates/steps-prefetch-nuget.yml Updates WinML prefetch to download the reg-free package directly (no transitive Foundation resolution).
.pipelines/v2/templates/steps-build-windows.yml Updates native staging to include Microsoft.Windows.AI.MachineLearning.dll for WinML builds.
.pipelines/v2/templates/stages-sdk-v2.yml Removes WinML-specific ORT version parameter wiring.
.pipelines/v2/templates/stages-build-native.yml Unifies WinML and non-WinML builds on the same ORT version parameter.
.pipelines/v2/sdk_v2-pipeline-plan.md Updates pipeline plan documentation for unified ORT pins and WinML 2.x package handling.
.pipelines/foundry-local-packaging.yml Updates packaging pipeline variables to use WinML 2.x version and removes WinML-specific ORT version variable.

Comment thread sdk_v2/cpp/src/ep_detection/winml_ep_bootstrapper.cc Outdated
Comment thread sdk_v2/cpp/cmake/FindWinMLEpCatalog.cmake Outdated
Comment thread .pipelines/v2/templates/steps-prefetch-nuget.yml
Switch from `Microsoft.WindowsAppSDK.ML` 1.8.2192 (WinML 1.x, WinAppSDK
bootstrap required, Win11 24H2+) to `Microsoft.Windows.AI.MachineLearning`
2.1.6 (WinML 2.x, registration-free, Win10 19H1+). This brings Foundry-Local
in line with the same migration neutron-server completed.

Highlights:

* Remove WinAppSDK Bootstrap plumbing across all SDKs. The `Bootstrap`
  `additionalSettings` key — which used to flip on WinAppSDK init in the
  native layer — is gone in every binding (C++, C#, JS, Python). It was an
  internal init knob; no public surface signaled it as a stable contract.
  - C++: delete winml_bootstrap.{h,cc}, the WinAppSdkBootstrap link target,
    the Bootstrap.dll post-build copy, and the additional_options key
    handling in Manager::Create / Destroy.
  - C#: drop the `IS_WINML` default that injected Bootstrap=true.
    Lower TFM from net9.0-windows10.0.26100.0 to net9.0-windows10.0.18362.0.
  - JS: delete applyBootstrapAutoDetect and its test; drop Bootstrap.dll
    from copy-native script.
  - Python: drop `Bootstrap=false` examples from README and integration
    test.
* Unify ORT to 1.25.1 / OnnxRuntimeGenAI to 0.13.2 for both the WinML and
  non-WinML flavors. Delete sdk_v2/deps_versions_winml.json and the
  `FOUNDRY_LOCAL_USE_WINML` branch in FindOnnxRuntime.cmake /
  FindOnnxRuntimeGenAI.cmake / the python build backend.
* Collapse cuda_ep_bootstrapper.cc to the single ORT-1.25.1 URL / binary
  set (previously branched on WinML for the older 1.23.2 build).
* Drop the WebGPU-EP skip on WinML builds (both flavors now satisfy ORT
  API >= 24).
* Drop the IsWindows11_24H2OrLater() runtime guard in
  winml_ep_bootstrapper.cc; LoadLibraryW is a sufficient probe.
* Gate `find_package(WinMLEpCatalog)` behind `FOUNDRY_LOCAL_USE_WINML`
  so non-WinML builds don't silently link the catalog DLL.
* CMake/cmake-modules: update DLL path
  `runtimes-framework/<rid>/native/` -> `runtimes/<rid>/native/` and
  bump default `WINML_EP_CATALOG_VERSION` to 2.1.6.
* Pipelines: bump `cppWinmlVersion` to 2.1.6, drop `cppOrtVersionWinml`
  and the entire `Microsoft.WindowsAppSDK.Foundation` resolution +
  Bootstrap.dll staging in steps-prefetch-nuget.yml /
  steps-build-windows.yml.
* Nuget pack: replace `Microsoft.WindowsAppRuntime.Bootstrap.dll` with
  `Microsoft.Windows.AI.MachineLearning.dll` in OPTIONAL_SIBLINGS.
* Bump gtest `DISCOVERY_TIMEOUT` to 60 for foundry_local_tests and
  cache_only_tests; WinML's delay-loaded DLL resolution + static
  initializers can exceed the 5 s default during test discovery.

Verified:

* `python sdk_v2/cpp/build.py --config RelWithDebInfo --skip_examples`
  (non-WinML) builds clean; 820 unit/cache tests pass.
* `python sdk_v2/cpp/build.py --config RelWithDebInfo --skip_examples
  --use_winml` builds clean; FindWinMLEpCatalog.cmake downloads
  Microsoft.Windows.AI.MachineLearning 2.1.6 from nuget.org;
  Microsoft.Windows.AI.MachineLearning.dll is co-located with
  foundry_local.dll in the build output.
* Targeted ctest run on the WinML build:
  `ctest -R "EpDetector|WinML|ManagerWebServiceTest|CacheOnlyTest"` ->
  18/18 pass.

Out of scope (deferred): WebGPU manifest-based granular updates;
adopting WinML's bundled onnxruntime.dll.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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.

Pull request overview

Copilot reviewed 53 out of 53 changed files in this pull request and generated 2 comments.

Comment thread sdk_v2/python/_build_backend/__init__.py
Comment thread sdk_v2/cpp/docs/EpDetectionPlan.md Outdated
bmehta001 and others added 3 commits June 12, 2026 08:21
The helper is only referenced from DiscoverProviders' EP-catalog code
path. When FOUNDRY_LOCAL_HAS_EP_CATALOG=0 (non-WinML Windows build)
the file is still compiled but the helper has no callers, which can
trip MSVC C4505 (unreferenced local function has been removed) under
/W4 builds. Moving the function definition inside the same
preprocessor guard that gates its sole call site makes the
compilation symmetric.

No behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The find-module advertised WINML_EP_CATALOG_HEADER_DIR as a public output (set
as CACHE PATH ... FORCE and printed via message(STATUS)), but no caller in the
repo reads it. Headers reach consumers through the WindowsML::Api target's
INTERFACE_INCLUDE_DIRECTORIES, propagated by the WinMLEpCatalog::WinMLEpCatalog
alias. The companion WINML_EP_CATALOG_DLL_DIR is genuinely consumed by the
post-build DLL-copy step in sdk_v2/cpp/CMakeLists.txt, so only the header
variable is dead.

Drop the cache var, its STATUS line, and the corresponding header-block doc
entry. Verified zero remaining references via 'git grep' and a clean configure
+ build of foundry_local on Windows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Respond to review feedback: testing net8.0 (LTS) is sufficient for CI.
The library still multi-targets net8.0;net9.0;netstandard2.0 for packaging.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace fixed MAX_PATH stack buffer with a dynamically-grown std::wstring
to support long paths (>260 chars) when the user has enabled them via
the Windows registry or app manifest.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
skottmckay
skottmckay previously approved these changes Jun 17, 2026
@bmehta001 bmehta001 enabled auto-merge (squash) June 17, 2026 03:14
ORT's install_name is @rpath/libonnxruntime.1.dylib (major-version soname),
but we only created the unversioned symlink. dyld couldn't find the library
at test time on macOS arm64. Add the major-version symlink alongside the
unversioned one.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ORT 1.26.0 changed libonnxruntime.dylib's install_name from
@rpath/libonnxruntime.<full-version>.dylib to @rpath/libonnxruntime.1.dylib
(the soversion), via the onnxruntime SOVERSION change (microsoft/onnxruntime
#28101) and the Foundry nupkg packaging update (#28191). Our macOS POST_BUILD
step still copied the library to libonnxruntime.<full-version>.dylib -- a name
nothing references -- so foundry_local_tests failed to load ORT on macOS arm64
(dyld could not find @rpath/libonnxruntime.1.dylib).

Name the copied library by the soversion (major version) to match ORT's
install_name, keeping the unversioned symlink that GenAI dlopen()s at runtime
and that -lonnxruntime resolves at link time. Mirrors the existing Linux
libonnxruntime.so.1 handling.

Verified by inspecting the published nupkgs: 1.25.1 install_name was
@rpath/libonnxruntime.1.25.1.dylib; 1.26.0 is @rpath/libonnxruntime.1.dylib.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ORT's macOS dylib install_name is the soversion (@rpath/libonnxruntime.1.dylib)
since the upstream SOVERSION change, not the full-version form the comment
claimed. Reword to describe the mechanism (a versioned install_name leaf, not
the bare libonnxruntime.dylib GenAI dlopens) without pinning to a specific
version. No behavior change; the GenAI->ORT symlink is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Match the C++ build's macOS layout (libonnxruntime.1.dylib real file +
unversioned symlink) in the JS SDK so the ORT dylib is named by its actual
install_name soversion rather than the full version:

- install-native.cjs: stage the downloaded ORT dylib as libonnxruntime.<major>.dylib
  (the soversion / install_name) with an unversioned libonnxruntime.dylib symlink
  for GenAI's runtime dlopen and link-time -lonnxruntime; correct the comment.
- copy-native.mjs: also copy libonnxruntime.1.dylib into dev prebuilds so the
  preload below resolves it locally.
- native.ts: preload ORT from the soversion path (libonnxruntime.1.dylib) on macOS
  instead of the unversioned name.

The JS loader preloads ORT by absolute path, so this is correctness/consistency
alignment, not a runtime break. No behavior change on Windows/Linux.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
foundry_local loads ORT by its soversion install_name (libonnxruntime.1.dylib)
while GenAI dlopen()s the unversioned libonnxruntime.dylib, so both must be
present. Note why this dev-only script copies both as plain files instead of
symlinking like the shipped paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bmehta001 bmehta001 merged commit d18c5a3 into main Jun 17, 2026
54 of 55 checks passed
@bmehta001 bmehta001 deleted the bhamehta/flcore/winml-2-ep-downloads branch June 17, 2026 20:15
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.

4 participants