Skip to content

Commit fa0948b

Browse files
Adding Phi Silica Agent for Copilot+PCs (#373)
1 parent ad02261 commit fa0948b

File tree

3 files changed

+162
-2
lines changed

3 files changed

+162
-2
lines changed

build.psm1

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
$metadata = Get-Content $PSScriptRoot/tools/metadata.json | ConvertFrom-Json
77
$dotnetSDKVersion = $(Get-Content $PSScriptRoot/global.json | ConvertFrom-Json).Sdk.Version
88
$dotnetLocalDir = if ($IsWindows) { "$env:LocalAppData\Microsoft\dotnet" } else { "$env:HOME/.dotnet" }
9+
$windowsOnlyAgents = @('phisilica')
910

1011
function Start-Build
1112
{
@@ -20,7 +21,7 @@ function Start-Build
2021
[string] $Runtime = [NullString]::Value,
2122

2223
[Parameter()]
23-
[ValidateSet('openai-gpt', 'msaz', 'interpreter', 'ollama')]
24+
[ValidateSet('openai-gpt', 'msaz', 'interpreter', 'ollama', 'phisilica')]
2425
[string[]] $AgentToInclude,
2526

2627
[Parameter()]
@@ -43,13 +44,18 @@ function Start-Build
4344
$MyInvocation.MyCommand.Parameters["AgentToInclude"].Attributes |
4445
Where-Object { $_ -is [ValidateSet] } |
4546
Select-Object -First 1 |
46-
ForEach-Object ValidValues
47+
ForEach-Object ValidValues |
48+
Skip-Unapplicable
4749
} else {
4850
$agents.Split(",", [System.StringSplitOptions]::TrimEntries)
4951
Write-Verbose "Include agents specified in Metadata.json"
5052
}
5153
}
5254

