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.
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/configresponse payload is now split into a pre-auth and post-auth variant. Pre-auth fields (whatvalidateServerUrl/fetchStartupConfigrely on) are unchanged from v0.8.4; post-auth adds fields driven by the logged-in user (not consumed by mobile).GET /api/configremovedinstanceProjectId. Mobile previously used it as an OR fallback inConfigRepositoryImpl.isValidLibreChatConfig; cleanup landed in v0.8.5 sync.GET /api/configaddedallowAccountDeletion: Boolean. Mobile honors this and hides the Delete Account button whenfalse. Defaults totruefor older servers that omit the field.GET /api/endpointsnow 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";modelandendpointmust be supplied together; combiningspecwith any ofagentId/model/endpointis rejected). Server also enforces 50 entries max / 256-character max per string; mobile short-circuits oversize writes. Thespecvariant is round-tripped unchanged (mobile does not yet render a spec picker).POSTreplaces 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):
content: Array<{type:"text", text}>— new default since v0.8.5.content: string— intermediate variant; rare but emitted by some code paths.- 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
- POST to
/api/agents/chatwith message payload → returns{ streamId } - Connect SSE to
GET /api/agents/chat/stream/:streamId - Receive events: message, step, created, attachment, final, sync, error
- On disconnect: reconnect with
?resume=truefor 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
- Server URL Entry (Android-only onboarding)
- Login/Register with social login buttons
- Chat List (sidebar on web → drawer or dedicated screen on Android)
- Chat View (messages + input)
- Landing/New Chat (greeting + model icon)
- Model Selector (dropdown → bottom sheet on Android)
- Settings (tabbed → Material 3 navigation)
- Agent Marketplace (grid of cards)
- Search (full-text search)
- 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