feat: rename CF_ORCH_URL to GPU_SERVER_URL for self-hoster clarity #14

Merged
pyr0ball merged 2 commits from fix/gpu-server-url-rename into main 2026-07-10 19:34:20 -07:00
6 changed files with 122 additions and 9 deletions
Showing only changes of commit 76aaabd857 - Show all commits

View file

@ -23,10 +23,13 @@ HEIMDALL_ADMIN_TOKEN=
# Must match COORDINATOR_PRODUCT_KEYS["pagepiper"] in cf-orch.env on the coordinator # Must match COORDINATOR_PRODUCT_KEYS["pagepiper"] in cf-orch.env on the coordinator
COORDINATOR_PAGEPIPER_KEY= COORDINATOR_PAGEPIPER_KEY=
# cf-orch coordinator URL — routes chat/embed calls through managed GPU allocation # GPU server / cf-orch coordinator URL — routes chat/embed calls through managed
# CF_LICENSE_KEY is the auth token sent to the coordinator (same value as COORDINATOR_PAGEPIPER_KEY) # GPU allocation. CF_LICENSE_KEY is the auth token sent to the coordinator (same
# Leave CF_ORCH_URL blank to skip allocation and hit PAGEPIPER_OLLAMA_URL directly # value as COORDINATOR_PAGEPIPER_KEY). Leave blank to skip allocation and hit
CF_ORCH_URL= # PAGEPIPER_OLLAMA_URL directly. CF_ORCH_URL is still honoured as a legacy alias
# if GPU_SERVER_URL is unset — Paid+ tiers auto-default to orch.circuitforge.tech
# when CF_LICENSE_KEY is present.
GPU_SERVER_URL=
CF_LICENSE_KEY= CF_LICENSE_KEY=
CF_APP_NAME=pagepiper CF_APP_NAME=pagepiper

View file

@ -11,6 +11,12 @@ PAGEPIPER_DATA_DIR=data
# PAGEPIPER_CHAT_MODEL=mistral:7b # PAGEPIPER_CHAT_MODEL=mistral:7b
# PAGEPIPER_EMBED_MODEL=nomic-embed-text # PAGEPIPER_EMBED_MODEL=nomic-embed-text
# Self-hosted GPU rig URL — set this instead of PAGEPIPER_OLLAMA_URL if you're
# running a cf-orch coordinator (e.g. a home GPU rack). The coordinator resolves
# the actual service URL at allocation time. (CF_ORCH_URL is still honoured as
# a legacy alias if you already have it set.)
# GPU_SERVER_URL=http://localhost:7700
# Forgejo API token — enables the in-app feedback button (files Forgejo issues) # Forgejo API token — enables the in-app feedback button (files Forgejo issues)
# Create a token at https://git.opensourcesolarpunk.com/user/settings/applications # Create a token at https://git.opensourcesolarpunk.com/user/settings/applications
# FORGEJO_API_TOKEN= # FORGEJO_API_TOKEN=

View file

@ -14,6 +14,21 @@ VEC_DIMENSIONS = int(os.environ.get("PAGEPIPER_EMBED_DIMS", "1024"))
LOCAL_USER_ID = "__local__" LOCAL_USER_ID = "__local__"
CF_LICENSE_KEY = os.environ.get("CF_LICENSE_KEY")
# Priority: GPU_SERVER_URL env var -> CF_ORCH_URL env var (backward compat)
# -> https://orch.circuitforge.tech when CF_LICENSE_KEY is present (Paid+)
# Resolved value is written back to os.environ["CF_ORCH_URL"] so every existing
# caller that reads os.environ.get("CF_ORCH_URL") directly (get_llm_config below,
# app/api/chat.py) sees the right URL without any further changes.
GPU_SERVER_URL = (
os.environ.get("GPU_SERVER_URL")
or os.environ.get("CF_ORCH_URL")
or ("https://orch.circuitforge.tech" if CF_LICENSE_KEY else None)
)
if GPU_SERVER_URL:
os.environ["CF_ORCH_URL"] = GPU_SERVER_URL
def user_data_dir(user_id: str) -> Path: def user_data_dir(user_id: str) -> Path:
"""Return (and create) the per-user data directory under DATA_DIR/users/.""" """Return (and create) the per-user data directory under DATA_DIR/users/."""

View file

@ -17,8 +17,10 @@ services:
PAGEPIPER_BOOKS_DIR: /devl/pagepiper-cloud-data/books PAGEPIPER_BOOKS_DIR: /devl/pagepiper-cloud-data/books
# PAGEPIPER_OLLAMA_URL — set in .env (BYOK gate for hybrid search + RAG) # PAGEPIPER_OLLAMA_URL — set in .env (BYOK gate for hybrid search + RAG)
# HEIMDALL_URL, HEIMDALL_ADMIN_TOKEN — set in .env for license validation # HEIMDALL_URL, HEIMDALL_ADMIN_TOKEN — set in .env for license validation
# cf-orch: route LLM inference through coordinator for managed GPU access # GPU server: route LLM inference through the cf-orch coordinator for
CF_ORCH_URL: http://host.docker.internal:7700 # managed GPU access (app/config.py normalizes this into CF_ORCH_URL
# internally, so no other service code needs to change)
GPU_SERVER_URL: http://host.docker.internal:7700
CF_APP_NAME: pagepiper CF_APP_NAME: pagepiper
# CF_LICENSE_KEY is the auth token CFOrchClient sends to the coordinator # CF_LICENSE_KEY is the auth token CFOrchClient sends to the coordinator
CF_LICENSE_KEY: ${COORDINATOR_PAGEPIPER_KEY:-} CF_LICENSE_KEY: ${COORDINATOR_PAGEPIPER_KEY:-}

