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 @@ -11,6 +11,11 @@ public interface IAIChatSessionAnalyticsRecorder
/// <summary>
/// Records end-of-session analytics for the specified chat session.
/// </summary>
/// <param name="profile">The AI profile associated with the session.</param>
/// <param name="session">The chat session to record analytics for.</param>
/// <param name="prompts">The prompts exchanged during the session.</param>
/// <param name="isResolved">Whether the session was resolved.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task RecordSessionEndedAsync(
AIProfile profile,
AIChatSession session,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public interface IAIChatSessionConversionGoalRecorder
/// <summary>
/// Records evaluated conversion-goal results for the specified chat session.
/// </summary>
/// <param name="profile">The AI profile associated with the session.</param>
/// <param name="session">The chat session to record goals for.</param>
/// <param name="goalResults">The evaluated conversion-goal results.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task RecordConversionGoalsAsync(
AIProfile profile,
AIChatSession session,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public interface IAIChatSessionExtractedDataRecorder
/// Records the current extracted-data snapshot for the specified chat session.
/// Implementations should upsert an existing record when one already exists.
/// </summary>
/// <param name="profile">The AI profile associated with the session.</param>
/// <param name="session">The chat session to record extracted data for.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task RecordExtractedDataAsync(
AIProfile profile,
AIChatSession session,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public interface IAICompletionClient
/// </summary>
/// <param name="messages">A collection of messages that are part of the chat conversation.</param>
/// <param name="context">The context that may provide additional parameters or configurations for the chat request.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation, with the completion response as the result.</returns>
Task<ChatResponse> CompleteAsync(IEnumerable<ChatMessage> messages, AICompletionContext context, CancellationToken cancellationToken = default);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public interface IAICompletionService
/// <param name="deployment">The deployment that identifies which AI client and model to use.</param>
/// <param name="messages">A collection of messages that are part of the chat conversation.</param>
/// <param name="context">The context that may provide additional parameters or configurations for the chat request.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A task representing the asynchronous operation, with the completion response as the result.</returns>
Task<ChatResponse> CompleteAsync(AIDeployment deployment, IEnumerable<ChatMessage> messages, AICompletionContext context, CancellationToken cancellationToken = default);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public interface IAIDeploymentManager : INamedSourceCatalogManager<AIDeployment>
/// Returns the deployment marked as IsDefault for that type on the client,
/// or the first deployment supporting that type on the client if none is marked as default.
/// </summary>
/// <param name="clientName">The name of the client to resolve the default deployment for.</param>
/// <param name="type">The deployment type to filter by.</param>
ValueTask<AIDeployment> GetDefaultAsync(string clientName, AIDeploymentType type);

/// <summary>
Expand All @@ -44,11 +46,16 @@ public interface IAIDeploymentManager : INamedSourceCatalogManager<AIDeployment>
/// 3. Falls back to the first deployment supporting the requested type within the current scope.
/// Returns <see langword="null"/> if no deployment can be resolved.
/// </summary>
/// <param name="type">The deployment type to resolve.</param>
/// <param name="deploymentName">The optional deployment name to look up directly.</param>
/// <param name="clientName">The optional client name to scope the resolution.</param>
ValueTask<AIDeployment> ResolveOrDefaultAsync(AIDeploymentType type, string deploymentName = null, string clientName = null);

/// <summary>
/// Gets all deployments of a given type, optionally filtered by client.
/// Results are suitable for dropdown population, grouped by connection.
/// </summary>
/// <param name="type">The deployment type to filter by.</param>
/// <param name="clientName">The optional client name to further filter results.</param>
ValueTask<IEnumerable<AIDeployment>> GetAllByTypeAsync(AIDeploymentType type, string clientName = null);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ public interface IOrchestratorAvailabilityProvider
/// <summary>
/// Gets the current availability state for the orchestrator.
/// </summary>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task<OrchestratorAvailability> GetAvailabilityAsync(CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ internal AIToolBuilder(AIToolDefinitionEntry entry)
{
_entry = entry;
}

