merge: track F group C

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
Umut CAN
2026-09-23 23:05:27 +03:00
co-authored by Claude Opus 5.5
12 changed files with 2069 additions and 9 deletions
+236 -1
View File
@@ -9783,7 +9783,7 @@ async def drawing_export_dwg(
# ---------------------------------------------------------------------------
# ── SECTION 25: Architecture (7 tools) ──────────────────────────────────────
# ── SECTION 25: Architecture (11 tools) ─────────────────────────────────────
# ---------------------------------------------------------------------------
@@ -10226,6 +10226,241 @@ async def arch_schedule(
# ── arch: catalogue (group C) ──
@cad_tool(
summary="Search the furniture and sanitary catalogue in English or Turkish.",
cost="read",
)
@mcp.tool(
annotations={"title": "Architecture: Catalogue", "readOnlyHint": True},
tags={"arch", "query"},
)
async def arch_catalogue_list(
query: Annotated[
str | None,
Field(
default=None,
description=(
"Words matched against the item name, family and its English or Turkish "
"label, ignoring case and Turkish diacritics - 'bed', 'yatak', 'klozet', "
"'buzdolabi'. Every word must match."
),
),
] = None,
family: Annotated[
str | None,
Field(default=None, description="furniture | sanitary"),
] = None,
lang: Annotated[
str,
Field(default="en", description="en | tr - the language of the 'label' column"),
] = "en",
ctx: Context = None,
) -> dict:
"""Catalogue rows: name, family, both labels, nominal size [w, d] in mm, block name, layer.
Sizes are nominal catalogue dimensions - what a furniture or appliance
catalogue lists as a common size - and every row says so in `size_basis`;
they are not standards values. Twenty items: thirteen furniture, seven
sanitary. Refusals: a `family` other than furniture/sanitary and a `lang`
other than en/tr, each with the list.
"""
from engineering.arch.catalogue import FAMILIES, SIZE_BASIS, catalogue
try:
rows = catalogue(query, family, lang=lang)
except ValueError as exc:
raise ToolError(str(exc)) from exc
return {
"count": len(rows),
"families": list(FAMILIES),
"size_basis": SIZE_BASIS,
"items": list(rows),
}
@cad_tool(
summary="Insert a furniture or sanitary item - bed, sofa, WC, basin, bathtub - as a block.",
cost="mutate",
)
@mcp.tool(
annotations={"title": "Architecture: Catalogue Insert", "readOnlyHint": False},
tags={"arch", "create"},
)
async def arch_catalogue_insert(
name: Annotated[
str,
Field(
description=(
"Catalogue name from arch_catalogue_list, e.g. 'double_bed', 'sofa_3_seat', "
"'wc', 'wall_basin', 'kitchen_counter'"
)
),
],
x: Annotated[float, Field(description="X (WCS) of the item's back-left corner")],
y: Annotated[float, Field(description="Y (WCS) of the item's back-left corner")],
rotation: Annotated[
float,
Field(
default=0.0,
description=(
"Degrees CCW about (x, y); 0 puts the item's back (its wall side) along +X "
"with the item extending towards +Y"
),
),
] = 0.0,
ctx: Context = None,
) -> dict:
"""Define the item's block ARCH_<NAME> once, insert it on the furniture or sanitary layer.
The block carries an invisible ITEM attribute with the catalogue name. Its
size is a nominal catalogue dimension (reported with `size_basis`), not a
standards value; the outline is a plan symbol drawn inside that footprint.
The furniture / sanitary layer is created from the `arch` layer set when
the drawing lacks it. Refusals, all before any write: an unknown name
(with the nearest catalogue names) and a non-finite coordinate or rotation.
"""
from engineering.arch.catalogue import insert_item
await ctx.info(f"arch catalogue: {name} at ({x}, {y})")
try:
return await insert_item(_backend(ctx), name, at=(x, y), rotation=rotation)
except ValueError as exc:
raise ToolError(str(exc)) from exc
@cad_tool(
summary="Draw a structural grid: axis lines with numbered and lettered bubbles at both ends.",
cost="mutate",
)
@mcp.tool(
annotations={"title": "Architecture: Structural Grid", "destructiveHint": False},
tags={"arch", "create"},
)
async def arch_grid(
x_axes: Annotated[
list[float],
Field(description="X positions (WCS) of the vertical axes; numbered 1, 2, 3 left to right"),
],
y_axes: Annotated[
list[float],
Field(
description="Y positions (WCS) of the horizontal axes; lettered A, B, C bottom to top"
),
],
labels: Annotated[
dict | None,
Field(
default=None,
description=(
"Override the labels: {'x': [...], 'y': [...]} (either key), one label per "
"position in the order the positions were given"
),
),
] = None,
extension: Annotated[
float,
Field(
default=1500.0,
gt=0,
description="Drawing units each axis runs past the outermost crossing axis",
),
] = 1500.0,
scale: Annotated[
float,
Field(
default=50.0,
gt=0,
description="Plot-scale denominator (50 = 1:50): bubbles and labels are paper mm x scale",
),
] = 50.0,
ctx: Context = None,
) -> dict:
"""Axis lines on the arch grid layer (its CENTER linetype comes from the layer) and a
5 mm bubble with its label at both ends of each axis, on the symbol layer.
Numbers run along x and letters along y (A..Z, then AA, AB - no letter is
skipped) unless `labels` names them. The bubble and label sizes are this
server's declared drafting sizes in paper millimetres, not a standards value.
Refusals, all before any write: an empty axis list in either direction, a
non-finite or duplicate position, a label list whose length does not match
its positions, a duplicate or empty label, an unknown `labels` key, and a
non-positive `extension` or `scale`.
"""
from engineering.arch.symbols import draw_grid
await ctx.info(f"arch grid: {len(x_axes)} x {len(y_axes)} axes at 1:{scale:g}")
try:
return await draw_grid(
_backend(ctx), x_axes, y_axes, labels=labels, extension=extension, scale=scale
)
except ValueError as exc:
raise ToolError(str(exc)) from exc
@cad_tool(
summary="Draw a plan symbol: north arrow, section mark, level mark or elevation mark.",
cost="mutate",
)
@mcp.tool(
annotations={"title": "Architecture: Symbol", "destructiveHint": False},
tags={"arch", "create"},
)
async def arch_symbol(
kind: Annotated[
str,
Field(description="north_arrow | section_mark | level | elevation_mark"),
],
x: Annotated[float, Field(description="Symbol origin X (WCS)")],
y: Annotated[float, Field(description="Symbol origin Y (WCS)")],
params: Annotated[
dict | None,
Field(
default=None,
description=(
"north_arrow: {rotation} (degrees CCW from +Y; 0 = north up). "
"section_mark: {p1, p2, label, side} - p1/p2 are [x, y] relative to (x, y), "
"side left|right is where the section looks, seen from p1 towards p2. "
"level: {value} in metres (0 -> '±0.00'). "
"elevation_mark: {label, directions} - directions from up|right|down|left"
),
),
] = None,
lang: Annotated[
str,
Field(default="en", description="en | tr - the north letter and the decimal separator"),
] = "en",
scale: Annotated[
float,
Field(
default=50.0,
gt=0,
description="Plot-scale denominator (50 = 1:50): symbol sizes are paper mm x scale",
),
] = 50.0,
ctx: Context = None,
) -> dict:
"""Draw one architectural symbol on the arch symbol layer.
Sizes are this server's declared drafting sizes in paper millimetres times
`scale` (a 16 mm north-arrow circle, 10 mm section and elevation bubbles),
not standards values. Refusals, all before any write: an unknown `kind`
(with the list), a parameter the kind does not take (with the ones it
does), a section mark without p1/p2, with an empty label, an unknown side
or a cut line too short for its two arrows, an elevation direction outside
up/right/down/left or named twice, a non-finite level value, and a `lang`
other than en/tr.
"""
from engineering.arch.symbols import draw_symbol
await ctx.info(f"arch symbol: {kind} at ({x}, {y})")
try:
return await draw_symbol(
_backend(ctx), kind, (x, y), lang=lang, scale=scale, **(params or {})
)
except (TypeError, ValueError) as exc:
raise ToolError(str(exc)) from exc
# ---------------------------------------------------------------------------
# ── RESOURCES ───────────────────────────────────────────────────────────────
# ---------------------------------------------------------------------------