Revert "Convert API records to POJOs and fix failing autconfig tests"

This reverts commit 4184af5341.
This commit is contained in:
Christian Tzolov
2024-11-05 10:00:57 +01:00
parent d1b8fa30f9
commit 3e9a3fd3b0
21 changed files with 157 additions and 602 deletions

View File

@@ -60,6 +60,7 @@ import org.springframework.ai.minimax.api.MiniMaxApi.ChatCompletionMessage.ChatC
import org.springframework.ai.minimax.api.MiniMaxApi.ChatCompletionMessage.Role;
import org.springframework.ai.minimax.api.MiniMaxApi.ChatCompletionMessage.ToolCall;
import org.springframework.ai.minimax.api.MiniMaxApi.ChatCompletionRequest;
import org.springframework.ai.minimax.api.MiniMaxApi.FunctionTool;
import org.springframework.ai.minimax.api.MiniMaxApiConstants;
import org.springframework.ai.minimax.metadata.MiniMaxUsage;
import org.springframework.ai.model.ModelOptionsUtils;
@@ -507,11 +508,11 @@ public class MiniMaxChatModel extends AbstractToolCallSupport implements ChatMod
return request;
}
private List<MiniMaxApi.FunctionTool> getFunctionTools(Set<String> functionNames) {
private List<FunctionTool> getFunctionTools(Set<String> functionNames) {
return this.resolveFunctionCallbacks(functionNames).stream().map(functionCallback -> {
var function = new MiniMaxApi.FunctionTool.Function(functionCallback.getDescription(),
functionCallback.getName(), functionCallback.getInputTypeSchema());
return new MiniMaxApi.FunctionTool(function);
var function = new FunctionTool.Function(functionCallback.getDescription(), functionCallback.getName(),
functionCallback.getInputTypeSchema());
return new FunctionTool(function);
}).toList();
}

View File

@@ -331,35 +331,14 @@ public class MiniMaxApi {
/**
* Represents a tool the model may call. Currently, only functions are supported as a tool.
*
* @param type The type of the tool. Currently, only 'function' is supported.
* @param function The function definition.
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class FunctionTool {
/**
* The type of the tool. Currently, only 'function' is supported.
*/
private Type type = Type.FUNCTION;
/**
* The function definition.
*/
private Function function;
public FunctionTool() {
}
/**
* Create a tool of type 'function' and the given function definition.
* @param type the tool type
* @param function function definition
*/
public FunctionTool(
@JsonProperty("type") Type type,
@JsonProperty("function") Function function) {
this.type = type;
this.function = function;
}
@JsonInclude(Include.NON_NULL)
public record FunctionTool(
@JsonProperty("type") Type type,
@JsonProperty("function") Function function) {
/**
* Create a tool of type 'function' and the given function definition.
@@ -369,22 +348,8 @@ public class MiniMaxApi {
this(Type.FUNCTION, function);
}
@JsonProperty("type")
public Type getType() {
return this.type;
}
@JsonProperty("function")
public Function getFunction() {
return this.function;
}
public void setType(Type type) {
this.type = type;
}
public void setFunction(Function function) {
this.function = function;
public static FunctionTool webSearchFunctionTool() {
return new FunctionTool(Type.WEB_SEARCH, null);
}
/**
@@ -396,104 +361,35 @@ public class MiniMaxApi {
*/
@JsonProperty("function")
FUNCTION,
@JsonProperty("web_search")
WEB_SEARCH
}
public static FunctionTool webSearchFunctionTool() {
return new FunctionTool(FunctionTool.Type.WEB_SEARCH, null);
}
/**
* Function definition.
*
* @param description A description of what the function does, used by the model to choose when and how to call
* the function.
* @param name The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes,
* with a maximum length of 64.
* @param parameters The parameters the functions accepts, described as a JSON Schema object. To describe a
* function that accepts no parameters, provide the value {"type": "object", "properties": {}}.
*/
public static class Function {
@JsonProperty("description")
private String description;
@JsonProperty("name")
private String name;
@JsonProperty("parameters")
private Map<String, Object> parameters;
private String jsonSchema;
private Function() {
}
/**
* Create tool function definition.
*
* @param description A description of what the function does, used by the model to choose when and how to call
* the function.
* @param name The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes,
* with a maximum length of 64.
* @param parameters The parameters the functions accepts, described as a JSON Schema object. To describe a
* function that accepts no parameters, provide the value {"type": "object", "properties": {}}.
*/
public Function(
String description,
String name,
Map<String, Object> parameters) {
this.description = description;
this.name = name;
this.parameters = parameters;
}
public record Function(
@JsonProperty("description") String description,
@JsonProperty("name") String name,
@JsonProperty("parameters") String parameters) {
/**
* Create tool function definition.
*
* @param description tool function description.
* @param name tool function name.
* @param jsonSchema tool function schema as json.
* @param parameters tool function schema.
*/
public Function(String description, String name, String jsonSchema) {
this(description, name, ModelOptionsUtils.jsonToMap(jsonSchema));
public Function(String description, String name, Map<String, Object> parameters) {
this(description, name, ModelOptionsUtils.toJsonString(parameters));
}
@JsonProperty("description")
public String getDescription() {
return this.description;
}
@JsonProperty("name")
public String getName() {
return this.name;
}
@JsonProperty("parameters")
public Map<String, Object> getParameters() {
return this.parameters;
}
public void setDescription(String description) {
this.description = description;
}
public void setName(String name) {
this.name = name;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
public String getJsonSchema() {
return this.jsonSchema;
}
public void setJsonSchema(String jsonSchema) {
this.jsonSchema = jsonSchema;
if (jsonSchema != null) {
this.parameters = ModelOptionsUtils.jsonToMap(jsonSchema);
}
}
}
}

View File

@@ -83,7 +83,7 @@ public class ChatCompletionRequestTests {
assertThat(request.model()).isEqualTo("PROMPT_MODEL");
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).isEqualTo(TOOL_FUNCTION_NAME);
assertThat(request.tools().get(0).function().name()).isEqualTo(TOOL_FUNCTION_NAME);
}
@Test
@@ -120,7 +120,7 @@ public class ChatCompletionRequestTests {
MiniMaxChatOptions.builder().withFunction(TOOL_FUNCTION_NAME).build()), false);
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).as("Explicitly enabled function")
assertThat(request.tools().get(0).function().name()).as("Explicitly enabled function")
.isEqualTo(TOOL_FUNCTION_NAME);
// Override the default options function with one from the prompt
@@ -134,7 +134,7 @@ public class ChatCompletionRequestTests {
false);
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).as("Explicitly enabled function")
assertThat(request.tools().get(0).function().name()).as("Explicitly enabled function")
.isEqualTo(TOOL_FUNCTION_NAME);
assertThat(client.getFunctionCallbackRegister()).hasSize(1);

