using MAF1.PluginContract; using MAF1.Utils; using Microsoft.Extensions.Configuration; namespace MAF1.Plugins; public sealed class CredentialRecord { public string Id { get; init; } = ""; public string Name { get; init; } = ""; public string Type { get; init; } = ""; public string Endpoint { get; init; } = ""; public string ApiKey { get; init; } = ""; public string Model { get; init; } = ""; public Dictionary Extra { get; init; } = new(StringComparer.OrdinalIgnoreCase); } public sealed class CredentialPublicView { public string Id { get; init; } = ""; public string Name { get; init; } = ""; public string Type { get; init; } = ""; public string Endpoint { get; init; } = ""; public string Model { get; init; } = ""; public bool HasApiKey { get; init; } } public sealed class CredentialStore { private readonly IConfiguration _config; private readonly Dictionary _named = new(StringComparer.OrdinalIgnoreCase); public CredentialStore(IConfiguration config) { _config = config; LlmOptions llm = AgentFactory.Load(config); _named["llm-default"] = new CredentialRecord { Id = "llm-default", Name = "系统默认模型", Type = "openai-compatible", Endpoint = llm.Endpoint, ApiKey = llm.ApiKey, Model = llm.Model, }; IConfigurationSection section = config.GetSection("Credentials"); foreach (IConfigurationSection child in section.GetChildren()) { string id = child.Key; string type = child["type"] ?? "openai-compatible"; bool useLlm = string.Equals(child["source"], "llm-section", StringComparison.OrdinalIgnoreCase) || child.GetValue("useLlmSection", false); CredentialRecord fallback = _named.GetValueOrDefault("llm-default")!; _named[id] = new CredentialRecord { Id = id, Name = child["name"] ?? id, Type = type, Endpoint = First(child["endpoint"], useLlm ? fallback.Endpoint : null), ApiKey = First(child["apiKey"], useLlm ? fallback.ApiKey : null), Model = First(child["model"], useLlm ? fallback.Model : null), }; } } public IReadOnlyList ListPublic() => _named.Values .OrderBy(item => item.Id, StringComparer.OrdinalIgnoreCase) .Select(ToPublic) .ToList(); public CredentialRecord Resolve(string? id) { if (string.IsNullOrWhiteSpace(id)) { return _named["llm-default"]; } if (_named.TryGetValue(id, out CredentialRecord? record)) { return record; } throw new InvalidOperationException($"找不到凭据 `{id}`。请在 appsettings.json 的 Credentials 中配置,或改用 llm-default。"); } public PluginCredentialPayload ToPayload(CredentialRecord record) => new() { Id = record.Id, Type = record.Type, Endpoint = record.Endpoint, ApiKey = record.ApiKey, Model = record.Model, Extra = record.Extra, }; public static CredentialPublicView ToPublic(CredentialRecord record) => new() { Id = record.Id, Name = record.Name, Type = record.Type, Endpoint = MaskEndpoint(record.Endpoint), Model = record.Model, HasApiKey = !string.IsNullOrWhiteSpace(record.ApiKey), }; private static string MaskEndpoint(string endpoint) => endpoint; private static string First(params string?[] values) => values.FirstOrDefault(v => !string.IsNullOrWhiteSpace(v)) ?? ""; }