55+
if (HasUnapplicableAgent $AgentToInclude) {
56+
throw "The following specified agent(s) cannot be built on the current platform: $($windowsOnlyAgents -join ', ')."
57+
}
58+
5359
$RID = $Runtime ?? (dotnet --info |
5460
Select-String '^\s*RID:\s+(\w+-\w+)$' |
5561
Select-Object -First 1 |
@@ -69,6 +75,7 @@ function Start-Build
6975
$msaz_dir = Join-Path $agent_dir "Microsoft.Azure.Agent"
7076
$interpreter_agent_dir = Join-Path $agent_dir "AIShell.Interpreter.Agent"
7177
$ollama_agent_dir = Join-Path $agent_dir "AIShell.Ollama.Agent"
78+
$phisilica_agent_dir = Join-Path $agent_dir "AIShell.PhiSilica.Agent"
7279

7380
$config = $Configuration.ToLower()
7481
$out_dir = Join-Path $PSScriptRoot "out"
@@ -79,6 +86,7 @@ function Start-Build
7986
$msaz_out_dir = Join-Path $app_out_dir "agents" "Microsoft.Azure.Agent"
8087
$interpreter_out_dir = Join-Path $app_out_dir "agents" "AIShell.Interpreter.Agent"
8188
$ollama_out_dir = Join-Path $app_out_dir "agents" "AIShell.Ollama.Agent"
89+
$phisilica_out_dir = Join-Path $app_out_dir "agents" "AIShell.PhiSilica.Agent"
8290

8391
if ($Clean) {
8492
if (Test-Path $out_dir) {
@@ -152,6 +160,12 @@ function Start-Build
152160
dotnet publish $ollama_csproj -c $Configuration -o $ollama_out_dir
153161
}
154162

163+
if ($LASTEXITCODE -eq 0 -and $AgentToInclude -contains 'phisilica') {
164+
Write-Host "`n[Build the PhiSilica agent ...]`n" -ForegroundColor Green
165+
$phisilica_csproj = GetProjectFile $phisilica_agent_dir
166+
dotnet publish $phisilica_csproj -c $Configuration -o $phisilica_out_dir
167+
}
168+
155169
if ($LASTEXITCODE -eq 0 -and -not $NotIncludeModule) {
156170
Write-Host "`n[Build the AIShell module ...]`n" -ForegroundColor Green
157171
$aish_module_csproj = GetProjectFile $module_dir
@@ -175,6 +189,26 @@ function Start-Build
175189
}
176190
}
177191

192+
filter Skip-Unapplicable {
193+
if ($IsWindows -or $windowsOnlyAgents -notcontains $_) {
194+
$_
195+
}
196+
}
197+
198+
function HasUnapplicableAgent($specifiedAgents) {
199+
if ($IsWindows) {
200+
return $false
201+
}
202+
203+
foreach ($agent in $windowsOnlyAgents) {
204+
if ($specifiedAgents -contains $agent) {
205+
return $true
206+
}
207+
}
208+
209+
return $false
210+
}
211+
178212
function GetProjectFile($dir)
179213
{
180214
return Get-Item "$dir/*.csproj" | ForEach-Object FullName
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Library</OutputType>
4+
<TargetFramework>net8.0-windows10.0.26100.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<NoWarn>CS8305</NoWarn>
7+
<Platforms>AnyCPU</Platforms>
8+
<WindowsPackageType>None</WindowsPackageType>
9+
<EnableDynamicLoading>true</EnableDynamicLoading>
10+
<WindowsAppSdkBootstrapInitialize>true</WindowsAppSdkBootstrapInitialize>
11+
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
12+
<RuntimeIdentifier>win-arm64</RuntimeIdentifier>
13+
<EnableMsixTooling>true</EnableMsixTooling>
14+
</PropertyGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="..\..\AIShell.Abstraction\AIShell.Abstraction.csproj">
18+
<!-- Disable copying AIShell.Abstraction.dll to output folder -->
19+
<Private>false</Private>
20+
<!-- Disable copying the transitive dependencies to output folder -->
21+
<ExcludeAssets>runtime</ExcludeAssets>
22+
</ProjectReference>
23+
</ItemGroup>
24+
25+
<ItemGroup>
26+
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.250410001-experimental1" />
27+
</ItemGroup>
28+
29+
</Project>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
using AIShell.Abstraction;
2+
using Microsoft.Windows.AI;
3+
using Microsoft.Windows.AI.Generative;
4+
5+
namespace AIShell.PhiSilica.Agent;
6+
7+
public sealed partial class PhiSilicaAgent : ILLMAgent
8+
{
9+
private readonly Task _initTask;
10+
private LanguageModel _model;
11+
12+
public string Name => "PhiSilica";
13+
public string Description => "This is the AI Shell Agent for talking to the inbox Phi Silica model on Copilot+ PCs.";
14+
public string SettingFile => null;
15+
16+
public IEnumerable<CommandBase> GetCommands() => null;
17+
public bool CanAcceptFeedback(UserAction action) => false;
18+
public Task RefreshChatAsync(IShell shell, bool force) => Task.CompletedTask;
19+
public void OnUserAction(UserActionPayload actionPayload) { }
20+
public void Initialize(AgentConfig config) { }
21+
public void Dispose() { }
22+
23+
public PhiSilicaAgent()
24+
{
25+
// Start the initialization for AI feature and model on a background thread.
26+
_initTask = Task.Run(InitFeatureAndModelAsync);
27+
}
28+
29+
private async Task InitFeatureAndModelAsync()
30+
{
31+
AIFeatureReadyState state = LanguageModel.GetReadyState();
32+
if (state is AIFeatureReadyState.NotSupportedOnCurrentSystem)
33+
{
34+
throw new PlatformNotSupportedException("The Phi Silica feature is not supported on current system.");
35+
}
36+
37+
if (state is AIFeatureReadyState.DisabledByUser)
38+
{
39+
throw new PlatformNotSupportedException("The Phi Silica feature is currently disabled.");
40+
}
41+
42+
if (state is AIFeatureReadyState.EnsureNeeded)
43+
{
44+
// Initialize the WinRT runtime.
45+
AIFeatureReadyResult result = await LanguageModel.EnsureReadyAsync();
46+
// Do not proceed if it failed to get the feature ready.
47+
if (result.Status is not AIFeatureReadyResultState.Success)
48+
{
49+
throw new InvalidOperationException(result.ErrorDisplayText, result.Error);
50+
}
51+
}
52+
53+
_model = await LanguageModel.CreateAsync();
54+
}
55+
56+
public async Task<bool> ChatAsync(string input, IShell shell)
57+
{
58+
IHost host = shell.Host;
59+
60+
try
61+
{
62+
// Wait for the init task to finish. Once it's finished, calling this again is a non-op.
63+
await _initTask;
64+
}
65+
catch (Exception e)
66+
{
67+
host.WriteErrorLine(e.Message);
68+
if (e is InvalidOperationException && e.InnerException is not null)
69+
{
70+
host.WriteErrorLine(e.InnerException.StackTrace);
71+
}
72+
else if (e is not PlatformNotSupportedException)
73+
{
74+
// Show stack trace for non-PNS exception.
75+
host.WriteErrorLine(e.StackTrace);
76+
}
77+
78+
return false;
79+
}
80+
81+
var result = await host.RunWithSpinnerAsync(
82+
status: "Thinking ...",
83+
func: async () => await _model.GenerateResponseAsync(input)
84+
);
85+
86+
if (result is not null && !string.IsNullOrEmpty(result.Text))
87+
{
88+
host.RenderFullResponse(result.Text);
89+
}
90+
else
91+
{
92+
host.WriteErrorLine("No response received from the language model.");
93+
}
94+
95+
return true;
96+
}
97+
}

0 commit comments

Comments
 (0)