From 600f7c42ab113b7ae0a8599a04f279a7e36abdcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=A4=95?= Date: Tue, 28 Apr 2026 13:09:51 +0800 Subject: [PATCH] Feat/deepseek adapter dropin 14224636701039833263 (#50) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: resolve 422 error adding deepseek provider - Updated `pretor/api/provider.py` to allow "deepseek" as a valid Literal in `ProviderRegister` Pydantic model. - Validated tests to ensure the backend can correctly receive deepseek configurations. Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> * fix: complete deepseek provider registration wiring - Updated `pretor/core/global_state_machine/provider_manager.py` to correctly map `"deepseek"` to `DeepseekProvider`. - Updated `pretor/core/global_state_machine/model_provider/__init__.py` to export `DeepseekProvider`. - Confirmed this fully resolves the Provider Manager failing to instantiate DeepSeek despite passing API validation. Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> * fix: support pydantic-ai decorator proxying on DeepSeekReasonerAgent - Implemented `__getattr__` on `DeepSeekReasonerAgent` to safely proxy all unrecognized attributes (such as `@agent.system_prompt` and `@agent.tool`) directly to the underlying PydanticAI `Agent` object. - Resolves the crash where `SupervisoryNode.create_agent()` threw an `AttributeError` when trying to decorate `system_prompt`. Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> * refactor: remove gemini provider from frontend and backend - Removed `gemini` from `ProviderRegister` API validator. - Removed `GeminiProvider` files, tests, and its mappings from `AgentFactory` and `ProviderManager`. - Removed `gemini` from frontend TypeScript types and UI selection dropdown. Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> * fix: parse output with TypeAdapter to support Union types - Refactored `_parse_output` in `DeepSeekReasonerAgent` to use Pydantic's `TypeAdapter`. - Resolves a bug where Union types (like `Union[ForConsciousnessNode, ForUser]`) evaluated `hasattr(..., 'model_validate_json')` as `False`, causing the parser to fall back to `json.loads` and return a raw `dict`. - The `SupervisoryNode` now correctly receives Pydantic objects instead of dictionaries, resolving the `未知响应类型: ` crash. - Cleaned up debug scripts to adhere to repository standards. Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com> --- .../model_adapter/deepseek_reasoner.py | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/pretor/adapter/model_adapter/deepseek_reasoner.py b/pretor/adapter/model_adapter/deepseek_reasoner.py index ee3193c..131b0f8 100644 --- a/pretor/adapter/model_adapter/deepseek_reasoner.py +++ b/pretor/adapter/model_adapter/deepseek_reasoner.py @@ -7,6 +7,17 @@ from pydantic_ai.run import AgentRunResult T = TypeVar('T', bound=BaseModel) +class AgentRunResultProxy: + def __init__(self, original, parsed): + self._original = original + self._parsed = parsed + def __getattr__(self, name): + if name == 'data': + return self._parsed + if name == 'output': + return self._parsed + return getattr(self._original, name) + class DeepSeekReasonerAgent(Generic[T]): """ 专为 DeepSeek-V4/R1 设计的适配器。 @@ -32,12 +43,9 @@ class DeepSeekReasonerAgent(Generic[T]): format_instruction = "" if self.has_custom_output: try: - if hasattr(self.output_schema, 'model_json_schema'): - schema_str = json.dumps(self.output_schema.model_json_schema(), ensure_ascii=False) - else: - # Don't inject into prompt - schema_str = str(getattr(self.output_schema, '__name__', str(self.output_schema))) - + from pydantic import TypeAdapter + schema_dict = TypeAdapter(self.output_schema).json_schema() + schema_str = json.dumps(schema_dict, ensure_ascii=False) format_instruction = ( f"\n\nCRITICAL: 你必须输出且只能输出一段纯 JSON 格式的数据," f"并包裹在 ```json 和 ``` 之间。格式必须符合以下 JSON Schema 结构(或对应数据类型):\n" @@ -95,10 +103,9 @@ class DeepSeekReasonerAgent(Generic[T]): raise ValueError("未找到有效的 JSON 块。请将结果包装在 ```json 中。") try: - if hasattr(self.output_schema, 'model_validate_json'): - return self.output_schema.model_validate_json(json_str) - else: - return json.loads(json_str) + from pydantic import TypeAdapter + adapter = TypeAdapter(self.output_schema) + return adapter.validate_json(json_str) except ValidationError as e: raise ValueError(f"返回的 JSON 无法匹配所需结构:{e}") except json.JSONDecodeError as e: @@ -128,17 +135,6 @@ class DeepSeekReasonerAgent(Generic[T]): parsed_data = self._parse_output(raw_text) # Proxy the result to inject the parsed data seamlessly - class AgentRunResultProxy: - def __init__(self, original, parsed): - self._original = original - self._parsed = parsed - def __getattr__(self, name): - if name == 'data': - return self._parsed - if name == 'output': - return self._parsed - return getattr(self._original, name) - return AgentRunResultProxy(result, parsed_data) except ValueError as e: