@dylanl1/dsh-plugin-pdf 0.1.2 → 0.1.3

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.
Files changed (89) hide show
  1. package/NATIVE_V1.md +3 -1
  2. package/README.md +54 -114
  3. package/README.zh.md +61 -121
  4. package/SPEC.md +46 -51
  5. package/dist/THIRD_PARTY_NOTICES.md +1 -56
  6. package/dist/client.js +5045 -2779
  7. package/dist/embedding.js +34 -9
  8. package/dist/engines.js +49 -4
  9. package/dist/image-host.js +837 -505
  10. package/dist/index.js +6790 -4126
  11. package/dist/ocr-host.js +1036 -175
  12. package/dist/ocr.js +4 -1
  13. package/dist/translation.js +43 -14
  14. package/dist/types/adapters/host/dsh/agent-tools.d.ts +1 -1
  15. package/dist/types/adapters/host/dsh/document-status.d.ts +0 -1
  16. package/dist/types/adapters/host/dsh/form-guidance.d.ts +2 -2
  17. package/dist/types/adapters/host/dsh/image-backends.d.ts +19 -3
  18. package/dist/types/adapters/host/dsh/image-tools.d.ts +15 -0
  19. package/dist/types/adapters/host/dsh/image-transport.d.ts +8 -7
  20. package/dist/types/adapters/host/dsh/index.d.ts +3 -2
  21. package/dist/types/adapters/host/dsh/model-cache-identity.d.ts +26 -0
  22. package/dist/types/adapters/host/dsh/ocr-session-llm.d.ts +2 -3
  23. package/dist/types/adapters/host/dsh/ocr-tool.d.ts +4 -2
  24. package/dist/types/adapters/host/dsh/page-content.d.ts +27 -0
  25. package/dist/types/adapters/host/dsh/pdf-evidence-meta.d.ts +13 -148
  26. package/dist/types/adapters/host/dsh/retrieval-prefetch.d.ts +49 -0
  27. package/dist/types/adapters/host/dsh/retrieval.d.ts +132 -25
  28. package/dist/types/adapters/host/dsh/translation-model.d.ts +3 -5
  29. package/dist/types/adapters/host/ocr/local-backend.d.ts +4 -0
  30. package/dist/types/contracts/indexing.d.ts +156 -0
  31. package/dist/types/embedding/registry.d.ts +2 -1
  32. package/dist/types/embedding/types.d.ts +10 -2
  33. package/dist/types/entrypoints/image-understanding-host.d.ts +2 -8
  34. package/dist/types/host/image-understanding-plugin.d.ts +1 -1
  35. package/dist/types/modules/document/index.d.ts +7 -0
  36. package/dist/types/modules/document/page-content-error.d.ts +3 -0
  37. package/dist/types/modules/document/page-content-native.d.ts +10 -0
  38. package/dist/types/modules/document/page-content-ocr.d.ts +5 -0
  39. package/dist/types/modules/document/page-content-text.d.ts +12 -0
  40. package/dist/types/modules/document/page-content.d.ts +158 -0
  41. package/dist/types/modules/engines/cache-identity.d.ts +16 -0
  42. package/dist/types/modules/engines/catalog.d.ts +20 -0
  43. package/dist/types/modules/engines/directory.d.ts +1 -0
  44. package/dist/types/modules/engines/index.d.ts +3 -0
  45. package/dist/types/modules/engines/serialization.d.ts +3 -0
  46. package/dist/types/modules/engines/types.d.ts +13 -0
  47. package/dist/types/modules/evidence/agent-page-image.d.ts +9 -112
  48. package/dist/types/modules/evidence/agent-page-read.d.ts +36 -2
  49. package/dist/types/modules/evidence/image-capture.d.ts +1 -6
  50. package/dist/types/modules/evidence/index.d.ts +9 -136
  51. package/dist/types/modules/evidence/provenance.d.ts +8 -0
  52. package/dist/types/modules/evidence/reference-store.d.ts +91 -1
  53. package/dist/types/modules/evidence/status.d.ts +17 -0
  54. package/dist/types/modules/evidence/text-range.d.ts +28 -0
  55. package/dist/types/modules/evidence/text-target.d.ts +7 -1
  56. package/dist/types/modules/forms/index.d.ts +4 -4
  57. package/dist/types/modules/forms/inspection-references.d.ts +1 -1
  58. package/dist/types/modules/forms/validation.d.ts +4 -8
  59. package/dist/types/modules/image-understanding/service.d.ts +24 -42
  60. package/dist/types/modules/model-write/index.d.ts +1 -2
  61. package/dist/types/modules/ocr/service.d.ts +51 -3
  62. package/dist/types/modules/retrieval/cache.d.ts +44 -2
  63. package/dist/types/modules/retrieval/document-policy.d.ts +83 -0
  64. package/dist/types/modules/retrieval/index.d.ts +4 -1
  65. package/dist/types/modules/retrieval/page-content.d.ts +4 -0
  66. package/dist/types/modules/retrieval/paragraphs.d.ts +1 -12
  67. package/dist/types/modules/retrieval/shared-source.d.ts +25 -0
  68. package/dist/types/modules/retrieval/text.d.ts +19 -1
  69. package/dist/types/modules/retrieval/types.d.ts +83 -9
  70. package/dist/types/modules/retrieval/vector.d.ts +3 -0
  71. package/dist/types/modules/working-copy/index.d.ts +1 -1
  72. package/dist/types/modules/working-copy/ports.d.ts +11 -0
  73. package/dist/types/modules/working-copy/service.d.ts +13 -1
  74. package/dist/types/ocr/types.d.ts +2 -1
  75. package/dist/types/shared/contracts.d.ts +4 -0
  76. package/dist/types/shared/geometry/native-viewport.d.ts +0 -18
  77. package/dist/types/shared/geometry/text-target.d.ts +2 -6
  78. package/dist/types/shared/native.d.ts +2 -1
  79. package/dist/types/shared/passive-poll.d.ts +4 -0
  80. package/dist/types/translation/locales.d.ts +4 -3
  81. package/dist/types/translation/schema.d.ts +14 -0
  82. package/dist/types/translation/types.d.ts +12 -2
  83. package/docs/AI_READER_TOOLS.md +87 -210
  84. package/docs/ARCHITECTURE_V2.md +64 -18
  85. package/docs/ENGINE_EXTENSIONS.md +295 -25
  86. package/docs/RETRIEVAL_EXPERIMENT.md +169 -47
  87. package/docs/UX_TYPOGRAPHY.md +3 -3
  88. package/package.json +13 -13
  89. package/dist/types/adapters/host/dsh/image-auxiliary.d.ts +0 -20
@@ -11,9 +11,10 @@ annotation, navigation and multi-step history pipeline. Model edits continue to
11
11
  the shared draft directly; saving still requires confirmation. No second document,
12
12
  draft or anchor registry is introduced.
13
13
 
14
- The first implementation indexes extracted text, reports OCR/quality/empty-page
15
- coverage separately, and never claims images or formulas have been understood.
16
- Page-image retrieval and reranking remain extension work, not release claims.
14
+ The original 2026-10-25 implementation indexed extracted text and reported
15
+ OCR/quality/empty-page coverage separately. Its measurements below do not cover
16
+ the later OCR and image-description pipeline. Raw page-image vector retrieval
17
+ and reranking remain extension work, not release claims.
17
18
 
18
19
  1. [x] Validate the supplied local MLX embedding runtime with synthetic bilingual data.
19
20
  2. [x] Original-offset chunks, BM25, cosine ranking and protected reciprocal-rank fusion.
@@ -55,6 +56,24 @@ all 37 browser cases; these changes do not alter production behavior.
55
56
 
56
57
  ## Runtime decision
57
58
 
59
+ Current source keeps the two indexing switches as persistent preferences per
60
+ PDF path. Engines and their connections are selected globally in PDF settings;
61
+ the Search panel saves only each document's OCR and image-description switches
62
+ and leaves costly updates to the user. Native text, OCR and image
63
+ descriptions have independent caches. Changing one content source reuses the
64
+ others, and matching document-encoding identities reuse vectors across query or
65
+ batch-size changes. Disabling semantic indexing takes effect immediately;
66
+ otherwise pending choices replace the active plan only after a successful update.
67
+
68
+ The built-in OpenAI-compatible adapter now supplies `documentFingerprint`.
69
+ Old vector keys are not migrated or matched by guesswork, so the first upgrade
70
+ may recompute document embeddings. Existing aggregate `PageContent` records
71
+ remain readable and are split into per-source records when reused; subsequent
72
+ compatible records can be reused normally. Third-party providers without a
73
+ document fingerprint retain their conservative model key when its identity is
74
+ unchanged. The historical benchmark results below predate these policy and cache
75
+ changes; they are not new measurements of them.
76
+
58
77
  The supplied `mlx-lm-local-demo` has a cached
