## Implementation Plan: Harden Embed API Key Fallback ### Objective Prevent embedding calls from failing when `gateway_embed_key` is empty and the fallback key (vision key) does not have embedding permissions. Add a dedicated, explicit environment variable `EMBED_API_KEY` as the first fallback, improve diagnostic logging, and ensure the project’s verification commands pass. ### Changes Required #### 1. Add new environment variable `EMBED_API_KEY` - **File:** `.env.example` (if exists) – add `EMBED_API_KEY=your-openrouter-embed-key` - **File:** `devplacepy/services/ai_gateway/settings.py` (or wherever `Settings` class is defined) – add field `EMBED_API_KEY: str = ""` #### 2. Modify `effective_config()` to chain fallback through new env var - **File:** `devplacepy/services/openai_gateway/service.py` - **Location:** lines 408–412 (fallback block) - **Change:** ```python if not cfg["gateway_embed_key"]: cfg["gateway_embed_key"] = ( os.getenv("EMBED_API_KEY") or cfg.get("gateway_vision_key") or os.getenv("OPENROUTER_API_KEY") or "" ) ``` (The `os.getenv("EMBED_API_KEY")` is inserted before the vision key fallback.) #### 3. Improve logging when resolve key is empty or non-OpenRouter - **File:** `devplacepy/services/openai_gateway/gateway.py` - **Location:** line 467 (after key is resolved, before sending) - **Change:** ```python logger.info("Using embed key: %s...", resolved_key[:8] if resolved_key else "EMPTY") if not resolved_key.startswith("sk-or-"): logger.warning("Embed key may not be an OpenRouter key; embeddings may fail") ``` Adjust key prefix check if OpenRouter keys change format (current: `sk-or-`). #### 4. Seed default embed route (optional hardening) - **File:** `devplacepy/services/openai_gateway/routes.py` (function `seed_default_deepseek_routes`) - **Add:** ```python def seed_default_embed_routes(db: Session): """Ensure the embed model route exists.""" # Similar pattern to chat routes – create if not exists ... ``` Call this during app bootstrap (in `main.py` or `startup` event) alongside chat route seeding. #### 5. Fix verification commands to bypass PEP 668 - **File:** `Makefile` or test/lint commands in CI config - **Change:** Append `--break-system-packages` to pip install invocations, e.g.: ```makefile test: pip install -e '.[dev]' -q --break-system-packages && make test-unit lint: pip install -q ruff --break-system-packages && ruff check . ``` If no Makefile, the commands in the issue description can be updated in the agent’s execution script. #### 6. Resolve prior merge conflicts The earlier attempts failed with merge conflicts in several files. To avoid this, create the branch from the latest `main` (or `develop`) and apply only the above changes. Do **not** modify files from the unmerged list unless required by this plan. The plan’s changes are scoped to: - `devplacepy/services/openai_gateway/service.py` - `devplacepy/services/openai_gateway/gateway.py` - `.env.example` - `devplacepy/services/openai_gateway/settings.py` - `devplacepy/services/openai_gateway/routes.py` (optional) - Test/lint command runner (e.g., `Makefile` or shell invocation) These files are not in the conflict list, so no merge issues should arise. ### Definition of Done - [ ] Environment variable `EMBED_API_KEY` is defined and documented in `.env.example`. - [ ] `effective_config()` uses `EMBED_API_KEY` as the first fallback before vision key. - [ ] Logging in `handle_embeddings()` includes the first few characters of the resolved key and a warning if it does not look like an OpenRouter key. - [ ] (Optional) Default embed route is seeded on startup. - [ ] The command `pip install -e '.[dev]' -q --break-system-packages && make test-unit` passes with exit code 0. - [ ] The command `pip install -q ruff --break-system-packages && ruff check .` passes with exit code 0. - [ ] No merge conflicts occur when rebasing onto the base branch (branch off latest base, apply only the changes listed).