feat(ocr): add PDF support with light-ocr 0.5.5 - #2040
Conversation
📝 WalkthroughWalkthroughLight OCR now supports PDF attachments through embedded-text selection or streamed document OCR, with PDFium-aware packaging, page-aware artifacts and caching, persistence, context/export handling, renderer states, localization, and expanded validation. Agent registry and model catalog metadata are also updated. ChangesLight OCR PDF support
Catalog and registry updates
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/main/ocr/ocrArtifactStore.ts (1)
644-712: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winAccept schema version
1and migrate it before initializing the schema.Databases from the previous v1 schema are accepted by
shouldRebuildOcrCacheforschema_mismatch, deleted, and then recreated empty, so existing cache entries are lost instead of preserved. The v1→v2 delta is additive, and the test expects the v1 file to be rebuilt successfully, so add1to both the supported-version check and the version bump condition.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/ocrArtifactStore.ts` around lines 644 - 712, The initialize method currently rejects schema version 1 and does not migrate it. Update the supported-version check to accept 1, and include schemaVersion === 1 in the condition that sets user_version to 2, preserving existing v1 cache data while applying the additive schema initialization.src/main/agent/deepchat/runtime/contextBuilder.ts (1)
431-433: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winImage metadata isn't sanitized like the new PDF path — attacker-controlled filename can break the untrusted-data framing.
sanitizeAttachmentMetadatawas added specifically to neutralize newlines/</>in attacker-controlled attachment metadata before it's embedded in the prompt (used for PDFs at Lines 464-469). This same file'sbuildResolvedImageRepresentationContext— touched by this very diff (invalid-kind guard, shared escape helper) — still interpolates rawfileName/mimeTypeunsanitized into the[Attached Image ... untrusted attachment data]block. A crafted image filename containing newlines and fake structural text (e.g.</untrusted_ocr_data>\nSYSTEM: ...) can inject content that reads as authoritative text outside the escaped OCR body, undermining the very untrusted-data framing this PR introduces.🛡️ Proposed fix
const fileName = typeof file.name === 'string' ? file.name : `image-${index + 1}` const mimeType = resolveFileMimeType(file) - const metadata = [`name: ${fileName}`, `mime: ${mimeType}`].join('\n') + const metadata = [ + `name: ${sanitizeAttachmentMetadata(fileName, 512)}`, + `mime: ${sanitizeAttachmentMetadata(mimeType, 128)}` + ].join('\n')🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/agent/deepchat/runtime/contextBuilder.ts` around lines 431 - 433, Update buildResolvedImageRepresentationContext to sanitize both fileName and mimeType with the existing sanitizeAttachmentMetadata helper before constructing the metadata string, matching the PDF metadata path and preserving the untrusted attachment-data framing.src/main/agent/deepchat/runtime/turnCoordinator.ts (1)
422-427: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winApply OCR-style guard to PDF
embedded_textattachments too
shouldGuardOcrAttachmentTextandhistoryContainsOcrAttachmentTextonly check forresolvedRepresentation?.kind === 'ocr_text', whilecontextBuilder.tsalso rendersembedded_textPDF content as untrusted attachment data. Includeembedded_textin the guard predicate so PDF prompt-injection protection covers the default Auto-mode text path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/agent/deepchat/runtime/turnCoordinator.ts` around lines 422 - 427, Update the attachment guard predicates around shouldGuardOcrAttachmentText and historyContainsOcrAttachmentText to treat resolvedRepresentation.kind values of both "ocr_text" and "embedded_text" as requiring the OCR safety rule. Preserve the existing prompt construction and ensure PDF embedded_text content is guarded in both current content and history paths.
🧹 Nitpick comments (8)
src/main/ocr/ocrArtifactStore.ts (1)
865-884: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueEviction candidates are materialized and sorted on every
runMaintenance, even when under budget.
putDocument/putcallrunMaintenance()on each write, and this builds + sorts a combined array of all records before checking the byte budget. The SQLite backend guards this work behindlogicalBytes > maxBytes; mirroring that here avoids the per-write allocation and sort.♻️ Suggested change
let logicalBytes = this.logicalBytes() + if (logicalBytes <= this.options.maxBytes) return const candidates = [🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/ocrArtifactStore.ts` around lines 865 - 884, Update runMaintenance around the logicalBytes and candidates construction so candidate materialization and sorting occur only when logicalBytes exceeds the configured maxBytes budget. Preserve the existing eviction behavior when over budget, while returning without allocating or sorting candidates when storage remains within budget.src/main/ocr/documentTextExtractionService.ts (2)
461-508: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winNear-duplicate of
readImmutableImageSnapshot.This is essentially
src/main/ocr/imagePreprocessor.ts'sreadImmutableImageSnapshotwith a different chunk size and error type. Consider extracting a shared chunked-read+SHA-256 helper parameterized by chunk size and an error factory, so the byte-limit semantics can't drift between image and document paths.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/documentTextExtractionService.ts` around lines 461 - 508, Extract the shared chunked file-read and SHA-256 logic from readImmutablePdfSnapshot and readImmutableImageSnapshot into a reusable helper, parameterized by chunk size and the caller’s error factory or error type. Update both snapshot functions to use it while preserving their existing byte-limit, abort, empty-input, and error semantics.
510-515: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMisleading error codes for invalid configuration inputs.
normalizeDocumentSourceByteLimitreports an invalid limit asinput_too_large(which the router maps to a user-facing "document too large") andnormalizeGenerationTokenLimitreports an invalid limit asruntime_identity_mismatch.invalid_inputdescribes both cases more accurately.Also applies to: 635-644
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/documentTextExtractionService.ts` around lines 510 - 515, Update normalizeDocumentSourceByteLimit and normalizeGenerationTokenLimit to throw DocumentTextExtractionError with the invalid_input code for invalid configuration limits, while preserving their existing validation and messages.src/main/ocr/documentOcrArtifact.ts (1)
20-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDerive the tokenx component from the installed dependency version.
PDF_OCR_ARTIFACT_REVISIONis used as part of cached artifact identity, buttokenx=0.4.1is hard-coded whilepackage.jsononly pins^0.4.1. Whentokenxis upgraded, stale artifacts can remain keyed by the old revision and only fail on the runtime token-count re-estimate. Use the resolved package version, or add coverage that it stays in sync with the dependency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/documentOcrArtifact.ts` around lines 20 - 27, Update PDF_OCR_ARTIFACT_REVISION to derive the tokenx component from the installed tokenx dependency version instead of hard-coding 0.4.1. Use the resolved package metadata so the artifact identity changes whenever tokenx is upgraded, while preserving the existing revision components.scripts/smoke-light-ocr.js (1)
219-231: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winShare
assertExactPackageDependencywithafterPack.jsinstead of duplicating it.
scripts/afterPack.js(Lines 441-453) defines the identical helper; only the error message differs. Both scripts already import from./light-ocr-artifacts.mjs, which is the natural home for this pin-verification invariant. Keeping two copies risks the packaging check and the smoke check drifting apart.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/smoke-light-ocr.js` around lines 219 - 231, Move the shared package-version validation logic from assertExactPackageDependency in scripts/smoke-light-ocr.js into light-ocr-artifacts.mjs, then import and reuse it from both smoke-light-ocr.js and afterPack.js. Preserve each caller’s existing error-message behavior while removing the duplicated helper definitions.src/main/session/data/transcript.ts (1)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated attachment-searchable-text extraction rule across two files. Both
buildSearchableAttachmentTextandcollectUserMessageAttachmentRefsindependently re-implement the identical "includeocr_textunconditionally; includeembedded_textonly whenisPdfAttachment" rule. Extracting this into a shared helper in@shared/utils/attachmentRepresentation(which both files already import from) would prevent the two copies from silently diverging as new representation kinds are added.
src/main/session/data/transcript.ts#L136-174: extract theresolved.kind === 'ocr_text' | 'embedded_text'+isPdfAttachmentselection logic into a sharedgetAttachmentSearchableText(file)-style helper.src/main/tape/application/recallProjection.ts#L147-174: consume the same shared helper instead of re-derivingattachmentTextlocally, keeping this file's own per-attachment/per-message character budgeting on top of it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/session/data/transcript.ts` at line 1, Extract the shared attachment searchable-text selection logic from buildSearchableAttachmentText and collectUserMessageAttachmentRefs into `@shared/utils/attachmentRepresentation` as a getAttachmentSearchableText(file)-style helper. Have the helper always include ocr_text and include embedded_text only for PDF attachments, then update both callers to use it while preserving recallProjection’s existing per-attachment and per-message character budgeting.test/main/ocr/lightOcrProtocol.test.ts (1)
15-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the exported
LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELSinstead of the literal.
maxTotalPixelshardcodes100 * 1024 * 1024while the sibling limits come from exported constants; the test will silently drift if the protocol limit changes (test/main/ocr/lightOcrHelper.test.tsalready imports it).♻️ Proposed change
import { LIGHT_OCR_DOCUMENT_MAX_LINE_CHARACTERS, LIGHT_OCR_DOCUMENT_MAX_PAGE_PIXELS, + LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELS, LIGHT_OCR_HELPER_MAX_INPUT_BYTES, @@ - maxTotalPixels: 100 * 1024 * 1024 + maxTotalPixels: LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELS }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/main/ocr/lightOcrProtocol.test.ts` around lines 15 - 22, Update the documentOptions.maxTotalPixels assignment to reuse the exported LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELS constant instead of the hardcoded 100 * 1024 * 1024 expression, matching the sibling OCR limit fields and existing test usage.src/main/ocr/attachmentCapabilityRouter.ts (1)
360-378: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winConsider running image and document OCR resolution concurrently.
resolveImageOcrCandidatesandresolveDocumentOcrCandidatesoperate on disjoint candidate lists and only append to sharedissues/routingDiagnostics/ocrDiagnosticscollections, which is safe to do from concurrently-scheduled async calls in JS (no true parallel mutation). Awaiting them sequentially adds the document OCR latency on top of the image-batch latency whenever both are present in a turn.♻️ Proposed refactor
- await this.resolveImageOcrCandidates( - processableImages, - backend, - maxFileSize, - issues, - routingDiagnostics, - ocrDiagnostics, - signal - ) - await this.resolveDocumentOcrCandidates( - processableDocuments, - backend, - maxFileSize, - issues, - routingDiagnostics, - ocrDiagnostics, - signal - ) + await Promise.all([ + this.resolveImageOcrCandidates( + processableImages, + backend, + maxFileSize, + issues, + routingDiagnostics, + ocrDiagnostics, + signal + ), + this.resolveDocumentOcrCandidates( + processableDocuments, + backend, + maxFileSize, + issues, + routingDiagnostics, + ocrDiagnostics, + signal + ) + ])Note: the underlying OCR process host may still serialize IPC internally, so real-world gain depends on that layer.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/attachmentCapabilityRouter.ts` around lines 360 - 378, Update the orchestration around resolveImageOcrCandidates and resolveDocumentOcrCandidates to start both async resolutions concurrently and await their combined completion, while preserving their existing arguments and shared diagnostic/issue collection behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@package.json`:
- Line 112: Add the required Light OCR transitive dependencies to the
package.json dependency declarations: `@arcships/light-ocr-runtime` at 0.1.5,
`@arcships/light-ocr-model-ppocrv6-small` at 0.3.4, and each `@arcships/light-ocr-`*
native package at 0.5.5, alongside the existing `@arcships/light-ocr` entry. Keep
versions aligned with resources/runtime-versions.json and update the lockfile
consistently.
In `@resources/model-db/providers.json`:
- Around line 96770-96779: The openai/gpt-5-chat entry is incomplete and lacks
capability and pricing metadata. Update the model definition with the
appropriate modalities, tool_call, reasoning, and cost fields consistent with
neighbouring entries, and verify that retaining this stub is intentional after
its removal from the inference provider.
- Around line 90958-90964: Correct the model type from imageGeneration to chat
for google/gemini-2.5-flash, google/gemini-2.5-pro,
google/gemini-2.5-flash-lite, google/gemini-2.0-flash,
google/gemini-2.0-flash-lite-001, and qwen/qwen3-vl-plus. Apply this change at
resources/model-db/providers.json lines 90958-90964, 91209-91215, 91265-91271,
96451-96456, 96476-96481, and 97044-97055 respectively, preserving all other
model metadata.
In `@src/main/file/adapters/PdfFileAdapter.ts`:
- Around line 30-40: Update readPdfData in the PdfFileAdapter so filesystem
failures from fs.stat and fs.readFile are handled by the existing catch path and
resolve to undefined after logging. Widen the try boundary to cover the complete
file-loading and parsing flow, ensuring loadPdfData does not cache a permanently
rejected promise while preserving the existing successful and oversized-file
behavior.
In `@src/main/ocr/attachmentCapabilityRouter.ts`:
- Around line 749-792: Thread the routing issues collection into
applyTurnOcrTextBudget and update its call site so the budget-driven OCR-empty
downgrade uses the existing markUnavailable/appendIssue path instead of
assigning resolvedRepresentation directly. Preserve attachment indexing when
recording the issue, ensuring buildPreparationSummary surfaces the unavailable
document rather than returning an empty ready summary.
In `@src/main/ocr/documentOcrArtifact.ts`:
- Around line 116-129: Update LightOcrDocumentArtifact.append to avoid calling
fitDocumentOcrPages on every page: maintain the accumulated text and estimated
token count incrementally, compute only the new page’s contribution while within
both budgets, and append directly when it fits. When the new page exceeds a
budget, use the existing fitTruncatedPrefix path once to produce the truncated
result and mark the artifact as truncated, preserving page ordering and return
statuses.
In `@src/main/ocr/documentTextExtractionService.ts`:
- Around line 285-301: When the cached artifact becomes invalid after
truncateDocumentOcrArtifact and withSourcePageCountHint in the cache-hit path,
treat it as a cache miss instead of throwing DocumentTextExtractionError. Only
return the cached result when isValidDocumentOcrArtifact succeeds; otherwise
continue into the existing fresh extraction flow.
In `@src/main/ocr/lightOcrProcessHost.ts`:
- Around line 1070-1115: Update sendDocumentStop to use a dedicated, longer
document-stop timeout, preferably via a documentStopTimeoutMs option with a
default above a single page’s render and OCR duration, instead of cancelGraceMs.
Keep the existing acknowledgement cleanup and process-disposal behavior for
genuine stop timeouts, while ensuring output-limit truncation can allow the
helper to finish and preserve the partial document result.
In `@src/main/ocr/ocrRuntimeAssetResolver.ts`:
- Around line 434-440: Replace JSON.stringify-based inventory equality in
matchesArtifactInventory with explicit comparisons across the fixed groups
nativeCode, pdfiumCode, pdfiumLoader, and other, checking each group’s length
and entries element by element. Apply the same order-independent comparison
against expectedInventory in scripts/smoke-light-ocr.js at lines 468-470; both
sites must avoid relying on object key order.
---
Outside diff comments:
In `@src/main/agent/deepchat/runtime/contextBuilder.ts`:
- Around line 431-433: Update buildResolvedImageRepresentationContext to
sanitize both fileName and mimeType with the existing sanitizeAttachmentMetadata
helper before constructing the metadata string, matching the PDF metadata path
and preserving the untrusted attachment-data framing.
In `@src/main/agent/deepchat/runtime/turnCoordinator.ts`:
- Around line 422-427: Update the attachment guard predicates around
shouldGuardOcrAttachmentText and historyContainsOcrAttachmentText to treat
resolvedRepresentation.kind values of both "ocr_text" and "embedded_text" as
requiring the OCR safety rule. Preserve the existing prompt construction and
ensure PDF embedded_text content is guarded in both current content and history
paths.
In `@src/main/ocr/ocrArtifactStore.ts`:
- Around line 644-712: The initialize method currently rejects schema version 1
and does not migrate it. Update the supported-version check to accept 1, and
include schemaVersion === 1 in the condition that sets user_version to 2,
preserving existing v1 cache data while applying the additive schema
initialization.
---
Nitpick comments:
In `@scripts/smoke-light-ocr.js`:
- Around line 219-231: Move the shared package-version validation logic from
assertExactPackageDependency in scripts/smoke-light-ocr.js into
light-ocr-artifacts.mjs, then import and reuse it from both smoke-light-ocr.js
and afterPack.js. Preserve each caller’s existing error-message behavior while
removing the duplicated helper definitions.
In `@src/main/ocr/attachmentCapabilityRouter.ts`:
- Around line 360-378: Update the orchestration around resolveImageOcrCandidates
and resolveDocumentOcrCandidates to start both async resolutions concurrently
and await their combined completion, while preserving their existing arguments
and shared diagnostic/issue collection behavior.
In `@src/main/ocr/documentOcrArtifact.ts`:
- Around line 20-27: Update PDF_OCR_ARTIFACT_REVISION to derive the tokenx
component from the installed tokenx dependency version instead of hard-coding
0.4.1. Use the resolved package metadata so the artifact identity changes
whenever tokenx is upgraded, while preserving the existing revision components.
In `@src/main/ocr/documentTextExtractionService.ts`:
- Around line 461-508: Extract the shared chunked file-read and SHA-256 logic
from readImmutablePdfSnapshot and readImmutableImageSnapshot into a reusable
helper, parameterized by chunk size and the caller’s error factory or error
type. Update both snapshot functions to use it while preserving their existing
byte-limit, abort, empty-input, and error semantics.
- Around line 510-515: Update normalizeDocumentSourceByteLimit and
normalizeGenerationTokenLimit to throw DocumentTextExtractionError with the
invalid_input code for invalid configuration limits, while preserving their
existing validation and messages.
In `@src/main/ocr/ocrArtifactStore.ts`:
- Around line 865-884: Update runMaintenance around the logicalBytes and
candidates construction so candidate materialization and sorting occur only when
logicalBytes exceeds the configured maxBytes budget. Preserve the existing
eviction behavior when over budget, while returning without allocating or
sorting candidates when storage remains within budget.
In `@src/main/session/data/transcript.ts`:
- Line 1: Extract the shared attachment searchable-text selection logic from
buildSearchableAttachmentText and collectUserMessageAttachmentRefs into
`@shared/utils/attachmentRepresentation` as a
getAttachmentSearchableText(file)-style helper. Have the helper always include
ocr_text and include embedded_text only for PDF attachments, then update both
callers to use it while preserving recallProjection’s existing per-attachment
and per-message character budgeting.
In `@test/main/ocr/lightOcrProtocol.test.ts`:
- Around line 15-22: Update the documentOptions.maxTotalPixels assignment to
reuse the exported LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELS constant instead of the
hardcoded 100 * 1024 * 1024 expression, matching the sibling OCR limit fields
and existing test usage.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 26bedcb9-fa3d-4b41-9296-a7b0a26a4349
⛔ Files ignored due to path filters (3)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlsrc/renderer/src/lib/icons/icon-collections.generated.tsis excluded by!**/*.generated.*src/renderer/src/lib/icons/icon-whitelist.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing (99)
docs/features/light-ocr-integration/spec.mddocs/features/light-ocr-pdf-support/plan.mddocs/features/light-ocr-pdf-support/spec.mddocs/features/light-ocr-pdf-support/tasks.mdpackage.jsonresources/acp-registry/registry.jsonresources/model-db/providers.jsonresources/runtime-versions.jsonscripts/afterPack.jsscripts/install-runtime.mjsscripts/light-ocr-artifacts.mjsscripts/smoke-light-ocr.jssrc/main/agent/deepchat/runtime/contextBuilder.tssrc/main/agent/deepchat/runtime/turnCoordinator.tssrc/main/exporter/agentSessionExporter.tssrc/main/exporter/formats/userMessageText.tssrc/main/file/adapters/PdfFileAdapter.tssrc/main/file/index.tssrc/main/lightOcrHelperEntry.tssrc/main/ocr/attachmentCapabilityRouter.tssrc/main/ocr/documentOcrArtifact.tssrc/main/ocr/documentTextExtractionService.tssrc/main/ocr/imageTextExtractionService.tssrc/main/ocr/lightOcrHelper.tssrc/main/ocr/lightOcrNativePayload.tssrc/main/ocr/lightOcrProcessHost.tssrc/main/ocr/lightOcrProtocol.tssrc/main/ocr/ocrArtifactStore.tssrc/main/ocr/ocrRuntimeAssetResolver.tssrc/main/ocr/ocrRuntimeService.tssrc/main/ocr/ocrSourceSnapshotBudget.tssrc/main/session/data/transcript.tssrc/main/tape/application/recallProjection.tssrc/main/tape/infrastructure/sqlite/tapeSearchProjectionStore.tssrc/renderer/src/components/chat/AttachmentPreparationDialog.vuesrc/renderer/src/components/chat/ChatAttachmentItem.vuesrc/renderer/src/components/chat/PendingInputLane.vuesrc/renderer/src/components/chat/nodes/FileAttachmentView.vuesrc/renderer/src/features/chat-page/composables/useComposerSubmit.tssrc/renderer/src/features/chat-page/model/composerDraftState.tssrc/renderer/src/i18n/da-DK/chat.jsonsrc/renderer/src/i18n/de-DE/chat.jsonsrc/renderer/src/i18n/en-US/chat.jsonsrc/renderer/src/i18n/es-ES/chat.jsonsrc/renderer/src/i18n/fa-IR/chat.jsonsrc/renderer/src/i18n/fr-FR/chat.jsonsrc/renderer/src/i18n/he-IL/chat.jsonsrc/renderer/src/i18n/id-ID/chat.jsonsrc/renderer/src/i18n/it-IT/chat.jsonsrc/renderer/src/i18n/ja-JP/chat.jsonsrc/renderer/src/i18n/ko-KR/chat.jsonsrc/renderer/src/i18n/ms-MY/chat.jsonsrc/renderer/src/i18n/pl-PL/chat.jsonsrc/renderer/src/i18n/pt-BR/chat.jsonsrc/renderer/src/i18n/ru-RU/chat.jsonsrc/renderer/src/i18n/tr-TR/chat.jsonsrc/renderer/src/i18n/vi-VN/chat.jsonsrc/renderer/src/i18n/zh-CN/chat.jsonsrc/renderer/src/i18n/zh-HK/chat.jsonsrc/renderer/src/i18n/zh-TW/chat.jsonsrc/renderer/src/pages/NewThreadPage.vuesrc/shared/chat.d.tssrc/shared/contracts/common.tssrc/shared/contracts/domainSchemas.tssrc/shared/types/agent-interface.d.tssrc/shared/types/attachment.tssrc/shared/types/core/chat.tssrc/shared/utils/attachmentRepresentation.tstest/fixtures/light-ocr/fake-helper.mjstest/main/agent/deepchat/runtime/contextBuilder.test.tstest/main/exporter/agentSessionExporter.test.tstest/main/exporter/userMessageText.test.tstest/main/file/pdfFileAdapter.test.tstest/main/ocr/attachmentCapabilityRouter.test.tstest/main/ocr/documentOcrArtifact.test.tstest/main/ocr/documentOcrArtifactStore.test.tstest/main/ocr/documentTextExtractionService.test.tstest/main/ocr/lightOcrHelper.test.tstest/main/ocr/lightOcrNativePayload.test.tstest/main/ocr/lightOcrProcessHost.test.tstest/main/ocr/lightOcrProtocol.test.tstest/main/ocr/ocrRuntimeAssetResolver.test.tstest/main/ocr/ocrRuntimeService.test.tstest/main/ocr/ocrSourceSnapshotBudget.test.tstest/main/ocr/routes.test.tstest/main/scripts/afterPack.test.tstest/main/scripts/installRuntime.test.tstest/main/scripts/lightOcrArtifacts.test.tstest/main/scripts/smokeLightOcr.test.tstest/main/session/data/tables/deepchatPendingInputsTable.test.tstest/main/session/data/tapeRecall.test.tstest/main/session/data/transcript.test.tstest/main/shared/attachmentRepresentation.test.tstest/renderer/components/ChatAttachmentItem.test.tstest/renderer/components/FileAttachmentView.test.tstest/renderer/components/NewThreadPage.test.tstest/renderer/components/fileAttachmentNode.test.tstest/renderer/features/chat-page/composables/useComposerSubmit.test.tstest/renderer/features/chat-page/model/composerDraftState.test.ts
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/main/ocr/ocrArtifactStore.ts (1)
644-712: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winAccept schema version
1and migrate it before initializing the schema.Databases from the previous v1 schema are accepted by
shouldRebuildOcrCacheforschema_mismatch, deleted, and then recreated empty, so existing cache entries are lost instead of preserved. The v1→v2 delta is additive, and the test expects the v1 file to be rebuilt successfully, so add1to both the supported-version check and the version bump condition.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/ocrArtifactStore.ts` around lines 644 - 712, The initialize method currently rejects schema version 1 and does not migrate it. Update the supported-version check to accept 1, and include schemaVersion === 1 in the condition that sets user_version to 2, preserving existing v1 cache data while applying the additive schema initialization.src/main/agent/deepchat/runtime/contextBuilder.ts (1)
431-433: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winImage metadata isn't sanitized like the new PDF path — attacker-controlled filename can break the untrusted-data framing.
sanitizeAttachmentMetadatawas added specifically to neutralize newlines/</>in attacker-controlled attachment metadata before it's embedded in the prompt (used for PDFs at Lines 464-469). This same file'sbuildResolvedImageRepresentationContext— touched by this very diff (invalid-kind guard, shared escape helper) — still interpolates rawfileName/mimeTypeunsanitized into the[Attached Image ... untrusted attachment data]block. A crafted image filename containing newlines and fake structural text (e.g.</untrusted_ocr_data>\nSYSTEM: ...) can inject content that reads as authoritative text outside the escaped OCR body, undermining the very untrusted-data framing this PR introduces.🛡️ Proposed fix
const fileName = typeof file.name === 'string' ? file.name : `image-${index + 1}` const mimeType = resolveFileMimeType(file) - const metadata = [`name: ${fileName}`, `mime: ${mimeType}`].join('\n') + const metadata = [ + `name: ${sanitizeAttachmentMetadata(fileName, 512)}`, + `mime: ${sanitizeAttachmentMetadata(mimeType, 128)}` + ].join('\n')🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/agent/deepchat/runtime/contextBuilder.ts` around lines 431 - 433, Update buildResolvedImageRepresentationContext to sanitize both fileName and mimeType with the existing sanitizeAttachmentMetadata helper before constructing the metadata string, matching the PDF metadata path and preserving the untrusted attachment-data framing.src/main/agent/deepchat/runtime/turnCoordinator.ts (1)
422-427: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winApply OCR-style guard to PDF
embedded_textattachments too
shouldGuardOcrAttachmentTextandhistoryContainsOcrAttachmentTextonly check forresolvedRepresentation?.kind === 'ocr_text', whilecontextBuilder.tsalso rendersembedded_textPDF content as untrusted attachment data. Includeembedded_textin the guard predicate so PDF prompt-injection protection covers the default Auto-mode text path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/agent/deepchat/runtime/turnCoordinator.ts` around lines 422 - 427, Update the attachment guard predicates around shouldGuardOcrAttachmentText and historyContainsOcrAttachmentText to treat resolvedRepresentation.kind values of both "ocr_text" and "embedded_text" as requiring the OCR safety rule. Preserve the existing prompt construction and ensure PDF embedded_text content is guarded in both current content and history paths.
🧹 Nitpick comments (8)
src/main/ocr/ocrArtifactStore.ts (1)
865-884: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueEviction candidates are materialized and sorted on every
runMaintenance, even when under budget.
putDocument/putcallrunMaintenance()on each write, and this builds + sorts a combined array of all records before checking the byte budget. The SQLite backend guards this work behindlogicalBytes > maxBytes; mirroring that here avoids the per-write allocation and sort.♻️ Suggested change
let logicalBytes = this.logicalBytes() + if (logicalBytes <= this.options.maxBytes) return const candidates = [🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/ocrArtifactStore.ts` around lines 865 - 884, Update runMaintenance around the logicalBytes and candidates construction so candidate materialization and sorting occur only when logicalBytes exceeds the configured maxBytes budget. Preserve the existing eviction behavior when over budget, while returning without allocating or sorting candidates when storage remains within budget.src/main/ocr/documentTextExtractionService.ts (2)
461-508: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winNear-duplicate of
readImmutableImageSnapshot.This is essentially
src/main/ocr/imagePreprocessor.ts'sreadImmutableImageSnapshotwith a different chunk size and error type. Consider extracting a shared chunked-read+SHA-256 helper parameterized by chunk size and an error factory, so the byte-limit semantics can't drift between image and document paths.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/documentTextExtractionService.ts` around lines 461 - 508, Extract the shared chunked file-read and SHA-256 logic from readImmutablePdfSnapshot and readImmutableImageSnapshot into a reusable helper, parameterized by chunk size and the caller’s error factory or error type. Update both snapshot functions to use it while preserving their existing byte-limit, abort, empty-input, and error semantics.
510-515: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMisleading error codes for invalid configuration inputs.
normalizeDocumentSourceByteLimitreports an invalid limit asinput_too_large(which the router maps to a user-facing "document too large") andnormalizeGenerationTokenLimitreports an invalid limit asruntime_identity_mismatch.invalid_inputdescribes both cases more accurately.Also applies to: 635-644
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/documentTextExtractionService.ts` around lines 510 - 515, Update normalizeDocumentSourceByteLimit and normalizeGenerationTokenLimit to throw DocumentTextExtractionError with the invalid_input code for invalid configuration limits, while preserving their existing validation and messages.src/main/ocr/documentOcrArtifact.ts (1)
20-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDerive the tokenx component from the installed dependency version.
PDF_OCR_ARTIFACT_REVISIONis used as part of cached artifact identity, buttokenx=0.4.1is hard-coded whilepackage.jsononly pins^0.4.1. Whentokenxis upgraded, stale artifacts can remain keyed by the old revision and only fail on the runtime token-count re-estimate. Use the resolved package version, or add coverage that it stays in sync with the dependency.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/documentOcrArtifact.ts` around lines 20 - 27, Update PDF_OCR_ARTIFACT_REVISION to derive the tokenx component from the installed tokenx dependency version instead of hard-coding 0.4.1. Use the resolved package metadata so the artifact identity changes whenever tokenx is upgraded, while preserving the existing revision components.scripts/smoke-light-ocr.js (1)
219-231: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winShare
assertExactPackageDependencywithafterPack.jsinstead of duplicating it.
scripts/afterPack.js(Lines 441-453) defines the identical helper; only the error message differs. Both scripts already import from./light-ocr-artifacts.mjs, which is the natural home for this pin-verification invariant. Keeping two copies risks the packaging check and the smoke check drifting apart.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/smoke-light-ocr.js` around lines 219 - 231, Move the shared package-version validation logic from assertExactPackageDependency in scripts/smoke-light-ocr.js into light-ocr-artifacts.mjs, then import and reuse it from both smoke-light-ocr.js and afterPack.js. Preserve each caller’s existing error-message behavior while removing the duplicated helper definitions.src/main/session/data/transcript.ts (1)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated attachment-searchable-text extraction rule across two files. Both
buildSearchableAttachmentTextandcollectUserMessageAttachmentRefsindependently re-implement the identical "includeocr_textunconditionally; includeembedded_textonly whenisPdfAttachment" rule. Extracting this into a shared helper in@shared/utils/attachmentRepresentation(which both files already import from) would prevent the two copies from silently diverging as new representation kinds are added.
src/main/session/data/transcript.ts#L136-174: extract theresolved.kind === 'ocr_text' | 'embedded_text'+isPdfAttachmentselection logic into a sharedgetAttachmentSearchableText(file)-style helper.src/main/tape/application/recallProjection.ts#L147-174: consume the same shared helper instead of re-derivingattachmentTextlocally, keeping this file's own per-attachment/per-message character budgeting on top of it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/session/data/transcript.ts` at line 1, Extract the shared attachment searchable-text selection logic from buildSearchableAttachmentText and collectUserMessageAttachmentRefs into `@shared/utils/attachmentRepresentation` as a getAttachmentSearchableText(file)-style helper. Have the helper always include ocr_text and include embedded_text only for PDF attachments, then update both callers to use it while preserving recallProjection’s existing per-attachment and per-message character budgeting.test/main/ocr/lightOcrProtocol.test.ts (1)
15-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the exported
LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELSinstead of the literal.
maxTotalPixelshardcodes100 * 1024 * 1024while the sibling limits come from exported constants; the test will silently drift if the protocol limit changes (test/main/ocr/lightOcrHelper.test.tsalready imports it).♻️ Proposed change
import { LIGHT_OCR_DOCUMENT_MAX_LINE_CHARACTERS, LIGHT_OCR_DOCUMENT_MAX_PAGE_PIXELS, + LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELS, LIGHT_OCR_HELPER_MAX_INPUT_BYTES, @@ - maxTotalPixels: 100 * 1024 * 1024 + maxTotalPixels: LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELS }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/main/ocr/lightOcrProtocol.test.ts` around lines 15 - 22, Update the documentOptions.maxTotalPixels assignment to reuse the exported LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELS constant instead of the hardcoded 100 * 1024 * 1024 expression, matching the sibling OCR limit fields and existing test usage.src/main/ocr/attachmentCapabilityRouter.ts (1)
360-378: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winConsider running image and document OCR resolution concurrently.
resolveImageOcrCandidatesandresolveDocumentOcrCandidatesoperate on disjoint candidate lists and only append to sharedissues/routingDiagnostics/ocrDiagnosticscollections, which is safe to do from concurrently-scheduled async calls in JS (no true parallel mutation). Awaiting them sequentially adds the document OCR latency on top of the image-batch latency whenever both are present in a turn.♻️ Proposed refactor
- await this.resolveImageOcrCandidates( - processableImages, - backend, - maxFileSize, - issues, - routingDiagnostics, - ocrDiagnostics, - signal - ) - await this.resolveDocumentOcrCandidates( - processableDocuments, - backend, - maxFileSize, - issues, - routingDiagnostics, - ocrDiagnostics, - signal - ) + await Promise.all([ + this.resolveImageOcrCandidates( + processableImages, + backend, + maxFileSize, + issues, + routingDiagnostics, + ocrDiagnostics, + signal + ), + this.resolveDocumentOcrCandidates( + processableDocuments, + backend, + maxFileSize, + issues, + routingDiagnostics, + ocrDiagnostics, + signal + ) + ])Note: the underlying OCR process host may still serialize IPC internally, so real-world gain depends on that layer.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/attachmentCapabilityRouter.ts` around lines 360 - 378, Update the orchestration around resolveImageOcrCandidates and resolveDocumentOcrCandidates to start both async resolutions concurrently and await their combined completion, while preserving their existing arguments and shared diagnostic/issue collection behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@package.json`:
- Line 112: Add the required Light OCR transitive dependencies to the
package.json dependency declarations: `@arcships/light-ocr-runtime` at 0.1.5,
`@arcships/light-ocr-model-ppocrv6-small` at 0.3.4, and each `@arcships/light-ocr-`*
native package at 0.5.5, alongside the existing `@arcships/light-ocr` entry. Keep
versions aligned with resources/runtime-versions.json and update the lockfile
consistently.
In `@resources/model-db/providers.json`:
- Around line 96770-96779: The openai/gpt-5-chat entry is incomplete and lacks
capability and pricing metadata. Update the model definition with the
appropriate modalities, tool_call, reasoning, and cost fields consistent with
neighbouring entries, and verify that retaining this stub is intentional after
its removal from the inference provider.
- Around line 90958-90964: Correct the model type from imageGeneration to chat
for google/gemini-2.5-flash, google/gemini-2.5-pro,
google/gemini-2.5-flash-lite, google/gemini-2.0-flash,
google/gemini-2.0-flash-lite-001, and qwen/qwen3-vl-plus. Apply this change at
resources/model-db/providers.json lines 90958-90964, 91209-91215, 91265-91271,
96451-96456, 96476-96481, and 97044-97055 respectively, preserving all other
model metadata.
In `@src/main/file/adapters/PdfFileAdapter.ts`:
- Around line 30-40: Update readPdfData in the PdfFileAdapter so filesystem
failures from fs.stat and fs.readFile are handled by the existing catch path and
resolve to undefined after logging. Widen the try boundary to cover the complete
file-loading and parsing flow, ensuring loadPdfData does not cache a permanently
rejected promise while preserving the existing successful and oversized-file
behavior.
In `@src/main/ocr/attachmentCapabilityRouter.ts`:
- Around line 749-792: Thread the routing issues collection into
applyTurnOcrTextBudget and update its call site so the budget-driven OCR-empty
downgrade uses the existing markUnavailable/appendIssue path instead of
assigning resolvedRepresentation directly. Preserve attachment indexing when
recording the issue, ensuring buildPreparationSummary surfaces the unavailable
document rather than returning an empty ready summary.
In `@src/main/ocr/documentOcrArtifact.ts`:
- Around line 116-129: Update LightOcrDocumentArtifact.append to avoid calling
fitDocumentOcrPages on every page: maintain the accumulated text and estimated
token count incrementally, compute only the new page’s contribution while within
both budgets, and append directly when it fits. When the new page exceeds a
budget, use the existing fitTruncatedPrefix path once to produce the truncated
result and mark the artifact as truncated, preserving page ordering and return
statuses.
In `@src/main/ocr/documentTextExtractionService.ts`:
- Around line 285-301: When the cached artifact becomes invalid after
truncateDocumentOcrArtifact and withSourcePageCountHint in the cache-hit path,
treat it as a cache miss instead of throwing DocumentTextExtractionError. Only
return the cached result when isValidDocumentOcrArtifact succeeds; otherwise
continue into the existing fresh extraction flow.
In `@src/main/ocr/lightOcrProcessHost.ts`:
- Around line 1070-1115: Update sendDocumentStop to use a dedicated, longer
document-stop timeout, preferably via a documentStopTimeoutMs option with a
default above a single page’s render and OCR duration, instead of cancelGraceMs.
Keep the existing acknowledgement cleanup and process-disposal behavior for
genuine stop timeouts, while ensuring output-limit truncation can allow the
helper to finish and preserve the partial document result.
In `@src/main/ocr/ocrRuntimeAssetResolver.ts`:
- Around line 434-440: Replace JSON.stringify-based inventory equality in
matchesArtifactInventory with explicit comparisons across the fixed groups
nativeCode, pdfiumCode, pdfiumLoader, and other, checking each group’s length
and entries element by element. Apply the same order-independent comparison
against expectedInventory in scripts/smoke-light-ocr.js at lines 468-470; both
sites must avoid relying on object key order.
---
Outside diff comments:
In `@src/main/agent/deepchat/runtime/contextBuilder.ts`:
- Around line 431-433: Update buildResolvedImageRepresentationContext to
sanitize both fileName and mimeType with the existing sanitizeAttachmentMetadata
helper before constructing the metadata string, matching the PDF metadata path
and preserving the untrusted attachment-data framing.
In `@src/main/agent/deepchat/runtime/turnCoordinator.ts`:
- Around line 422-427: Update the attachment guard predicates around
shouldGuardOcrAttachmentText and historyContainsOcrAttachmentText to treat
resolvedRepresentation.kind values of both "ocr_text" and "embedded_text" as
requiring the OCR safety rule. Preserve the existing prompt construction and
ensure PDF embedded_text content is guarded in both current content and history
paths.
In `@src/main/ocr/ocrArtifactStore.ts`:
- Around line 644-712: The initialize method currently rejects schema version 1
and does not migrate it. Update the supported-version check to accept 1, and
include schemaVersion === 1 in the condition that sets user_version to 2,
preserving existing v1 cache data while applying the additive schema
initialization.
---
Nitpick comments:
In `@scripts/smoke-light-ocr.js`:
- Around line 219-231: Move the shared package-version validation logic from
assertExactPackageDependency in scripts/smoke-light-ocr.js into
light-ocr-artifacts.mjs, then import and reuse it from both smoke-light-ocr.js
and afterPack.js. Preserve each caller’s existing error-message behavior while
removing the duplicated helper definitions.
In `@src/main/ocr/attachmentCapabilityRouter.ts`:
- Around line 360-378: Update the orchestration around resolveImageOcrCandidates
and resolveDocumentOcrCandidates to start both async resolutions concurrently
and await their combined completion, while preserving their existing arguments
and shared diagnostic/issue collection behavior.
In `@src/main/ocr/documentOcrArtifact.ts`:
- Around line 20-27: Update PDF_OCR_ARTIFACT_REVISION to derive the tokenx
component from the installed tokenx dependency version instead of hard-coding
0.4.1. Use the resolved package metadata so the artifact identity changes
whenever tokenx is upgraded, while preserving the existing revision components.
In `@src/main/ocr/documentTextExtractionService.ts`:
- Around line 461-508: Extract the shared chunked file-read and SHA-256 logic
from readImmutablePdfSnapshot and readImmutableImageSnapshot into a reusable
helper, parameterized by chunk size and the caller’s error factory or error
type. Update both snapshot functions to use it while preserving their existing
byte-limit, abort, empty-input, and error semantics.
- Around line 510-515: Update normalizeDocumentSourceByteLimit and
normalizeGenerationTokenLimit to throw DocumentTextExtractionError with the
invalid_input code for invalid configuration limits, while preserving their
existing validation and messages.
In `@src/main/ocr/ocrArtifactStore.ts`:
- Around line 865-884: Update runMaintenance around the logicalBytes and
candidates construction so candidate materialization and sorting occur only when
logicalBytes exceeds the configured maxBytes budget. Preserve the existing
eviction behavior when over budget, while returning without allocating or
sorting candidates when storage remains within budget.
In `@src/main/session/data/transcript.ts`:
- Line 1: Extract the shared attachment searchable-text selection logic from
buildSearchableAttachmentText and collectUserMessageAttachmentRefs into
`@shared/utils/attachmentRepresentation` as a
getAttachmentSearchableText(file)-style helper. Have the helper always include
ocr_text and include embedded_text only for PDF attachments, then update both
callers to use it while preserving recallProjection’s existing per-attachment
and per-message character budgeting.
In `@test/main/ocr/lightOcrProtocol.test.ts`:
- Around line 15-22: Update the documentOptions.maxTotalPixels assignment to
reuse the exported LIGHT_OCR_DOCUMENT_MAX_TOTAL_PIXELS constant instead of the
hardcoded 100 * 1024 * 1024 expression, matching the sibling OCR limit fields
and existing test usage.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 26bedcb9-fa3d-4b41-9296-a7b0a26a4349
⛔ Files ignored due to path filters (3)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlsrc/renderer/src/lib/icons/icon-collections.generated.tsis excluded by!**/*.generated.*src/renderer/src/lib/icons/icon-whitelist.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing (99)
docs/features/light-ocr-integration/spec.mddocs/features/light-ocr-pdf-support/plan.mddocs/features/light-ocr-pdf-support/spec.mddocs/features/light-ocr-pdf-support/tasks.mdpackage.jsonresources/acp-registry/registry.jsonresources/model-db/providers.jsonresources/runtime-versions.jsonscripts/afterPack.jsscripts/install-runtime.mjsscripts/light-ocr-artifacts.mjsscripts/smoke-light-ocr.jssrc/main/agent/deepchat/runtime/contextBuilder.tssrc/main/agent/deepchat/runtime/turnCoordinator.tssrc/main/exporter/agentSessionExporter.tssrc/main/exporter/formats/userMessageText.tssrc/main/file/adapters/PdfFileAdapter.tssrc/main/file/index.tssrc/main/lightOcrHelperEntry.tssrc/main/ocr/attachmentCapabilityRouter.tssrc/main/ocr/documentOcrArtifact.tssrc/main/ocr/documentTextExtractionService.tssrc/main/ocr/imageTextExtractionService.tssrc/main/ocr/lightOcrHelper.tssrc/main/ocr/lightOcrNativePayload.tssrc/main/ocr/lightOcrProcessHost.tssrc/main/ocr/lightOcrProtocol.tssrc/main/ocr/ocrArtifactStore.tssrc/main/ocr/ocrRuntimeAssetResolver.tssrc/main/ocr/ocrRuntimeService.tssrc/main/ocr/ocrSourceSnapshotBudget.tssrc/main/session/data/transcript.tssrc/main/tape/application/recallProjection.tssrc/main/tape/infrastructure/sqlite/tapeSearchProjectionStore.tssrc/renderer/src/components/chat/AttachmentPreparationDialog.vuesrc/renderer/src/components/chat/ChatAttachmentItem.vuesrc/renderer/src/components/chat/PendingInputLane.vuesrc/renderer/src/components/chat/nodes/FileAttachmentView.vuesrc/renderer/src/features/chat-page/composables/useComposerSubmit.tssrc/renderer/src/features/chat-page/model/composerDraftState.tssrc/renderer/src/i18n/da-DK/chat.jsonsrc/renderer/src/i18n/de-DE/chat.jsonsrc/renderer/src/i18n/en-US/chat.jsonsrc/renderer/src/i18n/es-ES/chat.jsonsrc/renderer/src/i18n/fa-IR/chat.jsonsrc/renderer/src/i18n/fr-FR/chat.jsonsrc/renderer/src/i18n/he-IL/chat.jsonsrc/renderer/src/i18n/id-ID/chat.jsonsrc/renderer/src/i18n/it-IT/chat.jsonsrc/renderer/src/i18n/ja-JP/chat.jsonsrc/renderer/src/i18n/ko-KR/chat.jsonsrc/renderer/src/i18n/ms-MY/chat.jsonsrc/renderer/src/i18n/pl-PL/chat.jsonsrc/renderer/src/i18n/pt-BR/chat.jsonsrc/renderer/src/i18n/ru-RU/chat.jsonsrc/renderer/src/i18n/tr-TR/chat.jsonsrc/renderer/src/i18n/vi-VN/chat.jsonsrc/renderer/src/i18n/zh-CN/chat.jsonsrc/renderer/src/i18n/zh-HK/chat.jsonsrc/renderer/src/i18n/zh-TW/chat.jsonsrc/renderer/src/pages/NewThreadPage.vuesrc/shared/chat.d.tssrc/shared/contracts/common.tssrc/shared/contracts/domainSchemas.tssrc/shared/types/agent-interface.d.tssrc/shared/types/attachment.tssrc/shared/types/core/chat.tssrc/shared/utils/attachmentRepresentation.tstest/fixtures/light-ocr/fake-helper.mjstest/main/agent/deepchat/runtime/contextBuilder.test.tstest/main/exporter/agentSessionExporter.test.tstest/main/exporter/userMessageText.test.tstest/main/file/pdfFileAdapter.test.tstest/main/ocr/attachmentCapabilityRouter.test.tstest/main/ocr/documentOcrArtifact.test.tstest/main/ocr/documentOcrArtifactStore.test.tstest/main/ocr/documentTextExtractionService.test.tstest/main/ocr/lightOcrHelper.test.tstest/main/ocr/lightOcrNativePayload.test.tstest/main/ocr/lightOcrProcessHost.test.tstest/main/ocr/lightOcrProtocol.test.tstest/main/ocr/ocrRuntimeAssetResolver.test.tstest/main/ocr/ocrRuntimeService.test.tstest/main/ocr/ocrSourceSnapshotBudget.test.tstest/main/ocr/routes.test.tstest/main/scripts/afterPack.test.tstest/main/scripts/installRuntime.test.tstest/main/scripts/lightOcrArtifacts.test.tstest/main/scripts/smokeLightOcr.test.tstest/main/session/data/tables/deepchatPendingInputsTable.test.tstest/main/session/data/tapeRecall.test.tstest/main/session/data/transcript.test.tstest/main/shared/attachmentRepresentation.test.tstest/renderer/components/ChatAttachmentItem.test.tstest/renderer/components/FileAttachmentView.test.tstest/renderer/components/NewThreadPage.test.tstest/renderer/components/fileAttachmentNode.test.tstest/renderer/features/chat-page/composables/useComposerSubmit.test.tstest/renderer/features/chat-page/model/composerDraftState.test.ts
🛑 Comments failed to post (2)
resources/model-db/providers.json (2)
90958-90964: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Six chat models in the new
zenmuxprovider are typedimageGeneration. All declareoutput: ["text"](or no image output modality), so the shared root cause is an incorrecttypevalue that will route text models through image-generation categorization.
resources/model-db/providers.json#L90958-L90964: set"type": "chat"forgoogle/gemini-2.5-flash.resources/model-db/providers.json#L91209-L91215: set"type": "chat"forgoogle/gemini-2.5-pro.resources/model-db/providers.json#L91265-L91271: set"type": "chat"forgoogle/gemini-2.5-flash-lite.resources/model-db/providers.json#L96451-L96456: set"type": "chat"forgoogle/gemini-2.0-flash.resources/model-db/providers.json#L96476-L96481: set"type": "chat"forgoogle/gemini-2.0-flash-lite-001.resources/model-db/providers.json#L97044-L97055: set"type": "chat"forqwen/qwen3-vl-plus.📍 Affects 1 file
resources/model-db/providers.json#L90958-L90964(this comment)resources/model-db/providers.json#L91209-L91215resources/model-db/providers.json#L91265-L91271resources/model-db/providers.json#L96451-L96456resources/model-db/providers.json#L96476-L96481resources/model-db/providers.json#L97044-L97055🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@resources/model-db/providers.json` around lines 90958 - 90964, Correct the model type from imageGeneration to chat for google/gemini-2.5-flash, google/gemini-2.5-pro, google/gemini-2.5-flash-lite, google/gemini-2.0-flash, google/gemini-2.0-flash-lite-001, and qwen/qwen3-vl-plus. Apply this change at resources/model-db/providers.json lines 90958-90964, 91209-91215, 91265-91271, 96451-96456, 96476-96481, and 97044-97055 respectively, preserving all other model metadata.
96770-96779: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
openai/gpt-5-chatentry is missingmodalities,tool_call,reasoning, andcost.Every neighbouring entry declares at least modalities and tool_call; this stub will lose capability gating and cost estimation. Note the same model id is being removed from the
inferenceprovider in this PR — confirm the stub here is intentional.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@resources/model-db/providers.json` around lines 96770 - 96779, The openai/gpt-5-chat entry is incomplete and lacks capability and pricing metadata. Update the model definition with the appropriate modalities, tool_call, reasoning, and cost fields consistent with neighbouring entries, and verify that retaining this stub is intentional after its removal from the inference provider.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/ocr/documentTextExtractionService.ts (1)
619-639: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winNormalize
snapshot_io_failedandpage_handler_failedbefore throwing.In
normalizeRuntimeError, theseLightOcrProcessHostErrorcodes fall through and are re-thrown asLightOcrProcessHostError, soextractDocument()rejects with a non-DocumentTextExtractionError;mapDocumentExtractionFailure()already maps them to genericocr_failed, losing the specific failure reason. ConstructDocumentTextExtractionErrorfor these codes or align the router mapping with the host code.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/documentTextExtractionService.ts` around lines 619 - 639, The normalizeRuntimeError function must convert LightOcrProcessHostError codes snapshot_io_failed and page_handler_failed into DocumentTextExtractionError before they are thrown. Add both codes to the existing host-error normalization branch, preserving each original code, message, and cause so extractDocument returns the specific failure reason instead of a generic ocr_failed mapping.
🧹 Nitpick comments (5)
src/main/ocr/lightOcrProcessHost.ts (1)
1014-1026: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueCompute
renderedPixelsafter shape validation.
page.width * page.heightruns beforeisLightOcrDocumentPage(page), so it can beNaNfor a malformed payload. The||chain short-circuits so behavior is correct today, but the ordering is fragile if the conditions are ever reordered.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/lightOcrProcessHost.ts` around lines 1014 - 1026, Move the renderedPixels calculation in the page-validation flow to occur only after isLightOcrDocumentPage(page) has confirmed the payload shape. Preserve the existing invalid-sequence checks and rendered-pixel validation in the surrounding protocol handling.src/main/ocr/attachmentCapabilityRouter.ts (1)
817-832: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
recordTurnBudgetIssueoverwrites the pre-existing reason for that attachment.If the document already recorded
ocr_resource_limited(Line 517), it is replaced rather than kept alongside. That is defensible since the terminal state is nowturn_ocr_budget_exhausted, but the resource-limit signal is lost from the summary — worth a short comment so the intent is explicit.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/attachmentCapabilityRouter.ts` around lines 817 - 832, Clarify the intentional overwrite in recordTurnBudgetIssue by adding a short comment where an existing issue is replaced, noting that turn_ocr_budget_exhausted is the terminal reason and supersedes the prior reason such as ocr_resource_limited. Keep the current replacement and duplicate-removal behavior unchanged.src/shared/utils/documentOcrText.ts (1)
47-61: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueZero-length complete spans bypass the body check.
When
start === endtheif (chunk)branch is skipped, so acompletespan with no## Page Nheader and no body validates, while a complete span that has the header but an empty body is rejected at Line 52. If a fully empty page span is legal, consider making it explicit; otherwise reject it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/utils/documentOcrText.ts` around lines 47 - 61, Update the span validation logic around the chunk handling in document OCR validation so zero-length complete spans are handled explicitly. Reject a complete span when start equals end unless fully empty pages are an intended valid case; preserve the existing header and body validation for non-empty chunks and the incomplete-span behavior.src/main/ocr/documentTextExtractionService.ts (1)
250-278: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDead
if (!flight)guard.The preceding
if (flight) { ... return ... }already returns, so this check is always true and the non-null assertions below only exist to satisfy it.♻️ Suggested simplification
- let flight = this.flights.get(flightKey) - if (flight) { + const existing = this.flights.get(flightKey) + if (existing) { releaseUnusedSnapshot = false await this.releaseSnapshot(snapshot) - return await this.joinFlight(flightKey, flight, input.signal) + return await this.joinFlight(flightKey, existing, input.signal) } - if (!flight) { - const controller = new AbortController() - ... - } + const controller = new AbortController() + ... + const flight: SharedDocumentExtractionFlight = { controller, promise, snapshot, owners: 0, settled: false } + releaseUnusedSnapshot = false + this.flights.set(flightKey, flight) + promise.then( + () => this.finishFlight(flightKey, flight), + () => this.finishFlight(flightKey, flight) + ) return await this.joinFlight(flightKey, flight, input.signal)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/ocr/documentTextExtractionService.ts` around lines 250 - 278, Remove the redundant if (!flight) guard after the early-returning if (flight) block. Keep the flight creation, registration, and completion handling logic in the unconditional path, and remove the unnecessary non-null assertions when passing flight to finishFlight.test/main/ocr/documentTextExtractionService.test.ts (1)
52-85: 📐 Maintainability & Code Quality | 🔵 TrivialDefault
snapshotReaderfallback path is never exercised.
createProcessHost'screateDocumentSourceSnapshotstub (Lines 76-81) is unused by every test in this suite becausecreateService(Lines 104-125) and the direct-construction test (Lines 388-398) always pass an explicitsnapshotReader. The production fallback (options.snapshotReader ?? processHost.createDocumentSourceSnapshot) is therefore untested here.Consider adding one test that constructs the service without
snapshotReaderto confirm it correctly falls back toprocessHost.createDocumentSourceSnapshot.Also applies to: 104-125
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/main/ocr/documentTextExtractionService.test.ts` around lines 52 - 85, Add a test covering the default snapshotReader fallback by constructing the service through createService without passing snapshotReader, then trigger document text extraction and verify processHost.createDocumentSourceSnapshot is called and its snapshot is used. Keep existing explicit-snapshotReader tests unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/main/ocr/documentTextExtractionService.ts`:
- Around line 619-639: The normalizeRuntimeError function must convert
LightOcrProcessHostError codes snapshot_io_failed and page_handler_failed into
DocumentTextExtractionError before they are thrown. Add both codes to the
existing host-error normalization branch, preserving each original code,
message, and cause so extractDocument returns the specific failure reason
instead of a generic ocr_failed mapping.
---
Nitpick comments:
In `@src/main/ocr/attachmentCapabilityRouter.ts`:
- Around line 817-832: Clarify the intentional overwrite in
recordTurnBudgetIssue by adding a short comment where an existing issue is
replaced, noting that turn_ocr_budget_exhausted is the terminal reason and
supersedes the prior reason such as ocr_resource_limited. Keep the current
replacement and duplicate-removal behavior unchanged.
In `@src/main/ocr/documentTextExtractionService.ts`:
- Around line 250-278: Remove the redundant if (!flight) guard after the
early-returning if (flight) block. Keep the flight creation, registration, and
completion handling logic in the unconditional path, and remove the unnecessary
non-null assertions when passing flight to finishFlight.
In `@src/main/ocr/lightOcrProcessHost.ts`:
- Around line 1014-1026: Move the renderedPixels calculation in the
page-validation flow to occur only after isLightOcrDocumentPage(page) has
confirmed the payload shape. Preserve the existing invalid-sequence checks and
rendered-pixel validation in the surrounding protocol handling.
In `@src/shared/utils/documentOcrText.ts`:
- Around line 47-61: Update the span validation logic around the chunk handling
in document OCR validation so zero-length complete spans are handled explicitly.
Reject a complete span when start equals end unless fully empty pages are an
intended valid case; preserve the existing header and body validation for
non-empty chunks and the incomplete-span behavior.
In `@test/main/ocr/documentTextExtractionService.test.ts`:
- Around line 52-85: Add a test covering the default snapshotReader fallback by
constructing the service through createService without passing snapshotReader,
then trigger document text extraction and verify
processHost.createDocumentSourceSnapshot is called and its snapshot is used.
Keep existing explicit-snapshotReader tests unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d5bda813-8f7d-4f7c-b535-4dbf6208fec8
📒 Files selected for processing (43)
.github/workflows/prcheck.ymldocs/features/light-ocr-pdf-support/plan.mddocs/features/light-ocr-pdf-support/spec.mddocs/features/light-ocr-pdf-support/tasks.mdsrc/main/agent/deepchat/runtime/contextBuilder.tssrc/main/file/adapters/PdfFileAdapter.tssrc/main/ocr/attachmentCapabilityRouter.tssrc/main/ocr/documentOcrArtifact.tssrc/main/ocr/documentTextExtractionService.tssrc/main/ocr/lightOcrProcessHost.tssrc/main/ocr/lightOcrProtocol.tssrc/renderer/src/i18n/da-DK/chat.jsonsrc/renderer/src/i18n/de-DE/chat.jsonsrc/renderer/src/i18n/en-US/chat.jsonsrc/renderer/src/i18n/es-ES/chat.jsonsrc/renderer/src/i18n/fa-IR/chat.jsonsrc/renderer/src/i18n/fr-FR/chat.jsonsrc/renderer/src/i18n/he-IL/chat.jsonsrc/renderer/src/i18n/id-ID/chat.jsonsrc/renderer/src/i18n/it-IT/chat.jsonsrc/renderer/src/i18n/ja-JP/chat.jsonsrc/renderer/src/i18n/ko-KR/chat.jsonsrc/renderer/src/i18n/ms-MY/chat.jsonsrc/renderer/src/i18n/pl-PL/chat.jsonsrc/renderer/src/i18n/pt-BR/chat.jsonsrc/renderer/src/i18n/ru-RU/chat.jsonsrc/renderer/src/i18n/tr-TR/chat.jsonsrc/renderer/src/i18n/vi-VN/chat.jsonsrc/renderer/src/i18n/zh-CN/chat.jsonsrc/renderer/src/i18n/zh-HK/chat.jsonsrc/renderer/src/i18n/zh-TW/chat.jsonsrc/shared/contracts/common.tssrc/shared/types/attachment.tssrc/shared/utils/attachmentRepresentation.tssrc/shared/utils/documentOcrText.tstest/main/agent/deepchat/runtime/contextBuilder.test.tstest/main/ocr/attachmentCapabilityRouter.test.tstest/main/ocr/documentOcrArtifact.test.tstest/main/ocr/documentOcrArtifactStore.test.tstest/main/ocr/documentTextExtractionService.test.tstest/main/ocr/lightOcrProcessHost.test.tstest/main/scripts/prcheckWorkflow.test.tstest/main/shared/attachmentRepresentation.test.ts
🚧 Files skipped from review as they are similar to previous changes (28)
- docs/features/light-ocr-pdf-support/tasks.md
- src/renderer/src/i18n/id-ID/chat.json
- src/renderer/src/i18n/en-US/chat.json
- src/renderer/src/i18n/pl-PL/chat.json
- src/renderer/src/i18n/tr-TR/chat.json
- src/renderer/src/i18n/es-ES/chat.json
- src/renderer/src/i18n/zh-CN/chat.json
- src/renderer/src/i18n/ja-JP/chat.json
- src/renderer/src/i18n/ko-KR/chat.json
- src/main/file/adapters/PdfFileAdapter.ts
- src/renderer/src/i18n/fa-IR/chat.json
- src/renderer/src/i18n/da-DK/chat.json
- test/main/ocr/documentOcrArtifactStore.test.ts
- src/renderer/src/i18n/zh-TW/chat.json
- src/renderer/src/i18n/ms-MY/chat.json
- src/renderer/src/i18n/zh-HK/chat.json
- src/renderer/src/i18n/vi-VN/chat.json
- src/main/agent/deepchat/runtime/contextBuilder.ts
- src/renderer/src/i18n/fr-FR/chat.json
- test/main/ocr/attachmentCapabilityRouter.test.ts
- test/main/agent/deepchat/runtime/contextBuilder.test.ts
- src/renderer/src/i18n/ru-RU/chat.json
- src/renderer/src/i18n/he-IL/chat.json
- src/renderer/src/i18n/de-DE/chat.json
- src/renderer/src/i18n/it-IT/chat.json
- docs/features/light-ocr-pdf-support/plan.md
- src/shared/utils/attachmentRepresentation.ts
- src/main/ocr/lightOcrProtocol.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@resources/model-db/providers.json`:
- Around line 269259-269286: Add the missing cost object to the
zhipuai/openrouter claude-opus-5 entry, matching the provider-specific Claude
Opus 5 input, output, and cache pricing used by the corresponding provider
section. Keep the existing model capabilities unchanged and ensure the entry no
longer defaults to unknown or zero pricing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 0d10eee1-7c8d-46a9-a1f3-8072d4049a9d
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (27)
package.jsonresources/acp-registry/registry.jsonresources/model-db/providers.jsonscripts/light-ocr-artifacts.mjsscripts/smoke-light-ocr.jssrc/main/agent/deepchat/runtime/contextBuilder.tssrc/main/agent/deepchat/runtime/turnCoordinator.tssrc/main/file/adapters/PdfFileAdapter.tssrc/main/ocr/documentOcrArtifact.tssrc/main/ocr/documentTextExtractionService.tssrc/main/ocr/lightOcrProcessHost.tssrc/main/ocr/ocrArtifactStore.tssrc/main/ocr/ocrRuntimeAssetResolver.tssrc/main/session/data/transcript.tssrc/main/tape/application/recallProjection.tssrc/shared/utils/attachmentRepresentation.tstest/fixtures/light-ocr/fake-helper.mjstest/main/agent/deepchat/harness/deepChatAgentHarness.test.tstest/main/agent/deepchat/runtime/contextBuilder.test.tstest/main/file/pdfFileAdapter.test.tstest/main/ocr/documentOcrArtifact.test.tstest/main/ocr/documentTextExtractionService.test.tstest/main/ocr/lightOcrProcessHost.test.tstest/main/ocr/lightOcrProtocol.test.tstest/main/ocr/ocrRuntimeAssetResolver.test.tstest/main/scripts/lightOcrArtifacts.test.tstest/main/shared/attachmentRepresentation.test.ts
🚧 Files skipped from review as they are similar to previous changes (17)
- test/main/scripts/lightOcrArtifacts.test.ts
- package.json
- test/main/ocr/lightOcrProtocol.test.ts
- src/main/session/data/transcript.ts
- test/main/shared/attachmentRepresentation.test.ts
- test/main/ocr/documentTextExtractionService.test.ts
- test/main/ocr/documentOcrArtifact.test.ts
- test/fixtures/light-ocr/fake-helper.mjs
- src/main/ocr/ocrRuntimeAssetResolver.ts
- test/main/ocr/ocrRuntimeAssetResolver.test.ts
- src/shared/utils/attachmentRepresentation.ts
- src/main/agent/deepchat/runtime/contextBuilder.ts
- src/main/file/adapters/PdfFileAdapter.ts
- src/main/ocr/documentTextExtractionService.ts
- src/main/ocr/ocrArtifactStore.ts
- src/main/ocr/lightOcrProcessHost.ts
- scripts/smoke-light-ocr.js
Summary
@arcships/light-ocrto 0.5.5 and package its PDFium runtime across supported platforms.What changed
Runtime and packaging
PDF OCR pipeline
Routing and provider context
Auto,Text, andOCRrepresentation choices for PDF attachments.Summary by CodeRabbit