@deepseek-ai/dsh-attachment 0.1.5-rc.1 → 0.1.6-alpha.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/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/attachment/attachment/README.md
5
- README.md: fc3903cb1ab4ed4a1249ad2ec62c0df633f4a7c4
6
- README.zh.md: 9e84a5ed8889d541b3cb87fb5e5d5560d36a2bb5
5
+ README.md: d2a667e2d12deadc5e82a83cca6565f0b5a6aae0
6
+ README.zh.md: b5598eb8ccca39d8b5be346c585fd84d3dd38468
package/README.md CHANGED
@@ -66,13 +66,13 @@ This section explains the design decisions behind the seam and the service opera
66
66
  - **Normalize and persist before event.** Every source is prepared and verified before the batch publishes in order, so the session log never references a partial or failed normalization.
67
67
  - **Immutable and retention-neutral.** Objects are immutable once published; resumed and forked sessions may share them, so reference-aware garbage collection is deferred rather than tied to any one session's deletion.
68
68
  - **Verify on read.** Reads check bytes and metadata against the logged reference before returning them, and request projections fully decode cached bytes, so a missing, corrupted, or swapped object fails closed.
69
- - **Role-neutral image blocks.** The `ImageBlock` content block in `dsh-llm` carries an `ImageAttachmentRef`; provider adapters resolve it into deterministic request versions with explicit pixel and byte budgets, while execution filesystems may map the immutable host object to a model-readable process path.
69
+ - **Role-neutral image blocks.** The `ImageBlock` content block in `dsh-llm` carries an `ImageAttachmentRef`; provider adapters resolve it into deterministic request versions at an explicit route-chosen target size and byte target, while execution filesystems may map the immutable host object to a model-readable process path.
70
70
  - **Error routing by code.** `AttachmentError` re-implements the `HarnessError` shape instead of extending it because the base lives in `dsh-llm`, which depends on this package; consumers use `isAttachmentError` and route on `code`, never on the prototype chain.
71
71
  - **Files are verbatim, images are normalized.** `saveFile` commits an existing byte array, `saveFileStream` commits bounded chunks with backpressure and cancellation, `readFileStream` verifies and returns bounded chunks, and `fileHostPath` locates the stored object for read-on-demand projection; neither file write path applies admission limits. The image path keeps its separate normalization, limits, and request-version pipeline. The `FileBlock` content block in `dsh-llm` carries a `FileAttachmentRef`, and request assembly projects it to deterministic handle text for every route.
72
72
 
73
73
  ### Service operations
74
74
 
75
- The service family runs one admission-and-storage flow: every entry point enforces source batch limits and canonical base64, prepares provider-independent normalized attachments before publishing any member, and commits them durably in input order without partial results. Host prompt consumers pass ordered text, encoded images, and already resolved file references to `ctx.attachments.admitPromptContent()`; the method persists images and passes file references unchanged. Encoded protocol adapters call `ctx.attachments.admitEncodedFile()`, which checks canonical base64 before delegating to `saveFile`; adapters recognize attachment failures through `ctx.attachments.isAttachmentError()`. Generic-file callers choose `saveFile` for existing bytes or `saveFileStream` for a bounded asynchronous byte source; both return the same durable reference, while `readFileStream` verifies its digest and length during a bounded read. `readImageRequest` derives deterministic route-sized variants whose identity includes the attachment id, transform version, pixel and byte budgets, and encoder settings. The pure `requestImageDimensions` export computes each projection's aspect-preserving dimensions from a total-pixel budget, so providers and request pricing share one geometry. `imageHostPath` exposes an implementation-owned host location only to trusted same-process consumers that need execution-world mapping. Callers compose ordered batches while the implementation owns compression concurrency, caching, and singleflight. Reads, streamed writes, and projections preserve caller cancellation. Failures carry stable machine-readable codes, and the caller-correctable admission subset is recognizable at runtime so each protocol adapter maps its own vocabulary; the exact per-operation contracts live in [`src/index.ts`](src/index.ts) and [`src/error.ts`](src/error.ts).
75
+ The service family runs one admission-and-storage flow: every entry point enforces source batch limits and canonical base64, prepares provider-independent normalized attachments before publishing any member, and commits them durably in input order without partial results. Host prompt consumers pass ordered text, encoded images, and already resolved file references to `ctx.attachments.admitPromptContent()`; the method persists images and passes file references unchanged. Encoded protocol adapters call `ctx.attachments.admitEncodedFile()`, which checks canonical base64 before delegating to `saveFile`; adapters recognize attachment failures through `ctx.attachments.isAttachmentError()`. Generic-file callers choose `saveFile` for existing bytes or `saveFileStream` for a bounded asynchronous byte source; both return the same durable reference, while `readFileStream` verifies its digest and length during a bounded read. `readImageRequest` derives deterministic route-sized variants whose identity includes the attachment id, transform version, target dimensions, byte target, and encoder settings. The pure `requestImageDimensions` and `longEdgeDimensions` exports compute aspect-preserving dimensions from a total-pixel budget or an exact long edge, so routes and request pricing share one geometry. `imageHostPath` exposes an implementation-owned host location only to trusted same-process consumers that need execution-world mapping. Callers compose ordered batches while the implementation owns compression concurrency, caching, and singleflight. Reads, streamed writes, and projections preserve caller cancellation. Failures carry stable machine-readable codes, and the caller-correctable admission subset is recognizable at runtime so each protocol adapter maps its own vocabulary; the exact per-operation contracts live in [`src/index.ts`](src/index.ts) and [`src/error.ts`](src/error.ts).
76
76
 
