Skip to content

Commit

Permalink
Add error messages when OpenAPI calls
Browse files Browse the repository at this point in the history
  • Loading branch information
johnoliver committed Jun 11, 2024
1 parent 9f409dc commit 125fc6e
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand All @@ -61,8 +62,6 @@
import java.util.stream.Stream;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;

import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder;
import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -405,8 +404,22 @@ private Mono<ChatMessages> emitError(
ChatCompletionsToolCall toolCall,
ChatMessages msgs,
Throwable e) {

StringBuilder errorMessage = new StringBuilder();

Throwable currentError = e;
while (currentError != null) {
String msg = currentError.getMessage();
if (msg != null && !msg.isEmpty()) {
errorMessage
.append(msg)
.append("\n");
}
currentError = currentError.getCause();
}

msgs = msgs.add(new ChatRequestToolMessage(
"Call failed: " + e.getMessage(),
"Call failed: " + errorMessage,
toolCall.getId()));

return Mono.error(new FunctionInvocationError(e, msgs.allMessages));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ private static void getUsageAsync(Kernel kernel) {

FunctionInvokedHook postExecutionHandler = event -> {
System.out.println(
event.getFunction().getName() + " : Post Execution Handler - Usage: " + ((CompletionsUsage) event
.getResult()
.getMetadata()
.getUsage())
.getTotalTokens());
event.getFunction().getName() + " : Post Execution Handler - Usage: "
+ ((CompletionsUsage) event
.getResult()
.getMetadata()
.getUsage())
.getTotalTokens());
return event;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.samples.syntaxexamples.chatcompletion;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.samples.syntaxexamples.functions;

import com.google.cloud.vertexai.VertexAI;
Expand Down Expand Up @@ -31,7 +32,6 @@ public class Example98_GeminiFunctionCalling {
private static final String LOCATION = System.getenv("LOCATION");
private static final String MODEL_ID = System.getenv("GEMINI_MODEL_ID");


// Define functions that can be called by the model
public static class HelperFunctions {

Expand All @@ -42,7 +42,7 @@ public String currentUtcTime() {

@DefineKernelFunction(name = "getWeatherForCity", description = "Gets the current weather for the specified city")
public String getWeatherForCity(
@KernelFunctionParameter(name = "cityName", description = "Name of the city") String cityName) {
@KernelFunctionParameter(name = "cityName", description = "Name of the city") String cityName) {
switch (cityName) {
case "Thrapston":
return "80 and sunny";
Expand Down Expand Up @@ -71,53 +71,54 @@ public static void main(String[] args) throws NoSuchMethodException {
VertexAI client = new VertexAI(PROJECT_ID, LOCATION);

ChatCompletionService chat = GeminiChatCompletion.builder()
.withModelId(MODEL_ID)
.withVertexAIClient(client)
.build();
.withModelId(MODEL_ID)
.withVertexAIClient(client)
.build();

var plugin = KernelPluginFactory.createFromObject(new HelperFunctions(), "HelperFunctions");
var plugin = KernelPluginFactory.createFromObject(new HelperFunctions(),
"HelperFunctions");

var kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, chat)
.withPlugin(plugin)
.build();
.withAIService(ChatCompletionService.class, chat)
.withPlugin(plugin)
.build();

System.out.println("======== Example 1: Use automated function calling ========");

var function = KernelFunctionFromPrompt.builder()
.withTemplate(
"Given the current time of day and weather, what is the likely color of the sky in Boston?")
.withDefaultExecutionSettings(
PromptExecutionSettings.builder()
.withTemperature(0.4)
.withTopP(1)
.withMaxTokens(100)
.build())
.build();
.withTemplate(
"Given the current time of day and weather, what is the likely color of the sky in Boston?")
.withDefaultExecutionSettings(
PromptExecutionSettings.builder()
.withTemperature(0.4)
.withTopP(1)
.withMaxTokens(100)
.build())
.build();

var result = kernel
.invokeAsync(function)
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
.withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class))
.block();
.invokeAsync(function)
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(true))
.withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class))
.block();

System.out.println(result.getResult());

System.out.println("======== Example 2: Use manual function calling ========");

var chatHistory = new ChatHistory();
chatHistory.addUserMessage(
"Given the current time of day and weather, what is the likely color of the sky in Boston?");
"Given the current time of day and weather, what is the likely color of the sky in Boston?");

while (true) {
var message = (GeminiChatMessageContent<?>) chat.getChatMessageContentsAsync(
chatHistory,
kernel,
InvocationContext.builder()
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(false))
.withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY)
.build())
.block().get(0);
chatHistory,
kernel,
InvocationContext.builder()
.withToolCallBehavior(ToolCallBehavior.allowAllKernelFunctions(false))
.withReturnMode(InvocationReturnMode.LAST_MESSAGE_ONLY)
.build())
.block().get(0);

