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) {