/// <summary>
/// Sets the display title for this tool.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public interface IToolRegistry
/// <summary>
/// Gets all tool entries scoped to the given completion context.
/// </summary>
/// <param name="context">The completion context that scopes available tools.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task<IReadOnlyList<ToolRegistryEntry>> GetAllAsync(
AICompletionContext context,
CancellationToken cancellationToken = default);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ public interface IDataSourceDocumentReader
/// <summary>
/// Reads documents from the specified source index in batches.
/// </summary>
/// <param name="indexProfile">The index profile describing the source index.</param>
/// <param name="keyFieldName">The name of the field used as the document key.</param>
/// <param name="titleFieldName">The name of the field containing the document title.</param>
/// <param name="contentFieldName">The name of the field containing the document content.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
IAsyncEnumerable<KeyValuePair<string, SourceDocument>> ReadAsync(
IIndexProfileInfo indexProfile,
string keyFieldName,
Expand All @@ -20,6 +25,12 @@ IAsyncEnumerable<KeyValuePair<string, SourceDocument>> ReadAsync(
/// <summary>
/// Reads specific documents from the source index by their native document IDs.
/// </summary>
/// <param name="indexProfile">The index profile describing the source index.</param>
/// <param name="documentIds">The native document IDs to retrieve.</param>
/// <param name="keyFieldName">The name of the field used as the document key.</param>
/// <param name="titleFieldName">The name of the field containing the document title.</param>
/// <param name="contentFieldName">The name of the field containing the document content.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
IAsyncEnumerable<KeyValuePair<string, SourceDocument>> ReadByIdsAsync(
IIndexProfileInfo indexProfile,
IEnumerable<string> documentIds,
Expand Down
2 changes: 1 addition & 1 deletion src/CrestApps.Core.Docs/docs/changelog/v1.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ description: Initial standalone release notes for the CrestApps.Core repository.
- adds Chat History page listing previous sessions per AI Profile sorted by creation date, with resume, delete, delete-all, and new-chat actions
- adds Test page for Utility and Agent AI Profiles providing a single-prompt/single-response streamed UI
- renames the "Chat" button to "New Chat" on the AI Profile list and adds "Chat History" and "Test" buttons for applicable profile types
- splits document ingestion, document-processing services, document endpoints, and document RAG into the dedicated `CrestApps.Core.AI.Documents` package, renames the format-specific helpers to `CrestApps.Core.AI.Documents.OpenXml` and `CrestApps.Core.AI.Documents.Pdf`, removes the data-ingestion dependency from `CrestApps.Core.AI`, and persists uploaded files through `IDocumentFileStore` with GUID-based stored file names plus database-backed stored file metadata so hosts can redirect or clean up physical files reliably
- splits document ingestion, document-processing services, document endpoints, and document RAG into the dedicated `CrestApps.Core.AI.Documents` package, renames the format-specific helpers to `CrestApps.Core.AI.Documents.OpenXml` and `CrestApps.Core.AI.Documents.Pdf`, removes the data-ingestion dependency from `CrestApps.Core.AI`, persists uploaded files through `IDocumentFileStore` with GUID-based stored file names plus database-backed stored file metadata so hosts can redirect or clean up physical files reliably, and now registers a default filesystem-backed `IDocumentFileStore` from `AddCoreAIDocumentProcessing()` with `DocumentFileSystemFileStoreOptions` for base-path overrides
15 changes: 13 additions & 2 deletions src/CrestApps.Core.Docs/docs/core/ai-documents.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,24 @@ The document processing system handles this full pipeline from upload to retriev
| `ITabularBatchResultCache` | `CrestApps.Core.AI.Documents` | Caches tabular query results |
| `IngestionDocumentReader` | `CrestApps.Core.AI.Documents` | Abstract base for format-specific file readers |

Hosts can replace `IDocumentFileStore` to change where uploaded files are written:
`AddCoreAIDocumentProcessing()` registers a default `FileSystemFileStore` automatically. By default it stores uploaded files under `App_Data\Documents`, and each upload gets a new GUID-based stored file name while `AIDocument.FileName` keeps the original user upload name.

Configure a different local base path:

```csharp
builder.Services.Configure<DocumentFileSystemFileStoreOptions>(options =>
{
options.BasePath = "App_Data/CustomDocuments";
});
```

Hosts can replace `IDocumentFileStore` entirely to change where uploaded files are written:

```csharp
builder.Services.AddSingleton<IDocumentFileStore, AzureBlobDocumentFileStore>();
```

The default MVC host stores uploads on the local file system with a new GUID-based stored file name for each upload. `AIDocument.FileName` keeps the original user upload name, while `AIDocument.StoredFileName` and `AIDocument.StoredFilePath` preserve the backing file-store location.
`IDocumentFileStore` extends the general `IFileStore` abstraction. `AIDocument.StoredFileName` and `AIDocument.StoredFilePath` preserve the backing file-store location so hosts can trace and delete the physical file later.

## Document Processing Pipeline

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public override string Description
}

public override JsonElement JsonSchema => _jsonSchema;

public override IReadOnlyDictionary<string, object> AdditionalProperties { get; } = new Dictionary<string, object>()
{
["Strict"] = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public override string Description
}

public override JsonElement JsonSchema => _jsonSchema;

public override IReadOnlyDictionary<string, object> AdditionalProperties { get; } = new Dictionary<string, object>()
{
["Strict"] = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public override string Description
}

public override JsonElement JsonSchema => _jsonSchema;

public override IReadOnlyDictionary<string, object> AdditionalProperties { get; } = new Dictionary<string, object>()
{
["Strict"] = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ namespace CrestApps.Core.AI.A2A.Services;
internal sealed class DefaultA2AAgentCardCacheService : IA2AAgentCardCacheService
{
private static readonly TimeSpan _cacheDuration = TimeSpan.FromMinutes(15);

private readonly IMemoryCache _memoryCache;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger _logger;

public DefaultA2AAgentCardCacheService(IMemoryCache memoryCache, IHttpClientFactory httpClientFactory, IHttpContextAccessor httpContextAccessor, ILogger<DefaultA2AAgentCardCacheService> logger)
{
_memoryCache = memoryCache;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ namespace CrestApps.Core.AI.A2A.Services;
internal sealed class DefaultA2AConnectionAuthService : IA2AConnectionAuthService
{
private const int ExpirationBufferSeconds = 60;

private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IMemoryCache _cache;
private readonly TimeProvider _timeProvider;
private readonly ILogger _logger;

public DefaultA2AConnectionAuthService(IDataProtectionProvider dataProtectionProvider, IHttpClientFactory httpClientFactory, IMemoryCache cache, TimeProvider timeProvider, ILogger<DefaultA2AConnectionAuthService> logger)
{
_dataProtectionProvider = dataProtectionProvider;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Azure.Search.Documents.Indexes;
using CrestApps.Core.AI.AISearch.Services;
using CrestApps.Core.AI.Documents.Indexing;
using CrestApps.Core.AI.Documents;
using CrestApps.Core.AI.Indexing;
using CrestApps.Core.AI.Memory;
using CrestApps.Core.Azure.AISearch;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace CrestApps.Core.AI.Chat.Handlers;
internal sealed class ChatInteractionCompletionContextBuilderHandler : IAICompletionContextBuilderHandler
{
private readonly ITemplateService _aiTemplateService;

public ChatInteractionCompletionContextBuilderHandler(ITemplateService aiTemplateService)
{
_aiTemplateService = aiTemplateService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public sealed class DataSourceChatInteractionSettingsHandler : IChatInteractionS
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger _logger;

public DataSourceChatInteractionSettingsHandler(IServiceProvider serviceProvider, ILogger<DataSourceChatInteractionSettingsHandler> logger)
{
_serviceProvider = serviceProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public sealed class ExtractedDataOrchestrationHandler : IOrchestrationContextBui
{
private readonly ITemplateService _templateService;
private readonly ILogger<ExtractedDataOrchestrationHandler> _logger;

public ExtractedDataOrchestrationHandler(ITemplateService templateService, ILogger<ExtractedDataOrchestrationHandler> logger)
{
_templateService = templateService;
Expand Down
Loading
Loading