View File

@@ -33,6 +33,7 @@ import org.springframework.ai.minimax.api.MiniMaxApi.ChatCompletionMessage.Role;
import org.springframework.ai.minimax.api.MiniMaxApi.ChatCompletionMessage.ToolCall;
import org.springframework.ai.minimax.api.MiniMaxApi.ChatCompletionRequest;
import org.springframework.ai.minimax.api.MiniMaxApi.ChatCompletionRequest.ToolChoiceBuilder;
import org.springframework.ai.minimax.api.MiniMaxApi.FunctionTool.Type;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@@ -66,33 +67,31 @@ public class MiniMaxApiToolFunctionCallIT {
var message = new ChatCompletionMessage(
"What's the weather like in San Francisco? Return the temperature in Celsius.", Role.USER);
var functionTool = new MiniMaxApi.FunctionTool(MiniMaxApi.FunctionTool.Type.FUNCTION,
new MiniMaxApi.FunctionTool.Function(
"Get the weather in location. Return temperature in 30°F or 30°C format.", "getCurrentWeather",
"""
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state e.g. San Francisco, CA"
},
"lat": {
"type": "number",
"description": "The city latitude"
},
"lon": {
"type": "number",
"description": "The city longitude"
},
"unit": {
"type": "string",
"enum": ["C", "F"]
}
},
"required": ["location", "lat", "lon", "unit"]
var functionTool = new MiniMaxApi.FunctionTool(Type.FUNCTION, new MiniMaxApi.FunctionTool.Function(
"Get the weather in location. Return temperature in 30°F or 30°C format.", "getCurrentWeather", """
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state e.g. San Francisco, CA"
},
"lat": {
"type": "number",
"description": "The city latitude"
},
"lon": {
"type": "number",
"description": "The city longitude"
},
"unit": {
"type": "string",
"enum": ["C", "F"]
}
"""));
},
"required": ["location", "lat", "lon", "unit"]
}
"""));
List<ChatCompletionMessage> messages = new ArrayList<>(List.of(message));