View file

@ -19,12 +19,13 @@ Copy `.env.example` to `.env` and configure as needed.
| `PAGEPIPER_EMBED_DIMS` | `1024` | Embedding dimensions (must match the model) | | `PAGEPIPER_EMBED_DIMS` | `1024` | Embedding dimensions (must match the model) |
| `PAGEPIPER_CHAT_MODEL` | `mistral:7b` | Ollama chat/completion model | | `PAGEPIPER_CHAT_MODEL` | `mistral:7b` | Ollama chat/completion model |
## cf-orch (managed deployments) ## GPU server / cf-orch (managed deployments)
| Variable | Default | Description | | Variable | Default | Description |
|----------|---------|-------------| |----------|---------|-------------|
| `CF_ORCH_URL` | _(unset)_ | cf-orch coordinator URL for GPU allocation | | `GPU_SERVER_URL` | _(unset)_ | Self-hosted GPU rig / cf-orch coordinator URL for GPU allocation. Preferred over `CF_ORCH_URL`. |
| `CF_LICENSE_KEY` | _(unset)_ | License key for cf-orch authentication | | `CF_ORCH_URL` | _(unset)_ | Legacy alias for `GPU_SERVER_URL` — still honoured if `GPU_SERVER_URL` is unset. |
| `CF_LICENSE_KEY` | _(unset)_ | License key for cf-orch authentication. When set and neither `GPU_SERVER_URL` nor `CF_ORCH_URL` is configured, defaults `GPU_SERVER_URL` to `https://orch.circuitforge.tech` (Paid+ tiers). |
| `CF_APP_NAME` | `pagepiper` | Application identifier sent to cf-orch | | `CF_APP_NAME` | `pagepiper` | Application identifier sent to cf-orch |
## License (cloud tier) ## License (cloud tier)

86
tests/test_config.py Normal file
View file

@ -0,0 +1,86 @@
# tests/test_config.py
"""Unit tests for the GPU_SERVER_URL / CF_ORCH_URL resolution in app/config.py.
app/config.py resolves GPU_SERVER_URL at *module import time* (module-level
code, not a function), so each test reloads the module after adjusting env
vars via monkeypatch, then reloads it again afterward with the real
environment restored so later tests see normal module state.
"""
from __future__ import annotations
import importlib
import pytest
import app.config as config
@pytest.fixture(autouse=True)
def _restore_config_module():
yield
importlib.reload(config)
def _clear_orch_env(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.delenv("GPU_SERVER_URL", raising=False)
monkeypatch.delenv("CF_ORCH_URL", raising=False)
monkeypatch.delenv("CF_LICENSE_KEY", raising=False)
def test_gpu_server_url_prefers_explicit_env_var(monkeypatch):
_clear_orch_env(monkeypatch)
monkeypatch.setenv("GPU_SERVER_URL", "http://my-rig:7700")
monkeypatch.setenv("CF_ORCH_URL", "http://should-be-ignored:7700")
importlib.reload(config)
assert config.GPU_SERVER_URL == "http://my-rig:7700"
def test_gpu_server_url_falls_back_to_cf_orch_url_legacy_alias(monkeypatch):
_clear_orch_env(monkeypatch)
monkeypatch.setenv("CF_ORCH_URL", "http://legacy-coordinator:7700")
importlib.reload(config)
assert config.GPU_SERVER_URL == "http://legacy-coordinator:7700"
def test_gpu_server_url_defaults_when_license_key_present(monkeypatch):
_clear_orch_env(monkeypatch)
monkeypatch.setenv("CF_LICENSE_KEY", "test-key-123")
importlib.reload(config)
assert config.GPU_SERVER_URL == "https://orch.circuitforge.tech"
def test_gpu_server_url_none_when_nothing_set(monkeypatch):
_clear_orch_env(monkeypatch)
importlib.reload(config)
assert config.GPU_SERVER_URL is None
def test_gpu_server_url_writes_back_to_cf_orch_url_for_legacy_callers(monkeypatch):
"""get_llm_config() and app/api/chat.py read os.environ["CF_ORCH_URL"] directly —
the write-back must happen so they keep working without code changes."""
import os
_clear_orch_env(monkeypatch)
monkeypatch.setenv("GPU_SERVER_URL", "http://my-rig:7700")
importlib.reload(config)
assert os.environ.get("CF_ORCH_URL") == "http://my-rig:7700"
def test_gpu_server_url_unset_does_not_write_back(monkeypatch):
import os
_clear_orch_env(monkeypatch)
importlib.reload(config)
assert "CF_ORCH_URL" not in os.environ