@deepseek-ai/dsh-attachment 0.0.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, DeepSeek
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,6 @@
1
+ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
+ # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
+ # after editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/attachment/attachment/README.md
5
+ README.md: 4f450316294e554396adb9a8454051a08d9befd3
6
+ README.zh.md: fe51b0003cdf1659c7c56106b97c6f3139ebe890
package/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # @deepseek-ai/dsh-attachment
2
+
3
+ English | [中文](README.zh.md)
4
+
5
+ The durable attachment seam. `ctx.attachments` validates and atomically commits immutable image bytes, then returns a serializable `ImageAttachmentRef`; consumers never persist browser paths, object URLs, provider URLs, or base64 in session events.
6
+
7
+ Unsent composer images remain browser-owned temporary drafts. `validateImage` runs the same admission policy without persisting; batch writers validate every member first so a malformed member cannot strand earlier members as unreferenced objects. `saveImage` commits each accepted image before any model-visible session event is published, and `readImage` verifies the content-addressed object against its logged metadata.
8
+
9
+ ## Model Experience
10
+
11
+ Indirectly, through the role-neutral core `ImageBlock` and provider adapters that resolve its durable reference.
12
+
13
+ #### KV Cache effect
14
+
15
+ Adding an image changes the provider request and therefore invalidates the affected request suffix.
16
+
17
+ ## Known Limitations and Deferred Work
18
+
19
+ - Version one accepts PNG, JPEG, WebP, and GIF only.
20
+ - Retention and garbage collection are deferred because resumed and forked sessions may share immutable objects.
21
+ - Generic files, audio, video, and persistent unsent drafts require separate lifecycle and provider contracts.
package/README.zh.md ADDED
@@ -0,0 +1,21 @@
1
+ # @deepseek-ai/dsh-attachment
2
+
3
+ [English](README.md) | 中文
4
+
5
+ 持久附件服务边界。`ctx.attachments` 校验并以原子方式提交不可变图片字节,随后返回可序列化的 `ImageAttachmentRef`;消费方绝不会在会话事件中持久保存浏览器路径、对象 URL、提供方 URL 或 base64。
6
+
7
+ 未发送的输入区图片仍是由浏览器持有的临时草稿。`validateImage` 运行相同的准入策略,但不执行持久化;批量写入方会先校验每个成员,避免某个格式错误的成员使较早的成员成为无引用对象。`saveImage` 会在发布任何模型可见的会话事件前提交每张已接受的图片,`readImage` 则根据已记录的元数据校验内容寻址对象。
8
+
9
+ ## 模型体验
10
+
11
+ 该包通过角色无关的核心 `ImageBlock`,以及解析其持久引用的提供方适配器,间接影响模型。
12
+
13
+ #### KV 缓存影响
14
+
15
+ 添加图片会改变提供方请求,因此会使受影响的请求后缀失效。
16
+
17
+ ## 已知限制与待完成工作
18
+
19
+ - 第一版仅接受 PNG、JPEG、WebP 和 GIF。
20
+ - 保留策略与垃圾回收尚未实现,因为恢复和 fork 后的会话可能共享不可变对象。
21
+ - 通用文件、音频、视频和持久的未发送草稿需要单独的生命周期与提供方契约。
package/lib/index.js ADDED
@@ -0,0 +1,48 @@
1
+ import { Service } from "@deepseek-ai/cordis";
2
+ //#region lib/types/brand.js
3
+ /** Attachment identifier brand. @module @deepseek-ai/dsh-attachment/brand */
4
+ /**
5
+ * Brand a validated storage identifier.
6
+ * @param value - backend-produced opaque identifier.
7
+ * @returns the branded identifier.
8
+ */
9
+ function AttachmentId(value) {
10
+ return value;
11
+ }
12
+ //#endregion
13
+ //#region lib/types/error.js
14
+ /** Attachment failure class. @module @deepseek-ai/dsh-attachment/error */
15
+ /**
16
+ * Stable failures suitable for host RPC error mapping.
17
+ *
18
+ * Deliberately re-implements the `HarnessError` shape instead of extending it:
19
+ * the base lives in `@deepseek-ai/dsh-llm`, which itself depends on this
20
+ * package (`ImageBlock` references `ImageAttachmentRef`), so sharing the base
21
+ * would create a dependency cycle. Consumers route on `code`, never on the
22
+ * prototype chain, so the shapes stay interchangeable at the wire boundary.
23
+ */
24
+ var AttachmentError = class extends Error {
25
+ /** Stable machine-routing failure code. */
26
+ code;
27
+ /**
28
+ * @param message - human-readable failure description without raw bytes or host paths.
29
+ * @param code - stable machine-routing code.
30
+ * @param options - optional chained cause.
31
+ */
32
+ constructor(message, code, options) {
33
+ super(message, options);
34
+ this.name = "AttachmentError";
35
+ this.code = code;
36
+ }
37
+ };
38
+ //#endregion
39
+ //#region lib/types/index.js
40
+ /** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */
41
+ /** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */
42
+ var AttachmentStore = class extends Service {
43
+ constructor(ctx) {
44
+ super(ctx, "attachments");
45
+ }
46
+ };
47
+ //#endregion
48
+ export { AttachmentError, AttachmentId, AttachmentStore, AttachmentStore as default };
@@ -0,0 +1,17 @@
1
+ //#region lib/types/invariant.js
2
+ /** Package-owned invariant companion for `@deepseek-ai/dsh-attachment`. @module @deepseek-ai/dsh-attachment/invariant */
3
+ const PACKAGE_NAME = "@deepseek-ai/dsh-attachment";
4
+ /** Cordis companion plugin name. */
5
+ const name = "attachment-invariant";
6
+ /** Service required before package ownership can be reserved. */
7
+ const inject = ["invariants"];
8
+ /** No runtime invariant: this stateless seam owns types while implementations enforce immutable-store checks. */
9
+ const install = () => {};
10
+ /**
11
+ * Register the package invariant companion.
12
+ * @param ctx - Cordis context carrying the invariant service.
13
+ * @returns the registration disposer.
14
+ */
15
+ const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
16
+ //#endregion
17
+ export { apply, inject, name };
@@ -0,0 +1,11 @@
1
+ /** Attachment identifier brand. @module @deepseek-ai/dsh-attachment/brand */
2
+ import type { Branded } from '@deepseek-ai/dsh-brand';
3
+ /** Opaque content-addressed identifier for one immutable attachment object. */
4
+ export type AttachmentId = Branded<'AttachmentId'>;
5
+ /**
6
+ * Brand a validated storage identifier.
7
+ * @param value - backend-produced opaque identifier.
8
+ * @returns the branded identifier.
9
+ */
10
+ export declare function AttachmentId(value: string): AttachmentId;
11
+ //# sourceMappingURL=brand.d.ts.map
@@ -0,0 +1,21 @@
1
+ /** Attachment failure class. @module @deepseek-ai/dsh-attachment/error */
2
+ /**
3
+ * Stable failures suitable for host RPC error mapping.
4
+ *
5
+ * Deliberately re-implements the `HarnessError` shape instead of extending it:
6
+ * the base lives in `@deepseek-ai/dsh-llm`, which itself depends on this
7
+ * package (`ImageBlock` references `ImageAttachmentRef`), so sharing the base
8
+ * would create a dependency cycle. Consumers route on `code`, never on the
9
+ * prototype chain, so the shapes stay interchangeable at the wire boundary.
10
+ */
11
+ export declare class AttachmentError extends Error {
12
+ /** Stable machine-routing failure code. */
13
+ readonly code: string;
14
+ /**
15
+ * @param message - human-readable failure description without raw bytes or host paths.
16
+ * @param code - stable machine-routing code.
17
+ * @param options - optional chained cause.
18
+ */
19
+ constructor(message: string, code: string, options?: ErrorOptions);
20
+ }
21
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1,38 @@
1
+ /** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */
2
+ import { Context, Service } from '@deepseek-ai/cordis';
3
+ import type { ImageAttachmentLimits, ImageAttachmentRef, SaveImageAttachment, StoredImageAttachment } from './types.ts';
4
+ export { AttachmentId } from './brand.ts';
5
+ export { AttachmentError } from './error.ts';
6
+ export type { AttachmentId as AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef, ImageMediaType, SaveImageAttachment, StoredImageAttachment, } from './types.ts';
7
+ declare module '@deepseek-ai/cordis' {
8
+ interface Context {
9
+ attachments: AttachmentStore;
10
+ }
11
+ }
12
+ /** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */
13
+ export declare abstract class AttachmentStore extends Service {
14
+ constructor(ctx: Context);
15
+ /** Deployment-resolved image policy used by authoritative and fast-path validation. */
16
+ abstract readonly imageLimits: ImageAttachmentLimits;
17
+ /**
18
+ * Validate one image without persisting it.
19
+ * Batch callers validate every member before saving any member.
20
+ * @param input - encoded bytes, declared media type, and optional display name.
21
+ * @returns completion after the encoded raster has been fully decoded.
22
+ */
23
+ abstract validateImage(input: SaveImageAttachment): Promise<void>;
24
+ /**
25
+ * Validate and durably commit one image before its owning session event is appended.
26
+ * @param input - encoded bytes, declared media type, and optional display name.
27
+ * @returns a durable content-addressed reference.
28
+ */
29
+ abstract saveImage(input: SaveImageAttachment): Promise<ImageAttachmentRef>;
30
+ /**
31
+ * Read one image and verify that bytes still match the recorded reference.
32
+ * @param ref - durable reference from the session log.
33
+ * @returns the verified bytes and canonical reference.
34
+ */
35
+ abstract readImage(ref: ImageAttachmentRef): Promise<StoredImageAttachment>;
36
+ }
37
+ export default AttachmentStore;
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,13 @@
1
+ /** Package-owned invariant companion for `@deepseek-ai/dsh-attachment`. @module @deepseek-ai/dsh-attachment/invariant */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ /** Cordis companion plugin name. */
4
+ export declare const name = "attachment-invariant";
5
+ /** Service required before package ownership can be reserved. */
6
+ export declare const inject: string[];
7
+ /**
8
+ * Register the package invariant companion.
9
+ * @param ctx - Cordis context carrying the invariant service.
10
+ * @returns the registration disposer.
11
+ */
12
+ export declare const apply: (ctx: Context) => Promise<() => void>;
13
+ //# sourceMappingURL=invariant.d.ts.map
@@ -0,0 +1,42 @@
1
+ /** Durable attachment vocabulary. @module @deepseek-ai/dsh-attachment/types */
2
+ import type { AttachmentId } from './brand.ts';
3
+ export type { AttachmentId } from './brand.ts';
4
+ /** Raster image formats accepted by the version-one attachment path. */
5
+ export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';
6
+ /** Durable, serializable metadata for one immutable image object. */
7
+ export interface ImageAttachmentRef {
8
+ /** Opaque storage identifier; never a filesystem path or bearer URL. */
9
+ attachmentId: AttachmentId;
10
+ /** Media type verified from the stored bytes. */
11
+ mediaType: ImageMediaType;
12
+ /** Exact encoded byte length. */
13
+ bytes: number;
14
+ /** Intrinsic encoded width in pixels. */
15
+ width: number;
16
+ /** Intrinsic encoded height in pixels. */
17
+ height: number;
18
+ /** Optional display name stripped of local path information. */
19
+ name?: string;
20
+ }
21
+ /** Deployment-resolved limits used by upload admission and request buffering. */
22
+ export interface ImageAttachmentLimits {
23
+ maxImageBytes: number;
24
+ maxImagesPerMessage: number;
25
+ maxMessageImageBytes: number;
26
+ maxImagePixels: number;
27
+ mediaTypes: readonly ImageMediaType[];
28
+ }
29
+ /** Request to validate and durably commit one image. */
30
+ export interface SaveImageAttachment {
31
+ data: Uint8Array;
32
+ /** Caller-declared media type, checked against fully decoded bytes. */
33
+ mediaType: ImageMediaType;
34
+ /** Optional browser/provider display name; it is never interpreted as a path. */
35
+ name?: string;
36
+ }
37
+ /** Stored image bytes returned after reference and digest verification. */
38
+ export interface StoredImageAttachment {
39
+ ref: ImageAttachmentRef;
40
+ data: Uint8Array;
41
+ }
42
+ //# sourceMappingURL=types.d.ts.map
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@deepseek-ai/dsh-attachment",
3
+ "description": "Durable immutable attachment storage seam for the DeepSeek Harness",
4
+ "version": "0.0.1-rc.1",
5
+ "publishConfig": {
6
+ "access": "restricted"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
11
+ "directory": "packages/attachment/attachment"
12
+ },
13
+ "type": "module",
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./invariant": {
22
+ "types": "./lib/types/invariant.d.ts",
23
+ "default": "./lib/invariant.js"
24
+ },
25
+ "./src/*": "./src/*",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "files": [
29
+ "lib/index.js",
30
+ "lib/invariant.js",
31
+ "lib/types/**/*.d.ts"
32
+ ],
33
+ "license": "BSD-3-Clause",
34
+ "peerDependencies": {
35
+ "@deepseek-ai/dsh-brand": "^0.0.1-rc.1",
36
+ "@deepseek-ai/cordis": "^4.0.1-rc.1",
37
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.1"
38
+ },
39
+ "devDependencies": {
40
+ "@deepseek-ai/dsh-brand": "^0.0.1-rc.1",
41
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
42
+ "@deepseek-ai/cordis": "^4.0.1-rc.1"
43
+ }
44
+ }