Spaces:
Running
Running
| """Patch backend: replace AVAILABLE_MODELS (remove old 6, add 18 new) + OpenRouter routing.""" | |
| import ast | |
| import os | |
| import re | |
| AGENT_FILE = "/app/backend/routes/agent.py" | |
| LLM_PARAMS_FILE = "/app/agent/core/llm_params.py" | |
| # === Step 1: Replace _available_models() to return ONLY new models === | |
| with open(AGENT_FILE) as f: | |
| content = f.read() | |
| # Make DEFAULT_MODEL_ID point to our default | |
| content = content.replace( | |
| "DEFAULT_MODEL_ID = GLM_52_MODEL_ID", | |
| 'DEFAULT_MODEL_ID = "deepseek-ai/DeepSeek-V4-Pro:novita"' | |
| ) | |
| content = content.replace( | |
| "DEFAULT_GPT_MODEL_ID = GPT_55_MODEL_ID", | |
| 'DEFAULT_GPT_MODEL_ID = "openai/gpt-oss-120b"' | |
| ) | |
| # Find and replace the _available_models() function using regex | |
| func_pattern = re.compile( | |
| r'def _available_models\(\) -> list\[dict\[str, Any\]\]:\s*\n' | |
| r'\s+models\s*=\s*\[.*?\]\s*\n\s+return models', | |
| re.DOTALL | |
| ) | |
| new_func = '''def _available_models() -> list[dict[str, Any]]: | |
| models = [ | |
| { | |
| "id": "openai/openrouter/owl-alpha", | |
| "label": "Owl Alpha", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "deepseek-ai/DeepSeek-V4-Pro:novita", | |
| "label": "DeepSeek V4 Pro", | |
| "provider": "huggingface", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "deepseek-ai/DeepSeek-V4-Flash:novita", | |
| "label": "DeepSeek V4 Flash", | |
| "provider": "huggingface", | |
| "tier": "free", | |
| }, | |
| { | |
| "id": "openai/gpt-oss-120b", | |
| "label": "gpt-oss-120b", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| }, | |
| { | |
| "id": "Qwen/Qwen3-Coder-Next:novita", | |
| "label": "Qwen3 Coder Next", | |
| "provider": "huggingface", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "google/gemma-3-1b-it:novita", | |
| "label": "Gemma 3 1B", | |
| "provider": "huggingface", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "openai/google/gemini-2.0-flash-001", | |
| "label": "Gemini 2.0 Flash", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| }, | |
| { | |
| "id": "openai/deepseek/deepseek-v4-flash", | |
| "label": "DeepSeek V4 Flash (OR)", | |
| "provider": "openrouter", | |
| "tier": "paid", | |
| }, | |
| { | |
| "id": "openai/google/gemma-4-9b-it:free", | |
| "label": "Gemma 4 9B", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "openai/google/gemma-4-31b-it:free", | |
| "label": "Gemma 4 31B", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "openai/tencent/hy3-preview", | |
| "label": "Hy3 Preview", | |
| "provider": "openrouter", | |
| "tier": "paid", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "openai/cohere/north-mini-code:free", | |
| "label": "north-mini-code:free", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "openai/nvidia/nemotron-3-super-120b-a12b:free", | |
| "label": "Nemotron 3 Super 120B", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| }, | |
| { | |
| "id": "openai/nvidia/nemotron-3-ultra-550b-a55b:free", | |
| "label": "Nemotron 3 Ultra 550B", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "openai/poolside/laguna-m.1:free", | |
| "label": "Laguna M.1", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| "recommended": True, | |
| }, | |
| { | |
| "id": "openai/poolside/laguna-xs.2:free", | |
| "label": "Laguna XS.2", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| }, | |
| { | |
| "id": "openai/qwen/qwen3.7-flash", | |
| "label": "Qwen3.7 Flash", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| }, | |
| { | |
| "id": "openai/inclusionai/ling-2.6-flash", | |
| "label": "Ling 2.6 Flash", | |
| "provider": "openrouter", | |
| "tier": "free", | |
| }, | |
| ] | |
| return models''' | |
| func_match = func_pattern.search(content) | |
| if func_match: | |
| content = content[:func_match.start()] + new_func + content[func_match.end():] | |
| print("OK: Replaced _available_models() with 18 new models via regex") | |
| else: | |
| print("WARN: Could not find _available_models() via regex, trying extend approach...") | |
| target = "AVAILABLE_MODELS = _available_models()\n" | |
| if target in content: | |
| content = content.replace( | |
| target, | |
| target + "AVAILABLE_MODELS.clear()\n" + | |
| "AVAILABLE_MODELS.extend([\n" | |
| ' {"id": "openai/openrouter/owl-alpha", "label": "Owl Alpha", "provider": "openrouter", "tier": "free", "recommended": True},\n' | |
| ' {"id": "deepseek-ai/DeepSeek-V4-Pro:novita", "label": "DeepSeek V4 Pro", "provider": "huggingface", "tier": "free", "recommended": True},\n' | |
| ' {"id": "deepseek-ai/DeepSeek-V4-Flash:novita", "label": "DeepSeek V4 Flash", "provider": "huggingface", "tier": "free"},\n' | |
| ' {"id": "openai/gpt-oss-120b", "label": "gpt-oss-120b", "provider": "openrouter", "tier": "free"},\n' | |
| ' {"id": "Qwen/Qwen3-Coder-Next:novita", "label": "Qwen3 Coder Next", "provider": "huggingface", "tier": "free", "recommended": True},\n' | |
| ' {"id": "google/gemma-3-1b-it:novita", "label": "Gemma 3 1B", "provider": "huggingface", "tier": "free", "recommended": True},\n' | |
| ' {"id": "openai/google/gemini-2.0-flash-001", "label": "Gemini 2.0 Flash", "provider": "openrouter", "tier": "free"},\n' | |
| ' {"id": "openai/deepseek/deepseek-v4-flash", "label": "DeepSeek V4 Flash (OR)", "provider": "openrouter", "tier": "paid"},\n' | |
| ' {"id": "openai/google/gemma-4-9b-it:free", "label": "Gemma 4 9B", "provider": "openrouter", "tier": "free", "recommended": True},\n' | |
| ' {"id": "openai/google/gemma-4-31b-it:free", "label": "Gemma 4 31B", "provider": "openrouter", "tier": "free", "recommended": True},\n' | |
| ' {"id": "openai/tencent/hy3-preview", "label": "Hy3 Preview", "provider": "openrouter", "tier": "paid", "recommended": True},\n' | |
| ' {"id": "openai/cohere/north-mini-code:free", "label": "north-mini-code:free", "provider": "openrouter", "tier": "free", "recommended": True},\n' | |
| ' {"id": "openai/nvidia/nemotron-3-super-120b-a12b:free", "label": "Nemotron 3 Super 120B", "provider": "openrouter", "tier": "free"},\n' | |
| ' {"id": "openai/nvidia/nemotron-3-ultra-550b-a55b:free", "label": "Nemotron 3 Ultra 550B", "provider": "openrouter", "tier": "free", "recommended": True},\n' | |
| ' {"id": "openai/poolside/laguna-m.1:free", "label": "Laguna M.1", "provider": "openrouter", "tier": "free", "recommended": True},\n' | |
| ' {"id": "openai/poolside/laguna-xs.2:free", "label": "Laguna XS.2", "provider": "openrouter", "tier": "free"},\n' | |
| ' {"id": "openai/qwen/qwen3.7-flash", "label": "Qwen3.7 Flash", "provider": "openrouter", "tier": "free"},\n' | |
| ' {"id": "openai/inclusionai/ling-2.6-flash", "label": "Ling 2.6 Flash", "provider": "openrouter", "tier": "free"},\n' | |
| "])\n" | |
| 'DEFAULT_FREE_MODEL_ID = "openai/openrouter/owl-alpha"\n' | |
| ) | |
| print("OK: Used extend approach") | |
| else: | |
| print("FAIL: Cannot patch agent.py!") | |
| import sys | |
| sys.exit(1) | |
| try: | |
| ast.parse(content) | |
| print("OK: agent.py syntax OK") | |
| except SyntaxError as e: | |
| print(f"FAIL: Syntax error in agent.py: {e}") | |
| raise | |
| with open(AGENT_FILE, "w") as f: | |
| f.write(content) | |
| # === Step 2: Patch _resolve_llm_params for OpenRouter routing === | |
| with open(LLM_PARAMS_FILE) as f: | |
| llm_content = f.read() | |
| # Insert the OpenRouter routing before the params block | |
| api_key_match = re.search(r'api_key\s*=\s*_resolve_hf_router_token\(session_hf_token\)', llm_content) | |
| if api_key_match: | |
| line_end = llm_content.find('\n', api_key_match.end()) + 1 | |
| if line_end > 0: | |
| routing_insert = ''' # === PATCH: Route ALL openai/-prefixed models to OpenRouter === | |
| if normalized_model.startswith("openai/"): | |
| return { | |
| "model": normalized_model, | |
| "api_base": "https://openrouter.ai/api/v1", | |
| "api_key": os.environ.get("OPENROUTER_API_KEY") or api_key or "", | |
| } | |
| # === END PATCH === | |
| ''' | |
| llm_content = llm_content[:line_end] + routing_insert + llm_content[line_end:] | |
| print("OK: Patched _resolve_llm_params (catch-all openai/ -> OR)") | |
| else: | |
| print("OK: Could not find end of api_key line") | |
| else: | |
| print("OK: api_key line not found, may already be patched") | |
| try: | |
| ast.parse(llm_content) | |
| print("OK: llm_params.py syntax OK") | |
| except SyntaxError as e: | |
| print(f"FAIL: Syntax error in llm_params.py: {e}") | |
| raise | |
| with open(LLM_PARAMS_FILE, "w") as f: | |
| f.write(llm_content) | |
| print("OK: Backend patched - 18 models, ALL openai/ -> OR") |