--- name: aml-design description: 以 AML 为唯一事实源读写建筑模型并编译校验。当用户要求创建/修改建筑方案、房间布局、层高、开洞、围护结构或做建筑性能相关的模型准备时使用。 --- # DETA 建筑性能设计(AML) ## ★ 先读:工具怎么找、模型怎么改(任意工作目录都适用) **工具发现规则(重要)**:宿主对插件类 MCP 工具做**懒加载检索**,一次检索只返回少量结果 (实测 `Only 10 shown of 23`)。**搜不到不等于不存在**——不确定有哪些工具时,先调 **`list_capabilities`**(能力目录)拿到当前形态的**完整工具名清单**,再按名字**直接调用**。 **改建筑模型只有一个标准动作**(能力目录里有 `build_model` 时): `build_model({ aml, projectId })` —— 写服务端工作区 → 编译成建筑模型 → 规范校验 → 写进云项目, 一次调用完成;返回 `gate`(校验是否通过)、编译摘要、校验明细、云工作区 `headSha`。 - **不要**把 AML 拷进 Studio 的代码编辑器手工点编译(那是没有闭环工具时的兜底,不是正常路径); - **不要**用脚本自绘模型图代替 Studio; - 校验不通过(`gate: failed`)就按 `validation` 明细改 AML 后重跑,直到通过; - 冲突(`version_conflict`)说明云工作区被其它会话改过:确认要覆盖才传 `force: true`。 **看模型 / 打开 Studio**:`open_studio` 拿一次性免密链接,再用宿主内置浏览器(`iab`)打开—— 不要手工在面板登录,也不要用 playwright 逐步点击。 **执行器在线是模拟类工具的前置条件**:`simulate` / `studio_command` / `query_simulation_db` / `view_canvas` 的算力在 ant-model 浏览器里的执行器,经网关 host-call 中继干活;项目标签页一关 就离线,工具会 fail fast 报「执行器离线」。`open_studio` 会回报 `executor_online`,遇到离线提示 就再调一次它,不要改用手工登录。 ## 何时使用 用户提到建筑方案、房间/空间布局、层高、墙体开洞(门窗)、围护结构、体形系数、 建筑模型校验,或需要为后续能耗/日照/CFD 模拟准备模型时使用本技能。 ## 编辑与校验分工(先搞清"哪份文件是真值") 本插件挂的是**本机 MCP**:引擎工作区才是编译/校验/模拟读的真值(启动器 stderr 会回显路径)。 两种用法: - **工作区 = 项目目录**(启动宿主前设 `DETA_WORKSPACE=<项目目录>`):宿主原生文件工具与 MCP 工作区工具看的是同一份文件,直接改完就能编译,不需要同步步骤。 - **工作区 ≠ 项目目录**(缺省 `~/.deta/workspace`):本地改动要先同步进引擎工作区, 引擎工具读到的才是最新版本。 编辑手段按场景选:纯文本改动优先用宿主原生文件工具(read / patch / grep);需要按元素定向 读写 AML(按空间 ID 改属性、只取某实体块原文)时用 MCP 的工作区工具。编译、规范校验、 规则检查、围护结构统计、空间邻接一律走引擎工具。 当前形态到底有哪些工具、叫什么名字,以运行时调 `list_capabilities` 的结果为准。 | 要做的事 | 用什么 | |----------|--------| | 读取 / 修改 / 搜索 AML 与其它设计源文件(`aml.xml`、`bss.md`、`rules.yml`、`behaviors.yml`、`design-brief.md`) | **宿主原生工具**:read / patch / grep / shell(直接改文件,不走 MCP 编辑工具) | | 云端编译(AML → building.json) | MCP `apply_design` | | **改模型并让它出现在云项目/Studio(闭环单入口)** | **MCP `build_model`**(写工作区 → 编译 → 校验 → 云同步,一次调用完成) | | 语法与几何校验 / 规则检查 | MCP `validate_model`(`checks` 一次要齐几何 + issues + rules,三类共用同一次编译) | | 围护结构统计 | MCP `envelope_stats` | | 空间邻接、交通空间合并 | MCP `query_spatial_graph`、`apply_design(merge_traffic_spaces=…)` | | 领域脚本(面积预算 / 轴网 / 布局建议 / 校核) | MCP `run_script`、`run_scripts` | | 把本地改动送上云端、取回云端工作区 | MCP `push_project`、`pull_project` | | 语法规则与生成上下文 | MCP `get_aml_schema`、`generate_aml` | 固定顺序(工具面里有 `build_model` 时):**本地写 AML → `build_model` → 看 gate →(Studio 里看效果)**。 `build_model` 一次完成「写服务端工作区 → 编译 → 校验 → 写进云项目工作区」,Studio 里立即可见。 工具面里没有 `build_model`(部分部署形态会裁掉它)时才退化为:本地编辑 → `push_project` → `apply_design` → `validate_model` → Studio 查看。引擎工具读的是**服务端工作区**的文件,没推送过就读不到你的最新改动。 **工具检索结果条数有限**:一次搜索没看到某个工具,不代表它不存在——先调 `list_capabilities` 拿当前形态的完整工具名,再按名字直接调用。 ### 闭环单入口 build_model ``` build_model({ aml?: "", files?: { "aml.xml": "…" }, projectId?: "24", force?: false }) ``` - `aml` 给出则先写入引擎工作区 `aml.xml`;`files` 可一并写其它工作区文件(路径规则同 `push_project`)。 - `projectId` 缺省取工作区 `deta.json` 绑定的云项目;没有绑定就先 `push_project({ files, projectId })` 绑一次。 - 返回:`gate`(`passed` / `failed`)、编译摘要、校验明细、`cloud.headSha`、`studioUrl`。 - `gate: failed` → 按 warning/error 改 AML,再调一次 `build_model`,直到 `passed`。 - `status: conflict`(`version_conflict`)→ 云项目工作区被其它会话改过(例如 Studio 面板里编辑过), 确认要覆盖再传 `force: true` 重跑一次。 - `status: unavailable` → 当前没有云同步通道(未注入云令牌,或该部署形态未接云),改用 `apply_design` + `validate_model`(编译校验不依赖云)。 - **禁止**把 AML 拷进 Studio 的代码编辑器手工点编译:那是没有闭环工具时的兜底,不是正常路径。 ### push 与 Studio 深链 - 需要云端校验、或想在 Studio 里看效果时,先 `push_project({ files: { "aml.xml": "<全文>", "rules.yml": "…" }, projectId?: "…" })`。 `files` 至少含 `aml.xml`;路径必须是工作区相对路径(绝对路径、`..` 穿越会被拒绝); 单次载荷上限 1 MiB。传 `projectId` 会同时把本项目绑定到云项目 (写入服务端工作区 `deta.json`,之后 `generate_aml` / `pull_project` 也带同一深链)。 - 返回的 `studioUrl`(`https://deta.city/design/`,例:云项目 11 → `https://deta.city/design/11`): **在宿主右侧的内置浏览器面板打开**(做法见下一节);已有相同 URL 的标签优先复用,不要重复开新标签。 - 反向核对 / 拉回云端工作区用 `pull_project`(返回 `{ files, projectId?, studioUrl? }`, 工作区为空时 `files` 为 `{}`)。 ## 在右侧面板打开 Studio,并在其中跑模拟 Studio 就是deta.city 上的建筑性能应用。在 Codex 右侧内置浏览器面板打开它之后, 看模型、跑模拟、看结果图层都在面板里完成;本插件的 MCP 只负责把本地改动推上去,不执行模拟。 打开步骤(用宿主内置浏览器 = browser 插件的 `iab`): 1. **先调 `open_studio` 拿链接并确认执行器上线**(免手工登录)。返回 `url` (`https://deta.city/mcp-api/portal-session/landing?ticket=…&next=/design/`)、 `studioUrl`、`executor_online`、`expiresInSeconds`(180)。该链接在面板内会自动完成 deta.city 登录并跳到 Studio。 - 典型节奏:`open_studio()` 拿 `url` → 面板打开 → `open_studio({ waitSeconds: 20 })` 确认 `executor_online: true` → 再调 `simulate` / `studio_command` 等执行器侧工具。 - 若返回 `auth_required` → 先让用户完成 MCP 授权(`codex mcp login deta_mcp`)再重试; 若 `url` 报「票据无效或已过期」→ 重新调一次,不要改成手工登录。 2. 按 browser 插件技能(`control-in-app-browser`)的 Bootstrap 初始化,再取内置浏览器句柄: `const iab = await agent.browsers.get("iab");`,并先读一次 `await iab.documentation()`。 3. 先 `await iab.tabs.list()` 看是否已有该 URL 的标签:**有就复用,不要调 `goto` 重载** (重载会丢面板里正在进行的操作);没有才 `const tab = await iab.tabs.new(); await tab.goto(url);` 4. 打开后告诉用户「Studio 已在右侧面板打开(项目名/ID)」,并说明模拟在面板里运行。 旧路径(工具面里没有 `open_studio` 时):自己拼 `studioUrl` (本机项目目录 `deta.json` 的 `projectId`,或 `push_project(…, projectId)` 的返回值, 形如 `https://deta.city/design/`),按上面第 2–4 步打开——但需面板已登录。 在面板里跑模拟: - 模拟入口在 Studio 界面内(分析/模拟面板、GH 模板等)。**默认交给用户在面板里操作**—— 模拟参数与结果解读属设计决策,不要代替用户点。 - 用户明确要你代跑时:先 `await tab.ax.write()` 取当前界面元素,再 `await tab.ax.click(<元素序号>)` 逐步操作;每一步后重新取一次状态确认,**不要凭记忆点坐标**。 - 结果出来后用 `await tab.ax.write("both")` 或 `await tab.screenshot()` 确认图层与数值,再向用户汇报。 前置与故障: - 面板未登录 deta.city:用 `open_studio` 的一次性链接即可免手工登录(见上);只有拿不到 `open_studio` 时才退化为手工:在面板里打开 `https://deta.city/login` 完成一次登录 (登录态写入该浏览器的 `ant_token` cookie 与 `ant-model-auth` localStorage,之后长期有效), 登录完成后重新打开 `studioUrl` 即自动加载项目。 - **宿主把 MCP 授权页开在哪个浏览器由宿主决定**(实测 Codex Desktop 走系统默认浏览器), 且**那一页的登录态不会进入面板**——所以别把"MCP 已授权"当成"面板已登录",两者要分别确认: MCP 授权只解决 Codex↔服务端;面板登录解决 Studio 在面板里的会话(`open_studio` 正是两者的桥)。 实测口径:授权页在系统浏览器完成换码后停留在宿主的回调页("Authentication complete. You may close this window."),该页不归我们控制;授权页自身已改为**在隐藏框架内完成换码**并给出「打开 deta.city」 与「关闭本页」,不再顶层跳走。 - 没有 `projectId`:Studio 打开的是空项目。先在门户创建云项目拿到 ID,再 `push_project(…, projectId)` 绑定。 - 宿主没有内置浏览器(CLI 等形态):直接把 `studioUrl` 给用户,让他自己打开,不要假装已经打开。 ## 铁律 1. **AML 是建筑语义的唯一事实源**。任何几何或属性变更都必须落到 AML 文本, 不得用中间 JSON 表达修改意图。 2. **禁止凭记忆编写 AML 结构**。动手前必须先取真实语法: - 已有模型:读工作区里的 `aml.xml`(宿主原生 read 工具,或 MCP 的 `read_source`) - 语法规则:`get_aml_schema`(从编译服务实时获取,唯一权威) 3. **属性知识不硬编码**:房间用途、构造材料、洞口参数等可选值从工具返回中获取, 不要凭经验列举。 4. **局部修改优于整体重写**:改单个空间属性时只改该空间,不重写整个模型。 5. **控制单会话工具调用量**。编码代理在会话累积较多本插件工具调用后,会在请求里重复 声明 `deta` 命名空间,上游模型服务(Responses 兼容层)直接拒绝: `Duplicate namespace name 'deta'; Namespace names must be unique`。 实测触发点随会话长度前移(并发调用会显著提前触发)。规程: - 同一轮只调用一个本插件工具,不要并发; - 单会话保持轻量,完成任务后另起会话继续; - 一旦出现该错误,**停止重试并告知用户重开会话**(工作区文件不会丢失)。 6. **复杂形体(``)的脚本属于工作区文件,不是宿主本地文件**。 编译服务没有工作区访问权:编译前引擎会按 AML 声明的相对路径把脚本内容**随请求携带** (键名必须与 AML 一字不差,含 `geometry/` 前缀)。因此: - 脚本必须真实存在于**工作区**(用工作区文件工具读写,如 `geometry/shapes.py`); - 脚本取不到时编译会**显式失败并列出原因**(而不是"编译通过但形体丢失"); - 改动脚本内容后无需重命名或改 AML;若 AML 里写了 `version="sha256:…"`,脚本内容变了 必须同步更新该版本号,否则编译报「几何脚本版本不匹配」。 ## 标准工作流 1. **读**:用宿主原生工具读本地项目里的设计源码(`aml.xml` 等)。模型为空时先用 `generate_aml` 取生成上下文,再用 `get_aml_schema` 核对语法,然后在本地写出 AML。 2. **改**:在本地用 read / patch / grep 直接改 AML 文本(局部修改优于整体重写)。 3. **推**:`push_project({ files: { "aml.xml": … } })` 把改好的源码送到服务端工作区 (要绑云项目就带上 `projectId`)。 4. **编**:`apply_design` 提交编译 → 编译为建筑模型,产物落盘 `building.json`。 5. **校**:`validate_model` 做语法与规则校验,逐条读取错误码并修复,不得跳过; 规则类问题用 `validate_model({ checks: ['issues','rules'] })` 一次查齐(info 级提示只在 issues 视图可见)。 6. **看**:需要几何指标用 `envelope_stats`(围护结构/外窗面积)或 `query_spatial_graph` (空间邻接与查询);要看模型、**跑模拟**、看结果图层,就在右侧面板打开 `studioUrl` (见「在右侧面板打开 Studio,并在其中跑模拟」一节),模拟在 Studio 界面里运行。 ## 错误处理 - 编译服务未在线时,编译/校验类工具会返回明确错误文本。此时**不要伪造结果**, 直接报告「编译服务未接入」,改用宿主原生文件工具(read / patch)核对与编辑本地 AML。 - 编译报错必须逐条修复后重新 `apply_design`,禁止在报错状态下声称完成。 ## 工具名从哪来 本技能**不列工具清单**:工具面随部署形态(引擎形态 / 全量形态)裁剪,任何手写清单都会过期。 不确定有哪些工具时,调 `list_capabilities` 拿当前形态的**完整工具名**,再按名字直接调用; 每个工具能做什么、参数怎么给,以它自身的 description 与返回为准。