77
77
  ### Source map
78
78
 
@@ -94,7 +94,7 @@ The service family runs one admission-and-storage flow: every entry point enforc
94
94
 
95
95
  For the full service contract and payload types, read the subsystem reference; for the storage that backs this capability, read the local backend.
96
96
 
97
- - [Attachment subsystem reference](../../../docs/subsystems/attachment.md) — service contract, payload types, and the `ctx.attachments` cordis surface.
97
+ - [Attachment subsystem reference](../../../docs/subsystems/attachment.md) — service contract, payload types, and the `ctx.attachments` Cordis surface.
98
98
  - [Local filesystem backend](../attachment-local/README.md) — where your attached images are stored on this machine.
99
99
  - [Capability seams](../../../docs/capability-seams.md) — how this capability family is split into roles.
100
100
 
@@ -114,7 +114,7 @@ Adding an image changes the provider request and therefore invalidates the affec
114
114
  <a id="known-limitations-and-deferred-work"></a>
115
115
 
116
116
 
117
- These limits describe what image attachments can and cannot do; they are current package constraints, not a task backlog.
117
+ These limits describe what attachments can and cannot do; they are current package constraints, not a task backlog.
118
118
 
119
119
  - **Raster image limits apply to images only** — PNG, JPEG, WebP, and GIF are accepted as images under deployment limits; every other file is stored verbatim with no type or size limit, and audio and video have no dedicated handling yet.
120
120
  - **Attachments are never deleted** — stored images and files are retained indefinitely; nothing removes them automatically.
package/README.zh.md CHANGED
@@ -41,7 +41,7 @@ kind: "package-reference"
41
41
 
42
42
  ### 把附件传给命令
43
43
 
44
- 声明接受附件的命令会按选择顺序接收图片与通用文件。不接受附件的命令会返回错误,并保留 composer 的草稿与附件卡。
44
+ 声明接受附件的命令会按选择顺序接收图片与通用文件。不接受附件的命令会返回错误,并保留输入区的草稿与附件卡。
45
45
 
46
46
  ### 在整个会话中复用图片
47
47
 
@@ -65,14 +65,14 @@ kind: "package-reference"
65
65
 
66
66
  - **事件前完成规范化与持久化。** 每个源图都会在批次按序发布前完成准备与校验,因此会话日志绝不会引用部分完成或规范化失败的对象。
67
67
  - **不可变且保留策略中立。** 对象一经发布即不可变;恢复和 fork 后的会话可能共享它们,因此引用感知的垃圾回收被推迟,而不是与任何单个会话的删除绑定。
