Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions .github/workflows/build-cs-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,21 @@ jobs:
with:
clean: true

# adapted from https://github.com/actions/setup-dotnet?tab=readme-ov-file#azure-artifacts
# saves auth credentials to ../nuget.config
- name: Setup .NET 9 SDK
uses: actions/setup-dotnet@v5
with:
dotnet-version: '9.0.x'
source-url: https://pkgs.dev.azure.com/microsoft/windows.ai.toolkit/_packaging/Neutron/nuget/v3/index.json
env:
NUGET_AUTH_TOKEN: ${{ secrets.AZURE_DEVOPS_PAT }}

# /p:FoundryLocalCoreVersion="*-*" to always use nightly version of Foundry Local Core
- name: Restore dependencies
run: |
dotnet restore sdk_v2\cs\src\Microsoft.AI.Foundry.Local.csproj /p:UseWinML=${{ inputs.useWinML }} --configfile ../nuget.config
dotnet restore sdk_v2\cs\src\Microsoft.AI.Foundry.Local.csproj /p:UseWinML=${{ inputs.useWinML }} /p:FoundryLocalCoreVersion="*-*" --configfile sdk_v2\cs\NuGet.config

- name: Build solution
run: |
dotnet build sdk_v2\cs\src\Microsoft.AI.Foundry.Local.csproj --configfile ../nuget.config --no-restore --configuration ${{ inputs.buildConfiguration }} /p:UseWinML=${{ inputs.useWinML }}
dotnet build sdk_v2\cs\src\Microsoft.AI.Foundry.Local.csproj --no-restore --configuration ${{ inputs.buildConfiguration }} /p:UseWinML=${{ inputs.useWinML }} /p:FoundryLocalCoreVersion="*-*"

# need to use direct git commands to clone from Azure DevOps instead of actions/checkout
- name: Checkout test-data-shared from Azure DevOps
Expand Down Expand Up @@ -80,7 +78,7 @@ jobs:

- name: Run Foundry Local Core tests
run: |
dotnet test sdk_v2\cs\test\FoundryLocal.Tests\Microsoft.AI.Foundry.Local.Tests.csproj --verbosity normal /p:UseWinML=${{ inputs.useWinML }}
dotnet test sdk_v2\cs\test\FoundryLocal.Tests\Microsoft.AI.Foundry.Local.Tests.csproj --verbosity normal /p:UseWinML=${{ inputs.useWinML }} /p:FoundryLocalCoreVersion="*-*"

- name: Pack NuGet package
shell: pwsh
Expand All @@ -90,14 +88,21 @@ jobs:
$version = "${{ inputs.version }}"
$config = "${{ inputs.buildConfiguration }}"
$useWinML = "${{ inputs.useWinML }}"
# $coreVersion = "${{ env.FOUNDRY_CORE_VERSION }}"

# Always mark as prerelease since we use nightly core
if (-not $version.Contains("dev")) {
$version = "$version-dev"
}

Write-Host "Packing project: $projectPath"
Write-Host "Output directory: $outputDir"
Write-Host "Version: $version"
Write-Host "Configuration: $config"
Write-Host "UseWinML: $useWinML"
# Write-Host "FoundryLocalCoreVersion: $coreVersion"

& dotnet pack $projectPath --no-build --configuration $config --output $outputDir /p:PackageVersion=$version /p:UseWinML=$useWinML /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg --verbosity normal
& dotnet pack $projectPath --no-build --configuration $config --output $outputDir /p:PackageVersion=$version /p:UseWinML=$useWinML /p:FoundryLocalCoreVersion="*-*" /p:IncludeSymbols=true /p:SymbolPackageFormat=snupkg --verbosity normal

