Skip to content

AI chat (user)

HTTP routes and behavior for ai chat (user).

POST /api/ai/chat # SSE-streamed conversation with tool use
GET /api/ai/available # effective availability + personal|shared|none source
GET /api/ai/settings # provider catalog, credential flags, effective source, per-user chat_capabilities
PUT /api/ai/settings # test + atomically save personal provider/model/key override
DELETE /api/ai/settings # clear personal override and return to granted included access
PUT /api/ai/credentials/{provider} # test + set/replace one personal API key (write-only)
DELETE /api/ai/credentials/{provider} # erase one personal API key
GET /api/ai/codex/status # personal linked state, safe account metadata, usage windows
POST /api/ai/codex/device/begin # begin ChatGPT device authorization
GET /api/ai/codex/device/{flowID} # poll this user's pending device flow
DELETE /api/ai/codex/device/{flowID} # cancel this user's pending device flow
DELETE /api/ai/codex # unlink this user's ChatGPT account
GET /api/ai/grok/status # personal xAI link state and safe account metadata
POST /api/ai/grok/device/begin # begin xAI Grok device authorization
GET /api/ai/grok/device/{flowID} # poll this user's pending xAI device flow
DELETE /api/ai/grok/device/{flowID} # cancel this user's pending xAI device flow
DELETE /api/ai/grok # unlink this user's xAI account

All personal settings, credentials, OAuth accounts, and device flows derive ownership from the authenticated caller; no user ID is accepted from the client. Both providers’ device/begin return a verification URL, one-time code, flow ID, expiry, and polling interval; the app opens the explicit ChatGPT or xAI browser sign-in while keeping access and refresh tokens off the device. Codex delegates its flow to the pinned app-server; the xAI flow is served directly against auth.x.ai with xAI’s public Grok CLI client, and its rotating refresh tokens are persisted per use. API keys and completed OAuth authorization are AES-256-GCM encrypted at rest, and responses expose configured booleans rather than secret values. A provider, model, key, or completed OAuth selection is accepted only after the exact candidate completes a small tool-free response turn; a failure leaves the previous key and selection unchanged.

chat_capabilities in the settings response summarizes discovery and request media types separately, plus availability, library browsing, download reads/management, troubleshooting, and supported service configuration. It reads the current device-bound role, library grants, instance inventory, and enabled tools without contacting upstream services. Books and music are advertised only with an accessible Chaptarr or Lidarr instance; TMDB movie/TV discovery can work without a library. Missing or unreadable capability data is null, so clients use a neutral introduction. This summary grants no authority; tools still check access when called.

Resolution is deterministic: a personal selection row is the explicit override; otherwise a user with an included-access grant receives the admin’s shared provider. If the personal key, OAuth link, runtime, or allowance is unavailable, that request fails as personal instead of silently switching accounts and spending shared quota. The source is resolved once per request and never changes during a provider turn. Chat admission is non-blocking and cost-aware: one active turn per user, 16 turns server-wide, and at most four included-provider turns; excess requests are rejected before any provider call.

Model fallback is opt-in and defaults off. AIConfig.model_fallback_enabled is returned for personal and shared profiles; PUT /api/ai/settings accepts the optional boolean and preserves it when omitted for the same provider. A preference-only edit skips probing an unchanged selection so a retired model can be repaired. New model/key selections still validate without fallback. Provider catalog entries expose model_fallback recommendation metadata (model, source, description); Codex’s concrete replacement comes from account-scoped, paginated model/list upgrade/default metadata, never model-list ordering. The capability contains no pinned replacement model. Gemini resolves its family-specific latest alias, xAI API resolves grok-build-latest, and Grok OAuth reads /settings.default_model and confirms it in the same account’s Responses catalog. OpenAI API, Anthropic, and local endpoints omit model_fallback and reject an explicit opt-in. See provider contracts.

A confirmed model-specific unavailable response permits one replacement on the same account/provider/endpoint. Generic 404s, credentials, quota/rate limits, outages, and schema errors cannot trigger it. The chat SSE model_fallback frame contains status, source, scope, provider, selected_model, replacement_model, reason, recommendation_source, differences, and settings_path; it announces attempting before the replacement request, then used or failed with the outcome alongside normal text or an explicit error. No restart is permitted after text or tool callbacks. Autonomous TurnResult.ModelFallback carries the same provenance while the runner preserves completed tool results and records the effective model in its audit steps. Saved model IDs are never rewritten. Save-time and daily probes remain exact-model checks.

Administrator notifications use source=system, media_type=system issues. Their permanent idx_issues_model_fallback_dedupe index covers the system:ai-model-fallback: namespace, including closed issues, so repeated requests and restarts do not page again. Event identity includes the source/owner, usage scope, provider, selected/replacement models and a hash of endpoint/credential identity; raw credentials, URLs, and upstream error details never enter the notification. A notification includes the attempt outcome, known capability differences without invented prices, and a fixed settings_path (/settings/credentials or /settings/ai). Personal provider settings remain editable only by their owner. Issue notification preferences still gate push delivery.

View the maintained source for this page.