From 641c7d58aa197dad206d490d1f42e9dad8fe5a6b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 1 Jul 2026 14:07:44 +0800 Subject: [PATCH] =?UTF-8?q?fix(tools):=20look=5Fat=5Fimage/seedream=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=97=E5=AE=B9=E5=99=A8=20/workspace=20=E7=BB=9D?= =?UTF-8?q?=E5=AF=B9=E8=B7=AF=E5=BE=84(bump=200.34.6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docker backend 下系统提示告知主模型一切在 /workspace 下,模型自然产出 /workspace//x 绝对路径,但 image_ref.resolve_in_root 不翻译该前缀, 报「图片找不到或越界」。加容器根前缀翻译(与 send_email 的 _resolve_user_file 一致),按字符串前缀判断而非 is_absolute()(Windows 上 /workspace 缺盘符不算 绝对);越界仍靠 relative_to(root) 兜住。 Co-Authored-By: Claude Opus 4.8 (1M context) --- PROGRESS.md | 5 ++++- core/__init__.py | 2 +- tools/image_ref.py | 16 +++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/PROGRESS.md b/PROGRESS.md index 23a2101..12254a7 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-07-01(ppt skill 工作目录重构:中间物收进隐藏 .build/ + 反卡片映射 + svg_preview 兜底/gate + bump 0.34.0) +最后更新:2026-07-01(修 look_at_image/seedream 拒收容器 `/workspace` 绝对路径 + bump 0.34.6) --- @@ -21,6 +21,9 @@ ## 已完成关键能力 +### 2026-07-01 / 修 look_at_image/seedream 拒收容器绝对路径(bump 0.34.6) +现象:docker backend 下主模型被系统提示告知一切都在 `/workspace` 下,自然产出容器绝对路径(如 `/workspace/ppt生成2/ceramic-node/images/cover_bg.png`)喂给 `look_at_image`,却报「图片找不到或越界」,只有改成 working_dir 相对路径才成功。根因:`tools/image_ref.py resolve_in_root`(look_at_image + seedream 共用)只吃「working_dir 相对 / user_root 相对 / 宿主绝对」三形态,唯独不把 `/workspace/` 翻回宿主 `user_root/`——而 host-side 的 send_email 早在 `Tool._resolve_user_file` 做了这翻译。改动:`resolve_in_root` 加容器根(`/workspace`)前缀翻译,**按字符串前缀判断而非 `is_absolute()`**(Windows 上 `/workspace/...` 缺盘符不算绝对);越界仍靠原 `relative_to(root)` 兜住(`/workspace/../secret`、`/workspace/../../etc/passwd` 实测仍拒)。这样 look_at_image/seedream 接受的路径形态与 send_email/wechat_push 及系统提示告诉 agent 的口径一致。 + ### 2026-07-01 / admin 各用户用量加「最近使用」列(bump 0.34.3) 用户需求:admin 页面「各用户用量」表加一列展示每个用户的最近使用时间。改动:`web/admin.py _user_usage_page` 加一个**全量**(不随 range 筛选)的相关子查询 `max(usage_events.created_at)`,新字段 `last_used_at`(ISO 或 null);语义上刻意用全量而非跟着 range 走的 join——否则选 7d/30d 会把更早的真实 last-used 藏掉,列就失去意义。前端 `admin.js renderUserUsage` 加「最近使用」表头 + 单元格,用 `fmtTimeAgo`(相对时间)展示、`fmtTime` 全时间戳作 title 悬浮,无用量用户显示「—」;colspan 7→8。 diff --git a/core/__init__.py b/core/__init__.py index a7ea280..425b1bf 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,3 +1,3 @@ # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # 改版本只动这一行。 -__version__ = "0.34.3" +__version__ = "0.34.6" diff --git a/tools/image_ref.py b/tools/image_ref.py index a05059b..fa01069 100644 --- a/tools/image_ref.py +++ b/tools/image_ref.py @@ -22,14 +22,28 @@ REF_MIME = { } MAX_IMAGE_BYTES = 10 * 1024 * 1024 # 单图 10MB(ARK 约束) +# docker 沙箱把 user_root bind 到容器内 `/workspace`(见 tools/base.py 同名常量)。 +# docker backend 下主模型被告知一切都在 `/workspace` 下,故它自然产出容器绝对路径 +# `/workspace//x`。look_at_image / seedream 在宿主进程读文件,需和 send_email +# 的 _resolve_user_file 一样把这前缀翻回宿主 user_root,否则宿主上找不到文件。 +_CONTAINER_ROOT = "/workspace" + def resolve_in_root( rel: str, working_dir: Path, user_root: Optional[Path] ) -> Optional[Path]: """三形态解析 + user_root 边界校验。命中返回解析后的绝对 Path,否则 None。""" + rel = (rel or "").strip() p = Path(rel) candidates: list[Path] = [] - if p.is_absolute(): + is_container = rel == _CONTAINER_ROOT or rel.startswith(_CONTAINER_ROOT + "/") + if user_root is not None and is_container: + # 容器绝对路径 `/workspace/` → 翻回宿主 `user_root/`(docker bind)。 + # 注意:Windows 上 `/workspace/...` 不被 is_absolute() 认作绝对(缺盘符),故按 + # 字符串前缀判断、与宿主 OS 无关;越界仍靠下方 relative_to(root) 兜住。 + candidates.append(user_root / rel[len(_CONTAINER_ROOT):].lstrip("/")) + candidates.append(p) # 兼容 tool 真在容器内跑(/workspace 实存) + elif p.is_absolute(): candidates.append(p) else: candidates.append(working_dir / rel)