Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,20 @@

namespace CrestApps.Core.AI.Models;

public class AIProviderOptions
{
public Dictionary<string, AIProvider> Providers { get; } = new(StringComparer.OrdinalIgnoreCase);
}

public sealed class AIProvider
{
public IDictionary<string, AIProviderConnectionEntry> Connections { get; set; }
}

/// <summary>
/// Represents a normalized provider connection payload used by AI client factories
/// and providers.
/// </summary>
[JsonConverter(typeof(AIProviderConnectionConverter))]
public sealed class AIProviderConnectionEntry : ReadOnlyDictionary<string, object>
{
public AIProviderConnectionEntry(AIProviderConnectionEntry connection)
: base(connection)
: base(connection)
{
}

public AIProviderConnectionEntry(IDictionary<string, object> dictionary)
: base(dictionary)
: base(dictionary)
{
}
}
1 change: 1 addition & 0 deletions src/CrestApps.Core.Docs/docs/changelog/v1.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ description: Initial standalone release notes for the CrestApps.Core repository.
- merges appsettings-backed and UI-managed AI provider connections and deployments through runtime catalogs, so MVC selectors and AI resolution stay current without rebuilding options or restarting the app
- exposes merged AI connection and deployment views through `INamedSourceCatalog<T>` registrations, adds generic `Add*DocumentCatalog<TModel, TIndex, T>()` helpers for custom catalog registration, keeps deterministic name conflict handling so UI-managed records override conflicting appsettings entries, and standardizes settings so connections and deployments are configured separately
- documents the default AI configuration sections (`CrestApps:AI:Connections` and `CrestApps:AI:Deployments`), tightens the quick-start path around Chat Interactions, and refreshes the docs navigation and landing page for faster onboarding
- keeps the MVC sample focused on the recommended standalone AI configuration layout by default, using `CrestApps:AI:Connections` and `CrestApps:AI:Deployments` instead of provider-grouped sample settings
- adds Debug-level diagnostics in `ConfigurationAIDeploymentCatalog` so hosts can trace which configuration sections were evaluated and how standalone deployments were parsed
- treats `CrestApps:AI:Deployments` as shared deployment metadata for all providers, not only providers with contained-connection support, so hosts can keep credentials in `Connections` while still declaring deployment names and types in appsettings
- evaluates every configured AI connection and deployment section when importing appsettings records, including provider-grouped connection sections and deployment entries that reference shared `ConnectionName` values
Expand Down
4 changes: 3 additions & 1 deletion src/CrestApps.Core.Docs/docs/core/data-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,9 @@ The configuration sources read from `appsettings.json` using the sections config
| Options class | Default sections |
|--------------|------------------|
| `AIDeploymentCatalogOptions` | `CrestApps:AI:Deployments` |
| `AIProviderConnectionCatalogOptions` | `CrestApps:AI:Connections` (connection sections) and `CrestApps:AI:Providers` (provider sections) |
| `AIProviderConnectionCatalogOptions` | `CrestApps:AI:Connections` (connection sections) plus provider sections under `CrestApps:AI:Providers` |

Hosts can override those lists to focus only on the standalone `Connections` array or to append additional provider-grouped sections for compatibility scenarios.

When a persistence package (YesSql or EntityCore) is added, it registers an additional **writable** DB binding source at Order 0, so database entries take priority over `appsettings.json` entries and all write operations go to the database.

