Skip to main content
In the community edition, each user has their own model providers under Settings → Providers & models. Administrators can also manage each user’s providers. Credentials remain in the control plane.

Administrator control

Under Administration → Users, use Edit providers to manage a user’s endpoints, encrypted headers, models, default model, and connection tests. Turn off a user’s Provider settings switch to hide their provider page and block provider and model changes through the user API. The user can still chat with their configured models, but cannot retrieve stored headers or run connection tests. Administrators retain access through the admin console and API. Disable provider settings for all users applies the restriction to all current non-admin accounts, including disabled accounts. Turning it off restores access for those accounts. Administrators retain provider access. New accounts have provider settings enabled by default; this bulk action does not change that default. The managed edition continues to use one administrator-managed installation catalogue instead of these per-user controls.

Add a provider

A provider is any endpoint implementing the OpenAI API surface.
1

Enter the base URL

Use the URL that has /chat/completions and /models beneath it, usually ending in /v1.
2

Add the API key

The key is encrypted with SETTINGS_ENCRYPTION_KEY before storage. It is write-only: the API returns a hasApiKey flag and never the value itself.
3

Add custom headers if needed

Some gateways require extra headers, such as OpenRouter’s HTTP-Referer and X-Title.
Custom headers are different from API keys. Because they must remain editable in the UI, GET /api/providers decrypts them for the authenticated owner when provider settings are enabled. Administrators can retrieve them through the admin API. Treat header values as secrets.
4

Test the connection

Test connection requests <base URL>/models through the outbound guard. This validates the URL, the key, and network reachability in one step.

Conversation identification

Chat LLM requests automatically include x-session-id: <chat UUID>. This is the persisted conversation ID, not a login session, user ID, message ID, or request ID. It stays the same across turns, resumes, fresh context, tool steps, retries, and model switches, including when collaborators contribute to the same chat. Different conversations have different IDs. The generated header replaces any configured x-session-id header regardless of casing, so a static provider setting cannot group unrelated chats together. Other custom headers and authentication are unchanged. Delegated web research also receives this ID in its model headers (x-awr-llm-headers). It is not added to model discovery/connection tests, MCP requests, ordinary web search/read requests, or bounded inference calls that have no conversation. This is a correlation hint for upstream providers that support it; it does not replace the conversation history sent with each request. No provider-specific body metadata or additional conversation-header aliases are added automatically.

Model history and reasoning

A response can take several model calls, one per tool step. The conversation stores each call separately, so later turns send the model the same sequence of assistant messages and tool results it saw while working. The unchanged prefix lets providers with prompt caching reuse it. Reasoning text that a model returns without provider state, such as reasoning_content, is shown in the transcript but not sent back as context.

Claude through unified-llm-proxy

unified-llm-proxy reports the original content of each Claude response, including signed, empty and redacted thinking, as a claude_replay extension of its Chat Completions API. r5d-chat stores that state with the model call it belongs to and returns it unchanged on that call’s assistant message, both within a tool loop and on later turns. This keeps Claude’s thinking intact across tool calls and its prompt cache warm.
  • Use a provider whose base URL is the proxy’s OpenAI-compatible /v1 endpoint, running a proxy version with claude_replay support.
  • The state is only returned to the provider that produced it. It is never shown in the transcript or sent to browsers, and it is not part of published snapshots or context estimates.
  • Other providers are unaffected. Conversations from before this support have no stored state to return.

Images from tools

The agent sees images through its tools: readfile returns an image file itself, and MCP tools can return images such as screenshots. The Chat Completions API accepts images only in user messages, not in tool results, so r5d-chat sends each tool result as text and the images it contained in a user message directly after that step’s tool results, as image_url content with a data: URL:
Images stay in the conversation like any other tool result, so later turns send them again and the request prefix stays cacheable. Each counts as a fixed vision allowance in context estimates, not as base64 text. A gateway in front of another API must translate these image_url parts into that API’s image input; one that drops them leaves the model with only the text. Turn off Image input for a text-only model. Its readfile then returns OCR text for images, and images from other tools are replaced by a short note.

Add models

A provider holds any number of models. Each needs:
string
required
The exact identifier the provider expects, such as gpt-4o-mini or anthropic/claude-sonnet-4.
string
required
The label shown in the model picker.
positive integer ID
required
Choose one of the catalogue’s configured tiers. Administrators manage shared managed-edition tiers; community users with provider access manage their own. Multiple models can share a tier. This does not change pricing or reasoning settings.

Configure tiers

