From 33ca56ddc4aac82c7396ee7469dac3b32279340c Mon Sep 17 00:00:00 2001 From: Typosaurus Date: Sun, 19 Jul 2026 18:57:56 +0000 Subject: [PATCH] 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). --- devplacepy/database/schema.py | 3 +++ devplacepy/services/openai_gateway/CLAUDE.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/devplacepy/database/schema.py b/devplacepy/database/schema.py index c5845de8..4135cea7 100644 --- a/devplacepy/database/schema.py +++ b/devplacepy/database/schema.py @@ -1353,6 +1353,9 @@ def migrate_ai_gateway_settings() -> None: if not get_setting("gateway_vision_key", "") and openrouter: set_setting("gateway_vision_key", openrouter) 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"): if get_setting(key, "") == OLD_GATEWAY_URL: set_setting(key, INTERNAL_GATEWAY_URL) diff --git a/devplacepy/services/openai_gateway/CLAUDE.md b/devplacepy/services/openai_gateway/CLAUDE.md index 6b58f004..ab7a4ae7 100644 --- a/devplacepy/services/openai_gateway/CLAUDE.md +++ b/devplacepy/services/openai_gateway/CLAUDE.md @@ -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`. - 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. -- `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. - 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`.