From 44b27cdf1c1af071ec2eba2ca30f0d48621afc80 Mon Sep 17 00:00:00 2001 From: Milder Hernandez Cagua Date: Thu, 17 Apr 2025 09:00:39 -0700 Subject: [PATCH 1/4] Add AIServiceSelector.trySelectAIService(Class,KernelArguments) and related updates --- .../com/microsoft/semantickernel/Kernel.java | 27 +++++++++++++-- .../semanticfunctions/KernelArguments.java | 10 ++++++ .../KernelFunctionFromPrompt.java | 8 +++-- .../services/AIServiceSelector.java | 26 ++++++++++++++- .../services/BaseAIServiceSelector.java | 33 +++++++++++++++++++ .../services/OrderedAIServiceSelector.java | 16 +++++---- 6 files changed, 107 insertions(+), 13 deletions(-) diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java index cf38760f..d8059ef7 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java @@ -302,14 +302,12 @@ public AIServiceSelector getServiceSelector() { * @param clazz The class of the service to get. * @return The service of the specified type from the kernel. * @throws ServiceNotFoundException if the service is not found. - * @see com.microsoft.semantickernel.services.AIServiceSelector#trySelectAIService(Class, - * KernelFunction, KernelArguments) + * @see com.microsoft.semantickernel.services.AIServiceSelector#trySelectAIService(Class, KernelArguments) */ public T getService(Class clazz) throws ServiceNotFoundException { AIServiceSelection selector = serviceSelector .trySelectAIService( clazz, - null, null); if (selector == null) { @@ -319,6 +317,29 @@ public T getService(Class clazz) throws ServiceNotFound return selector.getService(); } + /** + * Get the service of the specified type from the kernel. + * + * @param The type of the service to get. + * @param clazz The class of the service to get. + * @param args The arguments to help select the service to get. + * @return The service of the specified type from the kernel. + * @throws ServiceNotFoundException if the service is not found. + * @see com.microsoft.semantickernel.services.AIServiceSelector#trySelectAIService(Class, KernelArguments) + */ + public T getService(Class clazz, KernelArguments args) throws ServiceNotFoundException { + AIServiceSelection selector = serviceSelector + .trySelectAIService( + clazz, + args); + + if (selector == null) { + throw new ServiceNotFoundException("Unable to find service of type " + clazz.getName()); + } + + return selector.getService(); + } + /** * A fluent builder for creating a new instance of {@code Kernel}. */ diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java index 80ec5972..8f731915 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java @@ -360,6 +360,16 @@ public Builder withVariable(String key, T value, value)); } + /** + * Set prompt execution settings + * + * @param executionSettings Execution settings + * @return {$code this} Builder for fluent coding + */ + public Builder withExecutionSettings(PromptExecutionSettings executionSettings) { + return withExecutionSettings(Collections.singletonList(executionSettings)); + } + /** * Set prompt execution settings * diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java index 1d12f961..7671e9e1 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java @@ -133,13 +133,17 @@ private Flux> invokeInternalAsync( FunctionInvokingEvent updateArguments = kernelHooks .executeHooks(new FunctionInvokingEvent(this, args)); - args = updateArguments.getArguments(); + + args = KernelArguments.builder() + .withVariables(updateArguments.getArguments()) + .withExecutionSettings( + this.getExecutionSettings()) + .build(); AIServiceSelection aiServiceSelection = kernel .getServiceSelector() .trySelectAIService( TextAIService.class, - this, args); AIService client = aiServiceSelection != null ? aiServiceSelection.getService() diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java index e68e6a69..9116add4 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java @@ -20,15 +20,39 @@ public interface AIServiceSelector { * @param serviceType The type of service to select. This must be the same type with which the * service was registered in the {@link AIServiceSelection} * @param function The KernelFunction to use to select the service, or {@code null}. - * @param arguments The KernelFunctionArguments to use to select the service, or + * @param arguments The KernelArguments to use to select the service, or * {@code null}. * @param The type of service to select. * @return An {@code AIServiceSelection} containing the selected service and associated * PromptExecutionSettings. + * + * @deprecated Use {@link #trySelectAIService(Class, KernelArguments)} instead. */ + @Deprecated @Nullable AIServiceSelection trySelectAIService( Class serviceType, @Nullable KernelFunction function, @Nullable KernelArguments arguments); + + /** + * Resolves an {@link AIService} and associated and + * {@link com.microsoft.semantickernel.orchestration.PromptExecutionSettings} based on the + * associated {@link KernelFunction} and {@link KernelArguments}. + * + * @param serviceType The type of service to select. This must be the same type with which the + * service was registered in the {@link AIServiceSelection} + * @param arguments The KernelArguments to use to select the service, or + * {@code null}. + * @param The type of service to select. + * @return An {@code AIServiceSelection} containing the selected service and associated + * PromptExecutionSettings. + */ + @Nullable + default AIServiceSelection trySelectAIService( + Class serviceType, + @Nullable KernelArguments arguments) { + throw new UnsupportedOperationException( + "This method is not implemented."); + } } diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java index c3e42b8e..eb745894 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java @@ -35,6 +35,14 @@ public AIServiceSelection trySelectAIService( return trySelectAIService(serviceType, function, arguments, services); } + @Override + @Nullable + public AIServiceSelection trySelectAIService( + Class serviceType, + @Nullable KernelArguments arguments) { + return trySelectAIService(serviceType, arguments, services); + } + /** * Resolves an {@link AIService} from the {@code services} argument using the specified * {@code function} and {@code arguments} for selection. @@ -47,11 +55,36 @@ public AIServiceSelection trySelectAIService( * @param services The services to select from. * @param The type of service to select. * @return The selected service, or {@code null} if no service could be selected. + * + * @deprecated Implement {@link #trySelectAIService(Class, KernelArguments)} */ + @Deprecated @Nullable protected abstract AIServiceSelection trySelectAIService( Class serviceType, @Nullable KernelFunction function, @Nullable KernelArguments arguments, Map, AIService> services); + + + /** + * Resolves an {@link AIService} from the {@code services} argument using the specified + * {@code function} and {@code arguments} for selection. + * + * @param serviceType The type of service to select. This must be the same type with which the + * service was registered in the {@link AIServiceSelection} + * @param arguments The KernelArguments to use to select the service, or + * {@code null}. + * @param services The services to select from. + * @param The type of service to select. + * @return The selected service, or {@code null} if no service could be selected. + */ + @Nullable + protected AIServiceSelection trySelectAIService( + Class serviceType, + @Nullable KernelArguments arguments, + Map, AIService> services) { + throw new UnsupportedOperationException( + "This method is not implemented."); + } } diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java index 2be73543..d478a41f 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java @@ -66,13 +66,15 @@ private static Map settingsFromFunctionSettings return null; } -// @Nullable -// @Override -// public AIServiceSelection trySelectAIService( -// Class serviceType, -// @Nullable KernelArguments arguments) { -// return selectAIService(serviceType, arguments.getPromptExecutionSettings()); -// } + @Nullable + @Override + public AIServiceSelection trySelectAIService( + Class serviceType, + @Nullable KernelArguments arguments, + Map, AIService> services) { + + return selectAIService(serviceType, arguments != null ? arguments.getExecutionSettings() : null); + } @Nullable @Override From 5859394d4bbde27e2a0d97fc09f2e9de8e34d8b4 Mon Sep 17 00:00:00 2001 From: Milder Hernandez Cagua Date: Thu, 24 Apr 2025 00:46:49 -0700 Subject: [PATCH 2/4] Updates to service selector --- .../services/AIServiceSelector.java | 3 --- .../services/BaseAIServiceSelector.java | 5 +--- .../services/OrderedAIServiceSelector.java | 27 +++---------------- 3 files changed, 5 insertions(+), 30 deletions(-) diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java index 9116add4..ac95f7d3 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/AIServiceSelector.java @@ -25,10 +25,7 @@ public interface AIServiceSelector { * @param The type of service to select. * @return An {@code AIServiceSelection} containing the selected service and associated * PromptExecutionSettings. - * - * @deprecated Use {@link #trySelectAIService(Class, KernelArguments)} instead. */ - @Deprecated @Nullable AIServiceSelection trySelectAIService( Class serviceType, diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java index eb745894..03ecdd78 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/BaseAIServiceSelector.java @@ -56,9 +56,7 @@ public AIServiceSelection trySelectAIService( * @param The type of service to select. * @return The selected service, or {@code null} if no service could be selected. * - * @deprecated Implement {@link #trySelectAIService(Class, KernelArguments)} */ - @Deprecated @Nullable protected abstract AIServiceSelection trySelectAIService( Class serviceType, @@ -84,7 +82,6 @@ protected AIServiceSelection trySelectAIService( Class serviceType, @Nullable KernelArguments arguments, Map, AIService> services) { - throw new UnsupportedOperationException( - "This method is not implemented."); + return trySelectAIService(serviceType, null, arguments, services); } } diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java index d478a41f..6b04fe2b 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/OrderedAIServiceSelector.java @@ -57,25 +57,6 @@ private static AIServiceSelection castServiceSelection( } } - @Nullable - private static Map settingsFromFunctionSettings( - @Nullable KernelFunction function) { - if (function != null) { - return function.getExecutionSettings(); - } - return null; - } - - @Nullable - @Override - public AIServiceSelection trySelectAIService( - Class serviceType, - @Nullable KernelArguments arguments, - Map, AIService> services) { - - return selectAIService(serviceType, arguments != null ? arguments.getExecutionSettings() : null); - } - @Nullable @Override public AIServiceSelection trySelectAIService( @@ -84,11 +65,11 @@ public AIServiceSelection trySelectAIService( @Nullable KernelArguments arguments, Map, AIService> services) { - // Allow the execution settings from the kernel arguments to take precedence - Map executionSettings = settingsFromFunctionSettings( - function); + if (function == null) { + return selectAIService(serviceType, arguments != null ? arguments.getExecutionSettings() : null); + } - return selectAIService(serviceType, executionSettings); + return selectAIService(serviceType, function.getExecutionSettings()); } From 393d987f3b31093a4f86ab08738474480f3c1b64 Mon Sep 17 00:00:00 2001 From: Milder Hernandez Cagua Date: Thu, 24 Apr 2025 01:16:08 -0700 Subject: [PATCH 3/4] Remove unnecessary line --- .../com/microsoft/semantickernel/tests/ResponseSchemaTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java index 77d4b4a3..ef792e2b 100644 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java +++ b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java @@ -160,8 +160,6 @@ private static void verifyCalled(OpenAIAsyncClient client, String expected) { writer, new JsonOptions() ); - JsonWriter format = chatCompletionsOptions.getResponseFormat() - .toJson(jsonWriter); jsonWriter.flush(); writer.flush(); From 17a920eb514ed50364b3b0bf442ffff63015f79b Mon Sep 17 00:00:00 2001 From: Milder Hernandez Cagua Date: Thu, 24 Apr 2025 02:10:09 -0700 Subject: [PATCH 4/4] Fixes --- .../microsoft/semantickernel/tests/ResponseSchemaTest.java | 4 ++++ .../semantickernel/semanticfunctions/KernelArguments.java | 2 ++ .../semanticfunctions/KernelFunctionFromPrompt.java | 7 +++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java index ef792e2b..4ec67774 100644 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java +++ b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ResponseSchemaTest.java @@ -160,15 +160,19 @@ private static void verifyCalled(OpenAIAsyncClient client, String expected) { writer, new JsonOptions() ); + JsonWriter format = chatCompletionsOptions.getResponseFormat() + .toJson(jsonWriter); jsonWriter.flush(); writer.flush(); String json = String.valueOf(writer.getBuffer()) .replaceAll("\n", "") + .replaceAll("\r", "") .replaceAll(" +", ""); String expectedClean = expected .stripIndent() .replaceAll("\n", "") + .replaceAll("\r", "") .replaceAll(" +", ""); return json.equals(expectedClean); diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java index 8f731915..e4fb8319 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java @@ -409,6 +409,8 @@ public Builder withExecutionSettings(List executionS serviceId) ); } + + this.executionSettings.put(serviceId, settings); } return this; diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java index 7671e9e1..2ea90974 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionFromPrompt.java @@ -131,13 +131,12 @@ private Flux> invokeInternalAsync( LOGGER.info(SemanticKernelResources.getString("rendered.prompt"), prompt); - FunctionInvokingEvent updateArguments = kernelHooks + FunctionInvokingEvent invokingEvent = kernelHooks .executeHooks(new FunctionInvokingEvent(this, args)); args = KernelArguments.builder() - .withVariables(updateArguments.getArguments()) - .withExecutionSettings( - this.getExecutionSettings()) + .withVariables(invokingEvent.getArguments()) + .withExecutionSettings(this.getExecutionSettings()) .build(); AIServiceSelection aiServiceSelection = kernel