Просмотр исходного кода

主机:细化脚本工具领域失败处置

补充正式内容、Goal Coverage、任务合同和 ownership 等错误到 retry、repair、replan、abort 的稳定分类,确保框架收到真实业务错误而非 protocol_violation。
SamLee 9 часов назад
Родитель
Сommit
9d18d38c21

+ 9 - 1
script_build_host/src/script_build_host/tools/failures.py

@@ -6,6 +6,7 @@ from collections.abc import Mapping
 from typing import Any
 
 from agent import FailureDetail, FailureDisposition
+
 from script_build_host.domain.errors import ScriptBuildError
 
 _REPLAN_CODES = frozenset({
@@ -30,6 +31,7 @@ _RETRY_CODES = frozenset({
     "PUBLICATION_LOCK_TIMEOUT",
     "PUBLICATION_DEADLOCK_RETRYABLE",
     "STALE_BASE_REVISION",
+    "VALIDATION_EVIDENCE_INVALID",
 })
 _ABORT_MARKERS = (
     "STOP",
@@ -61,7 +63,13 @@ def classify_script_tool_failure(
         )
 
     code = error.code
-    if (
+    if code == "SCRIPT_CONTENT_INCOMPLETE":
+        disposition = (
+            FailureDisposition.REPAIR_ATTEMPT
+            if source_tool in {"submit_attempt", "save_paragraph_candidate"}
+            else FailureDisposition.REPLAN_TASK
+        )
+    elif (
         code in _REPLAN_CODES
         or code.startswith("GOAL_")
         or code.startswith("TASK_CONTRACT_")

+ 22 - 14
script_build_host/tests/test_tool_failure_bridge.py

@@ -3,8 +3,16 @@ from __future__ import annotations
 import json
 
 import pytest
+from agent import (
+    AgentRunner,
+    FailureDetail,
+    FailureDisposition,
+    RunConfig,
+    ToolRegistry,
+)
 from agent.orchestration import CompletionPolicy
 from agent.trace.store import FileSystemTraceStore
+
 from script_build_host.agents.presets import register_script_presets
 from script_build_host.application.phase_two_candidates import PhaseTwoCandidateError
 from script_build_host.domain.errors import (
@@ -16,14 +24,6 @@ from script_build_host.domain.errors import (
 from script_build_host.tools.failures import classify_script_tool_failure
 from script_build_host.tools.registry import register_script_tools
 
-from agent import (
-    AgentRunner,
-    FailureDetail,
-    FailureDisposition,
-    RunConfig,
-    ToolRegistry,
-)
-
 
 class _Coordinator:
     async def ensure_ledger(self, *_args, **_kwargs):
@@ -146,7 +146,7 @@ async def test_workspace_error_can_be_repaired_in_same_attempt(tmp_path):
             self.write_calls = 0
 
         async def candidate_command(self, name, _payload, _context):
-            assert name == "create_script_paragraph"
+            assert name == "create_script_paragraphs"
             self.write_calls += 1
             if self.write_calls == 1:
                 raise PhaseTwoCandidateError(
@@ -168,11 +168,19 @@ async def test_workspace_error_can_be_repaired_in_same_attempt(tmp_path):
         nonlocal calls
         calls += 1
         if calls <= 2:
-            tool_name = "create_script_paragraph"
+            tool_name = "create_script_paragraphs"
             arguments = json.dumps({
-                "paragraph_index": 1,
-                "name": "opening",
-                "content_range": {"start": 0, "end": 100},
+                "paragraphs": [{
+                    "client_key": "opening",
+                    "paragraph_index": 1,
+                    "name": "opening",
+                    "content_range": {"start": 0, "end": 100},
+                    "level": 1,
+                    "theme_elements": [{"原子点": "theme", "维度": "topic", "维度类型": "主维度"}],
+                    "form_elements": [{"原子点": "form", "维度": "contrast", "维度类型": "主维度"}],
+                    "function_elements": [{"原子点": "hook", "维度": "role", "维度类型": "主维度"}],
+                    "feeling_elements": [{"原子点": "curious", "维度": "tone"}],
+                }],
             })
         else:
             tool_name = "submit_attempt"
@@ -197,7 +205,7 @@ async def test_workspace_error_can_be_repaired_in_same_attempt(tmp_path):
         RunConfig(
             agent_type="script_paragraph_worker",
             completion_policy=CompletionPolicy.EXPLICIT_VALIDATION,
-            tools=["create_script_paragraph", "submit_attempt"],
+            tools=["create_script_paragraphs", "submit_attempt"],
             tool_groups=[],
             context={"task_id": "paragraph-task", "attempt_id": "attempt-1"},
             knowledge=_knowledge_off(),