68
- - **读取时校验。** 读取在返回前把字节和元数据与记录的引用比对,请求投影还会完整解码缓存字节,因此缺失、损坏或被替换的对象都会失败关闭。
69
- - **角色无关的图片块。** `dsh-llm` 中的 `ImageBlock` 内容块携带 `ImageAttachmentRef`;提供方适配器以显式像素与字节预算把引用解析为确定性请求版本,执行文件系统则可以把不可变宿主对象映射为模型可读的进程路径。
68
+ - **读取时校验。** 读取在返回前把字节和元数据与记录的引用比对,请求投影还会完整解码缓存字节,因此缺失、损坏或被替换的对象不会通过校验。
69
+ - **角色无关的图片块。** `dsh-llm` 中的 `ImageBlock` 内容块携带 `ImageAttachmentRef`;提供方适配器按路由显式选定的目标尺寸与字节目标把引用解析为确定性请求版本,执行文件系统则可以把不可变宿主对象映射为模型可读的进程路径。
70
70
  - **按错误码路由。** `AttachmentError` 重新实现 `HarnessError` 的结构而不是继承它,因为基类位于 `dsh-llm`,而后者依赖本包;消费方用 `isAttachmentError` 识别错误并按 `code` 路由,绝不依赖原型链。
71
- - **文件原样,图片规范化。**`saveFile` 提交已有字节数组,`saveFileStream` 以背压和取消语义提交有界分块,`readFileStream` 校验并返回有界分块,`fileHostPath` 定位存储对象供按需读取投影;两种文件写入路径都不设准入限制。图片路径保留其独立的规范化、限额与请求版本流水线。`dsh-llm` 中的 `FileBlock` 内容块承载 `FileAttachmentRef`,请求组装把它对每条路由都投影成确定性 handle 文本。
71
+ - **文件原样,图片规范化。**`saveFile` 提交已有字节数组,`saveFileStream` 以背压和取消语义提交有界分块,`readFileStream` 校验并返回有界分块,`fileHostPath` 定位存储对象供按需读取投影;两种文件写入路径都不设准入限制。图片路径保留其独立的规范化、限额与请求版本流水线。`dsh-llm` 中的 `FileBlock` 内容块承载 `FileAttachmentRef`,请求组装会为每条路由将其投影为确定性的句柄文本。
72
72
 
73
73
  ### 服务操作
74
74
 
75
- 服务族运行同一条准入与存储流程:每个入口都强制执行源批次限制与规范 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)。
75
+ 服务族运行同一条准入与存储流程:每个入口都强制执行源批次限制与规范 base64,在发布任何成员前准备提供方无关的规范化附件,再按输入顺序持久提交而不产生部分结果。Host 提示词消费方把有序文本、编码图片和已经解析的文件引用交给 `ctx.attachments.admitPromptContent()`;该方法持久化图片,并让文件引用原样通过。编码协议适配器调用 `ctx.attachments.admitEncodedFile()`,由该方法检查规范 base64 后委托给 `saveFile`;适配器通过 `ctx.attachments.isAttachmentError()` 识别附件错误。通用文件调用方可以用 `saveFile` 提交已有字节,或用 `saveFileStream` 提交有界异步字节源;两者返回相同的持久引用,`readFileStream` 则在有界读取过程中校验摘要与长度。`readImageRequest` 派生确定性的路由尺寸变体,其身份包含附件 id、变换版本、目标尺寸、字节目标及编码参数。纯函数导出 `requestImageDimensions` 与 `longEdgeDimensions` 按总像素预算或精确长边计算保持宽高比的尺寸,使路由与请求定价共享同一套几何计算。`imageHostPath` 只向需要把该位置映射到执行环境的受信任同进程消费方暴露实现拥有的宿主位置。调用方组合有序批次,而实现负责管理压缩并发、缓存与 singleflight。读取、流式写入和投影保留调用方的取消语义。失败带有稳定且机器可读的错误码,运行时即可识别可由调用方修正的准入子集,让每个协议适配器映射自己的词汇;各操作的确切约定见 [`src/index.ts`](src/index.ts) 与 [`src/error.ts`](src/error.ts)。
76
76
 
77
77
  ### 源码地图
78
78
 
@@ -83,7 +83,7 @@ kind: "package-reference"
83
83
  | [`src/admission.ts`](src/admission.ts) | 对编码图片和文件上传强制执行规范 base64 并委托存储 |
84
84
  | [`src/error.ts`](src/error.ts) | `AttachmentError` 类与 `isImageAdmissionError` 运行时子集 |