View File

@@ -318,21 +318,12 @@ public class MistralAiApi {
/**
* Represents a tool the model may call. Currently, only functions are supported as a
* tool.
*
* @param type The type of the tool. Currently, only 'function' is supported.
* @param function The function definition.
*/
@JsonInclude(Include.NON_NULL)
public static class FunctionTool {
// The type of the tool. Currently, only 'function' is supported.
@JsonProperty("type")
Type type = Type.FUNCTION;
// The function definition.
@JsonProperty("function")
Function function;
public FunctionTool() {
}
public record FunctionTool(@JsonProperty("type") Type type, @JsonProperty("function") Function function) {
/**
* Create a tool of type 'function' and the given function definition.
@@ -342,27 +333,6 @@ public class MistralAiApi {
this(Type.FUNCTION, function);
}
public FunctionTool(Type type, Function function) {
this.type = type;
this.function = function;
}
public Type getType() {
return this.type;
}
public Function getFunction() {
return this.function;
}
public void setType(Type type) {
this.type = type;
}
public void setFunction(Function function) {
this.function = function;
}
/**
* Create a tool of type 'function' and the given function definition.
*/
@@ -378,39 +348,17 @@ public class MistralAiApi {
/**
* Function definition.
*
* @param description A description of what the function does, used by the model
* to choose when and how to call the function.
* @param name The name of the function to be called. Must be a-z, A-Z, 0-9, or
* contain underscores and dashes, with a maximum length of 64.
* @param parameters The parameters the functions accepts, described as a JSON
* Schema object. To describe a function that accepts no parameters, provide the
* value {"type": "object", "properties": {}}.
*/
public static class Function {
@JsonProperty("description")
private String description;
@JsonProperty("name")
private String name;
@JsonProperty("parameters")
private Map<String, Object> parameters;
private String jsonSchema;
private Function() {
}
/**
* Create tool function definition.
* @param description A description of what the function does, used by the
* model to choose when and how to call the function.
* @param name The name of the function to be called. Must be a-z, A-Z, 0-9,
* or contain underscores and dashes, with a maximum length of 64.
* @param parameters The parameters the functions accepts, described as a JSON
* Schema object. To describe a function that accepts no parameters, provide
* the value {"type": "object", "properties": {}}.
*/
public Function(String description, String name, Map<String, Object> parameters) {
this.description = description;
this.name = name;
this.parameters = parameters;
}
public record Function(@JsonProperty("description") String description, @JsonProperty("name") String name,
@JsonProperty("parameters") Map<String, Object> parameters) {
/**
* Create tool function definition.
@@ -422,41 +370,6 @@ public class MistralAiApi {
this(description, name, ModelOptionsUtils.jsonToMap(jsonSchema));
}
public String getDescription() {
return this.description;
}
public String getName() {
return this.name;
}
public Map<String, Object> getParameters() {
return this.parameters;
}
public void setDescription(String description) {
this.description = description;
}
public void setName(String name) {
this.name = name;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
public String getJsonSchema() {
return this.jsonSchema;
}
public void setJsonSchema(String jsonSchema) {
this.jsonSchema = jsonSchema;
if (jsonSchema != null) {
this.parameters = ModelOptionsUtils.jsonToMap(jsonSchema);
}
}
}
}

View File

@@ -131,8 +131,7 @@
<artifactId>ollama</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -37,6 +37,7 @@ import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest.ResponseFormat;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest.StreamOptions;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest.ToolChoiceBuilder;
import org.springframework.ai.openai.api.OpenAiApi.FunctionTool;
import org.springframework.util.Assert;
/**
@@ -132,7 +133,7 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
* A list of tools the model may call. Currently, only functions are supported as a tool. Use this to
* provide a list of functions the model may generate JSON inputs for.
*/
private @JsonProperty("tools") List<OpenAiApi.FunctionTool> tools;
private @JsonProperty("tools") List<FunctionTool> tools;
/**
* Controls which (if any) function is called by the model. none means the model will not call a
* function and instead generates a message. auto means the model can pick between generating a message or calling a
@@ -369,11 +370,11 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
this.topP = topP;
}
public List<OpenAiApi.FunctionTool> getTools() {
public List<FunctionTool> getTools() {
return this.tools;
}
public void setTools(List<OpenAiApi.FunctionTool> tools) {
public void setTools(List<FunctionTool> tools) {
this.tools = tools;
}
@@ -592,7 +593,7 @@ public class OpenAiChatOptions implements FunctionCallingOptions, ChatOptions {
return this;
}
public Builder withTools(List<OpenAiApi.FunctionTool> tools) {
public Builder withTools(List<FunctionTool> tools) {
this.options.tools = tools;
return this;
}

View File

@@ -532,35 +532,14 @@ public class OpenAiApi {
/**
* Represents a tool the model may call. Currently, only functions are supported as a
* tool.
*
* @param type The type of the tool. Currently, only 'function' is supported.
* @param function The function definition.
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class FunctionTool {
/**
* The type of the tool. Currently, only 'function' is supported.
*/
@JsonProperty("type")
private Type type = Type.FUNCTION;
/**
* The function definition.
*/
@JsonProperty("function")
private Function function;
public FunctionTool() {
}
/**
* Create a tool of type 'function' and the given function definition.
* @param type the tool type
* @param function function definition
*/
public FunctionTool(Type type, Function function) {
this.type = type;
this.function = function;
}
@JsonInclude(Include.NON_NULL)
public record FunctionTool(// @formatter:off
@JsonProperty("type") Type type,
@JsonProperty("function") Function function) {
/**
* Create a tool of type 'function' and the given function definition.
@@ -570,73 +549,35 @@ public class OpenAiApi {
this(Type.FUNCTION, function);
}
public Type getType() {
return this.type;
}
public Function getFunction() {
return this.function;
}
public void setType(Type type) {
this.type = type;
}
public void setFunction(Function function) {
this.function = function;
}
/**
* Create a tool of type 'function' and the given function definition.
*/
public enum Type {
/**
* Function tool type.
*/
@JsonProperty("function")
FUNCTION
}
/**
* Function definition.
*
* @param description A description of what the function does, used by the model to choose when and how to call
* the function.
* @param name The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes,
* with a maximum length of 64.
* @param parameters The parameters the functions accepts, described as a JSON Schema object. To describe a
* function that accepts no parameters, provide the value {"type": "object", "properties": {}}.
*/
public static class Function {
@JsonProperty("description")
private String description;
@JsonProperty("name")
private String name;
@JsonProperty("parameters")
private Map<String, Object> parameters;
private String jsonSchema;
private Function() {
}
/**
* Create tool function definition.
* @param description A description of what the function does, used by the
* model to choose when and how to call the function.
* @param name The name of the function to be called. Must be a-z, A-Z, 0-9,
* or contain underscores and dashes, with a maximum length of 64.
* @param parameters The parameters the functions accepts, described as a JSON
* Schema object. To describe a function that accepts no parameters, provide
* the value {"type": "object", "properties": {}}.
*/
public Function(String description, String name, Map<String, Object> parameters) {
this.description = description;
this.name = name;
this.parameters = parameters;
}
public record Function(
@JsonProperty("description") String description,
@JsonProperty("name") String name,
@JsonProperty("parameters") Map<String, Object> parameters) {
/**
* Create tool function definition.
*
* @param description tool function description.
* @param name tool function name.
* @param jsonSchema tool function schema as json.
@@ -644,45 +585,8 @@ public class OpenAiApi {
public Function(String description, String name, String jsonSchema) {
this(description, name, ModelOptionsUtils.jsonToMap(jsonSchema));
}
public String getDescription() {
return this.description;
}
public String getName() {
return this.name;
}
public Map<String, Object> getParameters() {
return this.parameters;
}
public void setDescription(String description) {
this.description = description;
}
public void setName(String name) {
this.name = name;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
public String getJsonSchema() {
return this.jsonSchema;
}
public void setJsonSchema(String jsonSchema) {
this.jsonSchema = jsonSchema;
if (jsonSchema != null) {
this.parameters = ModelOptionsUtils.jsonToMap(jsonSchema);
}
}
}
}
} // @formatter:on
/**
* Creates a model response for the given chat conversation.
@@ -921,9 +825,9 @@ public class OpenAiApi {
*/
@JsonInclude(Include.NON_NULL)
public record JsonSchema(
@JsonProperty("name") String name,
@JsonProperty("schema") Map<String, Object> schema,
@JsonProperty("strict") Boolean strict) {
@JsonProperty("name") String name,
@JsonProperty("schema") Map<String, Object> schema,
@JsonProperty("strict") Boolean strict) {
public JsonSchema(String name, String schema) {
this(name, ModelOptionsUtils.jsonToMap(schema), true);

View File

@@ -83,7 +83,7 @@ public class ChatCompletionRequestTests {
assertThat(request.model()).isEqualTo("PROMPT_MODEL");
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).isEqualTo(TOOL_FUNCTION_NAME);
assertThat(request.tools().get(0).function().name()).isEqualTo(TOOL_FUNCTION_NAME);
}
@Test
@@ -120,7 +120,7 @@ public class ChatCompletionRequestTests {
OpenAiChatOptions.builder().withFunction(TOOL_FUNCTION_NAME).build()), false);
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).as("Explicitly enabled function")
assertThat(request.tools().get(0).function().name()).as("Explicitly enabled function")
.isEqualTo(TOOL_FUNCTION_NAME);
// Override the default options function with one from the prompt
@@ -134,7 +134,7 @@ public class ChatCompletionRequestTests {
false);
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).as("Explicitly enabled function")
assertThat(request.tools().get(0).function().name()).as("Explicitly enabled function")
.isEqualTo(TOOL_FUNCTION_NAME);
assertThat(client.getFunctionCallbackRegister()).hasSize(1);

View File

@@ -34,6 +34,7 @@ import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionMessage.Role;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionMessage.ToolCall;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest.ToolChoiceBuilder;
import org.springframework.ai.openai.api.OpenAiApi.FunctionTool.Type;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@@ -70,7 +71,7 @@ public class OpenAiApiToolFunctionCallIT {
var message = new ChatCompletionMessage("What's the weather like in San Francisco, Tokyo, and Paris?",
Role.USER);
var functionTool = new OpenAiApi.FunctionTool(OpenAiApi.FunctionTool.Type.FUNCTION,
var functionTool = new OpenAiApi.FunctionTool(Type.FUNCTION,
new OpenAiApi.FunctionTool.Function("Get the weather in location. Return temperature in Celsius.",
"getCurrentWeather", ModelOptionsUtils.jsonToMap("""
{

View File

@@ -68,6 +68,7 @@ import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionMessage.Media
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionMessage.Role;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionMessage.ToolCall;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionRequest;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.FunctionTool;
import org.springframework.ai.zhipuai.api.ZhiPuApiConstants;
import org.springframework.ai.zhipuai.metadata.ZhiPuAiUsage;
import org.springframework.http.ResponseEntity;
@@ -469,11 +470,11 @@ public class ZhiPuAiChatModel extends AbstractToolCallSupport implements ChatMod
.build();
}
private List<ZhiPuAiApi.FunctionTool> getFunctionTools(Set<String> functionNames) {
private List<FunctionTool> getFunctionTools(Set<String> functionNames) {
return this.resolveFunctionCallbacks(functionNames).stream().map(functionCallback -> {
var function = new ZhiPuAiApi.FunctionTool.Function(functionCallback.getDescription(),
functionCallback.getName(), functionCallback.getInputTypeSchema());
return new ZhiPuAiApi.FunctionTool(function);
var function = new FunctionTool.Function(functionCallback.getDescription(), functionCallback.getName(),
functionCallback.getInputTypeSchema());
return new FunctionTool(function);
}).toList();
}

View File

@@ -31,6 +31,7 @@ import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.ai.model.function.FunctionCallingOptions;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.FunctionTool;
import org.springframework.util.Assert;
/**
@@ -73,10 +74,7 @@ public class ZhiPuAiChatOptions implements FunctionCallingOptions, ChatOptions {
* A list of tools the model may call. Currently, only functions are supported as a tool. Use this to
* provide a list of functions the model may generate JSON inputs for.
*/
private @JsonProperty("tools") List<ZhiPuAiApi.FunctionTool> tools;
private @JsonProperty("tools1") List<ZhiPuAiApi.Foo> foos;
private @JsonProperty("tools") List<FunctionTool> tools;
/**
* Controls which (if any) function is called by the model. none means the model will not call a
* function and instead generates a message. auto means the model can pick between generating a message or calling a
@@ -209,11 +207,11 @@ public class ZhiPuAiChatOptions implements FunctionCallingOptions, ChatOptions {
this.topP = topP;
}
public List<ZhiPuAiApi.FunctionTool> getTools() {
public List<FunctionTool> getTools() {
return this.tools;
}
public void setTools(List<ZhiPuAiApi.FunctionTool> tools) {
public void setTools(List<FunctionTool> tools) {
this.tools = tools;
}
@@ -475,7 +473,7 @@ public class ZhiPuAiChatOptions implements FunctionCallingOptions, ChatOptions {
return this;
}
public Builder withTools(List<ZhiPuAiApi.FunctionTool> tools) {
public Builder withTools(List<FunctionTool> tools) {
this.options.tools = tools;
return this;
}

View File

@@ -312,48 +312,16 @@ public class ZhiPuAiApi {
}
}
public class Foo {
String foo;
public Foo() {
}
public Foo(String foo) {
this.foo = foo;
}
}
/**
* Represents a tool the model may call. Currently, only functions are supported as a tool.
*
* @param type The type of the tool. Currently, only 'function' is supported.
* @param function The function definition.
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class FunctionTool {
// The type of the tool. Currently, only 'function' is supported.
@JsonProperty("type")
private Function function;
// The function definition.
@JsonProperty("function")
private Type type = Type.FUNCTION;
public FunctionTool() {
}
/**
* Create a tool of type 'function' and the given function definition.
* @param type the tool type
* @param function function definition
*/
public FunctionTool(
Type type,
Function function) {
this.type = type;
this.function = function;
}
@JsonInclude(Include.NON_NULL)
public record FunctionTool(
@JsonProperty("type") Type type,
@JsonProperty("function") Function function) {
/**
* Create a tool of type 'function' and the given function definition.
@@ -363,22 +331,6 @@ public class ZhiPuAiApi {
this(Type.FUNCTION, function);
}
public Type getType() {
return this.type;
}
public Function getFunction() {
return this.function;
}
public void setType(Type type) {
this.type = type;
}
public void setFunction(Function function) {
this.function = function;
}
/**
* Create a tool of type 'function' and the given function definition.
*/
@@ -392,42 +344,18 @@ public class ZhiPuAiApi {
/**
* Function definition.
*
* @param description A description of what the function does, used by the model to choose when and how to call
* the function.
* @param name The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes,
* with a maximum length of 64.
* @param parameters The parameters the functions accepts, described as a JSON Schema object. To describe a
* function that accepts no parameters, provide the value {"type": "object", "properties": {}}.
*/
public static class Function {
@JsonProperty("description")
private String description;
@JsonProperty("name")
private String name;
@JsonProperty("parameters")
private Map<String, Object> parameters;
private String jsonSchema;
private Function() {
}
/**
* Create tool function definition.
*
* @param description A description of what the function does, used by the model to choose when and how to call
* the function.
* @param name The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes,
* with a maximum length of 64.
* @param parameters The parameters the functions accepts, described as a JSON Schema object. To describe a
* function that accepts no parameters, provide the value {"type": "object", "properties": {}}.
*/
public Function(
String description,
String name,
Map<String, Object> parameters) {
this.description = description;
this.name = name;
this.parameters = parameters;
}
public record Function(
@JsonProperty("description") String description,
@JsonProperty("name") String name,
@JsonProperty("parameters") Map<String, Object> parameters) {
/**
* Create tool function definition.
@@ -439,42 +367,6 @@ public class ZhiPuAiApi {
public Function(String description, String name, String jsonSchema) {
this(description, name, ModelOptionsUtils.jsonToMap(jsonSchema));
}
public String getDescription() {
return this.description;
}
public String getName() {
return this.name;
}
public Map<String, Object> getParameters() {
return this.parameters;
}
public void setDescription(String description) {
this.description = description;
}
public void setName(String name) {
this.name = name;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
public String getJsonSchema() {
return this.jsonSchema;
}
public void setJsonSchema(String jsonSchema) {
this.jsonSchema = jsonSchema;
if (jsonSchema != null) {
this.parameters = ModelOptionsUtils.jsonToMap(jsonSchema);
}
}
}
}

View File

@@ -83,7 +83,7 @@ public class ChatCompletionRequestTests {
assertThat(request.model()).isEqualTo("PROMPT_MODEL");
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).isEqualTo(TOOL_FUNCTION_NAME);
assertThat(request.tools().get(0).function().name()).isEqualTo(TOOL_FUNCTION_NAME);
}
@Test
@@ -120,7 +120,7 @@ public class ChatCompletionRequestTests {
ZhiPuAiChatOptions.builder().withFunction(TOOL_FUNCTION_NAME).build()), false);
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).as("Explicitly enabled function")
assertThat(request.tools().get(0).function().name()).as("Explicitly enabled function")
.isEqualTo(TOOL_FUNCTION_NAME);
// Override the default options function with one from the prompt
@@ -134,7 +134,7 @@ public class ChatCompletionRequestTests {
false);
assertThat(request.tools()).hasSize(1);
assertThat(request.tools().get(0).getFunction().getName()).as("Explicitly enabled function")
assertThat(request.tools().get(0).function().name()).as("Explicitly enabled function")
.isEqualTo(TOOL_FUNCTION_NAME);
assertThat(client.getFunctionCallbackRegister()).hasSize(1);

View File

@@ -34,6 +34,7 @@ import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionMessage.Role;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionMessage.ToolCall;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionRequest;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.ChatCompletionRequest.ToolChoiceBuilder;
import org.springframework.ai.zhipuai.api.ZhiPuAiApi.FunctionTool.Type;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@@ -67,7 +68,7 @@ public class ZhiPuAiApiToolFunctionCallIT {
var message = new ChatCompletionMessage(
"What's the weather like in San Francisco? Return the temperature in Celsius.", Role.USER);
var functionTool = new ZhiPuAiApi.FunctionTool(ZhiPuAiApi.FunctionTool.Type.FUNCTION,
var functionTool = new ZhiPuAiApi.FunctionTool(Type.FUNCTION,
new ZhiPuAiApi.FunctionTool.Function(
"Get the weather in location. Return temperature in 30°F or 30°C format.", "getCurrentWeather",
ModelOptionsUtils.jsonToMap("""

View File

@@ -229,11 +229,11 @@ public class MiniMaxPropertiesTests {
assertThat(chatProperties.getOptions().getTools()).hasSize(1);
var tool = chatProperties.getOptions().getTools().get(0);
assertThat(tool.getType()).isEqualTo(MiniMaxApi.FunctionTool.Type.FUNCTION);
var function = tool.getFunction();
assertThat(function.getName()).isEqualTo("myFunction1");
assertThat(function.getDescription()).isEqualTo("function description");
assertThat(function.getParameters()).isNotEmpty();
assertThat(tool.type()).isEqualTo(MiniMaxApi.FunctionTool.Type.FUNCTION);
var function = tool.function();
assertThat(function.name()).isEqualTo("myFunction1");
assertThat(function.description()).isEqualTo("function description");
assertThat(function.parameters()).isNotEmpty();
});
}

View File

@@ -19,7 +19,6 @@ package org.springframework.ai.autoconfigure.mistralai;
import org.junit.jupiter.api.Test;
import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration;
import org.springframework.ai.mistralai.api.MistralAiApi;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -53,54 +52,6 @@ public class MistralAiPropertiesTests {
});
}
@Test
public void chatOptionsTest() {
new ApplicationContextRunner().withPropertyValues("spring.ai.mistralai.base-url=TEST_BASE_URL",
"spring.ai.mistralai.chat.options.tools[0].function.name=myFunction1",
"spring.ai.mistralai.chat.options.tools[0].function.description=function description",
"spring.ai.mistralai.chat.options.tools[0].function.jsonSchema=" + """
{
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state e.g. San Francisco, CA"
},
"lat": {
"type": "number",
"description": "The city latitude"
},
"lon": {
"type": "number",
"description": "The city longitude"
},
"unit": {
"type": "string",
"enum": ["c", "f"]
}
},
"required": ["location", "lat", "lon", "unit"]
}
""",
"spring.ai.mistralai.api-key=abc123", "spring.ai.mistralai.embedding.base-url=TEST_BASE_URL2",
"spring.ai.mistralai.embedding.api-key=456", "spring.ai.mistralai.embedding.options.model=MODEL_XYZ")
.withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class,
RestClientAutoConfiguration.class, MistralAiAutoConfiguration.class))
.run(context -> {
var chatProperties = context.getBean(MistralAiChatProperties.class);
var tool = chatProperties.getOptions().getTools().get(0);
assertThat(tool.getType()).isEqualTo(MistralAiApi.FunctionTool.Type.FUNCTION);
var function = tool.getFunction();
assertThat(function.getName()).isEqualTo("myFunction1");
assertThat(function.getDescription()).isEqualTo("function description");
assertThat(function.getParameters()).isNotEmpty();
});
}
@Test
public void embeddingOverrideConnectionProperties() {

View File

@@ -26,8 +26,8 @@ import org.springframework.ai.openai.OpenAiAudioTranscriptionModel;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.OpenAiImageModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest.ToolChoiceBuilder;
import org.springframework.ai.openai.api.OpenAiApi.FunctionTool.Type;
import org.springframework.ai.openai.api.OpenAiAudioApi;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -426,11 +426,11 @@ public class OpenAiPropertiesTests {
assertThat(chatProperties.getOptions().getTools()).hasSize(1);
var tool = chatProperties.getOptions().getTools().get(0);
assertThat(tool.getType()).isEqualTo(OpenAiApi.FunctionTool.Type.FUNCTION);
var function = tool.getFunction();
assertThat(function.getName()).isEqualTo("myFunction1");
assertThat(function.getDescription()).isEqualTo("function description");
assertThat(function.getParameters()).isNotEmpty();
assertThat(tool.type()).isEqualTo(Type.FUNCTION);
var function = tool.function();
assertThat(function.name()).isEqualTo("myFunction1");
assertThat(function.description()).isEqualTo("function description");
assertThat(function.parameters()).isNotEmpty();
});
}

View File

@@ -36,7 +36,6 @@ import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationDocumentation.HighCardinalityKeyNames;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
@@ -128,12 +127,11 @@ public class ChromaVectorStoreAutoConfigurationIT {
@Test
public void throwExceptionOnMissingCollectionAndDisabledInitializedSchema() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.chroma.initializeSchema=false")
.run(context -> assertThatThrownBy(() -> context.getBean(VectorStore.class))
.isInstanceOf(IllegalStateException.class)
.hasCauseInstanceOf(BeanCreationException.class)
.hasRootCauseExactlyInstanceOf(RuntimeException.class)
.hasRootCauseMessage(
.isInstanceOf(RuntimeException.class)
.hasMessage(
"Collection TestCollection doesn't exist and won't be created as the initializeSchema is set to false."));
}

View File

@@ -18,9 +18,9 @@ package org.springframework.ai.autoconfigure.vectorstore.hanadb;
import java.util.List;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration;

View File

@@ -273,11 +273,11 @@ public class ZhiPuAiPropertiesTests {
assertThat(chatProperties.getOptions().getTools()).hasSize(1);
var tool = chatProperties.getOptions().getTools().get(0);
assertThat(tool.getType()).isEqualTo(ZhiPuAiApi.FunctionTool.Type.FUNCTION);
var function = tool.getFunction();
assertThat(function.getName()).isEqualTo("myFunction1");
assertThat(function.getDescription()).isEqualTo("function description");
assertThat(function.getParameters()).isNotEmpty();
assertThat(tool.type()).isEqualTo(ZhiPuAiApi.FunctionTool.Type.FUNCTION);
var function = tool.function();
assertThat(function.name()).isEqualTo("myFunction1");
assertThat(function.description()).isEqualTo("function description");
assertThat(function.parameters()).isNotEmpty();
});
}