Bug Report
OpenRouter supports PDF inputs via the chat-completions messages[].content[] array using type: "file" (with file.file_data as either a public URL or a data:application/pdf;base64,... data URL). However, Rig’s OpenRouter provider currently cannot represent/serialize PDF inputs in this format.
Today, rig-core’s OpenRouter Message::User uses OneOrMany<openai::UserContent> for its content, which does not include a file variant. This prevents sending PDFs as OpenRouter-native file inputs.
As a result, trying to pass a PDF via Rig’s message::UserContent::Document either:
- gets coerced into plain text (base64/string) rather than a
type:"file" part, or
- fails/behaves unexpectedly depending on the call path and message composition.
This blocks use of OpenRouter’s PDF parsing/OCR pipeline (and related features like file annotations).
Reproduction
- Use the OpenRouter provider with any model (PDFs work with any model on OpenRouter).
- Send a user message that includes:
- a normal text prompt, and
- a PDF input (URL or base64 data URL) using Rig’s document/message abstractions (e.g.
message::UserContent::Document with DocumentMediaType::PDF).
What OpenRouter expects
OpenRouter’s docs show PDFs are sent as a file content part:
{
"role": "user",
"content": [
{ "type": "text", "text": "What are the main points in this document?" },
{
"type": "file",
"file": {
"filename": "document.pdf",
"file_data": "https://bitcoin.org/bitcoin.pdf"
}
}
]
}
or for base64:
{
"type": "file",
"file": {
"filename": "document.pdf",
"file_data": "data:application/pdf;base64,JVBERi0xLjcKJc..."
}
}
Expected behavior
Rig’s OpenRouter provider should allow passing a PDF “document” and serialize it into OpenRouter’s type: "file" format, so OpenRouter can parse/OCR it and the model can answer questions about the PDF.
Actual behaviour
Rig’s OpenRouter provider cannot serialize type: "file" content parts at all (since it uses OpenAI chat-completions content types). PDF inputs end up as plain text or are otherwise unsupported, so OpenRouter’s PDF processing is not used.
Environment
- rig-core version: 0.30.0 (latest at time of writing)
- Rust version:
- OS:
- Provider: OpenRouter
Additional context / suspected cause
The OpenRouter provider’s message structs reuse OpenAI chat-completions content types:
Message::User { content: OneOrMany<openai::UserContent>, ... }
Since OpenAI’s UserContent enum doesn’t contain file, the OpenRouter provider can’t represent PDFs as OpenRouter expects.
Separately, the OpenAI conversion layer maps message::UserContent::Document to a text content item (base64/string), which is not equivalent to OpenRouter’s file input mechanism.
Proposed fix
-
Add an OpenRouter-specific UserContent enum (or extend existing OpenRouter message content types) that includes:
text
image_url (optional but OpenRouter supports images)
input_audio (optional)
file (for PDFs and potentially other file types)
-
Implement TryFrom<rig::message::UserContent> mapping such that:
-
(Nice-to-have) Support OpenRouter’s plugins configuration for selecting PDF engines (pdf-text / mistral-ocr / native), but even without this, the default behavior should work.
-
Add tests similar to other provider message conversion tests that assert the serialized JSON matches OpenRouter’s documented schema.
References (docs + code pointers)
OpenRouter docs:
Rig code pointers (docs.rs sources):
- OpenRouter provider uses
openai::UserContent for user message content:
src/rig/providers/openrouter/completion.rs
- OpenAI conversion maps
message::UserContent::Document to UserContent::Text:
src/rig/providers/openai/completion/mod.rs
Bug Report
OpenRouter supports PDF inputs via the chat-completions
messages[].content[]array usingtype: "file"(withfile.file_dataas either a public URL or adata:application/pdf;base64,...data URL). However, Rig’s OpenRouter provider currently cannot represent/serialize PDF inputs in this format.Today,
rig-core’s OpenRouterMessage::UserusesOneOrMany<openai::UserContent>for itscontent, which does not include afilevariant. This prevents sending PDFs as OpenRouter-native file inputs.As a result, trying to pass a PDF via Rig’s
message::UserContent::Documenteither:type:"file"part, orThis blocks use of OpenRouter’s PDF parsing/OCR pipeline (and related features like file annotations).
Reproduction
message::UserContent::DocumentwithDocumentMediaType::PDF).What OpenRouter expects
OpenRouter’s docs show PDFs are sent as a
filecontent part:{ "role": "user", "content": [ { "type": "text", "text": "What are the main points in this document?" }, { "type": "file", "file": { "filename": "document.pdf", "file_data": "https://bitcoin.org/bitcoin.pdf" } } ] }or for base64:
{ "type": "file", "file": { "filename": "document.pdf", "file_data": "data:application/pdf;base64,JVBERi0xLjcKJc..." } }Expected behavior
Rig’s OpenRouter provider should allow passing a PDF “document” and serialize it into OpenRouter’s
type: "file"format, so OpenRouter can parse/OCR it and the model can answer questions about the PDF.Actual behaviour
Rig’s OpenRouter provider cannot serialize
type: "file"content parts at all (since it uses OpenAI chat-completions content types). PDF inputs end up as plain text or are otherwise unsupported, so OpenRouter’s PDF processing is not used.Environment
Additional context / suspected cause
The OpenRouter provider’s message structs reuse OpenAI chat-completions content types:
Message::User { content: OneOrMany<openai::UserContent>, ... }Since OpenAI’s
UserContentenum doesn’t containfile, the OpenRouter provider can’t represent PDFs as OpenRouter expects.Separately, the OpenAI conversion layer maps
message::UserContent::Documentto a text content item (base64/string), which is not equivalent to OpenRouter’s file input mechanism.Proposed fix
Add an OpenRouter-specific
UserContentenum (or extend existing OpenRouter message content types) that includes:textimage_url(optional but OpenRouter supports images)input_audio(optional)file(for PDFs and potentially other file types)Implement
TryFrom<rig::message::UserContent>mapping such that:message::UserContent::Documentwith media type PDF maps totype:"file"with:filename(optional/default)file_data= URL ordata:application/pdf;base64,...document source kinds (URL/base64) map cleanly.
(Nice-to-have) Support OpenRouter’s
pluginsconfiguration for selecting PDF engines (pdf-text / mistral-ocr / native), but even without this, the default behavior should work.Add tests similar to other provider message conversion tests that assert the serialized JSON matches OpenRouter’s documented schema.
References (docs + code pointers)
OpenRouter docs:
Rig code pointers (docs.rs sources):
openai::UserContentfor user message content:src/rig/providers/openrouter/completion.rsmessage::UserContent::DocumenttoUserContent::Text:src/rig/providers/openai/completion/mod.rs