@deepseek-ai/dsh-spill 0.1.1-rc.2 → 0.1.2-alpha.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
@@ -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/spill/spill/README.md
5
- README.md: f36dccfa1e6f1f21e80c0b0aa97ee150a0f5fd45
6
- README.zh.md: 64f0a99bd1cdb10af2bbe0007de802d8ce658b7a
5
+ README.md: 735c628f3aef6fa4b76d45a69375a2a2a8b72898
6
+ README.zh.md: 1953368bb9010f64d76b2691a45e82780e150ea7
package/README.md CHANGED
@@ -1,36 +1,126 @@
1
+ ---
2
+ description: "The spill storage service: how deployments and plugin authors save oversized tool text and get back a retrievable locator."
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-spill
2
7
 
3
8
  English | [中文](README.zh.md)
4
9
 
5
- The **`SpillStore`** (`ctx.spillStore`) defines WHAT a spill backend does — persist a tool's oversized text and return a model-facing locator plus retrieval guidance — without saying HOW.
10
+ ## Summary
6
11
 
7
- This package is one third of the spill capability, split so each concern evolves (and swaps) independently:
12
+ `dsh-spill` lets any plugin or tool save oversized text through `ctx.spillStore` and receive an opaque locator, the exact byte count, and retrieval guidance the model can act on. It defines what a spill backend does, not how it stores a deployment mounts a backend such as `dsh-spill-local` for real persistence, and the `dsh-spill-policy` plugin decides when a tool result is too large. Choose it when a deployment must keep oversized tool output retrievable without flooding the model's context. The service owns storage only: no retention policy, no tool-result replacement, and no retrieval or search API. A real storage failure rejects loudly, so the caller decides how to degrade.
8
13
 
9
- | Package | Role |
10
- |---|---|
11
- | `@deepseek-ai/dsh-spill` (this) | Service Definition: abstract service + vocabulary types |
12
- | `@deepseek-ai/dsh-spill-local` | Service Provider: private session-scoped files on the host filesystem |
13
- | `@deepseek-ai/dsh-spill-policy` | Consumer: the tool-result policy that spills oversized final results |
14
+ ## Table of Contents
15
+
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Model Experience](#model-experience)
20
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
21
+ - [Dev Note](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## Use this package
27
+
28
+ A composition that spills tool output mounts one spill backend — this package alone stores nothing — and the `dsh-spill-policy` plugin decides when to spill. Plugin and tool authors call `ctx.spillStore.saveText()` directly to persist text under the current session.
29
+
30
+ ### When to choose it
31
+
32
+ Choose spill storage when a deployment needs to keep oversized tool output retrievable after the model has only seen a bounded preview — for example a fetched page body the model may want to read or grep later. You do not need this package when no tool in the composition produces results large enough to matter, or when the deployment has no local filesystem the model's tools can read; a backend whose locator is meaningful in that environment is a prerequisite.
33
+
34
+ ### Smallest working composition
35
+
36
+ Mount a backend and the policy together; with `maxInlineBytes` set, any oversized plain-text tool result becomes a preview plus a locator automatically.
37
+
38
+ ```yaml
39
+ - name: '@deepseek-ai/dsh-spill-local'
40
+ - name: '@deepseek-ai/dsh-spill-policy'
41
+ config:
42
+ maxInlineBytes: 50000
43
+ ```
44
+
45
+ ### Saving text
46
+
47
+ With a backend mounted, call `ctx.spillStore.saveText()` with the owning session, a source description, a suggested file name, and the full text:
48
+
49
+ ```text
50
+ const ref = await ctx.spillStore.saveText({
51
+ owner: { sessionId: 'session-1' },
52
+ source: { toolName: 'web_fetch', callId: 'call-1', label: 'result' },
53
+ suggestedName: 'web_fetch.txt',
54
+ content: fullText,
55
+ })
56
+ ```
57
+
58
+ The returned `SpillRef` carries three fields: `locator`, an opaque model-facing handle the backend produces (a local file path for `dsh-spill-local`, possibly a URI or key for another backend); `bytes`, the exact UTF-8 byte count written; and `retrievalHint`, the guidance a consumer shows the model — for the local backend, read or grep the path. Consumers render the locator with the hint and never parse the locator itself.
59
+
60
+ ### Ownership and boundaries
61
+
62
+ Storage is grouped by the owning session: forked sessions inherit existing locators from the seeded log without copying or re-owning them, and new spills after a fork use the child session id. `suggestedName` is only a hint — backends sanitize it to one safe segment and never trust it as a path. The service deliberately excludes what other packages own: retention and preview decisions (`dsh-output-retention`), when to spill (`dsh-spill-policy`), and retrieval or search (the backend's `retrievalHint` tells the model what to do with the locator).
63
+
64
+ ### Failures and recovery
65
+
66
+ `saveText` rejects only on a real storage failure — permissions, no space left, or a backend that is down. The caller decides how to degrade: the shipped policy treats a rejection as best-effort, logs a warning, and keeps the original inline result, so a spill failure never turns a successful tool call into an error or hides content. If no backend is mounted, there is nothing to save; load `dsh-spill-local` or another backend in the composition.
67
+
68
+ -----
69
+
70
+ <a id="understand-the-implementation"></a>
71
+ ## Understand the implementation
14
72
 
15
- The split mirrors the shell/fs seams. A future remote or virtual backend (e.g. a `spill://…` URI, a database key, or a backend-specific retrieval tool) implements this Service Definition without touching the policy plugin.
73
+ <details>
74
+ <summary>Implementation internals — click to expand</summary>
16
75
 
17
- ## Service API (`ctx.spillStore`)
76
+ This section explains the design decisions behind the service; the observable behavior is fully covered in [Use this package](#use-this-package).
18
77
 
19
- | Member | Semantics |
78
+ ### Design philosophy
79
+
80
+ The package is built on one separation and a deliberate minimum:
81
+
82
+ - **Contract, implementation, and policy stay separate.** This package defines what a backend does (`saveText`); `dsh-spill-local` implements it; `dsh-spill-policy` decides when. Each concern evolves and swaps independently.
83
+ - **One method, nothing else.** The seam owns no retention policy, no result replacement, and no retrieval or search API — those have owning packages.
84
+ - **Reject, never silently degrade at the seam.** The caller owns degradation; the seam reports real storage failures.
85
+
86
+ ### Source map
87
+
88
+ | File | Role |
20
89
  |---|---|
21
- | `saveText(input)` | Persist `input.content` verbatim; resolves with a `SpillRef` (opaque locator, exact bytes written, and retrieval hint). **Rejects on a real storage failure** (permissions, ENOSPC, backend unavailable) — the caller decides how to degrade. |
90
+ | [`src/index.ts`](src/index.ts) | Plugin entry: the abstract `SpillStore` service and its `saveText` contract |
91
+ | [`src/types.ts`](src/types.ts) | Vocabulary: `SaveTextSpill`, `SpillRef`, branded `SpillLocator`, `SpillOwner`, `SpillSource` |
92
+ | [`src/invariant.ts`](src/invariant.ts) | Invariant companion (no runtime invariant; contracts are enforced at the seam) |
93
+
94
+ ### Data model
95
+
96
+ `SaveTextSpill` (owner, source, suggestedName, content) is the request; `SpillRef` (locator, bytes, retrievalHint) is the result. `SpillLocator` is a branded string so consumers cannot treat it as a path without the backend's intent; `SpillOwner.sessionId` is the save-time storage namespace, and `SpillSource` records the producing tool, call id, and label for readable filenames — descriptive only, never access control.
22
97
 
23
- Storage is grouped by the request's `owner` session as a save-time namespace; the backend chooses its own private representation and may derive names from — never trust as a path — the caller's `suggestedName`. The seam owns storage only: NO retention policy (that is [`@deepseek-ai/dsh-output-retention`](../../util/output-retention)), NO tool-result replacement (that is `@deepseek-ai/dsh-spill-policy`), NO retrieval/search API (the backend's `retrievalHint` tells the model what to do with the locator).
98
+ ### Lifecycle
24
99
 
25
- ## Vocabulary
100
+ A backend subclasses `SpillStore` and loads as a plugin, registering as `ctx.spillStore`; one implementation per context, and a second load fails. Disposal releases the service. The abstract class itself registers nothing — this package contributes the contract and vocabulary only.
26
101
 
27
- `SaveTextSpill` (owner, source, suggestedName, content) is the request; `SpillRef` (locator, bytes, retrievalHint) is the result. `SpillLocator` is [branded](../../util/brand) and rendered to the model as an opaque string — a local path for `dsh-spill-local`, but a future backend may return a URI, key, or command token without changing policy/tool consumers. `SpillOwner.sessionId` is the save-time storage namespace: forked sessions inherit existing locators from the seeded log without copying or re-owning them, and new spills after the fork use the child session id. `SpillSource` records the producing `toolName`, `callId`, and `label` for backend naming and inspection, not access control. See `src/types.ts` for the full contracts.
102
+ </details>
28
103
 
29
- See the [tool output spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md) for the design rationale, including why creation belongs to the runtime spill seam rather than the model-facing `write` tool.
104
+ -----
30
105
 
106
+ <a id="further-exploration"></a>
107
+ ## Further Exploration
108
+
109
+ Read these pages when the package-level contract is not enough. They move from the shared vocabulary to the shipped backend, the policy, and the design rationale.
110
+
111
+ - [Spill subsystem](../../../docs/subsystems/spill.md) — the exhaustive vocabulary, ownership, and backend relationships.
112
+ - [Spill package map](../README.md) — the three-package family and each role.
113
+ - [dsh-spill-local](../spill-local/README.md) — the shipped local filesystem backend.
114
+ - [dsh-spill-policy](../spill-policy/README.md) — the policy that decides when a final result is too large.
115
+ - [dsh-output-retention](../../util/output-retention/README.md) — the preview mechanics behind the policy.
116
+ - [Tool output spill decision](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md) — the capability boundary and design rationale.
117
+
118
+ -----
119
+
120
+ <a id="model-experience"></a>
31
121
  ## Model Experience
32
122
 
33
- Indirectly, through spill consumers that render a backend locator and retrieval guidance.
123
+ Indirectly, through spill consumers, which render the backend's locator and retrieval guidance to the model.
34
124
 
35
125
  #### KV Cache effect
36
126
 
@@ -38,5 +128,28 @@ No direct invalidation; the named consumer owns any request-prefix changes.
38
128
 
39
129
  ## Known Limitations and Deferred Work
40
130
 
41
- - **The seam has no retrieval or deletion API** — consumers can only render the backend's locator and guidance; lifecycle and access semantics remain backend-specific.
42
- - **Storage is not access control** — `SpillOwner` namespaces writes but does not authorize reads of a locator; each backend and retrieval consumer must enforce its own boundary.
131
+ <a id="known-limitations-and-deferred-work"></a>
132
+
133
+
134
+ These limits define when the spill storage service is incomplete on its own. They are current package constraints.
135
+
136
+ - **No retrieval or deletion API** — consumers can only render the backend's locator and guidance; lifecycle and access semantics remain backend-specific.
137
+ - **Storage is not access control** — the owner session namespaces writes but does not authorize reads of a locator; each backend and retrieval consumer must enforce its own boundary.
138
+
139
+ <a id="dev-note"></a>
140
+ ### Dev Note
141
+
142
+ <details>
143
+ <summary>Working context for maintainers — click to expand</summary>
144
+
145
+ This Dev Note is working context for maintainers: undecided directions and open questions. It is explicitly non-authoritative.
146
+
147
+ #### Future: executor spill-file integration
148
+
149
+ The seam has only `saveText`; a save-file or link/copy path for existing executor spill files (for example normalizing bash temp files) and tool-owned spill for subagent rollouts remain deferred, per the [tool output spill decision](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md).
150
+
151
+ #### Future: non-local backends and cleanup
152
+
153
+ Remote or database backends for ACP or remote environments, and a cleanup or retention policy for old spill files (likely tied to session cleanup), remain open. A predictable, world-readable spill root would let other local users read spilled tool output, which is why the shipped backend keeps files private.
154
+
155
+ </details>
package/README.zh.md CHANGED
@@ -1,42 +1,155 @@
1
+ ---
2
+ description: "spill 存储服务:部署方与插件作者如何保存过大的工具文本并取回可检索的定位信息。"
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-spill
2
7
 
3
8
  [English](README.md) | 中文
4
9
 
5
- **`SpillStore`**(`ctx.spillStore`)定义 spill 后端做什么,即持久化某个工具过大的文本,并返回面向模型的定位信息与取回指引;它不规定如何实现。
10
+ ## 概述
6
11
 
7
- 该包是 spill 能力的三个组成部分之一。拆分后,各项关注点可独立演进和替换:
12
+ `dsh-spill` 让任何插件或工具都能通过 `ctx.spillStore` 保存过大的文本,并拿到一个不透明定位信息、精确的字节数与模型可以直接依据的取回指引。它定义 spill 后端做什么,而不规定如何存储——部署需要挂载 `dsh-spill-local` 之类的后端才能真正持久化,由 `dsh-spill-policy` 插件决定工具结果何时过大。当部署必须在不让模型上下文泛滥的前提下保留超大工具输出时,选择它。该服务只负责存储:没有保留策略、没有工具结果替换,也没有取回或搜索 API。真实存储故障会以拒绝结束,由调用方决定如何降级。
8
13
 
9
- | 包 | 职责 |
10
- |---|---|
11
- | `@deepseek-ai/dsh-spill`(本包) | Service Definition:抽象服务与词汇类型 |
12
- | `@deepseek-ai/dsh-spill-local` | Service Provider:位于宿主文件系统中的私有会话级文件 |
13
- | `@deepseek-ai/dsh-spill-policy` | Consumer:对过大最终结果执行 spill 的工具结果策略 |
14
+ ## 目录
15
+
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
22
+
23
+ -----
24
+
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
27
+
28
+ 需要 spill 工具输出的组合会挂载一个 spill 后端——仅本包本身不存储任何内容——并由 `dsh-spill-policy` 插件决定何时 spill。插件与工具作者直接调用 `ctx.spillStore.saveText()`,在当前会话下持久化文本。
29
+
30
+ ### 何时选择
31
+
32
+ 当部署需要在模型只看到有界预览之后仍可检索超大的工具输出时,选择 spill 存储——例如模型稍后可能想读取或搜索的抓取页面正文。当组合中没有工具会产生大到值得处理的输出,或部署没有模型工具可读取的本地文件系统时,你不需要本包;此时需要的是一个在该环境中定位信息有明确含义的后端。
33
+
34
+ ### 最小可用组合
35
+
36
+ 把后端与策略一起挂载;设置 `maxInlineBytes` 后,任何过大的纯文本工具结果都会自动变成预览加定位信息。
37
+
38
+ ```yaml
39
+ - name: '@deepseek-ai/dsh-spill-local'
40
+ - name: '@deepseek-ai/dsh-spill-policy'
41
+ config:
42
+ maxInlineBytes: 50000
43
+ ```
44
+
45
+ ### 保存文本
46
+
47
+ 挂载后端后,用所属会话、来源描述、建议文件名与完整文本调用 `ctx.spillStore.saveText()`:
48
+
49
+ ```text
50
+ const ref = await ctx.spillStore.saveText({
51
+ owner: { sessionId: 'session-1' },
52
+ source: { toolName: 'web_fetch', callId: 'call-1', label: 'result' },
53
+ suggestedName: 'web_fetch.txt',
54
+ content: fullText,
55
+ })
56
+ ```
57
+
58
+ 返回的 `SpillRef` 携带三个字段:`locator`,后端产生的不透明模型面向句柄(对 `dsh-spill-local` 是本地文件路径,对其他后端可能是 URI 或键);`bytes`,写入的精确 UTF-8 字节数;`retrievalHint`,消费方展示给模型的指引——对本地后端而言是读取或搜索该路径。消费方按指引渲染定位信息,绝不自行解析定位信息。
59
+
60
+ ### 归属与边界
61
+
62
+ 存储按所属会话分组:fork 后的会话从种子日志继承既有定位信息,无需复制或更改归属,fork 后新产生的 spill 使用子会话 id。`suggestedName` 只是提示——后端会把它清理成单个安全路径段,绝不把它当作可信路径。该服务刻意排除其他包负责的内容:保留与预览决策(`dsh-output-retention`)、何时 spill(`dsh-spill-policy`),以及取回或搜索(后端的 `retrievalHint` 会告诉模型如何处理定位信息)。
63
+
64
+ ### 故障与恢复
65
+
66
+ `saveText` 只在真实存储故障时拒绝——权限不足、磁盘已满或后端不可用。由调用方决定如何降级:随附策略把拒绝当作尽力而为处理,记录警告并保留原始内联结果,因此 spill 失败绝不会把成功的工具调用变成错误或隐藏内容。如果没有挂载后端,就没有可保存的目标;请在组合中加载 `dsh-spill-local` 或其他后端。
67
+
68
+ -----
69
+
70
+ <a id="understand-the-implementation"></a>
71
+ ## 理解实现
14
72
 
15
- 这种拆分方式与 shell/fs seam 相同。未来的远程或虚拟后端(例如 `spill://…` URI、数据库键或后端专用取回工具)可实现此 Service Definition,无需修改策略插件。
73
+ <details>
74
+ <summary>实现细节——点击展开</summary>
16
75
 
17
- ## 服务 API(`ctx.spillStore`)
76
+ 本节解释该服务背后的设计决策;可观察行为已在[使用本包](#use-this-package)中完整说明。
18
77
 
19
- | 成员 | 语义 |
78
+ ### 设计理念
79
+
80
+ 本包建立在一个分离与刻意的极简之上:
81
+
82
+ - **约定、实现与策略保持分离。** 本包定义后端做什么(`saveText`);`dsh-spill-local` 实现它;`dsh-spill-policy` 决定何时触发。各项关注点独立演进与替换。
83
+ - **只有一个方法,别无其他。** 该 seam 不负责保留策略、结果替换或取回/搜索 API——那些都有各自的归属包。
84
+ - **在 seam 处拒绝,绝不静默降级。** 降级由调用方负责;seam 报告真实存储故障。
85
+
86
+ ### 源码地图
87
+
88
+ | 文件 | 职责 |
20
89
  |---|---|
21
- | `saveText(input)` | 逐字保存 `input.content`;成功时返回 `SpillRef`(不透明定位信息、写入的精确字节数和取回指引)。**发生真实存储故障时,调用会以拒绝状态结束**(权限、ENOSPC、后端不可用);由调用方决定如何降级。 |
90
+ | [`src/index.ts`](src/index.ts) | 插件入口:抽象 `SpillStore` 服务及其 `saveText` 约定 |
91
+ | [`src/types.ts`](src/types.ts) | 词汇:`SaveTextSpill`、`SpillRef`、带品牌类型 `SpillLocator`、`SpillOwner`、`SpillSource` |
92
+ | [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件(无运行时不变式;约定在 seam 处强制执行) |
93
+
94
+ ### 数据模型
95
+
96
+ `SaveTextSpill`(owner、source、suggestedName、content)是请求;`SpillRef`(locator、bytes、retrievalHint)是结果。`SpillLocator` 是带品牌类型的字符串,消费方无法在未获后端意图的情况下把它当作路径;`SpillOwner.sessionId` 是保存时存储命名空间,`SpillSource` 记录产生 spill 的工具、调用 id 与标签,用于可读文件名——仅作描述,绝非访问控制。
22
97
 
23
- 存储操作以请求的 `owner` 会话作为保存时命名空间进行分组;后端自行选择私有表示,并可以从调用方的 `suggestedName` 派生名称,但绝不能将其当作可信路径。该 seam 只负责存储:不提供保留策略(由 [`@deepseek-ai/dsh-output-retention`](../../util/output-retention) 负责),不替换工具结果(由 `@deepseek-ai/dsh-spill-policy` 负责),也不提供取回/搜索 API(后端的 `retrievalHint` 会告诉模型如何使用定位信息)。
98
+ ### 生命周期
24
99
 
25
- ## 词汇
100
+ 后端继承 `SpillStore` 并以插件方式加载,注册为 `ctx.spillStore`;每个上下文只有一个实现,第二次加载会失败。dispose 会释放该服务。抽象类本身不注册任何内容——本包只提供约定与词汇。
26
101
 
27
- `SaveTextSpill`(owner、source、suggestedName、content)是请求;`SpillRef`(locator、bytes、retrievalHint)是结果。`SpillLocator` 是[带品牌类型](../../util/brand)的值,并以不透明字符串的形式呈现给模型;对 `dsh-spill-local` 而言它是本地路径,但未来的后端可以返回 URI、键或命令 token,无需修改策略/工具消费方。`SpillOwner.sessionId` 是保存时存储命名空间:fork 后的会话会从种子日志继承现有定位信息,无需复制或更改其归属;fork 后新产生的 spill 使用子会话 id。`SpillSource` 记录产生该 spill 的 `toolName`、`callId` 和 `label`,供后端命名和检查使用,不用于访问控制。完整约定见 `src/types.ts`。
102
+ </details>
28
103
 
29
- 设计原理见[工具输出 spill Agent Note](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.zh.md),其中说明了为什么创建操作应由运行时 spill seam 而非面向模型的 `write` 工具承担。
104
+ -----
30
105
 
106
+ <a id="further-exploration"></a>
107
+ ## 进一步探索
108
+
109
+ 当包级约定不够用时阅读以下页面。它们从共享词汇逐步进入已交付后端、策略与设计依据。
110
+
111
+ - [spill 子系统](../../../docs/subsystems/spill.zh.md)——穷尽式词汇、归属与后端关系。
112
+ - [spill 包映射](../README.zh.md)——三包家族与各自职责。
113
+ - [dsh-spill-local](../spill-local/README.zh.md)——已交付的本地文件系统后端。
114
+ - [dsh-spill-policy](../spill-policy/README.zh.md)——决定最终结果何时过大的策略。
115
+ - [dsh-output-retention](../../util/output-retention/README.zh.md)——策略背后的预览机制。
116
+ - [工具输出 spill 决策](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.zh.md)——能力边界与设计依据。
117
+
118
+ -----
119
+
120
+ <a id="model-experience"></a>
31
121
  ## 模型体验
32
122
 
33
- 通过渲染后端定位信息和取回指引的 spill 消费方间接影响模型。
123
+ 间接地,通过把后端定位信息与取回指引渲染给模型的 spill 消费方。
34
124
 
35
125
  #### KV Cache 影响
36
126
 
37
- 不会直接导致 KV Cache 失效;请求前缀变更由上述消费方负责。
127
+ 无直接失效;请求前缀变更由上述消费方负责。
128
+
129
+ ## 已知限制与延期工作
130
+
131
+ <a id="known-limitations-and-deferred-work"></a>
132
+
133
+
134
+ 这些限制说明 spill 存储服务单独使用时在哪些方面不完整。它们是当前的包约束。
135
+
136
+ - **没有取回或删除 API**——消费方只能渲染后端的定位信息与指引;生命周期与访问语义仍由后端自行决定。
137
+ - **存储不等于访问控制**——所属会话区分写入命名空间,但不会授权通过定位信息读取内容;每个后端与取回消费方都必须自行强制执行访问边界。
138
+
139
+ <a id="dev-note"></a>
140
+ ### 开发备注
141
+
142
+ <details>
143
+ <summary>维护者的工作上下文——点击展开</summary>
144
+
145
+ 本开发备注是维护者的工作上下文:尚未决定的探索方向与开放问题。它明确不具权威性。
146
+
147
+ #### 未来:执行器 spill 文件集成
148
+
149
+ 该 seam 只有 `saveText`;为既有执行器 spill 文件提供保存文件或链接/复制路径(例如规范化 bash 临时文件),以及为 subagent 展开提供工具自有 spill,仍然延期,见[工具输出 spill 决策](../../../.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.zh.md)。
150
+
151
+ #### 未来:非本地后端与清理
38
152
 
39
- ## 已知限制与暂缓事项
153
+ 面向 ACP 或远程环境的远程或数据库后端,以及旧 spill 文件的清理或保留策略(很可能与会话清理挂钩),仍是开放问题。可预测且任何用户均可读取的 spill 根目录会让其他本地用户读到 spill 工具输出,这正是已交付后端把文件保持私有的原因。
40
154
 
41
- - **该 seam 没有取回或删除 API**:消费方只能渲染后端的定位信息与指引;生命周期和访问语义仍由后端自行决定。
42
- - **存储不等于访问控制**:`SpillOwner` 会区分写入命名空间,但不会授予通过定位信息读取内容的权限;每个后端和取回消费方都必须自行强制执行访问边界。
155
+ </details>
@@ -6,7 +6,7 @@
6
6
  * @module @deepseek-ai/dsh-spill/types
7
7
  */
8
8
  import type { Branded } from '@deepseek-ai/dsh-brand';
9
- import type { CallId } from '@deepseek-ai/dsh-llm';
9
+ import type { ToolCallId } from '@deepseek-ai/dsh-llm';
10
10
  import type { SessionId } from '@deepseek-ai/dsh-session';
11
11
  /**
12
12
  * Opaque model-facing handle for one spilled artifact. A local backend may use a
@@ -40,7 +40,7 @@ export interface SpillSource {
40
40
  /** The tool whose result was spilled (e.g. `web_fetch`). */
41
41
  toolName: string;
42
42
  /** The model-issued call id the result belongs to. */
43
- callId: CallId;
43
+ callId: ToolCallId;
44
44
  /** A short human label for the artifact (e.g. `result`). */
45
45
  label: string;
46
46
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-spill",
3
3
  "description": "Abstract spill storage seam (ctx.spillStore) for the DeepSeek Harness — save oversized tool text and return a retrieval locator",
4
- "version": "0.1.1-rc.2",
4
+ "version": "0.1.2-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,17 +32,17 @@
32
32
  ],
33
33
  "license": "MIT",
34
34
  "peerDependencies": {
35
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
36
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
37
- "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
38
- "@deepseek-ai/cordis": "^4.0.1",
39
- "@deepseek-ai/dsh-brand": "^0.1.1-rc.2"
35
+ "@deepseek-ai/dsh-brand": "^0.1.2-alpha.2",
36
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
37
+ "@deepseek-ai/dsh-llm": "^0.1.2-alpha.2",
38
+ "@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
39
+ "@deepseek-ai/cordis": "^4.0.2"
40
40
  },
41
41
  "devDependencies": {
42
- "@deepseek-ai/dsh-brand": "^0.1.1-rc.2",
43
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
44
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
45
- "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
46
- "@deepseek-ai/cordis": "^4.0.1"
42
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
43
+ "@deepseek-ai/dsh-llm": "^0.1.2-alpha.2",
44
+ "@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
45
+ "@deepseek-ai/cordis": "^4.0.2",
46
+ "@deepseek-ai/dsh-brand": "^0.1.2-alpha.2"
47
47
  }
48
48
  }