feat: host_type field for OpenRouter / OpenAI-compatible API support
Adds host_type ("openwebui" | "openai") to the host schema so Cortex can
talk to both Open WebUI/Ollama and OpenRouter/standard-OpenAI endpoints.
Path differences per type:
openwebui (default): /api/chat/completions, /api/models
openai: /chat/completions, /models
model_registry.py:
- host_type added to host schema (default "openwebui", backward compat)
- save_host() accepts host_type parameter
- _resolve_model() passes host_type through with the merged host fields
llm_client._local():
- Reads host_type from resolved model_cfg
- Selects correct chat completions path accordingly
routers/local_llm.py:
- save_host route accepts host_type form field
- fetch-models uses /models for openai type, /api/models for openwebui
- Existing host rows show type selector pre-filled from stored value
local_llm.html:
- "Add host" form includes type selector
To use OpenRouter:
- Add host: URL = https://openrouter.ai/api/v1, Type = OpenAI-compatible
- API key from openrouter.ai (store in .env or model_registry.json only)
- Fetch models or add manually (e.g. anthropic/claude-sonnet-4-5-20251022)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,18 @@ Stored in: home/{user}/model_registry.json
|
||||
Schema:
|
||||
{
|
||||
"version": 1,
|
||||
"hosts": [{"id", "label", "api_url", "api_key"}, ...],
|
||||
"hosts": [{"id", "label", "api_url", "api_key",
|
||||
"host_type": "openwebui" | "openai"}, ...],
|
||||
#
|
||||
# host_type controls the API path layout:
|
||||
# "openwebui" (default) — Open WebUI / Ollama:
|
||||
# chat: POST {url}/api/chat/completions
|
||||
# models: GET {url}/api/models
|
||||
# "openai" — OpenRouter, LiteLLM, Anthropic-compatible, etc.:
|
||||
# chat: POST {url}/chat/completions
|
||||
# models: GET {url}/models
|
||||
# Set api_url to the base path that ends just before /chat/completions,
|
||||
# e.g. https://openrouter.ai/api/v1 for OpenRouter.
|
||||
"models": [
|
||||
{
|
||||
"id": str, # unique within this registry
|
||||
@@ -212,7 +223,12 @@ def _resolve_model(registry: dict, model_id: str) -> dict | None:
|
||||
if not host:
|
||||
logger.warning("model %s references missing host_id %s", model_id, host_id)
|
||||
return None
|
||||
return {**model, "api_url": host.get("api_url", ""), "api_key": host.get("api_key", "")}
|
||||
return {
|
||||
**model,
|
||||
"api_url": host.get("api_url", ""),
|
||||
"api_key": host.get("api_key", ""),
|
||||
"host_type": host.get("host_type", "openwebui"),
|
||||
}
|
||||
|
||||
return dict(model)
|
||||
|
||||
@@ -308,15 +324,21 @@ def get_defined_roles(username: str) -> dict[str, dict]:
|
||||
# ── Write API (CRUD) ──────────────────────────────────────────────────────────
|
||||
|
||||
def save_host(username: str, host_id: str | None,
|
||||
label: str, api_url: str, api_key: str) -> str:
|
||||
"""Create or update a host. Returns the host ID."""
|
||||
label: str, api_url: str, api_key: str,
|
||||
host_type: str = "openwebui") -> str:
|
||||
"""Create or update a host. Returns the host ID.
|
||||
|
||||
host_type: "openwebui" (default) or "openai" (OpenRouter, LiteLLM, etc.)
|
||||
"""
|
||||
data = _load(username)
|
||||
host_type = host_type if host_type in ("openwebui", "openai") else "openwebui"
|
||||
|
||||
if host_id:
|
||||
for h in data["hosts"]:
|
||||
if h["id"] == host_id:
|
||||
h["label"] = label.strip()
|
||||
h["api_url"] = api_url.strip()
|
||||
h["label"] = label.strip()
|
||||
h["api_url"] = api_url.strip()
|
||||
h["host_type"] = host_type
|
||||
if api_key.strip():
|
||||
h["api_key"] = api_key.strip()
|
||||
_save(username, data)
|
||||
@@ -325,10 +347,11 @@ def save_host(username: str, host_id: str | None,
|
||||
|
||||
host_id = secrets.token_hex(4)
|
||||
data["hosts"].append({
|
||||
"id": host_id,
|
||||
"label": label.strip(),
|
||||
"api_url": api_url.strip(),
|
||||
"api_key": api_key.strip(),
|
||||
"id": host_id,
|
||||
"label": label.strip(),
|
||||
"api_url": api_url.strip(),
|
||||
"api_key": api_key.strip(),
|
||||
"host_type": host_type,
|
||||
})
|
||||
_save(username, data)
|
||||
return host_id
|
||||
|
||||
Reference in New Issue
Block a user