Skip to main content
EverOS turns non-text content — images, PDFs, audio, office documents, HTML, email — into the same structured, searchable memory as plain text. Attach the asset to a message at ingest time; a vision/audio-capable LLM parses it into text, and from there it flows through the identical extraction → markdown → index pipeline as any text turn. The result is fully retrievable with the same /search stack.

How It Works

Each non-text ContentItem is routed through the parser, which calls a separate, vision/audio-capable LLM configured independently from the main extraction [llm] — so parsing can target a multimodal endpoint without changing boundary or extraction behaviour. Visual/audio formats (image / pdf / audio / office) always go through that LLM; a few text-bearing formats (e.g. a plain email with no inline images) can be parsed without it. The parser returns text that takes the place of the asset in the message buffer — nothing downstream knows or cares that the content originated as an image or PDF. The raw bytes are not persisted past extraction — only the parsed text is stored.

Prerequisites

1

Install the multimodal extra

Multimodal parsing lives behind an optional dependency group so the base install stays lean:
This pulls in everalgo-parser[svg] — the [svg] bundle adds cairosvg so SVG works out of the box.
2

Install LibreOffice (office documents only)

Office formats (.doc / .docx / .ppt / .pptx / .xls / .xlsx) are converted to PDF before being fed to the multimodal LLM. LibreOffice must be present on the server host:
Without LibreOffice, office uploads return 503 (CAPABILITY_UNAVAILABLE). Image, PDF, audio, HTML, and email parsing are unaffected.
3

Configure the multimodal LLM

The parser uses its own LLM section, independent from [llm]. The model must accept OpenAI image_url parts. everos init writes these into the generated .env:
The default targets Gemini via OpenRouter so a single key covers both chat extraction and multimodal parsing.

Supported Content Types

A non-text item must carry either uri or base64 — a non-text item with only a text field returns 415.

Sending Multimodal Content

Switch the content field from a plain string to an array of typed ContentItem objects:
Prefer uri for anything large. A multi-MB base64 blob becomes multi-MB of SQLite buffer text for the buffer’s lifetime and slows request parsing. The bytes are never persisted past extraction either way — only the parsed text is.

Local files via file://

A file:// URI is read from the server’s local filesystem. The path must be reachable by the server process and pass these guardrails (violation returns 415):
  • Must be an existing regular file (symlinks resolved)
  • Size ≤ EVEROS_MULTIMODAL__FILE_URI_MAX_BYTES (default 50 MiB)
  • If EVEROS_MULTIMODAL__FILE_URI_ALLOW_DIRS is set, the path must lie within one of the listed roots

Searching Multimodal Memory

Nothing special is required. Parsed text is folded into the same episodes and memory cells as text turns, so every retrieval method works across multimodal-derived memory unchanged:
See Retrieval for full details on keyword, vector, hybrid, and agentic methods.

Configuration Reference

All fields bind from environment variables (EVEROS_MULTIMODAL__<FIELD>) or the [multimodal] TOML section:

Error Handling

Two failure classes behave differently: A malformed-input or unsupported-format problem aborts the whole /add batch with 415; a missing capability such as LibreOffice aborts with 503 (CAPABILITY_UNAVAILABLE). A transient LLM failure degrades only the affected item: the request returns 200 and the remaining messages extract normally.