diff --git a/server/utils/AiProviders/ollama/index.js b/server/utils/AiProviders/ollama/index.js
index b88a8121870..c07867b0c7a 100644
--- a/server/utils/AiProviders/ollama/index.js
+++ b/server/utils/AiProviders/ollama/index.js
@@ -18,6 +18,7 @@ class OllamaAILLM {
if (!process.env.OLLAMA_BASE_PATH)
throw new Error("No Ollama Base Path was set.");
+ this.className = "OllamaAILLM";
this.authToken = process.env.OLLAMA_AUTH_TOKEN;
this.basePath = process.env.OLLAMA_BASE_PATH;
this.model = modelPreference || process.env.OLLAMA_MODEL_PREF;
@@ -257,8 +258,14 @@ class OllamaAILLM {
},
})
.then((res) => {
+ let content = res.message.content;
+
+ if (res.message.thinking) {
+ content = `${res.message.thinking}${content}`;
+ }
+
return {
- content: res.message.content,
+ content,
usage: {
prompt_tokens: res.prompt_eval_count,
completion_tokens: res.eval_count,
@@ -339,6 +346,8 @@ class OllamaAILLM {
};
response.on("close", handleAbort);
+ let hasOpenedThinkTag = false;
+ let hasClosedThinkTag = false;
try {
for await (const chunk of stream) {
if (chunk === undefined)
@@ -365,15 +374,71 @@ class OllamaAILLM {
if (chunk.hasOwnProperty("message")) {
const content = chunk.message.content;
- fullText += content;
- writeResponseChunk(response, {
- uuid,
- sources,
- type: "textResponseChunk",
- textResponse: content,
- close: false,
- error: false,
- });
+ const thinking = chunk.message.thinking;
+
+ // In newer Ollama versions (v0.9.0+), thinking content comes in a separate property and we have to wrap it in tags ourself.
+ if (thinking) {
+ // Open tag if we haven't already
+ if (!hasOpenedThinkTag) {
+ const openTag = "";
+ writeResponseChunk(response, {
+ uuid,
+ sources,
+ type: "textResponseChunk",
+ textResponse: openTag,
+ close: false,
+ error: false,
+ });
+ fullText += openTag;
+ hasOpenedThinkTag = true;
+ }
+
+ // Write thinking content
+ if (thinking.length > 0) {
+ writeResponseChunk(response, {
+ uuid,
+ sources,
+ type: "textResponseChunk",
+ textResponse: thinking,
+ close: false,
+ error: false,
+ });
+ fullText += thinking;
+ }
+ }
+
+ // Close think tag when thinking is done and we start receiving content
+ if (
+ thinking === undefined &&
+ hasOpenedThinkTag &&
+ !hasClosedThinkTag &&
+ content.length > 0
+ ) {
+ const closeTag = "";
+ writeResponseChunk(response, {
+ uuid,
+ sources,
+ type: "textResponseChunk",
+ textResponse: closeTag,
+ close: false,
+ error: false,
+ });
+ fullText += closeTag;
+ hasClosedThinkTag = true;
+ }
+
+ // Write content, assumes thinking is within the content property wrapped in tags.
+ if (content.length > 0) {
+ fullText += content;
+ writeResponseChunk(response, {
+ uuid,
+ sources,
+ type: "textResponseChunk",
+ textResponse: content,
+ close: false,
+ error: false,
+ });
+ }
}
}
} catch (error) {