diff --git a/src/common/LanguageModelProvider/FoundryLocal/FoundryClient.cs b/src/common/LanguageModelProvider/FoundryLocal/FoundryClient.cs index 287588a71e..a279f7389a 100644 --- a/src/common/LanguageModelProvider/FoundryLocal/FoundryClient.cs +++ b/src/common/LanguageModelProvider/FoundryLocal/FoundryClient.cs @@ -10,6 +10,23 @@ namespace LanguageModelProvider.FoundryLocal; internal sealed class FoundryClient { public static async Task CreateAsync() + { + // First attempt with current environment + var client = await TryCreateClientAsync().ConfigureAwait(false); + if (client != null) + { + return client; + } + + // If failed, refresh PATH from registry and retry once + // This handles cases where PowerToys was launched by MSI installer. + Logger.LogInfo("[FoundryClient] First attempt failed, refreshing PATH and retrying"); + RefreshEnvironmentPath(); + + return await TryCreateClientAsync().ConfigureAwait(false); + } + + private static async Task TryCreateClientAsync() { try { @@ -195,4 +212,68 @@ internal sealed class FoundryClient await _foundryManager.StartServiceAsync(); } } + + /// + /// Refreshes the PATH environment variable from the system registry. + /// This is necessary when tools are installed while PowerToys is running, + /// as the installer updates the system PATH but running processes don't see the change. + /// + private static void RefreshEnvironmentPath() + { + try + { + Logger.LogInfo("[FoundryClient] Refreshing PATH environment variable from system"); + + var currentPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process) ?? string.Empty; + var machinePath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) ?? string.Empty; + var userPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User) ?? string.Empty; + + var pathsToAdd = new List(); + + if (!string.IsNullOrWhiteSpace(currentPath)) + { + pathsToAdd.AddRange(currentPath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries)); + } + + if (!string.IsNullOrWhiteSpace(userPath)) + { + var userPaths = userPath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); + foreach (var path in userPaths) + { + if (!pathsToAdd.Contains(path, StringComparer.OrdinalIgnoreCase)) + { + pathsToAdd.Add(path); + } + } + } + + if (!string.IsNullOrWhiteSpace(machinePath)) + { + var machinePaths = machinePath.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); + foreach (var path in machinePaths) + { + if (!pathsToAdd.Contains(path, StringComparer.OrdinalIgnoreCase)) + { + pathsToAdd.Add(path); + } + } + } + + var newPath = string.Join(Path.PathSeparator.ToString(), pathsToAdd); + + if (currentPath != newPath) + { + Logger.LogInfo("[FoundryClient] Updating process PATH with latest system values"); + Environment.SetEnvironmentVariable("PATH", newPath, EnvironmentVariableTarget.Process); + } + else + { + Logger.LogInfo("[FoundryClient] PATH is already up to date"); + } + } + catch (Exception ex) + { + Logger.LogError($"[FoundryClient] Failed to refresh PATH: {ex.Message}"); + } + } }