# Conflicts: # .agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.i18n.yaml # docs/config-catalog.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/core.md # docs/core-data-structures/core.zh.md # docs/core-data-structures/llm-streaming.i18n.yaml # docs/core-data-structures/llm-streaming.md # docs/core-data-structures/llm-streaming.zh.md # docs/event-producer-consumer.md # docs/module-graph.md # docs/subsystems/attachment.i18n.yaml # docs/subsystems/attachment.md # docs/subsystems/attachment.zh.md # docs/subsystems/core.i18n.yaml # examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl # packages/README.i18n.yaml # packages/README.md # packages/README.zh.md # packages/client/runtime/package.json # packages/client/ui-conversation/package.json # packages/client/ui-conversation/src/client/chat/AssistantMarkdown.tsx # packages/client/ui-conversation/src/client/chat/ChatView.tsx # packages/client/ui-conversation/src/client/chat/MessageItem.tsx # packages/client/ui-conversation/src/client/index.ts # packages/client/ui-conversation/tests/input-bar.spec.tsx # packages/compact/compact-basic/README.i18n.yaml # packages/compact/compact-basic/README.md # packages/compact/compact-basic/README.zh.md # packages/host/apiproxy/src/api-proxy.ts # packages/host/apiproxy/src/api/index.ts # packages/host/apiproxy/src/api/sessions.ts # packages/host/apiproxy/src/index.ts # packages/host/apiproxy/tests/api-proxy-models.spec.ts # packages/self-modification/tool-cordis/src/api-catalog.ts # pnpm-lock.yaml # scripts/type-equiv.manifest.json
5.3 KiB
持久图片附件
English | 中文
附件 seam 将二进制图片的所有权与会话日志分离。生成方把经过校验的编码字节交给 ctx.attachments;只有对象完成持久化后,该服务才会发布不可变的内容寻址引用。会话事件和模型可见的 ImageBlock 包含该引用及其元数据,绝不包含浏览器对象 URL、宿主临时路径、提供方 URL 或 base64 数据。
未发送的浏览器草稿可以保留在内存中,原生客户端也可以将其暂存于操作系统临时存储。宿主接受用户消息后,会先把消息中的图片移到 <DSH_HOME>/attachments/v1 下,再追加用户事件。结构化模型图片输出遵循同样的先持久化、后追加事件规则。
来源:packages/attachment/attachment/src/types.ts
标识与经过校验的元数据
AttachmentId 是带类型标记的不透明字符串。本地后端目前生成 sha256:<digest>,但消费方既不能解析这种表示,也不能据此派生文件系统路径。
/** Raster image formats accepted by the version-one attachment path. */
type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'
/** Durable, serializable metadata for one immutable image object. */
interface ImageAttachmentRef {
/** Opaque storage identifier; never a filesystem path or bearer URL. */
attachmentId: AttachmentId
/** Media type verified from the stored bytes. */
mediaType: ImageMediaType
/** Exact encoded byte length. */
bytes: number
/** Intrinsic encoded width in pixels. */
width: number
/** Intrinsic encoded height in pixels. */
height: number
/** Optional display name stripped of local path information. */
name?: string
}
/** Deployment-resolved limits used by upload admission and request buffering. */
interface ImageAttachmentLimits {
maxImageBytes: number
maxImagesPerMessage: number
maxMessageImageBytes: number
maxImagePixels: number
mediaTypes: readonly ImageMediaType[]
}
引用记录固有尺寸和编码长度,使客户端无需先解码即可排布历史记录;每次权威读取仍会根据对象重新校验摘要、媒体签名、尺寸和元数据。
提交与校验读取的数据
/** Request to validate and durably commit one image. */
interface SaveImageAttachment {
data: Uint8Array
/** Caller-declared media type, checked against fully decoded bytes. */
mediaType: ImageMediaType
/** Optional browser/provider display name; it is never interpreted as a path. */
name?: string
}
/** Stored image bytes returned after reference and digest verification. */
interface StoredImageAttachment {
ref: ImageAttachmentRef
data: Uint8Array
}
saveImage() 校验字节并以原子方式提交一个对象,之后才返回其引用。validateImage() 执行相同的准入检查,但不持久化任何内容;批量调用方会在保存任何成员前通过它校验所有成员,因此校验拒绝不会留下部分对象。readImage() 接受来自已授权会话路径的引用,只在完整性校验通过后返回字节。该服务刻意不规定保留策略:恢复和 fork 后的会话可能共享对象,因此基于引用的垃圾回收会延期实现,而不是与任何一个会话的删除绑定。
Cordis surface
Generated from source by scripts/gen-cordis-catalog.ts (verified fresh by pnpm run verify-cordis-catalog in doc-sync; regenerate with pnpm run gen-cordis-catalog) — this section is byte-identical in both language sides of the page. Signature blocks use a ts cordis-catalog fence and keep the original source JSDoc; dispatch modes are defined in the primer, and the framework-inherited ctx surface lives in cordis-api/inherited.md.
ctx.attachments — AttachmentStore (abstract seam)
Immutable binary attachment service. Implementations validate bytes before publishing a reference.
/**
* Validate one image without persisting it.
* Batch callers validate every member before saving any member.
* @param input - encoded bytes, declared media type, and optional display name.
* @returns completion after the encoded raster has been fully decoded.
*/
abstract validateImage(input: SaveImageAttachment): Promise<void>
/**
* Validate and durably commit one image before its owning session event is appended.
* @param input - encoded bytes, declared media type, and optional display name.
* @returns a durable content-addressed reference.
*/
abstract saveImage(input: SaveImageAttachment): Promise<ImageAttachmentRef>
/**
* Read one image and verify that bytes still match the recorded reference.
* @param ref - durable reference from the session log.
* @returns the verified bytes and canonical reference.
*/
abstract readImage(ref: ImageAttachmentRef): Promise<StoredImageAttachment>