// Add the assistant's response to the chat history
chatHistory.addMessage(message);
Expand All @@ -136,26 +137,30 @@ public static void main(String[] args) throws NoSuchMethodException {
String content = null;
try {
// getFunction will throw an exception if the function is not found
var fn = kernel.getFunction(geminiFunction.getPluginName(), geminiFunction.getFunctionName());
var fn = kernel.getFunction(geminiFunction.getPluginName(),
geminiFunction.getFunctionName());

var arguments = KernelFunctionArguments.builder();
geminiFunction.getFunctionCall().getArgs().getFieldsMap().forEach((key, value) -> {
arguments.withVariable(key, value.getStringValue());
});
geminiFunction.getFunctionCall().getArgs().getFieldsMap()
.forEach((key, value) -> {
arguments.withVariable(key, value.getStringValue());
});

// Invoke the function and add the result to the list of function responses
FunctionResult<?> functionResult = fn
.invokeAsync(kernel, arguments.build(), null, null).block();
.invokeAsync(kernel, arguments.build(), null, null).block();

functionResponses.add(new GeminiFunctionCall(geminiFunction.getFunctionCall(), functionResult));
functionResponses.add(new GeminiFunctionCall(
geminiFunction.getFunctionCall(), functionResult));
} catch (IllegalArgumentException e) {
content = "Unable to find function. Please try again!";
}
}

// Add the function responses to the chat history
ChatMessageContent<?> functionResponsesMessage = new GeminiChatMessageContent<>(AuthorRole.USER,
"", null, null, null, null, functionResponses);
ChatMessageContent<?> functionResponsesMessage = new GeminiChatMessageContent<>(
AuthorRole.USER,
"", null, null, null, null, functionResponses);

chatHistory.addMessage(functionResponsesMessage);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.semantickernel.contextvariables.ContextVariable;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
Expand Down Expand Up @@ -103,12 +104,25 @@ public Mono<String> execute(KernelFunctionArguments arguments) {
.send(request)
.flatMap(response -> {
if (response.getStatusCode() >= 400) {
return Mono.error(new RuntimeException(
"Request failed with status code: " + response.getStatusCode()));
return response.getBodyAsString()
.defaultIfEmpty("")
.flatMap(responseBody -> {
if (!responseBody.isEmpty()) {
responseBody += "\nResponse Body:" + responseBody;
}
return Mono.error(new SKException(
"Request failed with status code: " + response.getStatusCode()
+ responseBody));
});
} else {
return Mono.just(response);
}
})
.onErrorResume(e -> {
SKException exception = SKException.build("Request failed", e);
exception.setStackTrace(new StackTraceElement[0]);
return Mono.error(exception);
})
.flatMap(HttpResponse::getBodyAsString)
.doOnNext(response -> LOGGER.debug("Request response: {}", response));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public SKException(Throwable e) {
*/
public static SKException build(
String message,
@Nullable Exception e) {
@Nullable Throwable e) {

if (e == null) {
return new SKException(message);
Expand Down

0 comments on commit 125fc6e

Please sign in to comment.