The streamFunctionCallTest failed in CI and also on my local machine.

I disabled it but then OllamaChatModelIT.mapOutputConvert failed in CI, but not on my local machine.

here are the errors

Error:  Errors: 
Error:  org.springframework.ai.ollama.OllamaChatModelFunctionCallingIT.streamFunctionCallTest
Error:    Run 1: OllamaChatModelFunctionCallingIT.streamFunctionCallTest:109 

There is also this error, not related but should be looked at. It seems it can't connect to ollama, but the message is null, so probably something needs to be improved not just here since most chat models follow a similar code path.


2024-12-08T22:32:46.960Z  INFO 4348 --- [           main] o.s.ai.ollama.OllamaChatModelIT          : Starting OllamaChatModelIT using Java 17.0.13 with PID 4348 (started by runner in /home/runner/work/spring-ai/spring-ai/models/spring-ai-ollama)
2024-12-08T22:32:46.960Z  INFO 4348 --- [           main] o.s.ai.ollama.OllamaChatModelIT          : No active profile set, falling back to 1 default profile: "default"
2024-12-08T22:32:46.981Z  INFO 4348 --- [           main] tc.ollama/ollama:0.3.14                  : Creating container for image: ollama/ollama:0.3.14
2024-12-08T22:32:47.002Z  INFO 4348 --- [           main] tc.ollama/ollama:0.3.14                  : Container ollama/ollama:0.3.14 is starting: 1113c49b1dead7d55dd6cdde03cd95fbcc226f38cc5df799a024a9eefc56a2bd
2024-12-08T22:32:47.284Z  INFO 4348 --- [           main] tc.ollama/ollama:0.3.14                  : Container ollama/ollama:0.3.14 started in PT0.303834581S
2024-12-08T22:32:47.292Z  INFO 4348 --- [           main] o.s.a.o.management.OllamaModelManager    : Start pulling model: llama3.2
2024-12-08T22:32:48.743Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: pulling manifest
2024-12-08T22:32:54.416Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: pulling dde5aa3fc5ff
2024-12-08T22:32:56.286Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: pulling 966de95ca8a6
2024-12-08T22:32:58.196Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: pulling fcc5a6bec9da
2024-12-08T22:33:00.150Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: pulling a70ff7e570d9
2024-12-08T22:33:01.988Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: pulling 56bb8bd477a5
2024-12-08T22:33:02.956Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: pulling 34bb5ab01051
2024-12-08T22:33:04.480Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: verifying sha256 digest
2024-12-08T22:33:04.480Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: writing manifest
2024-12-08T22:33:04.481Z  INFO 4348 --- [ent-20-Worker-0] o.s.a.o.management.OllamaModelManager    : Pulling the 'llama3.2' model - Status: success
2024-12-08T22:33:04.481Z  INFO 4348 --- [           main] o.s.a.o.management.OllamaModelManager    : Completed pulling the 'llama3.2' model
2024-12-08T22:33:04.485Z  INFO 4348 --- [           main] o.s.a.o.management.OllamaModelManager    : Start pulling model: tinyllama
2024-12-08T22:33:05.762Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: pulling manifest
2024-12-08T22:33:09.658Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: pulling 2af3b81862c6
2024-12-08T22:33:11.527Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: pulling af0ddbdaaa26
2024-12-08T22:33:13.480Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: pulling c8472cd9daed
2024-12-08T22:33:15.511Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: pulling fa956ab37b8c
2024-12-08T22:33:16.482Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: pulling 6331358be52a
2024-12-08T22:33:16.962Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: verifying sha256 digest
2024-12-08T22:33:16.962Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: writing manifest
2024-12-08T22:33:16.962Z  INFO 4348 --- [ent-20-Worker-2] o.s.a.o.management.OllamaModelManager    : Pulling the 'tinyllama' model - Status: success
2024-12-08T22:33:16.962Z  INFO 4348 --- [           main] o.s.a.o.management.OllamaModelManager    : Completed pulling the 'tinyllama' model
2024-12-08T22:33:16.966Z  INFO 4348 --- [           main] o.s.ai.ollama.OllamaChatModelIT          : Started OllamaChatModelIT in 30.022 seconds (process running for 550.688)
2024-12-08T22:36:39.382Z  INFO 4348 --- [           main] o.s.a.o.management.OllamaModelManager    : Start deletion of model: tinyllama
2024-12-08T22:36:39.501Z  INFO 4348 --- [           main] o.s.a.o.management.OllamaModelManager    : Completed deletion of model: tinyllama
[INFO] Tests run: 8, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 252.2 s -- in org.springframework.ai.ollama.OllamaChatModelIT
[INFO] Running org.springframework.ai.ollama.OllamaChatModelFunctionCallingIT
2024-12-08T22:36:59.133Z ERROR 4348 --- [onPool-worker-5] o.s.ai.chat.model.MessageAggregator      : Aggregation Error

org.springframework.web.reactive.function.client.WebClientRequestException: null
    at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:136) ~[spring-webflux-6.1.15.jar:6.1.15]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ⇢ Request to POST http://localhost:32768/api/chat [DefaultWebClient]
