Skip to content

bug: OpenRouter provider can’t send PDFs (missing file content type support) #1398

@Mnwa

Description

@Mnwa
  • I have looked for existing issues (including closed) about this

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

  1. Use the OpenRouter provider with any model (PDFs work with any model on OpenRouter).
  2. 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

  1. 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)
  2. Implement TryFrom<rig::message::UserContent> mapping such that:

    • message::UserContent::Document with media type PDF maps to type:"file" with:

      • filename (optional/default)
      • file_data = URL or data:application/pdf;base64,...
    • document source kinds (URL/base64) map cleanly.

  3. (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.

  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions