diff --git a/frontend/src/components/Agent/ProvidersSettings.tsx b/frontend/src/components/Agent/ProvidersSettings.tsx index 46ebebd..d3bd6e0 100644 --- a/frontend/src/components/Agent/ProvidersSettings.tsx +++ b/frontend/src/components/Agent/ProvidersSettings.tsx @@ -181,7 +181,6 @@ export function ProvidersSettings() { className="w-full bg-slate-50 border border-slate-200 text-sm rounded-lg px-3 py-2.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all cursor-pointer" > - diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 662d5fe..1308952 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -14,7 +14,7 @@ export interface User { // Provider types export interface Provider { - provider_type: 'openai' | 'gemini' | 'claude' | 'local' | 'deepseek'; + provider_type: 'openai' | 'claude' | 'local' | 'deepseek'; provider_title: string; provider_url?: string; provider_owner?: string; @@ -25,7 +25,7 @@ export interface Provider { } export interface ProviderRegisterRequest { - provider_type: 'openai' | 'gemini' | 'claude' | 'local' | 'deepseek'; + provider_type: 'openai' | 'claude' | 'local' | 'deepseek'; provider_title: string; provider_url: string; provider_apikey: string; diff --git a/pretor/adapter/model_adapter/agent_factory.py b/pretor/adapter/model_adapter/agent_factory.py index db281a3..725769f 100644 --- a/pretor/adapter/model_adapter/agent_factory.py +++ b/pretor/adapter/model_adapter/agent_factory.py @@ -14,10 +14,8 @@ from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIChatModel -from pydantic_ai.models.google import GoogleModel from pydantic_ai.models.anthropic import AnthropicModel from pydantic_ai.providers.openai import OpenAIProvider -from pydantic_ai.providers.google import GoogleProvider from pydantic_ai.providers.anthropic import AnthropicProvider from pretor.adapter.model_adapter.deepseek_reasoner import DeepSeekReasonerAgent from pretor.core.global_state_machine.model_provider import Provider @@ -27,7 +25,6 @@ from pretor.utils.error import ModelNotExistError class AgentFactory: def __init__(self): self._models_mapping = {"openai": (OpenAIChatModel, OpenAIProvider), - "gemini": (GoogleModel, GoogleProvider), "claude": (AnthropicModel, AnthropicProvider), "deepseek": (OpenAIChatModel, OpenAIProvider),} diff --git a/pretor/adapter/model_adapter/deepseek_reasoner.py b/pretor/adapter/model_adapter/deepseek_reasoner.py index 753354c..ee3193c 100644 --- a/pretor/adapter/model_adapter/deepseek_reasoner.py +++ b/pretor/adapter/model_adapter/deepseek_reasoner.py @@ -104,6 +104,11 @@ class DeepSeekReasonerAgent(Generic[T]): except json.JSONDecodeError as e: raise ValueError(f"返回的不是合法的 JSON:{e}") + + def __getattr__(self, item): + # Delegate any unknown attributes (like .system_prompt, .tool) to the underlying pydantic_ai Agent + return getattr(self.agent, item) + async def run(self, user_prompt: str, deps: Any = None, message_history: list = None, **kwargs) -> Any: # Custom retry loop current_history = message_history or [] diff --git a/pretor/api/provider.py b/pretor/api/provider.py index 07f3285..3ebfba5 100644 --- a/pretor/api/provider.py +++ b/pretor/api/provider.py @@ -25,7 +25,7 @@ from pretor.utils.ray_hook import ray_actor_hook provider_router = APIRouter(prefix="/api/v1/provider", tags=["provider"]) class ProviderRegister(BaseModel): - provider_type: Literal["openai", "gemini", "claude", "deepseek"] + provider_type: Literal["openai", "claude", "deepseek"] provider_title: str provider_url: str provider_apikey: str diff --git a/pretor/core/global_state_machine/model_provider/__init__.py b/pretor/core/global_state_machine/model_provider/__init__.py index 77aded4..5cb81a3 100644 --- a/pretor/core/global_state_machine/model_provider/__init__.py +++ b/pretor/core/global_state_machine/model_provider/__init__.py @@ -14,7 +14,6 @@ from pretor.core.global_state_machine.model_provider.base_provider import Provider, ProviderArgs from pretor.core.global_state_machine.model_provider.openai_provider import OpenAIProvider -from pretor.core.global_state_machine.model_provider.gemini_provider import GeminiProvider from pretor.core.global_state_machine.model_provider.claude_provider import ClaudeProvider from pretor.core.global_state_machine.model_provider.deepseek_provider import DeepseekProvider -__all__ = ["Provider", "ProviderArgs", "OpenAIProvider", "GeminiProvider", "ClaudeProvider", "DeepseekProvider"] +__all__ = ["Provider", "ProviderArgs", "OpenAIProvider", "ClaudeProvider", "DeepseekProvider"] diff --git a/pretor/core/global_state_machine/model_provider/gemini_provider.py b/pretor/core/global_state_machine/model_provider/gemini_provider.py deleted file mode 100644 index b2ad340..0000000 --- a/pretor/core/global_state_machine/model_provider/gemini_provider.py +++ /dev/null @@ -1,65 +0,0 @@ -from pretor.utils.retry import retry_on_retryable_error -# Copyright 2026 zhaoxi826 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from pretor.core.global_state_machine.model_provider.base_provider import BaseProvider, Provider, ProviderArgs -import httpx -from typing import List - -class GeminiProvider(BaseProvider): - @staticmethod - async def create_provider(provider_args: ProviderArgs) -> Provider: - provider_models: List[str] = await GeminiProvider._load_models(provider_args) - provider: Provider = GeminiProvider._return_provider(provider_args, provider_models) - return provider - - @staticmethod - @retry_on_retryable_error() - async def _load_models(provider_args: ProviderArgs) -> List[str]: - # Google Gemini 原生鉴权通常使用 x-goog-api-key 或 query parameter - headers = { - "x-goog-api-key": provider_args.provider_apikey, - "Content-Type": "application/json" - } - # 官方路径通常是 v1beta/models - url = f"{provider_args.provider_url.rstrip('/')}/v1beta/models" - - try: - async with httpx.AsyncClient(timeout=10.0) as client: - response = await client.get(url, headers=headers) - if response.status_code != 200: - print(f"[{provider_args.provider_title}] 获取 Gemini 模型失败: {response.status_code}") - return [] - - data = response.json() - # Gemini 返回的结构中模型 ID 通常带 "models/" 前缀 - raw_models = data.get("models", []) - model_ids = [m["name"].split("/")[-1] for m in raw_models if - "generateContent" in m.get("supportedGenerationMethods", [])] - return sorted(list(set(model_ids))) - except httpx.RequestError as e: - from pretor.utils.error import RetryableError - print(f"[{provider_args.provider_title}] 网络请求异常: {e}") - raise RetryableError(f"[{provider_args.provider_title}] 网络请求异常: {e}") from e - except Exception as e: - print(f"[{provider_args.provider_title}] 获取 Gemini 模型列表错误: {e}") - return [] - - @staticmethod - def _return_provider(provider_args: ProviderArgs, provider_models: List[str]) -> Provider: - return Provider(provider_title=provider_args.provider_title, - provider_apikey=provider_args.provider_apikey, - provider_url=provider_args.provider_url, - provider_models=provider_models, - provider_type="gemini") \ No newline at end of file diff --git a/pretor/core/global_state_machine/provider_manager.py b/pretor/core/global_state_machine/provider_manager.py index fa5ef25..b714700 100644 --- a/pretor/core/global_state_machine/provider_manager.py +++ b/pretor/core/global_state_machine/provider_manager.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from pretor.core.global_state_machine.model_provider import Provider, OpenAIProvider,GeminiProvider, ClaudeProvider, DeepseekProvider +from pretor.core.global_state_machine.model_provider import Provider, OpenAIProvider, ClaudeProvider, DeepseekProvider from typing import Dict, Type class ProviderManager: @@ -28,7 +28,6 @@ class ProviderManager: """供应商注册表:键为用户自定义别名,值为已实例化的 Provider 对象。""" def __init__(self, postgres): self.provider_mapper = {"openai": OpenAIProvider, - "gemini": GeminiProvider, "claude": ClaudeProvider, "deepseek": DeepseekProvider} self.provider_register = {} diff --git a/tests/core/global_state_machine/model_provider/gemini_provider_test.py b/tests/core/global_state_machine/model_provider/gemini_provider_test.py deleted file mode 100644 index b1f7f61..0000000 --- a/tests/core/global_state_machine/model_provider/gemini_provider_test.py +++ /dev/null @@ -1,69 +0,0 @@ -import pytest -from unittest.mock import patch, MagicMock, AsyncMock -from pretor.core.global_state_machine.model_provider.gemini_provider import GeminiProvider, ProviderArgs - - -@pytest.fixture -def provider_args(): - return ProviderArgs( - provider_title="TestGemini", - provider_url="https://generativelanguage.googleapis.com", - provider_apikey="testkey", - provider_owner="1" - ) - - -@pytest.mark.asyncio -@patch("pretor.core.global_state_machine.model_provider.gemini_provider.httpx.AsyncClient") -async def test_load_models_success(mock_client, provider_args): - mock_response = MagicMock() - mock_response.status_code = 200 - mock_response.json.return_value = { - "models": [ - {"name": "models/gemini-1.5-pro", "supportedGenerationMethods": ["generateContent"]}, - {"name": "models/gemini-1.5-flash", "supportedGenerationMethods": ["generateContent"]}, - {"name": "models/other", "supportedGenerationMethods": []} - ] - } - - mock_client_instance = AsyncMock() - mock_client_instance.get.return_value = mock_response - mock_client.return_value.__aenter__.return_value = mock_client_instance - - models = await GeminiProvider._load_models(provider_args) - assert models == ["gemini-1.5-flash", "gemini-1.5-pro"] - - -@pytest.mark.asyncio -@patch("pretor.core.global_state_machine.model_provider.gemini_provider.httpx.AsyncClient") -async def test_load_models_status_error(mock_client, provider_args): - mock_response = MagicMock() - mock_response.status_code = 401 - - mock_client_instance = AsyncMock() - mock_client_instance.get.return_value = mock_response - mock_client.return_value.__aenter__.return_value = mock_client_instance - - models = await GeminiProvider._load_models(provider_args) - assert models == [] - - -@pytest.mark.asyncio -@patch("pretor.core.global_state_machine.model_provider.gemini_provider.httpx.AsyncClient") -async def test_load_models_error(mock_client, provider_args): - mock_client_instance = AsyncMock() - mock_client_instance.get.side_effect = Exception("network error") - mock_client.return_value.__aenter__.return_value = mock_client_instance - - models = await GeminiProvider._load_models(provider_args) - assert models == [] - - -@pytest.mark.asyncio -@patch("pretor.core.global_state_machine.model_provider.gemini_provider.GeminiProvider._load_models", - return_value=["gemini-1"]) -async def test_create_provider(mock_load, provider_args): - provider = await GeminiProvider.create_provider(provider_args) - assert provider.provider_title == "TestGemini" - assert provider.provider_models == ["gemini-1"] - assert provider.provider_type == "gemini" diff --git a/tests/core/global_state_machine/provider_manager_test.py b/tests/core/global_state_machine/provider_manager_test.py index 27c3fa3..1111dd1 100644 --- a/tests/core/global_state_machine/provider_manager_test.py +++ b/tests/core/global_state_machine/provider_manager_test.py @@ -21,7 +21,6 @@ async def test_provider_manager_init(): await manager.init_provider_register(mock_postgres) assert "openai" in manager.provider_mapper - assert "gemini" in manager.provider_mapper assert "claude" in manager.provider_mapper assert manager.provider_register["title1"] == mock_provider1