Summary
measure() returns one face_inventory entry per distinct face with no cap. On analytic parts this is fine — faces collapse by type and the list stays short. On an imported or BSpline-heavy model it produces hundreds of lines of JSON for a single call.
Concrete case
measure() on an imported STEP (156 faces, volume 16381 mm3, bbox 77.1 x 11.4 x 160.8) returned roughly 120 face_inventory entries, the large majority being single-line BSpline areas:
{"type": "BSpline", "area": 757.7802},
{"type": "BSpline", "area": 609.7587},
{"type": "BSpline", "area": 584.8847},
... ~90 more ...
{"type": "BSpline", "area": 3.355},
Several hundred lines of output to answer "what is this object?". For an LLM caller that is a large, low-signal chunk of context — the same question is answered by volume, bbox and topology, which are the first ~15 lines.
The summarising machinery already exists
The response already demonstrates the right idea in two places:
- identical faces collapse with a
count field
- sub-threshold non-analytic faces fold into one entry:
{"type": "slivers_folded", "count": 6, "total_area": 10.4669, "note": "non-analytic faces < 2.9343 mm2 each"}
It is only the main list that is unbounded, so a model with many distinct BSpline areas defeats both mechanisms.
Relevant too: execute()'s own docstring advises save_json(name, obj) "instead of printing large results" — but measure() itself has no equivalent escape hatch.
Suggested fix
Any one of:
- Cap the inventory: top N by area, then
{"type": "...", "count": N, "total_area": X, "note": "N smaller faces"}.
- Add a
max_faces / summary=True parameter.
- Auto-route to
save_json above a threshold and return the path, mirroring the advice already given for execute().
Version
build123d-mcp 0.3.82.dev372, build123d 0.11.1, macOS.
🤖 Generated with Claude Code
Summary
measure()returns oneface_inventoryentry per distinct face with no cap. On analytic parts this is fine — faces collapse by type and the list stays short. On an imported or BSpline-heavy model it produces hundreds of lines of JSON for a single call.Concrete case
measure()on an imported STEP (156 faces, volume 16381 mm3, bbox 77.1 x 11.4 x 160.8) returned roughly 120face_inventoryentries, the large majority being single-line BSpline areas:{"type": "BSpline", "area": 757.7802}, {"type": "BSpline", "area": 609.7587}, {"type": "BSpline", "area": 584.8847}, ... ~90 more ... {"type": "BSpline", "area": 3.355},Several hundred lines of output to answer "what is this object?". For an LLM caller that is a large, low-signal chunk of context — the same question is answered by
volume,bboxandtopology, which are the first ~15 lines.The summarising machinery already exists
The response already demonstrates the right idea in two places:
countfield{"type": "slivers_folded", "count": 6, "total_area": 10.4669, "note": "non-analytic faces < 2.9343 mm2 each"}It is only the main list that is unbounded, so a model with many distinct BSpline areas defeats both mechanisms.
Relevant too:
execute()'s own docstring advisessave_json(name, obj)"instead of printing large results" — butmeasure()itself has no equivalent escape hatch.Suggested fix
Any one of:
{"type": "...", "count": N, "total_area": X, "note": "N smaller faces"}.max_faces/summary=Trueparameter.save_jsonabove a threshold and return the path, mirroring the advice already given forexecute().Version
build123d-mcp 0.3.82.dev372, build123d 0.11.1, macOS.
🤖 Generated with Claude Code