"""Patch backend llm_params.py: force OpenRouter as the LiteLLM provider. Root cause: the openai/-prefixed (and deepseek/) model routing returns only ``api_base`` + ``api_key``. LiteLLM resolves the provider from the model string's org prefix, so for models whose org is NOT a recognized LiteLLM provider (upstage/, nvidia/, liquid/, meta-llama/, google/, poolside/, inclusionai/, ...) it raises "LLM Provider NOT provided" even though ``api_base`` points at OpenRouter. Only orgs that happen to match a real LiteLLM provider (e.g. tencent/) worked by luck. Fix: add ``custom_llm_provider: "openrouter"`` to both OpenRouter routing branches so LiteLLM always uses the OpenRouter OpenAI-compatible client. This runs AFTER patch_models.py (which may already have inserted the routing blocks); it is idempotent. """ import ast import os FILE = "/app/agent/core/llm_params.py" with open(FILE) as f: c = f.read() before = c # --- 1. openai/ branch (unique via or_model line) --- openai_old = ( ' or_model = normalized_model[len("openai/"):]\n' ' return {\n' ' "model": or_model,\n' ' "api_base": "https://openrouter.ai/api/v1",\n' ' "api_key": os.environ.get("OPENROUTER_API_KEY") or api_key or "",\n' ' }\n' ) openai_new = ( ' or_model = normalized_model[len("openai/"):]\n' ' return {\n' ' "model": or_model,\n' ' "api_base": "https://openrouter.ai/api/v1",\n' ' "api_key": os.environ.get("OPENROUTER_API_KEY") or api_key or "",\n' ' "custom_llm_provider": "openrouter",\n' ' }\n' ) # --- 2. deepseek/ branch (unique via normalized_model on its own line) --- deepseek_old = ( ' if normalized_model.startswith("deepseek/"):\n' ' return {\n' ' "model": normalized_model,\n' ' "api_base": "https://openrouter.ai/api/v1",\n' ' "api_key": os.environ.get("OPENROUTER_API_KEY") or api_key or "",\n' ' }\n' ) deepseek_new = ( ' if normalized_model.startswith("deepseek/"):\n' ' return {\n' ' "model": normalized_model,\n' ' "api_base": "https://openrouter.ai/api/v1",\n' ' "api_key": os.environ.get("OPENROUTER_API_KEY") or api_key or "",\n' ' "custom_llm_provider": "openrouter",\n' ' }\n' ) if 'custom_llm_provider' in c: print("OK: llm_params.py already contains custom_llm_provider (idempotent)") else: n1 = c.count(openai_old) n2 = c.count(deepseek_old) if n1 == 1: c = c.replace(openai_old, openai_new) print("OK: openai/ branch -> custom_llm_provider='openrouter'") else: print(f"WARN: openai/ branch match count = {n1} (expected 1)") if n2 == 1: c = c.replace(deepseek_old, deepseek_new) print("OK: deepseek/ branch -> custom_llm_provider='openrouter'") else: print(f"WARN: deepseek/ branch match count = {n2} (expected 1)") if c != before: with open(FILE, "w") as f: f.write(c) try: ast.parse(c) print("OK: llm_params.py written & syntax valid") except SyntaxError as e: print(f"FAIL: llm_params.py syntax error: {e}") raise else: print("WARN: no changes applied")