@deepseek-ai/dsh-output-retention 0.1.7-alpha.2 → 0.1.7-rc.2

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
@@ -1,6 +1,67 @@
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:
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/util/output-retention/README.md
5
- README.md: bb0902b959f298f9f7b0a64de23d48e29bfd75ad
6
- README.zh.md: 7d96ba4da33a98b24eba53f9dd5a2f2c98b79f39
5
+ /:
6
+ en: 058416b280f64a3a
7
+ zh: 6dd741394b67bd30
8
+ /deepseek-ai-dsh-output-retention:
9
+ en: 909b14f93584c835
10
+ zh: da2b6de301df901a
11
+ /deepseek-ai-dsh-output-retention/summary:
12
+ en: 22e523125ade3619
13
+ zh: 2cf48b1a6658056f
14
+ /deepseek-ai-dsh-output-retention/table-of-contents:
15
+ en: d152484eb41ac6b4
16
+ zh: 09388d293f9be9cb
17
+ /deepseek-ai-dsh-output-retention/use-this-package:
18
+ en: f62f2da3b880d972
19
+ zh: be8b8bea3bff9cb6
20
+ /deepseek-ai-dsh-output-retention/use-this-package/bounding-a-list-of-items:
21
+ en: 4e33df2bffae04a9
22
+ zh: b79773e1936605bf
23
+ /deepseek-ai-dsh-output-retention/use-this-package/bounding-a-text-stream:
24
+ en: c0002b8dd81f4732
25
+ zh: 4f8c0e9f03e4ecf9
26
+ /deepseek-ai-dsh-output-retention/use-this-package/building-the-omission-footer:
27
+ en: 24a79057aea704e0
28
+ zh: ab6b91d0d1c3b8d7
29
+ /deepseek-ai-dsh-output-retention/use-this-package/capping-a-character-budget-preview:
30
+ en: ca55f16ac7f494d4
31
+ zh: 181c19d0d5f0128b
32
+ /deepseek-ai-dsh-output-retention/use-this-package/what-truncated-means:
33
+ en: d496be708ac637dc
34
+ zh: 739017ce47f08148
35
+ /deepseek-ai-dsh-output-retention/use-this-package/how-the-current-tools-use-it:
36
+ en: ed4b3b343ad80143
37
+ zh: 65dd1f707c3ac747
38
+ /deepseek-ai-dsh-output-retention/understand-the-implementation:
39
+ en: fd2a6c959bfe864e
40
+ zh: 25b11d28aced568c
41
+ /deepseek-ai-dsh-output-retention/understand-the-implementation/source-map:
42
+ en: cb49af8772b97f13
43
+ zh: 23810afb65f350ee
44
+ /deepseek-ai-dsh-output-retention/understand-the-implementation/two-retainers-two-resource-models:
45
+ en: 6a5dd228d9f9808b
46
+ zh: 9bba82c5771ee705
47
+ /deepseek-ai-dsh-output-retention/understand-the-implementation/how-the-budget-facts-stay-honest:
48
+ en: 101d99e1107d91c7
49
+ zh: ab64a35b62938db1
50
+ /deepseek-ai-dsh-output-retention/understand-the-implementation/the-read-render-exclusion:
51
+ en: f76b67fa9e940705
52
+ zh: e7731bfd31cc9f5c
53
+ /deepseek-ai-dsh-output-retention/further-exploration:
54
+ en: 32497c10ffb10c75
55
+ zh: 1176c882cbed93c0
56
+ /deepseek-ai-dsh-output-retention/model-experience:
57
+ en: 247cdeeae9390244
58
+ zh: 0720d77e0a1d1c15
59
+ /deepseek-ai-dsh-output-retention/model-experience/kv-cache-effect:
60
+ en: 4487c456cf996b48
61
+ zh: 2c25fe4a5a53f345
62
+ /deepseek-ai-dsh-output-retention/known-limitations-and-deferred-work:
63
+ en: 34e646397df5e681
64
+ zh: 344609df5eb0c4fa
65
+ /deepseek-ai-dsh-output-retention/known-limitations-and-deferred-work/dev-note:
66
+ en: e67f633dc6fe7773
67
+ zh: 3bb0c20c93f16f98
package/README.md CHANGED
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- Use `dsh-output-retention` to cap the items or text a tool returns to a model while reporting what was omitted. `ItemRetainer` keeps an ordered head window and can report an exact omitted-item count; `TextRetainer` keeps head, tail, or head-and-tail byte windows without returning invalid UTF-8 cuts. `formatRetentionNotice` adds a consistent omission clause while each tool supplies its own recovery guidance. Grouping, line numbering, spill files, and provider errors remain tool responsibilities; consumers import this library directly rather than loading it through `cordis.yml`.
12
+ Use `dsh-output-retention` to cap the items or text a tool returns to a model while reporting what was omitted. `ItemRetainer` keeps an ordered head window and can report an exact omitted-item count; `TextRetainer` keeps head, tail, or head-and-tail byte windows without returning invalid UTF-8 cuts. `formatRetentionNotice` adds a consistent omission clause while each tool supplies its own recovery guidance. `truncateWithoutSplittingSurrogatePair` caps a character-budget preview without leaving a lone high surrogate at the cut. Grouping, line numbering, spill files, and provider errors remain tool responsibilities; consumers import this library directly rather than loading it through `cordis.yml`.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -74,6 +74,10 @@ const footer = formatRetentionNotice(
74
74
 
75
75
  The library standardizes the omission clause (`Omitted 3 items.`) and joins it with the tool's own recovery guidance; only the tool knows the recovery action, so the tool supplies those words.
76
76
 
77
+ ### Capping a character-budget preview
78
+
79
+ `truncateWithoutSplittingSurrogatePair` caps a preview measured in UTF-16 code units. A cut that lands inside a surrogate pair drops the unpaired half instead of returning a lone high surrogate, so the kept text stays a prefix. The persistent `bash` and `pwsh` shells and `str_replace_editor` use it for their character-budget previews; each still owns its truncation notice and its `incomplete` prefix.
80
+
77
81
  ### What `truncated` means
78
82
 
79
83
  `truncated` is a budget fact: the retainer omitted otherwise-available content because of a cap. It never means the upstream was incomplete — permission failures, skipped binary files, provider partial failures, and unreadable candidates stay in tool-domain fields, never folded into `truncated`.
@@ -104,7 +108,7 @@ The library is built on one separation: it owns the mechanical question of what
104
108
 
105
109
  | File | Role |
106
110
  |---|---|
107
- | [`src/index.ts`](src/index.ts) | `ItemRetainer`, `TextRetainer`, `describeOmitted`, and `formatRetentionNotice` |
111
+ | [`src/index.ts`](src/index.ts) | `ItemRetainer`, `TextRetainer`, `describeOmitted`, `formatRetentionNotice`, and `truncateWithoutSplittingSurrogatePair` |
108
112
  | — | No runtime invariant companion is published; this pure utility owns no event stream or mutable runtime data; its value algebra is enforced by unit tests. |
109
113
 
110
114
  ### Two retainers, two resource models
@@ -151,7 +155,7 @@ No direct invalidation; the retention consumers own any request-prefix changes.
151
155
  These limits define what the retainers deliberately do not cover. They are current package constraints, not a task backlog.
152
156
 
153
157
  - **Item retention supports `head` only** — tail, head/tail, pagination, grouping, and provider-completeness semantics remain tool-owned.
154
- - **Text retention is byte-oriented** — line and character windows such as `read` pagination require a separate renderer, and a cut may discard partial UTF-8 boundary bytes to keep the returned text valid.
158
+ - **Text retention is byte-oriented** — `TextRetainer` counts bytes; character-budget head caps go through `truncateWithoutSplittingSurrogatePair`, and line windows such as `read` pagination still require a separate renderer. A cut may discard partial UTF-8 boundary bytes to keep the returned text valid.
155
159
 
156
160
  <a id="dev-note"></a>
157
161
  ### Dev Note
package/README.zh.md CHANGED
@@ -9,7 +9,7 @@ kind: "package-library"
9
9
 
10
10
  ## 概述
11
11
 
12
- 使用 `dsh-output-retention` 限制工具返回给模型的项或文本量,并报告省略了什么。`ItemRetainer` 保留有序的头部窗口,并可报告精确的省略项数;`TextRetainer` 保留 head、tail 或 head-and-tail 字节窗口,且不会返回因切割而无效的 UTF-8。`formatRetentionNotice` 添加一致的省略子句,各工具则提供自己的恢复指引。分组、行号、spill 文件与提供方错误仍归工具负责;消费方直接导入本库,而不通过 `cordis.yml` 加载。
12
+ 使用 `dsh-output-retention` 限制工具返回给模型的项或文本量,并报告省略了什么。`ItemRetainer` 保留有序的头部窗口,并可报告精确的省略项数;`TextRetainer` 保留 head、tail 或 head-and-tail 字节窗口,且不会返回因切割而无效的 UTF-8。`formatRetentionNotice` 添加一致的省略子句,各工具则提供自己的恢复指引。`truncateWithoutSplittingSurrogatePair` 按字符预算截断预览时,不会在切口留下孤立的高位代理项。分组、行号、spill 文件与提供方错误仍归工具负责;消费方直接导入本库,而不通过 `cordis.yml` 加载。
13
13
 
14
14
  ## 目录
15
15
 
@@ -74,6 +74,10 @@ const footer = formatRetentionNotice(
74
74
 
75
75
  库负责标准化省略子句(`Omitted 3 items.`)并把它与工具自有的恢复指引拼接;只有工具知道恢复动作,因此这些措辞由工具提供。
76
76
 
77
+ ### 按字符预算截断预览
78
+
79
+ `truncateWithoutSplittingSurrogatePair` 按 UTF-16 码元限制预览文本。切口落在代理对内部时丢弃不成对的半个码元,而不是返回孤立高位代理项,因此保留文本仍是前缀。持久 `bash`、`pwsh` 与 `str_replace_editor` 用它处理各自的字符预算预览;截断提示与 `incomplete` 前缀仍由各工具自行负责。
80
+
77
81
  ### `truncated` 意味着什么
78
82
 
79
83
  `truncated` 是预算事实:retainer 因上限而省略了本可获得的内容。它绝不表示上游不完整——权限失败、跳过二进制文件、提供方部分失败与不可读候选项都留在工具领域字段中,绝不并入 `truncated`。
@@ -104,7 +108,7 @@ const footer = formatRetentionNotice(
104
108
 
105
109
  | 文件 | 职责 |
106
110
  |---|---|
107
- | [`src/index.ts`](src/index.ts) | `ItemRetainer`、`TextRetainer`、`describeOmitted` 与 `formatRetentionNotice` |
111
+ | [`src/index.ts`](src/index.ts) | `ItemRetainer`、`TextRetainer`、`describeOmitted`、`formatRetentionNotice` 与 `truncateWithoutSplittingSurrogatePair` |
108
112
  | — | 不发布运行时不变式伴生入口;这个纯工具不拥有事件流或可变运行时数据;其值代数由单元测试保证。 |
109
113
 
110
114
  ### 两个 retainer,两种资源模型
@@ -151,7 +155,7 @@ const footer = formatRetentionNotice(
151
155
  这些限制说明 retainer 刻意不覆盖什么。它们是当前包约束,不是任务积压。
152
156
 
153
157
  - **项保留只支持 `head`**——tail、head/tail、分页、分组与提供方完整性语义仍归工具所有。
154
- - **文本保留面向字节**——`read` 分页等行窗口与字符窗口需要单独的渲染器;切割可能丢弃部分 UTF-8 边界字节,以保持返回文本有效。
158
+ - **文本保留面向字节**——`TextRetainer` 以字节计数;字符预算的头部截断走 `truncateWithoutSplittingSurrogatePair`,`read` 分页等行窗口仍需独立渲染器;切割可能丢弃部分 UTF-8 边界字节,以保持返回文本有效。
155
159
 
156
160
  <a id="dev-note"></a>
157
161
  ### 开发备注
package/lib/index.js CHANGED
@@ -281,5 +281,21 @@ function describeOmitted(omitted, unit) {
281
281
  function formatRetentionNotice(notice, recovery) {
282
282
  return [describeOmitted(notice.omitted, notice.unit), recovery(notice)].filter((part) => part.length > 0).join(" ");
283
283
  }
284
+ /**
285
+ * Cap `text` at `maxChars` UTF-16 code units without introducing a lone high
286
+ * surrogate: a cut that lands inside a surrogate pair drops the unpaired half,
287
+ * so the result is one code unit shorter than the cap. An unpaired surrogate is
288
+ * not well-formed text — a strict JSON reader rejects a durable Session log that
289
+ * carries one. An unpaired surrogate `text` already carries is not repaired here.
290
+ *
291
+ * @param text The text to cap.
292
+ * @param maxChars The maximum number of UTF-16 code units to retain.
293
+ * @returns A prefix of `text` no longer than `maxChars`; the cut never introduces a lone high surrogate.
294
+ */
295
+ function truncateWithoutSplittingSurrogatePair(text, maxChars) {
296
+ if (text.length <= maxChars) return text;
297
+ const capped = text.slice(0, maxChars);
298
+ return /[\uD800-\uDBFF]$/.test(capped) ? capped.slice(0, -1) : capped;
299
+ }
284
300
  //#endregion
285
- export { ItemRetainer, TextRetainer, describeOmitted, formatRetentionNotice };
301
+ export { ItemRetainer, TextRetainer, describeOmitted, formatRetentionNotice, truncateWithoutSplittingSurrogatePair };
@@ -222,4 +222,16 @@ export declare function describeOmitted(omitted: Omitted, unit: RetentionNotice[
222
222
  * @returns The combined footer line.
223
223
  */
224
224
  export declare function formatRetentionNotice(notice: RetentionNotice, recovery: (notice: RetentionNotice) => string): string;
225
+ /**
226
+ * Cap `text` at `maxChars` UTF-16 code units without introducing a lone high
227
+ * surrogate: a cut that lands inside a surrogate pair drops the unpaired half,
228
+ * so the result is one code unit shorter than the cap. An unpaired surrogate is
229
+ * not well-formed text — a strict JSON reader rejects a durable Session log that
230
+ * carries one. An unpaired surrogate `text` already carries is not repaired here.
231
+ *
232
+ * @param text The text to cap.
233
+ * @param maxChars The maximum number of UTF-16 code units to retain.
234
+ * @returns A prefix of `text` no longer than `maxChars`; the cut never introduces a lone high surrogate.
235
+ */
236
+ export declare function truncateWithoutSplittingSurrogatePair(text: string, maxChars: number): string;
225
237
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-output-retention",
3
3
  "description": "Zero-dependency bounded-retention primitive: ItemRetainer/TextRetainer + neutral notice helpers (what did we keep, what did we omit)",
4
- "version": "0.1.7-alpha.2",
4
+ "version": "0.1.7-rc.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },