gjm
|
2b6b52aa8c
|
Merge pull request 'feat(review): PDF/图片离线源适配(C1)—— 无需 CAD 的整条审查链路' (#18) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/18
|
2026-10-16 23:08:46 +08:00 |
|
gjm
|
6143bb9ab2
|
feat(review): PDF/图片离线源适配(C1)—— 无需 CAD 的整条审查链路
支持直接审查 PDF 与位图图纸,全链路离线(不连 CAD、不连 8080 端口)。
渲染在内存内完成,复用既有墨迹热力图 + 自适应瓦片规划。
- 新增 dwg_review/sources.py
- detect_source / plan_file / collect 统一入口
- PdfReader:pypdfium2 惰性导入,页序即图框序,处理 /Rotate 与 crop 边距
- ImageReader:世界单位 = 源像素,snap_box 整数对齐保证窗口与像素严格一致
- ink_grid:纯 PIL 灰度阈值 → 占用网格(不引入 numpy)
- ReviewContext.create(connect_cad=False):离线时 client/tools 均为 None
- 全链路 ctx.tools is None 守卫:review 只读子循环 / inspect_region / annotator /
checks 的窗口类检查 / 绘图区最大化
- checklist.build_system_prompt(allow_tools=False, offline=True):离线提示词
- __main__:位置参数 source,按扩展名自动判定源类型并决定是否连 CAD
- config 新增 8 个常量(PDF_MAX_PAGES / 文本最小字数 / 各源缩放上限 / 墨迹阈值等)
- tiling.content_predicate 与 heatmap.cell_box 提升为公开函数
验证:
- pytest 457 passed
- verify_pdf_source.py:PDF 23/23、图片 9/9(不需 CAD),含实测瓦片字高像素与
旋转映射自检(文本区墨迹 0.311 vs 忽略 /Rotate 反向对照 0.145)
- 真实 LLM 端到端:20 页 HVAC 图纸前 3 页跑通,结论具体可核验且未编造 handle
已知局限:页边线在墨迹网格里会把整页连成单簇,瓦片常退化为整页象限(CAD 侧
靠 drop_oversized 丢图框块,离线侧暂无等价手段),留待后续打磨。
|
2026-10-16 23:07:23 +08:00 |
|
gjm
|
80a23161c1
|
Merge pull request 'feat(review): 几何干涉检查 find_collisions(BVH 粗筛 + 容器过滤)' (#17) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/17
|
2026-10-16 19:47:18 +08:00 |
|
gjm
|
d4a9442e30
|
feat(review): 几何干涉检查 find_collisions(BVH 粗筛 + 容器过滤)
C++(cad_mcp_plugins):
- 新增 bvh.h:header-only 2D BVH(质心中位分割,叶<=4,SelfPairs 交叉对枚举)
- 新增 find_collisions.cpp:粗筛 AABB 相交实体对,附重叠盒 + 逐轴重叠比 ratio
(= 逐轴重叠长/较短长 之积,退化轴取 1.0),按 ratio 降序 + 分页;
narrow=true 只对返回页跑 intersectWith 细筛(附 exact)
- 容器过滤(关键):图框块/分区边界会与一切相交,用重叠【度】判定
deg >= max(exclude_container_deg=8, exclude_container_frac=0.25 * 其他实体数),
与图幅/缩放无关;被剔除者在 excluded_containers 里如实报告
(初版用面积判据对多图框并排失效:3 框只占并集 27/13/7% 全部漏过,
全模型 163 对噪声;改度判据后图框 deg=35/25/23 vs 其余 deg<=3,分离干净)
- cmakelists.txt + 两个 mcp_config.json 注册(28 工具)
agent 侧(Python):
- cad_tools.READ_ONLY_TOOLS += find_collisions(受控子循环可调用)
- checks.check_collisions + run_deterministic_checks(受 CHECK_COLLISIONS 开关,默认关)
- config += CHECK_COLLISIONS=False / COLLISION_MIN_OVERLAP=0.5
- checklist.py / review_checklist.json += 「干涉/碰撞」类别(high)+ 提示词协议
(先 find_collisions 拿候选 → inspect_region 目视确认;AABB 相交 != 真干涉)
验证:
- verify_collisions.py 17/17 PASS:全模型候选 163→80(全部 ratio=0.000),
min_overlap=0.5 → 0 对;逐图框 0 对;narrow top-5 中 4 条 exact=true;
--inject 注入深重叠矩形报出 ratio=0.902 并清理 2/2
- pytest 355 passed(新增 12 项)
- 端到端:LLM 主动调用 find_collisions{min_overlap:0.2,narrow:true,window:<图框>},未误报
|
2026-10-16 19:46:44 +08:00 |
|
gjm
|
a77a090281
|
Merge pull request 'feat(review): agent 侧虚拟工具 inspect_region —— 按可读分辨率放大指定区域' (#16) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/16
|
2026-10-16 19:16:04 +08:00 |
|
gjm
|
b757892c67
|
feat(review): agent 侧虚拟工具 inspect_region —— 按可读分辨率放大指定区域
解决三个缺口:① 放大没复用标定/瓦片数学(LLM 一次 zoom 只出一张,宽区域仍读不清);
②「看清没」由 VLM 自评(易过度自信/幻觉);③ 只能按 handle / 手算 bbox 指认,
图上看到但没 handle 的东西指认不了。
核心思路:把「放大」升级成一个语义化工具——LLM 只指认「要看哪里」,由 agent 复用
tiling.py 的标定数学算出该切几张、每张覆盖多大,用构造保证可读。
新增 dwg_review/inspect.py(agent 侧,不编 DLL):
- TOOL_SCHEMA:inspect_region(target, purpose);target 三形态 {handle} / {window} /
{label,cx,cy,span},purpose = text(8px) / line(6px)。
- InspectState:单图框内「截图标签 → 世界可见范围」登记表,支持逐级下钻
(返回的 inspect-N 可继续作为 label 指认)。
- resolve_target / _point_box:label+cx+cy → WCS。cy 是图像坐标(上→下),
世界 y 必须翻转(y = y2 - cy*H)——单测专门钉住。
- plan_tiles:复用 world_per_px + tiles_for_box + subdivide;超 INSPECT_MAX_TILES(4)
则硬失败并给出「缩小 target / 分多次请求」的指引(不静默降级);拿不到比例/像素
则退回单张并如实告知。
关键几何:CAD 的 _.ZOOM _W 是等比适配(不拉伸),故「截图上的归一化坐标」必须按
max(W/ew, H/eh) 反算真实可见范围(新增 tiling.visible_box)——直接用送进去的窗口会偏。
zoom_to_window 返回的 view 是「加过 margin 的窗口」,不是可见范围,不能混用。
证据层配套:evidence_model.make_image(..., window=) 记录每张图的可见世界范围;
capture_images 用 view_px(overall 图原始像素)+ visible_box 逐张登记。
子循环接入:_run_readonly_tool 在只读白名单校验之前拦截 inspect_region(它不在
READ_ONLY_TOOLS 里,内部只调白名单内的只读 MCP 工具);_review_tools 启用时用
inspect_region 取代三个裸视口工具;inspect_region 计入 _VIEW_TOOLS → 结束复位视口。
配置:INSPECT_ENABLED(True) / INSPECT_MAX_TILES(4)。
端到端实测(真实图纸 1 图框):取证与审查两阶段均在最大化态、结束精确还原(4 项 PASS);
LLM 的 11 次取证调用里 2 次是 inspect_region,且都显式给 window + purpose:"text"
(x[20000,115000] y[-6500,3000],即 A0 图框底部横条=标题栏所在)。
验收口径达成:报告报出标题栏乱码 ???????????????,而 get_text_content 对全图返回 0 条文字
(本图文字全在块/自定义实体内)→ 块内文字是被视觉放大读出来的。
pytest 343 passed。
|
2026-10-16 19:15:32 +08:00 |
|
gjm
|
3bc64b6c3e
|
Merge pull request 'feat(review): 审查阶段对齐绘图区分辨率 + 放大取证闭环' (#15) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/15
|
2026-10-16 18:57:04 +08:00 |
|
gjm
|
e8140f2bc5
|
feat(review): 审查阶段对齐绘图区分辨率 + 放大取证闭环
发现的缺口:maximized_drawing_area 原先只包住取证循环,审查阶段没被包住 →
LLM 在受控子循环里 zoom + 截图拿到的是未最大化的 2110x462(正是上一轮刚解决的
低分辨率问题,在最需要放大看细节的审查阶段又出现了);且审查中的 zoom 不复位视口,
跑完把用户的 CAD 留在最后一次放大处。
改动:
1. __main__.run_review:把 maximized_drawing_area 从「只包取证」扩到「包取证 + 审查」
(两者都要截图);report/annotate 留在 with 之外。
2. phases/review.py:新增 _VIEW_TOOLS;review_frame 拆成外壳 + _review_frame,
外壳 try/finally 里仅当确实动过视口才复位到该图框整幅视图
(zoom_to_window(win, margin=0.02))。纯查结构化数据的路径不受影响。
3. checklist.build_system_prompt:把「可调用只读工具」改写成明确的放大取证协议——
截图看不清时用 zoom_to_window(坐标由图框/实体 bbox 算)或 zoom_to_entity,
再 get_viewport_screenshot 复核;并约束不要为看图而反复放大。
次生问题(同轮修复):_MAX_OBS_IMAGES 原为硬编码 3,而模型一轮内会发 8 次截图 →
拍了 8 张只回灌 3 张。改为配置项 REVIEW_OBS_IMAGES(默认 6),并把预算耗尽的占位
文案改成明确告知模型「不要再请求截图,请给出结论」。
实测(真实图纸 1 图框,新增 verify_review_maximized.py):取证与审查两阶段窗口均为
[-4,-2,3444,1442](最大化态),结束精确还原 [68,0,2316,960],三项全 PASS;
子循环里 LLM 连发 8 组 zoom_to_window + get_viewport_screenshot,提示词生效。
pytest 304 passed。
|
2026-10-16 18:55:31 +08:00 |
|
gjm
|
931a430ba4
|
Merge pull request 'docs(memory): Agent 多源架构 + 工具分层;补真实测试图纸与启动方式' (#14) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/14
|
2026-10-15 23:46:39 +08:00 |
|
gjm
|
1e5bff268a
|
feat(review): 截屏前最大化绘图区 + 空瓦片过滤覆盖回退路径
新增 MCP 工具 set_drawing_area(mode="max"|"restore"):最大化主窗口 + CLEANSCREENON
(隐藏功能区/命令行/面板)。实测绘图区 2110x462 -> 3310x1084(面积 3.68x),
restore 精确回位(窗口矩形/最大化态/绘图区尺寸全部还原)。
坑:CLEANSCREENOFF 是异步命令,AutoCAD 会按「进入干净屏幕时的布局」重设窗口几何,
把同步的 SetWindowPlacement 覆盖掉(表现为窗口停在最大化)。解法是插件内
SetTimer 延迟 700ms 再压回;实测窗口在 0.5~1.0s 之间收敛,故调用方等待取 1.5s。
取证层:
- 新增 maximized_drawing_area(ctx) 上下文管理器,__main__ 用它包住整个取证循环
(多图框只进出一次);受 DRAWING_AREA_MAXIMIZE 控制,工具缺失/调用失败静默降级,
restore 失败不掩盖业务异常。
- 内容过滤统一到规划与回退两条路径,共用同一谓词;过滤后为空则退回原集合。
- 判定改用「实体 bbox」而非「占用格」:格子量化会把跨界内容算进相邻格,反而更粗
(实测实体 bbox 正好压象限边界时 4 个象限全判有内容)。heatmap.occupied_boxes 随之删除。
实测(真实图纸 A0/A1/A2 三图框):截图张数 12/8/4 -> 8/5/4;pytest 296 passed。
新增 verify_drawing_area.py 作为该工具的验收脚本。
|
2026-10-15 23:44:32 +08:00 |
|
gjm
|
9c4ab62dc1
|
feat(tiling): CAD 实测标定 R_text/R_line + 瓦片粒度内容过滤 + 默认参数定稿
Stage B2(CAD 实测标定)与收尾:
- 新增 verify_text_resolution.py:临时加字(字高 200 图形单位 = 1:100 纸面 2mm)+
平行线对,按目标像素换算 zoom 窗口 → 截图 → 问 VLM;测完 delete_entities 清理不保存。
- 标定结论:
* **可读下限与字体强相关**——离线合成(Consolas 抗锯齿填充字体)12px;
真实 CAD 单线体 .shx(描边字体)6px 即可读对(3/3,两轮)。
* 线条「1 条 vs 2 条」:2/3/4px 失败,5/8/12px 成功 → R_line ≈ 5px。
* **必须用 ACI 7 白字**:实测红字(ACI 1)12px 因对比度不足完全读不出。
- config 定稿:TEXT_READABLE_PX=8(折中)、LINE_READABLE_PX=6、
EVIDENCE_MAX_IMAGES=12(原 5 会把规划结果截到只剩 4 张瓦片)。
- 新增 heatmap.occupied_boxes:占用格的**世界 bbox**。
- tiling.plan_regions 新增 keep 谓词;evidence._plan_tiles 按占用格剔除**空瓦片**
(簇 bbox 是包围盒,L 形/斜向分布含大片空白,实测有效)。
- 测试:test_heatmap 补 occupied_boxes;test_tiling 补 keep 过滤;全量 286 项全绿。
- 真实图纸端到端验证:A0 图框出 12 张(1 整体 + 11 瓦片),单框审查 1m38s 通过。
- 记忆库同步:工具语义坑(type_filter 必须传列表 / layer_filter 是通配字符串 /
add_* 返回句柄在 created 键)、标定结论与默认值。
|
2026-10-15 23:22:15 +08:00 |
|
gjm
|
cba05b0c65
|
feat(tiling): 自适应瓦片规划器 + VLM 分辨率离线标定
背景:逐图框审查固定「整体 + 2x2 象限」截图,大图幅(A0/A1)读不清细节。
改为按**实体分布**自适应决定截几张、截哪里。
- 新增 dwg_review/tiling.py(纯函数):
SHEET_SIZES_MM / frame_world_size / frame_scale(sheet_scale>0 用之,否则由
bbox/纸张反算,否则 default)/ effective_px(与 downsample 同规则)/
world_per_px / is_text_type(标准名 + 自定义类名含 TEXT/LABEL/DIM/NOTE/TAG/
ANNO/TITLE)/ cluster_text_flags / tiles_for_box / subdivide / plan_regions
(文字簇优先、空白区不出图、max_tiles 截断、窗口夹到图框范围)
- 新增 verify_vlm_resolution_offline.py:PIL 合成类图纸图(精确像素字高 +
可控线间距/线宽/虚线)→ 问 VLM 强约束 JSON → 定 R_text / R_line。
实测:R_text=12px(黑底;白底 10px);R_line=6px。
另:实测该模型**无法可靠计数**(6 条线在 2~10px 间距下答 4/10/4/5/4/4),
故线条判据改用「1 条 vs 2 条」二选一。
- config 新增 TILING_ENABLED / TEXT_HEIGHT_MM / TEXT_READABLE_PX=12 /
LINE_READABLE_PX=6 / TILE_MAX_COUNT / TILE_OVERLAP / HEATMAP_CELL_DIV /
HEATMAP_CLUSTER_DILATE / HEATMAP_MAX_AREA_FRAC;EVIDENCE_DETAIL_TILES 与
EVIDENCE_MAX_IMAGES 保留作回退路径参数
- llm_client 新增 image_size_b64(测量绘图区实际像素,决定单张覆盖范围)
- phases/evidence.capture_images 支持瓦片规划:先截整体图并测像素 →
plan_regions 成功用规划窗口,否则退回 sub_windows(行为零变化);
末尾始终复位整体视口。collect_frame 传实体/文字 bbox;任一信封
total>returned(截断)→ 退回固定策略,避免误删有内容的瓦片
- 测试:tests/test_tiling.py(28 项)、tests/test_evidence.py 新增规划路径与
降级用例、test_config / test_llm_client 补新常量与 image_size_b64;
全量 283 项全绿
|
2026-10-15 23:03:27 +08:00 |
|
gjm
|
9b8a2329df
|
feat(heatmap): 实体分布热力图(占用网格 + 聚类 + 可视化)
- 新增 dwg_review/heatmap.py:entity_boxes / build_grid(counts+coverage)/ occupied_cells /
cluster_cells(4-连通,可选膨胀合并)/ grid_to_windows / grid_stats / render_overlay
- drop_oversized:过滤 bbox 占满图框的实体(实测每框恰 1 个,即图框块),否则热力图全满
- 新增 verify_heatmap.py:取实体 bbox(分页)-> 建网格 -> 聚类 -> 渲染 PNG,并缓存 bbox JSON 供离线调参
- 新增 tests/test_heatmap.py(22 项)
|
2026-10-15 22:51:05 +08:00 |
|
gjm
|
7cf71c9948
|
docs(memory): 截图去 UI(VPCONTROL/NAVVCUBEDISPLAY)+ grounding 实测结论
|
2026-10-15 21:20:23 +08:00 |
|
gjm
|
f8bd12dcec
|
fix(mcp): 截图去除 CAD 界面元素(视口控件/ViewCube/滚动条)
- get_viewport_screenshot 改用 acedGetAcadDwgView() 只截图形区(排除滚动条/状态栏)
- 截图期间临时置 NAVVCUBEDISPLAY=0、VPCONTROL=0 隐藏 ViewCube 与视口控件,
RAII 守卫自动恢复原值,不影响用户 CAD 界面设置;配合 RedrawWindow 同步重绘
- 新增 verify_grounding.py:grounding 实测探针(截整体图 + VLM 定位放大区域)
|
2026-10-15 21:19:59 +08:00 |
|
gjm
|
32d552f1f0
|
docs(memory): Agent 多源架构 + 工具分层;补真实测试图纸与启动方式
- 新增 project_agent_roadmap.md(总目标/多源分层/第一步/后续路线)
- 新增 feedback_tool_layering.md(工具层正交分工,反对无休止加工具)
- reference_environment.md 补 e:\desktop\agent_test.dwg 与 /p SHS-ENVI2026 启动方式
- 一并提交上次会话遗留的记忆更新
|
2026-10-15 19:48:56 +08:00 |
|
gjm
|
1c9fc72839
|
feat(review): 取证层多源化 + 视觉多图(整体+2x2 象限)
- 新增 evidence_model.py:统一证据模型(source_type + images 列表),访问器兼容旧 image_b64/image_mime 单图字段
- phases/evidence.py:新增 collect() 多源分发 seam(仅 CAD)、capture_images() 整体+等分象限多图(结束复位视口)、sub_windows()
- phases/review.py:多图逐张下采样喂 LLM,payload 增加 source_type
- config.py:EVIDENCE_DETAIL_TILES=4 / EVIDENCE_MAX_IMAGES=5(默认开启多图)
- 新增 tests/test_evidence_model.py,更新 evidence/review 断言与 fakes 归一
|
2026-10-15 19:48:18 +08:00 |
|
gjm
|
22db93b6f5
|
Merge pull request 'fix(review): 批注去重 + 删除残留调试截图' (#13) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/13
|
2026-10-14 19:56:58 +08:00 |
|
gjm
|
17c202549e
|
docs(memory): 记录可信度三件套落地、window 参数实机事实与 CAD 自启偏好
- project_review_agent_impl:三件套链路(结构化结论删除二次抽取、确定性检查前置、
handle 交叉校验)、开关与数据结构;find_zero_length/find_duplicate_entities 的
window 参数 schema 未声明但实机生效
- feedback_preferences:需要 CAD 时自己启动(自动加载已配好),不要先问用户
|
2026-10-14 19:54:53 +08:00 |
|
gjm
|
81d8c3d2ca
|
fix(review): 批注去重 + 删除残留调试截图
- annotator.annotate:同一 handle 只批注一次(修复 created 无去重的既有 gap,
同 handle 出现两次不再产生重复引线)
- 删除 test_screenshot.png(已删除脚本 test_autoagent.py 的残留产物)
|
2026-10-14 19:53:41 +08:00 |
|
gjm
|
f7fa8f14d9
|
feat(review): 审查结论改为结构化 JSON,移除二次 LLM 抽取
- checklist.py:系统提示加入结构化输出契约(只输出 {summary, issues[]},
引用 handle 必须真实存在、不得编造)
- review.py:review_frame 返回 {summary, issues, raw};仅在「不再请求工具」的回合
解析结论,中间工具回合的 content 永不解析;强制收口那次 chat 不传 tools
- report.py:删除 extract_issues 与 _EXTRACT_SYSTEM(不再需要第二次 LLM 调用);
新增 format_finding(用 .get,顺带修复缺 frame 键 KeyError);save_report 的
issues 省略时从 findings 拍平
- __main__.py:主流程改为 确定性检查 → review_frame → build_finding(合并+校验),
issues 由 flatten_issues 派生
顺带修复既有 gap:summarize 硬下标 KeyError、extract_issues 单行围栏解析失败。
|
2026-10-14 19:53:41 +08:00 |
|
gjm
|
f6d61f8d07
|
feat(review): 新增确定性检查前置与结论结构化内核
- checks.py:确定性检查(find_zero_length / find_duplicate_entities 传 window
+ 纯 Python 派生空文字、未闭合多段线)。问题带 source=deterministic,handle 来自
工具/数据本身,不依赖 LLM 回忆
- findings.py:解析 LLM 的 JSON 结论 + handle 交叉校验(引用未知 handle 时保留问题、
剥掉 handle、verified=False)+ findings 装配
- config.py:新增 DETERMINISTIC_CHECKS / VALIDATE_HANDLES / CHECK_UNCLOSED_POLYLINES
开关与 ZERO_LENGTH_TOLERANCE / DUP_TOLERANCE / DUP_GROUP_LIMIT
实机验证:find_zero_length / find_duplicate_entities 的 window 参数在基座上生效
(schema 未声明,C++ 侧 parseCommonQuery 实际支持)。
|
2026-10-14 19:53:31 +08:00 |
|
gjm
|
a0ea902b50
|
Merge pull request 'chore: 删除 5 个遗留调试脚本并同步文档引用' (#12) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/12
|
2026-10-14 19:16:39 +08:00 |
|
gjm
|
f4564d49fc
|
docs(memory): 安全备案结案——旧 Key 已吊销、新 Key 验证可用
用户已在 DeepSeek 控制台吊销旧 Key 并在系统级 DEEPSEEK_API_KEY 设置新 Key;
AI 侧验证:read_env 读到非空 + 一次真实 chat_text 调用成功。
|
2026-10-14 19:14:44 +08:00 |
|
gjm
|
daccc734bf
|
test(review): 把 5 处既有瑕疵锁成 *_known_gap 用例
让既有瑕疵可见,而不是被当成正确行为;改 1~3(确定性检查前置/结论结构化/
证据交叉校验)时可据此判断行为是否被改变。
- bbox_to_window 含非数值 → ValueError(上游只判长度)
- summarize / extract_issues 硬下标 f['frame'] → KeyError
- annotate 的 created 无去重(同 handle 产生重复批注)
- extract_issues 单行 ```json[...]``` 围栏剥离失败 → []
- result_json 文本 'null' → None(与「无 text 返回 default」语义易混)
|
2026-10-14 19:09:56 +08:00 |
|
gjm
|
fa2d01aad2
|
docs(memory): 备案 DeepSeek API Key 泄露与轮换待办
Key 已随 bdd77af 进入 git 历史并推送远程,删除文件无法清除历史,
须由用户去 DeepSeek 控制台轮换(仓库外人工操作)。
|
2026-10-14 19:08:49 +08:00 |
|
gjm
|
8c0fcfee83
|
chore: 删除 5 个遗留调试脚本并同步文档引用
- 删除 agent_loop.py / dwg_review_agent.py / countOfCircle.py
(硬编码 DeepSeek API Key)与 test.py / test_autoagent.py
(重复实现;且 test_autoagent.py 名字与 pytest 的 test_*.py 收集规则冲突)
- CODEBUDDY.md 测试章节改为「pytest 快层 + verify_* 慢层」
- review_checklist.json 描述改指 dwg_review 包
- ai.memory 同步引用与历史说明
安全:Key 已随提交 bdd77af 进入 git 历史并推到远程,删除文件不能清除历史,
需去 DeepSeek 控制台轮换该 Key(已在 ai.memory 备案)。
|
2026-10-14 19:07:35 +08:00 |
|
gjm
|
0656397a68
|
test(review): 新增 pytest 离线回归网,锁定 dwg_review 既有行为
在改动审查流水线(确定性检查前置 / 结论结构化 / 证据交叉校验)之前,
先立一张离线、确定性、秒级的回归网。
- tests/fakes.py:假 LLM + 假 MCP 基座 + 响应构造器(ok_text/ok_image/err)
+ make_ctx/make_evidence,绝不触网、不读密钥
- 10 个模块共 134 用例:
mcp_client / llm_client / cad_tools / checklist / config /
planning / evidence / review / report / annotator
- pytest.ini(testpaths=tests)+ requirements-dev.txt + 根 conftest.py
(sys.path + RENDER_WAIT=0 / REPORT_DIR=tmp fixture)
|
2026-10-14 19:07:27 +08:00 |
|
gjm
|
8c07c7cad6
|
Merge pull request 'fix(frame): 加固 TCP 收发路径(大响应、分帧判定、超限回包、PostMessage 泄漏)' (#11) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/11
|
2026-10-14 15:51:25 +08:00 |
|
gjm
|
c021d7ae39
|
docs(memory): 记录基座 TCP 路径的主线程阻塞约束与分帧规则
|
2026-10-14 15:49:49 +08:00 |
|
gjm
|
4167ea033f
|
fix(frame): 加固 TCP 收发路径(大响应、分帧判定、超限回包、PostMessage 泄漏)
- SendAll:发送改为循环直到发完并检查返回值。原实现单次 send 且忽略返回值,
截图这类大响应可能被截断;同时 accept 时补设 SO_SNDTIMEO——响应由 AutoCAD
主线程发送,慢客户端若把 send 卡住会直接拖死 CAD 的 UI。
- RecvOneFrame:去掉"收完 select 探测 150ms 无后续数据即判定整帧"的启发式。
该做法与分片时机强相关,真实网络上分片间隔 >150ms 的大报文会被误截断成 -32700。
改为「零超时 select 探测 + JSON 完整性判定」:数据仍在流式到达时不解析,
与分片间隔无关;且仅在内容以 '}'/']' 收尾时才尝试解析,避免大报文反复解析(O(n^2))。
- 帧超限:不再静默断开,回顶层 -32700。回包后先 shutdown(SD_SEND) 再有界排空剩余
输入再关闭——否则接收缓冲仍有未读数据会触发 RST,可能把刚发出的响应丢掉。
- PostMessage:检查返回值。原实现只在窗口为空时 delete,投递失败(窗口已销毁 /
队列满)会让 TaskData 永久泄漏;现在失败即释放(析构会关闭 socket)。
验证(关 CAD -> 重建 -> 重启后实测):
- 新增 verify_mcp_tcp_hardening.py 8/8 PASS:截图 base64 解码为完整 PNG(92175 字节,
含文件头与 IEND);>8MB 帧回 -32700;不带换行的旧式请求仍可用;分片间隔 450ms
不被截断(旧实现会失败);客户端中途断开后基座存活;常规路径无回归。
- 回归:verify_mcp_frame 4/4、verify_mcp_fault_injection 22/22、verify_stdio_bridge 24/24、
verify_annotate 9/9、dwg_review --check 正常。
|
2026-10-14 15:49:15 +08:00 |
|
gjm
|
446a5b3cb9
|
Merge pull request 'fix(frame): 工具执行加异常保护,畸形参数不再崩溃 CAD / 泄漏写锁' (#10) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/10
|
2026-10-14 15:45:18 +08:00 |
|
gjm
|
bfacb020a8
|
docs(memory): 记录基座工具执行的异常安全不变量与故障注入验证
|
2026-10-14 15:40:56 +08:00 |
|
gjm
|
48229c28b0
|
fix(frame): 工具执行加异常保护,畸形参数不再崩溃 CAD / 泄漏写锁
cad_mcp_frame 的工具执行发生在 AutoCAD 主线程的窗口消息处理链上
(TcpServerLoop -> PostMessage -> WndProc -> ExecuteTaskInMainThread -> mcp_Tools::Call)。
插件 Execute 在参数类型不符时会抛 nlohmann::type_error(如 args.value("bulge", 0.5)
收到字符串、parsePoint 对 ["a","b"] 取 get<double>())。原实现全程无 try/catch,
异常逃逸出 WndProc 属未定义行为(实测表现为 CAD 崩溃),且会让 DLL 代理的文档写锁
无法释放。LLM 驱动的审图流程会生成这类错误参数,属日常会踩到的路径。
- mcp_ConfigParser.cpp: mcp_Tools::Call 用 try/catch 包住 Execute,
std::exception -> make_error(-32603)(上层映射为 result.isError=true),catch(...) 兜底。
- mcp_server.cpp: HandleToolsCall 入口校验 params/arguments 必须是对象、name 必须是
字符串,否则回 -32602(协议错误),从源头避免 value()/get<>() 抛异常;
ExecuteTaskInMainThread 增加兜底 try/catch,并补 !req.is_object() -> -32600。
- mcp_tool.cpp: mcp_Tool_DllProxy::Execute 的文档写锁改为 RAII 守卫
(ScopedDocumentWriteLock),异常展开时同样解锁,避免写锁泄漏。
验证(关 CAD -> 重建 -> 重启后实测):
- 新增 verify_mcp_fault_injection.py 22/22 PASS:
A 结构性错误(params/arguments/name 类型错、非对象请求、非法 JSON)分别回
-32602/-32600/-32700;B 工具内部类型异常被兜为 result.isError=true;
C 反复注入 10 次后 CAD 存活、写锁未泄漏(有效写操作仍成功)。
- 回归:verify_mcp_frame 4/4、verify_stdio_bridge 24/24、verify_annotate 9/9、
dwg_review --check 正常。
|
2026-10-14 15:40:20 +08:00 |
|
gjm
|
5d83d3fa76
|
Merge pull request 'fix(build): 修正 cmake SOURCES 的文件名大小写,使 Linux/macOS 可构建' (#9) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/9
|
2026-10-14 15:18:07 +08:00 |
|
gjm
|
526d5f8911
|
fix(build): 修正 cmake SOURCES 的文件名大小写,使 Linux/macOS 可构建
cmake 的 SOURCES 列表引用的文件名与 git 跟踪名仅大小写不同。Windows 大小写不
敏感故能编译,但在 Linux/macOS 上 git checkout 会按跟踪名落盘,CMake 精确匹配
不到便报 "Cannot find source file"。
- src/cad_mcp_frame/cmakelists.txt: stdafx.cpp → StdAfx.cpp,
mcp_configParser.cpp → mcp_ConfigParser.cpp
- src/cad_mcp_plugins/cmakelists.txt: stdafx.cpp → StdAfx.cpp
统一方向取「大写」,与既有引用保持一致:
- 所有 #include "StdAfx.h"、target_precompile_headers(... PRIVATE StdAfx.h)
- #include "mcp_ConfigParser.h"、class mcp_ConfigParser
仅上述两处 SOURCES 列表写成了小写,是唯一的例外,故改 cmake 而非重命名文件。
同时把本机磁盘上的 mcp_configParser.cpp 规范化为 mcp_ConfigParser.cpp,使工作
副本与仓库一致(Windows 大小写不敏感,不影响构建)。
验证:
- 全项目扫描 cmake/include 引用与 git ls-files 的精确大小写匹配 → 无不一致
- cmake --build --preset R230 --config Debug 成功(CMake 重新配置正常,
源码未变故未重链接,无需关闭 CAD)
|
2026-10-14 15:14:23 +08:00 |
|
gjm
|
4ab591ad23
|
Merge pull request 'feat(bridge): 新增 stdio↔TCP 桥,让标准 MCP 客户端可直连 CAD 基座' (#8) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/8
|
2026-10-14 13:33:34 +08:00 |
|
gjm
|
3bd77d950e
|
fix(frame): 未知工具错误码 -32601 改为 -32602,符合 MCP 规范
MCP 规范《Tools / Error Handling》把「未知工具」归为**协议错误**,
示例即为 {"code": -32602, "message": "Unknown tool: invalid_tool_name"}。
基座原先回 -32601(Method not found),语义偏 JSON-RPC 方法层。
- mcp_configParser.cpp: mcp_Tools::Call 改 -32601 → -32602,
消息改为 "Unknown tool: <name>"。
- 无需改 mcp_server.cpp 的 HandleToolsCall:其协议错误白名单
{-32700,-32600,-32601,-32602} 已含 -32602,分类逻辑不变。
- 同步更新 verify_mcp_frame.py 与 verify_stdio_bridge.py 的断言
(未知「方法」仍是 -32601,语义正确,不动)。
验证(重建基座 + 重启 CAD 后实测):
- 直连 TCP:{"error":{"code":-32602,"message":"Unknown tool: __no_such_tool__"}}
- verify_mcp_frame.py 4/4 PASS;verify_stdio_bridge.py 24/24 PASS
- 回归:verify_annotate.py 9/9、dwg_review --check 正常
- MCP Inspector 冒烟:tools/list 26 个工具、tools/call get_drawing_info 正常
|
2026-10-14 06:21:46 +08:00 |
|
gjm
|
f33d42afe9
|
feat(bridge): 新增 stdio↔TCP 桥,让标准 MCP 客户端可直连 CAD 基座
标准 MCP 客户端(Claude Desktop / CodeBuddy / MCP Inspector)只实现 stdio 与
Streamable HTTP,无法直连 cad_mcp_frame 的自定义裸 TCP。新增 mcp_bridge 包在
客户端与基座之间做协议适配,CAD 侧零改动:
- 合成基座缺失的生命周期:initialize(含协议版本协商、capabilities、serverInfo)
与 ping;notifications/* 按规范不回包。
- tools/list、tools/call 原样转发到 127.0.0.1:8080,result 与顶层 error 忠实透传,
仅把 id 改写回客户端原始 id。
- 并发:读线程即时应答 initialize/ping,单工作线程串行转发工具调用(保证顺序、
慢工具不阻塞 ping)。
- stdout 只走 sys.stdout.buffer 并加锁,规避 Windows 的 \n→\r\n 翻译;
诊断信息一律走 stderr。
- CAD 未启动时桥照常启动,工具调用回 -32603(可重试)。
- 入口:python -m mcp_bridge,支持 --host/--port/--timeout/--verbose/--print-config。
dwg_review/mcp_client.py 增加 raw_rpc()(_rpc 新增 normalize 开关),
返回基座原始响应 dict 供桥透传,避免重复实现 TCP 封装。
验证:
- verify_stdio_bridge.py 24/24 PASS(版本协商、通知不回包、ping、tools/list 与基座
等价、tools/call、错误透传、-32700、string id、stdout 纯净性、死端口降级)。
- 真实标准客户端 MCP Inspector 冒烟通过:tools/list 拿到 26 个工具,
tools/list --strict 退出码 0(无 schema 可移植性问题),
tools/call get_drawing_info 返回标准 content + isError:false。
- 回归:verify_mcp_frame.py 4/4、verify_annotate.py 9/9、dwg_review --list-tools/--check 正常。
|
2026-10-14 00:44:15 +08:00 |
|
gjm
|
e56ce09caf
|
Merge pull request 'feat(plugins): 截图前检测 CAD 窗口遮挡并自动置前' (#7) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/7
|
2026-10-13 23:57:00 +08:00 |
|
gjm
|
bcc4f72e91
|
docs(memory): 记录插件 DLL 重链接需先关闭 CAD(无热重载)
|
2026-10-13 23:56:10 +08:00 |
|
gjm
|
40aff77dd1
|
feat(plugins): 截图前检测 CAD 窗口遮挡并自动置前
get_viewport_screenshot 使用 GDI 抓屏(GetDC+BitBlt 读屏幕内容),
若 CAD 窗口被其它窗口遮挡会截到遮挡窗口。现增加:
- IsWindowOccluded:客户区中心点经 WindowFromPoint 取顶层窗口,
根窗口不同即判定被遮挡。
- ForceWindowForeground:AttachThreadInput + SetWindowPos/BringWindowToTop/
SetForegroundWindow 强制置前,RedrawWindow(RDW_UPDATENOW) 同步重绘。
- Execute 中先检测遮挡/前台状态,必要时置前并 Sleep(120) 等 DWM 合成,
返回文本按「已置前」「仍被遮挡」给出提示。
|
2026-10-13 23:55:40 +08:00 |
|
gjm
|
ca17abadb6
|
Merge pull request 'feat(mcp): 基座换行分帧与 isError 映射;新增 dwg_review 审查 Agent' (#6) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/6
|
2026-10-13 23:49:17 +08:00 |
|
gjm
|
1cbcbb92f4
|
perf(review): 安装 Pillow 并优化截图下采样策略
- 视觉 token 成本由像素尺寸决定,故仅在长边超过 IMAGE_MAX_EDGE(默认1280) 时才缩放
- 不需要缩放且格式未变时原样返回,不重新编码,避免 CAD 线稿的无谓压缩损失
- 缩放后默认输出无损 PNG(IMAGE_FORMAT=png),可设 jpeg 换取更小体积
- 缺少 Pillow 时自动降级为原图直传
|
2026-10-13 23:48:46 +08:00 |
|
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 |
|
gjm
|
201191dc67
|
Merge pull request 'fix(mcp_frame): c++_dll 版本校验默认只比大版本,R24.3 单独分组' (#5) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: https://git.ethereal-realm.top/gjm/cad-agent/pulls/5
|
2026-10-09 23:44:59 +08:00 |
|
gjm
|
3b1cc88262
|
fix(mcp_frame): 补齐版本校验源码(上一提交因文件名大小写漏带)
2fa27b1 只带上了文档,未纳入源文件。此处补上 mcp_ConfigParser.cpp 的实际改动:
- acrxGetApiVersion 返回值按 (major<<16)|minor 拆分大/小版本;
- 默认只比大版本(同一大版本内二进制兼容);
- 例外 R24.3 与 R24.0~R24.2 因 MSVC toolset 不同,按 minor>=3 分组判定。
|
2026-10-09 23:42:31 +08:00 |
|
gjm
|
2fa27b1161
|
fix(mcp_frame): c++_dll 版本校验默认只比大版本,R24.3 单独分组
- acrxGetApiVersion 返回值编码为 (major<<16)|minor,据此拆分大/小版本
(实测 R22.0=0x160000、R23.0=0x170000)。
- 同一大版本内二进制兼容(R24.0/R24.1/R24.2 可共用 ARX;2019/R23.0 编的 ARX
可跑在 2020/R23.1 上),故默认只比大版本,避免为每个小版本各编一份。
- 唯一例外 R24.3:换了 MSVC toolset,与 R24.0~R24.2 不兼容,
对 major==24 再按 minor>=3 分组判定。
- 同步更新 CODEBUDDY.md 与 ai.memory 说明。
|
2026-10-09 23:42:05 +08:00 |
|
gjm
|
1c4160fa55
|
Merge pull request 'chore(memory): 沉淀基座 c++_dll 加载/执行的排查结论' (#4) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: #4
|
2026-10-09 22:38:08 +08:00 |
|
gjm
|
0b4ffdec0c
|
chore(memory): 沉淀基座 c++_dll 加载/执行的排查结论
- 新增 ai.memory/project_mcp_frame_dll_loader.md:
1) 运行时 acrxGetApiVersion() 有状态、不可用于版本比对;
2) DLL 工具写数据库需文档锁(应用上下文 → eLockViolation);
3) 同一 DLL 只加载一次(模块缓存)及代理不再 FreeLibrary 的原因。
- 更新索引 MEMORY.md;reference_environment.md 的 c++_dll 说明改为「只加载一次」
并指向新文件,测试脚本表补 verify_annotate.py。
- 修正 feedback_preferences.md 中 ai.memory「尚未入库」的过时说明。
|
2026-10-09 22:37:31 +08:00 |
|
gjm
|
1a454b96bf
|
Merge pull request 'feat(annotate): 新增图纸批注工具集(云线/文字/多段线/引线等 8 个工具)' (#3) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: #3
|
2026-10-09 22:34:45 +08:00 |
|
gjm
|
ec5f62670d
|
fix(mcp_frame): 修复 c++_dll 工具大量注册失败与写库被文档锁拦截
- 版本校验:基座侧改用编译期常量 (ARX<<16)|SUB_ARX,不再调用运行时的
acrxGetApiVersion()。该函数由 rxapi.lib 的 acrxGetApiVersionImpl 提供,
是有状态实现(读写进程内全局),返回值随调用次数变化;AutoCAD 加载 ARX
时已调用过一次,导致基座值与 DLL 值不等,绝大多数 DLL 工具被拒绝注册。
- 新增 DLL 模块缓存:同一 DLL 全进程只 LoadLibrary 一次,后续工具复用句柄
并跳过版本校验。
- 文档锁:mcp_Tool_DllProxy::Execute 统一 lockDocument/unlockDocument,
修复 DLL 工具在 AutoCAD 应用上下文写数据库返回 eLockViolation
(表现为 openWriteSpace 拿不到模型空间)的问题。
- 代理类不再 FreeLibrary 模块(改由模块缓存统一卸载),避免同一 DLL 的多个
工具重复释放、引用计数被打穿。
- 诊断日志精简为仅记录 arx_version/dll_version,且每次加载清空重写。
- 新增 verify_annotate.py:批注工具集运行时验证脚本(绘制/校验/改属性/清理)。
|
2026-10-09 22:31:49 +08:00 |
|
gjm
|
0bd290c96e
|
chore(memory): 记录 SSH 密钥变更(改用 id_ed25519_guojianming)
|
2026-10-09 15:19:02 +08:00 |
|
gjm
|
5b81a71be9
|
feat(annotate): 新增图纸批注工具集(云线/文字/多段线/引线等 8 个工具)
- 新增 dwg_annotate_common/draw/edit(命名前缀 dwg_annotate)
- 工具:draw_revision_cloud、add_text、add_mtext、add_polyline、
add_line、add_leader_annotation、delete_entities、set_entity_properties
- 批注默认落在 AI_REVIEW 图层(不存在则自动创建)
- 同步 cmakelists.txt 与 cad-mcp-frame.json(工具数 18 -> 26)
- 记录 UTF-8 BOM 编译约定到 ai.memory
|
2026-10-09 15:17:54 +08:00 |
|
gjm
|
ad11a1e1c4
|
Merge pull request 'chore(memory): 新增 ai.memory 记忆库' (#2) from home-lenovo-legion-r9000/home-ai-dev into main
Reviewed-on: #2
|
2026-10-09 09:48:01 +08:00 |
|
gjm
|
e25aa0a650
|
chore(memory): 新增 ai.memory 记忆库
- MEMORY.md 索引 + 分主题记忆文件
- project: 图纸审查 Agent 工作汇总
- feedback: 协作偏好(含 Git 推送规则:refs/for/main 触发 Gitea PR)
- reference: 环境与外部资源
|
2026-10-09 09:43:21 +08:00 |
|
gjm
|
da1545cbcf
|
Merge pull request '修改gitignore' (#1) from home-ai-dev into main
Reviewed-on: #1
|
2026-10-08 22:45:54 +08:00 |
|
gjm
|
30f568a033
|
修改gitignore
增加一些忽略类型
|
2026-10-08 22:39:26 +08:00 |
|
gjm
|
bdd77af041
|
feat(review): 新增图纸审查工具集与逐图框审查流程
向 MCP 基座注册 15 个 C++ 工具(cad_mcp_plugins.dll):
- 概览: get_drawing_info / get_layers / get_layouts
- 数据: query_entities / get_text_content / get_dimensions /
get_block_references / get_polylines_info / get_entity_detail
- 图框识别: detect_drawing_frames(块/闭合多段线/直线组三种形态,推算图幅)
- 检查: find_duplicate_entities / find_zero_length
- 视图: zoom_to_entity / zoom_to_window / highlight_entities
其它:
- 抽出 dwg_review_common 公共层(实体遍历 / handle / bbox / 分页 / 错误码)
- 工具返回统一为 MCP content 信封,与既有截图工具保持一致
- 新增 dwg_review_agent.py 逐图框审查脚本(deepseek-flash)
- 新增可配置审查清单 review_checklist.json
- 更新 cad-mcp-frame.json:合并视图工具与审查工具,共 18 个
- cmakelists 加入新增源文件
|
2026-10-08 15:21:23 +08:00 |
|
gjm
|
1afcc10a61
|
add
测试mcp基座
|
2026-10-06 23:10:38 +08:00 |
|
gjm
|
c0966ad334
|
refactor
重构以加强 abi 的兼容性
|
2026-10-03 00:24:32 +08:00 |
|
gjm
|
a7eaa8483f
|
add
增加了 plugin 工程
|
2026-10-02 23:43:18 +08:00 |
|
gjm
|
cf87cfe93d
|
refactor
修改了目录和部分源文件名称
|
2026-10-02 21:02:40 +08:00 |
|
gjm
|
1435b864f8
|
refactor
重构 mcp-server 功能
|
2026-10-02 20:39:34 +08:00 |
|
gjm
|
5d6f1c74d1
|
feat
搭建 mcp server+mcp plugin
|
2026-10-02 12:39:35 +08:00 |
|
gjm
|
09f9d69d36
|
fix
修正了mcp的主线程调用问题
|
2026-09-29 22:33:28 +08:00 |
|
gjm
|
1fdcdefef1
|
无
|
2026-09-28 22:13:47 +08:00 |
|
gjm
|
5289689737
|
mcp 功能初步
|
2026-09-28 22:09:19 +08:00 |
|
gjm
|
9c41e1d91c
|
新增工程cadproject
|
2026-09-28 21:19:38 +08:00 |
|