优化生成流程

This commit is contained in:
2026-08-25 17:41:24 +08:00
parent 51575161dc
commit beaa5dd9fe
50 changed files with 4204 additions and 4261 deletions
+35 -24
View File
@@ -9,10 +9,12 @@ from types import SimpleNamespace
from unittest.mock import patch
from app.models.contracts import ChatMessage, MessagePart
from app.services.agent_service import AgentService, CDSL_TOOL_SCHEMA, RepeatedToolArgumentsError, StrictToolSchemaError, TOOL_SCHEMAS, ToolArgumentsError, normalize_image_analysis, parse_tool_arguments, response_language_instruction, tools_for_model, use_flange_sleeve_template, user_visible_error_message
from app.services.agent_service import AgentService, CDSL_TOOL_SCHEMA, RepeatedToolArgumentsError, StrictToolSchemaError, TOOL_SCHEMAS, ToolArgumentsError, engine_capability_manifest, normalize_image_analysis, parse_tool_arguments, response_language_instruction, system_prompt, tools_for_model, user_visible_error_message
from app.services.engine_service import load_engine
from app.services.quality import QUALITY_RULE_TYPES
from app.services.library import CdslLibrary
from app.services.storage import WorkspaceStore
from app.settings import ProviderConfig, ProviderModel, Settings
from app.settings import ProviderConfig, ProviderModel, Settings, get_settings
class ToolChoiceCompatibilityTests(unittest.TestCase):
@@ -107,16 +109,31 @@ class ParseToolArgumentsTests(unittest.TestCase):
self.assertNotIn("extrude", cdsl["$defs"]["feature_atomic_ids"]["enum"])
self.assertEqual(cdsl, CDSL_TOOL_SCHEMA)
def test_generation_schema_exposes_only_runtime_atomic_ids(self) -> None:
settings = get_settings()
engine = load_engine(settings)
self.assertEqual(
set(CDSL_TOOL_SCHEMA["$defs"]["feature_atomic_ids"]["enum"]),
set(engine.SUPPORTED_ATOMIC_IDS),
)
def test_verification_schema_exposes_only_implemented_rule_types(self) -> None:
generate_tool = next(tool for tool in TOOL_SCHEMAS if tool["function"]["name"] == "generate_cdsl_model")
verification = generate_tool["function"]["parameters"]["properties"]["verification"]
rule_type = verification["properties"]["rules"]["items"]["properties"]["type"]
self.assertEqual(set(rule_type["enum"]), set(QUALITY_RULE_TYPES))
def test_strict_tool_schema_covers_generation_arguments(self) -> None:
tools = tools_for_model(ProviderModel("strict-model", strict_tool_schema=True))
strict_tools = [tool["function"]["name"] for tool in tools if tool["function"].get("strict")]
self.assertEqual(strict_tools, ["generate_flange_sleeve_model", "generate_cdsl_model"])
template_tool = next(tool for tool in tools if tool["function"]["name"] == "generate_flange_sleeve_model")
self.assertEqual(template_tool["function"]["parameters"]["properties"]["plan"]["required"], ["template"])
self.assertEqual(strict_tools, ["generate_cdsl_model", "patch_cdsl_model"])
generate_tool = next(tool for tool in tools if tool["function"]["name"] == "generate_cdsl_model")
self.assertEqual(generate_tool["function"]["parameters"]["properties"]["summary"], {"type": "string", "minLength": 1})
self.assertEqual(generate_tool["function"]["parameters"]["properties"]["cdsl"], CDSL_TOOL_SCHEMA)
self.assertIn("verification", generate_tool["function"]["parameters"]["properties"])
patch_tool = next(tool for tool in tools if tool["function"]["name"] == "patch_cdsl_model")
self.assertIn("base_revision_id", patch_tool["function"]["parameters"]["required"])
self.assertFalse(generate_tool["function"]["parameters"]["additionalProperties"])
def test_default_model_does_not_receive_strict_tool_schema(self) -> None:
@@ -124,21 +141,14 @@ class ParseToolArgumentsTests(unittest.TestCase):
self.assertFalse(any(tool["function"].get("strict") for tool in tools))
def test_flange_sleeve_image_route_exposes_only_the_compact_plan_generator(self) -> None:
analysis = {
"partType": "带方形法兰的圆筒管座",
"visibleFeatures": ["同轴中空管", "四个安装孔"],
}
self.assertTrue(use_flange_sleeve_template(analysis, ""))
self.assertFalse(use_flange_sleeve_template(analysis, "cad_existing"))
tools = tools_for_model(ProviderModel("default-model"), flange_sleeve_only=True)
names = [tool["function"]["name"] for tool in tools]
self.assertIn("generate_flange_sleeve_model", names)
self.assertNotIn("search_cdsl_library", names)
self.assertNotIn("read_cdsl_reference", names)
self.assertNotIn("read_current_cdsl", names)
self.assertNotIn("generate_cdsl_model", names)
def test_direct_cdsl_tools_exclude_spec_and_template_generators(self) -> None:
names = [tool["function"]["name"] for tool in tools_for_model(ProviderModel("default-model"))]
self.assertIn("generate_cdsl_model", names)
self.assertIn("patch_cdsl_model", names)
self.assertNotIn("create_generation_spec", names)
self.assertNotIn("author_cdsl_from_generation_spec", names)
self.assertNotIn("patch_generation_spec", names)
self.assertNotIn("generate_flange_sleeve_model", names)
def test_recorded_image_analysis_is_not_exposed_as_a_tool(self) -> None:
tools = tools_for_model(ProviderModel("vision-model", vision=True), include_image_analysis=False)
@@ -385,15 +395,15 @@ class ToolArgumentsRetryTests(unittest.TestCase):
diagnostics = settings.conversation_root / conversation_id / "diagnostics"
attempts = sorted(diagnostics.glob("cdsl_attempt_*.json"))
failures = sorted(diagnostics.glob("cdsl_validation_*.json"))
self.assertEqual(len(attempts), 7)
self.assertEqual(len(failures), 7)
self.assertEqual(len(attempts), 5)
self.assertEqual(len(failures), 5)
self.assertTrue(all(json.loads(path.read_text(encoding="utf-8")) == {} for path in attempts))
records = sorted(
(json.loads(path.read_text(encoding="utf-8")) for path in failures),
key=lambda record: int(record["iteration"]),
)
self.assertEqual([record["iteration"] for record in records], list(range(2, 9)))
self.assertEqual([record["iteration"] for record in records], list(range(2, 7)))
self.assertTrue(all(record["kind"] == "cdsl_validation_failure" for record in records))
self.assertTrue(all(record["validation_error_type"] == "ValueError" for record in records))
self.assertTrue(all(record["validation_error"] for record in records))
@@ -402,7 +412,7 @@ class ToolArgumentsRetryTests(unittest.TestCase):
{path.name for path in attempts},
)
self.assertTrue(any("每次 CDSL 校验失败的诊断已保存到" in str(event.get("message", "")) for event in events))
self.assertEqual(agent.responses, [])
self.assertEqual(len(agent.responses), 2)
self.assertEqual(list(settings.task_root.glob("cad_*")), [])
@@ -822,5 +832,6 @@ class StructuredResultResponseTests(unittest.TestCase):
self.assertEqual(json.loads(attempts[0].read_text(encoding="utf-8")), {})
self.assertEqual(list(diagnostics.glob("cdsl_validation_*.json")), [])
if __name__ == "__main__":
unittest.main()