mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Java: Add sequential planner (#1526)
### 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 SK Contribution Guidelines (https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) - [ ] The code follows the .NET coding conventions (https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions) verified with `dotnet format` - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄
This commit is contained in:
@@ -1,16 +1,4 @@
|
||||
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
@@ -21,6 +9,16 @@ import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class InlineFunctionExample {
|
||||
public static final String AZURE_CONF_PROPERTIES = "conf.properties";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(InlineFunctionExample.class);
|
||||
@@ -28,7 +26,8 @@ public class InlineFunctionExample {
|
||||
|
||||
private static final String API_KEY;
|
||||
private static final String ENDPOINT;
|
||||
private static final String TEXT_TO_SUMMARIZE = """
|
||||
private static final String TEXT_TO_SUMMARIZE =
|
||||
"""
|
||||
Demo (ancient Greek poet)
|
||||
From Wikipedia, the free encyclopedia
|
||||
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
|
||||
@@ -94,28 +93,30 @@ public class InlineFunctionExample {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.endpoint(ENDPOINT)
|
||||
.credential(new AzureKeyCredential(API_KEY))
|
||||
.buildAsyncClient();
|
||||
OpenAIAsyncClient client =
|
||||
new OpenAIClientBuilder()
|
||||
.endpoint(ENDPOINT)
|
||||
.credential(new AzureKeyCredential(API_KEY))
|
||||
.buildAsyncClient();
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, MODEL);
|
||||
String prompt = "{{$input}}\n" + "Summarize the content above.";
|
||||
|
||||
KernelConfig kernelConfig = new KernelConfig.Builder()
|
||||
.addTextCompletionService(MODEL, kernel -> textCompletion)
|
||||
.build();
|
||||
KernelConfig kernelConfig =
|
||||
new KernelConfig.Builder()
|
||||
.addTextCompletionService(MODEL, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
CompletionSKFunction summarize = kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
CompletionSKFunction summarize =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(0.2, 0.5, 0, 0, 2000));
|
||||
|
||||
if (summarize == null) {
|
||||
LOGGER.error("Null function");
|
||||
|
||||
+60
-61
@@ -1,16 +1,4 @@
|
||||
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
@@ -21,43 +9,55 @@ import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class InlineFunctionWithPreBuiltSkillExample {
|
||||
public static final String AZURE_CONF_PROPERTIES = "conf.properties";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(InlineFunctionWithPreBuiltSkillExample.class);
|
||||
private static final Logger LOGGER =
|
||||
LoggerFactory.getLogger(InlineFunctionWithPreBuiltSkillExample.class);
|
||||
private static final String MODEL = "text-davinci-003";
|
||||
|
||||
private static final String API_KEY;
|
||||
private static final String ENDPOINT;
|
||||
private static final String TEXT_TO_SUMMARIZE = """
|
||||
Demo (ancient Greek poet)
|
||||
From Wikipedia, the free encyclopedia
|
||||
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
|
||||
Roman period, known for a single epigram, engraved upon the Colossus of
|
||||
Memnon, which bears her name. She speaks of herself therein as a lyric
|
||||
poetess dedicated to the Muses, but nothing is known of her life.[1]
|
||||
Identity
|
||||
Demo was evidently Greek, as her name, a traditional epithet of Demeter,
|
||||
signifies. The name was relatively common in the Hellenistic world, in
|
||||
Egypt and elsewhere, and she cannot be further identified. The date of her
|
||||
visit to the Colossus of Memnon cannot be established with certainty, but
|
||||
internal evidence on the left leg suggests her poem was inscribed there at
|
||||
some point in or after AD 196.[2]
|
||||
Epigram
|
||||
There are a number of graffiti inscriptions on the Colossus of Memnon.
|
||||
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac
|
||||
couplets, entitled and presumably authored by "Demo" or "Damo" (the
|
||||
Greek inscription is difficult to read), is a dedication to the Muses.[2]
|
||||
The poem is traditionally published with the works of Balbilla, though the
|
||||
internal evidence suggests a different author.[1]
|
||||
In the poem, Demo explains that Memnon has shown her special respect. In
|
||||
return, Demo offers the gift for poetry, as a gift to the hero. At the end
|
||||
of this epigram, she addresses Memnon, highlighting his divine status by
|
||||
recalling his strength and holiness.[2]
|
||||
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic
|
||||
dialect. The language indicates she was knowledgeable in Homeric
|
||||
poetry—'bearing a pleasant gift', for example, alludes to the use of that
|
||||
phrase throughout the Iliad and Odyssey.[a][2];
|
||||
""";
|
||||
private static final String TEXT_TO_SUMMARIZE =
|
||||
"""
|
||||
Demo (ancient Greek poet)
|
||||
From Wikipedia, the free encyclopedia
|
||||
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
|
||||
Roman period, known for a single epigram, engraved upon the Colossus of
|
||||
Memnon, which bears her name. She speaks of herself therein as a lyric
|
||||
poetess dedicated to the Muses, but nothing is known of her life.[1]
|
||||
Identity
|
||||
Demo was evidently Greek, as her name, a traditional epithet of Demeter,
|
||||
signifies. The name was relatively common in the Hellenistic world, in
|
||||
Egypt and elsewhere, and she cannot be further identified. The date of her
|
||||
visit to the Colossus of Memnon cannot be established with certainty, but
|
||||
internal evidence on the left leg suggests her poem was inscribed there at
|
||||
some point in or after AD 196.[2]
|
||||
Epigram
|
||||
There are a number of graffiti inscriptions on the Colossus of Memnon.
|
||||
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac
|
||||
couplets, entitled and presumably authored by "Demo" or "Damo" (the
|
||||
Greek inscription is difficult to read), is a dedication to the Muses.[2]
|
||||
The poem is traditionally published with the works of Balbilla, though the
|
||||
internal evidence suggests a different author.[1]
|
||||
In the poem, Demo explains that Memnon has shown her special respect. In
|
||||
return, Demo offers the gift for poetry, as a gift to the hero. At the end
|
||||
of this epigram, she addresses Memnon, highlighting his divine status by
|
||||
recalling his strength and holiness.[2]
|
||||
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic
|
||||
dialect. The language indicates she was knowledgeable in Homeric
|
||||
poetry—'bearing a pleasant gift', for example, alludes to the use of that
|
||||
phrase throughout the Iliad and Odyssey.[a][2];
|
||||
""";
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -94,31 +94,30 @@ public class InlineFunctionWithPreBuiltSkillExample {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.endpoint(ENDPOINT)
|
||||
.credential(new AzureKeyCredential(API_KEY))
|
||||
.buildAsyncClient();
|
||||
OpenAIAsyncClient client =
|
||||
new OpenAIClientBuilder()
|
||||
.endpoint(ENDPOINT)
|
||||
.credential(new AzureKeyCredential(API_KEY))
|
||||
.buildAsyncClient();
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, MODEL);
|
||||
String prompt = "{{$input}}\nSummarize the content above.";
|
||||
|
||||
CompletionSKFunction summarizeFunc = SKBuilders.completionFunctions()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
|
||||
KernelConfig kernelConfig = new KernelConfig.Builder()
|
||||
.addTextCompletionService(MODEL, kernel -> textCompletion)
|
||||
.addSkill(summarizeFunc)
|
||||
.build();
|
||||
KernelConfig kernelConfig =
|
||||
new KernelConfig.Builder()
|
||||
.addTextCompletionService(MODEL, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
CompletionSKFunction summarize = kernel.getSkills().getFunction("summarize", CompletionSKFunction.class);
|
||||
CompletionSKFunction summarize =
|
||||
SKBuilders.completionFunctions(kernel)
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(0.2, 0.5, 0, 0, 2000));
|
||||
|
||||
if (summarize == null) {
|
||||
LOGGER.error("Null function");
|
||||
|
||||
+16
-13
@@ -11,6 +11,7 @@ import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion;
|
||||
import com.microsoft.semantickernel.memory.VolatileMemoryStore;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
import java.io.File;
|
||||
@@ -29,12 +30,15 @@ public class AbstractKernelTest {
|
||||
final OpenAIAsyncClient openAIClient = getAzureOpenAIClient();
|
||||
TextCompletion textCompletion = new OpenAITextCompletion(openAIClient, model);
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.addTextEmbeddingsGenerationService(
|
||||
model,
|
||||
kernel -> SKBuilders.textEmbeddingGenerationService().build(openAIClient, model))
|
||||
.build();
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.addTextEmbeddingsGenerationService(
|
||||
model,
|
||||
kernel ->
|
||||
SKBuilders.textEmbeddingGenerationService()
|
||||
.build(openAIClient, model))
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel()
|
||||
.setKernelConfig(kernelConfig)
|
||||
@@ -45,18 +49,17 @@ public class AbstractKernelTest {
|
||||
public static OpenAIAsyncClient getOpenAIClient() throws IOException {
|
||||
String apiKey = getToken(CONF_OPENAI_PROPERTIES);
|
||||
NonAzureOpenAIKeyCredential credential = new NonAzureOpenAIKeyCredential(apiKey);
|
||||
return new OpenAIClientBuilder()
|
||||
.credential(credential)
|
||||
.buildAsyncClient();
|
||||
return new OpenAIClientBuilder().credential(credential).buildAsyncClient();
|
||||
}
|
||||
|
||||
public static OpenAIAsyncClient getAzureOpenAIClient() throws IOException {
|
||||
String apiKey = getToken(AZURE_CONF_PROPERTIES);
|
||||
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.endpoint(getEndpoint(AZURE_CONF_PROPERTIES))
|
||||
.credential(new AzureKeyCredential(apiKey))
|
||||
.buildAsyncClient();
|
||||
OpenAIAsyncClient client =
|
||||
new OpenAIClientBuilder()
|
||||
.endpoint(getEndpoint(AZURE_CONF_PROPERTIES))
|
||||
.credential(new AzureKeyCredential(apiKey))
|
||||
.buildAsyncClient();
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
+7
-10
@@ -2,8 +2,9 @@
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -14,7 +15,6 @@ import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Function;
|
||||
@@ -50,10 +50,9 @@ public class ContextVariableFunctionTest extends AbstractKernelTest {
|
||||
"ChatBot",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.7, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
new PromptTemplateConfig.CompletionConfig(0.7, 0.5, 0, 0, 2000));
|
||||
|
||||
CompletionSKContext readOnlySkContext = chat.buildContext();
|
||||
SKContext readOnlySkContext = SKBuilders.context().build(kernel);
|
||||
|
||||
chat("Hi, I'm looking for book suggestions?", chat, readOnlySkContext)
|
||||
.flatMap(
|
||||
@@ -72,8 +71,7 @@ public class ContextVariableFunctionTest extends AbstractKernelTest {
|
||||
.block();
|
||||
}
|
||||
|
||||
private Function<CompletionSKContext, Mono<CompletionSKContext>> chat(
|
||||
String input, CompletionSKFunction chat) {
|
||||
private Function<SKContext, Mono<SKContext>> chat(String input, CompletionSKFunction chat) {
|
||||
return (context) -> {
|
||||
try {
|
||||
return chat(input, chat, context);
|
||||
@@ -83,14 +81,13 @@ public class ContextVariableFunctionTest extends AbstractKernelTest {
|
||||
};
|
||||
}
|
||||
|
||||
private Mono<CompletionSKContext> chat(
|
||||
String input, CompletionSKFunction chat, CompletionSKContext context)
|
||||
private Mono<SKContext> chat(String input, CompletionSKFunction chat, SKContext context)
|
||||
throws ExecutionException, InterruptedException, TimeoutException {
|
||||
context = context.setVariable("user_input", input);
|
||||
|
||||
LOGGER.info("User:\n" + input);
|
||||
|
||||
CompletionSKContext finalContext = context;
|
||||
SKContext finalContext = context;
|
||||
return chat.invokeAsync(context, null)
|
||||
.map(
|
||||
result -> {
|
||||
|
||||
+3
-7
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -20,12 +19,9 @@ public class FunSkillTest extends AbstractKernelTest {
|
||||
|
||||
@Test
|
||||
public void tellAJoke() throws IOException {
|
||||
Mono<CompletionSKContext> result =
|
||||
Mono<SKContext> result =
|
||||
buildTextCompletionKernel()
|
||||
.importSkill(
|
||||
"FunSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../../samples/skills", "FunSkill"))
|
||||
.importSkillFromDirectory("FunSkill", "../../../samples/skills")
|
||||
.getFunction("joke", CompletionSKFunction.class)
|
||||
.invokeAsync("time travel to dinosaur age");
|
||||
|
||||
|
||||
+3
-5
@@ -2,8 +2,8 @@
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -14,7 +14,6 @@ import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class InlineFunctionTest extends AbstractKernelTest {
|
||||
|
||||
@@ -33,8 +32,7 @@ public class InlineFunctionTest extends AbstractKernelTest {
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
new PromptTemplateConfig.CompletionConfig(0.2, 0.5, 0, 0, 2000));
|
||||
|
||||
String text =
|
||||
"""
|
||||
@@ -49,7 +47,7 @@ public class InlineFunctionTest extends AbstractKernelTest {
|
||||
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic dialect. The language indicates she was knowledgeable in Homeric poetry—'bearing a pleasant gift', for example, alludes to the use of that phrase throughout the Iliad and Odyssey.[a][2]
|
||||
""";
|
||||
|
||||
Mono<CompletionSKContext> result = summarize.invokeAsync(text);
|
||||
Mono<SKContext> result = summarize.invokeAsync(text);
|
||||
|
||||
LOGGER.info("Result: " + result.block().getResult());
|
||||
}
|
||||
|
||||
+25
-25
@@ -1,61 +1,61 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class KernelTest extends AbstractKernelTest {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(KernelTest.class);
|
||||
|
||||
private static void executeCompletion(Kernel kernel) {
|
||||
CompletionSKFunction summarize = kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
"""
|
||||
CompletionSKFunction summarize =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
"""
|
||||
{{$input}}
|
||||
|
||||
One line TLDR with the fewest words.""",
|
||||
null,
|
||||
"",
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0, 0, 0, 0, 256, new ArrayList<>()));
|
||||
null,
|
||||
"",
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(0, 0, 0, 0, 256));
|
||||
|
||||
String text1 = """
|
||||
String text1 =
|
||||
"""
|
||||
1st Law of Thermodynamics - Energy cannot be created or destroyed.
|
||||
2nd Law of Thermodynamics - For a spontaneous process, the entropy of the universe increases.
|
||||
3rd Law of Thermodynamics - A perfect crystal at zero Kelvin has zero entropy""";
|
||||
|
||||
Mono<CompletionSKContext> mono = summarize.invokeAsync(text1);
|
||||
CompletionSKContext result = mono.block();
|
||||
Mono<SKContext> mono = summarize.invokeAsync(text1);
|
||||
SKContext result = mono.block();
|
||||
|
||||
if (result != null)
|
||||
LOGGER.info("Result: " + result.getResult());
|
||||
if (result != null) LOGGER.info("Result: " + result.getResult());
|
||||
}
|
||||
|
||||
public static Kernel buildKernel(OpenAIAsyncClient client, String model) {
|
||||
|
||||
TextCompletion textCompletion = new OpenAITextCompletion(client, model);
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.build();
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
}
|
||||
|
||||
+9
-11
@@ -2,9 +2,9 @@
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.planner.actionplanner.Plan;
|
||||
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlanner;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
@@ -21,21 +21,19 @@ public class PlannerTest extends AbstractKernelTest {
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void executeInlineFunction() throws IOException {
|
||||
Kernel kernel = buildTextCompletionKernel();
|
||||
kernel.importSkill(
|
||||
"SummarizeSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../../samples/skills", "SummarizeSkill"));
|
||||
kernel.importSkill(
|
||||
"WriterSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../../samples/skills", "WriterSkill"));
|
||||
kernel.importSkillFromDirectory(
|
||||
"SummarizeSkill", "../../../samples/skills", "SummarizeSkill");
|
||||
kernel.importSkillFromDirectory("WriterSkill", "../../../samples/skills", "WriterSkill");
|
||||
|
||||
SequentialPlanner planner = new SequentialPlanner(kernel, null, null);
|
||||
|
||||
CompletionSKContext result =
|
||||
Plan plan =
|
||||
planner.createPlanAsync(
|
||||
"Write a poem about John Doe, then translate it into Italian.")
|
||||
.block();
|
||||
|
||||
SKContext result = plan.invokeAsync().block();
|
||||
|
||||
LOGGER.info("Result: " + result.getResult());
|
||||
}
|
||||
}
|
||||
|
||||
+116
-123
@@ -1,9 +1,16 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.e2e;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textembeddings.OpenAITextEmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.coreskills.TextMemorySkill;
|
||||
import com.microsoft.semantickernel.memory.MemoryQueryResult;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.memory.VolatileMemoryStore;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -11,155 +18,141 @@ import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textembeddings.OpenAITextEmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.coreskills.TextMemorySkill;
|
||||
import com.microsoft.semantickernel.memory.MemoryQueryResult;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.memory.VolatileMemoryStore;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TextEmbeddingsTest extends AbstractKernelTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TextEmbeddingsTest.class);
|
||||
private static final int EXPECTED_EMBEDDING_SIZE = 1536;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TextEmbeddingsTest.class);
|
||||
private static final int EXPECTED_EMBEDDING_SIZE = 1536;
|
||||
|
||||
@Test
|
||||
@EnabledIf("isOpenAIComTestEnabled")
|
||||
public void testEmbeddingGenerationOpenAI() throws IOException {
|
||||
testEmbeddingGeneration(getOpenAIClient(), EXPECTED_EMBEDDING_SIZE);
|
||||
}
|
||||
@Test
|
||||
@EnabledIf("isOpenAIComTestEnabled")
|
||||
public void testEmbeddingGenerationOpenAI() throws IOException {
|
||||
testEmbeddingGeneration(getOpenAIClient(), EXPECTED_EMBEDDING_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void testEmbeddingGenerationAzure() throws IOException {
|
||||
testEmbeddingGeneration(getAzureOpenAIClient(), EXPECTED_EMBEDDING_SIZE);
|
||||
}
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void testEmbeddingGenerationAzure() throws IOException {
|
||||
testEmbeddingGeneration(getAzureOpenAIClient(), EXPECTED_EMBEDDING_SIZE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void testEmbeddingGeneration() throws IOException {
|
||||
String model = "text-embedding-ada-002";
|
||||
OpenAITextEmbeddingGeneration embeddingGeneration = new OpenAITextEmbeddingGeneration(getOpenAIClient(),
|
||||
model);
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void testEmbeddingGeneration() throws IOException {
|
||||
String model = "text-embedding-ada-002";
|
||||
OpenAITextEmbeddingGeneration embeddingGeneration =
|
||||
new OpenAITextEmbeddingGeneration(getOpenAIClient(), model);
|
||||
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("This is just a test");
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("This is just a test");
|
||||
|
||||
LOGGER.info(String.valueOf(embeddingGeneration.generateEmbeddingsAsync(data).block()));
|
||||
}
|
||||
LOGGER.info(String.valueOf(embeddingGeneration.generateEmbeddingsAsync(data).block()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf("isAzureTestEnabled")
|
||||
public void testMemory() throws IOException {
|
||||
|
||||
Kernel kernel = buildTextCompletionKernel();
|
||||
kernel.importSkill(new TextMemorySkill(), "aboutMe");
|
||||
Kernel kernel = buildTextCompletionKernel();
|
||||
kernel.importSkill(new TextMemorySkill(), "aboutMe");
|
||||
|
||||
String skPrompt = """
|
||||
String skPrompt =
|
||||
"""
|
||||
|
||||
ChatBot can have a conversation with you about any topic.
|
||||
It can give explicit instructions or say 'I don't know' if it does not have an answer.
|
||||
ChatBot can have a conversation with you about any topic.
|
||||
It can give explicit instructions or say 'I don't know' if it does not have an answer.
|
||||
|
||||
Information about me, from previous conversations:
|
||||
- {{$fact1}} {{recall $fact1}}
|
||||
- {{$fact2}} {{recall $fact2}}
|
||||
- {{$fact3}} {{recall $fact3}}
|
||||
- {{$fact4}} {{recall $fact4}}
|
||||
- {{$fact5}} {{recall $fact5}}
|
||||
Information about me, from previous conversations:
|
||||
- {{$fact1}} {{recall $fact1}}
|
||||
- {{$fact2}} {{recall $fact2}}
|
||||
- {{$fact3}} {{recall $fact3}}
|
||||
- {{$fact4}} {{recall $fact4}}
|
||||
- {{$fact5}} {{recall $fact5}}
|
||||
|
||||
Chat:
|
||||
{{$history}}
|
||||
User: {{$userInput}}
|
||||
ChatBot:\s""";
|
||||
Chat:
|
||||
{{$history}}
|
||||
User: {{$userInput}}
|
||||
ChatBot:\s""";
|
||||
|
||||
CompletionSKFunction chat = kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
skPrompt, "recall", "aboutMe", "TextEmbeddingTest#testMemory");
|
||||
CompletionSKFunction chat =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
skPrompt, "recall", "aboutMe", "TextEmbeddingTest#testMemory");
|
||||
|
||||
VolatileMemoryStore volatileMemoryStore = new VolatileMemoryStore();
|
||||
volatileMemoryStore.createCollectionAsync("aboutMe").block();
|
||||
VolatileMemoryStore volatileMemoryStore = new VolatileMemoryStore();
|
||||
volatileMemoryStore.createCollectionAsync("aboutMe").block();
|
||||
|
||||
OpenAITextEmbeddingGeneration embeddingGeneration = new OpenAITextEmbeddingGeneration(
|
||||
getAzureOpenAIClient(), "text-embedding-ada-002");
|
||||
OpenAITextEmbeddingGeneration embeddingGeneration =
|
||||
new OpenAITextEmbeddingGeneration(getAzureOpenAIClient(), "text-embedding-ada-002");
|
||||
|
||||
SemanticTextMemory memory = SKBuilders.semanticTextMemory()
|
||||
.setEmbeddingGenerator(embeddingGeneration)
|
||||
.setStorage(volatileMemoryStore)
|
||||
.build();
|
||||
SemanticTextMemory memory =
|
||||
SKBuilders.semanticTextMemory()
|
||||
.setEmbeddingGenerator(embeddingGeneration)
|
||||
.setStorage(volatileMemoryStore)
|
||||
.build();
|
||||
|
||||
CompletionSKContext context = chat.buildContext(SKBuilders.variables().build(), memory,
|
||||
kernel.getSkills());
|
||||
SKContext context =
|
||||
SKBuilders.context()
|
||||
.with(SKBuilders.variables().build())
|
||||
.with(memory)
|
||||
.with(kernel.getSkills())
|
||||
.build();
|
||||
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync("aboutMe", "My name is Andrea", "fact1", null, null)
|
||||
.block();
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync("aboutMe", "My name is Andrea", "fact1", null, null)
|
||||
.block();
|
||||
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync(
|
||||
"aboutMe", "I currently work as a tour guide", "fact2", null, null)
|
||||
.block();
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync(
|
||||
"aboutMe", "I currently work as a tour guide", "fact2", null, null)
|
||||
.block();
|
||||
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync(
|
||||
"aboutMe", "I've been living in Seattle since 2005", "fact3", null,
|
||||
null)
|
||||
.block();
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync(
|
||||
"aboutMe", "I've been living in Seattle since 2005", "fact3", null, null)
|
||||
.block();
|
||||
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync(
|
||||
"aboutMe",
|
||||
"I visited France and Italy five times since 2015",
|
||||
"fact4",
|
||||
null,
|
||||
null)
|
||||
.block();
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync(
|
||||
"aboutMe",
|
||||
"I visited France and Italy five times since 2015",
|
||||
"fact4",
|
||||
null,
|
||||
null)
|
||||
.block();
|
||||
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync("aboutMe", "My family is from New York", "fact5", null, null)
|
||||
.block();
|
||||
context.getSemanticMemory()
|
||||
.saveInformationAsync("aboutMe", "My family is from New York", "fact5", null, null)
|
||||
.block();
|
||||
|
||||
String query = "Where are you from originally?";
|
||||
List<MemoryQueryResult> results = memory.searchAsync("aboutMe", query, 10, .5, false).block();
|
||||
results.forEach(
|
||||
result -> System.out.printf(
|
||||
"%s %s (relevance=%f)%n",
|
||||
query, result.getMetadata().getText(), result.getRelevance()));
|
||||
}
|
||||
String query = "Where are you from originally?";
|
||||
List<MemoryQueryResult> results =
|
||||
memory.searchAsync("aboutMe", query, 10, .5, false).block();
|
||||
results.forEach(
|
||||
result ->
|
||||
System.out.printf(
|
||||
"%s %s (relevance=%f)%n",
|
||||
query, result.getMetadata().getText(), result.getRelevance()));
|
||||
}
|
||||
|
||||
public void testEmbeddingGeneration(OpenAIAsyncClient client, int expectedEmbeddingSize) {
|
||||
String model = "text-embedding-ada-002";
|
||||
OpenAITextEmbeddingGeneration embeddingGeneration = new OpenAITextEmbeddingGeneration(client, model);
|
||||
public void testEmbeddingGeneration(OpenAIAsyncClient client, int expectedEmbeddingSize) {
|
||||
String model = "text-embedding-ada-002";
|
||||
OpenAITextEmbeddingGeneration embeddingGeneration =
|
||||
new OpenAITextEmbeddingGeneration(client, model);
|
||||
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("This is just");
|
||||
data.add("a test");
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("This is just");
|
||||
data.add("a test");
|
||||
|
||||
embeddingGeneration
|
||||
.generateEmbeddingsAsync(data)
|
||||
.block()
|
||||
.forEach(
|
||||
embedding -> Assertions.assertEquals(
|
||||
expectedEmbeddingSize, embedding.getVector().size()));
|
||||
}
|
||||
|
||||
private Kernel buildTextEmbeddingsKernel() throws IOException {
|
||||
String model = "text-embedding-ada-002";
|
||||
OpenAITextEmbeddingGeneration embeddingGeneration = new OpenAITextEmbeddingGeneration(getOpenAIClient(),
|
||||
model);
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addTextEmbeddingsGenerationService(model, kernel -> embeddingGeneration)
|
||||
.build();
|
||||
|
||||
// TODO: .WithMemoryStorage(new VolatileMemoryStore())
|
||||
|
||||
// TODO: .WithMemoryStorage(new VolatileMemoryStore())
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
}
|
||||
embeddingGeneration
|
||||
.generateEmbeddingsAsync(data)
|
||||
.block()
|
||||
.forEach(
|
||||
embedding ->
|
||||
Assertions.assertEquals(
|
||||
expectedEmbeddingSize, embedding.getVector().size()));
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -12,7 +12,7 @@
|
||||
<url>https://www.github.com/microsoft/semantic-kernel</url>
|
||||
|
||||
<properties>
|
||||
<azure-ai-openai.version>1.0.0-beta.1</azure-ai-openai.version>
|
||||
<azure-ai-openai.version>1.0.0-beta.2</azure-ai-openai.version>
|
||||
<checkstyle.version>10.11.0</checkstyle.version>
|
||||
<com.uber.nullaway.version>0.10.10</com.uber.nullaway.version>
|
||||
<google.errorprone.core.version>2.19.1</google.errorprone.core.version>
|
||||
@@ -131,6 +131,11 @@
|
||||
<artifactId>sequentialplanner-extensions</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>actionplanner-extension</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -35,4 +35,113 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.release}</source>
|
||||
<target>${maven.compiler.release}</target>
|
||||
<release>${maven.compiler.release}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.connectors</groupId>
|
||||
<artifactId>semantickernel-connectors</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
<artifactId>semantickernel-core-skills</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>sequentialplanner-extensions</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>actionplanner-extension</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>bug-check</id>
|
||||
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven.compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${maven.compiler.release}</source>
|
||||
<target>${maven.compiler.release}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArgs>
|
||||
<arg>-XDcompilePolicy=simple</arg>
|
||||
|
||||
<!-- Remove exclusions when more project is stable -->
|
||||
<arg>-Xplugin:ErrorProne
|
||||
-XepOpt:NullAway:AnnotatedPackages=com.microsoft.semantickernel
|
||||
-Xep:AlmostJavadoc:OFF -Xep:MissingSummary:OFF
|
||||
-Xep:UnusedVariable:OFF -Xep:EmptyBlockTag:OFF
|
||||
</arg>
|
||||
</compilerArgs>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_core</artifactId>
|
||||
<version>${google.errorprone.core.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>com.uber.nullaway</groupId>
|
||||
<artifactId>nullaway</artifactId>
|
||||
<version>${com.uber.nullaway.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
@@ -16,11 +16,24 @@ public class Config {
|
||||
public static final String CONF_PROPERTIES =
|
||||
System.getProperty("CONF_PROPERTIES", "java/samples/conf.properties");
|
||||
|
||||
public static final String OPENAI_CLIENT_TYPE =
|
||||
System.getProperty("OPENAI_CLIENT_TYPE", "OPEN_AI");
|
||||
|
||||
public static OpenAIAsyncClient getClient() throws IOException {
|
||||
return ClientType.valueOf(OPENAI_CLIENT_TYPE).getClient();
|
||||
}
|
||||
|
||||
public enum ClientType {
|
||||
OPEN_AI {
|
||||
@Override
|
||||
public OpenAIAsyncClient getClient() throws IOException {
|
||||
OpenAISettings settings = AIProviderSettings.getOpenAISettingsFromFile(CONF_PROPERTIES);
|
||||
return getClient(CONF_PROPERTIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenAIAsyncClient getClient(String file) throws IOException {
|
||||
OpenAISettings settings = AIProviderSettings.getOpenAISettingsFromFile(file);
|
||||
|
||||
return new OpenAIClientBuilder()
|
||||
.credential(new NonAzureOpenAIKeyCredential(settings.getKey()))
|
||||
.buildAsyncClient();
|
||||
@@ -28,9 +41,14 @@ public class Config {
|
||||
},
|
||||
AZURE_OPEN_AI {
|
||||
@Override
|
||||
public OpenAIAsyncClient getClient()
|
||||
public OpenAIAsyncClient getClient() throws IOException {
|
||||
return getClient(CONF_PROPERTIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenAIAsyncClient getClient(String file)
|
||||
throws IOException {
|
||||
AzureOpenAISettings settings = AIProviderSettings.getAzureOpenAISettingsFromFile(CONF_PROPERTIES);
|
||||
AzureOpenAISettings settings = AIProviderSettings.getAzureOpenAISettingsFromFile(file);
|
||||
|
||||
return new OpenAIClientBuilder()
|
||||
.endpoint(settings.getEndpoint())
|
||||
@@ -40,5 +58,12 @@ public class Config {
|
||||
};
|
||||
|
||||
public abstract OpenAIAsyncClient getClient() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the client that will handle AzureOpenAI or OpenAI requests.
|
||||
*
|
||||
* @return client to be used by the kernel.
|
||||
*/
|
||||
public abstract OpenAIAsyncClient getClient(String file) throws IOException;
|
||||
}
|
||||
}
|
||||
|
||||
+35
-38
@@ -4,9 +4,8 @@ import java.io.IOException;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -24,54 +23,52 @@ import reactor.core.publisher.Mono;
|
||||
*/
|
||||
public class Example00_GettingStarted {
|
||||
|
||||
/**
|
||||
* Returns a Semantic Kernel with Text Completion.
|
||||
*
|
||||
* @param client Client that will handle requests to AzureOpenAI or OpenAI.
|
||||
* @return
|
||||
*/
|
||||
public static Kernel getKernel(OpenAIAsyncClient client) {
|
||||
KernelConfig config = SKBuilders.kernelConfig()
|
||||
/**
|
||||
* Returns a Semantic Kernel with Text Completion.
|
||||
*
|
||||
* @param client Client that will handle requests to AzureOpenAI or OpenAI.
|
||||
* @return
|
||||
*/
|
||||
public static Kernel getKernel(OpenAIAsyncClient client) {
|
||||
KernelConfig config = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService("davinci",
|
||||
kernel -> SKBuilders.textCompletionService().build(client, "text-davinci-003"))
|
||||
.build();
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(config)
|
||||
.build();
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(config)
|
||||
.build();
|
||||
|
||||
return kernel;
|
||||
}
|
||||
return kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Imports 'FunSkill' from directory examples and runs the 'Joke' function
|
||||
* within it.
|
||||
*
|
||||
* @param kernel Kernel with Text Completion.
|
||||
*/
|
||||
public static void joke(Kernel kernel) {
|
||||
*
|
||||
* @param kernel Kernel with Text Completion.
|
||||
*/
|
||||
public static void joke(Kernel kernel) {
|
||||
|
||||
ReadOnlyFunctionCollection skill = kernel
|
||||
.importSkill("FunSkill", KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"samples/skills", "FunSkill"));
|
||||
ReadOnlyFunctionCollection skill = kernel.importSkillFromDirectory("FunSkill", "samples/skills", "FunSkill");
|
||||
|
||||
CompletionSKFunction function = skill.getFunction("Joke",
|
||||
CompletionSKFunction.class);
|
||||
CompletionSKFunction function = skill.getFunction("Joke",
|
||||
CompletionSKFunction.class);
|
||||
|
||||
Mono<CompletionSKContext> result = function.invokeAsync("time travel to dinosaur age");
|
||||
Mono<SKContext> result = function.invokeAsync("time travel to dinosaur age");
|
||||
|
||||
if (result != null) {
|
||||
System.out.println(result.block().getResult());
|
||||
if (result != null) {
|
||||
System.out.println(result.block().getResult());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void run(Config.ClientType clientType) throws IOException {
|
||||
Kernel kernel = getKernel(clientType.getClient());
|
||||
joke(kernel);
|
||||
}
|
||||
public static void run(Config.ClientType clientType) throws IOException {
|
||||
Kernel kernel = getKernel(clientType.getClient());
|
||||
joke(kernel);
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws IOException {
|
||||
// Send one of Config.ClientType.OPEN_AI or Config.ClientType.AZURE_OPEN_AI
|
||||
run(Config.ClientType.OPEN_AI);
|
||||
}
|
||||
public static void main(String args[]) throws IOException {
|
||||
// Send one of Config.ClientType.OPEN_AI or Config.ClientType.AZURE_OPEN_AI
|
||||
run(Config.ClientType.OPEN_AI);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-24
@@ -1,12 +1,10 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Using Semantic Functions stored on disk
|
||||
*
|
||||
@@ -22,30 +20,29 @@ import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
*/
|
||||
public class Example02_RunnningPromptsFromFile {
|
||||
|
||||
/**
|
||||
/**
|
||||
* Imports skill 'FunSkill' stored in the samples folder and then returns the
|
||||
* semantic function 'Joke' within it.
|
||||
*
|
||||
* @param kernel Kernel with Text Completion
|
||||
* @return Joke function
|
||||
*/
|
||||
public static CompletionSKFunction getJokeFunction(Kernel kernel) {
|
||||
ReadOnlyFunctionCollection skill = kernel
|
||||
.importSkill("FunSkill", KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"samples/skills", "FunSkill"));
|
||||
*
|
||||
* @param kernel Kernel with Text Completion
|
||||
* @return Joke function
|
||||
*/
|
||||
public static CompletionSKFunction getJokeFunction(Kernel kernel) {
|
||||
ReadOnlyFunctionCollection skill = kernel
|
||||
.importSkillFromDirectory("FunSkill", "samples/skills", "FunSkill");
|
||||
|
||||
return skill.getFunction("Joke", CompletionSKFunction.class);
|
||||
}
|
||||
return skill.getFunction("Joke", CompletionSKFunction.class);
|
||||
}
|
||||
|
||||
public static void run(Config.ClientType clientType) throws IOException {
|
||||
Kernel kernel = Example00_GettingStarted.getKernel(clientType.getClient());
|
||||
CompletionSKFunction jokeFunction = getJokeFunction(kernel);
|
||||
public static void run(Config.ClientType clientType) throws IOException {
|
||||
Kernel kernel = Example00_GettingStarted.getKernel(clientType.getClient());
|
||||
CompletionSKFunction jokeFunction = getJokeFunction(kernel);
|
||||
|
||||
System.out.println(jokeFunction.invokeAsync("time travel to dinosaur age").block().getResult());
|
||||
}
|
||||
System.out.println(jokeFunction.invokeAsync("time travel to dinosaur age").block().getResult());
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws IOException {
|
||||
// Send one of Config.ClientType.OPEN_AI or Config.ClientType.AZURE_OPEN_AI
|
||||
run(Config.ClientType.OPEN_AI);
|
||||
}
|
||||
public static void main(String args[]) throws IOException {
|
||||
// Send one of Config.ClientType.OPEN_AI or Config.ClientType.AZURE_OPEN_AI
|
||||
run(Config.ClientType.OPEN_AI);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-10
@@ -1,15 +1,13 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Define a Semantic Function inline with Java code.
|
||||
*/
|
||||
@@ -36,10 +34,9 @@ public class Example03_SemanticFunctionInline {
|
||||
0.5,
|
||||
0,
|
||||
0,
|
||||
2000,
|
||||
new ArrayList<>()));
|
||||
2000));
|
||||
|
||||
Mono<CompletionSKContext> result = summarize.invokeAsync(text);
|
||||
Mono<SKContext> result = summarize.invokeAsync(text);
|
||||
|
||||
if (result != null) {
|
||||
System.out.println(result.block().getResult());
|
||||
|
||||
+12
-13
@@ -1,17 +1,17 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Chatbot using context variables
|
||||
*
|
||||
@@ -43,10 +43,9 @@ public class Example04_ContextVariablesChat {
|
||||
0.5,
|
||||
0,
|
||||
0,
|
||||
2000,
|
||||
new ArrayList<>()));
|
||||
2000));
|
||||
|
||||
CompletionSKContext readOnlySkContext = chat.buildContext();
|
||||
SKContext readOnlySkContext = SKBuilders.context().build(kernel);
|
||||
|
||||
chat("Hi, I'm looking for book suggestions?", chat, readOnlySkContext)
|
||||
.flatMap(
|
||||
@@ -65,14 +64,14 @@ public class Example04_ContextVariablesChat {
|
||||
.block();
|
||||
}
|
||||
|
||||
private static Mono<CompletionSKContext> chat(
|
||||
String input, CompletionSKFunction chat, CompletionSKContext context)
|
||||
private static Mono<SKContext> chat(
|
||||
String input, CompletionSKFunction chat, SKContext context)
|
||||
throws ExecutionException, InterruptedException, TimeoutException {
|
||||
context = context.setVariable("user_input", input);
|
||||
|
||||
System.out.println("User: " + input);
|
||||
|
||||
CompletionSKContext finalContext = context;
|
||||
SKContext finalContext = context;
|
||||
return chat.invokeAsync(context, null)
|
||||
.map(
|
||||
result -> {
|
||||
@@ -87,7 +86,7 @@ public class Example04_ContextVariablesChat {
|
||||
});
|
||||
}
|
||||
|
||||
private static Function<CompletionSKContext, Mono<CompletionSKContext>> chat(
|
||||
private static Function<SKContext, Mono<SKContext>> chat(
|
||||
String input, CompletionSKFunction chat) {
|
||||
return (context) -> {
|
||||
try {
|
||||
|
||||
+4
-8
@@ -1,7 +1,5 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlanner;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -9,21 +7,19 @@ import java.io.IOException;
|
||||
public class Example05_UsingThePlanner {
|
||||
|
||||
public static SequentialPlanner getPlanner(Kernel kernel) {
|
||||
kernel.importSkill("SummarizeSkill", KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"samples/skills", "SummarizeSkill"));
|
||||
kernel.importSkill("WriterSkill", KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"samples/skills", "WriterSkill"));
|
||||
kernel.importSkillFromDirectory("SummarizeSkill", "samples/skills", "SummarizeSkill");
|
||||
kernel.importSkillFromDirectory("WriterSkill", "samples/skills", "WriterSkill");
|
||||
|
||||
return new SequentialPlanner(kernel, null, null);
|
||||
}
|
||||
|
||||
public static void run (Config.ClientType clientType) throws IOException {
|
||||
public static void run(Config.ClientType clientType) throws IOException {
|
||||
Kernel kernel = Example00_GettingStarted.getKernel(clientType.getClient());
|
||||
|
||||
SequentialPlanner planner = getPlanner(kernel);
|
||||
System.out.println(planner.createPlanAsync(
|
||||
"Write a poem about John Doe, then translate it into Italian.")
|
||||
.block().getResult());
|
||||
.block().invokeAsync().block());
|
||||
|
||||
// TODO: execute the plan
|
||||
}
|
||||
|
||||
+1
-3
@@ -11,9 +11,7 @@ public class Example06_MemoryAndEmbeddings {
|
||||
KernelConfig config = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"davinci", kernel -> SKBuilders.textCompletionService().build(client, "text-davinci-003"))
|
||||
.addTextEmbeddingsGenerationService(
|
||||
"embeddings", kernel -> SKBuilders.textEmbeddingGenerationService().build(client, "text-embedding-ada-002"))
|
||||
.build();
|
||||
.build();
|
||||
|
||||
// TODO: Add Volatile memory
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ public class Example02_Pipeline {
|
||||
// Load native skill
|
||||
ReadOnlyFunctionCollection text = kernel.importSkill(new TextSkill(), null);
|
||||
|
||||
Mono<SKContext<?>> result =
|
||||
Mono<SKContext> result =
|
||||
kernel.runAsync(
|
||||
" i n f i n i t e s p a c e ",
|
||||
text.getFunction("LStrip"),
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.orchestration.ContextVariables;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.DefineSKFunction;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionInputAttribute;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class Example03_Variables {
|
||||
|
||||
public static class StaticTextSkill {
|
||||
@DefineSKFunction(description = "Change all string chars to uppercase.", name = "Uppercase")
|
||||
public static Mono<String> uppercase(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(description = "Text to uppercase", name = "input")
|
||||
String text) {
|
||||
return Mono.just(text.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@DefineSKFunction(description = "Append the day variable", name = "appendDay")
|
||||
public Mono<String> appendDay(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(description = "Text to append to", name = "input")
|
||||
String input,
|
||||
@SKFunctionParameters(description = "Current day", name = "day") String day) {
|
||||
return Mono.just(input + day);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig().build();
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
// Load native skill
|
||||
ReadOnlyFunctionCollection functionCollection =
|
||||
kernel.importSkill(new StaticTextSkill(), "text");
|
||||
|
||||
ContextVariables variables =
|
||||
SKBuilders.variables()
|
||||
.build("Today is: ")
|
||||
.writableClone()
|
||||
.setVariable("day", "Monday");
|
||||
|
||||
Mono<SKContext> result =
|
||||
kernel.runAsync(
|
||||
variables,
|
||||
functionCollection.getFunction("AppendDay"),
|
||||
functionCollection.getFunction("Uppercase"));
|
||||
|
||||
System.out.println(result.block().getResult());
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.DefineSKFunction;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionInputAttribute;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Example04_CombineLLMPromptsAndNativeCode {
|
||||
|
||||
public static class SearchEngineSkill {
|
||||
@DefineSKFunction(description = "Append the day variable", name = "search")
|
||||
public Mono<String> search(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(description = "Text to search", name = "input")
|
||||
String input) {
|
||||
return Mono.just("Gran Torre Santiago is the tallest building in South America");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
OpenAIAsyncClient client = Config.ClientType.AZURE_OPEN_AI.getClient();
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, "text-davinci-003");
|
||||
|
||||
KernelConfig kernelConfig = new KernelConfig.Builder()
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
kernel.importSkill(new SearchEngineSkill(), null);
|
||||
kernel.importSkillFromDirectory("SummarizeSkill", "./samples/skills", "SummarizeSkill");
|
||||
|
||||
// Run
|
||||
String ask = "What's the tallest building in South America?";
|
||||
|
||||
Mono<SKContext> result =
|
||||
kernel.runAsync(ask, kernel.getSkills().getFunction("Search", null));
|
||||
|
||||
result =
|
||||
kernel.runAsync(
|
||||
ask,
|
||||
kernel.getSkills().getFunction("Search", null),
|
||||
kernel.getSkill("SummarizeSkill").getFunction("Summarize", null));
|
||||
|
||||
System.out.println(result.block().getResult());
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
|
||||
public class Example05_InlineFunctionDefinition {
|
||||
public static void main(String[] args) throws IOException {
|
||||
OpenAIAsyncClient client = Config.ClientType.AZURE_OPEN_AI.getClient();
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, "text-davinci-003");
|
||||
|
||||
KernelConfig kernelConfig = new KernelConfig.Builder()
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
System.out.println("======== Inline Function Definition ========");
|
||||
|
||||
// Function defined using few-shot design pattern
|
||||
String functionDefinition = """
|
||||
Generate a creative reason or excuse for the given event.
|
||||
Be creative and be funny. Let your imagination run wild.
|
||||
|
||||
Event: I am running late.
|
||||
Excuse: I was being held ransom by giraffe gangsters.
|
||||
|
||||
Event: I haven't been to the gym for a year
|
||||
Excuse: I've been too busy training my pet dragon.
|
||||
|
||||
Event: {{$input}}
|
||||
""".stripIndent();
|
||||
|
||||
// Create function via builder
|
||||
var excuseFunction = SKBuilders
|
||||
.completionFunctions(kernel)
|
||||
.createFunction(
|
||||
functionDefinition,
|
||||
new PromptTemplateConfig.CompletionConfigBuilder()
|
||||
.maxTokens(100)
|
||||
.temperature(0.4)
|
||||
.topP(1)
|
||||
.build());
|
||||
|
||||
|
||||
var result = excuseFunction.invokeAsync("I missed the F1 final race").block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
result = excuseFunction.invokeAsync("sorry I forgot your birthday").block();
|
||||
System.out.println(result.getResult());
|
||||
|
||||
// Create function via kernel
|
||||
var fixedFunction = kernel.
|
||||
getSemanticFunctionBuilder()
|
||||
.createFunction("Translate this date " +
|
||||
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(LocalDateTime.now()) + " to French format",
|
||||
new PromptTemplateConfig.CompletionConfigBuilder()
|
||||
.maxTokens(100)
|
||||
.temperature(0.4)
|
||||
.topP(1)
|
||||
.build());
|
||||
|
||||
System.out.println(fixedFunction.invokeAsync().block().getResult());
|
||||
}
|
||||
}
|
||||
+77
-68
@@ -4,91 +4,100 @@ package com.microsoft.semantickernel.syntaxexamples;
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.coreskills.TimeSkill;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Example06_TemplateLanguage {
|
||||
/// <summary>
|
||||
/// Show how to invoke a Native Function written in C#
|
||||
/// from a Semantic Function written in natural language
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Show how to invoke a Native Function written in C#
|
||||
/// from a Semantic Function written in natural language
|
||||
/// </summary>
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.out.println("======== TemplateLanguage ========");
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.out.println("======== TemplateLanguage ========");
|
||||
|
||||
OpenAIAsyncClient client = Config.ClientType.AZURE_OPEN_AI.getClient();
|
||||
OpenAIAsyncClient client = Config.getClient();
|
||||
KernelConfig kernelConfig = SKBuilders
|
||||
.kernelConfig()
|
||||
.addTextCompletionService("text-davinci-003", kernel1 -> SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-003"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().build();
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(kernelConfig)
|
||||
.build();
|
||||
|
||||
// Load native skill into the kernel skill collection, sharing its functions
|
||||
// with prompt templates
|
||||
// Functions loaded here are available as "time.*"
|
||||
kernel.importSkill(new TimeSkill(), "time");
|
||||
// Load native skill into the kernel skill collection, sharing its functions
|
||||
// with prompt templates
|
||||
// Functions loaded here are available as "time.*"
|
||||
kernel.importSkill(new TimeSkill(), "time");
|
||||
|
||||
// Semantic Function invoking time.Date and time.Time native functions
|
||||
String functionDefinition = """
|
||||
Today is: {{time.Date}}
|
||||
Current time is: {{time.Time}}
|
||||
// Semantic Function invoking time.Date and time.Time native functions
|
||||
String functionDefinition = """
|
||||
Today is: {{time.Date}}
|
||||
Current time is: {{time.Time}}
|
||||
|
||||
Answer to the following questions using JSON syntax, including the data used.
|
||||
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
|
||||
Is it weekend time (weekend/not weekend)?
|
||||
""";
|
||||
Answer to the following questions using JSON syntax, including the data used.
|
||||
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
|
||||
Is it weekend time (weekend/not weekend)?
|
||||
""";
|
||||
|
||||
// This allows to see the prompt before it's sent to OpenAI
|
||||
System.out.println("--- Rendered Prompt");
|
||||
// This allows to see the prompt before it's sent to OpenAI
|
||||
System.out.println("--- Rendered Prompt");
|
||||
|
||||
var promptRenderer = SKBuilders.promptTemplate().build(functionDefinition, null);
|
||||
var promptRenderer = SKBuilders.promptTemplate()
|
||||
.withPromptTemplateConfig(new PromptTemplateConfig())
|
||||
.withPromptTemplate(functionDefinition)
|
||||
.build(kernel.getPromptTemplateEngine());
|
||||
|
||||
SKContext skContext = SKBuilders
|
||||
.context()
|
||||
.build(kernel.getSkills());
|
||||
SKContext skContext = SKBuilders
|
||||
.context()
|
||||
.build(kernel.getSkills());
|
||||
|
||||
PromptTemplateEngine promptTemplateEngine = SKBuilders.promptTemplateEngine().build();
|
||||
var renderedPrompt = promptRenderer.renderAsync(skContext);
|
||||
System.out.println(renderedPrompt.block());
|
||||
|
||||
var renderedPrompt = promptRenderer.renderAsync(skContext, promptTemplateEngine);
|
||||
System.out.println(renderedPrompt.block());
|
||||
// Run the prompt / semantic function
|
||||
var kindOfDay = kernel
|
||||
.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
functionDefinition,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0, 0, 0, 0, 256));
|
||||
|
||||
// Run the prompt / semantic function
|
||||
var kindOfDay = kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
functionDefinition,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0, 0, 0, 0, 256, new ArrayList<>()));
|
||||
|
||||
// Show the result
|
||||
System.out.println("--- Semantic Function result");
|
||||
var result = kindOfDay.invokeAsync("").block().getResult();
|
||||
System.out.println(result);
|
||||
/*
|
||||
* OUTPUT:
|
||||
*
|
||||
* --- Rendered Prompt
|
||||
*
|
||||
* Today is: Friday, April 28, 2023
|
||||
* Current time is: 11:04:30 PM
|
||||
*
|
||||
* Answer to the following questions using JSON syntax, including the data used.
|
||||
* Is it morning, afternoon, evening, or night
|
||||
* (morning/afternoon/evening/night)?
|
||||
* Is it weekend time (weekend/not weekend)?
|
||||
*
|
||||
* --- Semantic Function result
|
||||
*
|
||||
* {
|
||||
* "date": "Friday, April 28, 2023",
|
||||
* "time": "11:04:30 PM",
|
||||
* "period": "night",
|
||||
* "weekend": "weekend"
|
||||
* }
|
||||
*/
|
||||
}
|
||||
// Show the result
|
||||
System.out.println("--- Semantic Function result");
|
||||
var result = kindOfDay.invokeAsync("").block().getResult();
|
||||
System.out.println(result);
|
||||
/*
|
||||
* OUTPUT:
|
||||
*
|
||||
* --- Rendered Prompt
|
||||
*
|
||||
* Today is: Friday, April 28, 2023
|
||||
* Current time is: 11:04:30 PM
|
||||
*
|
||||
* Answer to the following questions using JSON syntax, including the data used.
|
||||
* Is it morning, afternoon, evening, or night
|
||||
* (morning/afternoon/evening/night)?
|
||||
* Is it weekend time (weekend/not weekend)?
|
||||
*
|
||||
* --- Semantic Function result
|
||||
*
|
||||
* {
|
||||
* "date": "Friday, April 28, 2023",
|
||||
* "time": "11:04:30 PM",
|
||||
* "period": "night",
|
||||
* "weekend": "weekend"
|
||||
* }
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
+69
-68
@@ -1,12 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import static com.microsoft.semantickernel.Config.CONF_PROPERTIES;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
@@ -15,84 +9,91 @@ import com.azure.core.http.policy.RetryOptions;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
import com.microsoft.semantickernel.util.AIProviderSettings;
|
||||
import com.microsoft.semantickernel.util.AzureOpenAISettings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
|
||||
import static com.microsoft.semantickernel.Config.CONF_PROPERTIES;
|
||||
|
||||
public class Example08_RetryHandler {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
RetryOptions retryOptions = new RetryOptions(new ExponentialBackoffOptions()
|
||||
.setMaxDelay(Duration.ofSeconds(180))
|
||||
.setBaseDelay(Duration.ofSeconds(60))
|
||||
.setMaxRetries(3));
|
||||
public static void main(String[] args) throws IOException {
|
||||
RetryOptions retryOptions = new RetryOptions(new ExponentialBackoffOptions()
|
||||
.setMaxDelay(Duration.ofSeconds(180))
|
||||
.setBaseDelay(Duration.ofSeconds(60))
|
||||
.setMaxRetries(3));
|
||||
|
||||
AzureOpenAISettings settings = AIProviderSettings.getAzureOpenAISettingsFromFile(CONF_PROPERTIES);
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.retryOptions(retryOptions)
|
||||
.endpoint(settings.getEndpoint())
|
||||
.credential(new AzureKeyCredential(settings.getKey()))
|
||||
.buildAsyncClient();
|
||||
AzureOpenAISettings settings = AIProviderSettings.getAzureOpenAISettingsFromFile(CONF_PROPERTIES);
|
||||
OpenAIAsyncClient client = new OpenAIClientBuilder()
|
||||
.retryOptions(retryOptions)
|
||||
.endpoint(settings.getEndpoint())
|
||||
.credential(new AzureKeyCredential(settings.getKey()))
|
||||
.buildAsyncClient();
|
||||
|
||||
String text = """
|
||||
Demo (ancient Greek poet)
|
||||
From Wikipedia, the free encyclopedia
|
||||
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
|
||||
Roman period, known for a single epigram, engraved upon the Colossus of
|
||||
Memnon, which bears her name. She speaks of herself therein as a lyric
|
||||
poetess dedicated to the Muses, but nothing is known of her life.[1]
|
||||
Identity
|
||||
Demo was evidently Greek, as her name, a traditional epithet of Demeter,
|
||||
signifies. The name was relatively common in the Hellenistic world, in
|
||||
Egypt and elsewhere, and she cannot be further identified. The date of her
|
||||
visit to the Colossus of Memnon cannot be established with certainty, but
|
||||
internal evidence on the left leg suggests her poem was inscribed there at
|
||||
some point in or after AD 196.[2]
|
||||
Epigram
|
||||
There are a number of graffiti inscriptions on the Colossus of Memnon.
|
||||
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac
|
||||
couplets, entitled and presumably authored by "Demo" or "Damo" (the
|
||||
Greek inscription is difficult to read), is a dedication to the Muses.[2]
|
||||
The poem is traditionally published with the works of Balbilla, though the
|
||||
internal evidence suggests a different author.[1]
|
||||
In the poem, Demo explains that Memnon has shown her special respect. In
|
||||
return, Demo offers the gift for poetry, as a gift to the hero. At the end
|
||||
of this epigram, she addresses Memnon, highlighting his divine status by
|
||||
recalling his strength and holiness.[2]
|
||||
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic
|
||||
dialect. The language indicates she was knowledgeable in Homeric
|
||||
poetry—'bearing a pleasant gift', for example, alludes to the use of that
|
||||
phrase throughout the Iliad and Odyssey.[a][2];
|
||||
""";
|
||||
String text = """
|
||||
Demo (ancient Greek poet)
|
||||
From Wikipedia, the free encyclopedia
|
||||
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
|
||||
Roman period, known for a single epigram, engraved upon the Colossus of
|
||||
Memnon, which bears her name. She speaks of herself therein as a lyric
|
||||
poetess dedicated to the Muses, but nothing is known of her life.[1]
|
||||
Identity
|
||||
Demo was evidently Greek, as her name, a traditional epithet of Demeter,
|
||||
signifies. The name was relatively common in the Hellenistic world, in
|
||||
Egypt and elsewhere, and she cannot be further identified. The date of her
|
||||
visit to the Colossus of Memnon cannot be established with certainty, but
|
||||
internal evidence on the left leg suggests her poem was inscribed there at
|
||||
some point in or after AD 196.[2]
|
||||
Epigram
|
||||
There are a number of graffiti inscriptions on the Colossus of Memnon.
|
||||
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac
|
||||
couplets, entitled and presumably authored by "Demo" or "Damo" (the
|
||||
Greek inscription is difficult to read), is a dedication to the Muses.[2]
|
||||
The poem is traditionally published with the works of Balbilla, though the
|
||||
internal evidence suggests a different author.[1]
|
||||
In the poem, Demo explains that Memnon has shown her special respect. In
|
||||
return, Demo offers the gift for poetry, as a gift to the hero. At the end
|
||||
of this epigram, she addresses Memnon, highlighting his divine status by
|
||||
recalling his strength and holiness.[2]
|
||||
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic
|
||||
dialect. The language indicates she was knowledgeable in Homeric
|
||||
poetry—'bearing a pleasant gift', for example, alludes to the use of that
|
||||
phrase throughout the Iliad and Odyssey.[a][2];
|
||||
""";
|
||||
|
||||
String prompt = "{{$input}}\nSummarize the content above.";
|
||||
String prompt = "{{$input}}\nSummarize the content above.";
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, "text-davinci-003");
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, "text-davinci-003");
|
||||
|
||||
CompletionSKFunction summarizeFunc = SKBuilders.completionFunctions()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
KernelConfig kernelConfig = new KernelConfig.Builder()
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
KernelConfig kernelConfig = new KernelConfig.Builder()
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.addSkill(summarizeFunc)
|
||||
.build();
|
||||
Kernel kernel = SKBuilders
|
||||
.kernel()
|
||||
.setKernelConfig(kernelConfig)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
CompletionSKFunction summarizeFunc = SKBuilders.completionFunctions(kernel)
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000));
|
||||
|
||||
CompletionSKFunction summarize = kernel.getSkills().getFunction("summarize",
|
||||
CompletionSKFunction.class);
|
||||
|
||||
CompletionSKContext context = summarize.invokeAsync(text).block();
|
||||
kernel.registerSemanticFunction(summarizeFunc);
|
||||
|
||||
System.out.println(context.getResult());
|
||||
}
|
||||
SKContext context = summarizeFunc.invokeAsync(text).block();
|
||||
|
||||
System.out.println(context.getResult());
|
||||
}
|
||||
}
|
||||
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.DefineSKFunction;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionInputAttribute;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
|
||||
public class Example09_FunctionTypes {
|
||||
public static void main(String[] args) throws IOException {
|
||||
OpenAIAsyncClient client = Config.ClientType.AZURE_OPEN_AI.getClient();
|
||||
|
||||
TextCompletion textCompletion = SKBuilders.textCompletionService().build(client, "text-davinci-003");
|
||||
|
||||
KernelConfig kernelConfig = new KernelConfig.Builder()
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
System.out.println("======== Native function types ========");
|
||||
|
||||
// Load native skill into the kernel skill collection, sharing its functions with prompt templates
|
||||
var test = kernel
|
||||
.importSkill(new LocalExampleSkill(), "test");
|
||||
|
||||
kernel.importSkillsFromDirectory("./samples/skills", "SummarizeSkill");
|
||||
|
||||
|
||||
var fakeContext = SKBuilders.context()
|
||||
.with(kernel.getSkills())
|
||||
.build();
|
||||
|
||||
// The kernel takes care of wiring the input appropriately
|
||||
SKContext result = kernel.runAsync(
|
||||
"",
|
||||
test.getFunction("type01"),
|
||||
test.getFunction("type02"),
|
||||
test.getFunction("type03"),
|
||||
test.getFunction("type04"),
|
||||
test.getFunction("type05"),
|
||||
test.getFunction("type06"),
|
||||
test.getFunction("type07"),
|
||||
test.getFunction("type08"),
|
||||
test.getFunction("type09"),
|
||||
test.getFunction("type10"),
|
||||
test.getFunction("type11"),
|
||||
test.getFunction("type12"),
|
||||
test.getFunction("type13"),
|
||||
test.getFunction("type14"),
|
||||
test.getFunction("type15"),
|
||||
test.getFunction("type16"),
|
||||
test.getFunction("type17"),
|
||||
test.getFunction("type18")
|
||||
)
|
||||
.block();
|
||||
|
||||
kernel.getFunction("test", "type01").invokeAsync().block();
|
||||
test.getFunction("type01").invokeAsync().block();
|
||||
|
||||
kernel.getFunction("test", "type02").invokeAsync().block();
|
||||
test.getFunction("type02").invokeAsync().block();
|
||||
|
||||
kernel.getFunction("test", "type03").invokeAsync().block();
|
||||
test.getFunction("type03").invokeAsync().block();
|
||||
|
||||
kernel.getFunction("test", "type04").invokeAsync(fakeContext).block();
|
||||
test.getFunction("type04").invokeAsync(fakeContext).block();
|
||||
|
||||
kernel.getFunction("test", "type05").invokeAsync(fakeContext).block();
|
||||
test.getFunction("type05").invokeAsync(fakeContext).block();
|
||||
|
||||
kernel.getFunction("test", "type06").invokeAsync(fakeContext).block();
|
||||
test.getFunction("type06").invokeAsync(fakeContext).block();
|
||||
|
||||
kernel.getFunction("test", "type07").invokeAsync(fakeContext).block();
|
||||
test.getFunction("type07").invokeAsync(fakeContext).block();
|
||||
|
||||
kernel.getFunction("test", "type08").invokeAsync("").block();
|
||||
test.getFunction("type08").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type09").invokeAsync("").block();
|
||||
test.getFunction("type09").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type10").invokeAsync("").block();
|
||||
test.getFunction("type10").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type11").invokeAsync("").block();
|
||||
test.getFunction("type11").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type12").invokeAsync("").block();
|
||||
test.getFunction("type12").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type13").invokeAsync("").block();
|
||||
test.getFunction("type13").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type14").invokeAsync("").block();
|
||||
test.getFunction("type14").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type15").invokeAsync("").block();
|
||||
test.getFunction("type15").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type16").invokeAsync("").block();
|
||||
test.getFunction("type16").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type17").invokeAsync("").block();
|
||||
test.getFunction("type17").invokeAsync("").block();
|
||||
|
||||
kernel.getFunction("test", "type18").invokeAsync("").block();
|
||||
test.getFunction("type18").invokeAsync("").block();
|
||||
}
|
||||
|
||||
|
||||
public static class LocalExampleSkill {
|
||||
|
||||
@DefineSKFunction(name = "type01")
|
||||
public void Type01() {
|
||||
System.out.println("Running function type 1");
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type02")
|
||||
public String Type02() {
|
||||
System.out.println("Running function type 2");
|
||||
return "";
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type03")
|
||||
public Mono<String> Type03Async() {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.map(x -> {
|
||||
System.out.println("Running function type 3");
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@DefineSKFunction(name = "type04")
|
||||
public void Type04(SKContext context) {
|
||||
System.out.println("Running function type 4");
|
||||
}
|
||||
|
||||
|
||||
@DefineSKFunction(name = "type05")
|
||||
public String Type05(SKContext context) {
|
||||
System.out.println("Running function type 5");
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@DefineSKFunction(name = "type06")
|
||||
public Mono<String> Type06Async(SKContext context) {
|
||||
var summarizer = context.getSkills().getFunction("SummarizeSkill", "Summarize", null);
|
||||
|
||||
return summarizer
|
||||
.invokeAsync("blah blah blah")
|
||||
.map(summary -> {
|
||||
System.out.println("Running function type 6 " + summary.getResult());
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type07")
|
||||
public Mono<SKContext> Type07Async(SKContext context) {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.map(x -> {
|
||||
System.out.println("Running function type 7");
|
||||
return context;
|
||||
});
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type08")
|
||||
public void Type08(
|
||||
@SKFunctionInputAttribute
|
||||
String x) {
|
||||
System.out.println("Running function type 8");
|
||||
}
|
||||
|
||||
|
||||
@DefineSKFunction(name = "type09")
|
||||
public String Type09(
|
||||
@SKFunctionInputAttribute
|
||||
String x) {
|
||||
System.out.println("Running function type 9");
|
||||
return "";
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type10")
|
||||
public Mono<String> Type10Async(
|
||||
@SKFunctionInputAttribute
|
||||
String x) {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.map(x2 -> {
|
||||
System.out.println("Running function type 10");
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type11")
|
||||
public void Type11(
|
||||
@SKFunctionInputAttribute
|
||||
String x,
|
||||
SKContext context) {
|
||||
System.out.println("Running function type 11");
|
||||
}
|
||||
|
||||
|
||||
@DefineSKFunction(name = "type12")
|
||||
public String Type12(
|
||||
@SKFunctionInputAttribute
|
||||
String x,
|
||||
SKContext context) {
|
||||
System.out.println("Running function type 12");
|
||||
return "";
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type13")
|
||||
public Mono<String> Type13Async(
|
||||
@SKFunctionInputAttribute
|
||||
String x, SKContext context) {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.map(x2 -> {
|
||||
System.out.println("Running function type 13");
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type14")
|
||||
public Mono<SKContext> Type14Async(
|
||||
@SKFunctionInputAttribute
|
||||
String x, SKContext context) {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.ignoreElement()
|
||||
.map(x2 -> {
|
||||
System.out.println("Running function type 14");
|
||||
return context;
|
||||
});
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type15")
|
||||
public Mono<Void> Type15Async(String x) {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.ignoreElement()
|
||||
.doFinally(ignore -> System.out.println("Running function type 15"))
|
||||
.then();
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type16")
|
||||
public Mono<Void> Type16Async(SKContext context) {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.ignoreElement()
|
||||
.doFinally(ignore -> System.out.println("Running function type 16"))
|
||||
.then();
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type17")
|
||||
public Mono<Void> Type17Async(String x, SKContext context) {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.ignoreElement()
|
||||
.doFinally(ignore -> System.out.println("Running function type 17"))
|
||||
.then();
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "type18")
|
||||
public Mono<Void> Type18Async() {
|
||||
return Mono.delay(Duration.ZERO)
|
||||
.ignoreElement()
|
||||
.doFinally(ignore -> System.out.println("Running function type 18"))
|
||||
.then();
|
||||
}
|
||||
}
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
package com.microsoft.semantickernel.syntaxexamples;// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.coreskills.TextSkill;
|
||||
import com.microsoft.semantickernel.memory.VolatileMemoryStore;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlanner;
|
||||
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlannerRequestSettings;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.DefineSKFunction;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionInputAttribute;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
public class Example12_SequentialPlanner {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Example12_SequentialPlanner.class);
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
poetrySamplesAsync();
|
||||
emailSamplesAsync();
|
||||
bookSamplesAsync();
|
||||
//MemorySampleAsync();
|
||||
}
|
||||
|
||||
private static void poetrySamplesAsync() throws IOException {
|
||||
System.out.println("======== Sequential Planner - Create and Execute Poetry Plan ========");
|
||||
var kernel = initializeKernel();
|
||||
|
||||
kernel.importSkill(new TextSkill(), "TextSkill");
|
||||
|
||||
var planner = new SequentialPlanner(kernel, null, null);
|
||||
|
||||
var plan = planner.createPlanAsync("Write a poem about John Doe, then translate it into Italian, then convert it to uppercase.").block();
|
||||
|
||||
// Original plan:
|
||||
// Goal: Write a poem about John Doe, then translate it into Italian.
|
||||
|
||||
// Steps:
|
||||
// - WriterSkill.ShortPoem INPUT='John Doe is a friendly guy who likes to help others and enjoys reading books.' =>
|
||||
// - WriterSkill.Translate language='Italian' INPUT='' =>
|
||||
|
||||
SKContext result = plan.invokeAsync().block();
|
||||
|
||||
System.out.println("Result:");
|
||||
System.out.println(result.getResult());
|
||||
}
|
||||
|
||||
public static class EmailSkill {
|
||||
@DefineSKFunction(name = "SendEmail", description = "Given an e-mail and message body, send an email")
|
||||
public void sendEmail(
|
||||
@SKFunctionInputAttribute()
|
||||
@SKFunctionParameters(description = "The body of the email message to send.", name = "input")
|
||||
String input,
|
||||
@SKFunctionParameters(description = "The email address to send email to.", name = "email_address")
|
||||
String emailAddress
|
||||
) {
|
||||
LOGGER.info("Emailing to " + emailAddress + "\n" + input);
|
||||
}
|
||||
|
||||
@DefineSKFunction(name = "GetEmailAddressAsync", description = "Lookup an email address for a person given a name")
|
||||
public String getEmailAddressAsync(
|
||||
@SKFunctionInputAttribute()
|
||||
@SKFunctionParameters(description = "The name of the person to email.", name = "input")
|
||||
String input) {
|
||||
return "[email protected]";
|
||||
}
|
||||
}
|
||||
|
||||
private static void emailSamplesAsync() throws IOException {
|
||||
System.out.println("======== Sequential Planner - Create and Execute Email Plan ========");
|
||||
var kernel = initializeKernel();
|
||||
|
||||
kernel.importSkill(new EmailSkill(), "email");
|
||||
|
||||
|
||||
SequentialPlanner planner = initPlanner(kernel, 1024);
|
||||
|
||||
var plan = planner.createPlanAsync("Summarize an input, translate to french, and e-mail to John Doe").block();
|
||||
|
||||
// Original plan:
|
||||
// Goal: Summarize an input, translate to french, and e-mail to John Doe
|
||||
|
||||
// Steps:
|
||||
// - SummarizeSkill.Summarize INPUT='' =>
|
||||
// - WriterSkill.Translate language='French' INPUT='' => TRANSLATED_SUMMARY
|
||||
// - email.GetEmailAddress INPUT='John Doe' => EMAIL_ADDRESS
|
||||
// - email.SendEmail INPUT='$TRANSLATED_SUMMARY' email_address='$EMAIL_ADDRESS' =>
|
||||
|
||||
System.out.println("Original plan:");
|
||||
System.out.println(plan.toPlanString());
|
||||
|
||||
var input =
|
||||
"Once upon a time, in a faraway kingdom, there lived a kind and just king named Arjun. " +
|
||||
"He ruled over his kingdom with fairness and compassion, earning him the love and admiration of his people. " +
|
||||
"However, the kingdom was plagued by a terrible dragon that lived in the nearby mountains and terrorized the nearby villages, " +
|
||||
"burning their crops and homes. The king had tried everything to defeat the dragon, but to no avail. " +
|
||||
"One day, a young woman named Mira approached the king and offered to help defeat the dragon. She was a skilled archer " +
|
||||
"and claimed that she had a plan to defeat the dragon once and for all. The king was skeptical, but desperate for a solution, " +
|
||||
"so he agreed to let her try. Mira set out for the dragon's lair and, with the help of her trusty bow and arrow, " +
|
||||
"she was able to strike the dragon with a single shot through its heart, killing it instantly. The people rejoiced " +
|
||||
"and the kingdom was at peace once again. The king was so grateful to Mira that he asked her to marry him and she agreed. " +
|
||||
"They ruled the kingdom together, ruling with fairness and compassion, just as Arjun had done before. They lived " +
|
||||
"happily ever after, with the people of the kingdom remembering Mira as the brave young woman who saved them from the dragon.";
|
||||
|
||||
System.out.println(plan.invokeAsync(input).block());
|
||||
}
|
||||
|
||||
private static void bookSamplesAsync() throws IOException {
|
||||
System.out.println("======== Sequential Planner - Create and Execute Book Creation Plan ========");
|
||||
var kernel = initializeKernel();
|
||||
|
||||
SequentialPlanner planner = initPlanner(kernel, 1024);
|
||||
|
||||
var plan = planner.createPlanAsync("Create a book with 3 chapters about a group of kids in a club called 'The Thinking Caps.'").block();
|
||||
|
||||
// Original plan:
|
||||
// Goal: Create a book with 3 chapters about a group of kids in a club called 'The Thinking Caps.'
|
||||
|
||||
// Steps:
|
||||
// - WriterSkill.NovelOutline chapterCount='3' INPUT='A group of kids in a club called 'The Thinking Caps' that solve mysteries and puzzles using their creativity and logic.' endMarker='<!--===ENDPART===-->' => OUTLINE
|
||||
// - MiscSkill.ElementAtIndex count='3' INPUT='$OUTLINE' index='0' => CHAPTER_1_SYNOPSIS
|
||||
// - WriterSkill.NovelChapter chapterIndex='1' previousChapter='' INPUT='$CHAPTER_1_SYNOPSIS' theme='Children's mystery' => RESULT__CHAPTER_1
|
||||
// - MiscSkill.ElementAtIndex count='3' INPUT='$OUTLINE' index='1' => CHAPTER_2_SYNOPSIS
|
||||
// - WriterSkill.NovelChapter chapterIndex='2' previousChapter='$CHAPTER_1_SYNOPSIS' INPUT='$CHAPTER_2_SYNOPSIS' theme='Children's mystery' => RESULT__CHAPTER_2
|
||||
// - MiscSkill.ElementAtIndex count='3' INPUT='$OUTLINE' index='2' => CHAPTER_3_SYNOPSIS
|
||||
// - WriterSkill.NovelChapter chapterIndex='3' previousChapter='$CHAPTER_2_SYNOPSIS' INPUT='$CHAPTER_3_SYNOPSIS' theme='Children's mystery' => RESULT__CHAPTER_3
|
||||
System.out.println(plan.invokeAsync().block().getResult());
|
||||
}
|
||||
|
||||
/*
|
||||
TODO
|
||||
private static void memorySampleAsync() throws IOException {
|
||||
System.out.println("======== Sequential Planner - Create and Execute Plan using Memory ========");
|
||||
var kernel = initializeKernel();
|
||||
|
||||
SequentialPlanner planner = initPlanner(kernel, 1024);
|
||||
|
||||
kernel.importSkillsFromDirectory("samples/skills",
|
||||
"CalendarSkill",
|
||||
"ChatSkill",
|
||||
"ChildrensBookSkill",
|
||||
"ClassificationSkill",
|
||||
"CodingSkill",
|
||||
"FunSkill",
|
||||
"IntentDetectionSkill",
|
||||
"MiscSkill",
|
||||
"QASkill");
|
||||
|
||||
kernel.importSkill(new EmailSkill(), "email");
|
||||
kernel.importSkill(new StaticTextSkill(), "statictext");
|
||||
kernel.importSkill(new TextSkill(), "text");
|
||||
kernel.importSkill(new Microsoft.SemanticKernel.CoreSkills.TextSkill(), "coretext");
|
||||
|
||||
var goal = "Create a book with 3 chapters about a group of kids in a club called 'The Thinking Caps.'";
|
||||
|
||||
var planner = new SequentialPlanner(kernel, new SequentialPlannerConfig {
|
||||
RelevancyThreshold =0.78
|
||||
});
|
||||
|
||||
var plan = await planner.CreatePlanAsync(goal);
|
||||
|
||||
System.out.println("Original plan:");
|
||||
System.out.println(plan.ToPlanString());
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static Kernel initializeKernel() throws IOException {
|
||||
OpenAIAsyncClient client = Config.getClient();
|
||||
var kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(SKBuilders
|
||||
.kernelConfig()
|
||||
.addTextCompletionService("text-davinci-003", kernel1 -> SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-003"))
|
||||
.build())
|
||||
.withMemory(SKBuilders
|
||||
.semanticTextMemory()
|
||||
.setEmbeddingGenerator(
|
||||
SKBuilders.textEmbeddingGenerationService().build(client, "text-davinci-003")
|
||||
)
|
||||
.setStorage(new VolatileMemoryStore())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
|
||||
// Load additional skills to enable planner to do non-trivial asks.
|
||||
kernel.importSkillFromDirectory("SummarizeSkill", "samples/skills", "SummarizeSkill");
|
||||
kernel.importSkillFromDirectory("WriterSkill", "samples/skills", "WriterSkill");
|
||||
kernel.importSkillFromDirectory("MiscSkill", "samples/skills", "MiscSkill");
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
private static SequentialPlanner initPlanner(Kernel kernel, int maxTokens) {
|
||||
return new SequentialPlanner(kernel, new SequentialPlannerRequestSettings(
|
||||
null,
|
||||
100,
|
||||
Set.of(),
|
||||
Set.of(),
|
||||
Set.of(),
|
||||
maxTokens
|
||||
), null);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -7,9 +7,9 @@ import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.coreskills.ConversationSummarySkill;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -127,7 +127,7 @@ public class Example13_ConversationSummarySkill {
|
||||
""".stripIndent();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
Config.ClientType clientType = Config.ClientType.OPEN_AI;
|
||||
Config.ClientType clientType = Config.ClientType.AZURE_OPEN_AI;
|
||||
|
||||
conversationSummarySkillAsync(clientType);
|
||||
getConversationActionItemsAsync(clientType);
|
||||
@@ -141,7 +141,7 @@ public class Example13_ConversationSummarySkill {
|
||||
ReadOnlyFunctionCollection conversationSummarySkill =
|
||||
kernel.importSkill(new ConversationSummarySkill(kernel), null);
|
||||
|
||||
Mono<CompletionSKContext> summary = conversationSummarySkill
|
||||
Mono<SKContext> summary = conversationSummarySkill
|
||||
.getFunction("SummarizeConversation", SKFunction.class)
|
||||
.invokeAsync(ChatTranscript);
|
||||
|
||||
@@ -157,7 +157,7 @@ public class Example13_ConversationSummarySkill {
|
||||
ReadOnlyFunctionCollection conversationSummarySkill =
|
||||
kernel.importSkill(new ConversationSummarySkill(kernel), null);
|
||||
|
||||
Mono<CompletionSKContext> summary = conversationSummarySkill
|
||||
Mono<SKContext> summary = conversationSummarySkill
|
||||
.getFunction("GetConversationActionItems", SKFunction.class)
|
||||
.invokeAsync(ChatTranscript);
|
||||
|
||||
@@ -171,7 +171,7 @@ public class Example13_ConversationSummarySkill {
|
||||
ReadOnlyFunctionCollection conversationSummarySkill =
|
||||
kernel.importSkill(new ConversationSummarySkill(kernel), null);
|
||||
|
||||
Mono<CompletionSKContext> summary = conversationSummarySkill
|
||||
Mono<SKContext> summary = conversationSummarySkill
|
||||
.getFunction("GetConversationTopics", SKFunction.class)
|
||||
.invokeAsync(ChatTranscript);
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import java.io.IOException;
|
||||
public class Example17_ChatGPT {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
OpenAIAsyncClient client = Config.ClientType.OPEN_AI.getClient();
|
||||
OpenAIAsyncClient client = Config.ClientType.AZURE_OPEN_AI.getClient();
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addChatCompletionService(
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.coreskills.TextSkill;
|
||||
import com.microsoft.semantickernel.planner.actionplanner.ActionPlanner;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Example28_ActionPlanner {
|
||||
public static void main(String[] args) throws IOException {
|
||||
OpenAIAsyncClient client = Config.ClientType.AZURE_OPEN_AI.getClient();
|
||||
|
||||
System.out.println("======== Action Planner ========");
|
||||
|
||||
var kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(SKBuilders
|
||||
.kernelConfig()
|
||||
.addTextCompletionService("text-davinci-002", kernel1 -> SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-002"))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
kernel.importSkillFromDirectory("SummarizeSkill", "./samples/skills", "SummarizeSkill");
|
||||
|
||||
kernel.importSkillFromDirectory("WriterSkill", "./samples/skills", "WriterSkill");
|
||||
|
||||
kernel.importSkill(new TextSkill(), "TextSkill");
|
||||
|
||||
// Create an instance of ActionPlanner.
|
||||
// The ActionPlanner takes one goal and returns a single function to execute.
|
||||
var planner = new ActionPlanner(kernel, null);
|
||||
|
||||
// We're going to ask the planner to find a function to achieve this goal.
|
||||
var goal = "Write a poem about Cleopatra.";
|
||||
|
||||
// The planner returns a plan, consisting of a single function
|
||||
// to execute and achieve the goal requested.
|
||||
var plan = planner.createPlanAsync(goal).block();
|
||||
|
||||
// Show the result, which should match the given goal
|
||||
System.out.println(plan.getName());
|
||||
|
||||
System.out.println(plan.invokeAsync(goal).block().getResult());
|
||||
|
||||
/* Output:
|
||||
*
|
||||
* Cleopatra was a queen
|
||||
* But she didn't act like one
|
||||
* She was more like a teen
|
||||
|
||||
* She was always on the scene
|
||||
* And she loved to be seen
|
||||
* But she didn't have a queenly bone in her body
|
||||
*/
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class RunAll {
|
||||
public interface MainMethod {
|
||||
void run(String[] args) throws Exception;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<MainMethod> mains = Arrays.asList(
|
||||
Example01_NativeFunctions::main,
|
||||
Example02_Pipeline::main,
|
||||
Example06_TemplateLanguage::main,
|
||||
Example08_RetryHandler::main,
|
||||
Example12_SequentialPlanner::main,
|
||||
Example13_ConversationSummarySkill::main,
|
||||
Example14_SemanticMemory::main,
|
||||
Example17_ChatGPT::main,
|
||||
Example28_ActionPlanner::main
|
||||
);
|
||||
|
||||
mains.forEach(mainMethod -> {
|
||||
try {
|
||||
mainMethod.run(args);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="info">
|
||||
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{HH:mm:ss} %-5level %c{1.} - %msg%n"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="reactor.netty" level="warn">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Logger>
|
||||
<Logger name="io.netty" level="warn">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Logger>
|
||||
<Root level="debug">
|
||||
<AppenderRef ref="Console"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
-2
@@ -98,8 +98,6 @@ public class SemanticKernelModule extends AbstractModule {
|
||||
if (embeddingsGenerationServiceId != null) {
|
||||
OpenAITextEmbeddingGeneration embeddings = new OpenAITextEmbeddingGeneration(client,
|
||||
embeddingsGenerationServiceId);
|
||||
kernelConfig.addTextEmbeddingsGenerationService(
|
||||
embeddingsGenerationServiceId, kernel -> embeddings);
|
||||
bind(new TypeLiteral<EmbeddingGeneration<String, Float>>() {
|
||||
}).toInstance(embeddings);
|
||||
}
|
||||
|
||||
+3
-3
@@ -4,8 +4,8 @@ package com.microsoft.semantickernel.guice;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -61,13 +61,13 @@ public class CompletionFunctionExample {
|
||||
+ "poetry—'bearing a pleasant gift', for example, alludes to the use of that\n"
|
||||
+ "phrase throughout the Iliad and Odyssey.[a][2];";
|
||||
|
||||
CompletionSKContext summary =
|
||||
SKContext summary =
|
||||
completionFunctionFactory
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()))
|
||||
0.2, 0.5, 0, 0, 2000))
|
||||
.invokeAsync(text)
|
||||
.block();
|
||||
|
||||
|
||||
@@ -2,26 +2,20 @@
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.builders.BuildersSingleton;
|
||||
import com.microsoft.semantickernel.exceptions.SkillsNotFoundException;
|
||||
import com.microsoft.semantickernel.memory.MemoryStore;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.orchestration.ContextVariables;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Interface for the semantic kernel. */
|
||||
public interface Kernel {
|
||||
public interface Kernel extends SkillExecutor {
|
||||
|
||||
/**
|
||||
* Settings required to execute functions, including details about AI dependencies, e.g.
|
||||
@@ -49,7 +43,7 @@ public interface Kernel {
|
||||
* @param pipeline List of functions
|
||||
* @return Result of the function composition
|
||||
*/
|
||||
Mono<SKContext<?>> runAsync(SKFunction<?, ?>... pipeline);
|
||||
Mono<SKContext> runAsync(SKFunction<?>... pipeline);
|
||||
|
||||
/**
|
||||
* Run a pipeline composed of synchronous and asynchronous functions.
|
||||
@@ -58,7 +52,7 @@ public interface Kernel {
|
||||
* @param pipeline List of functions
|
||||
* @return Result of the function composition
|
||||
*/
|
||||
Mono<SKContext<?>> runAsync(String input, SKFunction<?, ?>... pipeline);
|
||||
Mono<SKContext> runAsync(String input, SKFunction<?>... pipeline);
|
||||
|
||||
/**
|
||||
* Run a pipeline composed of synchronous and asynchronous functions.
|
||||
@@ -67,42 +61,7 @@ public interface Kernel {
|
||||
* @param pipeline List of functions
|
||||
* @return Result of the function composition
|
||||
*/
|
||||
Mono<SKContext<?>> runAsync(ContextVariables variables, SKFunction<?, ?>... pipeline);
|
||||
|
||||
/**
|
||||
* Import a set of skills
|
||||
*
|
||||
* @param skillName
|
||||
* @param skills
|
||||
* @return
|
||||
* @throws SkillsNotFoundException
|
||||
*/
|
||||
ReadOnlyFunctionCollection importSkill(
|
||||
String skillName, Map<String, SemanticFunctionConfig> skills)
|
||||
throws SkillsNotFoundException;
|
||||
|
||||
/**
|
||||
* Get function collection with the skill name
|
||||
*
|
||||
* @param skillName
|
||||
* @return
|
||||
* @throws SkillsNotFoundException
|
||||
*/
|
||||
ReadOnlyFunctionCollection getSkill(String skillName) throws SkillsNotFoundException;
|
||||
|
||||
/**
|
||||
* Imports the native functions annotated on the given object as a skill.
|
||||
*
|
||||
* @param nativeSkill
|
||||
* @param skillName
|
||||
* @return
|
||||
*/
|
||||
ReadOnlyFunctionCollection importSkill(Object nativeSkill, @Nullable String skillName);
|
||||
|
||||
/**
|
||||
* @return Reference to the read-only skill collection containing all the imported functions
|
||||
*/
|
||||
ReadOnlySkillCollection getSkills();
|
||||
Mono<SKContext> runAsync(ContextVariables variables, SKFunction<?>... pipeline);
|
||||
|
||||
CompletionSKFunction.Builder getSemanticFunctionBuilder();
|
||||
|
||||
@@ -110,12 +69,11 @@ public interface Kernel {
|
||||
<T> T getService(@Nullable String name, Class<T> clazz) throws KernelException;
|
||||
|
||||
/** Registers a semantic functon on this kernel */
|
||||
<
|
||||
RequestConfiguration,
|
||||
ContextType extends SKContext<ContextType>,
|
||||
FunctionType extends SKFunction<RequestConfiguration, ContextType>>
|
||||
<RequestConfiguration, FunctionType extends SKFunction<RequestConfiguration>>
|
||||
FunctionType registerSemanticFunction(FunctionType semanticFunctionDefinition);
|
||||
|
||||
SKFunction getFunction(String skill, String function);
|
||||
|
||||
// <T extends ReadOnlySKContext<T>> T createNewContext();
|
||||
|
||||
class Builder {
|
||||
|
||||
+13
-28
@@ -3,17 +3,13 @@ package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.chatcompletion.ChatCompletion;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class KernelConfig {
|
||||
|
||||
private static final String DEFAULT_SERVICE_ID = "__SK_DEFAULT";
|
||||
@@ -22,19 +18,16 @@ public final class KernelConfig {
|
||||
|
||||
private final Map<String, Function<Kernel, EmbeddingGeneration<String, Float>>>
|
||||
textEmbeddingGenerationServices;
|
||||
private final ArrayList<SKFunction<?, ?>> skills;
|
||||
|
||||
public KernelConfig(
|
||||
Map<String, Function<Kernel, TextCompletion>> textCompletionServices,
|
||||
Map<String, Function<Kernel, EmbeddingGeneration<String, Float>>>
|
||||
textEmbeddingGenerationServices,
|
||||
Map<String, Function<Kernel, ChatCompletion>> chatCompletionServices,
|
||||
List<SKFunction<?, ?>> skills) {
|
||||
Map<String, Function<Kernel, ChatCompletion>> chatCompletionServices) {
|
||||
this.textCompletionServices = new HashMap<>();
|
||||
this.textCompletionServices.putAll(textCompletionServices);
|
||||
this.textEmbeddingGenerationServices = new HashMap<>(textEmbeddingGenerationServices);
|
||||
this.chatCompletionServices = new HashMap<>(chatCompletionServices);
|
||||
this.skills = new ArrayList<>(skills);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -42,10 +35,6 @@ public final class KernelConfig {
|
||||
return textCompletionServices.get(serviceId);
|
||||
}
|
||||
|
||||
public List<SKFunction<?, ?>> getSkills() {
|
||||
return Collections.unmodifiableList(skills);
|
||||
}
|
||||
|
||||
public Function<Kernel, TextCompletion> getTextCompletionServiceOrDefault(
|
||||
@Nullable String serviceId) {
|
||||
if (serviceId == null) {
|
||||
@@ -55,7 +44,10 @@ public final class KernelConfig {
|
||||
if (!this.textCompletionServices.containsKey(serviceId)) {
|
||||
throw new KernelException(
|
||||
KernelException.ErrorCodes.ServiceNotFound,
|
||||
"A text completion service id '" + serviceId + "' doesn't exist");
|
||||
"A text completion service id '"
|
||||
+ serviceId
|
||||
+ "' doesn't exist. This likely means a text completion service was not"
|
||||
+ " registered on this kernel.");
|
||||
}
|
||||
|
||||
return this.textCompletionServices.get(serviceId);
|
||||
@@ -76,8 +68,8 @@ public final class KernelConfig {
|
||||
return this.chatCompletionServices.get(serviceId);
|
||||
}
|
||||
|
||||
public Function<Kernel, EmbeddingGeneration<String,Float>> getTextEmbeddingGenerationServiceOrDefault(
|
||||
@Nullable String serviceId) {
|
||||
public Function<Kernel, EmbeddingGeneration<String, Float>>
|
||||
getTextEmbeddingGenerationServiceOrDefault(@Nullable String serviceId) {
|
||||
|
||||
if (serviceId == null) {
|
||||
serviceId = DEFAULT_SERVICE_ID;
|
||||
@@ -96,18 +88,11 @@ public final class KernelConfig {
|
||||
private Map<String, Function<Kernel, TextCompletion>> textCompletionServices =
|
||||
new HashMap<>();
|
||||
|
||||
private List<SKFunction<?, ?>> skillBuilders = new ArrayList<>();
|
||||
|
||||
private Map<String, Function<Kernel, EmbeddingGeneration<String, Float>>>
|
||||
textEmbeddingGenerationServices = new HashMap<>();
|
||||
private final Map<String, Function<Kernel, ChatCompletion>> chatCompletionServices =
|
||||
new HashMap<>();
|
||||
|
||||
public Builder addSkill(SKFunction<?, ?> functionDefinition) {
|
||||
skillBuilders.add(functionDefinition);
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO, is there a need for this to be a factory?
|
||||
public Builder addTextCompletionService(
|
||||
String serviceId, Function<Kernel, TextCompletion> serviceFactory) {
|
||||
@@ -160,7 +145,8 @@ public final class KernelConfig {
|
||||
*/
|
||||
public Builder addChatCompletionService(
|
||||
@Nullable String serviceId, Function<Kernel, ChatCompletion> serviceFactory) {
|
||||
if (serviceId != null && serviceId.toUpperCase().equals(DEFAULT_SERVICE_ID)) {
|
||||
if (serviceId != null
|
||||
&& serviceId.toUpperCase(Locale.ROOT).equals(DEFAULT_SERVICE_ID)) {
|
||||
String msg =
|
||||
"The service id '"
|
||||
+ serviceId
|
||||
@@ -185,8 +171,7 @@ public final class KernelConfig {
|
||||
return new KernelConfig(
|
||||
Collections.unmodifiableMap(textCompletionServices),
|
||||
textEmbeddingGenerationServices,
|
||||
chatCompletionServices,
|
||||
skillBuilders);
|
||||
chatCompletionServices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.exceptions.SkillsNotFoundException;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface SkillExecutor {
|
||||
|
||||
/**
|
||||
* Import a set of skills
|
||||
*
|
||||
* @param skillName
|
||||
* @param skills
|
||||
* @return
|
||||
* @throws SkillsNotFoundException
|
||||
*/
|
||||
ReadOnlyFunctionCollection importSkill(
|
||||
String skillName, Map<String, SemanticFunctionConfig> skills)
|
||||
throws SkillsNotFoundException;
|
||||
|
||||
/**
|
||||
* Get function collection with the skill name
|
||||
*
|
||||
* @param skillName
|
||||
* @return
|
||||
* @throws SkillsNotFoundException
|
||||
*/
|
||||
ReadOnlyFunctionCollection getSkill(String skillName) throws SkillsNotFoundException;
|
||||
|
||||
/**
|
||||
* Imports the native functions annotated on the given object as a skill.
|
||||
*
|
||||
* @param skillName
|
||||
* @return
|
||||
*/
|
||||
ReadOnlyFunctionCollection importSkillFromDirectory(
|
||||
String skillName, String parentDirectory, String skillDirectoryName);
|
||||
|
||||
/** Imports the native functions annotated on the given object as a skill. */
|
||||
void importSkillsFromDirectory(String parentDirectory, String... skillNames);
|
||||
|
||||
/**
|
||||
* Imports the native functions annotated on the given object as a skill. Assumes that the
|
||||
* directory that contains the skill is the same as skillName
|
||||
*
|
||||
* @param skillName
|
||||
* @return
|
||||
*/
|
||||
ReadOnlyFunctionCollection importSkillFromDirectory(String skillName, String parentDirectory);
|
||||
|
||||
/**
|
||||
* Imports the native functions annotated on the given object as a skill.
|
||||
*
|
||||
* @param nativeSkill
|
||||
* @param skillName
|
||||
* @return
|
||||
*/
|
||||
ReadOnlyFunctionCollection importSkill(Object nativeSkill, @Nullable String skillName);
|
||||
|
||||
/**
|
||||
* @return Reference to the read-only skill collection containing all the imported functions
|
||||
*/
|
||||
ReadOnlySkillCollection getSkills();
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class Verify {
|
||||
public static void notNull(Object object) {
|
||||
assert object != null;
|
||||
}
|
||||
|
||||
public static boolean isNullOrEmpty(@Nullable String s) {
|
||||
return s == null || s.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
+24
-4
@@ -11,14 +11,32 @@ public class AIException extends SKException {
|
||||
|
||||
@Nonnull private final ErrorCodes errorCode;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@link AIException} class.
|
||||
*
|
||||
* @param error The error code.
|
||||
*/
|
||||
public AIException(@Nonnull ErrorCodes error) {
|
||||
this(error, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@link AIException} class.
|
||||
*
|
||||
* @param errorCode The error code.
|
||||
* @param message The message.
|
||||
*/
|
||||
public AIException(@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
this(errorCode, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the {@link AIException} class.
|
||||
*
|
||||
* @param errorCode The error code.
|
||||
* @param message The message.
|
||||
* @param innerException The cause of the exception.
|
||||
*/
|
||||
public AIException(
|
||||
@Nonnull ErrorCodes errorCode,
|
||||
@Nullable String message,
|
||||
@@ -27,19 +45,21 @@ public class AIException extends SKException {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error code.
|
||||
*
|
||||
* @return The error code.
|
||||
*/
|
||||
public ErrorCodes getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/* Translate the error code into a default message */
|
||||
/** Translate the error code into a default message */
|
||||
private static String getDefaultMessage(
|
||||
@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
return String.format("%s: %s", errorCode.getMessage(), message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Possible error codes for exceptions
|
||||
/// </summary>
|
||||
public enum ErrorCodes {
|
||||
UnknownError("Unknown error"),
|
||||
|
||||
|
||||
+2
-9
@@ -19,14 +19,6 @@ public class Embedding<EmbeddingType extends Number> {
|
||||
|
||||
private final List<EmbeddingType> vector;
|
||||
|
||||
// /// <summary>
|
||||
// /// An empty <see cref="Embedding{TEmbedding}"/> instance.
|
||||
// /// </summary>
|
||||
// [SuppressMessage("Design", "CA1000:Do not declare static members on generic types",
|
||||
// Justification = "Static empty struct instance.")]
|
||||
// public static Embedding<TEmbedding> Empty { get; } = new
|
||||
// Embedding<TEmbedding>(Array.Empty<TEmbedding>());
|
||||
|
||||
private static final Embedding<Number> EMPTY =
|
||||
new Embedding(Collections.unmodifiableList(new ArrayList<>()));
|
||||
|
||||
@@ -43,6 +35,7 @@ public class Embedding<EmbeddingType extends Number> {
|
||||
// /// <exception cref="ArgumentException">Type <typeparamref name="TEmbedding"/> is
|
||||
// unsupported.</exception>
|
||||
// /// <exception cref="ArgumentNullException">A <c>null</c> vector is passed in.</exception>
|
||||
|
||||
public Embedding() {
|
||||
this.vector = Collections.emptyList();
|
||||
}
|
||||
@@ -62,7 +55,7 @@ public class Embedding<EmbeddingType extends Number> {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!(o instanceof Embedding)) return false;
|
||||
|
||||
Embedding<?> embedding = (Embedding<?>) o;
|
||||
|
||||
|
||||
+45
-80
@@ -16,7 +16,12 @@ import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/** Enum singleton that service loads builder implementations */
|
||||
@SuppressWarnings("ImmutableEnumChecker")
|
||||
public enum BuildersSingleton {
|
||||
INST;
|
||||
|
||||
@@ -27,94 +32,46 @@ public enum BuildersSingleton {
|
||||
"com.microsoft.semantickernel.DefaultKernel$Builder";
|
||||
private static final String FALLBACK_TEXT_COMPLETION_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion$Builder";
|
||||
|
||||
private static final String FALLBACK_TEXT_EMBEDDING_GENERATION_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.connectors.ai.openai.textembeddings.OpenAITextEmbeddingGeneration$Builder";
|
||||
private static final String FALLBACK_SKILL_COLLECTION_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.skilldefinition.DefaultCollection$Builder";
|
||||
|
||||
"com.microsoft.semantickernel.skilldefinition.DefaultSkillCollection$Builder";
|
||||
private static final String FALLBACK_PROMPT_TEMPLATE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.semanticfunctions.DefaultPromptTemplate$Builder";
|
||||
|
||||
private static final String FALLBACK_VARIABLE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.orchestration.DefaultContextVariables$Builder";
|
||||
|
||||
private static final String FALLBACK_CONTEXT_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.orchestration.DefaultSemanticSKContext$Builder";
|
||||
"com.microsoft.semantickernel.orchestration.DefaultSKContext$Builder";
|
||||
private static final String FALLBACK_PROMPT_TEMPLATE_ENGINE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.templateengine.DefaultPromptTemplateEngine$Builder";
|
||||
private static final String FALLBACK_SEMANTIC_TEXT_MEMORY_CLASS =
|
||||
"com.microsoft.semantickernel.memory.DefaultSemanticTextMemory$Builder";
|
||||
private static final String FALLBACK_CHAT_COMPLETION_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.connectors.ai.openai.chatcompletion.OpenAIChatCompletion$Builder";
|
||||
|
||||
private static final String FALLBACK_MEMORY_STORE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.memory.VolatileMemoryStore$Builder";
|
||||
|
||||
private final FunctionBuilders functionBuilders;
|
||||
private final Kernel.InternalBuilder kernelBuilder;
|
||||
private final TextCompletion.Builder textCompletionBuilder;
|
||||
private final EmbeddingGeneration.Builder<String, Float> textEmbeddingGenerationBuilder;
|
||||
private final ReadOnlySkillCollection.Builder readOnlySkillCollection;
|
||||
private final PromptTemplate.Builder promptTemplate;
|
||||
private final ContextVariables.Builder variables;
|
||||
private final SKContext.Builder context;
|
||||
private final PromptTemplateEngine.Builder promptTemplateEngine;
|
||||
private final ChatCompletion.Builder chatCompletion;
|
||||
private final SemanticTextMemory.Builder semanticTextMemoryBuilder;
|
||||
private final MemoryStore.Builder memoryStoreBuilder;
|
||||
private final Map<Class, Supplier> builders = new HashMap<>();
|
||||
|
||||
BuildersSingleton() {
|
||||
try {
|
||||
functionBuilders =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
FunctionBuilders.class, FALLBACK_FUNCTION_BUILDER_CLASS);
|
||||
|
||||
kernelBuilder =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
Kernel.InternalBuilder.class, FALLBACK_KERNEL_BUILDER_CLASS);
|
||||
|
||||
textCompletionBuilder =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
TextCompletion.Builder.class, FALLBACK_TEXT_COMPLETION_BUILDER_CLASS);
|
||||
|
||||
textEmbeddingGenerationBuilder =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
EmbeddingGeneration.Builder.class,
|
||||
FALLBACK_TEXT_EMBEDDING_GENERATION_BUILDER_CLASS);
|
||||
|
||||
readOnlySkillCollection =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
ReadOnlySkillCollection.Builder.class,
|
||||
FALLBACK_SKILL_COLLECTION_BUILDER_CLASS);
|
||||
|
||||
promptTemplate =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
PromptTemplate.Builder.class, FALLBACK_PROMPT_TEMPLATE_BUILDER_CLASS);
|
||||
|
||||
variables =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
ContextVariables.Builder.class, FALLBACK_VARIABLE_BUILDER_CLASS);
|
||||
semanticTextMemoryBuilder =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
SemanticTextMemory.Builder.class, FALLBACK_SEMANTIC_TEXT_MEMORY_CLASS);
|
||||
|
||||
context =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
SKContext.Builder.class, FALLBACK_CONTEXT_BUILDER_CLASS);
|
||||
|
||||
promptTemplateEngine =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
PromptTemplateEngine.Builder.class,
|
||||
FALLBACK_PROMPT_TEMPLATE_ENGINE_BUILDER_CLASS);
|
||||
|
||||
chatCompletion =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
ChatCompletion.Builder.class, FALLBACK_CHAT_COMPLETION_BUILDER_CLASS);
|
||||
|
||||
memoryStoreBuilder =
|
||||
ServiceLoadUtil.findServiceLoader(
|
||||
MemoryStore.Builder.class, FALLBACK_MEMORY_STORE_BUILDER_CLASS);
|
||||
registerBuilder(FunctionBuilders.class, FALLBACK_FUNCTION_BUILDER_CLASS);
|
||||
registerBuilder(Kernel.InternalBuilder.class, FALLBACK_KERNEL_BUILDER_CLASS);
|
||||
registerBuilder(TextCompletion.Builder.class, FALLBACK_TEXT_COMPLETION_BUILDER_CLASS);
|
||||
registerBuilder(
|
||||
EmbeddingGeneration.Builder.class,
|
||||
FALLBACK_TEXT_EMBEDDING_GENERATION_BUILDER_CLASS);
|
||||
registerBuilder(
|
||||
ReadOnlySkillCollection.Builder.class, FALLBACK_SKILL_COLLECTION_BUILDER_CLASS);
|
||||
registerBuilder(PromptTemplate.Builder.class, FALLBACK_PROMPT_TEMPLATE_BUILDER_CLASS);
|
||||
registerBuilder(ContextVariables.Builder.class, FALLBACK_VARIABLE_BUILDER_CLASS);
|
||||
registerBuilder(SemanticTextMemory.Builder.class, FALLBACK_SEMANTIC_TEXT_MEMORY_CLASS);
|
||||
registerBuilder(SKContext.Builder.class, FALLBACK_CONTEXT_BUILDER_CLASS);
|
||||
registerBuilder(
|
||||
PromptTemplateEngine.Builder.class,
|
||||
FALLBACK_PROMPT_TEMPLATE_ENGINE_BUILDER_CLASS);
|
||||
registerBuilder(ChatCompletion.Builder.class, FALLBACK_CHAT_COMPLETION_BUILDER_CLASS);
|
||||
registerBuilder(MemoryStore.Builder.class, FALLBACK_MEMORY_STORE_BUILDER_CLASS);
|
||||
|
||||
} catch (Throwable e) {
|
||||
Logger LOGGER = LoggerFactory.getLogger(BuildersSingleton.class);
|
||||
@@ -141,51 +98,59 @@ public enum BuildersSingleton {
|
||||
}
|
||||
}
|
||||
|
||||
private void registerBuilder(Class<?> clazz, String fallbackClassName) {
|
||||
builders.put(clazz, ServiceLoadUtil.findServiceLoader(clazz, fallbackClassName));
|
||||
}
|
||||
|
||||
private <T> T getInstance(Class<T> clazz) {
|
||||
return (T) builders.get(clazz).get();
|
||||
}
|
||||
|
||||
public FunctionBuilders getFunctionBuilders() {
|
||||
return functionBuilders;
|
||||
return getInstance(FunctionBuilders.class);
|
||||
}
|
||||
|
||||
public Kernel.InternalBuilder getKernelBuilder() {
|
||||
return kernelBuilder;
|
||||
return getInstance(Kernel.InternalBuilder.class);
|
||||
}
|
||||
|
||||
public TextCompletion.Builder getTextCompletionBuilder() {
|
||||
return textCompletionBuilder;
|
||||
return getInstance(TextCompletion.Builder.class);
|
||||
}
|
||||
|
||||
public EmbeddingGeneration.Builder<String, Float> getTextEmbeddingGenerationBuilder() {
|
||||
return textEmbeddingGenerationBuilder;
|
||||
return getInstance(EmbeddingGeneration.Builder.class);
|
||||
}
|
||||
|
||||
public ReadOnlySkillCollection.Builder getReadOnlySkillCollection() {
|
||||
return readOnlySkillCollection;
|
||||
return getInstance(ReadOnlySkillCollection.Builder.class);
|
||||
}
|
||||
|
||||
public PromptTemplate.Builder getPromptTemplateBuilder() {
|
||||
return promptTemplate;
|
||||
return getInstance(PromptTemplate.Builder.class);
|
||||
}
|
||||
|
||||
public PromptTemplateEngine.Builder getPromptTemplateEngineBuilder() {
|
||||
return promptTemplateEngine;
|
||||
return getInstance(PromptTemplateEngine.Builder.class);
|
||||
}
|
||||
|
||||
public ContextVariables.Builder variables() {
|
||||
return variables;
|
||||
return getInstance(ContextVariables.Builder.class);
|
||||
}
|
||||
|
||||
public SKContext.Builder context() {
|
||||
return context;
|
||||
return getInstance(SKContext.Builder.class);
|
||||
}
|
||||
|
||||
public SemanticTextMemory.Builder getSemanticTextMemoryBuilder() {
|
||||
return semanticTextMemoryBuilder;
|
||||
return getInstance(SemanticTextMemory.Builder.class);
|
||||
}
|
||||
|
||||
public ChatCompletion.Builder getChatCompletion() {
|
||||
return chatCompletion;
|
||||
return getInstance(ChatCompletion.Builder.class);
|
||||
}
|
||||
|
||||
public MemoryStore.Builder getMemoryStoreBuilder() {
|
||||
return memoryStoreBuilder;
|
||||
return getInstance(MemoryStore.Builder.class);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-8
@@ -4,18 +4,12 @@ package com.microsoft.semantickernel.builders;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Provides various builders for completion functions */
|
||||
public interface FunctionBuilders {
|
||||
|
||||
static CompletionSKFunction.Builder getCompletionBuilder() {
|
||||
return getCompletionBuilder(null);
|
||||
}
|
||||
|
||||
static CompletionSKFunction.Builder getCompletionBuilder(@Nullable Kernel kernel) {
|
||||
static CompletionSKFunction.Builder getCompletionBuilder(Kernel kernel) {
|
||||
return BuildersSingleton.INST.getFunctionBuilders().completionBuilders(kernel);
|
||||
}
|
||||
|
||||
CompletionSKFunction.Builder completionBuilders(@Nullable Kernel kernel);
|
||||
CompletionSKFunction.Builder completionBuilders(Kernel kernel);
|
||||
}
|
||||
|
||||
+2
-7
@@ -16,23 +16,18 @@ import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SKBuilders {
|
||||
// Prevent creating object
|
||||
private SKBuilders() {}
|
||||
|
||||
public static CompletionSKFunction.Builder completionFunctions() {
|
||||
return completionFunctions(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A CompletionSKFunction builder, the created function will be registered on the kernel
|
||||
* provided
|
||||
*
|
||||
* @param kernel The kernel to register the function on
|
||||
* @return a function builder
|
||||
*/
|
||||
public static CompletionSKFunction.Builder completionFunctions(@Nullable Kernel kernel) {
|
||||
public static CompletionSKFunction.Builder completionFunctions(Kernel kernel) {
|
||||
return FunctionBuilders.getCompletionBuilder(kernel);
|
||||
}
|
||||
|
||||
|
||||
+36
-4
@@ -4,21 +4,26 @@ package com.microsoft.semantickernel.builders;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ServiceLoadUtil {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceLoadUtil.class);
|
||||
|
||||
private ServiceLoadUtil() {}
|
||||
|
||||
public static <T> T findServiceLoader(Class<T> clazz, String alternativeClassName) {
|
||||
public static <T> Supplier<T> findServiceLoader(Class<T> clazz, String alternativeClassName) {
|
||||
List<T> services = findAllServiceLoaders(clazz);
|
||||
|
||||
T impl = null;
|
||||
|
||||
if (services.size() > 0) {
|
||||
return services.get(0);
|
||||
impl = services.get(0);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -26,7 +31,7 @@ public class ServiceLoadUtil {
|
||||
Object instance =
|
||||
Class.forName(alternativeClassName).getDeclaredConstructor().newInstance();
|
||||
if (clazz.isInstance(instance)) {
|
||||
return (T) instance;
|
||||
impl = (T) instance;
|
||||
}
|
||||
} catch (ClassNotFoundException
|
||||
| InvocationTargetException
|
||||
@@ -37,7 +42,34 @@ public class ServiceLoadUtil {
|
||||
LOGGER.error("Unable to load service " + clazz.getName() + " ", e);
|
||||
}
|
||||
|
||||
throw new RuntimeException("Service not found: " + clazz.getName());
|
||||
if (impl == null) {
|
||||
throw new RuntimeException("Service not found: " + clazz.getName());
|
||||
}
|
||||
|
||||
try {
|
||||
Constructor<?> constructor = impl.getClass().getConstructor();
|
||||
|
||||
// Test that we can construct the builder
|
||||
if (!clazz.isInstance(constructor.newInstance())) {
|
||||
throw new RuntimeException(
|
||||
"Builder creates instance of the wrong type: " + clazz.getName());
|
||||
}
|
||||
|
||||
return () -> {
|
||||
try {
|
||||
return (T) constructor.newInstance();
|
||||
} catch (InstantiationException
|
||||
| IllegalAccessException
|
||||
| InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(
|
||||
"Builder requires a no args constructor: " + clazz.getName());
|
||||
} catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
|
||||
throw new RuntimeException("Builder is of wrong type: " + clazz.getName());
|
||||
}
|
||||
}
|
||||
|
||||
static <T> List<T> findAllServiceLoaders(Class<T> clazz) {
|
||||
|
||||
+18
-11
@@ -2,10 +2,12 @@
|
||||
package com.microsoft.semantickernel.extensions;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.microsoft.semantickernel.KernelException;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -14,7 +16,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -24,7 +25,9 @@ public class KernelExtensions {
|
||||
private KernelExtensions() {}
|
||||
|
||||
public static Map<String, SemanticFunctionConfig> importSemanticSkillFromDirectory(
|
||||
String parentDirectory, String skillDirectoryName) {
|
||||
String parentDirectory,
|
||||
String skillDirectoryName,
|
||||
PromptTemplateEngine promptTemplateEngine) {
|
||||
|
||||
String CONFIG_FILE = "config.json";
|
||||
String PROMPT_FILE = "skprompt.txt";
|
||||
@@ -35,7 +38,9 @@ public class KernelExtensions {
|
||||
|
||||
File[] files = skillDir.listFiles();
|
||||
if (files == null) {
|
||||
return Collections.unmodifiableMap(new HashMap<>());
|
||||
throw new KernelException(
|
||||
KernelException.ErrorCodes.FunctionNotAvailable,
|
||||
"No Skills found in directory " + skillDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
HashMap<String, SemanticFunctionConfig> skills = new HashMap<>();
|
||||
@@ -64,15 +69,17 @@ public class KernelExtensions {
|
||||
// config.ToJson());
|
||||
|
||||
// Load prompt template
|
||||
PromptTemplate template =
|
||||
SKBuilders.promptTemplate()
|
||||
.build(
|
||||
new String(
|
||||
Files.readAllBytes(promptPath.toPath()),
|
||||
Charset.defaultCharset()),
|
||||
config);
|
||||
String template =
|
||||
new String(
|
||||
Files.readAllBytes(promptPath.toPath()), Charset.defaultCharset());
|
||||
|
||||
skills.put(dir.getName(), new SemanticFunctionConfig(config, template));
|
||||
PromptTemplate promptTemplate =
|
||||
SKBuilders.promptTemplate()
|
||||
.withPromptTemplate(template)
|
||||
.withPromptTemplateConfig(config)
|
||||
.build(promptTemplateEngine);
|
||||
|
||||
skills.put(dir.getName(), new SemanticFunctionConfig(config, promptTemplate));
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to read file", e);
|
||||
}
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ public class MemoryRecord extends DataEntryBase {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!(o instanceof MemoryRecord)) return false;
|
||||
|
||||
MemoryRecord that = (MemoryRecord) o;
|
||||
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ public class MemoryRecordMetadata {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!(o instanceof MemoryRecordMetadata)) return false;
|
||||
|
||||
MemoryRecordMetadata that = (MemoryRecordMetadata) o;
|
||||
|
||||
|
||||
+13
-15
@@ -8,7 +8,6 @@ import reactor.core.publisher.Mono;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** An interface for semantic memory that creates and recalls memories associated with text. */
|
||||
@@ -28,9 +27,9 @@ public interface SemanticTextMemory {
|
||||
* @return Unique identifier of the saved memory record.
|
||||
*/
|
||||
public Mono<String> saveInformationAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String text,
|
||||
@Nonnull String externalId,
|
||||
String collection,
|
||||
String text,
|
||||
String externalId,
|
||||
@Nullable String description,
|
||||
@Nullable String additionalMetadata);
|
||||
|
||||
@@ -48,10 +47,10 @@ public interface SemanticTextMemory {
|
||||
* @return Unique identifier of the saved memory record.
|
||||
*/
|
||||
public Mono<String> saveReferenceAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String text,
|
||||
@Nonnull String externalId,
|
||||
@Nonnull String externalSourceName,
|
||||
String collection,
|
||||
String text,
|
||||
String externalId,
|
||||
String externalSourceName,
|
||||
@Nullable String description,
|
||||
@Nullable String additionalMetadata);
|
||||
|
||||
@@ -64,8 +63,7 @@ public interface SemanticTextMemory {
|
||||
* @param withEmbedding Whether to return the embedding of the memory found.
|
||||
* @return Memory record, or null when nothing is found
|
||||
*/
|
||||
public Mono<MemoryQueryResult> getAsync(
|
||||
@Nonnull String collection, @Nonnull String key, boolean withEmbedding);
|
||||
public Mono<MemoryQueryResult> getAsync(String collection, String key, boolean withEmbedding);
|
||||
|
||||
/**
|
||||
* Remove a memory by key. For local memories the key is the "id" used when saving the record.
|
||||
@@ -75,7 +73,7 @@ public interface SemanticTextMemory {
|
||||
* @param key Unique memory record identifier.
|
||||
* @return Mono completion.
|
||||
*/
|
||||
public Mono<Void> removeAsync(@Nonnull String collection, @Nonnull String key);
|
||||
public Mono<Void> removeAsync(String collection, String key);
|
||||
|
||||
/**
|
||||
* Find some information in memory
|
||||
@@ -88,8 +86,8 @@ public interface SemanticTextMemory {
|
||||
* @return Memories found
|
||||
*/
|
||||
public Mono<List<MemoryQueryResult>> searchAsync(
|
||||
@Nonnull String collection,
|
||||
@Nonnull String query,
|
||||
String collection,
|
||||
String query,
|
||||
int limit,
|
||||
double minRelevanceScore,
|
||||
boolean withEmbeddings);
|
||||
@@ -102,10 +100,10 @@ public interface SemanticTextMemory {
|
||||
public Mono<List<String>> getCollectionsAsync();
|
||||
|
||||
interface Builder {
|
||||
Builder setStorage(@Nonnull MemoryStore storage);
|
||||
Builder setStorage(MemoryStore storage);
|
||||
|
||||
Builder setEmbeddingGenerator(
|
||||
@Nonnull EmbeddingGeneration<String, ? extends Number> embeddingGenerator);
|
||||
EmbeddingGeneration<String, ? extends Number> embeddingGenerator);
|
||||
|
||||
SemanticTextMemory build();
|
||||
}
|
||||
|
||||
+14
-11
@@ -15,8 +15,8 @@ import javax.annotation.CheckReturnValue;
|
||||
/// <summary>
|
||||
/// Semantic Kernel context.
|
||||
/// </summary>memory
|
||||
public abstract class AbstractSKContext<T extends SKContext<T>> implements SKContext<T> {
|
||||
@Nullable private final ReadOnlySkillCollection skills;
|
||||
public abstract class AbstractSKContext implements SKContext {
|
||||
private final ReadOnlySkillCollection skills;
|
||||
private final WritableContextVariables variables;
|
||||
@Nullable private final SemanticTextMemory memory;
|
||||
|
||||
@@ -59,15 +59,19 @@ public abstract class AbstractSKContext<T extends SKContext<T>> implements SKCon
|
||||
this.memory = null;
|
||||
}
|
||||
|
||||
this.skills = skills;
|
||||
if (skills == null) {
|
||||
this.skills = SKBuilders.skillCollection().build();
|
||||
} else {
|
||||
this.skills = skills;
|
||||
}
|
||||
}
|
||||
|
||||
@CheckReturnValue
|
||||
@Override
|
||||
public T copy() {
|
||||
public SKContext copy() {
|
||||
ReadOnlySkillCollection clonedSkill;
|
||||
if (skills == null) {
|
||||
clonedSkill = skills;
|
||||
clonedSkill = null;
|
||||
} else {
|
||||
clonedSkill = skills.copy();
|
||||
}
|
||||
@@ -80,20 +84,19 @@ public abstract class AbstractSKContext<T extends SKContext<T>> implements SKCon
|
||||
return memory != null ? memory.copy() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ReadOnlySkillCollection getSkills() {
|
||||
return skills;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T setVariable(@NonNull String key, @NonNull String content) {
|
||||
public SKContext setVariable(@NonNull String key, @NonNull String content) {
|
||||
variables.setVariable(key, content);
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T appendToVariable(@NonNull String key, @NonNull String content) {
|
||||
public SKContext appendToVariable(@NonNull String key, @NonNull String content) {
|
||||
variables.appendToVariable(key, content);
|
||||
return getThis();
|
||||
}
|
||||
@@ -106,16 +109,16 @@ public abstract class AbstractSKContext<T extends SKContext<T>> implements SKCon
|
||||
/// if the pipeline reached the end.</param>
|
||||
/// <returns>The current instance</returns>
|
||||
@Override
|
||||
public T update(@NonNull String content) {
|
||||
public SKContext update(@NonNull String content) {
|
||||
variables.update(content);
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T update(@NonNull ContextVariables newData) {
|
||||
public SKContext update(@NonNull ContextVariables newData) {
|
||||
variables.update(newData, true);
|
||||
return getThis();
|
||||
}
|
||||
|
||||
protected abstract T getThis();
|
||||
protected abstract SKContext getThis();
|
||||
}
|
||||
|
||||
+45
-25
@@ -17,9 +17,8 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class AbstractSkFunction<
|
||||
RequestConfiguration, ContextType extends SKContext<ContextType>>
|
||||
implements SKFunction<RequestConfiguration, ContextType>, RegistrableSkFunction {
|
||||
public abstract class AbstractSkFunction<RequestConfiguration>
|
||||
implements SKFunction<RequestConfiguration>, RegistrableSkFunction {
|
||||
|
||||
private final DelegateTypes delegateType;
|
||||
private final List<ParameterView> parameters;
|
||||
@@ -60,36 +59,43 @@ public abstract class AbstractSkFunction<
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeAsync(
|
||||
String input, @Nullable ContextType context, @Nullable RequestConfiguration settings) {
|
||||
public Mono<SKContext> invokeAsync(
|
||||
@Nullable String input,
|
||||
@Nullable SKContext context,
|
||||
@Nullable RequestConfiguration settings) {
|
||||
if (context == null) {
|
||||
assertSkillSupplierRegistered();
|
||||
|
||||
context =
|
||||
buildContext(
|
||||
SKBuilders.variables().build(),
|
||||
NullMemory.getInstance(),
|
||||
skillsSupplier.get());
|
||||
SKBuilders.context()
|
||||
.with(NullMemory.getInstance())
|
||||
.with(skillsSupplier == null ? null : skillsSupplier.get())
|
||||
.build();
|
||||
} else {
|
||||
context = context.copy();
|
||||
}
|
||||
|
||||
context = context.update(input);
|
||||
if (input != null) {
|
||||
context = context.update(input);
|
||||
}
|
||||
|
||||
return this.invokeAsync(context, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeAsync(String input) {
|
||||
public Mono<SKContext> invokeAsync(String input) {
|
||||
return invokeAsync(input, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeAsync(
|
||||
ContextType context, @Nullable RequestConfiguration settings) {
|
||||
// return new FutureTask<SKContext>(() -> function.run(null, settings, context));
|
||||
|
||||
public Mono<SKContext> invokeAsync(
|
||||
@Nullable SKContext context, @Nullable RequestConfiguration settings) {
|
||||
if (context == null) {
|
||||
context = buildContext(SKBuilders.variables().build(), NullMemory.getInstance(), null);
|
||||
context =
|
||||
SKBuilders.context()
|
||||
.with(SKBuilders.variables().build())
|
||||
.with(NullMemory.getInstance())
|
||||
.build();
|
||||
} else {
|
||||
context = context.copy();
|
||||
}
|
||||
@@ -97,8 +103,8 @@ public abstract class AbstractSkFunction<
|
||||
return this.invokeAsyncInternal(context, settings);
|
||||
}
|
||||
|
||||
protected abstract Mono<ContextType> invokeAsyncInternal(
|
||||
ContextType context, @Nullable RequestConfiguration settings);
|
||||
protected abstract Mono<SKContext> invokeAsyncInternal(
|
||||
SKContext context, @Nullable RequestConfiguration settings);
|
||||
|
||||
@Override
|
||||
public String getSkillName() {
|
||||
@@ -157,6 +163,7 @@ public abstract class AbstractSkFunction<
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
@@ -205,18 +212,31 @@ public abstract class AbstractSkFunction<
|
||||
+ inputs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextType buildContext() {
|
||||
protected SKContext buildContext() {
|
||||
assertSkillSupplierRegistered();
|
||||
return buildContext(SKBuilders.variables().build(), null, getSkillsSupplier().get());
|
||||
return SKBuilders.context()
|
||||
.with(SKBuilders.variables().build())
|
||||
.with(skillsSupplier == null ? null : skillsSupplier.get())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeWithCustomInputAsync(
|
||||
public Mono<SKContext> invokeWithCustomInputAsync(
|
||||
ContextVariables input,
|
||||
SemanticTextMemory semanticMemory,
|
||||
ReadOnlySkillCollection skills) {
|
||||
ContextType tmpContext = buildContext(input, semanticMemory, skills);
|
||||
@Nullable SemanticTextMemory semanticMemory,
|
||||
@Nullable ReadOnlySkillCollection skills) {
|
||||
SKContext tmpContext =
|
||||
SKBuilders.context().with(input).with(semanticMemory).with(skills).build();
|
||||
return invokeAsync(tmpContext, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SKContext> invokeAsync() {
|
||||
return invokeAsync(null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SKContext> invokeAsync(SKContext context) {
|
||||
return invokeAsync(context, null);
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -21,6 +21,11 @@ public interface ContextVariables {
|
||||
@CheckReturnValue
|
||||
WritableContextVariables writableClone();
|
||||
|
||||
@Nullable
|
||||
String getInput();
|
||||
|
||||
String prettyPrint();
|
||||
|
||||
interface Builder {
|
||||
ContextVariables build();
|
||||
|
||||
|
||||
+7
-7
@@ -5,13 +5,13 @@ import com.microsoft.semantickernel.SKException;
|
||||
|
||||
public class FunctionNotRegisteredException extends SKException {
|
||||
|
||||
private static final String format =
|
||||
"It does not appear this function(%s) has been registered on a kernel.%n"
|
||||
+ "Register it on a kernel either by passing it to "
|
||||
+ "KernelConfig.Builder().addSkill() when building the kernel, or%n"
|
||||
+ "passing it to Kernel.registerSemanticFunction";
|
||||
|
||||
public FunctionNotRegisteredException(String name) {
|
||||
super(String.format(format, name));
|
||||
super(
|
||||
String.format(
|
||||
"It does not appear this function(%s) has been registered on a kernel.%n"
|
||||
+ "Register it on a kernel either by passing it to "
|
||||
+ "KernelConfig.Builder().addSkill() when building the kernel, or%n"
|
||||
+ "passing it to Kernel.registerSemanticFunction",
|
||||
name));
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -6,6 +6,9 @@ import com.microsoft.semantickernel.builders.ServiceLoadUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@SuppressWarnings("ImmutableEnumChecker")
|
||||
enum InternalBuildersSingleton {
|
||||
INST;
|
||||
|
||||
@@ -14,7 +17,7 @@ enum InternalBuildersSingleton {
|
||||
private static final String FALLBACK_VARIABLE_BUILDER_CLASS =
|
||||
"com.microsoft.semantickernel.orchestration.DefaultContextVariables$WritableBuilder";
|
||||
|
||||
private final WritableContextVariables.Builder variables;
|
||||
private final Supplier<WritableContextVariables.Builder> variables;
|
||||
|
||||
InternalBuildersSingleton() {
|
||||
try {
|
||||
@@ -49,6 +52,6 @@ enum InternalBuildersSingleton {
|
||||
}
|
||||
|
||||
public static WritableContextVariables.Builder variables() {
|
||||
return INST.variables;
|
||||
return INST.variables.get();
|
||||
}
|
||||
}
|
||||
|
||||
+45
-9
@@ -1,18 +1,20 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import reactor.util.annotation.NonNull;
|
||||
import reactor.util.annotation.Nullable;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
|
||||
/** Semantic Kernel context. */
|
||||
public interface SKContext<Type extends SKContext<Type>> {
|
||||
public interface SKContext {
|
||||
|
||||
Type build(
|
||||
SKContext build(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills);
|
||||
@@ -42,7 +44,6 @@ public interface SKContext<Type extends SKContext<Type>> {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
ReadOnlySkillCollection getSkills();
|
||||
|
||||
/**
|
||||
@@ -52,7 +53,7 @@ public interface SKContext<Type extends SKContext<Type>> {
|
||||
* @param content
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
Type setVariable(@NonNull String key, @NonNull String content);
|
||||
SKContext setVariable(String key, String content);
|
||||
|
||||
/**
|
||||
* Appends data to the given key
|
||||
@@ -61,7 +62,7 @@ public interface SKContext<Type extends SKContext<Type>> {
|
||||
* @param content
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
Type appendToVariable(@NonNull String key, @NonNull String content);
|
||||
SKContext appendToVariable(String key, String content);
|
||||
|
||||
/**
|
||||
* Updates the input entry with the given data
|
||||
@@ -70,7 +71,7 @@ public interface SKContext<Type extends SKContext<Type>> {
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Type update(@NonNull String content);
|
||||
SKContext update(String content);
|
||||
|
||||
/**
|
||||
* Merges in the given variables. Duplicate keys provided by newData will overwrite existing
|
||||
@@ -80,11 +81,46 @@ public interface SKContext<Type extends SKContext<Type>> {
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Type update(@NonNull ContextVariables newData);
|
||||
SKContext update(ContextVariables newData);
|
||||
|
||||
Type copy();
|
||||
SKContext copy();
|
||||
|
||||
interface BuilderSupplier extends Supplier<Builder> {}
|
||||
|
||||
interface Builder {
|
||||
SKContext build(ReadOnlySkillCollection skills);
|
||||
|
||||
SKContext build();
|
||||
|
||||
SKContext build(Class<? extends SKContext> clazz);
|
||||
|
||||
Builder with(ContextVariables variables);
|
||||
|
||||
/**
|
||||
* Sets the skills
|
||||
*
|
||||
* @param skills null argument will be ignored
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
Builder with(@Nullable ReadOnlySkillCollection skills);
|
||||
|
||||
/**
|
||||
* Sets the memory
|
||||
*
|
||||
* @param memory null argument will be ignored
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
Builder with(@Nullable SemanticTextMemory memory);
|
||||
|
||||
Builder clone(SKContext context);
|
||||
|
||||
/**
|
||||
* Builds a context from the given kernel. If not explicitly set, the skills and memory will
|
||||
* be used from the kernel.
|
||||
*
|
||||
* @param kernel
|
||||
* @return
|
||||
*/
|
||||
SKContext build(Kernel kernel);
|
||||
}
|
||||
}
|
||||
|
||||
+30
-90
@@ -2,6 +2,7 @@
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.FunctionView;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -15,52 +16,14 @@ import javax.annotation.Nullable;
|
||||
* @param <RequestConfiguration> The type of the configuration argument that will be provided when
|
||||
* the function is invoked
|
||||
*/
|
||||
public interface SKFunction<RequestConfiguration, ContextType extends SKContext<ContextType>> {
|
||||
/*
|
||||
/// <summary>
|
||||
/// Name of the function. The name is used by the skill collection and in prompt templates e.g. {{skillName.functionName}}
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the skill containing the function. The name is used by the skill collection and in prompt templates e.g. {{skillName.functionName}}
|
||||
/// </summary>
|
||||
string SkillName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Function description. The description is used in combination with embeddings when searching relevant functions.
|
||||
/// </summary>
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the function is defined using a prompt template.
|
||||
/// IMPORTANT: native functions might use semantic functions internally,
|
||||
/// so when this property is False, executing the function might still involve AI calls.
|
||||
/// </summary>
|
||||
public bool IsSemantic { get; }
|
||||
|
||||
/// <summary>
|
||||
/// AI service settings
|
||||
/// </summary>
|
||||
public CompleteRequestSettings RequestSettings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a description of the function, including parameters.
|
||||
/// </summary>
|
||||
/// <returns>An instance of <see cref="FunctionView"/> describing the function</returns>
|
||||
FunctionView Describe();
|
||||
*/
|
||||
// TODO: CancellationToken
|
||||
/// <summary>
|
||||
/// Invoke the internal delegate with an explicit string input
|
||||
/// </summary>
|
||||
/// <param name="input">String input</param>
|
||||
/// <param name="context">SK context</param>
|
||||
/// <param name="settings">LLM completion settings</param>
|
||||
/// <param name="log">Application logger</param>
|
||||
/// <param name="cancel">Cancellation token</param>
|
||||
/// <returns>The updated context, potentially a new one if context switching is
|
||||
// implemented.</returns>
|
||||
public interface SKFunction<RequestConfiguration> {
|
||||
/**
|
||||
* Returns a description of the function, including parameters.
|
||||
*
|
||||
* @return An instance of {@link FunctionView} describing the function
|
||||
*/
|
||||
@Nullable
|
||||
FunctionView describe();
|
||||
|
||||
/**
|
||||
* Invokes the function with the given input, context and settings
|
||||
@@ -71,7 +34,9 @@ public interface SKFunction<RequestConfiguration, ContextType extends SKContext<
|
||||
* @return an updated context with the result of the request
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Mono<ContextType> invokeAsync(String input, ContextType context, RequestConfiguration settings);
|
||||
Mono<SKContext> invokeAsync(String input, SKContext context, RequestConfiguration settings);
|
||||
|
||||
Mono<SKContext> invokeAsync();
|
||||
|
||||
/**
|
||||
* Invokes the function with the given input
|
||||
@@ -80,10 +45,20 @@ public interface SKFunction<RequestConfiguration, ContextType extends SKContext<
|
||||
* @return an updated context with the result of the request
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Mono<ContextType> invokeAsync(String input);
|
||||
Mono<SKContext> invokeAsync(String input);
|
||||
|
||||
@Nullable
|
||||
Class<RequestConfiguration> getType();
|
||||
|
||||
/**
|
||||
* Invokes the function with the given context and settings
|
||||
*
|
||||
* @param context Request context
|
||||
* @return an updated context with the result of the request
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Mono<SKContext> invokeAsync(SKContext context);
|
||||
|
||||
/**
|
||||
* Invokes the function with the given context and settings
|
||||
*
|
||||
@@ -92,31 +67,7 @@ public interface SKFunction<RequestConfiguration, ContextType extends SKContext<
|
||||
* @return an updated context with the result of the request
|
||||
*/
|
||||
@CheckReturnValue
|
||||
Mono<ContextType> invokeAsync(ContextType context, @Nullable RequestConfiguration settings);
|
||||
|
||||
/// <summary>
|
||||
/// Set the default skill collection to use when the function is invoked
|
||||
/// without a context or with a context that doesn't have a collection.
|
||||
/// </summary>
|
||||
/// <param name="skills">Kernel's skill collection</param>
|
||||
/// <returns>Self instance</returns>
|
||||
/*
|
||||
SKFunction<RequestConfiguration> setDefaultSkillCollection(SkillCollection skills);
|
||||
/// <summary>
|
||||
/// Set the AI service used by the semantic function, passing a factory method.
|
||||
/// The factory allows to lazily instantiate the client and to properly handle its disposal.
|
||||
/// </summary>
|
||||
/// <param name="serviceFactory">AI service factory</param>
|
||||
/// <returns>Self instance</returns>
|
||||
SKFunction setAIService(Supplier<TextCompletion> serviceFactory);
|
||||
|
||||
/// <summary>
|
||||
/// Set the AI completion settings used with LLM requests
|
||||
/// </summary>
|
||||
/// <param name="settings">LLM completion settings</param>
|
||||
/// <returns>Self instance</returns>
|
||||
SKFunction setAIConfiguration(CompleteRequestSettings settings);
|
||||
*/
|
||||
Mono<SKContext> invokeAsync(SKContext context, @Nullable RequestConfiguration settings);
|
||||
|
||||
/**
|
||||
* @return The name of the skill that this function is within
|
||||
@@ -135,28 +86,17 @@ public interface SKFunction<RequestConfiguration, ContextType extends SKContext<
|
||||
*/
|
||||
String toFullyQualifiedName();
|
||||
|
||||
/**
|
||||
* @return A description of the function
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
String toEmbeddingString();
|
||||
|
||||
String toManualString();
|
||||
|
||||
ContextType buildContext(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills);
|
||||
|
||||
ContextType buildContext();
|
||||
|
||||
/**
|
||||
* Build a context cloning the state of the given context
|
||||
*
|
||||
* @param toClone The context to clone
|
||||
*/
|
||||
ContextType buildContext(SKContext toClone);
|
||||
|
||||
Mono<ContextType> invokeWithCustomInputAsync(
|
||||
Mono<SKContext> invokeWithCustomInputAsync(
|
||||
ContextVariables variablesClone,
|
||||
SemanticTextMemory semanticMemory,
|
||||
ReadOnlySkillCollection skills);
|
||||
@Nullable SemanticTextMemory semanticMemory,
|
||||
@Nullable ReadOnlySkillCollection skills);
|
||||
}
|
||||
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
/** Semantic Kernel context. */
|
||||
public interface SemanticSKContext extends SKContext<SemanticSKContext> {}
|
||||
+7
-7
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import reactor.util.annotation.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -16,11 +14,11 @@ public interface WritableContextVariables extends ContextVariables {
|
||||
*
|
||||
* @param key variable name
|
||||
* @param content value to set
|
||||
* @return Contect for fluent calls
|
||||
* @return Context for fluent calls
|
||||
*/
|
||||
ContextVariables setVariable(@NonNull String key, @NonNull String content);
|
||||
ContextVariables setVariable(String key, String content);
|
||||
|
||||
ContextVariables appendToVariable(@NonNull String key, @NonNull String content);
|
||||
ContextVariables appendToVariable(String key, String content);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the main input text with the new value after a function is complete.
|
||||
@@ -29,9 +27,11 @@ public interface WritableContextVariables extends ContextVariables {
|
||||
// result for the user
|
||||
/// if the pipeline reached the end.</param>
|
||||
/// <returns>The current instance</returns>
|
||||
ContextVariables update(@NonNull String content);
|
||||
ContextVariables update(String content);
|
||||
|
||||
ContextVariables update(@NonNull ContextVariables newData, boolean merge);
|
||||
ContextVariables update(ContextVariables newData, boolean merge);
|
||||
|
||||
ContextVariables remove(String key);
|
||||
|
||||
interface Builder {
|
||||
/**
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.planner;
|
||||
|
||||
import com.microsoft.semantickernel.SKException;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Exception thrown for errors related to planning. */
|
||||
public class PlanningException extends SKException {
|
||||
@Nonnull private final ErrorCodes errorCode;
|
||||
|
||||
public PlanningException(@Nonnull ErrorCodes error) {
|
||||
this(error, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the PlanningException class with a provided error code and
|
||||
* message
|
||||
*
|
||||
* @param errorCode Error code
|
||||
* @param message The exception message
|
||||
*/
|
||||
public PlanningException(@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
this(errorCode, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the <see cref="PlanningException"/> class with a provided error
|
||||
* code, message, and inner exception.
|
||||
*
|
||||
* @param errorCode The error code
|
||||
* @param message A string that describes the error
|
||||
* @param innerException The exception that is the cause of the current exception
|
||||
*/
|
||||
public PlanningException(
|
||||
@Nonnull ErrorCodes errorCode,
|
||||
@Nullable String message,
|
||||
@Nullable Throwable innerException) {
|
||||
super(getDefaultMessage(errorCode, message), innerException);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error code
|
||||
*
|
||||
* @return The error code
|
||||
*/
|
||||
public ErrorCodes getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/* Translate the error code into a default message */
|
||||
private static String getDefaultMessage(
|
||||
@Nonnull ErrorCodes errorCode, @Nullable String message) {
|
||||
return String.format("%s: %s", errorCode.getMessage(), message);
|
||||
}
|
||||
|
||||
/** Error codes for PlanningException */
|
||||
public enum ErrorCodes {
|
||||
UnknownError("Unknown error"),
|
||||
|
||||
InvalidGoal("Invalid goal"),
|
||||
|
||||
InvalidPlan("Invalid plan"),
|
||||
|
||||
InvalidConfiguration("Invalid configuration");
|
||||
|
||||
private final String message;
|
||||
|
||||
ErrorCodes(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -22,14 +22,17 @@ public interface PromptTemplate {
|
||||
* Render the template using the information in the context
|
||||
*
|
||||
* @param executionContext Kernel execution context helpers
|
||||
* @param promptTemplateEngine
|
||||
* @return Prompt rendered to string
|
||||
*/
|
||||
Mono<String> renderAsync(SKContext executionContext, PromptTemplateEngine promptTemplateEngine);
|
||||
Mono<String> renderAsync(SKContext executionContext);
|
||||
|
||||
abstract class Builder {
|
||||
protected Builder() {}
|
||||
|
||||
public abstract PromptTemplate build(String promptTemplate, PromptTemplateConfig config);
|
||||
public abstract PromptTemplate build(PromptTemplateEngine promptTemplateEngine);
|
||||
|
||||
public abstract Builder withPromptTemplate(String promptTemplate);
|
||||
|
||||
public abstract Builder withPromptTemplateConfig(PromptTemplateConfig config);
|
||||
}
|
||||
}
|
||||
|
||||
+123
-25
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import reactor.util.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** Prompt template configuration */
|
||||
@@ -44,6 +45,8 @@ public class PromptTemplateConfig {
|
||||
completionConfig.presencePenalty,
|
||||
completionConfig.frequencyPenalty,
|
||||
completionConfig.maxTokens,
|
||||
completionConfig.bestOf,
|
||||
completionConfig.user,
|
||||
completionConfig.stopSequences));
|
||||
}
|
||||
|
||||
@@ -55,6 +58,8 @@ public class PromptTemplateConfig {
|
||||
completionConfig.presencePenalty,
|
||||
completionConfig.frequencyPenalty,
|
||||
completionConfig.maxTokens,
|
||||
completionConfig.bestOf,
|
||||
completionConfig.user,
|
||||
completionConfig.stopSequences));
|
||||
}
|
||||
|
||||
@@ -66,6 +71,8 @@ public class PromptTemplateConfig {
|
||||
presencePenalty,
|
||||
completionConfig.frequencyPenalty,
|
||||
completionConfig.maxTokens,
|
||||
completionConfig.bestOf,
|
||||
completionConfig.user,
|
||||
completionConfig.stopSequences));
|
||||
}
|
||||
|
||||
@@ -77,6 +84,8 @@ public class PromptTemplateConfig {
|
||||
completionConfig.presencePenalty,
|
||||
frequencyPenalty,
|
||||
completionConfig.maxTokens,
|
||||
completionConfig.bestOf,
|
||||
completionConfig.user,
|
||||
completionConfig.stopSequences));
|
||||
}
|
||||
|
||||
@@ -88,6 +97,8 @@ public class PromptTemplateConfig {
|
||||
completionConfig.presencePenalty,
|
||||
completionConfig.frequencyPenalty,
|
||||
maxTokens,
|
||||
completionConfig.bestOf,
|
||||
completionConfig.user,
|
||||
completionConfig.stopSequences));
|
||||
}
|
||||
|
||||
@@ -99,6 +110,8 @@ public class PromptTemplateConfig {
|
||||
completionConfig.presencePenalty,
|
||||
completionConfig.frequencyPenalty,
|
||||
completionConfig.maxTokens,
|
||||
completionConfig.bestOf,
|
||||
completionConfig.user,
|
||||
stopSequences));
|
||||
}
|
||||
|
||||
@@ -107,6 +120,10 @@ public class PromptTemplateConfig {
|
||||
}
|
||||
}
|
||||
|
||||
public InputConfig getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
/** Completion configuration parameters */
|
||||
public static class CompletionConfig {
|
||||
/*
|
||||
@@ -166,8 +183,37 @@ public class PromptTemplateConfig {
|
||||
*/
|
||||
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, new ArrayList<>());
|
||||
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
|
||||
@@ -177,12 +223,22 @@ public class PromptTemplateConfig {
|
||||
@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<>();
|
||||
}
|
||||
@@ -208,6 +264,22 @@ public class PromptTemplateConfig {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/** Input parameter for semantic functions */
|
||||
@@ -226,6 +298,34 @@ public class PromptTemplateConfig {
|
||||
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). */
|
||||
@@ -235,37 +335,27 @@ public class PromptTemplateConfig {
|
||||
|
||||
@JsonCreator
|
||||
public InputConfig(@JsonProperty("parameters") List<InputParameter> parameters) {
|
||||
this.parameters = parameters;
|
||||
this.parameters = Collections.unmodifiableList(parameters);
|
||||
}
|
||||
|
||||
public List<InputParameter> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Schema - Not currently used.
|
||||
/// </summary>
|
||||
[JsonPropertyName("schema")]
|
||||
[JsonPropertyOrder(1)]
|
||||
public int Schema { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Type, such as "completion", "embeddings", etc.
|
||||
/// </summary>
|
||||
/// <remarks>TODO: use enum</remarks>
|
||||
[JsonPropertyName("type")]
|
||||
[JsonPropertyOrder(2)]
|
||||
*/
|
||||
private final int schema;
|
||||
|
||||
private final String type; // { get; set; } = "completion";
|
||||
/*
|
||||
/// <summary>
|
||||
/// Description
|
||||
/// </summary>
|
||||
[JsonPropertyName("description")]
|
||||
[JsonPropertyOrder(3)]
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
public PromptTemplateConfig() {
|
||||
this("", "", null);
|
||||
}
|
||||
|
||||
public PromptTemplateConfig(CompletionConfig completionConfig) {
|
||||
this(1, "", "", completionConfig, new InputConfig(new ArrayList<>()));
|
||||
}
|
||||
|
||||
public PromptTemplateConfig(
|
||||
String description, String type, @Nullable CompletionConfig completionConfig) {
|
||||
this(1, description, type, completionConfig, new InputConfig(new ArrayList<>()));
|
||||
@@ -277,7 +367,7 @@ public class PromptTemplateConfig {
|
||||
@JsonProperty("description") String description,
|
||||
@JsonProperty("type") String type,
|
||||
@Nullable @JsonProperty("completion") CompletionConfig completionConfig,
|
||||
@JsonProperty("input") InputConfig input) {
|
||||
@Nullable @JsonProperty("input") InputConfig input) {
|
||||
if (completionConfig == null) {
|
||||
completionConfig = new CompletionConfig();
|
||||
}
|
||||
@@ -285,9 +375,17 @@ public class PromptTemplateConfig {
|
||||
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;
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.skilldefinition;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class used to copy and export data from the skill collection. The data is mutable, but changes do
|
||||
* not affect the skill collection.
|
||||
*/
|
||||
public class FunctionView {
|
||||
// Name of the function. The name is used by the skill collection and in prompt templates e.g.
|
||||
// {{skillName.functionName}}
|
||||
private final String name;
|
||||
|
||||
/// Name of the skill containing the function. The name is used by the skill collection and in
|
||||
// prompt templates e.g. {{skillName.functionName}}
|
||||
private final String skillName;
|
||||
|
||||
// Function description. The description is used in combination with embeddings when searching
|
||||
// relevant functions.
|
||||
private final String description;
|
||||
|
||||
// Whether the delegate points to a semantic function
|
||||
private final boolean isSemantic;
|
||||
|
||||
// Whether the delegate is an asynchronous function
|
||||
private final boolean isAsynchronous;
|
||||
|
||||
// List of function parameters
|
||||
private final List<ParameterView> parameters;
|
||||
|
||||
/**
|
||||
* Create a function view.
|
||||
*
|
||||
* @param name Function name
|
||||
* @param skillName Skill name, e.g. the function namespace
|
||||
* @param description Function description
|
||||
* @param parameters List of function parameters provided by the skill developer
|
||||
* @param isSemantic Whether the function is a semantic one (or native is False)
|
||||
* @param isAsynchronous Whether the function is async. Note: all semantic functions are async
|
||||
*/
|
||||
public FunctionView(
|
||||
String name,
|
||||
String skillName,
|
||||
String description,
|
||||
List<ParameterView> parameters,
|
||||
boolean isSemantic,
|
||||
boolean isAsynchronous) {
|
||||
this.name = name;
|
||||
this.skillName = skillName;
|
||||
this.description = description;
|
||||
this.parameters = Collections.unmodifiableList(parameters);
|
||||
this.isSemantic = isSemantic;
|
||||
this.isAsynchronous = isAsynchronous;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of function parameters
|
||||
*
|
||||
* @return the list of function parameters
|
||||
*/
|
||||
public List<ParameterView> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
+4
@@ -28,6 +28,10 @@ public class ParameterView {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public ParameterView(String name) {
|
||||
this(name, "", "");
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ public interface ReadOnlyFunctionCollection {
|
||||
|
||||
String getSkillName();
|
||||
|
||||
SKFunction<?, ?> getFunction(String functionName);
|
||||
SKFunction<?> getFunction(String functionName);
|
||||
|
||||
/**
|
||||
* Get function with the given SKFunction type argument.
|
||||
@@ -34,5 +34,5 @@ public interface ReadOnlyFunctionCollection {
|
||||
/**
|
||||
* @return An unmodifiable list of all functions
|
||||
*/
|
||||
List<SKFunction<?, ?>> getAll();
|
||||
List<SKFunction<?>> getAll();
|
||||
}
|
||||
|
||||
+5
-4
@@ -35,18 +35,19 @@ public interface ReadOnlySkillCollection {
|
||||
|
||||
/** Get function with name from the global scope */
|
||||
@Nullable
|
||||
<T extends SKFunction<?, ?>> T getFunction(
|
||||
String functionName, @Nullable Class<T> functionType);
|
||||
<T extends SKFunction<?>> T getFunction(String functionName, @Nullable Class<T> functionType);
|
||||
|
||||
@Nullable
|
||||
<T extends SKFunction<?, ?>> T getFunction(
|
||||
String skillName, String funName, Class<T> functionClazz);
|
||||
<T extends SKFunction<?>> T getFunction(
|
||||
String skillName, String funName, @Nullable Class<T> functionClazz);
|
||||
|
||||
@Nullable
|
||||
ReadOnlyFunctionCollection getFunctions(String skillName);
|
||||
|
||||
boolean hasFunction(String functionName);
|
||||
|
||||
boolean hasFunction(String skillName, String functionName);
|
||||
|
||||
public interface Builder {
|
||||
public ReadOnlySkillCollection build();
|
||||
}
|
||||
|
||||
+12
@@ -2,9 +2,12 @@
|
||||
package com.microsoft.semantickernel.templateengine;
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.templateengine.blocks.Block;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Prompt template engine interface */
|
||||
public interface PromptTemplateEngine {
|
||||
|
||||
@@ -30,6 +33,15 @@ public interface PromptTemplateEngine {
|
||||
*/
|
||||
Mono<String> renderAsync(String templateText, SKContext context);
|
||||
|
||||
/**
|
||||
* Given a prompt template string, extract all the blocks (text, variables, function calls)
|
||||
*
|
||||
* @param promptTemplate Prompt template (see skprompt.txt files)
|
||||
* @return A list of all the blocks, ie the template tokenized in text, variables and function
|
||||
* calls
|
||||
*/
|
||||
List<Block> extractBlocks(String promptTemplate);
|
||||
|
||||
abstract class Builder {
|
||||
protected Builder() {}
|
||||
|
||||
|
||||
+52
-1
@@ -40,23 +40,56 @@ public class CompletionRequestSettings {
|
||||
/** Sequences where the completion will stop generating further tokens. */
|
||||
private final List<String> stopSequences; // { get; set; } = Array.Empty<string>();
|
||||
|
||||
/**
|
||||
* 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 int bestOf;
|
||||
|
||||
/**
|
||||
* A unique identifier representing your end-user, which can help OpenAI to monitor and detect
|
||||
* abuse
|
||||
*/
|
||||
private final String user;
|
||||
|
||||
public CompletionRequestSettings(
|
||||
double temperature,
|
||||
double topP,
|
||||
double presencePenalty,
|
||||
double frequencyPenalty,
|
||||
int maxTokens) {
|
||||
this(
|
||||
temperature,
|
||||
topP,
|
||||
presencePenalty,
|
||||
frequencyPenalty,
|
||||
maxTokens,
|
||||
1,
|
||||
"",
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
public CompletionRequestSettings(
|
||||
double temperature,
|
||||
double topP,
|
||||
double presencePenalty,
|
||||
double frequencyPenalty,
|
||||
int maxTokens,
|
||||
int bestOf,
|
||||
String user,
|
||||
List<String> stopSequences) {
|
||||
this.temperature = temperature;
|
||||
this.topP = topP;
|
||||
this.presencePenalty = presencePenalty;
|
||||
this.frequencyPenalty = frequencyPenalty;
|
||||
this.maxTokens = maxTokens;
|
||||
this.bestOf = bestOf;
|
||||
this.user = user;
|
||||
this.stopSequences = new ArrayList<>(stopSequences);
|
||||
}
|
||||
|
||||
public CompletionRequestSettings() {
|
||||
this(0, 0, 0, 0, 256, new ArrayList<>());
|
||||
this(0, 0, 0, 0, 256, 1, "", new ArrayList<>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,6 +105,8 @@ public class CompletionRequestSettings {
|
||||
config.getPresencePenalty(),
|
||||
config.getFrequencyPenalty(),
|
||||
config.getMaxTokens(),
|
||||
config.getBestOf(),
|
||||
config.getUser(),
|
||||
new ArrayList<>());
|
||||
}
|
||||
|
||||
@@ -117,4 +152,20 @@ public class CompletionRequestSettings {
|
||||
public List<String> getStopSequences() {
|
||||
return Collections.unmodifiableList(stopSequences);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Integer getBestOf() {
|
||||
return bestOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* A unique identifier representing your end-user, which can help OpenAI to monitor and detect
|
||||
* abuse
|
||||
*/
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.textcompletion;
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
|
||||
public interface CompletionSKContext extends SKContext<CompletionSKContext> {}
|
||||
+5
-10
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.textcompletion;
|
||||
|
||||
import com.microsoft.semantickernel.builders.BuildersSingleton;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
@@ -12,8 +12,7 @@ import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface CompletionSKFunction
|
||||
extends SKFunction<CompletionRequestSettings, CompletionSKContext> {
|
||||
public interface CompletionSKFunction extends SKFunction<CompletionRequestSettings> {
|
||||
|
||||
/**
|
||||
* Method to aggregate partitioned results of a semantic function.
|
||||
@@ -22,12 +21,8 @@ public interface CompletionSKFunction
|
||||
* @param context Semantic Kernel context
|
||||
* @return Aggregated results
|
||||
*/
|
||||
Mono<CompletionSKContext> aggregatePartitionedResultsAsync(
|
||||
List<String> partitionedInput, @Nullable CompletionSKContext context);
|
||||
|
||||
static CompletionSKFunction.Builder builder() {
|
||||
return BuildersSingleton.INST.getFunctionBuilders().completionBuilders(null);
|
||||
}
|
||||
Mono<SKContext> aggregatePartitionedResultsAsync(
|
||||
List<String> partitionedInput, @Nullable SKContext context);
|
||||
|
||||
abstract class Builder {
|
||||
|
||||
@@ -40,7 +35,7 @@ public interface CompletionSKFunction
|
||||
@Nullable String skillName);
|
||||
|
||||
public abstract CompletionSKFunction createFunction(
|
||||
String functionName, SemanticFunctionConfig functionConfig);
|
||||
String prompt, PromptTemplateConfig.CompletionConfig functionConfig);
|
||||
|
||||
public abstract CompletionSKFunction createFunction(
|
||||
@Nullable String skillNameFinal,
|
||||
|
||||
+17
-3
@@ -3,12 +3,17 @@ package com.microsoft.semantickernel.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AzureOpenAISettings extends ClientSettings<AzureOpenAISettings> {
|
||||
|
||||
private static final String DEFAULT_CLIENT_ID = "azureopenai";
|
||||
private String key;
|
||||
private String endpoint;
|
||||
private String deploymentName;
|
||||
|
||||
@Nullable private String key = null;
|
||||
|
||||
@Nullable private String endpoint = null;
|
||||
|
||||
@Nullable private String deploymentName = null;
|
||||
|
||||
public enum Property {
|
||||
AZURE_OPEN_AI_KEY("key"),
|
||||
@@ -26,14 +31,23 @@ public class AzureOpenAISettings extends ClientSettings<AzureOpenAISettings> {
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
if (key == null) {
|
||||
throw new RuntimeException("Azure OpenAI key is not set");
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getEndpoint() {
|
||||
if (endpoint == null) {
|
||||
throw new RuntimeException("Azure OpenAI endpoint is not set");
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public String getDeploymentName() {
|
||||
if (deploymentName == null) {
|
||||
throw new RuntimeException("Azure OpenAI deployment name is not set");
|
||||
}
|
||||
return deploymentName;
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -3,10 +3,12 @@ package com.microsoft.semantickernel.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class OpenAISettings extends ClientSettings<OpenAISettings> {
|
||||
private String key;
|
||||
private String organizationId;
|
||||
private static final String DEFAULT_CLIENT_ID = "openai";
|
||||
@Nullable private String key = null;
|
||||
@Nullable private String organizationId = null;
|
||||
|
||||
private enum Property {
|
||||
OPEN_AI_KEY("key"),
|
||||
@@ -23,10 +25,16 @@ public class OpenAISettings extends ClientSettings<OpenAISettings> {
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
if (key == null) {
|
||||
throw new RuntimeException("OpenAI key is not set");
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getOrganizationId() {
|
||||
if (organizationId == null) {
|
||||
throw new RuntimeException("OpenAI organization id is not set");
|
||||
}
|
||||
return organizationId;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.microsoft.semantickernel</groupId>
|
||||
@@ -44,10 +44,17 @@
|
||||
<artifactId>semantickernel-core-skills</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>actionplanner-extension</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.azure</groupId>
|
||||
<artifactId>azure-ai-openai</artifactId>
|
||||
<version>1.0.0-beta.1</version>
|
||||
<version>1.0.0-beta.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
+6
-1
@@ -14,6 +14,7 @@ import com.microsoft.semantickernel.connectors.ai.openai.azuresdk.ClientBase;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -28,6 +29,7 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
|
||||
public static class Builder implements ChatCompletion.Builder {
|
||||
public Builder() {}
|
||||
|
||||
@Override
|
||||
public ChatCompletion<OpenAIChatHistory> build(OpenAIAsyncClient client, String modelId) {
|
||||
return new OpenAIChatCompletion(client, modelId);
|
||||
}
|
||||
@@ -40,6 +42,7 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
|
||||
* @param requestSettings AI request settings
|
||||
* @return The response generated by the request
|
||||
*/
|
||||
@Override
|
||||
public Mono<String> generateMessageAsync(
|
||||
OpenAIChatHistory chat, @Nullable ChatRequestSettings requestSettings) {
|
||||
|
||||
@@ -98,7 +101,9 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
|
||||
options.setTopP(requestSettings.getTopP());
|
||||
options.setFrequencyPenalty(requestSettings.getFrequencyPenalty());
|
||||
options.setPresencePenalty(requestSettings.getPresencePenalty());
|
||||
options.setN(1);
|
||||
options.setLogitBias(new HashMap<>());
|
||||
options.setN(requestSettings.getBestOf());
|
||||
options.setUser(requestSettings.getUser());
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
+4
-1
@@ -15,6 +15,7 @@ import jakarta.inject.Inject;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/// <summary>
|
||||
@@ -59,7 +60,9 @@ public class OpenAITextCompletion extends ClientBase implements TextCompletion {
|
||||
.setFrequencyPenalty(requestSettings.getFrequencyPenalty())
|
||||
.setPresencePenalty(requestSettings.getPresencePenalty())
|
||||
.setModel(getModelId())
|
||||
.setUser(null);
|
||||
.setUser(requestSettings.getUser())
|
||||
.setBestOf(requestSettings.getBestOf())
|
||||
.setLogitBias(new HashMap<>());
|
||||
|
||||
return getClient()
|
||||
.getCompletions(getModelId(), completionsOptions)
|
||||
|
||||
+2
-1
@@ -27,7 +27,8 @@ public class OpenAITextEmbeddingGeneration extends ClientBase
|
||||
}
|
||||
|
||||
protected Mono<List<Embedding<Float>>> internalGenerateTextEmbeddingsAsync(List<String> data) {
|
||||
EmbeddingsOptions options = new EmbeddingsOptions(data).setModel(getModelId()).setUser("default");
|
||||
EmbeddingsOptions options =
|
||||
new EmbeddingsOptions(data).setModel(getModelId()).setUser("default");
|
||||
|
||||
return getClient()
|
||||
.getEmbeddings(getModelId(), options)
|
||||
|
||||
+22
-20
@@ -19,14 +19,12 @@ import com.azure.search.documents.models.QueryLanguage;
|
||||
import com.azure.search.documents.models.QueryType;
|
||||
import com.azure.search.documents.models.SearchOptions;
|
||||
import com.azure.search.documents.util.SearchPagedResponse;
|
||||
import com.microsoft.semantickernel.exceptions.NotSupportedException;
|
||||
import com.microsoft.semantickernel.memory.MemoryQueryResult;
|
||||
import com.microsoft.semantickernel.memory.MemoryRecordMetadata;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -40,6 +38,9 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Semantic Memory implementation using Azure Cognitive Search. For more information about Azure
|
||||
* Cognitive Search {@see https://learn.microsoft.com/azure/search/search-what-is-azure-search}
|
||||
@@ -57,7 +58,8 @@ public class AzureCognitiveSearchMemory implements SemanticTextMemory {
|
||||
* Create a new instance of semantic memory using Azure Cognitive Search.
|
||||
*
|
||||
* @param endpoint Azure Cognitive Search URI, e.g. {@code "https://contoso.search.windows.net"}
|
||||
* @param apiKey The key used to authenticate HTTP requests sent to the Azure Cognitive Search service.
|
||||
* @param apiKey The key used to authenticate HTTP requests sent to the Azure Cognitive Search
|
||||
* service.
|
||||
*/
|
||||
public AzureCognitiveSearchMemory(String endpoint, String apiKey) {
|
||||
AzureKeyCredential credentials = new AzureKeyCredential(apiKey);
|
||||
@@ -72,7 +74,8 @@ public class AzureCognitiveSearchMemory implements SemanticTextMemory {
|
||||
* Create a new instance of semantic memory using Azure Cognitive Search.
|
||||
*
|
||||
* @param endpoint Azure Cognitive Search URI, e.g. {@code "https://contoso.search.windows.net"}
|
||||
* @param credentials TokenCredential used to authorize requests sent to the Azure Cognitive Search service.
|
||||
* @param credentials TokenCredential used to authorize requests sent to the Azure Cognitive
|
||||
* Search service.
|
||||
*/
|
||||
public AzureCognitiveSearchMemory(String endpoint, TokenCredential credentials) {
|
||||
this._adminClient =
|
||||
@@ -255,21 +258,18 @@ public class AzureCognitiveSearchMemory implements SemanticTextMemory {
|
||||
|
||||
PrioritizedFields prioritizedFields =
|
||||
new PrioritizedFields()
|
||||
.setTitleField(titleField)
|
||||
.setPrioritizedContentFields(prioritizedContentFields);
|
||||
.setTitleField(titleField)
|
||||
.setPrioritizedContentFields(prioritizedContentFields);
|
||||
|
||||
SemanticConfiguration semanticConfiguration =
|
||||
new SemanticConfiguration("default", prioritizedFields);
|
||||
|
||||
SemanticSettings semanticSettings =
|
||||
new SemanticSettings()
|
||||
.setConfigurations(
|
||||
Collections.singletonList(semanticConfiguration)
|
||||
);
|
||||
.setConfigurations(Collections.singletonList(semanticConfiguration));
|
||||
|
||||
SearchIndex newIndex =
|
||||
new SearchIndex(indexName, fields)
|
||||
.setSemanticSettings(semanticSettings);
|
||||
new SearchIndex(indexName, fields).setSemanticSettings(semanticSettings);
|
||||
|
||||
return this._adminClient.createIndex(newIndex);
|
||||
}
|
||||
@@ -292,15 +292,17 @@ public class AzureCognitiveSearchMemory implements SemanticTextMemory {
|
||||
return response.getValue().getResults().get(0).getKey();
|
||||
};
|
||||
|
||||
return client.mergeOrUploadDocumentsWithResponse(Collections.singleton(record), throwOnAnyError)
|
||||
return client.mergeOrUploadDocumentsWithResponse(
|
||||
Collections.singleton(record), throwOnAnyError)
|
||||
.map(transform)
|
||||
.onErrorResume(e ->
|
||||
createIndexAsync(indexName)
|
||||
.then(client.mergeOrUploadDocumentsWithResponse(
|
||||
Collections.singleton(record), throwOnAnyError))
|
||||
.map(transform)
|
||||
);
|
||||
|
||||
.onErrorResume(
|
||||
e ->
|
||||
createIndexAsync(indexName)
|
||||
.then(
|
||||
client.mergeOrUploadDocumentsWithResponse(
|
||||
Collections.singleton(record),
|
||||
throwOnAnyError))
|
||||
.map(transform));
|
||||
}
|
||||
|
||||
private static MemoryRecordMetadata toMemoryRecordMetadata(AzureCognitiveSearchRecord data) {
|
||||
|
||||
+7
-9
@@ -12,7 +12,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Azure Cognitive Search record and index definition. Note: once defined, index cannot be modified.
|
||||
*/
|
||||
@@ -37,12 +36,12 @@ public final class AzureCognitiveSearchRecord {
|
||||
|
||||
@JsonCreator
|
||||
public AzureCognitiveSearchRecord(
|
||||
@JsonProperty("Id") String id,
|
||||
@JsonProperty("Text") String text,
|
||||
@JsonProperty("Description") String description,
|
||||
@JsonProperty("AdditionalMetadata") String additionalMetadata,
|
||||
@JsonProperty("ExternalSourceName") String externalSourceName,
|
||||
@JsonProperty("Reference") boolean isReference) {
|
||||
@JsonProperty("Id") String id,
|
||||
@JsonProperty("Text") String text,
|
||||
@JsonProperty("Description") String description,
|
||||
@JsonProperty("AdditionalMetadata") String additionalMetadata,
|
||||
@JsonProperty("ExternalSourceName") String externalSourceName,
|
||||
@JsonProperty("Reference") boolean isReference) {
|
||||
this.id = id;
|
||||
this.text = text;
|
||||
this.description = description;
|
||||
@@ -126,8 +125,7 @@ public final class AzureCognitiveSearchRecord {
|
||||
new SearchField("ExternalSourceName", SearchFieldDataType.STRING)
|
||||
.setSearchable(true)
|
||||
.setAnalyzerName(LexicalAnalyzerName.EN_LUCENE),
|
||||
new SearchField("Reference", SearchFieldDataType.BOOLEAN).setFilterable(true)
|
||||
);
|
||||
new SearchField("Reference", SearchFieldDataType.BOOLEAN).setFilterable(true));
|
||||
}
|
||||
// TODO: add one more field with the vector, float array, mark it as searchable
|
||||
|
||||
|
||||
+16
-10
@@ -8,7 +8,6 @@ import com.microsoft.semantickernel.skilldefinition.annotations.DefineSKFunction
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionInputAttribute;
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
|
||||
import com.microsoft.semantickernel.text.TextChunker;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -25,6 +24,7 @@ public class ConversationSummarySkill {
|
||||
private final CompletionSKFunction summarizeConversationFunction;
|
||||
private final CompletionSKFunction conversationActionItemsFunction;
|
||||
private final CompletionSKFunction conversationTopicsFunction;
|
||||
private final Kernel kernel;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the ConversationSummarySkill class
|
||||
@@ -32,6 +32,7 @@ public class ConversationSummarySkill {
|
||||
* @param kernel Kernel instance
|
||||
*/
|
||||
public ConversationSummarySkill(Kernel kernel) {
|
||||
this.kernel = kernel;
|
||||
this.summarizeConversationFunction =
|
||||
SKBuilders.completionFunctions(kernel)
|
||||
.createFunction(
|
||||
@@ -85,17 +86,22 @@ public class ConversationSummarySkill {
|
||||
@DefineSKFunction(
|
||||
description = "Given a long conversation transcript, summarize the conversation.",
|
||||
name = "SummarizeConversation")
|
||||
public Mono<CompletionSKContext> summarizeConversationAsync(
|
||||
public Mono<SKContext> summarizeConversationAsync(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(
|
||||
description = "A long conversation transcript.",
|
||||
name = "input")
|
||||
String input,
|
||||
@Nullable SKContext<?> context) {
|
||||
@Nullable SKContext context) {
|
||||
List<String> lines = TextChunker.splitPlainTextLines(input, MaxTokens);
|
||||
List<String> paragraphs = TextChunker.splitPlainTextParagraphs(lines, MaxTokens);
|
||||
|
||||
CompletionSKContext completionContext = summarizeConversationFunction.buildContext(context);
|
||||
if (context == null) {
|
||||
context =
|
||||
SKBuilders.context().with(kernel.getSkills()).with(kernel.getMemory()).build();
|
||||
}
|
||||
|
||||
SKContext completionContext = context.copy();
|
||||
|
||||
return this.summarizeConversationFunction.aggregatePartitionedResultsAsync(
|
||||
paragraphs, completionContext);
|
||||
@@ -111,17 +117,17 @@ public class ConversationSummarySkill {
|
||||
@DefineSKFunction(
|
||||
description = "Given a long conversation transcript, identify action items.",
|
||||
name = "GetConversationActionItems")
|
||||
public Mono<CompletionSKContext> getConversationActionItemsAsync(
|
||||
public Mono<SKContext> getConversationActionItemsAsync(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(
|
||||
description = "A long conversation transcript.",
|
||||
name = "input")
|
||||
String input,
|
||||
SKContext<?> context) {
|
||||
SKContext context) {
|
||||
List<String> lines = TextChunker.splitPlainTextLines(input, MaxTokens);
|
||||
List<String> paragraphs = TextChunker.splitPlainTextParagraphs(lines, MaxTokens);
|
||||
|
||||
CompletionSKContext completionContext = summarizeConversationFunction.buildContext(context);
|
||||
SKContext completionContext = context.copy();
|
||||
|
||||
return this.conversationActionItemsFunction.aggregatePartitionedResultsAsync(
|
||||
paragraphs, completionContext);
|
||||
@@ -138,17 +144,17 @@ public class ConversationSummarySkill {
|
||||
description =
|
||||
"Given a long conversation transcript, identify topics worth remembering.",
|
||||
name = "GetConversationTopics")
|
||||
public Mono<CompletionSKContext> getConversationTopicsAsync(
|
||||
public Mono<SKContext> getConversationTopicsAsync(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(
|
||||
description = "A long conversation transcript.",
|
||||
name = "input")
|
||||
String input,
|
||||
SKContext<?> context) {
|
||||
SKContext context) {
|
||||
List<String> lines = TextChunker.splitPlainTextLines(input, MaxTokens);
|
||||
List<String> paragraphs = TextChunker.splitPlainTextParagraphs(lines, MaxTokens);
|
||||
|
||||
CompletionSKContext completionContext = summarizeConversationFunction.buildContext(context);
|
||||
SKContext completionContext = context.copy();
|
||||
|
||||
return this.conversationTopicsFunction.aggregatePartitionedResultsAsync(
|
||||
paragraphs, completionContext);
|
||||
|
||||
+17
-9
@@ -6,6 +6,7 @@ import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionInputA
|
||||
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@@ -41,12 +42,16 @@ public class FileIOSkill {
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(name = "path", description = "Source file")
|
||||
String path,
|
||||
@SKFunctionParameters(name = "charset", description = "Character set to use to read the file", defaultValue="UTF-8")
|
||||
String charset) throws IOException {
|
||||
@SKFunctionParameters(
|
||||
name = "charset",
|
||||
description = "Character set to use to read the file",
|
||||
defaultValue = "UTF-8")
|
||||
String charset)
|
||||
throws IOException {
|
||||
Path filePath = Paths.get(path);
|
||||
byte[] fileBytes;
|
||||
fileBytes = Files.readAllBytes(filePath);
|
||||
String fileContents = new String(fileBytes, charset);
|
||||
String fileContents = new String(fileBytes, Charset.forName(charset));
|
||||
return fileContents;
|
||||
}
|
||||
|
||||
@@ -61,22 +66,25 @@ public class FileIOSkill {
|
||||
*
|
||||
* @param path The destination file.
|
||||
* @param content Contains the 'content' to write
|
||||
* @return An awaitable task.
|
||||
*/
|
||||
@DefineSKFunction(description = "Write a file", name = "writeAsync")
|
||||
public void writeFileAsync(
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(name = "path", description = "Destination file")
|
||||
String path,
|
||||
@SKFunctionParameters(
|
||||
@SKFunctionParameters(
|
||||
name = "content",
|
||||
description = "File content",
|
||||
defaultValue = "",
|
||||
type = String.class)
|
||||
String content,
|
||||
@SKFunctionParameters(name = "charset", description = "Character set to use to read the file", defaultValue="UTF-8")
|
||||
String charset) throws IOException {
|
||||
Path filePath = Paths.get(path);
|
||||
Files.write(filePath, content.getBytes(charset));
|
||||
@SKFunctionParameters(
|
||||
name = "charset",
|
||||
description = "Character set to use to read the file",
|
||||
defaultValue = "UTF-8")
|
||||
String charset)
|
||||
throws IOException {
|
||||
Path filePath = Paths.get(path);
|
||||
Files.write(filePath, content.getBytes(charset));
|
||||
}
|
||||
}
|
||||
|
||||
+22
-18
@@ -9,31 +9,35 @@ import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* MathSkill provides a set of functions to make Math calculations.
|
||||
*
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>input</code> is the first number in the operation.</li>
|
||||
* <li><code>amount</code> is the second number in the operation.</li>
|
||||
* <li><code>input</code> is the first number in the operation.
|
||||
* <li><code>amount</code> is the second number in the operation.
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* <p>Usage:
|
||||
* <blockquote><pre>
|
||||
*
|
||||
* <blockquote>
|
||||
*
|
||||
* <pre>
|
||||
* kernel.ImportSkill("math", new MathSkill());
|
||||
*
|
||||
*
|
||||
* {{math.add}} => Returns the sum of input and amount
|
||||
* {{math.subtract}} => Returns the differentce of input from amount
|
||||
* </pre></blockquote>
|
||||
* </p>
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @implNote This skill uses BigDecimal to perform the number conversion and the calculations.
|
||||
*/
|
||||
public class MathSkill {
|
||||
|
||||
/**
|
||||
* Returns the addition result of input and amount values provided.
|
||||
*
|
||||
* This skill attempts to convert the numbers to BigDecimal and then add them.
|
||||
*
|
||||
* If a conversion error occurs, the skill will throw an exception.
|
||||
*
|
||||
* <p>This skill attempts to convert the numbers to BigDecimal and then add them.
|
||||
*
|
||||
* <p>If a conversion error occurs, the skill will throw an exception.
|
||||
*
|
||||
* @param input Initial value as string to add the specified amount
|
||||
* @param amount The amount to be added to input
|
||||
@@ -54,11 +58,11 @@ public class MathSkill {
|
||||
|
||||
/**
|
||||
* Returns the subtraction result of input and amount values provided.
|
||||
*
|
||||
* This skill attempts to convert the numbers to BigDecimal and then subtract them.
|
||||
*
|
||||
* If a conversion error occurs, the skill will throw an exception.
|
||||
*
|
||||
*
|
||||
* <p>This skill attempts to convert the numbers to BigDecimal and then subtract them.
|
||||
*
|
||||
* <p>If a conversion error occurs, the skill will throw an exception.
|
||||
*
|
||||
* @param input Initial value as string to subtract the specified amount
|
||||
* @param amount The amount to be subtracted from input
|
||||
* @return The resulting difference as a String.
|
||||
|
||||
+1
-1
@@ -49,6 +49,6 @@ public class TextSkill {
|
||||
@SKFunctionInputAttribute
|
||||
@SKFunctionParameters(description = "Text to lowercase", name = "input")
|
||||
String input) {
|
||||
return input.toLowerCase();
|
||||
return input.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-7
@@ -7,7 +7,6 @@ import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.time.format.TextStyle;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -55,6 +54,9 @@ import java.util.Locale;
|
||||
* <p>{{time.timeZoneName}} => Pacific Time
|
||||
*/
|
||||
public class TimeSkill {
|
||||
|
||||
public static final String DAY_MONTH_DAY_YEAR = "EEEE, MMMM d, yyyy";
|
||||
|
||||
/**
|
||||
* Get the current date.
|
||||
*
|
||||
@@ -64,7 +66,8 @@ public class TimeSkill {
|
||||
*/
|
||||
@DefineSKFunction(name = "date", description = "Get the current date")
|
||||
public String date() {
|
||||
return DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(ZonedDateTime.now());
|
||||
// Example: Sunday, 12 January, 2025
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR).format(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,6 +79,7 @@ public class TimeSkill {
|
||||
*/
|
||||
@DefineSKFunction(name = "time", description = "Get the current time")
|
||||
public String time() {
|
||||
// Example: 09:15:07 PM
|
||||
return DateTimeFormatter.ofPattern("hh:mm:ss a").format(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
@@ -88,7 +92,7 @@ public class TimeSkill {
|
||||
*/
|
||||
@DefineSKFunction(name = "utcNow", description = "Get the current UTC date and time")
|
||||
public String utcNow() {
|
||||
return DateTimeFormatter.ofPattern("EEEE, MMMM dd, yyyy h:mm a")
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a")
|
||||
.format(ZonedDateTime.now().withZoneSameInstant(ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
@@ -115,7 +119,7 @@ public class TimeSkill {
|
||||
name = "now",
|
||||
description = "Get the current date and time in the local time zone")
|
||||
public String now() {
|
||||
return DateTimeFormatter.ofPattern("EEEE, MMMM dd, yyyy h:mm a")
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR + " h:mm a")
|
||||
.format(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
@@ -164,7 +168,7 @@ public class TimeSkill {
|
||||
*/
|
||||
@DefineSKFunction(name = "day", description = "Get the current day of the month")
|
||||
public String day() {
|
||||
return DateTimeFormatter.ofPattern("dd").format(ZonedDateTime.now());
|
||||
return DateTimeFormatter.ofPattern("d").format(ZonedDateTime.now());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,7 +221,7 @@ public class TimeSkill {
|
||||
description = "Get the date of offset from today by a provided number of days")
|
||||
public static String daysAgo(String days) {
|
||||
int offsetDays = Integer.parseInt(days);
|
||||
return DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR)
|
||||
.format(ZonedDateTime.now().minusDays(offsetDays));
|
||||
}
|
||||
|
||||
@@ -241,7 +245,7 @@ public class TimeSkill {
|
||||
currentDate.getDayOfWeek().getDisplayName(TextStyle.FULL, systemLocale);
|
||||
|
||||
if (currentDayName.equalsIgnoreCase(dayName)) {
|
||||
return DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(currentDate);
|
||||
return DateTimeFormatter.ofPattern(DAY_MONTH_DAY_YEAR).format(currentDate);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("dayName is not recognized");
|
||||
|
||||
+6
-11
@@ -1,18 +1,13 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.coreskills;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import com.microsoft.semantickernel.orchestration.ContextVariables;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
|
||||
import reactor.test.StepVerifier;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class FileIOSkillTest {
|
||||
|
||||
@@ -21,7 +16,7 @@ public class FileIOSkillTest {
|
||||
// Create a temporary file with some content
|
||||
String content = "Hello, World!";
|
||||
Path tempFile = Files.createTempFile("test", ".txt");
|
||||
Files.write(tempFile, content.getBytes());
|
||||
Files.write(tempFile, content.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// Create an instance of FileIOSkill
|
||||
FileIOSkill fileIOSkill = new FileIOSkill();
|
||||
@@ -52,7 +47,7 @@ public class FileIOSkillTest {
|
||||
fileIOSkill.writeFileAsync(tempFile.toAbsolutePath().toString(), content, "UTF-8");
|
||||
|
||||
// Read the written file to verify the content
|
||||
String fileContents = new String(Files.readAllBytes(tempFile));
|
||||
String fileContents = new String(Files.readAllBytes(tempFile), StandardCharsets.UTF_8);
|
||||
Assertions.assertEquals(content, fileContents);
|
||||
|
||||
// Delete the temporary file
|
||||
|
||||
+11
-4
@@ -4,10 +4,13 @@ package com.microsoft.semantickernel.coreskills;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.time.*;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Locale;
|
||||
|
||||
@SuppressWarnings("ReturnValueIgnored")
|
||||
public class TimeSkillTest {
|
||||
@@ -37,7 +40,7 @@ public class TimeSkillTest {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.time();
|
||||
assertEquals("09:15:07 AM", result);
|
||||
assertEqualsIgnoreCase("09:15:07 AM", result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +64,7 @@ public class TimeSkillTest {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.now();
|
||||
assertEquals("Sunday, January 12, 2025 9:15 AM", result);
|
||||
assertEqualsIgnoreCase("Sunday, January 12, 2025 9:15 AM", result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +128,10 @@ public class TimeSkillTest {
|
||||
}
|
||||
}
|
||||
|
||||
public void assertEqualsIgnoreCase(String a, String b) {
|
||||
Assertions.assertEquals(a.toUpperCase(Locale.ROOT), b.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHour() {
|
||||
TimeSkill timeSkill = new TimeSkill();
|
||||
@@ -133,7 +140,7 @@ public class TimeSkillTest {
|
||||
mocked.when(ZonedDateTime::now).thenReturn(mockDateTime);
|
||||
|
||||
String result = timeSkill.hour();
|
||||
assertEquals("9 AM", result);
|
||||
assertEqualsIgnoreCase("9 AM", result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,11 @@
|
||||
<artifactId>sequentialplanner-extensions</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.semantickernel.extensions</groupId>
|
||||
<artifactId>actionplanner-extension</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.inject</groupId>
|
||||
|
||||
+83
-32
@@ -9,14 +9,12 @@ import com.microsoft.semantickernel.chatcompletion.ChatCompletion;
|
||||
import com.microsoft.semantickernel.coreskills.SkillImporter;
|
||||
import com.microsoft.semantickernel.exceptions.NotSupportedException;
|
||||
import com.microsoft.semantickernel.exceptions.SkillsNotFoundException;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.memory.MemoryConfiguration;
|
||||
import com.microsoft.semantickernel.memory.MemoryStore;
|
||||
import com.microsoft.semantickernel.memory.NullMemory;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.orchestration.ContextVariables;
|
||||
import com.microsoft.semantickernel.orchestration.DefaultCompletionSKFunction;
|
||||
import com.microsoft.semantickernel.orchestration.RegistrableSkFunction;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.orchestration.*;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
import com.microsoft.semantickernel.skilldefinition.DefaultSkillCollection;
|
||||
import com.microsoft.semantickernel.skilldefinition.FunctionNotFound;
|
||||
@@ -26,15 +24,18 @@ import com.microsoft.semantickernel.templateengine.DefaultPromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DefaultKernel implements Kernel {
|
||||
|
||||
private final KernelConfig kernelConfig;
|
||||
@@ -46,7 +47,7 @@ public class DefaultKernel implements Kernel {
|
||||
public DefaultKernel(
|
||||
KernelConfig kernelConfig,
|
||||
PromptTemplateEngine promptTemplateEngine,
|
||||
SemanticTextMemory memory) {
|
||||
@Nullable SemanticTextMemory memoryStore) {
|
||||
if (kernelConfig == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
@@ -54,13 +55,16 @@ public class DefaultKernel implements Kernel {
|
||||
this.kernelConfig = kernelConfig;
|
||||
this.promptTemplateEngine = promptTemplateEngine;
|
||||
this.defaultSkillCollection = new DefaultSkillCollection();
|
||||
this.memory = memory;
|
||||
|
||||
kernelConfig.getSkills().forEach(this::registerSemanticFunction);
|
||||
if (memoryStore != null) {
|
||||
this.memory = memoryStore.copy();
|
||||
} else {
|
||||
this.memory = new NullMemory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getService(String serviceId, Class<T> clazz) {
|
||||
public <T> T getService(@Nullable String serviceId, Class<T> clazz) {
|
||||
if (TextCompletion.class.isAssignableFrom(clazz)) {
|
||||
Function<Kernel, TextCompletion> factory =
|
||||
kernelConfig.getTextCompletionServiceOrDefault(serviceId);
|
||||
@@ -82,7 +86,7 @@ public class DefaultKernel implements Kernel {
|
||||
|
||||
return (T) factory.apply(this);
|
||||
} else if (EmbeddingGeneration.class.isAssignableFrom(clazz)) {
|
||||
Function<Kernel, EmbeddingGeneration<String,Float>> factory =
|
||||
Function<Kernel, EmbeddingGeneration<String, Float>> factory =
|
||||
kernelConfig.getTextEmbeddingGenerationServiceOrDefault(serviceId);
|
||||
if (factory == null) {
|
||||
throw new KernelException(
|
||||
@@ -91,7 +95,7 @@ public class DefaultKernel implements Kernel {
|
||||
}
|
||||
|
||||
return (T) factory.apply(this);
|
||||
}else {
|
||||
} else {
|
||||
// TODO correct exception
|
||||
throw new NotSupportedException(
|
||||
"The kernel service collection doesn't support the type " + clazz.getName());
|
||||
@@ -104,10 +108,7 @@ public class DefaultKernel implements Kernel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <
|
||||
RequestConfiguration,
|
||||
ContextType extends SKContext<ContextType>,
|
||||
FunctionType extends SKFunction<RequestConfiguration, ContextType>>
|
||||
public <RequestConfiguration, FunctionType extends SKFunction<RequestConfiguration>>
|
||||
FunctionType registerSemanticFunction(FunctionType func) {
|
||||
if (!(func instanceof RegistrableSkFunction)) {
|
||||
throw new RuntimeException("This function does not implement RegistrableSkFunction");
|
||||
@@ -117,6 +118,11 @@ public class DefaultKernel implements Kernel {
|
||||
return func;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKFunction<?> getFunction(String skill, String function) {
|
||||
return defaultSkillCollection.getFunction(skill, function, null);
|
||||
}
|
||||
|
||||
/*
|
||||
/// <inheritdoc/>
|
||||
public SKFunction registerSemanticFunction(
|
||||
@@ -149,7 +155,10 @@ public class DefaultKernel implements Kernel {
|
||||
.map(
|
||||
(entry) -> {
|
||||
return DefaultCompletionSKFunction.createFunction(
|
||||
skillName, entry.getKey(), entry.getValue());
|
||||
skillName,
|
||||
entry.getKey(),
|
||||
entry.getValue(),
|
||||
promptTemplateEngine);
|
||||
})
|
||||
.forEach(this::registerSemanticFunction);
|
||||
|
||||
@@ -163,6 +172,13 @@ public class DefaultKernel implements Kernel {
|
||||
@Override
|
||||
public ReadOnlyFunctionCollection importSkill(
|
||||
Object skillInstance, @Nullable String skillName) {
|
||||
if (skillInstance instanceof String) {
|
||||
throw new KernelException(
|
||||
KernelException.ErrorCodes.FunctionNotAvailable,
|
||||
"Called importSkill with a string argument, it is likely the intention was to"
|
||||
+ " call importSkillFromDirectory");
|
||||
}
|
||||
|
||||
if (skillName == null || skillName.isEmpty()) {
|
||||
skillName = ReadOnlySkillCollection.GlobalSkill;
|
||||
}
|
||||
@@ -203,6 +219,30 @@ public class DefaultKernel implements Kernel {
|
||||
return functions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadOnlyFunctionCollection importSkillFromDirectory(
|
||||
String skillName, String parentDirectory, String skillDirectoryName) {
|
||||
Map<String, SemanticFunctionConfig> skills =
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
parentDirectory, skillDirectoryName, promptTemplateEngine);
|
||||
return importSkill(skillName, skills);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importSkillsFromDirectory(String parentDirectory, String... skillNames) {
|
||||
Arrays.stream(skillNames)
|
||||
.forEach(
|
||||
skill -> {
|
||||
importSkillFromDirectory(skill, parentDirectory, skill);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadOnlyFunctionCollection importSkillFromDirectory(
|
||||
String skillName, String parentDirectory) {
|
||||
return importSkillFromDirectory(skillName, parentDirectory, skillName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PromptTemplateEngine getPromptTemplateEngine() {
|
||||
return promptTemplateEngine;
|
||||
@@ -218,36 +258,47 @@ public class DefaultKernel implements Kernel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SKContext<?>> runAsync(SKFunction<?, ?>... pipeline) {
|
||||
public Mono<SKContext> runAsync(SKFunction<?>... pipeline) {
|
||||
return runAsync(SKBuilders.variables().build(), pipeline);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SKContext<?>> runAsync(String input, SKFunction<?, ?>... pipeline) {
|
||||
public Mono<SKContext> runAsync(String input, SKFunction<?>... pipeline) {
|
||||
return runAsync(SKBuilders.variables().build(input), pipeline);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<SKContext<?>> runAsync(ContextVariables variables, SKFunction<?, ?>... pipeline) {
|
||||
public Mono<SKContext> runAsync(ContextVariables variables, SKFunction<?>... pipeline) {
|
||||
if (pipeline == null || pipeline.length == 0) {
|
||||
throw new SKException("No parameters provided to pipeline");
|
||||
}
|
||||
// TODO: The SemanticTextMemory can be null, but there should be a way to provide it.
|
||||
// Not sure registerMemory is the right way.
|
||||
Mono<SKContext<?>> pipelineBuilder =
|
||||
Mono.just(pipeline[0].buildContext(variables, null, getSkills()));
|
||||
Mono<SKContext> pipelineBuilder =
|
||||
Mono.just(SKBuilders.context().with(variables).with(getSkills()).build());
|
||||
|
||||
for (SKFunction f : Arrays.asList(pipeline)) {
|
||||
pipelineBuilder =
|
||||
pipelineBuilder.flatMap(
|
||||
newContext -> {
|
||||
SKContext context =
|
||||
f.buildContext(
|
||||
newContext.getVariables(),
|
||||
newContext.getSemanticMemory(),
|
||||
newContext.getSkills());
|
||||
return f.invokeAsync(context, null);
|
||||
});
|
||||
pipelineBuilder
|
||||
.switchIfEmpty(
|
||||
Mono.fromCallable(
|
||||
() -> {
|
||||
// Previous pipeline did not produce a result
|
||||
return SKBuilders.context()
|
||||
.with(variables)
|
||||
.with(getSkills())
|
||||
.build();
|
||||
}))
|
||||
.flatMap(
|
||||
newContext -> {
|
||||
SKContext context =
|
||||
SKBuilders.context()
|
||||
.with(newContext.getVariables())
|
||||
.with(newContext.getSemanticMemory())
|
||||
.with(newContext.getSkills())
|
||||
.build();
|
||||
return f.invokeAsync(context, null);
|
||||
});
|
||||
}
|
||||
|
||||
return pipelineBuilder;
|
||||
|
||||
+27
-17
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.ai.AIException;
|
||||
import com.microsoft.semantickernel.builders.FunctionBuilders;
|
||||
import com.microsoft.semantickernel.orchestration.DefaultCompletionSKFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
@@ -12,13 +13,10 @@ import javax.annotation.Nullable;
|
||||
public class SkFunctionBuilders implements FunctionBuilders {
|
||||
public SkFunctionBuilders() {}
|
||||
|
||||
public static final CompletionSKFunction.Builder COMPLETION_BUILDERS =
|
||||
new InternalCompletionBuilder(null);
|
||||
|
||||
private static class InternalCompletionBuilder extends CompletionSKFunction.Builder {
|
||||
private final @Nullable Kernel kernel;
|
||||
private final Kernel kernel;
|
||||
|
||||
private InternalCompletionBuilder(@Nullable Kernel kernel) {
|
||||
private InternalCompletionBuilder(Kernel kernel) {
|
||||
this.kernel = kernel;
|
||||
}
|
||||
|
||||
@@ -37,14 +35,17 @@ public class SkFunctionBuilders implements FunctionBuilders {
|
||||
@Nullable String skillName) {
|
||||
return register(
|
||||
DefaultCompletionSKFunction.createFunction(
|
||||
promptTemplate, config, functionName, skillName));
|
||||
promptTemplate,
|
||||
config,
|
||||
functionName,
|
||||
skillName,
|
||||
kernel.getPromptTemplateEngine()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionSKFunction createFunction(
|
||||
String functionName, SemanticFunctionConfig functionConfig) {
|
||||
return register(
|
||||
DefaultCompletionSKFunction.createFunction(functionName, functionConfig));
|
||||
String prompt, PromptTemplateConfig.CompletionConfig functionConfig) {
|
||||
return createFunction(prompt, null, null, null, functionConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,7 +55,10 @@ public class SkFunctionBuilders implements FunctionBuilders {
|
||||
SemanticFunctionConfig functionConfig) {
|
||||
return register(
|
||||
DefaultCompletionSKFunction.createFunction(
|
||||
skillNameFinal, functionName, functionConfig));
|
||||
skillNameFinal,
|
||||
functionName,
|
||||
functionConfig,
|
||||
kernel.getPromptTemplateEngine()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,19 +82,25 @@ public class SkFunctionBuilders implements FunctionBuilders {
|
||||
@Nullable String skillName,
|
||||
@Nullable String description,
|
||||
PromptTemplateConfig.CompletionConfig completionConfig) {
|
||||
if (kernel == null) {
|
||||
throw new AIException(
|
||||
AIException.ErrorCodes.InvalidConfiguration,
|
||||
"Called builder to create a function that");
|
||||
}
|
||||
|
||||
return register(
|
||||
DefaultCompletionSKFunction.createFunction(
|
||||
prompt, functionName, skillName, description, completionConfig));
|
||||
prompt,
|
||||
functionName,
|
||||
skillName,
|
||||
description,
|
||||
completionConfig,
|
||||
kernel.getPromptTemplateEngine()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionSKFunction.Builder completionBuilders(@Nullable Kernel kernel) {
|
||||
if (kernel == null) {
|
||||
return COMPLETION_BUILDERS;
|
||||
} else {
|
||||
return new InternalCompletionBuilder(kernel);
|
||||
}
|
||||
public CompletionSKFunction.Builder completionBuilders(Kernel kernel) {
|
||||
return new InternalCompletionBuilder(kernel);
|
||||
}
|
||||
}
|
||||
|
||||
+26
-19
@@ -4,17 +4,19 @@ package com.microsoft.semantickernel.memory;
|
||||
import com.microsoft.semantickernel.ai.embeddings.Embedding;
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.exceptions.NotSupportedException;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="ISemanticTextMemory"/>./>.
|
||||
/// </summary>
|
||||
@@ -136,23 +138,28 @@ public class DefaultSemanticTextMemory implements SemanticTextMemory {
|
||||
@Nullable String description,
|
||||
@Nullable String additionalMetadata) {
|
||||
|
||||
return this._storage.doesCollectionExistAsync(collection)
|
||||
.map(exists -> {
|
||||
if (!exists) {
|
||||
return this._storage.createCollectionAsync(collection);
|
||||
}
|
||||
return Mono.empty();
|
||||
})
|
||||
.then(this._embeddingGenerator.generateEmbeddingsAsync(Collections.singletonList(text)))
|
||||
.map(embeddings -> MemoryRecord.referenceRecord(
|
||||
externalId,
|
||||
externalSourceName,
|
||||
description,
|
||||
(Embedding<Float>) embeddings.iterator().next(),
|
||||
additionalMetadata,
|
||||
null,
|
||||
null)
|
||||
)
|
||||
return this._storage
|
||||
.doesCollectionExistAsync(collection)
|
||||
.map(
|
||||
exists -> {
|
||||
if (!exists) {
|
||||
return this._storage.createCollectionAsync(collection);
|
||||
}
|
||||
return Mono.empty();
|
||||
})
|
||||
.then(
|
||||
this._embeddingGenerator.generateEmbeddingsAsync(
|
||||
Collections.singletonList(text)))
|
||||
.map(
|
||||
embeddings ->
|
||||
MemoryRecord.referenceRecord(
|
||||
externalId,
|
||||
externalSourceName,
|
||||
description,
|
||||
(Embedding<Float>) embeddings.iterator().next(),
|
||||
additionalMetadata,
|
||||
null,
|
||||
null))
|
||||
.flatMap(record -> this._storage.upsertAsync(collection, record));
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -3,11 +3,11 @@ package com.microsoft.semantickernel.memory;
|
||||
|
||||
import com.microsoft.semantickernel.ai.EmbeddingVector;
|
||||
import com.microsoft.semantickernel.ai.embeddings.Embedding;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -20,6 +20,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/** A simple volatile memory embeddings store. */
|
||||
public class VolatileMemoryStore implements MemoryStore {
|
||||
|
||||
@@ -159,6 +161,7 @@ public class VolatileMemoryStore implements MemoryStore {
|
||||
return new EmbeddingVector<Number>((List<Number>) list);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryLambda")
|
||||
private static final ToDoubleFunction<Tuple2<MemoryRecord, ? extends Number>>
|
||||
extractSimilarity = tuple -> tuple.getT2().doubleValue();
|
||||
|
||||
@@ -246,6 +249,7 @@ public class VolatileMemoryStore implements MemoryStore {
|
||||
public static class Builder implements MemoryStore.Builder {
|
||||
|
||||
public Builder() {}
|
||||
|
||||
@Override
|
||||
public MemoryStore build() {
|
||||
return new VolatileMemoryStore();
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DefaultCompletionSKContext extends AbstractSKContext<CompletionSKContext>
|
||||
implements CompletionSKContext {
|
||||
|
||||
DefaultCompletionSKContext(ContextVariables variables) {
|
||||
super(variables);
|
||||
}
|
||||
|
||||
public DefaultCompletionSKContext(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills) {
|
||||
super(variables, memory, skills);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletionSKContext getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionSKContext build(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills) {
|
||||
return new DefaultCompletionSKContext(variables, memory, skills);
|
||||
}
|
||||
}
|
||||
+64
-50
@@ -2,19 +2,22 @@
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.semanticfunctions.DefaultPromptTemplate;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
|
||||
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
import com.microsoft.semantickernel.skilldefinition.FunctionView;
|
||||
import com.microsoft.semantickernel.skilldefinition.KernelSkillsSupplier;
|
||||
import com.microsoft.semantickernel.skilldefinition.ParameterView;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -32,10 +35,12 @@ import javax.annotation.Nullable;
|
||||
/// with additional methods required by the kernel.
|
||||
/// </summary>
|
||||
public class DefaultCompletionSKFunction
|
||||
extends DefaultSemanticSKFunction<CompletionRequestSettings, CompletionSKContext>
|
||||
extends DefaultSemanticSKFunction<CompletionRequestSettings>
|
||||
implements CompletionSKFunction {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCompletionSKFunction.class);
|
||||
|
||||
private final SemanticFunctionConfig functionConfig;
|
||||
private SKSemanticAsyncTask<CompletionSKContext> function;
|
||||
private SKSemanticAsyncTask<SKContext> function;
|
||||
private final CompletionRequestSettings requestSettings;
|
||||
|
||||
@Nullable private DefaultTextCompletionSupplier aiService;
|
||||
@@ -107,10 +112,10 @@ public class DefaultCompletionSKFunction
|
||||
* @return Aggregated results
|
||||
*/
|
||||
@Override
|
||||
public Mono<CompletionSKContext> aggregatePartitionedResultsAsync(
|
||||
List<String> partitionedInput, @Nullable CompletionSKContext contextIn) {
|
||||
public Mono<SKContext> aggregatePartitionedResultsAsync(
|
||||
List<String> partitionedInput, @Nullable SKContext contextIn) {
|
||||
|
||||
CompletionSKContext context;
|
||||
SKContext context;
|
||||
if (contextIn == null) {
|
||||
context = buildContext();
|
||||
} else {
|
||||
@@ -119,15 +124,15 @@ public class DefaultCompletionSKFunction
|
||||
|
||||
// Function that takes the current context, updates it with the latest input and invokes the
|
||||
// function
|
||||
BiFunction<Flux<CompletionSKContext>, String, Flux<CompletionSKContext>> executeNextChunk =
|
||||
BiFunction<Flux<SKContext>, String, Flux<SKContext>> executeNextChunk =
|
||||
(contextInput, input) ->
|
||||
contextInput.flatMap(
|
||||
newContext -> {
|
||||
CompletionSKContext updated = newContext.update(input);
|
||||
SKContext updated = newContext.update(input);
|
||||
return invokeAsync(updated, null);
|
||||
});
|
||||
|
||||
Mono<List<CompletionSKContext>> results =
|
||||
Mono<List<SKContext>> results =
|
||||
Flux.fromIterable(partitionedInput)
|
||||
.reduceWith(() -> Flux.just(context), executeNextChunk)
|
||||
.flatMap(Flux::collectList);
|
||||
@@ -140,24 +145,10 @@ public class DefaultCompletionSKFunction
|
||||
.map(context::update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionSKContext buildContext(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills) {
|
||||
return new DefaultCompletionSKContext(variables, memory, skills);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionSKContext buildContext(SKContext toClone) {
|
||||
return new DefaultCompletionSKContext(
|
||||
toClone.getVariables(), toClone.getSemanticMemory(), toClone.getSkills());
|
||||
}
|
||||
|
||||
// Run the semantic function
|
||||
@Override
|
||||
protected Mono<CompletionSKContext> invokeAsyncInternal(
|
||||
CompletionSKContext context, @Nullable CompletionRequestSettings settings) {
|
||||
protected Mono<SKContext> invokeAsyncInternal(
|
||||
SKContext context, @Nullable CompletionRequestSettings settings) {
|
||||
// TODO
|
||||
// this.VerifyIsSemantic();
|
||||
// this.ensureContextHasSkills(context);
|
||||
@@ -188,15 +179,17 @@ public class DefaultCompletionSKFunction
|
||||
this.function =
|
||||
(TextCompletion client,
|
||||
CompletionRequestSettings requestSettings,
|
||||
CompletionSKContext contextInput) -> {
|
||||
CompletionSKContext context = contextInput.copy();
|
||||
SKContext contextInput) -> {
|
||||
SKContext context = contextInput.copy();
|
||||
// TODO
|
||||
// Verify.NotNull(client, "AI LLM backed is empty");
|
||||
return functionConfig
|
||||
.getTemplate()
|
||||
.renderAsync(context, kernel.getPromptTemplateEngine())
|
||||
|
||||
PromptTemplate func = functionConfig.getTemplate();
|
||||
|
||||
return func.renderAsync(context)
|
||||
.flatMapMany(
|
||||
prompt -> {
|
||||
LOGGER.debug("RENDERED PROMPT: \n" + prompt);
|
||||
return client.completeAsync(prompt, requestSettings);
|
||||
})
|
||||
.single()
|
||||
@@ -206,15 +199,13 @@ public class DefaultCompletionSKFunction
|
||||
})
|
||||
.doOnError(
|
||||
ex -> {
|
||||
System.err.println(ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
// TODO
|
||||
/*
|
||||
log ?.LogWarning(ex,
|
||||
"Something went wrong while rendering the semantic function or while executing the text completion. Function: {0}.{1}. Error: {2}",
|
||||
skillName, functionName, ex.Message);
|
||||
context.Fail(ex.Message, ex);
|
||||
*/
|
||||
LOGGER.warn(
|
||||
"Something went wrong while rendering the semantic"
|
||||
+ " function or while executing the text"
|
||||
+ " completion. Function: {}.{}. Error: {}",
|
||||
getSkillName(),
|
||||
getName(),
|
||||
ex.getMessage());
|
||||
});
|
||||
};
|
||||
|
||||
@@ -236,7 +227,8 @@ public class DefaultCompletionSKFunction
|
||||
@Nullable String functionName,
|
||||
@Nullable String skillName,
|
||||
@Nullable String description,
|
||||
PromptTemplateConfig.CompletionConfig completion) {
|
||||
PromptTemplateConfig.CompletionConfig completion,
|
||||
PromptTemplateEngine promptTemplateEngine) {
|
||||
|
||||
if (functionName == null) {
|
||||
functionName = randomFunctionName();
|
||||
@@ -249,14 +241,16 @@ public class DefaultCompletionSKFunction
|
||||
PromptTemplateConfig config =
|
||||
new PromptTemplateConfig(description, "completion", completion);
|
||||
|
||||
return createFunction(promptTemplate, config, functionName, skillName);
|
||||
return createFunction(
|
||||
promptTemplate, config, functionName, skillName, promptTemplateEngine);
|
||||
}
|
||||
|
||||
public static DefaultCompletionSKFunction createFunction(
|
||||
String promptTemplate,
|
||||
PromptTemplateConfig config,
|
||||
String functionName,
|
||||
@Nullable String skillName) {
|
||||
@Nullable String skillName,
|
||||
PromptTemplateEngine promptTemplateEngine) {
|
||||
if (functionName == null) {
|
||||
functionName = randomFunctionName();
|
||||
}
|
||||
@@ -267,17 +261,23 @@ public class DefaultCompletionSKFunction
|
||||
// Verify.ValidSkillName(skillName);
|
||||
// }
|
||||
|
||||
PromptTemplate template = new DefaultPromptTemplate(promptTemplate, config);
|
||||
PromptTemplate template =
|
||||
SKBuilders.promptTemplate()
|
||||
.withPromptTemplateConfig(config)
|
||||
.withPromptTemplate(promptTemplate)
|
||||
.build(promptTemplateEngine);
|
||||
|
||||
// Prepare lambda wrapping AI logic
|
||||
SemanticFunctionConfig functionConfig = new SemanticFunctionConfig(config, template);
|
||||
|
||||
return createFunction(skillName, functionName, functionConfig);
|
||||
return createFunction(skillName, functionName, functionConfig, promptTemplateEngine);
|
||||
}
|
||||
|
||||
public static DefaultCompletionSKFunction createFunction(
|
||||
String functionName, SemanticFunctionConfig functionConfig) {
|
||||
return createFunction(null, functionName, functionConfig);
|
||||
String functionName,
|
||||
SemanticFunctionConfig functionConfig,
|
||||
PromptTemplateEngine promptTemplateEngine) {
|
||||
return createFunction(null, functionName, functionConfig, promptTemplateEngine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -291,7 +291,8 @@ public class DefaultCompletionSKFunction
|
||||
public static DefaultCompletionSKFunction createFunction(
|
||||
@Nullable String skillNameFinal,
|
||||
String functionName,
|
||||
SemanticFunctionConfig functionConfig) {
|
||||
SemanticFunctionConfig functionConfig,
|
||||
PromptTemplateEngine promptTemplateEngine) {
|
||||
String skillName = skillNameFinal;
|
||||
// Verify.NotNull(functionConfig, "Function configuration is empty");
|
||||
if (skillName == null) {
|
||||
@@ -302,9 +303,11 @@ public class DefaultCompletionSKFunction
|
||||
CompletionRequestSettings.fromCompletionConfig(
|
||||
functionConfig.getConfig().getCompletionConfig());
|
||||
|
||||
PromptTemplate promptTemplate = functionConfig.getTemplate();
|
||||
|
||||
return new DefaultCompletionSKFunction(
|
||||
DelegateTypes.ContextSwitchInSKContextOutTaskSKContext,
|
||||
functionConfig.getTemplate().getParameters(),
|
||||
promptTemplate.getParameters(),
|
||||
skillName,
|
||||
functionName,
|
||||
functionConfig.getConfig().getDescription(),
|
||||
@@ -312,4 +315,15 @@ public class DefaultCompletionSKFunction
|
||||
functionConfig,
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionView describe() {
|
||||
return new FunctionView(
|
||||
super.getName(),
|
||||
super.getSkillName(),
|
||||
super.getDescription(),
|
||||
super.getParameters(),
|
||||
true,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
+29
@@ -42,6 +42,7 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextVariables appendToVariable(@NonNull String key, @NonNull String content) {
|
||||
String existing = this.variables.get(key);
|
||||
|
||||
@@ -67,6 +68,7 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
|
||||
// result for the user
|
||||
/// if the pipeline reached the end.</param>
|
||||
/// <returns>The current instance</returns>
|
||||
@Override
|
||||
public ContextVariables update(@NonNull String content) {
|
||||
return setVariable(MAIN_KEY, content);
|
||||
}
|
||||
@@ -84,6 +86,7 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
|
||||
// data.</param>
|
||||
/// <returns>The current instance</returns>
|
||||
|
||||
@Override
|
||||
public DefaultContextVariables update(@NonNull ContextVariables newData, boolean merge) {
|
||||
/*
|
||||
// If requested, discard old data and keep only the new one.
|
||||
@@ -99,11 +102,37 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextVariables remove(String key) {
|
||||
variables.remove(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WritableContextVariables writableClone() {
|
||||
return new DefaultContextVariables(variables);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getInput() {
|
||||
return get(MAIN_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return variables.entrySet().stream()
|
||||
.reduce(
|
||||
"",
|
||||
(str, entry) ->
|
||||
str
|
||||
+ System.lineSeparator()
|
||||
+ entry.getKey()
|
||||
+ ": "
|
||||
+ entry.getValue(),
|
||||
(a, b) -> a + b);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String get(String key) {
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.memory.NullMemory;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DefaultSKContext extends AbstractSKContext {
|
||||
public DefaultSKContext(ContextVariables variables) {
|
||||
super(variables);
|
||||
}
|
||||
|
||||
public DefaultSKContext(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skillCollection) {
|
||||
super(variables, memory, skillCollection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SKContext getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKContext build(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skillCollection) {
|
||||
return new DefaultSKContext(variables, memory, skillCollection);
|
||||
}
|
||||
|
||||
public static class Builder implements SKContext.Builder {
|
||||
|
||||
private ContextVariables variables;
|
||||
private ReadOnlySkillCollection skills;
|
||||
private SemanticTextMemory memory = NullMemory.getInstance();
|
||||
|
||||
@Override
|
||||
public SKContext build(ReadOnlySkillCollection skills) {
|
||||
return new DefaultSKContext(
|
||||
SKBuilders.variables().build(), NullMemory.getInstance(), skills);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKContext build() {
|
||||
if (variables == null) {
|
||||
variables = SKBuilders.variables().build();
|
||||
}
|
||||
return new DefaultSKContext(variables, memory, skills);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKContext build(Class<? extends SKContext> clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKContext.Builder with(ContextVariables variables) {
|
||||
this.variables = variables;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKContext.Builder with(@Nullable ReadOnlySkillCollection skills) {
|
||||
if (skills != null) {
|
||||
this.skills = skills;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKContext.Builder with(@Nullable SemanticTextMemory memory) {
|
||||
if (memory != null) {
|
||||
this.memory = memory.copy();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKContext.Builder clone(SKContext context) {
|
||||
return with(context.getVariables())
|
||||
.with(context.getSkills())
|
||||
.with(context.getSemanticMemory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKContext build(Kernel kernel) {
|
||||
if (memory == null) {
|
||||
memory = kernel.getMemory();
|
||||
}
|
||||
if (skills == null) {
|
||||
skills = kernel.getSkills();
|
||||
}
|
||||
if (variables == null) {
|
||||
variables = SKBuilders.variables().build();
|
||||
}
|
||||
return build();
|
||||
}
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.orchestration;
|
||||
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.memory.NullMemory;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DefaultSemanticSKContext extends AbstractSKContext<SemanticSKContext>
|
||||
implements SemanticSKContext {
|
||||
public DefaultSemanticSKContext(ContextVariables variables) {
|
||||
super(variables);
|
||||
}
|
||||
|
||||
public DefaultSemanticSKContext(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skillCollection) {
|
||||
super(variables, memory, skillCollection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SemanticSKContext getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SemanticSKContext build(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skillCollection) {
|
||||
return new DefaultSemanticSKContext(variables, memory, skillCollection);
|
||||
}
|
||||
|
||||
public static class Builder implements SKContext.Builder {
|
||||
|
||||
@Override
|
||||
public SKContext build(ReadOnlySkillCollection skills) {
|
||||
return new DefaultSemanticSKContext(
|
||||
SKBuilders.variables().build(), NullMemory.getInstance(), skills);
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
-11
@@ -18,10 +18,9 @@ import javax.annotation.Nullable;
|
||||
// cref="Action"/>,
|
||||
/// with additional methods required by the kernel.
|
||||
/// </summary>
|
||||
public abstract class DefaultSemanticSKFunction<
|
||||
RequestConfiguration, ContextType extends SKContext<ContextType>>
|
||||
extends AbstractSkFunction<RequestConfiguration, ContextType>
|
||||
implements SKFunction<RequestConfiguration, ContextType> {
|
||||
public abstract class DefaultSemanticSKFunction<RequestConfiguration>
|
||||
extends AbstractSkFunction<RequestConfiguration>
|
||||
implements SKFunction<RequestConfiguration> {
|
||||
|
||||
public DefaultSemanticSKFunction(
|
||||
DelegateTypes delegateType,
|
||||
@@ -34,20 +33,25 @@ public abstract class DefaultSemanticSKFunction<
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ContextType> invokeAsync(
|
||||
String input, @Nullable ContextType context, @Nullable RequestConfiguration settings) {
|
||||
public Mono<SKContext> invokeAsync(
|
||||
@Nullable String input,
|
||||
@Nullable SKContext context,
|
||||
@Nullable RequestConfiguration settings) {
|
||||
if (context == null) {
|
||||
assertSkillSupplierRegistered();
|
||||
context =
|
||||
buildContext(
|
||||
SKBuilders.variables().build(),
|
||||
NullMemory.getInstance(),
|
||||
super.getSkillsSupplier().get());
|
||||
SKBuilders.context()
|
||||
.with(SKBuilders.variables().build())
|
||||
.with(NullMemory.getInstance())
|
||||
.with(super.getSkillsSupplier().get())
|
||||
.build();
|
||||
} else {
|
||||
context = context.copy();
|
||||
}
|
||||
|
||||
context = context.update(input);
|
||||
if (input != null) {
|
||||
context = context.update(input);
|
||||
}
|
||||
|
||||
return this.invokeAsync(context, settings);
|
||||
}
|
||||
|
||||
+94
-40
@@ -5,7 +5,7 @@ import static com.microsoft.semantickernel.skilldefinition.annotations.SKFunctio
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.ai.AIException;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.skilldefinition.FunctionView;
|
||||
import com.microsoft.semantickernel.skilldefinition.KernelSkillsSupplier;
|
||||
import com.microsoft.semantickernel.skilldefinition.ParameterView;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
|
||||
@@ -17,6 +17,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -32,15 +33,15 @@ import javax.annotation.Nullable;
|
||||
// cref="Action"/>,
|
||||
/// with additional methods required by the kernel.
|
||||
/// </summary>
|
||||
public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext> {
|
||||
public class NativeSKFunction extends AbstractSkFunction<Void> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(NativeSKFunction.class);
|
||||
|
||||
private final SKNativeTask<SemanticSKContext> function;
|
||||
private final SKNativeTask<SKContext> function;
|
||||
|
||||
public NativeSKFunction(
|
||||
AbstractSkFunction.DelegateTypes delegateType,
|
||||
SKNativeTask<SemanticSKContext> delegateFunction,
|
||||
SKNativeTask<SKContext> delegateFunction,
|
||||
List<ParameterView> parameters,
|
||||
String skillName,
|
||||
String functionName,
|
||||
@@ -56,6 +57,17 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
this.function = delegateFunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionView describe() {
|
||||
return new FunctionView(
|
||||
super.getName(),
|
||||
super.getSkillName(),
|
||||
super.getDescription(),
|
||||
super.getParameters(),
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Void> getType() {
|
||||
return Void.class;
|
||||
@@ -69,7 +81,7 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
private static class MethodDetails {
|
||||
public final boolean hasSkFunctionAttribute;
|
||||
public final AbstractSkFunction.DelegateTypes type;
|
||||
public final SKNativeTask<SemanticSKContext> function;
|
||||
public final SKNativeTask<SKContext> function;
|
||||
public final List<ParameterView> parameters;
|
||||
public final String name;
|
||||
public final String description;
|
||||
@@ -77,7 +89,7 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
private MethodDetails(
|
||||
boolean hasSkFunctionAttribute,
|
||||
AbstractSkFunction.DelegateTypes type,
|
||||
SKNativeTask<SemanticSKContext> function,
|
||||
SKNativeTask<SKContext> function,
|
||||
List<ParameterView> parameters,
|
||||
String name,
|
||||
String description) {
|
||||
@@ -116,24 +128,9 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
kernelSkillsSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SemanticSKContext buildContext(
|
||||
ContextVariables variables,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable ReadOnlySkillCollection skills) {
|
||||
return new DefaultSemanticSKContext(variables, memory, skills);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SemanticSKContext buildContext(SKContext toClone) {
|
||||
return new DefaultSemanticSKContext(
|
||||
toClone.getVariables(), toClone.getSemanticMemory(), toClone.getSkills());
|
||||
}
|
||||
|
||||
// Run the native function
|
||||
@Override
|
||||
protected Mono<SemanticSKContext> invokeAsyncInternal(
|
||||
SemanticSKContext context, @Nullable Void settings) {
|
||||
protected Mono<SKContext> invokeAsyncInternal(SKContext context, @Nullable Void settings) {
|
||||
return this.function.run(context);
|
||||
}
|
||||
|
||||
@@ -142,7 +139,6 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
// Verify.NotNull(methodSignature, "Method is NULL");
|
||||
|
||||
// String name = methodSignature.getName();
|
||||
ArrayList<ParameterView> parameters = new ArrayList<>();
|
||||
|
||||
boolean hasSkFunctionAttribute =
|
||||
methodSignature.isAnnotationPresent(DefineSKFunction.class);
|
||||
@@ -151,8 +147,7 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
throw new RuntimeException("method is not annotated with DefineSKFunction");
|
||||
}
|
||||
DelegateTypes type = getDelegateType(methodSignature);
|
||||
SKNativeTask<SemanticSKContext> function =
|
||||
getFunction(methodSignature, methodContainerInstance);
|
||||
SKNativeTask<SKContext> function = getFunction(methodSignature, methodContainerInstance);
|
||||
|
||||
// boolean hasStringParam =
|
||||
// Arrays.asList(methodSignature.getGenericParameterTypes()).contains(String.class);
|
||||
@@ -165,18 +160,61 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
|
||||
String description = methodSignature.getAnnotation(DefineSKFunction.class).description();
|
||||
|
||||
List<ParameterView> parameters = getParameters(methodSignature);
|
||||
|
||||
return new MethodDetails(
|
||||
hasSkFunctionAttribute, type, function, parameters, name, description);
|
||||
}
|
||||
|
||||
private static SKNativeTask<SemanticSKContext> getFunction(Method method, Object instance) {
|
||||
private static List<ParameterView> getParameters(Method method) {
|
||||
|
||||
List<ParameterView> params =
|
||||
Arrays.stream(method.getParameters())
|
||||
.filter(
|
||||
parameter ->
|
||||
parameter.isAnnotationPresent(SKFunctionParameters.class)
|
||||
|| parameter.isAnnotationPresent(
|
||||
SKFunctionInputAttribute.class))
|
||||
.map(
|
||||
parameter -> {
|
||||
if (parameter.isAnnotationPresent(SKFunctionParameters.class)) {
|
||||
SKFunctionParameters annotation =
|
||||
parameter.getAnnotation(SKFunctionParameters.class);
|
||||
return new ParameterView(
|
||||
annotation.name(),
|
||||
annotation.description(),
|
||||
annotation.defaultValue());
|
||||
} else {
|
||||
return new ParameterView("input");
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
HashSet<ParameterView> out = new HashSet<>(params);
|
||||
|
||||
boolean hasInput = params.stream().anyMatch(p -> p.getName().equals("input"));
|
||||
|
||||
if (!hasInput) {
|
||||
List<ParameterView> inputArgs =
|
||||
determineInputArgs(method).stream()
|
||||
.map(
|
||||
parameter -> {
|
||||
return new ParameterView("input");
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
out.addAll(inputArgs);
|
||||
}
|
||||
|
||||
return new ArrayList<>(out);
|
||||
}
|
||||
|
||||
private static SKNativeTask<SKContext> getFunction(Method method, Object instance) {
|
||||
return (contextInput) -> {
|
||||
SemanticSKContext context = contextInput.copy();
|
||||
SKContext context = contextInput.copy();
|
||||
|
||||
Set<Parameter> inputArgs = determineInputArgs(method);
|
||||
|
||||
try {
|
||||
|
||||
List<Object> args =
|
||||
Arrays.stream(method.getParameters())
|
||||
.map(
|
||||
@@ -209,11 +247,26 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
return Mono.error(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
mono = Mono.just(method.invoke(instance, args.toArray()));
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
mono =
|
||||
Mono.defer(
|
||||
() -> {
|
||||
return Mono.fromCallable(
|
||||
() -> {
|
||||
try {
|
||||
Object result =
|
||||
method.invoke(
|
||||
instance,
|
||||
args.toArray());
|
||||
|
||||
return result;
|
||||
} catch (IllegalAccessException
|
||||
| InvocationTargetException e) {
|
||||
throw new RuntimeException(
|
||||
e.getCause());
|
||||
}
|
||||
})
|
||||
.subscribeOn(Schedulers.boundedElastic());
|
||||
});
|
||||
}
|
||||
|
||||
return mono.map(
|
||||
@@ -231,10 +284,7 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
}
|
||||
|
||||
private static String getArgumentValue(
|
||||
Method method,
|
||||
SemanticSKContext context,
|
||||
Parameter parameter,
|
||||
Set<Parameter> inputArgs) {
|
||||
Method method, SKContext context, Parameter parameter, Set<Parameter> inputArgs) {
|
||||
String variableName = getGetVariableName(parameter);
|
||||
|
||||
String arg = context.getVariables().get(variableName);
|
||||
@@ -242,12 +292,12 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
// If this is bound to input get the input value
|
||||
if (inputArgs.contains(parameter)) {
|
||||
String input = context.getVariables().get(ContextVariables.MAIN_KEY);
|
||||
if (input != null && !input.isEmpty()) {
|
||||
if (input != null) {
|
||||
arg = input;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg == null || arg.isEmpty()) {
|
||||
if (arg == null) {
|
||||
SKFunctionParameters annotation =
|
||||
parameter.getAnnotation(SKFunctionParameters.class);
|
||||
if (annotation != null) {
|
||||
@@ -256,7 +306,7 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
}
|
||||
}
|
||||
|
||||
if ((arg == null || arg.isEmpty()) && variableName.matches("arg\\d")) {
|
||||
if (arg == null && variableName.matches("arg\\d")) {
|
||||
LOGGER.warn(
|
||||
"For the function "
|
||||
+ method.getDeclaringClass().getName()
|
||||
@@ -366,6 +416,10 @@ public class NativeSKFunction extends AbstractSkFunction<Void, SemanticSKContext
|
||||
return AbstractSkFunction.DelegateTypes.OutString;
|
||||
}
|
||||
|
||||
if (method.getReturnType().getName().equals("void")) {
|
||||
return DelegateTypes.Void;
|
||||
}
|
||||
|
||||
if (method.getReturnType().equals(Mono.class)) {
|
||||
return AbstractSkFunction.DelegateTypes.InSKContextOutTaskString;
|
||||
}
|
||||
|
||||
+64
-8
@@ -4,11 +4,17 @@ package com.microsoft.semantickernel.semanticfunctions;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.ParameterView;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.templateengine.blocks.BlockTypes;
|
||||
import com.microsoft.semantickernel.templateengine.blocks.VarBlock;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/// <summary>
|
||||
/// Prompt template.
|
||||
@@ -16,27 +22,77 @@ import java.util.List;
|
||||
public class DefaultPromptTemplate implements PromptTemplate {
|
||||
private final String promptTemplate;
|
||||
private final PromptTemplateConfig config;
|
||||
private final PromptTemplateEngine templateEngine;
|
||||
|
||||
public DefaultPromptTemplate(String promptTemplate, PromptTemplateConfig config) {
|
||||
public DefaultPromptTemplate(
|
||||
String promptTemplate,
|
||||
PromptTemplateConfig config,
|
||||
PromptTemplateEngine templateEngine) {
|
||||
this.promptTemplate = promptTemplate;
|
||||
this.config = config;
|
||||
this.templateEngine = templateEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ParameterView> getParameters() {
|
||||
return new ArrayList<>();
|
||||
// Parameters from config.json
|
||||
List<ParameterView> result =
|
||||
this.config.getInput().getParameters().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(
|
||||
p ->
|
||||
new ParameterView(
|
||||
p.getName(),
|
||||
p.getDescription(),
|
||||
p.getDefaultValue()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<String> seen =
|
||||
result.stream().map(ParameterView::getName).collect(Collectors.toList());
|
||||
|
||||
List<VarBlock> listFromTemplate =
|
||||
templateEngine.extractBlocks(this.promptTemplate).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(x -> x.getType() == BlockTypes.Variable)
|
||||
.map(x -> (VarBlock) x)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<ParameterView> newParams =
|
||||
listFromTemplate.stream()
|
||||
.filter(x -> !seen.contains(x.getName()))
|
||||
.map(x -> new ParameterView(x.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Stream.concat(result.stream(), newParams.stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<String> renderAsync(
|
||||
SKContext executionContext, PromptTemplateEngine promptTemplateEngine) {
|
||||
return promptTemplateEngine.renderAsync(this.promptTemplate, executionContext);
|
||||
public Mono<String> renderAsync(SKContext executionContext) {
|
||||
return templateEngine.renderAsync(this.promptTemplate, executionContext);
|
||||
}
|
||||
|
||||
public static final class Builder extends PromptTemplate.Builder {
|
||||
@Nullable private String promptTemplate = null;
|
||||
@Nullable private PromptTemplateConfig config = null;
|
||||
|
||||
@Override
|
||||
public PromptTemplate build(String promptTemplate, PromptTemplateConfig config) {
|
||||
return new DefaultPromptTemplate(promptTemplate, config);
|
||||
public PromptTemplate build(PromptTemplateEngine promptTemplateEngine) {
|
||||
if (promptTemplate == null || config == null)
|
||||
throw new IllegalStateException(
|
||||
"PromptTemplate and PromptTemplateConfig must be set");
|
||||
return new DefaultPromptTemplate(promptTemplate, config, promptTemplateEngine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder withPromptTemplate(String promptTemplate) {
|
||||
this.promptTemplate = promptTemplate;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder withPromptTemplateConfig(PromptTemplateConfig config) {
|
||||
this.config = config;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-14
@@ -2,6 +2,7 @@
|
||||
package com.microsoft.semantickernel.skilldefinition;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
@@ -22,7 +23,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.computeIfAbsent(null, mappingFunction);
|
||||
}
|
||||
return super.computeIfAbsent(key.toLowerCase(), mappingFunction);
|
||||
return super.computeIfAbsent(key.toLowerCase(Locale.ROOT), mappingFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -31,7 +32,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.computeIfPresent(null, remappingFunction);
|
||||
}
|
||||
return super.computeIfPresent(key.toLowerCase(), remappingFunction);
|
||||
return super.computeIfPresent(key.toLowerCase(Locale.ROOT), remappingFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,7 +41,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.compute(null, remappingFunction);
|
||||
}
|
||||
return super.compute(key.toLowerCase(), remappingFunction);
|
||||
return super.compute(key.toLowerCase(Locale.ROOT), remappingFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,7 +49,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.containsKey(null);
|
||||
}
|
||||
return super.containsKey(((String) key).toLowerCase());
|
||||
return super.containsKey(((String) key).toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,7 +57,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.get(null);
|
||||
}
|
||||
return super.get(((String) key).toLowerCase());
|
||||
return super.get(((String) key).toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,7 +65,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.getOrDefault(null, defaultValue);
|
||||
}
|
||||
return super.getOrDefault(((String) key).toLowerCase(), defaultValue);
|
||||
return super.getOrDefault(((String) key).toLowerCase(Locale.ROOT), defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,7 +74,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.merge(null, value, remappingFunction);
|
||||
}
|
||||
return super.merge(key.toLowerCase(), value, remappingFunction);
|
||||
return super.merge(key.toLowerCase(Locale.ROOT), value, remappingFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,7 +82,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.put(null, value);
|
||||
}
|
||||
return super.put(key.toLowerCase(), value);
|
||||
return super.put(key.toLowerCase(Locale.ROOT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,7 +91,8 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
m.entrySet().stream()
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
key -> key.getKey().toLowerCase(), Entry::getValue)));
|
||||
key -> key.getKey().toLowerCase(Locale.ROOT),
|
||||
Entry::getValue)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,7 +100,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.putIfAbsent(null, value);
|
||||
}
|
||||
return super.putIfAbsent(key.toLowerCase(), value);
|
||||
return super.putIfAbsent(key.toLowerCase(Locale.ROOT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,7 +108,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.remove(null, value);
|
||||
}
|
||||
return super.remove(((String) key).toLowerCase(), value);
|
||||
return super.remove(((String) key).toLowerCase(Locale.ROOT), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,7 +116,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.remove(null);
|
||||
}
|
||||
return super.remove(((String) key).toLowerCase());
|
||||
return super.remove(((String) key).toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,7 +125,7 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.replace(null, oldValue, newValue);
|
||||
}
|
||||
return super.replace(key.toLowerCase(), oldValue, newValue);
|
||||
return super.replace(key.toLowerCase(Locale.ROOT), oldValue, newValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,6 +133,6 @@ public class CaseInsensitiveMap<T> extends HashMap<String, T> {
|
||||
if (key == null) {
|
||||
return super.replace(null, value);
|
||||
}
|
||||
return super.replace(key.toLowerCase(), value);
|
||||
return super.replace(key.toLowerCase(Locale.ROOT), value);
|
||||
}
|
||||
}
|
||||
|
||||
+18
-9
@@ -4,11 +4,11 @@ package com.microsoft.semantickernel.skilldefinition;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/// <summary>
|
||||
@@ -77,16 +77,16 @@ public class DefaultSkillCollection implements ReadOnlySkillCollection {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T extends SKFunction<?, ?>> T getFunction(
|
||||
String funName, @Nonnull Class<T> functionClazz) {
|
||||
public <T extends SKFunction<?>> T getFunction(
|
||||
String funName, @Nullable Class<T> functionClazz) {
|
||||
return getFunction(GlobalSkill, funName, functionClazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T extends SKFunction<?, ?>> T getFunction(
|
||||
String skillName, String funName, Class<T> functionClazz) {
|
||||
FunctionCollection skills = skillCollection.get(skillName.toLowerCase());
|
||||
public <T extends SKFunction<?>> T getFunction(
|
||||
String skillName, String funName, @Nullable Class<T> functionClazz) {
|
||||
FunctionCollection skills = skillCollection.get(skillName.toLowerCase(Locale.ROOT));
|
||||
if (skills == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class DefaultSkillCollection implements ReadOnlySkillCollection {
|
||||
@Nullable
|
||||
@Override
|
||||
public FunctionCollection getFunctions(String skillName) {
|
||||
return skillCollection.get(skillName.toLowerCase());
|
||||
return skillCollection.get(skillName.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,6 +104,15 @@ public class DefaultSkillCollection implements ReadOnlySkillCollection {
|
||||
return getFunction(functionName, SKFunction.class) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFunction(String skillName, String functionName) {
|
||||
FunctionCollection skills = skillCollection.get(skillName.toLowerCase(Locale.ROOT));
|
||||
if (skills == null) {
|
||||
return false;
|
||||
}
|
||||
return skills.getFunction(functionName) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@CheckReturnValue
|
||||
public ReadOnlySkillCollection copy() {
|
||||
@@ -121,10 +130,10 @@ public class DefaultSkillCollection implements ReadOnlySkillCollection {
|
||||
.forEach(
|
||||
entry -> {
|
||||
FunctionCollection existing =
|
||||
skillCollection.get(entry.getKey().toLowerCase());
|
||||
skillCollection.get(entry.getKey().toLowerCase(Locale.ROOT));
|
||||
if (existing == null) {
|
||||
skillCollection.put(
|
||||
entry.getKey().toLowerCase(),
|
||||
entry.getKey().toLowerCase(Locale.ROOT),
|
||||
new FunctionCollection(entry.getValue()));
|
||||
} else {
|
||||
existing.merge(new FunctionCollection(entry.getValue()));
|
||||
|
||||
+14
-16
@@ -4,10 +4,7 @@ package com.microsoft.semantickernel.skilldefinition;
|
||||
import com.microsoft.semantickernel.exceptions.SkillsNotFoundException;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
@@ -15,21 +12,22 @@ import javax.annotation.Nullable;
|
||||
|
||||
/** A collection of functions. */
|
||||
public class FunctionCollection implements ReadOnlyFunctionCollection {
|
||||
private final CaseInsensitiveMap<SKFunction<?, ?>> functionCollection;
|
||||
private final CaseInsensitiveMap<SKFunction<?>> functionCollection;
|
||||
|
||||
private final String skillName;
|
||||
|
||||
private FunctionCollection(String skillName, Map<String, SKFunction<?, ?>> functionCollection) {
|
||||
private FunctionCollection(String skillName, Map<String, SKFunction<?>> functionCollection) {
|
||||
this.functionCollection = new CaseInsensitiveMap<>(functionCollection);
|
||||
this.skillName = skillName;
|
||||
}
|
||||
|
||||
public FunctionCollection(
|
||||
String skillName, List<? extends SKFunction<?, ?>> functionCollection) {
|
||||
public FunctionCollection(String skillName, List<? extends SKFunction<?>> functionCollection) {
|
||||
this(
|
||||
skillName,
|
||||
functionCollection.stream()
|
||||
.collect(Collectors.toMap(it -> it.getName().toLowerCase(), it -> it)));
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
it -> it.getName().toLowerCase(Locale.ROOT), it -> it)));
|
||||
}
|
||||
|
||||
public FunctionCollection(String skillName) {
|
||||
@@ -40,7 +38,7 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
|
||||
public FunctionCollection(ReadOnlyFunctionCollection value) {
|
||||
this.skillName = value.getSkillName();
|
||||
this.functionCollection =
|
||||
new CaseInsensitiveMap<SKFunction<?, ?>>(
|
||||
new CaseInsensitiveMap<SKFunction<?>>(
|
||||
Collections.unmodifiableMap(
|
||||
value.getAll().stream()
|
||||
.collect(Collectors.toMap(SKFunction::getName, it -> it))));
|
||||
@@ -52,8 +50,8 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SKFunction<?, ?> getFunction(String functionName) {
|
||||
SKFunction<?, ?> func = functionCollection.get(functionName.toLowerCase());
|
||||
public SKFunction<?> getFunction(String functionName) {
|
||||
SKFunction<?> func = functionCollection.get(functionName.toLowerCase(Locale.ROOT));
|
||||
if (func == null) {
|
||||
throw new FunctionNotFound(functionName);
|
||||
}
|
||||
@@ -71,7 +69,7 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
|
||||
*/
|
||||
@Override
|
||||
public <T extends SKFunction> T getFunction(String functionName, @Nullable Class<T> clazz) {
|
||||
SKFunction<?, ?> func = getFunction(functionName);
|
||||
SKFunction<?> func = getFunction(functionName);
|
||||
if (clazz == null) {
|
||||
return (T) func;
|
||||
}
|
||||
@@ -99,7 +97,7 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
|
||||
* @return An unmodifiable list of all functions
|
||||
*/
|
||||
@Override
|
||||
public List<SKFunction<?, ?>> getAll() {
|
||||
public List<SKFunction<?>> getAll() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(functionCollection.values()));
|
||||
}
|
||||
|
||||
@@ -110,8 +108,8 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
|
||||
* @param functionInstance
|
||||
* @return Collection for fluent callse
|
||||
*/
|
||||
public FunctionCollection put(String functionName, SKFunction<?, ?> functionInstance) {
|
||||
this.functionCollection.put(functionName.toLowerCase(), functionInstance);
|
||||
public FunctionCollection put(String functionName, SKFunction<?> functionInstance) {
|
||||
this.functionCollection.put(functionName.toLowerCase(Locale.ROOT), functionInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -35,11 +35,11 @@ public class DefaultPromptTemplateEngine implements PromptTemplateEngine {
|
||||
tokenizer = new TemplateTokenizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Block> extractBlocks(String templateText) {
|
||||
return extractBlocks(templateText, true);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<Block> extractBlocks(String templateText, boolean validate) {
|
||||
// TODO
|
||||
// this._log.LogTrace("Extracting blocks from template: {0}", templateText);
|
||||
|
||||
+10
-11
@@ -12,12 +12,13 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.annotation.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class CodeBlock extends Block implements CodeRendering {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CodeBlock.class);
|
||||
@@ -28,11 +29,6 @@ public final class CodeBlock extends Block implements CodeRendering {
|
||||
this.tokens = Collections.unmodifiableList(tokens);
|
||||
}
|
||||
|
||||
public CodeBlock(String content) {
|
||||
super(content, BlockTypes.Code);
|
||||
this.tokens = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
Optional<Block> invalid = tokens.stream().filter(token -> !token.isValid()).findFirst();
|
||||
@@ -63,7 +59,6 @@ public final class CodeBlock extends Block implements CodeRendering {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Mono<String> renderCodeAsync(SKContext context) {
|
||||
if (!this.isValid()) {
|
||||
throw new TemplateException(TemplateException.ErrorCodes.SyntaxError);
|
||||
@@ -79,9 +74,13 @@ public final class CodeBlock extends Block implements CodeRendering {
|
||||
|
||||
case FunctionId:
|
||||
return this.renderFunctionCallAsync((FunctionIdBlock) this.tokens.get(0), context);
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unknown type");
|
||||
case Undefined:
|
||||
case Text:
|
||||
case Code:
|
||||
default:
|
||||
throw new RuntimeException("Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<String> renderFunctionCallAsync(FunctionIdBlock fBlock, SKContext context) {
|
||||
@@ -115,14 +114,14 @@ public final class CodeBlock extends Block implements CodeRendering {
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SKFunction getFunctionFromSkillCollection(
|
||||
ReadOnlySkillCollection skills, FunctionIdBlock fBlock) {
|
||||
String skillName = fBlock.getSkillName();
|
||||
// Function in the global skill
|
||||
if ((skillName == null || skillName.isEmpty())
|
||||
&& skills.hasFunction(fBlock.getFunctionName())) {
|
||||
SKFunction<?, ?> function =
|
||||
skills.getFunction(fBlock.getFunctionName(), SKFunction.class);
|
||||
SKFunction<?> function = skills.getFunction(fBlock.getFunctionName(), SKFunction.class);
|
||||
return function;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user