Repository navigation
fix(inference): keep Windows Ollama requests in Docker #10741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
59 commits
Select commit
Hold shift + click to select a range
d591a90
fix(inference): keep Windows Ollama requests in Docker
ericksoa 97eaa30
Merge branch 'main' into fix/wsl-ollama-model-discovery-10553
ericksoa a2e4956
fix(inference): complete Windows Ollama transport
ericksoa a426ab8
fix(inference): persist Windows Ollama cleanup route
ericksoa 057ebc5
fix(inference): preserve destroy cleanup contract
ericksoa e4cc146
refactor(inference): finalize Ollama route ownership
ericksoa a0059be
fix(inference): restore accepted Ollama route
ericksoa 4fc9f3d
fix(inference): complete Ollama route recovery
ericksoa abc65bd
fix(inference): finalize Ollama lifecycle recovery
ericksoa 3dbf08b
fix(tunnel): scope Ollama cleanup completion
ericksoa 71e39e6
fix(inference): complete Ollama route lifecycle
ericksoa e191f6a
test(inference): require exact Ollama probe URLs
ericksoa bed0a10
fix(destroy): preserve failed Ollama cleanup recovery
ericksoa b35166e
test(inference): focus Ollama transport contracts
ericksoa a15ea79
fix: clear Windows-host Ollama review gaps
ericksoa 7125b6e
fix: isolate every Windows Ollama operation
ericksoa 6ba00d7
test: require exact Windows Ollama URLs
ericksoa 40c869a
fix: preserve peer Ollama model ownership
ericksoa 1307316
refactor: retire Ollama routes through owner
ericksoa ed3c43a
fix: persist scoped Ollama cleanup retries
ericksoa 9382e36
fix: propagate Ollama cleanup exceptions
ericksoa 715c315
fix(inference): preserve Ollama cleanup recovery
prekshivyas 38a6327
Merge remote-tracking branch 'origin/fix/wsl-ollama-model-discovery-1…
prekshivyas 6eb158b
test: allow policy rollback under coverage
ericksoa aa89007
Merge remote-tracking branch 'origin/fix/wsl-ollama-model-discovery-1…
prekshivyas e7e8582
fix: preserve scoped Ollama cleanup recovery
ericksoa b2929f5
test: stabilize readiness deadline budget
ericksoa 5686a33
Merge remote-tracking branch 'origin/fix/wsl-ollama-model-discovery-1…
prekshivyas 11855ea
test: use readiness clock fix from base
ericksoa 146fbe0
Merge remote-tracking branch 'origin/fix/wsl-ollama-model-discovery-1…
prekshivyas 735203b
fix: retain Ollama cleanup when host is unavailable
ericksoa b6b3464
Merge remote-tracking branch 'origin/fix/wsl-ollama-model-discovery-1…
prekshivyas 7e60520
fix: scope final Ollama cleanup to model owners
ericksoa c394f83
Merge remote-tracking branch 'origin/fix/wsl-ollama-model-discovery-1…
ericksoa 7df5c02
fix: isolate Windows Ollama readiness transport
ericksoa b1c6ac3
refactor: centralize Windows Ollama model discovery
ericksoa 9a48167
fix: keep Ollama lifecycle transitions atomic
ericksoa d2968fa
Merge remote-tracking branch 'origin/main' into fix/wsl-ollama-model-…
ericksoa 7051d83
test: remove duplicate readiness clock
ericksoa edcb7f3
Merge remote-tracking branch 'origin/main' into fix/wsl-ollama-model-…
ericksoa f059cd0
test: prove Ollama unload runs under ownership lock
ericksoa fac042b
fix: preserve destroy recovery guidance
prekshivyas a101ffb
fix: complete Windows Ollama transport migration
ericksoa 27be95f
merge: incorporate concurrent Windows Ollama migration
prekshivyas c3ac1ce
test: pair immutable probe image with fast E2E
ericksoa 284f65a
merge: incorporate concurrent branch updates
prekshivyas 6f3827e
test: expect immutable probe image guidance
ericksoa 301d64b
test: isolate sandbox service tests from Ollama
ericksoa 09b199f
fix: use multi-platform Ollama probe image
ericksoa afde82a
test: verify probe pin through transport
ericksoa 5142e5c
fix: serialize Ollama route ownership transitions
ericksoa 6032621
test: guard retired Windows sleep path
prekshivyas 1cb5f9d
test: allow bounded Windows readiness waits
ericksoa e43ae80
test: focus Windows fallback on behavior
prekshivyas ebc31a2
test: reject subprocess Windows readiness sleeps
ericksoa f7975ea
test: isolate missing advisor model lookup
ericksoa 2587eff
fix: protect local Ollama route ownership
prekshivyas da9fbfc
test: verify bounded Windows readiness delays
ericksoa 2b5cd70
Merge remote-tracking branch 'origin/fix/wsl-ollama-model-discovery-1…
ericksoa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
214 changes: 214 additions & 0 deletions
214
src/lib/inference/local-windows-ollama-transport.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,214 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { mkdtempSync, rmSync } from "node:fs"; | ||
| import { tmpdir } from "node:os"; | ||
| import { join } from "node:path"; | ||
| import { afterEach, describe, expect, it, vi } from "vitest"; | ||
|
|
||
| import { | ||
| applyOllamaRuntimeContextWindow, | ||
| CONTAINER_REACHABILITY_IMAGE, | ||
| getLocalProviderHealthCheck, | ||
| getOllamaHostForCleanup, | ||
| getOllamaModelOptions, | ||
| getOllamaProbeCommand, | ||
| getOllamaWarmupRequestCommand, | ||
| OLLAMA_HOST_DOCKER_INTERNAL, | ||
| loadPersistedOllamaHost, | ||
| persistResolvedOllamaHost, | ||
| probeOllamaModelCapabilities, | ||
| resetOllamaHostCache, | ||
| resetOllamaRuntimeContextWindowAutoState, | ||
| setResolvedOllamaHost, | ||
| validateLocalProvider, | ||
| } from "./local"; | ||
|
|
||
| describe("Windows-host Ollama transport", () => { | ||
| afterEach(() => { | ||
| resetOllamaHostCache(); | ||
| resetOllamaRuntimeContextWindowAutoState(); | ||
| }); | ||
|
|
||
| it("restores the accepted route for cleanup in a fresh process", () => { | ||
| const stateRoot = mkdtempSync(join(tmpdir(), "nemoclaw-ollama-host-receipt-")); | ||
| try { | ||
| setResolvedOllamaHost(OLLAMA_HOST_DOCKER_INTERNAL); | ||
| persistResolvedOllamaHost(undefined, stateRoot); | ||
| resetOllamaHostCache(); | ||
|
|
||
| expect(loadPersistedOllamaHost(stateRoot)).toBe(OLLAMA_HOST_DOCKER_INTERNAL); | ||
| expect(getOllamaHostForCleanup(stateRoot)).toBe(OLLAMA_HOST_DOCKER_INTERNAL); | ||
| } finally { | ||
| rmSync(stateRoot, { recursive: true, force: true }); | ||
| } | ||
| }); | ||
|
|
||
| it("reads the model inventory through Docker Desktop (#10553)", () => { | ||
| setResolvedOllamaHost(OLLAMA_HOST_DOCKER_INTERNAL); | ||
| const capture = vi.fn(() => JSON.stringify({ models: [{ name: "qwen3.5:9b" }] })); | ||
|
|
||
| expect(getOllamaModelOptions(capture)).toEqual(["qwen3.5:9b"]); | ||
| expect(capture).toHaveBeenCalledWith( | ||
| [ | ||
| "docker", | ||
| "run", | ||
| "--rm", | ||
| CONTAINER_REACHABILITY_IMAGE, | ||
| "-sf", | ||
| "--connect-timeout", | ||
| "3", | ||
| "--max-time", | ||
| "5", | ||
| "http://host.docker.internal:11434/api/tags", | ||
| ], | ||
| { ignoreError: true }, | ||
| ); | ||
| }); | ||
|
|
||
| it("builds warm-up and validation requests for Docker Desktop (#10553)", () => { | ||
| setResolvedOllamaHost(OLLAMA_HOST_DOCKER_INTERNAL); | ||
|
|
||
| expect(getOllamaWarmupRequestCommand("qwen3.5:9b")).toEqual([ | ||
| "docker", | ||
| "run", | ||
| "--rm", | ||
| CONTAINER_REACHABILITY_IMAGE, | ||
| "-s", | ||
| "--connect-timeout", | ||
| "10", | ||
| "--max-time", | ||
| "120", | ||
| "http://host.docker.internal:11434/api/generate", | ||
| "-H", | ||
| "Content-Type: application/json", | ||
| "-d", | ||
| expect.stringContaining('"model":"qwen3.5:9b"'), | ||
| ]); | ||
|
|
||
| expect(getOllamaProbeCommand("qwen3.5:9b")).toEqual([ | ||
| "docker", | ||
| "run", | ||
| "--rm", | ||
| CONTAINER_REACHABILITY_IMAGE, | ||
| "-sS", | ||
| "--max-time", | ||
| "120", | ||
| "http://host.docker.internal:11434/api/generate", | ||
| "-H", | ||
| "Content-Type: application/json", | ||
| "-d", | ||
| expect.stringContaining('"model":"qwen3.5:9b"'), | ||
| ]); | ||
| }); | ||
|
|
||
| it("validates health and container reachability through Docker Desktop (#10553)", () => { | ||
| setResolvedOllamaHost(OLLAMA_HOST_DOCKER_INTERNAL); | ||
| const capture = vi.fn((_command: readonly string[]) => JSON.stringify({ models: [] })); | ||
|
|
||
| expect(getLocalProviderHealthCheck("ollama-local")).toEqual([ | ||
| "docker", | ||
| "run", | ||
| "--rm", | ||
| CONTAINER_REACHABILITY_IMAGE, | ||
| "-sf", | ||
| "http://host.docker.internal:11434/api/tags", | ||
| ]); | ||
| expect( | ||
| validateLocalProvider( | ||
| "ollama-local", | ||
| capture, | ||
| () => {}, | ||
| () => ({ | ||
| env: {}, | ||
| isolatedCredentialConfig: false, | ||
| cleanup: () => ({ ok: true }), | ||
| }), | ||
| ), | ||
| ).toEqual({ ok: true }); | ||
|
|
||
| expect(capture).toHaveBeenCalledTimes(2); | ||
| expect(capture.mock.calls[0]?.[0]).toEqual( | ||
| expect.arrayContaining([ | ||
| "docker", | ||
| "run", | ||
| "--rm", | ||
| CONTAINER_REACHABILITY_IMAGE, | ||
| "http://host.docker.internal:11434/api/tags", | ||
| ]), | ||
| ); | ||
| expect(capture.mock.calls[1]?.[0]).toEqual( | ||
| expect.arrayContaining([ | ||
| "docker", | ||
| "run", | ||
| "--rm", | ||
| "--add-host", | ||
| "host.openshell.internal:host-gateway", | ||
| ]), | ||
| ); | ||
| }); | ||
|
|
||
| it("checks the Hermes context window through Docker Desktop (#10553)", () => { | ||
| setResolvedOllamaHost(OLLAMA_HOST_DOCKER_INTERNAL); | ||
| const capture = vi.fn((command: readonly string[]) => | ||
| String(command.at(-1)).endsWith("/api/ps") | ||
| ? JSON.stringify({ | ||
| models: [{ name: "qwen3.5:9b", context_length: 65_536, processor: "100% GPU" }], | ||
| }) | ||
| : "", | ||
| ); | ||
| const env: NodeJS.ProcessEnv = {}; | ||
|
|
||
| expect( | ||
| applyOllamaRuntimeContextWindow("qwen3.5:9b", { | ||
| contextWindowFloor: 64_000, | ||
| env, | ||
| logger: { log: vi.fn(), warn: vi.fn() }, | ||
| runCaptureImpl: capture, | ||
| }), | ||
| ).toEqual({ ok: true }); | ||
| expect(env.NEMOCLAW_CONTEXT_WINDOW).toBe("65536"); | ||
| expect(capture).toHaveBeenCalledOnce(); | ||
| expect(capture.mock.calls[0]?.[0]).toEqual( | ||
| expect.arrayContaining(["docker", "run", "--rm", CONTAINER_REACHABILITY_IMAGE]), | ||
| ); | ||
| }); | ||
|
|
||
| it("checks model capability metadata through Docker Desktop (#10553)", () => { | ||
| setResolvedOllamaHost(OLLAMA_HOST_DOCKER_INTERNAL); | ||
| const capture = vi.fn((_command: readonly string[]) => | ||
| JSON.stringify({ capabilities: ["tools"] }), | ||
| ); | ||
|
|
||
| expect(probeOllamaModelCapabilities("qwen3.5:9b", capture)).toMatchObject({ | ||
| source: "api", | ||
| supportsTools: true, | ||
| }); | ||
| expect(capture).toHaveBeenCalledOnce(); | ||
| expect(capture.mock.calls[0]?.[0]).toEqual( | ||
| expect.arrayContaining(["docker", "run", "--rm", CONTAINER_REACHABILITY_IMAGE]), | ||
| ); | ||
| }); | ||
|
|
||
| it("keeps the Hermes context-window check fail-closed on an invalid Docker response (#10553)", () => { | ||
| setResolvedOllamaHost(OLLAMA_HOST_DOCKER_INTERNAL); | ||
| const capture = vi.fn((_command: readonly string[]) => | ||
| JSON.stringify({ models: [{ name: "qwen3.5:9b", context_length: "invalid" }] }), | ||
| ); | ||
|
|
||
| const result = applyOllamaRuntimeContextWindow("qwen3.5:9b", { | ||
| contextWindowFloor: 64_000, | ||
| env: {}, | ||
| logger: { log: vi.fn(), warn: vi.fn() }, | ||
| runCaptureImpl: capture, | ||
| }); | ||
|
|
||
| expect(result).toMatchObject({ | ||
| ok: false, | ||
| message: expect.stringContaining("cannot verify the required 64000-token window"), | ||
| }); | ||
| expect(capture.mock.calls[0]?.[0]).toEqual( | ||
| expect.arrayContaining(["docker", "run", "--rm", CONTAINER_REACHABILITY_IMAGE]), | ||
| ); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.