Librechat-Mobile/DISCOVERY.md
Garfie abde86ca4e chore(sync): sync to upstream LibreChat v0.8.5
Targets upstream tag v0.8.5 (commit 9ccc8d9be). Bumps the supported
backend version constant, advances the upstream submodule pin, and
adds wire-protocol parity for new server features.

Wire protocol
- Add ContentType.SUMMARY enum value and flat sibling fields on
  MessageContentPart (content as JsonElement to absorb array/string/
  legacy-text variants per BaseClient.getSummaryText).
- Add Anthropic effort.xhigh dropdown value, ThinkingDisplay (Opus 4.7
  reasoning visibility), and Message.contextMeta pass-through.
- Add allowAccountDeletion to StartupConfig (defaults to true to
  preserve older-server behavior).
- Drop unused instanceProjectId from StartupConfig and from
  ConfigRepositoryImpl.isValidLibreChatConfig.

New endpoints / features
- Favorites: UserFavorite DTO + FavoritesApi + FavoritesRepository,
  Settings -> Favorites sub-screen (list/unpin), pin icons in chat
  model selector. Repository owns the canonical list as a StateFlow
  guarded by Mutex.withLock so chat-side toggles and settings-side
  bulk-unpin can't drift apart and concurrent writes can't lose each
  other.
- Prompt-group usage telemetry (POST /api/prompts/groups/:id/use,
  fire-and-forget on prompt insertion).
- Summarize SSE events (on_summarize_complete -> StreamEvent.ContextSummary)
  and a collapsible "Summarized earlier messages" card rendered from
  the persisted SUMMARY content part. Forward-compat else-arm preserved
  on both LangGraph and legacy SSE mappers.

Backward compatibility
- BackendVersion.isCompatibleOrNewer helper added; documented fail-open
  contract for callers that have already null-checked
  detectedBackendVersion.
- New VERSION_GATES.md catalog at repo root tracks every code path that
  branches on server version. Initial entries:
  - isCollaborative agent toggle (hidden on v0.8.5+; full-ACL UX deferred)
  - xhigh effort dropdown value (filtered out on <v0.8.5 to avoid
    server-side enum rejection)

Defensive hardening
- ChatApi.startChat asserts Content-Type: application/json before
  decoding ChatStartResponse and catches NoTransformationFoundException
  as a backstop, translating both to a friendly ApiException. Observed
  during testing on v0.8.5-rc1 with summarization enabled, where the
  agents chat-start endpoint returned 200 OK with no Content-Type and
  Ktor leaked a NoTransformationFoundException stack trace into the
  chat surface. Belt-and-suspenders against future backend regressions
  or unsupported-server pointing.

