From 5bc8fc587524524d7637063b0e2c65ff20fb099b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 14:13:14 -0700 Subject: [PATCH 001/112] packaging pipeline --- .pipelines/foundry-local-packaging.yml | 306 ++++++++++++++++++++ .pipelines/templates/build-core-steps.yml | 106 +++++++ .pipelines/templates/build-cs-steps.yml | 186 ++++++++++++ .pipelines/templates/build-js-steps.yml | 149 ++++++++++ .pipelines/templates/package-core-steps.yml | 136 +++++++++ 5 files changed, 883 insertions(+) create mode 100644 .pipelines/foundry-local-packaging.yml create mode 100644 .pipelines/templates/build-core-steps.yml create mode 100644 .pipelines/templates/build-cs-steps.yml create mode 100644 .pipelines/templates/build-js-steps.yml create mode 100644 .pipelines/templates/package-core-steps.yml diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml new file mode 100644 index 00000000..6534ca80 --- /dev/null +++ b/.pipelines/foundry-local-packaging.yml @@ -0,0 +1,306 @@ +# Foundry Local SDK Packaging Pipeline +# +# Builds Foundry Local Core from neutron-server (AIFoundryLocal project), +# then packages the C# and JS SDKs from this repo using the built Core. +# +# Produces artifacts: flc-nuget, cs-sdk, cs-sdk-winml, js-sdk + +trigger: none +name: $(Date:yyyyMMdd).$(Rev:r) + +parameters: +- name: version + displayName: 'Package version (e.g. 0.9.0)' + type: string + default: '0.9.0' +- name: isRelease + displayName: 'Release build (omits dev suffix)' + type: boolean + default: false + +variables: +- group: FoundryLocal-ESRP-Signing + +resources: + repositories: + - repository: neutron-server + type: git + name: AIFoundryLocal/neutron-server + endpoint: aiinfra-AIFoundryLocal-FoundryLocalCore-SP + ref: refs/heads/dev/FoundryLocalCore/main + - repository: test-data-shared + type: git + name: AIFoundryLocal/test-data-shared + endpoint: aiinfra-AIFoundryLocal-FoundryLocalCore-SP + lfs: true + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + settings: + networkIsolationPolicy: Permissive + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + customBuildTags: + - ES365AIMigrationTooling-Release + stages: + # ── Stage 1: Build Foundry Local Core ── + - stage: build_core + displayName: 'Build Foundry Local Core' + jobs: + - job: flc_win_x64 + displayName: 'FLC win-x64' + templateContext: + outputs: + - output: pipelineArtifact + artifactName: 'flc-win-x64' + targetPath: '$(Build.ArtifactStagingDirectory)/native' + steps: + - checkout: neutron-server + clean: true + - template: templates/build-core-steps.yml + parameters: + flavor: win-x64 + platform: x64 + + - job: flc_win_arm64 + displayName: 'FLC win-arm64' + templateContext: + outputs: + - output: pipelineArtifact + artifactName: 'flc-win-arm64' + targetPath: '$(Build.ArtifactStagingDirectory)/native' + steps: + - checkout: neutron-server + clean: true + - template: templates/build-core-steps.yml + parameters: + flavor: win-arm64 + platform: arm64 + + - job: flc_linux_x64 + displayName: 'FLC linux-x64' + pool: + vmImage: 'ubuntu-latest' + templateContext: + outputs: + - output: pipelineArtifact + artifactName: 'flc-linux-x64' + targetPath: '$(Build.ArtifactStagingDirectory)/native' + steps: + - checkout: neutron-server + clean: true + - template: templates/build-core-steps.yml + parameters: + flavor: linux-x64 + platform: x64 + + - job: flc_osx_arm64 + displayName: 'FLC osx-arm64' + pool: + vmImage: 'macos-14-arm64' + templateContext: + outputs: + - output: pipelineArtifact + artifactName: 'flc-osx-arm64' + targetPath: '$(Build.ArtifactStagingDirectory)/native' + steps: + - checkout: neutron-server + clean: true + - template: templates/build-core-steps.yml + parameters: + flavor: osx-arm64 + platform: arm64 + + # WinML variants (Windows-only) + - job: flc_winml_win_x64 + displayName: 'FLC win-x64 (WinML)' + templateContext: + outputs: + - output: pipelineArtifact + artifactName: 'flc-winml-win-x64' + targetPath: '$(Build.ArtifactStagingDirectory)/native' + steps: + - checkout: neutron-server + clean: true + - template: templates/build-core-steps.yml + parameters: + flavor: win-x64 + platform: x64 + isWinML: true + + - job: flc_winml_win_arm64 + displayName: 'FLC win-arm64 (WinML)' + templateContext: + outputs: + - output: pipelineArtifact + artifactName: 'flc-winml-win-arm64' + targetPath: '$(Build.ArtifactStagingDirectory)/native' + steps: + - checkout: neutron-server + clean: true + - template: templates/build-core-steps.yml + parameters: + flavor: win-arm64 + platform: arm64 + isWinML: true + + # ── Stage 2: Package FLC NuGet ───────────────────────────── + - stage: package_core + displayName: 'Package FLC NuGet' + dependsOn: build_core + jobs: + - job: package_flc + displayName: 'Package FLC (standard)' + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-win-x64' + targetPath: '$(Pipeline.Workspace)/flc-win-x64' + - input: pipelineArtifact + artifactName: 'flc-win-arm64' + targetPath: '$(Pipeline.Workspace)/flc-win-arm64' + - input: pipelineArtifact + artifactName: 'flc-linux-x64' + targetPath: '$(Pipeline.Workspace)/flc-linux-x64' + - input: pipelineArtifact + artifactName: 'flc-osx-arm64' + targetPath: '$(Pipeline.Workspace)/flc-osx-arm64' + outputs: + - output: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Build.ArtifactStagingDirectory)/flc-nuget' + steps: + - checkout: neutron-server + clean: true + - template: templates/package-core-steps.yml + parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + isWinML: false + platforms: + - name: win-x64 + artifactName: flc-win-x64 + - name: win-arm64 + artifactName: flc-win-arm64 + - name: linux-x64 + artifactName: flc-linux-x64 + - name: osx-arm64 + artifactName: flc-osx-arm64 + + - job: package_flc_winml + displayName: 'Package FLC (WinML)' + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-winml-win-x64' + targetPath: '$(Pipeline.Workspace)/flc-winml-win-x64' + - input: pipelineArtifact + artifactName: 'flc-winml-win-arm64' + targetPath: '$(Pipeline.Workspace)/flc-winml-win-arm64' + outputs: + - output: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Build.ArtifactStagingDirectory)/flc-nuget' + steps: + - checkout: neutron-server + clean: true + - template: templates/package-core-steps.yml + parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + isWinML: true + platforms: + - name: win-x64 + artifactName: flc-winml-win-x64 + - name: win-arm64 + artifactName: flc-winml-win-arm64 + + # ── Stage 3: Build C# SDK (standard) ────────────────────── + - stage: build_cs + displayName: 'Build C# SDK' + dependsOn: package_core + jobs: + - job: cs_sdk + displayName: 'Build' + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + outputs: + - output: pipelineArtifact + artifactName: 'cs-sdk' + targetPath: '$(Build.ArtifactStagingDirectory)/cs-sdk' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: templates/build-cs-steps.yml + parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # ── Stage 3: Build C# SDK (WinML) ───────────────────────── + - stage: build_cs_winml + displayName: 'Build C# SDK (WinML)' + dependsOn: package_core + jobs: + - job: cs_sdk_winml + displayName: 'Build' + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + outputs: + - output: pipelineArtifact + artifactName: 'cs-sdk-winml' + targetPath: '$(Build.ArtifactStagingDirectory)/cs-sdk-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: templates/build-cs-steps.yml + parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + + # ── Stage 4: Build JS SDK ───────────────────────────── + - stage: build_js + displayName: 'Build JS SDK' + dependsOn: package_core + jobs: + - job: js_sdk + displayName: 'Build' + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + outputs: + - output: pipelineArtifact + artifactName: 'js-sdk' + targetPath: '$(Build.ArtifactStagingDirectory)/js-sdk' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: templates/build-js-steps.yml + parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml new file mode 100644 index 00000000..389e455d --- /dev/null +++ b/.pipelines/templates/build-core-steps.yml @@ -0,0 +1,106 @@ +# Steps to build a single Foundry Local Core native AOT binary. +# Parameterized by flavor (RID) and platform (arch). +# The parent job must checkout 'neutron-server'. +parameters: +- name: flavor + type: string # e.g. win-x64, linux-x64, osx-arm64 +- name: platform + type: string # e.g. x64, arm64 +- name: isWinML + type: boolean + default: false + +steps: +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $nsRoot = "$(Agent.BuildDirectory)/s/neutron-server" + Write-Host "##vso[task.setvariable variable=nsRoot]$nsRoot" + +- task: UseDotNet@2 + displayName: 'Use .NET SDK from global.json' + inputs: + packageType: sdk + useGlobalJson: true + workingDirectory: '$(nsRoot)' + +- task: NuGetAuthenticate@1 + displayName: 'Authenticate NuGet feeds' + +- ${{ if eq(parameters.isWinML, true) }}: + - task: DotNetCoreCLI@2 + displayName: 'Restore FLC ${{ parameters.flavor }} (WinML)' + inputs: + command: restore + projects: '$(nsRoot)/foundry_local_core.proj' + restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + feedsToUse: config + nugetConfigPath: '$(nsRoot)/nuget.config' + + - task: DotNetCoreCLI@2 + displayName: 'Build FLC ${{ parameters.flavor }} (WinML)' + inputs: + command: build + projects: '$(nsRoot)/foundry_local_core.proj' + arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + + - task: DotNetCoreCLI@2 + displayName: 'Publish FLC AOT ${{ parameters.flavor }} (WinML)' + inputs: + command: publish + projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' + arguments: '--no-restore --no-build -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + publishWebProjects: false + zipAfterPublish: false + +- ${{ if eq(parameters.isWinML, false) }}: + - task: DotNetCoreCLI@2 + displayName: 'Restore FLC ${{ parameters.flavor }}' + inputs: + command: restore + projects: '$(nsRoot)/foundry_local_core.proj' + restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' + feedsToUse: config + nugetConfigPath: '$(nsRoot)/nuget.config' + + - task: DotNetCoreCLI@2 + displayName: 'Build FLC ${{ parameters.flavor }}' + inputs: + command: build + projects: '$(nsRoot)/foundry_local_core.proj' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' + + - task: DotNetCoreCLI@2 + displayName: 'Publish FLC AOT ${{ parameters.flavor }}' + inputs: + command: publish + projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' + arguments: '--no-restore --no-build -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0' + publishWebProjects: false + zipAfterPublish: false + +# Cleanup non-binary files +- task: PowerShell@2 + displayName: 'Cleanup publish artifacts' + inputs: + targetType: inline + script: | + Get-ChildItem "$(nsRoot)/artifacts/publish" -Recurse -Include "*.json", "*.xml" | + Remove-Item -Force + +# Stage the native binary for the artifact +- task: PowerShell@2 + displayName: 'Stage ${{ parameters.flavor }} binary' + inputs: + targetType: inline + script: | + $destDir = "$(Build.ArtifactStagingDirectory)/native" + New-Item -ItemType Directory -Path $destDir -Force | Out-Null + Get-ChildItem "$(nsRoot)/artifacts/publish" -Recurse -File | + Where-Object { $_.Name -like "Microsoft.AI.Foundry.Local.Core.*" } | + Copy-Item -Destination $destDir -Force + Write-Host "Staged binaries:" + Get-ChildItem $destDir | ForEach-Object { Write-Host " $($_.Name)" } + diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml new file mode 100644 index 00000000..dfa6c456 --- /dev/null +++ b/.pipelines/templates/build-cs-steps.yml @@ -0,0 +1,186 @@ +# Steps to build, test, sign, and pack the C# SDK NuGet package. +# When test-data-shared is checked out alongside self, ADO places repos under +# $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. +parameters: +- name: version + type: string +- name: isRelease + type: boolean + default: false +- name: isWinML + type: boolean + default: false +- name: flcNugetDir + type: string + displayName: 'Path to directory containing the FLC .nupkg' + +steps: +# Set paths for multi-repo checkout +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $repoRoot = "$(Build.SourcesDirectory)/Foundry-Local" + $testDataDir = "$(Build.SourcesDirectory)/test-data-shared" + Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" + +- task: UseDotNet@2 + displayName: 'Use .NET 10 SDK' + inputs: + packageType: sdk + version: '10.0.x' + +# Compute package version +- task: PowerShell@2 + displayName: 'Set package version' + inputs: + targetType: inline + script: | + $v = "${{ parameters.version }}" + if ("${{ parameters.isRelease }}" -ne "True") { + $ts = Get-Date -Format "yyyyMMddHHmm" + $v = "$v-dev.$ts" + } + Write-Host "##vso[task.setvariable variable=packageVersion]$v" + Write-Host "Package version: $v" + +# Create a temporary NuGet.config that includes the local FLC feed +- task: PowerShell@2 + displayName: 'Create NuGet.config with local FLC feed' + inputs: + targetType: inline + script: | + $nugetConfig = @" + + + + + + + + + "@ + $configPath = "$(Build.ArtifactStagingDirectory)/NuGet.config" + Set-Content -Path $configPath -Value $nugetConfig + Write-Host "##vso[task.setvariable variable=customNugetConfig]$configPath" + + # Determine the FLC version from the .nupkg filename + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" } + $flcVer = $nupkg.BaseName -replace '^Microsoft\.AI\.Foundry\.Local\.Core(\.WinML)?\.', '' + Write-Host "##vso[task.setvariable variable=resolvedFlcVersion]$flcVer" + Write-Host "Resolved FLC version: $flcVer" + +- task: NuGetAuthenticate@1 + displayName: 'Authenticate NuGet feeds' + +- task: DotNetCoreCLI@2 + displayName: 'Restore SDK' + inputs: + command: restore + projects: $(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj + feedsToUse: config + nugetConfigPath: $(customNugetConfig) + restoreArguments: '/p:UseWinML=${{ parameters.isWinML }} /p:FoundryLocalCoreVersion=$(resolvedFlcVersion)' + +- task: DotNetCoreCLI@2 + displayName: 'Build SDK' + inputs: + command: build + projects: $(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj + arguments: '--no-restore --configuration Release /p:UseWinML=${{ parameters.isWinML }}' + +# Restore and build test project +- task: DotNetCoreCLI@2 + displayName: 'Restore tests' + inputs: + command: restore + projects: $(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj + feedsToUse: config + nugetConfigPath: $(customNugetConfig) + restoreArguments: '/p:UseWinML=${{ parameters.isWinML }} /p:FoundryLocalCoreVersion=$(resolvedFlcVersion)' + +- task: DotNetCoreCLI@2 + displayName: 'Build tests' + inputs: + command: build + projects: $(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj + arguments: '--no-restore --configuration Release /p:UseWinML=${{ parameters.isWinML }}' + +# Run tests — test-data-shared is a sibling of the repo root +- task: DotNetCoreCLI@2 + displayName: 'Run SDK tests' + inputs: + command: test + projects: $(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj + arguments: '--no-build --configuration Release' + env: + TF_BUILD: 'true' + +# Discover target framework directory +- task: PowerShell@2 + displayName: 'Find target framework' + inputs: + targetType: inline + script: | + $base = "$(repoRoot)/sdk/cs/src/bin/Release" + $tfm = (Get-ChildItem $base -Directory -Filter "net10.0*" | Select-Object -First 1).Name + Write-Host "##vso[task.setvariable variable=TargetFramework]$tfm" + Write-Host "Target framework: $tfm" + +# Sign DLLs +- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 + displayName: 'Sign SDK DLLs' + inputs: + ConnectedServiceName: '$(esrpServiceConnection)' + UseMSIAuthentication: true + AppRegistrationClientId: '$(esrpClientId)' + AppRegistrationTenantId: '$(esrpTenantId)' + EsrpClientId: '$(esrpClientId)' + AuthAKVName: '$(esrpAkvName)' + AuthSignCertName: '$(esrpSignCertName)' + FolderPath: '$(repoRoot)/sdk/cs/src/bin/Release/$(TargetFramework)' + Pattern: '*.dll' + SessionTimeout: 90 + ServiceEndpointUrl: 'https://api.esrp.microsoft.com/api/v2' + MaxConcurrency: 25 + signConfigType: inlineSignParams + inlineOperation: | + [{"keyCode":"CP-230012","operationSetCode":"SigntoolSign","parameters":[{"parameterName":"OpusName","parameterValue":"Microsoft"},{"parameterName":"OpusInfo","parameterValue":"http://www.microsoft.com"},{"parameterName":"PageHash","parameterValue":"/NPH"},{"parameterName":"FileDigest","parameterValue":"/fd sha256"},{"parameterName":"TimeStamp","parameterValue":"/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"}],"toolName":"signtool.exe","toolVersion":"6.2.9304.0"}] + +# Pack NuGet +- task: PowerShell@2 + displayName: 'Pack NuGet' + inputs: + targetType: inline + script: | + dotnet pack "$(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj" ` + --no-build --configuration Release ` + --output "$(Build.ArtifactStagingDirectory)/cs-sdk" ` + /p:PackageVersion=$(packageVersion) ` + /p:UseWinML=${{ parameters.isWinML }} ` + /p:IncludeSymbols=true ` + /p:SymbolPackageFormat=snupkg + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +# Sign NuGet package +- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 + displayName: 'Sign SDK NuGet package' + inputs: + ConnectedServiceName: '$(esrpServiceConnection)' + UseMSIAuthentication: true + AppRegistrationClientId: '$(esrpClientId)' + AppRegistrationTenantId: '$(esrpTenantId)' + EsrpClientId: '$(esrpClientId)' + AuthAKVName: '$(esrpAkvName)' + AuthSignCertName: '$(esrpSignCertName)' + FolderPath: '$(Build.ArtifactStagingDirectory)/cs-sdk' + Pattern: '*.nupkg' + SessionTimeout: 90 + ServiceEndpointUrl: 'https://api.esrp.microsoft.com/api/v2' + MaxConcurrency: 25 + signConfigType: inlineSignParams + inlineOperation: | + [{"keyCode":"CP-401405","operationSetCode":"NuGetSign","parameters":[],"toolName":"sign","toolVersion":"6.2.9304.0"},{"keyCode":"CP-401405","operationSetCode":"NuGetVerify","parameters":[],"toolName":"sign","toolVersion":"6.2.9304.0"}] diff --git a/.pipelines/templates/build-js-steps.yml b/.pipelines/templates/build-js-steps.yml new file mode 100644 index 00000000..8adc3df8 --- /dev/null +++ b/.pipelines/templates/build-js-steps.yml @@ -0,0 +1,149 @@ +# Steps to build, test, and pack the JS SDK. +# When test-data-shared is checked out alongside self, ADO places repos under +# $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. +parameters: +- name: version + type: string +- name: isRelease + type: boolean + default: false +- name: isWinML + type: boolean + default: false +- name: flcNugetDir + type: string + default: '' + displayName: 'Path to directory containing the FLC .nupkg (for tests)' + +steps: +# Set paths for multi-repo checkout +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $repoRoot = "$(Build.SourcesDirectory)/Foundry-Local" + $testDataDir = "$(Build.SourcesDirectory)/test-data-shared" + Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" + Write-Host "Repo root: $repoRoot" + Write-Host "Test data: $testDataDir" + +- task: NodeTool@0 + displayName: 'Use Node.js 20' + inputs: + versionSpec: '20.x' + +# Compute version +- task: PowerShell@2 + displayName: 'Set package version' + inputs: + targetType: inline + script: | + $v = "${{ parameters.version }}" + if ("${{ parameters.isRelease }}" -ne "True") { + $ts = Get-Date -Format "yyyyMMddHHmm" + $v = "$v-dev.$ts" + } + Write-Host "##vso[task.setvariable variable=packageVersion]$v" + +# Install dependencies including native binaries (FLC, ORT, GenAI) from NuGet feeds +- ${{ if eq(parameters.isWinML, true) }}: + - task: Npm@1 + displayName: 'npm install (WinML)' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'install --winml' + +- ${{ else }}: + - task: Npm@1 + displayName: 'npm install' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'install' + +# Overwrite the FLC native binary with the one we just built +- task: PowerShell@2 + displayName: 'Overwrite FLC with pipeline-built binary' + condition: and(succeeded(), ne('${{ parameters.flcNugetDir }}', '')) + inputs: + targetType: inline + script: | + $os = 'win32' + $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x64' } + $platformKey = "$os-$arch" + $rid = if ($arch -eq 'arm64') { 'win-arm64' } else { 'win-x64' } + + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found" } + + # Extract the NuGet package (it's a zip) + $extractDir = "$(Build.ArtifactStagingDirectory)/flc-extract" + $zip = [System.IO.Path]::ChangeExtension($nupkg.FullName, ".zip") + Copy-Item $nupkg.FullName $zip -Force + Expand-Archive -Path $zip -DestinationPath $extractDir -Force + + # Overwrite FLC binary in the npm-installed location + $destDir = "$(repoRoot)/sdk/js/packages/@foundry-local-core/$platformKey" + $nativeDir = "$extractDir/runtimes/$rid/native" + if (Test-Path $nativeDir) { + Get-ChildItem $nativeDir -File | ForEach-Object { + Copy-Item $_.FullName -Destination "$destDir/$($_.Name)" -Force + Write-Host "Overwrote $($_.Name) with pipeline-built version" + } + } else { + Write-Warning "No native binaries found at $nativeDir for RID $rid" + } + + Write-Host "Final binaries in $destDir`:" + Get-ChildItem $destDir | ForEach-Object { Write-Host " $($_.Name)" } + +- task: Npm@1 + displayName: 'npm version' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'version $(packageVersion) --no-git-tag-version --allow-same-version' + +- task: Npm@1 + displayName: 'npm build' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'run build' + +# Run tests (test-data-shared provides model cache) +- task: Npm@1 + displayName: 'npm test' + condition: and(succeeded(), ne('${{ parameters.flcNugetDir }}', '')) + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'test' + env: + TF_BUILD: 'true' + +- task: Npm@1 + displayName: 'npm pack' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'pack' + +- task: PowerShell@2 + displayName: 'Stage artifact' + inputs: + targetType: inline + script: | + $destDir = "$(Build.ArtifactStagingDirectory)/js-sdk" + New-Item -ItemType Directory -Path $destDir -Force | Out-Null + if ("${{ parameters.isWinML }}" -eq "True") { + Get-ChildItem "$(repoRoot)/sdk/js/*.tgz" | ForEach-Object { + $new = $_.Name -replace '^foundry-local-sdk-', 'foundry-local-sdk-winml-' + Copy-Item $_.FullName "$destDir/$new" + } + } else { + Copy-Item "$(repoRoot)/sdk/js/*.tgz" "$destDir/" + } diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml new file mode 100644 index 00000000..0d029d1c --- /dev/null +++ b/.pipelines/templates/package-core-steps.yml @@ -0,0 +1,136 @@ +# Steps to collect per-platform FLC native binaries, organize into NuGet layout, +# and pack + sign the NuGet package. +# The parent job must download all platform artifacts and checkout neutron-server. +parameters: +- name: version + type: string +- name: isRelease + type: boolean + default: false +- name: isWinML + type: boolean + default: false +- name: platforms + type: object # list of { name, artifactName } + +steps: +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $nsRoot = "$(Agent.BuildDirectory)/s/neutron-server" + Write-Host "##vso[task.setvariable variable=nsRoot]$nsRoot" + +- task: PowerShell@2 + displayName: 'Organize native binaries' + inputs: + targetType: inline + script: | + $unifiedPath = "$(Build.ArtifactStagingDirectory)/unified" + New-Item -ItemType Directory -Path $unifiedPath -Force | Out-Null + + $platforms = @( + ${{ each p in parameters.platforms }}: + @{name="${{ p.name }}"; artifact="${{ p.artifactName }}"}, + ) + + foreach ($p in $platforms) { + $srcDir = "$(Pipeline.Workspace)/$($p.artifact)/native" + if (-not (Test-Path $srcDir)) { + Write-Warning "No artifact directory found at $srcDir" + continue + } + $destDir = "$unifiedPath/runtimes/$($p.name)/native" + New-Item -ItemType Directory -Path $destDir -Force | Out-Null + Get-ChildItem $srcDir -File | Where-Object { $_.Name -like "Microsoft.AI.Foundry.Local.Core.*" } | + Copy-Item -Destination $destDir -Force + Write-Host "Copied $($p.name) binaries to $destDir" + } + + # Copy build integration files from neutron-server + $nsRoot = "$(nsRoot)" + foreach ($dir in @("build", "buildTransitive")) { + $src = "$nsRoot/src/FoundryLocalCore/Core/$dir" + if (Test-Path $src) { + Copy-Item -Path $src -Destination "$unifiedPath/$dir" -Recurse -Force + } + } + $license = "$nsRoot/src/FoundryLocalCore/Core/LICENSE.txt" + if (Test-Path $license) { + Copy-Item $license "$unifiedPath/LICENSE.txt" -Force + } + +# Compute version +- task: PowerShell@2 + displayName: 'Set FLC package version' + inputs: + targetType: inline + script: | + $v = "${{ parameters.version }}" + if ("${{ parameters.isRelease }}" -ne "True") { + $ts = Get-Date -Format "yyyyMMddHHmm" + $commitId = "$(Build.SourceVersion)".Substring(0, 8) + $v = "$v-dev-$ts-$commitId" + } + Write-Host "##vso[task.setvariable variable=flcVersion]$v" + Write-Host "FLC version: $v" + +# Pack NuGet +- task: PowerShell@2 + displayName: 'Pack FLC NuGet' + inputs: + targetType: inline + script: | + $nsRoot = "$(nsRoot)" + [xml]$propsXml = Get-Content "$nsRoot/Directory.Packages.props" + $pg = $propsXml.Project.PropertyGroup + + $outDir = "$(Build.ArtifactStagingDirectory)/flc-nuget" + New-Item -ItemType Directory -Path $outDir -Force | Out-Null + + if ("${{ parameters.isWinML }}" -eq "True") { + $nuspec = "$nsRoot/src/FoundryLocalCore/Core/WinMLNuget.nuspec" + $id = "Microsoft.AI.Foundry.Local.Core.WinML" + $ortVer = $pg.OnnxRuntimeFoundryVersionForWinML + $genaiVer = $pg.OnnxRuntimeGenAIWinML + $winAppSdkVer = $pg.WinAppSdkVersion + $props = "id=$id;version=$(flcVersion);commitId=$(Build.SourceVersion);OnnxRuntimeFoundryVersion=$ortVer;OnnxRuntimeGenAIWinML=$genaiVer;WinAppSdkVersion=$winAppSdkVer" + } else { + $nuspec = "$nsRoot/src/FoundryLocalCore/Core/NativeNuget.nuspec" + $id = "Microsoft.AI.Foundry.Local.Core" + $ortVer = $pg.OnnxRuntimeFoundryVersion + $genaiVer = $pg.OnnxRuntimeGenAIFoundryVersion + $props = "id=$id;version=$(flcVersion);commitId=$(Build.SourceVersion);OnnxRuntimeFoundryVersion=$ortVer;OnnxRuntimeGenAIFoundryVersion=$genaiVer" + } + + $nugetArgs = @( + 'pack', $nuspec, + '-OutputDirectory', $outDir, + '-BasePath', "$(Build.ArtifactStagingDirectory)/unified", + '-Properties', $props, + '-Symbols', '-SymbolPackageFormat', 'snupkg' + ) + Write-Host "Running: nuget $($nugetArgs -join ' ')" + & nuget $nugetArgs + if ($LASTEXITCODE -ne 0) { throw "NuGet pack failed" } + +# Sign NuGet package +- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 + displayName: 'Sign FLC NuGet package' + inputs: + ConnectedServiceName: '$(esrpServiceConnection)' + UseMSIAuthentication: true + AppRegistrationClientId: '$(esrpClientId)' + AppRegistrationTenantId: '$(esrpTenantId)' + EsrpClientId: '$(esrpClientId)' + AuthAKVName: '$(esrpAkvName)' + AuthSignCertName: '$(esrpSignCertName)' + FolderPath: '$(Build.ArtifactStagingDirectory)/flc-nuget' + Pattern: '*.nupkg' + SessionTimeout: 90 + ServiceEndpointUrl: 'https://api.esrp.microsoft.com/api/v2' + MaxConcurrency: 25 + signConfigType: inlineSignParams + inlineOperation: | + [{"keyCode":"CP-401405","operationSetCode":"NuGetSign","parameters":[],"toolName":"sign","toolVersion":"6.2.9304.0"},{"keyCode":"CP-401405","operationSetCode":"NuGetVerify","parameters":[],"toolName":"sign","toolVersion":"6.2.9304.0"}] From 8bf879039d9bce8f1211fc598f1d89a53cdb6ac0 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 17:01:54 -0700 Subject: [PATCH 002/112] wheels --- .pipelines/foundry-local-packaging.yml | 7 +- .pipelines/templates/package-core-steps.yml | 99 ++++++++++++++++++++- 2 files changed, 103 insertions(+), 3 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 6534ca80..17c968c0 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -1,9 +1,9 @@ -# Foundry Local SDK Packaging Pipeline +# Foundry Local Packaging Pipeline # # Builds Foundry Local Core from neutron-server (AIFoundryLocal project), # then packages the C# and JS SDKs from this repo using the built Core. # -# Produces artifacts: flc-nuget, cs-sdk, cs-sdk-winml, js-sdk +# Produces artifacts: flc-nuget, flc-nuget-winml, flc-wheels, cs-sdk, cs-sdk-winml, js-sdk trigger: none name: $(Date:yyyyMMdd).$(Rev:r) @@ -175,6 +175,9 @@ extends: - output: pipelineArtifact artifactName: 'flc-nuget' targetPath: '$(Build.ArtifactStagingDirectory)/flc-nuget' + - output: pipelineArtifact + artifactName: 'flc-wheels' + targetPath: '$(Build.ArtifactStagingDirectory)/flc-wheels' steps: - checkout: neutron-server clean: true diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 0d029d1c..c4cb12f2 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -1,5 +1,5 @@ # Steps to collect per-platform FLC native binaries, organize into NuGet layout, -# and pack + sign the NuGet package. +# pack + sign the NuGet package, and (for non-WinML) build Python wheels. # The parent job must download all platform artifacts and checkout neutron-server. parameters: - name: version @@ -134,3 +134,100 @@ steps: signConfigType: inlineSignParams inlineOperation: | [{"keyCode":"CP-401405","operationSetCode":"NuGetSign","parameters":[],"toolName":"sign","toolVersion":"6.2.9304.0"},{"keyCode":"CP-401405","operationSetCode":"NuGetVerify","parameters":[],"toolName":"sign","toolVersion":"6.2.9304.0"}] + +# Build Python wheels from the NuGet package (standard builds only; WinML has no PyPI distribution) +- ${{ if eq(parameters.isWinML, false) }}: + - task: PowerShell@2 + displayName: 'Build foundry_local_core Python Wheels' + inputs: + targetType: inline + script: | + $stagingDir = "$(Build.ArtifactStagingDirectory)/flc-wheels" + New-Item -ItemType Directory -Path $stagingDir -Force | Out-Null + + # Find and extract the NuGet package (.nupkg is a zip archive) + $nupkg = Get-ChildItem "$(Build.ArtifactStagingDirectory)/flc-nuget" -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found" } + Write-Host "Found NuGet package: $($nupkg.Name)" + + $extractDir = "$(Build.ArtifactStagingDirectory)/flc-extracted" + $nupkgZip = [System.IO.Path]::ChangeExtension($nupkg.FullName, ".zip") + Copy-Item -Path $nupkg.FullName -Destination $nupkgZip -Force + Expand-Archive -Path $nupkgZip -DestinationPath $extractDir -Force + + # Convert NuGet version to PEP 440 + # NuGet dev format: X.Y.Z-dev-YYYYMMDD-HHmm-commitid + # PEP 440 dev format: X.Y.Z.devYYYYMMDDHHmm + $nupkgVersion = $nupkg.BaseName -replace '^Microsoft\.AI\.Foundry\.Local\.Core\.', '' + $parts = $nupkgVersion -split '-' + $pyVersion = if ($parts.Count -ge 4 -and $parts[1] -eq 'dev') { "$($parts[0]).dev$($parts[2])$($parts[3])" } + elseif ($parts.Count -eq 2) { "$($parts[0])$($parts[1])" } + else { $parts[0] } + Write-Host "Python package version: $pyVersion" + $packageName = "foundry_local_core" + + $platforms = @( + @{rid="win-x64"; pyKey="bin"; tag="win_amd64"}, + @{rid="win-arm64"; pyKey="bin"; tag="win_arm64"}, + @{rid="linux-x64"; pyKey="bin"; tag="manylinux_2_28_x86_64"}, + @{rid="osx-arm64"; pyKey="bin"; tag="macosx_11_0_arm64"} + ) + + foreach ($p in $platforms) { + $nativeSrc = "$extractDir/runtimes/$($p.rid)/native" + if (-not (Test-Path $nativeSrc)) { + Write-Warning "No native binaries found for $($p.rid) — skipping." + continue + } + + $wheelRoot = "$(Build.ArtifactStagingDirectory)/wheels-build/flc_wheel_$($p.tag)" + $pkgDir = "$wheelRoot/$packageName" + New-Item -ItemType Directory -Path "$pkgDir/$($p.pyKey)" -Force | Out-Null + "" | Set-Content -Encoding ascii "$pkgDir/__init__.py" + Get-ChildItem $nativeSrc -File | Copy-Item -Destination "$pkgDir/$($p.pyKey)" + + $normalizedName = $packageName.Replace('_', '-') + $wheelTag = "py3-none-$($p.tag)" + $distInfoName = "$packageName-$pyVersion" + $wheelName = "$distInfoName-$wheelTag.whl" + $distInfoDir = "$wheelRoot/$distInfoName.dist-info" + New-Item -ItemType Directory -Path $distInfoDir -Force | Out-Null + + # Use no-BOM UTF-8 — PowerShell 5's -Encoding utf8 adds a BOM that + # breaks twine/pkginfo metadata parsing. + $utf8NoBom = [System.Text.UTF8Encoding]::new($false) + + [System.IO.File]::WriteAllText("$distInfoDir/WHEEL", + "Wheel-Version: 1.0`nGenerator: custom`nRoot-Is-Purelib: false`nTag: $wheelTag`n", $utf8NoBom) + + [System.IO.File]::WriteAllText("$distInfoDir/METADATA", + "Metadata-Version: 2.1`nName: $normalizedName`nVersion: $pyVersion`n", $utf8NoBom) + + $recordLines = Get-ChildItem $wheelRoot -Recurse -File | ForEach-Object { + $rel = $_.FullName.Substring($wheelRoot.Length + 1).Replace('\', '/') + $raw = (Get-FileHash $_.FullName -Algorithm SHA256).Hash + $bytes = [byte[]]::new($raw.Length / 2) + for ($i = 0; $i -lt $raw.Length; $i += 2) { $bytes[$i/2] = [Convert]::ToByte($raw.Substring($i, 2), 16) } + $b64 = [Convert]::ToBase64String($bytes) -replace '\+','-' -replace '/','_' -replace '=','' + "$rel,sha256=$b64,$($_.Length)" + } + $recordContent = ($recordLines + "$distInfoName.dist-info/RECORD,,") -join "`n" + [System.IO.File]::WriteAllText("$distInfoDir/RECORD", $recordContent, $utf8NoBom) + + # Pack wheel with forward-slash zip entries (Compress-Archive uses backslashes) + $wheelPath = "$stagingDir/$wheelName" + Add-Type -AssemblyName System.IO.Compression.FileSystem + $zip = [System.IO.Compression.ZipFile]::Open($wheelPath, 'Create') + try { + Get-ChildItem $wheelRoot -Recurse -File | ForEach-Object { + $rel = $_.FullName.Substring($wheelRoot.Length + 1).Replace('\', '/') + [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $_.FullName, $rel) | Out-Null + } + } finally { + $zip.Dispose() + } + Write-Host "Created wheel: $wheelName" + } + + Write-Host "`nAll wheels:" + Get-ChildItem $stagingDir -Filter "*.whl" | ForEach-Object { Write-Host " $($_.Name)" } From a559eada3a650a0f5a88c14a2104641186cbf55b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 21:28:33 -0700 Subject: [PATCH 003/112] service connection --- .pipelines/foundry-local-packaging.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 17c968c0..fd6799bf 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -26,12 +26,12 @@ resources: - repository: neutron-server type: git name: AIFoundryLocal/neutron-server - endpoint: aiinfra-AIFoundryLocal-FoundryLocalCore-SP + endpoint: AIFoundryLocal-WindowsAIToolkit-SC ref: refs/heads/dev/FoundryLocalCore/main - repository: test-data-shared type: git name: AIFoundryLocal/test-data-shared - endpoint: aiinfra-AIFoundryLocal-FoundryLocalCore-SP + endpoint: AIFoundryLocal-WindowsAIToolkit-SC lfs: true - repository: 1ESPipelineTemplates type: git From 32285b3f3a0fd22c2f9fa3bd65afcc8ad79961f7 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 21:29:37 -0700 Subject: [PATCH 004/112] windows.ai.toolkit --- .pipelines/foundry-local-packaging.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index fd6799bf..732fba4d 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -25,12 +25,12 @@ resources: repositories: - repository: neutron-server type: git - name: AIFoundryLocal/neutron-server + name: windows.ai.toolkit/neutron-server endpoint: AIFoundryLocal-WindowsAIToolkit-SC ref: refs/heads/dev/FoundryLocalCore/main - repository: test-data-shared type: git - name: AIFoundryLocal/test-data-shared + name: windows.ai.toolkit/test-data-shared endpoint: AIFoundryLocal-WindowsAIToolkit-SC lfs: true - repository: 1ESPipelineTemplates From 95fd7ed323dce7de6ef92e427fbbe3b2387c0bc0 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 21:31:01 -0700 Subject: [PATCH 005/112] self --- .pipelines/foundry-local-packaging.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 732fba4d..4223db1f 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -63,7 +63,7 @@ extends: steps: - checkout: neutron-server clean: true - - template: templates/build-core-steps.yml + - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: win-x64 platform: x64 @@ -78,7 +78,7 @@ extends: steps: - checkout: neutron-server clean: true - - template: templates/build-core-steps.yml + - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: win-arm64 platform: arm64 @@ -95,7 +95,7 @@ extends: steps: - checkout: neutron-server clean: true - - template: templates/build-core-steps.yml + - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: linux-x64 platform: x64 @@ -112,7 +112,7 @@ extends: steps: - checkout: neutron-server clean: true - - template: templates/build-core-steps.yml + - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: osx-arm64 platform: arm64 @@ -128,7 +128,7 @@ extends: steps: - checkout: neutron-server clean: true - - template: templates/build-core-steps.yml + - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: win-x64 platform: x64 @@ -144,7 +144,7 @@ extends: steps: - checkout: neutron-server clean: true - - template: templates/build-core-steps.yml + - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: win-arm64 platform: arm64 @@ -181,7 +181,7 @@ extends: steps: - checkout: neutron-server clean: true - - template: templates/package-core-steps.yml + - template: .pipelines/templates/package-core-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} @@ -213,7 +213,7 @@ extends: steps: - checkout: neutron-server clean: true - - template: templates/package-core-steps.yml + - template: .pipelines/templates/package-core-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} @@ -245,7 +245,7 @@ extends: clean: true - checkout: test-data-shared lfs: true - - template: templates/build-cs-steps.yml + - template: .pipelines/templates/build-cs-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} @@ -273,7 +273,7 @@ extends: clean: true - checkout: test-data-shared lfs: true - - template: templates/build-cs-steps.yml + - template: .pipelines/templates/build-cs-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} @@ -301,7 +301,7 @@ extends: clean: true - checkout: test-data-shared lfs: true - - template: templates/build-js-steps.yml + - template: .pipelines/templates/build-js-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} From 371af5158a734d2e11134544a9e3da3b8489bf17 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 21:33:50 -0700 Subject: [PATCH 006/112] each --- .pipelines/templates/package-core-steps.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index c4cb12f2..834ee881 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -30,13 +30,13 @@ steps: $unifiedPath = "$(Build.ArtifactStagingDirectory)/unified" New-Item -ItemType Directory -Path $unifiedPath -Force | Out-Null - $platforms = @( - ${{ each p in parameters.platforms }}: - @{name="${{ p.name }}"; artifact="${{ p.artifactName }}"}, - ) + $platformsJson = @' + ${{ convertToJson(parameters.platforms) }} + '@ + $platforms = $platformsJson | ConvertFrom-Json foreach ($p in $platforms) { - $srcDir = "$(Pipeline.Workspace)/$($p.artifact)/native" + $srcDir = "$(Pipeline.Workspace)/$($p.artifactName)/native" if (-not (Test-Path $srcDir)) { Write-Warning "No artifact directory found at $srcDir" continue From 1e51dfa474d416f0821b7587675e1172fbd4e98f Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 21:35:47 -0700 Subject: [PATCH 007/112] sdl --- .pipelines/foundry-local-packaging.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 4223db1f..23a05e45 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -43,6 +43,12 @@ extends: parameters: settings: networkIsolationPolicy: Permissive + sdl: + sourceRepositoriesToScan: + include: + - repository: self + - repository: neutron-server + - repository: test-data-shared pool: name: onnxruntime-Win-CPU-2022 os: windows From 8af728ef7756cd663bbf0900b2ed9acf4a920a63 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 21:41:01 -0700 Subject: [PATCH 008/112] esrpserviceconnection --- .pipelines/foundry-local-packaging.yml | 4 ++++ .pipelines/templates/build-cs-steps.yml | 6 ++++-- .pipelines/templates/package-core-steps.yml | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 23a05e45..88665758 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -192,6 +192,7 @@ extends: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: false + esrpServiceConnection: $(esrpServiceConnection) platforms: - name: win-x64 artifactName: flc-win-x64 @@ -224,6 +225,7 @@ extends: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: true + esrpServiceConnection: $(esrpServiceConnection) platforms: - name: win-x64 artifactName: flc-winml-win-x64 @@ -256,6 +258,7 @@ extends: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: false + esrpServiceConnection: $(esrpServiceConnection) flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' # ── Stage 3: Build C# SDK (WinML) ───────────────────────── @@ -284,6 +287,7 @@ extends: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: true + esrpServiceConnection: $(esrpServiceConnection) flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' # ── Stage 4: Build JS SDK ───────────────────────────── diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index dfa6c456..7631e9a8 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -13,6 +13,8 @@ parameters: - name: flcNugetDir type: string displayName: 'Path to directory containing the FLC .nupkg' +- name: esrpServiceConnection + type: string steps: # Set paths for multi-repo checkout @@ -134,7 +136,7 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign SDK DLLs' inputs: - ConnectedServiceName: '$(esrpServiceConnection)' + ConnectedServiceName: '${{ parameters.esrpServiceConnection }}' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' @@ -169,7 +171,7 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign SDK NuGet package' inputs: - ConnectedServiceName: '$(esrpServiceConnection)' + ConnectedServiceName: '${{ parameters.esrpServiceConnection }}' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 834ee881..17201b6e 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -12,6 +12,8 @@ parameters: default: false - name: platforms type: object # list of { name, artifactName } +- name: esrpServiceConnection + type: string steps: - task: PowerShell@2 @@ -119,7 +121,7 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign FLC NuGet package' inputs: - ConnectedServiceName: '$(esrpServiceConnection)' + ConnectedServiceName: '${{ parameters.esrpServiceConnection }}' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' From 94e563ad8e795e5e5936602e979ddf25d3e155ed Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 21:46:44 -0700 Subject: [PATCH 009/112] esrpserviceconnection --- .pipelines/foundry-local-packaging.yml | 8 +++----- .pipelines/templates/build-cs-steps.yml | 12 +++++++----- .pipelines/templates/package-core-steps.yml | 4 +--- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 88665758..ff11b580 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -20,6 +20,8 @@ parameters: variables: - group: FoundryLocal-ESRP-Signing +- name: esrpServiceConnection + value: 'OnnxrunTimeCodeSign_20240611' # <-- Service Connection Name must be static resources: repositories: @@ -46,7 +48,6 @@ extends: sdl: sourceRepositoriesToScan: include: - - repository: self - repository: neutron-server - repository: test-data-shared pool: @@ -192,7 +193,6 @@ extends: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: false - esrpServiceConnection: $(esrpServiceConnection) platforms: - name: win-x64 artifactName: flc-win-x64 @@ -225,7 +225,6 @@ extends: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: true - esrpServiceConnection: $(esrpServiceConnection) platforms: - name: win-x64 artifactName: flc-winml-win-x64 @@ -258,7 +257,6 @@ extends: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: false - esrpServiceConnection: $(esrpServiceConnection) flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' # ── Stage 3: Build C# SDK (WinML) ───────────────────────── @@ -287,8 +285,8 @@ extends: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: true - esrpServiceConnection: $(esrpServiceConnection) flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + outputDir: '$(Build.ArtifactStagingDirectory)/cs-sdk-winml' # ── Stage 4: Build JS SDK ───────────────────────────── - stage: build_js diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 7631e9a8..4f074676 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -13,8 +13,10 @@ parameters: - name: flcNugetDir type: string displayName: 'Path to directory containing the FLC .nupkg' -- name: esrpServiceConnection +- name: outputDir type: string + default: '$(Build.ArtifactStagingDirectory)/cs-sdk' + displayName: 'Path to directory for the packed SDK' steps: # Set paths for multi-repo checkout @@ -136,7 +138,7 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign SDK DLLs' inputs: - ConnectedServiceName: '${{ parameters.esrpServiceConnection }}' + ConnectedServiceName: '$(esrpServiceConnection)' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' @@ -160,7 +162,7 @@ steps: script: | dotnet pack "$(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj" ` --no-build --configuration Release ` - --output "$(Build.ArtifactStagingDirectory)/cs-sdk" ` + --output "${{ parameters.outputDir }}" ` /p:PackageVersion=$(packageVersion) ` /p:UseWinML=${{ parameters.isWinML }} ` /p:IncludeSymbols=true ` @@ -171,14 +173,14 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign SDK NuGet package' inputs: - ConnectedServiceName: '${{ parameters.esrpServiceConnection }}' + ConnectedServiceName: '$(esrpServiceConnection)' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' EsrpClientId: '$(esrpClientId)' AuthAKVName: '$(esrpAkvName)' AuthSignCertName: '$(esrpSignCertName)' - FolderPath: '$(Build.ArtifactStagingDirectory)/cs-sdk' + FolderPath: '${{ parameters.outputDir }}' Pattern: '*.nupkg' SessionTimeout: 90 ServiceEndpointUrl: 'https://api.esrp.microsoft.com/api/v2' diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 17201b6e..834ee881 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -12,8 +12,6 @@ parameters: default: false - name: platforms type: object # list of { name, artifactName } -- name: esrpServiceConnection - type: string steps: - task: PowerShell@2 @@ -121,7 +119,7 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign FLC NuGet package' inputs: - ConnectedServiceName: '${{ parameters.esrpServiceConnection }}' + ConnectedServiceName: '$(esrpServiceConnection)' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' From 6165124e895bb695cc090b0db9c3bb5e2b507700 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 23:10:42 -0700 Subject: [PATCH 010/112] hardcode sc --- .pipelines/templates/build-cs-steps.yml | 4 ++-- .pipelines/templates/package-core-steps.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 4f074676..8994ac73 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -138,7 +138,7 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign SDK DLLs' inputs: - ConnectedServiceName: '$(esrpServiceConnection)' + ConnectedServiceName: 'OnnxrunTimeCodeSign_20240611' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' @@ -173,7 +173,7 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign SDK NuGet package' inputs: - ConnectedServiceName: '$(esrpServiceConnection)' + ConnectedServiceName: 'OnnxrunTimeCodeSign_20240611' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 834ee881..af2828ec 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -119,7 +119,7 @@ steps: - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 displayName: 'Sign FLC NuGet package' inputs: - ConnectedServiceName: '$(esrpServiceConnection)' + ConnectedServiceName: 'OnnxrunTimeCodeSign_20240611' UseMSIAuthentication: true AppRegistrationClientId: '$(esrpClientId)' AppRegistrationTenantId: '$(esrpTenantId)' From bd82fb41be438651c41fdb58a8a57f8b946dbeaa Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 23:11:26 -0700 Subject: [PATCH 011/112] rmv var --- .pipelines/foundry-local-packaging.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index ff11b580..82f0b10d 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -18,11 +18,6 @@ parameters: type: boolean default: false -variables: -- group: FoundryLocal-ESRP-Signing -- name: esrpServiceConnection - value: 'OnnxrunTimeCodeSign_20240611' # <-- Service Connection Name must be static - resources: repositories: - repository: neutron-server From cf19384d72270253e3fae761c69b02e9d5c26ef8 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 23:13:42 -0700 Subject: [PATCH 012/112] main --- .pipelines/foundry-local-packaging.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 82f0b10d..e0ef56ff 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -30,6 +30,7 @@ resources: name: windows.ai.toolkit/test-data-shared endpoint: AIFoundryLocal-WindowsAIToolkit-SC lfs: true + ref: refs/heads/main - repository: 1ESPipelineTemplates type: git name: 1ESPipelineTemplates/1ESPipelineTemplates From 4884bffcd66e8903cc6133d35cd2a606259f77fc Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 23:26:16 -0700 Subject: [PATCH 013/112] fixes --- .pipelines/foundry-local-packaging.yml | 39 +++++++++++++++++---- .pipelines/templates/build-core-steps.yml | 2 +- .pipelines/templates/package-core-steps.yml | 2 +- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index e0ef56ff..31efcca5 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -46,11 +46,6 @@ extends: include: - repository: neutron-server - repository: test-data-shared - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - customBuildTags: - - ES365AIMigrationTooling-Release stages: # ── Stage 1: Build Foundry Local Core ── - stage: build_core @@ -58,6 +53,9 @@ extends: jobs: - job: flc_win_x64 displayName: 'FLC win-x64' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: outputs: - output: pipelineArtifact @@ -73,6 +71,9 @@ extends: - job: flc_win_arm64 displayName: 'FLC win-arm64' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: outputs: - output: pipelineArtifact @@ -89,7 +90,8 @@ extends: - job: flc_linux_x64 displayName: 'FLC linux-x64' pool: - vmImage: 'ubuntu-latest' + name: onnxruntime-Ubuntu2404-AMD-CPU + os: linux templateContext: outputs: - output: pipelineArtifact @@ -106,7 +108,9 @@ extends: - job: flc_osx_arm64 displayName: 'FLC osx-arm64' pool: - vmImage: 'macos-14-arm64' + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS templateContext: outputs: - output: pipelineArtifact @@ -123,6 +127,9 @@ extends: # WinML variants (Windows-only) - job: flc_winml_win_x64 displayName: 'FLC win-x64 (WinML)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: outputs: - output: pipelineArtifact @@ -139,6 +146,9 @@ extends: - job: flc_winml_win_arm64 displayName: 'FLC win-arm64 (WinML)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: outputs: - output: pipelineArtifact @@ -160,6 +170,9 @@ extends: jobs: - job: package_flc displayName: 'Package FLC (standard)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: inputs: - input: pipelineArtifact @@ -201,6 +214,9 @@ extends: - job: package_flc_winml displayName: 'Package FLC (WinML)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: inputs: - input: pipelineArtifact @@ -234,6 +250,9 @@ extends: jobs: - job: cs_sdk displayName: 'Build' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: inputs: - input: pipelineArtifact @@ -262,6 +281,9 @@ extends: jobs: - job: cs_sdk_winml displayName: 'Build' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: inputs: - input: pipelineArtifact @@ -291,6 +313,9 @@ extends: jobs: - job: js_sdk displayName: 'Build' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: inputs: - input: pipelineArtifact diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 389e455d..f4070f36 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -16,7 +16,7 @@ steps: inputs: targetType: inline script: | - $nsRoot = "$(Agent.BuildDirectory)/s/neutron-server" + $nsRoot = "$(Build.SourcesDirectory)" Write-Host "##vso[task.setvariable variable=nsRoot]$nsRoot" - task: UseDotNet@2 diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index af2828ec..4d24cd7e 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -19,7 +19,7 @@ steps: inputs: targetType: inline script: | - $nsRoot = "$(Agent.BuildDirectory)/s/neutron-server" + $nsRoot = "$(Build.SourcesDirectory)" Write-Host "##vso[task.setvariable variable=nsRoot]$nsRoot" - task: PowerShell@2 From f4ba0abf0475a3a3ed9087abb97964b682c38fac Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 23:27:51 -0700 Subject: [PATCH 014/112] formatting --- .pipelines/foundry-local-packaging.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 31efcca5..49fecb75 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -49,7 +49,7 @@ extends: stages: # ── Stage 1: Build Foundry Local Core ── - stage: build_core - displayName: 'Build Foundry Local Core' + displayName: 'Build FLC' jobs: - job: flc_win_x64 displayName: 'FLC win-x64' @@ -163,9 +163,9 @@ extends: platform: arm64 isWinML: true - # ── Stage 2: Package FLC NuGet ───────────────────────────── + # ── Stage 2: Package Foundry Local Core ───────────────────────────── - stage: package_core - displayName: 'Package FLC NuGet' + displayName: 'Package FLC' dependsOn: build_core jobs: - job: package_flc @@ -276,7 +276,7 @@ extends: # ── Stage 3: Build C# SDK (WinML) ───────────────────────── - stage: build_cs_winml - displayName: 'Build C# SDK (WinML)' + displayName: 'Build C# SDK WinML' dependsOn: package_core jobs: - job: cs_sdk_winml From dca101d7ab88825f7b269457516ea642044567a4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 23:28:58 -0700 Subject: [PATCH 015/112] defaukt pool --- .pipelines/foundry-local-packaging.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 49fecb75..e7ba07ba 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -41,6 +41,9 @@ extends: parameters: settings: networkIsolationPolicy: Permissive + pool: + name: onnxruntime-Win-CPU-2022 + os: windows sdl: sourceRepositoriesToScan: include: From 52ec9288b05f0ac62c4aa72f6cd3e9c68b84f2db Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 23:37:27 -0700 Subject: [PATCH 016/112] externalFeedCredentials --- .pipelines/templates/build-core-steps.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index f4070f36..a830d092 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -38,6 +38,7 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' + externalFeedCredentials: 'AIFoundryLocal-WindowsAIToolkit-SC' - task: DotNetCoreCLI@2 displayName: 'Build FLC ${{ parameters.flavor }} (WinML)' @@ -64,6 +65,7 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' + externalFeedCredentials: 'AIFoundryLocal-WindowsAIToolkit-SC' - task: DotNetCoreCLI@2 displayName: 'Build FLC ${{ parameters.flavor }}' From 136089f86748a474e432927e70ce00c7f5f296ab Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 25 Mar 2026 23:45:44 -0700 Subject: [PATCH 017/112] nuget.config --- .pipelines/templates/build-core-steps.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index a830d092..ba4fd8d9 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -26,6 +26,23 @@ steps: useGlobalJson: true workingDirectory: '$(nsRoot)' +- task: PowerShell@2 + displayName: 'Override nuget.config' + inputs: + targetType: inline + script: | + $nugetConfig = @" + + + + + + + + "@ + Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig + Write-Host "Updated nuget.config to use ORT-Nightly" + - task: NuGetAuthenticate@1 displayName: 'Authenticate NuGet feeds' @@ -38,7 +55,6 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - externalFeedCredentials: 'AIFoundryLocal-WindowsAIToolkit-SC' - task: DotNetCoreCLI@2 displayName: 'Build FLC ${{ parameters.flavor }} (WinML)' @@ -65,7 +81,6 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - externalFeedCredentials: 'AIFoundryLocal-WindowsAIToolkit-SC' - task: DotNetCoreCLI@2 displayName: 'Build FLC ${{ parameters.flavor }}' From 9fbd0ec40c8a2c12aa8c7def16bc7ad5b19c00a6 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 00:01:32 -0700 Subject: [PATCH 018/112] restore --- .pipelines/templates/build-core-steps.yml | 48 +++++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index ba4fd8d9..64d92140 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -48,19 +48,35 @@ steps: - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 - displayName: 'Restore FLC ${{ parameters.flavor }} (WinML)' + displayName: 'Restore FLC Core ${{ parameters.flavor }} (WinML)' inputs: command: restore - projects: '$(nsRoot)/foundry_local_core.proj' + projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' + restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + feedsToUse: config + nugetConfigPath: '$(nsRoot)/nuget.config' + + - task: DotNetCoreCLI@2 + displayName: 'Restore FLC Tests ${{ parameters.flavor }} (WinML)' + inputs: + command: restore + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - task: DotNetCoreCLI@2 - displayName: 'Build FLC ${{ parameters.flavor }} (WinML)' + displayName: 'Build FLC Core ${{ parameters.flavor }} (WinML)' + inputs: + command: build + projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' + arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + + - task: DotNetCoreCLI@2 + displayName: 'Build FLC Tests ${{ parameters.flavor }} (WinML)' inputs: command: build - projects: '$(nsRoot)/foundry_local_core.proj' + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - task: DotNetCoreCLI@2 @@ -74,19 +90,35 @@ steps: - ${{ if eq(parameters.isWinML, false) }}: - task: DotNetCoreCLI@2 - displayName: 'Restore FLC ${{ parameters.flavor }}' + displayName: 'Restore FLC Core ${{ parameters.flavor }}' inputs: command: restore - projects: '$(nsRoot)/foundry_local_core.proj' + projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' + restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' + feedsToUse: config + nugetConfigPath: '$(nsRoot)/nuget.config' + + - task: DotNetCoreCLI@2 + displayName: 'Restore FLC Tests ${{ parameters.flavor }}' + inputs: + command: restore + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - task: DotNetCoreCLI@2 - displayName: 'Build FLC ${{ parameters.flavor }}' + displayName: 'Build FLC Core ${{ parameters.flavor }}' + inputs: + command: build + projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' + + - task: DotNetCoreCLI@2 + displayName: 'Build FLC Tests ${{ parameters.flavor }}' inputs: command: build - projects: '$(nsRoot)/foundry_local_core.proj' + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' - task: DotNetCoreCLI@2 From 3c1e098db6ca533f413750c1daf948d7754ed626 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 00:10:55 -0700 Subject: [PATCH 019/112] nuget --- .pipelines/templates/build-core-steps.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 64d92140..802f6b9c 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -36,12 +36,13 @@ steps: + "@ Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig - Write-Host "Updated nuget.config to use ORT-Nightly" + Write-Host "Updated nuget.config to use nuget.org and ORT-Nightly" - task: NuGetAuthenticate@1 displayName: 'Authenticate NuGet feeds' From 37a428be4a6af1de7fa0cb9e316a0c3a03db033a Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 00:20:51 -0700 Subject: [PATCH 020/112] only nuget.org --- .pipelines/templates/build-core-steps.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 802f6b9c..c3d2a866 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -37,15 +37,11 @@ steps: - "@ Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig - Write-Host "Updated nuget.config to use nuget.org and ORT-Nightly" - -- task: NuGetAuthenticate@1 - displayName: 'Authenticate NuGet feeds' + Write-Host "Updated nuget.config to use nuget.org" - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 From 33200576ce6d60d6d4ec5302b3d8144a2fb98dfb Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 00:27:30 -0700 Subject: [PATCH 021/112] mapping --- .pipelines/templates/build-core-steps.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index c3d2a866..693d6bb3 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -37,11 +37,23 @@ steps: + + + + + + + + + "@ Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig - Write-Host "Updated nuget.config to use nuget.org" + Write-Host "Updated nuget.config to use nuget.org and ORT-Nightly with mappings" + +- task: NuGetAuthenticate@1 + displayName: 'Authenticate NuGet feeds' - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 From 62e0f30a4029dfe52246419115b93758dbecb42c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 00:33:31 -0700 Subject: [PATCH 022/112] pattern --- .pipelines/templates/build-core-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 693d6bb3..596b46b2 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -41,7 +41,7 @@ steps: - + From 800682a2e55f9e17bf3e4fc11b56f540c0041d75 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 00:38:30 -0700 Subject: [PATCH 023/112] pls --- .pipelines/templates/build-core-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 596b46b2..aad87607 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -41,7 +41,7 @@ steps: - + From d491abbb4df6dbde580ed8cda695eb0fa7bb2a3e Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 00:46:52 -0700 Subject: [PATCH 024/112] only ort-nightly --- .pipelines/templates/build-core-steps.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index aad87607..7e56052b 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -36,17 +36,8 @@ steps: - - - - - - - - - "@ Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig From 8de6e15ce1c7c5d820f7966a335994a1988fad3c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 00:56:56 -0700 Subject: [PATCH 025/112] no auth --- .pipelines/templates/build-core-steps.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 7e56052b..35438323 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -43,9 +43,6 @@ steps: Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig Write-Host "Updated nuget.config to use nuget.org and ORT-Nightly with mappings" -- task: NuGetAuthenticate@1 - displayName: 'Authenticate NuGet feeds' - - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Core ${{ parameters.flavor }} (WinML)' From dcea1601e8e88cdc023401f6e496d1421fd9d875 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 01:05:40 -0700 Subject: [PATCH 026/112] NUGET_CREDENTIALPROVIDERS_PATH --- .pipelines/templates/build-core-steps.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 35438323..287e94b8 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -52,6 +52,8 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' + env: + NUGET_CREDENTIALPROVIDERS_PATH: '' - task: DotNetCoreCLI@2 displayName: 'Restore FLC Tests ${{ parameters.flavor }} (WinML)' @@ -61,6 +63,8 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' + env: + NUGET_CREDENTIALPROVIDERS_PATH: '' - task: DotNetCoreCLI@2 displayName: 'Build FLC Core ${{ parameters.flavor }} (WinML)' @@ -94,6 +98,8 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' + env: + NUGET_CREDENTIALPROVIDERS_PATH: '' - task: DotNetCoreCLI@2 displayName: 'Restore FLC Tests ${{ parameters.flavor }}' @@ -103,6 +109,8 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' + env: + NUGET_CREDENTIALPROVIDERS_PATH: '' - task: DotNetCoreCLI@2 displayName: 'Build FLC Core ${{ parameters.flavor }}' From 0a514ac4cf8fa95a0cc106495866cf139f6de5ab Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 01:20:26 -0700 Subject: [PATCH 027/112] try --- .pipelines/templates/build-core-steps.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 287e94b8..af632968 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -36,8 +36,17 @@ steps: + + + + + + + + + "@ Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig @@ -52,8 +61,6 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - env: - NUGET_CREDENTIALPROVIDERS_PATH: '' - task: DotNetCoreCLI@2 displayName: 'Restore FLC Tests ${{ parameters.flavor }} (WinML)' @@ -63,8 +70,6 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - env: - NUGET_CREDENTIALPROVIDERS_PATH: '' - task: DotNetCoreCLI@2 displayName: 'Build FLC Core ${{ parameters.flavor }} (WinML)' @@ -98,8 +103,6 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - env: - NUGET_CREDENTIALPROVIDERS_PATH: '' - task: DotNetCoreCLI@2 displayName: 'Restore FLC Tests ${{ parameters.flavor }}' @@ -109,8 +112,6 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - env: - NUGET_CREDENTIALPROVIDERS_PATH: '' - task: DotNetCoreCLI@2 displayName: 'Build FLC Core ${{ parameters.flavor }}' From a2c8227aa80a4c66f453a9201fa9c58db6ed7693 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 01:31:37 -0700 Subject: [PATCH 028/112] telemetry --- .pipelines/templates/build-core-steps.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index af632968..832f6ac0 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -40,7 +40,9 @@ steps: + # https://github.com/microsoft/azure-pipelines-tasks/issues/20910 + @@ -85,6 +87,13 @@ steps: projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + - task: DotNetCoreCLI@2 + displayName: 'Test FLC ${{ parameters.flavor }} (WinML)' + inputs: + command: test + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + arguments: '--no-build --configuration Release -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + - task: DotNetCoreCLI@2 displayName: 'Publish FLC AOT ${{ parameters.flavor }} (WinML)' inputs: @@ -127,6 +136,13 @@ steps: projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' + - task: DotNetCoreCLI@2 + displayName: 'Test FLC ${{ parameters.flavor }}' + inputs: + command: test + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + arguments: '--no-build --configuration Release -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }}' + - task: DotNetCoreCLI@2 displayName: 'Publish FLC AOT ${{ parameters.flavor }}' inputs: From 662c3b3ba64820410847689f0aa73b7659897a2c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 01:41:37 -0700 Subject: [PATCH 029/112] tests --- .pipelines/templates/build-core-steps.yml | 26 ++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 832f6ac0..3b454f5d 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -87,12 +87,13 @@ steps: projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - - task: DotNetCoreCLI@2 - displayName: 'Test FLC ${{ parameters.flavor }} (WinML)' - inputs: - command: test - projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' - arguments: '--no-build --configuration Release -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + - ${{ if eq(parameters.flavor, 'win-x64') }}: + - task: DotNetCoreCLI@2 + displayName: 'Test FLC ${{ parameters.flavor }} (WinML)' + inputs: + command: test + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + arguments: '--no-build --configuration Release -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - task: DotNetCoreCLI@2 displayName: 'Publish FLC AOT ${{ parameters.flavor }} (WinML)' @@ -136,12 +137,13 @@ steps: projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' - - task: DotNetCoreCLI@2 - displayName: 'Test FLC ${{ parameters.flavor }}' - inputs: - command: test - projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' - arguments: '--no-build --configuration Release -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }}' + - ${{ if eq(parameters.flavor, 'win-x64') }}: + - task: DotNetCoreCLI@2 + displayName: 'Test FLC ${{ parameters.flavor }}' + inputs: + command: test + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + arguments: '--no-build --configuration Release -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }}' - task: DotNetCoreCLI@2 displayName: 'Publish FLC AOT ${{ parameters.flavor }}' From 499ca6918ae4ab4c20ddf86ddc2e9c7f46f0615b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 01:53:48 -0700 Subject: [PATCH 030/112] neutron --- .pipelines/templates/build-core-steps.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 3b454f5d..a5b66730 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -38,13 +38,16 @@ steps: + # https://github.com/microsoft/azure-pipelines-tasks/issues/20910 - + + + @@ -52,7 +55,7 @@ steps: "@ Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig - Write-Host "Updated nuget.config to use nuget.org and ORT-Nightly with mappings" + Write-Host "Updated nuget.config to use nuget.org, ORT-Nightly, and Neutron with mappings" - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 From afdd39c9adc5c5153b81dd7102d129c3b0e97a09 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 08:43:11 -0700 Subject: [PATCH 031/112] Neutron --- .pipelines/templates/build-core-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index a5b66730..32028737 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -45,7 +45,7 @@ steps: - + From d288a4c0e9f31f3f0d2ad83781a7695418dd0973 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 08:58:09 -0700 Subject: [PATCH 032/112] telemetry on ort-nightly --- .pipelines/templates/build-core-steps.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 32028737..05122a27 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -38,14 +38,11 @@ steps: - # https://github.com/microsoft/azure-pipelines-tasks/issues/20910 - - From bd8966b3feed75c110823ad0b6752a7a1f269f6e Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 09:08:43 -0700 Subject: [PATCH 033/112] tests --- .pipelines/templates/build-core-steps.yml | 56 +++++++---------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 05122a27..cd76ddc7 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -64,15 +64,6 @@ steps: feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - - task: DotNetCoreCLI@2 - displayName: 'Restore FLC Tests ${{ parameters.flavor }} (WinML)' - inputs: - command: restore - projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' - restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - feedsToUse: config - nugetConfigPath: '$(nsRoot)/nuget.config' - - task: DotNetCoreCLI@2 displayName: 'Build FLC Core ${{ parameters.flavor }} (WinML)' inputs: @@ -80,21 +71,6 @@ steps: projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - - task: DotNetCoreCLI@2 - displayName: 'Build FLC Tests ${{ parameters.flavor }} (WinML)' - inputs: - command: build - projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - - - ${{ if eq(parameters.flavor, 'win-x64') }}: - - task: DotNetCoreCLI@2 - displayName: 'Test FLC ${{ parameters.flavor }} (WinML)' - inputs: - command: test - projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' - arguments: '--no-build --configuration Release -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - - task: DotNetCoreCLI@2 displayName: 'Publish FLC AOT ${{ parameters.flavor }} (WinML)' inputs: @@ -114,15 +90,6 @@ steps: feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - - task: DotNetCoreCLI@2 - displayName: 'Restore FLC Tests ${{ parameters.flavor }}' - inputs: - command: restore - projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' - restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' - feedsToUse: config - nugetConfigPath: '$(nsRoot)/nuget.config' - - task: DotNetCoreCLI@2 displayName: 'Build FLC Core ${{ parameters.flavor }}' inputs: @@ -130,14 +97,23 @@ steps: projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' - - task: DotNetCoreCLI@2 - displayName: 'Build FLC Tests ${{ parameters.flavor }}' - inputs: - command: build - projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' - - ${{ if eq(parameters.flavor, 'win-x64') }}: + - task: DotNetCoreCLI@2 + displayName: 'Restore FLC Tests ${{ parameters.flavor }}' + inputs: + command: restore + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' + feedsToUse: config + nugetConfigPath: '$(nsRoot)/nuget.config' + + - task: DotNetCoreCLI@2 + displayName: 'Build FLC Tests ${{ parameters.flavor }}' + inputs: + command: build + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' + - task: DotNetCoreCLI@2 displayName: 'Test FLC ${{ parameters.flavor }}' inputs: From 40f59dd2bb3eb0702658af6903f254f3ebf95755 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 09:30:44 -0700 Subject: [PATCH 034/112] test-data-shared --- .pipelines/foundry-local-packaging.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index e7ba07ba..0f80f6f8 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -122,6 +122,8 @@ extends: steps: - checkout: neutron-server clean: true + - checkout: test-data-shared + lfs: true - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: osx-arm64 From d75684c420b46257388d8f6c14ba84913614fa37 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 09:32:48 -0700 Subject: [PATCH 035/112] scan --- .pipelines/templates/build-core-steps.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index cd76ddc7..db066122 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -69,14 +69,11 @@ steps: inputs: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - - - task: DotNetCoreCLI@2 - displayName: 'Publish FLC AOT ${{ parameters.flavor }} (WinML)' + arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore --no-build -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + arguments: '--no-restore --no-build -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' publishWebProjects: false zipAfterPublish: false @@ -95,7 +92,7 @@ steps: inputs: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:CfgSupport=true' - ${{ if eq(parameters.flavor, 'win-x64') }}: - task: DotNetCoreCLI@2 @@ -106,7 +103,7 @@ steps: restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:TargetFramework=net9.0' feedsToUse: config nugetConfigPath: '$(nsRoot)/nuget.config' - + - task: DotNetCoreCLI@2 displayName: 'Build FLC Tests ${{ parameters.flavor }}' inputs: @@ -126,7 +123,7 @@ steps: inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore --no-build -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0' + arguments: '--no-restore --no-build -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0 /p:CfgSupport=true' publishWebProjects: false zipAfterPublish: false From 3c5d988ba44208f5e5c7b57e69ffa4e9b181de6b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 09:34:09 -0700 Subject: [PATCH 036/112] corr --- .pipelines/templates/build-core-steps.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index db066122..37b96bac 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -70,12 +70,6 @@ steps: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' - inputs: - command: publish - projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore --no-build -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' - publishWebProjects: false - zipAfterPublish: false - ${{ if eq(parameters.isWinML, false) }}: - task: DotNetCoreCLI@2 From 6513426be3f83bbf3e394837fb1ba8e8021a9392 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 09:41:16 -0700 Subject: [PATCH 037/112] Test-Data --- .pipelines/foundry-local-packaging.yml | 4 ++-- .pipelines/templates/build-core-steps.yml | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 0f80f6f8..c578122f 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -67,6 +67,8 @@ extends: steps: - checkout: neutron-server clean: true + - checkout: test-data-shared + lfs: true - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: win-x64 @@ -122,8 +124,6 @@ extends: steps: - checkout: neutron-server clean: true - - checkout: test-data-shared - lfs: true - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: osx-arm64 diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 37b96bac..3ae8650a 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -16,8 +16,15 @@ steps: inputs: targetType: inline script: | - $nsRoot = "$(Build.SourcesDirectory)" + # Multi-checkout places repos in subdirectories; single checkout places contents at root + $multiCheckout = "$(Build.SourcesDirectory)/neutron-server" + if (Test-Path $multiCheckout) { + $nsRoot = $multiCheckout + } else { + $nsRoot = "$(Build.SourcesDirectory)" + } Write-Host "##vso[task.setvariable variable=nsRoot]$nsRoot" + Write-Host "neutron-server root: $nsRoot" - task: UseDotNet@2 displayName: 'Use .NET SDK from global.json' From 86e787861d8ffb34c9f25f41c39a8580ecee1137 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 10:32:15 -0700 Subject: [PATCH 038/112] inject cfg --- .pipelines/foundry-local-packaging.yml | 1 + .pipelines/templates/build-core-steps.yml | 31 ++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index c578122f..1697219a 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -42,6 +42,7 @@ extends: settings: networkIsolationPolicy: Permissive pool: + # default for SDL scan, individual jobs override name: onnxruntime-Win-CPU-2022 os: windows sdl: diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 3ae8650a..e5644276 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -61,6 +61,22 @@ steps: Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig Write-Host "Updated nuget.config to use nuget.org, ORT-Nightly, and Neutron with mappings" +- task: PowerShell@2 + displayName: 'Inject CfgSupport into Directory.Build.props' + inputs: + targetType: inline + script: | + $propsPath = "$(nsRoot)/Directory.Build.props" + $xml = [xml](Get-Content $propsPath) + $ns = $xml.Project.NamespaceURI + $pg = $xml.CreateElement('PropertyGroup', $ns) + $cfg = $xml.CreateElement('CfgSupport', $ns) + $cfg.InnerText = 'true' + $pg.AppendChild($cfg) | Out-Null + $xml.Project.AppendChild($pg) | Out-Null + $xml.Save($propsPath) + Write-Host "Injected CfgSupport=true into $propsPath" + - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Core ${{ parameters.flavor }} (WinML)' @@ -76,7 +92,16 @@ steps: inputs: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' + arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + + - task: DotNetCoreCLI@2 + displayName: 'Publish FLC AOT ${{ parameters.flavor }} (WinML)' + inputs: + command: publish + projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' + arguments: '--no-restore --no-build -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + publishWebProjects: false + zipAfterPublish: false - ${{ if eq(parameters.isWinML, false) }}: - task: DotNetCoreCLI@2 @@ -93,7 +118,7 @@ steps: inputs: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:CfgSupport=true' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' - ${{ if eq(parameters.flavor, 'win-x64') }}: - task: DotNetCoreCLI@2 @@ -124,7 +149,7 @@ steps: inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore --no-build -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0 /p:CfgSupport=true' + arguments: '--no-restore --no-build -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0' publishWebProjects: false zipAfterPublish: false From 297674038b7c1afd02bc40e2d15b17d92136b88c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 10:45:54 -0700 Subject: [PATCH 039/112] cfg --- .pipelines/templates/build-core-steps.yml | 24 ++++------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index e5644276..4f26f754 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -61,22 +61,6 @@ steps: Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig Write-Host "Updated nuget.config to use nuget.org, ORT-Nightly, and Neutron with mappings" -- task: PowerShell@2 - displayName: 'Inject CfgSupport into Directory.Build.props' - inputs: - targetType: inline - script: | - $propsPath = "$(nsRoot)/Directory.Build.props" - $xml = [xml](Get-Content $propsPath) - $ns = $xml.Project.NamespaceURI - $pg = $xml.CreateElement('PropertyGroup', $ns) - $cfg = $xml.CreateElement('CfgSupport', $ns) - $cfg.InnerText = 'true' - $pg.AppendChild($cfg) | Out-Null - $xml.Project.AppendChild($pg) | Out-Null - $xml.Save($propsPath) - Write-Host "Injected CfgSupport=true into $propsPath" - - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Core ${{ parameters.flavor }} (WinML)' @@ -92,14 +76,14 @@ steps: inputs: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' - task: DotNetCoreCLI@2 displayName: 'Publish FLC AOT ${{ parameters.flavor }} (WinML)' inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore --no-build -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' publishWebProjects: false zipAfterPublish: false @@ -118,7 +102,7 @@ steps: inputs: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:CfgSupport=true' - ${{ if eq(parameters.flavor, 'win-x64') }}: - task: DotNetCoreCLI@2 @@ -149,7 +133,7 @@ steps: inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore --no-build -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0 /p:CfgSupport=true' publishWebProjects: false zipAfterPublish: false From d25cc8cb010c53dc9b1e8a578ef2d264f51d1189 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 11:00:06 -0700 Subject: [PATCH 040/112] supress --- .pipelines/templates/build-core-steps.yml | 36 ++++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 4f26f754..ae8587a6 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -61,6 +61,34 @@ steps: Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig Write-Host "Updated nuget.config to use nuget.org, ORT-Nightly, and Neutron with mappings" +# Suppress BinSkim BA2008/BA2024 for .NET Native AOT binaries. +# CFG and Spectre mitigations cannot be enabled via the .NET AOT linker (ILC). +- task: PowerShell@2 + displayName: 'Create BinSkim suppression file' + inputs: + targetType: inline + script: | + $gdnDir = "$(Agent.BuildDirectory)/.gdn" + New-Item -ItemType Directory -Path $gdnDir -Force | Out-Null + $suppress = @' + { + "suppressions": [ + { + "tool": "binskim", + "ruleId": "BA2008", + "justification": ".NET Native AOT binary — CFG not supported by ILC linker." + }, + { + "tool": "binskim", + "ruleId": "BA2024", + "justification": ".NET Native AOT binary — Spectre mitigations not applicable to SDK-shipped runtime libs." + } + ] + } + '@ + Set-Content -Path "$gdnDir/.gdnsuppress" -Value $suppress + Write-Host "Created BinSkim suppression at $gdnDir/.gdnsuppress" + - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Core ${{ parameters.flavor }} (WinML)' @@ -76,14 +104,14 @@ steps: inputs: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' + arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' - task: DotNetCoreCLI@2 displayName: 'Publish FLC AOT ${{ parameters.flavor }} (WinML)' inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true /p:CfgSupport=true' + arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' publishWebProjects: false zipAfterPublish: false @@ -102,7 +130,7 @@ steps: inputs: command: build projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:CfgSupport=true' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' - ${{ if eq(parameters.flavor, 'win-x64') }}: - task: DotNetCoreCLI@2 @@ -133,7 +161,7 @@ steps: inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0 /p:CfgSupport=true' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0' publishWebProjects: false zipAfterPublish: false From 6b49475b662e793091f3e72ed455f2a8e0fe0159 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 11:10:42 -0700 Subject: [PATCH 041/112] naming --- .pipelines/foundry-local-packaging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 1697219a..71170601 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -175,7 +175,7 @@ extends: dependsOn: build_core jobs: - job: package_flc - displayName: 'Package FLC (standard)' + displayName: 'Package FLC' pool: name: onnxruntime-Win-CPU-2022 os: windows From 89b8892f1517fcd7e7e5f8f8f30de9e574d52160 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 11:13:54 -0700 Subject: [PATCH 042/112] custom core --- .pipelines/foundry-local-packaging.yml | 2 +- .pipelines/templates/build-core-steps.yml | 28 ----------------------- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 71170601..4f520359 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -24,7 +24,7 @@ resources: type: git name: windows.ai.toolkit/neutron-server endpoint: AIFoundryLocal-WindowsAIToolkit-SC - ref: refs/heads/dev/FoundryLocalCore/main + ref: refs/heads/prathikrao/flc-cfg-true - repository: test-data-shared type: git name: windows.ai.toolkit/test-data-shared diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index ae8587a6..c4045fca 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -61,34 +61,6 @@ steps: Set-Content -Path "$(nsRoot)/nuget.config" -Value $nugetConfig Write-Host "Updated nuget.config to use nuget.org, ORT-Nightly, and Neutron with mappings" -# Suppress BinSkim BA2008/BA2024 for .NET Native AOT binaries. -# CFG and Spectre mitigations cannot be enabled via the .NET AOT linker (ILC). -- task: PowerShell@2 - displayName: 'Create BinSkim suppression file' - inputs: - targetType: inline - script: | - $gdnDir = "$(Agent.BuildDirectory)/.gdn" - New-Item -ItemType Directory -Path $gdnDir -Force | Out-Null - $suppress = @' - { - "suppressions": [ - { - "tool": "binskim", - "ruleId": "BA2008", - "justification": ".NET Native AOT binary — CFG not supported by ILC linker." - }, - { - "tool": "binskim", - "ruleId": "BA2024", - "justification": ".NET Native AOT binary — Spectre mitigations not applicable to SDK-shipped runtime libs." - } - ] - } - '@ - Set-Content -Path "$gdnDir/.gdnsuppress" -Value $suppress - Write-Host "Created BinSkim suppression at $gdnDir/.gdnsuppress" - - ${{ if eq(parameters.isWinML, true) }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Core ${{ parameters.flavor }} (WinML)' From eba6681bae9638c94c8992e6220f22b624b6934a Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 12:03:47 -0700 Subject: [PATCH 043/112] binskim --- .pipelines/foundry-local-packaging.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 4f520359..d424e661 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -24,7 +24,7 @@ resources: type: git name: windows.ai.toolkit/neutron-server endpoint: AIFoundryLocal-WindowsAIToolkit-SC - ref: refs/heads/prathikrao/flc-cfg-true + ref: refs/heads/dev/FoundryLocalCore/main - repository: test-data-shared type: git name: windows.ai.toolkit/test-data-shared @@ -46,6 +46,9 @@ extends: name: onnxruntime-Win-CPU-2022 os: windows sdl: + binskim: + break: false + scanOutputDirectoryOnly: true sourceRepositoriesToScan: include: - repository: neutron-server From 7e332699f2f93c7de51622f998b2fce0a7abe104 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 14:10:41 -0700 Subject: [PATCH 044/112] refactor --- .pipelines/foundry-local-packaging.yml | 234 +++++++++++--------- .pipelines/templates/package-core-steps.yml | 10 +- 2 files changed, 135 insertions(+), 109 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index d424e661..1db4b2d0 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -54,7 +54,7 @@ extends: - repository: neutron-server - repository: test-data-shared stages: - # ── Stage 1: Build Foundry Local Core ── + # ── Build FLC ── - stage: build_core displayName: 'Build FLC' jobs: @@ -133,46 +133,7 @@ extends: flavor: osx-arm64 platform: arm64 - # WinML variants (Windows-only) - - job: flc_winml_win_x64 - displayName: 'FLC win-x64 (WinML)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - outputs: - - output: pipelineArtifact - artifactName: 'flc-winml-win-x64' - targetPath: '$(Build.ArtifactStagingDirectory)/native' - steps: - - checkout: neutron-server - clean: true - - template: .pipelines/templates/build-core-steps.yml@self - parameters: - flavor: win-x64 - platform: x64 - isWinML: true - - - job: flc_winml_win_arm64 - displayName: 'FLC win-arm64 (WinML)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - outputs: - - output: pipelineArtifact - artifactName: 'flc-winml-win-arm64' - targetPath: '$(Build.ArtifactStagingDirectory)/native' - steps: - - checkout: neutron-server - clean: true - - template: .pipelines/templates/build-core-steps.yml@self - parameters: - flavor: win-arm64 - platform: arm64 - isWinML: true - - # ── Stage 2: Package Foundry Local Core ───────────────────────────── + # ── Package FLC ── - stage: package_core displayName: 'Package FLC' dependsOn: build_core @@ -183,19 +144,6 @@ extends: name: onnxruntime-Win-CPU-2022 os: windows templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-win-x64' - targetPath: '$(Pipeline.Workspace)/flc-win-x64' - - input: pipelineArtifact - artifactName: 'flc-win-arm64' - targetPath: '$(Pipeline.Workspace)/flc-win-arm64' - - input: pipelineArtifact - artifactName: 'flc-linux-x64' - targetPath: '$(Pipeline.Workspace)/flc-linux-x64' - - input: pipelineArtifact - artifactName: 'flc-osx-arm64' - targetPath: '$(Pipeline.Workspace)/flc-osx-arm64' outputs: - output: pipelineArtifact artifactName: 'flc-nuget' @@ -206,6 +154,26 @@ extends: steps: - checkout: neutron-server clean: true + - task: DownloadPipelineArtifact@2 + inputs: + buildType: current + artifactName: 'flc-win-x64' + targetPath: '$(Pipeline.Workspace)/flc-win-x64' + - task: DownloadPipelineArtifact@2 + inputs: + buildType: current + artifactName: 'flc-win-arm64' + targetPath: '$(Pipeline.Workspace)/flc-win-arm64' + - task: DownloadPipelineArtifact@2 + inputs: + buildType: current + artifactName: 'flc-linux-x64' + targetPath: '$(Pipeline.Workspace)/flc-linux-x64' + - task: DownloadPipelineArtifact@2 + inputs: + buildType: current + artifactName: 'flc-osx-arm64' + targetPath: '$(Pipeline.Workspace)/flc-osx-arm64' - template: .pipelines/templates/package-core-steps.yml@self parameters: version: ${{ parameters.version }} @@ -221,43 +189,43 @@ extends: - name: osx-arm64 artifactName: flc-osx-arm64 - - job: package_flc_winml - displayName: 'Package FLC (WinML)' + # ── Build C# SDK ── + - stage: build_cs + displayName: 'Build C# SDK' + dependsOn: package_core + jobs: + - job: cs_sdk + displayName: 'Build' pool: name: onnxruntime-Win-CPU-2022 os: windows templateContext: inputs: - input: pipelineArtifact - artifactName: 'flc-winml-win-x64' - targetPath: '$(Pipeline.Workspace)/flc-winml-win-x64' - - input: pipelineArtifact - artifactName: 'flc-winml-win-arm64' - targetPath: '$(Pipeline.Workspace)/flc-winml-win-arm64' + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' outputs: - output: pipelineArtifact - artifactName: 'flc-nuget-winml' - targetPath: '$(Build.ArtifactStagingDirectory)/flc-nuget' + artifactName: 'cs-sdk' + targetPath: '$(Build.ArtifactStagingDirectory)/cs-sdk' steps: - - checkout: neutron-server + - checkout: self clean: true - - template: .pipelines/templates/package-core-steps.yml@self + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/build-cs-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} - isWinML: true - platforms: - - name: win-x64 - artifactName: flc-winml-win-x64 - - name: win-arm64 - artifactName: flc-winml-win-arm64 + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Stage 3: Build C# SDK (standard) ────────────────────── - - stage: build_cs - displayName: 'Build C# SDK' + # ── Build JS SDK ── + - stage: build_js + displayName: 'Build JS SDK' dependsOn: package_core jobs: - - job: cs_sdk + - job: js_sdk displayName: 'Build' pool: name: onnxruntime-Win-CPU-2022 @@ -269,58 +237,107 @@ extends: targetPath: '$(Pipeline.Workspace)/flc-nuget' outputs: - output: pipelineArtifact - artifactName: 'cs-sdk' - targetPath: '$(Build.ArtifactStagingDirectory)/cs-sdk' + artifactName: 'js-sdk' + targetPath: '$(Build.ArtifactStagingDirectory)/js-sdk' steps: - checkout: self clean: true - checkout: test-data-shared lfs: true - - template: .pipelines/templates/build-cs-steps.yml@self + - template: .pipelines/templates/build-js-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Stage 3: Build C# SDK (WinML) ───────────────────────── - - stage: build_cs_winml - displayName: 'Build C# SDK WinML' - dependsOn: package_core + # ── Build FLC (WinML) ── + - stage: build_core_winml + displayName: 'Build FLC WinML' jobs: - - job: cs_sdk_winml - displayName: 'Build' + - job: flc_winml_win_x64 + displayName: 'FLC win-x64 (WinML)' pool: name: onnxruntime-Win-CPU-2022 os: windows templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget-winml' - targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' outputs: - output: pipelineArtifact - artifactName: 'cs-sdk-winml' - targetPath: '$(Build.ArtifactStagingDirectory)/cs-sdk-winml' + artifactName: 'flc-winml-win-x64' + targetPath: '$(Build.ArtifactStagingDirectory)/native' steps: - - checkout: self + - checkout: neutron-server clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/build-cs-steps.yml@self + - template: .pipelines/templates/build-core-steps.yml@self + parameters: + flavor: win-x64 + platform: x64 + isWinML: true + + - job: flc_winml_win_arm64 + displayName: 'FLC win-arm64 (WinML)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + outputs: + - output: pipelineArtifact + artifactName: 'flc-winml-win-arm64' + targetPath: '$(Build.ArtifactStagingDirectory)/native' + steps: + - checkout: neutron-server + clean: true + - template: .pipelines/templates/build-core-steps.yml@self + parameters: + flavor: win-arm64 + platform: arm64 + isWinML: true + + # ── Package FLC (WinML) ── + - stage: package_core_winml + displayName: 'Package FLC WinML' + dependsOn: build_core_winml + jobs: + - job: package_flc_winml + displayName: 'Package FLC (WinML)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + outputs: + - output: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Build.ArtifactStagingDirectory)/flc-nuget' + steps: + - checkout: neutron-server + clean: true + - task: DownloadPipelineArtifact@2 + inputs: + buildType: current + artifactName: 'flc-winml-win-x64' + targetPath: '$(Pipeline.Workspace)/flc-winml-win-x64' + - task: DownloadPipelineArtifact@2 + inputs: + buildType: current + artifactName: 'flc-winml-win-arm64' + targetPath: '$(Pipeline.Workspace)/flc-winml-win-arm64' + - template: .pipelines/templates/package-core-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} isWinML: true - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - outputDir: '$(Build.ArtifactStagingDirectory)/cs-sdk-winml' + platforms: + - name: win-x64 + artifactName: flc-winml-win-x64 + - name: win-arm64 + artifactName: flc-winml-win-arm64 - # ── Stage 4: Build JS SDK ───────────────────────────── - - stage: build_js - displayName: 'Build JS SDK' - dependsOn: package_core + # ── Build C# SDK (WinML) ── + - stage: build_cs_winml + displayName: 'Build C# SDK WinML' + dependsOn: package_core_winml jobs: - - job: js_sdk + - job: cs_sdk_winml displayName: 'Build' pool: name: onnxruntime-Win-CPU-2022 @@ -328,20 +345,21 @@ extends: templateContext: inputs: - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' outputs: - output: pipelineArtifact - artifactName: 'js-sdk' - targetPath: '$(Build.ArtifactStagingDirectory)/js-sdk' + artifactName: 'cs-sdk-winml' + targetPath: '$(Build.ArtifactStagingDirectory)/cs-sdk-winml' steps: - checkout: self clean: true - checkout: test-data-shared lfs: true - - template: .pipelines/templates/build-js-steps.yml@self + - template: .pipelines/templates/build-cs-steps.yml@self parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + outputDir: '$(Build.ArtifactStagingDirectory)/cs-sdk-winml' diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 4d24cd7e..ee863d81 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -37,8 +37,16 @@ steps: foreach ($p in $platforms) { $srcDir = "$(Pipeline.Workspace)/$($p.artifactName)/native" + Write-Host "Looking for artifacts at: $srcDir" if (-not (Test-Path $srcDir)) { - Write-Warning "No artifact directory found at $srcDir" + Write-Host "Contents of $(Pipeline.Workspace)/$($p.artifactName):" + if (Test-Path "$(Pipeline.Workspace)/$($p.artifactName)") { + Get-ChildItem "$(Pipeline.Workspace)/$($p.artifactName)" -Recurse | ForEach-Object { Write-Host " $($_.FullName)" } + } else { + Write-Warning "Artifact directory $(Pipeline.Workspace)/$($p.artifactName) does not exist" + Write-Host "Contents of $(Pipeline.Workspace):" + Get-ChildItem "$(Pipeline.Workspace)" -Depth 2 | ForEach-Object { Write-Host " $($_.FullName)" } + } continue } $destDir = "$unifiedPath/runtimes/$($p.name)/native" From 4a878639e1d7cf02ca3cebcbe8794c2776168837 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 14:12:09 -0700 Subject: [PATCH 045/112] explicit dependson --- .pipelines/foundry-local-packaging.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 1db4b2d0..deb7bb0a 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -254,6 +254,7 @@ extends: # ── Build FLC (WinML) ── - stage: build_core_winml displayName: 'Build FLC WinML' + dependsOn: [] jobs: - job: flc_winml_win_x64 displayName: 'FLC win-x64 (WinML)' From 1f7a9fa878d6af6248684799556bdc5587d79bb7 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 14:42:23 -0700 Subject: [PATCH 046/112] no native folder --- .pipelines/templates/package-core-steps.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index ee863d81..10676517 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -36,17 +36,10 @@ steps: $platforms = $platformsJson | ConvertFrom-Json foreach ($p in $platforms) { - $srcDir = "$(Pipeline.Workspace)/$($p.artifactName)/native" + $srcDir = "$(Pipeline.Workspace)/$($p.artifactName)" Write-Host "Looking for artifacts at: $srcDir" if (-not (Test-Path $srcDir)) { - Write-Host "Contents of $(Pipeline.Workspace)/$($p.artifactName):" - if (Test-Path "$(Pipeline.Workspace)/$($p.artifactName)") { - Get-ChildItem "$(Pipeline.Workspace)/$($p.artifactName)" -Recurse | ForEach-Object { Write-Host " $($_.FullName)" } - } else { - Write-Warning "Artifact directory $(Pipeline.Workspace)/$($p.artifactName) does not exist" - Write-Host "Contents of $(Pipeline.Workspace):" - Get-ChildItem "$(Pipeline.Workspace)" -Depth 2 | ForEach-Object { Write-Host " $($_.FullName)" } - } + Write-Warning "Artifact directory $srcDir does not exist" continue } $destDir = "$unifiedPath/runtimes/$($p.name)/native" From e74c263dd6e5a24b4dad2d9e16fa985234a8189a Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 15:12:19 -0700 Subject: [PATCH 047/112] variable group --- .pipelines/foundry-local-packaging.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index deb7bb0a..d2a0e804 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -18,6 +18,9 @@ parameters: type: boolean default: false +variables: +- group: FoundryLocal-ESRP-Signing + resources: repositories: - repository: neutron-server From 0400b23329bef59dda635329b79810646346ec00 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 22:23:46 -0700 Subject: [PATCH 048/112] edits --- .pipelines/foundry-local-packaging.yml | 3 + .pipelines/templates/package-core-steps.yml | 173 ++++++++++---------- 2 files changed, 92 insertions(+), 84 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index d2a0e804..36903d6e 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -312,6 +312,9 @@ extends: - output: pipelineArtifact artifactName: 'flc-nuget-winml' targetPath: '$(Build.ArtifactStagingDirectory)/flc-nuget' + - output: pipelineArtifact + artifactName: 'flc-wheels-winml' + targetPath: '$(Build.ArtifactStagingDirectory)/flc-wheels' steps: - checkout: neutron-server clean: true diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 10676517..0e52ca46 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -136,99 +136,104 @@ steps: inlineOperation: | [{"keyCode":"CP-401405","operationSetCode":"NuGetSign","parameters":[],"toolName":"sign","toolVersion":"6.2.9304.0"},{"keyCode":"CP-401405","operationSetCode":"NuGetVerify","parameters":[],"toolName":"sign","toolVersion":"6.2.9304.0"}] -# Build Python wheels from the NuGet package (standard builds only; WinML has no PyPI distribution) -- ${{ if eq(parameters.isWinML, false) }}: - - task: PowerShell@2 - displayName: 'Build foundry_local_core Python Wheels' - inputs: - targetType: inline - script: | - $stagingDir = "$(Build.ArtifactStagingDirectory)/flc-wheels" - New-Item -ItemType Directory -Path $stagingDir -Force | Out-Null - - # Find and extract the NuGet package (.nupkg is a zip archive) - $nupkg = Get-ChildItem "$(Build.ArtifactStagingDirectory)/flc-nuget" -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 - if (-not $nupkg) { throw "No FLC .nupkg found" } - Write-Host "Found NuGet package: $($nupkg.Name)" - - $extractDir = "$(Build.ArtifactStagingDirectory)/flc-extracted" - $nupkgZip = [System.IO.Path]::ChangeExtension($nupkg.FullName, ".zip") - Copy-Item -Path $nupkg.FullName -Destination $nupkgZip -Force - Expand-Archive -Path $nupkgZip -DestinationPath $extractDir -Force - - # Convert NuGet version to PEP 440 - # NuGet dev format: X.Y.Z-dev-YYYYMMDD-HHmm-commitid - # PEP 440 dev format: X.Y.Z.devYYYYMMDDHHmm - $nupkgVersion = $nupkg.BaseName -replace '^Microsoft\.AI\.Foundry\.Local\.Core\.', '' - $parts = $nupkgVersion -split '-' - $pyVersion = if ($parts.Count -ge 4 -and $parts[1] -eq 'dev') { "$($parts[0]).dev$($parts[2])$($parts[3])" } - elseif ($parts.Count -eq 2) { "$($parts[0])$($parts[1])" } - else { $parts[0] } - Write-Host "Python package version: $pyVersion" - $packageName = "foundry_local_core" +# Build Python wheels from the NuGet package +- task: PowerShell@2 + displayName: 'Build foundry_local_core Python Wheels' + inputs: + targetType: inline + script: | + $stagingDir = "$(Build.ArtifactStagingDirectory)/flc-wheels" + New-Item -ItemType Directory -Path $stagingDir -Force | Out-Null + + $isWinML = "${{ parameters.isWinML }}" -eq "True" + + # Find and extract the NuGet package (.nupkg is a zip archive) + $nupkgFilter = if ($isWinML) { "Microsoft.AI.Foundry.Local.Core.WinML*.nupkg" } else { "Microsoft.AI.Foundry.Local.Core*.nupkg" } + $nupkg = Get-ChildItem "$(Build.ArtifactStagingDirectory)/flc-nuget" -Filter $nupkgFilter | Where-Object { $_.Name -notlike "*.snupkg" } | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found matching $nupkgFilter" } + Write-Host "Found NuGet package: $($nupkg.Name)" + $extractDir = "$(Build.ArtifactStagingDirectory)/flc-extracted" + $nupkgZip = [System.IO.Path]::ChangeExtension($nupkg.FullName, ".zip") + Copy-Item -Path $nupkg.FullName -Destination $nupkgZip -Force + Expand-Archive -Path $nupkgZip -DestinationPath $extractDir -Force + + # Convert NuGet version to PEP 440 + $nupkgVersion = $nupkg.BaseName -replace '^Microsoft\.AI\.Foundry\.Local\.Core(\.WinML)?\.', '' + $parts = $nupkgVersion -split '-' + $pyVersion = if ($parts.Count -ge 4 -and $parts[1] -eq 'dev') { "$($parts[0]).dev$($parts[2])$($parts[3])" } + elseif ($parts.Count -eq 2) { "$($parts[0])$($parts[1])" } + else { $parts[0] } + Write-Host "Python package version: $pyVersion" + + $packageName = if ($isWinML) { "foundry_local_core_winml" } else { "foundry_local_core" } + + if ($isWinML) { + $platforms = @( + @{rid="win-x64"; pyKey="bin"; tag="win_amd64"}, + @{rid="win-arm64"; pyKey="bin"; tag="win_arm64"} + ) + } else { $platforms = @( @{rid="win-x64"; pyKey="bin"; tag="win_amd64"}, @{rid="win-arm64"; pyKey="bin"; tag="win_arm64"}, @{rid="linux-x64"; pyKey="bin"; tag="manylinux_2_28_x86_64"}, @{rid="osx-arm64"; pyKey="bin"; tag="macosx_11_0_arm64"} ) + } - foreach ($p in $platforms) { - $nativeSrc = "$extractDir/runtimes/$($p.rid)/native" - if (-not (Test-Path $nativeSrc)) { - Write-Warning "No native binaries found for $($p.rid) — skipping." - continue - } + foreach ($p in $platforms) { + $nativeSrc = "$extractDir/runtimes/$($p.rid)/native" + if (-not (Test-Path $nativeSrc)) { + Write-Warning "No native binaries found for $($p.rid) — skipping." + continue + } - $wheelRoot = "$(Build.ArtifactStagingDirectory)/wheels-build/flc_wheel_$($p.tag)" - $pkgDir = "$wheelRoot/$packageName" - New-Item -ItemType Directory -Path "$pkgDir/$($p.pyKey)" -Force | Out-Null - "" | Set-Content -Encoding ascii "$pkgDir/__init__.py" - Get-ChildItem $nativeSrc -File | Copy-Item -Destination "$pkgDir/$($p.pyKey)" - - $normalizedName = $packageName.Replace('_', '-') - $wheelTag = "py3-none-$($p.tag)" - $distInfoName = "$packageName-$pyVersion" - $wheelName = "$distInfoName-$wheelTag.whl" - $distInfoDir = "$wheelRoot/$distInfoName.dist-info" - New-Item -ItemType Directory -Path $distInfoDir -Force | Out-Null - - # Use no-BOM UTF-8 — PowerShell 5's -Encoding utf8 adds a BOM that - # breaks twine/pkginfo metadata parsing. - $utf8NoBom = [System.Text.UTF8Encoding]::new($false) - - [System.IO.File]::WriteAllText("$distInfoDir/WHEEL", - "Wheel-Version: 1.0`nGenerator: custom`nRoot-Is-Purelib: false`nTag: $wheelTag`n", $utf8NoBom) - - [System.IO.File]::WriteAllText("$distInfoDir/METADATA", - "Metadata-Version: 2.1`nName: $normalizedName`nVersion: $pyVersion`n", $utf8NoBom) - - $recordLines = Get-ChildItem $wheelRoot -Recurse -File | ForEach-Object { - $rel = $_.FullName.Substring($wheelRoot.Length + 1).Replace('\', '/') - $raw = (Get-FileHash $_.FullName -Algorithm SHA256).Hash - $bytes = [byte[]]::new($raw.Length / 2) - for ($i = 0; $i -lt $raw.Length; $i += 2) { $bytes[$i/2] = [Convert]::ToByte($raw.Substring($i, 2), 16) } - $b64 = [Convert]::ToBase64String($bytes) -replace '\+','-' -replace '/','_' -replace '=','' - "$rel,sha256=$b64,$($_.Length)" - } - $recordContent = ($recordLines + "$distInfoName.dist-info/RECORD,,") -join "`n" - [System.IO.File]::WriteAllText("$distInfoDir/RECORD", $recordContent, $utf8NoBom) - - # Pack wheel with forward-slash zip entries (Compress-Archive uses backslashes) - $wheelPath = "$stagingDir/$wheelName" - Add-Type -AssemblyName System.IO.Compression.FileSystem - $zip = [System.IO.Compression.ZipFile]::Open($wheelPath, 'Create') - try { - Get-ChildItem $wheelRoot -Recurse -File | ForEach-Object { - $rel = $_.FullName.Substring($wheelRoot.Length + 1).Replace('\', '/') - [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $_.FullName, $rel) | Out-Null - } - } finally { - $zip.Dispose() + $wheelRoot = "$(Build.ArtifactStagingDirectory)/wheels-build/flc_wheel_$($p.tag)" + $pkgDir = "$wheelRoot/$packageName" + New-Item -ItemType Directory -Path "$pkgDir/$($p.pyKey)" -Force | Out-Null + "" | Set-Content -Encoding ascii "$pkgDir/__init__.py" + Get-ChildItem $nativeSrc -File | Copy-Item -Destination "$pkgDir/$($p.pyKey)" + + $normalizedName = $packageName.Replace('_', '-') + $wheelTag = "py3-none-$($p.tag)" + $distInfoName = "$packageName-$pyVersion" + $wheelName = "$distInfoName-$wheelTag.whl" + $distInfoDir = "$wheelRoot/$distInfoName.dist-info" + New-Item -ItemType Directory -Path $distInfoDir -Force | Out-Null + + $utf8NoBom = [System.Text.UTF8Encoding]::new($false) + + [System.IO.File]::WriteAllText("$distInfoDir/WHEEL", + "Wheel-Version: 1.0`nGenerator: custom`nRoot-Is-Purelib: false`nTag: $wheelTag`n", $utf8NoBom) + + [System.IO.File]::WriteAllText("$distInfoDir/METADATA", + "Metadata-Version: 2.1`nName: $normalizedName`nVersion: $pyVersion`n", $utf8NoBom) + + $recordLines = Get-ChildItem $wheelRoot -Recurse -File | ForEach-Object { + $rel = $_.FullName.Substring($wheelRoot.Length + 1).Replace('\', '/') + $raw = (Get-FileHash $_.FullName -Algorithm SHA256).Hash + $bytes = [byte[]]::new($raw.Length / 2) + for ($i = 0; $i -lt $raw.Length; $i += 2) { $bytes[$i/2] = [Convert]::ToByte($raw.Substring($i, 2), 16) } + $b64 = [Convert]::ToBase64String($bytes) -replace '\+','-' -replace '/','_' -replace '=','' + "$rel,sha256=$b64,$($_.Length)" + } + $recordContent = ($recordLines + "$distInfoName.dist-info/RECORD,,") -join "`n" + [System.IO.File]::WriteAllText("$distInfoDir/RECORD", $recordContent, $utf8NoBom) + + $wheelPath = "$stagingDir/$wheelName" + Add-Type -AssemblyName System.IO.Compression.FileSystem + $zip = [System.IO.Compression.ZipFile]::Open($wheelPath, 'Create') + try { + Get-ChildItem $wheelRoot -Recurse -File | ForEach-Object { + $rel = $_.FullName.Substring($wheelRoot.Length + 1).Replace('\', '/') + [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $_.FullName, $rel) | Out-Null } - Write-Host "Created wheel: $wheelName" + } finally { + $zip.Dispose() } + Write-Host "Created wheel: $wheelName" + } - Write-Host "`nAll wheels:" - Get-ChildItem $stagingDir -Filter "*.whl" | ForEach-Object { Write-Host " $($_.Name)" } + Write-Host "`nAll wheels:" + Get-ChildItem $stagingDir -Filter "*.whl" | ForEach-Object { Write-Host " $($_.Name)" } From 688dd9c42c0814d6c8c5a1d2b83d44dcfcff127e Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 26 Mar 2026 22:29:46 -0700 Subject: [PATCH 049/112] js winml --- .pipelines/foundry-local-packaging.yml | 31 +++++++++++++++ .pipelines/templates/build-js-steps.yml | 51 +++++++++++-------------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 36903d6e..24d594ae 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -370,3 +370,34 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' outputDir: '$(Build.ArtifactStagingDirectory)/cs-sdk-winml' + + # ── Build JS SDK (WinML) ── + - stage: build_js_winml + displayName: 'Build JS SDK WinML' + dependsOn: package_core_winml + jobs: + - job: js_sdk_winml + displayName: 'Build' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + outputs: + - output: pipelineArtifact + artifactName: 'js-sdk-winml' + targetPath: '$(Build.ArtifactStagingDirectory)/js-sdk' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/build-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' diff --git a/.pipelines/templates/build-js-steps.yml b/.pipelines/templates/build-js-steps.yml index 8adc3df8..6bac419e 100644 --- a/.pipelines/templates/build-js-steps.yml +++ b/.pipelines/templates/build-js-steps.yml @@ -48,21 +48,12 @@ steps: Write-Host "##vso[task.setvariable variable=packageVersion]$v" # Install dependencies including native binaries (FLC, ORT, GenAI) from NuGet feeds -- ${{ if eq(parameters.isWinML, true) }}: - - task: Npm@1 - displayName: 'npm install (WinML)' - inputs: - command: custom - workingDir: $(repoRoot)/sdk/js - customCommand: 'install --winml' - -- ${{ else }}: - - task: Npm@1 - displayName: 'npm install' - inputs: - command: custom - workingDir: $(repoRoot)/sdk/js - customCommand: 'install' +- task: Npm@1 + displayName: 'npm install' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'install' # Overwrite the FLC native binary with the one we just built - task: PowerShell@2 @@ -125,12 +116,21 @@ steps: env: TF_BUILD: 'true' -- task: Npm@1 - displayName: 'npm pack' - inputs: - command: custom - workingDir: $(repoRoot)/sdk/js - customCommand: 'pack' +- ${{ if eq(parameters.isWinML, true) }}: + - task: Npm@1 + displayName: 'npm run pack:winml' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'run pack:winml' + +- ${{ else }}: + - task: Npm@1 + displayName: 'npm run pack' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'run pack' - task: PowerShell@2 displayName: 'Stage artifact' @@ -139,11 +139,4 @@ steps: script: | $destDir = "$(Build.ArtifactStagingDirectory)/js-sdk" New-Item -ItemType Directory -Path $destDir -Force | Out-Null - if ("${{ parameters.isWinML }}" -eq "True") { - Get-ChildItem "$(repoRoot)/sdk/js/*.tgz" | ForEach-Object { - $new = $_.Name -replace '^foundry-local-sdk-', 'foundry-local-sdk-winml-' - Copy-Item $_.FullName "$destDir/$new" - } - } else { - Copy-Item "$(repoRoot)/sdk/js/*.tgz" "$destDir/" - } + Copy-Item "$(repoRoot)/sdk/js/*.tgz" "$destDir/" From 3bb6902261efb3abe93dfebd85475e8987da2d30 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 08:29:31 -0700 Subject: [PATCH 050/112] prints --- .pipelines/foundry-local-packaging.yml | 22 ++++++++++++++++++++++ .pipelines/templates/build-cs-steps.yml | 23 ++++++++++++++++++----- .pipelines/templates/build-js-steps.yml | 13 +++++++++++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 24d594ae..300005b1 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -177,6 +177,17 @@ extends: buildType: current artifactName: 'flc-osx-arm64' targetPath: '$(Pipeline.Workspace)/flc-osx-arm64' + - task: PowerShell@2 + displayName: 'List downloaded platform artifacts' + inputs: + targetType: inline + script: | + foreach ($name in @('flc-win-x64','flc-win-arm64','flc-linux-x64','flc-osx-arm64')) { + $dir = "$(Pipeline.Workspace)/$name" + Write-Host "Contents of ${dir}:" + if (Test-Path $dir) { Get-ChildItem $dir -Recurse | ForEach-Object { Write-Host $_.FullName } } + else { Write-Host " (directory not found)" } + } - template: .pipelines/templates/package-core-steps.yml@self parameters: version: ${{ parameters.version }} @@ -328,6 +339,17 @@ extends: buildType: current artifactName: 'flc-winml-win-arm64' targetPath: '$(Pipeline.Workspace)/flc-winml-win-arm64' + - task: PowerShell@2 + displayName: 'List downloaded WinML platform artifacts' + inputs: + targetType: inline + script: | + foreach ($name in @('flc-winml-win-x64','flc-winml-win-arm64')) { + $dir = "$(Pipeline.Workspace)/$name" + Write-Host "Contents of ${dir}:" + if (Test-Path $dir) { Get-ChildItem $dir -Recurse | ForEach-Object { Write-Host $_.FullName } } + else { Write-Host " (directory not found)" } + } - template: .pipelines/templates/package-core-steps.yml@self parameters: version: ${{ parameters.version }} diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 8994ac73..84b5a190 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -50,6 +50,15 @@ steps: Write-Host "##vso[task.setvariable variable=packageVersion]$v" Write-Host "Package version: $v" +# List downloaded artifact for debugging +- task: PowerShell@2 + displayName: 'List downloaded FLC artifact' + inputs: + targetType: inline + script: | + Write-Host "Contents of ${{ parameters.flcNugetDir }}:" + Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } + # Create a temporary NuGet.config that includes the local FLC feed - task: PowerShell@2 displayName: 'Create NuGet.config with local FLC feed' @@ -66,17 +75,21 @@ steps: "@ - $configPath = "$(Build.ArtifactStagingDirectory)/NuGet.config" - Set-Content -Path $configPath -Value $nugetConfig - Write-Host "##vso[task.setvariable variable=customNugetConfig]$configPath" - # Determine the FLC version from the .nupkg filename - $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" } $flcVer = $nupkg.BaseName -replace '^Microsoft\.AI\.Foundry\.Local\.Core(\.WinML)?\.', '' Write-Host "##vso[task.setvariable variable=resolvedFlcVersion]$flcVer" Write-Host "Resolved FLC version: $flcVer" + # Point the local NuGet feed at the directory that actually contains the .nupkg + $flcFeedDir = $nupkg.DirectoryName + $nugetConfig = $nugetConfig -replace [regex]::Escape("${{ parameters.flcNugetDir }}"), $flcFeedDir + $configPath = "$(Build.ArtifactStagingDirectory)/NuGet.config" + Set-Content -Path $configPath -Value $nugetConfig + Write-Host "##vso[task.setvariable variable=customNugetConfig]$configPath" + Write-Host "Local FLC feed directory: $flcFeedDir" + - task: NuGetAuthenticate@1 displayName: 'Authenticate NuGet feeds' diff --git a/.pipelines/templates/build-js-steps.yml b/.pipelines/templates/build-js-steps.yml index 6bac419e..67717964 100644 --- a/.pipelines/templates/build-js-steps.yml +++ b/.pipelines/templates/build-js-steps.yml @@ -29,6 +29,15 @@ steps: Write-Host "Repo root: $repoRoot" Write-Host "Test data: $testDataDir" +- task: PowerShell@2 + displayName: 'List downloaded FLC artifact' + condition: and(succeeded(), ne('${{ parameters.flcNugetDir }}', '')) + inputs: + targetType: inline + script: | + Write-Host "Contents of ${{ parameters.flcNugetDir }}:" + Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } + - task: NodeTool@0 displayName: 'Use Node.js 20' inputs: @@ -67,8 +76,8 @@ steps: $platformKey = "$os-$arch" $rid = if ($arch -eq 'arm64') { 'win-arm64' } else { 'win-x64' } - $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 - if (-not $nupkg) { throw "No FLC .nupkg found" } + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" } # Extract the NuGet package (it's a zip) $extractDir = "$(Build.ArtifactStagingDirectory)/flc-extract" From 7f24227e5d318215854083d438894725b3b2533b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 08:58:32 -0700 Subject: [PATCH 051/112] add python --- .pipelines/foundry-local-packaging.yml | 66 ++++++++- .pipelines/templates/build-python-steps.yml | 143 ++++++++++++++++++++ 2 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 .pipelines/templates/build-python-steps.yml diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 300005b1..e05c3c39 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -3,7 +3,8 @@ # Builds Foundry Local Core from neutron-server (AIFoundryLocal project), # then packages the C# and JS SDKs from this repo using the built Core. # -# Produces artifacts: flc-nuget, flc-nuget-winml, flc-wheels, cs-sdk, cs-sdk-winml, js-sdk +# Produces artifacts: flc-nuget, flc-nuget-winml, flc-wheels, flc-wheels-winml, +# cs-sdk, cs-sdk-winml, js-sdk, js-sdk-winml, python-sdk, python-sdk-winml trigger: none name: $(Date:yyyyMMdd).$(Rev:r) @@ -265,6 +266,37 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + # ── Build Python SDK ── + - stage: build_python + displayName: 'Build Python SDK' + dependsOn: package_core + jobs: + - job: python_sdk + displayName: 'Build' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels' + targetPath: '$(Pipeline.Workspace)/flc-wheels' + outputs: + - output: pipelineArtifact + artifactName: 'python-sdk' + targetPath: '$(Build.ArtifactStagingDirectory)/python-sdk' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/build-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + isWinML: false + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + # ── Build FLC (WinML) ── - stage: build_core_winml displayName: 'Build FLC WinML' @@ -423,3 +455,35 @@ extends: isRelease: ${{ parameters.isRelease }} isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + + # ── Build Python SDK (WinML) ── + - stage: build_python_winml + displayName: 'Build Python SDK WinML' + dependsOn: package_core_winml + jobs: + - job: python_sdk_winml + displayName: 'Build' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels-winml' + targetPath: '$(Pipeline.Workspace)/flc-wheels-winml' + outputs: + - output: pipelineArtifact + artifactName: 'python-sdk-winml' + targetPath: '$(Build.ArtifactStagingDirectory)/python-sdk-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/build-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + isWinML: true + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' + outputDir: '$(Build.ArtifactStagingDirectory)/python-sdk-winml' diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml new file mode 100644 index 00000000..3d8dfa58 --- /dev/null +++ b/.pipelines/templates/build-python-steps.yml @@ -0,0 +1,143 @@ +# Steps to build, test, and pack the Python SDK wheel. +# When test-data-shared is checked out alongside self, ADO places repos under +# $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. +parameters: +- name: version + type: string +- name: isRelease + type: boolean + default: false +- name: isWinML + type: boolean + default: false +- name: flcWheelsDir + type: string + default: '' + displayName: 'Path to directory containing the FLC wheels (for overriding foundry-local-core)' +- name: outputDir + type: string + default: '$(Build.ArtifactStagingDirectory)/python-sdk' + displayName: 'Path to directory for the built wheel' + +steps: +# Set paths for multi-repo checkout +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $repoRoot = "$(Build.SourcesDirectory)/Foundry-Local" + $testDataDir = "$(Build.SourcesDirectory)/test-data-shared" + Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" + +- task: UsePythonVersion@0 + displayName: 'Use Python 3.12' + inputs: + versionSpec: '3.12' + +# List downloaded FLC wheels for debugging +- task: PowerShell@2 + displayName: 'List downloaded FLC wheels' + condition: and(succeeded(), ne('${{ parameters.flcWheelsDir }}', '')) + inputs: + targetType: inline + script: | + Write-Host "Contents of ${{ parameters.flcWheelsDir }}:" + Get-ChildItem "${{ parameters.flcWheelsDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } + +# Compute package version +- task: PowerShell@2 + displayName: 'Set package version' + inputs: + targetType: inline + script: | + $v = "${{ parameters.version }}" + if ("${{ parameters.isRelease }}" -ne "True") { + $ts = Get-Date -Format "yyyyMMddHHmm" + $v = "$v-dev.$ts" + } + Write-Host "##vso[task.setvariable variable=packageVersion]$v" + Write-Host "Package version: $v" + +# Configure pip to use ORT-Nightly feed (plus PyPI as fallback) +- task: PowerShell@2 + displayName: 'Configure pip for Azure Artifacts' + inputs: + targetType: inline + script: | + pip config set global.index-url https://pkgs.dev.azure.com/aiinfra/PublicPackages/_packaging/ORT-Nightly/pypi/simple/ + pip config set global.extra-index-url https://pypi.org/simple/ + pip config set global.pre true + +# Install the build tool +- script: python -m pip install build + displayName: 'Install build tool' + +# Write version file +- task: PowerShell@2 + displayName: 'Set SDK version' + inputs: + targetType: inline + script: | + Set-Content -Path "$(repoRoot)/sdk/python/src/version.py" -Value '__version__ = "$(packageVersion)"' + +# Install the FLC wheels from the pipeline if provided, so the build +# backend picks up the freshly-built foundry-local-core instead of +# pulling a stale one from the feed. +- task: PowerShell@2 + displayName: 'Pre-install pipeline-built FLC wheel' + condition: and(succeeded(), ne('${{ parameters.flcWheelsDir }}', '')) + inputs: + targetType: inline + script: | + $filter = if ("${{ parameters.isWinML }}" -eq "True") { "foundry_local_core_winml*.whl" } else { "foundry_local_core-*.whl" } + $wheel = Get-ChildItem "${{ parameters.flcWheelsDir }}" -Recurse -Filter $filter | Where-Object { $_.Name -notlike "*winml*" -or "${{ parameters.isWinML }}" -eq "True" } | Select-Object -First 1 + if ($wheel) { + Write-Host "Installing pipeline-built FLC wheel: $($wheel.FullName)" + pip install $($wheel.FullName) + } else { + Write-Warning "No FLC wheel found matching $filter in ${{ parameters.flcWheelsDir }}" + } + +# Build wheel — standard or WinML variant +- script: python -m build --wheel --outdir dist/ + displayName: 'Build wheel' + condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'false')) + workingDirectory: $(repoRoot)/sdk/python + +- script: python -m build --wheel -C winml=true --outdir dist/ + displayName: 'Build wheel (WinML)' + condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'true')) + workingDirectory: $(repoRoot)/sdk/python + +# Install the built wheel +- task: PowerShell@2 + displayName: 'Install built wheel' + inputs: + targetType: inline + script: | + $wheel = (Get-ChildItem "$(repoRoot)/sdk/python/dist/*.whl" | Select-Object -First 1).FullName + pip install $wheel + +# Install test dependencies and run tests +- script: pip install coverage pytest>=7.0.0 pytest-timeout>=2.1.0 + displayName: 'Install test dependencies' + +- script: python -m pytest test/ -v + displayName: 'Run tests' + workingDirectory: $(repoRoot)/sdk/python + env: + TF_BUILD: 'true' + +# Stage output +- task: PowerShell@2 + displayName: 'Stage wheel artifact' + inputs: + targetType: inline + script: | + $destDir = "${{ parameters.outputDir }}" + New-Item -ItemType Directory -Path $destDir -Force | Out-Null + Copy-Item "$(repoRoot)/sdk/python/dist/*" "$destDir/" + Write-Host "Staged wheels:" + Get-ChildItem $destDir | ForEach-Object { Write-Host " $($_.Name)" } From 330118f9f270a5572b95c67be017c870608affc8 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 10:04:36 -0700 Subject: [PATCH 052/112] rust --- .pipelines/foundry-local-packaging.yml | 62 ++++++++++++++++++++++++- .pipelines/templates/build-cs-steps.yml | 62 +++++++++++++++---------- 2 files changed, 99 insertions(+), 25 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index e05c3c39..de3ad1bf 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -4,7 +4,8 @@ # then packages the C# and JS SDKs from this repo using the built Core. # # Produces artifacts: flc-nuget, flc-nuget-winml, flc-wheels, flc-wheels-winml, -# cs-sdk, cs-sdk-winml, js-sdk, js-sdk-winml, python-sdk, python-sdk-winml +# cs-sdk, cs-sdk-winml, js-sdk, js-sdk-winml, python-sdk, python-sdk-winml, +# rust-sdk, rust-sdk-winml trigger: none name: $(Date:yyyyMMdd).$(Rev:r) @@ -297,6 +298,35 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + # ── Build Rust SDK ── + - stage: build_rust + displayName: 'Build Rust SDK' + dependsOn: package_core + jobs: + - job: rust_sdk + displayName: 'Build' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + outputs: + - output: pipelineArtifact + artifactName: 'rust-sdk' + targetPath: '$(Build.ArtifactStagingDirectory)/rust-sdk' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/build-rust-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + # ── Build FLC (WinML) ── - stage: build_core_winml displayName: 'Build FLC WinML' @@ -487,3 +517,33 @@ extends: isWinML: true flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' outputDir: '$(Build.ArtifactStagingDirectory)/python-sdk-winml' + + # ── Build Rust SDK (WinML) ── + - stage: build_rust_winml + displayName: 'Build Rust SDK WinML' + dependsOn: package_core_winml + jobs: + - job: rust_sdk_winml + displayName: 'Build' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + outputs: + - output: pipelineArtifact + artifactName: 'rust-sdk-winml' + targetPath: '$(Build.ArtifactStagingDirectory)/rust-sdk-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/build-rust-steps.yml@self + parameters: + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + outputDir: '$(Build.ArtifactStagingDirectory)/rust-sdk-winml' diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 84b5a190..facbe10a 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -93,46 +93,60 @@ steps: - task: NuGetAuthenticate@1 displayName: 'Authenticate NuGet feeds' -- task: DotNetCoreCLI@2 +- task: PowerShell@2 displayName: 'Restore SDK' inputs: - command: restore - projects: $(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj - feedsToUse: config - nugetConfigPath: $(customNugetConfig) - restoreArguments: '/p:UseWinML=${{ parameters.isWinML }} /p:FoundryLocalCoreVersion=$(resolvedFlcVersion)' + targetType: inline + script: | + $proj = "$(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj" + if (-not (Test-Path $proj)) { throw "Project not found: $proj" } + dotnet restore $proj ` + --configfile "$(customNugetConfig)" ` + /p:UseWinML=${{ parameters.isWinML }} ` + /p:FoundryLocalCoreVersion=$(resolvedFlcVersion) + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -- task: DotNetCoreCLI@2 +- task: PowerShell@2 displayName: 'Build SDK' inputs: - command: build - projects: $(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj - arguments: '--no-restore --configuration Release /p:UseWinML=${{ parameters.isWinML }}' + targetType: inline + script: | + dotnet build "$(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj" ` + --no-restore --configuration Release ` + /p:UseWinML=${{ parameters.isWinML }} + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Restore and build test project -- task: DotNetCoreCLI@2 +- task: PowerShell@2 displayName: 'Restore tests' inputs: - command: restore - projects: $(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj - feedsToUse: config - nugetConfigPath: $(customNugetConfig) - restoreArguments: '/p:UseWinML=${{ parameters.isWinML }} /p:FoundryLocalCoreVersion=$(resolvedFlcVersion)' + targetType: inline + script: | + dotnet restore "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + --configfile "$(customNugetConfig)" ` + /p:UseWinML=${{ parameters.isWinML }} ` + /p:FoundryLocalCoreVersion=$(resolvedFlcVersion) + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -- task: DotNetCoreCLI@2 +- task: PowerShell@2 displayName: 'Build tests' inputs: - command: build - projects: $(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj - arguments: '--no-restore --configuration Release /p:UseWinML=${{ parameters.isWinML }}' + targetType: inline + script: | + dotnet build "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + --no-restore --configuration Release ` + /p:UseWinML=${{ parameters.isWinML }} + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Run tests — test-data-shared is a sibling of the repo root -- task: DotNetCoreCLI@2 +- task: PowerShell@2 displayName: 'Run SDK tests' inputs: - command: test - projects: $(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj - arguments: '--no-build --configuration Release' + targetType: inline + script: | + dotnet test "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + --no-build --configuration Release + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } env: TF_BUILD: 'true' From bb400310368c3ff29903f463cce12b1d736d472c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 10:04:51 -0700 Subject: [PATCH 053/112] rusty rust --- .pipelines/templates/build-rust-steps.yml | 189 ++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 .pipelines/templates/build-rust-steps.yml diff --git a/.pipelines/templates/build-rust-steps.yml b/.pipelines/templates/build-rust-steps.yml new file mode 100644 index 00000000..fe559bc1 --- /dev/null +++ b/.pipelines/templates/build-rust-steps.yml @@ -0,0 +1,189 @@ +# Steps to build, test, and package the Rust SDK crate. +# When test-data-shared is checked out alongside self, ADO places repos under +# $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. +parameters: +- name: isWinML + type: boolean + default: false +- name: flcNugetDir + type: string + displayName: 'Path to directory containing the FLC .nupkg' +- name: outputDir + type: string + default: '$(Build.ArtifactStagingDirectory)/rust-sdk' + displayName: 'Path to directory for the packaged crate' + +steps: +# Set paths for multi-repo checkout +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $repoRoot = "$(Build.SourcesDirectory)/Foundry-Local" + $testDataDir = "$(Build.SourcesDirectory)/test-data-shared" + Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" + +# List downloaded FLC artifact for debugging +- task: PowerShell@2 + displayName: 'List downloaded FLC artifact' + inputs: + targetType: inline + script: | + Write-Host "Contents of ${{ parameters.flcNugetDir }}:" + Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } + +# Extract FLC native binaries from the pipeline-built .nupkg so that +# build.rs finds them already present and skips downloading from the feed. +- task: PowerShell@2 + displayName: 'Extract FLC native binaries for Rust build' + inputs: + targetType: inline + script: | + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" } + Write-Host "Found NuGet package: $($nupkg.FullName)" + + $extractDir = "$(Build.ArtifactStagingDirectory)/flc-extract-rust" + $zip = [System.IO.Path]::ChangeExtension($nupkg.FullName, ".zip") + Copy-Item $nupkg.FullName $zip -Force + Expand-Archive -Path $zip -DestinationPath $extractDir -Force + + # Determine RID for this agent + $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x64' } + $rid = "win-$arch" + + $nativeDir = "$extractDir/runtimes/$rid/native" + if (-not (Test-Path $nativeDir)) { throw "No native binaries found at $nativeDir for RID $rid" } + + # Stage them where build.rs can discover them + $flcNativeDir = "$(Build.ArtifactStagingDirectory)/flc-native-rust" + New-Item -ItemType Directory -Path $flcNativeDir -Force | Out-Null + Get-ChildItem $nativeDir -File | Copy-Item -Destination $flcNativeDir -Force + Write-Host "##vso[task.setvariable variable=flcNativeDir]$flcNativeDir" + Write-Host "Extracted FLC native binaries to $flcNativeDir`:" + Get-ChildItem $flcNativeDir | ForEach-Object { Write-Host " $($_.Name)" } + +# Install Rust toolchain +- task: PowerShell@2 + displayName: 'Install Rust toolchain' + inputs: + targetType: inline + script: | + Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile rustup-init.exe + .\rustup-init.exe -y --default-toolchain stable --profile minimal -c clippy,rustfmt + Remove-Item rustup-init.exe + # Add cargo to PATH for subsequent steps + $cargoPath = "$env:USERPROFILE\.cargo\bin" + Write-Host "##vso[task.prependpath]$cargoPath" + +# The .cargo/config.toml redirects crates-io to an Azure Artifacts feed +# for CFS compliance. Remove the redirect in CI so cargo can fetch from +# crates.io directly without Azure DevOps auth. +- task: PowerShell@2 + displayName: 'Use crates.io directly' + inputs: + targetType: inline + script: | + $configPath = "$(repoRoot)/sdk/rust/.cargo/config.toml" + if (Test-Path $configPath) { + Remove-Item $configPath + Write-Host "Removed .cargo/config.toml crates-io redirect" + } + +- task: PowerShell@2 + displayName: 'Check formatting' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + cargo fmt --all -- --check + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +- task: PowerShell@2 + displayName: 'Run clippy' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } + Invoke-Expression "cargo clippy --all-targets $features -- -D warnings" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +- task: PowerShell@2 + displayName: 'Build' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } + Invoke-Expression "cargo build $features" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +# Overwrite the FLC core binary in cargo's OUT_DIR with the pipeline-built +# version so that integration tests use the freshly-built FLC. build.rs +# sets FOUNDRY_NATIVE_DIR to OUT_DIR, which the SDK checks at runtime. +- task: PowerShell@2 + displayName: 'Overwrite FLC binary with pipeline-built version' + inputs: + targetType: inline + script: | + # Find cargo's OUT_DIR for the foundry-local-sdk build script + $outDir = Get-ChildItem "$(repoRoot)/sdk/rust/target/debug/build" -Directory -Filter "foundry-local-sdk-*" -Recurse | + Where-Object { Test-Path "$($_.FullName)/out" } | + ForEach-Object { "$($_.FullName)/out" } | + Select-Object -First 1 + if (-not $outDir) { throw "Could not find cargo OUT_DIR for foundry-local-sdk" } + Write-Host "Cargo OUT_DIR: $outDir" + + # Copy pipeline-built FLC native binaries over the downloaded ones + Get-ChildItem "$(flcNativeDir)" -File -Filter "Microsoft.AI.Foundry.Local.Core.*" | ForEach-Object { + Copy-Item $_.FullName -Destination "$outDir/$($_.Name)" -Force + Write-Host "Overwrote $($_.Name) with pipeline-built version" + } + +- task: PowerShell@2 + displayName: 'Run unit tests' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } + Invoke-Expression "cargo test --lib $features" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +- task: PowerShell@2 + displayName: 'Run integration tests' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } + Invoke-Expression "cargo test --tests $features -- --include-ignored --test-threads=1 --nocapture" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + env: + TF_BUILD: 'true' + +# --allow-dirty allows packaging with uncommitted changes (build.rs modifies generated files) +- task: PowerShell@2 + displayName: 'Package crate' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } + Invoke-Expression "cargo package $features --allow-dirty" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +# Stage output +- task: PowerShell@2 + displayName: 'Stage crate artifact' + inputs: + targetType: inline + script: | + $destDir = "${{ parameters.outputDir }}" + New-Item -ItemType Directory -Path $destDir -Force | Out-Null + Copy-Item "$(repoRoot)/sdk/rust/target/package/*.crate" "$destDir/" + Write-Host "Staged crates:" + Get-ChildItem $destDir | ForEach-Object { Write-Host " $($_.Name)" } From 867d6ca5104a9524a2b5f1a56a22797e10df2383 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 10:57:46 -0700 Subject: [PATCH 054/112] tests --- .pipelines/foundry-local-packaging.yml | 293 ++++++++++++++++++++ .pipelines/templates/build-cs-steps.yml | 1 - .pipelines/templates/build-js-steps.yml | 12 +- .pipelines/templates/build-python-steps.yml | 1 - .pipelines/templates/build-rust-steps.yml | 23 +- .pipelines/templates/package-core-steps.yml | 4 +- .pipelines/templates/test-cs-steps.yml | 92 ++++++ .pipelines/templates/test-js-steps.yml | 98 +++++++ .pipelines/templates/test-python-steps.yml | 98 +++++++ .pipelines/templates/test-rust-steps.yml | 136 +++++++++ 10 files changed, 747 insertions(+), 11 deletions(-) create mode 100644 .pipelines/templates/test-cs-steps.yml create mode 100644 .pipelines/templates/test-js-steps.yml create mode 100644 .pipelines/templates/test-python-steps.yml create mode 100644 .pipelines/templates/test-rust-steps.yml diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index de3ad1bf..ed8ea5e8 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -327,6 +327,196 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + # ── Test C# SDK (win-arm64, macOS) ── + - stage: test_cs + displayName: 'Test C# SDK' + dependsOn: build_cs + jobs: + - job: test_cs_win_arm64 + displayName: 'Test C# (win-arm64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + - job: test_cs_osx_arm64 + displayName: 'Test C# (macOS)' + pool: + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # ── Test JS SDK (win-arm64, macOS) ── + - stage: test_js + displayName: 'Test JS SDK' + dependsOn: build_js + jobs: + - job: test_js_win_arm64 + displayName: 'Test JS (win-arm64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + - job: test_js_osx_arm64 + displayName: 'Test JS (macOS)' + pool: + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # ── Test Python SDK (win-arm64, macOS) ── + - stage: test_python + displayName: 'Test Python SDK' + dependsOn: build_python + jobs: + - job: test_python_win_arm64 + displayName: 'Test Python (win-arm64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels' + targetPath: '$(Pipeline.Workspace)/flc-wheels' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + + - job: test_python_osx_arm64 + displayName: 'Test Python (macOS)' + pool: + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels' + targetPath: '$(Pipeline.Workspace)/flc-wheels' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + + # ── Test Rust SDK (win-arm64, macOS) ── + - stage: test_rust + displayName: 'Test Rust SDK' + dependsOn: build_rust + jobs: + - job: test_rust_win_arm64 + displayName: 'Test Rust (win-arm64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + - job: test_rust_osx_arm64 + displayName: 'Test Rust (macOS)' + pool: + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + # ── Build FLC (WinML) ── - stage: build_core_winml displayName: 'Build FLC WinML' @@ -547,3 +737,106 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' outputDir: '$(Build.ArtifactStagingDirectory)/rust-sdk-winml' + + # ── Test C# SDK WinML (win-arm64) ── + - stage: test_cs_winml + displayName: 'Test C# SDK WinML' + dependsOn: build_cs_winml + jobs: + - job: test_cs_winml_win_arm64 + displayName: 'Test C# WinML (win-arm64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + + # ── Test JS SDK WinML (win-arm64) ── + - stage: test_js_winml + displayName: 'Test JS SDK WinML' + dependsOn: build_js_winml + jobs: + - job: test_js_winml_win_arm64 + displayName: 'Test JS WinML (win-arm64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + + # ── Test Python SDK WinML (win-arm64) ── + - stage: test_python_winml + displayName: 'Test Python SDK WinML' + dependsOn: build_python_winml + jobs: + - job: test_python_winml_win_arm64 + displayName: 'Test Python WinML (win-arm64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels-winml' + targetPath: '$(Pipeline.Workspace)/flc-wheels-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' + + # ── Test Rust SDK WinML (win-arm64) ── + - stage: test_rust_winml + displayName: 'Test Rust SDK WinML' + dependsOn: build_rust_winml + jobs: + - job: test_rust_winml_win_arm64 + displayName: 'Test Rust WinML (win-arm64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index facbe10a..eb9c2ac8 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -17,7 +17,6 @@ parameters: type: string default: '$(Build.ArtifactStagingDirectory)/cs-sdk' displayName: 'Path to directory for the packed SDK' - steps: # Set paths for multi-repo checkout - task: PowerShell@2 diff --git a/.pipelines/templates/build-js-steps.yml b/.pipelines/templates/build-js-steps.yml index 67717964..44ed9dcf 100644 --- a/.pipelines/templates/build-js-steps.yml +++ b/.pipelines/templates/build-js-steps.yml @@ -14,7 +14,6 @@ parameters: type: string default: '' displayName: 'Path to directory containing the FLC .nupkg (for tests)' - steps: # Set paths for multi-repo checkout - task: PowerShell@2 @@ -76,6 +75,17 @@ steps: $platformKey = "$os-$arch" $rid = if ($arch -eq 'arm64') { 'win-arm64' } else { 'win-x64' } + # Detect macOS/Linux + if ($IsLinux) { + $os = 'linux' + $platformKey = "$os-$arch" + $rid = "linux-$arch" + } elseif ($IsMacOS) { + $os = 'darwin' + $platformKey = "$os-$arch" + $rid = "osx-$arch" + } + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" } diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml index 3d8dfa58..257efa2d 100644 --- a/.pipelines/templates/build-python-steps.yml +++ b/.pipelines/templates/build-python-steps.yml @@ -18,7 +18,6 @@ parameters: type: string default: '$(Build.ArtifactStagingDirectory)/python-sdk' displayName: 'Path to directory for the built wheel' - steps: # Set paths for multi-repo checkout - task: PowerShell@2 diff --git a/.pipelines/templates/build-rust-steps.yml b/.pipelines/templates/build-rust-steps.yml index fe559bc1..514ae6ee 100644 --- a/.pipelines/templates/build-rust-steps.yml +++ b/.pipelines/templates/build-rust-steps.yml @@ -12,7 +12,6 @@ parameters: type: string default: '$(Build.ArtifactStagingDirectory)/rust-sdk' displayName: 'Path to directory for the packaged crate' - steps: # Set paths for multi-repo checkout - task: PowerShell@2 @@ -52,7 +51,13 @@ steps: # Determine RID for this agent $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x64' } - $rid = "win-$arch" + if ($IsLinux) { + $rid = "linux-$arch" + } elseif ($IsMacOS) { + $rid = "osx-$arch" + } else { + $rid = "win-$arch" + } $nativeDir = "$extractDir/runtimes/$rid/native" if (-not (Test-Path $nativeDir)) { throw "No native binaries found at $nativeDir for RID $rid" } @@ -71,11 +76,15 @@ steps: inputs: targetType: inline script: | - Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile rustup-init.exe - .\rustup-init.exe -y --default-toolchain stable --profile minimal -c clippy,rustfmt - Remove-Item rustup-init.exe - # Add cargo to PATH for subsequent steps - $cargoPath = "$env:USERPROFILE\.cargo\bin" + if ($IsWindows -or (-not $IsLinux -and -not $IsMacOS)) { + Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile rustup-init.exe + .\rustup-init.exe -y --default-toolchain stable --profile minimal -c clippy,rustfmt + Remove-Item rustup-init.exe + $cargoPath = "$env:USERPROFILE\.cargo\bin" + } else { + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal -c clippy,rustfmt + $cargoPath = "$env:HOME/.cargo/bin" + } Write-Host "##vso[task.prependpath]$cargoPath" # The .cargo/config.toml redirects crates-io to an Azure Artifacts feed diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 0e52ca46..4d2a2941 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -159,9 +159,11 @@ steps: Expand-Archive -Path $nupkgZip -DestinationPath $extractDir -Force # Convert NuGet version to PEP 440 + # NuGet: 0.9.0-dev-202603271723-bb400310 → PEP 440: 0.9.0.dev202603271723 + # The commit hash is dropped because .devN requires N to be a pure integer. $nupkgVersion = $nupkg.BaseName -replace '^Microsoft\.AI\.Foundry\.Local\.Core(\.WinML)?\.', '' $parts = $nupkgVersion -split '-' - $pyVersion = if ($parts.Count -ge 4 -and $parts[1] -eq 'dev') { "$($parts[0]).dev$($parts[2])$($parts[3])" } + $pyVersion = if ($parts.Count -ge 3 -and $parts[1] -eq 'dev') { "$($parts[0]).dev$($parts[2])" } elseif ($parts.Count -eq 2) { "$($parts[0])$($parts[1])" } else { $parts[0] } Write-Host "Python package version: $pyVersion" diff --git a/.pipelines/templates/test-cs-steps.yml b/.pipelines/templates/test-cs-steps.yml new file mode 100644 index 00000000..70097e30 --- /dev/null +++ b/.pipelines/templates/test-cs-steps.yml @@ -0,0 +1,92 @@ +# Lightweight test-only steps for the C# SDK. +# Builds from source and runs tests — no signing or NuGet packing. +parameters: +- name: version + type: string +- name: isWinML + type: boolean + default: false +- name: flcNugetDir + type: string + displayName: 'Path to directory containing the FLC .nupkg' + +steps: +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $repoRoot = "$(Build.SourcesDirectory)/Foundry-Local" + $testDataDir = "$(Build.SourcesDirectory)/test-data-shared" + Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" + +- task: UseDotNet@2 + displayName: 'Use .NET 10 SDK' + inputs: + packageType: sdk + version: '10.0.x' + +- task: PowerShell@2 + displayName: 'List downloaded FLC artifact' + inputs: + targetType: inline + script: | + Write-Host "Contents of ${{ parameters.flcNugetDir }}:" + Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } + +- task: PowerShell@2 + displayName: 'Create NuGet.config with local FLC feed' + inputs: + targetType: inline + script: | + $nugetConfig = @" + + + + + + + + + "@ + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" } + $flcVer = $nupkg.BaseName -replace '^Microsoft\.AI\.Foundry\.Local\.Core(\.WinML)?\.', '' + Write-Host "##vso[task.setvariable variable=resolvedFlcVersion]$flcVer" + + $flcFeedDir = $nupkg.DirectoryName + $nugetConfig = $nugetConfig -replace [regex]::Escape("${{ parameters.flcNugetDir }}"), $flcFeedDir + $configPath = "$(Build.ArtifactStagingDirectory)/NuGet.config" + Set-Content -Path $configPath -Value $nugetConfig + Write-Host "##vso[task.setvariable variable=customNugetConfig]$configPath" + +- task: NuGetAuthenticate@1 + displayName: 'Authenticate NuGet feeds' + +- task: PowerShell@2 + displayName: 'Restore & build tests' + inputs: + targetType: inline + script: | + dotnet restore "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + --configfile "$(customNugetConfig)" ` + /p:UseWinML=${{ parameters.isWinML }} ` + /p:FoundryLocalCoreVersion=$(resolvedFlcVersion) + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + dotnet build "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + --no-restore --configuration Release ` + /p:UseWinML=${{ parameters.isWinML }} + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +- task: PowerShell@2 + displayName: 'Run SDK tests' + inputs: + targetType: inline + script: | + dotnet test "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + --no-build --configuration Release + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + env: + TF_BUILD: 'true' diff --git a/.pipelines/templates/test-js-steps.yml b/.pipelines/templates/test-js-steps.yml new file mode 100644 index 00000000..d0fbde5a --- /dev/null +++ b/.pipelines/templates/test-js-steps.yml @@ -0,0 +1,98 @@ +# Lightweight test-only steps for the JS SDK. +# Builds from source and runs tests — no npm pack or artifact staging. +parameters: +- name: version + type: string +- name: isWinML + type: boolean + default: false +- name: flcNugetDir + type: string + displayName: 'Path to directory containing the FLC .nupkg' + +steps: +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $repoRoot = "$(Build.SourcesDirectory)/Foundry-Local" + $testDataDir = "$(Build.SourcesDirectory)/test-data-shared" + Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" + +- task: PowerShell@2 + displayName: 'List downloaded FLC artifact' + inputs: + targetType: inline + script: | + Write-Host "Contents of ${{ parameters.flcNugetDir }}:" + Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } + +- task: NodeTool@0 + displayName: 'Use Node.js 20' + inputs: + versionSpec: '20.x' + +- task: Npm@1 + displayName: 'npm install' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'install' + +# Overwrite the FLC native binary with the pipeline-built one +- task: PowerShell@2 + displayName: 'Overwrite FLC with pipeline-built binary' + inputs: + targetType: inline + script: | + $os = 'win32' + $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x64' } + $platformKey = "$os-$arch" + $rid = if ($arch -eq 'arm64') { 'win-arm64' } else { 'win-x64' } + + if ($IsLinux) { + $os = 'linux' + $platformKey = "$os-$arch" + $rid = "linux-$arch" + } elseif ($IsMacOS) { + $os = 'darwin' + $platformKey = "$os-$arch" + $rid = "osx-$arch" + } + + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" } + + $extractDir = "$(Build.ArtifactStagingDirectory)/flc-extract" + $zip = [System.IO.Path]::ChangeExtension($nupkg.FullName, ".zip") + Copy-Item $nupkg.FullName $zip -Force + Expand-Archive -Path $zip -DestinationPath $extractDir -Force + + $destDir = "$(repoRoot)/sdk/js/packages/@foundry-local-core/$platformKey" + $nativeDir = "$extractDir/runtimes/$rid/native" + if (Test-Path $nativeDir) { + Get-ChildItem $nativeDir -File | ForEach-Object { + Copy-Item $_.FullName -Destination "$destDir/$($_.Name)" -Force + Write-Host "Overwrote $($_.Name) with pipeline-built version" + } + } else { + Write-Warning "No native binaries found at $nativeDir for RID $rid" + } + +- task: Npm@1 + displayName: 'npm build' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'run build' + +- task: Npm@1 + displayName: 'npm test' + inputs: + command: custom + workingDir: $(repoRoot)/sdk/js + customCommand: 'test' + env: + TF_BUILD: 'true' diff --git a/.pipelines/templates/test-python-steps.yml b/.pipelines/templates/test-python-steps.yml new file mode 100644 index 00000000..505dd350 --- /dev/null +++ b/.pipelines/templates/test-python-steps.yml @@ -0,0 +1,98 @@ +# Lightweight test-only steps for the Python SDK. +# Builds from source and runs tests — no artifact staging. +parameters: +- name: version + type: string +- name: isWinML + type: boolean + default: false +- name: flcWheelsDir + type: string + default: '' + displayName: 'Path to directory containing the FLC wheels' + +steps: +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $repoRoot = "$(Build.SourcesDirectory)/Foundry-Local" + $testDataDir = "$(Build.SourcesDirectory)/test-data-shared" + Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" + +- task: UsePythonVersion@0 + displayName: 'Use Python 3.12' + inputs: + versionSpec: '3.12' + +- task: PowerShell@2 + displayName: 'List downloaded FLC wheels' + condition: and(succeeded(), ne('${{ parameters.flcWheelsDir }}', '')) + inputs: + targetType: inline + script: | + Write-Host "Contents of ${{ parameters.flcWheelsDir }}:" + Get-ChildItem "${{ parameters.flcWheelsDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } + +- task: PowerShell@2 + displayName: 'Configure pip for Azure Artifacts' + inputs: + targetType: inline + script: | + pip config set global.index-url https://pkgs.dev.azure.com/aiinfra/PublicPackages/_packaging/ORT-Nightly/pypi/simple/ + pip config set global.extra-index-url https://pypi.org/simple/ + pip config set global.pre true + +- script: python -m pip install build + displayName: 'Install build tool' + +- task: PowerShell@2 + displayName: 'Set SDK version' + inputs: + targetType: inline + script: | + Set-Content -Path "$(repoRoot)/sdk/python/src/version.py" -Value '__version__ = "${{ parameters.version }}"' + +- task: PowerShell@2 + displayName: 'Pre-install pipeline-built FLC wheel' + condition: and(succeeded(), ne('${{ parameters.flcWheelsDir }}', '')) + inputs: + targetType: inline + script: | + $filter = if ("${{ parameters.isWinML }}" -eq "True") { "foundry_local_core_winml*.whl" } else { "foundry_local_core-*.whl" } + $wheel = Get-ChildItem "${{ parameters.flcWheelsDir }}" -Recurse -Filter $filter | Where-Object { $_.Name -notlike "*winml*" -or "${{ parameters.isWinML }}" -eq "True" } | Select-Object -First 1 + if ($wheel) { + Write-Host "Installing pipeline-built FLC wheel: $($wheel.FullName)" + pip install $($wheel.FullName) + } else { + Write-Warning "No FLC wheel found matching $filter" + } + +- script: python -m build --wheel --outdir dist/ + displayName: 'Build wheel' + condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'false')) + workingDirectory: $(repoRoot)/sdk/python + +- script: python -m build --wheel -C winml=true --outdir dist/ + displayName: 'Build wheel (WinML)' + condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'true')) + workingDirectory: $(repoRoot)/sdk/python + +- task: PowerShell@2 + displayName: 'Install built wheel' + inputs: + targetType: inline + script: | + $wheel = (Get-ChildItem "$(repoRoot)/sdk/python/dist/*.whl" | Select-Object -First 1).FullName + pip install $wheel + +- script: pip install coverage pytest>=7.0.0 pytest-timeout>=2.1.0 + displayName: 'Install test dependencies' + +- script: python -m pytest test/ -v + displayName: 'Run tests' + workingDirectory: $(repoRoot)/sdk/python + env: + TF_BUILD: 'true' diff --git a/.pipelines/templates/test-rust-steps.yml b/.pipelines/templates/test-rust-steps.yml new file mode 100644 index 00000000..51da7c2a --- /dev/null +++ b/.pipelines/templates/test-rust-steps.yml @@ -0,0 +1,136 @@ +# Lightweight test-only steps for the Rust SDK. +# Builds from source and runs tests — no cargo package or artifact staging. +parameters: +- name: isWinML + type: boolean + default: false +- name: flcNugetDir + type: string + displayName: 'Path to directory containing the FLC .nupkg' + +steps: +- task: PowerShell@2 + displayName: 'Set source paths' + inputs: + targetType: inline + script: | + $repoRoot = "$(Build.SourcesDirectory)/Foundry-Local" + $testDataDir = "$(Build.SourcesDirectory)/test-data-shared" + Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" + Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" + +- task: PowerShell@2 + displayName: 'List downloaded FLC artifact' + inputs: + targetType: inline + script: | + Write-Host "Contents of ${{ parameters.flcNugetDir }}:" + Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } + +# Extract FLC native binaries from the pipeline-built .nupkg +- task: PowerShell@2 + displayName: 'Extract FLC native binaries' + inputs: + targetType: inline + script: | + $nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1 + if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" } + + $extractDir = "$(Build.ArtifactStagingDirectory)/flc-extract-rust" + $zip = [System.IO.Path]::ChangeExtension($nupkg.FullName, ".zip") + Copy-Item $nupkg.FullName $zip -Force + Expand-Archive -Path $zip -DestinationPath $extractDir -Force + + $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x64' } + if ($IsLinux) { + $rid = "linux-$arch" + } elseif ($IsMacOS) { + $rid = "osx-$arch" + } else { + $rid = "win-$arch" + } + + $nativeDir = "$extractDir/runtimes/$rid/native" + if (-not (Test-Path $nativeDir)) { throw "No native binaries found at $nativeDir for RID $rid" } + + $flcNativeDir = "$(Build.ArtifactStagingDirectory)/flc-native-rust" + New-Item -ItemType Directory -Path $flcNativeDir -Force | Out-Null + Get-ChildItem $nativeDir -File | Copy-Item -Destination $flcNativeDir -Force + Write-Host "##vso[task.setvariable variable=flcNativeDir]$flcNativeDir" + Write-Host "Extracted FLC native binaries for $rid" + +- task: PowerShell@2 + displayName: 'Install Rust toolchain' + inputs: + targetType: inline + script: | + if ($IsWindows -or (-not $IsLinux -and -not $IsMacOS)) { + Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile rustup-init.exe + .\rustup-init.exe -y --default-toolchain stable --profile minimal -c clippy,rustfmt + Remove-Item rustup-init.exe + $cargoPath = "$env:USERPROFILE\.cargo\bin" + } else { + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal -c clippy,rustfmt + $cargoPath = "$env:HOME/.cargo/bin" + } + Write-Host "##vso[task.prependpath]$cargoPath" + +- task: PowerShell@2 + displayName: 'Use crates.io directly' + inputs: + targetType: inline + script: | + $configPath = "$(repoRoot)/sdk/rust/.cargo/config.toml" + if (Test-Path $configPath) { + Remove-Item $configPath + Write-Host "Removed .cargo/config.toml crates-io redirect" + } + +- task: PowerShell@2 + displayName: 'Build' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } + Invoke-Expression "cargo build $features" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +# Overwrite FLC binary with pipeline-built version +- task: PowerShell@2 + displayName: 'Overwrite FLC binary with pipeline-built version' + inputs: + targetType: inline + script: | + $outDir = Get-ChildItem "$(repoRoot)/sdk/rust/target/debug/build" -Directory -Filter "foundry-local-sdk-*" -Recurse | + Where-Object { Test-Path "$($_.FullName)/out" } | + ForEach-Object { "$($_.FullName)/out" } | + Select-Object -First 1 + if (-not $outDir) { throw "Could not find cargo OUT_DIR for foundry-local-sdk" } + + Get-ChildItem "$(flcNativeDir)" -File -Filter "Microsoft.AI.Foundry.Local.Core.*" | ForEach-Object { + Copy-Item $_.FullName -Destination "$outDir/$($_.Name)" -Force + Write-Host "Overwrote $($_.Name) with pipeline-built version" + } + +- task: PowerShell@2 + displayName: 'Run unit tests' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } + Invoke-Expression "cargo test --lib $features" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +- task: PowerShell@2 + displayName: 'Run integration tests' + inputs: + targetType: inline + script: | + Set-Location "$(repoRoot)/sdk/rust" + $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } + Invoke-Expression "cargo test --tests $features -- --include-ignored --test-threads=1 --nocapture" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + env: + TF_BUILD: 'true' From dd65c180d4cb835d369dea54993015535049a7e6 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 11:03:45 -0700 Subject: [PATCH 055/112] versioning --- .pipelines/foundry-local-packaging.yml | 12 ++++++++++++ .pipelines/templates/build-cs-steps.yml | 8 +++++++- .pipelines/templates/build-js-steps.yml | 8 +++++++- .pipelines/templates/build-python-steps.yml | 8 +++++++- .pipelines/templates/package-core-steps.yml | 8 +++++++- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index ed8ea5e8..86eed86a 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -19,6 +19,10 @@ parameters: displayName: 'Release build (omits dev suffix)' type: boolean default: false +- name: prereleaseId + displayName: 'Pre-release identifier (e.g. rc1, beta2). Overrides dev suffix when set.' + type: string + default: '' variables: - group: FoundryLocal-ESRP-Signing @@ -194,6 +198,7 @@ extends: parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: false platforms: - name: win-x64 @@ -233,6 +238,7 @@ extends: parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' @@ -264,6 +270,7 @@ extends: parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' @@ -295,6 +302,7 @@ extends: parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' @@ -606,6 +614,7 @@ extends: parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: true platforms: - name: win-x64 @@ -641,6 +650,7 @@ extends: parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' outputDir: '$(Build.ArtifactStagingDirectory)/cs-sdk-winml' @@ -673,6 +683,7 @@ extends: parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' @@ -704,6 +715,7 @@ extends: parameters: version: ${{ parameters.version }} isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: true flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' outputDir: '$(Build.ArtifactStagingDirectory)/python-sdk-winml' diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index eb9c2ac8..f83b07de 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -17,6 +17,9 @@ parameters: type: string default: '$(Build.ArtifactStagingDirectory)/cs-sdk' displayName: 'Path to directory for the packed SDK' +- name: prereleaseId + type: string + default: '' steps: # Set paths for multi-repo checkout - task: PowerShell@2 @@ -42,7 +45,10 @@ steps: targetType: inline script: | $v = "${{ parameters.version }}" - if ("${{ parameters.isRelease }}" -ne "True") { + $preId = "${{ parameters.prereleaseId }}" + if ($preId -ne '') { + $v = "$v-$preId" + } elseif ("${{ parameters.isRelease }}" -ne "True") { $ts = Get-Date -Format "yyyyMMddHHmm" $v = "$v-dev.$ts" } diff --git a/.pipelines/templates/build-js-steps.yml b/.pipelines/templates/build-js-steps.yml index 44ed9dcf..34e28d89 100644 --- a/.pipelines/templates/build-js-steps.yml +++ b/.pipelines/templates/build-js-steps.yml @@ -14,6 +14,9 @@ parameters: type: string default: '' displayName: 'Path to directory containing the FLC .nupkg (for tests)' +- name: prereleaseId + type: string + default: '' steps: # Set paths for multi-repo checkout - task: PowerShell@2 @@ -49,7 +52,10 @@ steps: targetType: inline script: | $v = "${{ parameters.version }}" - if ("${{ parameters.isRelease }}" -ne "True") { + $preId = "${{ parameters.prereleaseId }}" + if ($preId -ne '') { + $v = "$v-$preId" + } elseif ("${{ parameters.isRelease }}" -ne "True") { $ts = Get-Date -Format "yyyyMMddHHmm" $v = "$v-dev.$ts" } diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml index 257efa2d..00974beb 100644 --- a/.pipelines/templates/build-python-steps.yml +++ b/.pipelines/templates/build-python-steps.yml @@ -18,6 +18,9 @@ parameters: type: string default: '$(Build.ArtifactStagingDirectory)/python-sdk' displayName: 'Path to directory for the built wheel' +- name: prereleaseId + type: string + default: '' steps: # Set paths for multi-repo checkout - task: PowerShell@2 @@ -52,7 +55,10 @@ steps: targetType: inline script: | $v = "${{ parameters.version }}" - if ("${{ parameters.isRelease }}" -ne "True") { + $preId = "${{ parameters.prereleaseId }}" + if ($preId -ne '') { + $v = "$v-$preId" + } elseif ("${{ parameters.isRelease }}" -ne "True") { $ts = Get-Date -Format "yyyyMMddHHmm" $v = "$v-dev.$ts" } diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 4d2a2941..2a57f4c9 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -10,6 +10,9 @@ parameters: - name: isWinML type: boolean default: false +- name: prereleaseId + type: string + default: '' - name: platforms type: object # list of { name, artifactName } @@ -69,7 +72,10 @@ steps: targetType: inline script: | $v = "${{ parameters.version }}" - if ("${{ parameters.isRelease }}" -ne "True") { + $preId = "${{ parameters.prereleaseId }}" + if ($preId -ne '') { + $v = "$v-$preId" + } elseif ("${{ parameters.isRelease }}" -ne "True") { $ts = Get-Date -Format "yyyyMMddHHmm" $commitId = "$(Build.SourceVersion)".Substring(0, 8) $v = "$v-dev-$ts-$commitId" From f61dfea938378054d257c0acb8d52e55bf1ad47c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 11:06:55 -0700 Subject: [PATCH 056/112] prerelease id --- .pipelines/foundry-local-packaging.yml | 4 ++-- .pipelines/templates/build-cs-steps.yml | 2 +- .pipelines/templates/build-js-steps.yml | 2 +- .pipelines/templates/build-python-steps.yml | 2 +- .pipelines/templates/package-core-steps.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 86eed86a..bdfe1ce8 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -20,9 +20,9 @@ parameters: type: boolean default: false - name: prereleaseId - displayName: 'Pre-release identifier (e.g. rc1, beta2). Overrides dev suffix when set.' + displayName: 'Pre-release identifier (e.g. rc1, beta).' type: string - default: '' + default: 'none' variables: - group: FoundryLocal-ESRP-Signing diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index f83b07de..35f970d9 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -46,7 +46,7 @@ steps: script: | $v = "${{ parameters.version }}" $preId = "${{ parameters.prereleaseId }}" - if ($preId -ne '') { + if ($preId -ne '' -and $preId -ne 'none') { $v = "$v-$preId" } elseif ("${{ parameters.isRelease }}" -ne "True") { $ts = Get-Date -Format "yyyyMMddHHmm" diff --git a/.pipelines/templates/build-js-steps.yml b/.pipelines/templates/build-js-steps.yml index 34e28d89..0293e357 100644 --- a/.pipelines/templates/build-js-steps.yml +++ b/.pipelines/templates/build-js-steps.yml @@ -53,7 +53,7 @@ steps: script: | $v = "${{ parameters.version }}" $preId = "${{ parameters.prereleaseId }}" - if ($preId -ne '') { + if ($preId -ne '' -and $preId -ne 'none') { $v = "$v-$preId" } elseif ("${{ parameters.isRelease }}" -ne "True") { $ts = Get-Date -Format "yyyyMMddHHmm" diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml index 00974beb..df68284e 100644 --- a/.pipelines/templates/build-python-steps.yml +++ b/.pipelines/templates/build-python-steps.yml @@ -56,7 +56,7 @@ steps: script: | $v = "${{ parameters.version }}" $preId = "${{ parameters.prereleaseId }}" - if ($preId -ne '') { + if ($preId -ne '' -and $preId -ne 'none') { $v = "$v-$preId" } elseif ("${{ parameters.isRelease }}" -ne "True") { $ts = Get-Date -Format "yyyyMMddHHmm" diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 2a57f4c9..2b53b76e 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -73,7 +73,7 @@ steps: script: | $v = "${{ parameters.version }}" $preId = "${{ parameters.prereleaseId }}" - if ($preId -ne '') { + if ($preId -ne '' -and $preId -ne 'none') { $v = "$v-$preId" } elseif ("${{ parameters.isRelease }}" -ne "True") { $ts = Get-Date -Format "yyyyMMddHHmm" From 5122a6c3aa38d0cc3da18337c48b18f0b488ab0f Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 11:07:49 -0700 Subject: [PATCH 057/112] params naming --- .pipelines/foundry-local-packaging.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index bdfe1ce8..d747a755 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -12,17 +12,17 @@ name: $(Date:yyyyMMdd).$(Rev:r) parameters: - name: version - displayName: 'Package version (e.g. 0.9.0)' + displayName: 'Package version' type: string default: '0.9.0' -- name: isRelease - displayName: 'Release build (omits dev suffix)' - type: boolean - default: false - name: prereleaseId displayName: 'Pre-release identifier (e.g. rc1, beta).' type: string default: 'none' +- name: isRelease + displayName: 'Release build' + type: boolean + default: false variables: - group: FoundryLocal-ESRP-Signing From ba913a136d34373a72dbb058880def7112c4a79d Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 11:25:11 -0700 Subject: [PATCH 058/112] more tests --- .pipelines/foundry-local-packaging.yml | 8 +++---- .pipelines/templates/build-core-steps.yml | 26 ++++++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index d747a755..e67d9f4e 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -63,9 +63,9 @@ extends: - repository: neutron-server - repository: test-data-shared stages: - # ── Build FLC ── + # ── Build & Test FLC ── - stage: build_core - displayName: 'Build FLC' + displayName: 'Build & Test FLC' jobs: - job: flc_win_x64 displayName: 'FLC win-x64' @@ -525,9 +525,9 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Build FLC (WinML) ── + # ── Build & Test FLC (WinML) ── - stage: build_core_winml - displayName: 'Build FLC WinML' + displayName: 'Build & Test FLC WinML' dependsOn: [] jobs: - job: flc_winml_win_x64 diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index c4045fca..4c3ac0cd 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -87,6 +87,30 @@ steps: publishWebProjects: false zipAfterPublish: false + - ${{ if or(eq(parameters.flavor, 'win-x64'), eq(parameters.flavor, 'win-arm64')) }}: + - task: DotNetCoreCLI@2 + displayName: 'Restore FLC Tests ${{ parameters.flavor }} (WinML)' + inputs: + command: restore + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + restoreArguments: '-r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + feedsToUse: config + nugetConfigPath: '$(nsRoot)/nuget.config' + + - task: DotNetCoreCLI@2 + displayName: 'Build FLC Tests ${{ parameters.flavor }} (WinML)' + inputs: + command: build + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + + - task: DotNetCoreCLI@2 + displayName: 'Test FLC ${{ parameters.flavor }} (WinML)' + inputs: + command: test + projects: '$(nsRoot)/test/FoundryLocalCore/Core/FoundryLocalCore.Tests.csproj' + arguments: '--no-build --configuration Release -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }}' + - ${{ if eq(parameters.isWinML, false) }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Core ${{ parameters.flavor }}' @@ -104,7 +128,7 @@ steps: projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' - - ${{ if eq(parameters.flavor, 'win-x64') }}: + - ${{ if or(eq(parameters.flavor, 'win-x64'), eq(parameters.flavor, 'win-arm64')) }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Tests ${{ parameters.flavor }}' inputs: From b6f0863f9323cace08e37a2b62b22f911ff4705c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 11:33:31 -0700 Subject: [PATCH 059/112] no arm --- .pipelines/templates/build-core-steps.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 4c3ac0cd..92691373 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -87,7 +87,7 @@ steps: publishWebProjects: false zipAfterPublish: false - - ${{ if or(eq(parameters.flavor, 'win-x64'), eq(parameters.flavor, 'win-arm64')) }}: + - ${{ if eq(parameters.flavor, 'win-x64') }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Tests ${{ parameters.flavor }} (WinML)' inputs: @@ -128,7 +128,7 @@ steps: projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:IncludeWebService=true /p:Configuration=Release' - - ${{ if or(eq(parameters.flavor, 'win-x64'), eq(parameters.flavor, 'win-arm64')) }}: + - ${{ if eq(parameters.flavor, 'win-x64') }}: - task: DotNetCoreCLI@2 displayName: 'Restore FLC Tests ${{ parameters.flavor }}' inputs: From 166e6ae56e77c4fc56d0633a55afae67527796c6 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 11:49:50 -0700 Subject: [PATCH 060/112] Test data shared --- .pipelines/foundry-local-packaging.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index e67d9f4e..d78904a4 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -543,6 +543,8 @@ extends: steps: - checkout: neutron-server clean: true + - checkout: test-data-shared + lfs: true - template: .pipelines/templates/build-core-steps.yml@self parameters: flavor: win-x64 From 12df205fe55011a7816a62ebd3892054bcb7b1ea Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 12:31:45 -0700 Subject: [PATCH 061/112] tests all after --- .pipelines/foundry-local-packaging.yml | 182 +++++++++++++++++++- .pipelines/templates/build-cs-steps.yml | 36 +--- .pipelines/templates/build-js-steps.yml | 13 +- .pipelines/templates/build-python-steps.yml | 12 +- .pipelines/templates/build-rust-steps.yml | 24 +-- 5 files changed, 178 insertions(+), 89 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index d78904a4..bd03f5fc 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -335,11 +335,32 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Test C# SDK (win-arm64, macOS) ── + # ── Test C# SDK (win-x64, win-arm64, macOS) ── - stage: test_cs displayName: 'Test C# SDK' dependsOn: build_cs jobs: + - job: test_cs_win_x64 + displayName: 'Test C# (win-x64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + - job: test_cs_win_arm64 displayName: 'Test C# (win-arm64)' pool: @@ -383,11 +404,32 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Test JS SDK (win-arm64, macOS) ── + # ── Test JS SDK (win-x64, win-arm64, macOS) ── - stage: test_js displayName: 'Test JS SDK' dependsOn: build_js jobs: + - job: test_js_win_x64 + displayName: 'Test JS (win-x64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + - job: test_js_win_arm64 displayName: 'Test JS (win-arm64)' pool: @@ -431,11 +473,32 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Test Python SDK (win-arm64, macOS) ── + # ── Test Python SDK (win-x64, win-arm64, macOS) ── - stage: test_python displayName: 'Test Python SDK' dependsOn: build_python jobs: + - job: test_python_win_x64 + displayName: 'Test Python (win-x64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels' + targetPath: '$(Pipeline.Workspace)/flc-wheels' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + - job: test_python_win_arm64 displayName: 'Test Python (win-arm64)' pool: @@ -479,11 +542,31 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - # ── Test Rust SDK (win-arm64, macOS) ── + # ── Test Rust SDK (win-x64, win-arm64, macOS) ── - stage: test_rust displayName: 'Test Rust SDK' dependsOn: build_rust jobs: + - job: test_rust_win_x64 + displayName: 'Test Rust (win-x64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + - job: test_rust_win_arm64 displayName: 'Test Rust (win-arm64)' pool: @@ -752,11 +835,32 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' outputDir: '$(Build.ArtifactStagingDirectory)/rust-sdk-winml' - # ── Test C# SDK WinML (win-arm64) ── + # ── Test C# SDK WinML (win-x64, win-arm64) ── - stage: test_cs_winml displayName: 'Test C# SDK WinML' dependsOn: build_cs_winml jobs: + - job: test_cs_winml_win_x64 + displayName: 'Test C# WinML (win-x64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + - job: test_cs_winml_win_arm64 displayName: 'Test C# WinML (win-arm64)' pool: @@ -778,11 +882,32 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - # ── Test JS SDK WinML (win-arm64) ── + # ── Test JS SDK WinML (win-x64, win-arm64) ── - stage: test_js_winml displayName: 'Test JS SDK WinML' dependsOn: build_js_winml jobs: + - job: test_js_winml_win_x64 + displayName: 'Test JS WinML (win-x64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + - job: test_js_winml_win_arm64 displayName: 'Test JS WinML (win-arm64)' pool: @@ -804,11 +929,32 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - # ── Test Python SDK WinML (win-arm64) ── + # ── Test Python SDK WinML (win-x64, win-arm64) ── - stage: test_python_winml displayName: 'Test Python SDK WinML' dependsOn: build_python_winml jobs: + - job: test_python_winml_win_x64 + displayName: 'Test Python WinML (win-x64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels-winml' + targetPath: '$(Pipeline.Workspace)/flc-wheels-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' + - job: test_python_winml_win_arm64 displayName: 'Test Python WinML (win-arm64)' pool: @@ -830,11 +976,31 @@ extends: isWinML: true flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' - # ── Test Rust SDK WinML (win-arm64) ── + # ── Test Rust SDK WinML (win-x64, win-arm64) ── - stage: test_rust_winml displayName: 'Test Rust SDK WinML' dependsOn: build_rust_winml jobs: + - job: test_rust_winml_win_x64 + displayName: 'Test Rust WinML (win-x64)' + pool: + name: onnxruntime-Win-CPU-2022 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + - job: test_rust_winml_win_arm64 displayName: 'Test Rust WinML (win-arm64)' pool: diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 35f970d9..940f7271 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -1,4 +1,4 @@ -# Steps to build, test, sign, and pack the C# SDK NuGet package. +# Steps to build, sign, and pack the C# SDK NuGet package. # When test-data-shared is checked out alongside self, ADO places repos under # $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. parameters: @@ -121,40 +121,6 @@ steps: /p:UseWinML=${{ parameters.isWinML }} if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -# Restore and build test project -- task: PowerShell@2 - displayName: 'Restore tests' - inputs: - targetType: inline - script: | - dotnet restore "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` - --configfile "$(customNugetConfig)" ` - /p:UseWinML=${{ parameters.isWinML }} ` - /p:FoundryLocalCoreVersion=$(resolvedFlcVersion) - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - -- task: PowerShell@2 - displayName: 'Build tests' - inputs: - targetType: inline - script: | - dotnet build "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` - --no-restore --configuration Release ` - /p:UseWinML=${{ parameters.isWinML }} - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - -# Run tests — test-data-shared is a sibling of the repo root -- task: PowerShell@2 - displayName: 'Run SDK tests' - inputs: - targetType: inline - script: | - dotnet test "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` - --no-build --configuration Release - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - env: - TF_BUILD: 'true' - # Discover target framework directory - task: PowerShell@2 displayName: 'Find target framework' diff --git a/.pipelines/templates/build-js-steps.yml b/.pipelines/templates/build-js-steps.yml index 0293e357..e288bbce 100644 --- a/.pipelines/templates/build-js-steps.yml +++ b/.pipelines/templates/build-js-steps.yml @@ -1,4 +1,4 @@ -# Steps to build, test, and pack the JS SDK. +# Steps to build and pack the JS SDK. # When test-data-shared is checked out alongside self, ADO places repos under # $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. parameters: @@ -130,17 +130,6 @@ steps: workingDir: $(repoRoot)/sdk/js customCommand: 'run build' -# Run tests (test-data-shared provides model cache) -- task: Npm@1 - displayName: 'npm test' - condition: and(succeeded(), ne('${{ parameters.flcNugetDir }}', '')) - inputs: - command: custom - workingDir: $(repoRoot)/sdk/js - customCommand: 'test' - env: - TF_BUILD: 'true' - - ${{ if eq(parameters.isWinML, true) }}: - task: Npm@1 displayName: 'npm run pack:winml' diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml index df68284e..b701907c 100644 --- a/.pipelines/templates/build-python-steps.yml +++ b/.pipelines/templates/build-python-steps.yml @@ -1,4 +1,4 @@ -# Steps to build, test, and pack the Python SDK wheel. +# Steps to build and pack the Python SDK wheel. # When test-data-shared is checked out alongside self, ADO places repos under # $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. parameters: @@ -125,16 +125,6 @@ steps: $wheel = (Get-ChildItem "$(repoRoot)/sdk/python/dist/*.whl" | Select-Object -First 1).FullName pip install $wheel -# Install test dependencies and run tests -- script: pip install coverage pytest>=7.0.0 pytest-timeout>=2.1.0 - displayName: 'Install test dependencies' - -- script: python -m pytest test/ -v - displayName: 'Run tests' - workingDirectory: $(repoRoot)/sdk/python - env: - TF_BUILD: 'true' - # Stage output - task: PowerShell@2 displayName: 'Stage wheel artifact' diff --git a/.pipelines/templates/build-rust-steps.yml b/.pipelines/templates/build-rust-steps.yml index 514ae6ee..ed9aff71 100644 --- a/.pipelines/templates/build-rust-steps.yml +++ b/.pipelines/templates/build-rust-steps.yml @@ -1,4 +1,4 @@ -# Steps to build, test, and package the Rust SDK crate. +# Steps to build and package the Rust SDK crate. # When test-data-shared is checked out alongside self, ADO places repos under # $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. parameters: @@ -152,28 +152,6 @@ steps: Write-Host "Overwrote $($_.Name) with pipeline-built version" } -- task: PowerShell@2 - displayName: 'Run unit tests' - inputs: - targetType: inline - script: | - Set-Location "$(repoRoot)/sdk/rust" - $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } - Invoke-Expression "cargo test --lib $features" - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - -- task: PowerShell@2 - displayName: 'Run integration tests' - inputs: - targetType: inline - script: | - Set-Location "$(repoRoot)/sdk/rust" - $features = if ("${{ parameters.isWinML }}" -eq "True") { "--features winml" } else { "" } - Invoke-Expression "cargo test --tests $features -- --include-ignored --test-threads=1 --nocapture" - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - env: - TF_BUILD: 'true' - # --allow-dirty allows packaging with uncommitted changes (build.rs modifies generated files) - task: PowerShell@2 displayName: 'Package crate' From fb832846e22507dab65ccc4de513282a72b97108 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 12:37:04 -0700 Subject: [PATCH 062/112] skip native deps --- .pipelines/templates/build-python-steps.yml | 6 +- .pipelines/templates/test-python-steps.yml | 4 +- sdk/python/build_backend.py | 115 +++++++++++++++----- 3 files changed, 93 insertions(+), 32 deletions(-) diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml index b701907c..2756f0dc 100644 --- a/.pipelines/templates/build-python-steps.yml +++ b/.pipelines/templates/build-python-steps.yml @@ -106,12 +106,14 @@ steps: } # Build wheel — standard or WinML variant -- script: python -m build --wheel --outdir dist/ +# skip-native-deps=true omits foundry-local-core/onnxruntime pinned versions +# from the wheel metadata, since the pipeline pre-installs its own builds. +- script: python -m build --wheel -C skip-native-deps=true --outdir dist/ displayName: 'Build wheel' condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'false')) workingDirectory: $(repoRoot)/sdk/python -- script: python -m build --wheel -C winml=true --outdir dist/ +- script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/ displayName: 'Build wheel (WinML)' condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'true')) workingDirectory: $(repoRoot)/sdk/python diff --git a/.pipelines/templates/test-python-steps.yml b/.pipelines/templates/test-python-steps.yml index 505dd350..d754f1d3 100644 --- a/.pipelines/templates/test-python-steps.yml +++ b/.pipelines/templates/test-python-steps.yml @@ -70,12 +70,12 @@ steps: Write-Warning "No FLC wheel found matching $filter" } -- script: python -m build --wheel --outdir dist/ +- script: python -m build --wheel -C skip-native-deps=true --outdir dist/ displayName: 'Build wheel' condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'false')) workingDirectory: $(repoRoot)/sdk/python -- script: python -m build --wheel -C winml=true --outdir dist/ +- script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/ displayName: 'Build wheel (WinML)' condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'true')) workingDirectory: $(repoRoot)/sdk/python diff --git a/sdk/python/build_backend.py b/sdk/python/build_backend.py index b4b91a1b..3789501b 100644 --- a/sdk/python/build_backend.py +++ b/sdk/python/build_backend.py @@ -18,9 +18,14 @@ python -m build --wheel -C winml=true +Skip native deps (use pre-installed foundry-local-core / ORT / GenAI):: + + python -m build --wheel -C skip-native-deps=true + Environment variable fallback (useful in CI pipelines):: FOUNDRY_VARIANT=winml python -m build --wheel + FOUNDRY_SKIP_NATIVE_DEPS=1 python -m build --wheel """ from __future__ import annotations @@ -46,6 +51,13 @@ _STANDARD_NAME = 'name = "foundry-local-sdk"' _WINML_NAME = 'name = "foundry-local-sdk-winml"' +# Native binary package prefixes to strip when skip-native-deps is active. +_NATIVE_DEP_PREFIXES = ( + "foundry-local-core", + "onnxruntime-core", + "onnxruntime-genai-core", +) + # --------------------------------------------------------------------------- # Variant detection @@ -63,6 +75,23 @@ def _is_winml(config_settings: dict | None) -> bool: return os.environ.get("FOUNDRY_VARIANT", "").lower() == "winml" +def _is_skip_native_deps(config_settings: dict | None) -> bool: + """Return True when native binary dependencies should be omitted. + + When set, ``foundry-local-core``, ``onnxruntime-core``, and + ``onnxruntime-genai-core`` are stripped from requirements.txt so the + wheel is built against whatever versions are already installed. + Useful in CI pipelines that pre-install pipeline-built native wheels. + + Checks ``config_settings["skip-native-deps"]`` first + (set via ``-C skip-native-deps=true``), then falls back to the + ``FOUNDRY_SKIP_NATIVE_DEPS`` environment variable. + """ + if config_settings and str(config_settings.get("skip-native-deps", "")).lower() == "true": + return True + return os.environ.get("FOUNDRY_SKIP_NATIVE_DEPS", "").lower() in ("1", "true") + + # --------------------------------------------------------------------------- # In-place patching context manager # --------------------------------------------------------------------------- @@ -96,58 +125,88 @@ def _patch_for_winml() -> Generator[None, None, None]: _REQUIREMENTS.write_text(requirements_original, encoding="utf-8") +@contextlib.contextmanager +def _strip_native_deps() -> Generator[None, None, None]: + """Temporarily remove native binary deps from requirements.txt. + + Lines starting with any prefix in ``_NATIVE_DEP_PREFIXES`` (case- + insensitive) are removed. The file is restored in the ``finally`` + block. + """ + requirements_original = _REQUIREMENTS.read_text(encoding="utf-8") + try: + filtered = [ + line for line in requirements_original.splitlines(keepends=True) + if not any(line.lstrip().lower().startswith(p) for p in _NATIVE_DEP_PREFIXES) + ] + _REQUIREMENTS.write_text("".join(filtered), encoding="utf-8") + yield + finally: + _REQUIREMENTS.write_text(requirements_original, encoding="utf-8") + + +def _apply_patches(config_settings: dict | None): + """Return a context manager that applies the appropriate patches.""" + winml = _is_winml(config_settings) + skip_native = _is_skip_native_deps(config_settings) + + @contextlib.contextmanager + def _combined(): + # Stack contexts: WinML swaps requirements first, then strip_native + # removes native deps from whatever requirements are active. + if winml and skip_native: + with _patch_for_winml(), _strip_native_deps(): + yield + elif winml: + with _patch_for_winml(): + yield + elif skip_native: + with _strip_native_deps(): + yield + else: + yield + + return _combined() + + # --------------------------------------------------------------------------- # PEP 517 hook delegation # --------------------------------------------------------------------------- def get_requires_for_build_wheel(config_settings=None): - if _is_winml(config_settings): - with _patch_for_winml(): - return _sb.get_requires_for_build_wheel(config_settings) - return _sb.get_requires_for_build_wheel(config_settings) + with _apply_patches(config_settings): + return _sb.get_requires_for_build_wheel(config_settings) def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): - if _is_winml(config_settings): - with _patch_for_winml(): - return _sb.prepare_metadata_for_build_wheel(metadata_directory, config_settings) - return _sb.prepare_metadata_for_build_wheel(metadata_directory, config_settings) + with _apply_patches(config_settings): + return _sb.prepare_metadata_for_build_wheel(metadata_directory, config_settings) def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): - if _is_winml(config_settings): - with _patch_for_winml(): - return _sb.build_wheel(wheel_directory, config_settings, metadata_directory) - return _sb.build_wheel(wheel_directory, config_settings, metadata_directory) + with _apply_patches(config_settings): + return _sb.build_wheel(wheel_directory, config_settings, metadata_directory) def get_requires_for_build_editable(config_settings=None): - if _is_winml(config_settings): - with _patch_for_winml(): - return _sb.get_requires_for_build_editable(config_settings) - return _sb.get_requires_for_build_editable(config_settings) + with _apply_patches(config_settings): + return _sb.get_requires_for_build_editable(config_settings) def prepare_metadata_for_build_editable(metadata_directory, config_settings=None): - if _is_winml(config_settings): - with _patch_for_winml(): - return _sb.prepare_metadata_for_build_editable(metadata_directory, config_settings) - return _sb.prepare_metadata_for_build_editable(metadata_directory, config_settings) + with _apply_patches(config_settings): + return _sb.prepare_metadata_for_build_editable(metadata_directory, config_settings) def build_editable(wheel_directory, config_settings=None, metadata_directory=None): - if _is_winml(config_settings): - with _patch_for_winml(): - return _sb.build_editable(wheel_directory, config_settings, metadata_directory) - return _sb.build_editable(wheel_directory, config_settings, metadata_directory) + with _apply_patches(config_settings): + return _sb.build_editable(wheel_directory, config_settings, metadata_directory) def get_requires_for_build_sdist(config_settings=None): - if _is_winml(config_settings): - with _patch_for_winml(): - return _sb.get_requires_for_build_sdist(config_settings) - return _sb.get_requires_for_build_sdist(config_settings) + with _apply_patches(config_settings): + return _sb.get_requires_for_build_sdist(config_settings) def build_sdist(sdist_directory, config_settings=None): From 8d44d0ffab3b6fb4973e46f66979be302b761693 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 12:38:33 -0700 Subject: [PATCH 063/112] cs tests --- .pipelines/templates/test-cs-steps.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pipelines/templates/test-cs-steps.yml b/.pipelines/templates/test-cs-steps.yml index 70097e30..6e21290f 100644 --- a/.pipelines/templates/test-cs-steps.yml +++ b/.pipelines/templates/test-cs-steps.yml @@ -69,13 +69,13 @@ steps: inputs: targetType: inline script: | - dotnet restore "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + dotnet restore "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj" ` --configfile "$(customNugetConfig)" ` /p:UseWinML=${{ parameters.isWinML }} ` /p:FoundryLocalCoreVersion=$(resolvedFlcVersion) if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - dotnet build "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + dotnet build "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj" ` --no-restore --configuration Release ` /p:UseWinML=${{ parameters.isWinML }} if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } @@ -85,7 +85,7 @@ steps: inputs: targetType: inline script: | - dotnet test "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/FoundryLocal.Tests.csproj" ` + dotnet test "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj" ` --no-build --configuration Release if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } env: From 0fd954b97c753d2757fd4f6fddee3da657e19f6d Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 12:42:09 -0700 Subject: [PATCH 064/112] fix macos tests --- .pipelines/templates/test-js-steps.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.pipelines/templates/test-js-steps.yml b/.pipelines/templates/test-js-steps.yml index d0fbde5a..9c8a0b81 100644 --- a/.pipelines/templates/test-js-steps.yml +++ b/.pipelines/templates/test-js-steps.yml @@ -34,6 +34,30 @@ steps: inputs: versionSpec: '20.x' +# Ensure Node.js arch matches the OS. On macOS ARM64 the tool installer +# may provide an x64 Node running under Rosetta, which cannot load +# ARM64 native libraries. +- task: PowerShell@2 + displayName: 'Verify Node.js architecture' + inputs: + targetType: inline + script: | + $nodeArch = node -p "process.arch" + $osArch = node -p "require('os').arch()" + Write-Host "Node arch: $nodeArch, OS arch: $osArch" + if ($IsMacOS -and $nodeArch -eq 'x64') { + Write-Host "Detected x64 Node on macOS ARM64 — reinstalling ARM64 Node" + $ver = node -p "process.version" + $url = "https://nodejs.org/dist/$ver/node-$ver-darwin-arm64.tar.gz" + $tmp = "$(Agent.TempDirectory)/node-arm64.tar.gz" + Invoke-WebRequest -Uri $url -OutFile $tmp + $extractDir = "$(Agent.TempDirectory)/node-arm64" + New-Item -ItemType Directory -Path $extractDir -Force | Out-Null + tar -xzf $tmp -C $extractDir --strip-components=1 + Write-Host "##vso[task.prependpath]$extractDir/bin" + Write-Host "Installed ARM64 Node: $(& $extractDir/bin/node -p 'process.arch')" + } + - task: Npm@1 displayName: 'npm install' inputs: From a7c8c655a4b8f5c1e8fb68ee3cd8a43ade2782f3 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 13:29:00 -0700 Subject: [PATCH 065/112] python find correct package --- .pipelines/templates/build-python-steps.yml | 10 ++++++++-- .pipelines/templates/test-python-steps.yml | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml index 2756f0dc..3a2119a2 100644 --- a/.pipelines/templates/build-python-steps.yml +++ b/.pipelines/templates/build-python-steps.yml @@ -96,8 +96,14 @@ steps: inputs: targetType: inline script: | - $filter = if ("${{ parameters.isWinML }}" -eq "True") { "foundry_local_core_winml*.whl" } else { "foundry_local_core-*.whl" } - $wheel = Get-ChildItem "${{ parameters.flcWheelsDir }}" -Recurse -Filter $filter | Where-Object { $_.Name -notlike "*winml*" -or "${{ parameters.isWinML }}" -eq "True" } | Select-Object -First 1 + # Determine platform wheel tag for the current machine + $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'amd64' } + if ($IsLinux) { $platTag = "manylinux*x86_64" } + elseif ($IsMacOS) { $platTag = "macosx*$arch" } + else { $platTag = "win_$arch" } + + $filter = if ("${{ parameters.isWinML }}" -eq "True") { "foundry_local_core_winml*$platTag.whl" } else { "foundry_local_core-*$platTag.whl" } + $wheel = Get-ChildItem "${{ parameters.flcWheelsDir }}" -Recurse -Filter $filter | Select-Object -First 1 if ($wheel) { Write-Host "Installing pipeline-built FLC wheel: $($wheel.FullName)" pip install $($wheel.FullName) diff --git a/.pipelines/templates/test-python-steps.yml b/.pipelines/templates/test-python-steps.yml index d754f1d3..7b31d0cd 100644 --- a/.pipelines/templates/test-python-steps.yml +++ b/.pipelines/templates/test-python-steps.yml @@ -61,8 +61,14 @@ steps: inputs: targetType: inline script: | - $filter = if ("${{ parameters.isWinML }}" -eq "True") { "foundry_local_core_winml*.whl" } else { "foundry_local_core-*.whl" } - $wheel = Get-ChildItem "${{ parameters.flcWheelsDir }}" -Recurse -Filter $filter | Where-Object { $_.Name -notlike "*winml*" -or "${{ parameters.isWinML }}" -eq "True" } | Select-Object -First 1 + # Determine platform wheel tag for the current machine + $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'amd64' } + if ($IsLinux) { $platTag = "manylinux*x86_64" } + elseif ($IsMacOS) { $platTag = "macosx*$arch" } + else { $platTag = "win_$arch" } + + $filter = if ("${{ parameters.isWinML }}" -eq "True") { "foundry_local_core_winml*$platTag.whl" } else { "foundry_local_core-*$platTag.whl" } + $wheel = Get-ChildItem "${{ parameters.flcWheelsDir }}" -Recurse -Filter $filter | Select-Object -First 1 if ($wheel) { Write-Host "Installing pipeline-built FLC wheel: $($wheel.FullName)" pip install $($wheel.FullName) From 6e84ce7aa01af75dfae7eac31ec43e853bd1c106 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 13:30:43 -0700 Subject: [PATCH 066/112] rust version --- .pipelines/foundry-local-packaging.yml | 6 +++++ .pipelines/templates/build-rust-steps.yml | 31 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index bd03f5fc..16a4d189 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -332,6 +332,9 @@ extends: lfs: true - template: .pipelines/templates/build-rust-steps.yml@self parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' @@ -831,6 +834,9 @@ extends: lfs: true - template: .pipelines/templates/build-rust-steps.yml@self parameters: + version: ${{ parameters.version }} + isRelease: ${{ parameters.isRelease }} + prereleaseId: ${{ parameters.prereleaseId }} isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' outputDir: '$(Build.ArtifactStagingDirectory)/rust-sdk-winml' diff --git a/.pipelines/templates/build-rust-steps.yml b/.pipelines/templates/build-rust-steps.yml index ed9aff71..efccfaa4 100644 --- a/.pipelines/templates/build-rust-steps.yml +++ b/.pipelines/templates/build-rust-steps.yml @@ -2,6 +2,14 @@ # When test-data-shared is checked out alongside self, ADO places repos under # $(Build.SourcesDirectory)/. The self repo is 'Foundry-Local'. parameters: +- name: version + type: string +- name: isRelease + type: boolean + default: false +- name: prereleaseId + type: string + default: '' - name: isWinML type: boolean default: false @@ -24,6 +32,29 @@ steps: Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" +# Compute package version and patch Cargo.toml +- task: PowerShell@2 + displayName: 'Set crate version' + inputs: + targetType: inline + script: | + $v = "${{ parameters.version }}" + $preId = "${{ parameters.prereleaseId }}" + if ($preId -ne '' -and $preId -ne 'none') { + $v = "$v-$preId" + } elseif ("${{ parameters.isRelease }}" -ne "True") { + $ts = Get-Date -Format "yyyyMMddHHmm" + $v = "$v-dev.$ts" + } + Write-Host "Crate version: $v" + + # Patch Cargo.toml version field + $cargoPath = "$(repoRoot)/sdk/rust/Cargo.toml" + $content = Get-Content $cargoPath -Raw + $content = $content -replace '(?m)^version\s*=\s*"[^"]+"', "version = `"$v`"" + Set-Content -Path $cargoPath -Value $content + Write-Host "Patched Cargo.toml with version $v" + # List downloaded FLC artifact for debugging - task: PowerShell@2 displayName: 'List downloaded FLC artifact' From 74e61e085ba0570e1b080c6a98551ef44b1860e4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 13:37:05 -0700 Subject: [PATCH 067/112] refactor --- .pipelines/foundry-local-packaging.yml | 99 ++++---------------------- .pipelines/templates/test-js-steps.yml | 24 ------- 2 files changed, 12 insertions(+), 111 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 16a4d189..94e90c8b 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -338,7 +338,7 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Test C# SDK (win-x64, win-arm64, macOS) ── + # ── Test C# SDK (win-x64, win-arm64) ── - stage: test_cs displayName: 'Test C# SDK' dependsOn: build_cs @@ -385,29 +385,10 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_cs_osx_arm64 - displayName: 'Test C# (macOS)' - pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-cs-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here + # when ARM64 macOS agents and Linux pools are available. - # ── Test JS SDK (win-x64, win-arm64, macOS) ── + # ── Test JS SDK (win-x64, win-arm64) ── - stage: test_js displayName: 'Test JS SDK' dependsOn: build_js @@ -454,29 +435,10 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_js_osx_arm64 - displayName: 'Test JS (macOS)' - pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-js-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here + # when ARM64 macOS agents and Linux pools are available. - # ── Test Python SDK (win-x64, win-arm64, macOS) ── + # ── Test Python SDK (win-x64, win-arm64) ── - stage: test_python displayName: 'Test Python SDK' dependsOn: build_python @@ -523,29 +485,10 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - - job: test_python_osx_arm64 - displayName: 'Test Python (macOS)' - pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-wheels' - targetPath: '$(Pipeline.Workspace)/flc-wheels' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-python-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here + # when ARM64 macOS agents and Linux pools are available. - # ── Test Rust SDK (win-x64, win-arm64, macOS) ── + # ── Test Rust SDK (win-x64, win-arm64) ── - stage: test_rust displayName: 'Test Rust SDK' dependsOn: build_rust @@ -590,26 +533,8 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_rust_osx_arm64 - displayName: 'Test Rust (macOS)' - pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-rust-steps.yml@self - parameters: - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here + # when ARM64 macOS agents and Linux pools are available. # ── Build & Test FLC (WinML) ── - stage: build_core_winml diff --git a/.pipelines/templates/test-js-steps.yml b/.pipelines/templates/test-js-steps.yml index 9c8a0b81..d0fbde5a 100644 --- a/.pipelines/templates/test-js-steps.yml +++ b/.pipelines/templates/test-js-steps.yml @@ -34,30 +34,6 @@ steps: inputs: versionSpec: '20.x' -# Ensure Node.js arch matches the OS. On macOS ARM64 the tool installer -# may provide an x64 Node running under Rosetta, which cannot load -# ARM64 native libraries. -- task: PowerShell@2 - displayName: 'Verify Node.js architecture' - inputs: - targetType: inline - script: | - $nodeArch = node -p "process.arch" - $osArch = node -p "require('os').arch()" - Write-Host "Node arch: $nodeArch, OS arch: $osArch" - if ($IsMacOS -and $nodeArch -eq 'x64') { - Write-Host "Detected x64 Node on macOS ARM64 — reinstalling ARM64 Node" - $ver = node -p "process.version" - $url = "https://nodejs.org/dist/$ver/node-$ver-darwin-arm64.tar.gz" - $tmp = "$(Agent.TempDirectory)/node-arm64.tar.gz" - Invoke-WebRequest -Uri $url -OutFile $tmp - $extractDir = "$(Agent.TempDirectory)/node-arm64" - New-Item -ItemType Directory -Path $extractDir -Force | Out-Null - tar -xzf $tmp -C $extractDir --strip-components=1 - Write-Host "##vso[task.prependpath]$extractDir/bin" - Write-Host "Installed ARM64 Node: $(& $extractDir/bin/node -p 'process.arch')" - } - - task: Npm@1 displayName: 'npm install' inputs: From 1f13ac0992350e932dcfedfac575d371179c07cb Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 13:44:02 -0700 Subject: [PATCH 068/112] useWinML --- .pipelines/templates/test-cs-steps.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/test-cs-steps.yml b/.pipelines/templates/test-cs-steps.yml index 6e21290f..3060b137 100644 --- a/.pipelines/templates/test-cs-steps.yml +++ b/.pipelines/templates/test-cs-steps.yml @@ -86,7 +86,8 @@ steps: targetType: inline script: | dotnet test "$(repoRoot)/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj" ` - --no-build --configuration Release + --no-build --configuration Release ` + /p:UseWinML=${{ parameters.isWinML }} if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } env: TF_BUILD: 'true' From 53930c92a7c3bee1c2b6d077b1578a19a52dcb5d Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 14:53:47 -0700 Subject: [PATCH 069/112] install deps --- .pipelines/foundry-local-packaging.yml | 165 --------------------- .pipelines/templates/test-python-steps.yml | 6 + 2 files changed, 6 insertions(+), 165 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 94e90c8b..30ea3334 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -364,27 +364,6 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_cs_win_arm64 - displayName: 'Test C# (win-arm64)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-cs-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here # when ARM64 macOS agents and Linux pools are available. @@ -414,27 +393,6 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_js_win_arm64 - displayName: 'Test JS (win-arm64)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-js-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here # when ARM64 macOS agents and Linux pools are available. @@ -464,27 +422,6 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - - job: test_python_win_arm64 - displayName: 'Test Python (win-arm64)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-wheels' - targetPath: '$(Pipeline.Workspace)/flc-wheels' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-python-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here # when ARM64 macOS agents and Linux pools are available. @@ -513,26 +450,6 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_rust_win_arm64 - displayName: 'Test Rust (win-arm64)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-rust-steps.yml@self - parameters: - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here # when ARM64 macOS agents and Linux pools are available. @@ -792,27 +709,6 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - - job: test_cs_winml_win_arm64 - displayName: 'Test C# WinML (win-arm64)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget-winml' - targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-cs-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: true - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - # ── Test JS SDK WinML (win-x64, win-arm64) ── - stage: test_js_winml displayName: 'Test JS SDK WinML' @@ -839,27 +735,6 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - - job: test_js_winml_win_arm64 - displayName: 'Test JS WinML (win-arm64)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget-winml' - targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-js-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: true - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - # ── Test Python SDK WinML (win-x64, win-arm64) ── - stage: test_python_winml displayName: 'Test Python SDK WinML' @@ -886,27 +761,6 @@ extends: isWinML: true flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' - - job: test_python_winml_win_arm64 - displayName: 'Test Python WinML (win-arm64)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-wheels-winml' - targetPath: '$(Pipeline.Workspace)/flc-wheels-winml' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-python-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: true - flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' - # ── Test Rust SDK WinML (win-x64, win-arm64) ── - stage: test_rust_winml displayName: 'Test Rust SDK WinML' @@ -932,22 +786,3 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - - job: test_rust_winml_win_arm64 - displayName: 'Test Rust WinML (win-arm64)' - pool: - name: onnxruntime-Win-CPU-2022 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget-winml' - targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-rust-steps.yml@self - parameters: - isWinML: true - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' diff --git a/.pipelines/templates/test-python-steps.yml b/.pipelines/templates/test-python-steps.yml index 7b31d0cd..965c59ed 100644 --- a/.pipelines/templates/test-python-steps.yml +++ b/.pipelines/templates/test-python-steps.yml @@ -76,6 +76,12 @@ steps: Write-Warning "No FLC wheel found matching $filter" } +# Install ORT native packages from the ORT-Nightly feed. +# skip-native-deps strips these from the SDK wheel metadata, so they +# must be installed explicitly for tests to locate the native binaries. +- script: pip install onnxruntime-core onnxruntime-genai-core + displayName: 'Install ORT native packages' + - script: python -m build --wheel -C skip-native-deps=true --outdir dist/ displayName: 'Build wheel' condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'false')) From 4f8881e54f58d4da76c09f3d4c09673bd8a123a5 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 15:45:15 -0700 Subject: [PATCH 070/112] windows.ai.toolkit --- .pipelines/foundry-local-packaging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 30ea3334..d938afc0 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -1,6 +1,6 @@ # Foundry Local Packaging Pipeline # -# Builds Foundry Local Core from neutron-server (AIFoundryLocal project), +# Builds Foundry Local Core from neutron-server (windows.ai.toolkit project), # then packages the C# and JS SDKs from this repo using the built Core. # # Produces artifacts: flc-nuget, flc-nuget-winml, flc-wheels, flc-wheels-winml, From ab6de55735f54a483fd1bd5673ec4caa0772a750 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 16:03:02 -0700 Subject: [PATCH 071/112] Arm64 --- .pipelines/foundry-local-packaging.yml | 182 +++++++++++++++++++++++-- 1 file changed, 172 insertions(+), 10 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index d938afc0..d8415e3c 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -90,7 +90,7 @@ extends: - job: flc_win_arm64 displayName: 'FLC win-arm64' pool: - name: onnxruntime-Win-CPU-2022 + name: onnxruntime-genai-windows-vs-2022-arm64 os: windows templateContext: outputs: @@ -364,8 +364,28 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here - # when ARM64 macOS agents and Linux pools are available. + - job: test_cs_win_arm64 + displayName: 'Test C# (win-arm64)' + pool: + name: onnxruntime-genai-windows-vs-2022-arm64 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs when pools are available. # ── Test JS SDK (win-x64, win-arm64) ── - stage: test_js @@ -393,8 +413,28 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here - # when ARM64 macOS agents and Linux pools are available. + - job: test_js_win_arm64 + displayName: 'Test JS (win-arm64)' + pool: + name: onnxruntime-genai-windows-vs-2022-arm64 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs when pools are available. # ── Test Python SDK (win-x64, win-arm64) ── - stage: test_python @@ -422,8 +462,28 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here - # when ARM64 macOS agents and Linux pools are available. + - job: test_python_win_arm64 + displayName: 'Test Python (win-arm64)' + pool: + name: onnxruntime-genai-windows-vs-2022-arm64 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels' + targetPath: '$(Pipeline.Workspace)/flc-wheels' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + + # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs when pools are available. # ── Test Rust SDK (win-x64, win-arm64) ── - stage: test_rust @@ -450,8 +510,27 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs here - # when ARM64 macOS agents and Linux pools are available. + - job: test_rust_win_arm64 + displayName: 'Test Rust (win-arm64)' + pool: + name: onnxruntime-genai-windows-vs-2022-arm64 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs when pools are available. # ── Build & Test FLC (WinML) ── - stage: build_core_winml @@ -482,7 +561,7 @@ extends: - job: flc_winml_win_arm64 displayName: 'FLC win-arm64 (WinML)' pool: - name: onnxruntime-Win-CPU-2022 + name: onnxruntime-genai-windows-vs-2022-arm64 os: windows templateContext: outputs: @@ -709,6 +788,27 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + - job: test_cs_winml_win_arm64 + displayName: 'Test C# WinML (win-arm64)' + pool: + name: onnxruntime-genai-windows-vs-2022-arm64 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + # ── Test JS SDK WinML (win-x64, win-arm64) ── - stage: test_js_winml displayName: 'Test JS SDK WinML' @@ -735,6 +835,27 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + - job: test_js_winml_win_arm64 + displayName: 'Test JS WinML (win-arm64)' + pool: + name: onnxruntime-genai-windows-vs-2022-arm64 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + # ── Test Python SDK WinML (win-x64, win-arm64) ── - stage: test_python_winml displayName: 'Test Python SDK WinML' @@ -761,6 +882,27 @@ extends: isWinML: true flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' + - job: test_python_winml_win_arm64 + displayName: 'Test Python WinML (win-arm64)' + pool: + name: onnxruntime-genai-windows-vs-2022-arm64 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels-winml' + targetPath: '$(Pipeline.Workspace)/flc-wheels-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: true + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' + # ── Test Rust SDK WinML (win-x64, win-arm64) ── - stage: test_rust_winml displayName: 'Test Rust SDK WinML' @@ -786,3 +928,23 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + - job: test_rust_winml_win_arm64 + displayName: 'Test Rust WinML (win-arm64)' + pool: + name: onnxruntime-genai-windows-vs-2022-arm64 + os: windows + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget-winml' + targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: true + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + From a507127d70f59c39deaaf53fe77a91a84f41eda7 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 19:48:33 -0700 Subject: [PATCH 072/112] bug fixes --- .pipelines/foundry-local-packaging.yml | 105 ++++++++++++++++++++-- .pipelines/templates/build-core-steps.yml | 1 - 2 files changed, 96 insertions(+), 10 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index d8415e3c..b2a07180 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -90,7 +90,7 @@ extends: - job: flc_win_arm64 displayName: 'FLC win-arm64' pool: - name: onnxruntime-genai-windows-vs-2022-arm64 + name: onnxruntime-qnn-windows-vs-2022-arm64 os: windows templateContext: outputs: @@ -338,7 +338,7 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Test C# SDK (win-x64, win-arm64) ── + # ── Test C# SDK (win-x64, win-arm64, osx-arm64) ── - stage: test_cs displayName: 'Test C# SDK' dependsOn: build_cs @@ -385,9 +385,31 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs when pools are available. + - job: test_cs_osx_arm64 + displayName: 'Test C# (osx-arm64)' + pool: + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-cs-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # TODO: Add Linux (linux-x64) test job when Linux pools are available. - # ── Test JS SDK (win-x64, win-arm64) ── + # ── Test JS SDK (win-x64, win-arm64, osx-arm64) ── - stage: test_js displayName: 'Test JS SDK' dependsOn: build_js @@ -434,9 +456,31 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs when pools are available. + - job: test_js_osx_arm64 + displayName: 'Test JS (osx-arm64)' + pool: + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-js-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # TODO: Add Linux (linux-x64) test job when Linux pools are available. - # ── Test Python SDK (win-x64, win-arm64) ── + # ── Test Python SDK (win-x64, win-arm64, osx-arm64) ── - stage: test_python displayName: 'Test Python SDK' dependsOn: build_python @@ -483,9 +527,31 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs when pools are available. + - job: test_python_osx_arm64 + displayName: 'Test Python (osx-arm64)' + pool: + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-wheels' + targetPath: '$(Pipeline.Workspace)/flc-wheels' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-python-steps.yml@self + parameters: + version: ${{ parameters.version }} + isWinML: false + flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' + + # TODO: Add Linux (linux-x64) test job when Linux pools are available. - # ── Test Rust SDK (win-x64, win-arm64) ── + # ── Test Rust SDK (win-x64, win-arm64, osx-arm64) ── - stage: test_rust displayName: 'Test Rust SDK' dependsOn: build_rust @@ -530,7 +596,28 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add macOS (osx-arm64) and Linux (linux-x64) test jobs when pools are available. + - job: test_rust_osx_arm64 + displayName: 'Test Rust (osx-arm64)' + pool: + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'flc-nuget' + targetPath: '$(Pipeline.Workspace)/flc-nuget' + steps: + - checkout: self + clean: true + - checkout: test-data-shared + lfs: true + - template: .pipelines/templates/test-rust-steps.yml@self + parameters: + isWinML: false + flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' + + # TODO: Add Linux (linux-x64) test job when Linux pools are available. # ── Build & Test FLC (WinML) ── - stage: build_core_winml diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index 92691373..b30772b5 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -47,7 +47,6 @@ steps: - # https://github.com/microsoft/azure-pipelines-tasks/issues/20910 From 6ea492c51ba0f6ae2976f54159c937ae28edf3ce Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 20:16:21 -0700 Subject: [PATCH 073/112] win-x64 and osx-arm64 tests only --- .pipelines/foundry-local-packaging.yml | 217 +++---------------------- 1 file changed, 26 insertions(+), 191 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index b2a07180..17b7efba 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -90,7 +90,7 @@ extends: - job: flc_win_arm64 displayName: 'FLC win-arm64' pool: - name: onnxruntime-qnn-windows-vs-2022-arm64 + name: onnxruntime-Win-CPU-2022 os: windows templateContext: outputs: @@ -126,9 +126,7 @@ extends: - job: flc_osx_arm64 displayName: 'FLC osx-arm64' pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS + vmImage: 'macOS-latest' templateContext: outputs: - output: pipelineArtifact @@ -338,7 +336,7 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Test C# SDK (win-x64, win-arm64, osx-arm64) ── + # ── Test C# SDK (win-x64, osx-arm64) ── - stage: test_cs displayName: 'Test C# SDK' dependsOn: build_cs @@ -364,33 +362,10 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_cs_win_arm64 - displayName: 'Test C# (win-arm64)' - pool: - name: onnxruntime-genai-windows-vs-2022-arm64 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-cs-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_cs_osx_arm64 displayName: 'Test C# (osx-arm64)' pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS + vmImage: 'macOS-latest' templateContext: inputs: - input: pipelineArtifact @@ -407,9 +382,10 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add Linux (linux-x64) test job when Linux pools are available. + # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. + # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. - # ── Test JS SDK (win-x64, win-arm64, osx-arm64) ── + # ── Test JS SDK (win-x64, osx-arm64) ── - stage: test_js displayName: 'Test JS SDK' dependsOn: build_js @@ -435,33 +411,10 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_js_win_arm64 - displayName: 'Test JS (win-arm64)' - pool: - name: onnxruntime-genai-windows-vs-2022-arm64 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-js-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_js_osx_arm64 displayName: 'Test JS (osx-arm64)' pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS + vmImage: 'macOS-latest' templateContext: inputs: - input: pipelineArtifact @@ -478,9 +431,10 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add Linux (linux-x64) test job when Linux pools are available. + # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. + # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. - # ── Test Python SDK (win-x64, win-arm64, osx-arm64) ── + # ── Test Python SDK (win-x64, osx-arm64) ── - stage: test_python displayName: 'Test Python SDK' dependsOn: build_python @@ -506,33 +460,10 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - - job: test_python_win_arm64 - displayName: 'Test Python (win-arm64)' - pool: - name: onnxruntime-genai-windows-vs-2022-arm64 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-wheels' - targetPath: '$(Pipeline.Workspace)/flc-wheels' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-python-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - - job: test_python_osx_arm64 displayName: 'Test Python (osx-arm64)' pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS + vmImage: 'macOS-latest' templateContext: inputs: - input: pipelineArtifact @@ -549,9 +480,9 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - # TODO: Add Linux (linux-x64) test job when Linux pools are available. + # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. - # ── Test Rust SDK (win-x64, win-arm64, osx-arm64) ── + # ── Test Rust SDK (win-x64, osx-arm64) ── - stage: test_rust displayName: 'Test Rust SDK' dependsOn: build_rust @@ -576,32 +507,10 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_rust_win_arm64 - displayName: 'Test Rust (win-arm64)' - pool: - name: onnxruntime-genai-windows-vs-2022-arm64 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-rust-steps.yml@self - parameters: - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_rust_osx_arm64 displayName: 'Test Rust (osx-arm64)' pool: - name: Azure Pipelines - vmImage: 'macOS-14' - os: macOS + vmImage: 'macOS-latest' templateContext: inputs: - input: pipelineArtifact @@ -617,7 +526,8 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # TODO: Add Linux (linux-x64) test job when Linux pools are available. + # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. + # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. # ── Build & Test FLC (WinML) ── - stage: build_core_winml @@ -648,7 +558,7 @@ extends: - job: flc_winml_win_arm64 displayName: 'FLC win-arm64 (WinML)' pool: - name: onnxruntime-genai-windows-vs-2022-arm64 + name: onnxruntime-Win-CPU-2022 os: windows templateContext: outputs: @@ -849,7 +759,7 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' outputDir: '$(Build.ArtifactStagingDirectory)/rust-sdk-winml' - # ── Test C# SDK WinML (win-x64, win-arm64) ── + # ── Test C# SDK WinML (win-x64) ── - stage: test_cs_winml displayName: 'Test C# SDK WinML' dependsOn: build_cs_winml @@ -875,28 +785,9 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - - job: test_cs_winml_win_arm64 - displayName: 'Test C# WinML (win-arm64)' - pool: - name: onnxruntime-genai-windows-vs-2022-arm64 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget-winml' - targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-cs-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: true - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. - # ── Test JS SDK WinML (win-x64, win-arm64) ── + # ── Test JS SDK WinML (win-x64) ── - stage: test_js_winml displayName: 'Test JS SDK WinML' dependsOn: build_js_winml @@ -922,28 +813,9 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - - job: test_js_winml_win_arm64 - displayName: 'Test JS WinML (win-arm64)' - pool: - name: onnxruntime-genai-windows-vs-2022-arm64 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget-winml' - targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-js-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: true - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. - # ── Test Python SDK WinML (win-x64, win-arm64) ── + # ── Test Python SDK WinML (win-x64) ── - stage: test_python_winml displayName: 'Test Python SDK WinML' dependsOn: build_python_winml @@ -969,28 +841,9 @@ extends: isWinML: true flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' - - job: test_python_winml_win_arm64 - displayName: 'Test Python WinML (win-arm64)' - pool: - name: onnxruntime-genai-windows-vs-2022-arm64 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-wheels-winml' - targetPath: '$(Pipeline.Workspace)/flc-wheels-winml' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-python-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: true - flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml' + # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. - # ── Test Rust SDK WinML (win-x64, win-arm64) ── + # ── Test Rust SDK WinML (win-x64) ── - stage: test_rust_winml displayName: 'Test Rust SDK WinML' dependsOn: build_rust_winml @@ -1015,23 +868,5 @@ extends: isWinML: true flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' - - job: test_rust_winml_win_arm64 - displayName: 'Test Rust WinML (win-arm64)' - pool: - name: onnxruntime-genai-windows-vs-2022-arm64 - os: windows - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget-winml' - targetPath: '$(Pipeline.Workspace)/flc-nuget-winml' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-rust-steps.yml@self - parameters: - isWinML: true - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml' + # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. From ace8252267b6a9f4285a25f23860f031f1e740f4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 20:26:33 -0700 Subject: [PATCH 074/112] windows-ize pipeline --- .pipelines/foundry-local-packaging.yml | 107 +++++-------------------- 1 file changed, 21 insertions(+), 86 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 17b7efba..c238dce8 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -90,6 +90,8 @@ extends: - job: flc_win_arm64 displayName: 'FLC win-arm64' pool: + # dotnet supports cross compilation from win-x64 to osx-arm64, linux-x64, and win-arm64: + # https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile#windows name: onnxruntime-Win-CPU-2022 os: windows templateContext: @@ -108,8 +110,10 @@ extends: - job: flc_linux_x64 displayName: 'FLC linux-x64' pool: - name: onnxruntime-Ubuntu2404-AMD-CPU - os: linux + # dotnet supports cross compilation from win-x64 to linux-x64, osx-arm64, and win-arm64: + # https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile#windows + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: outputs: - output: pipelineArtifact @@ -126,7 +130,10 @@ extends: - job: flc_osx_arm64 displayName: 'FLC osx-arm64' pool: - vmImage: 'macOS-latest' + # dotnet supports cross compilation from win-x64 to linux-x64, osx-arm64, and win-arm64: + # https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile#windows + name: onnxruntime-Win-CPU-2022 + os: windows templateContext: outputs: - output: pipelineArtifact @@ -336,7 +343,7 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - # ── Test C# SDK (win-x64, osx-arm64) ── + # ── Test C# SDK (win-x64) ── - stage: test_cs displayName: 'Test C# SDK' dependsOn: build_cs @@ -362,30 +369,11 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_cs_osx_arm64 - displayName: 'Test C# (osx-arm64)' - pool: - vmImage: 'macOS-latest' - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-cs-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - + # TODO: Add macOS (osx-arm64) test job when a macOS ARM64 pool is available. # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. - # ── Test JS SDK (win-x64, osx-arm64) ── + # ── Test JS SDK (win-x64) ── - stage: test_js displayName: 'Test JS SDK' dependsOn: build_js @@ -411,30 +399,11 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_js_osx_arm64 - displayName: 'Test JS (osx-arm64)' - pool: - vmImage: 'macOS-latest' - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-js-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - + # TODO: Add macOS (osx-arm64) test job when a macOS ARM64 pool is available. # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. - # ── Test Python SDK (win-x64, osx-arm64) ── + # ── Test Python SDK (win-x64) ── - stage: test_python displayName: 'Test Python SDK' dependsOn: build_python @@ -460,29 +429,11 @@ extends: isWinML: false flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - - job: test_python_osx_arm64 - displayName: 'Test Python (osx-arm64)' - pool: - vmImage: 'macOS-latest' - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-wheels' - targetPath: '$(Pipeline.Workspace)/flc-wheels' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-python-steps.yml@self - parameters: - version: ${{ parameters.version }} - isWinML: false - flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' - + # TODO: Add macOS (osx-arm64) test job when a macOS ARM64 pool is available. # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. + # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. - # ── Test Rust SDK (win-x64, osx-arm64) ── + # ── Test Rust SDK (win-x64) ── - stage: test_rust displayName: 'Test Rust SDK' dependsOn: build_rust @@ -507,25 +458,7 @@ extends: isWinML: false flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - - job: test_rust_osx_arm64 - displayName: 'Test Rust (osx-arm64)' - pool: - vmImage: 'macOS-latest' - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'flc-nuget' - targetPath: '$(Pipeline.Workspace)/flc-nuget' - steps: - - checkout: self - clean: true - - checkout: test-data-shared - lfs: true - - template: .pipelines/templates/test-rust-steps.yml@self - parameters: - isWinML: false - flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' - + # TODO: Add macOS (osx-arm64) test job when a macOS ARM64 pool is available. # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. @@ -558,6 +491,8 @@ extends: - job: flc_winml_win_arm64 displayName: 'FLC win-arm64 (WinML)' pool: + # dotnet supports cross compilation from win-x64 to win-arm64: + # https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile#windows name: onnxruntime-Win-CPU-2022 os: windows templateContext: From e702b900b1c50e212ca96c612bcbe88023f91e65 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 20:39:58 -0700 Subject: [PATCH 075/112] return pools --- .pipelines/foundry-local-packaging.yml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index c238dce8..4f4a184c 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -90,8 +90,6 @@ extends: - job: flc_win_arm64 displayName: 'FLC win-arm64' pool: - # dotnet supports cross compilation from win-x64 to osx-arm64, linux-x64, and win-arm64: - # https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile#windows name: onnxruntime-Win-CPU-2022 os: windows templateContext: @@ -110,10 +108,8 @@ extends: - job: flc_linux_x64 displayName: 'FLC linux-x64' pool: - # dotnet supports cross compilation from win-x64 to linux-x64, osx-arm64, and win-arm64: - # https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile#windows - name: onnxruntime-Win-CPU-2022 - os: windows + name: onnxruntime-Ubuntu2404-AMD-CPU + os: linux templateContext: outputs: - output: pipelineArtifact @@ -130,10 +126,9 @@ extends: - job: flc_osx_arm64 displayName: 'FLC osx-arm64' pool: - # dotnet supports cross compilation from win-x64 to linux-x64, osx-arm64, and win-arm64: - # https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile#windows - name: onnxruntime-Win-CPU-2022 - os: windows + name: Azure Pipelines + vmImage: 'macOS-14' + os: macOS templateContext: outputs: - output: pipelineArtifact @@ -491,8 +486,6 @@ extends: - job: flc_winml_win_arm64 displayName: 'FLC win-arm64 (WinML)' pool: - # dotnet supports cross compilation from win-x64 to win-arm64: - # https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile#windows name: onnxruntime-Win-CPU-2022 os: windows templateContext: From 6e89cecfc3d96388262c52cc2a338748417894fb Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 22:07:49 -0700 Subject: [PATCH 076/112] macos-latest --- .pipelines/foundry-local-packaging.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 4f4a184c..a7591fdc 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -126,8 +126,7 @@ extends: - job: flc_osx_arm64 displayName: 'FLC osx-arm64' pool: - name: Azure Pipelines - vmImage: 'macOS-14' + name: macos-latest os: macOS templateContext: outputs: From 2c40b4394160750763d45f6d8d4d4370df8c4d0c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 22:13:00 -0700 Subject: [PATCH 077/112] try --- .pipelines/foundry-local-packaging.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index a7591fdc..61cbb6d7 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -126,7 +126,8 @@ extends: - job: flc_osx_arm64 displayName: 'FLC osx-arm64' pool: - name: macos-latest + name: Azure Pipelines + vmImage: 'macOS-14-arm64' os: macOS templateContext: outputs: From a27a281a2e5a10594ffb816b914fb80461bb3076 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 22:14:55 -0700 Subject: [PATCH 078/112] latest --- .pipelines/foundry-local-packaging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 61cbb6d7..29a785b0 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -127,7 +127,7 @@ extends: displayName: 'FLC osx-arm64' pool: name: Azure Pipelines - vmImage: 'macOS-14-arm64' + vmImage: 'macOS-latest' os: macOS templateContext: outputs: From 28b6f5160353ba578086d824474056ebdd2195cc Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 27 Mar 2026 22:20:03 -0700 Subject: [PATCH 079/112] azure pipelines --- .pipelines/foundry-local-packaging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 29a785b0..4f4a184c 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -127,7 +127,7 @@ extends: displayName: 'FLC osx-arm64' pool: name: Azure Pipelines - vmImage: 'macOS-latest' + vmImage: 'macOS-14' os: macOS templateContext: outputs: From d2e429e1570a650a12c171f63a96adb34ed70908 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 11:08:14 -0700 Subject: [PATCH 080/112] bootstrap --- .pipelines/templates/build-core-steps.yml | 15 ++++++++++++--- .pipelines/templates/package-core-steps.yml | 13 +++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index b30772b5..e1492547 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -177,9 +177,18 @@ steps: script: | $destDir = "$(Build.ArtifactStagingDirectory)/native" New-Item -ItemType Directory -Path $destDir -Force | Out-Null - Get-ChildItem "$(nsRoot)/artifacts/publish" -Recurse -File | - Where-Object { $_.Name -like "Microsoft.AI.Foundry.Local.Core.*" } | - Copy-Item -Destination $destDir -Force + # WinML publishes additional files (e.g. WindowsAppRuntime Bootstrapper DLLs) + # beyond Microsoft.AI.Foundry.Local.Core.*. + $isWinML = "${{ parameters.isWinML }}" -eq "True" + if ($isWinML) { + Get-ChildItem "$(nsRoot)/artifacts/publish" -Recurse -File | + Where-Object { $_.Name -like "Microsoft.AI.Foundry.Local.Core.*" -or $_.Name -eq "Microsoft.WindowsAppRuntime.Bootstrap.dll" } | + Copy-Item -Destination $destDir -Force + } else { + Get-ChildItem "$(nsRoot)/artifacts/publish" -Recurse -File | + Where-Object { $_.Name -like "Microsoft.AI.Foundry.Local.Core.*" } | + Copy-Item -Destination $destDir -Force + } Write-Host "Staged binaries:" Get-ChildItem $destDir | ForEach-Object { Write-Host " $($_.Name)" } diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 2b53b76e..1d8e3789 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -47,8 +47,17 @@ steps: } $destDir = "$unifiedPath/runtimes/$($p.name)/native" New-Item -ItemType Directory -Path $destDir -Force | Out-Null - Get-ChildItem $srcDir -File | Where-Object { $_.Name -like "Microsoft.AI.Foundry.Local.Core.*" } | - Copy-Item -Destination $destDir -Force + # WinML artifacts include WindowsAppRuntime Bootstrapper DLLs in addition + # to Microsoft.AI.Foundry.Local.Core.*. + $isWinML = "${{ parameters.isWinML }}" -eq "True" + if ($isWinML) { + Get-ChildItem $srcDir -File | + Where-Object { $_.Name -like "Microsoft.AI.Foundry.Local.Core.*" -or $_.Name -eq "Microsoft.WindowsAppRuntime.Bootstrap.dll" } | + Copy-Item -Destination $destDir -Force + } else { + Get-ChildItem $srcDir -File | Where-Object { $_.Name -like "Microsoft.AI.Foundry.Local.Core.*" } | + Copy-Item -Destination $destDir -Force + } Write-Host "Copied $($p.name) binaries to $destDir" } From a8a49df131266b74e412c3837e694d8d1ce8f1d0 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 12:12:30 -0700 Subject: [PATCH 081/112] load bootstrap dll --- sdk/python/src/detail/core_interop.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/python/src/detail/core_interop.py b/sdk/python/src/detail/core_interop.py index 7a6bb08c..4f4ddb67 100644 --- a/sdk/python/src/detail/core_interop.py +++ b/sdk/python/src/detail/core_interop.py @@ -205,6 +205,9 @@ def __init__(self, config: Configuration): if sys.platform.startswith("win"): bootstrap_dll = paths.core_dir / "Microsoft.WindowsAppRuntime.Bootstrap.dll" if bootstrap_dll.exists(): + # Pre-load so the DLL is already in the process when + # C# P/Invoke resolves it during Bootstrap.Initialize(). + ctypes.CDLL(str(bootstrap_dll)) if config.additional_settings is None: config.additional_settings = {} if "Bootstrap" not in config.additional_settings: From 0571163573a4397d18cb8b59c388da86580ecaaa Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 12:15:09 -0700 Subject: [PATCH 082/112] no build --- .pipelines/templates/build-core-steps.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/build-core-steps.yml b/.pipelines/templates/build-core-steps.yml index e1492547..9f024c42 100644 --- a/.pipelines/templates/build-core-steps.yml +++ b/.pipelines/templates/build-core-steps.yml @@ -82,7 +82,7 @@ steps: inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' + arguments: '--no-restore --no-build -r ${{ parameters.flavor }} -f net9.0-windows10.0.26100.0 /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:NetTargetFramework=net9.0-windows10.0.26100.0 /p:UseWinML=true' publishWebProjects: false zipAfterPublish: false @@ -156,7 +156,7 @@ steps: inputs: command: publish projects: '$(nsRoot)/src/FoundryLocalCore/Core/Core.csproj' - arguments: '--no-restore -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0' + arguments: '--no-restore --no-build -r ${{ parameters.flavor }} /p:Platform=${{ parameters.platform }} /p:Configuration=Release /p:PublishAot=true /p:TargetFramework=net9.0' publishWebProjects: false zipAfterPublish: false From 47d16d0dea54167902bc3b90b9ac39f4a476b18b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 13:01:29 -0700 Subject: [PATCH 083/112] download_and_register_eps --- .pipelines/foundry-local-packaging.yml | 6 +++++- sdk/cs/src/FoundryLocalManager.cs | 16 ++++++++-------- sdk/js/src/foundryLocalManager.ts | 18 ++++++++++++++++++ sdk/python/src/foundry_local_manager.py | 10 +++++----- sdk/rust/src/foundry_local_manager.rs | 14 ++++++++++++++ 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 4f4a184c..c889538e 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -23,6 +23,10 @@ parameters: displayName: 'Release build' type: boolean default: false +- name: neutronServerBranch + displayName: 'Foundry Local Core branch (windows.ai.toolkit/neutron-server)' + type: string + default: 'dev/FoundryLocalCore/main' variables: - group: FoundryLocal-ESRP-Signing @@ -33,7 +37,7 @@ resources: type: git name: windows.ai.toolkit/neutron-server endpoint: AIFoundryLocal-WindowsAIToolkit-SC - ref: refs/heads/dev/FoundryLocalCore/main + ref: refs/heads/${{ parameters.neutronServerBranch }} - repository: test-data-shared type: git name: windows.ai.toolkit/test-data-shared diff --git a/sdk/cs/src/FoundryLocalManager.cs b/sdk/cs/src/FoundryLocalManager.cs index 639be3a2..99e7e74c 100644 --- a/sdk/cs/src/FoundryLocalManager.cs +++ b/sdk/cs/src/FoundryLocalManager.cs @@ -99,7 +99,7 @@ public static async Task CreateAsync(Configuration configuration, ILogger logger /// /// The catalog is populated on first use. /// If you are using a WinML build this will trigger a one-off execution provider download if not already done. - /// It is recommended to call first to separate out the two steps. + /// It is recommended to call first to separate out the two steps. /// public async Task GetCatalogAsync(CancellationToken? ct = null) { @@ -135,7 +135,7 @@ await Utils.CallWithExceptionHandling(() => StopWebServiceImplAsync(ct), } /// - /// Ensure execution providers are downloaded and registered. + /// Download and register execution providers. /// Only relevant when using WinML. /// /// Execution provider download can be time consuming due to the size of the packages. @@ -143,10 +143,10 @@ await Utils.CallWithExceptionHandling(() => StopWebServiceImplAsync(ct), /// on subsequent calls. /// /// Optional cancellation token. - public async Task EnsureEpsDownloadedAsync(CancellationToken? ct = null) + public async Task DownloadAndRegisterEpsAsync(CancellationToken? ct = null) { - await Utils.CallWithExceptionHandling(() => EnsureEpsDownloadedImplAsync(ct), - "Error ensuring execution providers downloaded.", _logger) + await Utils.CallWithExceptionHandling(() => DownloadAndRegisterEpsImplAsync(ct), + "Error downloading and registering execution providers.", _logger) .ConfigureAwait(false); } @@ -259,16 +259,16 @@ private async Task StopWebServiceImplAsync(CancellationToken? ct = null) Urls = null; } - private async Task EnsureEpsDownloadedImplAsync(CancellationToken? ct = null) + private async Task DownloadAndRegisterEpsImplAsync(CancellationToken? ct = null) { using var disposable = await asyncLock.LockAsync().ConfigureAwait(false); CoreInteropRequest? input = null; - var result = await _coreInterop!.ExecuteCommandAsync("ensure_eps_downloaded", input, ct); + var result = await _coreInterop!.ExecuteCommandAsync("download_and_register_eps", input, ct); if (result.Error != null) { - throw new FoundryLocalException($"Error ensuring execution providers downloaded: {result.Error}", _logger); + throw new FoundryLocalException($"Error downloading and registering execution providers: {result.Error}", _logger); } } diff --git a/sdk/js/src/foundryLocalManager.ts b/sdk/js/src/foundryLocalManager.ts index bc408f78..6da0bcc7 100644 --- a/sdk/js/src/foundryLocalManager.ts +++ b/sdk/js/src/foundryLocalManager.ts @@ -61,6 +61,24 @@ export class FoundryLocalManager { return this._urls; } + /** + * Download and register execution providers. + * Only relevant when using the WinML variant. On non-WinML builds this is a no-op. + * + * Call this after initialization to trigger EP download before accessing the catalog, + * so that hardware-accelerated execution providers (e.g. QNN for NPU) are available + * when listing and loading models. + * + * @throws Error - If execution provider download or registration fails. + */ + public downloadAndRegisterEps(): void { + try { + this.coreInterop.executeCommand("download_and_register_eps"); + } catch (error) { + throw new Error(`Error downloading and registering execution providers: ${error}`); + } + } + /** * Starts the local web service. * Use the `urls` property to retrieve the bound addresses after the service has started. diff --git a/sdk/python/src/foundry_local_manager.py b/sdk/python/src/foundry_local_manager.py index 4486eaf1..4c02a127 100644 --- a/sdk/python/src/foundry_local_manager.py +++ b/sdk/python/src/foundry_local_manager.py @@ -71,17 +71,17 @@ def _initialize(self): self._model_load_manager = ModelLoadManager(self._core_interop, external_service_url) self.catalog = Catalog(self._model_load_manager, self._core_interop) - def ensure_eps_downloaded(self) -> None: - """Ensure execution providers are downloaded and registered (synchronous). + def download_and_register_eps(self) -> None: + """Download and register execution providers. Only relevant when using WinML. Raises: - FoundryLocalException: If execution provider download fails. + FoundryLocalException: If execution provider download or registration fails. """ - result = self._core_interop.execute_command("ensure_eps_downloaded") + result = self._core_interop.execute_command("download_and_register_eps") if result.error is not None: - raise FoundryLocalException(f"Error ensuring execution providers downloaded: {result.error}") + raise FoundryLocalException(f"Error downloading and registering execution providers: {result.error}") def start_web_service(self): """Start the optional web service. diff --git a/sdk/rust/src/foundry_local_manager.rs b/sdk/rust/src/foundry_local_manager.rs index f80a7176..9cf2477f 100644 --- a/sdk/rust/src/foundry_local_manager.rs +++ b/sdk/rust/src/foundry_local_manager.rs @@ -133,4 +133,18 @@ impl FoundryLocalManager { .clear(); Ok(()) } + + /// Download and register execution providers. + /// + /// Only relevant when using the WinML variant. On non-WinML builds this + /// is a no-op. Call this after initialisation to trigger EP download + /// before accessing the catalog, so that hardware-accelerated execution + /// providers (e.g. QNN for NPU) are available when listing and loading + /// models. + pub async fn download_and_register_eps(&self) -> Result<()> { + self.core + .execute_command_async("download_and_register_eps".into(), None) + .await?; + Ok(()) + } } From fbb0b5dba2ee5b726c4d43a589a2a52270455b07 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 15:19:17 -0700 Subject: [PATCH 084/112] try install winappsdk --- .pipelines/templates/test-cs-steps.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.pipelines/templates/test-cs-steps.yml b/.pipelines/templates/test-cs-steps.yml index 3060b137..d0a1fc06 100644 --- a/.pipelines/templates/test-cs-steps.yml +++ b/.pipelines/templates/test-cs-steps.yml @@ -35,6 +35,28 @@ steps: Write-Host "Contents of ${{ parameters.flcNugetDir }}:" Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } +- task: PowerShell@2 + displayName: 'Install Windows App SDK Runtime' + inputs: + targetType: 'inline' + script: | + $installerUrl = "https://aka.ms/windowsappsdk/1.8/latest/windowsappruntimeinstall-x64.exe" + $installerPath = "$env:TEMP\windowsappruntimeinstall.exe" + + Write-Host "Downloading Windows App SDK Runtime installer from $installerUrl..." + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath + + Write-Host "Installing Windows App SDK Runtime..." + & $installerPath --quiet --force + + if ($LASTEXITCODE -ne 0) { + Write-Error "Installation failed with exit code $LASTEXITCODE" + exit 1 + } + + Write-Host "Windows App SDK Runtime installed successfully." + errorActionPreference: 'stop' + - task: PowerShell@2 displayName: 'Create NuGet.config with local FLC feed' inputs: From 63e4192d0a9957d24f00090d2b383a5297b6d9c6 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 15:26:50 -0700 Subject: [PATCH 085/112] iswinml installwinml --- .pipelines/templates/test-cs-steps.yml | 43 +++++++++++++------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/.pipelines/templates/test-cs-steps.yml b/.pipelines/templates/test-cs-steps.yml index d0a1fc06..506ce39a 100644 --- a/.pipelines/templates/test-cs-steps.yml +++ b/.pipelines/templates/test-cs-steps.yml @@ -35,27 +35,28 @@ steps: Write-Host "Contents of ${{ parameters.flcNugetDir }}:" Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse | ForEach-Object { Write-Host $_.FullName } -- task: PowerShell@2 - displayName: 'Install Windows App SDK Runtime' - inputs: - targetType: 'inline' - script: | - $installerUrl = "https://aka.ms/windowsappsdk/1.8/latest/windowsappruntimeinstall-x64.exe" - $installerPath = "$env:TEMP\windowsappruntimeinstall.exe" - - Write-Host "Downloading Windows App SDK Runtime installer from $installerUrl..." - Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath - - Write-Host "Installing Windows App SDK Runtime..." - & $installerPath --quiet --force - - if ($LASTEXITCODE -ne 0) { - Write-Error "Installation failed with exit code $LASTEXITCODE" - exit 1 - } - - Write-Host "Windows App SDK Runtime installed successfully." - errorActionPreference: 'stop' +- ${{ if eq(parameters.isWinML, true) }}: + - task: PowerShell@2 + displayName: 'Install Windows App SDK Runtime' + inputs: + targetType: 'inline' + script: | + $installerUrl = "https://aka.ms/windowsappsdk/1.8/latest/windowsappruntimeinstall-x64.exe" + $installerPath = "$env:TEMP\windowsappruntimeinstall.exe" + + Write-Host "Downloading Windows App SDK Runtime installer from $installerUrl..." + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath + + Write-Host "Installing Windows App SDK Runtime..." + & $installerPath --quiet --force + + if ($LASTEXITCODE -ne 0) { + Write-Error "Installation failed with exit code $LASTEXITCODE" + exit 1 + } + + Write-Host "Windows App SDK Runtime installed successfully." + errorActionPreference: 'stop' - task: PowerShell@2 displayName: 'Create NuGet.config with local FLC feed' From 23c275adcd3e141917dae20f42e83af4977672b4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 15:47:47 -0700 Subject: [PATCH 086/112] copilot feedback Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .pipelines/templates/test-python-steps.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.pipelines/templates/test-python-steps.yml b/.pipelines/templates/test-python-steps.yml index 965c59ed..8ca12aac 100644 --- a/.pipelines/templates/test-python-steps.yml +++ b/.pipelines/templates/test-python-steps.yml @@ -82,15 +82,15 @@ steps: - script: pip install onnxruntime-core onnxruntime-genai-core displayName: 'Install ORT native packages' -- script: python -m build --wheel -C skip-native-deps=true --outdir dist/ - displayName: 'Build wheel' - condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'false')) - workingDirectory: $(repoRoot)/sdk/python +- ${{ if not(parameters.isWinML) }}: + - script: python -m build --wheel -C skip-native-deps=true --outdir dist/ + displayName: 'Build wheel' + workingDirectory: $(repoRoot)/sdk/python -- script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/ - displayName: 'Build wheel (WinML)' - condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'true')) - workingDirectory: $(repoRoot)/sdk/python +- ${{ if parameters.isWinML }}: + - script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/ + displayName: 'Build wheel (WinML)' + workingDirectory: $(repoRoot)/sdk/python - task: PowerShell@2 displayName: 'Install built wheel' From 7d53fd151bfbebc41c28036570f56b8a2c4906e1 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 15:48:12 -0700 Subject: [PATCH 087/112] copilot feedback Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- sdk/cs/src/FoundryLocalManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cs/src/FoundryLocalManager.cs b/sdk/cs/src/FoundryLocalManager.cs index 99e7e74c..d3e4fb79 100644 --- a/sdk/cs/src/FoundryLocalManager.cs +++ b/sdk/cs/src/FoundryLocalManager.cs @@ -265,7 +265,7 @@ private async Task DownloadAndRegisterEpsImplAsync(CancellationToken? ct = null) using var disposable = await asyncLock.LockAsync().ConfigureAwait(false); CoreInteropRequest? input = null; - var result = await _coreInterop!.ExecuteCommandAsync("download_and_register_eps", input, ct); + var result = await _coreInterop!.ExecuteCommandAsync("download_and_register_eps", input, ct).ConfigureAwait(false); if (result.Error != null) { throw new FoundryLocalException($"Error downloading and registering execution providers: {result.Error}", _logger); From e68c9d24d7c29d654fc432c67a5cbb26fd4b0f88 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 15:53:08 -0700 Subject: [PATCH 088/112] copilot feedback --- .pipelines/templates/build-python-steps.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.pipelines/templates/build-python-steps.yml b/.pipelines/templates/build-python-steps.yml index 3a2119a2..6fd0cd34 100644 --- a/.pipelines/templates/build-python-steps.yml +++ b/.pipelines/templates/build-python-steps.yml @@ -114,15 +114,15 @@ steps: # Build wheel — standard or WinML variant # skip-native-deps=true omits foundry-local-core/onnxruntime pinned versions # from the wheel metadata, since the pipeline pre-installs its own builds. -- script: python -m build --wheel -C skip-native-deps=true --outdir dist/ - displayName: 'Build wheel' - condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'false')) - workingDirectory: $(repoRoot)/sdk/python +- ${{ if eq(parameters.isWinML, true) }}: + - script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/ + displayName: 'Build wheel (WinML)' + workingDirectory: $(repoRoot)/sdk/python -- script: python -m build --wheel -C winml=true -C skip-native-deps=true --outdir dist/ - displayName: 'Build wheel (WinML)' - condition: and(succeeded(), eq('${{ parameters.isWinML }}', 'true')) - workingDirectory: $(repoRoot)/sdk/python +- ${{ else }}: + - script: python -m build --wheel -C skip-native-deps=true --outdir dist/ + displayName: 'Build wheel' + workingDirectory: $(repoRoot)/sdk/python # Install the built wheel - task: PowerShell@2 From 6a3d0444a220af2a9ea63de2abba2fce27b29949 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 15:54:40 -0700 Subject: [PATCH 089/112] copilot feedback --- .pipelines/templates/package-core-steps.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 1d8e3789..7337decf 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -42,8 +42,7 @@ steps: $srcDir = "$(Pipeline.Workspace)/$($p.artifactName)" Write-Host "Looking for artifacts at: $srcDir" if (-not (Test-Path $srcDir)) { - Write-Warning "Artifact directory $srcDir does not exist" - continue + throw "Artifact directory $srcDir does not exist. All platform artifacts must be present to produce a complete NuGet package." } $destDir = "$unifiedPath/runtimes/$($p.name)/native" New-Item -ItemType Directory -Path $destDir -Force | Out-Null From 9f4c2122309411080aef9f49e7c992f3c39e845b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 15:55:49 -0700 Subject: [PATCH 090/112] docs --- sdk/js/docs/classes/FoundryLocalManager.md | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sdk/js/docs/classes/FoundryLocalManager.md b/sdk/js/docs/classes/FoundryLocalManager.md index 63bb2dd1..dc4908a6 100644 --- a/sdk/js/docs/classes/FoundryLocalManager.md +++ b/sdk/js/docs/classes/FoundryLocalManager.md @@ -87,6 +87,29 @@ Error - If the web service is not running. *** +### downloadAndRegisterEps() + +```ts +downloadAndRegisterEps(): void; +``` + +Download and register execution providers. +Only relevant when using the WinML variant. On non-WinML builds this is a no-op. + +Call this after initialization to trigger EP download before accessing the catalog, +so that hardware-accelerated execution providers (e.g. QNN for NPU) are available +when listing and loading models. + +#### Returns + +`void` + +#### Throws + +Error - If execution provider download or registration fails. + +*** + ### startWebService() ```ts From 0ee533bcaad1f0410bf7bfed36daa9fdcace6c99 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 16:03:15 -0700 Subject: [PATCH 091/112] net9.0 --- .pipelines/templates/build-cs-steps.yml | 13 ++++++++----- .pipelines/templates/test-cs-steps.yml | 2 +- sdk/cs/src/Microsoft.AI.Foundry.Local.csproj | 4 ++-- .../Microsoft.AI.Foundry.Local.Tests.csproj | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 940f7271..df4d6d05 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -33,10 +33,10 @@ steps: Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" - task: UseDotNet@2 - displayName: 'Use .NET 10 SDK' + displayName: 'Use .NET 9 SDK' inputs: packageType: sdk - version: '10.0.x' + version: '9.0.x' # Compute package version - task: PowerShell@2 @@ -128,9 +128,12 @@ steps: targetType: inline script: | $base = "$(repoRoot)/sdk/cs/src/bin/Release" - $tfm = (Get-ChildItem $base -Directory -Filter "net10.0*" | Select-Object -First 1).Name - Write-Host "##vso[task.setvariable variable=TargetFramework]$tfm" - Write-Host "Target framework: $tfm" + # The SDK targets net8.0 (standard) or net8.0-windows10.0.26100.0 (WinML). + # Find whichever TFM directory was produced by the build. + $tfmDir = Get-ChildItem $base -Directory | Select-Object -First 1 + if (-not $tfmDir) { throw "No target framework directory found under $base" } + Write-Host "##vso[task.setvariable variable=TargetFramework]$($tfmDir.Name)" + Write-Host "Target framework: $($tfmDir.Name)" # Sign DLLs - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 diff --git a/.pipelines/templates/test-cs-steps.yml b/.pipelines/templates/test-cs-steps.yml index 506ce39a..77be3373 100644 --- a/.pipelines/templates/test-cs-steps.yml +++ b/.pipelines/templates/test-cs-steps.yml @@ -22,7 +22,7 @@ steps: Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" - task: UseDotNet@2 - displayName: 'Use .NET 10 SDK' + displayName: 'Use .NET 9 SDK' inputs: packageType: sdk version: '10.0.x' diff --git a/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj b/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj index 905f9652..84300a97 100644 --- a/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj +++ b/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj @@ -13,7 +13,7 @@ https://github.com/microsoft/Foundry-Local git - net8.0 + net9.0 win-x64;win-arm64;linux-x64;linux-arm64;osx-arm64 true @@ -87,7 +87,7 @@ Microsoft Foundry Local SDK for WinML Microsoft.AI.Foundry.Local.WinML Microsoft.AI.Foundry.Local.WinML - net8.0-windows10.0.26100.0 + net9.0-windows10.0.26100.0 win-x64;win-arm64 10.0.17763.0 diff --git a/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj b/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj index 5f0c7cf2..b0bd3cd0 100644 --- a/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj +++ b/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj @@ -1,7 +1,7 @@  - net10.0 + net9.0 enable enable false @@ -19,7 +19,7 @@ - net10.0-windows10.0.26100.0 + net9.0-windows10.0.26100.0 10.0.17763.0 None true From 75764bf43935e8e141a6880b158204c1061d458b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 16:05:44 -0700 Subject: [PATCH 092/112] update c# docs --- sdk/cs/README.md | 4 ++-- .../api/microsoft.ai.foundry.local.foundrylocalmanager.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sdk/cs/README.md b/sdk/cs/README.md index f58e41e0..2b574325 100644 --- a/sdk/cs/README.md +++ b/sdk/cs/README.md @@ -48,7 +48,7 @@ dotnet build src/Microsoft.AI.Foundry.Local.csproj /p:UseWinML=true ### Triggering EP download -EP download can be time-consuming. Call `EnsureEpsDownloadedAsync` early (after initialization) to separate the download step from catalog access: +EP download can be time-consuming. Call `DownloadAndRegisterEpsAsync` early (after initialization) to separate the download step from catalog access: ```csharp // Initialize the manager first (see Quick Start) @@ -56,7 +56,7 @@ await FoundryLocalManager.CreateAsync( new Configuration { AppName = "my-app" }, NullLogger.Instance); -await FoundryLocalManager.Instance.EnsureEpsDownloadedAsync(); +await FoundryLocalManager.Instance.DownloadAndRegisterEpsAsync(); // Now catalog access won't trigger an EP download var catalog = await FoundryLocalManager.Instance.GetCatalogAsync(); diff --git a/sdk/cs/docs/api/microsoft.ai.foundry.local.foundrylocalmanager.md b/sdk/cs/docs/api/microsoft.ai.foundry.local.foundrylocalmanager.md index 93f162b7..9e5be8aa 100644 --- a/sdk/cs/docs/api/microsoft.ai.foundry.local.foundrylocalmanager.md +++ b/sdk/cs/docs/api/microsoft.ai.foundry.local.foundrylocalmanager.md @@ -98,7 +98,7 @@ The model catalog. The catalog is populated on first use. If you are using a WinML build this will trigger a one-off execution provider download if not already done. - It is recommended to call [FoundryLocalManager.EnsureEpsDownloadedAsync(Nullable<CancellationToken>)](./microsoft.ai.foundry.local.foundrylocalmanager.md#ensureepsdownloadedasyncnullablecancellationtoken) first to separate out the two steps. + It is recommended to call [FoundryLocalManager.DownloadAndRegisterEpsAsync(Nullable<CancellationToken>)](./microsoft.ai.foundry.local.foundrylocalmanager.md#downloadandregisterepsasyncnullablecancellationtoken) first to separate out the two steps. ### **StartWebServiceAsync(Nullable<CancellationToken>)** @@ -141,9 +141,9 @@ Optional cancellation token. [Task](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task)
Task stopping the web service. -### **EnsureEpsDownloadedAsync(Nullable<CancellationToken>)** +### **DownloadAndRegisterEpsAsync(Nullable<CancellationToken>)** -Ensure execution providers are downloaded and registered. +Download and register execution providers. Only relevant when using WinML. Execution provider download can be time consuming due to the size of the packages. @@ -151,7 +151,7 @@ Ensure execution providers are downloaded and registered. on subsequent calls. ```csharp -public Task EnsureEpsDownloadedAsync(Nullable ct) +public Task DownloadAndRegisterEpsAsync(Nullable ct) ``` #### Parameters From ac8081e55b5a8ac3a5e4e7ab1b0aee08a597b9fd Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 16:07:30 -0700 Subject: [PATCH 093/112] copilot feedback Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .pipelines/templates/build-cs-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index df4d6d05..026d84bc 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -162,7 +162,7 @@ steps: targetType: inline script: | dotnet pack "$(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj" ` - --no-build --configuration Release ` + --no-build --no-restore --configuration Release ` --output "${{ parameters.outputDir }}" ` /p:PackageVersion=$(packageVersion) ` /p:UseWinML=${{ parameters.isWinML }} ` From d13c1022e430b206aa3cb64ce849b9bd4b05d315 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 16:08:19 -0700 Subject: [PATCH 094/112] stabilized --- .pipelines/foundry-local-packaging.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index c889538e..6fe1f0bf 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -369,7 +369,7 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' # TODO: Add macOS (osx-arm64) test job when a macOS ARM64 pool is available. - # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. + # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabilized. # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. # ── Test JS SDK (win-x64) ── @@ -399,7 +399,7 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' # TODO: Add macOS (osx-arm64) test job when a macOS ARM64 pool is available. - # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. + # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabilized. # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. # ── Test Python SDK (win-x64) ── @@ -429,7 +429,7 @@ extends: flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels' # TODO: Add macOS (osx-arm64) test job when a macOS ARM64 pool is available. - # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. + # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabilized. # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. # ── Test Rust SDK (win-x64) ── @@ -458,7 +458,7 @@ extends: flcNugetDir: '$(Pipeline.Workspace)/flc-nuget' # TODO: Add macOS (osx-arm64) test job when a macOS ARM64 pool is available. - # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabalized. + # TODO: Add Linux (linux-x64) test job when Linux onnxruntime dependency is stabilized. # TODO: Add Windows ARM64 (win-arm64) test job when a Windows ARM64 pool is available. # ── Build & Test FLC (WinML) ── From c12fa5d28b9ff45633190dd0718e2c717f7cd867 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 16:22:35 -0700 Subject: [PATCH 095/112] install winappsdk --- .pipelines/templates/test-js-steps.yml | 23 ++++++++++++++++++++++ .pipelines/templates/test-python-steps.yml | 23 ++++++++++++++++++++++ .pipelines/templates/test-rust-steps.yml | 23 ++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/.pipelines/templates/test-js-steps.yml b/.pipelines/templates/test-js-steps.yml index d0fbde5a..41ef7f62 100644 --- a/.pipelines/templates/test-js-steps.yml +++ b/.pipelines/templates/test-js-steps.yml @@ -21,6 +21,29 @@ steps: Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" +- ${{ if eq(parameters.isWinML, true) }}: + - task: PowerShell@2 + displayName: 'Install Windows App SDK Runtime' + inputs: + targetType: 'inline' + script: | + $installerUrl = "https://aka.ms/windowsappsdk/1.8/latest/windowsappruntimeinstall-x64.exe" + $installerPath = "$env:TEMP\windowsappruntimeinstall.exe" + + Write-Host "Downloading Windows App SDK Runtime installer from $installerUrl..." + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath + + Write-Host "Installing Windows App SDK Runtime..." + & $installerPath --quiet --force + + if ($LASTEXITCODE -ne 0) { + Write-Error "Installation failed with exit code $LASTEXITCODE" + exit 1 + } + + Write-Host "Windows App SDK Runtime installed successfully." + errorActionPreference: 'stop' + - task: PowerShell@2 displayName: 'List downloaded FLC artifact' inputs: diff --git a/.pipelines/templates/test-python-steps.yml b/.pipelines/templates/test-python-steps.yml index 8ca12aac..f54a9464 100644 --- a/.pipelines/templates/test-python-steps.yml +++ b/.pipelines/templates/test-python-steps.yml @@ -22,6 +22,29 @@ steps: Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" +- ${{ if eq(parameters.isWinML, true) }}: + - task: PowerShell@2 + displayName: 'Install Windows App SDK Runtime' + inputs: + targetType: 'inline' + script: | + $installerUrl = "https://aka.ms/windowsappsdk/1.8/latest/windowsappruntimeinstall-x64.exe" + $installerPath = "$env:TEMP\windowsappruntimeinstall.exe" + + Write-Host "Downloading Windows App SDK Runtime installer from $installerUrl..." + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath + + Write-Host "Installing Windows App SDK Runtime..." + & $installerPath --quiet --force + + if ($LASTEXITCODE -ne 0) { + Write-Error "Installation failed with exit code $LASTEXITCODE" + exit 1 + } + + Write-Host "Windows App SDK Runtime installed successfully." + errorActionPreference: 'stop' + - task: UsePythonVersion@0 displayName: 'Use Python 3.12' inputs: diff --git a/.pipelines/templates/test-rust-steps.yml b/.pipelines/templates/test-rust-steps.yml index 51da7c2a..31bfd75e 100644 --- a/.pipelines/templates/test-rust-steps.yml +++ b/.pipelines/templates/test-rust-steps.yml @@ -19,6 +19,29 @@ steps: Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot" Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir" +- ${{ if eq(parameters.isWinML, true) }}: + - task: PowerShell@2 + displayName: 'Install Windows App SDK Runtime' + inputs: + targetType: 'inline' + script: | + $installerUrl = "https://aka.ms/windowsappsdk/1.8/latest/windowsappruntimeinstall-x64.exe" + $installerPath = "$env:TEMP\windowsappruntimeinstall.exe" + + Write-Host "Downloading Windows App SDK Runtime installer from $installerUrl..." + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath + + Write-Host "Installing Windows App SDK Runtime..." + & $installerPath --quiet --force + + if ($LASTEXITCODE -ne 0) { + Write-Error "Installation failed with exit code $LASTEXITCODE" + exit 1 + } + + Write-Host "Windows App SDK Runtime installed successfully." + errorActionPreference: 'stop' + - task: PowerShell@2 displayName: 'List downloaded FLC artifact' inputs: From 6f836488c60ca78b281808c710a5cb50f3ec34bd Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 16:27:41 -0700 Subject: [PATCH 096/112] try onnxruntime-genai-win11-arm64-cpu2 for c# winml tests --- .pipelines/foundry-local-packaging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 6fe1f0bf..39d826e1 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -699,7 +699,7 @@ extends: - job: test_cs_winml_win_x64 displayName: 'Test C# WinML (win-x64)' pool: - name: onnxruntime-Win-CPU-2022 + name: onnxruntime-genai-win11-arm64-cpu2 os: windows templateContext: inputs: From b2b8ac4c29c8e660549f66e69cf3943fca949e7c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sat, 28 Mar 2026 16:38:12 -0700 Subject: [PATCH 097/112] revert --- .pipelines/foundry-local-packaging.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 39d826e1..2ee77cd1 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -55,7 +55,7 @@ extends: settings: networkIsolationPolicy: Permissive pool: - # default for SDL scan, individual jobs override + # default all windows jobs, individual jobs override name: onnxruntime-Win-CPU-2022 os: windows sdl: @@ -699,7 +699,7 @@ extends: - job: test_cs_winml_win_x64 displayName: 'Test C# WinML (win-x64)' pool: - name: onnxruntime-genai-win11-arm64-cpu2 + name: onnxruntime-Win-CPU-2022 os: windows templateContext: inputs: From ba979ca59a88d97ba51deaca82919660e2bd9576 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 10:56:50 -0700 Subject: [PATCH 098/112] copilot feedback Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .pipelines/templates/build-cs-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 026d84bc..31ff4423 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -128,7 +128,7 @@ steps: targetType: inline script: | $base = "$(repoRoot)/sdk/cs/src/bin/Release" - # The SDK targets net8.0 (standard) or net8.0-windows10.0.26100.0 (WinML). + # The SDK targets net9.0 (standard) or net9.0-windows10.0.26100.0 (WinML). # Find whichever TFM directory was produced by the build. $tfmDir = Get-ChildItem $base -Directory | Select-Object -First 1 if (-not $tfmDir) { throw "No target framework directory found under $base" } From 480b6c738a76fae98cd2849a6757898e6072e5d8 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 10:57:28 -0700 Subject: [PATCH 099/112] copilot feedback Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .pipelines/templates/package-core-steps.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/package-core-steps.yml b/.pipelines/templates/package-core-steps.yml index 7337decf..e5755a21 100644 --- a/.pipelines/templates/package-core-steps.yml +++ b/.pipelines/templates/package-core-steps.yml @@ -1,6 +1,7 @@ # Steps to collect per-platform FLC native binaries, organize into NuGet layout, -# pack + sign the NuGet package, and (for non-WinML) build Python wheels. -# The parent job must download all platform artifacts and checkout neutron-server. +# pack + sign the NuGet package, and build Python wheels (wheel package name and +# platforms depend on the isWinML parameter). The parent job must download all +# platform artifacts and checkout neutron-server. parameters: - name: version type: string From 52c74d79a81c9c0b5dc7541ee221797e5bf89392 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 10:57:48 -0700 Subject: [PATCH 100/112] copilot feedback --- .pipelines/templates/test-cs-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/test-cs-steps.yml b/.pipelines/templates/test-cs-steps.yml index 77be3373..f7dc1aff 100644 --- a/.pipelines/templates/test-cs-steps.yml +++ b/.pipelines/templates/test-cs-steps.yml @@ -25,7 +25,7 @@ steps: displayName: 'Use .NET 9 SDK' inputs: packageType: sdk - version: '10.0.x' + version: '9.0.x' - task: PowerShell@2 displayName: 'List downloaded FLC artifact' From 5c8e297b5028b629c08430268fe881e23690707e Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 11:18:34 -0700 Subject: [PATCH 101/112] corruption issue --- .pipelines/templates/build-cs-steps.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 31ff4423..29b718a7 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -103,6 +103,10 @@ steps: inputs: targetType: inline script: | + # Clear local NuGet cache to avoid 'Central Directory corrupt' errors on CI agents. + dotnet nuget locals all --clear + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $proj = "$(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj" if (-not (Test-Path $proj)) { throw "Project not found: $proj" } dotnet restore $proj ` From a660e660753594993fa14951460d8f173b9324a5 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 11:38:27 -0700 Subject: [PATCH 102/112] c# pipeline fix --- .github/workflows/build-cs-steps.yml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-cs-steps.yml b/.github/workflows/build-cs-steps.yml index dcfed979..cbb1ec88 100644 --- a/.github/workflows/build-cs-steps.yml +++ b/.github/workflows/build-cs-steps.yml @@ -41,19 +41,31 @@ jobs: env: NUGET_AUTH_TOKEN: ${{ secrets.AZURE_DEVOPS_PAT }} + - name: Generate temporary NuGet.config + run: | + # The repo-level NuGet.config is restricted to one source for compliance. + # We generate a temporary one with both nuget.org and ORT-Nightly for CI. + cat < sdk/cs/NuGet.temp.config + + + + + + + + + EOF + # TODO: once the nightly packaging is fixed, add back the commented out lines with /p:FoundryLocalCoreVersion="*-*" # /p:FoundryLocalCoreVersion="*-*" to always use nightly version of Foundry Local Core - - name: Authenticate to Azure Artifacts NuGet feed - run: dotnet nuget update source ORT-Nightly --username az --password ${{ secrets.AZURE_DEVOPS_PAT }} --store-password-in-clear-text --configfile sdk/cs/NuGet.config - - name: Restore dependencies run: | - # dotnet restore sdk/cs/src/Microsoft.AI.Foundry.Local.csproj /p:UseWinML=${{ inputs.useWinML }} /p:FoundryLocalCoreVersion="*-*" --configfile sdk/cs/NuGet.config - dotnet restore sdk/cs/src/Microsoft.AI.Foundry.Local.csproj /p:UseWinML=${{ inputs.useWinML }} --configfile sdk/cs/NuGet.config + # Clear the local NuGet cache to avoid bad metadata or corrupted package states. + dotnet nuget locals all --clear + dotnet restore sdk/cs/src/Microsoft.AI.Foundry.Local.csproj /p:UseWinML=${{ inputs.useWinML }} --configfile sdk/cs/NuGet.temp.config - name: Build solution run: | - # dotnet build sdk/cs/src/Microsoft.AI.Foundry.Local.csproj --no-restore --configuration ${{ inputs.buildConfiguration }} /p:UseWinML=${{ inputs.useWinML }} /p:FoundryLocalCoreVersion="*-*" dotnet build sdk/cs/src/Microsoft.AI.Foundry.Local.csproj --no-restore --configuration ${{ inputs.buildConfiguration }} /p:UseWinML=${{ inputs.useWinML }} # need to use direct git commands to clone from Azure DevOps instead of actions/checkout @@ -89,7 +101,8 @@ jobs: - name: Run Foundry Local Core tests run: | # dotnet test sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj --verbosity normal /p:UseWinML=${{ inputs.useWinML }} /p:FoundryLocalCoreVersion="*-*" - dotnet test sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj --verbosity normal /p:UseWinML=${{ inputs.useWinML }} + # Use the temporary config file for test restore as well. + dotnet test sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj --verbosity normal /p:UseWinML=${{ inputs.useWinML }} --configfile sdk/cs/NuGet.temp.config - name: Pack NuGet package shell: pwsh From c5316523c9aa5d2955ae99e18a2fbb8b21e0039a Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 11:44:58 -0700 Subject: [PATCH 103/112] auth --- .github/workflows/build-cs-steps.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-cs-steps.yml b/.github/workflows/build-cs-steps.yml index cbb1ec88..4486efbd 100644 --- a/.github/workflows/build-cs-steps.yml +++ b/.github/workflows/build-cs-steps.yml @@ -43,8 +43,9 @@ jobs: - name: Generate temporary NuGet.config run: | - # The repo-level NuGet.config is restricted to one source for compliance. - # We generate a temporary one with both nuget.org and ORT-Nightly for CI. + # The repo-level NuGet.config cleared all sources and only included ORT-Nightly. + # We generate a temporary one with both nuget.org and ORT-Nightly. + # We provide credentials to allow the ORT-Nightly feed to pull from its upstreams. cat < sdk/cs/NuGet.temp.config @@ -53,6 +54,12 @@ jobs: + + + + + + EOF @@ -62,6 +69,7 @@ jobs: run: | # Clear the local NuGet cache to avoid bad metadata or corrupted package states. dotnet nuget locals all --clear + # Restore using the temporary config file with credentials. dotnet restore sdk/cs/src/Microsoft.AI.Foundry.Local.csproj /p:UseWinML=${{ inputs.useWinML }} --configfile sdk/cs/NuGet.temp.config - name: Build solution From d8e7726063c223cf6fb328dc3973e772969d7f34 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 11:48:35 -0700 Subject: [PATCH 104/112] xml --- .github/workflows/build-cs-steps.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-cs-steps.yml b/.github/workflows/build-cs-steps.yml index 4486efbd..922866f9 100644 --- a/.github/workflows/build-cs-steps.yml +++ b/.github/workflows/build-cs-steps.yml @@ -46,7 +46,7 @@ jobs: # The repo-level NuGet.config cleared all sources and only included ORT-Nightly. # We generate a temporary one with both nuget.org and ORT-Nightly. # We provide credentials to allow the ORT-Nightly feed to pull from its upstreams. - cat < sdk/cs/NuGet.temp.config + $xml = @" @@ -61,7 +61,9 @@ jobs: - EOF + "@ + Set-Content -Path sdk/cs/NuGet.temp.config -Value $xml + shell: pwsh # TODO: once the nightly packaging is fixed, add back the commented out lines with /p:FoundryLocalCoreVersion="*-*" # /p:FoundryLocalCoreVersion="*-*" to always use nightly version of Foundry Local Core From edf6980b7f2a8f58fc9e44cd7832083ab5d93de0 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 11:51:30 -0700 Subject: [PATCH 105/112] configfile --- .github/workflows/build-cs-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-cs-steps.yml b/.github/workflows/build-cs-steps.yml index 922866f9..cf680d49 100644 --- a/.github/workflows/build-cs-steps.yml +++ b/.github/workflows/build-cs-steps.yml @@ -112,7 +112,7 @@ jobs: run: | # dotnet test sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj --verbosity normal /p:UseWinML=${{ inputs.useWinML }} /p:FoundryLocalCoreVersion="*-*" # Use the temporary config file for test restore as well. - dotnet test sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj --verbosity normal /p:UseWinML=${{ inputs.useWinML }} --configfile sdk/cs/NuGet.temp.config + dotnet test sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj --verbosity normal /p:UseWinML=${{ inputs.useWinML }} - name: Pack NuGet package shell: pwsh From 7d26a421d73e12e6f273703f0e059590f1a347a4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 12:25:06 -0700 Subject: [PATCH 106/112] clear --- .pipelines/templates/build-cs-steps.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 29b718a7..2c5ff9b2 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -104,8 +104,11 @@ steps: targetType: inline script: | # Clear local NuGet cache to avoid 'Central Directory corrupt' errors on CI agents. - dotnet nuget locals all --clear - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $packagesRoot = "$HOME\.nuget\packages" + if (Test-Path $packagesRoot) { + Write-Host "Force-cleaning NuGet packages directory: $packagesRoot" + Get-ChildItem -Path $packagesRoot | Remove-Item -Recurse -Force + } $proj = "$(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj" if (-not (Test-Path $proj)) { throw "Project not found: $proj" } From e6afb0ad6b842e8ec208cb271e92b56ab52352ac Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 13:35:58 -0700 Subject: [PATCH 107/112] nuget.org --- .pipelines/templates/build-cs-steps.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index 2c5ff9b2..cec97923 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -75,6 +75,7 @@ steps: + @@ -103,13 +104,6 @@ steps: inputs: targetType: inline script: | - # Clear local NuGet cache to avoid 'Central Directory corrupt' errors on CI agents. - $packagesRoot = "$HOME\.nuget\packages" - if (Test-Path $packagesRoot) { - Write-Host "Force-cleaning NuGet packages directory: $packagesRoot" - Get-ChildItem -Path $packagesRoot | Remove-Item -Recurse -Force - } - $proj = "$(repoRoot)/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj" if (-not (Test-Path $proj)) { throw "Project not found: $proj" } dotnet restore $proj ` From 85dbc6b7600522163442f05a970310e46ae73df4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Sun, 29 Mar 2026 15:37:54 -0700 Subject: [PATCH 108/112] no flc --- .pipelines/templates/build-cs-steps.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.pipelines/templates/build-cs-steps.yml b/.pipelines/templates/build-cs-steps.yml index cec97923..978c2fff 100644 --- a/.pipelines/templates/build-cs-steps.yml +++ b/.pipelines/templates/build-cs-steps.yml @@ -108,8 +108,7 @@ steps: if (-not (Test-Path $proj)) { throw "Project not found: $proj" } dotnet restore $proj ` --configfile "$(customNugetConfig)" ` - /p:UseWinML=${{ parameters.isWinML }} ` - /p:FoundryLocalCoreVersion=$(resolvedFlcVersion) + /p:UseWinML=${{ parameters.isWinML }} if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - task: PowerShell@2 From 5a4e3baceb17f040ae6feec5d3887b2169eaf6eb Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Mon, 30 Mar 2026 11:20:39 -0700 Subject: [PATCH 109/112] add triggers --- .pipelines/foundry-local-packaging.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index 2ee77cd1..d88776ca 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -7,7 +7,10 @@ # cs-sdk, cs-sdk-winml, js-sdk, js-sdk-winml, python-sdk, python-sdk-winml, # rust-sdk, rust-sdk-winml -trigger: none +trigger: +- main +- releases/* + name: $(Date:yyyyMMdd).$(Rev:r) parameters: From f6efa8d3ff3b0c7767b60c3e0e922370d89097b5 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Mon, 30 Mar 2026 11:29:05 -0700 Subject: [PATCH 110/112] pr --- .pipelines/foundry-local-packaging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/foundry-local-packaging.yml b/.pipelines/foundry-local-packaging.yml index d88776ca..2cb9ee2a 100644 --- a/.pipelines/foundry-local-packaging.yml +++ b/.pipelines/foundry-local-packaging.yml @@ -7,7 +7,7 @@ # cs-sdk, cs-sdk-winml, js-sdk, js-sdk-winml, python-sdk, python-sdk-winml, # rust-sdk, rust-sdk-winml -trigger: +pr: - main - releases/* From f30693a4b6cc8d209d333667ea452b70ec9d5b34 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Mon, 30 Mar 2026 15:32:09 -0700 Subject: [PATCH 111/112] rmv self-contained --- .../FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj b/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj index b0bd3cd0..fe0dfcd2 100644 --- a/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj +++ b/sdk/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj @@ -22,7 +22,6 @@ net9.0-windows10.0.26100.0 10.0.17763.0 None - true
From d71f23ef22b1ca9b76763681b6ecc5859a8098d8 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Mon, 30 Mar 2026 16:32:40 -0700 Subject: [PATCH 112/112] bootstrap --- .github/workflows/foundry-local-sdk-build.yml | 56 +------------------ sdk/cs/src/Detail/CoreInterop.cs | 9 +++ sdk/cs/src/Microsoft.AI.Foundry.Local.csproj | 1 + 3 files changed, 12 insertions(+), 54 deletions(-) diff --git a/.github/workflows/foundry-local-sdk-build.yml b/.github/workflows/foundry-local-sdk-build.yml index 13eddf6d..07ae4d68 100644 --- a/.github/workflows/foundry-local-sdk-build.yml +++ b/.github/workflows/foundry-local-sdk-build.yml @@ -17,60 +17,8 @@ permissions: contents: read jobs: - build-cs-windows: - uses: ./.github/workflows/build-cs-steps.yml - with: - version: '0.9.0.${{ github.run_number }}' - platform: 'windows' - secrets: inherit - build-js-windows: - uses: ./.github/workflows/build-js-steps.yml - with: - version: '0.9.0.${{ github.run_number }}' - platform: 'windows' - secrets: inherit - build-python-windows: - uses: ./.github/workflows/build-python-steps.yml - with: - version: '0.9.0.${{ github.run_number }}' - platform: 'windows' - secrets: inherit - build-rust-windows: - uses: ./.github/workflows/build-rust-steps.yml - with: - platform: 'windows' - run-integration-tests: true - secrets: inherit - - build-cs-windows-WinML: - uses: ./.github/workflows/build-cs-steps.yml - with: - version: '0.9.0.${{ github.run_number }}' - platform: 'windows' - useWinML: true - secrets: inherit - build-js-windows-WinML: - uses: ./.github/workflows/build-js-steps.yml - with: - version: '0.9.0.${{ github.run_number }}' - platform: 'windows' - useWinML: true - secrets: inherit - build-python-windows-WinML: - uses: ./.github/workflows/build-python-steps.yml - with: - version: '0.9.0.${{ github.run_number }}' - platform: 'windows' - useWinML: true - secrets: inherit - build-rust-windows-WinML: - uses: ./.github/workflows/build-rust-steps.yml - with: - platform: 'windows' - useWinML: true - run-integration-tests: true - secrets: inherit - + # Windows build/test moved to .pipelines/foundry-local-packaging.yml and runs in ADO + # MacOS ARM64 not supported in ADO, need to use GitHub Actions build-cs-macos: uses: ./.github/workflows/build-cs-steps.yml with: diff --git a/sdk/cs/src/Detail/CoreInterop.cs b/sdk/cs/src/Detail/CoreInterop.cs index 8411473b..d7867cad 100644 --- a/sdk/cs/src/Detail/CoreInterop.cs +++ b/sdk/cs/src/Detail/CoreInterop.cs @@ -124,6 +124,15 @@ internal CoreInterop(Configuration config, ILogger logger) _logger = logger ?? throw new ArgumentNullException(nameof(logger)); var request = new CoreInteropRequest { Params = config.AsDictionary() }; + +#if IS_WINML + // WinML builds require bootstrapping the Windows App Runtime + if (!request.Params.ContainsKey("Bootstrap")) + { + request.Params["Bootstrap"] = "true"; + } +#endif + var response = ExecuteCommand("initialize", request); if (response.Error != null) diff --git a/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj b/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj index 84300a97..936f3a93 100644 --- a/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj +++ b/sdk/cs/src/Microsoft.AI.Foundry.Local.csproj @@ -87,6 +87,7 @@ Microsoft Foundry Local SDK for WinML Microsoft.AI.Foundry.Local.WinML Microsoft.AI.Foundry.Local.WinML + $(DefineConstants);IS_WINML net9.0-windows10.0.26100.0 win-x64;win-arm64