Skip to content

Instantly share code, notes, and snippets.

@romero126
Last active April 30, 2026 19:48
Show Gist options
  • Select an option

  • Save romero126/acc0c8909a25e6e30edb8863212f2417 to your computer and use it in GitHub Desktop.

Select an option

Save romero126/acc0c8909a25e6e30edb8863212f2417 to your computer and use it in GitHub Desktop.
Phi Silica
#Requires -Version 7.0
<#
.SYNOPSIS
Invoke the on-device Phi Silica AI model through the Windows App SDK.
.DESCRIPTION
Uses the Microsoft.Windows.AI.Text.LanguageModel API from the Windows App SDK
to run the Phi Silica small language model locally on Copilot+ PCs.
All inference runs on the device NPU — no cloud connection required.
On first run the script downloads the Windows App SDK NuGet package to a local
.sdk folder for the .NET projection assemblies. The Phi Silica model itself is
managed by Windows and may download via Windows Update if not already present.
.PARAMETER Prompt
A single prompt to send to the model. Output is written to the pipeline.
.PARAMETER SystemPrompt
System-level instructions that guide the model's behavior and persona.
.PARAMETER Temperature
Sampling temperature (0.0-2.0). Lower values produce more deterministic output.
.PARAMETER TopP
Nucleus sampling threshold. Only tokens whose cumulative probability exceeds
this value are considered.
.PARAMETER TopK
Maximum number of top-probability tokens to consider at each step.
.PARAMETER Interactive
Enter an interactive chat session with conversation history.
Type 'exit' or 'quit' to end the session.
.PARAMETER SdkVersion
Windows App SDK NuGet package version. Defaults to the latest experimental
build that includes AI APIs.
.EXAMPLE
.\Invoke-WinCopilot.ps1 "Explain quantum computing in simple terms"
.EXAMPLE
.\Invoke-WinCopilot.ps1 -Interactive -SystemPrompt "You are a concise coding assistant"
.EXAMPLE
.\Invoke-WinCopilot.ps1 -Prompt "Translate to French: Good morning" -Temperature 0.3
.NOTES
Requirements:
- Windows 11 24H2+ on a Copilot+ PC (NPU required)
- PowerShell 7.0+
- Windows App Runtime installed (pre-installed on Copilot+ PCs)
- Internet access on first run to download the SDK NuGet package
#>
[CmdletBinding(DefaultParameterSetName = 'Query')]
[OutputType([string])]
param(
[Parameter(ParameterSetName = 'Query', Position = 0, Mandatory)]
[string]$Prompt,
[Parameter()]
[string]$SystemPrompt,
[Parameter()]
[ValidateRange(0.0, 2.0)]
[double]$Temperature = 0.7,
[Parameter()]
[ValidateRange(0.0, 1.0)]
[double]$TopP,
[Parameter()]
[ValidateRange(1, 500)]
[int]$TopK,
[Parameter(ParameterSetName = 'Chat', Mandatory)]
[switch]$Interactive,
[Parameter()]
[string]$SdkVersion = '1.8.260416003'
)
$ErrorActionPreference = 'Stop'
$SdkCache = Join-Path $PSScriptRoot '.sdk'
$PkgRoot = Join-Path $SdkCache "microsoft.windowsappsdk.$SdkVersion"
$CsWinRTVer = '2.1.6'
$CsWinRTDir = Join-Path $SdkCache "microsoft.windows.cswinrt.$CsWinRTVer"
$WinSdkNetVer = '10.0.26100.84'
$WinSdkNetDir = Join-Path $SdkCache "microsoft.windows.sdk.net.ref.$WinSdkNetVer"
# ---------------------------------------------------------------------------
# SDK acquisition — download NuGet package for .NET projection assemblies
# ---------------------------------------------------------------------------
function Install-NuGetPackage {
[CmdletBinding()]
param(
[string]$PackageName,
[string]$Version,
[string]$DestPath
)
if (Test-Path $DestPath) {
Write-Verbose "$PackageName cached at $DestPath"
return
}
Write-Host "[*] Downloading $PackageName $Version..." -ForegroundColor Cyan
$null = New-Item $SdkCache -ItemType Directory -Force
$zip = Join-Path $SdkCache 'pkg.zip'
$url = "https://api.nuget.org/v3-flatcontainer/$($PackageName.ToLower())/$Version/$($PackageName.ToLower()).$Version.nupkg"
try {
Invoke-WebRequest $url -OutFile $zip -UseBasicParsing
}
catch {
throw "Failed to download $PackageName v$Version. Verify the version exists on nuget.org. $_"
}
Expand-Archive $zip -DestinationPath $DestPath -Force
Remove-Item $zip
Write-Host "[+] $PackageName extracted." -ForegroundColor Green
}
function Install-SdkPackage {
[CmdletBinding()]
param()
Install-NuGetPackage -PackageName 'Microsoft.WindowsAppSDK' -Version $SdkVersion -DestPath $PkgRoot
$nuspec = Join-Path $PkgRoot 'Microsoft.WindowsAppSDK.nuspec'
if (Test-Path $nuspec) {
[xml]$spec = Get-Content $nuspec
$ns = @{ n = 'http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd' }
$deps = Select-Xml -Xml $spec -XPath '//n:dependency' -Namespace $ns |
ForEach-Object { $_.Node }
foreach ($dep in $deps) {
$depId = $dep.id
$depVer = $dep.version -replace '[\[\]]', ''
$depDir = Join-Path $SdkCache "$($depId.ToLower()).$depVer"
Install-NuGetPackage -PackageName $depId -Version $depVer -DestPath $depDir
}
}
Install-NuGetPackage -PackageName 'Microsoft.Windows.CsWinRT' -Version $CsWinRTVer -DestPath $CsWinRTDir
Install-NuGetPackage -PackageName 'Microsoft.Windows.SDK.NET.Ref' -Version $WinSdkNetVer -DestPath $WinSdkNetDir
}
# ---------------------------------------------------------------------------
# Assembly loading and Windows App Runtime bootstrap
# ---------------------------------------------------------------------------
function Initialize-Runtime {
[CmdletBinding()]
param()
$arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'win-arm64' } else { 'win-x64' }
$pkgDirs = Get-ChildItem $SdkCache -Directory | Select-Object -ExpandProperty FullName
$libDirs = @()
$nativeDirs = @()
foreach ($pkg in $pkgDirs) {
$libParent = Join-Path $pkg 'lib'
if (Test-Path $libParent) {
$best = Get-ChildItem $libParent -Directory |
Where-Object Name -like 'net8.0*' |
Sort-Object Name -Descending |
Select-Object -First 1 -ExpandProperty FullName
if (-not $best) {
$best = Get-ChildItem $libParent -Directory |
Where-Object Name -like 'net6.0*' |
Sort-Object Name -Descending |
Select-Object -First 1 -ExpandProperty FullName
}
if ($best) { $libDirs += $best }
}
$natDir = Join-Path $pkg "runtimes/$arch/native"
if (Test-Path $natDir) { $nativeDirs += $natDir }
}
if ($libDirs.Count -eq 0) { throw "No .NET projection folders found in SDK packages." }
if ($nativeDirs.Count -eq 0) { throw "No native runtime found for $arch." }
Write-Verbose "Projection dirs : $($libDirs -join ', ')"
Write-Verbose "Native dirs : $($nativeDirs -join ', ')"
foreach ($nd in $nativeDirs) {
$env:PATH = "$nd;$env:PATH"
$bootstrapNative = Join-Path $nd 'Microsoft.WindowsAppRuntime.Bootstrap.dll'
if (Test-Path $bootstrapNative) {
[System.Runtime.InteropServices.NativeLibrary]::Load($bootstrapNative) | Out-Null
Write-Verbose "Pre-loaded native bootstrap DLL from $nd"
}
}
$dllNames = @(
'WinRT.Runtime.dll'
'Microsoft.Windows.SDK.NET.dll'
'Microsoft.WindowsAppRuntime.Bootstrap.Net.dll'
'Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll'
'Microsoft.Windows.AI.Projection.dll'
'Microsoft.Windows.AI.Foundation.Projection.dll'
'Microsoft.Windows.AI.Text.Projection.dll'
'Microsoft.Windows.AI.ContentSafety.Projection.dll'
)
foreach ($dll in $dllNames) {
$found = $false
foreach ($dir in $libDirs) {
$path = Join-Path $dir $dll
if (Test-Path $path) {
Add-Type -Path $path
Write-Verbose "Loaded $dll"
$found = $true
break
}
}
if (-not $found) { Write-Verbose "Skipped $dll (not in any package)" }
}
try {
$versionTag = if ($SdkVersion -match '-(experimental\d*)$') { $Matches[1] } else { '' }
$minVer = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageVersion]::new([uint16]0)
$opts = [Microsoft.Windows.ApplicationModel.DynamicDependency.Bootstrap+InitializeOptions]::OnPackageIdentity_NOOP
# 0x00010008 = major 1, minor 8
[Microsoft.Windows.ApplicationModel.DynamicDependency.Bootstrap]::Initialize(
[uint32]0x00010008, $versionTag, $minVer, $opts)
Write-Verbose "Windows App Runtime bootstrapped (tag: '$versionTag')."
}
catch {
$msg = @(
'Failed to bootstrap the Windows App Runtime.'
'Ensure the Windows App SDK 1.8+ runtime is installed.'
'On Copilot+ PCs it should be pre-installed; otherwise install from:'
'https://learn.microsoft.com/windows/apps/windows-app-sdk/downloads'
) -join "`n"
throw "$msg`n$_"
}
}
# ---------------------------------------------------------------------------
# Model readiness check
# ---------------------------------------------------------------------------
function Assert-ModelReady {
[CmdletBinding()]
param()
try {
$state = [Microsoft.Windows.AI.Text.LanguageModel]::GetReadyState()
}
catch {
if ($_.Exception.InnerException -and
$_.Exception.InnerException.HResult -eq [int]0x80040154) {
throw @(
'The Phi Silica AI runtime is not registered on this system.'
'This requires a Copilot+ PC with Windows 11 24H2+ and an NPU.'
'Ensure the Windows AI feature is enabled in Settings > Windows Update > Advanced options.'
) -join "`n"
}
throw
}
Write-Verbose "Model readiness: $state"
switch ($state.ToString()) {
'Ready' { return }
'NotReady' {
Write-Host '[*] Phi Silica model is downloading — this may take several minutes...' -ForegroundColor Yellow
[Microsoft.Windows.AI.Text.LanguageModel]::EnsureReadyAsync().GetAwaiter().GetResult()
Write-Host '[+] Model download complete.' -ForegroundColor Green
}
'NotSupportedOnCurrentSystem' {
throw 'This device does not support Phi Silica. A Copilot+ PC with an NPU is required.'
}
'DisabledByUser' {
throw 'The Phi Silica model has been disabled or removed. Re-enable it in Settings > Windows Update.'
}
default {
throw "Phi Silica is not available (state: $state)."
}
}
}
# ---------------------------------------------------------------------------
# Session management
# ---------------------------------------------------------------------------
function New-AISession {
[CmdletBinding()]
[OutputType([hashtable])]
param(
[string]$SysPrompt,
[double]$Temp,
[double]$P,
[int]$K
)
$model = [Microsoft.Windows.AI.Text.LanguageModel]::CreateAsync().GetAwaiter().GetResult()
$options = [Microsoft.Windows.AI.Text.LanguageModelOptions]::new()
$options.Temperature = [float]$Temp
if ($P -gt 0) { $options.TopP = [float]$P }
if ($K -gt 0) { $options.TopK = [float]$K }
$context = if ($SysPrompt) {
$model.CreateContext($SysPrompt)
}
else {
$model.CreateContext()
}
@{
Model = $model
Options = $options
Context = $context
}
}
function Send-Prompt {
[CmdletBinding()]
[OutputType([string])]
param(
[hashtable]$Session,
[string]$Text
)
$result = $Session.Model.GenerateResponseAsync(
$Session.Context,
$Text,
$Session.Options
).GetAwaiter().GetResult()
$status = $result.Status.ToString()
if ($status -ne 'Success') {
$detail = if ($result.ExtendedError) { $result.ExtendedError.Message } else { $status }
Write-Warning "Model response failed: $detail"
return $null
}
$result.Text
}
# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
try {
Install-SdkPackage
Initialize-Runtime
Assert-ModelReady
$session = New-AISession -SysPrompt $SystemPrompt -Temp $Temperature -P $TopP -K $TopK
Write-Host "[+] Phi Silica ready.`n" -ForegroundColor Green
if ($Interactive) {
Write-Host " Type 'exit' or 'quit' to end the session." -ForegroundColor DarkGray
Write-Host " Conversation context is preserved between turns.`n" -ForegroundColor DarkGray
while ($true) {
Write-Host 'You> ' -NoNewline -ForegroundColor Yellow
$userInput = Read-Host
if ($userInput -in 'exit', 'quit') { break }
if ([string]::IsNullOrWhiteSpace($userInput)) { continue }
$response = Send-Prompt -Session $session -Text $userInput
if ($response) {
Write-Host "Copilot> " -NoNewline -ForegroundColor Cyan
Write-Host "$response`n"
}
}
Write-Host "`nSession ended." -ForegroundColor DarkGray
}
else {
$response = Send-Prompt -Session $session -Text $Prompt
if ($response) { Write-Output $response }
}
}
finally {
if ($session -and $session.Model) {
$session.Model.Dispose()
Write-Verbose 'Model disposed.'
}
try {
[Microsoft.Windows.ApplicationModel.DynamicDependency.Bootstrap]::Shutdown()
Write-Verbose 'Runtime shut down.'
}
catch {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment