Skip to content

Commit 93c0844

Browse files
author
Milder Hernandez Cagua
committed
Merge branch 'main' of https://github.com/microsoft/semantic-kernel-java into sqlite
2 parents 7c47812 + a4d38e9 commit 93c0844

60 files changed

Lines changed: 1293 additions & 87 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
# 1.3.0
2+
3+
- Added support for Json Schema to Open AI Chat Completions
4+
- Upgraded to openai sdk 1.0.0-beta.11
5+
- Added convenience method `FunctionInvocation.withResultTypeAutoConversion` which sets the return type and registers a
6+
type converter based on Jackson for the return type.
7+
8+
### Bug Fixes
9+
10+
- Fixed type converters not being passed on to be used in tool invocations
11+
12+
### Breaking Changes
13+
14+
- To support the new Json Schema feature, ResponseFormat has changed from an enum to a class.
15+
116
# 1.2.2
217

318
- Fix bug in `FunctionInvocation` not using per-invocation type conversion when calling `withResultType`.

aiservices/google/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>com.microsoft.semantic-kernel</groupId>
66
<artifactId>semantickernel-parent</artifactId>
7-
<version>1.2.3-SNAPSHOT</version>
7+
<version>1.3.0-SNAPSHOT</version>
88
<relativePath>../../pom.xml</relativePath>
99
</parent>
1010

aiservices/huggingface/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<parent>
77
<groupId>com.microsoft.semantic-kernel</groupId>
88
<artifactId>semantickernel-parent</artifactId>
9-
<version>1.2.3-SNAPSHOT</version>
9+
<version>1.3.0-SNAPSHOT</version>
1010
<relativePath>../../pom.xml</relativePath>
1111
</parent>
1212

aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
package com.microsoft.semantickernel.aiservices.huggingface.services;
33

44
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
5+
import com.microsoft.semantickernel.orchestration.responseformat.ResponseFormat;
56
import java.util.List;
67
import java.util.Map;
78
import java.util.Objects;
@@ -38,7 +39,7 @@ public HuggingFacePromptExecutionSettings(PromptExecutionSettings copy) {
3839
copy.getUser(),
3940
copy.getStopSequences(),
4041
copy.getTokenSelectionBiases(),
41-
copy.getResponseFormat() == null ? null : copy.getResponseFormat().toString());
42+
copy.getResponseFormat() == null ? null : copy.getResponseFormat());
4243
this.topK = null;
4344
this.repetitionPenalty = null;
4445
this.maxTime = null;
@@ -78,7 +79,7 @@ public HuggingFacePromptExecutionSettings(
7879
String user,
7980
@Nullable List<String> stopSequences,
8081
@Nullable Map<Integer, Integer> tokenSelectionBiases,
81-
@Nullable String responseFormat,
82+
@Nullable ResponseFormat responseFormat,
8283
@Nullable Integer topK,
8384
@Nullable Double repetitionPenalty,
8485
@Nullable Double maxTime,
@@ -119,7 +120,7 @@ public static HuggingFacePromptExecutionSettings fromExecutionSettings(
119120
promptExecutionSettings.getStopSequences(),
120121
promptExecutionSettings.getTokenSelectionBiases(),
121122
promptExecutionSettings.getResponseFormat() != null
122-
? promptExecutionSettings.getResponseFormat().toString()
123+
? promptExecutionSettings.getResponseFormat()
123124
: null,
124125
null,
125126
null,

aiservices/openai/pom.xml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<?xml version="1.0" encoding="UTF-8" ?>
22

3-
<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">
3+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
45
<modelVersion>4.0.0</modelVersion>
56

67
<parent>
78
<groupId>com.microsoft.semantic-kernel</groupId>
89
<artifactId>semantickernel-parent</artifactId>
9-
<version>1.2.3-SNAPSHOT</version>
10+
<version>1.3.0-SNAPSHOT</version>
1011
<relativePath>../../pom.xml</relativePath>
1112
</parent>
1213

@@ -55,6 +56,17 @@
5556
<artifactId>mockito-core</artifactId>
5657
<scope>test</scope>
5758
</dependency>
59+
60+
<dependency>
61+
<groupId>com.github.victools</groupId>
62+
<artifactId>jsonschema-generator</artifactId>
63+
<optional>true</optional>
64+
</dependency>
65+
<dependency>
66+
<groupId>com.github.victools</groupId>
67+
<artifactId>jsonschema-module-jackson</artifactId>
68+
<optional>true</optional>
69+
</dependency>
5870
</dependencies>
5971

6072
<build>

aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
import com.azure.ai.openai.models.ChatCompletionsFunctionToolCall;
88
import com.azure.ai.openai.models.ChatCompletionsFunctionToolDefinition;
99
import com.azure.ai.openai.models.ChatCompletionsJsonResponseFormat;
10+
import com.azure.ai.openai.models.ChatCompletionsNamedToolSelection;
1011
import com.azure.ai.openai.models.ChatCompletionsOptions;
1112
import com.azure.ai.openai.models.ChatCompletionsTextResponseFormat;
1213
import com.azure.ai.openai.models.ChatCompletionsToolCall;
1314
import com.azure.ai.openai.models.ChatCompletionsToolDefinition;
15+
import com.azure.ai.openai.models.ChatCompletionsToolSelection;
16+
import com.azure.ai.openai.models.ChatCompletionsToolSelectionPreset;
1417
import com.azure.ai.openai.models.ChatMessageImageContentItem;
1518
import com.azure.ai.openai.models.ChatMessageImageDetailLevel;
1619
import com.azure.ai.openai.models.ChatMessageImageUrl;
@@ -23,13 +26,15 @@
2326
import com.azure.ai.openai.models.ChatResponseMessage;
2427
import com.azure.ai.openai.models.CompletionsUsage;
2528
import com.azure.ai.openai.models.FunctionCall;
26-
import com.azure.core.util.BinaryData;
29+
import com.azure.json.JsonOptions;
30+
import com.azure.json.implementation.DefaultJsonReader;
2731
import com.fasterxml.jackson.core.JsonProcessingException;
2832
import com.fasterxml.jackson.databind.JsonNode;
2933
import com.fasterxml.jackson.databind.ObjectMapper;
3034
import com.fasterxml.jackson.databind.node.ContainerNode;
3135
import com.microsoft.semantickernel.Kernel;
3236
import com.microsoft.semantickernel.aiservices.openai.OpenAiService;
37+
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.responseformat.ChatCompletionsJsonSchemaResponseFormat;
3338
import com.microsoft.semantickernel.aiservices.openai.implementation.OpenAIRequestSettings;
3439
import com.microsoft.semantickernel.contextvariables.ContextVariable;
3540
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
@@ -50,6 +55,8 @@
5055
import com.microsoft.semantickernel.orchestration.InvocationReturnMode;
5156
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
5257
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
58+
import com.microsoft.semantickernel.orchestration.responseformat.JsonResponseSchema;
59+
import com.microsoft.semantickernel.orchestration.responseformat.JsonSchemaResponseFormat;
5360
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
5461
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
5562
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
@@ -61,6 +68,7 @@
6168
import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageImageContent;
6269
import com.microsoft.semantickernel.services.openai.OpenAiServiceBuilder;
6370
import io.opentelemetry.api.trace.Span;
71+
import java.io.IOException;
6472
import java.util.ArrayList;
6573
import java.util.Arrays;
6674
import java.util.Collections;
@@ -618,6 +626,8 @@ private Mono<FunctionResult<String>> invokeFunctionTool(
618626
return function
619627
.invokeAsync(kernel)
620628
.withArguments(arguments)
629+
.withTypes(invocationContext.getContextVariableTypes())
630+
.withTypes(contextVariableTypes)
621631
.withResultType(contextVariableTypes.getVariableTypeForClass(String.class));
622632
} catch (JsonProcessingException e) {
623633
return Mono.error(new SKException("Failed to parse tool arguments", e));
@@ -900,13 +910,21 @@ private static ChatCompletionsOptions getCompletionsOptions(
900910
.setLogitBias(logit);
901911

902912
if (promptExecutionSettings.getResponseFormat() != null) {
903-
switch (promptExecutionSettings.getResponseFormat()) {
913+
switch (promptExecutionSettings.getResponseFormat().getType()) {
914+
case JSON_SCHEMA:
915+
JsonResponseSchema schema = ((JsonSchemaResponseFormat) promptExecutionSettings
916+
.getResponseFormat())
917+
.getJsonSchema();
918+
919+
options.setResponseFormat(new ChatCompletionsJsonSchemaResponseFormat(schema));
920+
break;
904921
case JSON_OBJECT:
905922
options.setResponseFormat(new ChatCompletionsJsonResponseFormat());
906923
break;
907924
case TEXT:
908925
options.setResponseFormat(new ChatCompletionsTextResponseFormat());
909926
break;
927+
910928
default:
911929
throw new SKException(
912930
"Unknown response format: " + promptExecutionSettings.getResponseFormat());
@@ -957,9 +975,17 @@ private static void configureToolCallBehaviorOptions(
957975
try {
958976
String json = String.format(
959977
"{\"type\":\"function\",\"function\":{\"name\":\"%s\"}}", toolChoiceName);
960-
options.setToolChoice(BinaryData.fromObject(new ObjectMapper().readTree(json)));
978+
979+
options.setToolChoice(
980+
new ChatCompletionsToolSelection(
981+
ChatCompletionsNamedToolSelection.fromJson(
982+
DefaultJsonReader.fromString(
983+
json,
984+
new JsonOptions()))));
961985
} catch (JsonProcessingException e) {
962986
throw SKException.build("Failed to parse tool choice", e);
987+
} catch (IOException e) {
988+
throw new SKException(e);
963989
}
964990
return;
965991
}
@@ -985,7 +1011,8 @@ private static void configureToolCallBehaviorOptions(
9851011
}
9861012

9871013
options.setTools(toolDefinitions);
988-
options.setToolChoice(BinaryData.fromString("auto"));
1014+
options.setToolChoice(
1015+
new ChatCompletionsToolSelection(ChatCompletionsToolSelectionPreset.AUTO));
9891016
}
9901017

9911018
private static boolean hasToolCallBeenExecuted(List<ChatRequestMessage> chatRequestMessages,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
package com.microsoft.semantickernel.aiservices.openai.chatcompletion.responseformat;
3+
4+
import com.azure.ai.openai.models.ChatCompletionsResponseFormat;
5+
import com.azure.json.JsonWriter;
6+
import com.microsoft.semantickernel.orchestration.responseformat.JsonResponseSchema;
7+
import java.io.IOException;
8+
9+
public class ChatCompletionsJsonSchemaResponseFormat extends ChatCompletionsResponseFormat {
10+
11+
private final JsonResponseSchema schema;
12+
private String type = "json_schema";
13+
14+
public ChatCompletionsJsonSchemaResponseFormat(JsonResponseSchema schema) {
15+
this.schema = schema;
16+
}
17+
18+
public String getType() {
19+
return this.type;
20+
}
21+
22+
public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
23+
jsonWriter.writeStartObject();
24+
jsonWriter.writeStringField("type", this.type);
25+
jsonWriter.writeStartObject("json_schema");
26+
27+
jsonWriter.writeBooleanField("strict", this.schema.isStrict());
28+
jsonWriter.writeStringField("name", this.schema.getName());
29+
30+
jsonWriter.writeRawField("schema", this.schema.getSchema());
31+
jsonWriter.writeEndObject();
32+
return jsonWriter.writeEndObject();
33+
}
34+
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
package com.microsoft.semantickernel.aiservices.openai.chatcompletion.responseformat;
3+
4+
import com.fasterxml.jackson.databind.JsonNode;
5+
import com.fasterxml.jackson.databind.node.ArrayNode;
6+
import com.fasterxml.jackson.databind.node.ContainerNode;
7+
import com.fasterxml.jackson.databind.node.ObjectNode;
8+
import com.github.victools.jsonschema.generator.OptionPreset;
9+
import com.github.victools.jsonschema.generator.SchemaGenerator;
10+
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
11+
import com.github.victools.jsonschema.generator.SchemaVersion;
12+
import com.github.victools.jsonschema.module.jackson.JacksonModule;
13+
import com.microsoft.semantickernel.orchestration.responseformat.ResponseSchemaGenerator;
14+
15+
public class JacksonResponseFormatGenerator implements ResponseSchemaGenerator {
16+
17+
private final SchemaGenerator generator;
18+
19+
public JacksonResponseFormatGenerator() {
20+
JacksonModule module = new JacksonModule();
21+
SchemaGeneratorConfigBuilder builder = new SchemaGeneratorConfigBuilder(
22+
SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON)
23+
.with(module);
24+
25+
builder
26+
.forFields()
27+
.withRequiredCheck(fieldScope -> {
28+
return true;
29+
});
30+
31+
generator = new SchemaGenerator(builder.build());
32+
}
33+
34+
public JacksonResponseFormatGenerator(SchemaGenerator generator) {
35+
this.generator = generator;
36+
}
37+
38+
@Override
39+
public String generateSchema(Class<?> clazz) {
40+
ObjectNode schema = generator.generateSchema(clazz);
41+
42+
sanitize(schema);
43+
44+
return schema.toPrettyString();
45+
}
46+
47+
private static void sanitize(ContainerNode schema) {
48+
if (schema instanceof ObjectNode) {
49+
((ObjectNode) schema).remove("$schema");
50+
51+
if (schema.has("type") && schema.get("type").asText().equals("object")) {
52+
((ObjectNode) schema).put("additionalProperties", false);
53+
}
54+
55+
for (JsonNode node : (ObjectNode) schema) {
56+
if (node instanceof ContainerNode) {
57+
sanitize((ContainerNode) node);
58+
}
59+
}
60+
} else if (schema instanceof ArrayNode) {
61+
for (JsonNode node : (ArrayNode) schema) {
62+
if (node instanceof ContainerNode) {
63+
sanitize((ContainerNode) node);
64+
}
65+
}
66+
}
67+
}
68+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
3+
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
6+
public class Bar {
7+
8+
private final String bar;
9+
10+
public Bar(
11+
@JsonProperty("bar") String bar) {
12+
this.bar = bar;
13+
}
14+
15+
public String getBar() {
16+
return bar;
17+
}
18+
19+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
package com.microsoft.semantickernel.aiservices.openai.chatcompletion;
3+
4+
import com.fasterxml.jackson.annotation.JsonCreator;
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
7+
public class Baz {
8+
9+
@JsonProperty("bar")
10+
private final Bar bar;
11+
12+
@JsonCreator
13+
public Baz(
14+
@JsonProperty("bar") Bar bar) {
15+
this.bar = bar;
16+
}
17+
18+
@JsonProperty("bar")
19+
public Bar getBar() {
20+
return bar;
21+
}
22+
}

0 commit comments

Comments
 (0)