@qlzt/dsh-tool-fs 0.0.0-stage → 0.2.1-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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepSeek
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,142 @@
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
+ # pnpm run verify-translation-pairing --write packages/fs/tool-fs/README.md
5
+ /:
6
+ en: 52b93805befe8077
7
+ zh: 9786e662303f0e2f
8
+ /deepseek-ai-dsh-tool-fs:
9
+ en: fc8f28deebe5fa6b
10
+ zh: 738c6ad45034da88
11
+ /deepseek-ai-dsh-tool-fs/summary:
12
+ en: c8f608c85c8d6626
13
+ zh: 4133a867517baca5
14
+ /deepseek-ai-dsh-tool-fs/table-of-contents:
15
+ en: d152484eb41ac6b4
16
+ zh: 09388d293f9be9cb
17
+ /deepseek-ai-dsh-tool-fs/use-this-package:
18
+ en: c7da73c9e2691ea1
19
+ zh: 0eba82c1c3553ab9
20
+ /deepseek-ai-dsh-tool-fs/use-this-package/minimal-composition:
21
+ en: eb21d89a3ecbd2d4
22
+ zh: f05ccbb1e7515f32
23
+ /deepseek-ai-dsh-tool-fs/use-this-package/the-tools:
24
+ en: 29a1d47e9677f2a3
25
+ zh: 0ae3c794cc7c54db
26
+ /deepseek-ai-dsh-tool-fs/use-this-package/configuration:
27
+ en: 7eb705e3b132fcba
28
+ zh: 883207b13d381f9e
29
+ /deepseek-ai-dsh-tool-fs/use-this-package/policy-and-sandbox-behavior:
30
+ en: 53d4ac2db089ef39
31
+ zh: 214ea051ed56f500
32
+ /deepseek-ai-dsh-tool-fs/use-this-package/failures-and-recovery:
33
+ en: 962b09e21305a04b
34
+ zh: 382d2b8cce217569
35
+ /deepseek-ai-dsh-tool-fs/understand-the-implementation:
36
+ en: e30f7038c28e93f8
37
+ zh: a3868dbd90367b13
38
+ /deepseek-ai-dsh-tool-fs/understand-the-implementation/design-concept:
39
+ en: 454b5291db9ba847
40
+ zh: 9fe7081dfb416c93
41
+ /deepseek-ai-dsh-tool-fs/understand-the-implementation/source-map:
42
+ en: ec1517d657fbce14
43
+ zh: be0038b88f7b68fc
44
+ /deepseek-ai-dsh-tool-fs/understand-the-implementation/per-tool-flow:
45
+ en: d741e01be9fddb76
46
+ zh: 7aa1d7ca719a4aac
47
+ /deepseek-ai-dsh-tool-fs/understand-the-implementation/observation-and-concurrency:
48
+ en: 665d437dc35bf05f
49
+ zh: 8004334d6a3246b4
50
+ /deepseek-ai-dsh-tool-fs/further-exploration:
51
+ en: 485bc55482f576bc
52
+ zh: fc5fa55b41098bd0
53
+ /deepseek-ai-dsh-tool-fs/model-experience:
54
+ en: 215e7ba838619b7b
55
+ zh: a311da3843709f90
56
+ /deepseek-ai-dsh-tool-fs/model-experience/system-prompt:
57
+ en: cf78b9dd5596495f
58
+ zh: bd44560f8c2435e8
59
+ /deepseek-ai-dsh-tool-fs/model-experience/system-prompt/what-the-model-sees:
60
+ en: b09ee4be5e522c29
61
+ zh: ffd30b57d7fc96e8
62
+ /deepseek-ai-dsh-tool-fs/model-experience/system-prompt/what-the-model-sees/read-guidance:
63
+ en: f8961df3f3a6a671
64
+ zh: 85c7bd418b40b089
65
+ /deepseek-ai-dsh-tool-fs/model-experience/system-prompt/what-the-model-sees/write-guidance:
66
+ en: 7e34af48c583f210
67
+ zh: e39ad6823689c665
68
+ /deepseek-ai-dsh-tool-fs/model-experience/system-prompt/what-the-model-sees/edit-guidance:
69
+ en: 28f07502a411303b
70
+ zh: 437897dc99fc4360
71
+ /deepseek-ai-dsh-tool-fs/model-experience/system-prompt/token-effect:
72
+ en: 7a44cabe439a879a
73
+ zh: 1adf9bf3de7658b6
74
+ /deepseek-ai-dsh-tool-fs/model-experience/system-prompt/kv-cache-effect:
75
+ en: 4f1b5639f91405a8
76
+ zh: f90ffe077a2e52a3
77
+ /deepseek-ai-dsh-tool-fs/model-experience/tool-schemas:
78
+ en: 3039bc5e7a796b21
79
+ zh: 6b7a9eaf69c9ea53
80
+ /deepseek-ai-dsh-tool-fs/model-experience/tool-schemas/what-the-model-sees:
81
+ en: 6f2a072c474e39e7
82
+ zh: dbee4c2b206bf68f
83
+ /deepseek-ai-dsh-tool-fs/model-experience/tool-schemas/token-effect:
84
+ en: 68517f7d65ef7e9d
85
+ zh: 544a4b81e8ea16c0
86
+ /deepseek-ai-dsh-tool-fs/model-experience/tool-schemas/kv-cache-effect:
87
+ en: 1e6d3da20012762d
88
+ zh: 482f8bc569b8b490
89
+ /deepseek-ai-dsh-tool-fs/model-experience/read-result:
90
+ en: ebd38733c0490428
91
+ zh: b45101c325efe784
92
+ /deepseek-ai-dsh-tool-fs/model-experience/read-result/what-the-model-sees:
93
+ en: 8f7a10746df88c03
94
+ zh: d4fab398b14db940
95
+ /deepseek-ai-dsh-tool-fs/model-experience/read-result/token-effect:
96
+ en: 4269b4368622ec2f
97
+ zh: f4df80c1fb6972f1
98
+ /deepseek-ai-dsh-tool-fs/model-experience/read-result/kv-cache-effect:
99
+ en: f5d5f97a153f7c70
100
+ zh: 3d6bc05b9eadfbc2
101
+ /deepseek-ai-dsh-tool-fs/model-experience/image-read-result:
102
+ en: 9dac44e6d0b9d8de
103
+ zh: 7bc4dc1c5df39eaf
104
+ /deepseek-ai-dsh-tool-fs/model-experience/image-read-result/what-the-model-sees:
105
+ en: 9b5070a15f565c20
106
+ zh: 96043df8c0ae7f76
107
+ /deepseek-ai-dsh-tool-fs/model-experience/image-read-result/token-effect:
108
+ en: 68bd5255f1c9ca48
109
+ zh: 0474213531c1aae3
110
+ /deepseek-ai-dsh-tool-fs/model-experience/image-read-result/kv-cache-effect:
111
+ en: f5d5f97a153f7c70
112
+ zh: 48e202e396bc5fcc
113
+ /deepseek-ai-dsh-tool-fs/model-experience/write-and-edit-results:
114
+ en: 1b3b6cfa3605d0b4
115
+ zh: 78e37c2aa4f76d54
116
+ /deepseek-ai-dsh-tool-fs/model-experience/write-and-edit-results/what-the-model-sees:
117
+ en: 816b07ebfddab5f8
118
+ zh: 0e80580a5902c7ed
119
+ /deepseek-ai-dsh-tool-fs/model-experience/write-and-edit-results/token-effect:
120
+ en: fb4d0b17a99f49cf
121
+ zh: 17460a2a5d72f6cc
122
+ /deepseek-ai-dsh-tool-fs/model-experience/write-and-edit-results/kv-cache-effect:
123
+ en: f5d5f97a153f7c70
124
+ zh: 3d6bc05b9eadfbc2
125
+ /deepseek-ai-dsh-tool-fs/model-experience/tool-errors:
126
+ en: 2d4f2c8605eccab3
127
+ zh: 67f1f0218f73c6bf
128
+ /deepseek-ai-dsh-tool-fs/model-experience/tool-errors/what-the-model-sees:
129
+ en: 4e8fac7bac8ced61
130
+ zh: 7ba921dbcddc9f97
131
+ /deepseek-ai-dsh-tool-fs/model-experience/tool-errors/token-effect:
132
+ en: 681cadd5be7b8ac1
133
+ zh: 65e483f62fb819d9
134
+ /deepseek-ai-dsh-tool-fs/model-experience/tool-errors/kv-cache-effect:
135
+ en: f5d5f97a153f7c70
136
+ zh: 3d6bc05b9eadfbc2
137
+ /deepseek-ai-dsh-tool-fs/known-limitations-and-deferred-work:
138
+ en: ce7a91d41d2f7597
139
+ zh: d4a3c905e124fd7f
140
+ /deepseek-ai-dsh-tool-fs/known-limitations-and-deferred-work/dev-note:
141
+ en: e67f633dc6fe7773
142
+ zh: 3bb0c20c93f16f98
package/README.md CHANGED
@@ -1,3 +1,260 @@
1
- # Temporary Holding Version
1
+ ---
2
+ description: "The model-facing read, read_image, write, and edit tools for users and maintainers composing or debugging filesystem access for agents."
3
+ kind: "package-reference"
4
+ ---
2
5
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
6
+ # @deepseek-ai/dsh-tool-fs
7
+
8
+ English | [中文](README.zh.md)
9
+
10
+ ## Summary
11
+
12
+ Use `dsh-tool-fs` to let a model read UTF-8 files with line numbers, read supported images, create or atomically replace files, and apply targeted literal edits. Results are capped, and failures provide stable error codes and recovery instructions. Add `dsh-fs-observation-policy` when writes and edits must follow a successful read; without it, mutations remain atomic but are unconditional. Image reads require durable attachment storage and an image-capable routed model. Choose the sibling discovery package for glob or grep searches.
13
+
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
+ Relative paths use the Session's current working directory. A directory change affects subsequent reads and mutations without changing sandbox permission roots. Successful results return the canonical absolute path from `fs.processPath`, and root result metadata retains that operation-time path for replay and navigation.
29
+
30
+ Mount the tools after a `ctx.fs` backend and, for read-before-write/edit behavior, the policy plugin. The model then gets line-numbered reads, atomic writes and edits, and — with an attachment store mounted — image reads; every result is capped, and failures carry stable codes with recovery instructions.
31
+
32
+ ### Minimal composition
33
+
34
+ A backend, the policy plugin, then the tools; the attachment store is optional and enables `read_image`.
35
+
36
+ ```yaml
37
+ - name: '@deepseek-ai/dsh-fs-local'
38
+ - name: '@deepseek-ai/dsh-fs-observation-policy'
39
+ - name: '@deepseek-ai/dsh-tool-fs'
40
+ ```
41
+
42
+ The policy plugin is optional: without it the tools run against the bare provider (unconditional write, overwrite, and edit with no observed-state). A deployment that loads these tools is expected to also load it, so the behavior is read-before-write/edit. `read_image` registers only while a durable `ctx.attachments` service is mounted; execution additionally refuses on a route whose exact model does not declare image input, so a text route's durable history stays free of image blocks.
43
+
44
+ ### The tools
45
+
46
+ | Tool | Arguments | Behavior |
47
+ |---|---|---|
48
+ | `read` | `file_path`, `offset?`, `limit?` | Line-numbered UTF-8 content with a pagination footer; `offset` is 1-based and `limit` defaults to and caps at the configured `readLimit` |
49
+ | `read_image` | `file_path` | Reads and persists a PNG/JPEG/WebP/GIF source; an extension-less path (normalized attachment object paths included) is identified from its file signature; normalization can downscale it before the next model request, so the model need not create a thumbnail first |
50
+ | `write` | `file_path`, `content` | Creates or fully replaces a file; with the policy plugin, overwriting requires a prior `read` at the unchanged version, creating does not |
51
+ | `edit` | `file_path`, `old_string`, `new_string`, `replace_all?` | Literal replacement requiring a unique match unless `replace_all` is true; with the policy plugin, requires a prior `read` and an unchanged file |
52
+
53
+ Field names are snake_case to match Claude Code and existing harness tool schemas. The `write` and `edit` path descriptions ask the model to emit `file_path` before the content or replacement strings; this guides streaming presentation but does not enforce JSON member order. Successes return compact envelopes — a read window, an image reference, or a `Created file`/`Updated file` confirmation — and `write`/`edit` derive replayable diff-card metadata for UI presentation.
54
+
55
+ ### Configuration
56
+
57
+ All keys are optional; the defaults are the shipped read caps.
58
+
59
+ | Key | Default | Meaning |
60
+ |---|---|---|
61
+ | `readLimit` | `2000` | Default and maximum lines returned by one `read` call |
62
+ | `readMaxLineLength` | `2000` | Characters kept per line before truncation |
63
+ | `readMaxBytes` | `51200` | Byte cap on one `read` call's selected lines; overflow ends the window with a capped footer |
64
+ | `readStreamMinSize` | `10485760` | Files at or above this size (or of unknown size) stream instead of loading whole into memory |
65
+
66
+ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-tool-fs) is the exhaustive source for every accepted field and its JSDoc.
67
+
68
+ ### Policy and sandbox behavior
69
+
70
+ Path authorization for `read` and `read_image` belongs entirely to `ctx.fs`; media-type declarations and file signatures only decide whether `read_image` accepts the bytes returned by that backend.
71
+
72
+ With the policy plugin mounted, `write` and `edit` obtain their guard from the `fs/*` intent slots, so an unread target or a stale observation fails with `FS_NOT_OBSERVED` or `FS_STALE_VERSION` and a recovery instruction. Under a confining backend (`fs-sandbox`), `write`/`edit` additionally advertise `sandbox_permissions` and `justification`; a denied mutation returns the `[sandbox: file access denied under <mode> mode]` marker with the same-turn escalation hint, and an approved retry may stamp a strictly wider mode for that one call. The justification asks the model to use the language of the current user request.
73
+
74
+ ### Failures and recovery
75
+
76
+ Failures are normalized as `Error: <message>` with a structured code preserved for callers. Stable messages include `file_path must be a non-empty string`, `limit must be less than or equal to <max>`, `cannot read "<path>": not found`, `cannot read "<path>": not a regular file`, and the image-route refusal `cannot read "<path>" as an image: model "<model>" does not declare image input; switch to an image-capable model to read images`. `FS_NOT_OBSERVED` is normalized to `cannot modify "<path>": file has not been read — read the file, then retry`, independent of whether the policy or provider rejected the operation; `FS_STALE_VERSION` retains the provider's reason and appends `— re-read the file, then retry`. After the reread confirms absence, `edit` reports `FS_NOT_FOUND` instead of repeating a stale remedy, while `write` uses guarded creation.
77
+
78
+ -----
79
+
80
+ <a id="understand-the-implementation"></a>
81
+ ## Understand the implementation
82
+
83
+ <details>
84
+ <summary>Implementation internals — click to expand</summary>
85
+
86
+ This section explains the design decisions behind the tool suite and points at the code that realizes them; the observable behavior is fully covered in [Use this package](#use-this-package).
87
+
88
+ ### Design concept
89
+
90
+ The tools are the executor; policy is an event gate. The tools inject no policy service and inspect no cache — each mutation asks the single intent slot for its guard through `ctx.waterfall`, and each operation emits `fs/observed` only after it succeeded. Reads do exactly one provider `stat` (type and size routing plus the observed version); mutations do none, because the guard comes from the intent slot and the provider re-checks under its lock.
91
+
92
+ ### Source map
93
+
94
+ | File | Role |
95
+ |---|---|
96
+ | [`src/index.ts`](src/index.ts) | Plugin entry: `Config`, tool composition, `read_image` attachments gate |
97
+ | [`src/read.ts`](src/read.ts) | `read` executor: one stat, streaming decision, window build, observation |
98
+ | [`src/read-image.ts`](src/read-image.ts) | `read_image` executor: route and media-type gates, bounded bytes, attachment save |
99
+ | [`src/write.ts`](src/write.ts) | `write` executor: intent waterfall, atomic write, observation |
100
+ | [`src/edit.ts`](src/edit.ts) | `edit` executor: intent waterfall, literal edit, observation |
101
+ | [`src/read-render.ts`](src/read-render.ts) | Cordis-free windowing and envelope formatting |
102
+ | [`src/sandbox.ts`](src/sandbox.ts) | Escalation API shared by `write`/`edit`: policy resolution and denial-marker mapping |
103
+ | [`src/error.ts`](src/error.ts) | Stable model-facing diagnostics for guarded-mutation failures |
104
+ | [`src/mutation-result.ts`](src/mutation-result.ts) | Successful mutation observation and canonical result paths |
105
+
106
+ ### Per-tool flow
107
+
108
+ All four tools share one flow shape: resolve the path with the calling session's cwd, run the applicable gate, perform exactly one provider operation, and emit `fs/observed` only after success. `read` and `read_image` pay one `stat` for type and size routing; `write` and `edit` pay none because their guard comes from the intent slot, and provider failures surface as typed `FsError` results. The per-tool executors live in `src/read.ts`, `src/read-image.ts`, `src/write.ts`, and `src/edit.ts`.
109
+
110
+ ### Observation and concurrency
111
+
112
+ `fs/observed` fires after the operation succeeded via a plain `ctx.emit`; a listener is contractually a synchronous, side-effect-only recorder, so async or fallible observation does not belong on this event. `read` opts into concurrent scheduling because its only mutation is the synchronous version recorder; recorder races fail closed when a later `write` or `edit` re-checks the version under its target lock, and both mutation tools remain exclusive.
113
+
114
+ </details>
115
+
116
+ -----
117
+
118
+ <a id="further-exploration"></a>
119
+ ## Further Exploration
120
+
121
+ Read these pages when the package-level contract is not enough. They move from the tools to the contract, backends, and policy they compose with.
122
+
123
+ - [Filesystem subsystem](../../../docs/subsystems/filesystem.md) — exhaustive provider contract, policy events, and error taxonomy.
124
+ - [dsh-fs](../fs/README.md) — the `ctx.fs` contract these tools consume.
125
+ - [fs-local](../fs-local/README.md) — the host-filesystem backend these tools run against.
126
+ - [fs-sandbox](../fs-sandbox/README.md) — the sandbox-enforcing backend that adds the escalation fields.
127
+ - [fs-observation-policy](../fs-observation-policy/README.md) — the policy plugin that guards mutations through the `fs/*` events.
128
+ - [Generated tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-tool-fs) — the exhaustive schemas this package registers.
129
+
130
+ -----
131
+
132
+ <a id="model-experience"></a>
133
+ ## Model Experience
134
+
135
+ ### System prompt
136
+
137
+ #### What the model sees
138
+
139
+ At assembly time, each guidance section checks `ctx.tools.get(name, scope)` and renders only while its tool is visible to that agent. The write paragraph recommends edit only while edit is visible. The text below is unchanged when all three tools are available; restrictions, their removal, and tool registration changes take effect on the next assembly. The same check works for direct agent restrictions and subagent `toolFilter`, including PTC capabilities behind `run_code`. The read-before-mutation sentences in write/edit describe the observation policy, not a requirement to invoke the tool named `read`. They remain when `read` is hidden: the policy still guards mutations, and another observing operation, such as `str_replace_editor` with `command: view`, can establish the same file observation. Tool visibility does not disable that precondition.
140
+
141
+ ##### Read guidance
142
+
143
+ ```markdown
144
+ Use the read tool — not shell commands like cat — to inspect text files. Use offset and limit to continue reading large files.
145
+ ```
146
+
147
+ ##### Write guidance
148
+
149
+ ```markdown
150
+ Read an existing file before overwriting it with write (the default fs-observation-policy requires it) and prefer edit for targeted changes.
151
+ ```
152
+
153
+ ##### Edit guidance
154
+
155
+ ```markdown
156
+ Read a file before editing it (the default fs-observation-policy requires it), unless you just created or edited it in this session.
157
+ ```
158
+
159
+ #### Token effect
160
+
161
+ Guidance cost follows the visible tools and their applicable cross-tool recommendations.
162
+
163
+ #### KV Cache effect
164
+
165
+ Prefix-stable while the visible tool set, plugin scope, and guidance text are unchanged. Restrictions or plugin lifecycle changes may invalidate reuse from the first changed section.
166
+
167
+ ### Tool schemas
168
+
169
+ #### What the model sees
170
+
171
+ The model sees the generated [`read`, `read_image`, `write`, and `edit` schemas](../../../docs/tool-catalog.md#deepseek-aidsh-tool-fs), with snake_case arguments. The image tool appears only while a durable attachment store is mounted; its schema is route-independent, and the strict gate refuses at execution. Scoped tool restrictions can remove any definition for one agent.
172
+
173
+ #### Token effect
174
+
175
+ Fixed schema cost on every request in that tool view.
176
+
177
+ #### KV Cache effect
178
+
179
+ Prefix-stable while the visible tool definitions and order are unchanged. Registration lifecycle or scoped restrictions may invalidate reuse from the first changed schema token.
180
+
181
+ ### Read result
182
+
183
+ #### What the model sees
184
+
185
+ A successful read is exactly `<path><resolvedPath></path>`, newline, `<type>file</type>`, newline, `<content>`, numbered lines as `<lineNumber>: <text>`, a blank line, one footer, and `</content>`. The footer is exactly `(Output capped. Showing lines <start>-<end>. Use offset=<next> to continue.)`, `(Showing lines <start>-<end> of <total>. Use offset=<next> to continue.)`, or `(End of file - total <total> lines)`. A long line ends exactly `... (line truncated to <max> chars)`. A missing read still returns `FS_NOT_FOUND`, but it records confirmed absence for the calling session; after an externally deleted file is re-read, a retried `write` can safely recreate it through the provider's no-replace guard.
186
+
187
+ #### Token effect
188
+
189
+ Read output is capped by `readLimit`, `readMaxLineLength`, and `readMaxBytes`; the retained call and result are resent until compaction.
190
+
191
+ #### KV Cache effect
192
+
193
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
194
+
195
+ ### Image read result
196
+
197
+ #### What the model sees
198
+
199
+ A successful `read_image` returns `<path><resolvedPath></path>`, `<type>image</type>`, and a `<content>` envelope naming the media type, normalized dimensions, and byte size, followed by the image itself as a native image block. The result is logged with its durable reference before the next model request.
200
+
201
+ #### Token effect
202
+
203
+ The image is billed on every later request until compaction. Each call is independently bounded by the attachment store's `maxImageBytes`/`maxImagePixels`/`maxImageDimension`; repeated successful calls accumulate history, and content addressing deduplicates only the stored bytes, not the per-request token cost.
204
+
205
+ #### KV Cache effect
206
+
207
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
208
+
209
+ ### Write and edit results
210
+
211
+ #### What the model sees
212
+
213
+ Write returns the exact five-line envelope `<path><resolvedPath></path>`, `<type>file</type>`, `<content>`, `Created file` or `Updated file`, then `</content>`. Edit returns exactly `The file <resolvedPath> has been updated successfully.` or, for `replace_all`, `The file <resolvedPath> has been updated. All occurrences were successfully replaced.` The full write or replacement text remains in the assistant tool-call arguments.
214
+
215
+ #### Token effect
216
+
217
+ Success text is small, but large mutation arguments and any result are resent until compaction.
218
+
219
+ #### KV Cache effect
220
+
221
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
222
+
223
+ ### Tool errors
224
+
225
+ #### What the model sees
226
+
227
+ Failures are normalized as `Error: <message>`. This package's stable validation and read messages are `file_path must be a non-empty string`, `limit must be less than or equal to <max>`, `old_string must be a non-empty string`, `old_string and new_string must differ`, `cannot read "<path>": not found`, `cannot read "<path>": not a regular file`, `offset <offset> is out of range for "<path>" (<total> lines)`, `cannot read "<path>": the <ext> extension does not declare a supported image format; read_image accepts PNG/JPEG/WebP/GIF files, including extension-less files in those formats`, `cannot read "<path>": the file content is not a supported image format; read_image accepts PNG/JPEG/WebP/GIF`, `cannot read "<path>": the bytes do not decode as a supported PNG/JPEG/WebP/GIF image; the file may be truncated or corrupt`, `cannot read "<path>" as an image: model "<model>" does not declare image input; switch to an image-capable model to read images`, and the mismatch repair `cannot read "<path>": the <ext> extension declares <type>, but the bytes use a different image format; rename the file to match its actual format if it is PNG/JPEG/WebP/GIF, or convert it to one of those formats` (an extension-less mismatch reports `cannot read "<path>": the file signature claims <type>, but the bytes decode as a different image format; the file may be corrupt`). A failed 16-bit conversion reports `cannot read "<path>": the 16-bit PNG could not be converted to the normalized 8-bit sRGB form; convert it to an 8-bit PNG/JPEG/WebP and retry`. Provider and policy templates are quoted in their package READMEs. The model-facing error wrapper normalizes every `FS_NOT_OBSERVED` source to `cannot modify "<path>": file has not been read — read the file, then retry`; `FS_STALE_VERSION` keeps the provider's reason and adds `— re-read the file, then retry`. Both retain the structured error code and original cause. After that reread confirms absence, `edit` reports `FS_NOT_FOUND` instead of repeating a stale remedy, while `write` uses guarded creation.
228
+
229
+ #### Token effect
230
+
231
+ Only a failing call adds these retained tokens.
232
+
233
+ #### KV Cache effect
234
+
235
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
236
+
237
+ ## Known Limitations and Deferred Work
238
+
239
+ <a id="known-limitations-and-deferred-work"></a>
240
+
241
+
242
+ These limits define when the tool suite is a poor fit or needs special operational care. They are current package constraints, not a general filesystem comparison or a task backlog.
243
+
244
+ - **No model-facing directory listing ships** — `ctx.fs.listDir` serves provider code such as skill discovery, while the sibling `dsh-tool-fs-search` package supplies ripgrep-backed `glob` and `grep` rather than extending the filesystem seam.
245
+ - **`read` handles UTF-8 text files only** — images use the separate `read_image` tool; PDF, audio, and video remain deferred. A directory target is `FS_NOT_REGULAR_FILE`.
246
+ - **Extension-declared media type** — an extension selects the declared type and the attachment store's magic-byte validation stays authoritative; a correctly formatted image under a wrong extension is refused with the rename remedy rather than sniffed. Only a path with no extension is identified from its file signature.
247
+ - **Object paths re-enter source admission** — `read_image` on a normalized attachment object re-admits its bytes as a new source, so a deployment whose `maxImageBytes`/`maxMessageImageBytes` sit below the normalized-image byte budget can refuse an object path that `ctx.attachments.readImage` still serves; shipped defaults keep the normalized budget (4 MiB) far under the source caps (20 MiB).
248
+ - **Inline image preview rides the UI composition** — the tool-result card renders the image through the browser's `tool.call.images` slot, which the attachment presentation plugin fills; a UI without that plugin shows the result's envelope text instead.
249
+ - **No attachment-region tool** — an agent may crop an image through another available tool when it has a filesystem path; a pasted or dragged image without a path cannot be re-read at higher resolution.
250
+ - **No timeout surface** — `read`/`write`/`edit` take no timeout argument and declare no timeout budget; cancellation rides `exec.signal` only ([provider rationale](../README.md)).
251
+
252
+ <a id="dev-note"></a>
253
+ ### Dev Note
254
+
255
+ <details>
256
+ <summary>Working context for maintainers — click to expand</summary>
257
+
258
+ None.
259
+
260
+ </details>