# Files and file processing

The answering model and the file processor are separate choices. A processor changes what the answering model receives; it never becomes the answering model.

## Attach a file

A user message carries files in `files`. A tool result carries files in `result.documents`. Both locations use the
same public source shape and the same processing policy.

```json
{
  "type": "user",
  "value": "Summarize this report.",
  "files": [
    {
      "type": "url",
      "value": "https://example.com/report.pdf",
      "name": "report.pdf",
      "contentType": "application/pdf"
    }
  ]
}
```

| `type` | `value` | Public behavior |
|---|---|---|
| `url` | An absolute `http` or `https` URL. | Travels as a URL where the selected provider has a native URL part. Momor does not fetch it merely to manufacture inline bytes. |
| `bytes` | Base64-encoded bytes. | Decoded before the per-file and total-inline limits are checked. |
| `handle` | — | Rejected. The current handle does not prove that the caller owns the stored file. |

`name` is required, and `contentType` is required and must be a valid media type. The public discriminator is lower-camel `type`. `kind`,
`Kind`, and `$type` are not public spellings. `hash` is derived internally and is rejected on input and omitted from
responses.

Inline content is limited to 10 MiB per file and 20 MiB across one request by default, counted after base64
decoding. The whole body is limited to 30 MiB, which carries the full inline allowance once it is base64-encoded.

## Native reading and conversion

Every model can receive `text/*` and `application/json`. Beyond that floor, the catalog's
`capabilities.contentTypes` is the model offering's declaration of what it reads natively.

`fileProcessing` applies per attachment:

| Value | What happens |
|---|---|
| `{ "type": "none" }` | Default. No processor runs. The answering model must declare the type or the model is removed from the routing ladder. |
| `{ "type": "auto" }` | A type the answering model reads travels unchanged. Otherwise the internal processor fleet is asked; if nothing accepts it, the original file still travels to the provider when that provider's wire can carry it. |
| `{ "type": "directed", "types": { … } }` | A mapped type must use the named processor. Unmapped types follow `auto`. |

`auto` is Momor-owned work. Its processor fleet may use internal models regardless of which public model
availability flags the caller can route to. The caller selects `auto`, not the internal model that performs it.

## Data retention

With `fileProcessing` at `none`, the default, Momor keeps none of a call's content. A call with `auto` or
`directed` is not zero data retention: the description of an image or video, or the transcript of a recording,
including an image found inside a PDF or DOCX, is cached by Momor for up to a day, keyed by the file's hash, so the
same file is not described again. Leave file processing off for any call that must retain nothing; a call under
[zero data retention](/docs/gateway/routing/#zero-data-retention) that asks for it is refused with `400`.

## Force a processor

```json
"fileProcessing": {
  "type": "directed",
  "types": {
    "application/pdf": "pdf-text",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx-text",
    "image/*": "gemini-3.6-flash"
  }
}
```

Each `types` key is an exact media type or a prefix ending in `*`. An exact match wins; otherwise the longest
matching prefix wins. A mapped type is always processed, even when the answering model could read it itself.

The value is either a named built-in processor or a canonical model name. A model-backed processor is routed under
the same public availability boundary as the parent request and must declare the file's content type. Its answer text
becomes the converted content. It does not inherit the parent request's tools or generation parameters, and its own
file processing is `none`, which prevents recursive conversion. A
[transcription model](/docs/gateway/reference/transcribe/) named for an audio type transcribes the recording, and
the transcript becomes the converted content. An OCR model named for a PDF, a Word document or an image reads the file
page by page, fetching it from the address Momor sends: a stored file's refreshed address, your own address as you sent
it, or inline bytes as a data URI. The text of its pages, scans included, becomes the converted content.

An empty `types` map is rejected when a request actually contains a file. With no attachment there is no processor
selection to validate or execute.

## Named processor catalog

| Processor | Reads | Produces | Important limits |
|---|---|---|---|
| `pdf-text` | `application/pdf` | Text blocks, inferred tables, AcroForm values and descriptions of extracted embedded images. | It extracts PDF text and embedded images; it is not general page-raster OCR for image-only scans. Table detection is layout-based. |
| `docx-text` | `application/vnd.openxmlformats-officedocument.wordprocessingml.document` | Paragraphs with heading context, tables, content controls and descriptions of embedded images. | It reads the Open XML document structure. Unsupported or malformed package content fails processing rather than being silently rewritten. |

`pdf-text` and `docx-text` are deterministic readers. Embedded media can invoke the internal media-description fleet,
so a document containing images can still cause model-backed processing. Model-backed processors keep their canonical
model names rather than receiving a second processor alias.

Processor pricing and separate processing-charge telemetry are not yet a stable public contract. Model-backed work
is charged as the selected processor model's provider charges it: by its tokens, or at the model's `perUnit` price
for each page an OCR model read or each minute of audio a transcription model transcribed; do not infer that a
zero-token deterministic reader has no eventual processing charge.

## Failures

| Outcome | Status behavior |
|---|---|
| Invalid public file shape, `handle`, caller-supplied `hash`, or an empty directed map with an attachment | `400` |
| Named built-in does not support the mapped content type | `422` |
| Named model does not exist in the caller's public routing boundary | `404` |
| Named model exists but cannot accept that file request | `422` |
| Selected processor runs and fails | That processor failure is terminal and keeps its status and message. The processor is not silently replaced. |

Conversion happens once per file hash during a routed call. The converted text is returned in the answer turn's
`content.data` annotations; replaying that turn with the same file lets a later request reuse the conversion instead
of processing and charging for it again.
