修改agent流程,分步构建cdsl

This commit is contained in:
2026-08-27 18:59:33 +08:00
parent 7fc1dfa84d
commit b26db86d78
54 changed files with 6835 additions and 9984 deletions
+44 -52
View File
@@ -5,7 +5,7 @@ import tempfile
import unittest
from pathlib import Path
from app.services.engine_service import load_engine, normalize_cdsl_for_engine, validate_cdsl
from app.services.engine_service import load_engine, validate_cdsl
from app.settings import get_settings
@@ -105,52 +105,6 @@ class ProfileSchemaTests(unittest.TestCase):
with self.assertRaisesRegex(ValueError, "positions\\[0\\].*not of type 'object'"):
validate_cdsl(cdsl, self.engine)
def test_normalizes_unambiguous_legacy_llm_field_names_before_validation(self) -> None:
legacy_cdsl = {
"schema": "cad.cdsl.llm.v1",
"part_id": "legacy-flange-base",
"geometry": {"sketches": [{
"id": "base_sketch",
"plane": "XY",
"offset_mm": 12,
"profile": {"type": "circle", "radius_mm": 20},
}]},
"features": [{
"id": "base_add",
"atomic_id": "extrude_add_blind",
"sketch": "base_sketch",
"params": {"distance_mm": 8},
}],
}
normalized, repairs = normalize_cdsl_for_engine(legacy_cdsl)
self.assertEqual(legacy_cdsl["geometry"]["sketches"][0]["plane"], "XY")
self.assertEqual(normalized["features"][0]["sketch_id"], "base_sketch")
self.assertNotIn("sketch", normalized["features"][0])
self.assertEqual(normalized["features"][0]["depends_on"], [])
self.assertEqual(normalized["geometry"]["sketches"][0]["workplane"], {
"origin_mm": [0.0, 0.0, 12.0],
"x_dir": [1.0, 0.0, 0.0],
"normal": [0.0, 0.0, 1.0],
})
self.assertEqual(len(repairs), 3)
validate_cdsl(normalized, self.engine)
def test_normalizer_rewrites_the_legacy_revolve_axis_point_name(self) -> None:
normalized, repairs = normalize_cdsl_for_engine({
"features": [{
"id": "turn",
"atomic_id": "revolve_add",
"params": {"axis": {"point_mm": [0, 0, 0], "direction": [0, 0, 1]}},
}],
})
axis = normalized["features"][0]["params"]["axis"]
self.assertEqual(axis["origin_mm"], [0, 0, 0])
self.assertNotIn("point_mm", axis)
self.assertIn("features[0].params.axis: point_mm -> origin_mm", repairs)
def test_cdsl_only_rebuild_preserves_its_actual_failure(self) -> None:
cdsl = {
"schema": "cad.cdsl.llm.v1",
@@ -168,11 +122,49 @@ class ProfileSchemaTests(unittest.TestCase):
with self.assertRaisesRegex(RuntimeError, "CDSL-only rebuild failed: unsupported atomic_id: extrude"):
self.engine.run_rebuild(cdsl, out_step)
def test_product_revision_path_uses_the_cdsl_only_entry_point(self) -> None:
source = (Path(__file__).resolve().parents[2] / "backend" / "app" / "services" / "engine_service.py").read_text(encoding="utf-8")
build_revision_source = source[source.index("def build_revision"):]
self.assertIn("engine.run_cdsl_only(cdsl_copy, step_path)", build_revision_source)
self.assertNotIn("engine.run_rebuild(cdsl_copy, step_path)", build_revision_source)
def test_autonomous_candidate_path_uses_the_cdsl_only_entry_point(self) -> None:
source = (Path(__file__).resolve().parents[2] / "backend" / "app" / "services" / "autonomous_cdsl_generation.py").read_text(encoding="utf-8")
candidate_builder = source[source.index("def build_candidate"):source.index("def commit_candidate")]
self.assertIn("engine.run_cdsl_only(cdsl_copy, step_path)", candidate_builder)
self.assertNotIn("engine.run_rebuild(cdsl_copy, step_path)", candidate_builder)
def test_hole_uses_inverse_host_face_normal_for_a_concave_l_bracket(self) -> None:
"""A local top face can be below the global body centre on an L part.
The drill must still enter its host face rather than point out into
empty space, otherwise the runtime reports a successful no-op hole.
"""
cdsl = {
"schema": "cad.cdsl.llm.v1", "schema_version": "1.1.0", "kind": "part", "part_id": "l-bracket-hole",
"meta": {"unit": "mm"},
"geometry": {"sketches": [
{
"id": "base", "workplane": {"origin_mm": [0, 0, 0], "x_dir": [1, 0, 0], "normal": [0, 0, 1]},
"profile": {"type": "polygon", "vertices": [[-25, 0], [25, 0], [25, 80], [-25, 80]]},
},
{
"id": "upright", "workplane": {"origin_mm": [0, 8, 0], "x_dir": [1, 0, 0], "normal": [0, -1, 0]},
"profile": {"type": "polygon", "vertices": [[-25, 0], [25, 0], [25, 60], [-25, 60]]},
},
]},
"features": [
{"id": "base_add", "atomic_id": "extrude_add_blind", "depends_on": [], "params": {"distance_mm": 8}, "sketch_id": "base"},
{"id": "upright_add", "atomic_id": "extrude_add_blind", "depends_on": ["base_add"], "params": {"distance_mm": 8}, "sketch_id": "upright"},
{
"id": "top_holes", "atomic_id": "hole_blind", "depends_on": ["upright_add"],
"params": {
"diameter_mm": 8, "depth_mm": 10,
"positions": [{"mm": [-15, 50, 0]}, {"mm": [15, 50, 0]}],
"host_face": {"frame": {"origin_mm": [0, 0, 8], "x_dir": [1, 0, 0], "y_dir": [0, 1, 0], "normal": [0, 0, 1]}},
},
},
],
}
validate_cdsl(cdsl, self.engine)
with tempfile.TemporaryDirectory() as temporary_directory:
result = self.engine.run_cdsl_only(cdsl, Path(temporary_directory) / "l-bracket.step")
self.assertAlmostEqual(float(result["volume_mm3"]), 52800 - 2 * 3.141592653589793 * 4 * 4 * 8, places=4)
self.assertEqual(int(result["solid_count"]), 1)
def test_all_official_samples_match_the_engine_schema(self) -> None:
from cdsl_importer.legacy_profile_adapter import lower_legacy_profiles