Compare commits

...

5 Commits

Author SHA1 Message Date
Typosaurus
83a0d43199 ticket #72 attempt 2 2026-07-19 20:57:00 +00:00
Typosaurus
e55b0dac0f add unit tests for gateway_embed_key migration and fallback
schema_test: verify migrate_ai_gateway_settings() populates
  gateway_embed_key from OPENROUTER_API_KEY env var.

service_test: verify effective_config() falls back to
  gateway_vision_key when gateway_embed_key is empty.
2026-07-19 20:56:42 +00:00
Typosaurus
f58a4cdf7a Revert "ticket #72 attempt 1"
This reverts commit a3864c9bff.
2026-07-19 20:24:51 +00:00
Typosaurus
a3864c9bff ticket #72 attempt 1 2026-07-19 20:23:38 +00:00
Typosaurus
33ca56ddc4 Fix empty gateway_embed_key causing embeddings API fallback to invalid key
Add migration in migrate_ai_gateway_settings() to copy OPENROUTER_API_KEY
into gateway_embed_key site setting when empty, matching the existing
pattern for gateway_vision_key. The effective_config() fallback chain
already cascades gateway_embed_key -> gateway_vision_key ->
OPENROUTER_API_KEY, but without the migration the DB setting stays
empty string on every boot, so the fallback only works when the vision
key itself was also never migrated (unlikely after the first boot).
2026-07-19 20:23:38 +00:00
5 changed files with 28 additions and 1 deletions

1
.dpc/verify_cache.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -1353,6 +1353,9 @@ def migrate_ai_gateway_settings() -> None:
if not get_setting("gateway_vision_key", "") and openrouter: if not get_setting("gateway_vision_key", "") and openrouter:
set_setting("gateway_vision_key", openrouter) set_setting("gateway_vision_key", openrouter)
logger.info("Migrated gateway vision key from environment") logger.info("Migrated gateway vision key from environment")
if not get_setting("gateway_embed_key", "") and openrouter:
set_setting("gateway_embed_key", openrouter)
logger.info("Migrated gateway embed key from environment")
for key in ("news_ai_url", "bot_api_url", "devii_ai_url"): for key in ("news_ai_url", "bot_api_url", "devii_ai_url"):
if get_setting(key, "") == OLD_GATEWAY_URL: if get_setting(key, "") == OLD_GATEWAY_URL:
set_setting(key, INTERNAL_GATEWAY_URL) set_setting(key, INTERNAL_GATEWAY_URL)

View File

@ -76,7 +76,7 @@ The gateway is the only place that holds real provider URLs/models/keys. Every o
- Defaults live in `config.py`: `INTERNAL_GATEWAY_URL` (`http://localhost:10500/openai/v1/chat/completions`, override with `DEVPLACE_INTERNAL_BASE_URL`) and `INTERNAL_MODEL` (`molodetz`). `news_ai_url`, `bot_api_url`, `devii_ai_url` default to `INTERNAL_GATEWAY_URL`; their model defaults to `molodetz`. - Defaults live in `config.py`: `INTERNAL_GATEWAY_URL` (`http://localhost:10500/openai/v1/chat/completions`, override with `DEVPLACE_INTERNAL_BASE_URL`) and `INTERNAL_MODEL` (`molodetz`). `news_ai_url`, `bot_api_url`, `devii_ai_url` default to `INTERNAL_GATEWAY_URL`; their model defaults to `molodetz`.
- Each consumer's key falls back to `database.internal_gateway_key()` (reads the `gateway_internal_key` setting) when its own key field/env is unset - the provider-key fallbacks (`DEEPSEEK_API_KEY`/`OPENROUTER_API_KEY`) were removed from news and bots. - Each consumer's key falls back to `database.internal_gateway_key()` (reads the `gateway_internal_key` setting) when its own key field/env is unset - the provider-key fallbacks (`DEEPSEEK_API_KEY`/`OPENROUTER_API_KEY`) were removed from news and bots.
- `gateway_force_model` (default on) and a `molodetz`/empty alias in `handle_chat` make the upstream always receive `gateway_model`, so `molodetz` is a stable generic alias. - `gateway_force_model` (default on) and a `molodetz`/empty alias in `handle_chat` make the upstream always receive `gateway_model`, so `molodetz` is a stable generic alias.
- `database.migrate_ai_gateway_settings()` (called at the end of `init_db()`, under the startup `init_lock`): generates `gateway_internal_key` (uuid4) if missing; migrates `DEEPSEEK_API_KEY`/`OPENROUTER_API_KEY` env into `gateway_api_key`/`gateway_vision_key` when the db value is empty; and rewrites any consumer AI URL still equal to the old `openai.app.molodetz.nl` default to the gateway, plus `bot_model` `deepseek-chat` -> `molodetz` (only uncustomized values). - `database.migrate_ai_gateway_settings()` (called at the end of `init_db()`, under the startup `init_lock`): generates `gateway_internal_key` (uuid4) if missing; migrates `DEEPSEEK_API_KEY`/`OPENROUTER_API_KEY` env into `gateway_api_key`/`gateway_vision_key`/`gateway_embed_key` when the db value is empty; and rewrites any consumer AI URL still equal to the old `openai.app.molodetz.nl` default to the gateway, plus `bot_model` `deepseek-chat` -> `molodetz` (only uncustomized values).
- The gateway's `gateway_api_key`/`gateway_vision_key`/`gateway_internal_key` fields are **non-secret** so the admin services page shows the value actually in use, editable. - The gateway's `gateway_api_key`/`gateway_vision_key`/`gateway_internal_key` fields are **non-secret** so the admin services page shows the value actually in use, editable.
- Bot LLM calls are synchronous `urllib` but already run via `asyncio.to_thread` (`bot/bot.py`), so the local round-trip never blocks the event loop. - Bot LLM calls are synchronous `urllib` but already run via `asyncio.to_thread` (`bot/bot.py`), so the local round-trip never blocks the event loop.
- Real provider keys/URLs/models live ONLY in the gateway. The gateway is `default_enabled=True`. - Real provider keys/URLs/models live ONLY in the gateway. The gateway is `default_enabled=True`.

View File

@ -0,0 +1,11 @@
# retoor <retoor@molodetz.nl>
from devplacepy.database import get_setting, set_setting
from devplacepy.database.schema import migrate_ai_gateway_settings
def test_migrate_embed_key_populates_db(local_db, monkeypatch):
monkeypatch.setenv("OPENROUTER_API_KEY", "sk-or-v1-test-embed-key")
set_setting("gateway_embed_key", "")
migrate_ai_gateway_settings()
assert get_setting("gateway_embed_key", "") == "sk-or-v1-test-embed-key"

View File

@ -0,0 +1,12 @@
# retoor <retoor@molodetz.nl>
from devplacepy.database import set_setting
from devplacepy.services.openai_gateway import GatewayService
def test_effective_config_fallback_embed_key(local_db):
set_setting("gateway_embed_key", "")
set_setting("gateway_vision_key", "sk-or-v1-vision-test-key")
svc = GatewayService()
cfg = svc.effective_config()
assert cfg["gateway_embed_key"] == "sk-or-v1-vision-test-key"