From da76be282be0b8934f0037572470b1a230574011 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Wed, 29 Jan 2025 07:28:43 +0100 Subject: [PATCH] Added a ERI ((E)xternal (R)etrieval (I)nterface) client for communication with any ERI server. --- app/ERIClientV1/Client.Generated.cs | 1277 ----------------- app/ERIClientV1/ERIClientV1.csproj | 10 - app/MindWork AI Studio.sln | 9 - .../SettingsPanelDataSources.razor.cs | 3 +- .../MindWork AI Studio.csproj | 4 - .../Settings/DataModel/DataSourceERI_V1.cs | 5 +- .../Settings/IERIDataSource.cs | 2 +- .../Tools/AuthMethodsV1Extensions.cs | 2 +- .../Tools/ERIClient/APIResponse.cs | 19 + .../Tools/ERIClient/DataModel/AuthField.cs | 13 + .../ERIClient/DataModel/AuthFieldMapping.cs | 8 + .../Tools/ERIClient/DataModel/AuthMethod.cs | 9 + .../Tools/ERIClient/DataModel/AuthResponse.cs | 9 + .../Tools/ERIClient/DataModel/AuthScheme.cs | 9 + .../Tools/ERIClient/DataModel/ChatThread.cs | 7 + .../Tools/ERIClient/DataModel/ContentBlock.cs | 12 + .../Tools/ERIClient/DataModel/ContentType.cs | 16 + .../Tools/ERIClient/DataModel/Context.cs | 27 + .../ERIClient/DataModel/DataSourceInfo.cs | 9 + .../ERIClient/DataModel/EmbeddingInfo.cs | 20 + .../Tools/ERIClient/DataModel/ProviderType.cs | 22 + .../ERIClient/DataModel/RetrievalInfo.cs | 20 + .../ERIClient/DataModel/RetrievalRequest.cs | 25 + .../Tools/ERIClient/DataModel/Role.cs | 15 + .../DataModel/SecurityRequirements.cs | 7 + .../Tools/ERIClient/ERIClientBase.cs | 36 + .../Tools/ERIClient/ERIClientFactory.cs | 14 + .../Tools/ERIClient/ERIClientV1.cs | 344 +++++ .../Tools/ERIClient/IERIClient.cs | 62 + .../Tools/Validation/DataSourceValidation.cs | 2 +- .../wwwroot/changelog/v0.9.28.md | 1 + 31 files changed, 711 insertions(+), 1307 deletions(-) delete mode 100644 app/ERIClientV1/Client.Generated.cs delete mode 100644 app/ERIClientV1/ERIClientV1.csproj create mode 100644 app/MindWork AI Studio/Tools/ERIClient/APIResponse.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthField.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthFieldMapping.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthMethod.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthResponse.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthScheme.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/ChatThread.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/ContentBlock.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/ContentType.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/Context.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/DataSourceInfo.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/EmbeddingInfo.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/ProviderType.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/RetrievalInfo.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/RetrievalRequest.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/Role.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/DataModel/SecurityRequirements.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/ERIClientBase.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/ERIClientFactory.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/ERIClientV1.cs create mode 100644 app/MindWork AI Studio/Tools/ERIClient/IERIClient.cs diff --git a/app/ERIClientV1/Client.Generated.cs b/app/ERIClientV1/Client.Generated.cs deleted file mode 100644 index 96698e1..0000000 --- a/app/ERIClientV1/Client.Generated.cs +++ /dev/null @@ -1,1277 +0,0 @@ -//---------------------- -// -// Generated using the NSwag toolchain v14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org) -// -//---------------------- - -#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." -#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." -#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' -#pragma warning disable 612 // Disable "CS0612 '...' is obsolete" -#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... -#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." -#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'" -#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant" -#pragma warning disable 8603 // Disable "CS8603 Possible null reference return" -#pragma warning disable 8604 // Disable "CS8604 Possible null reference argument for parameter" -#pragma warning disable 8625 // Disable "CS8625 Cannot convert null literal to non-nullable reference type" - -namespace ERI_Client.V1 -{ - using System = global::System; - - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Client - { - private System.Net.Http.HttpClient _httpClient; - private static System.Lazy _settings = new System.Lazy(CreateSerializerSettings, true); - - public Client(System.Net.Http.HttpClient httpClient) - { - _httpClient = httpClient; - } - - private static System.Text.Json.JsonSerializerOptions CreateSerializerSettings() - { - var settings = new System.Text.Json.JsonSerializerOptions(); - UpdateJsonSerializerSettings(settings); - return settings; - } - - protected System.Text.Json.JsonSerializerOptions JsonSerializerSettings { get { return _settings.Value; } } - - static partial void UpdateJsonSerializerSettings(System.Text.Json.JsonSerializerOptions settings); - - partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); - partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); - partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); - - /// - /// Get the available authentication methods. - /// - /// OK - /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetAuthMethodsAsync() - { - return GetAuthMethodsAsync(System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get the available authentication methods. - /// - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetAuthMethodsAsync(System.Threading.CancellationToken cancellationToken) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - - // Operation Path: "auth/methods" - urlBuilder_.Append("auth/methods"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Authenticate with the data source to get a token for further requests. - /// - /// OK - /// A server side error occurred. - public virtual System.Threading.Tasks.Task AuthenticateAsync(AuthMethod authMethod) - { - return AuthenticateAsync(authMethod, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Authenticate with the data source to get a token for further requests. - /// - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task AuthenticateAsync(AuthMethod authMethod, System.Threading.CancellationToken cancellationToken) - { - if (authMethod == null) - throw new System.ArgumentNullException("authMethod"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "application/json"); - request_.Method = new System.Net.Http.HttpMethod("POST"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - - // Operation Path: "auth" - urlBuilder_.Append("auth"); - urlBuilder_.Append('?'); - urlBuilder_.Append(System.Uri.EscapeDataString("authMethod")).Append('=').Append(System.Uri.EscapeDataString(ConvertToString(authMethod, System.Globalization.CultureInfo.InvariantCulture))).Append('&'); - urlBuilder_.Length--; - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Get information about the data source. - /// - /// OK - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetDataSourceInfoAsync() - { - return GetDataSourceInfoAsync(System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get information about the data source. - /// - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetDataSourceInfoAsync(System.Threading.CancellationToken cancellationToken) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - - // Operation Path: "dataSource" - urlBuilder_.Append("dataSource"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Get information about the used embedding(s). - /// - /// OK - /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetEmbeddingInfoAsync() - { - return GetEmbeddingInfoAsync(System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get information about the used embedding(s). - /// - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetEmbeddingInfoAsync(System.Threading.CancellationToken cancellationToken) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - - // Operation Path: "embedding/info" - urlBuilder_.Append("embedding/info"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Get information about the retrieval processes implemented by this data source. - /// - /// OK - /// A server side error occurred. - public virtual System.Threading.Tasks.Task> GetRetrievalInfoAsync() - { - return GetRetrievalInfoAsync(System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get information about the retrieval processes implemented by this data source. - /// - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> GetRetrievalInfoAsync(System.Threading.CancellationToken cancellationToken) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - - // Operation Path: "retrieval/info" - urlBuilder_.Append("retrieval/info"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Retrieve information from the data source. - /// - /// OK - /// A server side error occurred. - public virtual System.Threading.Tasks.Task> RetrieveAsync(RetrievalRequest body) - { - return RetrieveAsync(body, System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Retrieve information from the data source. - /// - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task> RetrieveAsync(RetrievalRequest body, System.Threading.CancellationToken cancellationToken) - { - if (body == null) - throw new System.ArgumentNullException("body"); - - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - var json_ = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(body, _settings.Value); - var content_ = new System.Net.Http.ByteArrayContent(json_); - content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json"); - request_.Content = content_; - request_.Method = new System.Net.Http.HttpMethod("POST"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - - // Operation Path: "retrieval" - urlBuilder_.Append("retrieval"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - /// - /// Get the security requirements for this data source. - /// - /// OK - /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetSecurityRequirementsAsync() - { - return GetSecurityRequirementsAsync(System.Threading.CancellationToken.None); - } - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Get the security requirements for this data source. - /// - /// OK - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetSecurityRequirementsAsync(System.Threading.CancellationToken cancellationToken) - { - var client_ = _httpClient; - var disposeClient_ = false; - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("GET"); - request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); - - var urlBuilder_ = new System.Text.StringBuilder(); - - // Operation Path: "security/requirements" - urlBuilder_.Append("security/requirements"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 200) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - return objectResponse_.Object; - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - if (disposeClient_) - client_.Dispose(); - } - } - - protected struct ObjectResponseResult - { - public ObjectResponseResult(T responseObject, string responseText) - { - this.Object = responseObject; - this.Text = responseText; - } - - public T Object { get; } - - public string Text { get; } - } - - public bool ReadResponseAsString { get; set; } - - protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) - { - if (response == null || response.Content == null) - { - return new ObjectResponseResult(default(T), string.Empty); - } - - if (ReadResponseAsString) - { - var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - try - { - var typedBody = System.Text.Json.JsonSerializer.Deserialize(responseText, JsonSerializerSettings); - return new ObjectResponseResult(typedBody, responseText); - } - catch (System.Text.Json.JsonException exception) - { - var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; - throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); - } - } - else - { - try - { - using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) - { - var typedBody = await System.Text.Json.JsonSerializer.DeserializeAsync(responseStream, JsonSerializerSettings, cancellationToken).ConfigureAwait(false); - return new ObjectResponseResult(typedBody, string.Empty); - } - } - catch (System.Text.Json.JsonException exception) - { - var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; - throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); - } - } - } - - private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) - { - if (value == null) - { - return ""; - } - - if (value is System.Enum) - { - var name = System.Enum.GetName(value.GetType(), value); - if (name != null) - { - var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); - if (field != null) - { - var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) - as System.Runtime.Serialization.EnumMemberAttribute; - if (attribute != null) - { - return attribute.Value != null ? attribute.Value : name; - } - } - - var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); - return converted == null ? string.Empty : converted; - } - } - else if (value is bool) - { - return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); - } - else if (value is byte[]) - { - return System.Convert.ToBase64String((byte[]) value); - } - else if (value is string[]) - { - return string.Join(",", (string[])value); - } - else if (value.GetType().IsArray) - { - var valueArray = (System.Array)value; - var valueTextArray = new string[valueArray.Length]; - for (var i = 0; i < valueArray.Length; i++) - { - valueTextArray[i] = ConvertToString(valueArray.GetValue(i), cultureInfo); - } - return string.Join(",", valueTextArray); - } - - var result = System.Convert.ToString(value, cultureInfo); - return result == null ? "" : result; - } - } - - /// - /// An authentication field. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum AuthField - { - - [System.Runtime.Serialization.EnumMember(Value = @"NONE")] - NONE = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"USERNAME")] - USERNAME = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"PASSWORD")] - PASSWORD = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"TOKEN")] - TOKEN = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"KERBEROS_TICKET")] - KERBEROS_TICKET = 4, - - } - - /// - /// The mapping between an AuthField and the field name in the authentication request. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class AuthFieldMapping - { - - [System.Text.Json.Serialization.JsonPropertyName("authField")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] - public AuthField AuthField { get; set; } - - /// - /// The field name in the authentication request. - /// - - [System.Text.Json.Serialization.JsonPropertyName("fieldName")] - public string FieldName { get; set; } - - } - - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum AuthMethod - { - - [System.Runtime.Serialization.EnumMember(Value = @"NONE")] - NONE = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"KERBEROS")] - KERBEROS = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"USERNAME_PASSWORD")] - USERNAME_PASSWORD = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"TOKEN")] - TOKEN = 3, - - } - - /// - /// The response to an authentication request. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class AuthResponse - { - /// - /// True, when the authentication was successful. - /// - - [System.Text.Json.Serialization.JsonPropertyName("success")] - public bool Success { get; set; } - - /// - /// The token to use for further requests. - /// - - [System.Text.Json.Serialization.JsonPropertyName("token")] - public string Token { get; set; } - - /// - /// When the authentication was not successful, this contains the reason. - /// - - [System.Text.Json.Serialization.JsonPropertyName("message")] - public string Message { get; set; } - - } - - /// - /// Describes one authentication scheme for this data source. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class AuthScheme - { - - [System.Text.Json.Serialization.JsonPropertyName("authMethod")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] - public AuthMethod AuthMethod { get; set; } - - /// - /// A list of field mappings for the authentication method. The client must know, - ///
e.g., how the password field is named in the request. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("authFieldMappings")] - public System.Collections.Generic.ICollection AuthFieldMappings { get; set; } - - } - - /// - /// A chat thread, which is a list of content blocks. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ChatThread - { - /// - /// The content blocks in this chat thread. - /// - - [System.Text.Json.Serialization.JsonPropertyName("contentBlocks")] - public System.Collections.Generic.ICollection ContentBlocks { get; set; } - - } - - /// - /// A block of content of a chat thread. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ContentBlock - { - /// - /// The content of the block. Remember that images and other media are base64 encoded. - /// - - [System.Text.Json.Serialization.JsonPropertyName("content")] - public string Content { get; set; } - - [System.Text.Json.Serialization.JsonPropertyName("role")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] - public Role Role { get; set; } - - [System.Text.Json.Serialization.JsonPropertyName("type")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] - public ContentType Type { get; set; } - - } - - /// - /// The type of content. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum ContentType - { - - [System.Runtime.Serialization.EnumMember(Value = @"NONE")] - NONE = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"UNKNOWN")] - UNKNOWN = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"TEXT")] - TEXT = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"IMAGE")] - IMAGE = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"VIDEO")] - VIDEO = 4, - - [System.Runtime.Serialization.EnumMember(Value = @"AUDIO")] - AUDIO = 5, - - [System.Runtime.Serialization.EnumMember(Value = @"SPEECH")] - SPEECH = 6, - - } - - /// - /// Matching context returned by the data source as a result of a retrieval request. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class Context - { - /// - /// The name of the source, e.g., a document name, database name, - ///
collection name, etc. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("name")] - public string Name { get; set; } - - /// - /// What are the contents of the source? For example, is it a - ///
dictionary, a book chapter, business concept, a paper, etc. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("category")] - public string Category { get; set; } - - /// - /// The path to the content, e.g., a URL, a file path, a path in a - ///
graph database, etc. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("path")] - public string Path { get; set; } - - [System.Text.Json.Serialization.JsonPropertyName("type")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] - public ContentType Type { get; set; } - - /// - /// The content that matched the user prompt. For text, you - ///
return the matched text and, e.g., three words before and after it. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("matchedContent")] - public string MatchedContent { get; set; } - - /// - /// The surrounding content of the matched content. - ///
For text, you may return, e.g., one sentence or paragraph before and after - ///
the matched content. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("surroundingContent")] - public System.Collections.Generic.ICollection SurroundingContent { get; set; } - - /// - /// Links to related content, e.g., links to Wikipedia articles, - ///
links to sources, etc. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("links")] - public System.Collections.Generic.ICollection Links { get; set; } - - } - - /// - /// Information about the data source. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class DataSourceInfo - { - /// - /// The name of the data source, e.g., "Internal Organization Documents." - /// - - [System.Text.Json.Serialization.JsonPropertyName("name")] - public string Name { get; set; } - - /// - /// A short description of the data source. What kind of data does it contain? - ///
What is the data source used for? - ///
- - [System.Text.Json.Serialization.JsonPropertyName("description")] - public string Description { get; set; } - - } - - /// - /// Represents information about the used embedding for this data source. The purpose of this information is to give the - ///
interested user an idea of what kind of embedding is used and what it does. - ///
- [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class EmbeddingInfo - { - /// - /// What kind of embedding is used. For example, "Transformer Embedding," "Contextual Word - ///
Embedding," "Graph Embedding," etc. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("embeddingType")] - public string EmbeddingType { get; set; } - - /// - /// Name the embedding used. This can be a library, a framework, or the name of the used - ///
algorithm. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("embeddingName")] - public string EmbeddingName { get; set; } - - /// - /// A short description of the embedding. Describe what the embedding is doing. - /// - - [System.Text.Json.Serialization.JsonPropertyName("description")] - public string Description { get; set; } - - /// - /// Describe when the embedding is used. For example, when the user prompt contains certain - ///
keywords, or anytime? - ///
- - [System.Text.Json.Serialization.JsonPropertyName("usedWhen")] - public string UsedWhen { get; set; } - - /// - /// A link to the embedding's documentation or the source code. Might be null. - /// - - [System.Text.Json.Serialization.JsonPropertyName("link")] - public string Link { get; set; } - - } - - /// - /// Known types of providers that can process data. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum ProviderType - { - - [System.Runtime.Serialization.EnumMember(Value = @"NONE")] - NONE = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"ANY")] - ANY = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"SELF_HOSTED")] - SELF_HOSTED = 2, - - } - - /// - /// Information about a retrieval process, which this data source implements. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class RetrievalInfo - { - /// - /// A unique identifier for the retrieval process. This can be a GUID, a unique name, or an increasing integer. - /// - - [System.Text.Json.Serialization.JsonPropertyName("id")] - public string Id { get; set; } - - /// - /// The name of the retrieval process, e.g., "Keyword-Based Wikipedia Article Retrieval". - /// - - [System.Text.Json.Serialization.JsonPropertyName("name")] - public string Name { get; set; } - - /// - /// A short description of the retrieval process. What kind of retrieval process is it? - /// - - [System.Text.Json.Serialization.JsonPropertyName("description")] - public string Description { get; set; } - - /// - /// A link to the retrieval process's documentation, paper, Wikipedia article, or the source code. Might be null. - /// - - [System.Text.Json.Serialization.JsonPropertyName("link")] - public string Link { get; set; } - - /// - /// A dictionary that describes the parameters of the retrieval process. The key is the parameter name, - ///
and the value is a description of the parameter. Although each parameter will be sent as a string, the description should indicate the - ///
expected type and range, e.g., 0.0 to 1.0 for a float parameter. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("parametersDescription")] - public System.Collections.Generic.IDictionary ParametersDescription { get; set; } - - /// - /// A list of embeddings used in this retrieval process. It might be empty in case no embedding is used. - /// - - [System.Text.Json.Serialization.JsonPropertyName("embeddings")] - public System.Collections.Generic.ICollection Embeddings { get; set; } - - } - - /// - /// The retrieval request sent by AI Studio. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class RetrievalRequest - { - /// - /// The latest user prompt that AI Studio received. - /// - - [System.Text.Json.Serialization.JsonPropertyName("latestUserPrompt")] - public string LatestUserPrompt { get; set; } - - [System.Text.Json.Serialization.JsonPropertyName("latestUserPromptType")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] - public ContentType LatestUserPromptType { get; set; } - - [System.Text.Json.Serialization.JsonPropertyName("thread")] - public ChatThread Thread { get; set; } - - /// - /// Optional. The ID of the retrieval process that the data source should use. - ///
When null, the data source chooses an appropriate retrieval process. Selecting a retrieval process is optional - ///
for AI Studio users. Most users do not specify a retrieval process. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("retrievalProcessId")] - public string RetrievalProcessId { get; set; } - - /// - /// A dictionary of parameters that the data source should use for the retrieval process. - ///
Although each parameter will be sent as a string, the retrieval process specifies the expected type and range. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("parameters")] - public System.Collections.Generic.IDictionary Parameters { get; set; } - - /// - /// The maximum number of matches that the data source should return. AI Studio uses - ///
any value below 1 to indicate that the data source should return as many matches as appropriate. - ///
- - [System.Text.Json.Serialization.JsonPropertyName("maxMatches")] - public int MaxMatches { get; set; } - - } - - /// - /// Possible roles of any chat thread. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public enum Role - { - - [System.Runtime.Serialization.EnumMember(Value = @"NONE")] - NONE = 0, - - [System.Runtime.Serialization.EnumMember(Value = @"UNKNOW")] - UNKNOW = 1, - - [System.Runtime.Serialization.EnumMember(Value = @"SYSTEM")] - SYSTEM = 2, - - [System.Runtime.Serialization.EnumMember(Value = @"USER")] - USER = 3, - - [System.Runtime.Serialization.EnumMember(Value = @"AI")] - AI = 4, - - [System.Runtime.Serialization.EnumMember(Value = @"AGENT")] - AGENT = 5, - - } - - /// - /// Represents the security requirements for this data source. - /// - [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class SecurityRequirements - { - - [System.Text.Json.Serialization.JsonPropertyName("allowedProviderType")] - [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] - public ProviderType AllowedProviderType { get; set; } - - } - - - - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ApiException : System.Exception - { - public int StatusCode { get; private set; } - - public string Response { get; private set; } - - public System.Collections.Generic.IReadOnlyDictionary> Headers { get; private set; } - - public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Exception innerException) - : base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) - { - StatusCode = statusCode; - Response = response; - Headers = headers; - } - - public override string ToString() - { - return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString()); - } - } - - [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class ApiException : ApiException - { - public TResult Result { get; private set; } - - public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary> headers, TResult result, System.Exception innerException) - : base(message, statusCode, response, headers, innerException) - { - Result = result; - } - } - -} - -#pragma warning restore 108 -#pragma warning restore 114 -#pragma warning restore 472 -#pragma warning restore 612 -#pragma warning restore 1573 -#pragma warning restore 1591 -#pragma warning restore 8073 -#pragma warning restore 3016 -#pragma warning restore 8603 -#pragma warning restore 8604 -#pragma warning restore 8625 \ No newline at end of file diff --git a/app/ERIClientV1/ERIClientV1.csproj b/app/ERIClientV1/ERIClientV1.csproj deleted file mode 100644 index 8ca0662..0000000 --- a/app/ERIClientV1/ERIClientV1.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - net8.0 - latest - enable - enable - - - diff --git a/app/MindWork AI Studio.sln b/app/MindWork AI Studio.sln index 6bf20b2..ef02b51 100644 --- a/app/MindWork AI Studio.sln +++ b/app/MindWork AI Studio.sln @@ -2,10 +2,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MindWork AI Studio", "MindWork AI Studio\MindWork AI Studio.csproj", "{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ERIClients", "ERIClients", "{5C2AF789-287B-4FCB-B675-7273D8CD4579}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ERIClientV1", "ERIClientV1\ERIClientV1.csproj", "{9E35A273-0FA6-4BD5-8880-A1DDAC106926}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -16,12 +12,7 @@ Global {059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Debug|Any CPU.Build.0 = Debug|Any CPU {059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Release|Any CPU.ActiveCfg = Release|Any CPU {059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Release|Any CPU.Build.0 = Release|Any CPU - {9E35A273-0FA6-4BD5-8880-A1DDAC106926}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9E35A273-0FA6-4BD5-8880-A1DDAC106926}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9E35A273-0FA6-4BD5-8880-A1DDAC106926}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9E35A273-0FA6-4BD5-8880-A1DDAC106926}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution - {9E35A273-0FA6-4BD5-8880-A1DDAC106926} = {5C2AF789-287B-4FCB-B675-7273D8CD4579} EndGlobalSection EndGlobal diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor.cs index 41daae9..53aced4 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelDataSources.razor.cs @@ -1,8 +1,7 @@ using AIStudio.Dialogs; using AIStudio.Settings; using AIStudio.Settings.DataModel; - -using ERI_Client.V1; +using AIStudio.Tools.ERIClient.DataModel; using Microsoft.AspNetCore.Components; diff --git a/app/MindWork AI Studio/MindWork AI Studio.csproj b/app/MindWork AI Studio/MindWork AI Studio.csproj index ccc96df..0d6fc28 100644 --- a/app/MindWork AI Studio/MindWork AI Studio.csproj +++ b/app/MindWork AI Studio/MindWork AI Studio.csproj @@ -53,10 +53,6 @@ - - - - diff --git a/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs b/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs index 387accf..acf49ec 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs @@ -1,6 +1,7 @@ -using ERI_Client.V1; - // ReSharper disable InconsistentNaming + +using AIStudio.Tools.ERIClient.DataModel; + namespace AIStudio.Settings.DataModel; /// diff --git a/app/MindWork AI Studio/Settings/IERIDataSource.cs b/app/MindWork AI Studio/Settings/IERIDataSource.cs index 34874fc..42cd3f7 100644 --- a/app/MindWork AI Studio/Settings/IERIDataSource.cs +++ b/app/MindWork AI Studio/Settings/IERIDataSource.cs @@ -1,4 +1,4 @@ -using ERI_Client.V1; +using AIStudio.Tools.ERIClient.DataModel; namespace AIStudio.Settings; diff --git a/app/MindWork AI Studio/Tools/AuthMethodsV1Extensions.cs b/app/MindWork AI Studio/Tools/AuthMethodsV1Extensions.cs index e26a20b..4d11017 100644 --- a/app/MindWork AI Studio/Tools/AuthMethodsV1Extensions.cs +++ b/app/MindWork AI Studio/Tools/AuthMethodsV1Extensions.cs @@ -1,4 +1,4 @@ -using ERI_Client.V1; +using AIStudio.Tools.ERIClient.DataModel; namespace AIStudio.Tools; diff --git a/app/MindWork AI Studio/Tools/ERIClient/APIResponse.cs b/app/MindWork AI Studio/Tools/ERIClient/APIResponse.cs new file mode 100644 index 0000000..1f82914 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/APIResponse.cs @@ -0,0 +1,19 @@ +namespace AIStudio.Tools.ERIClient; + +public sealed class APIResponse +{ + /// + /// Was the API call successful? + /// + public bool Successful { get; set; } + + /// + /// When the API call was not successful, this will contain the error message. + /// + public string Message { get; set; } = string.Empty; + + /// + /// The data returned by the API call. + /// + public T? Data { get; set; } +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthField.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthField.cs new file mode 100644 index 0000000..8972743 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthField.cs @@ -0,0 +1,13 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// An authentication field. +/// +public enum AuthField +{ + NONE, + USERNAME, + PASSWORD, + TOKEN, + KERBEROS_TICKET, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthFieldMapping.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthFieldMapping.cs new file mode 100644 index 0000000..e11c3d9 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthFieldMapping.cs @@ -0,0 +1,8 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// The mapping between an AuthField and the field name in the authentication request. +/// +/// The AuthField that is mapped to the field name. +/// The field name in the authentication request. +public record AuthFieldMapping(AuthField AuthField, string FieldName); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthMethod.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthMethod.cs new file mode 100644 index 0000000..7494ce9 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthMethod.cs @@ -0,0 +1,9 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +public enum AuthMethod +{ + NONE, + KERBEROS, + USERNAME_PASSWORD, + TOKEN, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthResponse.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthResponse.cs new file mode 100644 index 0000000..cdc325d --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthResponse.cs @@ -0,0 +1,9 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// The response to an authentication request. +/// +/// True, when the authentication was successful. +/// The token to use for further requests. +/// When the authentication was not successful, this contains the reason. +public readonly record struct AuthResponse(bool Success, string? Token, string? Message); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthScheme.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthScheme.cs new file mode 100644 index 0000000..bde0175 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/AuthScheme.cs @@ -0,0 +1,9 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// Describes one authentication scheme for this data source. +/// +/// The method used for authentication, e.g., "API Key," "Username/Password," etc. +/// A list of field mappings for the authentication method. The client must know, +/// e.g., how the password field is named in the request. +public readonly record struct AuthScheme(AuthMethod AuthMethod, List AuthFieldMappings); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/ChatThread.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ChatThread.cs new file mode 100644 index 0000000..8d6a098 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ChatThread.cs @@ -0,0 +1,7 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// A chat thread, which is a list of content blocks. +/// +/// The content blocks in this chat thread. +public readonly record struct ChatThread(List ContentBlocks); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/ContentBlock.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ContentBlock.cs new file mode 100644 index 0000000..0a46d3b --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ContentBlock.cs @@ -0,0 +1,12 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// A block of content of a chat thread. +/// +/// +/// Images and other media are base64 encoded. +/// +/// The content of the block. Remember that images and other media are base64 encoded. +/// The role of the content in the chat thread. +/// The type of the content, e.g., text, image, video, etc. +public readonly record struct ContentBlock(string Content, Role Role, ContentType Type); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/ContentType.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ContentType.cs new file mode 100644 index 0000000..1420372 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ContentType.cs @@ -0,0 +1,16 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// The type of content. +/// +public enum ContentType +{ + NONE, + UNKNOWN, + + TEXT, + IMAGE, + VIDEO, + AUDIO, + SPEECH, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/Context.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/Context.cs new file mode 100644 index 0000000..fb5c13f --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/Context.cs @@ -0,0 +1,27 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// Matching context returned by the data source as a result of a retrieval request. +/// +/// The name of the source, e.g., a document name, database name, +/// collection name, etc. +/// What are the contents of the source? For example, is it a +/// dictionary, a book chapter, business concept, a paper, etc. +/// The path to the content, e.g., a URL, a file path, a path in a +/// graph database, etc. +/// The type of the content, e.g., text, image, video, audio, speech, etc. +/// The content that matched the user prompt. For text, you +/// return the matched text and, e.g., three words before and after it. +/// The surrounding content of the matched content. +/// For text, you may return, e.g., one sentence or paragraph before and after +/// the matched content. +/// Links to related content, e.g., links to Wikipedia articles, +/// links to sources, etc. +public readonly record struct Context( + string Name, + string Category, + string? Path, + ContentType Type, + string MatchedContent, + string[] SurroundingContent, + string[] Links); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/DataSourceInfo.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/DataSourceInfo.cs new file mode 100644 index 0000000..07a8f92 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/DataSourceInfo.cs @@ -0,0 +1,9 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// Information about the data source. +/// +/// The name of the data source, e.g., "Internal Organization Documents." +/// A short description of the data source. What kind of data does it contain? +/// What is the data source used for? +public readonly record struct DataSourceInfo(string Name, string Description); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/EmbeddingInfo.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/EmbeddingInfo.cs new file mode 100644 index 0000000..4728512 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/EmbeddingInfo.cs @@ -0,0 +1,20 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// Represents information about the used embedding for this data source. The purpose of this information is to give the +/// interested user an idea of what kind of embedding is used and what it does. +/// +/// What kind of embedding is used. For example, "Transformer Embedding," "Contextual Word +/// Embedding," "Graph Embedding," etc. +/// Name the embedding used. This can be a library, a framework, or the name of the used +/// algorithm. +/// A short description of the embedding. Describe what the embedding is doing. +/// Describe when the embedding is used. For example, when the user prompt contains certain +/// keywords, or anytime? +/// A link to the embedding's documentation or the source code. Might be null. +public readonly record struct EmbeddingInfo( + string EmbeddingType, + string EmbeddingName, + string Description, + string UsedWhen, + string? Link); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/ProviderType.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ProviderType.cs new file mode 100644 index 0000000..008811f --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/ProviderType.cs @@ -0,0 +1,22 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// Known types of providers that can process data. +/// +public enum ProviderType +{ + /// + /// The related data is not allowed to be sent to any provider. + /// + NONE, + + /// + /// The related data can be sent to any provider. + /// + ANY, + + /// + /// The related data can be sent to a provider that is hosted by the same organization, either on-premises or locally. + /// + SELF_HOSTED, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/RetrievalInfo.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/RetrievalInfo.cs new file mode 100644 index 0000000..cdd71a6 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/RetrievalInfo.cs @@ -0,0 +1,20 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// Information about a retrieval process, which this data source implements. +/// +/// A unique identifier for the retrieval process. This can be a GUID, a unique name, or an increasing integer. +/// The name of the retrieval process, e.g., "Keyword-Based Wikipedia Article Retrieval". +/// A short description of the retrieval process. What kind of retrieval process is it? +/// A link to the retrieval process's documentation, paper, Wikipedia article, or the source code. Might be null. +/// A dictionary that describes the parameters of the retrieval process. The key is the parameter name, +/// and the value is a description of the parameter. Although each parameter will be sent as a string, the description should indicate the +/// expected type and range, e.g., 0.0 to 1.0 for a float parameter. +/// A list of embeddings used in this retrieval process. It might be empty in case no embedding is used. +public readonly record struct RetrievalInfo( + string Id, + string Name, + string Description, + string? Link, + Dictionary? ParametersDescription, + List Embeddings); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/RetrievalRequest.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/RetrievalRequest.cs new file mode 100644 index 0000000..abeac50 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/RetrievalRequest.cs @@ -0,0 +1,25 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// The retrieval request sent by AI Studio. +/// +/// +/// Images and other media are base64 encoded. +/// +/// The latest user prompt that AI Studio received. +/// The type of the latest user prompt, e.g., text, image, etc. +/// The chat thread that the user is currently in. +/// Optional. The ID of the retrieval process that the data source should use. +/// When null, the data source chooses an appropriate retrieval process. Selecting a retrieval process is optional +/// for AI Studio users. Most users do not specify a retrieval process. +/// A dictionary of parameters that the data source should use for the retrieval process. +/// Although each parameter will be sent as a string, the retrieval process specifies the expected type and range. +/// The maximum number of matches that the data source should return. AI Studio uses +/// any value below 1 to indicate that the data source should return as many matches as appropriate. +public readonly record struct RetrievalRequest( + string LatestUserPrompt, + ContentType LatestUserPromptType, + ChatThread Thread, + string? RetrievalProcessId, + Dictionary? Parameters, + int MaxMatches); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/Role.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/Role.cs new file mode 100644 index 0000000..f19376f --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/Role.cs @@ -0,0 +1,15 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// Possible roles of any chat thread. +/// +public enum Role +{ + NONE, + UNKNOW, + + SYSTEM, + USER, + AI, + AGENT, +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/DataModel/SecurityRequirements.cs b/app/MindWork AI Studio/Tools/ERIClient/DataModel/SecurityRequirements.cs new file mode 100644 index 0000000..aa4df1f --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/DataModel/SecurityRequirements.cs @@ -0,0 +1,7 @@ +namespace AIStudio.Tools.ERIClient.DataModel; + +/// +/// Represents the security requirements for this data source. +/// +/// Which provider types are allowed to process the data? +public readonly record struct SecurityRequirements(ProviderType AllowedProviderType); \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/ERIClientBase.cs b/app/MindWork AI Studio/Tools/ERIClient/ERIClientBase.cs new file mode 100644 index 0000000..66882a1 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/ERIClientBase.cs @@ -0,0 +1,36 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace AIStudio.Tools.ERIClient; + +public abstract class ERIClientBase(string baseAddress) : IDisposable +{ + protected static readonly JsonSerializerOptions JSON_OPTIONS = new() + { + WriteIndented = true, + AllowTrailingCommas = true, + PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, + DictionaryKeyPolicy = JsonNamingPolicy.CamelCase, + PropertyNameCaseInsensitive = true, + Converters = + { + new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseUpper), + } + }; + + protected readonly HttpClient httpClient = new() + { + BaseAddress = new Uri(baseAddress), + }; + + protected string securityToken = string.Empty; + + #region Implementation of IDisposable + + public void Dispose() + { + this.httpClient.Dispose(); + } + + #endregion +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/ERIClientFactory.cs b/app/MindWork AI Studio/Tools/ERIClient/ERIClientFactory.cs new file mode 100644 index 0000000..2858164 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/ERIClientFactory.cs @@ -0,0 +1,14 @@ +using AIStudio.Assistants.ERI; +using AIStudio.Settings; + +namespace AIStudio.Tools.ERIClient; + +public static class ERIClientFactory +{ + public static IERIClient? Get(ERIVersion version, IERIDataSource dataSource) => version switch + { + ERIVersion.V1 => new ERIClientV1($"{dataSource.Hostname}:{dataSource.Port}"), + + _ => null + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/ERIClientV1.cs b/app/MindWork AI Studio/Tools/ERIClient/ERIClientV1.cs new file mode 100644 index 0000000..62e3f55 --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/ERIClientV1.cs @@ -0,0 +1,344 @@ +using System.Text; +using System.Text.Json; + +using AIStudio.Settings; +using AIStudio.Tools.ERIClient.DataModel; + +namespace AIStudio.Tools.ERIClient; + +public class ERIClientV1(string baseAddress) : ERIClientBase(baseAddress), IERIClient +{ + #region Implementation of IERIClient + + public async Task>> GetAuthMethodsAsync(CancellationToken cancellationToken = default) + { + using var response = await this.httpClient.GetAsync("/auth/methods", cancellationToken); + if(!response.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to retrieve the authentication methods: there was an issue communicating with the ERI server. Code: {response.StatusCode}, Reason: {response.ReasonPhrase}" + }; + } + + var authMethods = await response.Content.ReadFromJsonAsync>(JSON_OPTIONS, cancellationToken); + if(authMethods is null) + { + return new() + { + Successful = false, + Message = "Failed to retrieve the authentication methods: the ERI server did not return a valid response." + }; + } + + return new() + { + Successful = true, + Data = authMethods + }; + } + + public async Task> AuthenticateAsync(IERIDataSource dataSource, RustService rustService, CancellationToken cancellationToken = default) + { + var authMethod = dataSource.AuthMethod; + var username = dataSource.Username; + switch (dataSource.AuthMethod) + { + case AuthMethod.NONE: + using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}")) + { + using var noneAuthResponse = await this.httpClient.SendAsync(request, cancellationToken); + if(!noneAuthResponse.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to authenticate with the ERI server. Code: {noneAuthResponse.StatusCode}, Reason: {noneAuthResponse.ReasonPhrase}" + }; + } + + var noneAuthResult = await noneAuthResponse.Content.ReadFromJsonAsync(JSON_OPTIONS, cancellationToken); + if(noneAuthResult == default) + { + return new() + { + Successful = false, + Message = "Failed to authenticate with the ERI server: the response was invalid." + }; + } + + this.securityToken = noneAuthResult.Token ?? string.Empty; + return new() + { + Successful = true, + Data = noneAuthResult + }; + } + + case AuthMethod.USERNAME_PASSWORD: + var passwordResponse = await rustService.GetSecret(dataSource); + if (!passwordResponse.Success) + { + return new() + { + Successful = false, + Message = "Failed to retrieve the password." + }; + } + + var password = await passwordResponse.Secret.Decrypt(Program.ENCRYPTION); + using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}")) + { + // We must send both values inside the header. The username field is named 'user'. + // The password field is named 'password'. + request.Headers.Add("user", username); + request.Headers.Add("password", password); + + using var usernamePasswordAuthResponse = await this.httpClient.SendAsync(request, cancellationToken); + if(!usernamePasswordAuthResponse.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to authenticate with the ERI server. Code: {usernamePasswordAuthResponse.StatusCode}, Reason: {usernamePasswordAuthResponse.ReasonPhrase}" + }; + } + + var usernamePasswordAuthResult = await usernamePasswordAuthResponse.Content.ReadFromJsonAsync(JSON_OPTIONS, cancellationToken); + if(usernamePasswordAuthResult == default) + { + return new() + { + Successful = false, + Message = "Failed to authenticate with the server: the response was invalid." + }; + } + + this.securityToken = usernamePasswordAuthResult.Token ?? string.Empty; + return new() + { + Successful = true, + Data = usernamePasswordAuthResult + }; + } + + case AuthMethod.TOKEN: + var tokenResponse = await rustService.GetSecret(dataSource); + if (!tokenResponse.Success) + { + return new() + { + Successful = false, + Message = "Failed to retrieve the access token." + }; + } + + var token = await tokenResponse.Secret.Decrypt(Program.ENCRYPTION); + using (var request = new HttpRequestMessage(HttpMethod.Post, $"auth?authMethod={authMethod}")) + { + request.Headers.Add("Authorization", $"Bearer {token}"); + + using var tokenAuthResponse = await this.httpClient.SendAsync(request, cancellationToken); + if(!tokenAuthResponse.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to authenticate with the ERI server. Code: {tokenAuthResponse.StatusCode}, Reason: {tokenAuthResponse.ReasonPhrase}" + }; + } + + var tokenAuthResult = await tokenAuthResponse.Content.ReadFromJsonAsync(JSON_OPTIONS, cancellationToken); + if(tokenAuthResult == default) + { + return new() + { + Successful = false, + Message = "Failed to authenticate with the ERI server: the response was invalid." + }; + } + + this.securityToken = tokenAuthResult.Token ?? string.Empty; + return new() + { + Successful = true, + Data = tokenAuthResult + }; + } + + default: + this.securityToken = string.Empty; + return new() + { + Successful = false, + Message = "The authentication method is not supported yet." + }; + } + } + + public async Task> GetDataSourceInfoAsync(CancellationToken cancellationToken = default) + { + using var request = new HttpRequestMessage(HttpMethod.Get, "/dataSource"); + request.Headers.Add("token", this.securityToken); + + using var response = await this.httpClient.SendAsync(request, cancellationToken); + if(!response.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to retrieve the data source information: there was an issue communicating with the ERI server. Code: {response.StatusCode}, Reason: {response.ReasonPhrase}" + }; + } + + var dataSourceInfo = await response.Content.ReadFromJsonAsync(JSON_OPTIONS, cancellationToken); + if(dataSourceInfo == default) + { + return new() + { + Successful = false, + Message = "Failed to retrieve the data source information: the ERI server did not return a valid response." + }; + } + + return new() + { + Successful = true, + Data = dataSourceInfo + }; + } + + public async Task>> GetEmbeddingInfoAsync(CancellationToken cancellationToken = default) + { + using var request = new HttpRequestMessage(HttpMethod.Get, "/embedding/info"); + request.Headers.Add("token", this.securityToken); + + using var response = await this.httpClient.SendAsync(request, cancellationToken); + if(!response.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to retrieve the embedding information: there was an issue communicating with the ERI server. Code: {response.StatusCode}, Reason: {response.ReasonPhrase}" + }; + } + + var embeddingInfo = await response.Content.ReadFromJsonAsync>(JSON_OPTIONS, cancellationToken); + if(embeddingInfo is null) + { + return new() + { + Successful = false, + Message = "Failed to retrieve the embedding information: the ERI server did not return a valid response." + }; + } + + return new() + { + Successful = true, + Data = embeddingInfo + }; + } + + public async Task>> GetRetrievalInfoAsync(CancellationToken cancellationToken = default) + { + using var request = new HttpRequestMessage(HttpMethod.Get, "/retrieval/info"); + request.Headers.Add("token", this.securityToken); + + using var response = await this.httpClient.SendAsync(request, cancellationToken); + if(!response.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to retrieve the retrieval information: there was an issue communicating with the ERI server. Code: {response.StatusCode}, Reason: {response.ReasonPhrase}" + }; + } + + var retrievalInfo = await response.Content.ReadFromJsonAsync>(JSON_OPTIONS, cancellationToken); + if(retrievalInfo is null) + { + return new() + { + Successful = false, + Message = "Failed to retrieve the retrieval information: the ERI server did not return a valid response." + }; + } + + return new() + { + Successful = true, + Data = retrievalInfo + }; + } + + public async Task>> ExecuteRetrievalAsync(RetrievalRequest request, CancellationToken cancellationToken = default) + { + using var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/retrieval"); + requestMessage.Headers.Add("token", this.securityToken); + + using var content = new StringContent(JsonSerializer.Serialize(request, JSON_OPTIONS), Encoding.UTF8, "application/json"); + requestMessage.Content = content; + + using var response = await this.httpClient.SendAsync(requestMessage, cancellationToken); + if(!response.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to execute the retrieval request: there was an issue communicating with the ERI server. Code: {response.StatusCode}, Reason: {response.ReasonPhrase}" + }; + } + + var contexts = await response.Content.ReadFromJsonAsync>(JSON_OPTIONS, cancellationToken); + if(contexts is null) + { + return new() + { + Successful = false, + Message = "Failed to execute the retrieval request: the ERI server did not return a valid response." + }; + } + + return new() + { + Successful = true, + Data = contexts + }; + } + + public async Task> GetSecurityRequirementsAsync(CancellationToken cancellationToken = default) + { + using var request = new HttpRequestMessage(HttpMethod.Get, "/security/requirements"); + request.Headers.Add("token", this.securityToken); + + using var response = await this.httpClient.SendAsync(request, cancellationToken); + if(!response.IsSuccessStatusCode) + { + return new() + { + Successful = false, + Message = $"Failed to retrieve the security requirements: there was an issue communicating with the ERI server. Code: {response.StatusCode}, Reason: {response.ReasonPhrase}" + }; + } + + var securityRequirements = await response.Content.ReadFromJsonAsync(JSON_OPTIONS, cancellationToken); + if(securityRequirements == default) + { + return new() + { + Successful = false, + Message = "Failed to retrieve the security requirements: the ERI server did not return a valid response." + }; + } + + return new() + { + Successful = true, + Data = securityRequirements + }; + } + + #endregion +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ERIClient/IERIClient.cs b/app/MindWork AI Studio/Tools/ERIClient/IERIClient.cs new file mode 100644 index 0000000..9cf27fb --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/IERIClient.cs @@ -0,0 +1,62 @@ +using AIStudio.Settings; +using AIStudio.Tools.ERIClient.DataModel; + +namespace AIStudio.Tools.ERIClient; + +public interface IERIClient : IDisposable +{ + /// + /// Retrieves the available authentication methods from the ERI server. + /// + /// + /// No authentication is required to retrieve the available authentication methods. + /// + /// The cancellation token. + /// The available authentication methods. + public Task>> GetAuthMethodsAsync(CancellationToken cancellationToken = default); + + /// + /// Authenticate the user to the ERI server. + /// + /// The data source to use. + /// The Rust service. + /// The cancellation token. + /// The authentication response. + public Task> AuthenticateAsync(IERIDataSource dataSource, RustService rustService, CancellationToken cancellationToken = default); + + /// + /// Retrieves the data source information from the ERI server. + /// + /// The cancellation token. + /// The data source information. + public Task> GetDataSourceInfoAsync(CancellationToken cancellationToken = default); + + /// + /// Retrieves the embedding information from the ERI server. + /// + /// The cancellation token. + /// A list of embedding information. + public Task>> GetEmbeddingInfoAsync(CancellationToken cancellationToken = default); + + /// + /// Retrieves the retrieval information from the ERI server. + /// + /// The cancellation token. + /// A list of retrieval information. + public Task>> GetRetrievalInfoAsync(CancellationToken cancellationToken = default); + + /// + /// Executes a retrieval request on the ERI server. + /// + /// The retrieval request. + /// The cancellation token. + /// The retrieved contexts to use for augmentation and generation. + public Task>> ExecuteRetrievalAsync(RetrievalRequest request, CancellationToken cancellationToken = default); + + /// + /// Retrieves the security requirements from the ERI server. + /// + /// The cancellation token. + /// The security requirements. + public Task> GetSecurityRequirementsAsync(CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/Validation/DataSourceValidation.cs b/app/MindWork AI Studio/Tools/Validation/DataSourceValidation.cs index f55f906..cdd2f13 100644 --- a/app/MindWork AI Studio/Tools/Validation/DataSourceValidation.cs +++ b/app/MindWork AI Studio/Tools/Validation/DataSourceValidation.cs @@ -1,4 +1,4 @@ -using ERI_Client.V1; +using AIStudio.Tools.ERIClient.DataModel; namespace AIStudio.Tools.Validation; diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.9.28.md b/app/MindWork AI Studio/wwwroot/changelog/v0.9.28.md index a833761..29875ad 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v0.9.28.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v0.9.28.md @@ -1,3 +1,4 @@ # v0.9.28, build 203 (2025-0x-xx xx:xx UTC) - Added an information view to all data sources to the data source configuration page. The data source configuration is a preview feature behind the RAG feature flag. +- Added a ERI ((E)xternal (R)etrieval (I)nterface) client for communication with any ERI server. - Improved the resource handling when loading models. \ No newline at end of file