diff --git a/dayu/contracts/model_config.py b/dayu/contracts/model_config.py index ff6977d3..7b2a4198 100644 --- a/dayu/contracts/model_config.py +++ b/dayu/contracts/model_config.py @@ -125,6 +125,7 @@ class OpenAICompatibleModelConfig(BaseModelConfig, total=False): supports_stream_usage: bool extra_payloads: dict[str, ModelConfigJsonValue] max_retries: int + verify_ssl: bool class CliModelConfig(BaseModelConfig, total=False): @@ -155,6 +156,7 @@ class OpenAICompatibleRunnerParams(TypedDict, total=False): supports_stream: bool supports_tool_calling: bool supports_stream_usage: bool + verify_ssl: bool class CliRunnerParams(TypedDict, total=False): diff --git a/dayu/engine/async_openai_runner.py b/dayu/engine/async_openai_runner.py index 543f065a..dd69db82 100644 --- a/dayu/engine/async_openai_runner.py +++ b/dayu/engine/async_openai_runner.py @@ -517,6 +517,7 @@ def __init__( supports_stream_usage: bool = False, running_config: Optional[AsyncOpenAIRunnerRunningConfig] = None, cancellation_token: CancellationToken | None = None, + verify_ssl: bool = True, ): """ 初始化 OpenAI 兼容 Runner。 @@ -583,6 +584,7 @@ def __init__( self.supports_tool_calling = supports_tool_calling self.supports_stream_usage = supports_stream_usage self.cancellation_token = cancellation_token + self._verify_ssl = verify_ssl self._session: Optional[Any] = None self._tool_executor: Optional[ToolExecutor] = None @@ -626,7 +628,11 @@ def _ensure_session(self) -> "ClientSession": if session is not None and not bool(getattr(session, "closed", False)): return session aiohttp_module = _require_aiohttp_module() - new_session = aiohttp_module.ClientSession() + if self._verify_ssl: + new_session = aiohttp_module.ClientSession() + else: + connector = aiohttp_module.TCPConnector(verify_ssl=False) + new_session = aiohttp_module.ClientSession(connector=connector) self._session = new_session return new_session diff --git a/dayu/engine/runner_factory.py b/dayu/engine/runner_factory.py index 697dcfc8..97079f67 100644 --- a/dayu/engine/runner_factory.py +++ b/dayu/engine/runner_factory.py @@ -64,6 +64,7 @@ def create_runner( supports_stream_usage=bool(runner_params.get("supports_stream_usage", False)), running_config=_build_openai_runner_running_config(agent_create_args), cancellation_token=cancellation_token, + verify_ssl=bool(runner_params.get("verify_ssl", True)), ) raise ValueError(f"不支持的 runner_type: {runner_type}") diff --git a/dayu/host/agent_builder.py b/dayu/host/agent_builder.py index 477355a0..0e01bb9a 100644 --- a/dayu/host/agent_builder.py +++ b/dayu/host/agent_builder.py @@ -172,6 +172,7 @@ def _build_runner_params( "supports_stream": bool(openai_model_config.get("supports_stream", True)), "supports_tool_calling": bool(openai_model_config.get("supports_tool_calling", True)), "supports_stream_usage": bool(openai_model_config.get("supports_stream_usage", False)), + "verify_ssl": bool(openai_model_config.get("verify_ssl", True)), } return openai_runner_params raise ValueError(f"不支持的 runner_type: {runner_type}") diff --git a/dayu/startup/config_loader.py b/dayu/startup/config_loader.py index 568dd194..83c7908b 100644 --- a/dayu/startup/config_loader.py +++ b/dayu/startup/config_loader.py @@ -273,26 +273,21 @@ def load_llm_models(self) -> dict[str, ModelConfig]: FileNotFoundError: 配置文件不存在 json.JSONDecodeError: JSON 格式错误 """ - if self._llm_models_cache is None: - loaded_models = _require_structured_config_object( - self._resolver.read_json("llm_models.json", required=True), - filename="llm_models.json", - ) - normalized_models: dict[str, ModelConfig] = {} - for raw_model_name, raw_model_config in loaded_models.items(): - model_name = str(raw_model_name or "").strip() - if not model_name: - raise TypeError("llm_models.json 的 key 必须是非空字符串") - if model_name.startswith("_"): - continue - if not isinstance(raw_model_config, dict): - raise TypeError(f"llm_models.json.{model_name} 必须是对象") - normalized_models[model_name] = cast(ModelConfig, raw_model_config) - self._llm_models_cache = normalized_models - llm_models = self._llm_models_cache - if llm_models is None: - raise RuntimeError("llm_models.json 缓存为空") - return cast(dict[str, ModelConfig], deepcopy(llm_models)) + loaded_models = _require_structured_config_object( + self._resolver.read_json("llm_models.json", required=True), + filename="llm_models.json", + ) + normalized_models: dict[str, ModelConfig] = {} + for raw_model_name, raw_model_config in loaded_models.items(): + model_name = str(raw_model_name or "").strip() + if not model_name: + raise TypeError("llm_models.json 的 key 必须是非空字符串") + if model_name.startswith("_"): + continue + if not isinstance(raw_model_config, dict): + raise TypeError(f"llm_models.json.{model_name} 必须是对象") + normalized_models[model_name] = cast(ModelConfig, raw_model_config) + return cast(dict[str, ModelConfig], deepcopy(normalized_models)) def load_llm_model(self, model_name: str) -> ModelConfig: """加载指定 LLM 模型的配置(包含环境变量替换) @@ -323,9 +318,10 @@ def load_llm_model(self, model_name: str) -> ModelConfig: Log.error(error_msg, module=MODULE) raise KeyError(error_msg) + raw_config = models[model_name] model_config = cast( ModelConfig, - _replace_model_config_env_vars(cast(ModelConfigJsonValue, models[model_name])), + _replace_model_config_env_vars(cast(ModelConfigJsonValue, raw_config)), ) ensure_runner_type_enabled(model_config.get("runner_type")) return cast(ModelConfig, model_config)