85
85
  | [`src/brand.ts`](src/brand.ts) | `AttachmentId` 带类型标记的不透明标识符 |
86
- | — | 不发布运行时不变式伴生入口;实现负责强制不可变存储检查。 |
86
+ | — | 不发布运行时不变式伴生入口;这个无状态 seam 承载类型,实现则负责强制执行不可变存储检查。 |
87
87
 
88
88
  </details>
89
89
 
@@ -94,7 +94,7 @@ kind: "package-reference"
94
94
 
95
95
  完整的服务约定与载荷类型请看子系统参考;支撑这一能力的存储请看本地后端。
96
96
 
97
- - [附件子系统参考](../../../docs/subsystems/attachment.zh.md)——服务约定、载荷类型与 `ctx.attachments` 的 cordis 接口面。
97
+ - [附件子系统参考](../../../docs/subsystems/attachment.zh.md)——服务约定、载荷类型与 `ctx.attachments` 的 Cordis 接口面。
98
98
  - [本地文件系统后端](../attachment-local/README.zh.md)——你的附加图片在本机上的存储位置。
99
99
  - [能力 seam](../../../docs/capability-seams.zh.md)——本能力家族如何拆分为多个角色。
100
100
 
@@ -103,7 +103,7 @@ kind: "package-reference"
103
103
  <a id="model-experience"></a>
104
104
  ## 模型体验
105
105
 
106
- 该包通过提供方适配器间接影响模型;适配器会把每个持久图片引用解析为确切请求版本,并在图片旁发送稳定附件 id 与实际尺寸。执行文件系统可以映射已存对象时,描述符还会包含只读进程路径,以及可写副本使用的匹配扩展名。通用文件的字节永远不会到达提供方:每条路由都收到一行确定性 handle 文本,指出文件名、字节数、摘要前缀,以及供文件工具读取的只读保存路径。
106
+ 该包通过提供方适配器间接影响模型;适配器会把每个持久图片引用解析为确切请求版本,并在图片旁发送稳定附件 id 与实际尺寸。执行文件系统可以映射已存对象时,描述符还会包含只读进程路径,以及可写副本使用的匹配扩展名。通用文件的字节永远不会到达提供方:每条路由都收到一行确定性的句柄文本,指出文件名、字节数、摘要前缀,以及供文件工具读取的只读保存路径。
107
107
 
108
108
  #### KV Cache 影响
109
109
 
@@ -134,6 +134,6 @@ kind: "package-reference"
134
134
 
135
135
  #### 未来:音频、视频与助手侧输出
136
136
 
137
- 音频与视频需要原样文件路径之外的专门生命周期与提供方契约;角色无关的 `ImageBlock` 也把助手侧图片输出留作前瞻兼容——当前生产适配器声明只输出文本,因此只有用户内容携带图片。两个方向都尚未决定。
137
+ 音频与视频需要原样文件路径之外的专门生命周期与提供方约定;角色无关的 `ImageBlock` 也为助手侧图片输出保留向前兼容空间——当前生产适配器声明只输出文本,因此只有用户内容携带图片。两个方向都尚未决定。
138
138
 
139
139
  </details>
