Files
2026-07-13 12:23:54 +08:00

135 lines
5.1 KiB
Python

from __future__ import annotations
import os
from functools import lru_cache
from pathlib import Path
from typing import Any
import yaml
DEFAULT_LLM_MODEL = "gpt-5.5"
DEFAULT_LLM_MODEL_PROVIDER = "openai"
DEFAULT_LLM_BASE_URL = "https://yunwu.ai/v1"
DEFAULT_IMAGE_MODEL = "gemini-3.1-flash-image-preview"
DEFAULT_IMAGE_BASE_URL = "https://yunwu.ai"
DEFAULT_VIDEO_MODEL = "veo3.1-fast"
DEFAULT_VIDEO_BASE_URL = "https://openrouter.ai/api/v1"
DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small"
DEFAULT_EMBEDDING_MODEL_PROVIDER = "openai"
DEFAULT_RERANKER_MODEL = "BAAI/bge-reranker-v2-m3"
@lru_cache(maxsize=4)
def load_agent_config(workspace_root: str | Path = ".") -> dict[str, Any]:
path = Path(workspace_root).resolve() / "configs" / "agent.local.yaml"
if not path.exists():
return {}
try:
payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
except yaml.YAMLError as exc:
raise RuntimeError(f"Invalid configs/agent.local.yaml: {exc}") from exc
if not isinstance(payload, dict):
raise RuntimeError("configs/agent.local.yaml must be a YAML mapping")
return payload
def config_value(section: str, key: str, env_names: list[str], default: str = "", workspace_root: str | Path = ".") -> str:
for env_name in env_names:
value = os.environ.get(env_name)
if value:
return value
section_payload = load_agent_config(workspace_root).get(section, {})
if isinstance(section_payload, dict):
value = section_payload.get(key)
if isinstance(value, str) and value:
return value
return default
def llm_model(workspace_root: str | Path = ".") -> str:
return config_value("llm", "model", ["VIMAX_LLM_MODEL"], DEFAULT_LLM_MODEL, workspace_root)
def llm_model_provider(workspace_root: str | Path = ".") -> str:
return config_value("llm", "model_provider", ["VIMAX_LLM_MODEL_PROVIDER"], DEFAULT_LLM_MODEL_PROVIDER, workspace_root)
def llm_base_url(workspace_root: str | Path = ".") -> str:
return config_value("llm", "base_url", ["VIMAX_LLM_BASE_URL"], DEFAULT_LLM_BASE_URL, workspace_root)
def llm_api_key(workspace_root: str | Path = ".") -> str:
return config_value("llm", "api_key", ["VIMAX_LLM_API_KEY", "VIMAX_API_KEY"], "", workspace_root)
def image_model(workspace_root: str | Path = ".") -> str:
return config_value("image", "model", ["VIMAX_IMAGE_MODEL"], DEFAULT_IMAGE_MODEL, workspace_root)
def image_base_url(workspace_root: str | Path = ".") -> str:
return config_value("image", "base_url", ["VIMAX_IMAGE_BASE_URL"], DEFAULT_IMAGE_BASE_URL, workspace_root)
def image_api_key(workspace_root: str | Path = ".") -> str:
return config_value("image", "api_key", ["VIMAX_IMAGE_API_KEY", "VIMAX_LLM_API_KEY", "VIMAX_API_KEY"], llm_api_key(workspace_root), workspace_root)
def embedding_model(workspace_root: str | Path = ".") -> str:
return config_value("embedding", "model", ["VIMAX_EMBEDDING_MODEL"], DEFAULT_EMBEDDING_MODEL, workspace_root)
def embedding_model_provider(workspace_root: str | Path = ".") -> str:
return config_value("embedding", "model_provider", ["VIMAX_EMBEDDING_MODEL_PROVIDER"], DEFAULT_EMBEDDING_MODEL_PROVIDER, workspace_root)
def embedding_base_url(workspace_root: str | Path = ".") -> str:
return config_value("embedding", "base_url", ["VIMAX_EMBEDDING_BASE_URL"], "", workspace_root)
def embedding_api_key(workspace_root: str | Path = ".") -> str:
return config_value("embedding", "api_key", ["VIMAX_EMBEDDING_API_KEY"], "", workspace_root)
def reranker_model(workspace_root: str | Path = ".") -> str:
return config_value("reranker", "model", ["VIMAX_RERANKER_MODEL"], DEFAULT_RERANKER_MODEL, workspace_root)
def reranker_base_url(workspace_root: str | Path = ".") -> str:
return config_value("reranker", "base_url", ["VIMAX_RERANKER_BASE_URL"], "", workspace_root)
def reranker_api_key(workspace_root: str | Path = ".") -> str:
return config_value("reranker", "api_key", ["VIMAX_RERANKER_API_KEY"], "", workspace_root)
def video_model(workspace_root: str | Path = ".") -> str:
return config_value("video", "model", ["VIMAX_VIDEO_MODEL"], DEFAULT_VIDEO_MODEL, workspace_root)
def video_base_url(workspace_root: str | Path = ".") -> str:
return config_value("video", "base_url", ["VIMAX_VIDEO_BASE_URL"], DEFAULT_VIDEO_BASE_URL, workspace_root)
def video_api_key(workspace_root: str | Path = ".") -> str:
return config_value("video", "api_key", ["VIMAX_VIDEO_API_KEY", "VIMAX_LLM_API_KEY", "VIMAX_API_KEY"], llm_api_key(workspace_root), workspace_root)
def api_provider_from_base_url(base_url: str) -> str:
normalized = base_url.strip().lower()
if "openrouter.ai" in normalized:
return "openrouter"
if "yunwu.ai" in normalized:
return "yunwu"
return ""
def video_provider(workspace_root: str | Path = ".") -> str:
"""Infer the video API relay/provider from video.base_url.
This is not a model provider setting. OpenRouter/Yunwu are transport/API
gateways here, so users should configure base_url and let the adapter pick
the matching implementation.
"""
return api_provider_from_base_url(video_base_url(workspace_root))