---
description: "持久图片与文件附件，供用户与维护者在提示词与命令中附加、复用或排查上传内容。"
kind: "package-reference"
---

# @deepseek-ai/dsh-attachment

[English](README.md) | 中文

## 概述

把图片与通用文件附加到提示词和命令中，同一会话重启后仍可复用；随附的 `dsh` 组合无需额外配置。图片会在消息被接受前完成校验与规范化；部署限额内支持 PNG、JPEG、WebP 和 GIF。其他文件按字节原样保存，不设格式与大小限制；模型通过保存的只读路径按需读取，而不接收文件字节。持久会话事件不包含浏览器路径、提供方 URL、本地存储路径和 base64。已存储附件不会被自动删除；音频和视频暂无专门处理。

## 目录

- [使用本包](#use-this-package)
- [理解实现](#understand-the-implementation)
- [进一步探索](#further-exploration)
- [模型体验](#model-experience)
- [已知限制与延期工作](#known-limitations-and-deferred-work)
- [开发备注](#dev-note)

-----

<a id="use-this-package"></a>
## 使用本包

图片附件端到端可用：把图片附加到提示词或命令，它会自动保存、显示在历史中并发送给模型，无需你再做任何操作。在默认 `dsh` 组合中一切都已接好；自行组合时，一个插件即可启用该能力。

### 在提示词中附加图片

在客户端 UI 中向用户提示词附加一张或多张图片。每个源图都会在你的消息被处理前接受检查、规范化为提供方无关的 8-bit sRGB/sRGBA 光栅并保存；如果任何一张图片被拒绝，整条消息都会失败且不会发布任何内容。支持的源格式为 PNG、JPEG、WebP 与 GIF；部署方分别控制源图限制、规范化存储限制与路由专用请求限制。下面这一个插件即可启用持久图片附件（随附的 base 组合已经挂载它）：

```yaml
- name: '@deepseek-ai/dsh-attachment-local'
```

### 在提示词中附加任意其他文件

任何非图片文件都以通用文件的形式附加到提示词：确切字节被只读保存在 harness 主目录下，消息记录文件名、字节数与内容摘要，模型收到一行指出保存路径的文本，只在需要时用文件工具读取内容。没有文件类型白名单，也没有大小上限；你附加什么就原样存什么。

### 把附件传给命令

声明接受附件的命令会按选择顺序接收图片与通用文件。不接受附件的命令会返回错误，并保留 composer 的草稿与附件卡。

### 在整个会话中复用图片

已保存的规范化图片会保留在对话历史中，并在后续轮次投影为确定性的路由尺寸请求版本；重启后，恢复的会话会显示并复用相同的图片。当前执行文件系统可以映射已存宿主对象时，请求描述符还会携带模型可检查的只读进程路径。回读历史或请求版本时，已存储的字节会与记录的内容比对，因此缺失、损坏或被替换的图片会以错误形式呈现，而不是错误的字节。

### 可能出什么问题

附加图片时可能被拒绝——格式不受支持、超出大小、像素或尺寸限制，或者字节与声明类型不符——此时整条消息失败。之后，如果磁盘上的图片被删除或损坏，历史读取也可能失败。失败带有稳定错误码，客户端与协议适配器可以用自己的措辞解释它们。

-----

<a id="understand-the-implementation"></a>
## 理解实现

<details>
<summary>实现细节——点击展开</summary>

本节解释 seam 背后的设计决策，以及实现用户可见行为的服务操作；可观察行为已在[使用本包](#use-this-package)中完整说明。

### 设计决策

- **事件前完成规范化与持久化。** 每个源图都会在批次按序发布前完成准备与校验，因此会话日志绝不会引用部分完成或规范化失败的对象。
- **不可变且保留策略中立。** 对象一经发布即不可变；恢复和 fork 后的会话可能共享它们，因此引用感知的垃圾回收被推迟，而不是与任何单个会话的删除绑定。
- **读取时校验。** 读取在返回前把字节和元数据与记录的引用比对，请求投影还会完整解码缓存字节，因此缺失、损坏或被替换的对象都会失败关闭。
- **角色无关的图片块。** `dsh-llm` 中的 `ImageBlock` 内容块携带 `ImageAttachmentRef`；提供方适配器以显式像素与字节预算把引用解析为确定性请求版本，执行文件系统则可以把不可变宿主对象映射为模型可读的进程路径。
- **按错误码路由。** `AttachmentError` 重新实现 `HarnessError` 的结构而不是继承它，因为基类位于 `dsh-llm`，而后者依赖本包；消费方用 `isAttachmentError` 识别错误并按 `code` 路由，绝不依赖原型链。
- **文件原样，图片规范化。**`saveFile` 提交已有字节数组，`saveFileStream` 以背压和取消语义提交有界分块，`readFileStream` 校验并返回有界分块，`fileHostPath` 定位存储对象供按需读取投影；两种文件写入路径都不设准入限制。图片路径保留其独立的规范化、限额与请求版本流水线。`dsh-llm` 中的 `FileBlock` 内容块承载 `FileAttachmentRef`，请求组装把它对每条路由都投影成确定性 handle 文本。

### 服务操作

服务族运行同一条准入与存储流程：每个入口都强制执行源批次限制与规范 base64，在发布任何成员前准备提供方无关的规范化附件，再按输入顺序持久提交而不产生部分结果。Host prompt 消费方把有序文本、编码图片和已经解析的文件引用交给 `ctx.attachments.admitPromptContent()`；该方法持久化图片，并让文件引用原样通过。编码协议适配器调用 `ctx.attachments.admitEncodedFile()`，由该方法检查规范 base64 后委托给 `saveFile`；适配器通过 `ctx.attachments.isAttachmentError()` 识别附件错误。通用文件调用方可以用 `saveFile` 提交已有字节，或用 `saveFileStream` 提交有界异步字节源；两者返回相同的持久引用，`readFileStream` 则在有界读取过程中校验摘要与长度。`readImageRequest` 派生确定性的路由尺寸变体，其身份包含附件 id、变换版本、像素与字节预算及编码参数。纯函数导出 `requestImageDimensions` 会按总像素预算计算每个投影保持宽高比的尺寸，使提供方与请求定价共享同一套几何计算。`imageHostPath` 只向需要执行世界映射的受信任同进程消费方暴露实现拥有的宿主位置。调用方组合有序批次，而实现拥有压缩并发、缓存与 singleflight。读取、流式写入和投影保留调用方的取消语义。失败带有稳定且机器可读的错误码，运行时即可识别可由调用方修正的准入子集，让每个协议适配器映射自己的词汇；各操作的确切约定见 [`src/index.ts`](src/index.ts) 与 [`src/error.ts`](src/error.ts)。

### 源码地图

| 文件 | 职责 |
|---|---|
| [`src/index.ts`](src/index.ts) | 插件入口：抽象 `AttachmentStore` 服务与再导出 |
| [`src/types.ts`](src/types.ts) | 持久词汇：引用、限额、上传与存储载荷 |
| [`src/admission.ts`](src/admission.ts) | 对编码图片和文件上传强制执行规范 base64 并委托存储 |
| [`src/error.ts`](src/error.ts) | `AttachmentError` 类与 `isImageAdmissionError` 运行时子集 |
| [`src/brand.ts`](src/brand.ts) | `AttachmentId` 带类型标记的不透明标识符 |
| — | 不发布运行时不变式伴生入口；实现负责强制不可变存储检查。 |

</details>

-----

<a id="further-exploration"></a>
## 进一步探索

完整的服务约定与载荷类型请看子系统参考；支撑这一能力的存储请看本地后端。

- [附件子系统参考](../../../docs/subsystems/attachment.zh.md)——服务约定、载荷类型与 `ctx.attachments` 的 cordis 接口面。
- [本地文件系统后端](../attachment-local/README.zh.md)——你的附加图片在本机上的存储位置。
- [能力 seam](../../../docs/capability-seams.zh.md)——本能力家族如何拆分为多个角色。

-----

<a id="model-experience"></a>
## 模型体验

该包通过提供方适配器间接影响模型；适配器会把每个持久图片引用解析为确切请求版本，并在图片旁发送稳定附件 id 与实际尺寸。执行文件系统可以映射已存对象时，描述符还会包含只读进程路径，以及可写副本使用的匹配扩展名。通用文件的字节永远不会到达提供方：每条路由都收到一行确定性 handle 文本，指出文件名、字节数、摘要前缀，以及供文件工具读取的只读保存路径。

#### KV Cache 影响

添加图片会改变提供方请求，因此会使受影响的请求后缀失效。

## 已知限制与延期工作

<a id="known-limitations-and-deferred-work"></a>


这些限制描述了附件能做什么、不能做什么；它们是当前包约束，而非任务积压。

- **光栅图片限制只作用于图片**——图片接受部署限额内的 PNG、JPEG、WebP 与 GIF；其他任何文件都原样保存、不设类型与大小限制，音频和视频暂无专门处理。
- **附件永远不会被删除**——已存储的图片与文件无限期保留；没有任何机制自动移除它们。
- **未发送的草稿不会保存**——输入区草稿在提交消息前一直留在浏览器中。

<a id="dev-note"></a>
### 开发备注

<details>
<summary>维护者的工作上下文——点击展开</summary>

本开发备注是维护者的工作上下文：尚未决定的探索方向与开放问题。它明确不具权威性——已交付的行为与限制以上文和包代码为准。

#### 未来：引用感知的垃圾回收

恢复和 fork 后的会话可能共享不可变对象，因此任何保留策略都需要一个能考虑会话血缘的引用模型，之后才能回收对象。目前尚未记录任何决定；本地后端当前保留一切。

#### 未来：音频、视频与助手侧输出

音频与视频需要原样文件路径之外的专门生命周期与提供方契约；角色无关的 `ImageBlock` 也把助手侧图片输出留作前瞻兼容——当前生产适配器声明只输出文本，因此只有用户内容携带图片。两个方向都尚未决定。

</details>
