kaushikpaul's picture
Deploy Space
ca22196 verified
Raw
History Blame Contribute Delete
4.4 kB
import os
from functools import lru_cache
from typing import Any
import requests
from crewai import LLM
from dotenv import load_dotenv
load_dotenv()
OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1"
OPENCODE_GO_OPENAI_BASE_URL = "https://opencode.ai/zen/go/v1"
OPENCODE_GO_ANTHROPIC_BASE_URL = "https://opencode.ai/zen/go"
OPENCODE_GO_MODELS_URL = "https://opencode.ai/zen/go/v1/models"
DEFAULT_OPENROUTER_MODEL = "moonshotai/kimi-k2:free"
DEFAULT_OPENCODE_GO_MODEL = "deepseek-v4-flash"
def _env_bool(name: str, default: bool = False) -> bool:
value = os.getenv(name)
if value is None:
return default
return value.strip().lower() in {"1", "true", "yes", "y", "on"}
def _env_required(name: str) -> str:
value = os.getenv(name)
if not value:
raise RuntimeError(f"Missing required environment variable: {name}")
return value
def _opencode_model_id(model: str) -> str:
return model.removeprefix("opencode-go/").strip()
def _openrouter_model_id(model: str) -> str:
model = model.strip()
if model.startswith("openrouter/"):
return model
return f"openrouter/{model}"
def _strings_from(value: Any) -> list[str]:
if isinstance(value, str):
return [value.lower()]
if isinstance(value, dict):
strings: list[str] = []
for item in value.values():
strings.extend(_strings_from(item))
return strings
if isinstance(value, list):
strings = []
for item in value:
strings.extend(_strings_from(item))
return strings
return []
@lru_cache(maxsize=32)
def _opencode_go_api_style(model: str, api_key: str) -> str:
configured = os.getenv("OPENCODE_GO_API_STYLE", "auto").strip().lower()
if configured in {"openai", "anthropic"}:
return configured
if configured != "auto":
raise RuntimeError("OPENCODE_GO_API_STYLE must be auto, openai, or anthropic")
model_id = _opencode_model_id(model)
try:
response = requests.get(
OPENCODE_GO_MODELS_URL,
headers={"Authorization": f"Bearer {api_key}"},
timeout=5,
)
response.raise_for_status()
payload = response.json()
models = payload.get("data", payload) if isinstance(payload, dict) else payload
if isinstance(models, list):
for item in models:
if not isinstance(item, dict):
continue
ids = {
str(item.get("id", "")),
str(item.get("model", "")),
str(item.get("name", "")),
}
if model_id not in ids and f"opencode-go/{model_id}" not in ids:
continue
details = " ".join(_strings_from(item))
if "messages" in details or "anthropic" in details:
return "anthropic"
if (
"chat/completions" in details
or "openai" in details
or "alibaba" in details
):
return "openai"
except requests.RequestException:
pass
if model_id.startswith("minimax-"):
return "anthropic"
return "openai"
def create_llm() -> LLM:
temperature = float(os.getenv("LLM_TEMPERATURE", "0.2"))
timeout = int(os.getenv("LLM_TIMEOUT", "300"))
if _env_bool("USE_OPENROUTER", default=False):
return LLM(
model=_openrouter_model_id(
os.getenv("OPENROUTER_MODEL", DEFAULT_OPENROUTER_MODEL)
),
api_base=OPENROUTER_BASE_URL,
api_key=_env_required("OPENROUTER_API_KEY"),
temperature=temperature,
timeout=timeout,
)
api_key = _env_required("OPENCODE_GO_API_KEY")
model = _opencode_model_id(os.getenv("OPENCODE_GO_MODEL", DEFAULT_OPENCODE_GO_MODEL))
api_style = _opencode_go_api_style(model, api_key)
if api_style == "anthropic":
return LLM(
model=f"anthropic/{model}",
api_base=OPENCODE_GO_ANTHROPIC_BASE_URL,
api_key=api_key,
temperature=temperature,
timeout=timeout,
)
return LLM(
model=f"openai/{model}",
api_base=OPENCODE_GO_OPENAI_BASE_URL,
api_key=api_key,
temperature=temperature,
timeout=timeout,
)