Expand Down
8 changes: 4 additions & 4 deletions src/CrestApps.Core.Docs/docs/core/mvc-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,13 @@ builder.Services.AddCrestAppsCore(crestApps => crestApps
);
```

The MVC sample still binds static provider metadata from `CrestApps:AI:Providers`, but mutable AI connections and deployments now come from first-class merged catalogs instead of rebuilding `AIProviderOptions` after admin edits.
The MVC sample is configured to use the recommended standalone settings by default: `CrestApps:AI:Connections` for shared connection records and `CrestApps:AI:Deployments` for deployment metadata.

`AddCoreAIAzureOpenAI()` also registers the `AzureSpeech` deployment provider used by MVC speech-to-text and text-to-speech selectors, so Azure AI Services deployments from `CrestApps:AI:Deployments` participate in the same merged deployment catalog as UI-managed deployments.

The MVC runtime now reads connection definitions from `CrestApps:AI:Connections`, client-grouped connections under `CrestApps:Providers:{ClientName}:Connections:{ConnectionName}` or `CrestApps:AI:Providers:{ClientName}:Connections:{ConnectionName}`, and UI-managed connection records from the store into one merged connection catalog. The deployment catalog layers together UI-managed typed deployments and `CrestApps:AI:Deployments` entries from every configured section. Those deployment entries can either reference a shared `ConnectionName` or carry contained-connection settings directly. That means dropdowns, deployment resolution, and connection resolution all see the same unified set without an app restart.
The MVC runtime reads connection definitions from `CrestApps:AI:Connections` and UI-managed connection records from the store into one merged connection catalog. The deployment catalog layers together UI-managed typed deployments and `CrestApps:AI:Deployments` entries from every configured section. Those deployment entries can either reference a shared `ConnectionName` or carry contained-connection settings directly. That means dropdowns, deployment resolution, and connection resolution all see the same unified set without an app restart.

Both merged catalogs also expose configurable section lists through `AIProviderConnectionCatalogOptions` and `AIDeploymentCatalogOptions`, so a host can append additional configuration paths without replacing the MVC/UI store integration. By default, connection discovery reads `CrestApps:AI:Connections`, `CrestApps:Providers`, and `CrestApps:AI:Providers`, while deployment discovery reads `CrestApps:AI:Deployments`.
Both merged catalogs also expose configurable section lists through `AIProviderConnectionCatalogOptions` and `AIDeploymentCatalogOptions`, so a host can append additional configuration paths without replacing the MVC/UI store integration. The MVC sample intentionally keeps its default connection discovery focused on `CrestApps:AI:Connections` so the local sample demonstrates the recommended standalone configuration layout, while deployment discovery reads `CrestApps:AI:Deployments`.

```json
{
Expand All @@ -177,7 +177,7 @@ Both merged catalogs also expose configurable section lists through `AIProviderC
}
```

Client-grouped connection settings under `CrestApps:Providers:{ClientName}:Connections:{ConnectionName}` and `CrestApps:AI:Providers:{ClientName}:Connections:{ConnectionName}` still work too. The merged connection catalog keeps those client-defined records and the `CrestApps:AI:Connections` array visible alongside UI-managed MVC connections, and the MVC AI Deployment editor reads that catalog directly when it builds the connection dropdown. Connection settings only describe the AI connection itself; deployment names and types belong in `CrestApps:AI:Deployments` or in the UI deployment editor, and config deployments can optionally point back to a shared connection by setting `ConnectionName`.
The framework can still be configured to read additional provider-grouped connection sections when a host explicitly opts into them, but the MVC sample does not enable those paths by default. Connection settings only describe the AI connection itself; deployment names and types belong in `CrestApps:AI:Deployments` or in the UI deployment editor, and config deployments can optionally point back to a shared connection by setting `ConnectionName`.


```json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ public AzureAIInferenceCompletionClient(
ILoggerFactory loggerFactory,
IDistributedCache distributedCache,
IServiceProvider serviceProvider,
IOptions<AIProviderOptions> providerOptions,
IEnumerable<IAICompletionServiceHandler> handlers,
IOptions<DefaultAIOptions> defaultOptions,
ITemplateService aiTemplateService,
IAIDeploymentManager deploymentManager)
: base(AzureAIInferenceConstants.ClientName, aIClientFactory, distributedCache, loggerFactory, serviceProvider, providerOptions.Value, defaultOptions.Value, handlers, aiTemplateService, deploymentManager)
: base(AzureAIInferenceConstants.ClientName, aIClientFactory, distributedCache, loggerFactory, serviceProvider, defaultOptions.Value, handlers, aiTemplateService, deploymentManager)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ public OllamaCompletionClient(
ILoggerFactory loggerFactory,
IDistributedCache distributedCache,
IServiceProvider serviceProvider,
IOptions<AIProviderOptions> providerOptions,
IEnumerable<IAICompletionServiceHandler> handlers,
IOptions<DefaultAIOptions> defaultOptions,
ITemplateService aiTemplateService,
IAIDeploymentManager deploymentManager)
: base(OllamaConstants.ClientName, aIClientFactory, distributedCache, loggerFactory, serviceProvider, providerOptions.Value, defaultOptions.Value, handlers, aiTemplateService, deploymentManager)
: base(OllamaConstants.ClientName, aIClientFactory, distributedCache, loggerFactory, serviceProvider, defaultOptions.Value, handlers, aiTemplateService, deploymentManager)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public sealed class AzureOpenAICompletionClient : AICompletionServiceBase, IAICo
private readonly ILogger _logger;

public AzureOpenAICompletionClient(
IOptions<AIProviderOptions> providerOptions,
IServiceProvider serviceProvider,
ILoggerFactory loggerFactory,
IEnumerable<IAICompletionServiceHandler> completionServiceHandlers,
Expand All @@ -43,7 +42,7 @@ public AzureOpenAICompletionClient(
IAIProviderConnectionStore connectionStore,
IDataProtectionProvider dataProtectionProvider,
IOptionsSnapshot<AzureClientOptions> azureClientOptions)
: base(providerOptions.Value, aiTemplateService, deploymentManager)
: base(aiTemplateService, deploymentManager)
{
_serviceProvider = serviceProvider;
_loggerFactory = loggerFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ public OpenAICompletionClient(
ILoggerFactory loggerFactory,
IDistributedCache distributedCache,
IServiceProvider serviceProvider,
IOptions<AIProviderOptions> providerOptions,
IEnumerable<IAICompletionServiceHandler> handlers,
IOptions<DefaultAIOptions> defaultOptions,
ITemplateService aiTemplateService,
IAIDeploymentManager deploymentManager)
: base(OpenAIConstants.ClientName, aIClientFactory, distributedCache, loggerFactory, serviceProvider, providerOptions.Value, defaultOptions.Value, handlers, aiTemplateService, deploymentManager)
: base(OpenAIConstants.ClientName, aIClientFactory, distributedCache, loggerFactory, serviceProvider, defaultOptions.Value, handlers, aiTemplateService, deploymentManager)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ public static IServiceCollection AddCoreAIServices(this IServiceCollection servi

services.TryAddEnumerable(ServiceDescriptor.Singleton<IAIProfileTemplateProvider, AIProfileFileSystemTemplateProvider>());

services.TryAddEnumerable(ServiceDescriptor.Transient<IPostConfigureOptions<AIProviderOptions>, ConfigurationAIProviderConnectionsOptionsConfiguration>());
services.TryAddScoped<IAICompletionService, DefaultAICompletionService>();
services.TryAddScoped<IAICompletionContextBuilder, DefaultAICompletionContextBuilder>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,24 @@ namespace CrestApps.Core.AI.Services;

public abstract class AICompletionServiceBase
{
protected readonly AIProviderOptions ProviderOptions;
protected readonly ITemplateService AITemplateService;
protected readonly IAIDeploymentManager DeploymentResolver;

protected AICompletionServiceBase(
AIProviderOptions providerOptions,
ITemplateService aiTemplateService)
protected AICompletionServiceBase(ITemplateService aiTemplateService)
{
ProviderOptions = providerOptions;
AITemplateService = aiTemplateService;
}

protected AICompletionServiceBase(
AIProviderOptions providerOptions,
ITemplateService aiTemplateService,
IAIDeploymentManager deploymentResolver)
: this(providerOptions, aiTemplateService)
: this(aiTemplateService)
{
DeploymentResolver = deploymentResolver;
}

/// <summary>
/// Resolves a deployment using the <see cref="IAIDeploymentManager"/>
/// with fallback to legacy connection entry values when they are still present.
/// Resolves a deployment using the <see cref="IAIDeploymentManager"/>.
/// </summary>
protected virtual async ValueTask<AIDeployment> ResolveDeploymentAsync(
AIDeploymentType type,
Expand Down

This file was deleted.

Loading
Loading