Skip to content

Commit 379ea2c

Browse files
committed
Merge remote-tracking branch 'origin/feat-support-ollama-thinking' into feat-support-ollama-thinking
# Conflicts: # models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApi.java # models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApiHelper.java # models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaModel.java # models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaOptions.java # models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaImage.java # models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/api/OllamaApiIT.java
2 parents f61a99f + 557a98e commit 379ea2c

File tree

6 files changed

+53
-331
lines changed

6 files changed

+53
-331
lines changed

models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApi.java

Lines changed: 27 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ public static Builder builder() {
6666

6767
private static final Log logger = LogFactory.getLog(OllamaApi.class);
6868

69+
70+
private static final String DEFAULT_BASE_URL = "http://localhost:11434";
71+
6972
private final RestClient restClient;
7073

7174
private final WebClient webClient;
@@ -78,18 +81,22 @@ public static Builder builder() {
7881
* @param responseErrorHandler Response error handler.
7982
*/
8083
private OllamaApi(String baseUrl, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) {
84+
85+
8186
Consumer<HttpHeaders> defaultHeaders = headers -> {
8287
headers.setContentType(MediaType.APPLICATION_JSON);
8388
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
8489
};
8590

91+
8692
this.restClient = restClientBuilder
8793
.clone()
8894
.baseUrl(baseUrl)
8995
.defaultHeaders(defaultHeaders)
9096
.defaultStatusHandler(responseErrorHandler)
9197
.build();
9298

99+
93100
this.webClient = webClientBuilder
94101
.clone()
95102
.baseUrl(baseUrl)
@@ -252,22 +259,19 @@ public Flux<ProgressResponse> pullModel(PullModelRequest pullModelRequest) {
252259
*
253260
* @param role The role of the message of type {@link Role}.
254261
* @param content The content of the message.
262+
* @param thinking The thinking of the model.
255263
* @param images The list of base64-encoded images to send with the message.
256264
* Requires multimodal models such as llava or bakllava.
257-
* @param toolCalls The list of tools that the model wants to use.
258-
* @param toolName The name of the tool that was executed to inform the model of the result.
259-
* @param thinking The model's thinking process. Requires thinking models such as qwen3.
265+
* @param toolCalls The relevant tool call.
260266
*/
261267
@JsonInclude(Include.NON_NULL)
262268
@JsonIgnoreProperties(ignoreUnknown = true)
263269
public record Message(
264270
@JsonProperty("role") Role role,
265271
@JsonProperty("content") String content,
272+
@JsonProperty("thinking") String thinking,
266273
@JsonProperty("images") List<String> images,
267-
@JsonProperty("tool_calls") List<ToolCall> toolCalls,
268-
@JsonProperty("tool_name") String toolName,
269-
@JsonProperty("thinking") String thinking
270-
) {
274+
@JsonProperty("tool_calls") List<ToolCall> toolCalls) {
271275

272276
public static Builder builder(Role role) {
273277
return new Builder(role);
@@ -316,29 +320,20 @@ public record ToolCall(
316320
*
317321
* @param name The name of the function.
318322
* @param arguments The arguments that the model expects you to pass to the function.
319-
* @param index The index of the function call in the list of tool calls.
320323
*/
321324
@JsonInclude(Include.NON_NULL)
322325
public record ToolCallFunction(
323326
@JsonProperty("name") String name,
324-
@JsonProperty("arguments") Map<String, Object> arguments,
325-
@JsonProperty("index") Integer index
326-
) {
327-
328-
public ToolCallFunction(String name, Map<String, Object> arguments) {
329-
this(name, arguments, null);
330-
}
331-
327+
@JsonProperty("arguments") Map<String, Object> arguments) {
332328
}
333329

334-
public static final class Builder {
330+
public static class Builder {
335331

336332
private final Role role;
337333
private String content;
334+
private String thinking;
338335
private List<String> images;
339336
private List<ToolCall> toolCalls;
340-
private String toolName;
341-
private String thinking;
342337

343338
public Builder(Role role) {
344339
this.role = role;
@@ -349,6 +344,11 @@ public Builder content(String content) {
349344
return this;
350345
}
351346

347+
public Builder thinking(String thinking) {
348+
this.thinking = thinking;
349+
return this;
350+
}
351+
352352
public Builder images(List<String> images) {
353353
this.images = images;
354354
return this;
@@ -359,18 +359,8 @@ public Builder toolCalls(List<ToolCall> toolCalls) {
359359
return this;
360360
}
361361

362-
public Builder toolName(String toolName) {
363-
this.toolName = toolName;
364-
return this;
365-
}
366-
367-
public Builder thinking(String thinking) {
368-
this.thinking = thinking;
369-
return this;
370-
}
371-
372362
public Message build() {
373-
return new Message(this.role, this.content, this.images, this.toolCalls, this.toolName, this.thinking);
363+
return new Message(this.role, this.content, this.thinking, this.images, this.toolCalls);
374364
}
375365
}
376366
}
@@ -385,8 +375,8 @@ public Message build() {
385375
* @param keepAlive Controls how long the model will stay loaded into memory following this request (default: 5m).
386376
* @param tools List of tools the model has access to.
387377
* @param options Model-specific options. For example, "temperature" can be set through this field, if the model supports it.
388-
* @param think Think controls whether thinking/reasoning models will think before responding.
389-
* You can use the {@link OllamaChatOptions} builder to create the options then {@link OllamaChatOptions#toMap()} to convert the options into a map.
378+
* @param think The model should think before responding, if the model supports it.
379+
* You can use the {@link OllamaOptions} builder to create the options then {@link OllamaOptions#toMap()} to convert the options into a map.
390380
*
391381
* @see <a href=
392382
* "https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-chat-completion">Chat
@@ -467,7 +457,7 @@ public Function(String description, String name, String jsonSchema) {
467457
}
468458
}
469459

470-
public static final class Builder {
460+
public static class Builder {
471461

472462
private final String model;
473463
private List<Message> messages = List.of();
@@ -515,21 +505,14 @@ public Builder options(Map<String, Object> options) {
515505
return this;
516506
}
517507

518-
public Builder think(Boolean think) {
519-
this.think = think;
520-
return this;
521-
}
522-
523-
@Deprecated
524508
public Builder options(OllamaOptions options) {
525509
Objects.requireNonNull(options, "The options can not be null.");
526510
this.options = OllamaOptions.filterNonSupportedFields(options.toMap());
527511
return this;
528512
}
529513

530-
public Builder options(OllamaChatOptions options) {
531-
Objects.requireNonNull(options, "The options can not be null.");
532-
this.options = OllamaChatOptions.filterNonSupportedFields(options.toMap());
514+
public Builder think(Boolean think) {
515+
this.think = think;
533516
return this;
534517
}
535518

@@ -621,7 +604,7 @@ public Duration getEvalDuration() {
621604
public record EmbeddingsRequest(
622605
@JsonProperty("model") String model,
623606
@JsonProperty("input") List<String> input,
624-
@JsonProperty("keep_alive") String keepAlive,
607+
@JsonProperty("keep_alive") Duration keepAlive,
625608
@JsonProperty("options") Map<String, Object> options,
626609
@JsonProperty("truncate") Boolean truncate) {
627610

@@ -751,7 +734,7 @@ public record ProgressResponse(
751734
@JsonProperty("completed") Long completed
752735
) { }
753736

754-
public static final class Builder {
737+
public static class Builder {
755738

756739
private String baseUrl = OllamaApiConstants.DEFAULT_BASE_URL;
757740

models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaApiHelper.java

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2024-2025 the original author or authors.
2+
* Copyright 2024-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -87,14 +87,12 @@ private static OllamaApi.Message merge(OllamaApi.Message previous, OllamaApi.Mes
8787
role = (role != null ? role : OllamaApi.Message.Role.ASSISTANT);
8888
List<String> images = mergeImages(previous, current);
8989
List<OllamaApi.Message.ToolCall> toolCalls = mergeToolCall(previous, current);
90-
String toolName = mergeToolName(previous, current);
9190

9291
return OllamaApi.Message.builder(role)
9392
.content(content)
9493
.thinking(thinking)
9594
.images(images)
9695
.toolCalls(toolCalls)
97-
.toolName(toolName)
9896
.build();
9997
}
10098

@@ -143,37 +141,26 @@ private static String mergeContent(OllamaApi.Message previous, OllamaApi.Message
143141
return previous.content() + current.content();
144142
}
145143

146-
private static List<OllamaApi.Message.ToolCall> mergeToolCall(OllamaApi.Message previous,
147-
OllamaApi.Message current) {
148-
if (previous == null) {
149-
return (current != null ? current.toolCalls() : null);
150-
}
151-
if (current == null) {
152-
return previous.toolCalls();
153-
}
154-
return merge(previous.toolCalls(), current.toolCalls());
155-
}
156-
157144
private static String mergeThinking(OllamaApi.Message previous, OllamaApi.Message current) {
158145
if (previous == null || previous.thinking() == null) {
159146
return (current != null ? current.thinking() : null);
160147
}
161148
if (current == null || current.thinking() == null) {
162-
return (previous.thinking());
149+
return (previous != null ? previous.thinking() : null);
163150
}
164151

165152
return previous.thinking() + current.thinking();
166153
}
167154

168-
private static String mergeToolName(OllamaApi.Message previous, OllamaApi.Message current) {
169-
if (previous == null || previous.toolName() == null) {
170-
return (current != null ? current.toolName() : null);
155+
private static List<OllamaApi.Message.ToolCall> mergeToolCall(OllamaApi.Message previous,
156+
OllamaApi.Message current) {
157+
if (previous == null) {
158+
return (current != null ? current.toolCalls() : null);
171159
}
172-
if (current == null || current.toolName() == null) {
173-
return (previous.toolName());
160+
if (current == null) {
161+
return previous.toolCalls();
174162
}
175-
176-
return previous.toolName() + current.toolName();
163+
return merge(previous.toolCalls(), current.toolCalls());
177164
}
178165

179166
private static List<String> mergeImages(OllamaApi.Message previous, OllamaApi.Message current) {

models/spring-ai-ollama/src/main/java/org/springframework/ai/ollama/api/OllamaModel.java

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,15 @@
2828
*/
2929
public enum OllamaModel implements ChatModelDescription {
3030

31-
QWEN_2_5_3B("qwen2.5:3b"),
32-
3331
/**
3432
* Qwen 2.5
3533
*/
3634
QWEN_2_5_7B("qwen2.5"),
3735

3836
/**
39-
* Flagship vision-language model of Qwen and also a significant leap from the
40-
* previous Qwen2-VL.
37+
* Qwen3
4138
*/
42-
QWEN2_5_VL("qwen2.5vl"),
43-
44-
/**
45-
* Qwen3 is the latest generation of large language models in Qwen series, offering a
46-
* comprehensive suite of dense and mixture-of-experts (MoE) models.
47-
* Qwen3 1.7b
48-
*/
49-
QWEN3_7B("qwen3:7b"),
50-
51-
/**
52-
* Qwen3 4B
53-
*/
54-
QWEN3_4B("qwen3:4b"),
39+
QWEN_3_8B("qwen3"),
5540

5641
/**
5742
* Qwen3 1.7b
@@ -170,11 +155,6 @@ public enum OllamaModel implements ChatModelDescription {
170155
*/
171156
GEMMA("gemma"),
172157

173-
/**
174-
* The current, most capable model that runs on a single GPU.
175-
*/
176-
GEMMA3("gemma3"),
177-
178158
/**
179159
* Uncensored Llama 2 model
180160
*/

0 commit comments

Comments
 (0)