V1 / 8f6c47b125e8
ProviderSetup.cs
Interfaces/ConsoleApp/LilithConsole/Setup/ProviderSetup.cs
Changed in this versionCS
using System.Text.Json;
using System.Text.RegularExpressions;
using Lilith.Agent;
using Lilith.Core.LMStudio;
using Lilith.Core.Logging;
using Lilith.Core.Extensions;
namespace LilithConsole.Setup;
public static class ProviderSetup
{
public static async Task<LilithCredentials?> RunAsync(TextReader input, TextWriter output, Logger logger, string settingsPath)
{
string? selected = Environment.GetEnvironmentVariable("LILITH_PROVIDER");
if (string.IsNullOrWhiteSpace(selected))
{
output.WriteLine("Choose your provider: 1. Ollama 2. LM Studio (Windows GUI) 0. Exit");
output.Write("Provider [1]: ");
selected = input.ReadLine()?.Trim();
if (selected is null or "0" || selected.Equals("exit", StringComparison.OrdinalIgnoreCase)) return null;
if (selected == "") selected = "1";
}
if (selected is "1" || selected.Equals("Ollama", StringComparison.OrdinalIgnoreCase))
return await new ConsoleSetup(input, output, new OllamaSetupServices(logger), logger, settingsPath).RunAsync();
if (selected != "2" && !selected.Equals("LMStudio", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("Select 1/Ollama or 2/LMStudio.");
string path = settingsPath + ".lmstudio.json";
ConsoleSettings preferences = new();
if (File.Exists(path))
{
try { preferences = JsonSettings.Load<ConsoleSettings>(path, settings => settings.IsValid()); }
catch (JsonException) { output.WriteLine("Saved LM Studio preferences are invalid; choose them again."); }
}
if (!LMStudioSetup.IsInstalled())
{
output.Write("Download and install the LM Studio Windows GUI? [y/N]: ");
string? answer = input.ReadLine()?.Trim();
if (!string.Equals(answer, "y", StringComparison.OrdinalIgnoreCase) && !string.Equals(answer, "yes", StringComparison.OrdinalIgnoreCase)) return null;
await LMStudioSetup.InstallGuiAsync(logger);
}
await LMStudioSetup.EnsureServerAsync(logger);
if (preferences.AgentName is null)
{
output.Write("Agent name [Lilith]: ");
string? name = input.ReadLine()?.Trim();
if (name is null || name.Equals("/exit", StringComparison.OrdinalIgnoreCase)) return null;
if (name.Length > 80 || name.Any(char.IsControl)) throw new ArgumentException("Invalid agent name.");
preferences = preferences with { AgentName = name.Length == 0 ? "Lilith" : name };
}
void Save() => JsonSettings.Save(path, preferences);
Save();
var models = await LMStudioSetup.ListModelsAsync();
if (preferences.Model is null || !models.Any(m => m.Id == preferences.Model))
{
output.WriteLine("Downloaded LM Studio models:");
for (int i = 0; i < models.Count; i++) output.WriteLine($"{i + 1}. {models[i].Name} ({models[i].Id})");
output.Write("Choose a number or enter a catalog ID (e.g. ibm/granite-4-micro); 0 exits: ");
string? model = input.ReadLine()?.Trim();
if (model is null or "0" || model.Equals("exit", StringComparison.OrdinalIgnoreCase)) return null;
if (int.TryParse(model, out int index))
{
if (index < 1 || index > models.Count) throw new ArgumentException("Invalid model number.");
model = models[index - 1].Id;
}
if (model.Length > 200 || !RegexPatterns.ModelIdentifier().IsMatch(model)) throw new ArgumentException("Invalid LM Studio model identifier.");
preferences = preferences with { Model = model };
Save();
if (!models.Any(m => m.Id == model))
{
output.Write($"Download LM Studio model '{model}'? [y/N]: ");
string? answer = input.ReadLine()?.Trim();
if (!string.Equals(answer, "y", StringComparison.OrdinalIgnoreCase) && !string.Equals(answer, "yes", StringComparison.OrdinalIgnoreCase)) return null;
await LMStudioSetup.DownloadModelAsync(model, logger);
}
}
return new LilithCredentials(preferences.Model!,
$"You are {preferences.AgentName}, a helpful AI assistant. Greet the user warmly when the conversation begins.",
preferences.AgentName!, Lilith.Core.Providers.ProviderKind.LMStudio);
}
}