A catalogue starts with Low (1), Medium (2), High (3), and Maximum (4), but these are defaults, not a fixed scale. Rename, reorder, add, or remove tiers in provider settings. The configured order controls the picker; numeric IDs remain stable when labels or order change. Community administrators can also edit a user’s tiers through Edit providers. Each catalogue has 1–32 tiers. IDs are unique positive integers up to 2147483647; labels are trimmed, nonempty, at most 40 characters, and unique ignoring case. Every model must reference a configured ID, including disabled models. Removing a tier still referenced by any model returns 409: reassign or delete those models first. Disabling them is not enough. Existing assignments survive upgrades. New models, including provisioning- manifest models, require an explicit configured tier. Provisioning accepts modelTiers at the root for managed installations or on each users[] entry for community catalogues; omitting it retains the existing definitions.
integer
required
Total token limit for the model. Used to decide when to trim context.
integer
required
Upper bound on a single response. Setting this above the provider’s real limit causes request errors.
boolean
default:"on"
Whether the model accepts images. On by default; turn it off for a text-only model, which would otherwise reject requests that contain an image. See Images from tools.

Default model rules

Exactly one model per user is the default, enforced by the models_one_default_per_user partial unique index.
  • Make default releases the current holder before setting the new one, because the index rejects the opposite order.
  • Deleting or disabling the default model, or the provider that owns it, automatically promotes the oldest remaining enabled model.
  • A user therefore always has a usable default as long as one enabled model exists.

Which model a conversation uses

A conversation follows the default. Each new message, and each resumed response, runs on whichever model is the default at that moment, not the one that was the default when the conversation started. Changing the default therefore moves every existing conversation on its next message. Picking another model in the composer pins it to that conversation, and later messages keep using it. The pin ends when the default is chosen again, or when the picked model or its provider is disabled or deleted; the conversation then follows the default again. The compact model selector sits beside the send button and shows the current capability level. Click it to open a popover above the composer, with the model name and a slider following your configured tier order. Drag the slider or use the arrow keys. Empty tiers are skipped. Escape or clicking outside closes the popover. Click the model name to choose an exact model; returning to a tier remembers that choice for the current page session. Otherwise it selects that tier’s default model, then the first model alphabetically. In the community edition, click the star to make the selected model your default for new chats and chats following your default. A filled star marks the current default. Every response names the model that wrote it, with the time, beside its copy button; hover the name for the provider’s model ID, which is what an upstream gateway reports.

The outbound request guard

Every outbound call is checked before it is made. By default the guard rejects:
  • Non-HTTPS URLs
  • URLs containing embedded credentials
  • Private, loopback, and link-local addresses
  • Cloud metadata endpoints
  • Redirects to any of the above
No configuration needed. Public HTTPS endpoints pass the guard.

Troubleshooting

The guard rejected the URL. Confirm it is HTTPS and publicly resolvable, or enable ALLOW_PRIVATE_EGRESS for an internal endpoint.
The stored key is wrong or lacks access to the requested model. Keys are write-only, so re-enter it rather than trying to read it back.
The base URL is probably missing or duplicating its version segment. The application appends /chat/completions, so the base URL should end at /v1.
The configured context window exceeds the model’s real limit. Lower it to the provider’s documented value.
If SETTINGS_ENCRYPTION_KEY changed, stored credentials cannot be decrypted. Restore the original key or have users re-enter their credentials.

Backup implications

Provider credentials are encrypted in the database with the installation key. The database and SETTINGS_ENCRYPTION_KEY form a single recovery unit; a database restore without the matching key yields unreadable credentials.

Backup and restore

What to back up and how to validate a restore.

Usage and budget

In the community edition, the sidebar shows Spent (or Used), Budget, and Remaining for each provider that reports usage. Click a card to open Settings → Usage for the monthly report, reporting dates, and optional technical token details. Other providers retain their own reporting periods; the app does not assume every balance is monthly. The conversation context popup only describes the current conversation’s context window. Any supported usage response can include this optional top-level extension:
This is an r5d-chat integration convention, not a standard OpenAI API field. It works with the recognized native gateway, LiteLLM, OpenRouter, and credits responses. The normalized /api/usage result exposes it as dashboardUrl. Without the field, the app still displays the usage report and omits the link. The URL must be absolute HTTP(S) with no embedded username or password. It should identify a normal signed-in dashboard, without API keys or access tokens in the URL. View full usage opens it in a new tab using the user’s browser session; r5d-chat never fetches it or sends provider headers to it. A separate provider login may be required. Providers own the accounting: amounts, currency or unit, account/key scope, reporting boundaries and timezone, balance adjustments, and actual reset times. The chat app owns readable labels, currency and date formatting, and the budget layout. A period’s exclusive end is not automatically a balance reset, and an explicit remaining balance is preserved even if it differs from budget minus spend. Missing values appear as Not reported, never zero or unlimited.