Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/allenygy_gagent.json
T

1 line
106 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "allenygy/gagent", "files": {".env.example": {"51052fdf77c8e32c76578a4efdd8884cb4f03e97": {"t": 1785746731.1381478, "n": 3349, "h": "ad966ee07f16154b", "c": "# Copy this file to `.env`, fill in the secrets you intend to use locally,\n# and NEVER commit the populated file.\n\n# =============================================================================\n# LLM Provider selection + global retry/backoff\n# =============================================================================\n# e.g. glm | qwen | perplexity | doubao | moonshot | deepseek | grok | gemini\nLLM_PROVIDER=glm\nLLM_RETRIES=3\nLLM_BACKOFF_BASE=0.5\nLLM_REQUEST_TIMEOUT=60\n\n# Task-specific model defaults (used by decomposer/executor if not overridden)\nDECOMP_MODEL=qwen3-max\nPLAN_EXECUTOR_MODEL=qwen3-max\n\n# =============================================================================\n# Provider-specific credentials\n# Only fill the ones you actually use. Leave others blank.\n# =============================================================================\n\n## Qwen (high quota / high concurrency)\nQWEN_API_KEY=\nQWEN_API_URL=https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\nQWEN_MODEL=qwen3-max\n\n## GLM (fallback /-compatible default)\nGLM_API_KEY=\nGLM_API_URL=https://open.bigmodel.cn/api/paas/v4/chat/completions\nGLM_MODEL=glm-4-flash\n\n## Perplexity\nPERPLEXITY_API_KEY=\nPERPLEXITY_API_URL=https://api.perplexity.ai/chat/completions\nPERPLEXITY_MODEL=sonar-reasoning-pro\n\n## Doubao (Volcengine Ark)\nDOUBAO_API_KEY=\nDOUBAO_API_URL=https://ark.cn-beijing.volces.com/api/v3\nDOUBAO_MODEL=doubao-seed-1-6-251015\n\n## Moonshot / Kimi\nMOONSHOT_API_KEY=\nMOONSHOT_API_URL=https://api.moonshot.cn/v1\nMOONSHOT_MODEL=kimi-k2-turbo-preview\n\n## DeepSeek\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com\nDEEPSEEK_MODEL=deepseek-chat\n\n## Grok / xAI\nGROK_API_KEY=\nGROK_API_URL=https://api.x.ai/v1\nGROK_MODEL=grok-4\n\n## Gemini (OpenAI-compatible endpoint)\nGEMINI_API_KEY=\nGEMINI_API_URL=https://generativelanguage.googleapis.com/v1beta/openai/\nGEMINI_MODEL=gemini-2.5-flash\n\n## Other optional providers already supported elsewhere\nOPENAI_API_KEY=\nANTHROPIC_API_KEY=\nTAVILY_API_KEY=\n\n# =============================================================================\n# Springer Nature\n# =============================================================================\nSPRINGER_META_API_KEY=\nSPRINGER_OPENACCESS_API_KEY=\n\n# =============================================================================\n# MultiRAG\n# =============================================================================\nMULTIRAG_BASE_URL=\nMULTIRAG_API_KEY=\nMULTIRAG_QUERY_TIMEOUT_SECONDS=420\nMULTIRAG_HEALTH_TIMEOUT_SECONDS=5\nMULTIRAG_HEALTH_CACHE_TTL=60\nGRAPH_RAG_CACHE_TTL=900\n\n\n# =============================================================================\n# Core application configuration\n# =============================================================================\nBACKEND_HOST=0.0.0.0\nBACKEND_PORT=9000\nBASE_URL=http://0.0.0.0:9000\nDATABASE_URL=sqlite:///./tasks.db\nLOG_LEVEL=INFO\n\n# Frontend dev server defaults (used for local Vite dev/proxy hints)\nVITE_DEV_SERVER_HOST=0.0.0.0\nVITE_DEV_SERVER_PORT=3001\n# =============================================================================\n# Backend service tuning (timeouts, etc.) can be overridden below as needed.\n# =============================================================================\n# CORS_ORIGINS=http://localhost:3001\n# VITE_API_BASE_URL=http://localhost:9000\n# VITE_WS_BASE_URL=ws://localhost:9000\n"}, "16888d3a5bf21e372b37cd02e3050f738085328d": {"t": 1785767363.8207796, "n": 3349, "h": "ad966ee07f16154b", "c": "# Copy this file to `.env`, fill in the secrets you intend to use locally,\n# and NEVER commit the populated file.\n\n# =============================================================================\n# LLM Provider selection + global retry/backoff\n# =============================================================================\n# e.g. glm | qwen | perplexity | doubao | moonshot | deepseek | grok | gemini\nLLM_PROVIDER=glm\nLLM_RETRIES=3\nLLM_BACKOFF_BASE=0.5\nLLM_REQUEST_TIMEOUT=60\n\n# Task-specific model defaults (used by decomposer/executor if not overridden)\nDECOMP_MODEL=qwen3-max\nPLAN_EXECUTOR_MODEL=qwen3-max\n\n# =============================================================================\n# Provider-specific credentials\n# Only fill the ones you actually use. Leave others blank.\n# =============================================================================\n\n## Qwen (high quota / high concurrency)\nQWEN_API_KEY=\nQWEN_API_URL=https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\nQWEN_MODEL=qwen3-max\n\n## GLM (fallback /-compatible default)\nGLM_API_KEY=\nGLM_API_URL=https://open.bigmodel.cn/api/paas/v4/chat/completions\nGLM_MODEL=glm-4-flash\n\n## Perplexity\nPERPLEXITY_API_KEY=\nPERPLEXITY_API_URL=https://api.perplexity.ai/chat/completions\nPERPLEXITY_MODEL=sonar-reasoning-pro\n\n## Doubao (Volcengine Ark)\nDOUBAO_API_KEY=\nDOUBAO_API_URL=https://ark.cn-beijing.volces.com/api/v3\nDOUBAO_MODEL=doubao-seed-1-6-251015\n\n## Moonshot / Kimi\nMOONSHOT_API_KEY=\nMOONSHOT_API_URL=https://api.moonshot.cn/v1\nMOONSHOT_MODEL=kimi-k2-turbo-preview\n\n## DeepSeek\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com\nDEEPSEEK_MODEL=deepseek-chat\n\n## Grok / xAI\nGROK_API_KEY=\nGROK_API_URL=https://api.x.ai/v1\nGROK_MODEL=grok-4\n\n## Gemini (OpenAI-compatible endpoint)\nGEMINI_API_KEY=\nGEMINI_API_URL=https://generativelanguage.googleapis.com/v1beta/openai/\nGEMINI_MODEL=gemini-2.5-flash\n\n## Other optional providers already supported elsewhere\nOPENAI_API_KEY=\nANTHROPIC_API_KEY=\nTAVILY_API_KEY=\n\n# =============================================================================\n# Springer Nature\n# =============================================================================\nSPRINGER_META_API_KEY=\nSPRINGER_OPENACCESS_API_KEY=\n\n# =============================================================================\n# MultiRAG\n# =============================================================================\nMULTIRAG_BASE_URL=\nMULTIRAG_API_KEY=\nMULTIRAG_QUERY_TIMEOUT_SECONDS=420\nMULTIRAG_HEALTH_TIMEOUT_SECONDS=5\nMULTIRAG_HEALTH_CACHE_TTL=60\nGRAPH_RAG_CACHE_TTL=900\n\n\n# =============================================================================\n# Core application configuration\n# =============================================================================\nBACKEND_HOST=0.0.0.0\nBACKEND_PORT=9000\nBASE_URL=http://0.0.0.0:9000\nDATABASE_URL=sqlite:///./tasks.db\nLOG_LEVEL=INFO\n\n# Frontend dev server defaults (used for local Vite dev/proxy hints)\nVITE_DEV_SERVER_HOST=0.0.0.0\nVITE_DEV_SERVER_PORT=3001\n# =============================================================================\n# Backend service tuning (timeouts, etc.) can be overridden below as needed.\n# =============================================================================\n# CORS_ORIGINS=http://localhost:3001\n# VITE_API_BASE_URL=http://localhost:9000\n# VITE_WS_BASE_URL=ws://localhost:9000\n"}, "406b44d8ba6b5eb491429d7009d7771b9ed2d346": {"t": 1785767365.0047827, "n": 3018, "h": "aa7e63a994ab7dec", "c": "# Copy this file to `.env`, fill in the secrets you intend to use locally,\n# and NEVER commit the populated file.\n\n# =============================================================================\n# LLM Provider selection + global retry/backoff\n# =============================================================================\n# e.g. glm | qwen | perplexity | doubao | moonshot | deepseek | grok | gemini\nLLM_PROVIDER=glm\nLLM_RETRIES=3\nLLM_BACKOFF_BASE=0.5\nLLM_REQUEST_TIMEOUT=60\n\n# Task-specific model defaults (used by decomposer/executor if not overridden)\nDECOMP_MODEL=qwen3-max\nPLAN_EXECUTOR_MODEL=qwen3-max\n\n# =============================================================================\n# Provider-specific credentials\n# Only fill the ones you actually use. Leave others blank.\n# =============================================================================\n\n## Qwen (high quota / high concurrency)\nQWEN_API_KEY=\nQWEN_API_URL=https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\nQWEN_MODEL=qwen3-max\n\n## GLM (fallback /-compatible default)\nGLM_API_KEY=\nGLM_API_URL=https://open.bigmodel.cn/api/paas/v4/chat/completions\nGLM_MODEL=glm-4-flash\n\n## Perplexity\nPERPLEXITY_API_KEY=\nPERPLEXITY_API_URL=https://api.perplexity.ai/chat/completions\nPERPLEXITY_MODEL=sonar-reasoning-pro\n\n## Doubao (Volcengine Ark)\nDOUBAO_API_KEY=\nDOUBAO_API_URL=https://ark.cn-beijing.volces.com/api/v3\nDOUBAO_MODEL=doubao-seed-1-6-251015\n\n## Moonshot / Kimi\nMOONSHOT_API_KEY=\nMOONSHOT_API_URL=https://api.moonshot.cn/v1\nMOONSHOT_MODEL=kimi-k2-turbo-preview\n\n## DeepSeek\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com\nDEEPSEEK_MODEL=deepseek-chat\n\n## Grok / xAI\nGROK_API_KEY=\nGROK_API_URL=https://api.x.ai/v1\nGROK_MODEL=grok-4\n\n## Gemini (OpenAI-compatible endpoint)\nGEMINI_API_KEY=\nGEMINI_API_URL=https://generativelanguage.googleapis.com/v1beta/openai/\nGEMINI_MODEL=gemini-2.5-flash\n\n## Other optional providers already supported elsewhere\nOPENAI_API_KEY=\nANTHROPIC_API_KEY=\nTAVILY_API_KEY=\n\n# =============================================================================\n# Springer Nature\n# =============================================================================\nSPRINGER_META_API_KEY=\nSPRINGER_OPENACCESS_API_KEY=\n\n\n# =============================================================================\n# Core application configuration\n# =============================================================================\nBACKEND_HOST=0.0.0.0\nBACKEND_PORT=9000\nBASE_URL=http://0.0.0.0:9000\nDATABASE_URL=sqlite:///./tasks.db\nLOG_LEVEL=INFO\n\n# Frontend dev server defaults (used for local Vite dev/proxy hints)\nVITE_DEV_SERVER_HOST=0.0.0.0\nVITE_DEV_SERVER_PORT=3001\n# =============================================================================\n# Backend service tuning (timeouts, etc.) can be overridden below as needed.\n# =============================================================================\n# CORS_ORIGINS=http://localhost:3001\n# VITE_API_BASE_URL=http://localhost:9000\n# VITE_WS_BASE_URL=ws://localhost:9000\n"}, "2755eec0bd9fdf5e244cc01348129e1b4b89df12": {"t": 1785767366.4603398, "n": 2786, "h": "7b2fd52eb9be1bdc", "c": "# Copy this file to `.env`, fill in the secrets you intend to use locally,\n# and NEVER commit the populated file.\n\n# =============================================================================\n# LLM Provider selection + global retry/backoff\n# =============================================================================\n# e.g. glm | qwen | perplexity | doubao | moonshot | deepseek | grok | gemini\nLLM_PROVIDER=glm\nLLM_RETRIES=3\nLLM_BACKOFF_BASE=0.5\nLLM_REQUEST_TIMEOUT=60\n\n# Task-specific model defaults (used by decomposer/executor if not overridden)\nDECOMP_MODEL=qwen3-max\nPLAN_EXECUTOR_MODEL=qwen3-max\n\n# =============================================================================\n# Provider-specific credentials\n# Only fill the ones you actually use. Leave others blank.\n# =============================================================================\n\n## Qwen (high quota / high concurrency)\nQWEN_API_KEY=\nQWEN_API_URL=https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\nQWEN_MODEL=qwen3-max\n\n## GLM (fallback /-compatible default)\nGLM_API_KEY=\nGLM_API_URL=https://open.bigmodel.cn/api/paas/v4/chat/completions\nGLM_MODEL=glm-4-flash\n\n## Perplexity\nPERPLEXITY_API_KEY=\nPERPLEXITY_API_URL=https://api.perplexity.ai/chat/completions\nPERPLEXITY_MODEL=sonar-reasoning-pro\n\n## Doubao (Volcengine Ark)\nDOUBAO_API_KEY=\nDOUBAO_API_URL=https://ark.cn-beijing.volces.com/api/v3\nDOUBAO_MODEL=doubao-seed-1-6-251015\n\n## Moonshot / Kimi\nMOONSHOT_API_KEY=\nMOONSHOT_API_URL=https://api.moonshot.cn/v1\nMOONSHOT_MODEL=kimi-k2-turbo-preview\n\n## DeepSeek\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com\nDEEPSEEK_MODEL=deepseek-chat\n\n## Grok / xAI\nGROK_API_KEY=\nGROK_API_URL=https://api.x.ai/v1\nGROK_MODEL=grok-4\n\n## Gemini (OpenAI-compatible endpoint)\nGEMINI_API_KEY=\nGEMINI_API_URL=https://generativelanguage.googleapis.com/v1beta/openai/\nGEMINI_MODEL=gemini-2.5-flash\n\n## Other optional providers already supported elsewhere\nOPENAI_API_KEY=\nANTHROPIC_API_KEY=\nTAVILY_API_KEY=\n\n\n# =============================================================================\n# Core application configuration\n# =============================================================================\nBACKEND_HOST=0.0.0.0\nBACKEND_PORT=9000\nBASE_URL=http://0.0.0.0:9000\nDATABASE_URL=sqlite:///./tasks.db\nLOG_LEVEL=INFO\n\n# Frontend dev server defaults (used for local Vite dev/proxy hints)\nVITE_DEV_SERVER_HOST=0.0.0.0\nVITE_DEV_SERVER_PORT=3001\n# =============================================================================\n# Backend service tuning (timeouts, etc.) can be overridden below as needed.\n# =============================================================================\n# CORS_ORIGINS=http://localhost:3001\n# VITE_API_BASE_URL=http://localhost:9000\n# VITE_WS_BASE_URL=ws://localhost:9000"}, "8ba709eface0542608e5320aa934ba9ed155a74f": {"t": 1785767367.668171, "n": 2787, "h": "325e476dd584782a", "c": "# Copy this file to `.env`, fill in the secrets you intend to use locally,\n# and NEVER commit the populated file.\n\n# =============================================================================\n# Core application configuration\n# =============================================================================\nBACKEND_HOST=0.0.0.0\nBACKEND_PORT=9000\nBASE_URL=http://0.0.0.0:9000\nDATABASE_URL=sqlite:///./tasks.db\nLOG_LEVEL=INFO\n\n# Frontend dev server defaults (used for local Vite dev/proxy hints)\nVITE_DEV_SERVER_HOST=0.0.0.0\nVITE_DEV_SERVER_PORT=3001\n\n\n# =============================================================================\n# LLM Provider selection + global retry/backoff\n# =============================================================================\n# e.g. glm | qwen | perplexity | doubao | moonshot | deepseek | grok | gemini\nLLM_PROVIDER=glm\nLLM_RETRIES=3\nLLM_BACKOFF_BASE=0.5\nLLM_REQUEST_TIMEOUT=60\n\n# Task-specific model defaults (used by decomposer/executor if not overridden)\nDECOMP_MODEL=qwen3-max\nPLAN_EXECUTOR_MODEL=qwen3-max\n\n# =============================================================================\n# Provider-specific credentials\n# Only fill the ones you actually use. Leave others blank.\n# =============================================================================\n\n## Qwen (high quota / high concurrency)\nQWEN_API_KEY=\nQWEN_API_URL=https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\nQWEN_MODEL=qwen3-max\n\n## GLM (fallback /-compatible default)\nGLM_API_KEY=\nGLM_API_URL=https://open.bigmodel.cn/api/paas/v4/chat/completions\nGLM_MODEL=glm-4-flash\n\n## Perplexity\nPERPLEXITY_API_KEY=\nPERPLEXITY_API_URL=https://api.perplexity.ai/chat/completions\nPERPLEXITY_MODEL=sonar-reasoning-pro\n\n## Doubao (Volcengine Ark)\nDOUBAO_API_KEY=\nDOUBAO_API_URL=https://ark.cn-beijing.volces.com/api/v3\nDOUBAO_MODEL=doubao-seed-1-6-251015\n\n## Moonshot / Kimi\nMOONSHOT_API_KEY=\nMOONSHOT_API_URL=https://api.moonshot.cn/v1\nMOONSHOT_MODEL=kimi-k2-turbo-preview\n\n## DeepSeek\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com\nDEEPSEEK_MODEL=deepseek-chat\n\n## Grok / xAI\nGROK_API_KEY=\nGROK_API_URL=https://api.x.ai/v1\nGROK_MODEL=grok-4\n\n## Gemini (OpenAI-compatible endpoint)\nGEMINI_API_KEY=\nGEMINI_API_URL=https://generativelanguage.googleapis.com/v1beta/openai/\nGEMINI_MODEL=gemini-2.5-flash\n\n## Other optional providers already supported elsewhere\nOPENAI_API_KEY=\nANTHROPIC_API_KEY=\nTAVILY_API_KEY=\n\n# =============================================================================\n# Backend service tuning (timeouts, etc.) can be overridden below as needed.\n# =============================================================================\n# CORS_ORIGINS=http://localhost:3001\n# VITE_API_BASE_URL=http://localhost:9000\n# VITE_WS_BASE_URL=ws://localhost:9000"}}, "app/services/foundation/settings.py": {"51052fdf77c8e32c76578a4efdd8884cb4f03e97": {"t": 1785746917.7038214, "n": 9024, "h": "bde996858aac09bb", "c": "#!/usr/bin/env python3\n\"\"\"Centralized application settings loaded from environment variables.\"\"\"\n\nimport os\nfrom functools import lru_cache\nfrom typing import Optional\n\n# Best-effort: load .env even in fallback or mixed environments\ntry:\n from dotenv import load_dotenv # type: ignore\n\n _skip = os.getenv(\"SKIP_DOTENV\", \"\").strip().lower() in {\"1\", \"true\", \"yes\", \"on\", \"y\"}\n if not _skip:\n load_dotenv(override=True)\nexcept Exception:\n pass\n\n\ndef _env_first(names: list[str], default: Optional[str] = None) -> Optional[str]:\n for name in names:\n if not name:\n continue\n value = os.getenv(name)\n if value:\n return value\n return default\n\n\ndef _env_str(name: str, default: str) -> str:\n return os.getenv(name, default)\n\n\ndef _env_bool(name: str, default: bool = False) -> bool:\n value = os.getenv(name)\n if value is None:\n return default\n return value.strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n\ndef _env_int(name: str, default: int) -> int:\n value = os.getenv(name)\n if value is None:\n return default\n try:\n return int(value)\n except Exception:\n return default\n\n\ndef _env_float(name: str, default: float) -> float:\n value = os.getenv(name)\n if value is None:\n return default\n try:\n return float(value)\n except Exception:\n return default\n\n\nclass AppSettings:\n \"\"\"Lightweight settings loaded from environment variables.\"\"\"\n\n def __init__(self) -> None:\n # Logging\n self.log_level: str = _env_str(\"LOG_LEVEL\", \"INFO\")\n self.log_format: str = _env_str(\"LOG_FORMAT\", \"json\")\n\n # Database\n self.database_url: str = _env_str(\"DATABASE_URL\", \"sqlite:///./tasks.db\")\n self.base_url: Optional[str] = os.getenv(\"BASE_URL\")\n\n # GLM / LLM\n self.glm_api_key: Optional[str] = os.getenv(\"GLM_API_KEY\")\n self.glm_api_url: str = _env_str(\n \"GLM_API_URL\", \"https://open.bigmodel.cn/api/paas/v4/chat/completions\"\n )\n self.glm_model: str = _env_str(\"GLM_MODEL\", \"glm-4-flash\")\n self.glm_request_timeout: int = _env_int(\"GLM_REQUEST_TIMEOUT\", 60)\n self.llm_request_timeout: int = _env_int(\"LLM_REQUEST_TIMEOUT\", 60)\n self.llm_mock: bool = _env_bool(\"LLM_MOCK\", False)\n self.llm_retries: int = _env_int(\"LLM_RETRIES\", 2)\n self.llm_backoff_base: float = _env_float(\"LLM_BACKOFF_BASE\", 0.5)\n\n # Perplexity\n self.perplexity_api_key: Optional[str] = os.getenv(\"PERPLEXITY_API_KEY\")\n self.perplexity_api_url: str = _env_str(\n \"PERPLEXITY_API_URL\", \"https://api.perplexity.ai/chat/completions\"\n )\n self.perplexity_model: str = _env_str(\"PERPLEXITY_MODEL\", \"sonar-reasoning-pro\")\n\n # Doubao\n self.doubao_api_key: Optional[str] = os.getenv(\"DOUBAO_API_KEY\")\n self.doubao_api_url: str = _env_str(\n \"DOUBAO_API_URL\", \"https://ark.cn-beijing.volces.com/api/v3\"\n )\n self.doubao_model: str = _env_str(\"DOUBAO_MODEL\", \"doubao-seed-1-6-251015\")\n\n # Moonshot / Kimi\n self.moonshot_api_key: Optional[str] = os.getenv(\"MOONSHOT_API_KEY\")\n self.moonshot_api_url: str = _env_str(\"MOONSHOT_API_URL\", \"https://api.moonshot.cn/v1\")\n self.moonshot_model: str = _env_str(\"MOONSHOT_MODEL\", \"kimi-k2-turbo-preview\")\n\n # DeepSeek\n self.deepseek_api_key: Optional[str] = os.getenv(\"DEEPSEEK_API_KEY\")\n self.deepseek_api_url: str = _env_str(\"DEEPSEEK_API_URL\", \"https://api.deepseek.com\")\n self.deepseek_model: str = _env_str(\"DEEPSEEK_MODEL\", \"deepseek-chat\")\n\n # Grok / xAI\n self.grok_api_key: Optional[str] = os.getenv(\"GROK_API_KEY\")\n self.grok_api_url: str = _env_str(\"GROK_API_URL\", \"https://api.x.ai/v1\")\n self.grok_model: str = _env_str(\"GROK_MODEL\", \"grok-4\")\n\n # Gemini\n self.gemini_api_key: Optional[str] = os.getenv(\"GEMINI_API_KEY\")\n self.gemini_api_url: str = _env_str(\n \"GEMINI_API_URL\", \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n )\n self.gemini_model: str = _env_str(\"GEMINI_MODEL\", \"gemini-2.5-flash\")\n\n # Custom OpenAI-compatible gateway\n self.custom_wxx_api_key: Optional[str] = _env_first(\n [\"CUSTOM_WXX_API_KEY\", \"OPENAI_COMPAT_API_KEY\"],\n \"sk-5cc515423d064bfda6f7e18ff433a6c1\",\n )\n self.custom_wxx_api_url: str = (\n _env_first(\n [\"CUSTOM_WXX_API_URL\", \"OPENAI_COMPAT_API_URL\"],\n \"https://trial-units-sms-leeds.trycloudflare.com/v1\",\n )\n or \"https://trial-units-sms-leeds.trycloudflare.com/v1\"\n )\n self.custom_wxx_model: str = (\n _env_first([\"CUSTOM_WXX_MODEL\", \"OPENAI_COMPAT_MODEL\"], \"gemini-3-flash\")\n or \"gemini-3-flash\"\n )\n # Backward compatibility alias\n self.openai_compat_api_key: Optional[str] = self.custom_wxx_api_key\n self.openai_compat_api_url: str = self.custom_wxx_api_url\n self.openai_compat_model: str = self.custom_wxx_model\n\n # QWEN\n self.qwen_api_key: Optional[str] = os.getenv(\"QWEN_API_KEY\")\n self.qwen_api_url: str = _env_str(\n \"QWEN_API_URL\",\n \"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\",\n )\n self.qwen_model: str = _env_str(\"QWEN_MODEL\", \"qwen-turbo\")\n\n # Provider selection\n self.llm_provider: str = _env_str(\"LLM_PROVIDER\", \"glm\")\n\n # Embeddings\n self.glm_embeddings_api_url: Optional[str] = os.getenv(\"GLM_EMBEDDINGS_API_URL\")\n self.glm_embedding_model: str = _env_str(\"GLM_EMBEDDING_MODEL\", \"embedding-3\")\n self.glm_embedding_dimension: int = _env_int(\"GLM_EMBEDDING_DIM\", 1536)\n self.glm_batch_size: int = _env_int(\"GLM_BATCH_SIZE\", 25)\n self.semantic_default_k: int = _env_int(\"SEMANTIC_DEFAULT_K\", 5)\n self.semantic_min_similarity: float = _env_float(\"SEMANTIC_MIN_SIMILARITY\", 0.3)\n self.glm_max_retries: int = _env_int(\"GLM_MAX_RETRIES\", 3)\n self.glm_retry_delay: float = _env_float(\"GLM_RETRY_DELAY\", 1.0)\n self.glm_debug: bool = _env_bool(\"GLM_DEBUG\", False)\n\n # Embedding cache\n self.embedding_cache_size: int = _env_int(\"EMBEDDING_CACHE_SIZE\", 10000)\n self.embedding_cache_persistent: bool = _env_bool(\"EMBEDDING_CACHE_PERSISTENT\", True)\n\n # Context/debug flags\n self.ctx_debug: bool = _env_bool(\"CTX_DEBUG\", False) or _env_bool(\"CONTEXT_DEBUG\", False)\n self.budget_debug: bool = _env_bool(\"BUDGET_DEBUG\", False)\n self.decomp_debug: bool = _env_bool(\"DECOMP_DEBUG\", False)\n self.global_index_path: str = _env_str(\"GLOBAL_INDEX_PATH\", \"INDEX.md\")\n\n # External providers\n self.openai_api_key: Optional[str] = _env_first([\"OPENAI_API_KEY\", \"GPT_API_KEY\"])\n self.xai_api_key: Optional[str] = _env_first([\"XAI_API_KEY\", \"GROK_API_KEY\"])\n self.anthropic_api_key: Optional[str] = _env_first([\"ANTHROPIC_API_KEY\", \"CLAUDE_API_KEY\"])\n self.tavily_api_key: Optional[str] = os.getenv(\"TAVILY_API_KEY\")\n\n # Server\n self.backend_host: str = _env_str(\"BACKEND_HOST\", \"0.0.0.0\")\n self.backend_port: int = _env_int(\"BACKEND_PORT\", 9000)\n self.cors_origins: str = _env_str(\n \"CORS_ORIGINS\",\n \"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n )\n self.chat_include_action_summary: bool = _env_bool(\"CHAT_INCLUDE_ACTION_SUMMARY\", True)\n self.job_log_retention_days: int = _env_int(\"JOB_LOG_RETENTION_DAYS\", 30)\n self.job_log_max_rows: int = _env_int(\"JOB_LOG_MAX_ROWS\", 10000)\n\n # Simulation\n self.sim_user_model: str = _env_str(\"SIM_USER_MODEL\", \"qwen3-max\")\n self.sim_judge_model: str = _env_str(\"SIM_JUDGE_MODEL\", \"qwen3-max\")\n self.sim_default_turns: int = _env_int(\"SIM_DEFAULT_TURNS\", 5)\n self.sim_max_turns: int = _env_int(\"SIM_MAX_TURNS\", 10)\n self.sim_default_goal: str = _env_str(\n \"SIM_DEFAULT_GOAL\",\n \"Refine the currently bound plan to better achieve the user's objectives.\",\n )\n\n # Memory\n self.memory_auto_save_enabled: bool = _env_bool(\"MEMORY_AUTO_SAVE_ENABLED\", True)\n self.memory_retrieve_enabled: bool = _env_bool(\"MEMORY_RETRIEVE_ENABLED\", True)\n self.memory_query_limit: int = _env_int(\"MEMORY_QUERY_LIMIT\", 5)\n self.memory_min_similarity: float = _env_float(\"MEMORY_MIN_SIMILARITY\", 0.6)\n self.memory_text_similarity: float = _env_float(\"MEMORY_TEXT_SIMILARITY\", 1.0)\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> AppSettings:\n \"\"\"Return cached application settings.\"\"\"\n settings = AppSettings()\n\n # Ensure BASE_URL fallback stays in sync with BACKEND_HOST/BACKEND_PORT\n if not settings.base_url:\n settings.base_url = f\"http://{settings.backend_host}:{settings.backend_port}\"\n\n return settings\n"}, "16888d3a5bf21e372b37cd02e3050f738085328d": {"t": 1785767364.887629, "n": 9024, "h": "bde996858aac09bb", "c": "#!/usr/bin/env python3\n\"\"\"Centralized application settings loaded from environment variables.\"\"\"\n\nimport os\nfrom functools import lru_cache\nfrom typing import Optional\n\n# Best-effort: load .env even in fallback or mixed environments\ntry:\n from dotenv import load_dotenv # type: ignore\n\n _skip = os.getenv(\"SKIP_DOTENV\", \"\").strip().lower() in {\"1\", \"true\", \"yes\", \"on\", \"y\"}\n if not _skip:\n load_dotenv(override=True)\nexcept Exception:\n pass\n\n\ndef _env_first(names: list[str], default: Optional[str] = None) -> Optional[str]:\n for name in names:\n if not name:\n continue\n value = os.getenv(name)\n if value:\n return value\n return default\n\n\ndef _env_str(name: str, default: str) -> str:\n return os.getenv(name, default)\n\n\ndef _env_bool(name: str, default: bool = False) -> bool:\n value = os.getenv(name)\n if value is None:\n return default\n return value.strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n\ndef _env_int(name: str, default: int) -> int:\n value = os.getenv(name)\n if value is None:\n return default\n try:\n return int(value)\n except Exception:\n return default\n\n\ndef _env_float(name: str, default: float) -> float:\n value = os.getenv(name)\n if value is None:\n return default\n try:\n return float(value)\n except Exception:\n return default\n\n\nclass AppSettings:\n \"\"\"Lightweight settings loaded from environment variables.\"\"\"\n\n def __init__(self) -> None:\n # Logging\n self.log_level: str = _env_str(\"LOG_LEVEL\", \"INFO\")\n self.log_format: str = _env_str(\"LOG_FORMAT\", \"json\")\n\n # Database\n self.database_url: str = _env_str(\"DATABASE_URL\", \"sqlite:///./tasks.db\")\n self.base_url: Optional[str] = os.getenv(\"BASE_URL\")\n\n # GLM / LLM\n self.glm_api_key: Optional[str] = os.getenv(\"GLM_API_KEY\")\n self.glm_api_url: str = _env_str(\n \"GLM_API_URL\", \"https://open.bigmodel.cn/api/paas/v4/chat/completions\"\n )\n self.glm_model: str = _env_str(\"GLM_MODEL\", \"glm-4-flash\")\n self.glm_request_timeout: int = _env_int(\"GLM_REQUEST_TIMEOUT\", 60)\n self.llm_request_timeout: int = _env_int(\"LLM_REQUEST_TIMEOUT\", 60)\n self.llm_mock: bool = _env_bool(\"LLM_MOCK\", False)\n self.llm_retries: int = _env_int(\"LLM_RETRIES\", 2)\n self.llm_backoff_base: float = _env_float(\"LLM_BACKOFF_BASE\", 0.5)\n\n # Perplexity\n self.perplexity_api_key: Optional[str] = os.getenv(\"PERPLEXITY_API_KEY\")\n self.perplexity_api_url: str = _env_str(\n \"PERPLEXITY_API_URL\", \"https://api.perplexity.ai/chat/completions\"\n )\n self.perplexity_model: str = _env_str(\"PERPLEXITY_MODEL\", \"sonar-reasoning-pro\")\n\n # Doubao\n self.doubao_api_key: Optional[str] = os.getenv(\"DOUBAO_API_KEY\")\n self.doubao_api_url: str = _env_str(\n \"DOUBAO_API_URL\", \"https://ark.cn-beijing.volces.com/api/v3\"\n )\n self.doubao_model: str = _env_str(\"DOUBAO_MODEL\", \"doubao-seed-1-6-251015\")\n\n # Moonshot / Kimi\n self.moonshot_api_key: Optional[str] = os.getenv(\"MOONSHOT_API_KEY\")\n self.moonshot_api_url: str = _env_str(\"MOONSHOT_API_URL\", \"https://api.moonshot.cn/v1\")\n self.moonshot_model: str = _env_str(\"MOONSHOT_MODEL\", \"kimi-k2-turbo-preview\")\n\n # DeepSeek\n self.deepseek_api_key: Optional[str] = os.getenv(\"DEEPSEEK_API_KEY\")\n self.deepseek_api_url: str = _env_str(\"DEEPSEEK_API_URL\", \"https://api.deepseek.com\")\n self.deepseek_model: str = _env_str(\"DEEPSEEK_MODEL\", \"deepseek-chat\")\n\n # Grok / xAI\n self.grok_api_key: Optional[str] = os.getenv(\"GROK_API_KEY\")\n self.grok_api_url: str = _env_str(\"GROK_API_URL\", \"https://api.x.ai/v1\")\n self.grok_model: str = _env_str(\"GROK_MODEL\", \"grok-4\")\n\n # Gemini\n self.gemini_api_key: Optional[str] = os.getenv(\"GEMINI_API_KEY\")\n self.gemini_api_url: str = _env_str(\n \"GEMINI_API_URL\", \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n )\n self.gemini_model: str = _env_str(\"GEMINI_MODEL\", \"gemini-2.5-flash\")\n\n # Custom OpenAI-compatible gateway\n self.custom_wxx_api_key: Optional[str] = _env_first(\n [\"CUSTOM_WXX_API_KEY\", \"OPENAI_COMPAT_API_KEY\"],\n \"sk-5cc515423d064bfda6f7e18ff433a6c1\",\n )\n self.custom_wxx_api_url: str = (\n _env_first(\n [\"CUSTOM_WXX_API_URL\", \"OPENAI_COMPAT_API_URL\"],\n \"https://trial-units-sms-leeds.trycloudflare.com/v1\",\n )\n or \"https://trial-units-sms-leeds.trycloudflare.com/v1\"\n )\n self.custom_wxx_model: str = (\n _env_first([\"CUSTOM_WXX_MODEL\", \"OPENAI_COMPAT_MODEL\"], \"gemini-3-flash\")\n or \"gemini-3-flash\"\n )\n # Backward compatibility alias\n self.openai_compat_api_key: Optional[str] = self.custom_wxx_api_key\n self.openai_compat_api_url: str = self.custom_wxx_api_url\n self.openai_compat_model: str = self.custom_wxx_model\n\n # QWEN\n self.qwen_api_key: Optional[str] = os.getenv(\"QWEN_API_KEY\")\n self.qwen_api_url: str = _env_str(\n \"QWEN_API_URL\",\n \"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\",\n )\n self.qwen_model: str = _env_str(\"QWEN_MODEL\", \"qwen-turbo\")\n\n # Provider selection\n self.llm_provider: str = _env_str(\"LLM_PROVIDER\", \"glm\")\n\n # Embeddings\n self.glm_embeddings_api_url: Optional[str] = os.getenv(\"GLM_EMBEDDINGS_API_URL\")\n self.glm_embedding_model: str = _env_str(\"GLM_EMBEDDING_MODEL\", \"embedding-3\")\n self.glm_embedding_dimension: int = _env_int(\"GLM_EMBEDDING_DIM\", 1536)\n self.glm_batch_size: int = _env_int(\"GLM_BATCH_SIZE\", 25)\n self.semantic_default_k: int = _env_int(\"SEMANTIC_DEFAULT_K\", 5)\n self.semantic_min_similarity: float = _env_float(\"SEMANTIC_MIN_SIMILARITY\", 0.3)\n self.glm_max_retries: int = _env_int(\"GLM_MAX_RETRIES\", 3)\n self.glm_retry_delay: float = _env_float(\"GLM_RETRY_DELAY\", 1.0)\n self.glm_debug: bool = _env_bool(\"GLM_DEBUG\", False)\n\n # Embedding cache\n self.embedding_cache_size: int = _env_int(\"EMBEDDING_CACHE_SIZE\", 10000)\n self.embedding_cache_persistent: bool = _env_bool(\"EMBEDDING_CACHE_PERSISTENT\", True)\n\n # Context/debug flags\n self.ctx_debug: bool = _env_bool(\"CTX_DEBUG\", False) or _env_bool(\"CONTEXT_DEBUG\", False)\n self.budget_debug: bool = _env_bool(\"BUDGET_DEBUG\", False)\n self.decomp_debug: bool = _env_bool(\"DECOMP_DEBUG\", False)\n self.global_index_path: str = _env_str(\"GLOBAL_INDEX_PATH\", \"INDEX.md\")\n\n # External providers\n self.openai_api_key: Optional[str] = _env_first([\"OPENAI_API_KEY\", \"GPT_API_KEY\"])\n self.xai_api_key: Optional[str] = _env_first([\"XAI_API_KEY\", \"GROK_API_KEY\"])\n self.anthropic_api_key: Optional[str] = _env_first([\"ANTHROPIC_API_KEY\", \"CLAUDE_API_KEY\"])\n self.tavily_api_key: Optional[str] = os.getenv(\"TAVILY_API_KEY\")\n\n # Server\n self.backend_host: str = _env_str(\"BACKEND_HOST\", \"0.0.0.0\")\n self.backend_port: int = _env_int(\"BACKEND_PORT\", 9000)\n self.cors_origins: str = _env_str(\n \"CORS_ORIGINS\",\n \"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n )\n self.chat_include_action_summary: bool = _env_bool(\"CHAT_INCLUDE_ACTION_SUMMARY\", True)\n self.job_log_retention_days: int = _env_int(\"JOB_LOG_RETENTION_DAYS\", 30)\n self.job_log_max_rows: int = _env_int(\"JOB_LOG_MAX_ROWS\", 10000)\n\n # Simulation\n self.sim_user_model: str = _env_str(\"SIM_USER_MODEL\", \"qwen3-max\")\n self.sim_judge_model: str = _env_str(\"SIM_JUDGE_MODEL\", \"qwen3-max\")\n self.sim_default_turns: int = _env_int(\"SIM_DEFAULT_TURNS\", 5)\n self.sim_max_turns: int = _env_int(\"SIM_MAX_TURNS\", 10)\n self.sim_default_goal: str = _env_str(\n \"SIM_DEFAULT_GOAL\",\n \"Refine the currently bound plan to better achieve the user's objectives.\",\n )\n\n # Memory\n self.memory_auto_save_enabled: bool = _env_bool(\"MEMORY_AUTO_SAVE_ENABLED\", True)\n self.memory_retrieve_enabled: bool = _env_bool(\"MEMORY_RETRIEVE_ENABLED\", True)\n self.memory_query_limit: int = _env_int(\"MEMORY_QUERY_LIMIT\", 5)\n self.memory_min_similarity: float = _env_float(\"MEMORY_MIN_SIMILARITY\", 0.6)\n self.memory_text_similarity: float = _env_float(\"MEMORY_TEXT_SIMILARITY\", 1.0)\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> AppSettings:\n \"\"\"Return cached application settings.\"\"\"\n settings = AppSettings()\n\n # Ensure BASE_URL fallback stays in sync with BACKEND_HOST/BACKEND_PORT\n if not settings.base_url:\n settings.base_url = f\"http://{settings.backend_host}:{settings.backend_port}\"\n\n return settings\n"}, "b7e0c7324694978138e0fd5e0b5b11d7c7a56f15": {"t": 1785767366.1321206, "n": 7981, "h": "427dccf61fd902c9", "c": "#!/usr/bin/env python3\n\"\"\"Centralized application settings loaded from environment variables.\"\"\"\n\nimport os\nfrom functools import lru_cache\nfrom typing import Optional\n\n# Best-effort: load .env even in fallback or mixed environments\ntry:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv(override=True)\nexcept Exception:\n pass\n\n\ndef _env_first(names: list[str], default: Optional[str] = None) -> Optional[str]:\n for name in names:\n if not name:\n continue\n value = os.getenv(name)\n if value:\n return value\n return default\n\n\ndef _env_str(name: str, default: str) -> str:\n return os.getenv(name, default)\n\n\ndef _env_bool(name: str, default: bool = False) -> bool:\n value = os.getenv(name)\n if value is None:\n return default\n return value.strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n\ndef _env_int(name: str, default: int) -> int:\n value = os.getenv(name)\n if value is None:\n return default\n try:\n return int(value)\n except Exception:\n return default\n\n\ndef _env_float(name: str, default: float) -> float:\n value = os.getenv(name)\n if value is None:\n return default\n try:\n return float(value)\n except Exception:\n return default\n\n\nclass AppSettings:\n \"\"\"Lightweight settings loaded from environment variables.\"\"\"\n\n def __init__(self) -> None:\n # Logging\n self.log_level: str = _env_str(\"LOG_LEVEL\", \"INFO\")\n self.log_format: str = _env_str(\"LOG_FORMAT\", \"json\")\n\n # Database\n self.database_url: str = _env_str(\"DATABASE_URL\", \"sqlite:///./tasks.db\")\n self.base_url: Optional[str] = os.getenv(\"BASE_URL\")\n\n # GLM / LLM\n self.glm_api_key: Optional[str] = os.getenv(\"GLM_API_KEY\")\n self.glm_api_url: str = _env_str(\n \"GLM_API_URL\", \"https://open.bigmodel.cn/api/paas/v4/chat/completions\"\n )\n self.glm_model: str = _env_str(\"GLM_MODEL\", \"glm-4-flash\")\n self.glm_request_timeout: int = _env_int(\"GLM_REQUEST_TIMEOUT\", 60)\n self.llm_request_timeout: int = _env_int(\"LLM_REQUEST_TIMEOUT\", 60)\n self.llm_mock: bool = _env_bool(\"LLM_MOCK\", False)\n self.llm_retries: int = _env_int(\"LLM_RETRIES\", 2)\n self.llm_backoff_base: float = _env_float(\"LLM_BACKOFF_BASE\", 0.5)\n\n # Perplexity\n self.perplexity_api_key: Optional[str] = os.getenv(\"PERPLEXITY_API_KEY\")\n self.perplexity_api_url: str = _env_str(\n \"PERPLEXITY_API_URL\", \"https://api.perplexity.ai/chat/completions\"\n )\n self.perplexity_model: str = _env_str(\"PERPLEXITY_MODEL\", \"sonar-reasoning-pro\")\n\n # Doubao\n self.doubao_api_key: Optional[str] = os.getenv(\"DOUBAO_API_KEY\")\n self.doubao_api_url: str = _env_str(\n \"DOUBAO_API_URL\", \"https://ark.cn-beijing.volces.com/api/v3\"\n )\n self.doubao_model: str = _env_str(\"DOUBAO_MODEL\", \"doubao-seed-1-6-251015\")\n\n # Moonshot / Kimi\n self.moonshot_api_key: Optional[str] = os.getenv(\"MOONSHOT_API_KEY\")\n self.moonshot_api_url: str = _env_str(\"MOONSHOT_API_URL\", \"https://api.moonshot.cn/v1\")\n self.moonshot_model: str = _env_str(\"MOONSHOT_MODEL\", \"kimi-k2-turbo-preview\")\n\n # DeepSeek\n self.deepseek_api_key: Optional[str] = os.getenv(\"DEEPSEEK_API_KEY\")\n self.deepseek_api_url: str = _env_str(\"DEEPSEEK_API_URL\", \"https://api.deepseek.com\")\n self.deepseek_model: str = _env_str(\"DEEPSEEK_MODEL\", \"deepseek-chat\")\n\n # Grok / xAI\n self.grok_api_key: Optional[str] = os.getenv(\"GROK_API_KEY\")\n self.grok_api_url: str = _env_str(\"GROK_API_URL\", \"https://api.x.ai/v1\")\n self.grok_model: str = _env_str(\"GROK_MODEL\", \"grok-4\")\n\n # Gemini\n self.gemini_api_key: Optional[str] = os.getenv(\"GEMINI_API_KEY\")\n self.gemini_api_url: str = _env_str(\n \"GEMINI_API_URL\", \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n )\n self.gemini_model: str = _env_str(\"GEMINI_MODEL\", \"gemini-2.5-flash\")\n\n # QWEN\n self.qwen_api_key: Optional[str] = os.getenv(\"QWEN_API_KEY\")\n self.qwen_api_url: str = _env_str(\n \"QWEN_API_URL\",\n \"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\",\n )\n self.qwen_model: str = _env_str(\"QWEN_MODEL\", \"qwen-turbo\")\n\n # Provider selection\n self.llm_provider: str = _env_str(\"LLM_PROVIDER\", \"glm\")\n\n # Embeddings\n self.glm_embeddings_api_url: Optional[str] = os.getenv(\"GLM_EMBEDDINGS_API_URL\")\n self.glm_embedding_model: str = _env_str(\"GLM_EMBEDDING_MODEL\", \"embedding-3\")\n self.glm_embedding_dimension: int = _env_int(\"GLM_EMBEDDING_DIM\", 1536)\n self.glm_batch_size: int = _env_int(\"GLM_BATCH_SIZE\", 25)\n self.semantic_default_k: int = _env_int(\"SEMANTIC_DEFAULT_K\", 5)\n self.semantic_min_similarity: float = _env_float(\"SEMANTIC_MIN_SIMILARITY\", 0.3)\n self.glm_max_retries: int = _env_int(\"GLM_MAX_RETRIES\", 3)\n self.glm_retry_delay: float = _env_float(\"GLM_RETRY_DELAY\", 1.0)\n self.glm_debug: bool = _env_bool(\"GLM_DEBUG\", False)\n\n # Embedding cache\n self.embedding_cache_size: int = _env_int(\"EMBEDDING_CACHE_SIZE\", 10000)\n self.embedding_cache_persistent: bool = _env_bool(\"EMBEDDING_CACHE_PERSISTENT\", True)\n\n # Context/debug flags\n self.ctx_debug: bool = _env_bool(\"CTX_DEBUG\", False) or _env_bool(\"CONTEXT_DEBUG\", False)\n self.budget_debug: bool = _env_bool(\"BUDGET_DEBUG\", False)\n self.decomp_debug: bool = _env_bool(\"DECOMP_DEBUG\", False)\n self.global_index_path: str = _env_str(\"GLOBAL_INDEX_PATH\", \"INDEX.md\")\n\n # External providers\n self.openai_api_key: Optional[str] = _env_first([\"OPENAI_API_KEY\", \"GPT_API_KEY\"])\n self.xai_api_key: Optional[str] = _env_first([\"XAI_API_KEY\", \"GROK_API_KEY\"])\n self.anthropic_api_key: Optional[str] = _env_first([\"ANTHROPIC_API_KEY\", \"CLAUDE_API_KEY\"])\n self.tavily_api_key: Optional[str] = os.getenv(\"TAVILY_API_KEY\")\n\n # Server\n self.backend_host: str = _env_str(\"BACKEND_HOST\", \"0.0.0.0\")\n self.backend_port: int = _env_int(\"BACKEND_PORT\", 9000)\n self.cors_origins: str = _env_str(\n \"CORS_ORIGINS\",\n \"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n )\n self.chat_include_action_summary: bool = _env_bool(\"CHAT_INCLUDE_ACTION_SUMMARY\", True)\n self.job_log_retention_days: int = _env_int(\"JOB_LOG_RETENTION_DAYS\", 30)\n self.job_log_max_rows: int = _env_int(\"JOB_LOG_MAX_ROWS\", 10000)\n\n # Simulation\n self.sim_user_model: str = _env_str(\"SIM_USER_MODEL\", \"qwen3-max\")\n self.sim_judge_model: str = _env_str(\"SIM_JUDGE_MODEL\", \"qwen3-max\")\n self.sim_default_turns: int = _env_int(\"SIM_DEFAULT_TURNS\", 5)\n self.sim_max_turns: int = _env_int(\"SIM_MAX_TURNS\", 10)\n self.sim_default_goal: str = _env_str(\n \"SIM_DEFAULT_GOAL\",\n \"Refine the currently bound plan to better achieve the user's objectives.\",\n )\n\n # Memory\n self.memory_auto_save_enabled: bool = _env_bool(\"MEMORY_AUTO_SAVE_ENABLED\", True)\n self.memory_retrieve_enabled: bool = _env_bool(\"MEMORY_RETRIEVE_ENABLED\", True)\n self.memory_query_limit: int = _env_int(\"MEMORY_QUERY_LIMIT\", 5)\n self.memory_min_similarity: float = _env_float(\"MEMORY_MIN_SIMILARITY\", 0.6)\n self.memory_text_similarity: float = _env_float(\"MEMORY_TEXT_SIMILARITY\", 1.0)\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> AppSettings:\n \"\"\"Return cached application settings.\"\"\"\n settings = AppSettings()\n\n # Ensure BASE_URL fallback stays in sync with BACKEND_HOST/BACKEND_PORT\n if not settings.base_url:\n settings.base_url = f\"http://{settings.backend_host}:{settings.backend_port}\"\n\n return settings\n"}, "6fb763618cba2812abc27694ccc23d6cd549b202": {"t": 1785767367.5564086, "n": 17909, "h": "a31a69d7d9a5e920", "c": "#!/usr/bin/env python3\n\"\"\"\n集中化应用配置(AppSettings)\n\n目标:\n- 统一管理日志、数据库、GLM 与外部 LLM 提供商密钥等配置\n- 合并嵌入(Embeddings)与聊天(Chat)相关参数,避免在 services 下分散读取环境变量\n- 默认从环境变量加载,支持 .env(如存在)\n- 为后续扩展结构化日志与指标埋点提供稳定入口\n\"\"\"\n\nimport os\nfrom functools import lru_cache\nfrom typing import Optional\n\n_USE_PYDANTIC = False\n_DOTENV_LOADED = False\ntry:\n # Pydantic v2: BaseSettings 已迁移到 pydantic_settings 包\n from pydantic import Field # type: ignore\n from pydantic_settings import BaseSettings # type: ignore\n\n _USE_PYDANTIC = True\nexcept Exception:\n try:\n # Pydantic v1 回退\n from pydantic import BaseSettings, Field # type: ignore\n\n _USE_PYDANTIC = True\n except Exception:\n # 本地回退:无 pydantic 时提供轻量实现\n class BaseSettings: # type: ignore\n pass\n\n def Field(default=None, **kwargs): # type: ignore\n return default\n\n _USE_PYDANTIC = False\n\n# Best-effort: load .env even in fallback or mixed environments\ntry:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv(override=True) # ensure .env values override exported vars\n _DOTENV_LOADED = True\nexcept Exception:\n _DOTENV_LOADED = False\n\n\nif _USE_PYDANTIC:\n\n class AppSettings(BaseSettings):\n # 日志配置\n log_level: str = Field(default=\"INFO\", env=\"LOG_LEVEL\")\n # json|plain\n log_format: str = Field(default=\"json\", env=\"LOG_FORMAT\")\n\n # 数据库配置(保留扩展位)\n database_url: str = Field(default=\"sqlite:///./tasks.db\", env=\"DATABASE_URL\")\n\n # API服务配置\n base_url: Optional[str] = Field(default=None, env=\"BASE_URL\")\n\n # GLM / LLM 配置\n glm_api_key: Optional[str] = Field(default=None, env=\"GLM_API_KEY\")\n glm_api_url: str = Field(\n default=\"https://open.bigmodel.cn/api/paas/v4/chat/completions\",\n env=\"GLM_API_URL\",\n )\n glm_model: str = Field(default=\"glm-4-flash\", env=\"GLM_MODEL\")\n glm_request_timeout: int = Field(default=60, env=\"GLM_REQUEST_TIMEOUT\")\n llm_request_timeout: int = Field(default=60, env=\"LLM_REQUEST_TIMEOUT\")\n llm_mock: bool = Field(default=False, env=\"LLM_MOCK\")\n llm_retries: int = Field(default=2, env=\"LLM_RETRIES\")\n llm_backoff_base: float = Field(default=0.5, env=\"LLM_BACKOFF_BASE\")\n\n # Perplexity API 配置\n perplexity_api_key: Optional[str] = Field(\n default=None, env=\"PERPLEXITY_API_KEY\"\n )\n perplexity_api_url: str = Field(\n default=\"https://api.perplexity.ai/chat/completions\",\n env=\"PERPLEXITY_API_URL\",\n )\n perplexity_model: str = Field(\n default=\"sonar-reasoning-pro\", env=\"PERPLEXITY_MODEL\"\n )\n\n # Doubao (Volcengine Ark)\n doubao_api_key: Optional[str] = Field(default=None, env=\"DOUBAO_API_KEY\")\n doubao_api_url: str = Field(\n default=\"https://ark.cn-beijing.volces.com/api/v3\",\n env=\"DOUBAO_API_URL\",\n )\n doubao_model: str = Field(default=\"doubao-seed-1-6-251015\", env=\"DOUBAO_MODEL\")\n\n # Moonshot / Kimi\n moonshot_api_key: Optional[str] = Field(default=None, env=\"MOONSHOT_API_KEY\")\n moonshot_api_url: str = Field(\n default=\"https://api.moonshot.cn/v1\",\n env=\"MOONSHOT_API_URL\",\n )\n moonshot_model: str = Field(\n default=\"kimi-k2-turbo-preview\", env=\"MOONSHOT_MODEL\"\n )\n\n # DeepSeek\n deepseek_api_key: Optional[str] = Field(default=None, env=\"DEEPSEEK_API_KEY\")\n deepseek_api_url: str = Field(\n default=\"https://api.deepseek.com\",\n env=\"DEEPSEEK_API_URL\",\n )\n deepseek_model: str = Field(default=\"deepseek-chat\", env=\"DEEPSEEK_MODEL\")\n\n # Grok / xAI\n grok_api_key: Optional[str] = Field(default=None, env=\"GROK_API_KEY\")\n grok_api_url: str = Field(\n default=\"https://api.x.ai/v1\",\n env=\"GROK_API_URL\",\n )\n grok_model: str = Field(default=\"grok-4\", env=\"GROK_MODEL\")\n\n # Gemini (OpenAI-compatible endpoint)\n gemini_api_key: Optional[str] = Field(default=None, env=\"GEMINI_API_KEY\")\n gemini_api_url: str = Field(\n default=\"https://generativelanguage.googleapis.com/v1beta/openai/\",\n env=\"GEMINI_API_URL\",\n )\n gemini_model: str = Field(default=\"gemini-2.5-flash\", env=\"GEMINI_MODEL\")\n\n # QWEN API 配置\n qwen_api_key: Optional[str] = Field(default=None, env=\"QWEN_API_KEY\")\n qwen_api_url: str = Field(\n default=\"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\",\n env=\"QWEN_API_URL\",\n )\n qwen_model: str = Field(default=\"qwen-turbo\", env=\"QWEN_MODEL\")\n\n # 通用LLM配置(用于选择提供商)\n llm_provider: str = Field(\n default=\"glm\", env=\"LLM_PROVIDER\"\n ) # glm, perplexity, qwen, openai, etc.\n\n # GLM Embeddings 专用配置(集中到此,供 app.services.config 使用)\n glm_embeddings_api_url: Optional[str] = Field(\n default=None, env=\"GLM_EMBEDDINGS_API_URL\"\n )\n glm_embedding_model: str = Field(\n default=\"embedding-3\", env=\"GLM_EMBEDDING_MODEL\"\n )\n glm_embedding_dimension: int = Field(default=1536, env=\"GLM_EMBEDDING_DIM\")\n glm_batch_size: int = Field(default=25, env=\"GLM_BATCH_SIZE\")\n semantic_default_k: int = Field(default=5, env=\"SEMANTIC_DEFAULT_K\")\n semantic_min_similarity: float = Field(\n default=0.3, env=\"SEMANTIC_MIN_SIMILARITY\"\n )\n glm_max_retries: int = Field(default=3, env=\"GLM_MAX_RETRIES\")\n glm_retry_delay: float = Field(default=1.0, env=\"GLM_RETRY_DELAY\")\n glm_debug: bool = Field(default=False, env=\"GLM_DEBUG\")\n\n # 嵌入缓存配置(避免在多个模块中直接读取环境变量)\n embedding_cache_size: int = Field(default=10000, env=\"EMBEDDING_CACHE_SIZE\")\n embedding_cache_persistent: bool = Field(\n default=True, env=\"EMBEDDING_CACHE_PERSISTENT\"\n )\n\n # 调试与上下文配置\n ctx_debug: bool = Field(default=False, env=[\"CTX_DEBUG\", \"CONTEXT_DEBUG\"])\n budget_debug: bool = Field(default=False, env=\"BUDGET_DEBUG\")\n decomp_debug: bool = Field(default=False, env=\"DECOMP_DEBUG\")\n global_index_path: str = Field(default=\"INDEX.md\", env=\"GLOBAL_INDEX_PATH\")\n\n # 外部提供商(可选)\n openai_api_key: Optional[str] = Field(\n default=None, env=[\"OPENAI_API_KEY\", \"GPT_API_KEY\"]\n )\n xai_api_key: Optional[str] = Field(\n default=None, env=[\"XAI_API_KEY\", \"GROK_API_KEY\"]\n )\n anthropic_api_key: Optional[str] = Field(\n default=None, env=[\"ANTHROPIC_API_KEY\", \"CLAUDE_API_KEY\"]\n )\n tavily_api_key: Optional[str] = Field(default=None, env=\"TAVILY_API_KEY\")\n\n # 服务器配置\n backend_host: str = Field(default=\"0.0.0.0\", env=\"BACKEND_HOST\")\n backend_port: int = Field(default=9000, env=\"BACKEND_PORT\")\n cors_origins: str = Field(\n default=\"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n env=\"CORS_ORIGINS\",\n )\n chat_include_action_summary: bool = Field(\n default=True, env=\"CHAT_INCLUDE_ACTION_SUMMARY\"\n )\n # Memory 相似度下限、文本匹配的默认相似度\n memory_min_similarity: float = Field(default=0.6, env=\"MEMORY_MIN_SIMILARITY\")\n memory_text_similarity: float = Field(default=1.0, env=\"MEMORY_TEXT_SIMILARITY\")\n job_log_retention_days: int = Field(default=30, env=\"JOB_LOG_RETENTION_DAYS\")\n job_log_max_rows: int = Field(default=10000, env=\"JOB_LOG_MAX_ROWS\")\n sim_user_model: str = Field(default=\"qwen3-max\", env=\"SIM_USER_MODEL\")\n sim_judge_model: str = Field(default=\"qwen3-max\", env=\"SIM_JUDGE_MODEL\")\n sim_default_turns: int = Field(default=5, env=\"SIM_DEFAULT_TURNS\")\n sim_max_turns: int = Field(default=10, env=\"SIM_MAX_TURNS\")\n memory_auto_save_enabled: bool = Field(default=True, env=\"MEMORY_AUTO_SAVE_ENABLED\")\n memory_retrieve_enabled: bool = Field(default=True, env=\"MEMORY_RETRIEVE_ENABLED\")\n memory_query_limit: int = Field(default=5, env=\"MEMORY_QUERY_LIMIT\")\n memory_min_similarity: float = Field(default=0.6, env=\"MEMORY_MIN_SIMILARITY\")\n sim_default_goal: str = Field(\n default=\"Refine the currently bound plan to better achieve the user's objectives.\",\n env=\"SIM_DEFAULT_GOAL\",\n )\n\n class Config:\n env_file = \".env\"\n case_sensitive = False\n\nelse:\n\n class AppSettings: # 轻量回退实现\n def __init__(self) -> None:\n # Ensure .env is loaded in pure os.getenv path as well\n if not _DOTENV_LOADED:\n try:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv(override=True)\n except Exception:\n pass\n self.log_level = os.getenv(\"LOG_LEVEL\", \"INFO\")\n self.log_format = os.getenv(\"LOG_FORMAT\", \"json\")\n self.database_url = os.getenv(\"DATABASE_URL\", \"sqlite:///./tasks.db\")\n self.base_url = os.getenv(\"BASE_URL\")\n self.glm_api_key = os.getenv(\"GLM_API_KEY\")\n self.glm_api_url = os.getenv(\n \"GLM_API_URL\", \"https://open.bigmodel.cn/api/paas/v4/chat/completions\"\n )\n self.glm_model = os.getenv(\"GLM_MODEL\", \"glm-4-flash\")\n try:\n self.glm_request_timeout = int(os.getenv(\"GLM_REQUEST_TIMEOUT\", \"60\"))\n except Exception:\n self.glm_request_timeout = 60\n try:\n self.llm_request_timeout = int(os.getenv(\"LLM_REQUEST_TIMEOUT\", \"60\"))\n except Exception:\n self.llm_request_timeout = 60\n self.llm_mock = os.getenv(\"LLM_MOCK\", \"\").strip().lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n\n # Perplexity API 配置\n self.perplexity_api_key = os.getenv(\"PERPLEXITY_API_KEY\")\n self.perplexity_api_url = os.getenv(\n \"PERPLEXITY_API_URL\", \"https://api.perplexity.ai/chat/completions\"\n )\n self.perplexity_model = os.getenv(\"PERPLEXITY_MODEL\", \"sonar-reasoning-pro\")\n self.doubao_api_key = os.getenv(\"DOUBAO_API_KEY\")\n self.doubao_api_url = os.getenv(\n \"DOUBAO_API_URL\", \"https://ark.cn-beijing.volces.com/api/v3\"\n )\n self.doubao_model = os.getenv(\"DOUBAO_MODEL\", \"doubao-seed-1-6-251015\")\n self.moonshot_api_key = os.getenv(\"MOONSHOT_API_KEY\")\n self.moonshot_api_url = os.getenv(\n \"MOONSHOT_API_URL\", \"https://api.moonshot.cn/v1\"\n )\n self.moonshot_model = os.getenv(\"MOONSHOT_MODEL\", \"kimi-k2-turbo-preview\")\n self.deepseek_api_key = os.getenv(\"DEEPSEEK_API_KEY\")\n self.deepseek_api_url = os.getenv(\n \"DEEPSEEK_API_URL\", \"https://api.deepseek.com\"\n )\n self.deepseek_model = os.getenv(\"DEEPSEEK_MODEL\", \"deepseek-chat\")\n self.grok_api_key = os.getenv(\"GROK_API_KEY\")\n self.grok_api_url = os.getenv(\"GROK_API_URL\", \"https://api.x.ai/v1\")\n self.grok_model = os.getenv(\"GROK_MODEL\", \"grok-4\")\n self.gemini_api_key = os.getenv(\"GEMINI_API_KEY\")\n self.gemini_api_url = os.getenv(\n \"GEMINI_API_URL\",\n \"https://generativelanguage.googleapis.com/v1beta/openai/\",\n )\n self.gemini_model = os.getenv(\"GEMINI_MODEL\", \"gemini-2.5-flash\")\n\n # 通用LLM配置\n self.llm_provider = os.getenv(\"LLM_PROVIDER\", \"glm\")\n try:\n self.llm_retries = int(os.getenv(\"LLM_RETRIES\", \"2\"))\n except Exception:\n self.llm_retries = 2\n try:\n self.llm_backoff_base = float(os.getenv(\"LLM_BACKOFF_BASE\", \"0.5\"))\n except Exception:\n self.llm_backoff_base = 0.5\n self.openai_api_key = os.getenv(\"OPENAI_API_KEY\") or os.getenv(\n \"GPT_API_KEY\"\n )\n self.xai_api_key = os.getenv(\"XAI_API_KEY\") or os.getenv(\"GROK_API_KEY\")\n self.anthropic_api_key = os.getenv(\"ANTHROPIC_API_KEY\") or os.getenv(\n \"CLAUDE_API_KEY\"\n )\n self.tavily_api_key = os.getenv(\"TAVILY_API_KEY\")\n self.sim_user_model = os.getenv(\"SIM_USER_MODEL\", \"qwen3-max\")\n self.sim_judge_model = os.getenv(\"SIM_JUDGE_MODEL\", \"qwen3-max\")\n try:\n self.sim_default_turns = int(os.getenv(\"SIM_DEFAULT_TURNS\", \"5\"))\n except Exception:\n self.sim_default_turns = 5\n try:\n self.sim_max_turns = int(os.getenv(\"SIM_MAX_TURNS\", \"10\"))\n except Exception:\n self.sim_max_turns = 10\n self.sim_default_goal = os.getenv(\n \"SIM_DEFAULT_GOAL\",\n \"Refine the currently bound plan to better achieve the user's objectives.\",\n )\n self.memory_auto_save_enabled = os.getenv(\"MEMORY_AUTO_SAVE_ENABLED\", \"true\").lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n self.memory_retrieve_enabled = os.getenv(\"MEMORY_RETRIEVE_ENABLED\", \"true\").lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n try:\n self.memory_query_limit = int(os.getenv(\"MEMORY_QUERY_LIMIT\", \"5\"))\n except Exception:\n self.memory_query_limit = 5\n try:\n self.memory_min_similarity = float(\n os.getenv(\"MEMORY_MIN_SIMILARITY\", \"0.6\")\n )\n except Exception:\n self.memory_min_similarity = 0.6\n\n # Embeddings 专用配置\n self.glm_embeddings_api_url = os.getenv(\"GLM_EMBEDDINGS_API_URL\")\n self.glm_embedding_model = os.getenv(\"GLM_EMBEDDING_MODEL\", \"embedding-3\")\n try:\n self.glm_embedding_dimension = int(\n os.getenv(\"GLM_EMBEDDING_DIM\", \"1536\")\n )\n except Exception:\n self.glm_embedding_dimension = 1536\n try:\n self.glm_batch_size = int(os.getenv(\"GLM_BATCH_SIZE\", \"25\"))\n except Exception:\n self.glm_batch_size = 25\n try:\n self.semantic_default_k = int(os.getenv(\"SEMANTIC_DEFAULT_K\", \"5\"))\n except Exception:\n self.semantic_default_k = 5\n try:\n self.semantic_min_similarity = float(\n os.getenv(\"SEMANTIC_MIN_SIMILARITY\", \"0.3\")\n )\n except Exception:\n self.semantic_min_similarity = 0.3\n try:\n self.glm_max_retries = int(os.getenv(\"GLM_MAX_RETRIES\", \"3\"))\n except Exception:\n self.glm_max_retries = 3\n try:\n self.glm_retry_delay = float(os.getenv(\"GLM_RETRY_DELAY\", \"1.0\"))\n except Exception:\n self.glm_retry_delay = 1.0\n self.glm_debug = os.getenv(\"GLM_DEBUG\", \"\").strip().lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n\n # 嵌入缓存配置\n try:\n self.embedding_cache_size = int(\n os.getenv(\"EMBEDDING_CACHE_SIZE\", \"10000\")\n )\n except Exception:\n self.embedding_cache_size = 10000\n self.embedding_cache_persistent = (\n os.getenv(\"EMBEDDING_CACHE_PERSISTENT\", \"1\").strip() == \"1\"\n )\n\n # 调试与上下文配置\n def _truthy(v: str) -> bool:\n return str(v).strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n self.ctx_debug = _truthy(os.getenv(\"CTX_DEBUG\", \"\")) or _truthy(\n os.getenv(\"CONTEXT_DEBUG\", \"\")\n )\n self.budget_debug = _truthy(os.getenv(\"BUDGET_DEBUG\", \"\"))\n self.decomp_debug = _truthy(os.getenv(\"DECOMP_DEBUG\", \"\"))\n self.global_index_path = os.getenv(\"GLOBAL_INDEX_PATH\", \"INDEX.md\")\n\n # 服务器配置\n self.backend_host = os.getenv(\"BACKEND_HOST\", \"0.0.0.0\")\n try:\n self.backend_port = int(os.getenv(\"BACKEND_PORT\", \"9000\"))\n except Exception:\n self.backend_port = 9000\n self.cors_origins = os.getenv(\n \"CORS_ORIGINS\",\n \"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n )\n self.chat_include_action_summary = os.getenv(\n \"CHAT_INCLUDE_ACTION_SUMMARY\", \"1\"\n ).strip().lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n try:\n self.job_log_retention_days = int(\n os.getenv(\"JOB_LOG_RETENTION_DAYS\", \"30\")\n )\n except Exception:\n self.job_log_retention_days = 30\n try:\n self.job_log_max_rows = int(os.getenv(\"JOB_LOG_MAX_ROWS\", \"10000\"))\n except Exception:\n self.job_log_max_rows = 10000\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> AppSettings:\n \"\"\"获取全局应用配置(带缓存)\"\"\"\n settings = AppSettings() # 自动从环境变量与 .env 读取\n\n # Ensure BASE_URL fallback stays in sync with BACKEND_HOST/BACKEND_PORT\n base_url = getattr(settings, \"base_url\", None)\n if not base_url:\n host = getattr(settings, \"backend_host\", \"0.0.0.0\")\n port = getattr(settings, \"backend_port\", 9000)\n settings.base_url = f\"http://{host}:{port}\"\n\n return settings\n"}, "8ba709eface0542608e5320aa934ba9ed155a74f": {"t": 1785767368.8109381, "n": 16536, "h": "a1db7b776e7b2e20", "c": "#!/usr/bin/env python3\n\"\"\"\n集中化应用配置(AppSettings)\n\n目标:\n- 统一管理日志、数据库、GLM 与外部 LLM 提供商密钥等配置\n- 合并嵌入(Embeddings)与聊天(Chat)相关参数,避免在 services 下分散读取环境变量\n- 默认从环境变量加载,支持 .env(如存在)\n- 为后续扩展结构化日志与指标埋点提供稳定入口\n\"\"\"\n\nimport os\nfrom functools import lru_cache\nfrom typing import Optional\n\n_USE_PYDANTIC = False\n_DOTENV_LOADED = False\ntry:\n # Pydantic v2: BaseSettings 已迁移到 pydantic_settings 包\n from pydantic import Field # type: ignore\n from pydantic_settings import BaseSettings # type: ignore\n\n _USE_PYDANTIC = True\nexcept Exception:\n try:\n # Pydantic v1 回退\n from pydantic import BaseSettings, Field # type: ignore\n\n _USE_PYDANTIC = True\n except Exception:\n # 本地回退:无 pydantic 时提供轻量实现\n class BaseSettings: # type: ignore\n pass\n\n def Field(default=None, **kwargs): # type: ignore\n return default\n\n _USE_PYDANTIC = False\n\n# Best-effort: load .env even in fallback or mixed environments\ntry:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv(override=True) # ensure .env values override exported vars\n _DOTENV_LOADED = True\nexcept Exception:\n _DOTENV_LOADED = False\n\n\nif _USE_PYDANTIC:\n\n class AppSettings(BaseSettings):\n # 日志配置\n log_level: str = Field(default=\"INFO\", env=\"LOG_LEVEL\")\n # json|plain\n log_format: str = Field(default=\"json\", env=\"LOG_FORMAT\")\n\n # 数据库配置(保留扩展位)\n database_url: str = Field(default=\"sqlite:///./tasks.db\", env=\"DATABASE_URL\")\n\n # API服务配置\n base_url: Optional[str] = Field(default=None, env=\"BASE_URL\")\n\n # GLM / LLM 配置\n glm_api_key: Optional[str] = Field(default=None, env=\"GLM_API_KEY\")\n glm_api_url: str = Field(\n default=\"https://open.bigmodel.cn/api/paas/v4/chat/completions\",\n env=\"GLM_API_URL\",\n )\n glm_model: str = Field(default=\"glm-4-flash\", env=\"GLM_MODEL\")\n glm_request_timeout: int = Field(default=60, env=\"GLM_REQUEST_TIMEOUT\")\n llm_request_timeout: int = Field(default=60, env=\"LLM_REQUEST_TIMEOUT\")\n llm_mock: bool = Field(default=False, env=\"LLM_MOCK\")\n llm_retries: int = Field(default=2, env=\"LLM_RETRIES\")\n llm_backoff_base: float = Field(default=0.5, env=\"LLM_BACKOFF_BASE\")\n\n # Perplexity API 配置\n perplexity_api_key: Optional[str] = Field(\n default=None, env=\"PERPLEXITY_API_KEY\"\n )\n perplexity_api_url: str = Field(\n default=\"https://api.perplexity.ai/chat/completions\",\n env=\"PERPLEXITY_API_URL\",\n )\n perplexity_model: str = Field(\n default=\"sonar-reasoning-pro\", env=\"PERPLEXITY_MODEL\"\n )\n\n # Doubao (Volcengine Ark)\n doubao_api_key: Optional[str] = Field(default=None, env=\"DOUBAO_API_KEY\")\n doubao_api_url: str = Field(\n default=\"https://ark.cn-beijing.volces.com/api/v3\",\n env=\"DOUBAO_API_URL\",\n )\n doubao_model: str = Field(default=\"doubao-seed-1-6-251015\", env=\"DOUBAO_MODEL\")\n\n # Moonshot / Kimi\n moonshot_api_key: Optional[str] = Field(default=None, env=\"MOONSHOT_API_KEY\")\n moonshot_api_url: str = Field(\n default=\"https://api.moonshot.cn/v1\",\n env=\"MOONSHOT_API_URL\",\n )\n moonshot_model: str = Field(\n default=\"kimi-k2-turbo-preview\", env=\"MOONSHOT_MODEL\"\n )\n\n # DeepSeek\n deepseek_api_key: Optional[str] = Field(default=None, env=\"DEEPSEEK_API_KEY\")\n deepseek_api_url: str = Field(\n default=\"https://api.deepseek.com\",\n env=\"DEEPSEEK_API_URL\",\n )\n deepseek_model: str = Field(default=\"deepseek-chat\", env=\"DEEPSEEK_MODEL\")\n\n # Grok / xAI\n grok_api_key: Optional[str] = Field(default=None, env=\"GROK_API_KEY\")\n grok_api_url: str = Field(\n default=\"https://api.x.ai/v1\",\n env=\"GROK_API_URL\",\n )\n grok_model: str = Field(default=\"grok-4\", env=\"GROK_MODEL\")\n\n # Gemini (OpenAI-compatible endpoint)\n gemini_api_key: Optional[str] = Field(default=None, env=\"GEMINI_API_KEY\")\n gemini_api_url: str = Field(\n default=\"https://generativelanguage.googleapis.com/v1beta/openai/\",\n env=\"GEMINI_API_URL\",\n )\n gemini_model: str = Field(default=\"gemini-2.5-flash\", env=\"GEMINI_MODEL\")\n\n # QWEN API 配置\n qwen_api_key: Optional[str] = Field(default=None, env=\"QWEN_API_KEY\")\n qwen_api_url: str = Field(\n default=\"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\",\n env=\"QWEN_API_URL\",\n )\n qwen_model: str = Field(default=\"qwen-turbo\", env=\"QWEN_MODEL\")\n\n # 通用LLM配置(用于选择提供商)\n llm_provider: str = Field(\n default=\"glm\", env=\"LLM_PROVIDER\"\n ) # glm, perplexity, qwen, openai, etc.\n\n # GLM Embeddings 专用配置(集中到此,供 app.services.config 使用)\n glm_embeddings_api_url: Optional[str] = Field(\n default=None, env=\"GLM_EMBEDDINGS_API_URL\"\n )\n glm_embedding_model: str = Field(\n default=\"embedding-3\", env=\"GLM_EMBEDDING_MODEL\"\n )\n glm_embedding_dimension: int = Field(default=1536, env=\"GLM_EMBEDDING_DIM\")\n glm_batch_size: int = Field(default=25, env=\"GLM_BATCH_SIZE\")\n semantic_default_k: int = Field(default=5, env=\"SEMANTIC_DEFAULT_K\")\n semantic_min_similarity: float = Field(\n default=0.3, env=\"SEMANTIC_MIN_SIMILARITY\"\n )\n glm_max_retries: int = Field(default=3, env=\"GLM_MAX_RETRIES\")\n glm_retry_delay: float = Field(default=1.0, env=\"GLM_RETRY_DELAY\")\n glm_debug: bool = Field(default=False, env=\"GLM_DEBUG\")\n\n # 嵌入缓存配置(避免在多个模块中直接读取环境变量)\n embedding_cache_size: int = Field(default=10000, env=\"EMBEDDING_CACHE_SIZE\")\n embedding_cache_persistent: bool = Field(\n default=True, env=\"EMBEDDING_CACHE_PERSISTENT\"\n )\n\n # 调试与上下文配置\n ctx_debug: bool = Field(default=False, env=[\"CTX_DEBUG\", \"CONTEXT_DEBUG\"])\n budget_debug: bool = Field(default=False, env=\"BUDGET_DEBUG\")\n decomp_debug: bool = Field(default=False, env=\"DECOMP_DEBUG\")\n global_index_path: str = Field(default=\"INDEX.md\", env=\"GLOBAL_INDEX_PATH\")\n\n # 外部提供商(可选)\n openai_api_key: Optional[str] = Field(\n default=None, env=[\"OPENAI_API_KEY\", \"GPT_API_KEY\"]\n )\n xai_api_key: Optional[str] = Field(\n default=None, env=[\"XAI_API_KEY\", \"GROK_API_KEY\"]\n )\n anthropic_api_key: Optional[str] = Field(\n default=None, env=[\"ANTHROPIC_API_KEY\", \"CLAUDE_API_KEY\"]\n )\n tavily_api_key: Optional[str] = Field(default=None, env=\"TAVILY_API_KEY\")\n\n # 服务器配置\n backend_host: str = Field(default=\"0.0.0.0\", env=\"BACKEND_HOST\")\n backend_port: int = Field(default=9000, env=\"BACKEND_PORT\")\n cors_origins: str = Field(\n default=\"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n env=\"CORS_ORIGINS\",\n )\n chat_include_action_summary: bool = Field(\n default=True, env=\"CHAT_INCLUDE_ACTION_SUMMARY\"\n )\n job_log_retention_days: int = Field(default=30, env=\"JOB_LOG_RETENTION_DAYS\")\n job_log_max_rows: int = Field(default=10000, env=\"JOB_LOG_MAX_ROWS\")\n sim_user_model: str = Field(default=\"qwen3-max\", env=\"SIM_USER_MODEL\")\n sim_judge_model: str = Field(default=\"qwen3-max\", env=\"SIM_JUDGE_MODEL\")\n sim_default_turns: int = Field(default=5, env=\"SIM_DEFAULT_TURNS\")\n sim_max_turns: int = Field(default=10, env=\"SIM_MAX_TURNS\")\n sim_default_goal: str = Field(\n default=\"Refine the currently bound plan to better achieve the user's objectives.\",\n env=\"SIM_DEFAULT_GOAL\",\n )\n\n class Config:\n env_file = \".env\"\n case_sensitive = False\n\nelse:\n\n class AppSettings: # 轻量回退实现\n def __init__(self) -> None:\n # Ensure .env is loaded in pure os.getenv path as well\n if not _DOTENV_LOADED:\n try:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv(override=True)\n except Exception:\n pass\n self.log_level = os.getenv(\"LOG_LEVEL\", \"INFO\")\n self.log_format = os.getenv(\"LOG_FORMAT\", \"json\")\n self.database_url = os.getenv(\"DATABASE_URL\", \"sqlite:///./tasks.db\")\n self.base_url = os.getenv(\"BASE_URL\")\n self.glm_api_key = os.getenv(\"GLM_API_KEY\")\n self.glm_api_url = os.getenv(\n \"GLM_API_URL\", \"https://open.bigmodel.cn/api/paas/v4/chat/completions\"\n )\n self.glm_model = os.getenv(\"GLM_MODEL\", \"glm-4-flash\")\n try:\n self.glm_request_timeout = int(os.getenv(\"GLM_REQUEST_TIMEOUT\", \"60\"))\n except Exception:\n self.glm_request_timeout = 60\n try:\n self.llm_request_timeout = int(os.getenv(\"LLM_REQUEST_TIMEOUT\", \"60\"))\n except Exception:\n self.llm_request_timeout = 60\n self.llm_mock = os.getenv(\"LLM_MOCK\", \"\").strip().lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n\n # Perplexity API 配置\n self.perplexity_api_key = os.getenv(\"PERPLEXITY_API_KEY\")\n self.perplexity_api_url = os.getenv(\n \"PERPLEXITY_API_URL\", \"https://api.perplexity.ai/chat/completions\"\n )\n self.perplexity_model = os.getenv(\"PERPLEXITY_MODEL\", \"sonar-reasoning-pro\")\n self.doubao_api_key = os.getenv(\"DOUBAO_API_KEY\")\n self.doubao_api_url = os.getenv(\n \"DOUBAO_API_URL\", \"https://ark.cn-beijing.volces.com/api/v3\"\n )\n self.doubao_model = os.getenv(\"DOUBAO_MODEL\", \"doubao-seed-1-6-251015\")\n self.moonshot_api_key = os.getenv(\"MOONSHOT_API_KEY\")\n self.moonshot_api_url = os.getenv(\n \"MOONSHOT_API_URL\", \"https://api.moonshot.cn/v1\"\n )\n self.moonshot_model = os.getenv(\"MOONSHOT_MODEL\", \"kimi-k2-turbo-preview\")\n self.deepseek_api_key = os.getenv(\"DEEPSEEK_API_KEY\")\n self.deepseek_api_url = os.getenv(\n \"DEEPSEEK_API_URL\", \"https://api.deepseek.com\"\n )\n self.deepseek_model = os.getenv(\"DEEPSEEK_MODEL\", \"deepseek-chat\")\n self.grok_api_key = os.getenv(\"GROK_API_KEY\")\n self.grok_api_url = os.getenv(\"GROK_API_URL\", \"https://api.x.ai/v1\")\n self.grok_model = os.getenv(\"GROK_MODEL\", \"grok-4\")\n self.gemini_api_key = os.getenv(\"GEMINI_API_KEY\")\n self.gemini_api_url = os.getenv(\n \"GEMINI_API_URL\",\n \"https://generativelanguage.googleapis.com/v1beta/openai/\",\n )\n self.gemini_model = os.getenv(\"GEMINI_MODEL\", \"gemini-2.5-flash\")\n\n # 通用LLM配置\n self.llm_provider = os.getenv(\"LLM_PROVIDER\", \"glm\")\n try:\n self.llm_retries = int(os.getenv(\"LLM_RETRIES\", \"2\"))\n except Exception:\n self.llm_retries = 2\n try:\n self.llm_backoff_base = float(os.getenv(\"LLM_BACKOFF_BASE\", \"0.5\"))\n except Exception:\n self.llm_backoff_base = 0.5\n self.openai_api_key = os.getenv(\"OPENAI_API_KEY\") or os.getenv(\n \"GPT_API_KEY\"\n )\n self.xai_api_key = os.getenv(\"XAI_API_KEY\") or os.getenv(\"GROK_API_KEY\")\n self.anthropic_api_key = os.getenv(\"ANTHROPIC_API_KEY\") or os.getenv(\n \"CLAUDE_API_KEY\"\n )\n self.tavily_api_key = os.getenv(\"TAVILY_API_KEY\")\n self.sim_user_model = os.getenv(\"SIM_USER_MODEL\", \"qwen3-max\")\n self.sim_judge_model = os.getenv(\"SIM_JUDGE_MODEL\", \"qwen3-max\")\n try:\n self.sim_default_turns = int(os.getenv(\"SIM_DEFAULT_TURNS\", \"5\"))\n except Exception:\n self.sim_default_turns = 5\n try:\n self.sim_max_turns = int(os.getenv(\"SIM_MAX_TURNS\", \"10\"))\n except Exception:\n self.sim_max_turns = 10\n self.sim_default_goal = os.getenv(\n \"SIM_DEFAULT_GOAL\",\n \"Refine the currently bound plan to better achieve the user's objectives.\",\n )\n\n # Embeddings 专用配置\n self.glm_embeddings_api_url = os.getenv(\"GLM_EMBEDDINGS_API_URL\")\n self.glm_embedding_model = os.getenv(\"GLM_EMBEDDING_MODEL\", \"embedding-3\")\n try:\n self.glm_embedding_dimension = int(\n os.getenv(\"GLM_EMBEDDING_DIM\", \"1536\")\n )\n except Exception:\n self.glm_embedding_dimension = 1536\n try:\n self.glm_batch_size = int(os.getenv(\"GLM_BATCH_SIZE\", \"25\"))\n except Exception:\n self.glm_batch_size = 25\n try:\n self.semantic_default_k = int(os.getenv(\"SEMANTIC_DEFAULT_K\", \"5\"))\n except Exception:\n self.semantic_default_k = 5\n try:\n self.semantic_min_similarity = float(\n os.getenv(\"SEMANTIC_MIN_SIMILARITY\", \"0.3\")\n )\n except Exception:\n self.semantic_min_similarity = 0.3\n try:\n self.glm_max_retries = int(os.getenv(\"GLM_MAX_RETRIES\", \"3\"))\n except Exception:\n self.glm_max_retries = 3\n try:\n self.glm_retry_delay = float(os.getenv(\"GLM_RETRY_DELAY\", \"1.0\"))\n except Exception:\n self.glm_retry_delay = 1.0\n self.glm_debug = os.getenv(\"GLM_DEBUG\", \"\").strip().lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n\n # 嵌入缓存配置\n try:\n self.embedding_cache_size = int(\n os.getenv(\"EMBEDDING_CACHE_SIZE\", \"10000\")\n )\n except Exception:\n self.embedding_cache_size = 10000\n self.embedding_cache_persistent = (\n os.getenv(\"EMBEDDING_CACHE_PERSISTENT\", \"1\").strip() == \"1\"\n )\n\n # 调试与上下文配置\n def _truthy(v: str) -> bool:\n return str(v).strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n self.ctx_debug = _truthy(os.getenv(\"CTX_DEBUG\", \"\")) or _truthy(\n os.getenv(\"CONTEXT_DEBUG\", \"\")\n )\n self.budget_debug = _truthy(os.getenv(\"BUDGET_DEBUG\", \"\"))\n self.decomp_debug = _truthy(os.getenv(\"DECOMP_DEBUG\", \"\"))\n self.global_index_path = os.getenv(\"GLOBAL_INDEX_PATH\", \"INDEX.md\")\n\n # 服务器配置\n self.backend_host = os.getenv(\"BACKEND_HOST\", \"0.0.0.0\")\n try:\n self.backend_port = int(os.getenv(\"BACKEND_PORT\", \"9000\"))\n except Exception:\n self.backend_port = 9000\n self.cors_origins = os.getenv(\n \"CORS_ORIGINS\",\n \"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n )\n self.chat_include_action_summary = os.getenv(\n \"CHAT_INCLUDE_ACTION_SUMMARY\", \"1\"\n ).strip().lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n try:\n self.job_log_retention_days = int(\n os.getenv(\"JOB_LOG_RETENTION_DAYS\", \"30\")\n )\n except Exception:\n self.job_log_retention_days = 30\n try:\n self.job_log_max_rows = int(os.getenv(\"JOB_LOG_MAX_ROWS\", \"10000\"))\n except Exception:\n self.job_log_max_rows = 10000\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> AppSettings:\n \"\"\"获取全局应用配置(带缓存)\"\"\"\n settings = AppSettings() # 自动从环境变量与 .env 读取\n\n # Ensure BASE_URL fallback stays in sync with BACKEND_HOST/BACKEND_PORT\n base_url = getattr(settings, \"base_url\", None)\n if not base_url:\n host = getattr(settings, \"backend_host\", \"0.0.0.0\")\n port = getattr(settings, \"backend_port\", 9000)\n settings.base_url = f\"http://{host}:{port}\"\n\n return settings\n"}, "9b5f67f493e17475c4c43c5fcb93664a4f9036f0": {"t": 1785767370.327938, "n": 12818, "h": "9803bb4827a4f280", "c": "#!/usr/bin/env python3\n\"\"\"\n集中化应用配置(AppSettings)\n\n目标:\n- 统一管理日志、数据库、GLM 与外部 LLM 提供商密钥等配置\n- 合并嵌入(Embeddings)与聊天(Chat)相关参数,避免在 services 下分散读取环境变量\n- 默认从环境变量加载,支持 .env(如存在)\n- 为后续扩展结构化日志与指标埋点提供稳定入口\n\"\"\"\nimport os\nfrom functools import lru_cache\nfrom typing import Optional\n\n_USE_PYDANTIC = False\n_DOTENV_LOADED = False\ntry:\n # Pydantic v2: BaseSettings 已迁移到 pydantic_settings 包\n from pydantic import Field # type: ignore\n from pydantic_settings import BaseSettings # type: ignore\n\n _USE_PYDANTIC = True\nexcept Exception:\n try:\n # Pydantic v1 回退\n from pydantic import BaseSettings, Field # type: ignore\n\n _USE_PYDANTIC = True\n except Exception:\n # 本地回退:无 pydantic 时提供轻量实现\n class BaseSettings: # type: ignore\n pass\n\n def Field(default=None, **kwargs): # type: ignore\n return default\n\n _USE_PYDANTIC = False\n\n# Best-effort: load .env even in fallback or mixed environments\ntry:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv() # no-op if file missing; respects current working dir\n _DOTENV_LOADED = True\nexcept Exception:\n _DOTENV_LOADED = False\n\n\nif _USE_PYDANTIC:\n\n class AppSettings(BaseSettings):\n # 日志配置\n log_level: str = Field(default=\"INFO\", env=\"LOG_LEVEL\")\n # json|plain\n log_format: str = Field(default=\"json\", env=\"LOG_FORMAT\")\n\n # 数据库配置(保留扩展位)\n database_url: str = Field(default=\"sqlite:///./tasks.db\", env=\"DATABASE_URL\")\n \n # API服务配置\n base_url: Optional[str] = Field(default=None, env=\"BASE_URL\")\n\n # GLM / LLM 配置\n glm_api_key: Optional[str] = Field(default=None, env=\"GLM_API_KEY\")\n glm_api_url: str = Field(\n default=\"https://open.bigmodel.cn/api/paas/v4/chat/completions\",\n env=\"GLM_API_URL\",\n )\n glm_model: str = Field(default=\"glm-4-flash\", env=\"GLM_MODEL\")\n glm_request_timeout: int = Field(default=60, env=\"GLM_REQUEST_TIMEOUT\")\n llm_request_timeout: int = Field(default=60, env=\"LLM_REQUEST_TIMEOUT\")\n llm_mock: bool = Field(default=False, env=\"LLM_MOCK\")\n llm_retries: int = Field(default=2, env=\"LLM_RETRIES\")\n llm_backoff_base: float = Field(default=0.5, env=\"LLM_BACKOFF_BASE\")\n\n # Perplexity API 配置\n perplexity_api_key: Optional[str] = Field(default=None, env=\"PERPLEXITY_API_KEY\")\n perplexity_api_url: str = Field(\n default=\"https://api.perplexity.ai/chat/completions\",\n env=\"PERPLEXITY_API_URL\",\n )\n perplexity_model: str = Field(default=\"sonar-reasoning-pro\", env=\"PERPLEXITY_MODEL\")\n\n # QWEN API 配置\n qwen_api_key: Optional[str] = Field(default=None, env=\"QWEN_API_KEY\")\n qwen_api_url: str = Field(\n default=\"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\",\n env=\"QWEN_API_URL\",\n )\n qwen_model: str = Field(default=\"qwen-turbo\", env=\"QWEN_MODEL\")\n\n # 通用LLM配置(用于选择提供商)\n llm_provider: str = Field(default=\"glm\", env=\"LLM_PROVIDER\") # glm, perplexity, qwen, openai, etc.\n\n # GLM Embeddings 专用配置(集中到此,供 app.services.config 使用)\n glm_embeddings_api_url: Optional[str] = Field(default=None, env=\"GLM_EMBEDDINGS_API_URL\")\n glm_embedding_model: str = Field(default=\"embedding-3\", env=\"GLM_EMBEDDING_MODEL\")\n glm_embedding_dimension: int = Field(default=1536, env=\"GLM_EMBEDDING_DIM\")\n glm_batch_size: int = Field(default=25, env=\"GLM_BATCH_SIZE\")\n semantic_default_k: int = Field(default=5, env=\"SEMANTIC_DEFAULT_K\")\n semantic_min_similarity: float = Field(default=0.3, env=\"SEMANTIC_MIN_SIMILARITY\")\n glm_max_retries: int = Field(default=3, env=\"GLM_MAX_RETRIES\")\n glm_retry_delay: float = Field(default=1.0, env=\"GLM_RETRY_DELAY\")\n glm_debug: bool = Field(default=False, env=\"GLM_DEBUG\")\n\n # 嵌入缓存配置(避免在多个模块中直接读取环境变量)\n embedding_cache_size: int = Field(default=10000, env=\"EMBEDDING_CACHE_SIZE\")\n embedding_cache_persistent: bool = Field(default=True, env=\"EMBEDDING_CACHE_PERSISTENT\")\n\n # 调试与上下文配置\n ctx_debug: bool = Field(default=False, env=[\"CTX_DEBUG\", \"CONTEXT_DEBUG\"])\n budget_debug: bool = Field(default=False, env=\"BUDGET_DEBUG\")\n decomp_debug: bool = Field(default=False, env=\"DECOMP_DEBUG\")\n global_index_path: str = Field(default=\"INDEX.md\", env=\"GLOBAL_INDEX_PATH\")\n\n # 外部提供商(可选)\n openai_api_key: Optional[str] = Field(default=None, env=[\"OPENAI_API_KEY\", \"GPT_API_KEY\"])\n xai_api_key: Optional[str] = Field(default=None, env=[\"XAI_API_KEY\", \"GROK_API_KEY\"])\n anthropic_api_key: Optional[str] = Field(default=None, env=[\"ANTHROPIC_API_KEY\", \"CLAUDE_API_KEY\"])\n tavily_api_key: Optional[str] = Field(default=None, env=\"TAVILY_API_KEY\")\n\n # 服务器配置\n backend_host: str = Field(default=\"0.0.0.0\", env=\"BACKEND_HOST\")\n backend_port: int = Field(default=9000, env=\"BACKEND_PORT\")\n cors_origins: str = Field(\n default=\"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n env=\"CORS_ORIGINS\"\n )\n chat_include_action_summary: bool = Field(\n default=True, env=\"CHAT_INCLUDE_ACTION_SUMMARY\"\n )\n job_log_retention_days: int = Field(\n default=30, env=\"JOB_LOG_RETENTION_DAYS\"\n )\n job_log_max_rows: int = Field(\n default=10000, env=\"JOB_LOG_MAX_ROWS\"\n )\n sim_user_model: str = Field(default=\"qwen3-max\", env=\"SIM_USER_MODEL\")\n sim_judge_model: str = Field(default=\"qwen3-max\", env=\"SIM_JUDGE_MODEL\")\n sim_default_turns: int = Field(default=5, env=\"SIM_DEFAULT_TURNS\")\n sim_max_turns: int = Field(default=10, env=\"SIM_MAX_TURNS\")\n sim_default_goal: str = Field(\n default=\"Refine the currently bound plan to better achieve the user's objectives.\",\n env=\"SIM_DEFAULT_GOAL\",\n )\n\n class Config:\n env_file = \".env\"\n case_sensitive = False\n\nelse:\n\n class AppSettings: # 轻量回退实现\n def __init__(self) -> None:\n # Ensure .env is loaded in pure os.getenv path as well\n if not _DOTENV_LOADED:\n try:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv()\n except Exception:\n pass\n self.log_level = os.getenv(\"LOG_LEVEL\", \"INFO\")\n self.log_format = os.getenv(\"LOG_FORMAT\", \"json\")\n self.database_url = os.getenv(\"DATABASE_URL\", \"sqlite:///./tasks.db\")\n self.base_url = os.getenv(\"BASE_URL\")\n self.glm_api_key = os.getenv(\"GLM_API_KEY\")\n self.glm_api_url = os.getenv(\"GLM_API_URL\", \"https://open.bigmodel.cn/api/paas/v4/chat/completions\")\n self.glm_model = os.getenv(\"GLM_MODEL\", \"glm-4-flash\")\n try:\n self.glm_request_timeout = int(os.getenv(\"GLM_REQUEST_TIMEOUT\", \"60\"))\n except Exception:\n self.glm_request_timeout = 60\n try:\n self.llm_request_timeout = int(os.getenv(\"LLM_REQUEST_TIMEOUT\", \"60\"))\n except Exception:\n self.llm_request_timeout = 60\n self.llm_mock = os.getenv(\"LLM_MOCK\", \"\").strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n \n # Perplexity API 配置\n self.perplexity_api_key = os.getenv(\"PERPLEXITY_API_KEY\")\n self.perplexity_api_url = os.getenv(\"PERPLEXITY_API_URL\", \"https://api.perplexity.ai/chat/completions\")\n self.perplexity_model = os.getenv(\"PERPLEXITY_MODEL\", \"sonar-reasoning-pro\")\n \n # 通用LLM配置\n self.llm_provider = os.getenv(\"LLM_PROVIDER\", \"glm\")\n try:\n self.llm_retries = int(os.getenv(\"LLM_RETRIES\", \"2\"))\n except Exception:\n self.llm_retries = 2\n try:\n self.llm_backoff_base = float(os.getenv(\"LLM_BACKOFF_BASE\", \"0.5\"))\n except Exception:\n self.llm_backoff_base = 0.5\n self.openai_api_key = os.getenv(\"OPENAI_API_KEY\") or os.getenv(\"GPT_API_KEY\")\n self.xai_api_key = os.getenv(\"XAI_API_KEY\") or os.getenv(\"GROK_API_KEY\")\n self.anthropic_api_key = os.getenv(\"ANTHROPIC_API_KEY\") or os.getenv(\"CLAUDE_API_KEY\")\n self.tavily_api_key = os.getenv(\"TAVILY_API_KEY\")\n self.sim_user_model = os.getenv(\"SIM_USER_MODEL\", \"qwen3-max\")\n self.sim_judge_model = os.getenv(\"SIM_JUDGE_MODEL\", \"qwen3-max\")\n try:\n self.sim_default_turns = int(os.getenv(\"SIM_DEFAULT_TURNS\", \"5\"))\n except Exception:\n self.sim_default_turns = 5\n try:\n self.sim_max_turns = int(os.getenv(\"SIM_MAX_TURNS\", \"10\"))\n except Exception:\n self.sim_max_turns = 10\n self.sim_default_goal = os.getenv(\n \"SIM_DEFAULT_GOAL\",\n \"Refine the currently bound plan to better achieve the user's objectives.\",\n )\n\n # Embeddings 专用配置\n self.glm_embeddings_api_url = os.getenv(\"GLM_EMBEDDINGS_API_URL\")\n self.glm_embedding_model = os.getenv(\"GLM_EMBEDDING_MODEL\", \"embedding-3\")\n try:\n self.glm_embedding_dimension = int(os.getenv(\"GLM_EMBEDDING_DIM\", \"1536\"))\n except Exception:\n self.glm_embedding_dimension = 1536\n try:\n self.glm_batch_size = int(os.getenv(\"GLM_BATCH_SIZE\", \"25\"))\n except Exception:\n self.glm_batch_size = 25\n try:\n self.semantic_default_k = int(os.getenv(\"SEMANTIC_DEFAULT_K\", \"5\"))\n except Exception:\n self.semantic_default_k = 5\n try:\n self.semantic_min_similarity = float(os.getenv(\"SEMANTIC_MIN_SIMILARITY\", \"0.3\"))\n except Exception:\n self.semantic_min_similarity = 0.3\n try:\n self.glm_max_retries = int(os.getenv(\"GLM_MAX_RETRIES\", \"3\"))\n except Exception:\n self.glm_max_retries = 3\n try:\n self.glm_retry_delay = float(os.getenv(\"GLM_RETRY_DELAY\", \"1.0\"))\n except Exception:\n self.glm_retry_delay = 1.0\n self.glm_debug = os.getenv(\"GLM_DEBUG\", \"\").strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n # 嵌入缓存配置\n try:\n self.embedding_cache_size = int(os.getenv(\"EMBEDDING_CACHE_SIZE\", \"10000\"))\n except Exception:\n self.embedding_cache_size = 10000\n self.embedding_cache_persistent = (os.getenv(\"EMBEDDING_CACHE_PERSISTENT\", \"1\").strip() == \"1\")\n\n # 调试与上下文配置\n def _truthy(v: str) -> bool:\n return str(v).strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n self.ctx_debug = _truthy(os.getenv(\"CTX_DEBUG\", \"\")) or _truthy(os.getenv(\"CONTEXT_DEBUG\", \"\"))\n self.budget_debug = _truthy(os.getenv(\"BUDGET_DEBUG\", \"\"))\n self.decomp_debug = _truthy(os.getenv(\"DECOMP_DEBUG\", \"\"))\n self.global_index_path = os.getenv(\"GLOBAL_INDEX_PATH\", \"INDEX.md\")\n\n # 服务器配置\n self.backend_host = os.getenv(\"BACKEND_HOST\", \"0.0.0.0\")\n try:\n self.backend_port = int(os.getenv(\"BACKEND_PORT\", \"9000\"))\n except Exception:\n self.backend_port = 9000\n self.cors_origins = os.getenv(\n \"CORS_ORIGINS\",\n \"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\"\n )\n self.chat_include_action_summary = os.getenv(\"CHAT_INCLUDE_ACTION_SUMMARY\", \"1\").strip().lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n try:\n self.job_log_retention_days = int(os.getenv(\"JOB_LOG_RETENTION_DAYS\", \"30\"))\n except Exception:\n self.job_log_retention_days = 30\n try:\n self.job_log_max_rows = int(os.getenv(\"JOB_LOG_MAX_ROWS\", \"10000\"))\n except Exception:\n self.job_log_max_rows = 10000\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> AppSettings:\n \"\"\"获取全局应用配置(带缓存)\"\"\"\n settings = AppSettings() # 自动从环境变量与 .env 读取\n\n # Ensure BASE_URL fallback stays in sync with BACKEND_HOST/BACKEND_PORT\n base_url = getattr(settings, \"base_url\", None)\n if not base_url:\n host = getattr(settings, \"backend_host\", \"0.0.0.0\")\n port = getattr(settings, \"backend_port\", 9000)\n settings.base_url = f\"http://{host}:{port}\"\n\n return settings\n"}, "9c5b3281e37f7e9ac0d23459fec5b0a4b3833f71": {"t": 1785767371.7474387, "n": 11659, "h": "224feaa3da3fe2c0", "c": "#!/usr/bin/env python3\n\"\"\"\n集中化应用配置(AppSettings)\n\n目标:\n- 统一管理日志、数据库、GLM 与外部 LLM 提供商密钥等配置\n- 合并嵌入(Embeddings)与聊天(Chat)相关参数,避免在 services 下分散读取环境变量\n- 默认从环境变量加载,支持 .env(如存在)\n- 为后续扩展结构化日志与指标埋点提供稳定入口\n\"\"\"\nimport os\nfrom functools import lru_cache\nfrom typing import Optional\n\n_USE_PYDANTIC = False\n_DOTENV_LOADED = False\ntry:\n # Pydantic v2: BaseSettings 已迁移到 pydantic_settings 包\n from pydantic import Field # type: ignore\n from pydantic_settings import BaseSettings # type: ignore\n\n _USE_PYDANTIC = True\nexcept Exception:\n try:\n # Pydantic v1 回退\n from pydantic import BaseSettings, Field # type: ignore\n\n _USE_PYDANTIC = True\n except Exception:\n # 本地回退:无 pydantic 时提供轻量实现\n class BaseSettings: # type: ignore\n pass\n\n def Field(default=None, **kwargs): # type: ignore\n return default\n\n _USE_PYDANTIC = False\n\n# Best-effort: load .env even in fallback or mixed environments\ntry:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv() # no-op if file missing; respects current working dir\n _DOTENV_LOADED = True\nexcept Exception:\n _DOTENV_LOADED = False\n\n\nif _USE_PYDANTIC:\n\n class AppSettings(BaseSettings):\n # 日志配置\n log_level: str = Field(default=\"INFO\", env=\"LOG_LEVEL\")\n # json|plain\n log_format: str = Field(default=\"json\", env=\"LOG_FORMAT\")\n\n # 数据库配置(保留扩展位)\n database_url: str = Field(default=\"sqlite:///./tasks.db\", env=\"DATABASE_URL\")\n \n # API服务配置\n base_url: Optional[str] = Field(default=None, env=\"BASE_URL\")\n\n # GLM / LLM 配置\n glm_api_key: Optional[str] = Field(default=None, env=\"GLM_API_KEY\")\n glm_api_url: str = Field(\n default=\"https://open.bigmodel.cn/api/paas/v4/chat/completions\",\n env=\"GLM_API_URL\",\n )\n glm_model: str = Field(default=\"glm-4-flash\", env=\"GLM_MODEL\")\n glm_request_timeout: int = Field(default=60, env=\"GLM_REQUEST_TIMEOUT\")\n llm_request_timeout: int = Field(default=60, env=\"LLM_REQUEST_TIMEOUT\")\n llm_mock: bool = Field(default=False, env=\"LLM_MOCK\")\n llm_retries: int = Field(default=2, env=\"LLM_RETRIES\")\n llm_backoff_base: float = Field(default=0.5, env=\"LLM_BACKOFF_BASE\")\n\n # Perplexity API 配置\n perplexity_api_key: Optional[str] = Field(default=None, env=\"PERPLEXITY_API_KEY\")\n perplexity_api_url: str = Field(\n default=\"https://api.perplexity.ai/chat/completions\",\n env=\"PERPLEXITY_API_URL\",\n )\n perplexity_model: str = Field(default=\"sonar-reasoning-pro\", env=\"PERPLEXITY_MODEL\")\n\n # QWEN API 配置\n qwen_api_key: Optional[str] = Field(default=None, env=\"QWEN_API_KEY\")\n qwen_api_url: str = Field(\n default=\"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions\",\n env=\"QWEN_API_URL\",\n )\n qwen_model: str = Field(default=\"qwen-turbo\", env=\"QWEN_MODEL\")\n\n # 通用LLM配置(用于选择提供商)\n llm_provider: str = Field(default=\"glm\", env=\"LLM_PROVIDER\") # glm, perplexity, qwen, openai, etc.\n\n # GLM Embeddings 专用配置(集中到此,供 app.services.config 使用)\n glm_embeddings_api_url: Optional[str] = Field(default=None, env=\"GLM_EMBEDDINGS_API_URL\")\n glm_embedding_model: str = Field(default=\"embedding-3\", env=\"GLM_EMBEDDING_MODEL\")\n glm_embedding_dimension: int = Field(default=1536, env=\"GLM_EMBEDDING_DIM\")\n glm_batch_size: int = Field(default=25, env=\"GLM_BATCH_SIZE\")\n semantic_default_k: int = Field(default=5, env=\"SEMANTIC_DEFAULT_K\")\n semantic_min_similarity: float = Field(default=0.3, env=\"SEMANTIC_MIN_SIMILARITY\")\n glm_max_retries: int = Field(default=3, env=\"GLM_MAX_RETRIES\")\n glm_retry_delay: float = Field(default=1.0, env=\"GLM_RETRY_DELAY\")\n glm_debug: bool = Field(default=False, env=\"GLM_DEBUG\")\n\n # 嵌入缓存配置(避免在多个模块中直接读取环境变量)\n embedding_cache_size: int = Field(default=10000, env=\"EMBEDDING_CACHE_SIZE\")\n embedding_cache_persistent: bool = Field(default=True, env=\"EMBEDDING_CACHE_PERSISTENT\")\n\n # 调试与上下文配置\n ctx_debug: bool = Field(default=False, env=[\"CTX_DEBUG\", \"CONTEXT_DEBUG\"])\n budget_debug: bool = Field(default=False, env=\"BUDGET_DEBUG\")\n decomp_debug: bool = Field(default=False, env=\"DECOMP_DEBUG\")\n global_index_path: str = Field(default=\"INDEX.md\", env=\"GLOBAL_INDEX_PATH\")\n\n # 外部提供商(可选)\n openai_api_key: Optional[str] = Field(default=None, env=[\"OPENAI_API_KEY\", \"GPT_API_KEY\"])\n xai_api_key: Optional[str] = Field(default=None, env=[\"XAI_API_KEY\", \"GROK_API_KEY\"])\n anthropic_api_key: Optional[str] = Field(default=None, env=[\"ANTHROPIC_API_KEY\", \"CLAUDE_API_KEY\"])\n tavily_api_key: Optional[str] = Field(default=None, env=\"TAVILY_API_KEY\")\n\n # 服务器配置\n backend_host: str = Field(default=\"0.0.0.0\", env=\"BACKEND_HOST\")\n backend_port: int = Field(default=9000, env=\"BACKEND_PORT\")\n cors_origins: str = Field(\n default=\"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\",\n env=\"CORS_ORIGINS\"\n )\n chat_include_action_summary: bool = Field(\n default=True, env=\"CHAT_INCLUDE_ACTION_SUMMARY\"\n )\n job_log_retention_days: int = Field(\n default=30, env=\"JOB_LOG_RETENTION_DAYS\"\n )\n job_log_max_rows: int = Field(\n default=10000, env=\"JOB_LOG_MAX_ROWS\"\n )\n\n class Config:\n env_file = \".env\"\n case_sensitive = False\n\nelse:\n\n class AppSettings: # 轻量回退实现\n def __init__(self) -> None:\n # Ensure .env is loaded in pure os.getenv path as well\n if not _DOTENV_LOADED:\n try:\n from dotenv import load_dotenv # type: ignore\n\n load_dotenv()\n except Exception:\n pass\n self.log_level = os.getenv(\"LOG_LEVEL\", \"INFO\")\n self.log_format = os.getenv(\"LOG_FORMAT\", \"json\")\n self.database_url = os.getenv(\"DATABASE_URL\", \"sqlite:///./tasks.db\")\n self.base_url = os.getenv(\"BASE_URL\")\n self.glm_api_key = os.getenv(\"GLM_API_KEY\")\n self.glm_api_url = os.getenv(\"GLM_API_URL\", \"https://open.bigmodel.cn/api/paas/v4/chat/completions\")\n self.glm_model = os.getenv(\"GLM_MODEL\", \"glm-4-flash\")\n try:\n self.glm_request_timeout = int(os.getenv(\"GLM_REQUEST_TIMEOUT\", \"60\"))\n except Exception:\n self.glm_request_timeout = 60\n try:\n self.llm_request_timeout = int(os.getenv(\"LLM_REQUEST_TIMEOUT\", \"60\"))\n except Exception:\n self.llm_request_timeout = 60\n self.llm_mock = os.getenv(\"LLM_MOCK\", \"\").strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n \n # Perplexity API 配置\n self.perplexity_api_key = os.getenv(\"PERPLEXITY_API_KEY\")\n self.perplexity_api_url = os.getenv(\"PERPLEXITY_API_URL\", \"https://api.perplexity.ai/chat/completions\")\n self.perplexity_model = os.getenv(\"PERPLEXITY_MODEL\", \"sonar-reasoning-pro\")\n \n # 通用LLM配置\n self.llm_provider = os.getenv(\"LLM_PROVIDER\", \"glm\")\n try:\n self.llm_retries = int(os.getenv(\"LLM_RETRIES\", \"2\"))\n except Exception:\n self.llm_retries = 2\n try:\n self.llm_backoff_base = float(os.getenv(\"LLM_BACKOFF_BASE\", \"0.5\"))\n except Exception:\n self.llm_backoff_base = 0.5\n self.openai_api_key = os.getenv(\"OPENAI_API_KEY\") or os.getenv(\"GPT_API_KEY\")\n self.xai_api_key = os.getenv(\"XAI_API_KEY\") or os.getenv(\"GROK_API_KEY\")\n self.anthropic_api_key = os.getenv(\"ANTHROPIC_API_KEY\") or os.getenv(\"CLAUDE_API_KEY\")\n self.tavily_api_key = os.getenv(\"TAVILY_API_KEY\")\n\n # Embeddings 专用配置\n self.glm_embeddings_api_url = os.getenv(\"GLM_EMBEDDINGS_API_URL\")\n self.glm_embedding_model = os.getenv(\"GLM_EMBEDDING_MODEL\", \"embedding-3\")\n try:\n self.glm_embedding_dimension = int(os.getenv(\"GLM_EMBEDDING_DIM\", \"1536\"))\n except Exception:\n self.glm_embedding_dimension = 1536\n try:\n self.glm_batch_size = int(os.getenv(\"GLM_BATCH_SIZE\", \"25\"))\n except Exception:\n self.glm_batch_size = 25\n try:\n self.semantic_default_k = int(os.getenv(\"SEMANTIC_DEFAULT_K\", \"5\"))\n except Exception:\n self.semantic_default_k = 5\n try:\n self.semantic_min_similarity = float(os.getenv(\"SEMANTIC_MIN_SIMILARITY\", \"0.3\"))\n except Exception:\n self.semantic_min_similarity = 0.3\n try:\n self.glm_max_retries = int(os.getenv(\"GLM_MAX_RETRIES\", \"3\"))\n except Exception:\n self.glm_max_retries = 3\n try:\n self.glm_retry_delay = float(os.getenv(\"GLM_RETRY_DELAY\", \"1.0\"))\n except Exception:\n self.glm_retry_delay = 1.0\n self.glm_debug = os.getenv(\"GLM_DEBUG\", \"\").strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n # 嵌入缓存配置\n try:\n self.embedding_cache_size = int(os.getenv(\"EMBEDDING_CACHE_SIZE\", \"10000\"))\n except Exception:\n self.embedding_cache_size = 10000\n self.embedding_cache_persistent = (os.getenv(\"EMBEDDING_CACHE_PERSISTENT\", \"1\").strip() == \"1\")\n\n # 调试与上下文配置\n def _truthy(v: str) -> bool:\n return str(v).strip().lower() in {\"1\", \"true\", \"yes\", \"on\"}\n\n self.ctx_debug = _truthy(os.getenv(\"CTX_DEBUG\", \"\")) or _truthy(os.getenv(\"CONTEXT_DEBUG\", \"\"))\n self.budget_debug = _truthy(os.getenv(\"BUDGET_DEBUG\", \"\"))\n self.decomp_debug = _truthy(os.getenv(\"DECOMP_DEBUG\", \"\"))\n self.global_index_path = os.getenv(\"GLOBAL_INDEX_PATH\", \"INDEX.md\")\n\n # 服务器配置\n self.backend_host = os.getenv(\"BACKEND_HOST\", \"0.0.0.0\")\n try:\n self.backend_port = int(os.getenv(\"BACKEND_PORT\", \"9000\"))\n except Exception:\n self.backend_port = 9000\n self.cors_origins = os.getenv(\n \"CORS_ORIGINS\",\n \"http://localhost:3000,http://127.0.0.1:3000,http://localhost:3001,http://127.0.0.1:3001\"\n )\n self.chat_include_action_summary = os.getenv(\"CHAT_INCLUDE_ACTION_SUMMARY\", \"1\").strip().lower() in {\n \"1\",\n \"true\",\n \"yes\",\n \"on\",\n }\n try:\n self.job_log_retention_days = int(os.getenv(\"JOB_LOG_RETENTION_DAYS\", \"30\"))\n except Exception:\n self.job_log_retention_days = 30\n try:\n self.job_log_max_rows = int(os.getenv(\"JOB_LOG_MAX_ROWS\", \"10000\"))\n except Exception:\n self.job_log_max_rows = 10000\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> AppSettings:\n \"\"\"获取全局应用配置(带缓存)\"\"\"\n settings = AppSettings() # 自动从环境变量与 .env 读取\n\n # Ensure BASE_URL fallback stays in sync with BACKEND_HOST/BACKEND_PORT\n base_url = getattr(settings, \"base_url\", None)\n if not base_url:\n host = getattr(settings, \"backend_host\", \"0.0.0.0\")\n port = getattr(settings, \"backend_port\", 9000)\n settings.base_url = f\"http://{host}:{port}\"\n\n return settings\n"}}}}