Skip to content

feat: render, edit and open message attachments (v1.2.0) - #5

Closed
TacKana wants to merge 1 commit into
SpookySandwich:masterfrom
TacKana:feat/attachments-edit-and-open
Closed

TacKana wants to merge 1 commit into
SpookySandwich:masterfrom
TacKana:feat/attachments-edit-and-open

Conversation

@TacKana

@TacKana TacKana commented Sep 22, 2026 •

Copy link
Copy Markdown

本变更内容

在 v1.1.0 基础上,围绕消息附件有三项变更。

1. 文件附件此前不可见(修复)

plugin.client.js 以优先级 -1 遮蔽了宿主的用户气泡,因此由它负责内容渲染——而它只理解 text 和 image。一个 file 块没有命中任何分支:带 .log 或 .json 附件的消息只显示其文本,既没有卡片也没有错误。

现在它镜像宿主自己的 contentParts 拆分:

  • 图像继续走 conversation.message.images 插槽;
  • file 块渲染为宿主的文件卡片(类型图标、名称、EXT SIZE),由平台预置的 @deepseek-ai/dsh-client-ui-primitives 原子组件构建;
  • 此渲染器不认识的块类型会回退到宿主的 JsonBlock,而不是被丢弃;
  • 附件保持其原始块顺序,位于气泡上方,与宿主的布局方式一致。

2. 编辑框可以管理附件集(功能)

  • 每个附件都是可移除的 chip(图片缩略图,或带上传进度和重试路径的文件卡片);回形针、文件选择器和拖放目标可添加新附件。
  • POST /message-tree 接受有序的 attachments 数组:持久引用直接通过,暂存上传回执通过文件上传服务解析,新添加的图片由 attachments.admitPromptContent 接纳。省略该数组会保留原始附件,因此旧客户端不受影响。
  • 上传接受客户端服务返回的两种形状(原始浏览器路由返回 { ok, value } 信封,远程回退返回裸值)。只读取第二种会让回执变成 undefined,JSON.stringify 丢弃该键,宿主以请求体格式错误为由拒绝整个请求。

3. 点击文件卡片即可打开(功能)

GET /message-tree/attachment 通过 attachments.fileHostPath 将一个已存储引用解析为其宿主路径,卡片会把 harness 为其自身文件卡片构建的同一个 dsh-resource://file/session/… 地址交给右侧栏,以便侧栏的文档预览(文本、代码、PDF、图像)读取它。该引用通过 store 传递,store 会验证摘要和显示名称,因此伪造的名称永远不会变成路径。

一个值得写下来的 DSH 约束

conversation.input.attachments 由 composer 的入口声明,而插槽注册表(dsh-client-ui-slots、register)只允许恰好一个入口声明子插槽。本分支的第一个修订版也声明了它,注册抛出异常,整个用户视图也随之消失——编辑按钮、版本环和卡片都一样。现在,当第一次尝试被拒绝时,气泡会在不带该栏的情况下进行第二次注册。如果将来想从另一个组件复用 composer 的草稿栏,那么这条单一声明者规则就是需要重新审视的地方。

验证

  • npm test:90 项测试通过(客户端渲染、可编辑附件集、保留的引用/暂存回执/编码图像/拒绝、上传信封处理、子插槽冲突、附件路径解析、路径遍历拒绝、侧栏地址语法)。客户端测试还会在出现 React key 警告时失败。
  • npm run check:package:打包归档仍只包含 13 个运行时文件。
  • 真实 DSH 0.1.5-rc.2、隔离的 Web 配置环境、本地离线模型适配器(无远程模型调用):附件渲染;在编辑框中移除/上传(包括一次失败的上传及其重试);上传路由返回 { ok, value: { receiptId, file } };一次编辑提交该回执,并且分支发布 file(sha256:…) + text;以及附件路由将一个真实存储的文件解析为会话文件系统可读取的路径。
  • 版本已提升到 1.2.0,并带有 .github/release-notes/v1.2.0.md,与 v1.1.0 的发布方式一致。如果你更愿意自己来做版本提升,说一声,我就把它去掉。

The shadowed user-message renderer only understood text and image blocks, so a
file attachment disappeared from the transcript entirely. It now renders every
attachment the host renders — images through the images slot, files as cards
built from the platform-seeded client atoms, unknown block types as the host's
JSON inspector — and the same edit box manages the message's attachment set.

Attachment display
- Render file attachments as file cards (type icon, name, extension, size) in
  the host's own attachment-row layout, preserving block order.
- Degrade to a name-only card when the host atoms are unavailable, and to the
  JSON inspector for a block type this renderer does not know.

Editable attachments
- The edit box lists the message's attachments as removable chips (image
  thumbnails, file cards with upload progress and retry); the paperclip, the
  file picker and a drop target add new ones.
- `POST /message-tree` accepts an ordered `attachments` array: durable
  references pass through, a staged upload receipt resolves through the
  file-upload service, and a newly added image is admitted by the attachment
  store. An omitted array keeps the original attachments.
- Uploads read the client service's `{ ok, value }` result envelope as well as
  its bare value; reading only one left the receipt undefined and JSON dropped
  the key, which the host rejected as a malformed request body.

Open a file attachment
- `GET /message-tree/attachment` resolves one stored reference to its host
  path through the attachment store, which validates the digest and display
  name, so a forged name cannot become a path.
- Transcript file cards open that path in the harness's right sidebar through
  the `dsh-resource://file/session/…` address the sidebar's document preview
  reads.

Registration no longer risks the whole view: `conversation.input.attachments`
belongs to the composer's entry, and a child slot may have exactly one
declaring entry, so the bubble is registered a second time without the rail
instead of losing the edit button.

Tests cover attachment rendering, the editable set (kept references, staged
receipts, encoded images, refusals), upload-result envelope handling, the
child-slot collision, attachment-path resolution and traversal refusal, and the
sidebar address grammar. Client tests fail on React key warnings.
@TacKana

TacKana commented Sep 22, 2026 •

Copy link
Copy Markdown
Author
image image image

修复了这个插件引发的 bug:
发送消息不显示附件内容


  1. 增加了编辑消息时可以上传或者删除附件
  2. 点击附件时可以显示附件内容

@TacKana TacKana closed this by deleting the head repository Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant