feat: strengthen CAD experience distillation and routing

This commit is contained in:
Jerry
2026-07-23 20:03:26 +08:00
parent a2f3ba6a90
commit 2edf8fb4c8
67 changed files with 16045 additions and 83 deletions
@@ -227,6 +227,115 @@ class CadRouterTests(unittest.TestCase):
plan["generalized_methods"][0]["id"],
)
def test_design_plan_exposes_promoted_reconstruction_grammar(self) -> None:
payload = {
"schema_version": "2.0",
"library_kind": "generalized_cad_experience",
"policy": {
"instance_parameters_allowed": False,
"absolute_coordinates_allowed": False,
"single_case_promotion_allowed": False,
"llm_semantic_review_required": True,
"draft_evidence_verified": True,
"router_consumable": True,
},
"experiences": [
{
"id": "reconstruction.flanged_hub_adapter.primary",
"kind": "reconstruction_grammar",
"scope": ["flanged_hub_adapter"],
"when": {"features": ["base_flange", "hollow_sleeve"]},
"guidance": "Establish shared datums before composing the envelope.",
"reconstruction_grammar": {
"parameter_roles": ["overall_long_span"],
"datum_roles": ["part_center", "primary_axis"],
"feature_roles": ["base_flange", "hollow_sleeve"],
"relation_roles": [],
"canonical_stages": [
{
"id": "establish_reference_frame",
"operation": "define_datums",
"feature_roles": [],
"reference_roles": ["part_center", "primary_axis"],
}
],
"cardinality_classes": ["cylinder_dense"],
"validation_roles": ["closed_solid"],
},
"support": 30,
"confidence": 0.9,
}
],
}
with tempfile.TemporaryDirectory() as directory:
library = Path(directory) / "library.json"
library.write_text(json.dumps(payload), encoding="utf-8")
result = route_module.route(
self.parse(
"生成一个带法兰轴套",
"--output",
"step",
"--experience-library",
str(library),
)
)
grammars = result["design_plan"]["reconstruction_grammars"]
self.assertEqual(1, len(grammars))
self.assertEqual(["overall_long_span"], grammars[0]["parameter_roles"])
def test_request_family_matches_geometry_facing_distilled_scope(self) -> None:
payload = {
"schema_version": "2.0",
"library_kind": "generalized_cad_experience",
"policy": {
"instance_parameters_allowed": False,
"absolute_coordinates_allowed": False,
"single_case_promotion_allowed": False,
"llm_semantic_review_required": True,
"draft_evidence_verified": True,
"router_consumable": True,
},
"experiences": [
{
"id": "motif.patterned_plate.holes",
"kind": "feature_motif",
"scope": ["patterned_plate"],
"when": {
"features": [
"planar_dominant_body",
"repeated_axial_hole_pattern",
]
},
"guidance": "Build the plate first, then place holes from symmetry.",
"support": 40,
"confidence": 0.94,
}
],
}
with tempfile.TemporaryDirectory() as directory:
library = Path(directory) / "library.json"
library.write_text(json.dumps(payload), encoding="utf-8")
result = route_module.route(
self.parse(
"Generate a mounting plate with four corner holes",
"--output",
"step",
"--experience-library",
str(library),
)
)
context = result["experience_context"]
self.assertEqual("plate", context["family"])
self.assertIn("patterned_plate", context["compatible_scopes"])
self.assertIn("planar_dominant_body", context["requested_features"])
self.assertIn(
"repeated_axial_hole_pattern", context["requested_features"]
)
self.assertEqual(
["motif.patterned_plate.holes"],
[item["id"] for item in context["experiences"]],
)
def test_step_edit_uses_source_and_library_not_private_case(self) -> None:
result = route_module.route(
self.parse(