From e6f910ec3cf57fa5ec8373dce010d0f19170c308 Mon Sep 17 00:00:00 2001 From: Govind Kamtamneni Date: Wed, 5 Apr 2023 11:00:59 -0700 Subject: [PATCH 1/3] add gRPC skill client in c# and server in java for random skill --- dotnet/SK-dotnet.sln | 7 ++ .../GrpcSkillRunner/GrpcSkillRunner.csproj | 19 +++ samples/dotnet/GrpcSkillRunner/Program.cs | 79 +++++++++++++ .../GrpcSkillRunner/Protos/activity.proto | 30 +++++ samples/java/JavaReferenceSkill/.gitignore | 38 ++++++ samples/java/JavaReferenceSkill/README.md | 23 ++++ samples/java/JavaReferenceSkill/pom.xml | 109 ++++++++++++++++++ .../semantickernel/skills/random/Main.java | 28 +++++ .../skills/random/RandomActivitySkill.java | 41 +++++++ .../src/main/proto/activity.proto | 30 +++++ .../random/RandomActivitySkillTest.java | 50 ++++++++ 11 files changed, 454 insertions(+) create mode 100644 samples/dotnet/GrpcSkillRunner/GrpcSkillRunner.csproj create mode 100644 samples/dotnet/GrpcSkillRunner/Program.cs create mode 100644 samples/dotnet/GrpcSkillRunner/Protos/activity.proto create mode 100644 samples/java/JavaReferenceSkill/.gitignore create mode 100644 samples/java/JavaReferenceSkill/README.md create mode 100644 samples/java/JavaReferenceSkill/pom.xml create mode 100644 samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/Main.java create mode 100644 samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/RandomActivitySkill.java create mode 100644 samples/java/JavaReferenceSkill/src/main/proto/activity.proto create mode 100644 samples/java/JavaReferenceSkill/src/test/java/com/microsoft/semantickernel/skills/random/RandomActivitySkillTest.java diff --git a/dotnet/SK-dotnet.sln b/dotnet/SK-dotnet.sln index eb34c6c394b9..55124c17acc0 100644 --- a/dotnet/SK-dotnet.sln +++ b/dotnet/SK-dotnet.sln @@ -66,6 +66,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaSkillRunner", "..\sampl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetReferenceSkill", "..\samples\dotnet\DotnetReferenceSkill\DotnetReferenceSkill.csproj", "{D49FC00D-3102-43B6-8120-093EF2FACA03}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcSkillRunner", "..\samples\dotnet\GrpcSkillRunner\GrpcSkillRunner.csproj", "{A2A10C59-4EE4-46C7-8BF7-00317AA1E5AD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -148,6 +150,10 @@ Global {D49FC00D-3102-43B6-8120-093EF2FACA03}.Debug|Any CPU.Build.0 = Debug|Any CPU {D49FC00D-3102-43B6-8120-093EF2FACA03}.Release|Any CPU.ActiveCfg = Release|Any CPU {D49FC00D-3102-43B6-8120-093EF2FACA03}.Release|Any CPU.Build.0 = Release|Any CPU + {A2A10C59-4EE4-46C7-8BF7-00317AA1E5AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2A10C59-4EE4-46C7-8BF7-00317AA1E5AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2A10C59-4EE4-46C7-8BF7-00317AA1E5AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2A10C59-4EE4-46C7-8BF7-00317AA1E5AD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -174,6 +180,7 @@ Global {8FBB03E4-7402-40D3-8A8A-BA1F327F6BF8} = {0E881C20-29A5-454D-97D0-9FEC762BBEFF} {5EB48620-02BE-4143-ABF8-F415D413EFE7} = {0E881C20-29A5-454D-97D0-9FEC762BBEFF} {D49FC00D-3102-43B6-8120-093EF2FACA03} = {0E881C20-29A5-454D-97D0-9FEC762BBEFF} + {A2A10C59-4EE4-46C7-8BF7-00317AA1E5AD} = {0E881C20-29A5-454D-97D0-9FEC762BBEFF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FBDC56A3-86AD-4323-AA0F-201E59123B83} diff --git a/samples/dotnet/GrpcSkillRunner/GrpcSkillRunner.csproj b/samples/dotnet/GrpcSkillRunner/GrpcSkillRunner.csproj new file mode 100644 index 000000000000..a2760920213b --- /dev/null +++ b/samples/dotnet/GrpcSkillRunner/GrpcSkillRunner.csproj @@ -0,0 +1,19 @@ + + + + Exe + net7.0 + + + + + + + + + + + + + + diff --git a/samples/dotnet/GrpcSkillRunner/Program.cs b/samples/dotnet/GrpcSkillRunner/Program.cs new file mode 100644 index 000000000000..7ccde063e43a --- /dev/null +++ b/samples/dotnet/GrpcSkillRunner/Program.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System; +using Grpc.Net.Client; +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.KernelExtensions; +using Microsoft.SemanticKernel.Orchestration; +using ReferenceSkill; + +const string RANDOM_ACTIVITY_PROMPT = "Find me an activity to do, return only a single activity. I like to {{$INPUT}}. Be creative!"; +const string DEGREES_OF_SEPARATION_PROMPT = "How many degrees of separation are there between {{$ITEM1}} and {{$ITEM2}}? Bonus points for Kevin Bacon reference."; +const string THING_I_LIKE_TO_DO = "surf"; + +//configure your Azure OpenAI backend +var key = ""; +var endpoint = ""; +var model = ""; + +//configure gRPC server address +const string DEFAULT_GRPC_SERVER_ADDRESS = "localhost:50051"; + +var sk = Kernel.Builder.Configure(c => c.AddAzureOpenAICompletionBackend(model, model, endpoint, key)).Build(); + +#region Semantic Function Loading + +sk.CreateSemanticFunction(RANDOM_ACTIVITY_PROMPT, + skillName: "RandomActivityLLMSkill", + functionName: "GetRandomActivity", + description: "Finds a random activity based on the interest input", + maxTokens: 256, + temperature: 0.1, + topP: 0.5); + +sk.CreateSemanticFunction(DEGREES_OF_SEPARATION_PROMPT, + skillName: "DegreesOfSeparation", + functionName: "FindDegrees", + description: "Returns the degrees of separation between two concepts.", + maxTokens: 256, + temperature: 0.2, + topP: 0.5); + +#endregion + +//TODO: load your python skill here +//currently loading a skill that will pull a random activity from an API. +//We will compare the activity to the one from the LLM and return true if they match, false if not +// var randomActivitySkill = new RandomActivitySkill(); +// sk.ImportSkill(randomActivitySkill, nameof(RandomActivitySkill)); + +var llmResult = string.Empty; +var apiResult = string.Empty; + +//ask the LLM for a random activity +var llmRandomActivityResult = await sk.RunAsync(THING_I_LIKE_TO_DO, sk.Skills.GetSemanticFunction("RandomActivityLLMSkill", "GetRandomActivity")); +llmResult = llmRandomActivityResult.Result; +Console.WriteLine("LLM suggested: " + llmResult); + +//ask the skill to find us a random activity via gRPC +var serverAddress = Environment.GetEnvironmentVariable("GRPC_SERVER_ADDRESS") ?? DEFAULT_GRPC_SERVER_ADDRESS; +using var channel = GrpcChannel.ForAddress(serverAddress); + +// Create client for random activity skill +var randomActivityClient = new RandomActivitySkill.RandomActivitySkillClient(channel); + +// Call gRPC service to get random activity +var randomActivityResponse = await randomActivityClient.GetRandomActivityAsync(new GetRandomActivityRequest { Input = THING_I_LIKE_TO_DO }); +apiResult = randomActivityResponse.Activity; +Console.WriteLine($"Random Activity: {apiResult}"); + +Console.WriteLine("Press any key to exit..."); +Console.ReadKey(); + +//lastly, for fun, find out how many degrees of separation exist between these concepts :) +var contextVariables = new ContextVariables(); +contextVariables.Set("Item1", llmResult); +contextVariables.Set("Item2", apiResult); + +var llmDegreesOfSeparationResult = await sk.RunAsync(contextVariables, sk.Skills.GetSemanticFunction("DegreesOfSeparation", "FindDegrees")); +Console.WriteLine("Degrees of separation: " + llmDegreesOfSeparationResult.Result); diff --git a/samples/dotnet/GrpcSkillRunner/Protos/activity.proto b/samples/dotnet/GrpcSkillRunner/Protos/activity.proto new file mode 100644 index 000000000000..ac09fb2b676f --- /dev/null +++ b/samples/dotnet/GrpcSkillRunner/Protos/activity.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package reference_skill; + +// GetRandomActivityRequest is a message that contains input for the GetRandomActivity RPC method. +message GetRandomActivityRequest { + string input = 1; // Input is a hobby that is use to generate a random activity. +} + +// GetRandomActivityResponse is a message that contains the activity returned by the GetRandomActivity RPC method. +message GetRandomActivityResponse { + string activity = 1; // Activity is a description of the random activity. +} + +// RandomActivitySkill is a service that provides methods related to random activities. +service RandomActivitySkill { + // GetRandomActivity is an RPC method that retrieves a random activity from an API. + rpc GetRandomActivity (GetRandomActivityRequest) returns (GetRandomActivityResponse); +} + +// Activity is a message that represents an activity with its various properties. +message Activity { + string activity = 1; // A description of the activity. + string type = 2; // The type or category of the activity. + int32 participants = 3; // The number of participants required for the activity. + double price = 4; // The cost associated with the activity, from 0 (free) to 1 (most expensive). + string link = 5; // A URL providing more information about the activity. + string key = 6; // A unique identifier for the activity. + float accessibility = 7; // The accessibility of the activity, from 0 (most accessible) to 1 (least accessible). +} diff --git a/samples/java/JavaReferenceSkill/.gitignore b/samples/java/JavaReferenceSkill/.gitignore new file mode 100644 index 000000000000..5ff6309b7199 --- /dev/null +++ b/samples/java/JavaReferenceSkill/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/samples/java/JavaReferenceSkill/README.md b/samples/java/JavaReferenceSkill/README.md new file mode 100644 index 000000000000..3e88becc773c --- /dev/null +++ b/samples/java/JavaReferenceSkill/README.md @@ -0,0 +1,23 @@ +# Java Reference Skill gRPC Server +This is a reference implementation of a gRPC server for the Java Reference Skill. It is intended to be used as a starting point for developers who want to create their own gRPC server for the Java Reference Skill. + +## Prerequisites +* Java 17 +* Maven + +## Build +To build the project, run the following command: +``` +mvn clean package +``` +To generate the gRPC classes, run the following command: +``` +mvn protobuf:compile +``` + +## Run +To run the project, run the following command: +``` +java -jar ./target/JavaReferenceSkill-1.0-SNAPSHOT-jar-with-dependencies.jar +``` + diff --git a/samples/java/JavaReferenceSkill/pom.xml b/samples/java/JavaReferenceSkill/pom.xml new file mode 100644 index 000000000000..9161cfc1cbe1 --- /dev/null +++ b/samples/java/JavaReferenceSkill/pom.xml @@ -0,0 +1,109 @@ + + + 4.0.0 + + com.microsoft.semantickernel.skills.random + JavaReferenceSkill + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + 1.54.0 + 1.2 + 1.7.1 + 0.6.1 + 3.22.2 + 5.2.0 + + + + + io.grpc + grpc-protobuf + ${grpc.version} + + + io.grpc + grpc-stub + ${grpc.version} + + + io.grpc + grpc-testing + ${grpc.version} + + + io.grpc + grpc-netty-shaded + ${grpc.version} + + + org.mockito + mockito-core + ${mockito-core.version} + + + javax.annotation + javax.annotation-api + ${javax.annotation-api.version} + + + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-maven-plugin.version} + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} + + + + + compile + compile-custom + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + jar-with-dependencies + + + + com.microsoft.semantickernel.skills.random.Main + + + + + + make-assembly + package + + single + + + + + + + + \ No newline at end of file diff --git a/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/Main.java b/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/Main.java new file mode 100644 index 000000000000..6719a9aefb59 --- /dev/null +++ b/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/Main.java @@ -0,0 +1,28 @@ +package com.microsoft.semantickernel.skills.random; + +import io.grpc.Server; +import io.grpc.ServerBuilder; + +import java.util.logging.Logger; + +public class Main { + + private static final int PORT = 50051; + + public static void main(String[] args) { + Logger logger = java.util.logging.Logger.getLogger(Main.class.getName()); + + Server server = ServerBuilder.forPort(PORT) + .addService(new RandomActivitySkill()).build(); + + System.out.println("Starting server..."); + try { + server.start(); + System.out.println("gRPC Server for random activity started on port " + PORT); + server.awaitTermination(); + } catch (Exception e) { + logger.severe("Error with request: " + e.getMessage()); + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/RandomActivitySkill.java b/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/RandomActivitySkill.java new file mode 100644 index 000000000000..980f2ff6597d --- /dev/null +++ b/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/RandomActivitySkill.java @@ -0,0 +1,41 @@ +package com.microsoft.semantickernel.skills.random; + +import io.grpc.stub.StreamObserver; +import reference_skill.ActivityOuterClass; +import reference_skill.RandomActivitySkillGrpc; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; + +public class RandomActivitySkill extends RandomActivitySkillGrpc.RandomActivitySkillImplBase { + + public static final String API_ACTIVITY_URL = "https://www.boredapi.com/api/activity"; + + /** + *
+     * GetRandomActivity is an RPC method that retrieves a random activity from an API.
+     * 
+ * + * @param request + * @param responseObserver + */ + @Override + public void getRandomActivity(ActivityOuterClass.GetRandomActivityRequest request, StreamObserver responseObserver) { + Logger logger = java.util.logging.Logger.getLogger(this.getClass().getName()); + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest httpRequest = HttpRequest.newBuilder() + .uri(URI.create(API_ACTIVITY_URL)) + .build(); + try { + CompletableFuture> response = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString()); + logger.info("Response: " + response.get().body()); + responseObserver.onNext(ActivityOuterClass.GetRandomActivityResponse.newBuilder().setActivity(response.get().body()).build()); + } catch (Exception e) { + logger.severe("Error with request: " + e.getMessage()); + } + } +} diff --git a/samples/java/JavaReferenceSkill/src/main/proto/activity.proto b/samples/java/JavaReferenceSkill/src/main/proto/activity.proto new file mode 100644 index 000000000000..ac09fb2b676f --- /dev/null +++ b/samples/java/JavaReferenceSkill/src/main/proto/activity.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package reference_skill; + +// GetRandomActivityRequest is a message that contains input for the GetRandomActivity RPC method. +message GetRandomActivityRequest { + string input = 1; // Input is a hobby that is use to generate a random activity. +} + +// GetRandomActivityResponse is a message that contains the activity returned by the GetRandomActivity RPC method. +message GetRandomActivityResponse { + string activity = 1; // Activity is a description of the random activity. +} + +// RandomActivitySkill is a service that provides methods related to random activities. +service RandomActivitySkill { + // GetRandomActivity is an RPC method that retrieves a random activity from an API. + rpc GetRandomActivity (GetRandomActivityRequest) returns (GetRandomActivityResponse); +} + +// Activity is a message that represents an activity with its various properties. +message Activity { + string activity = 1; // A description of the activity. + string type = 2; // The type or category of the activity. + int32 participants = 3; // The number of participants required for the activity. + double price = 4; // The cost associated with the activity, from 0 (free) to 1 (most expensive). + string link = 5; // A URL providing more information about the activity. + string key = 6; // A unique identifier for the activity. + float accessibility = 7; // The accessibility of the activity, from 0 (most accessible) to 1 (least accessible). +} diff --git a/samples/java/JavaReferenceSkill/src/test/java/com/microsoft/semantickernel/skills/random/RandomActivitySkillTest.java b/samples/java/JavaReferenceSkill/src/test/java/com/microsoft/semantickernel/skills/random/RandomActivitySkillTest.java new file mode 100644 index 000000000000..bca529fcedc4 --- /dev/null +++ b/samples/java/JavaReferenceSkill/src/test/java/com/microsoft/semantickernel/skills/random/RandomActivitySkillTest.java @@ -0,0 +1,50 @@ +package com.microsoft.semantickernel.skills.random; + +import io.grpc.stub.StreamObserver; +import io.grpc.testing.GrpcServerRule; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import reference_skill.ActivityOuterClass; +import reference_skill.RandomActivitySkillGrpc; + +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.concurrent.CompletableFuture; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +public class RandomActivitySkillTest { + + @Rule + public GrpcServerRule grpcServerRule = new GrpcServerRule().directExecutor(); + + private RandomActivitySkillGrpc.RandomActivitySkillBlockingStub blockingStub; + + @Before + public void setUp() { + grpcServerRule.getServiceRegistry().addService(new RandomActivitySkill()); + blockingStub = RandomActivitySkillGrpc.newBlockingStub(grpcServerRule.getChannel()); + } + + @Test + public void testGetRandomActivity() throws Exception { + HttpClient httpClient = mock(HttpClient.class); + HttpResponse httpResponse = mock(HttpResponse.class); + CompletableFuture> responseFuture = CompletableFuture.completedFuture(httpResponse); + + when(httpClient.sendAsync(any(HttpRequest.class), any(HttpResponse.BodyHandler.class))).thenReturn(responseFuture); + when(httpResponse.body()).thenReturn("{\"activity\":\"Test Activity\"}"); + + RandomActivitySkill randomActivitySkill = new RandomActivitySkill() { + }; + + ActivityOuterClass.GetRandomActivityRequest request = ActivityOuterClass.GetRandomActivityRequest.newBuilder().build(); + StreamObserver responseObserver = mock(StreamObserver.class); + randomActivitySkill.getRandomActivity(request, responseObserver); + + verify(responseObserver).onNext(any(ActivityOuterClass.GetRandomActivityResponse.class)); + } +} From ef27fd48dc5f82fe2a38cb5e24bee54d5f5e4dfd Mon Sep 17 00:00:00 2001 From: Govind Kamtamneni Date: Wed, 5 Apr 2023 11:44:20 -0700 Subject: [PATCH 2/3] fix serde issue --- samples/dotnet/GrpcSkillRunner/Program.cs | 6 ++++-- .../semantickernel/skills/random/RandomActivitySkill.java | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/samples/dotnet/GrpcSkillRunner/Program.cs b/samples/dotnet/GrpcSkillRunner/Program.cs index 7ccde063e43a..acc4b017bce1 100644 --- a/samples/dotnet/GrpcSkillRunner/Program.cs +++ b/samples/dotnet/GrpcSkillRunner/Program.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. using System; +using System.Collections.Generic; +using System.Text.Json; using Grpc.Net.Client; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.KernelExtensions; @@ -17,7 +19,7 @@ var model = ""; //configure gRPC server address -const string DEFAULT_GRPC_SERVER_ADDRESS = "localhost:50051"; +const string DEFAULT_GRPC_SERVER_ADDRESS = "http://localhost:50051"; var sk = Kernel.Builder.Configure(c => c.AddAzureOpenAICompletionBackend(model, model, endpoint, key)).Build(); @@ -64,7 +66,7 @@ // Call gRPC service to get random activity var randomActivityResponse = await randomActivityClient.GetRandomActivityAsync(new GetRandomActivityRequest { Input = THING_I_LIKE_TO_DO }); -apiResult = randomActivityResponse.Activity; +apiResult = JsonSerializer.Deserialize>(randomActivityResponse.Activity)["activity"].ToString(); Console.WriteLine($"Random Activity: {apiResult}"); Console.WriteLine("Press any key to exit..."); diff --git a/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/RandomActivitySkill.java b/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/RandomActivitySkill.java index 980f2ff6597d..7036a2dc8976 100644 --- a/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/RandomActivitySkill.java +++ b/samples/java/JavaReferenceSkill/src/main/java/com/microsoft/semantickernel/skills/random/RandomActivitySkill.java @@ -34,6 +34,7 @@ public void getRandomActivity(ActivityOuterClass.GetRandomActivityRequest reques CompletableFuture> response = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString()); logger.info("Response: " + response.get().body()); responseObserver.onNext(ActivityOuterClass.GetRandomActivityResponse.newBuilder().setActivity(response.get().body()).build()); + responseObserver.onCompleted(); } catch (Exception e) { logger.severe("Error with request: " + e.getMessage()); } From 12f2fc120045798262a94827d65c82c357ba9665 Mon Sep 17 00:00:00 2001 From: Govind Kamtamneni Date: Wed, 5 Apr 2023 11:47:15 -0700 Subject: [PATCH 3/3] improve test code coverage --- .../semantickernel/skills/random/RandomActivitySkillTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/java/JavaReferenceSkill/src/test/java/com/microsoft/semantickernel/skills/random/RandomActivitySkillTest.java b/samples/java/JavaReferenceSkill/src/test/java/com/microsoft/semantickernel/skills/random/RandomActivitySkillTest.java index bca529fcedc4..fdc8f7268e24 100644 --- a/samples/java/JavaReferenceSkill/src/test/java/com/microsoft/semantickernel/skills/random/RandomActivitySkillTest.java +++ b/samples/java/JavaReferenceSkill/src/test/java/com/microsoft/semantickernel/skills/random/RandomActivitySkillTest.java @@ -46,5 +46,6 @@ public void testGetRandomActivity() throws Exception { randomActivitySkill.getRandomActivity(request, responseObserver); verify(responseObserver).onNext(any(ActivityOuterClass.GetRandomActivityResponse.class)); + verify(responseObserver).onCompleted(); } }