feat(ai-openai): PDF document input#977
Conversation
…pter OpenAI chat models that declare the `document` input modality now accept PDF `document` content parts through `openaiText` on the Responses adapter. Base64 data sources are sent as `input_file` with a `file_data` data URL and a `filename` (from `metadata.filename`, defaulting to `document.pdf`); URL sources are sent as `input_file` with `file_url`. The adapter rejects non-PDF document MIME types with a clear error before the request goes out — including pre-wrapped `data:` URLs whose media type disagrees with `mimeType` — so callers get an actionable message instead of an opaque provider 400. `OpenAIDocumentMetadata` gains `filename` and `detail`, and the document-capable chat models declare the `document` input modality. The Chat Completions adapter throws a document-specific error pointing at the Responses adapter, since documents are only supported there. Adds unit coverage for the Responses and Chat Completions adapters, and an e2e fixture/spec/page for the multimodal-document feature.
Add a changeset (minor bump for `@tanstack/openai-base` and `@tanstack/ai-openai`) and a multimodal-content docs example for the new `document` content part support on the Responses adapter. The example uses `gpt-5.5`, one of the models that declares the `document` input modality; the "Supported modalities by model" list is expanded to include it and points readers at `model-meta.ts` for the full, authoritative list.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughOpenAI model metadata now declares PDF document input support. The Responses adapter converts PDF data and URL sources into ChangesOpenAI PDF document support
Estimated code review effort: 3 (Moderate) | ~30 minutes Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant ChatUI
participant ChatFeature
participant ResponsesAdapter
participant OpenAIResponsesAPI
ChatUI->>ChatFeature: select PDF and submit prompt
ChatFeature->>ChatFeature: read PDF as base64 data URL
ChatFeature->>ResponsesAdapter: send document content part
ResponsesAdapter->>ResponsesAdapter: validate PDF and build input_file
ResponsesAdapter->>OpenAIResponsesAPI: submit file_data or file_url
OpenAIResponsesAPI-->>ChatFeature: stream response events
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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: 2
🤖 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 `@packages/ai-openai/src/message-types.ts`:
- Around line 62-66: Allow OpenAIDocumentMetadata.detail to include 'auto' and
update its documentation to state that the API defaults to auto, resolving to
low or high by model; in packages/ai-openai/src/message-types.ts lines 62-66,
widen the type and revise the comment. Also widen the inline detail cast in
packages/openai-base/src/adapters/responses-text.ts lines 1843-1845 to accept
'auto' alongside the existing values.
In `@packages/openai-base/src/adapters/responses-text.ts`:
- Around line 1864-1873: Update the document handling logic in the relevant
responses-text conversion method so raw base64 documents without a mimeType
undergo the same local PDF validation instead of defaulting directly to
application/pdf and bypassing checks. Preserve explicit mimeType normalization
and rejection of non-PDF values, and add a regression test covering a raw base64
document with no mimeType.
🪄 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
Run ID: 39b1fe3a-2bad-4186-b445-34af67ff1dc0
⛔ Files ignored due to path filters (1)
testing/e2e/test-assets/tiny.pdfis excluded by!**/*.pdf
📒 Files selected for processing (19)
.changeset/openai-pdf-document-input.mddocs/advanced/multimodal-content.mddocs/config.jsonpackages/ai-openai/src/message-types.tspackages/ai-openai/src/model-meta.tspackages/ai-openai/tests/model-meta.test.tspackages/openai-base/src/adapters/chat-completions-text.tspackages/openai-base/src/adapters/responses-text.tspackages/openai-base/tests/chat-completions-text.test.tspackages/openai-base/tests/responses-text.test.tstesting/e2e/README.mdtesting/e2e/fixtures/multimodal-document/basic.jsontesting/e2e/src/components/ChatUI.tsxtesting/e2e/src/lib/feature-support.tstesting/e2e/src/lib/features.tstesting/e2e/src/lib/types.tstesting/e2e/src/routes/$provider/$feature.tsxtesting/e2e/tests/helpers.tstesting/e2e/tests/multimodal-document.spec.ts
…tail 'auto' Addresses CodeRabbit review on TanStack#977. Inline (base64) document payloads are now checked for the '%PDF' header, so non-PDF data sent without a mimeType, or mislabeled as application/pdf, is rejected locally instead of failing as an opaque provider 400. URL sources are unchanged (still validated server-side). Adds regression tests for the missing-mimeType, mislabeled, and non-PDF-data-URL cases. Widens OpenAIDocumentMetadata.detail to 'auto' | 'low' | 'high' to match the API, and casts at the payload boundary because the pinned OpenAI SDK type still lists only 'low' | 'high'. Fixes the doc comments that claimed the default was 'low'. Adds docstrings to the e2e document/image send helpers and the ChatUI props to cover the docstring pre-merge check. Co-authored-by: Cursor <cursoragent@cursor.com>
…il 'auto' Addresses CodeRabbit review on TanStack#977. Inline (base64) document data must now start with the '%PDF' file header, so non-PDF data sent without a mimeType, or mislabeled as application/pdf, is rejected locally instead of failing as an opaque provider 400. URL sources are unchanged (still validated server-side). Adds regression tests for the missing-mimeType, mislabeled, and non-PDF-data-URL cases. Widens OpenAIDocumentMetadata.detail to 'auto' | 'low' | 'high' to match the API, and casts at the payload boundary because the pinned OpenAI SDK type still lists only 'low' | 'high'. Fixes the doc comments that claimed the default was 'low'. Adds docstrings to the e2e document/image send helpers and the ChatUI props to cover the docstring pre-merge check.
7206288 to
0f81a09
Compare
…il 'auto' Addresses CodeRabbit review on TanStack#977. Inline (base64) document data must now start with the '%PDF' file header, so non-PDF data sent without a mimeType, or mislabeled as application/pdf, is rejected locally instead of failing as an opaque provider 400. URL sources are unchanged (still validated server-side). Adds regression tests for the missing-mimeType, mislabeled, and non-PDF-data-URL cases. Widens OpenAIDocumentMetadata.detail to 'auto' | 'low' | 'high' to match the API, and casts at the payload boundary because the pinned OpenAI SDK type still lists only 'low' | 'high'. Fixes the doc comments that claimed the default was 'low' (the actual default, 'auto', is model-dependent). Adds docstrings to the e2e document/image send helpers and the ChatUI props to cover the docstring pre-merge check.
0f81a09 to
e5d210e
Compare
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)
testing/e2e/src/components/ChatUI.tsx (1)
268-284: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReset the file input after handling the document.
Clearing
inputdoes not clear the native file input’s value, so selecting the same PDF again will not triggeronChange. Reset the file input element after invoking the callback, e.g.event.currentTarget.value = ''.🤖 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 `@testing/e2e/src/components/ChatUI.tsx` around lines 268 - 284, Update the document file input’s onChange handler in ChatUI so that after invoking onSendMessageWithDocument, it also clears the native file input via the event target value; preserve the existing text-input reset and callback conditions.
🤖 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 `@testing/e2e/src/components/ChatUI.tsx`:
- Around line 268-284: Update the document file input’s onChange handler in
ChatUI so that after invoking onSendMessageWithDocument, it also clears the
native file input via the event target value; preserve the existing text-input
reset and callback conditions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bfc978c7-da8d-4bb5-9125-459129ae4af2
📒 Files selected for processing (6)
.changeset/openai-pdf-document-input.mdpackages/ai-openai/src/message-types.tspackages/openai-base/src/adapters/responses-text.tspackages/openai-base/tests/responses-text.test.tstesting/e2e/src/components/ChatUI.tsxtesting/e2e/tests/helpers.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/ai-openai/src/message-types.ts
- testing/e2e/tests/helpers.ts
- .changeset/openai-pdf-document-input.md
- packages/openai-base/src/adapters/responses-text.ts
- packages/openai-base/tests/responses-text.test.ts
c8abe7b to
da24c95
Compare
da24c95 to
1c39896
Compare
feat(ai-openai): support PDF
documentcontent parts in the Responses adapter🎯 Changes
openaiText's Responses adapter now accepts PDFdocumentcontent parts. Any OpenAI chat model whosemodel-metaentry declares thedocumentinput modality can take a PDF as message content.data) sources sendinput_filewith afile_datadata URL and afilename(frommetadata.filename, defaulting todocument.pdf).input_filewithfile_url.data:URLs whose media type doesn't match the declaredmimeType— so callers get a clear error instead of an opaque provider400.OpenAIDocumentMetadatagainsfilenameanddetail.Test plan
mimeType, mismatcheddata:URL media type); the Chat Completions document-rejection error;model-metamodality assertions.multimodal-documentfeature — fixture, spec (testing/e2e/tests/multimodal-document.spec.ts), harness page, and atiny.pdfasset (a minimal PDF), wired intofeature-support.tsandfeatures.ts.documentexample indocs/advanced/multimodal-content.md; the modality list points readers atmodel-meta.ts.✅ Checklist
pnpm run test:pr.🚀 Release Impact
Summary by CodeRabbit
filenameanddetail, with sensible defaults likedocument.pdf.