current main is now successfully merged into branch

This commit is contained in:
Paul Koudelka committed 2026-05-27 20:02:43 +02:00
1 parent 00b6c98f3b
commit ea87d79ca9
32 files changed
+607 -478

No files matched your search

@@ -1,15 +1,14 @@
using AIStudio.Tools.Databases.Qdrant;
using AIStudio.Tools.Rust;
using AIStudio.Tools.Services;
using AIStudio.Tools.Databases.VectorStore;
namespace AIStudio.Tools.Databases;
public sealed class EmbeddingStoreProvider(RustService rustService, ILoggerFactory loggerFactory) : IDisposable
public sealed partial class DatabaseClientProvider(RustService rustService, ILoggerFactory loggerFactory) : IDisposable
{
private readonly Dictionary<DatabaseRole, EmbeddingStore> clients = new();
private readonly Dictionary<DatabaseRole, DatabaseClient> clients = new();
private readonly Dictionary<DatabaseRole, SemaphoreSlim> locks = new();
private readonly Lock locksLock = new();
private readonly ILogger<EmbeddingStoreProvider> logger = loggerFactory.CreateLogger<EmbeddingStoreProvider>();
private readonly ILogger<DatabaseClientProvider> logger = loggerFactory.CreateLogger<DatabaseClientProvider>();
private readonly ILogger<DatabaseClient> databaseClientLogger = loggerFactory.CreateLogger<DatabaseClient>();
public async Task<DatabaseClient> GetClientAsync(DatabaseRole databaseRole, CancellationToken cancellationToken = default)
@@ -45,6 +44,18 @@ public sealed class EmbeddingStoreProvider(RustService rustService, ILoggerFacto
}
}
public async Task<IVectorStoreClient> GetVectorStoreAsync(CancellationToken cancellationToken = default)
{
var client = await this.GetClientAsync(DatabaseRole.VECTOR_STORE, cancellationToken);
if (client is IVectorStoreClient vectorStore)
return vectorStore;
return new NoVectorStoreClient(
client.Name,
"The configured database client does not support vector store operations.",
client.Status);
}
private DatabaseClient CacheIfAvailable(DatabaseRole databaseRole, DatabaseClient client)
{
if (!client.IsAvailable)
@@ -84,79 +95,6 @@ public sealed class EmbeddingStoreProvider(RustService rustService, ILoggerFacto
_ => new NoDatabaseClient(databaseRole.ToString(), "The requested database role is not supported.")
};
private async Task<DatabaseClient> CreateQdrantClientAsync(CancellationToken cancellationToken)
{
var qdrantInfo = await rustService.GetQdrantInfo(cancellationToken);
if (qdrantInfo.Status is QdrantStatus.STARTING)
{
return this.CreateNoDatabaseClient(
"Qdrant",
"Qdrant is starting. Details will appear shortly.",
DatabaseClientStatus.STARTING);
}
if (!qdrantInfo.IsAvailable || qdrantInfo.Status is QdrantStatus.UNAVAILABLE)
{
var reason = qdrantInfo.UnavailableReason ?? "unknown";
this.logger.LogWarning("Qdrant is not available. Starting without vector database. Reason: '{Reason}'.", reason);
return this.CreateNoDatabaseClient("Qdrant", qdrantInfo.UnavailableReason, DatabaseClientStatus.UNAVAILABLE);
}
if (!HasValidQdrantConnectionInfo(qdrantInfo, out var invalidReason))
return this.CreateNoDatabaseClient("Qdrant", invalidReason, DatabaseClientStatus.UNAVAILABLE);
var client = new QdrantClientImplementation("Qdrant", qdrantInfo.Path, qdrantInfo.PortHttp, qdrantInfo.PortGrpc, qdrantInfo.Fingerprint, qdrantInfo.ApiToken);
client.SetLogger(this.databaseClientLogger);
try
{
await client.CheckAvailabilityAsync();
return client;
}
catch (Exception e)
{
client.Dispose();
this.logger.LogWarning(e, "Qdrant reported as available by Rust, but the health check failed.");
return this.CreateNoDatabaseClient("Qdrant", e.Message, DatabaseClientStatus.STARTING);
}
}
private static bool HasValidQdrantConnectionInfo(QdrantInfo qdrantInfo, out string invalidReason)
{
if (qdrantInfo.Path == string.Empty)
{
invalidReason = "Failed to get the Qdrant path from Rust.";
return false;
}
if (qdrantInfo.PortHttp == 0)
{
invalidReason = "Failed to get the Qdrant HTTP port from Rust.";
return false;
}
if (qdrantInfo.PortGrpc == 0)
{
invalidReason = "Failed to get the Qdrant gRPC port from Rust.";
return false;
}
if (qdrantInfo.Fingerprint == string.Empty)
{
invalidReason = "Failed to get the Qdrant fingerprint from Rust.";
return false;
}
if (qdrantInfo.ApiToken == string.Empty)
{
invalidReason = "Failed to get the Qdrant API token from Rust.";
return false;
}
invalidReason = string.Empty;
return true;
}
private NoDatabaseClient CreateNoDatabaseClient(string name, string? unavailableReason, DatabaseClientStatus status)
{
var client = new NoDatabaseClient(name, unavailableReason, status);