docs/image-generation.md
Rama main · réplica de lectura del repositorio original.
# Image generation
Bots can create images in a chat: ask "make an image of…" and the bot calls
its `generate_image` tool, on any engine. Bot avatars use the same providers.
The image is attached to the bot's reply when its turn ends, like a voice note.
## Setup
Open **Settings → Image generation** (an AI page shown in Advanced mode; a
link from the avatar editor opens it in Simple mode too). Choose:
- **Base provider**: used first for every image.
- **Backup provider** (optional): used only when the base could not start.
- **Model** for each: a list with the recommended models first. For
OpenRouter, the rest of the list is its live image catalog
(`/api/v1/models?output_modalities=image`, fetched without a key and kept
for an hour). When the catalog cannot be loaded, the page says so and shows
only the recommended ones. **Other** opens a field to type any model ID.
Custom has no list, so its model is always typed.
- **Images per reply**: the most images a bot may create in one turn (1–10,
default 4). Images still being made count, so parallel calls cannot pass it.
Images from Codex's own image tool count toward the same limit.
- **A day's images**: bots make at most 50 images a day on one installation,
counted on disk so a restart does not reset it, starting again at local
midnight. There is no setting for it. Avatars made in Settings are not
counted.
- **Only for a person**: `generate_image` makes an image only in a turn a
person's own message started (or work handed on from one). A routine, a
webhook, an outside app or a guest's turn is refused with a line the bot
can pass on, so nothing spends the image key unattended.
- **Keys**: each chosen provider gets a key field on this page. The Grok and
OpenRouter fields save the same key as **API keys**. A key pasted into a
model field is refused.
- **Test** (once a key is saved): checks the key with the provider and makes
no image. For OpenRouter it also checks that the chosen model exists, and
says when the account has no credit, since image models are paid. For the
other providers the model is only checked when the first image is made.
Bots are shown `generate_image` only while the base or the backup has what it
needs, so a bot never spends a turn finding out it cannot make images.
| Provider | Key | Default model | Endpoint |
| --- | --- | --- | --- |
| OpenAI | its own, in this section | `gpt-image-2` | `api.openai.com/v1/images/generations` |
| Grok (xAI) | in this section; the same key as under **API keys** | `grok-imagine-image-2.0` | `api.x.ai/v1/images/generations` |
| Gemini | its own (Google AI Studio), in this section | `gemini-2.5-flash-image` | `generativelanguage.googleapis.com/v1beta/openai/images/generations` |
| OpenRouter | in this section; the same key as under **API keys** | `google/gemini-2.5-flash-image` | `openrouter.ai/api/v1/images` |
| Custom | optional, in this section | none: enter one | `<base URL>/images/generations` |
Each key goes only to its own provider; a missing key is never borrowed from
another one. Signing in to a ChatGPT, Claude, Gemini, Grok or Copilot
subscription does not give API access, so it does not configure any of these.
Bots on Codex can also use Codex's own image tool, which bills the ChatGPT
plan; it does not use these providers, but its images count toward
**Images per reply**.
## When the backup is used
The backup is tried only when the base confirmed that nothing started, the
same rule the text backups follow:
- the base has no key (or no URL and model, for Custom);
- the connection was refused or the host was not found;
- the base answered HTTP 401, 402, 403 or 429.
A timeout or an HTTP 5xx stays on the base, because the image may already have
been made and billed. A refused request (HTTP 400, including a moderation
block) also stays on the base: OpenMausBot does not retry a refused prompt
with another provider.
When the backup makes the image, the bot is told why the base did not, such as
`OpenAI image generation failed (HTTP 401, model gpt-image-2)`. When both fail,
the error names both reasons.
When the person names a provider ("make it with Grok"), the bot passes it and
only that provider is tried; it must be the base or the backup. When the base
and the backup are the same provider, naming it keeps the normal base-then-backup
order.
A generation stops when the bot's tool call goes away (the turn is stopped or
the engine gives up on the call), and nothing is attached.
## Custom gateway compatibility
For a local gateway such as OmniRoute, a base URL might be
`http://127.0.0.1:20128/v1`. OpenMausBot appends `/images/generations`; pasting
that complete endpoint is also accepted. `localhost` and `127.0.0.1` refer to
the machine running the OpenMausBot server, including when you open the app
remotely. Public endpoints require HTTPS. HTTP is supported for local/private
endpoints. URLs must not contain embedded credentials, query parameters, or
fragments.
The gateway must accept a synchronous OpenAI-style Images API request with
`model`, `prompt`, `size`, `n: 1`, and `response_format: "b64_json"`. Its JSON
response must contain `data[0].b64_json` with raw base64-encoded PNG, JPEG, or
WebP bytes. Chat API compatibility alone is insufficient; URL-only responses,
redirects, and asynchronous job responses are not supported.
## Limits
Each decoded image is limited to 10 MiB, the response to 15 MiB, and
generation to two minutes. Provider error bodies are never shown or stored:
an error names only the provider, the HTTP status and the model ID.