Documentation
- DISCOVERY.md updated for the v0.8.5 surface: /api/endpoints now
  requires JWT, /api/config pre-auth/post-auth split, allowAccountDeletion,
  instanceProjectId removal, favorites endpoints (with all three XOR
  variants: agentId | model+endpoint | spec), prompt-usage endpoint,
  /api/admin/** marked out-of-scope. Plus a new MessageContentPart +
  SUMMARY wire-shape section.

iOS
- Swift SharedFrameworkTest.swift updated for the new
  StreamEvent.ContextSummary variant and Message.contextMeta
  constructor argument.

Out of scope (by design)
- /api/admin/** route family - web-only feature.
- Full ACL migration for agent sharing - replaced by version-gating
  the legacy isCollaborative toggle.
- Spec-pinning UI on mobile - UserFavorite.spec round-trips for
  fidelity with web-authored pins, but mobile does not yet surface
  a spec picker.
2026-04-26 23:48:14 -06:00

13 KiB

LibreChat Mobile - Discovery & Context Document

Project Goal

Build a native mobile app (LibreChat-Mobile) with full feature parity to the LibreChat web application. The app must connect to an existing LibreChat backend server (no backend changes). Users specify the server URL during onboarding.

Tech Stack (Mandated)

  • UI: Jetpack Compose + Compose Navigation
  • DI: Koin
  • Network: Ktor Client
  • Serialization: Kotlinx Serialization
  • Min SDK: TBD (recommend 26+)

LibreChat Web Application Overview

Architecture

  • Monorepo: /api (Express/Node backend), /client (React/Vite frontend), /packages (shared libs)
  • MongoDB database, optional Redis, optional Meilisearch
  • JWT-based auth with refresh tokens

Core Features (Full Parity Required)

1. Authentication & Onboarding

  • Server URL entry (Android-only: user specifies their LibreChat server)
  • Local login (email/password)
  • OAuth2 social logins (Google, GitHub, Discord, Facebook, Apple, OpenID, SAML)
  • Registration with email verification
  • Password reset flow
  • Two-factor authentication (TOTP + backup codes)
  • Terms of service acceptance

2. Chat (Primary Experience)

  • Conversation list in sidebar (cursor-paginated, sorted by updatedAt)
  • Create new conversations
  • Send messages, receive streaming AI responses via SSE
  • Message tree with parent/child relationships and branching
  • Sibling message navigation (e.g., "1/3" switcher for regenerated responses)
  • Edit user messages (creates new branch)
  • Regenerate AI responses
  • Continue incomplete responses
  • Stop generation mid-stream
  • Fork conversations from any message
  • Duplicate conversations
  • Markdown rendering with syntax highlighting
  • LaTeX/math rendering
  • Code blocks with copy button and language badge
  • Image display (inline + expandable)
  • File attachments in messages
  • Tool call display (expandable cards showing input/output)
  • Message feedback (thumbs up/down with optional comment)
  • Typing/streaming indicator
  • Time-based greeting on landing ("Good morning", etc.)
  • Custom welcome messages from server config

3. Model/Endpoint Selection

  • Multiple AI providers: OpenAI, Anthropic, Azure, Google, Groq, Mistral, Ollama, custom
  • Model selector dropdown with search
  • Endpoint icons (branded)
  • Model parameters (temperature, top_p, frequency_penalty, etc.)
  • Model specs from server config

4. Agents & Assistants

  • Agent marketplace (grid of cards with avatar, name, description, category)
  • Agent chat with tool calling
  • OpenAI Assistants integration
  • Agent/assistant selection UI

5. File Management

  • Upload files (images, PDFs, documents, code)
  • Drag-and-drop (not applicable on Android, use file picker)
  • File preview in messages
  • File download
  • Image generation display
  • Audio recording for voice input (STT)
  • Text-to-speech playback (TTS)

6. Conversation Management

  • Rename conversations (inline)
  • Archive/unarchive
  • Delete (single + bulk)
  • Share (generate public link)
  • Export (JSON, markdown)
  • Import conversations
  • Tags for organization
  • Bookmarks/favorites
  • Search conversations (full-text via Meilisearch)

7. Presets

  • Save chat configurations as presets
  • Load presets
  • Delete presets

8. Prompts Library

  • Create/edit/delete prompts
  • Share prompts
  • Prompt versioning
  • @mentions for prompts in chat input
  • Prompt variables

9. User Settings

  • Theme (dark/light)
  • Language selection (46+ languages)
  • Font size
  • Speech settings
  • Data export
  • Account management (profile, delete account)
  • Balance/credits display

10. Artifacts

  • Split-pane code preview/editor
  • Tabs: Preview, Code, Info
  • Live editing

API Endpoints (Key Routes)

Authentication

POST /api/auth/login        → { token, user } or { twoFAPending, tempToken }
POST /api/auth/register     → { status, message }
POST /api/auth/logout       → { status }
POST /api/auth/refresh      → { token, user } (refresh token in cookies)
POST /api/auth/requestPasswordReset
POST /api/auth/resetPassword
GET  /api/auth/2fa/enable   → { secret, qrCode }
POST /api/auth/2fa/verify
POST /api/auth/2fa/confirm  → { confirmed, backupCodes }
POST /api/auth/2fa/disable
POST /api/auth/2fa/verify-temp → { token, user }

Configuration

GET /api/config             → startup config (models, features, auth methods, interface config)
GET /api/endpoints          → available AI providers and models  (JWT required as of v0.8.5)
POST /api/user/settings/favorites → update user favorites (agent/model pins, v0.8.5+)
GET  /api/user/settings/favorites → list user favorites (v0.8.5+)
POST /api/prompts/groups/:id/use  → record prompt-group usage for analytics (v0.8.5+)

v0.8.5 notes

  • GET /api/config response payload is now split into a pre-auth and post-auth variant. Pre-auth fields (what validateServerUrl / fetchStartupConfig rely on) are unchanged from v0.8.4; post-auth adds fields driven by the logged-in user (not consumed by mobile).
  • GET /api/config removed instanceProjectId. Mobile previously used it as an OR fallback in ConfigRepositoryImpl.isValidLibreChatConfig; cleanup landed in v0.8.5 sync.
  • GET /api/config added allowAccountDeletion: Boolean. Mobile honors this and hides the Delete Account button when false. Defaults to true for older servers that omit the field.
  • GET /api/endpoints now requires JWT (was public in v0.8.4). Mobile already called it post-auth, so this is non-breaking.
  • Favorites schema: each entry has exactly one of { agentId }, { model, endpoint }, or { spec } — three mutually exclusive variants enforced by the server (FavoritesController.js: "Each favorite must have either agentId, model+endpoint, or spec"; model and endpoint must be supplied together; combining spec with any of agentId/model/endpoint is rejected). Server also enforces 50 entries max / 256-character max per string; mobile short-circuits oversize writes. The spec variant is round-tripped unchanged (mobile does not yet render a spec picker). POST replaces the entire list (upsert-by-overwrite), and the response echoes the stored list.

Out of scope (admin panel)

/api/admin/auth/**   → admin-only SAML + Social OAuth callbacks (v0.8.5, web-only)
/api/admin/config/** → admin YAML config endpoints
/api/admin/grants/**, /api/admin/groups/**, /api/admin/roles/**, /api/admin/users/**

Admin panel is a web-only surface in upstream; mobile intentionally does not implement it.

Conversations

GET    /api/convos                          → { conversations, nextCursor }
GET    /api/convos/:conversationId          → single conversation
POST   /api/convos/update                   → update title
POST   /api/convos/archive                  → archive/unarchive
DELETE /api/convos                           → delete conversation(s)
POST   /api/convos/fork                     → fork from message
POST   /api/convos/duplicate                → duplicate conversation
POST   /api/convos/import                   → import (multipart)
GET    /api/convos/gen_title/:conversationId → generated title

Messages

GET    /api/messages/:conversationId           → messages for conversation
GET    /api/messages/:conversationId/:messageId
POST   /api/messages/:conversationId           → save message
PUT    /api/messages/:conversationId/:messageId → update message
DELETE /api/messages/:conversationId/:messageId
PUT    /api/messages/:conversationId/:messageId/feedback

Chat (Streaming)

POST /api/agents/chat         → { streamId } (start generation)
GET  /api/agents/chat/stream/:streamId?resume=true → SSE stream
POST /api/agents/chat/abort   → abort generation
GET  /api/agents/chat/active  → { activeJobIds }
GET  /api/agents/chat/status/:conversationId → job status

Files

GET    /api/files              → user's files
POST   /api/files              → upload (multipart)
GET    /api/files/download/:userId/:file_id
DELETE /api/files              → delete file(s)
POST   /api/files/speech/stt   → speech-to-text
POST   /api/files/speech/tts   → text-to-speech

Other

GET/POST/DELETE /api/presets
GET/POST/PUT/DELETE /api/prompts
GET/POST/DELETE /api/tags
GET/POST/PATCH/DELETE /api/share
GET /api/balance
GET /api/search
GET /api/user
GET /api/banner

Data Models

User

  • id, name, email, username, avatar, role, provider
  • emailVerified, twoFactorEnabled
  • favorites, termsAccepted

Conversation

  • conversationId (UUID), title, user, endpoint, model
  • agent_id, assistant_id, tags, isArchived
  • Model parameters (temperature, top_p, etc.)

Message

  • messageId (UUID), conversationId, parentMessageId
  • user, sender, text, content (structured parts)
  • isCreatedByUser, model, endpoint
  • files, attachments, feedback
  • error, unfinished, finish_reason, tokenCount

MessageContentPart

Discriminated by type: text, think, text_delta, tool_call, image_file, image_url, video_url, input_audio, agent_update, summary, error.

SUMMARY part wire shape (v0.8.5+) — context-compaction emits a content part with fields at the top level (not nested under a summary key):

{
  "type": "summary",
  "content": [{"type":"text","text":"..."}],  // array OR string (two variants)
  "tokenCount": 42,
  "summarizing": false,
  "summaryVersion": 1,
  "model": "gpt-4o",
  "provider": "openai",
  "createdAt": "2026-04-22T...",
  "boundary": {"messageId": "...", "contentIndex": 0}
}

Variants for the body text (mirrors upstream BaseClient.getSummaryText, last-wins):

  1. content: Array<{type:"text", text}> — new default since v0.8.5.
  2. content: string — intermediate variant; rare but emitted by some code paths.
  3. No content; text: "..." at the top level — legacy fallback from pre-v0.8.5 summarization or test fixtures.

Mobile's MessageContentPart.content is typed JsonElement? to absorb variants 1/2, and falls back to the existing text: String? field for variant 3.

File

  • file_id, filename, filepath, type, bytes, source
  • user, conversationId, messageId

SSE Streaming Protocol

Flow

  1. POST to /api/agents/chat with message payload → returns { streamId }
  2. Connect SSE to GET /api/agents/chat/stream/:streamId
  3. Receive events: message, step, created, attachment, final, sync, error
  4. On disconnect: reconnect with ?resume=true for sync event

Agent-library event names (v0.8.5)

on_message_delta, on_reasoning_delta, on_run_step, on_run_step_delta, on_run_step_completed, on_chat_model_end, on_agent_update, attachment, and — added in v0.8.5 — on_summarize_start, on_summarize_delta, on_summarize_complete.

on_summarize_complete payload nests the finished summary block under a summary key (distinct from the message-persistence SUMMARY content part described in MessageContentPart):

{"id":"...","agentId":"...","summary":{"type":"summary","content":[{"type":"text","text":"..."}],...}}

Mobile only renders the compacted summary once it is persisted to the final message as a SUMMARY content part; the delta/lifecycle events are surfaced as status only.

SSE Event Format

event: message
data: {"type":"content","chunk":"...","status":"streaming"}

event: message
data: {"type":"tool_call","toolName":"...","input":{...}}

event: message
data: {"sync":true,"resumeState":{"runSteps":[...],"aggregatedContent":[...]}}

Reconnection

  • Exponential backoff: 1s, 2s, 4s, 8s... max 30s
  • Max 5 retries
  • Resume preserves state via sync event

Authentication Details

Token Management

  • JWT access token in Authorization: Bearer <token> header
  • Refresh token stored as HTTP-only cookie (for web; Android should store securely)
  • Access token expiry: ~15 minutes
  • Refresh token expiry: ~24 hours
  • Auto-refresh on 401 response

OAuth Flow (Android)

  • Open browser/Custom Chrome Tab for OAuth provider
  • Callback redirect to app via deep link
  • Exchange code for token

UI/UX Reference (from Web App)

Theme

  • Light: White bg (#fff), text #212121, surface hover #e3e3e3
  • Dark: #0d0d0d bg, text #ececf1, surface hover #424242
  • Material 3 equivalents should be used on Android

Key Screens

  1. Server URL Entry (Android-only onboarding)
  2. Login/Register with social login buttons
  3. Chat List (sidebar on web → drawer or dedicated screen on Android)
  4. Chat View (messages + input)
  5. Landing/New Chat (greeting + model icon)
  6. Model Selector (dropdown → bottom sheet on Android)
  7. Settings (tabbed → Material 3 navigation)
  8. Agent Marketplace (grid of cards)
  9. Search (full-text search)
  10. File Viewer/Picker

Navigation Patterns (Android Adaptation)

  • Web sidebar → Navigation drawer or bottom navigation
  • Web modals → Bottom sheets or new screens
  • Web dropdowns → Material 3 menus or bottom sheets
  • Web hover actions → Long-press menus or always-visible icons

Responsive Behavior

  • Single-pane on phones (chat list or chat view, not both)
  • Potential dual-pane on tablets
  • Bottom navigation for primary actions