Support for Ollama context window configuration

This commit is contained in:
Willie Zutz
2025-04-20 01:37:10 -06:00
parent 73b5e8832e
commit c0705d1d9e
10 changed files with 170 additions and 54 deletions

55
package-lock.json generated
View File

@ -16,6 +16,7 @@
"@langchain/community": "^0.3.36",
"@langchain/core": "^0.3.42",
"@langchain/google-genai": "^0.1.12",
"@langchain/ollama": "0.2.0",
"@langchain/openai": "^0.0.25",
"@langchain/textsplitters": "^0.1.0",
"@tailwindcss/typography": "^0.5.12",
@ -1989,6 +1990,37 @@
"@langchain/core": ">=0.3.17 <0.4.0"
}
},
"node_modules/@langchain/ollama": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@langchain/ollama/-/ollama-0.2.0.tgz",
"integrity": "sha512-jLlYFqt+nbhaJKLakk7lRTWHZJ7wHeJLM6yuv4jToQ8zPzpL//372+MjggDoW0mnw8ofysg1T2C6mEJspKJtiA==",
"license": "MIT",
"dependencies": {
"ollama": "^0.5.12",
"uuid": "^10.0.0",
"zod": "^3.24.1",
"zod-to-json-schema": "^3.24.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@langchain/core": ">=0.2.21 <0.4.0"
}
},
"node_modules/@langchain/ollama/node_modules/uuid": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
"integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@langchain/openai": {
"version": "0.0.25",
"resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.0.25.tgz",
@ -8221,6 +8253,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/ollama": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/ollama/-/ollama-0.5.15.tgz",
"integrity": "sha512-TSaZSJyP7MQJFjSmmNsoJiriwa3U+/UJRw6+M8aucs5dTsaWNZsBIGpDb5rXnW6nXxJBB/z79gZY8IaiIQgelQ==",
"license": "MIT",
"dependencies": {
"whatwg-fetch": "^3.6.20"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@ -10590,6 +10631,12 @@
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/whatwg-fetch": {
"version": "3.6.20",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
"integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==",
"license": "MIT"
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@ -10965,12 +11012,12 @@
}
},
"node_modules/zod-to-json-schema": {
"version": "3.23.1",
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.1.tgz",
"integrity": "sha512-oT9INvydob1XV0v1d2IadrR74rLtDInLvDFfAa1CG0Pmg/vxATk7I2gSelfj271mbzeM4Da0uuDQE/Nkj3DWNw==",
"version": "3.24.5",
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz",
"integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==",
"license": "ISC",
"peerDependencies": {
"zod": "^3.23.3"
"zod": "^3.24.1"
}
}
}

View File

@ -20,6 +20,7 @@
"@langchain/core": "^0.3.42",
"@langchain/google-genai": "^0.1.12",
"@langchain/openai": "^0.0.25",
"@langchain/ollama": "^0.2.0",
"@langchain/textsplitters": "^0.1.0",
"@tailwindcss/typography": "^0.5.12",
"@xenova/transformers": "^2.17.2",

View File

