Skip to content

Commit 4486b2f

Browse files
committed
fix: respect Ollama Modelfile num_ctx configuration
- Remove automatic num_ctx override in NativeOllamaHandler - Add optional ollamaNumCtx parameter to ApiHandlerOptions for explicit overrides - Update both createMessage and completePrompt to only include num_ctx when explicitly set - Add tests to verify num_ctx is not sent by default This allows Ollama to use the Modelfile-defined num_ctx by default while still providing users the ability to override it when needed. Fixes #7797
1 parent 0ce4e89 commit 4486b2f

File tree

3 files changed

+126
-7
lines changed

3 files changed

+126
-7
lines changed

src/api/providers/__tests__/native-ollama.spec.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,61 @@ describe("NativeOllamaHandler", () => {
7373
expect(results[2]).toEqual({ type: "usage", inputTokens: 10, outputTokens: 2 })
7474
})
7575

76+
it("should not include num_ctx by default", async () => {
77+
// Mock the chat response
78+
mockChat.mockImplementation(async function* () {
79+
yield { message: { content: "Response" } }
80+
})
81+
82+
const stream = handler.createMessage("System", [{ role: "user" as const, content: "Test" }])
83+
84+
// Consume the stream
85+
for await (const _ of stream) {
86+
// consume stream
87+
}
88+
89+
// Verify that num_ctx was NOT included in the options
90+
expect(mockChat).toHaveBeenCalledWith(
91+
expect.objectContaining({
92+
options: expect.not.objectContaining({
93+
num_ctx: expect.anything(),
94+
}),
95+
}),
96+
)
97+
})
98+
99+
it("should include num_ctx when explicitly set via ollamaNumCtx", async () => {
100+
const options: ApiHandlerOptions = {
101+
apiModelId: "llama2",
102+
ollamaModelId: "llama2",
103+
ollamaBaseUrl: "http://localhost:11434",
104+
ollamaNumCtx: 8192, // Explicitly set num_ctx
105+
}
106+
107+
handler = new NativeOllamaHandler(options)
108+
109+
// Mock the chat response
110+
mockChat.mockImplementation(async function* () {
111+
yield { message: { content: "Response" } }
112+
})
113+
114+
const stream = handler.createMessage("System", [{ role: "user" as const, content: "Test" }])
115+
116+
// Consume the stream
117+
for await (const _ of stream) {
118+
// consume stream
119+
}
120+
121+
// Verify that num_ctx was included with the specified value
122+
expect(mockChat).toHaveBeenCalledWith(
123+
expect.objectContaining({
124+
options: expect.objectContaining({
125+
num_ctx: 8192,
126+
}),
127+
}),
128+
)
129+
})
130+
76131
it("should handle DeepSeek R1 models with reasoning detection", async () => {
77132
const options: ApiHandlerOptions = {
78133
apiModelId: "deepseek-r1",
@@ -120,6 +175,49 @@ describe("NativeOllamaHandler", () => {
120175
})
121176
expect(result).toBe("This is the response")
122177
})
178+
179+
it("should not include num_ctx in completePrompt by default", async () => {
180+
mockChat.mockResolvedValue({
181+
message: { content: "Response" },
182+
})
183+
184+
await handler.completePrompt("Test prompt")
185+
186+
// Verify that num_ctx was NOT included in the options
187+
expect(mockChat).toHaveBeenCalledWith(
188+
expect.objectContaining({
189+
options: expect.not.objectContaining({
190+
num_ctx: expect.anything(),
191+
}),
192+
}),
193+
)
194+
})
195+
196+
it("should include num_ctx in completePrompt when explicitly set", async () => {
197+
const options: ApiHandlerOptions = {
198+
apiModelId: "llama2",
199+
ollamaModelId: "llama2",
200+
ollamaBaseUrl: "http://localhost:11434",
201+
ollamaNumCtx: 4096, // Explicitly set num_ctx
202+
}
203+
204+
handler = new NativeOllamaHandler(options)
205+
206+
mockChat.mockResolvedValue({
207+
message: { content: "Response" },
208+
})
209+
210+
await handler.completePrompt("Test prompt")
211+
212+
// Verify that num_ctx was included with the specified value
213+
expect(mockChat).toHaveBeenCalledWith(
214+
expect.objectContaining({
215+
options: expect.objectContaining({
216+
num_ctx: 4096,
217+
}),
218+
}),
219+
)
220+
})
123221
})
124222

125223
describe("error handling", () => {

src/api/providers/native-ollama.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,15 +184,22 @@ export class NativeOllamaHandler extends BaseProvider implements SingleCompletio
184184
)
185185

186186
try {
187+
// Build options object conditionally
188+
const chatOptions: any = {
189+
temperature: this.options.modelTemperature ?? (useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
190+
}
191+
192+
// Only include num_ctx if explicitly set via ollamaNumCtx
193+
if (this.options.ollamaNumCtx !== undefined) {
194+
chatOptions.num_ctx = this.options.ollamaNumCtx
195+
}
196+
187197
// Create the actual API request promise
188198
const stream = await client.chat({
189199
model: modelId,
190200
messages: ollamaMessages,
191201
stream: true,
192-
options: {
193-
num_ctx: modelInfo.contextWindow,
194-
temperature: this.options.modelTemperature ?? (useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
195-
},
202+
options: chatOptions,
196203
})
197204

198205
let totalInputTokens = 0
@@ -274,13 +281,21 @@ export class NativeOllamaHandler extends BaseProvider implements SingleCompletio
274281
const { id: modelId } = await this.fetchModel()
275282
const useR1Format = modelId.toLowerCase().includes("deepseek-r1")
276283

284+
// Build options object conditionally
285+
const chatOptions: any = {
286+
temperature: this.options.modelTemperature ?? (useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
287+
}
288+
289+
// Only include num_ctx if explicitly set via ollamaNumCtx
290+
if (this.options.ollamaNumCtx !== undefined) {
291+
chatOptions.num_ctx = this.options.ollamaNumCtx
292+
}
293+
277294
const response = await client.chat({
278295
model: modelId,
279296
messages: [{ role: "user", content: prompt }],
280297
stream: false,
281-
options: {
282-
temperature: this.options.modelTemperature ?? (useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
283-
},
298+
options: chatOptions,
284299
})
285300

286301
return response.message?.content || ""

src/shared/api.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ export type ApiHandlerOptions = Omit<ProviderSettings, "apiProvider"> & {
1414
* Defaults to true; set to false to disable summaries.
1515
*/
1616
enableGpt5ReasoningSummary?: boolean
17+
/**
18+
* Optional override for Ollama's num_ctx parameter.
19+
* When set, this value will be used in Ollama chat requests.
20+
* When undefined, Ollama will use the model's default num_ctx from the Modelfile.
21+
*/
22+
ollamaNumCtx?: number
1723
}
1824

1925
// RouterName

0 commit comments

Comments
 (0)