Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions libs/code/deepagents_code/model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,63 @@ def _get_ollama_installed_models(endpoint: str | None) -> list[str]:
return list(models)


def _ollama_host_reachable(
base: str, *, timeout: float = OLLAMA_DISCOVERY_TIMEOUT_SECONDS
) -> bool:
"""Return whether a TCP listener appears to accept connections at `base`.

A lightweight presence preflight so Ollama discovery can skip the HTTP
probe entirely when no daemon is running (e.g. Ollama is not installed).
The check opens and immediately closes a TCP connection to the endpoint's
host and port. Any failure -- connection refused, DNS error, timeout, or
sockets blocked under `pytest-socket` -- is treated as "not reachable" so
discovery falls back gracefully; an unexpected (non-`OSError`) failure is
additionally logged at warning so a real bug isn't misreported as absence.

Args:
base: Base URL of the Ollama daemon, e.g. `http://localhost:11434`.
timeout: Socket connection timeout in seconds.

Returns:
`True` when a connection is established (a daemon appears present) or
when the target cannot be determined (deferring to the HTTP probe);
`False` when the connection cannot be made.
"""
import socket

parsed = urlparse(base)
host = parsed.hostname
if not host:
# Can't determine a target host; let the HTTP probe make the decision.
return True
try:
port = parsed.port
except ValueError:
# Malformed port (out of range / non-numeric); defer to the HTTP probe.
return True
if port is None:
port = 443 if parsed.scheme == "https" else 80
# Mirror the discovery probe below: expected transport failures (refused,
# DNS, timeout) just mean the daemon is absent and stay silent; anything
# else is surfaced at warning so a real bug isn't misreported as "not
# detected". `pytest-socket`'s `SocketBlockedError` inherits from
# `Exception` (not `OSError`), so the broad branch catches it. The socket
# is its own context manager, so `with` closes the probe connection.
try:
with socket.create_connection((host, port), timeout=timeout):
return True
except OSError:
return False
except Exception as exc: # noqa: BLE001 # see comment above
logger.warning(
"Ollama presence preflight raised unexpected %s for %s: %s",
type(exc).__name__,
base,
exc,
)
return False


