| | | 1 | | using Elsa.Abstractions; |
| | | 2 | | using Elsa.AI.Abstractions.Contracts; |
| | | 3 | | using Elsa.AI.Host.Options; |
| | | 4 | | using Elsa.AI.Host.Permissions; |
| | | 5 | | using JetBrains.Annotations; |
| | | 6 | | using Microsoft.Extensions.Options; |
| | | 7 | | |
| | | 8 | | namespace Elsa.AI.Host.Endpoints.AI.Capabilities; |
| | | 9 | | |
| | | 10 | | [PublicAPI] |
| | | 11 | | public class Endpoint( |
| | | 12 | | IOptions<AIHostOptions> options, |
| | | 13 | | IEnumerable<IAIProvider> providers, |
| | | 14 | | IEnumerable<IAIConversationStore> conversationStores, |
| | | 15 | | IEnumerable<IAIProposalStore> proposalStores) : ElsaEndpointWithoutRequest<Response> |
| | | 16 | | { |
| | | 17 | | public override void Configure() |
| | | 18 | | { |
| | | 19 | | Get("/ai/capabilities"); |
| | | 20 | | ConfigurePermissions(AIPermissions.ViewCapabilities); |
| | | 21 | | } |
| | | 22 | | |
| | | 23 | | public override Task<Response> ExecuteAsync(CancellationToken cancellationToken) |
| | | 24 | | { |
| | | 25 | | var optionsValue = options.Value; |
| | | 26 | | var providerOptions = optionsValue.Providers.ToList(); |
| | | 27 | | var availableProviders = providers.Where(x => providerOptions.IsProviderEnabled(x.Name)).ToList(); |
| | | 28 | | var hasSelectableProvider = HasSelectableProvider(optionsValue.DefaultProviderName, providerOptions, availablePr |
| | | 29 | | var hasDurableConversationStore = conversationStores.Any(x => x is not IAITransientConversationStore); |
| | | 30 | | |
| | | 31 | | return Task.FromResult(new Response( |
| | | 32 | | optionsValue.StreamingEnabled && hasSelectableProvider, |
| | | 33 | | optionsValue.ConversationPersistenceEnabled && hasDurableConversationStore, |
| | | 34 | | optionsValue.ProposalReviewEnabled && proposalStores.Any(), |
| | | 35 | | optionsValue.SupportedAttachmentKinds.ToList(), |
| | | 36 | | optionsValue.Agents.Select(x => new AIAgentCapability(x.Name, x.DisplayName, x.Description)).ToList())); |
| | | 37 | | } |
| | | 38 | | |
| | | 39 | | private static bool HasSelectableProvider(string? providerName, IReadOnlyCollection<AIProviderOptions> providerOptio |
| | | 40 | | { |
| | | 41 | | if (!string.IsNullOrWhiteSpace(providerName)) |
| | | 42 | | { |
| | | 43 | | var configuredProviders = providerOptions.Where(x => x.Enabled).ToList(); |
| | | 44 | | var configuredProvider = configuredProviders.FirstOrDefault(x => string.Equals(x.Name, providerName, StringC |
| | | 45 | | return configuredProvider != null |
| | | 46 | | ? availableProviders.Any(x => string.Equals(x.Name, configuredProvider.Name, StringComparison.OrdinalIgn |
| | | 47 | | string.Equals(x.Name, configuredProvider.Provider, StringComparison.Ordina |
| | | 48 | | : availableProviders.Any(x => string.Equals(x.Name, providerName, StringComparison.OrdinalIgnoreCase)); |
| | | 49 | | } |
| | | 50 | | |
| | | 51 | | return availableProviders.Count == 1; |
| | | 52 | | } |
| | | 53 | | } |
| | | 54 | | |
| | | 55 | | public record Response( |
| | | 56 | | bool Streaming, |
| | | 57 | | bool ConversationPersistence, |
| | | 58 | | bool ProposalReview, |
| | | 59 | | IReadOnlyCollection<string> SupportedAttachmentKinds, |
| | | 60 | | IReadOnlyCollection<AIAgentCapability> Agents); |
| | | 61 | | |
| | 7 | 62 | | public record AIAgentCapability(string Name, string DisplayName, string Description); |