From 302a3e086285815531a6baa4f70f238a4c99dcc8 Mon Sep 17 00:00:00 2001 From: Nir Schleyen Date: Tue, 15 Aug 2023 16:44:34 -0700 Subject: [PATCH] .Net: [Error handling] [Part4] Replacing KernelException and OpenAIInvalidResponseException exceptions by SKException (#2362) (#14) ### Motivation and Context This PR is one of the follow-up PRs aimed at gradually replacing SK custom exceptions with SKException to provide a simple, consistent, and extensible exception model. You can find more details in the [ADR](https://github.com/microsoft/semantic-kernel/blob/main/docs/decisions/0004-error-handling.md) discussing error handling. ### Description This PR updates a few SK components to throw SKException instead of KernelException and OpenAIInvalidResponseException, and removes those exceptions. ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone :smile: --------- Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com> Co-authored-by: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com> Co-authored-by: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Co-authored-by: Shawn Callegari <36091529+shawncal@users.noreply.github.com> --- .../Example12_SequentialPlanner.cs | 3 +- .../AzureSdk/ClientBase.cs | 20 +-- .../OpenAIInvalidResponseException{T}.cs | 17 --- .../AzureOpenAIImageGeneration.cs | 8 +- .../src/Diagnostics/Verify.cs | 8 +- .../ChatCompletionServiceExtensions.cs | 5 +- .../TextEmbeddingServiceExtensions.cs | 5 +- .../ImageGenerationServiceExtensions.cs | 5 +- .../TextCompletionServiceExtensions.cs | 5 +- .../KernelException.cs | 119 ------------------ .../Orchestration/SKContext.cs | 3 +- .../IReadOnlySkillCollection.cs | 5 +- .../NullReadOnlySkillCollection.cs | 14 ++- .../KernelExceptionTests.cs | 63 ---------- .../Planning/PlanSerializationTests.cs | 3 +- .../Planning/PlanTests.cs | 5 +- .../SkillDefinition/SKFunctionTests3.cs | 3 +- dotnet/src/SemanticKernel/Kernel.cs | 6 +- dotnet/src/SemanticKernel/Planning/Plan.cs | 14 +-- .../SkillDefinition/NativeFunction.cs | 14 +-- .../SkillDefinition/SkillCollection.cs | 4 +- .../TemplateEngine/Blocks/CodeBlock.cs | 5 +- .../Extensions/KernelAIPluginExtensions.cs | 2 +- .../Extensions/KernelOpenApiExtensions.cs | 2 +- .../MsGraph/CalendarSkillTests.cs | 8 +- 25 files changed, 70 insertions(+), 276 deletions(-) delete mode 100644 dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/OpenAIInvalidResponseException{T}.cs delete mode 100644 dotnet/src/SemanticKernel.Abstractions/KernelException.cs delete mode 100644 dotnet/src/SemanticKernel.UnitTests/KernelExceptionTests.cs diff --git a/dotnet/samples/KernelSyntaxExamples/Example12_SequentialPlanner.cs b/dotnet/samples/KernelSyntaxExamples/Example12_SequentialPlanner.cs index f689034ff16e..1b3a456470b6 100644 --- a/dotnet/samples/KernelSyntaxExamples/Example12_SequentialPlanner.cs +++ b/dotnet/samples/KernelSyntaxExamples/Example12_SequentialPlanner.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Threading.Tasks; using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Memory; using Microsoft.SemanticKernel.Planning; using Microsoft.SemanticKernel.Planning.Sequential; @@ -272,7 +273,7 @@ private static async Task ExecutePlanAsync( Console.WriteLine(plan.State.ToString()); } } - catch (KernelException e) + catch (SKException e) { Console.WriteLine("Step - Execution failed:"); Console.WriteLine(e.Message); diff --git a/dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/ClientBase.cs b/dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/ClientBase.cs index e806b55acc71..3f8f57df8c54 100644 --- a/dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/ClientBase.cs +++ b/dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/ClientBase.cs @@ -66,16 +66,16 @@ private protected async Task> InternalGetTextResultsA Response? response = await RunRequestAsync?>( () => this.Client.GetCompletionsAsync(this.ModelId, options, cancellationToken)).ConfigureAwait(false); - if (response == null) + if (response is null) { - throw new OpenAIInvalidResponseException(null, "Text completions null response"); + throw new SKException("Text completions null response"); } var responseData = response.Value; if (responseData.Choices.Count == 0) { - throw new OpenAIInvalidResponseException(responseData, "Text completions not found"); + throw new SKException("Text completions not found"); } return responseData.Choices.Select(choice => new TextResult(responseData, choice)).ToList(); @@ -126,14 +126,14 @@ private protected async Task>> InternalGetEmbeddings Response? response = await RunRequestAsync?>( () => this.Client.GetEmbeddingsAsync(this.ModelId, options, cancellationToken)).ConfigureAwait(false); - if (response == null) + if (response is null) { - throw new OpenAIInvalidResponseException(null, "Text embedding null response"); + throw new SKException("Text embedding null response"); } if (response.Value.Data.Count == 0) { - throw new OpenAIInvalidResponseException(response.Value, "Text embedding not found"); + throw new SKException("Text embedding not found"); } result.Add(response.Value.Data[0].Embedding.ToArray()); @@ -163,14 +163,14 @@ private protected async Task> InternalGetChatResultsA Response? response = await RunRequestAsync?>( () => this.Client.GetChatCompletionsAsync(this.ModelId, chatOptions, cancellationToken)).ConfigureAwait(false); - if (response == null) + if (response is null) { - throw new OpenAIInvalidResponseException(null, "Chat completions null response"); + throw new SKException("Chat completions null response"); } if (response.Value.Choices.Count == 0) { - throw new OpenAIInvalidResponseException(response.Value, "Chat completions not found"); + throw new SKException("Chat completions not found"); } return response.Value.Choices.Select(chatChoice => new ChatResult(response.Value, chatChoice)).ToList(); @@ -200,7 +200,7 @@ private protected async IAsyncEnumerable InternalGetChatSt if (response is null) { - throw new OpenAIInvalidResponseException(null, "Chat completions null response"); + throw new SKException("Chat completions null response"); } using StreamingChatCompletions streamingChatCompletions = response.Value; diff --git a/dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/OpenAIInvalidResponseException{T}.cs b/dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/OpenAIInvalidResponseException{T}.cs deleted file mode 100644 index 3b2c5042853a..000000000000 --- a/dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/OpenAIInvalidResponseException{T}.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.SemanticKernel.AI; - -#pragma warning disable RCS1194 // Implement exception constructors. - -namespace Microsoft.SemanticKernel.Connectors.AI.OpenAI.AzureSdk; - -internal sealed class OpenAIInvalidResponseException : AIException -{ - public T? ResponseData { get; } - - public OpenAIInvalidResponseException(T? responseData, string? message = null) : base(ErrorCodes.InvalidResponseContent, message) - { - this.ResponseData = responseData; - } -} diff --git a/dotnet/src/Connectors/Connectors.AI.OpenAI/ImageGeneration/AzureOpenAIImageGeneration.cs b/dotnet/src/Connectors/Connectors.AI.OpenAI/ImageGeneration/AzureOpenAIImageGeneration.cs index 910ae36dbb99..e47a02e98865 100644 --- a/dotnet/src/Connectors/Connectors.AI.OpenAI/ImageGeneration/AzureOpenAIImageGeneration.cs +++ b/dotnet/src/Connectors/Connectors.AI.OpenAI/ImageGeneration/AzureOpenAIImageGeneration.cs @@ -107,14 +107,14 @@ public async Task GenerateImageAsync(string description, int width, int var operationId = await this.StartImageGenerationAsync(description, width, height, cancellationToken).ConfigureAwait(false); var result = await this.GetImageGenerationResultAsync(operationId, cancellationToken).ConfigureAwait(false); - if (result.Result == null) + if (result.Result is null) { - throw new AzureSdk.OpenAIInvalidResponseException(null, "Azure Image Generation null response"); + throw new SKException("Azure Image Generation null response"); } if (result.Result.Images.Count == 0) { - throw new AzureSdk.OpenAIInvalidResponseException(result, "Azure Image Generation result not found"); + throw new SKException("Azure Image Generation result not found"); } return result.Result.Images.First().Url; @@ -184,7 +184,7 @@ private async Task GetImageGenerationResultAsync(s } else if (this.IsFailedOrCancelled(result.Status)) { - throw new AzureSdk.OpenAIInvalidResponseException(result, $"Azure OpenAI image generation {result.Status}"); + throw new SKException($"Azure OpenAI image generation {result.Status}"); } if (response.Headers.TryGetValues("retry-after", out var afterValues) && long.TryParse(afterValues.FirstOrDefault(), out var after)) diff --git a/dotnet/src/InternalUtilities/src/Diagnostics/Verify.cs b/dotnet/src/InternalUtilities/src/Diagnostics/Verify.cs index 79ad183bd094..c179ec620955 100644 --- a/dotnet/src/InternalUtilities/src/Diagnostics/Verify.cs +++ b/dotnet/src/InternalUtilities/src/Diagnostics/Verify.cs @@ -108,9 +108,7 @@ internal static void ParametersUniqueness(IList parameters) if (!seen.Add(p.Name)) { - throw new KernelException( - KernelException.ErrorCodes.InvalidFunctionDescription, - $"The function has two or more parameters with the same name '{p.Name}'"); + throw new SKException($"The function has two or more parameters with the same name '{p.Name}'"); } } } @@ -118,9 +116,7 @@ internal static void ParametersUniqueness(IList parameters) [DoesNotReturn] private static void ThrowInvalidName(string kind, string name) => - throw new KernelException( - KernelException.ErrorCodes.InvalidFunctionDescription, - $"A {kind} can contain only ASCII letters, digits, and underscores: '{name}' is not a valid name."); + throw new SKException($"A {kind} can contain only ASCII letters, digits, and underscores: '{name}' is not a valid name."); [DoesNotReturn] internal static void ThrowArgumentNullException(string? paramName) => diff --git a/dotnet/src/SemanticKernel.Abstractions/AI/ChatCompletion/ChatCompletionServiceExtensions.cs b/dotnet/src/SemanticKernel.Abstractions/AI/ChatCompletion/ChatCompletionServiceExtensions.cs index f6edaf5a2ee0..a7b2f32ecf8a 100644 --- a/dotnet/src/SemanticKernel.Abstractions/AI/ChatCompletion/ChatCompletionServiceExtensions.cs +++ b/dotnet/src/SemanticKernel.Abstractions/AI/ChatCompletion/ChatCompletionServiceExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using Microsoft.SemanticKernel.AI.ChatCompletion; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Services; // Use base namespace for better discoverability and to avoid conflicts with other extensions. @@ -17,11 +18,11 @@ public static class ChatCompletionServiceExtensions /// The service provider. /// Optional identifier of the desired service. /// The completion service id matching the given id or the default. - /// Thrown when no suitable service is found. + /// Thrown when no suitable service is found. public static IChatCompletion GetChatCompletionService( this IAIServiceProvider services, string? serviceId = null) => services.GetService(serviceId) - ?? throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, "Chat completion service not found"); + ?? throw new SKException("Chat completion service not found"); /// /// Returns true if a exist with the specified ID. diff --git a/dotnet/src/SemanticKernel.Abstractions/AI/Embeddings/TextEmbeddingServiceExtensions.cs b/dotnet/src/SemanticKernel.Abstractions/AI/Embeddings/TextEmbeddingServiceExtensions.cs index 613161f68002..fbd404ccc063 100644 --- a/dotnet/src/SemanticKernel.Abstractions/AI/Embeddings/TextEmbeddingServiceExtensions.cs +++ b/dotnet/src/SemanticKernel.Abstractions/AI/Embeddings/TextEmbeddingServiceExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using Microsoft.SemanticKernel.AI.Embeddings; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Services; // Use base namespace for better discoverability and to avoid conflicts with other extensions. @@ -17,12 +18,12 @@ public static class TextEmbeddingServiceExtensions /// The service provider. /// Optional identifier of the desired service. /// The embedding service matching the given id or the default service. - /// Thrown when no suitable service is found. + /// Thrown when no suitable service is found. public static ITextEmbeddingGeneration GetTextEmbeddingService( this IAIServiceProvider services, string? serviceId = null) => services.GetService(serviceId) - ?? throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, "Text embedding service not available"); + ?? throw new SKException("Text embedding service not found"); /// /// Returns true if a exist with the specified ID. diff --git a/dotnet/src/SemanticKernel.Abstractions/AI/ImageGeneration/ImageGenerationServiceExtensions.cs b/dotnet/src/SemanticKernel.Abstractions/AI/ImageGeneration/ImageGenerationServiceExtensions.cs index 17541b3e3aca..cc1f335caaa2 100644 --- a/dotnet/src/SemanticKernel.Abstractions/AI/ImageGeneration/ImageGenerationServiceExtensions.cs +++ b/dotnet/src/SemanticKernel.Abstractions/AI/ImageGeneration/ImageGenerationServiceExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using Microsoft.SemanticKernel.AI.ImageGeneration; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Services; // Use base namespace for better discoverability and to avoid conflicts with other extensions. @@ -17,11 +18,11 @@ public static class ImageGenerationServiceExtensions /// The service provider. /// Optional identifier of the desired service. /// The id matching the given id or the default. - /// Thrown when no suitable service is found. + /// Thrown when no suitable service is found. public static IImageGeneration GetImageGenerationService( this IAIServiceProvider services, string? serviceId = null) => services.GetService(serviceId) - ?? throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, "Image generation service not found"); + ?? throw new SKException("Image generation service not found"); /// /// Returns true if a exist with the specified ID. diff --git a/dotnet/src/SemanticKernel.Abstractions/AI/TextCompletion/TextCompletionServiceExtensions.cs b/dotnet/src/SemanticKernel.Abstractions/AI/TextCompletion/TextCompletionServiceExtensions.cs index 5a0a9308af28..bf5816db1d22 100644 --- a/dotnet/src/SemanticKernel.Abstractions/AI/TextCompletion/TextCompletionServiceExtensions.cs +++ b/dotnet/src/SemanticKernel.Abstractions/AI/TextCompletion/TextCompletionServiceExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using Microsoft.SemanticKernel.AI.TextCompletion; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Services; // Use base namespace for better discoverability and to avoid conflicts with other extensions. @@ -17,11 +18,11 @@ public static class TextCompletionServiceExtensions /// The service provider. /// Optional identifier of the desired service. /// The text completion service id matching the given ID or the default. - /// Thrown when no suitable service is found. + /// Thrown when no suitable service is found. public static ITextCompletion GetTextCompletionServiceOrDefault( this IAIServiceProvider services, string? serviceId = null) => services.GetService(serviceId) - ?? throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, "Text completion service not found"); + ?? throw new SKException("Text completion service not found"); /// /// Returns true if a exist with the specified ID. diff --git a/dotnet/src/SemanticKernel.Abstractions/KernelException.cs b/dotnet/src/SemanticKernel.Abstractions/KernelException.cs deleted file mode 100644 index 681fc4d81c71..000000000000 --- a/dotnet/src/SemanticKernel.Abstractions/KernelException.cs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using Microsoft.SemanticKernel.Diagnostics; - -namespace Microsoft.SemanticKernel; - -#pragma warning disable RCS1194 // Implement exception constructors - -/// -/// Exception thrown for errors related to kernel logic. -/// -public class KernelException : SKException -{ - /// - /// Initializes a new instance of the class with a provided error code and message. - /// - /// The error code. - /// The exception message. - public KernelException(ErrorCodes errorCode, string? message) - : this(errorCode, message, innerException: null) - { - } - - /// - /// Initializes a new instance of the class with a provided error code, message, and inner exception. - /// - /// The error code. - /// A string that describes the error. - /// The exception that is the cause of the current exception. - public KernelException(ErrorCodes errorCode, string? message = null, Exception? innerException = null) - : base(GetDefaultMessage(errorCode, message), innerException) - { - this.ErrorCode = errorCode; - } - - /// - /// Gets the error code for this exception. - /// - public ErrorCodes ErrorCode { get; } - - /// Translate the error code into a default message. - /// The error code. - /// Default error message if nothing available. - private static string GetDefaultMessage(ErrorCodes errorCode, string? defaultMessage) - { - string description = errorCode switch - { - ErrorCodes.InvalidFunctionDescription => "Invalid function description", - ErrorCodes.FunctionOverloadNotSupported => "Function overload not supported", - ErrorCodes.FunctionNotAvailable => "Function not available", - ErrorCodes.FunctionTypeNotSupported => "Function type not supported", - ErrorCodes.InvalidFunctionType => "Invalid function type", - ErrorCodes.InvalidServiceConfiguration => "Invalid service configuration", - ErrorCodes.ServiceNotFound => "Service not found", - ErrorCodes.SkillCollectionNotSet => "Skill collection not set", - ErrorCodes.FunctionInvokeError => "Function invoke error", - _ => $"Unknown error ({errorCode:G})", - }; - - return defaultMessage is not null ? $"{description}: {defaultMessage}" : description; - } - - /// - /// Semantic kernel error codes. - /// - public enum ErrorCodes - { - /// - /// Unknown error. - /// - UnknownError = -1, - - /// - /// Invalid function description. - /// - InvalidFunctionDescription, - - /// - /// Function overload not supported. - /// - FunctionOverloadNotSupported, - - /// - /// Function not available. - /// - FunctionNotAvailable, - - /// - /// Function type not supported. - /// - FunctionTypeNotSupported, - - /// - /// Invalid function type. - /// - InvalidFunctionType, - - /// - /// Invalid service configuration. - /// - InvalidServiceConfiguration, - - /// - /// Service not found. - /// - ServiceNotFound, - - /// - /// Skill collection not set. - /// - SkillCollectionNotSet, - - /// - /// Represents an error that occurs when invoking a function. - /// - FunctionInvokeError, - } -} diff --git a/dotnet/src/SemanticKernel.Abstractions/Orchestration/SKContext.cs b/dotnet/src/SemanticKernel.Abstractions/Orchestration/SKContext.cs index 39d9286e2a50..00b6ddc8df91 100644 --- a/dotnet/src/SemanticKernel.Abstractions/Orchestration/SKContext.cs +++ b/dotnet/src/SemanticKernel.Abstractions/Orchestration/SKContext.cs @@ -8,6 +8,7 @@ using System.Threading; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Memory; using Microsoft.SemanticKernel.SkillDefinition; @@ -199,7 +200,7 @@ public ISemanticTextMemory Memory public SKContext Fail(string errorDescription, Exception? exception = null) { // Temporary workaround: if no exception is provided, create a new one. - this.LastException = exception ?? new KernelException(KernelException.ErrorCodes.UnknownError, errorDescription); + this.LastException = exception ?? new SKException(errorDescription); return this; } diff --git a/dotnet/src/SemanticKernel.Abstractions/SkillDefinition/IReadOnlySkillCollection.cs b/dotnet/src/SemanticKernel.Abstractions/SkillDefinition/IReadOnlySkillCollection.cs index abcebb7bf762..ab11f32de871 100644 --- a/dotnet/src/SemanticKernel.Abstractions/SkillDefinition/IReadOnlySkillCollection.cs +++ b/dotnet/src/SemanticKernel.Abstractions/SkillDefinition/IReadOnlySkillCollection.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using System.Diagnostics.CodeAnalysis; +using Microsoft.SemanticKernel.Diagnostics; namespace Microsoft.SemanticKernel.SkillDefinition; @@ -15,7 +16,7 @@ public interface IReadOnlySkillCollection /// /// The name of the function to retrieve. /// The function retrieved from the collection. - /// The specified function could not be found in the collection. + /// The specified function could not be found in the collection. ISKFunction GetFunction(string functionName); /// @@ -24,7 +25,7 @@ public interface IReadOnlySkillCollection /// The name of the skill with which the function is associated. /// The name of the function to retrieve. /// The function retrieved from the collection. - /// The specified function could not be found in the collection. + /// The specified function could not be found in the collection. ISKFunction GetFunction(string skillName, string functionName); /// diff --git a/dotnet/src/SemanticKernel.Abstractions/SkillDefinition/NullReadOnlySkillCollection.cs b/dotnet/src/SemanticKernel.Abstractions/SkillDefinition/NullReadOnlySkillCollection.cs index 2b833e9b4151..7e78c8c0fc7f 100644 --- a/dotnet/src/SemanticKernel.Abstractions/SkillDefinition/NullReadOnlySkillCollection.cs +++ b/dotnet/src/SemanticKernel.Abstractions/SkillDefinition/NullReadOnlySkillCollection.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using Microsoft.SemanticKernel.Diagnostics; namespace Microsoft.SemanticKernel.SkillDefinition; @@ -10,28 +11,33 @@ internal sealed class NullReadOnlySkillCollection : IReadOnlySkillCollection { public static readonly NullReadOnlySkillCollection Instance = new(); + /// public ISKFunction GetFunction(string functionName) { return ThrowFunctionNotAvailable(functionName); } + /// public ISKFunction GetFunction(string skillName, string functionName) { return ThrowFunctionNotAvailable(skillName, functionName); } + /// public bool TryGetFunction(string functionName, [NotNullWhen(true)] out ISKFunction? availableFunction) { availableFunction = null; return false; } + /// public bool TryGetFunction(string skillName, string functionName, [NotNullWhen(true)] out ISKFunction? availableFunction) { availableFunction = null; return false; } + /// public FunctionsView GetFunctionsView(bool includeSemantic = true, bool includeNative = true) { return new(); @@ -44,16 +50,12 @@ private NullReadOnlySkillCollection() [DoesNotReturn] private static ISKFunction ThrowFunctionNotAvailable(string skillName, string functionName) { - throw new KernelException( - KernelException.ErrorCodes.FunctionNotAvailable, - $"Function not available: {skillName}.{functionName}"); + throw new SKException($"Function not available: {skillName}.{functionName}"); } [DoesNotReturn] private static ISKFunction ThrowFunctionNotAvailable(string functionName) { - throw new KernelException( - KernelException.ErrorCodes.FunctionNotAvailable, - $"Function not available: {functionName}"); + throw new SKException($"Function not available: {functionName}"); } } diff --git a/dotnet/src/SemanticKernel.UnitTests/KernelExceptionTests.cs b/dotnet/src/SemanticKernel.UnitTests/KernelExceptionTests.cs deleted file mode 100644 index 3bb684cda1ec..000000000000 --- a/dotnet/src/SemanticKernel.UnitTests/KernelExceptionTests.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using System; -using Microsoft.SemanticKernel; -using Xunit; - -namespace SemanticKernel.UnitTests; - -public class KernelExceptionTests -{ - [Fact] - public void ItRoundtripsArgsToErrorCodeCtor() - { - // Arrange - var e = new KernelException(KernelException.ErrorCodes.FunctionNotAvailable); - - // Assert - Assert.Equal(KernelException.ErrorCodes.FunctionNotAvailable, e.ErrorCode); - Assert.Contains("Function not available", e.Message, StringComparison.Ordinal); - Assert.Null(e.InnerException); - } - - [Fact] - public void ItRoundtripsArgsToErrorCodeMessageCtor() - { - // Arrange - const string Message = "this is a test"; - var e = new KernelException(KernelException.ErrorCodes.FunctionNotAvailable, Message); - - // Assert - Assert.Equal(KernelException.ErrorCodes.FunctionNotAvailable, e.ErrorCode); - Assert.Contains("Function not available", e.Message, StringComparison.Ordinal); - Assert.Contains(Message, e.Message, StringComparison.Ordinal); - Assert.Null(e.InnerException); - } - - [Fact] - public void ItRoundtripsArgsToErrorCodeMessageExceptionCtor() - { - // Arrange - const string Message = "this is a test"; - var inner = new FormatException(); - var e = new KernelException(KernelException.ErrorCodes.FunctionNotAvailable, Message, inner); - - // Assert - Assert.Equal(KernelException.ErrorCodes.FunctionNotAvailable, e.ErrorCode); - Assert.Contains("Function not available", e.Message, StringComparison.Ordinal); - Assert.Contains(Message, e.Message, StringComparison.Ordinal); - Assert.Same(inner, e.InnerException); - } - - [Fact] - public void ItAllowsNullMessageAndInnerExceptionInCtors() - { - // Arrange - var e = new KernelException(KernelException.ErrorCodes.FunctionNotAvailable, null, null); - - // Assert - Assert.Equal(KernelException.ErrorCodes.FunctionNotAvailable, e.ErrorCode); - Assert.Contains("Function not available", e.Message, StringComparison.Ordinal); - Assert.Null(e.InnerException); - } -} diff --git a/dotnet/src/SemanticKernel.UnitTests/Planning/PlanSerializationTests.cs b/dotnet/src/SemanticKernel.UnitTests/Planning/PlanSerializationTests.cs index 09b64562d5cd..a14d73f519a4 100644 --- a/dotnet/src/SemanticKernel.UnitTests/Planning/PlanSerializationTests.cs +++ b/dotnet/src/SemanticKernel.UnitTests/Planning/PlanSerializationTests.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.AI.TextCompletion; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Orchestration; using Microsoft.SemanticKernel.Planning; using Microsoft.SemanticKernel.SkillDefinition; @@ -563,7 +564,7 @@ public void DeserializeWithMissingFunctions(bool requireFunctions) if (requireFunctions) { // Act + Assert - Assert.Throws(() => Plan.FromJson(serializedPlan, returnContext)); + Assert.Throws(() => Plan.FromJson(serializedPlan, returnContext)); } else { diff --git a/dotnet/src/SemanticKernel.UnitTests/Planning/PlanTests.cs b/dotnet/src/SemanticKernel.UnitTests/Planning/PlanTests.cs index 84fb7157e7b2..efcc33ae3d2e 100644 --- a/dotnet/src/SemanticKernel.UnitTests/Planning/PlanTests.cs +++ b/dotnet/src/SemanticKernel.UnitTests/Planning/PlanTests.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.AI.TextCompletion; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Orchestration; using Microsoft.SemanticKernel.Planning; using Microsoft.SemanticKernel.SkillDefinition; @@ -359,7 +360,7 @@ public async Task StepExceptionIsThrownAsync() // Act var cv = new ContextVariables(planInput); - await Assert.ThrowsAsync(async () => await kernel.Object.StepAsync(cv, plan)); + await Assert.ThrowsAsync(async () => await kernel.Object.StepAsync(cv, plan)); mockFunction.Verify(x => x.InvokeAsync(It.IsAny(), null, It.IsAny()), Times.Once); } @@ -388,7 +389,7 @@ public async Task PlanStepExceptionIsThrownAsync() // Act var cv = new ContextVariables(planInput); - await Assert.ThrowsAsync(async () => await kernel.Object.StepAsync(cv, plan)); + await Assert.ThrowsAsync(async () => await kernel.Object.StepAsync(cv, plan)); mockFunction.Verify(x => x.InvokeAsync(It.IsAny(), null, It.IsAny()), Times.Once); } diff --git a/dotnet/src/SemanticKernel.UnitTests/SkillDefinition/SKFunctionTests3.cs b/dotnet/src/SemanticKernel.UnitTests/SkillDefinition/SKFunctionTests3.cs index 0e8acbbb1d35..2d3d1777204c 100644 --- a/dotnet/src/SemanticKernel.UnitTests/SkillDefinition/SKFunctionTests3.cs +++ b/dotnet/src/SemanticKernel.UnitTests/SkillDefinition/SKFunctionTests3.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Orchestration; using Microsoft.SemanticKernel.SkillDefinition; using Xunit; @@ -67,7 +68,7 @@ public void ItThrowsForInvalidFunctions() { SKFunction.FromNativeMethod(method, instance, "skill"); } - catch (KernelException e) when (e.ErrorCode is KernelException.ErrorCodes.FunctionTypeNotSupported or KernelException.ErrorCodes.InvalidFunctionDescription) + catch (SKException) { count++; } diff --git a/dotnet/src/SemanticKernel/Kernel.cs b/dotnet/src/SemanticKernel/Kernel.cs index d9b9bf8b91b5..c3c4897caf22 100644 --- a/dotnet/src/SemanticKernel/Kernel.cs +++ b/dotnet/src/SemanticKernel/Kernel.cs @@ -238,7 +238,7 @@ public T GetService(string? name = null) where T : IAIService return service; } - throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, $"Service of type {typeof(T)} and name {name ?? ""} not registered."); + throw new SKException($"Service of type {typeof(T)} and name {name ?? ""} not registered."); } /// @@ -312,9 +312,7 @@ private static Dictionary ImportSkill(object skillInstance, ISKFunction function = SKFunction.FromNativeMethod(method, skillInstance, skillName, logger); if (result.ContainsKey(function.Name)) { - throw new KernelException( - KernelException.ErrorCodes.FunctionOverloadNotSupported, - "Function overloads are not supported, please differentiate function names"); + throw new SKException("Function overloads are not supported, please differentiate function names"); } result.Add(function.Name, function); diff --git a/dotnet/src/SemanticKernel/Planning/Plan.cs b/dotnet/src/SemanticKernel/Planning/Plan.cs index d15a11545ef5..57df53e01404 100644 --- a/dotnet/src/SemanticKernel/Planning/Plan.cs +++ b/dotnet/src/SemanticKernel/Planning/Plan.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.SemanticKernel.AI.TextCompletion; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Orchestration; using Microsoft.SemanticKernel.SkillDefinition; @@ -239,7 +240,7 @@ public Task RunNextStepAsync(IKernel kernel, ContextVariables variables, C /// Context to use /// The to monitor for cancellation requests. The default is . /// The updated plan - /// If an error occurs while running the plan + /// If an error occurs while running the plan public async Task InvokeNextStepAsync(SKContext context, CancellationToken cancellationToken = default) { if (this.HasNextStep) @@ -256,8 +257,7 @@ public async Task InvokeNextStepAsync(SKContext context, CancellationToken if (result.ErrorOccurred) { - throw new KernelException(KernelException.ErrorCodes.FunctionInvokeError, - $"Error occurred while running plan step: {result.LastException?.Message}", result.LastException); + throw new SKException($"Error occurred while running plan step: {result.LastException?.Message}", result.LastException); } #region Update State @@ -398,9 +398,7 @@ private static Plan SetAvailableFunctions(Plan plan, SKContext context, bool req { if (context.Skills == null) { - throw new KernelException( - KernelException.ErrorCodes.SkillCollectionNotSet, - "Skill collection not found in the context"); + throw new SKException("Skill collection not found in the context"); } if (context.Skills.TryGetFunction(plan.SkillName, plan.Name, out var skillFunction)) @@ -409,9 +407,7 @@ private static Plan SetAvailableFunctions(Plan plan, SKContext context, bool req } else if (requireFunctions) { - throw new KernelException( - KernelException.ErrorCodes.FunctionNotAvailable, - $"Function '{plan.SkillName}.{plan.Name}' not found in skill collection"); + throw new SKException($"Function '{plan.SkillName}.{plan.Name}' not found in skill collection"); } } else diff --git a/dotnet/src/SemanticKernel/SkillDefinition/NativeFunction.cs b/dotnet/src/SemanticKernel/SkillDefinition/NativeFunction.cs index c47b1889251f..bc485e92a467 100644 --- a/dotnet/src/SemanticKernel/SkillDefinition/NativeFunction.cs +++ b/dotnet/src/SemanticKernel/SkillDefinition/NativeFunction.cs @@ -261,14 +261,12 @@ internal NativeFunction( /// /// Throw an exception if the function is not semantic, use this method when some logic makes sense only for semantic functions. /// - /// + /// [DoesNotReturn] private void ThrowNotSemantic() { this._logger.LogError("The function is not semantic"); - throw new KernelException( - KernelException.ErrorCodes.InvalidFunctionType, - "Invalid operation, the method requires a semantic function"); + throw new SKException("Invalid operation, the method requires a semantic function"); } private static MethodDetails GetMethodDetails( @@ -495,7 +493,7 @@ private static (Func, ParameterView?) Get } // 4. Otherwise, fail. - throw new KernelException(KernelException.ErrorCodes.FunctionInvokeError, $"Missing value for parameter '{name}'"); + throw new SKException($"Missing value for parameter '{name}'"); object? Process(string value) { @@ -662,15 +660,13 @@ private static (Func, ParameterView?) Get // Throws an exception if a result is found to be null unexpectedly static object ThrowIfNullResult(object? result) => result ?? - throw new KernelException(KernelException.ErrorCodes.FunctionInvokeError, "Function returned null unexpectedly."); + throw new SKException("Function returned null unexpectedly."); } /// Gets an exception that can be thrown indicating an invalid signature. [DoesNotReturn] private static Exception GetExceptionForInvalidSignature(MethodInfo method, string reason) => - throw new KernelException( - KernelException.ErrorCodes.FunctionTypeNotSupported, - $"Function '{method.Name}' is not supported by the kernel. {reason}"); + throw new SKException($"Function '{method.Name}' is not supported by the kernel. {reason}"); /// Throws an exception indicating an invalid SKFunction signature if the specified condition is not met. private static void ThrowForInvalidSignatureIf([DoesNotReturnIf(true)] bool condition, MethodInfo method, string reason) diff --git a/dotnet/src/SemanticKernel/SkillDefinition/SkillCollection.cs b/dotnet/src/SemanticKernel/SkillDefinition/SkillCollection.cs index a0d0ca5833ba..1e36d9ca6889 100644 --- a/dotnet/src/SemanticKernel/SkillDefinition/SkillCollection.cs +++ b/dotnet/src/SemanticKernel/SkillDefinition/SkillCollection.cs @@ -106,9 +106,7 @@ public FunctionsView GetFunctionsView(bool includeSemantic = true, bool includeN private void ThrowFunctionNotAvailable(string skillName, string functionName) { this._logger.LogError("Function not available: skill:{0} function:{1}", skillName, functionName); - throw new KernelException( - KernelException.ErrorCodes.FunctionNotAvailable, - $"Function not available {skillName}.{functionName}"); + throw new SKException($"Function not available {skillName}.{functionName}"); } private readonly ILogger _logger; diff --git a/dotnet/src/SemanticKernel/TemplateEngine/Blocks/CodeBlock.cs b/dotnet/src/SemanticKernel/TemplateEngine/Blocks/CodeBlock.cs index 6c7e047069e7..2e254942a6f6 100644 --- a/dotnet/src/SemanticKernel/TemplateEngine/Blocks/CodeBlock.cs +++ b/dotnet/src/SemanticKernel/TemplateEngine/Blocks/CodeBlock.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Orchestration; using Microsoft.SemanticKernel.SkillDefinition; @@ -115,9 +116,7 @@ private async Task RenderFunctionCallAsync(FunctionIdBlock fBlock, SKCon { if (context.Skills == null) { - throw new KernelException( - KernelException.ErrorCodes.SkillCollectionNotSet, - "Skill collection not found in the context"); + throw new SKException("Skill collection not found in the context"); } if (!this.GetFunctionFromSkillCollection(context.Skills!, fBlock, out ISKFunction? function)) diff --git a/dotnet/src/Skills/Skills.OpenAPI/Extensions/KernelAIPluginExtensions.cs b/dotnet/src/Skills/Skills.OpenAPI/Extensions/KernelAIPluginExtensions.cs index dc77b59de1f1..63dd79ff4c03 100644 --- a/dotnet/src/Skills/Skills.OpenAPI/Extensions/KernelAIPluginExtensions.cs +++ b/dotnet/src/Skills/Skills.OpenAPI/Extensions/KernelAIPluginExtensions.cs @@ -387,7 +387,7 @@ private static string ConvertOperationIdToValidFunctionName(string operationId, Verify.ValidFunctionName(operationId); return operationId; } - catch (KernelException) + catch (SKException) { } diff --git a/dotnet/src/Skills/Skills.OpenAPI/Extensions/KernelOpenApiExtensions.cs b/dotnet/src/Skills/Skills.OpenAPI/Extensions/KernelOpenApiExtensions.cs index 6d296a3b9562..836226604425 100644 --- a/dotnet/src/Skills/Skills.OpenAPI/Extensions/KernelOpenApiExtensions.cs +++ b/dotnet/src/Skills/Skills.OpenAPI/Extensions/KernelOpenApiExtensions.cs @@ -325,7 +325,7 @@ private static string ConvertOperationIdToValidFunctionName(string operationId, Verify.ValidFunctionName(operationId); return operationId; } - catch (KernelException) + catch (SKException) { } diff --git a/dotnet/src/Skills/Skills.UnitTests/MsGraph/CalendarSkillTests.cs b/dotnet/src/Skills/Skills.UnitTests/MsGraph/CalendarSkillTests.cs index f9447c499243..10e52198b825 100644 --- a/dotnet/src/Skills/Skills.UnitTests/MsGraph/CalendarSkillTests.cs +++ b/dotnet/src/Skills/Skills.UnitTests/MsGraph/CalendarSkillTests.cs @@ -4,7 +4,7 @@ using System.Globalization; using System.Threading; using System.Threading.Tasks; -using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.Diagnostics; using Microsoft.SemanticKernel.Skills.MsGraph; using Microsoft.SemanticKernel.Skills.MsGraph.Models; using Moq; @@ -191,8 +191,7 @@ public async Task AddEventAsyncWithoutStartFailsAsync() // Assert Assert.True(context.ErrorOccurred); - KernelException e = Assert.IsType(context.LastException); - Assert.Equal(KernelException.ErrorCodes.FunctionInvokeError, e.ErrorCode); + Assert.IsType(context.LastException); } [Fact] @@ -219,8 +218,7 @@ public async Task AddEventAsyncWithoutEndFailsAsync() // Assert Assert.True(context.ErrorOccurred); - KernelException e = Assert.IsType(context.LastException); - Assert.Equal(KernelException.ErrorCodes.FunctionInvokeError, e.ErrorCode); + Assert.IsType(context.LastException); } [Fact]