feat(assets): PDF text extraction via unpdf#352
Conversation
There was a problem hiding this comment.
Sorry @aliasunder, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
PR Code Suggestions ✨Explore these optional code suggestions:
|
|
@CodeRabbit review |
✅ Action performedReview finished.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (10)
📝 WalkthroughWalkthroughChangesPDF assets are now read through PDF asset support
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. 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 |
vault_read_asset now extracts text from PDFs using unpdf's content-stream parser instead of returning a "not yet supported" error. Scanned or image-only PDFs (no extractable text) get a descriptive error with page count. Extracted text is subject to the same MAX_TEXT_OUTPUT_BYTES cap as other text assets. - Add unpdf dependency for serverless-first PDF.js text extraction - Replace PDF error block in asset-operations.ts with extractText dispatch - Convert Buffer → Uint8Array for unpdf compatibility - Update vault_read_asset tool description (PDF section, errors, examples) - Update vault_list_assets description (remove stale ".pdf unsupported" note) - Fix "MCP attachment reads" → "MCP asset reads" comment in config.ts - Add asset-operations unit tests (PDF happy path, scanned PDF, whitespace- only, text cap, unsupported type includes .pdf) - Add integration test with minimal valid PDF fixture - Update existing tool-definitions tests for new error message format Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PajwhEzt5cjqQjBPVBuXHn
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PajwhEzt5cjqQjBPVBuXHn
ARCHITECTURE.md still described PDFs as "not-yet-supported" after the feature landed. README.md and DOCKERHUB.md listed supported asset types without mentioning PDFs. Updated all three to reflect the new capability. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The unpdf overload for mergePages:true already narrows text to string — the typeof check was dead code and the "" fallback masked the invariant. Added a why-comment on the non-obvious Buffer→Uint8Array pool conversion. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tighten 4 substring error assertions to exact message matches (deterministic errors should not use substring matchers — catches message drift). Add content-length assertion to PDF integration test. Write coverage gap test for extractText rejection propagation (corrupt/unparseable PDFs). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both env vars were documented in every deploy surface (docker-compose, .env.example, cli/src/env.ts) and referenced in the vault_read_asset error descriptions, but missing from the README and DOCKERHUB config tables — a pre-existing gap from PR #351. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace flat extractText with extractTextItems + getMeta + extractLinks for richer PDF output at near-identical token cost (~7% overhead): - Document header: title, page count, links count - Heading hierarchy: relative font-size detection (top N-1 distinct sizes map to H1-H3, smallest is always body text) - Code fences: monospace fontFamily → fenced code blocks - Page separators: --- Page N --- - Links footer: deduplicated hyperlinks from the document - Proxy lifecycle: getDocumentProxy with try/finally cleanup The structured items are an intermediate processing step — the raw coordinates are never exposed; the delivery format is reconstructed markdown that a model reads naturally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
28efeff to
79d0674
Compare
…nt, stale example Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Exact error message for text-too-large (was substring match on deterministic output — 200024 bytes computed from header + body) - New test: code fence at end-of-page with no sans-serif transition covers the trailing `if (inCodeBlock)` branch; mutation-verified Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sweep of all 9 asset tool handler integration tests — every decomposed isError + content[0]?.text pattern replaced with a single toEqual on the full result shape. Locks structure so extra fields, type drift, or isError changes are caught. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…name sections→outputLines Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The tool input table listed only `path` but the tool also accepts `raw?` — every other tool in the table lists all optional params. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
groupIntoLines: for...of with tracked lastY replaces index-based iteration and eliminates three type-narrowing guards that could never fire at runtime. buildHeadingLevels: Map constructor with .map() replaces mutable for-loop. Double slice (remove smallest, cap at 3) reads sequentially. Pipeline naming fixed (sortedSizes, not roundedSizes). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Annotate the heading-level builder (visual hierarchy, body-text exclusion), line classifier (monospace/heading detection), fence transitions, end-of-page fence close, sequential proxy calls (structuredClone constraint), and scanned-PDF guard. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
What does this PR do?
Adds PDF text extraction to
vault_read_assetvia unpdf — a MIT-licensed, zero-dep, serverless-first PDF.js bundle. When a PDF is read, its text content is extracted and returned as a text content block, just like.svg,.json, and other text formats.Scanned/image-only PDFs that yield no extractable text throw a structured error naming the file, its size, and page count — guiding the caller toward the limitation rather than returning empty content silently.
Key implementation details:
unpdf'sextractTextrequiresUint8Arrayinput (rejectsBuffer), so the dispatch creates a zero-copy view via the sharedArrayBuffermergePages: truereturns all pages as a single stringassertTextWithinCapguard.pdfcase in the unsupported-type error is removed;.pdfadded to the readable-types list in that error messageType of change
Checklist
npm testpassesnpm run lintpassesnpm run prettier:checkpassesnpm run buildsucceedsNote: No new tools — this extends the existing
vault_read_assettool's dispatch. One pre-existing flaky test (fit-image-to-byte-budgetalpha WebP timeout) is unrelated to this change.Summary by CodeRabbit
New Features
Documentation