fix(ollama): resolve per-provider baseUrl in createStreamFn

The createStreamFn callback hardcoded config.models.providers.ollama.baseUrl,
ignoring the actual provider ID from the context. When multiple Ollama providers
are configured on different ports (e.g. ollama on 11434, ollama2 on 11435), all
requests routed to the first provider's port.

Export resolveConfiguredOllamaProviderConfig from stream.ts and use it with the
ctx.provider parameter to dynamically look up the correct baseUrl per provider.

Closes #61678
This commit is contained in:
Yossi Eliaz
2026-04-06 11:58:19 +03:00
committed by Peter Steinberger
parent 2989b78c12
commit 045d956111
3 changed files with 71 additions and 3 deletions

View File

@@ -19,6 +19,9 @@ const promptAndConfigureOllamaMock = vi.hoisted(() =>
);
const ensureOllamaModelPulledMock = vi.hoisted(() => vi.fn(async () => {}));
const buildOllamaProviderMock = vi.hoisted(() => vi.fn());
const createConfiguredOllamaStreamFnMock = vi.hoisted(() =>
vi.fn((_params: { model: unknown; providerBaseUrl?: string }) => ({}) as never),
);
vi.mock("./api.js", () => ({
promptAndConfigureOllama: promptAndConfigureOllamaMock,
@@ -27,10 +30,19 @@ vi.mock("./api.js", () => ({
buildOllamaProvider: buildOllamaProviderMock,
}));
vi.mock("./src/stream.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("./src/stream.js")>();
return {
...actual,
createConfiguredOllamaStreamFn: createConfiguredOllamaStreamFnMock,
};
});
beforeEach(() => {
promptAndConfigureOllamaMock.mockClear();
ensureOllamaModelPulledMock.mockClear();
buildOllamaProviderMock.mockReset();
createConfiguredOllamaStreamFnMock.mockClear();
});
function registerProvider() {
@@ -207,6 +219,60 @@ describe("ollama plugin", () => {
).toBeUndefined();
});
it("routes createStreamFn to the correct provider baseUrl for ollama2", () => {
const provider = registerProvider();
const config = {
models: {
providers: {
ollama: {
api: "ollama",
baseUrl: "http://127.0.0.1:11434",
models: [],
},
ollama2: {
api: "ollama",
baseUrl: "http://127.0.0.1:11435",
models: [],
},
},
},
};
const model = { id: "llama3.2", provider: "ollama2", baseUrl: undefined };
provider.createStreamFn?.({ config, model, provider: "ollama2" } as never);
expect(createConfiguredOllamaStreamFnMock).toHaveBeenCalledWith(
expect.objectContaining({ providerBaseUrl: "http://127.0.0.1:11435" }),
);
});
it("uses ollama provider baseUrl when provider is ollama (backward compat)", () => {
const provider = registerProvider();
const config = {
models: {
providers: {
ollama: {
api: "ollama",
baseUrl: "http://127.0.0.1:11434",
models: [],
},
ollama2: {
api: "ollama",
baseUrl: "http://127.0.0.1:11435",
models: [],
},
},
},
};
const model = { id: "llama3.2", provider: "ollama", baseUrl: undefined };
provider.createStreamFn?.({ config, model, provider: "ollama" } as never);
expect(createConfiguredOllamaStreamFnMock).toHaveBeenCalledWith(
expect.objectContaining({ providerBaseUrl: "http://127.0.0.1:11434" }),
);
});
it("wraps native Ollama payloads with top-level think=false when thinking is off", () => {
const provider = registerProvider();
let payloadSeen: Record<string, unknown> | undefined;

View File

@@ -23,6 +23,7 @@ import { resolveOllamaApiBase } from "./src/provider-models.js";
import {
createConfiguredOllamaCompatStreamWrapper,
createConfiguredOllamaStreamFn,
resolveConfiguredOllamaProviderConfig,
} from "./src/stream.js";
import { createOllamaWebSearchProvider } from "./src/web-search-provider.js";
@@ -183,10 +184,11 @@ export default definePluginEntry({
}
await ensureOllamaModelPulled({ config, model, prompter });
},
createStreamFn: ({ config, model }) => {
createStreamFn: ({ config, model, provider }) => {
return createConfiguredOllamaStreamFn({
model,
providerBaseUrl: config?.models?.providers?.ollama?.baseUrl,
providerBaseUrl: resolveConfiguredOllamaProviderConfig({ config, providerId: provider })
?.baseUrl,
});
},
...OPENAI_COMPATIBLE_REPLAY_HOOKS,

View File

@@ -50,7 +50,7 @@ export function resolveOllamaBaseUrlForRun(params: {
return OLLAMA_NATIVE_BASE_URL;
}
function resolveConfiguredOllamaProviderConfig(params: {
export function resolveConfiguredOllamaProviderConfig(params: {
config?: OpenClawConfig;
providerId?: string;
}) {