From a748341de971189f3477d894b6c05f38987fa647 Mon Sep 17 00:00:00 2001 From: Steven Bucher Date: Mon, 21 Apr 2025 21:51:43 -0700 Subject: [PATCH 1/6] init commit for phi silica agent --- build.psm1 | 10 ++- .../AIShell.PhiSilica.Agent.csproj | 33 +++++++++ .../AIShell.PhiSilica.Agent/PhiSilicaAgent.cs | 69 +++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 shell/agents/AIShell.PhiSilica.Agent/AIShell.PhiSilica.Agent.csproj create mode 100644 shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs diff --git a/build.psm1 b/build.psm1 index b521571c..58e4a9a3 100644 --- a/build.psm1 +++ b/build.psm1 @@ -20,7 +20,7 @@ function Start-Build [string] $Runtime = [NullString]::Value, [Parameter()] - [ValidateSet('openai-gpt', 'msaz', 'interpreter', 'ollama')] + [ValidateSet('openai-gpt', 'msaz', 'interpreter', 'ollama', 'phisilica')] [string[]] $AgentToInclude, [Parameter()] @@ -69,6 +69,7 @@ function Start-Build $msaz_dir = Join-Path $agent_dir "Microsoft.Azure.Agent" $interpreter_agent_dir = Join-Path $agent_dir "AIShell.Interpreter.Agent" $ollama_agent_dir = Join-Path $agent_dir "AIShell.Ollama.Agent" + $phisilica_agent_dir = Join-Path $agent_dir "AIShell.PhiSilica.Agent" $config = $Configuration.ToLower() $out_dir = Join-Path $PSScriptRoot "out" @@ -79,6 +80,7 @@ function Start-Build $msaz_out_dir = Join-Path $app_out_dir "agents" "Microsoft.Azure.Agent" $interpreter_out_dir = Join-Path $app_out_dir "agents" "AIShell.Interpreter.Agent" $ollama_out_dir = Join-Path $app_out_dir "agents" "AIShell.Ollama.Agent" + $phisilica_out_dir = Join-Path $app_out_dir "agents" "AIShell.PhiSilica.Agent" if ($Clean) { if (Test-Path $out_dir) { @@ -152,6 +154,12 @@ function Start-Build dotnet publish $ollama_csproj -c $Configuration -o $ollama_out_dir } + if ($LASTEXITCODE -eq 0 -and $AgentToInclude -contains 'phisilica') { + Write-Host "`n[Build the PhiSilica agent ...]`n" -ForegroundColor Green + $phisilica_csproj = GetProjectFile $phisilica_agent_dir + dotnet publish $phisilica_csproj -c $Configuration -o $phisilica_out_dir + } + if ($LASTEXITCODE -eq 0 -and -not $NotIncludeModule) { Write-Host "`n[Build the AIShell module ...]`n" -ForegroundColor Green $aish_module_csproj = GetProjectFile $module_dir diff --git a/shell/agents/AIShell.PhiSilica.Agent/AIShell.PhiSilica.Agent.csproj b/shell/agents/AIShell.PhiSilica.Agent/AIShell.PhiSilica.Agent.csproj new file mode 100644 index 00000000..36c116ba --- /dev/null +++ b/shell/agents/AIShell.PhiSilica.Agent/AIShell.PhiSilica.Agent.csproj @@ -0,0 +1,33 @@ + + + + Library + net8.0-windows10.0.26100.0 + enable + enable + AnyCPU + None + true + true + true + win-arm64 + true + + + + + + + + false + + runtime + + + + + + + + + diff --git a/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs b/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs new file mode 100644 index 00000000..007d00ce --- /dev/null +++ b/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs @@ -0,0 +1,69 @@ + +using Microsoft.Windows.AI.Generative; + +using AIShell.Abstraction; +using Microsoft.Windows.AI; + +namespace phisilicaagent_041825 +{ + public class PhiSilicaAgent : ILLMAgent + { + public string Name => "PhiSilica"; + + public string Description => "This is the Phi Silica agent, an offline local agent on Copilot+ PCs"; + + public string SettingFile => null; + + public bool CanAcceptFeedback(UserAction action) => false; + + + public async Task ChatAsync(string input, IShell shell) + { + IHost host = shell.Host; + if (LanguageModel.GetReadyState() == AIFeatureReadyState.EnsureNeeded) + { + var op = await LanguageModel.EnsureReadyAsync(); + + } + + var languageModel = await LanguageModel.CreateAsync(); + + var results = await languageModel.GenerateResponseAsync(input); + + if (results != null && !string.IsNullOrEmpty(results.Text)) + { + host.RenderFullResponse(results.Text); + } + else + { + host.WriteErrorLine("No response received from the language model."); + } + //host.RenderFullResponse("Goodbye World"); + + return true; + } + + public void Dispose() + { + + } + + public IEnumerable GetCommands() => null; + + public void Initialize(AgentConfig config) + { + + } + + public void OnUserAction(UserActionPayload actionPayload) + { + + } + + public Task RefreshChatAsync(IShell shell, bool force) + { + return Task.CompletedTask; + } + } + +} From 7ce8052e09a3f56aebe77e1f99a7b620088aa661 Mon Sep 17 00:00:00 2001 From: Steven Bucher Date: Mon, 21 Apr 2025 22:07:09 -0700 Subject: [PATCH 2/6] Fix namespace declaration for PhiSilicaAgent class --- shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs b/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs index 007d00ce..851267e8 100644 --- a/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs +++ b/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs @@ -4,7 +4,7 @@ using AIShell.Abstraction; using Microsoft.Windows.AI; -namespace phisilicaagent_041825 +namespace AIShell.PhiSilica.Agent { public class PhiSilicaAgent : ILLMAgent { From 484863ecac6146c51e5d55394ab4fdb0c6ffdf21 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 23 Apr 2025 18:18:08 -0700 Subject: [PATCH 3/6] Refactor and clean up the code --- .../AIShell.PhiSilica.Agent.csproj | 26 ++--- .../AIShell.PhiSilica.Agent/PhiSilicaAgent.cs | 106 +++++++++++------- 2 files changed, 78 insertions(+), 54 deletions(-) diff --git a/shell/agents/AIShell.PhiSilica.Agent/AIShell.PhiSilica.Agent.csproj b/shell/agents/AIShell.PhiSilica.Agent/AIShell.PhiSilica.Agent.csproj index 36c116ba..abc3f552 100644 --- a/shell/agents/AIShell.PhiSilica.Agent/AIShell.PhiSilica.Agent.csproj +++ b/shell/agents/AIShell.PhiSilica.Agent/AIShell.PhiSilica.Agent.csproj @@ -1,21 +1,18 @@ - - Library - net8.0-windows10.0.26100.0 - enable - enable - AnyCPU - None - true - true - true - win-arm64 - true - + Library + net8.0-windows10.0.26100.0 + enable + CS8305 + AnyCPU + None + true + true + true + win-arm64 + true - @@ -25,7 +22,6 @@ - diff --git a/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs b/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs index 851267e8..b4f8ea47 100644 --- a/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs +++ b/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs @@ -1,69 +1,97 @@ - -using Microsoft.Windows.AI.Generative; - using AIShell.Abstraction; using Microsoft.Windows.AI; +using Microsoft.Windows.AI.Generative; -namespace AIShell.PhiSilica.Agent +namespace AIShell.PhiSilica.Agent; + +public sealed partial class PhiSilicaAgent : ILLMAgent { - public class PhiSilicaAgent : ILLMAgent - { - public string Name => "PhiSilica"; + private readonly Task _initTask; + private LanguageModel _model; - public string Description => "This is the Phi Silica agent, an offline local agent on Copilot+ PCs"; + public string Name => "PhiSilica"; + public string Description => "This is the Phi Silica agent, an offline local agent on Copilot+ PCs"; + public string SettingFile => null; - public string SettingFile => null; + public IEnumerable GetCommands() => null; + public bool CanAcceptFeedback(UserAction action) => false; + public Task RefreshChatAsync(IShell shell, bool force) => Task.CompletedTask; + public void OnUserAction(UserActionPayload actionPayload) { } + public void Initialize(AgentConfig config) { } + public void Dispose() { } - public bool CanAcceptFeedback(UserAction action) => false; + public PhiSilicaAgent() + { + // Start the initialization for AI feature and model on a background thread. + _initTask = Task.Run(InitFeatureAndModelAsync); + } + private async Task InitFeatureAndModelAsync() + { + AIFeatureReadyState state = LanguageModel.GetReadyState(); + if (state is AIFeatureReadyState.NotSupportedOnCurrentSystem) + { + throw new PlatformNotSupportedException("The Phi Silica feature is not supported on current system."); + } - public async Task ChatAsync(string input, IShell shell) + if (state is AIFeatureReadyState.DisabledByUser) { - IHost host = shell.Host; - if (LanguageModel.GetReadyState() == AIFeatureReadyState.EnsureNeeded) - { - var op = await LanguageModel.EnsureReadyAsync(); + throw new PlatformNotSupportedException("The Phi Silica feature is currently disabled."); + } + if (state is AIFeatureReadyState.EnsureNeeded) + { + // Initialize the WinRT runtime. + AIFeatureReadyResult result = await LanguageModel.EnsureReadyAsync(); + // Do not proceed if it failed to get the feature ready. + if (result.Status is not AIFeatureReadyResultState.Success) + { + throw new InvalidOperationException(result.ErrorDisplayText, result.Error); } + } - var languageModel = await LanguageModel.CreateAsync(); + _model = await LanguageModel.CreateAsync(); + } - var results = await languageModel.GenerateResponseAsync(input); + public async Task ChatAsync(string input, IShell shell) + { + IHost host = shell.Host; - if (results != null && !string.IsNullOrEmpty(results.Text)) + try + { + // Wait for the init task to finish. Once it's finished, calling this again is a non-op. + await _initTask; + } + catch (Exception e) + { + host.WriteErrorLine(e.Message); + if (e is InvalidOperationException && e.InnerException is not null) { - host.RenderFullResponse(results.Text); + host.WriteErrorLine(e.InnerException.StackTrace); } - else + else if (e is not PlatformNotSupportedException) { - host.WriteErrorLine("No response received from the language model."); + // Show stack trace for non-PNS exception. + host.WriteErrorLine(e.StackTrace); } - //host.RenderFullResponse("Goodbye World"); - return true; + return false; } - public void Dispose() - { - - } + var result = await host.RunWithSpinnerAsync( + status: "Thinking ...", + func: async () => await _model.GenerateResponseAsync(input) + ); - public IEnumerable GetCommands() => null; - - public void Initialize(AgentConfig config) + if (result is not null && !string.IsNullOrEmpty(result.Text)) { - + host.RenderFullResponse(result.Text); } - - public void OnUserAction(UserActionPayload actionPayload) + else { - + host.WriteErrorLine("No response received from the language model."); } - public Task RefreshChatAsync(IShell shell, bool force) - { - return Task.CompletedTask; - } + return true; } - } From f8e4cea52071df20df8f60552a5ca5fac8a1ba96 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 30 Apr 2025 15:45:33 -0700 Subject: [PATCH 4/6] Update build to skip building 'phisilica' on non-windows --- build.psm1 | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/build.psm1 b/build.psm1 index 58e4a9a3..5e9e5a84 100644 --- a/build.psm1 +++ b/build.psm1 @@ -6,6 +6,7 @@ $metadata = Get-Content $PSScriptRoot/tools/metadata.json | ConvertFrom-Json $dotnetSDKVersion = $(Get-Content $PSScriptRoot/global.json | ConvertFrom-Json).Sdk.Version $dotnetLocalDir = if ($IsWindows) { "$env:LocalAppData\Microsoft\dotnet" } else { "$env:HOME/.dotnet" } +$windowsOnlyAgents = @('phisilica') function Start-Build { @@ -43,13 +44,18 @@ function Start-Build $MyInvocation.MyCommand.Parameters["AgentToInclude"].Attributes | Where-Object { $_ -is [ValidateSet] } | Select-Object -First 1 | - ForEach-Object ValidValues + ForEach-Object ValidValues | + Skip-Unapplicable } else { $agents.Split(",", [System.StringSplitOptions]::TrimEntries) Write-Verbose "Include agents specified in Metadata.json" } } + if (HasUnapplicableAgent $AgentToInclude) { + throw "One or more specified agents cannot be built on the current platform: $($windowsOnlyAgents -join ', ').`nPlease skip them and try again." + } + $RID = $Runtime ?? (dotnet --info | Select-String '^\s*RID:\s+(\w+-\w+)$' | Select-Object -First 1 | @@ -183,6 +189,26 @@ function Start-Build } } +filter Skip-Unapplicable { + if ($IsWindows -or $windowsOnlyAgents -notcontains $_) { + $_ + } +} + +function HasUnapplicableAgent($specifiedAgents) { + if ($IsWindows) { + return $false + } + + foreach ($agent in $windowsOnlyAgents) { + if ($specifiedAgents -contains $agent) { + return $true + } + } + + return $false +} + function GetProjectFile($dir) { return Get-Item "$dir/*.csproj" | ForEach-Object FullName From 18ff580540fa11dbe413baa7bd63b762b4b3ff5a Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 30 Apr 2025 16:14:54 -0700 Subject: [PATCH 5/6] Minor update to the exception message --- build.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.psm1 b/build.psm1 index 5e9e5a84..f84f5de3 100644 --- a/build.psm1 +++ b/build.psm1 @@ -53,7 +53,7 @@ function Start-Build } if (HasUnapplicableAgent $AgentToInclude) { - throw "One or more specified agents cannot be built on the current platform: $($windowsOnlyAgents -join ', ').`nPlease skip them and try again." + throw "The following specified agent(s) cannot be built on the current platform: $($windowsOnlyAgents -join ', ')." } $RID = $Runtime ?? (dotnet --info | From a1c2e855b2c9954ee62b752841de113559bb804b Mon Sep 17 00:00:00 2001 From: Steven Bucher Date: Sun, 4 May 2025 15:50:35 -0500 Subject: [PATCH 6/6] Update description of PhiSilicaAgent for clarity --- shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs b/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs index b4f8ea47..f10a4151 100644 --- a/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs +++ b/shell/agents/AIShell.PhiSilica.Agent/PhiSilicaAgent.cs @@ -10,7 +10,7 @@ public sealed partial class PhiSilicaAgent : ILLMAgent private LanguageModel _model; public string Name => "PhiSilica"; - public string Description => "This is the Phi Silica agent, an offline local agent on Copilot+ PCs"; + public string Description => "This is the AI Shell Agent for talking to the inbox Phi Silica model on Copilot+ PCs."; public string SettingFile => null; public IEnumerable GetCommands() => null;