dsh-book-reader 0.3.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -32,6 +32,28 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
32
32
  fixed zoom is replayed, so the cover no longer flashes for a few hundred
33
33
  milliseconds while the zoom settles. The scroll is re-applied after the zoom
34
34
  commit so the page stays aligned.
35
+ - `pdf_read_pages` no longer disappears from the model's tool list: its output
36
+ schema used a property-level `required: false`, which DSH's `defineTool`
37
+ rejects at registration time. The exception only reached the Host log, so the
38
+ plugin looked enabled with two tools instead of three.
39
+
40
+ ## [0.3.2] — 2026-10-23
41
+
42
+ ### Fixed
43
+
44
+ - `pdf_read_pages` is now registered synchronously with the other two tools
45
+ instead of waiting for the `attachments` injection. The later registration
46
+ made DSH announce `已添加工具:pdf_read_pages` at the start of every chat;
47
+ image calls still resolve the attachment store lazily, and text-only calls
48
+ never need it.
49
+
50
+ ## [0.3.1] — 2026-10-22
51
+
52
+ ### Fixed
53
+
54
+ - Text-only `pdf_read_pages` calls (`include_image:false`) no longer crash while
55
+ rendering their output, and they no longer require an image-capable model
56
+ route or the attachment store; image reads still require both.
35
57
 
36
58
  ## [0.2.0] — 2026-10-20
37
59
 
@@ -101,6 +123,8 @@ First public release.
101
123
  - `pdfjs-dist` is pinned to `6.3.289` to match the host process.
102
124
  - MIT licensed.
103
125
 
126
+ [0.3.2]: https://github.com/Strepsiades2/dsh-book-reader/releases/tag/v0.3.2
127
+ [0.3.1]: https://github.com/Strepsiades2/dsh-book-reader/releases/tag/v0.3.1
104
128
  [0.3.0]: https://github.com/Strepsiades2/dsh-book-reader/releases/tag/v0.3.0
105
129
  [0.2.0]: https://github.com/Strepsiades2/dsh-book-reader/releases/tag/v0.2.0
106
130
  [0.1.1]: https://github.com/Strepsiades2/dsh-book-reader/releases/tag/v0.1.1
package/lib/index.js CHANGED
@@ -1246,7 +1246,11 @@ export function renderPageReadContent(value) {
1246
1246
  type: 'text',
1247
1247
  text: `<page pdf="${page.pdf}" printed="${page.printed}">\n${body}${truncation}\n</page>`,
1248
1248
  })
1249
- blocks.push({ type: 'image', attachment: imageRefFromValue(page.image) })
1249
+ // Text-only reads (include_image:false) never carry an image; emitting an
1250
+ // image block for them crashed output.render on page.image.attachmentId.
1251
+ if (page.image !== undefined) {
1252
+ blocks.push({ type: 'image', attachment: imageRefFromValue(page.image) })
1253
+ }
1250
1254
  }
1251
1255
  return blocks
1252
1256
  }
@@ -2103,11 +2107,17 @@ export function createReadPagesTool({ defineTool: makeTool, ctx, config, core, i
2103
2107
  const path = resolveToolPath(args.path, exec)
2104
2108
  assertInsideWorkspace(path, exec, config)
2105
2109
  const targetStat = await assertPdfFile(path, { statFile, maxFileBytes: config.maxFileBytes })
2106
- const attachments = ctx.get('attachments')
2107
- if (attachments === undefined) {
2108
- throw codedError('cannot read PDF pages as images: no attachment service is mounted', 'PDF_READER_NO_ATTACHMENTS')
2110
+ // Images need the attachment store and an image-capable route; a
2111
+ // text-only read needs neither and must keep working without them.
2112
+ const includeImage = args.include_image !== false
2113
+ let attachments
2114
+ if (includeImage) {
2115
+ attachments = ctx.get('attachments')
2116
+ if (attachments === undefined) {
2117
+ throw codedError('cannot read PDF pages as images: no attachment service is mounted', 'PDF_READER_NO_ATTACHMENTS')
2118
+ }
2119
+ await assertImageCapableRoute(ctx, exec, path)
2109
2120
  }
2110
- await assertImageCapableRoute(ctx, exec, path)
2111
2121
  const info = (await infoCache.load(path, targetStat)).info
2112
2122
  const resolved = resolveRequestedPages({
2113
2123
  selection: args.pages,
@@ -2115,7 +2125,6 @@ export function createReadPagesTool({ defineTool: makeTool, ctx, config, core, i
2115
2125
  info,
2116
2126
  maxPages: config.maxPagesPerCall,
2117
2127
  })
2118
- const includeImage = args.include_image !== false
2119
2128
  if (!includeImage) {
2120
2129
  const book = titleFromPath(path)
2121
2130
  const includeText = args.include_text !== false && config.maxTextCharsPerPage > 0
@@ -2313,18 +2322,21 @@ export function apply(ctx, rawConfig) {
2313
2322
  ctx.tools.register(tool)
2314
2323
  }
2315
2324
 
2316
- ctx.inject(['attachments'], (attachmentCtx) => {
2317
- attachmentCtx.tools.register(
2318
- createReadPagesTool({
2319
- defineTool,
2320
- ctx: attachmentCtx,
2321
- config,
2322
- core,
2323
- infoCache,
2324
- statFile: stat,
2325
- }),
2326
- )
2327
- })
2325
+ // Register synchronously so the session's first tool list already holds all
2326
+ // three tools. Waiting for the attachments injection used to register this
2327
+ // one after the session started, which made every chat announce
2328
+ // "tool added: pdf_read_pages". Image calls resolve `attachments` lazily at
2329
+ // execution time; text-only reads do not need it at all.
2330
+ ctx.tools.register(
2331
+ createReadPagesTool({
2332
+ defineTool,
2333
+ ctx,
2334
+ config,
2335
+ core,
2336
+ infoCache,
2337
+ statFile: stat,
2338
+ }),
2339
+ )
2328
2340
 
2329
2341
  if (config.rememberView) {
2330
2342
  ctx.inject(['storageDomain'], (storageCtx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-book-reader",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Read books and papers in DSH: a reading toolbar on the official PDF preview that remembers your page and zoom, plus PDF tools for the model (page map, full-text search, page text and images).",
5
5
  "keywords": [
6
6
  "dsh",