@ -20,6 +20,7 @@ import {
getCustomOpenaiApiUrl,
getCustomOpenaiModelName,
} from '@/lib/config';
import { ChatOllama } from '@langchain/ollama';
import { searchHandlers } from '@/lib/search';
export const runtime = 'nodejs';
@ -34,6 +35,7 @@ type Message = {
type ChatModel = {
provider: string;
name: string;
ollamaContextWindow?: number;
};
type EmbeddingModel = {
@ -232,6 +234,11 @@ export const POST = async (req: Request) => {
}) as unknown as BaseChatModel;
} else if (chatModelProvider && chatModel) {
llm = chatModel.model;
// Set context window size for Ollama models
if (llm instanceof ChatOllama && body.chatModel?.provider === 'ollama') {
llm.numCtx = body.chatModel.ollamaContextWindow || 2048;
}
}
if (!llm) {

View File

@ -13,12 +13,14 @@ import {
getCustomOpenaiModelName,
} from '@/lib/config';
import { searchHandlers } from '@/lib/search';
import { ChatOllama } from '@langchain/ollama';
interface chatModel {
provider: string;
name: string;
customOpenAIKey?: string;
customOpenAIBaseURL?: string;
ollamaContextWindow?: number;
}
interface embeddingModel {
@ -96,6 +98,10 @@ export const POST = async (req: Request) => {
llm = chatModelProviders[chatModelProvider][chatModel]
.model as unknown as BaseChatModel | undefined;
}
if (llm instanceof ChatOllama && body.chatModel?.provider === 'ollama') {
llm.numCtx = body.chatModel.ollamaContextWindow || 2048;
}
if (
embeddingModelProviders[embeddingModelProvider] &&

View File

@ -8,10 +8,12 @@ import { getAvailableChatModelProviders } from '@/lib/providers';
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { AIMessage, BaseMessage, HumanMessage } from '@langchain/core/messages';
import { ChatOpenAI } from '@langchain/openai';
import { ChatOllama } from '@langchain/ollama';
interface ChatModel {
provider: string;
model: string;
ollamaContextWindow?: number;
}
interface SuggestionsGenerationBody {
@ -57,6 +59,10 @@ export const POST = async (req: Request) => {
}) as unknown as BaseChatModel;
} else if (chatModelProvider && chatModel) {
llm = chatModel.model;
// Set context window size for Ollama models
if (llm instanceof ChatOllama && body.chatModel?.provider === 'ollama') {
llm.numCtx = body.chatModel.ollamaContextWindow || 2048;
}
}
if (!llm) {

View File

@ -494,6 +494,8 @@ const sendMessage = async (
}
};
const ollamaContextWindow = localStorage.getItem('ollamaContextWindow') || '2048';
const res = await fetch('/api/chat', {
method: 'POST',
headers: {
@ -514,6 +516,9 @@ const sendMessage = async (
chatModel: {
name: chatModelProvider.name,
provider: chatModelProvider.provider,
...(chatModelProvider.provider === 'ollama' && {
ollamaContextWindow: parseInt(ollamaContextWindow),
}),
},
embeddingModel: {
name: embeddingModelProvider.name,

View File

@ -80,49 +80,11 @@ const MessageInput = ({
}}
className={cn(
'bg-light-secondary dark:bg-dark-secondary p-4 flex items-center border border-light-200 dark:border-dark-200',
mode === 'multi' ? 'flex-col rounded-lg' : 'flex-row rounded-full',
mode === 'multi' ? 'flex-col rounded-lg' : 'flex-col md:flex-row rounded-lg md:rounded-full',
)}
>
{mode === 'single' && (
<div className="flex flex-row items-center space-x-2">
<AttachSmall
fileIds={fileIds}
setFileIds={setFileIds}
files={files}
setFiles={setFiles}
/>
<Optimization
optimizationMode={optimizationMode}
setOptimizationMode={setOptimizationMode}
/>
</div>
)}
<TextareaAutosize
ref={inputRef}
value={message}
onChange={(e) => setMessage(e.target.value)}
onHeightChange={(height, props) => {
setTextareaRows(Math.ceil(height / props.rowHeight));
}}
className="transition bg-transparent dark:placeholder:text-white/50 placeholder:text-sm text-sm dark:text-white resize-none focus:outline-none w-full px-2 max-h-24 lg:max-h-36 xl:max-h-48 flex-grow flex-shrink"
placeholder="Ask a follow-up"
/>
{mode === 'single' && (
<div className="flex flex-row items-center space-x-4">
<CopilotToggle
copilotEnabled={copilotEnabled}
setCopilotEnabled={setCopilotEnabled}
/>
<button
disabled={message.trim().length === 0 || loading}
className="bg-[#24A0ED] text-white disabled:text-black/50 dark:disabled:text-white/50 hover:bg-opacity-85 transition duration-100 disabled:bg-[#e0e0dc79] dark:disabled:bg-[#ececec21] rounded-full p-2"
>
<ArrowUp className="bg-background" size={17} />
</button>
</div>
)}
{mode === 'multi' && (
<div className="flex flex-row items-center justify-between w-full pt-2">
<div className="flex flex-row items-center justify-between w-full mb-2 md:mb-0 md:w-auto">
<div className="flex flex-row items-center space-x-2">
<AttachSmall
fileIds={fileIds}
@ -135,14 +97,75 @@ const MessageInput = ({
setOptimizationMode={setOptimizationMode}
/>
</div>
<div className="flex flex-row items-center space-x-4">
<div className="md:hidden">
<CopilotToggle
copilotEnabled={copilotEnabled}
setCopilotEnabled={setCopilotEnabled}
/>
</div>
</div>
)}
<div className="flex flex-row items-center w-full">
<TextareaAutosize
ref={inputRef}
value={message}
onChange={(e) => setMessage(e.target.value)}
onHeightChange={(height, props) => {
setTextareaRows(Math.ceil(height / props.rowHeight));
}}
className="transition bg-transparent dark:placeholder:text-white/50 placeholder:text-sm text-sm dark:text-white resize-none focus:outline-none w-full px-2 max-h-24 lg:max-h-36 xl:max-h-48 flex-grow flex-shrink"
placeholder="Ask a follow-up"
/>
{mode === 'single' && (
<div className="flex flex-row items-center space-x-4">
<div className="hidden md:block">
<CopilotToggle
copilotEnabled={copilotEnabled}
setCopilotEnabled={setCopilotEnabled}
/>
</div>
<button
disabled={message.trim().length === 0 || loading}
className="bg-[#24A0ED] text-white text-black/50 dark:disabled:text-white/50 hover:bg-opacity-85 transition duration-100 disabled:bg-[#e0e0dc79] dark:disabled:bg-[#ececec21] rounded-full p-2"
className="bg-[#24A0ED] text-white disabled:text-black/50 dark:disabled:text-white/50 hover:bg-opacity-85 transition duration-100 disabled:bg-[#e0e0dc79] dark:disabled:bg-[#ececec21] rounded-full p-2"
>
<ArrowUp className="bg-background" size={17} />
</button>
</div>
)}
</div>
{mode === 'multi' && (
<div className="flex flex-col md:flex-row items-start md:items-center justify-between w-full pt-2">
<div className="flex flex-row items-center justify-between w-full md:w-auto mb-2 md:mb-0">
<div className="flex flex-row items-center space-x-2">
<AttachSmall
fileIds={fileIds}
setFileIds={setFileIds}
files={files}
setFiles={setFiles}
/>
<Optimization
optimizationMode={optimizationMode}
setOptimizationMode={setOptimizationMode}
/>
</div>
<div className="md:hidden">
<CopilotToggle
copilotEnabled={copilotEnabled}
setCopilotEnabled={setCopilotEnabled}
/>
</div>
</div>
<div className="flex flex-row items-center space-x-4 self-end">
<div className="hidden md:block">
<CopilotToggle
copilotEnabled={copilotEnabled}
setCopilotEnabled={setCopilotEnabled}
/>
</div>
<button
disabled={message.trim().length === 0 || loading}
className="bg-[#24A0ED] text-white disabled:text-black/50 dark:disabled:text-white/50 hover:bg-opacity-85 transition duration-100 disabled:bg-[#e0e0dc79] dark:disabled:bg-[#ececec21] rounded-full p-2"
>
<ArrowUp className="bg-background" size={17} />
</button>

View File

@ -6,8 +6,8 @@ export const PROVIDER_INFO = {
key: 'ollama',
displayName: 'Ollama',
};
import { ChatOllama } from '@langchain/community/chat_models/ollama';
import { OllamaEmbeddings } from '@langchain/community/embeddings/ollama';
import { ChatOllama } from '@langchain/ollama';
import { OllamaEmbeddings } from '@langchain/ollama';
export const loadOllamaChatModels = async () => {
const ollamaApiEndpoint = getOllamaApiEndpoint();

View File

@ -239,7 +239,6 @@ class MetaSearchAgent implements MetaSearchAgentType {
optimizationMode: 'speed' | 'balanced' | 'quality',
systemInstructions: string,
) {
console.log("optimization mode", optimizationMode);
return RunnableSequence.from([
RunnableMap.from({
systemInstructions: () => systemInstructions,

View File

@ -382,6 +382,16 @@
"@google/generative-ai" "^0.24.0"
zod-to-json-schema "^3.22.4"
"@langchain/ollama@0.2.0":
version "0.2.0"
resolved "https://registry.npmjs.org/@langchain/ollama/-/ollama-0.2.0.tgz"
integrity sha512-jLlYFqt+nbhaJKLakk7lRTWHZJ7wHeJLM6yuv4jToQ8zPzpL//372+MjggDoW0mnw8ofysg1T2C6mEJspKJtiA==
dependencies:
ollama "^0.5.12"
uuid "^10.0.0"
zod "^3.24.1"
zod-to-json-schema "^3.24.1"
"@langchain/openai@^0.0.25", "@langchain/openai@~0.0.19":
version "0.0.25"
resolved "https://registry.npmjs.org/@langchain/openai/-/openai-0.0.25.tgz"
@ -3353,6 +3363,13 @@ object.values@^1.1.6, object.values@^1.2.0, object.values@^1.2.1:
define-properties "^1.2.1"
es-object-atoms "^1.0.0"
ollama@^0.5.12:
version "0.5.15"
resolved "https://registry.npmjs.org/ollama/-/ollama-0.5.15.tgz"
integrity sha512-TSaZSJyP7MQJFjSmmNsoJiriwa3U+/UJRw6+M8aucs5dTsaWNZsBIGpDb5rXnW6nXxJBB/z79gZY8IaiIQgelQ==
dependencies:
whatwg-fetch "^3.6.20"
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
@ -4694,6 +4711,11 @@ webidl-conversions@^3.0.0:
resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
whatwg-fetch@^3.6.20:
version "3.6.20"
resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz"
integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz"
@ -4838,10 +4860,10 @@ yocto-queue@^0.1.0:
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zod-to-json-schema@^3.22.3, zod-to-json-schema@^3.22.4, zod-to-json-schema@^3.22.5:
version "3.23.1"
resolved "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.1.tgz"
integrity sha512-oT9INvydob1XV0v1d2IadrR74rLtDInLvDFfAa1CG0Pmg/vxATk7I2gSelfj271mbzeM4Da0uuDQE/Nkj3DWNw==
zod-to-json-schema@^3.22.3, zod-to-json-schema@^3.22.4, zod-to-json-schema@^3.22.5, zod-to-json-schema@^3.24.1:
version "3.24.5"
resolved "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz"
integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==
zod@^3.22.3, zod@^3.22.4:
zod@^3.22.3, zod@^3.22.4, zod@^3.24.1:
version "3.24.2"