Original Stack Trace:
        at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:136) ~[spring-webflux-6.1.15.jar:6.1.15]
        at reactor.core.publisher.MonoErrorSupplied.subscribe(MonoErrorSupplied.java:55) ~[reactor-core-3.6.12.jar:3.6.12]
        at reactor.core.publisher.Mono.subscribe(Mono.java:4576) ~[reactor-core-3.6.12.jar:3.6.12]
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.6.12.jar:3.6.12]
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222) ~[reactor-core-3.6.12.jar:3.6.12]
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:222) ~[reactor-core-3.6.12.jar:3.6.12]
        at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:280) ~[reactor-core-3.6.12.jar:3.6.12]
        at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:134) ~[reactor-core-3.6.12.jar:3.6.12]
        at reactor.core.publisher.MonoCompletionStage$MonoCompletionStageSubscription.apply(MonoCompletionStage.java:115) ~[reactor-core-3.6.12.jar:3.6.12]
        at reactor.core.publisher.MonoCompletionStage$MonoCompletionStageSubscription.apply(MonoCompletionStage.java:67) ~[reactor-core-3.6.12.jar:3.6.12]
        at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:614) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:844) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:483) ~[na:na]
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) ~[na:na]
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[na:na]
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[na:na]
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[na:na]
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[na:na]
Caused by: java.net.ConnectException: null
    at java.net.http/jdk.internal.net.http.common.Utils.toConnectException(Utils.java:1083) ~[java.net.http:na]
    at java.net.http/jdk.internal.net.http.PlainHttpConnection.connectAsync(PlainHttpConnection.java:198) ~[java.net.http:na]
    at java.net.http/jdk.internal.net.http.PlainHttpConnection.checkRetryConnect(PlainHttpConnection.java:230) ~[java.net.http:na]
    at java.net.http/jdk.internal.net.http.PlainHttpConnection.lambda$connectAsync$1(PlainHttpConnection.java:206) ~[java.net.http:na]
    at java.base/java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:934) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:911) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1773) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]
Caused by: java.nio.channels.ClosedChannelException: null
    at java.base/sun.nio.ch.SocketChannelImpl.ensureOpen(SocketChannelImpl.java:195) ~[na:na]
    at java.base/sun.nio.ch.SocketChannelImpl.beginConnect(SocketChannelImpl.java:760) ~[na:na]
    at java.base/sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:848) ~[na:na]
    at java.net.http/jdk.internal.net.http.PlainHttpConnection.lambda$connectAsync$0(PlainHttpConnection.java:183) ~[java.net.http:na]
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:569) ~[na:na]
    at java.net.http/jdk.internal.net.http.PlainHttpConnection.connectAsync(PlainHttpConnection.java:185) ~[java.net.http:na]
    ... 9 common frames omitted

and

Error:  Tests run: 8, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 251.6 s <<< FAILURE! -- in org.springframework.ai.ollama.OllamaChatModelIT
Error:  org.springframework.ai.ollama.OllamaChatModelIT.mapOutputConvert -- Time elapsed: 7.332 s <<< ERROR!
org.springframework.messaging.converter.MessageConversionException: 
Could not read JSON: Unexpected end-of-input: expected close marker for Object (start marker at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1])
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 4, column: 14], failedMessage=GenericMessage [payload=byte[45], headers={id=f2d2cf26-4ff0-4a32-ebd5-f23ce0a074a7, timestamp=1733715502608}]
    at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:256)
    at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:183)
    at org.springframework.messaging.converter.AbstractMessageConverter.fromMessage(AbstractMessageConverter.java:174)
    at org.springframework.ai.converter.MapOutputConverter.convert(MapOutputConverter.java:49)
    at org.springframework.ai.ollama.OllamaChatModelIT.mapOutputConvert(OllamaChatModelIT.java:178)
    at java.base/java.lang.reflect.Method.invoke(Method.java:569)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: expected close marker for Object (start marker at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1])
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 4, column: 14]
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportInvalidEOF(ParserMinimalBase.java:585)
    at com.fasterxml.jackson.core.base.ParserBase._handleEOF(ParserBase.java:535)
    at com.fasterxml.jackson.core.base.ParserBase._eofAsNextChar(ParserBase.java:552)
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._skipWSOrEnd(UTF8StreamJsonParser.java:3066)
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextFieldName(UTF8StreamJsonParser.java:999)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:608)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:449)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:32)
    at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4899)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3940)
    at org.springframework.messaging.converter.MappingJackson2MessageConverter.convertFromInternal(MappingJackson2MessageConverter.java:242)
    ... 7 more

Comment From: markpollack

The test fails as well on my local machine, seems like the response is the really the xml to call the tool.

2024-12-08T22:08:53.247-05:00  INFO 998046 --- [           main] o.s.a.o.OllamaChatModelFunctionCallingIT : Response: <tool_call>
{"name": "getCurrentWeather", "arguments": {"location": "San Francisco, CA", "unit": "C"}}
</tool_call>
ază
Get current weather information for location: San Francisco, CA with unit C.
<tool_call>
{"name": "getCurrentWeather", "arguments": {"location": "Tokyo, JP", "unit": "C"}}
</tool_call>
ază
Get current weather information for location: Tokyo, JP with unit C.
<tool_call>
{"name": "getCurrentWeather", "arguments": {"location": "Paris, FR", "unit": "C"}}
</tool_call>

Unrelated to function calling when streaming, but to hopefully add stability in CI, I've added the env var OLLAMA_WITH_REUSE=true to the github action for running the CI tests. It doesn't address the issue in question, but perhaps will reduce it's frequency as the model isn't getting pulled over and over again, maybe there is a timing issue in terms of when starts serving the model and that is why there was a connection exception.

Comment From: tzolov

The Ollama streaming tests failures should be resolved by : https://github.com/spring-projects/spring-ai/commit/9f775ab2c24b3b25a733bb5ca34ed663eb7d3e93 It was due to an outdated ollama docker images