package/lib/index.js CHANGED
@@ -137,8 +137,8 @@ function ImageVariantId(value) {
137
137
  //#endregion
138
138
  //#region lib/types/request-projection.js
139
139
  /**
140
- * Pure request-projection geometry shared by attachment providers and
141
- * provider-side request pricing. @module @deepseek-ai/dsh-attachment/request-projection
140
+ * Pure request-projection geometry shared by model routes and provider-side
141
+ * request pricing. @module @deepseek-ai/dsh-attachment/request-projection
142
142
  */
143
143
  /**
144
144
  * Compute aspect-preserving integer dimensions within a hard total-pixel budget.
@@ -176,6 +176,28 @@ function requestImageDimensions(width, height, maxPixels) {
176
176
  height: projectedHeight
177
177
  };
178
178
  }
179
+ /**
180
+ * Compute aspect-preserving integer dimensions with an exact long edge; the
181
+ * short edge rounds to the nearest pixel, as an encoder resize by the
182
+ * long edge alone.
183
+ * @param width - positive source width.
184
+ * @param height - positive source height.
185
+ * @param longEdge - positive target for the longer source edge.
186
+ * @returns the target dimensions; a long edge at or above the source returns the source unchanged.
187
+ */
188
+ function longEdgeDimensions(width, height, longEdge) {
189
+ if (longEdge >= Math.max(width, height)) return {
190
+ width,
191
+ height
192
+ };
193
+ return width >= height ? {
194
+ width: longEdge,
195
+ height: Math.max(1, Math.round(longEdge * height / width))
196
+ } : {
197
+ width: Math.max(1, Math.round(longEdge * width / height)),
198
+ height: longEdge
199
+ };
200
+ }
179
201
  //#endregion
180
202
  //#region lib/types/index.js
181
203
  /** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */
@@ -309,14 +331,14 @@ var AttachmentStore = class extends Service {
309
331
  /**
310
332
  * Generate or read one deterministic model-request version from the stored normalized image.
311
333
  * @param ref - durable provider-independent normalized attachment reference.
312
- * @param policy - exact route pixel budget and encoded-byte target; a target no ladder quality meets yields the smallest ladder output.
334
+ * @param target - route-chosen dimensions and byte target; an unmet byte target yields the smallest ladder output.
313
335
  * @param signal - optional cancellation.
314
336
  * @returns request bytes and the cache/upload identity covering every transform input.
315
337
  */
316
- readImageRequest(ref, policy, signal) {
338
+ readImageRequest(ref, target, signal) {
317
339
  signal?.throwIfAborted();
318
340
  return Promise.reject(new AttachmentError("The mounted attachment provider cannot derive model-request images.", "ATTACHMENT_PROJECTION_UNSUPPORTED"));
319
341
  }
320
342
  };
321
343
  //#endregion
322
- export { AttachmentError, AttachmentId, AttachmentStore, AttachmentStore as default, ImageVariantId, admitEncodedFile, admitEncodedImages, isAttachmentError, isImageAdmissionError, requestImageDimensions };
344
+ export { AttachmentError, AttachmentId, AttachmentStore, AttachmentStore as default, ImageVariantId, admitEncodedFile, admitEncodedImages, isAttachmentError, isImageAdmissionError, longEdgeDimensions, requestImageDimensions };
@@ -1,13 +1,14 @@
1
1
  /** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */
2
2
  import { Context, Service } from '@deepseek-ai/cordis';
3
3
  import { AttachmentError } from './error.ts';
4
- import type { AdmittedPromptContentPart, AttachmentAdmissionPart, EncodedFileAttachment, FileAttachmentRef, ImageAttachmentLimits, ImageAttachmentRef, ImageRequestPolicy, RequestImageAttachment, SaveFileAttachment, SaveFileStreamAttachment, SaveImageAttachment, StoredImageAttachment } from './types.ts';
4
+ import type { AdmittedPromptContentPart, AttachmentAdmissionPart, EncodedFileAttachment, FileAttachmentRef, ImageAttachmentLimits, ImageAttachmentRef, ImageRequestTarget, RequestImageAttachment, SaveFileAttachment, SaveFileStreamAttachment, SaveImageAttachment, StoredImageAttachment } from './types.ts';
5
5
  export { AttachmentId, ImageVariantId } from './brand.ts';
6
6
  export { AttachmentError, isAttachmentError, isImageAdmissionError } from './error.ts';
7
7
  export type { AttachmentErrorCode, ImageAdmissionErrorCode } from './error.ts';
8
8
  export { admitEncodedFile, admitEncodedImages } from './admission.ts';
9
- export { requestImageDimensions } from './request-projection.ts';
10
- export type { AttachmentId as AttachmentIdType, AdmittedPromptContentPart, AttachmentAdmissionPart, EncodedFileAttachment, EncodedImageAttachment, FileAttachmentRef, ImageAttachmentLimits, ImageAttachmentRef, ImageRequestPolicy, ImageMediaType, PromptContentPart, RequestImageAttachment, SaveFileAttachment, SaveFileStreamAttachment, SaveImageAttachment, StoredImageAttachment, } from './types.ts';
9
+ export { longEdgeDimensions, requestImageDimensions } from './request-projection.ts';
10
+ export type { ProjectedDimensions } from './request-projection.ts';
11
+ export type { AttachmentId as AttachmentIdType, AdmittedPromptContentPart, AttachmentAdmissionPart, EncodedFileAttachment, EncodedImageAttachment, FileAttachmentRef, ImageAttachmentLimits, ImageAttachmentRef, ImageRequestTarget, ImageMediaType, PromptContentPart, RequestImageAttachment, SaveFileAttachment, SaveFileStreamAttachment, SaveImageAttachment, StoredImageAttachment, } from './types.ts';
11
12
  declare module '@deepseek-ai/cordis' {
12
13
  interface Context {
13
14
  attachments: AttachmentStore;
@@ -121,11 +122,11 @@ export declare abstract class AttachmentStore extends Service {
121
122
  /**
122
123
  * Generate or read one deterministic model-request version from the stored normalized image.
123
124
  * @param ref - durable provider-independent normalized attachment reference.
124
- * @param policy - exact route pixel budget and encoded-byte target; a target no ladder quality meets yields the smallest ladder output.
125
+ * @param target - route-chosen dimensions and byte target; an unmet byte target yields the smallest ladder output.
125
126
  * @param signal - optional cancellation.
126
127
  * @returns request bytes and the cache/upload identity covering every transform input.
127
128
  */
128
- readImageRequest(ref: ImageAttachmentRef, policy: ImageRequestPolicy, signal?: AbortSignal): Promise<RequestImageAttachment>;
129
+ readImageRequest(ref: ImageAttachmentRef, target: ImageRequestTarget, signal?: AbortSignal): Promise<RequestImageAttachment>;
129
130
  }
130
131
  export default AttachmentStore;
131
132
  //# sourceMappingURL=index.d.ts.map
@@ -5,7 +5,7 @@ import { AttachmentError, isAttachmentError as matchesAttachmentError } from "./
5
5
  export { AttachmentId, ImageVariantId } from "./brand.js";
6
6
  export { AttachmentError, isAttachmentError, isImageAdmissionError } from "./error.js";
7
7
  export { admitEncodedFile, admitEncodedImages } from "./admission.js";
8
- export { requestImageDimensions } from "./request-projection.js";
8
+ export { longEdgeDimensions, requestImageDimensions } from "./request-projection.js";
9
9
  /** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */
10
10
  export class AttachmentStore extends Service {
11
11
  constructor(ctx) {
@@ -147,14 +147,14 @@ export class AttachmentStore extends Service {
147
147
  /**
148
148
  * Generate or read one deterministic model-request version from the stored normalized image.
149
149
  * @param ref - durable provider-independent normalized attachment reference.
150
- * @param policy - exact route pixel budget and encoded-byte target; a target no ladder quality meets yields the smallest ladder output.
150
+ * @param target - route-chosen dimensions and byte target; an unmet byte target yields the smallest ladder output.
151
151
  * @param signal - optional cancellation.
152
152
  * @returns request bytes and the cache/upload identity covering every transform input.
153
153
  */
154
- readImageRequest(ref, policy, signal) {
154
+ readImageRequest(ref, target, signal) {
155
155
  signal?.throwIfAborted();
156
156
  void ref;
157
- void policy;
157
+ void target;
158
158
  return Promise.reject(new AttachmentError('The mounted attachment provider cannot derive model-request images.', 'ATTACHMENT_PROJECTION_UNSUPPORTED'));
159
159
  }
160
160
  }
@@ -1,7 +1,12 @@
1
1
  /**
2
- * Pure request-projection geometry shared by attachment providers and
3
- * provider-side request pricing. @module @deepseek-ai/dsh-attachment/request-projection
2
+ * Pure request-projection geometry shared by model routes and provider-side
3
+ * request pricing. @module @deepseek-ai/dsh-attachment/request-projection
4
4
  */
5
+ /** Integer width and height of one projected image. */
6
+ export interface ProjectedDimensions {
7
+ width: number;
8
+ height: number;
9
+ }
5
10
  /**
6
11
  * Compute aspect-preserving integer dimensions within a hard total-pixel budget.
7
12
  * @param width - positive source width.
@@ -9,8 +14,15 @@
9
14
  * @param maxPixels - positive width-times-height cap.
10
15
  * @returns inward-rounded dimensions; small images are not enlarged.
11
16
  */
12
- export declare function requestImageDimensions(width: number, height: number, maxPixels: number): {
13
- width: number;
14
- height: number;
15
- };
17
+ export declare function requestImageDimensions(width: number, height: number, maxPixels: number): ProjectedDimensions;
18
+ /**
19
+ * Compute aspect-preserving integer dimensions with an exact long edge; the
20
+ * short edge rounds to the nearest pixel, as an encoder resize by the
21
+ * long edge alone.
22
+ * @param width - positive source width.
23
+ * @param height - positive source height.
24
+ * @param longEdge - positive target for the longer source edge.
25
+ * @returns the target dimensions; a long edge at or above the source returns the source unchanged.
26
+ */
27
+ export declare function longEdgeDimensions(width: number, height: number, longEdge: number): ProjectedDimensions;
16
28
  //# sourceMappingURL=request-projection.d.ts.map
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Pure request-projection geometry shared by attachment providers and
3
- * provider-side request pricing. @module @deepseek-ai/dsh-attachment/request-projection
2
+ * Pure request-projection geometry shared by model routes and provider-side
3
+ * request pricing. @module @deepseek-ai/dsh-attachment/request-projection
4
4
  */
5
5
  /**
6
6
  * Compute aspect-preserving integer dimensions within a hard total-pixel budget.
@@ -30,4 +30,20 @@ export function requestImageDimensions(width, height, maxPixels) {
30
30
  }
31
31
  return { width: projectedWidth, height: projectedHeight };
32
32
  }
33
+ /**
34
+ * Compute aspect-preserving integer dimensions with an exact long edge; the
35
+ * short edge rounds to the nearest pixel, as an encoder resize by the
36
+ * long edge alone.
37
+ * @param width - positive source width.
38
+ * @param height - positive source height.
39
+ * @param longEdge - positive target for the longer source edge.
40
+ * @returns the target dimensions; a long edge at or above the source returns the source unchanged.
41
+ */
42
+ export function longEdgeDimensions(width, height, longEdge) {
43
+ if (longEdge >= Math.max(width, height))
44
+ return { width, height };
45
+ return width >= height
46
+ ? { width: longEdge, height: Math.max(1, Math.round(longEdge * height / width)) }
47
+ : { width: Math.max(1, Math.round(longEdge * width / height)), height: longEdge };
48
+ }
33
49
  //# sourceMappingURL=request-projection.js.map
@@ -124,10 +124,12 @@ export interface StoredImageAttachment {
124
124
  ref: ImageAttachmentRef;
125
125
  data: Uint8Array;
126
126
  }
127
- /** Deterministic request-image policy selected by one exact model route. */
128
- export interface ImageRequestPolicy {
129
- /** Maximum width multiplied by height after aspect-preserving projection. */
130
- maxPixels: number;
127
+ /** Deterministic request-image target selected by one exact model route for one attachment. */
128
+ export interface ImageRequestTarget {
129
+ /** Target width in pixels; a target above the source keeps the source width. */
130
+ width: number;
131
+ /** Target height in pixels; a target above the source keeps the source height. */
132
+ height: number;
131
133
  /** Encoded-byte target before base64 expansion or Files API upload; the smallest quality-ladder output is kept when no quality fits. */
132
134
  maxBytes: number;
133
135
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-attachment",
3
3
  "description": "Durable immutable attachment storage seam for the DeepSeek Harness",
4
- "version": "0.1.5-rc.1",
4
+ "version": "0.1.6-alpha.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,11 +32,11 @@
32
32
  ],
33
33
  "license": "MIT",
34
34
  "peerDependencies": {
35
- "@deepseek-ai/dsh-brand": "^0.1.5-rc.1",
35
+ "@deepseek-ai/dsh-brand": "^0.1.6-alpha.1",
36
36
  "@deepseek-ai/cordis": "^4.0.2"
37
37
  },
38
38
  "devDependencies": {
39
- "@deepseek-ai/cordis": "^4.0.2",
40
- "@deepseek-ai/dsh-brand": "^0.1.5-rc.1"
39
+ "@deepseek-ai/dsh-brand": "^0.1.6-alpha.1",
40
+ "@deepseek-ai/cordis": "^4.0.2"
41
41
  }
42
42
  }