def _fetch_ollama_installed_models(
endpoint: str | None,
*,
Expand Down Expand Up @@ -1472,6 +1529,17 @@ def _fetch_ollama_installed_models(
base,
)
return []

# Presence preflight (local endpoints only -- remote hosts may be reachable
# only through a proxy that the HTTP probe honors but a raw socket does
# not). A dead/absent daemon (the common case when Ollama is not installed)
# refuses the connection; detecting that here lets us skip the HTTP probe
# and log a quiet "not detected" line instead of a misleading
# "discovery failed ... Connection refused" debug line.
if _is_local_endpoint(base) and not _ollama_host_reachable(base, timeout=timeout):
logger.debug("Ollama daemon not detected at %s; skipping discovery", base)
return []

url = f"{base}/api/tags"

headers = _ollama_discovery_headers(base, content_type=False)
Expand Down
218 changes: 217 additions & 1 deletion libs/code/tests/unit_tests/test_model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from contextlib import AbstractContextManager
from pathlib import Path
from typing import Any, ClassVar, cast
from unittest.mock import patch
from unittest.mock import MagicMock, patch

import pytest

Expand Down Expand Up @@ -2764,6 +2764,82 @@ def __exit__(self, *_exc: object) -> None:
class TestFetchOllamaInstalledModels:
"""Tests for the `_fetch_ollama_installed_models` HTTP probe."""

@pytest.fixture(autouse=True)
def _assume_host_reachable(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""Bypass the TCP presence preflight so HTTP parsing paths are exercised."""
monkeypatch.setattr(
"deepagents_code.model_config._ollama_host_reachable",
lambda *_args, **_kwargs: True,
)

def test_skips_http_probe_when_host_unreachable(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
"""An unreachable daemon short-circuits before any HTTP request."""
monkeypatch.setattr(
"deepagents_code.model_config._ollama_host_reachable",
lambda *_args, **_kwargs: False,
)

with patch("urllib.request.urlopen") as fake:
assert (
model_config._fetch_ollama_installed_models("http://localhost:11434")
== []
)

fake.assert_not_called()

def test_hosted_endpoint_skips_tcp_preflight(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Hosted endpoints proceed through the proxy-aware HTTP probe."""
import json

reachable = MagicMock(return_value=False)
monkeypatch.setattr(
"deepagents_code.model_config._ollama_host_reachable", reachable
)

with patch(
"urllib.request.urlopen",
return_value=_BytesContext(json.dumps({"models": []}).encode("utf-8")),
) as urlopen:
assert (
model_config._fetch_ollama_installed_models(
"https://ollama.example.com"
)
== []
)

reachable.assert_not_called()
urlopen.assert_called_once()

def test_forwards_normalized_base_and_timeout_to_preflight(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
"""The rstrip'd base and the caller's timeout reach the preflight."""
import json

reachable = MagicMock(return_value=True)
monkeypatch.setattr(
"deepagents_code.model_config._ollama_host_reachable", reachable
)
monkeypatch.delenv("OLLAMA_API_KEY", raising=False)
monkeypatch.delenv("DEEPAGENTS_CODE_OLLAMA_API_KEY", raising=False)

with patch(
"urllib.request.urlopen",
return_value=_BytesContext(json.dumps({"models": []}).encode("utf-8")),
):
assert (
model_config._fetch_ollama_installed_models(
"http://localhost:11434/", timeout=0.5
)
== []
)

reachable.assert_called_once_with("http://localhost:11434", timeout=0.5)

def test_returns_sorted_names_from_payload(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
Expand Down Expand Up @@ -2936,6 +3012,146 @@ def test_rejects_unsupported_scheme(self) -> None:
fake.assert_not_called()


class TestOllamaHostReachable:
"""Tests for the `_ollama_host_reachable` TCP presence preflight."""

def test_true_when_connection_succeeds(self) -> None:
"""A successful TCP connection reports the daemon as present.

Also pins that the default timeout reaches `socket.create_connection`:
the preflight exists to fail *fast*, so a dropped timeout would let an
absent host stall on the OS connect timeout -- the hang this removes.
"""
captured: list[tuple[tuple[str, int], float]] = []

def fake_create_connection(
address: tuple[str, int], *, timeout: float
) -> MagicMock:
captured.append((address, timeout))
return MagicMock()

with patch("socket.create_connection", side_effect=fake_create_connection):
assert model_config._ollama_host_reachable("http://localhost:11434") is True

assert captured == [
(("localhost", 11434), model_config.OLLAMA_DISCOVERY_TIMEOUT_SECONDS)
]

def test_forwards_explicit_timeout(self) -> None:
"""A caller-supplied timeout is forwarded to the socket connect."""
captured: list[float] = []

def fake_create_connection(
address: tuple[str, int], # noqa: ARG001
*,
timeout: float,
) -> MagicMock:
captured.append(timeout)
return MagicMock()

with patch("socket.create_connection", side_effect=fake_create_connection):
assert (
model_config._ollama_host_reachable(
"http://localhost:11434", timeout=0.25
)
is True
)

assert captured == [0.25]

def test_false_and_silent_when_connection_refused(
self, caplog: pytest.LogCaptureFixture
) -> None:
"""Connection refused (an `OSError`) reports absent without warning."""
refused = ConnectionRefusedError(61, "Connection refused")

def boom(*_args: object, **_kwargs: object) -> None:
raise refused

with (
caplog.at_level(logging.WARNING, logger="deepagents_code.model_config"),
patch("socket.create_connection", side_effect=boom),
):
assert (
model_config._ollama_host_reachable("http://localhost:11434") is False
)

assert caplog.records == []

def test_false_and_warns_when_error_unexpected(
self, caplog: pytest.LogCaptureFixture
) -> None:
"""A non-`OSError` failure reports absent and surfaces a warning.

Covers `pytest-socket`'s `SocketBlockedError`, which inherits from
`Exception` (not `OSError`); an unexpected error here is a possible
real bug, so it is logged rather than silently swallowed.
"""
blocked = RuntimeError("sockets disabled")

def boom(*_args: object, **_kwargs: object) -> None:
raise blocked

with (
caplog.at_level(logging.WARNING, logger="deepagents_code.model_config"),
patch("socket.create_connection", side_effect=boom),
):
assert (
model_config._ollama_host_reachable("http://localhost:11434") is False
)

assert any("unexpected RuntimeError" in r.getMessage() for r in caplog.records)

def test_defers_to_probe_when_host_unparseable(self) -> None:
"""A URL without a host defers to the HTTP probe instead of blocking it."""
with patch("socket.create_connection") as fake:
assert model_config._ollama_host_reachable("http://") is True

fake.assert_not_called()

@pytest.mark.parametrize(
"endpoint",
["http://localhost:notaport", "http://localhost:99999"],
)
def test_defers_to_probe_when_port_invalid(self, endpoint: str) -> None:
"""An invalid port defers to the best-effort HTTP probe."""
with patch("socket.create_connection") as fake:
assert model_config._ollama_host_reachable(endpoint) is True

fake.assert_not_called()

@pytest.mark.parametrize(
("endpoint", "expected"),
[
("https://ollama.example.com", ("ollama.example.com", 443)),
("http://ollama.internal", ("ollama.internal", 80)),
],
)
def test_defaults_scheme_port_when_absent(
self, endpoint: str, expected: tuple[str, int]
) -> None:
"""A schemed URL without an explicit port falls back to the scheme default.

The preflight and the HTTP probe must agree on the target, so a portless
`http` host resolves to 80 and `https` to 443 -- matching what urllib
would connect to.
"""
captured: list[tuple[str, int]] = []

def fake_create_connection(
address: tuple[str, int],
*,
timeout: float, # noqa: ARG001
) -> MagicMock:
captured.append(address)
return MagicMock()

with patch("socket.create_connection", side_effect=fake_create_connection):
assert model_config._ollama_host_reachable(endpoint) is True

assert captured == [expected]


class TestFetchOllamaInstalledModelProfiles:
"""Tests for Ollama `/api/show` profile discovery."""

Expand Down