if ($LASTEXITCODE -ne 0) {
Write-Error "dotnet pack failed with exit code $LASTEXITCODE"
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/build-js-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ jobs:
uses: actions/setup-dotnet@v5
with:
dotnet-version: '9.0.x'
source-url: https://pkgs.dev.azure.com/microsoft/windows.ai.toolkit/_packaging/Neutron/nuget/v3/index.json
env:
NUGET_AUTH_TOKEN: ${{ secrets.AZURE_DEVOPS_PAT }}

Expand Down Expand Up @@ -89,7 +88,7 @@ jobs:
- name: npm install (Standard)
if: ${{ inputs.useWinML == false }}
working-directory: sdk_v2\js
run: npm install
run: npm install --nightly

# Verify that installing new packages doesn't strip custom native binary folders
- name: npm install openai (verify persistence)
Expand Down
9 changes: 9 additions & 0 deletions sdk_v2/cs/NuGet.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="ORT" value="https://pkgs.dev.azure.com/aiinfra/PublicPackages/_packaging/ORT/nuget/v3/index.json" />
<add key="ORT-Nightly" value="https://pkgs.dev.azure.com/aiinfra/PublicPackages/_packaging/ORT-Nightly/nuget/v3/index.json" />
</packageSources>
</configuration>
18 changes: 16 additions & 2 deletions sdk_v2/cs/src/Microsoft.AI.Foundry.Local.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
</PropertyGroup>

<Target Name="DumpValues" BeforeTargets="Build">
<Message Importance="Normal" Text="FoundryLocalCoreVersion: $(FoundryLocalCoreVersion)" />
<Message Importance="Normal" Text="RuntimeIdentifiers: $(RuntimeIdentifiers)" />
<Message Importance="Normal" Text="RuntimeIdentifier: $(RuntimeIdentifier)" />
<Message Importance="Normal" Text="DefineConstants: $(DefineConstants)" />
Expand All @@ -67,6 +68,13 @@
<Message Importance="Normal" Text="IsLinux: $(IsLinux)" />
<Message Importance="Normal" Text="UseWinML: $(UseWinML)" />
</Target>

<!-- This target runs automatically after package assets are resolved and prints the exact version of the Core package that was selected. -->
<Target Name="PrintResolvedVersions" AfterTargets="ResolvePackageAssets">
<Message Importance="High" Text="Resolved Dependencies:" />
<Message Importance="High" Text=" %(PackageDependencies.Identity) : %(PackageDependencies.Version)"
Condition="$([System.String]::Copy('%(PackageDependencies.Identity)').StartsWith('Microsoft.AI.Foundry.Local.Core'))" />
</Target>

<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)../README.md" Pack="true" PackagePath="" />
Expand All @@ -87,6 +95,12 @@
<!-- we don't pass any types across the WinRT ABI -->
<NoWarn>$(NoWarn);CsWinRT1028</NoWarn>
</PropertyGroup>

<PropertyGroup>
<!-- default version unless overridden during dotnet build/restore command -->
<FoundryLocalCoreVersion Condition="'$(FoundryLocalCoreVersion)' == ''">0.8.1.0</FoundryLocalCoreVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
</PropertyGroup>
Expand All @@ -96,9 +110,9 @@

<ItemGroup>
<PackageReference Condition="'$(UseWinML)' == 'true'"
Include="Microsoft.AI.Foundry.Local.Core.WinML" Version="0.8.1.0" />
Include="Microsoft.AI.Foundry.Local.Core.WinML" Version="$(FoundryLocalCoreVersion)" />
<PackageReference Condition="'$(UseWinML)' != 'true'"
Include="Microsoft.AI.Foundry.Local.Core" Version="0.8.1.0" />
Include="Microsoft.AI.Foundry.Local.Core" Version="$(FoundryLocalCoreVersion)" />