59
78
  `mlx-community/Qwen3-Embedding-0.6B-8bit` model. Its installed convenience helper
60
79
  truncates to 512 tokens by default. The standalone
@@ -68,9 +87,12 @@ The tested model revision is `b8d7100604f51da6d14eab4dd1805f596fa1ce3f`, produci
68
87
  instruction; document encoding does not. The launcher permits at most 8 inputs,
69
88
  8,192 tokens per input and 16,384 padded tokens per batch. The adapter also bounds
70
89
  each original input to 16,000 UTF-16 units. Character limits do not replace the
71
- server's token check. Model metadata and response revision must match the selected
72
- encoding identity; an arbitrary endpoint with an OpenAI-shaped response alone is
73
- not sufficient.
90
+ server's token check. This launcher reports model metadata and the response
91
+ revision; the adapter learns `/models`' `embedding.revision` and includes it in
92
+ the internal cache fingerprint, while checking response consistency within each
93
+ operation. A reported model revision change automatically separates old indexes;
94
+ no user-configured revision is needed. The generic service adapter also accepts
95
+ standard OpenAI-compatible model lists and embedding responses without those extensions.
74
96
 
75
97
  Synthetic runtime probes encoded 2,028 tokens across long inputs, including
76
98
  different tails after token 512; those tails produced distinct vectors (L2
@@ -92,19 +114,62 @@ their dependencies, with the pinned model cached. The launcher binds only
92
114
  separate process whose startup/shutdown remains the operator's responsibility,
93
115
  not a cross-platform bundled embedding runtime.
94
116
 
95
- In PDF settings select **Local Qwen3 embedding**. The built-in defaults target
96
- `http://127.0.0.1:8001/v1/embeddings` and the revision above. `embeddingEngine: none`
97
- is the default: ordinary use starts no model and performs no download. The
98
- conversation model is not assumed to support embeddings. A third-party engine
99
- uses the same typed registration contract; see [engine extensions](ENGINE_EXTENSIONS.md).
117
+ In PDF settings select **Embedding service**. Qwen3 is the default
118
+ configuration example: the built-in defaults target
119
+ `http://127.0.0.1:8001/v1/embeddings` and the model above. The stable engine ID
120
+ remains `local-qwen3-embedding` so existing configurations keep working; the
121
+ descriptor uses `execution: 'service'`. The same settings accept a local HTTP
122
+ service or a third-party HTTPS service implementing OpenAI-compatible `/models`
123
+ and `/embeddings` endpoints. Configure that service's model, vector dimensions
124
+ and limits; optional `apiKeyRef` points to a DSH Host credential. Custom model
125
+ metadata is not required; reported limits and truncation are checked against the
126
+ configuration. The adapter includes a learned service revision in the cache
127
+ fingerprint and checks revision consistency within the operation, so reported
128
+ version changes automatically separate old indexes. Cache identity is managed
129
+ internally; there is no `modelRevision` setting. If a service changes the model
130
+ behind the same name without reporting a new revision, use **Recompute entire
131
+ index** under **Search → Current PDF index** to refresh one PDF, or **Clear all
132
+ index caches** in PDF settings to reset this profile's retrieval caches and old
133
+ searches. The profile reset drains background work before clearing, then resumes
134
+ still-open PDFs with their active plans; pending choices still need an explicit
135
+ update. Other documents rebuild on their next open or search, leaving PDFs,
136
+ drafts and saved policies unchanged.
137
+ `queryInstruction` defaults to an empty string for every model; configure it according to the model's
138
+ requirements. To reproduce this Qwen3 experiment, enter
139
+ `Given a search query, retrieve relevant passages from the document that answer the query`.
140
+ The benchmark runner supplies that instruction explicitly. Clearing the setting
141
+ disables the instruction.
142
+
143
+ `embeddingEngine: none` is the default: ordinary use starts no model and performs
144
+ no download. The conversation model is not assumed to support embeddings. Other
145
+ protocols can use the same typed registration contract; see
146
+ [engine extensions](ENGINE_EXTENSIONS.md). The measurements below use only the
147
+ local launcher, not a third-party service.
148
+
149
+ The current Host prepares opened PDFs in the background when their active plan
150
+ enables an available embedding engine. Reader opens and `pdf_open` share this
151
+ path. Preparation always includes native text, can recognize scanned/damaged
152
+ text, and can generate whole-page image descriptions according to that plan's
153
+ two independent switches. It embeds the resulting text and reuses the same
154
+ index, caches and build jobs as search; it does not generate query vectors.
155
+ Opening or searching does not activate pending choices. Opening does not wait
156
+ for preparation, and an early search may still need the remaining work. Remote
157
+ services may receive clean page images and extracted or generated text during
158
+ preparation, before any query. The task panel retains green **Index ready**
159
+ records until acknowledged with **Done** or the Host removes the closed PDF's
160
+ task; acknowledging feedback does not remove index readiness. Other short-lived
161
+ save notices retain their existing timers.
162
+ The historical benchmarks below do not measure this opening/background behavior.
100
163
 
101
164
  ## Data flow and ownership
102
165
 
103
166
  ```mermaid
104
167
  flowchart LR
105
- Tool["pdf_find_related"] --> Host["Authorized Host adapter"]
168
+ Tool["pdf_semantic_search"] --> Host["Authorized Host adapter"]
169
+ Open["Reader / pdf_open<br/>Shared document ownership"] --> Background["Enabled embedding<br/>Background preparation queue"]
170
+ Background --> Host
106
171
  Host --> Copy["Existing shared working copy"]
107
- Host --> Index["Retrieval service<br/>Page-local exact text chunks"]
172
+ Host --> Index["Shared derived index<br/>Page-local exact text chunks"]
108
173
  Index --> Lexical["BM25 postings"]
109
174
  Index --> Vectors["Typed embedding provider<br/>Document / query encodings"]
110
175
  Lexical --> Fuse["RRF + branch coverage protection"]
@@ -122,9 +187,18 @@ typed provider registry. Host adapters own DSH authorization, provider selection
122
187
  storage, model-facing search sessions and evidence signing. There is no second
123
188
  document table or anchor store.
124
189
 
190
+ Resident indexes and in-flight build steps are shared across authorized Sessions
191
+ within one Host instance by source-byte digest, page count, retrieval
192
+ scope/versions and embedding fingerprint/registration generation. Session-local document IDs, paths and
193
+ `contentVersion` are not shared-index keys. Each caller still validates its own
194
+ document binding and authorization; drafts, queries, continuation handles, results
195
+ and evidence references stay Session-scoped. Shared derived data grants no access
196
+ to the underlying file. Ready indexes remain bounded LRU residents and may be
197
+ evicted; this is not a permanent on-disk index.
198
+
125
199
  ### Public tool continuation
126
200
 
127
- Start `pdf_find_related` with `documentId`, `query` and its optional `terms`,
201
+ Start `pdf_semantic_search` with `documentId`, `query` and its optional `terms`,
128
202
  `mode`, `topK`, `fromPage` and `maxPages`. The response contains `searchId: "rel_…"`
129
203
  and a boolean `hasMore`. While `hasMore` is true, call the same tool with only
130
204
  `{"searchId":"rel_…"}`. Do not repeat the query, document or options. The public
@@ -133,15 +207,17 @@ request, source/engine constraints and internal continuation progress.
133
207
 
134
208
  `building` and `incomplete` still report progress and coverage without globally
135
209
  ranked candidates. Only `complete` returns rankings for the requested scope and
136
- sets `hasMore: false`. Inspect `effectiveMode`, `fallbackReason` and `coverage`
137
- before describing the result as semantic retrieval or complete text coverage.
210
+ sets `hasMore: false`. Inspect `effectiveMode` and `coverage` before describing a result as complete
211
+ text coverage. The current semantic-search tool requires an available embedding
212
+ engine; it does not expose the experiment's automatic lexical fallback.
138
213
 
139
- The exact, case-sensitive `pdf_search` uses the same initial-call pattern, with
214
+ The exact, case-sensitive `pdf_keyword_search` uses the same initial-call pattern, with
140
215
  its optional `fromPage` and `offset`, then only `{"searchId":"txt_…"}` on that
141
216
  same tool. Its results are paginated matches; `hasMore: false` means that search
142
217
  has finished. It does not use related-index build statuses. Neither search ID is
143
- a page-list cursor, and `pdf_bookmarks`, `pdf_locate` and `pdf_context` retain
144
- their existing cursor contracts.
218
+ a page-list cursor, and list tools such as `pdf_bookmark_list` retain their own cursor contracts.
219
+ The former locate/context model entrances are replaced by keyword search and
220
+ `pdf_evidence_read`; evidence replay remains source-bound.
145
221
 
146
222
  Search IDs are opaque, session-scoped and tool-scoped. Reset, TTL expiry or budget
147
223
  eviction invalidates them; unknown or expired IDs require a new initial call.
@@ -161,7 +237,7 @@ and index caches; matching text/model fingerprints can still reuse vectors.
161
237
  A reference denotes its entire stored quote, not an implicitly selected answer.
162
238
  Check that scope before marking it. A reference annotation target may include
163
239
  an exact `quote` to select a unique substring inside that parent reference;
164
- `pdf_navigate` accepts the same `refId` and `quote` to preserve the selected range.
240
+ `pdf_page_jump` accepts the same `refId` and `quote` to preserve the selected range.
165
241
  The shared resolver revalidates the source and full page before deriving native
166
242
  geometry for that subrange. Missing or ambiguous quotes fail without a draft
167
243
  edit. Omitting `quote` deliberately keeps the full parent range; annotation does
@@ -175,36 +251,77 @@ missing geometry. OCR-derived candidates are not promoted to native coordinates.
175
251
 
176
252
  ## Budgets and lifecycle
177
253
 
178
- - Index only after an explicit search; embedding is disabled by default.
254
+ - Embedding is disabled by default. Opened PDFs with an enabled, available active
255
+ plan are prepared in the background; explicit searches reuse its progress and cache.
256
+ Background preparation runs at most one document at a time and tracks up to 64
257
+ open documents, with excess documents left to on-demand retrieval.
258
+ - Only UI/model owners keep preparation eligible. Last-owner close or cancellation
259
+ detaches that Session's preparation without stopping other authorized subscribers
260
+ to the same build. Shared work aborts once no subscribers remain. Disabling a
261
+ document's index, changing its active plan or source, and provider unload fence
262
+ obsolete work. Editing global defaults or a pending policy does not switch the
263
+ active plan. Source changes can queue a replacement; unchanged annotation edits do not.
264
+ Failed preparations do not retry indefinitely. Rebuild suspends and drains this
265
+ queue before clearing caches, then resumes eligible still-open documents.
179
266
  - The default search scope is the whole document; `fromPage/maxPages` restrict
180
267
  the scope, not the amount processed per call. This intentionally changes the
181
- old `pdf_find_related` page-window meaning of `maxPages`.
268
+ old `pdf_semantic_search` page-window meaning of `maxPages`.
182
269
  - Process at most 20 pages and 4 embedding batches per indexing step, yielding
183
270
  between work units. The model continues with only `searchId` while `hasMore`
184
271
  is true; short public handles do not remove the internal bounded steps.
185
272
  - Host retains query continuation state and validates scope, query, source and
186
273
  engine generation. Incomplete coverage produces progress, not a global
187
274
  best-match or no-answer claim.
188
- - Runtime defaults cap indexes at 5,000 chunks each, 8 resident indexes, an
189
- estimated 64 MiB total index budget, 2 simultaneous build jobs and 8 admitted
190
- queries. Active indexes cannot be evicted mid-query; each build step retains
191
- its own document lease. These are
192
- admission limits, not a guarantee of total process RSS; larger scopes may need
193
- to be split explicitly.
275
+ - Production keeps at most four immutable-plan runtimes. Each has at most two
276
+ resident indexes, an estimated 64 MiB index budget, two simultaneous build jobs
277
+ and eight admitted queries; each index is capped at 20,000 chunks. Across four
278
+ runtimes this permits at most eight indexes and 256 MiB of indexed-data budget,
279
+ allocated as data becomes resident rather than reserved up front.
280
+ Build/query admission limits are per runtime, not Host-wide limits of two/eight;
281
+ background document preparation still runs one document at a time. The generic
282
+ retrieval service's standalone defaults remain eight indexes and 64 MiB per
283
+ instance; production limits each instance to two indexes while preserving that
284
+ original per-plan memory budget. Active indexes
285
+ cannot be evicted mid-query; each build step retains its own document lease.
286
+ These are admission estimates, not a guarantee of total process RSS; larger
287
+ scopes may need to be split explicitly.
288
+ Lexical estimates count one posting per distinct term/chunk pair. Resident
289
+ cosine-search vectors use normalized Float32 storage shared by identical text;
290
+ persisted vectors use versioned little-endian Float32/Base64 records with an
291
+ integrity checksum. At a compatible cache key, existing numeric-array records
292
+ migrate on a valid hit without requesting another embedding; this does not
293
+ migrate the old built-in adapter's keys across the document-fingerprint change.
194
294
  - The separate `pdf_retrieval_<profile>` Storage Domain stores derived text and
195
295
  vectors with default limits of 64 MiB serialized data, 12,000 records and 7 days.
196
296
  Individual records are limited to 2 MiB. Cache loss/corruption can be rebuilt
197
297
  and must not damage drafts. The cache may contain document text; it is local
198
298
  plugin storage, not an encrypted vault or an authorization token.
299
+ - Derived record keys use filename-safe `retrieval_<digest>` identifiers, as
300
+ required by DSH's per-record JSON backend. Persistence is verified against the
301
+ real backend, including closing and recreating the domain and retrieval
302
+ service. An earlier colon-prefixed key was rejected by that backend; affected
303
+ installations need one initial build because those records were never saved.
304
+ - After restart, the service restores text and vectors and reconstructs its
305
+ in-memory search structures; it does not persist Session authorization or query
306
+ cursors. The task panel distinguishes restoration, native page extraction and
307
+ new embedding requests, and reports reused/newly computed passage counts.
308
+ Missing, expired, evicted or invalid records are rebuilt individually. Unchanged
309
+ valid records require neither source extraction nor document embedding.
199
310
  - Reuse vectors by text/model identity after source revalidation; annotation-only
200
311
  edits do not rebuild the text index.
312
+ - Extraction-version changes invalidate cached page text and quality metadata.
313
+ The native-quality revision excludes PDFium's recognized U+0002 line-wrap
314
+ hyphen marker from invalid-control-character warnings; actual Unicode mapping
315
+ errors still report a warning. Existing indexes re-extract page metadata, while
316
+ unchanged text can reuse its document vectors.
201
317
  - A save can change PDF bytes. Page text is verified/re-extracted for the new
202
318
  source, while unchanged text may reuse vectors. Changes in weights, tokenizer,
203
319
  query instruction, dimensions or provider configuration change the model
204
320
  fingerprint; unloading/re-registering also fences the runtime generation.
205
- - Closing a session or unloading the plugin cancels queued work and fences late
206
- results. Cancellation of an HTTP request does not imply a running external model
207
- computation has stopped immediately.
321
+ - Closing a Session cancels its queued work and fences its late results without
322
+ cancelling another Session's shared build subscription or ready index. Plugin
323
+ unload cancels all work. Cancellation of an HTTP request does not imply a running
324
+ external model computation has stopped immediately.
208
325
 
209
326
  Native PDFium calls and active Metal kernels are not preempted halfway through;
210
327
  their bounded operation retains its execution slot until it finishes. No claim
@@ -212,19 +329,24 @@ is made that all CPU/GPU usage ends as soon as a caller receives cancellation.
212
329
 
213
330
  ## Coverage and limits
214
331
 
215
- The production indexing adapter deliberately requests native text with automatic
216
- character-repair OCR disabled. Opening/searching a long book must not silently
217
- launch hundreds of OCR jobs. Empty pages and undecodable characters appear in
218
- coverage/warnings. Explicit OCR and page-image tools remain available separately,
219
- but their output is not automatically ingested into this index.
220
-
221
- Text around a formula or figure can retrieve its page; this does not mean the
222
- formula, table or graph has been understood. Image-only content is reported as
223
- not indexed. The synthetic complex-page cases record this missing coverage rather
224
- than inventing images, layout evidence or OCR accuracy. No multimodal index,
225
- reranker, semantic answer validator, cross-document search or automatic section
226
- reconstruction is included. No-answer queries can still return ranked candidates;
227
- the agent must read context and cannot infer that a result proves the answer.
332
+ Native extraction requests `{ recover: false }`, disabling the Reader's fixed
333
+ character-repair path. This does not disable the active indexing plan's selected
334
+ OCR engine: its text-recognition switch handles missing/damaged native text, and
335
+ its independent image switch adds generated whole-page descriptions. Both may
336
+ run during background preparation and incur model calls. Ad-hoc OCR or page-image
337
+ tool output is not automatically inserted; indexing uses its own validated source
338
+ pipeline. Empty or failed representations remain visible in coverage/warnings.
339
+
340
+ Native text can retrieve a formula's or figure's page without understanding it.
341
+ Enabled OCR and description engines can add searchable derived text, with source
342
+ and approximate page/region evidence; they do not provide native text coordinates
343
+ or guaranteed formula, chart or table understanding. With those options disabled,
344
+ image-only content remains uncovered. The original synthetic complex-page cases
345
+ measure that older native-text-only scope, not the accuracy of later enrichment.
346
+ There is no raw-image vector index, reranker, semantic answer validator,
347
+ cross-document search or automatic section reconstruction. No-answer queries can
348
+ still return ranked candidates; the agent must read context and cannot infer that
349
+ a result proves the answer.
228
350
 
229
351
  Production ranking cooperatively yields and rechecks cancellation/source fences
230
352
  after 64 BM25 build chunks, 1,024 lexical posting contributions or 32 vectors.
@@ -298,8 +420,9 @@ The scale corpus repeats the 28 small passages, uses about 158,780 text characte
298
420
  at 1,000 pages and reuses already computed document/query vectors. Those timings
299
421
  exclude embedding, PDF extraction and disk IO; they do not represent an arbitrary
300
422
  1,000-page textbook. The theoretical 1,000 × 1,024 × Float32 vector payload is
301
- 4,096,000 bytes, but the benchmark reuses arrays and production uses JavaScript
302
- numbers, so this is not a measured cache-memory bound.
423
+ 4,096,000 bytes, but that benchmark reused arrays and the then-current service
424
+ stored JavaScript numbers. This is not a measured memory bound for the current
425
+ Float32 storage or its production runtime budgets.
303
426
 
304
427
  The same runner also calls the actual retrieval service, with a synthetic page
305
428
  provider and a structured-clone in-memory KV adapter:
@@ -363,7 +486,6 @@ After starting the cached local model:
363
486
  ```sh
364
487
  npm run bench:retrieval -- \
365
488
  --embedding-endpoint http://127.0.0.1:8001/v1/embeddings \
366
- --model-revision b8d7100604f51da6d14eab4dd1805f596fa1ce3f \
367
489
  --repeats 3 --out /tmp/retrieval-qwen.json
368
490
  ```
369
491
 
@@ -4,7 +4,7 @@ This is the typography contract for the PDF reader UI. PDF page content is rende
4
4
 
5
5
  ## Typeface and language
6
6
 
7
- - Inherit the application font from DSH so the reader stays aligned with the host UI. Let the operating system provide native Chinese glyph fallback; do not hard-code a second font stack in the plugin.
7
+ - Use the shared `--pdf-font-ui` system sans-serif stack, matching Codex's default UI font stack. On macOS the system supplies San Francisco and native Chinese fallback; other platforms use their native UI fonts. Do not inherit the host's chat or code font for plugin UI.
8
8
  - Chinese and English use the same semantic size and weight. Do not add locale-specific size overrides or tracking: mixed-language controls should remain aligned.
9
9
  - Keep tracking at the platform default for body text and Chinese. Only introduce display tracking after checking both scripts together.
10
10
  - Use a monospace face only for code or machine-readable data whose character alignment matters. Page numbers, dates, and counts stay in the UI font with tabular numerals.
@@ -17,7 +17,7 @@ This is the typography contract for the PDF reader UI. PDF page content is rende
17
17
  | `label` | 13px / 1.4 | Compact controls, field labels, sidebar section headings |
18
18
  | `body-compact` | 13px / 1.5 | Dense result summaries, dictionary meanings, and examples |
19
19
  | `body` | 14px / 1.5 | Default reader UI, buttons, inputs, and comment text |
20
- | `section` | 16px / 1.4 | Translation terms and prominent section headings |
20
+ | `section` | 16px / 1.4 | Prominent section headings |
21
21
  | `title` | 20px / 1.3 | Major dialog or panel title only |
22
22
 
23
23
  Use regular (400) for reading, medium (500) for quiet emphasis, semibold (600) for headings and primary actions, and bold (700) only for strong status emphasis. Avoid intermediate weights such as 550 or 650; use the closest supported semantic weight.
@@ -36,4 +36,4 @@ Long explanatory/helper copy may use 1.6 leading for easier reading; the compact
36
36
 
37
37
  ## Source of truth
38
38
 
39
- The semantic CSS variables live in the plugin stylesheet's `:root` in `src/client/reader.css` so both the reader and its evidence cards can consume them. Component styles should use those variables instead of introducing new pixel sizes. When adding a new text role, choose an existing token first; extend the scale only for a demonstrated need.
39
+ The font family and semantic CSS variables live in the plugin stylesheet's `:root` in `src/client/reader.css` so the reader, settings, evidence cards, and body-mounted tooltips can consume them. Set the family on these UI roots, not on every descendant: PDF text-layer spans must retain their document-defined fonts, and raw structured output keeps its monospace font. Component styles should use those variables instead of introducing new pixel sizes. When adding a new text role, choose an existing token first; extend the scale only for a demonstrated need.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dylanl1/dsh-plugin-pdf",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "PDF reading, annotations, navigation and selection translation for DeepSeek Harness",
6
6
  "license": "MIT",
@@ -86,12 +86,12 @@
86
86
  },
87
87
  "peerDependencies": {
88
88
  "@deepseek-ai/cordis": "*",
89
- "@deepseek-ai/dsh-attachment": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
90
- "@deepseek-ai/dsh-fs-local": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
91
- "@deepseek-ai/dsh-sandbox": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
92
- "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
93
- "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
94
- "@deepseek-ai/dsh-tools": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3",
89
+ "@deepseek-ai/dsh-attachment": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.5",
90
+ "@deepseek-ai/dsh-fs-local": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.5",
91
+ "@deepseek-ai/dsh-sandbox": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.5",
92
+ "@deepseek-ai/dsh-storage-domain": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.5",
93
+ "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.5",
94
+ "@deepseek-ai/dsh-tools": "0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-alpha.1 || 0.2.1-alpha.2 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.5",
95
95
  "@deepseek-ai/schemastery": "*"
96
96
  },
97
97
  "peerDependenciesMeta": {
@@ -118,7 +118,7 @@
118
118
  }
119
119
  },
120
120
  "dependencies": {
121
- "@deepseek-ai/dsh-util-workspace-path": "0.2.1-rc.3",
121
+ "@deepseek-ai/dsh-util-workspace-path": "0.2.1-rc.5",
122
122
  "@pdf-lib/fontkit": "1.1.1",
123
123
  "pdf-lib": "1.17.1",
124
124
  "zod": "~4.4.3"
@@ -131,10 +131,10 @@
131
131
  "node": ">=22"
132
132
  },
133
133
  "optionalDependencies": {
134
- "@dylanl1/dsh-plugin-pdf-native-linux-x64": "0.1.2",
135
- "@dylanl1/dsh-plugin-pdf-native-linux-arm64": "0.1.2",
136
- "@dylanl1/dsh-plugin-pdf-native-darwin-x64": "0.1.2",
137
- "@dylanl1/dsh-plugin-pdf-native-darwin-arm64": "0.1.2",
138
- "@dylanl1/dsh-plugin-pdf-native-win32-x64": "0.1.2"
134
+ "@dylanl1/dsh-plugin-pdf-native-linux-x64": "0.1.3",
135
+ "@dylanl1/dsh-plugin-pdf-native-linux-arm64": "0.1.3",
136
+ "@dylanl1/dsh-plugin-pdf-native-darwin-x64": "0.1.3",
137
+ "@dylanl1/dsh-plugin-pdf-native-darwin-arm64": "0.1.3",
138
+ "@dylanl1/dsh-plugin-pdf-native-win32-x64": "0.1.3"
139
139
  }
140
140
  }
@@ -1,20 +0,0 @@
1
- import { type ImageUnderstandingBackend } from '../../../modules/image-understanding/index.js';
2
- import type { SessionOcrAttachmentStore, SessionOcrLlm } from './ocr-session-llm.js';
3
- export interface AuxiliaryVisionModel {
4
- provider: string;
5
- model: string;
6
- reasoningEffort?: string;
7
- }
8
- export interface AuxiliaryVisionDependencies {
9
- /** An explicit Host profile selection; never inferred from the current session. */
10
- selectedModel(): AuxiliaryVisionModel | undefined;
11
- getLlm(): Pick<SessionOcrLlm, 'resolveModelInfo' | 'stream'> | undefined;
12
- getAttachments(): Pick<SessionOcrAttachmentStore, 'saveImage'> | undefined;
13
- maxOutputTokens?: number;
14
- }
15
- /**
16
- * Opt-in second-model image description for sessions whose own model is text-only.
17
- * It returns text with explicit provenance; it never changes the session model or
18
- * claims that OCR and visual reasoning are equivalent.
19
- */
20
- export declare function createAuxiliaryVisionBackend(dependencies: AuxiliaryVisionDependencies): ImageUnderstandingBackend;