Files
CherryHQ-cherry-studio/packages/shared/utils
Phantom fb42d4d0b5 fix(aiCore): improve PDF processing robustness for aggregator providers (#13641)
### What this PR does

Before this PR:
- `supportsPdfInput()` hardcodes a provider ID whitelist, causing
aggregator providers (cherryin, new-api type) to always fall back to
text extraction even when the underlying model supports native PDF.
- 5 places where PDF processing fails silently — files get dropped from
messages with no user notification.

After this PR:
- Message preparation always produces the richest representation
(FilePart) for all PDFs regardless of provider.
- A new `pdfCompatibilityPlugin` middleware handles compatibility by
converting PDF FileParts to TextParts for providers that don't support
native PDF input, using `pdf-parse` 2.x to extract text directly from
FilePart data in the renderer process.
- All 5 failure paths now show user-facing toast notifications
(warnings/errors).
- `pdf-parse` upgraded to 2.x (browser-compatible, TypeScript, extracts
text from buffer/base64 directly).
- New shared utility `extractPdfText()` for PDF text extraction from any
data format.

Fixes #13603, fixes #13638

### Why we need it and why it was done in this way

The following tradeoffs were made:
- The plugin uses `provider.type` (API protocol) instead of
`getAiSdkProviderId()` to determine PDF support, because aggregator
providers (cherryin, new-api, gateway) resolve to non-standard AI SDK
IDs but speak standard protocols that support PDF.
- `pdf-parse` 2.x is used directly in the renderer process to extract
text from base64 PDF data, eliminating the need for IPC calls or
providerOptions workarounds.
- The plugin runs for every request but short-circuits immediately for
supported providers (Set lookup).

The following alternatives were considered:
- Extending the whitelist to cover more providers — rejected because
it's a whack-a-mole approach.
- Using `getAiSdkProviderId()` — rejected because it returns unreliable
IDs for aggregator providers.
- Pre-extracting text in fileProcessor and passing via providerOptions —
rejected as it misuses providerOptions and adds unnecessary IO for
native providers.
- Adding IPC methods for buffer-based text extraction — rejected as
pdf-parse 2.x runs directly in renderer.

Links to places where the discussion took place:
- #13603 (provider whitelist issue)
- #13638 (silent failure paths)

### Breaking changes

None. This is a transparent improvement — providers that previously
supported native PDF still get FileParts, and providers that didn't now
get TextParts instead of silently dropped files.

### Special notes for your reviewer

- `pdf-parse` upgraded from 1.1.1 to 2.4.5. The existing patch
(`patches/pdf-parse-npm-1.1.1-04a6109b2a.patch`) is for the indirect
dependency (via `office-text-extractor`) and remains untouched.
- `@langchain/community` has a peer dep on `pdf-parse@1.1.1` but only
`VoyageEmbeddings` is imported from it — `PDFLoader` is not used, so the
peer warning is harmless.
- **NOTE**: The `pdf-parse` peer dependency warning for
`@langchain/community` is safe **only** when `PDFLoader` is not being
used. If `PDFLoader` is ever imported in the future, this
incompatibility must be addressed.
- `qwen-long`/`qwen-doc` models use `handleLargeFileUpload` →
`fileid://` reference → `SystemModelMessage`. They never reach the
plugin as FilePart, so they are unaffected.
- Non-PDF documents (Word, Excel) still return `null` from
`convertFileBlockToFilePart` and use the text fallback path unchanged.
- `isPdfFilePart` is a proper TypeScript type guard. No `as` type
assertions in the plugin code.

### Checklist

- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others

### Release note

```release-note
Improved PDF file processing: aggregator providers (cherryin, new-api, etc.) now correctly handle native PDF input instead of always falling back to text extraction. Added user-facing notifications when PDF processing fails instead of silently dropping files.
```

---------

Signed-off-by: icarus <eurfelux@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:29:53 +08:00
..