[Bug] 附件为 .docx/.pptx/.xlsx 时被降级为 local_ref/metadata_only,但仍生成空 file 内容块,导致会话永久 400
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 22
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
提交前确认 · Pre-submission checklist
- 我已搜索过现有 issue,确认这不是重复 / I searched existing issues and confirmed this isn't a duplicate.
- 我已阅读 CONTRIBUTING.md / I've read CONTRIBUTING.md.
问题类别 · Category
文件 / 项目操作 · File / Project ops
涉及的 Agent 框架 · Agent framework
ZCode Agent(自研)
严重程度 · Severity
阻塞使用 · Blocking (无法使用核心功能 / core function unusable)
复现频率 · Reproducibility
必现 · Always
问题描述 · Description
当附件是 .docx / .pptx / .xlsx 时,ZCode 将其降级为 local_ref / metadata_only(仅记录本地路径),
但构造上游请求时仍然生成了一个 file 类型的内容块,该块既无 file_id 也无 file_data,
导致自定义 Provider(OpenAI 兼容)返回 400 拒收。
更严重的是:由于每轮请求都会携带完整历史,一旦历史中存在这种空 file 块,
该会话之后任何消息(包括完全不相关的新提问)都会 400,且 UI 上没有移除该附件的入口,
会话实际上永久报废。本次受影响的会话已积累 666 条消息(历史 1150+ 条),只能作废。
根因:ZCode 按附件格式走了三条不同路径。从本地 part 表可以清楚看到:
| 附件格式 | metadata.storageKind | recoverability | 存储形态 | 发送结果 |
|---|---|---|---|---|
| .md / .txt | inline | provider_ready | metadata.preview 内含全文 | 正常 |
| .pdf / .png / .jpg | artifact | provider_ready | metadata.artifactUri,url=zcode-artifact:// | 正常 |
| .docx / .pptx / .xlsx | local_ref | metadata_only | 仅 url=本地路径 | 400 |
即:ZCode 对 Office 二进制格式既不提取文本内联,也不上传为 artifact,只留下一条本地路径引用,
却仍然为它生成了 file 内容块。metadata_only 这个标记本身就说明 ZCode 知道自己没有可发送的内容。
同一批附件中可以稳定复现对照:挂 .pdf + .md + .md + .pptx 四个附件时发送失败;
只删掉那个 .pptx、保留其余三个,立即发送成功。与网络、代理、模型通道、配额均无关
(只是自定义 Provider 的上游做了严格校验,把这个缺陷暴露了出来)。
相关 issue(已搜索确认非重复):
- #395 [Bug] 视频附件进入会话历史后每轮重发,持续触发 GLM 1210「视频数超限」——建议 consume-once / 占位符替代
→ 与本问题同构:都是「附件进入历史后每轮重发,持续触发上游错误」,只是触发物不同。
该 issue 提出的 consume-once / 占位符替代思路同样适用于这里。 - #244 粘贴的图片不保存为本地文件:纯文本模型返回 400
→ 同属「附件未正确落盘/内联即发送」导致 400 的一类问题。
已搜索 file must have a file_id、file_id、metadata_only、local_ref 等关键词,均无结果,未见重复报告。
复现步骤 · Steps to reproduce
- 打开 ZCode,进入任意会话,工作目录切到含本地文件的目录。
- 在输入框同时挂上 4 个附件:
- 02Nacos注册中心.pdf(PDF)
- 实训周记二.md(Markdown)
- 实训周记三.md(Markdown)
- 个人博客系统项目演示2.pptx(PowerPoint)
- 发送任意消息 → 发送失败,报 400(见「实际表现」)。
- 删掉那个 .pptx,只保留前 3 个附件,重新发送 → 发送成功。
- 回到步骤 3 的那条消息(或该会话任意位置),再次发送任意内容(哪怕是「你好」)→ 仍然 400。
期望表现 · Expected behavior
-
挂载 Office 格式(.docx/.pptx/.xlsx)附件时应当能正常发送;若该格式确实无法处理,
应在挂载当时就提示「该格式不支持」,而不是静默降级、等发送时才让整条请求失败。 -
发送前应当过滤掉 storageKind == local_ref / recoverability == metadata_only
且无 file_id/file_data 的 part,不要为它生成 file 块,降级为文本占位
(如 [附件不可用:<文件名>])。 -
或者真正读取本地文件 bytes 上传,保证 file 块至少带 file_data。
-
当上游返回指向历史中某条 message 的 invalid_request_error 时,应能定位并隔离该内容块,
允许用户「从该条之后继续」,而不是整个会话报废。 -
UI 上应提供「重试并移除附件」入口,让用户能自行摘除问题附件。
实际表现 · Actual behavior
发送时稳定报错:
Error from provider (Console Go): Upstream request failed:
[invalid_request_error] .messages[1114]: file must have a file_id or file_data
Turn execution failed
provider=87106480-3d00-46f9-9962-e8fddbe5801a
provider_code=invalid_request_error
model=deepseek-flash
reason=invalid_request status=400 retryable=false
后果:
- 该会话此后任何消息都会 400,换节点、换模型、重启 ZCode、停掉其它会话均无效。
- UI 上没有任何移除该附件的入口,用户只能放弃整个会话。
- 本地 part 表中共有 22 条 local_ref 附件,分布在多个会话,均存在同样风险。
ZCode 版本 · ZCode version
3.11.2.6792
设备 / 系统 / 浏览器 · Device / OS / Browser
Windows 11 家庭版 25H2(Build 26200.9445,64 位)/ ZCode 桌面版
截图 / 录屏 / 日志 · Screenshots / Recordings / Logs
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No source files or tests are named. Reproduce the failure with the listed PDF, Markdown, and PPTX attachments, then trace how local_ref/metadata_only parts become provider request content blocks. Done should prevent empty file blocks from causing 400 responses and leave the conversation usable, with regression coverage for the failing attachment combination.
Written by the indexing model from the issue text.
Assessment
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100