Java: Add Example30_ChatWithPrompts (#4682)

### Motivation and Context

<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  2. What problem does it solve?
  3. What scenario does it contribute to?
  4. If it fixes an open issue, please link to the issue here.
-->

### Description

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [ ] The code builds clean without any errors or warnings
- [ ] 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
- [ ] All unit tests pass, and I have added new tests where possible
- [ ] I didn't break anyone 😄
This commit is contained in:
John Oliver
2024-01-24 18:18:42 +00:00
committed by GitHub
parent 886a948139
commit ec10bf18af
57 changed files with 1326 additions and 858 deletions
@@ -19,23 +19,28 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.chatcompletion.AuthorRole;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.chatcompletion.StreamingChatMessageContent;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.slf4j.Logger;
@@ -123,8 +128,7 @@ public class OpenAIChatCompletion implements ChatCompletionService {
return client
.getChatCompletions(getModelId(), options)
.mapNotNull(ChatCompletions::getChoices)
.filter(choices -> choices != null && !choices.isEmpty())
.filter(choices -> choices.getChoices() != null && !choices.getChoices().isEmpty())
.map(this::accumulateResponses)
.map(responses ->
responses.stream()
@@ -136,33 +140,50 @@ public class OpenAIChatCompletion implements ChatCompletionService {
// non-streaming case
private List<ChatResponseCollector> accumulateResponses(List<ChatChoice> choices) {
private List<ChatResponseCollector> accumulateResponses(ChatCompletions chatCompletions) {
List<ChatResponseCollector> collectors = new ArrayList<>();
choices.stream()
chatCompletions
.getChoices()
.stream()
.map(ChatChoice::getMessage)
.filter(Objects::nonNull)
.map(this::accumulateResponse)
.map(accumulateResponse(chatCompletions))
.forEach(collectors::add);
return collectors;
}
private ChatResponseCollector accumulateResponse(ChatResponseMessage response) {
ChatResponseCollector collector = new ChatResponseCollector();
private Function<ChatResponseMessage, ChatResponseCollector> accumulateResponse(
ChatCompletions completions) {
// collector is null for the non-streaming case and not null for the streaming case
if (response.getContent() != null) {
collector.append(AuthorRole.ASSISTANT, response.getContent());
} else if (response.getToolCalls() != null) {
List<ChatCompletionsToolCall> toolCalls = response.getToolCalls();
// TODO: This assumes one tool call per response, which is _definitely_ a bad assumption.
for (ChatCompletionsToolCall toolCall : toolCalls) {
if (toolCall instanceof ChatCompletionsFunctionToolCall) {
collector.append(AuthorRole.TOOL, (ChatCompletionsFunctionToolCall) toolCall);
FunctionResultMetadata metadata = FunctionResultMetadata.build(
completions.getId(),
completions.getUsage(),
completions.getCreatedAt());
return response -> {
ChatResponseCollector collector = new ChatResponseCollector(
getModelId(),
null,
null,
metadata
);
// collector is null for the non-streaming case and not null for the streaming case
if (response.getContent() != null) {
collector.append(AuthorRole.ASSISTANT, response.getContent());
} else if (response.getToolCalls() != null) {
List<ChatCompletionsToolCall> toolCalls = response.getToolCalls();
// TODO: This assumes one tool call per response, which is _definitely_ a bad assumption.
for (ChatCompletionsToolCall toolCall : toolCalls) {
if (toolCall instanceof ChatCompletionsFunctionToolCall) {
collector.append(AuthorRole.TOOL,
(ChatCompletionsFunctionToolCall) toolCall);
}
}
}
}
return collector;
return collector;
};
}
/*
@@ -180,10 +201,10 @@ public class OpenAIChatCompletion implements ChatCompletionService {
jsonNode = jsonNode.get("function");
if (jsonNode != null) {
// function is the only tool we have right now.
Mono<ContextVariable<String>> result = invokeFunction(kernel, jsonNode);
Mono<FunctionResult<String>> result = invokeFunction(kernel, jsonNode);
if (result != null) {
return result.map(contextVariable -> {
String content = contextVariable.getValue();
String content = contextVariable.getResult();
return new StreamingChatMessageContent(AuthorRole.TOOL, content).setModelId(
id);
});
@@ -198,7 +219,7 @@ public class OpenAIChatCompletion implements ChatCompletionService {
/*
* The jsonNode should represent: {"name":"search-search", "parameters": {"query":"Banksy"}}}
*/
private Mono<ContextVariable<String>> invokeFunction(Kernel kernel, JsonNode jsonNode) {
private Mono<FunctionResult<String>> invokeFunction(Kernel kernel, JsonNode jsonNode) {
String name = jsonNode.get("name").asText();
String[] parts = name.split("-");
String pluginName = parts.length > 0 ? parts[0] : "";
@@ -321,6 +342,23 @@ public class OpenAIChatCompletion implements ChatCompletionService {
private static class AssistantContentBuffer implements ContentBuffer<String> {
private final StringBuilder sb = new StringBuilder();
@Nullable
private final String modelId;
@Nullable
private final String innerContent;
@Nullable
private final Charset encoding;
@Nullable
private final FunctionResultMetadata metadata;
private AssistantContentBuffer(@Nullable String modelId, @Nullable String innerContent,
@Nullable Charset encoding, @Nullable FunctionResultMetadata metadata) {
this.modelId = modelId;
this.innerContent = innerContent;
this.encoding = encoding;
this.metadata = metadata;
}
@Override
public void append(String content) {
@@ -329,7 +367,14 @@ public class OpenAIChatCompletion implements ChatCompletionService {
@Override
public ChatMessageContent toChatMessageContent() {
return new ChatMessageContent(AuthorRole.ASSISTANT, sb.toString());
return new ChatMessageContent(
AuthorRole.ASSISTANT,
sb.toString(),
modelId,
innerContent,
encoding,
metadata
);
}
}
@@ -398,14 +443,39 @@ public class OpenAIChatCompletion implements ChatCompletionService {
// For streaming,
private static class ChatResponseCollector {
@Nullable
private final String modelId;
@Nullable
private final String innerContent;
@Nullable
private final Charset encoding;
@Nullable
private final FunctionResultMetadata metadata;
private final Map<AuthorRole, ContentBuffer<?>> roleToContent = new HashMap<>();
private ChatResponseCollector(
@Nullable String modelId,
@Nullable String innerContent,
@Nullable Charset encoding,
@Nullable FunctionResultMetadata metadata) {
this.modelId = modelId;
this.innerContent = innerContent;
this.encoding = encoding;
this.metadata = metadata;
}
private ContentBuffer<?> collectorFor(AuthorRole role) {
return roleToContent.computeIfAbsent(role, k -> {
if (k == AuthorRole.TOOL) {
return new ToolContentBuffer();
}
return new AssistantContentBuffer();
return new AssistantContentBuffer(
modelId,
innerContent,
encoding,
metadata
);
});
}
@@ -1,16 +1,17 @@
package com.microsoft.semantickernel.aiservices.openai.textcompletion;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.models.Choice;
import com.azure.ai.openai.models.Completions;
import com.azure.ai.openai.models.CompletionsOptions;
import com.azure.ai.openai.models.CompletionsUsage;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.AIException;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.textcompletion.StreamingTextContent;
import com.microsoft.semantickernel.textcompletion.TextContent;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
import java.time.OffsetDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -61,14 +62,7 @@ public class OpenAITextGenerationService implements TextGenerationService {
@Override
public Mono<List<TextContent>> getTextContentsAsync(String prompt,
@Nullable PromptExecutionSettings executionSettings, @Nullable Kernel kernel) {
return this
.internalCompleteTextAsync(prompt, executionSettings)
.map(it -> {
return it.stream().map(
TextContent::new
)
.collect(Collectors.toList());
});
return this.internalCompleteTextAsync(prompt, executionSettings);
}
@Override
@@ -78,14 +72,11 @@ public class OpenAITextGenerationService implements TextGenerationService {
@Nullable Kernel kernel) {
return this
.internalCompleteTextAsync(prompt, executionSettings)
.flatMapMany(it -> {
return Flux.fromStream(it.stream())
.map(TextContent::new)
.map(StreamingTextContent::new);
});
.flatMapMany(it -> Flux.fromStream(it.stream())
.map(StreamingTextContent::new));
}
protected Mono<List<String>> internalCompleteTextAsync(
protected Mono<List<TextContent>> internalCompleteTextAsync(
String text,
PromptExecutionSettings requestSettings) {
@@ -93,9 +84,37 @@ public class OpenAITextGenerationService implements TextGenerationService {
return client
.getCompletions(getModelId(), completionsOptions)
.flatMapIterable(Completions::getChoices)
.mapNotNull(Choice::getText)
.collectList();
.map(completions -> {
FunctionResultMetadata metadata = FunctionResultMetadata.build(
completions.getId(),
completions.getUsage(),
completions.getCreatedAt());
return completions
.getChoices()
.stream()
.map(choice -> {
return new TextContent(
choice.getText(),
completionsOptions.getModel(),
metadata);
})
.collect(Collectors.toList());
});
}
public static Map<String, ContextVariable<?>> buildMetadata(
String id,
CompletionsUsage usage,
OffsetDateTime createdAt) {
Map<String, ContextVariable<?>> metadata = new HashMap<>();
metadata.put("id", ContextVariable.of(id));
metadata.put("usage", ContextVariable.of(usage));
metadata.put("created_at", ContextVariable.of(createdAt));
return metadata;
}
private CompletionsOptions getCompletionsOptions(
@@ -1,9 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.syntaxexamples;
import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
@@ -19,7 +18,7 @@ public class Example03_ArgumentsTest {
@Test
public void main() {
Kernel kernel = new DefaultKernel.Builder().build();
Kernel kernel = Kernel.builder().build();
// Load native skill
KernelPlugin functionCollection =
@@ -31,12 +30,12 @@ public class Example03_ArgumentsTest {
.writableClone()
.setVariable("day", "Monday");
ContextVariable<String> resultValue = kernel.invokeAsync(
FunctionResult<String> resultValue = kernel.invokeAsync(
functionCollection.get("AppendDay"),
arguments,
String.class)
.block();
Assertions.assertEquals("Today is: Monday", resultValue.getValue());
Assertions.assertEquals("Today is: Monday", resultValue.getResult());
}
}
@@ -6,11 +6,10 @@ import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelFunctionFactory;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
@@ -35,7 +34,7 @@ public class Example05_InlineFunctionDefinitionTest {
.withModelId("text-davinci-003")
.build();
Kernel kernel = new DefaultKernel.Builder()
Kernel kernel = Kernel.builder()
.withAIService(TextGenerationService.class, textGenerationService)
.build();
@@ -75,7 +74,7 @@ public class Example05_InlineFunctionDefinitionTest {
String.class)
.block();
Assertions.assertEquals("a-response", result.getValue());
Assertions.assertEquals("a-response", result.getResult());
WireMockUtil.mockCompletionResponse("sorry I forgot your birthday", "a-response-2");
@@ -86,7 +85,7 @@ public class Example05_InlineFunctionDefinitionTest {
String.class)
.block();
Assertions.assertEquals("a-response-2", result.getValue());
Assertions.assertEquals("a-response-2", result.getResult());
WireMockUtil.mockCompletionResponse("Translate this date ", "a-response-3");
@@ -104,11 +103,11 @@ public class Example05_InlineFunctionDefinitionTest {
null,
null);
ContextVariable<String> fixedFunctionResult = kernel
FunctionResult<String> fixedFunctionResult = kernel
.invokeAsync(fixedFunction, null, String.class)
.block();
Assertions.assertEquals("a-response-3", fixedFunctionResult.getValue());
Assertions.assertEquals("a-response-3", fixedFunctionResult.getResult());
}
}
@@ -134,7 +134,7 @@ public class ConversationSummaryPlugin {
ContextVariableTypes.getDefaultVariableTypeForClass(String.class));
})
.reduce("", (acc, next) -> {
return acc + "\n" + next.getValue();
return acc + "\n" + next.getResultVariable();
});
}
}
@@ -0,0 +1,427 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.samples.plugins;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
import com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter;
import com.microsoft.semantickernel.util.LocaleParser;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Locale;
/**
* Description: TimeSkill provides a set of functions to get the current time and date.
*
* <p>Usage: kernel.importSkill(new TimeSkill(), "time");
*
* <p>Examples:
*
* <p>{{time.date}} => Sunday, 12 January, 2031
*
* <p>{{time.today}} => Sunday, 12 January, 2031
*
* <p>{{time.now}} => Sunday, January 12, 2031 9:15 PM
*
* <p>{{time.utcNow}} => Sunday, January 13, 2031 5:15 AM
*
* <p>{{time.time}} => 09:15:07 PM
*
* <p>{{time.year}} => 2031
*
* <p>{{time.month}} => January
*
* <p>{{time.monthNumber}} => 01
*
* <p>{{time.day}} => 12
*
* <p>{{time.dayOfWeek}} => Sunday
*
* <p>{{time.hour}} => 9 PM
*
* <p>{{time.hourNumber}} => 21
*
* <p>{{time.days_ago $days}} => Sunday, 7 May, 2023
*
* <p>{{time.last_matching_day $dayName}} => Sunday, 7 May, 2023
*
* <p>{{time.minute}} => 15
*
* <p>{{time.second}} => 7
*
* <p>{{time.timeZoneOffset}} => -08:00
*
* <p>{{time.timeZoneName}} => Pacific Time
*/
public class TimePlugin {
public static final String DAY_MONTH_DAY_YEAR = "EEEE, MMMM d, yyyy";
/**
* Get the current date and time for the system default timezone.
*
* @return a ZonedDateTime object with the current date and time.
*/
public ZonedDateTime now() {
return ZonedDateTime.now(ZoneId.systemDefault());
}
/**
* Get the current date.
*
* <p>Example: {{time.date}} => Sunday, January 12, 2025
*
* @return The current date.
*/
@DefineKernelFunction(name = "date", description = "Get the current date")
public String date(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
// Example: Sunday, 12 January, 2025
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
.withLocale(parseLocale(locale))
.format(now());
}
/**
* Get the current time.
*
* <p>Example: {{time.time}} => 9:15:00 AM
*
* @return The current time.
*/
@DefineKernelFunction(name = "time", description = "Get the current time")
public String time(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
// Example: 09:15:07 PM
return DateTimeFormatter.ofPattern("hh:mm:ss a")
.withLocale(parseLocale(locale))
.format(now());
}
/**
* Get the current UTC date and time.
*
* <p>Example: {{time.utcNow}} => Sunday, January 13, 2025 5:15 AM
*
* @return The current UTC date and time.
*/
@DefineKernelFunction(name = "utcNow", description = "Get the current UTC date and time")
public String utcNow(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a")
.withLocale(parseLocale(locale))
.format(now().withZoneSameInstant(ZoneOffset.UTC));
}
/**
* Get the current date (alias for date() method).
*
* <p>Example: {{time.today}} => Sunday, January 12, 2025
*
* @return The current date.
*/
@DefineKernelFunction(name = "today", description = "Get the current date")
public String today(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return date(locale);
}
/**
* Get the current date and time in the local time zone.
*
* <p>Example: {{time.now}} => Sunday, January 12, 2025 9:15 AM
*
* @return The current date and time in the local time zone.
*/
@DefineKernelFunction(
name = "now",
description = "Get the current date and time in the local time zone")
public String now(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a")
.withLocale(parseLocale(locale))
.format(now());
}
/**
* Get the current year.
*
* <p>Example: {{time.year}} => 2025
*
* @return The current year.
*/
@DefineKernelFunction(name = "year", description = "Get the current year")
public String year(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("yyyy").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the current month name.
*
* <p>Example: {{time.month}} => January
*
* @return The current month name.
*/
@DefineKernelFunction(name = "month", description = "Get the current month name")
public String month(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("MMMM").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the current month number.
*
* <p>Example: {{time.monthNumber}} => 01
*
* @return The current month number.
*/
@DefineKernelFunction(name = "monthNumber", description = "Get the current month number")
public String monthNumber(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("MM").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the current day of the month.
*
* <p>Example: {{time.day}} => 12
*
* @return The current day of the month.
*/
@DefineKernelFunction(name = "day", description = "Get the current day of the month")
public String day(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("d").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the current day of the week.
*
* <p>Example: {{time.dayOfWeek}} => Sunday
*
* @return The current day of the week.
*/
@DefineKernelFunction(name = "dayOfWeek", description = "Get the current day of the week")
public String dayOfWeek(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("EEEE").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the current clock hour.
*
* <p>Example: {{time.hour}} => 9 AM
*
* @return The current clock hour.
*/
@DefineKernelFunction(name = "hour", description = "Get the current clock hour")
public String hour(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("h a").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the current clock 24-hour number.
*
* <p>Example: {{time.hourNumber}} => 09
*
* @return The current clock 24-hour number.
*/
@DefineKernelFunction(name = "hourNumber", description = "Get the current clock 24-hour number")
public String hourNumber(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("HH").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the date of offset from today by a provided number of days
*
* <p>Example: SKContext context = SKBuilders.context().build(); context.setVariable("input",
* "3"); {{time.daysAgo $input}} => Saturday, January 11, 2031
*
* @param days Number of days to subtract from the current day
* @return The date of offset from today by a provided number of days
*/
@DefineKernelFunction(
name = "daysAgo",
description = "Get the date of offset from today by a provided number of days")
public String daysAgo(
@KernelFunctionParameter(name = "days", description = "Number of days to offset from today.")
String days,
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
int offsetDays = Integer.parseInt(days);
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
.withLocale(parseLocale(locale))
.format(now().minusDays(offsetDays));
}
/**
* Get the date of the last day matching the supplied week day name
*
* <p>Example: {{time.dateMatchingLastDayName "Monday"}} => Monday, January 6, 2031
*
* @param dayName Name of the day to match
* @return The date of the last day matching the supplied week day name
*/
@DefineKernelFunction(
name = "dateMatchingLastDayName",
description = "Get the date of the last day matching the supplied week day name")
public String dateMatchingLastDayName(
@KernelFunctionParameter(name = "dayName", description = "Week name day.") String dayName,
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
ZonedDateTime currentDate = now();
for (int i = 1; i <= 7; i++) {
currentDate = currentDate.minusDays(1);
String currentDayName =
currentDate.getDayOfWeek().getDisplayName(TextStyle.FULL, parseLocale(locale));
if (currentDayName.equalsIgnoreCase(dayName)) {
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
.withLocale(parseLocale(locale))
.format(currentDate);
}
}
throw new IllegalArgumentException("dayName is not recognized");
}
/**
* Get the minutes on the current hour.
*
* <p>Example: {{time.minute}} => 15
*
* @return The minutes on the current hour.
*/
@DefineKernelFunction(name = "minute", description = "Get the minutes on the current hour")
public String minute(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("mm").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the seconds on the current minute.
*
* <p>Example: {{time.second}} => 00
*
* @return The seconds on the current minute.
*/
@DefineKernelFunction(name = "second", description = "Get the seconds on the current minute")
public String second(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("ss").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the local time zone offset from UTC.
*
* <p>Example: {{time.timeZoneOffset}} => +03:00
*
* @return The local time zone offset from UTC.
*/
@DefineKernelFunction(
name = "timeZoneOffset",
description = "Get the local time zone offset from UTC")
public String timeZoneOffset(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
return DateTimeFormatter.ofPattern("XXX").withLocale(parseLocale(locale)).format(now());
}
/**
* Get the local time zone name.
*
* <p>Example: {{time.timeZoneName}} => Pacific Time
*
* @return The local time zone name.
*/
@DefineKernelFunction(name = "timeZoneName", description = "Get the local time zone name")
public String timeZoneName(
@KernelFunctionParameter(
name = "locale",
description = "Locale to use when formatting the date",
required = false)
String locale) {
ZoneId zoneId = ZoneId.systemDefault();
return zoneId.getDisplayName(TextStyle.FULL, parseLocale(locale));
}
/**
* Parse the locale string into a Locale object.
*
* <p>By default, it parses using the LocaleParser utility class.
*
* @param locale string
* @return a locale object
*/
protected Locale parseLocale(String locale) {
return LocaleParser.parseLocale(locale);
}
}
@@ -1,9 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.samples.syntaxexamples;
import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
@@ -52,12 +51,12 @@ public class Example03_Arguments {
.writableClone()
.setVariable("day", "Monday");
ContextVariable<String> resultValue = kernel.invokeAsync(
FunctionResult<String> resultValue = kernel.invokeAsync(
functionCollection.get("AppendDay"),
arguments,
String.class)
.block();
System.out.println(resultValue.getValue());
System.out.println(resultValue.getResultVariable());
}
}
@@ -9,7 +9,7 @@ import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelFunctionFactory;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
@@ -85,7 +85,7 @@ public class Example05_InlineFunctionDefinition {
.build(),
String.class)
.block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
result = kernel.invokeAsync(excuseFunction,
KernelArguments.builder()
@@ -93,7 +93,7 @@ public class Example05_InlineFunctionDefinition {
.build(),
String.class)
.block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
var fixedFunction = KernelFunctionFactory.createFromPrompt(
"Translate this date " + DateTimeFormatter
@@ -109,10 +109,10 @@ public class Example05_InlineFunctionDefinition {
null,
null);
ContextVariable<String> fixedFunctionResult = kernel
FunctionResult<String> fixedFunctionResult = kernel
.invokeAsync(fixedFunction, null, String.class)
.block();
System.out.println(fixedFunctionResult.getValue());
System.out.println(fixedFunctionResult.getResultVariable());
}
}
@@ -105,6 +105,6 @@ public class Example06_TemplateLanguage {
// Show the result
System.out.println("--- Prompt Function result");
var result = kernel.invokeAsync(kindOfDay, null, String.class).block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
}
@@ -5,7 +5,6 @@ import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.http.policy.ExponentialBackoffOptions;
import com.azure.core.http.policy.RetryOptions;
import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.KernelFunction;
@@ -195,6 +195,12 @@ public class Example09_FunctionTypes {
Temporal.class)
.block();
kernel
.invokeAsync(plugin.get("withDefaultValue"),
null,
String.class)
.block();
/*
TODO: support FunctionResult
kernel
@@ -377,7 +383,6 @@ public class Example09_FunctionTypes {
);
}
@DefineKernelFunction(
name = "noInputComplexReturnType",
returnType = "java.time.temporal.Temporal"
@@ -386,6 +391,21 @@ public class Example09_FunctionTypes {
return LocalDateTime.now();
}
@DefineKernelFunction(
name = "withDefaultValue",
returnType = "java.lang.String"
)
public String withDefaultValue(
@KernelFunctionParameter(
name = "x",
defaultValue = "1",
type = int.class
)
int x
) {
return Integer.toString(x);
}
/*
/// <summary>
/// Example using a function to return the result of another inner function
@@ -8,8 +8,8 @@ import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.DefaultKernelArguments.Builder;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin;
@@ -158,7 +158,7 @@ public class Example13_ConversationSummaryPlugin {
KernelPlugin conversationSummaryPlugin = KernelPluginFactory.createFromObject(
new ConversationSummaryPlugin(), null);
Mono<ContextVariable<String>> summary = kernel
Mono<FunctionResult<String>> summary = kernel
.invokeAsync(
conversationSummaryPlugin
.getFunctions()
@@ -170,7 +170,7 @@ public class Example13_ConversationSummaryPlugin {
);
System.out.println("Generated Action Items:");
System.out.println(summary.block().getValue());
System.out.println(summary.block().getResultVariable());
}
private static void getConversationTopicsAsync() {
@@ -179,7 +179,7 @@ public class Example13_ConversationSummaryPlugin {
KernelPlugin conversationSummaryPlugin = KernelPluginFactory.createFromObject(
new ConversationSummaryPlugin(), null);
Mono<ContextVariable<String>> summary = kernel
Mono<FunctionResult<String>> summary = kernel
.invokeAsync(
conversationSummaryPlugin
.getFunctions()
@@ -191,7 +191,7 @@ public class Example13_ConversationSummaryPlugin {
);
System.out.println("Generated Topics:");
System.out.println(summary.block().getValue());
System.out.println(summary.block().getResultVariable());
}
@@ -203,7 +203,7 @@ public class Example13_ConversationSummaryPlugin {
KernelPlugin conversationSummaryPlugin = KernelPluginFactory.createFromObject(
new ConversationSummaryPlugin(), null);
Mono<ContextVariable<String>> summary = kernel
Mono<FunctionResult<String>> summary = kernel
.invokeAsync(
conversationSummaryPlugin
.getFunctions()
@@ -215,7 +215,7 @@ public class Example13_ConversationSummaryPlugin {
);
System.out.println("Generated Summary (This may take some time):");
System.out.println(summary.block().getValue());
System.out.println(summary.block().getResultVariable());
}
private static Kernel initializeKernel() {
@@ -58,7 +58,7 @@ public class Example27_PromptFunctionsUsingChatGPT {
ContextVariableTypes.getDefaultVariableTypeForClass(String.class)
)
.block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
}
@@ -0,0 +1,126 @@
package com.microsoft.semantickernel.samples.syntaxexamples;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.samples.plugins.TimePlugin;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory;
import com.microsoft.semantickernel.util.EmbeddedResourceLoader;
import java.io.FileNotFoundException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Example30_ChatWithPrompts {
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
// Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
private static final String MODEL_ID = System.getenv()
.getOrDefault("MODEL_ID", "gpt-35-turbo");
public static void main(String[] args) throws FileNotFoundException {
OpenAIAsyncClient client;
if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
} else {
client = new OpenAIClientBuilder()
.credential(new KeyCredential(CLIENT_KEY))
.buildAsyncClient();
}
ChatCompletionService openAIChatCompletion = ChatCompletionService.builder()
.withOpenAIAsyncClient(client)
.withModelId(MODEL_ID)
.build();
Kernel kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, openAIChatCompletion)
.build();
System.out.println("======== Chat with prompts ========");
/* Load 3 files:
* - 30-system-prompt.txt: the system prompt, used to initialize the chat session.
* - 30-user-context.txt: the user context, e.g. a piece of a document the user selected and is asking to process.
* - 30-user-prompt.txt: the user prompt, just for demo purpose showing that one can leverage the same approach also to augment user messages.
*/
var systemPromptTemplate = EmbeddedResourceLoader.readFile("30-system-prompt.txt",
Example30_ChatWithPrompts.class);
var selectedText = EmbeddedResourceLoader.readFile("30-user-context.txt",
Example30_ChatWithPrompts.class);
var userPromptTemplate = EmbeddedResourceLoader.readFile("30-user-prompt.txt",
Example30_ChatWithPrompts.class);
// As an example, we import the time plugin, which is used in system prompt to read the current date.
// We could also use a variable, this is just to show that the prompt can invoke functions.
KernelPlugin timePlugin = KernelPluginFactory.createFromObject(
new TimePlugin(), "time");
kernel.getPlugins().add(timePlugin);
// Adding required arguments referenced by the prompt templates.
var arguments = KernelArguments
.builder()
.withVariable("selectedText", selectedText)
.withVariable("startTime", DateTimeFormatter.ofPattern("hh:mm:ss a zz").format(
ZonedDateTime.now(ZoneId.systemDefault())))
.withVariable("userMessage", "extract locations as a bullet point list")
.build();
// Render the system prompt. This string is used to configure the chat.
// This contains the context, ie a piece of a wikipedia page selected by the user.
String systemMessage = PromptTemplateFactory
.build(new PromptTemplateConfig(systemPromptTemplate))
.renderAsync(kernel, arguments)
.block();
System.out.println("------------------------------------\n" + systemMessage);
// Render the user prompt. This string is the query sent by the user
// This contains the user request, ie "extract locations as a bullet point list"
String userMessage = PromptTemplateFactory
.build(new PromptTemplateConfig(userPromptTemplate))
.renderAsync(kernel, arguments)
.block();
System.out.println("------------------------------------\n" + userMessage);
// Client used to request answers
var chatCompletion = kernel.getService(ChatCompletionService.class);
// The full chat history. Depending on your scenario, you can pass the full chat if useful,
// or create a new one every time, assuming that the "system message" contains all the
// information needed.
var chatHistory = new ChatHistory(systemMessage);
// Add the user query to the chat history
chatHistory.addUserMessage(userMessage);
// Finally, get the response from AI
var answer = chatCompletion
.getChatMessageContentsAsync(chatHistory, null, kernel)
.block()
.stream()
.findFirst()
.get();
System.out.println("------------------------------------\n" + answer);
}
}
@@ -5,7 +5,6 @@ import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.azure.core.http.HttpClient;
import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.plugin.KernelPluginCollection;
@@ -66,7 +65,7 @@ public class Example42_KernelBuilder {
// KernelBuilder provides a convenient API for creating Kernel instances. However, it is just a
// wrapper, ultimately constructing a Kernel
// using the public constructor that's available for anyone to use directly if desired.
Kernel kernel = new DefaultKernel(
Kernel kernel = new Kernel(
new OrderedAIServiceSelector(),
new KernelPluginCollection()
);
@@ -0,0 +1,76 @@
package com.microsoft.semantickernel.samples.syntaxexamples;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
public class Example43_GetModelResult {
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
// Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
private static final String MODEL_ID = System.getenv()
.getOrDefault("MODEL_ID", "gpt-35-turbo");
public static void main(String[] args) {
System.out.println("======== Open AI - ChatGPT Streaming ========");
OpenAIAsyncClient client;
if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
} else {
client = new OpenAIClientBuilder()
.credential(new KeyCredential(CLIENT_KEY))
.buildAsyncClient();
}
ChatCompletionService chatCompletionService = OpenAIChatCompletion.builder()
.withModelId(MODEL_ID)
.withOpenAIAsyncClient(client)
.build();
Kernel kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, chatCompletionService)
.build();
System.out.println("======== Inline Function Definition + Invocation ========");
// Create function
String FunctionDefinition = "Hi, give me 5 book suggestions about: {{$input}}";
KernelFunction myFunction = KernelFunctionFromPrompt.create(
FunctionDefinition);
// Invoke function through kernel
FunctionResult<String> result = kernel.invokeAsync(
myFunction,
KernelArguments.builder()
.withVariable("input", "travel")
.build(),
String.class)
.block();
// Display results
System.out.println(result.getResult());
System.out.println(
"Usage: " + result
.getMetadata()
.getUsage().getTotalTokens());
System.out.println();
}
}
@@ -85,7 +85,7 @@ public class Example56_TemplateMethodFunctionsWithMultipleArguments {
// Show the result
System.out.println("--- Prompt Function result");
var result = kernel.invokeAsync(haiku, arguments, String.class).block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
}
@@ -65,7 +65,7 @@ public class Example58_ConfigureExecutionSettings {
String.class
).block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
// Option 2:
// Load prompt template configuration including the execution settings from a JSON payload
@@ -92,6 +92,6 @@ public class Example58_ConfigureExecutionSettings {
var func = KernelFunctionFactory.createFromPrompt(promptConfig, null);
result = kernel.invokeAsync(func, null, String.class).block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
}
@@ -85,7 +85,7 @@ public class Example61_MultipleLLMs {
.build();
var result = kernel.invokeAsync(func, arguments, String.class).block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
@@ -108,7 +108,7 @@ public class Example61_MultipleLLMs {
String.class
).block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
@@ -141,7 +141,7 @@ public class Example61_MultipleLLMs {
String.class)
.block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
}
@@ -78,7 +78,7 @@ public class Example62_CustomAIServiceSelector {
.build();
var result = kernel.invokeAsync(func, arguments, String.class).block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
// A dumb AIServiceSelector that just returns the first service and execution settings it finds
@@ -92,7 +92,11 @@ public class Example62_CustomAIServiceSelector {
@Override
public AIServiceSelection trySelectAIService(
Class<? extends AIService> serviceType,
@Nullable
KernelFunction function,
@Nullable
KernelArguments arguments,
Map<Class<? extends AIService>, AIService> services) {
@@ -0,0 +1,69 @@
package com.microsoft.semantickernel.samples.syntaxexamples;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import java.util.concurrent.CountDownLatch;
public class Example63_ChatCompletionPrompts {
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
// Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
private static final String MODEL_ID = System.getenv()
.getOrDefault("MODEL_ID", "gpt-35-turbo");
public static void main(String[] args) throws InterruptedException {
OpenAIAsyncClient client;
if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
} else {
client = new OpenAIClientBuilder()
.credential(new KeyCredential(CLIENT_KEY))
.buildAsyncClient();
}
ChatCompletionService openAIChatCompletion = ChatCompletionService.builder()
.withOpenAIAsyncClient(client)
.withModelId(MODEL_ID)
.build();
Kernel kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, openAIChatCompletion)
.build();
String chatPrompt = """
<message role="user">What is Seattle?</message>
<message role="system">Respond with JSON.</message>
""".stripIndent();
var chatSemanticFunction = KernelFunctionFromPrompt.create(chatPrompt);
var chatPromptResult = kernel.invokeAsync(chatSemanticFunction, null, String.class).block();
System.out.println("Chat Prompt:");
System.out.println(chatPrompt);
System.out.println("Chat Prompt Result:");
System.out.println(chatPromptResult.getResultVariable());
CountDownLatch cdl = new CountDownLatch(1);
System.out.println("Chat Prompt Result:");
kernel
.invokeAsync(chatSemanticFunction, null, String.class)
.doFinally(x -> cdl.countDown())
.subscribe(result -> System.out.println(result.getResultVariable()));
cdl.await();
}
}
@@ -4,7 +4,6 @@ import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
@@ -49,7 +48,7 @@ public class Example64_MultiplePromptTemplates {
.withOpenAIAsyncClient(client)
.build();
var kernel = new DefaultKernel.Builder()
var kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, openAIChatCompletion)
.build();
@@ -83,6 +82,6 @@ public class Example64_MultiplePromptTemplates {
.build();
var result = kernel.invokeAsync(function, arguments, String.class).block();
System.out.println(result.getValue());
System.out.println(result.getResultVariable());
}
}
@@ -8,6 +8,7 @@ import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
public class Example69_MutableKernelPlugin {
public static class Time {
@DefineKernelFunction(name = "date")
public String date() {
return "2021-09-01";
@@ -17,21 +18,22 @@ public class Example69_MutableKernelPlugin {
/**
* Mutable KernelPlugin example
* <p>
* KernelFunction can be added directly to the function collection of the KernelPlugin
* by using KernelPlugin.getFunctions and putting the corresponding KernelFunction
* KernelFunction can be added directly to the function collection of the KernelPlugin by using
* KernelPlugin.getFunctions and putting the corresponding KernelFunction
*/
public static void main(String[] args) throws NoSuchMethodException {
System.out.println("======== Example69_MutableKernelPlugin ========");
KernelPlugin plugin = new KernelPlugin("Plugin", "Mutable plugin", null);
plugin.getFunctions().put("dateFunction", KernelFunctionFactory.createFromMethod(
Time.class.getMethod("date"), new Time(),"date", null, null, null));
Time.class.getMethod("date"), new Time(), "date", null, null, null));
Kernel kernel = Kernel.builder().build();
kernel.getPlugins().add(plugin);
var result = kernel.invokeAsync(kernel.getPlugins().getFunction("Plugin", "dateFunction"), null, String.class).block();
var result = kernel.invokeAsync(kernel.getPlugins().getFunction("Plugin", "dateFunction"),
null, String.class).block();
System.out.println("Result: " + result.getValue());
System.out.println("Result: " + result.getResult());
}
}
@@ -0,0 +1,5 @@
You are an AI assistant that helps people find information.
The chat started at: {{ $startTime }}
The current time is: {{ time.now }}
Text selected:
{{ $selectedText }}
@@ -0,0 +1 @@
The central Sahara is hyperarid, with sparse vegetation. The northern and southern reaches of the desert, along with the highlands, have areas of sparse grassland and desert shrub, with trees and taller shrubs in wadis, where moisture collects. In the central, hyperarid region, there are many subdivisions of the great desert: Tanezrouft, the Ténéré, the Libyan Desert, the Eastern Desert, the Nubian Desert and others. These extremely arid areas often receive no rain for years.
@@ -6,7 +6,7 @@ import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import java.io.BufferedReader;
@@ -58,7 +58,7 @@ public class Main {
String input = bf.readLine();
chatHistory.addUserMessage(input);
ContextVariable<String> message = kernel
FunctionResult<String> message = kernel
.invokeAsync(
chatFunction,
KernelArguments
@@ -70,8 +70,8 @@ public class Main {
.block();
System.out.print("Assistant > ");
System.out.println(message.getValue());
chatHistory.addAssistantMessage(message.getValue());
System.out.println(message.getResult());
chatHistory.addAssistantMessage(message.getResult());
}
}
}
@@ -5,7 +5,7 @@ import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import java.io.IOException;
@@ -77,7 +77,7 @@ public class SimpleChatTest {
messages.forEach(message -> {
chatHistory.addUserMessage(message.matcher);
ContextVariable<String> result = kernel
FunctionResult<String> result = kernel
.invokeAsync(
chatFunction,
KernelArguments
@@ -88,8 +88,8 @@ public class SimpleChatTest {
)
.block();
Assertions.assertEquals(message.content(), result.getValue());
chatHistory.addAssistantMessage(result.getValue());
Assertions.assertEquals(message.content(), result.getResult());
chatHistory.addAssistantMessage(result.getResult());
});
}
}
@@ -6,14 +6,13 @@ import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.List;
public class Main {
@@ -56,7 +55,7 @@ public class Main {
// Run the chat function
// The persona chat function uses the persona variable to set the persona of the chat using a system message
// See Plugins/ChatPlugin/PersonaChat.prompt.yaml for the full prompt
ContextVariable<String> message = kernel
FunctionResult<String> message = kernel
.invokeAsync(
chatFunction,
KernelArguments
@@ -70,8 +69,8 @@ public class Main {
.block();
System.out.print("Assistant > ");
System.out.print(message.getValue());
chatHistory.addAssistantMessage(message.getValue());
System.out.print(message.getResult());
chatHistory.addAssistantMessage(message.getResult());
}
}
}
@@ -5,7 +5,7 @@ import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import java.io.IOException;
@@ -71,7 +71,7 @@ public class PersonaChatTest {
messages.forEach(message -> {
chatHistory.addUserMessage(message.matcher);
ContextVariable<String> result = kernel
FunctionResult<String> result = kernel
.invokeAsync(
chatFunction,
KernelArguments
@@ -84,8 +84,8 @@ public class PersonaChatTest {
)
.block();
Assertions.assertEquals(message.content(), result.getValue());
chatHistory.addAssistantMessage(result.getValue());
Assertions.assertEquals(message.content(), result.getResult());
chatHistory.addAssistantMessage(result.getResult());
});
}
}
@@ -6,7 +6,7 @@ import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
@@ -61,7 +61,7 @@ public class Main {
// Run the chat function
// The grounded chat function uses the search plugin to perform a Bing search to ground the response
// See Plugins/ChatPlugin/GroundedChat.prompt.yaml for the full prompt
ContextVariable<String> message = kernel
FunctionResult<String> message = kernel
.invokeAsync(
chatFunction,
KernelArguments.builder()
@@ -74,8 +74,8 @@ public class Main {
.block();
System.console().printf("Assistant > ");
System.out.println(message.getValue());
chatHistory.addAssistantMessage(message.getValue());
System.out.println(message.getResult());
chatHistory.addAssistantMessage(message.getResult());
}
}
}
@@ -5,7 +5,7 @@ import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
@@ -84,7 +84,7 @@ public class SimpleRagTest {
// Run the chat function
// The grounded chat function uses the search plugin to perform a Bing search to ground the response
// See Plugins/ChatPlugin/GroundedChat.prompt.yaml for the full prompt
ContextVariable<String> result = kernel
FunctionResult<String> result = kernel
.invokeAsync(
chatFunction,
KernelArguments.builder()
@@ -96,8 +96,8 @@ public class SimpleRagTest {
)
.block();
Assertions.assertEquals(message.content(), result.getValue());
chatHistory.addAssistantMessage(result.getValue());
Assertions.assertEquals(message.content(), result.getResult());
chatHistory.addAssistantMessage(result.getResult());
});
}
}
@@ -1,143 +0,0 @@
package com.microsoft.semantickernel;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter.NoopConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginCollection;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.services.AIServiceSelector;
import com.microsoft.semantickernel.services.OrderedAIServiceSelector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
public class DefaultKernel implements Kernel {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultKernel.class);
private final AIServiceSelector serviceSelector;
public KernelPluginCollection plugins;
public DefaultKernel(
AIServiceSelector serviceSelector,
@Nullable KernelPluginCollection plugins) {
this.serviceSelector = serviceSelector;
if (plugins != null) {
this.plugins = plugins;
} else {
this.plugins = new KernelPluginCollection();
}
}
@Override
public <T> Mono<ContextVariable<T>> invokeAsync(
KernelFunction function,
@Nullable KernelArguments arguments,
ContextVariableType<T> resultType) {
return function.invokeAsync(this, arguments, resultType);
}
@Override
public <T> Mono<ContextVariable<T>> invokeAsync(
String pluginName,
String functionName,
@Nullable KernelArguments arguments,
ContextVariableType<T> resultType) {
return plugins.getFunction(pluginName, functionName)
.invokeAsync(this, arguments, resultType);
}
@Override
public <T> Mono<ContextVariable<T>> invokeAsync(
KernelFunction function,
@Nullable KernelArguments arguments,
Class<T> resultType) {
ContextVariableType<T> contextVariable;
try {
contextVariable = ContextVariableTypes.getDefaultVariableTypeForClass(resultType);
} catch (Exception e) {
if (resultType.isAssignableFrom(
function.getMetadata().getReturnParameter().getParameterType())) {
contextVariable = new ContextVariableType<>(new NoopConverter<>(resultType),
resultType);
} else {
throw e;
}
}
return function.invokeAsync(this, arguments, contextVariable);
}
@Override
public List<KernelFunction> getFunctions() {
return null;
}
@Override
public AIServiceSelector getServiceSelector() {
return serviceSelector;
}
@Override
public KernelPluginCollection getPlugins() {
return plugins;
}
public static class Builder implements Kernel.Builder {
private final Map<Class<? extends AIService>, AIService> services = new HashMap<>();
private final List<KernelPlugin> plugins = new ArrayList<>();
private Function<Map<Class<? extends AIService>, AIService>, AIServiceSelector> serviceSelectorProvider;
@Override
public <T extends AIService> Builder withAIService(Class<T> clazz, T aiService) {
services.put(clazz, aiService);
return this;
}
@Override
public Builder withPromptTemplate(PromptTemplate promptTemplate) {
return this;
}
@Override
public Kernel.Builder withPlugin(KernelPlugin plugin) {
plugins.add(plugin);
return this;
}
@Override
public Kernel.Builder withServiceSelector(
Function<Map<Class<? extends AIService>, AIService>, AIServiceSelector> serviceSelector) {
this.serviceSelectorProvider = serviceSelector;
return this;
}
@Override
public Kernel build() {
AIServiceSelector serviceSelector;
if (serviceSelectorProvider == null) {
serviceSelector = new OrderedAIServiceSelector(services);
} else {
serviceSelector = serviceSelectorProvider.apply(services);
}
return new DefaultKernel(
serviceSelector,
new KernelPluginCollection(plugins));
}
}
}
@@ -3,70 +3,152 @@ package com.microsoft.semantickernel;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter.NoopConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginCollection;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.services.AIServiceSelector;
import com.microsoft.semantickernel.services.OrderedAIServiceSelector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
/**
* Interface for the semantic kernel.
*/
public interface Kernel extends Buildable {
public class Kernel implements Buildable {
/**
* Invokes the {@link KernelFunction}.
*
* @param <T> the type of the result value of the function.
* @param function the {@link KernelFunction} to invoke.
* @param arguments the arguments to pass to the function's invocation, including any
* {@link com.microsoft.semantickernel.orchestration.PromptExecutionSettings}.
* @return the result of the function's execution, cast to {@link T}.
*/
<T> Mono<ContextVariable<T>> invokeAsync(
private static final Logger LOGGER = LoggerFactory.getLogger(Kernel.class);
private final AIServiceSelector serviceSelector;
private final KernelPluginCollection plugins;
public Kernel(
AIServiceSelector serviceSelector,
@Nullable KernelPluginCollection plugins) {
this.serviceSelector = serviceSelector;
if (plugins != null) {
this.plugins = plugins;
} else {
this.plugins = new KernelPluginCollection();
}
}
public <T> Mono<FunctionResult<T>> invokeAsync(
KernelFunction function,
@Nullable KernelArguments arguments,
ContextVariableType<T> resultType);
ContextVariableType<T> resultType) {
return function.invokeAsync(this, arguments, resultType);
}
<T> Mono<ContextVariable<T>> invokeAsync(
public <T> Mono<FunctionResult<T>> invokeAsync(
String pluginName,
String functionName,
@Nullable KernelArguments arguments,
ContextVariableType<T> resultType);
ContextVariableType<T> resultType) {
return plugins.getFunction(pluginName, functionName)
.invokeAsync(this, arguments, resultType);
}
<T> Mono<ContextVariable<T>> invokeAsync(
public <T> Mono<FunctionResult<T>> invokeAsync(
KernelFunction function,
@Nullable KernelArguments arguments,
Class<T> resultType);
Class<T> resultType) {
List<KernelFunction> getFunctions();
ContextVariableType<T> contextVariable;
AIServiceSelector getServiceSelector();
KernelPluginCollection getPlugins();
static Builder builder() {
return new DefaultKernel.Builder();
try {
contextVariable = ContextVariableTypes.getDefaultVariableTypeForClass(resultType);
} catch (Exception e) {
if (resultType.isAssignableFrom(
function.getMetadata().getReturnParameter().getParameterType())) {
contextVariable = new ContextVariableType<>(new NoopConverter<>(resultType),
resultType);
} else {
throw e;
}
}
return function.invokeAsync(this, arguments, contextVariable);
}
interface Builder extends SemanticKernelBuilder<Kernel> {
<T extends AIService> Builder withAIService(Class<T> clazz, T aiService);
Builder withPromptTemplate(PromptTemplate promptTemplate);
Builder withPlugin(KernelPlugin searchPlugin);
Builder withServiceSelector(
Function<Map<Class<? extends AIService>, AIService>, AIServiceSelector> serviceSelector);
public List<KernelFunction> getFunctions() {
return null;
}
public AIServiceSelector getServiceSelector() {
return serviceSelector;
}
public KernelPluginCollection getPlugins() {
return plugins;
}
public <T extends AIService> T getService(Class<T> clazz) {
return (T) serviceSelector
.trySelectAIService(
clazz,
null,
null
)
.getService();
}
public static Kernel.Builder builder() {
return new Kernel.Builder();
}
public static class Builder implements SemanticKernelBuilder<Kernel> {
private final Map<Class<? extends AIService>, AIService> services = new HashMap<>();
private final List<KernelPlugin> plugins = new ArrayList<>();
private Function<Map<Class<? extends AIService>, AIService>, AIServiceSelector> serviceSelectorProvider;
public <T extends AIService> Builder withAIService(Class<T> clazz, T aiService) {
services.put(clazz, aiService);
return this;
}
public Builder withPromptTemplate(PromptTemplate promptTemplate) {
return this;
}
public Kernel.Builder withPlugin(KernelPlugin plugin) {
plugins.add(plugin);
return this;
}
public Kernel.Builder withServiceSelector(
Function<Map<Class<? extends AIService>, AIService>, AIServiceSelector> serviceSelector) {
this.serviceSelectorProvider = serviceSelector;
return this;
}
@Override
public Kernel build() {
AIServiceSelector serviceSelector;
if (serviceSelectorProvider == null) {
serviceSelector = new OrderedAIServiceSelector(services);
} else {
serviceSelector = serviceSelectorProvider.apply(services);
}
return new Kernel(
serviceSelector,
new KernelPluginCollection(plugins));
}
}
}
@@ -1,19 +1,19 @@
package com.microsoft.semantickernel;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
public class KernelContent<T extends KernelContent<T>> {
public abstract class KernelContent<T extends KernelContent<T>> {
@Nullable
private Object innerContent;
@Nullable
private String modelId;
@Nullable
private Map<String, ContextVariable<?>> metadata;
private FunctionResultMetadata metadata;
public KernelContent(
@Nullable
@@ -21,11 +21,13 @@ public class KernelContent<T extends KernelContent<T>> {
@Nullable
String modelId,
@Nullable
Map<String, ContextVariable<?>> metadata
FunctionResultMetadata metadata
) {
this.innerContent = innerContent;
this.modelId = modelId;
this.metadata = metadata;
if (metadata != null) {
this.metadata = metadata;
}
}
T setInnerContent(@Nullable Object innerContent) {
@@ -44,8 +46,9 @@ public class KernelContent<T extends KernelContent<T>> {
}
@CheckForNull
public Map<String, ContextVariable<?>> getMetadata() {
public FunctionResultMetadata getMetadata() {
return metadata;
}
public abstract String getContent();
}
@@ -11,6 +11,7 @@ import java.util.Optional;
import java.util.Spliterator;
import java.util.function.Consumer;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
/**
@@ -81,7 +82,7 @@ public class ChatHistory implements Iterable<ChatMessageContent> {
}
public void addMessage(AuthorRole authorRole, String content, Charset encoding,
Map<String, ContextVariable<?>> metadata) {
FunctionResultMetadata metadata) {
chatMessageContents.add(
new ChatMessageContent(authorRole, content, null, null, encoding, metadata));
}
@@ -2,6 +2,7 @@
package com.microsoft.semantickernel.chatcompletion;
import com.microsoft.semantickernel.KernelContent;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@@ -41,7 +42,7 @@ public class ChatMessageContent extends KernelContent<ChatMessageContent> {
@Nullable
Charset encoding,
@Nullable
Map<String, ContextVariable<?>> metadata
FunctionResultMetadata metadata
) {
super(innerContent, modelId, metadata);
this.authorRole = authorRole;
@@ -55,7 +56,7 @@ public class ChatMessageContent extends KernelContent<ChatMessageContent> {
String modelId,
String innerContent,
Charset encoding,
Map<String, ContextVariable<?>> metadata
FunctionResultMetadata metadata
) {
super(innerContent, modelId, metadata);
this.authorRole = authorRole;
@@ -0,0 +1,31 @@
package com.microsoft.semantickernel.orchestration;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
public class FunctionResult<T> {
private final ContextVariable<T> result;
private final FunctionResultMetadata metadata;
public FunctionResult(ContextVariable<T> result, FunctionResultMetadata metadata) {
this.result = result;
this.metadata = metadata;
}
public FunctionResult(ContextVariable<T> of) {
this(of, FunctionResultMetadata.empty());
}
public T getResult() {
return result.getValue();
}
public ContextVariable<T> getResultVariable() {
return result;
}
public FunctionResultMetadata getMetadata() {
return metadata;
}
}
@@ -0,0 +1,53 @@
package com.microsoft.semantickernel.orchestration;
import com.azure.ai.openai.models.CompletionsUsage;
import com.microsoft.semantickernel.orchestration.contextvariables.CaseInsensitiveMap;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import java.time.OffsetDateTime;
public class FunctionResultMetadata {
public static final String ID = "id";
public static final String USAGE = "usage";
public static final String CREATED_AT = "createdAt";
private final CaseInsensitiveMap<ContextVariable<?>> metadata;
public FunctionResultMetadata(CaseInsensitiveMap<ContextVariable<?>> metadata) {
this.metadata = metadata;
}
public static FunctionResultMetadata build(
String id,
CompletionsUsage usage,
OffsetDateTime createdAt) {
CaseInsensitiveMap<ContextVariable<?>> metadata = new CaseInsensitiveMap<>();
metadata.put(ID, ContextVariable.of(id));
metadata.put(USAGE, ContextVariable.of(usage));
metadata.put(CREATED_AT, ContextVariable.of(createdAt));
return new FunctionResultMetadata(metadata);
}
public static FunctionResultMetadata empty() {
return new FunctionResultMetadata(new CaseInsensitiveMap<>());
}
public CaseInsensitiveMap<ContextVariable<?>> getMetadata() {
return new CaseInsensitiveMap<>(metadata);
}
public String getId() {
return metadata.get(ID).getValue(String.class);
}
public CompletionsUsage getUsage() {
return metadata.get(USAGE).getValue(CompletionsUsage.class);
}
public OffsetDateTime getCreatedAt() {
return metadata.get(CREATED_AT).getValue(OffsetDateTime.class);
}
}
@@ -3,7 +3,6 @@ package com.microsoft.semantickernel.orchestration;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.semanticfunctions.InputVariable;
@@ -77,7 +76,7 @@ public interface KernelFunction extends Buildable {
* @param <T> The type of the context variable
* @return The result of the function's execution.
*/
<T> Mono<ContextVariable<T>> invokeAsync(
<T> Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
ContextVariableType<T> variableType);
@@ -1,6 +1,6 @@
package com.microsoft.semantickernel.orchestration;
import com.microsoft.semantickernel.orchestration.KernelFunctionFromMethod.ImplementationFunc;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod.ImplementationFunc;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelReturnParameterMetadata;
import java.util.List;
@@ -15,6 +15,15 @@ public class ContextVariable<T> {
return value;
}
public <U> U getValue(Class<U> clazz) {
if (clazz.isAssignableFrom(value.getClass())) {
return (U) value;
} else {
throw new RuntimeException("Cannot cast " + value.getClass() + " to " + clazz);
}
}
public ContextVariableType<T> getType() {
return type;
}
@@ -41,7 +50,6 @@ public class ContextVariable<T> {
return new ContextVariable<T>(type, value);
}
public static <T> ContextVariable<T> of(T value, ContextVariableTypeConverter<T> converter) {
ContextVariableType<T> type = new ContextVariableType<>(converter, converter.getType());
return new ContextVariable<>(type, value);
@@ -3,6 +3,8 @@ package com.microsoft.semantickernel.orchestration.contextvariables;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.BooleanVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.CharacterVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.ChatHistoryVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.CompletionUsageContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.DateTimeContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.NumberVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.StringVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.VoidVariableContextVariableTypeConverter;
@@ -22,6 +24,8 @@ public class ContextVariableTypes {
new ChatHistoryVariableContextVariableTypeConverter(),
new StringVariableContextVariableTypeConverter(),
new VoidVariableContextVariableTypeConverter(),
new DateTimeContextVariableTypeConverter(),
new CompletionUsageContextVariableTypeConverter(),
new NumberVariableContextVariableTypeConverter<>(Byte.class, Byte::parseByte),
new NumberVariableContextVariableTypeConverter<>(byte.class, Byte::parseByte),
@@ -0,0 +1,22 @@
package com.microsoft.semantickernel.orchestration.contextvariables.converters;
import com.azure.ai.openai.models.CompletionsUsage;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter;
public class CompletionUsageContextVariableTypeConverter extends
ContextVariableTypeConverter<CompletionsUsage> {
public CompletionUsageContextVariableTypeConverter() {
super(
CompletionsUsage.class,
s -> {
if (s instanceof CompletionsUsage) {
return (CompletionsUsage) s;
}
return null;
},
Object::toString,
o -> null // Do not support parsing from string
);
}
}
@@ -0,0 +1,26 @@
package com.microsoft.semantickernel.orchestration.contextvariables.converters;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
public class DateTimeContextVariableTypeConverter extends
ContextVariableTypeConverter<OffsetDateTime> {
public DateTimeContextVariableTypeConverter() {
super(
OffsetDateTime.class,
s -> {
if (s instanceof String) {
return ZonedDateTime.parse((String) s).toOffsetDateTime();
} else if (s instanceof OffsetDateTime) {
return (OffsetDateTime) s;
}
return null;
},
Object::toString,
o -> {
return ZonedDateTime.parse(o).toOffsetDateTime();
});
}
}
@@ -1,14 +1,15 @@
package com.microsoft.semantickernel.orchestration.contextvariables.converters;
import static com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes.convert;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter;
import java.util.function.Function;
import static com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes.convert;
public class NumberVariableContextVariableTypeConverter<T extends Number> extends
ContextVariableTypeConverter<T> {
public NumberVariableContextVariableTypeConverter(Class<T> clazz, Function<String, T> fromPromptString) {
public NumberVariableContextVariableTypeConverter(Class<T> clazz,
Function<String, T> fromPromptString) {
super(
clazz,
s -> convert(s, clazz),
@@ -1,7 +1,7 @@
package com.microsoft.semantickernel.plugin;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionFromMethod;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory;
@@ -1,10 +1,15 @@
package com.microsoft.semantickernel.orchestration;
package com.microsoft.semantickernel.semanticfunctions;
import static com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter.NO_DEFAULT_VALUE;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.AIException;
import com.microsoft.semantickernel.exceptions.AIException.ErrorCodes;
import com.microsoft.semantickernel.orchestration.DefaultKernelFunction;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionMetadata;
import com.microsoft.semantickernel.orchestration.MethodDetails;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter;
@@ -56,17 +61,16 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
}
@Override
public <T> Mono<ContextVariable<T>> invokeAsync(
public <T> Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
ContextVariableType<T> variableType) {
return function.invoke(kernel, this, arguments)
.map(variableType::of);
return function.invoke(kernel, this, arguments);
}
public interface ImplementationFunc {
<T> Mono<T> invoke(
<T> Mono<FunctionResult<T>> invoke(
Kernel kernel,
KernelFunction function,
@Nullable
@@ -133,7 +137,7 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
return new ImplementationFunc() {
@Override
public <T> Mono<T> invoke(Kernel kernel, KernelFunction function,
public <T> Mono<FunctionResult<T>> invoke(Kernel kernel, KernelFunction function,
@Nullable
KernelArguments arguments) {
@@ -161,21 +165,12 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
} else {
return (T) it;
}
/*
if (it instanceof KernelFunctionParameter) {
return it;
} else {
return context.update((String) it);
}
*/
});
return r;
return r
.map(it -> new FunctionResult<>(ContextVariable.of(it)));
} catch (Exception e) {
throw new RuntimeException(e);
//return Mono.error(e);
return Mono.error(e);
}
}
};
@@ -232,12 +227,9 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
@Nullable KernelArguments context,
Parameter parameter,
Kernel kernel) {
if (context == null) {
return context;
}
String variableName = getGetVariableName(parameter);
ContextVariable<?> arg = context.get(variableName);
ContextVariable<?> arg = context == null ? null : context.get(variableName);
if (arg == null) {
/*
// If this is bound to input get the input value
@@ -12,10 +12,10 @@ import com.microsoft.semantickernel.orchestration.DefaultKernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionMetadata;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.TextRequestContent;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.services.AIServiceSelection;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
@@ -84,7 +84,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
private <T> Flux<TextRequestContent<T>> invokeInternalAsync(
private <T> Flux<FunctionResult<T>> invokeInternalAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
ContextVariableType<T> variableType) {
@@ -108,7 +108,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
"Failed to initialise aiService, could not find any TextAIService implementations");
}
Flux<TextRequestContent<T>> result;
Flux<FunctionResult<T>> result;
PromptExecutionSettings executionSettings = aiServiceSelection.getSettings();
@@ -122,25 +122,40 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
.concatMap(chatMessageContent -> {
if (chatMessageContent.getAuthorRole()
== AuthorRole.ASSISTANT) {
T value = variableType
.getConverter()
.fromPromptString(
chatMessageContent.getContent());
return Flux.just(new TextRequestContent<>(value));
.fromObject(chatMessageContent);
} else if (chatMessageContent.getAuthorRole()
== AuthorRole.TOOL) {
Mono<ContextVariable<String>> toolResult = invokeTool(kernel,
chatMessageContent.getContent());
return toolResult.flatMapMany(contextVariable -> {
T value = variableType
if (value == null) {
value = variableType
.getConverter()
.fromPromptString(
contextVariable.getValue());
return Flux.just(new TextRequestContent<>(value));
});
chatMessageContent.getContent());
}
return Flux.just(
new FunctionResult<>(
new ContextVariable<>(variableType, value),
chatMessageContent.getMetadata()
)
);
} else if (chatMessageContent.getAuthorRole()
== AuthorRole.TOOL) {
Mono<FunctionResult<String>> toolResult = invokeTool(kernel,
chatMessageContent.getContent());
return toolResult.flux();
}
return Flux.empty();
})
.map(it -> {
return new FunctionResult<>(
new ContextVariable<>(
variableType,
variableType.of(it.getResult()).getValue()
),
it.getMetadata()
);
});
return result;
@@ -152,9 +167,25 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
kernel)
.flatMapMany(Flux::fromIterable)
.concatMap(textContent -> {
T value = variableType.getConverter().fromPromptString(
textContent.getContent());
return Flux.just(new TextRequestContent<>(value));
T value = variableType
.getConverter()
.fromObject(textContent);
if (value == null) {
value = variableType
.getConverter()
.fromPromptString(textContent.getContent());
}
return Flux.just(
new FunctionResult<>(
new ContextVariable<>(
variableType,
value
),
textContent.getMetadata()
)
);
});
} else {
return Flux.error(new IllegalStateException("Unknown service type"));
@@ -194,22 +225,13 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
@Override
public <T> Mono<ContextVariable<T>> invokeAsync(
public <T> Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
ContextVariableType<T> variableType) {
return invokeInternalAsync(kernel, arguments, variableType).
collectList()
.map(contents -> {
StringBuilder result = contents
.stream()
.reduce(
new StringBuilder(),
(sb, textRequestContent) -> sb.append(textRequestContent.innerContent),
StringBuilder::append);
T x = variableType.getConverter().fromPromptString(result.toString());
return new ContextVariable<>(variableType, x);
});
return invokeInternalAsync(kernel, arguments, variableType)
.take(1)
.single();
}
/*
@@ -219,7 +241,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
* {"type":"function", "function": {"name":"search-search", "parameters": {"query":"Banksy"}}}
* where 'name' is <plugin name '-' function name>.
*/
private Mono<ContextVariable<String>> invokeTool(Kernel kernel, String json) {
private Mono<FunctionResult<String>> invokeTool(Kernel kernel, String json) {
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(json);
@@ -236,7 +258,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
/*
* The jsonNode should represent: {"name":"search-search", "parameters": {"query":"Banksy"}}}
*/
private Mono<ContextVariable<String>> invokeFunction(Kernel kernel, JsonNode jsonNode) {
private Mono<FunctionResult<String>> invokeFunction(Kernel kernel, JsonNode jsonNode) {
String name = jsonNode.get("name").asText();
String[] parts = name.split("-");
String pluginName = parts.length > 0 ? parts[0] : "";
@@ -345,7 +367,10 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
if (this.executionSettings == null) {
this.executionSettings = new HashMap<>();
}
this.executionSettings.putAll(executionSettings);
if (executionSettings != null) {
this.executionSettings.putAll(executionSettings);
}
return this;
}
@@ -1,442 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.semanticfunctions;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import reactor.util.annotation.Nullable;
/**
* Prompt template configuration
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class PromptConfig {
private final CompletionConfig completionConfig;
private final InputConfig input;
/**
* A returns the configuration for the text completion
*
* @return CompletionConfig
*/
public CompletionConfig getCompletionConfig() {
return completionConfig;
}
public int getSchema() {
return schema;
}
public String getType() {
return type;
}
public String getName() {
return null;
}
public List<KernelParameterMetadata> getKernelParametersMetadata() {
return null;
}
public KernelReturnParameterMetadata getKernelReturnParameterMetadata() {
return null;
}
public List<PromptExecutionSettings> getExecutionSettings() {
return null;
}
/**
* Builder for CompletionConfig
*/
public static class CompletionConfigBuilder implements SemanticKernelBuilder<CompletionConfig> {
private CompletionConfig completionConfig;
public CompletionConfigBuilder() {
completionConfig = new CompletionConfig();
}
public CompletionConfigBuilder(CompletionConfig completionConfig) {
this.completionConfig = completionConfig;
}
public CompletionConfigBuilder temperature(double temperature) {
return new CompletionConfigBuilder(
new CompletionConfig(
temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder topP(double topP) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder presencePenalty(double presencePenalty) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
completionConfig.topP,
presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder frequencyPenalty(double frequencyPenalty) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder maxTokens(int maxTokens) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder stopSequences(List<String> stopSequences) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
stopSequences));
}
public CompletionConfig build() {
return completionConfig;
}
}
public InputConfig getInput() {
return input;
}
/**
* Completion configuration parameters
*/
public static class CompletionConfig implements Buildable {
/*
/// <summary>
/// Sampling temperature to use, between 0 and 2. Higher values will make the output more random.
/// Lower values will make it more focused and deterministic.
/// </summary>
[JsonPropertyName("temperature")]
[JsonPropertyOrder(1)]
*/
private final double temperature;
/*
/// <summary>
/// Cut-off of top_p probability mass of tokens to consider.
/// For example, 0.1 means only the tokens comprising the top 10% probability mass are considered.
/// </summary>
[JsonPropertyName("top_p")]
[JsonPropertyOrder(2)]
*/
private final double topP;
/*
/// <summary>
/// Lowers the probability of a word appearing if it already appeared in the predicted text.
/// Unlike the frequency penalty, the presence penalty does not depend on the frequency at which words
/// appear in past predictions.
/// </summary>
[JsonPropertyName("presence_penalty")]
[JsonPropertyOrder(3)]
*/
private final double presencePenalty;
/*
/// <summary>
/// Controls the model’s tendency to repeat predictions. The frequency penalty reduces the probability
/// of words that have already been generated. The penalty depends on how many times a word has already
/// occurred in the prediction.
/// </summary>
[JsonPropertyName("frequency_penalty")]
[JsonPropertyOrder(4)]
*/
private final double frequencyPenalty;
/*
/// <summary>
/// Maximum number of tokens that can be generated.
/// </summary>
[JsonPropertyName("max_tokens")]
[JsonPropertyOrder(5)]*/
private final int maxTokens; // { get; set; } = 256;
/*
/// <summary>
/// Stop sequences are optional sequences that tells the AI model when to stop generating tokens.
/// </summary>
[JsonPropertyName("stop_sequences")]
[JsonPropertyOrder(6)]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
*/
public final List<String> stopSequences; // { get; set; } = new();
/**
* The maximum number of completions to generate for each prompt. This is used by the
* CompletionService to generate multiple completions for a single prompt.
*/
private final Integer bestOf;
/**
* A unique identifier representing your end-user, which can help OpenAI to monitor and
* detect abuse
*/
private final String user;
public CompletionConfig() {
this(0.0, 0.0, 0.0, 0.0, 256, 1, "", new ArrayList<>());
}
public CompletionConfig(
double temperature,
double topP,
double presencePenalty,
double frequencyPenalty,
int maxTokens) {
this(
temperature,
topP,
presencePenalty,
frequencyPenalty,
maxTokens,
1,
"",
new ArrayList<>());
}
@JsonCreator
public CompletionConfig(
@JsonProperty("temperature") double temperature,
@JsonProperty("top_p") double topP,
@JsonProperty("presence_penalty") double presencePenalty,
@JsonProperty("frequency_penalty") double frequencyPenalty,
@JsonProperty("max_tokens") int maxTokens,
@JsonProperty("best_of") int bestOf,
@JsonProperty("user") String user,
@JsonProperty(value = "stop_sequences") List<String> stopSequences) {
this.temperature = temperature;
this.topP = topP;
this.presencePenalty = presencePenalty;
this.frequencyPenalty = frequencyPenalty;
this.maxTokens = maxTokens;
// bestOf must be at least 1
this.bestOf = Math.max(1, bestOf);
if (user == null) {
user = "";
}
this.user = user;
if (stopSequences == null) {
stopSequences = new ArrayList<>();
}
this.stopSequences = stopSequences;
}
public double getTemperature() {
return temperature;
}
public double getTopP() {
return topP;
}
public double getPresencePenalty() {
return presencePenalty;
}
public double getFrequencyPenalty() {
return frequencyPenalty;
}
public int getMaxTokens() {
return maxTokens;
}
/**
* The maximum number of completions to generate for each prompt. This is used by the
* CompletionService to generate multiple completions for a single prompt.
*/
public int getBestOf() {
return bestOf;
}
/**
* A unique identifier representing your end-user, which can help OpenAI to monitor and
* detect abuse
*/
public String getUser() {
return user;
}
public SemanticKernelBuilder<CompletionConfig> builder() {
return BuildersSingleton.INST.getInstance(CompletionConfigBuilder.class);
}
public List<String> getStopSequences() {
return Collections.unmodifiableList(stopSequences);
}
}
/**
* Input parameter for semantic functions
*/
public static class InputParameter {
private final String name;
private final String description;
private final String defaultValue;
@JsonCreator
public InputParameter(
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("defaultValue") String defaultValue) {
this.name = name;
this.description = description;
this.defaultValue = defaultValue;
}
/**
* Name of the parameter to pass to the function. e.g. when using "{{$input}}" the name is
* "input", when using "{{$style}}" the name is "style", etc.
*
* @return name
*/
public String getName() {
return name;
}
/**
* Parameter description for UI apps and planner. Localization is not supported here.
*
* @return description
*/
public String getDescription() {
return description;
}
/**
* Default value when nothing is provided
*
* @return the default value
*/
public String getDefaultValue() {
return defaultValue;
}
}
/**
* Input configuration (list of all input parameters for a semantic function).
*/
public static class InputConfig {
public final List<InputParameter> parameters;
@JsonCreator
public InputConfig(@JsonProperty("parameters") List<InputParameter> parameters) {
this.parameters = Collections.unmodifiableList(parameters);
}
public List<InputParameter> getParameters() {
return parameters;
}
}
private final int schema;
private final String type; // { get; set; } = "completion";
private final String description;
public PromptConfig() {
this("", "", null);
}
public PromptConfig(CompletionConfig completionConfig) {
this(1, "", "", completionConfig, new InputConfig(new ArrayList<>()));
}
public PromptConfig(
String description, String type, @Nullable CompletionConfig completionConfig) {
this(1, description, type, completionConfig, new InputConfig(new ArrayList<>()));
}
@JsonCreator
public PromptConfig(
@JsonProperty("schema") int schema,
@JsonProperty("description") String description,
@JsonProperty("type") String type,
@Nullable @JsonProperty("completion") CompletionConfig completionConfig,
@Nullable @JsonProperty("input") InputConfig input) {
if (completionConfig == null) {
completionConfig = new CompletionConfig();
}
this.schema = schema;
this.description = description;
this.type = type;
this.completionConfig = completionConfig;
if (input == null) {
input = new InputConfig(new ArrayList<>());
}
this.input = input;
}
/**
* Description
*
* @return Description
*/
public String getDescription() {
return description;
}
}
@@ -1,9 +1,15 @@
package com.microsoft.semantickernel.semanticfunctions;
public interface PromptTemplateFactory {
PromptTemplate tryCreate(PromptTemplateConfig templateConfig);
static PromptTemplate build(PromptTemplateConfig templateConfig) {
return new KernelPromptTemplateFactory().tryCreate(templateConfig);
}
class UnknownTemplateFormatException extends IllegalArgumentException {
public UnknownTemplateFormatException(String templateFormat) {
super("Unknown template format: " + templateFormat);
}
@@ -28,7 +28,10 @@ public interface AIServiceSelector {
@Nullable
AIServiceSelection trySelectAIService(
Class<? extends AIService> serviceType,
@Nullable
KernelFunction function,
@Nullable
KernelArguments arguments
);
}
@@ -22,7 +22,11 @@ public abstract class BaseAIServiceSelector implements AIServiceSelector {
@Nullable
public AIServiceSelection trySelectAIService(
Class<? extends AIService> serviceType,
@Nullable
KernelFunction function,
@Nullable
KernelArguments arguments) {
return trySelectAIService(serviceType, function, arguments, services);
}
@@ -30,7 +34,11 @@ public abstract class BaseAIServiceSelector implements AIServiceSelector {
@Nullable
public abstract AIServiceSelection trySelectAIService(
Class<? extends AIService> serviceType,
@Nullable
KernelFunction function,
@Nullable
KernelArguments arguments,
Map<Class<? extends AIService>, AIService> services);
}
@@ -31,7 +31,9 @@ public class OrderedAIServiceSelector extends BaseAIServiceSelector {
@Nullable
public AIServiceSelection trySelectAIService(
Class<? extends AIService> serviceType,
@Nullable
KernelFunction function,
@Nullable
KernelArguments arguments,
Map<Class<? extends AIService>, AIService> services) {
@@ -122,16 +124,21 @@ public class OrderedAIServiceSelector extends BaseAIServiceSelector {
@Nullable
private static Map<String, PromptExecutionSettings> settingsFromFunctionSettings(
KernelFunction function, Map<String, PromptExecutionSettings> executionSettings) {
@Nullable
KernelFunction function,
Map<String, PromptExecutionSettings> executionSettings) {
if (executionSettings == null || executionSettings.isEmpty()) {
executionSettings = function.getExecutionSettings();
if (function != null) {
executionSettings = function.getExecutionSettings();
}
}
return executionSettings;
}
@Nullable
private static Map<String, PromptExecutionSettings> settingsFromArguments(
KernelArguments arguments, Map<String, PromptExecutionSettings> executionSettings) {
@Nullable KernelArguments arguments,
Map<String, PromptExecutionSettings> executionSettings) {
if (arguments != null) {
executionSettings = arguments.getExecutionSettings();
}
@@ -1,41 +0,0 @@
package com.microsoft.semantickernel.services;
import com.microsoft.semantickernel.AIService;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class ParentAIServiceSelector implements AIServiceSelector {
private static final Logger LOGGER = LoggerFactory.getLogger(ParentAIServiceSelector.class);
protected final Map<Class<? extends AIService>, AIService> services;
public ParentAIServiceSelector() {
this.services = new HashMap<>();
}
public ParentAIServiceSelector(Map<Class<? extends AIService>, AIService> services) {
this.services = services;
}
@Override
@Nullable
public AIServiceSelection trySelectAIService(
Class<? extends AIService> serviceType,
KernelFunction function,
KernelArguments arguments) {
return trySelectAIService(serviceType, function, arguments, services);
}
@Nullable
public abstract AIServiceSelection trySelectAIService(
Class<? extends AIService> serviceType,
KernelFunction function,
KernelArguments arguments,
Map<Class<? extends AIService>, AIService> services);
}
@@ -8,6 +8,7 @@ import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariab
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.DefaultKernelArguments;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException;
import java.util.Collections;
@@ -121,7 +122,8 @@ public final class CodeBlock extends Block implements CodeRendering {
//Cloning the original arguments to avoid side effects - arguments added to the original arguments collection as a result of rendering template variables.
arguments = this.enrichFunctionArguments(kernel, fBlock,
arguments ==
null ? new DefaultKernelArguments() : new DefaultKernelArguments(arguments, new HashMap<>()));
null ? new DefaultKernelArguments()
: new DefaultKernelArguments(arguments, new HashMap<>()));
}
return kernel
@@ -129,7 +131,8 @@ public final class CodeBlock extends Block implements CodeRendering {
fBlock.getPluginName(),
fBlock.getFunctionName(),
arguments,
resultType);
resultType)
.map(FunctionResult::getResultVariable);
}
@@ -1,13 +1,19 @@
package com.microsoft.semantickernel.textcompletion;
import com.microsoft.semantickernel.KernelContent;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import java.util.Map;
public class TextContent extends KernelContent<TextContent> {
private final String content;
public TextContent(String content) {
super(content, null, null);
public TextContent(
String content,
String modelId,
FunctionResultMetadata metadata) {
super(content, modelId, metadata);
this.content = content;
}