fix(tools): look_at_image/seedream 接受容器 /workspace 绝对路径(bump 0.34.6)
docker backend 下系统提示告知主模型一切在 /workspace 下,模型自然产出 /workspace/<wd>/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) <noreply@anthropic.com>
This commit is contained in:
parent
eb9ffd654f
commit
641c7d58aa
|
|
@ -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/<rest>` 翻回宿主 `user_root/<rest>`——而 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。
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
||||
# 改版本只动这一行。
|
||||
__version__ = "0.34.3"
|
||||
__version__ = "0.34.6"
|
||||
|
|
|
|||
|
|
@ -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/<wd>/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/<rest>` → 翻回宿主 `user_root/<rest>`(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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue