mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 10:15:27 -04:00
Fix Cookbook container-local model endpoints (#1223)
Co-authored-by: ghreprimand <203024559+ghreprimand@users.noreply.github.com>
This commit is contained in:
+25
-8
@@ -124,7 +124,8 @@ def _clear_user_pref_endpoint_refs(all_prefs: dict, ep_id: str) -> int:
|
||||
# Loopback hosts a user might type for a local model server (LM Studio,
|
||||
# llama.cpp, vLLM, …). Inside Docker these point at the *container*, not the
|
||||
# host the server actually runs on.
|
||||
_LOOPBACK_HOSTS = {"localhost", "127.0.0.1", "0.0.0.0", "::1"}
|
||||
_ANY_BIND_HOSTS = {"0.0.0.0", "::"}
|
||||
_LOOPBACK_HOSTS = {"localhost", "127.0.0.1", "::1", *_ANY_BIND_HOSTS}
|
||||
|
||||
|
||||
def _docker_host_gateway_reachable() -> bool:
|
||||
@@ -148,19 +149,33 @@ def _docker_host_gateway_reachable() -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _rewrite_loopback_for_docker(base_url: str) -> str:
|
||||
def _rewrite_loopback_for_docker(base_url: str, *, container_local: bool = False) -> str:
|
||||
"""Rewrite a loopback model-endpoint URL to ``host.docker.internal`` when
|
||||
running in Docker. A URL like ``http://localhost:1234/v1`` (the LM Studio
|
||||
default) otherwise targets the Odysseus container itself, so the probe gets
|
||||
a connection error and the endpoint is rejected with a misleading "No
|
||||
models found for that provider/key". The Ollama paths already handle this;
|
||||
this extends the same fix to OpenAI-compatible local servers."""
|
||||
models found for that provider/key".
|
||||
|
||||
Cookbook local serves are the opposite case: Odysseus started the model
|
||||
server inside the same container/process environment, so the saved endpoint
|
||||
must remain container-local. In that mode, normalize a bind address such as
|
||||
0.0.0.0 to a connectable loopback host, but do not jump to the Docker host.
|
||||
"""
|
||||
try:
|
||||
parsed = urlparse(base_url)
|
||||
except Exception:
|
||||
return base_url
|
||||
if (parsed.hostname or "").lower() not in _LOOPBACK_HOSTS:
|
||||
host = (parsed.hostname or "").lower()
|
||||
if host not in _LOOPBACK_HOSTS:
|
||||
return base_url
|
||||
if container_local:
|
||||
if host in _ANY_BIND_HOSTS:
|
||||
netloc = "127.0.0.1" + (f":{parsed.port}" if parsed.port else "")
|
||||
return urlunparse(parsed._replace(netloc=netloc))
|
||||
return base_url
|
||||
if host in _ANY_BIND_HOSTS and not _docker_host_gateway_reachable():
|
||||
netloc = "127.0.0.1" + (f":{parsed.port}" if parsed.port else "")
|
||||
return urlunparse(parsed._replace(netloc=netloc))
|
||||
if not _docker_host_gateway_reachable():
|
||||
return base_url
|
||||
netloc = "host.docker.internal" + (f":{parsed.port}" if parsed.port else "")
|
||||
@@ -1115,6 +1130,7 @@ def setup_model_routes(model_discovery):
|
||||
require_models: str = Form("false"),
|
||||
model_type: str = Form("llm"),
|
||||
supports_tools: str = Form(""), # "true"/"false"/"" (unknown)
|
||||
container_local: str = Form("false"),
|
||||
# Default `shared=true` → endpoints are visible to all users (the
|
||||
# app's historical behaviour). Admins can pass `shared=false` to
|
||||
# scope a new endpoint to their own account only.
|
||||
@@ -1127,9 +1143,10 @@ def setup_model_routes(model_discovery):
|
||||
# Resolve hostname via Tailscale if DNS fails
|
||||
from src.endpoint_resolver import resolve_url
|
||||
base_url = resolve_url(base_url)
|
||||
# In Docker, rewrite a loopback URL to host.docker.internal so the probe
|
||||
# — and the saved URL used for chat — reach the host, not the container.
|
||||
base_url = _rewrite_loopback_for_docker(base_url)
|
||||
# In Docker, manually added loopback URLs usually point at a host-local
|
||||
# server. Cookbook local serves are launched inside Odysseus itself, so
|
||||
# keep those container-local when the frontend marks them as such.
|
||||
base_url = _rewrite_loopback_for_docker(base_url, container_local=_truthy(container_local))
|
||||
|
||||
# Auto-generate name from URL if not provided
|
||||
if not name.strip():
|
||||
|
||||
Reference in New Issue
Block a user