<PackageReference Include="Betalgo.Ranul.OpenAI" Version="9.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.9" />
Expand Down
67 changes: 57 additions & 10 deletions sdk_v2/js/script/install.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,37 +39,49 @@ const REQUIRED_FILES = [
// When you run npm install --winml, npm does not pass --winml as a command-line argument to your script.
// Instead, it sets an environment variable named npm_config_winml to 'true'.
const useWinML = process.env.npm_config_winml === 'true';
const useNightly = process.env.npm_config_nightly === 'true';

console.log(`[foundry-local] WinML enabled: ${useWinML}`);
console.log(`[foundry-local] Nightly enabled: ${useNightly}`);

const NUGET_FEED = 'https://api.nuget.org/v3/index.json';
const ORT_FEED = 'https://pkgs.dev.azure.com/aiinfra/PublicPackages/_packaging/ORT/nuget/v3/index.json';
const ORT_NIGHTLY_FEED = 'https://pkgs.dev.azure.com/aiinfra/PublicPackages/_packaging/ORT-Nightly/nuget/v3/index.json';

// If nightly is requested, pull Core/GenAI from the ORT-Nightly feed where nightly builds are published.
// Otherwise use the standard NuGet.org feed.
const CORE_FEED = useNightly ? ORT_NIGHTLY_FEED : NUGET_FEED;

const ARTIFACTS = [
{
name: useWinML ? 'Microsoft.AI.Foundry.Local.Core.WinML' : 'Microsoft.AI.Foundry.Local.Core',
version: '0.8.2.2',
version: useNightly ? undefined : '0.8.2.2', // Set later using resolveLatestVersion if undefined
files: ['Microsoft.AI.Foundry.Local.Core'],
feed: NUGET_FEED
feed: CORE_FEED
},
{
name: 'Microsoft.ML.OnnxRuntime.Foundry',
version: '1.23.2',
version: '1.23.2.1', // Hardcoded stable version
files: ['onnxruntime'],
feed: ORT_FEED
feed: ORT_NIGHTLY_FEED
},
{
name: useWinML ? 'Microsoft.ML.OnnxRuntimeGenAI.WinML' : 'Microsoft.ML.OnnxRuntimeGenAI.Foundry',
version: '0.11.4',
version: '0.11.2', // Hardcoded stable version
files: ['onnxruntime-genai'],
feed: NUGET_FEED
}
];

// Check if already installed
if (fs.existsSync(BIN_DIR) && REQUIRED_FILES.every(f => fs.existsSync(path.join(BIN_DIR, f)))) {
console.log(`[foundry-local] Native libraries already installed.`);
process.exit(0);
if (useNightly) {
console.log(`[foundry-local] Nightly requested. Forcing reinstall...`);
fs.rmSync(BIN_DIR, { recursive: true, force: true });
} else {
console.log(`[foundry-local] Native libraries already installed.`);
process.exit(0);
}
}

console.log(`[foundry-local] Installing native libraries for ${RID}...`);
Expand Down Expand Up @@ -143,7 +155,7 @@ async function downloadFile(url, dest) {
// Map to cache service index resources
const serviceIndexCache = new Map();

async function resolvePackageRawUrl(feedUrl, packageName, version) {
async function getBaseAddress(feedUrl) {
// 1. Get Service Index
if (!serviceIndexCache.has(feedUrl)) {
const index = await downloadJson(feedUrl);
Expand All @@ -162,7 +174,36 @@ async function resolvePackageRawUrl(feedUrl, packageName, version) {

const baseAddress = baseAddressRes['@id'];
// Ensure trailing slash
const properBase = baseAddress.endsWith('/') ? baseAddress : baseAddress + '/';
return baseAddress.endsWith('/') ? baseAddress : baseAddress + '/';
}

async function resolveLatestVersion(feedUrl, packageName) {
const baseAddress = await getBaseAddress(feedUrl);
const nameLower = packageName.toLowerCase();

// Fetch version list: {baseAddress}/{lower_id}/index.json
const versionsUrl = `${baseAddress}${nameLower}/index.json`;
try {
const versionData = await downloadJson(versionsUrl);
const versions = versionData.versions || [];

if (versions.length === 0) {
throw new Error('No versions found');
}

// Sort descending to prioritize latest date-based versions (e.g. 0.9.0-dev.YYYYMMDD...)
versions.sort((a, b) => b.localeCompare(a));

const latestVersion = versions[0];
console.log(`[foundry-local] Installing latest version of Foundry Local Core: ${latestVersion}`);
return latestVersion;
} catch (e) {
throw new Error(`Failed to fetch versions for ${packageName} from ${versionsUrl}: ${e.message}`);
}
}

async function resolvePackageRawUrl(feedUrl, packageName, version) {
const properBase = await getBaseAddress(feedUrl);

// 3. Construct .nupkg URL (lowercase is standard for V3)
const nameLower = packageName.toLowerCase();
Expand All @@ -173,9 +214,15 @@ async function resolvePackageRawUrl(feedUrl, packageName, version) {

async function installPackage(artifact, tempDir) {
const pkgName = artifact.name;
const pkgVer = artifact.version;
const feedUrl = artifact.feed;

// Resolve version if not specified
let pkgVer = artifact.version;
if (!pkgVer) {
console.log(` Resolving latest version for ${pkgName}...`);
pkgVer = await resolveLatestVersion(feedUrl, pkgName);
}

console.log(` Resolving ${pkgName} ${pkgVer}...`);
const downloadUrl = await resolvePackageRawUrl(feedUrl, pkgName, pkgVer);

Expand Down