// Ollama tests cover provider models plugin behavior. import { once } from "node:events"; import { createServer } from "node:http"; import type { Socket } from "node:net"; import { expectDefined } from "@openclaw/normalization-core"; import { jsonResponse, requestBodyText, requestUrl } from "openclaw/plugin-sdk/test-env"; import { afterEach, describe, expect, it, vi } from "vitest"; import { buildOllamaProvider, buildOllamaModelDefinition, capLocalOllamaProviderContext, enrichOllamaModelsWithContext, fetchLoadedOllamaModelNames, isOllamaCloudModel, fetchOllamaModels, queryOllamaModelShowInfo, readOllamaModelShowInfo, resolveOllamaApiBase, type OllamaTagModel, } from "./provider-models.js"; function cancelTrackedResponse( text: string, init: ResponseInit, ): { response: Response; wasCanceled: () => boolean; } { let canceled = false; const stream = new ReadableStream({ start(controller) { controller.enqueue(new TextEncoder().encode(text)); }, cancel() { canceled = true; }, }); return { response: new Response(stream, init), wasCanceled: () => canceled, }; } describe("ollama provider models", () => { afterEach(() => { vi.unstubAllGlobals(); }); it("strips /v1 when resolving the Ollama API base", () => { expect(resolveOllamaApiBase("http://127.0.0.1:11434/v1")).toBe("http://127.0.0.1:11434"); expect(resolveOllamaApiBase("http://127.0.0.1:11434///")).toBe("http://127.0.0.1:11434"); }); it("inspects local models using Ollama's canonical model request field", async () => { const fetchMock = vi.fn(async (_input: string | URL | Request, _init?: RequestInit) => jsonResponse({ model_info: {} }), ); vi.stubGlobal("fetch", fetchMock); await readOllamaModelShowInfo("http://127.0.0.1:11434", "gemma4:e2b"); const request = fetchMock.mock.calls[0]?.[1] as RequestInit | undefined; expect(JSON.parse(requestBodyText(request?.body))).toEqual({ model: "gemma4:e2b" }); }); it("caps local discovered runtime context while preserving native metadata", () => { const provider = capLocalOllamaProviderContext({ api: "ollama", baseUrl: "http://127.0.0.1:11434", models: [ buildOllamaModelDefinition("qwen3.5:4b", 262_144), buildOllamaModelDefinition("small", 16_384), buildOllamaModelDefinition("glm-5.2:cloud", 1_000_000), buildOllamaModelDefinition("gpt-oss:120b-cloud", 131_072), buildOllamaModelDefinition("local-cloud", 65_536), ], }); expect(provider.models).toEqual([ expect.objectContaining({ contextWindow: 262_144, contextTokens: 32_768 }), expect.objectContaining({ contextWindow: 16_384, contextTokens: 16_384 }), expect.objectContaining({ id: "glm-5.2:cloud", contextWindow: 1_000_000 }), expect.objectContaining({ id: "gpt-oss:120b-cloud", contextWindow: 131_072 }), expect.objectContaining({ id: "local-cloud", contextTokens: 32_768 }), ]); expect(provider.models?.[2]).not.toHaveProperty("contextTokens"); expect(provider.models?.[3]).not.toHaveProperty("contextTokens"); }); it.each([ ["glm-5.2:cloud", true], ["gpt-oss:120b-cloud", true], ["local-cloud", false], ["invalid:cloud-cloud", false], ["invalid:local:cloud", false], ["invalid:local-cloud", false], ["invalid:cloud:local", false], ])("classifies Ollama model source %s", (modelId, expected) => { expect(isOllamaCloudModel(modelId)).toBe(expected); }); it("sets discovered models with context windows from /api/show", async () => { const models: OllamaTagModel[] = [{ name: "llama3:8b" }, { name: "deepseek-r1:14b" }]; const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => { const url = requestUrl(input); if (!url.endsWith("/api/show")) { throw new Error(`Unexpected fetch: ${url}`); } const body = JSON.parse(requestBodyText(init?.body)) as { model?: string }; if (body.model === "llama3:8b") { return jsonResponse({ model_info: { "llama.context_length": 65536 } }); } return jsonResponse({}); }); vi.stubGlobal("fetch", fetchMock); const enriched = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", models); expect(enriched).toEqual([ { name: "llama3:8b", contextWindow: 65536, capabilities: undefined }, { name: "deepseek-r1:14b", contextWindow: undefined, capabilities: undefined }, ]); const fallbackModel = expectDefined(enriched[1], "fallback Ollama model"); expect( buildOllamaModelDefinition( fallbackModel.name, fallbackModel.contextWindow, fallbackModel.capabilities, ).compat?.supportsTools, ).toBe(true); }); it("forwards remote auth to model listing and show probes", async () => { const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => { expect(new Headers(init?.headers).get("Authorization")).toBe("Bearer cloud-key"); const url = requestUrl(input); if (url.endsWith("/api/tags")) { return jsonResponse({ models: [{ name: "glm-5.2:cloud" }] }); } if (url.endsWith("/api/show")) { return jsonResponse({ model_info: { "glm5.2.context_length": 1_000_000 }, capabilities: ["completion", "thinking", "tools"], }); } throw new Error(`Unexpected fetch: ${url}`); }); vi.stubGlobal("fetch", fetchMock); const provider = await buildOllamaProvider("https://ollama.com", { apiKey: "cloud-key", }); expect(provider.models).toEqual([ expect.objectContaining({ id: "glm-5.2:cloud", contextWindow: 1_000_000, maxTokens: 8_192, reasoning: true, }), ]); expect(fetchMock).toHaveBeenCalledTimes(2); }); it("reads loaded models from /api/ps with remote auth", async () => { const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => { expect(requestUrl(input)).toBe("https://ollama.example.com/api/ps"); expect(new Headers(init?.headers).get("Authorization")).toBe("Bearer private-key"); return jsonResponse({ models: [{ name: "qwen3.5:4b" }, { model: "llama3.3:70b" }, { name: " " }, {}], }); }); vi.stubGlobal("fetch", fetchMock); await expect( fetchLoadedOllamaModelNames("https://ollama.example.com/v1", { apiKey: "private-key", }), ).resolves.toEqual({ reachable: true, models: ["qwen3.5:4b", "llama3.3:70b"], }); }); it("discovers a chat model after 200 embedding-only catalog entries", async () => { const embeddingModels = Array.from({ length: 200 }, (_, index) => ({ name: `embedding-${index}:latest`, })); const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => { const url = requestUrl(input); if (url.endsWith("/api/tags")) { return jsonResponse({ models: [...embeddingModels, { name: "qwen-chat:latest" }], }); } if (url.endsWith("/api/show")) { const body = JSON.parse(requestBodyText(init?.body)) as { model?: string }; const completion = body.model === "qwen-chat:latest"; return jsonResponse({ capabilities: completion ? ["completion", "tools"] : ["embedding"], model_info: completion ? { "qwen.context_length": 32_768 } : {}, }); } throw new Error(`Unexpected fetch: ${url}`); }); vi.stubGlobal("fetch", fetchMock); const provider = await buildOllamaProvider("http://127.0.0.1:11434"); expect(provider.models?.map((model) => model.id)).toEqual(["qwen-chat:latest"]); expect(provider.models?.[0]?.contextWindow).toBe(32_768); expect(fetchMock).toHaveBeenCalledTimes(202); }); it("scopes cached show metadata by credential", async () => { const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => { const url = requestUrl(input); if (url.endsWith("/api/tags")) { return jsonResponse({ models: [{ name: "private-model", digest: "stable" }] }); } const apiKey = new Headers(init?.headers).get("Authorization"); return jsonResponse({ model_info: { "private.context_length": apiKey === "Bearer account-a" ? 16_000 : 32_000, }, }); }); vi.stubGlobal("fetch", fetchMock); const first = await buildOllamaProvider("https://ollama.example.com", { apiKey: "account-a", }); const second = await buildOllamaProvider("https://ollama.example.com", { apiKey: "account-b", }); expect(first.models?.[0]?.contextWindow).toBe(16_000); expect(second.models?.[0]?.contextWindow).toBe(32_000); expect(fetchMock).toHaveBeenCalledTimes(4); }); it("recognizes the static Ollama Cloud GLM-5.2 model as reasoning-capable", () => { expect(buildOllamaModelDefinition("glm-5.2:cloud")).toEqual( expect.objectContaining({ reasoning: true, contextWindow: 1_000_000, maxTokens: 8192, }), ); }); it("uses Modelfile num_ctx when it expands the discovered context window", async () => { const models: OllamaTagModel[] = [{ name: "llama3-32k:latest" }]; const fetchMock = vi.fn(async () => jsonResponse({ model_info: { "llama.context_length": 8192 }, parameters: 'stop "<|eot_id|>"\nnum_ctx 32768\nnum_keep 5', capabilities: ["completion"], }), ); vi.stubGlobal("fetch", fetchMock); const enriched = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", models); expect(enriched).toEqual([ { name: "llama3-32k:latest", contextWindow: 32768, capabilities: ["completion"], }, ]); }); it("keeps the larger native context window when Modelfile num_ctx is smaller", async () => { const models: OllamaTagModel[] = [{ name: "llama3.2:latest" }]; const fetchMock = vi.fn(async () => jsonResponse({ model_info: { "llama.context_length": 131072 }, parameters: "num_ctx 4096", }), ); vi.stubGlobal("fetch", fetchMock); const enriched = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", models); expect(enriched[0]?.contextWindow).toBe(131072); }); it("uses positive num_ctx when /api/show omits model context metadata", async () => { const models: OllamaTagModel[] = [{ name: "custom-model:latest" }]; const fetchMock = vi.fn(async () => jsonResponse({ model_info: {}, parameters: "num_ctx 16384", }), ); vi.stubGlobal("fetch", fetchMock); const enriched = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", models); expect(enriched[0]?.contextWindow).toBe(16384); }); it("sets models with vision capability from /api/show capabilities", async () => { const models: OllamaTagModel[] = [{ name: "kimi-k2.5:cloud" }, { name: "glm-5.1:cloud" }]; const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => { const url = requestUrl(input); if (!url.endsWith("/api/show")) { throw new Error(`Unexpected fetch: ${url}`); } const body = JSON.parse(requestBodyText(init?.body)) as { model?: string }; if (body.model === "kimi-k2.5:cloud") { return jsonResponse({ model_info: { "kimi-k2.context_length": 262144 }, capabilities: ["vision", "thinking", "completion", "tools"], }); } if (body.model === "glm-5.1:cloud") { return jsonResponse({ model_info: { "glm5.context_length": 202752 }, capabilities: ["thinking", "completion", "tools"], }); } return jsonResponse({}); }); vi.stubGlobal("fetch", fetchMock); const enriched = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", models); expect(enriched).toEqual([ { name: "kimi-k2.5:cloud", contextWindow: 262144, capabilities: ["vision", "thinking", "completion", "tools"], }, { name: "glm-5.1:cloud", contextWindow: 202752, capabilities: ["thinking", "completion", "tools"], }, ]); }); it("reuses cached /api/show metadata when the model digest is unchanged", async () => { const models: OllamaTagModel[] = [ { name: "qwen3:32b", digest: "sha256:abc123", modified_at: "2026-04-11T00:00:00Z" }, ]; const fetchMock = vi.fn(async () => jsonResponse({ model_info: { "qwen3.context_length": 131072 }, capabilities: ["thinking", "tools"], }), ); vi.stubGlobal("fetch", fetchMock); const first = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", models); const second = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", models); expect(first).toEqual(second); expect(fetchMock).toHaveBeenCalledTimes(1); }); it("refreshes cached /api/show metadata when the model digest changes", async () => { const fetchMock = vi .fn() .mockResolvedValueOnce( jsonResponse({ model_info: { "qwen3.context_length": 131072 }, capabilities: ["thinking", "tools"], }), ) .mockResolvedValueOnce( jsonResponse({ model_info: { "qwen3.context_length": 262144 }, capabilities: ["vision", "thinking", "tools"], }), ); vi.stubGlobal("fetch", fetchMock); const first = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", [ { name: "qwen3:32b", digest: "sha256:refresh-old" }, ]); const second = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", [ { name: "qwen3:32b", digest: "sha256:refresh-new" }, ]); expect(first).toEqual([ { name: "qwen3:32b", digest: "sha256:refresh-old", contextWindow: 131072, capabilities: ["thinking", "tools"], }, ]); expect(second).toEqual([ { name: "qwen3:32b", digest: "sha256:refresh-new", contextWindow: 262144, capabilities: ["vision", "thinking", "tools"], }, ]); expect(fetchMock).toHaveBeenCalledTimes(2); }); it("retries /api/show after an empty result for the same digest", async () => { const fetchMock = vi .fn() .mockResolvedValueOnce(jsonResponse({})) .mockResolvedValueOnce( jsonResponse({ model_info: { "qwen3.context_length": 131072 }, capabilities: ["thinking", "tools"], }), ); vi.stubGlobal("fetch", fetchMock); const model: OllamaTagModel = { name: "qwen3:32b", digest: "sha256:retry-empty" }; const first = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", [model]); const second = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", [model]); expect(first).toEqual([ { name: "qwen3:32b", digest: "sha256:retry-empty", contextWindow: undefined, capabilities: undefined, }, ]); expect(second).toEqual([ { name: "qwen3:32b", digest: "sha256:retry-empty", contextWindow: 131072, capabilities: ["thinking", "tools"], }, ]); expect(fetchMock).toHaveBeenCalledTimes(2); }); it("normalizes /v1 base URLs before fetching and reuses the same cache entry", async () => { const model: OllamaTagModel = { name: "qwen3:32b", digest: "sha256:normalized-base" }; const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => { expect(requestUrl(input)).toBe("http://127.0.0.1:11434/api/show"); expect(JSON.parse(requestBodyText(init?.body))).toEqual({ model: "qwen3:32b" }); return jsonResponse({ model_info: { "qwen3.context_length": 131072 }, capabilities: ["thinking", "tools"], }); }); vi.stubGlobal("fetch", fetchMock); const first = await enrichOllamaModelsWithContext("http://127.0.0.1:11434/v1/", [model]); const second = await enrichOllamaModelsWithContext("http://127.0.0.1:11434", [model]); expect(first).toEqual(second); expect(fetchMock).toHaveBeenCalledTimes(1); }); it("buildOllamaModelDefinition sets input to text+image when vision capability is present", () => { const visionModel = buildOllamaModelDefinition("kimi-k2.5:cloud", 262144, [ "vision", "completion", "tools", "thinking", ]); expect(visionModel.input).toEqual(["text", "image"]); expect(visionModel.reasoning).toBe(true); expect(visionModel.compat?.supportsTools).toBe(true); expect(visionModel.compat?.supportsUsageInStreaming).toBe(true); expect(visionModel.compat?.supportsJsonSchemaResponseFormat).toBe(false); const textModel = buildOllamaModelDefinition("glm-5.1:cloud", 202752, ["completion", "tools"]); expect(textModel.input).toEqual(["text"]); expect(textModel.reasoning).toBe(false); expect(textModel.compat?.supportsTools).toBe(true); expect(textModel.compat?.supportsUsageInStreaming).toBe(true); const deepseekCloudModel = buildOllamaModelDefinition("deepseek-v4-pro:cloud", 1048576, [ "completion", "tools", ]); expect(deepseekCloudModel.reasoning).toBe(true); expect(deepseekCloudModel.compat?.supportsTools).toBe(true); const deepseekCloudModelWithoutCapabilities = buildOllamaModelDefinition( "deepseek-v4-flash:cloud", 1048576, ); expect(deepseekCloudModelWithoutCapabilities.reasoning).toBe(true); const noCapabilities = buildOllamaModelDefinition("unknown-model", 65536); expect(noCapabilities.input).toEqual(["text"]); expect(noCapabilities.compat?.supportsTools).toBe(true); expect(noCapabilities.compat?.supportsUsageInStreaming).toBe(true); expect(noCapabilities.compat?.supportsJsonSchemaResponseFormat).toBe(true); }); it("disables tool support when Ollama capabilities omit tools", () => { const model = buildOllamaModelDefinition("embeddinggemma:latest", 2048, ["embedding"]); expect(model.reasoning).toBe(false); expect(model.compat?.supportsTools).toBe(false); expect(model.compat?.supportsUsageInStreaming).toBe(true); }); it("keeps failed inspection distinct from omitted and empty capabilities", () => { const uninspected = buildOllamaModelDefinition("deepseek-r1:14b", 65536); const authoritativeEmpty = buildOllamaModelDefinition("deepseek-r1:14b", 65536, []); const inspectionFailed = buildOllamaModelDefinition("deepseek-r1:14b", 65536, undefined, { showInspectionFailed: true, }); expect(uninspected).toMatchObject({ reasoning: true, compat: { supportsTools: true }, }); expect(authoritativeEmpty).toMatchObject({ reasoning: false, compat: { supportsTools: false }, }); expect(inspectionFailed).toMatchObject({ reasoning: true, compat: { supportsTools: false }, }); }); it.each([ { parameters: "num_ctx 8192\nnum_ctx 32768", expected: 32768 }, { parameters: "temperature 0.8\nnum_ctx -1\nnum_ctx 0", expected: undefined }, { parameters: 'stop "<|eot_id|>"', expected: undefined }, { parameters: { num_ctx: 8192 }, expected: undefined }, ])("reads Modelfile num_ctx through the model show query", async ({ parameters, expected }) => { vi.stubGlobal( "fetch", vi.fn(async () => jsonResponse({ model_info: {}, parameters })), ); const info = await queryOllamaModelShowInfo("http://127.0.0.1:11434", "test-model"); expect(info.contextWindow).toBe(expected); }); it("cancels non-OK discovery response bodies before fallback results", async () => { const tagsResponse = cancelTrackedResponse("ollama unavailable", { status: 503 }); vi.stubGlobal( "fetch", vi.fn(async () => tagsResponse.response), ); await expect(fetchOllamaModels("http://127.0.0.1:11434")).resolves.toEqual({ reachable: true, models: [], }); expect(tagsResponse.wasCanceled()).toBe(true); const psResponse = cancelTrackedResponse("process listing unavailable", { status: 503 }); vi.stubGlobal( "fetch", vi.fn(async () => psResponse.response), ); await expect(fetchLoadedOllamaModelNames("http://127.0.0.1:11434")).resolves.toEqual({ reachable: true, models: [], }); expect(psResponse.wasCanceled()).toBe(true); const showResponse = cancelTrackedResponse("model unavailable", { status: 503 }); vi.stubGlobal( "fetch", vi.fn(async () => showResponse.response), ); await expect(queryOllamaModelShowInfo("http://127.0.0.1:11434", "llama3:8b")).resolves.toEqual({ showInspectionFailed: true, }); expect(showResponse.wasCanceled()).toBe(true); }); it("reports failed strict model inspections while releasing their response bodies", async () => { const showResponse = cancelTrackedResponse("model unavailable", { status: 503 }); vi.stubGlobal( "fetch", vi.fn(async () => showResponse.response), ); await expect(readOllamaModelShowInfo("http://127.0.0.1:11434", "llama3:8b")).rejects.toThrow( "Ollama model inspection failed with HTTP 503", ); expect(showResponse.wasCanceled()).toBe(true); }); it("closes real failed discovery sockets while preserving successful discovery", async () => { const sockets = new Set(); const socketClosures = new Map>(); let mode: "failure" | "success" = "failure"; const server = createServer((request, response) => { const path = request.url; if (path !== "/api/tags" && path !== "/api/show") { response.writeHead(404); response.end(); return; } if (mode === "failure") { socketClosures.set( path, new Promise((resolve) => { request.socket.once("close", () => resolve()); }), ); response.writeHead(503, { "content-type": "text/plain" }); // Leave the body open so only real client cancellation can close its socket. response.write("ollama unavailable"); return; } response.writeHead(200, { "content-type": "application/json" }); if (path === "/api/tags") { response.end(JSON.stringify({ models: [{ name: "llama3:8b" }] })); return; } response.end( JSON.stringify({ model_info: { "llama.context_length": 32768 }, capabilities: ["completion", "tools"], }), ); }); server.on("connection", (socket) => { sockets.add(socket); socket.once("close", () => sockets.delete(socket)); }); const waitForSocketClose = async (path: string): Promise => { const closed = socketClosures.get(path); if (!closed) { throw new Error(`No failed discovery socket was recorded for ${path}`); } let timeout: ReturnType | undefined; try { await Promise.race([ closed, new Promise((_resolve, reject) => { timeout = setTimeout(() => { reject(new Error(`Failed discovery socket was not closed for ${path}`)); }, 2_000); }), ]); } finally { if (timeout !== undefined) { clearTimeout(timeout); } } }; const listening = once(server, "listening"); try { server.listen(0, "127.0.0.1"); await listening; const address = server.address(); if (!address || typeof address === "string") { throw new Error("Ollama test server did not expose a TCP address"); } const baseUrl = `http://127.0.0.1:${address.port}`; await expect(fetchOllamaModels(baseUrl)).resolves.toEqual({ reachable: true, models: [], }); await waitForSocketClose("/api/tags"); await expect(queryOllamaModelShowInfo(baseUrl, "llama3:8b")).resolves.toEqual({ showInspectionFailed: true, }); await waitForSocketClose("/api/show"); mode = "success"; await expect(fetchOllamaModels(baseUrl)).resolves.toEqual({ reachable: true, models: [{ name: "llama3:8b" }], }); await expect(queryOllamaModelShowInfo(baseUrl, "llama3:8b")).resolves.toEqual({ contextWindow: 32768, capabilities: ["completion", "tools"], }); } finally { for (const socket of sockets) { socket.destroy(); } if (server.listening) { await new Promise((resolve, reject) => { server.close((error) => { if (error) { reject(error); return; } resolve(); }); }); } } }); it("keeps tools off after a live /api/show failure", async () => { const server = createServer((request, response) => { response.setHeader("Content-Type", "application/json"); if (request.url === "/api/tags") { response.end( JSON.stringify({ models: [{ name: "deepseek-r1:14b", digest: "sha256:show-failure" }], }), ); return; } if (request.url === "/api/show") { response.statusCode = 500; response.end(JSON.stringify({ error: "show failed" })); return; } response.statusCode = 404; response.end(JSON.stringify({ error: "not found" })); }); const listening = once(server, "listening"); try { server.listen(0, "127.0.0.1"); await listening; const address = server.address(); if (!address || typeof address === "string") { throw new Error("Ollama test server did not expose a TCP address"); } const provider = await buildOllamaProvider(`http://127.0.0.1:${address.port}`); const model = expectDefined(provider.models?.[0], "show-failed Ollama model"); expect(model.id).toBe("deepseek-r1:14b"); expect(model.compat?.supportsTools).toBe(false); expect(model.reasoning).toBe(true); } finally { if (server.listening) { await new Promise((resolve, reject) => { server.close((error) => (error ? reject(error) : resolve())); }); } } }); it("fails soft and stops reading when discovery streams exceed the JSON byte cap", async () => { // Larger than the shared 16 MiB readProviderJsonResponse cap so the bounded reader cancels // the stream mid-flight; if the cap were removed the reader would buffer the whole payload. const ONE_MIB = 1024 * 1024; const TOTAL_CHUNKS = 32; // 32 MiB advertised body, double the cap. const chunk = new Uint8Array(ONE_MIB); let bytesPulled = 0; let canceled = false; const makeOversizedJsonResponse = (): Response => { bytesPulled = 0; canceled = false; let pulled = 0; const body = new ReadableStream({ pull(controller) { if (pulled >= TOTAL_CHUNKS) { controller.close(); return; } pulled += 1; bytesPulled += chunk.length; controller.enqueue(chunk); }, cancel() { canceled = true; }, }); return new Response(body, { status: 200, headers: { "Content-Type": "application/json" }, }); }; vi.stubGlobal( "fetch", vi.fn(async () => makeOversizedJsonResponse()), ); const tags = await fetchOllamaModels("http://127.0.0.1:11434"); expect(tags).toEqual({ reachable: false, models: [] }); expect(canceled).toBe(true); // Only the bounded prefix is pulled, never the full advertised 32 MiB stream. expect(bytesPulled).toBeLessThan(TOTAL_CHUNKS * ONE_MIB); vi.stubGlobal( "fetch", vi.fn(async () => makeOversizedJsonResponse()), ); const showInfo = await queryOllamaModelShowInfo("http://127.0.0.1:11434", "evil-model:latest"); expect(showInfo).toEqual({ showInspectionFailed: true }); expect(canceled).toBe(true); expect(bytesPulled).toBeLessThan(TOTAL_CHUNKS * ONE_MIB); }); });