Files
cad-agent/dwg_review/phases/planning.py
T
gjm ec5292debe feat(mcp): 基座换行分帧与 isError 映射;新增 dwg_review 审查 Agent
基座(cad_mcp_frame):
- 新增 RecvOneFrame: 以 '\n' 为消息边界分帧,去掉单次 recv(2048) 限制(上限 8MB);
  用 select 短探测兼容不发 '\n' 的旧客户端;clientSocket 设 SO_RCVTIMEO 防卸载卡死
- JSON-RPC id 支持 string/number;无 id 的通知不回包
- isError 映射: 协议级错误保留顶层 error,工具执行错误转 result.isError=true
- 响应补 '\n' 作为消息边界

Agent(新增 dwg_review 包):
- mcp_client: 唯一 TCP/JSON-RPC 封装(单飞锁/分帧/重试/兼容 error 与 isError)
- cad_tools: 从 tools/list 动态建表,含 15 个只读白名单
- phases: planning -> evidence -> review(受控只读取证子循环)-> report
- annotator: 批注回写 AI_REVIEW 层,支持 dry-run 与撤销
- config: 配置全部走环境变量;Windows 下回退读注册表以读到新设的系统变量

其它: 新增 verify_mcp_frame.py 验证脚本;.gitignore 补 Python/AutoCAD 锁文件规则;
ai.memory 记录架构决策与实测结论
2026-10-13 23:44:11 +08:00

40 lines
1.2 KiB
Python

"""阶段 1:全局规划。
收集图纸概览 + 识别图框,按阅读顺序排序,产出审查计划。
"""
from ..mcp_client import result_json
def _sort_frames(frames):
"""按阅读顺序排序:先上后下(max_y 降序)、再左后右(min_x 升序)。"""
def key(frame):
bbox = frame.get("bbox") or [0, 0, 0, 0]
return (-round(float(bbox[3]), 3), round(float(bbox[0]), 3))
return sorted(frames, key=key)
def plan(ctx):
"""返回 {drawing_info, layers, layouts, frames}。"""
drawing_info = result_json(ctx.tools.call("get_drawing_info", {}), {})
layers = result_json(ctx.tools.call("get_layers", {"count_entities": True}), {})
layouts = result_json(ctx.tools.call("get_layouts", {}), {})
frames_data = result_json(
ctx.tools.call("detect_drawing_frames", {"min_confidence": 0.3}), {}
)
frames = frames_data.get("items", []) if isinstance(frames_data, dict) else []
frames = _sort_frames(frames)
if ctx.max_frames > 0:
frames = frames[: ctx.max_frames]
return {
"drawing_info": drawing_info,
"layers": layers,
"layouts": layouts,
"frames": frames,
}