Merge pull request #8 from garfiec/chore/rename-to-mobile
Rename project from LibreChat Android to LibreChat Mobile
This commit is contained in:
commit
9be9a57b9b
161 changed files with 406 additions and 403 deletions
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: sync-upstream
|
||||
description: >
|
||||
Sync the LibreChat Android client with a newer official LibreChat server release.
|
||||
Diffs upstream tags, identifies gaps in the Android app, proposes changes with
|
||||
Sync the LibreChat Mobile client with a newer official LibreChat server release.
|
||||
Diffs upstream tags, identifies gaps in the mobile app, proposes changes with
|
||||
user approval, then implements them. Use when a new LibreChat version is released.
|
||||
allowed-tools: Bash, Read, Glob, Grep, Write, Edit, Agent, TeamCreate, SendMessage, TaskCreate, TaskUpdate, TaskGet, TaskList
|
||||
argument-hint: "[target-tag] (optional, defaults to latest stable)"
|
||||
|
|
@ -10,7 +10,7 @@ argument-hint: "[target-tag] (optional, defaults to latest stable)"
|
|||
|
||||
# Sync Upstream
|
||||
|
||||
Synchronize the LibreChat Android app with a newer version of the official LibreChat server.
|
||||
Synchronize the LibreChat Mobile app with a newer version of the official LibreChat server.
|
||||
This is a multi-phase, team-based workflow.
|
||||
|
||||
You are the **team lead**. You orchestrate at a high level. You NEVER read code, write code,
|
||||
|
|
@ -22,18 +22,20 @@ Create an Agent Team with 4 teammates at the start:
|
|||
|
||||
| Teammate | Role | Prompt Summary |
|
||||
|----------|------|----------------|
|
||||
| **investigator** | Reads upstream diffs, analyzes API/type/UI changes, cross-references with Android codebase | "You are the investigator for a LibreChat Android upstream sync. Your job is to analyze diffs between upstream tags and identify gaps in the Android client. You have read-only responsibilities — never write code." |
|
||||
| **android-expert** | Technical advisor on Android architecture and best practices. Cross-checks all guidance with online research before advising. | "You are the Android tech lead for a LibreChat Android upstream sync. You provide guidance on Android best practices, Jetpack Compose patterns, Kotlin idioms, and architectural decisions. CRITICAL: You MUST cross-check your knowledge by researching online (WebSearch/WebFetch) before giving advice. Never rely solely on training data — always verify current best practices, especially for Compose, Hilt, Ktor, and Material 3. Return researched guidance to teammates who ask." |
|
||||
| **implementer** | Writes code changes to Android app following existing patterns and conventions | "You are the implementer for a LibreChat Android upstream sync. Your job is to write code changes following existing architecture patterns. Always read the module's CLAUDE.md before touching it. Follow safeApiCall, Hilt DI, UDF, Ktor, @Serializable patterns. Before making significant architectural decisions, consult the android-expert teammate." |
|
||||
| **verifier** | Checks implementation correctness, runs builds, validates changes match proposal | "You are the verifier for a LibreChat Android upstream sync. Your job is to independently validate that implementation matches the approved proposal. Run builds, review changes, and flag issues. Message the implementer directly if fixes are needed." |
|
||||
| **investigator** | Reads upstream diffs, analyzes API/type/UI changes, cross-references with mobile codebase | "You are the investigator for a LibreChat Mobile upstream sync. Your job is to analyze diffs between upstream tags and identify gaps in the mobile client. You have read-only responsibilities — never write code." |
|
||||
| **android-expert** | Technical advisor on Android architecture and best practices. Cross-checks all guidance with online research before advising. | "You are the Android tech lead for a LibreChat Mobile upstream sync. You provide guidance on Android best practices, Jetpack Compose patterns, Kotlin idioms, and architectural decisions. CRITICAL: You MUST cross-check your knowledge by researching online (WebSearch/WebFetch) before giving advice. Never rely solely on training data — always verify current best practices, especially for Compose, Ktor, and Material 3. Return researched guidance to teammates who ask." |
|
||||
| **ios-kmp-expert** | Technical advisor on iOS and Kotlin Multiplatform architecture. Ensures KMP shared code and iOS-specific implementations follow platform conventions. | "You are the iOS/KMP tech lead for a LibreChat Mobile upstream sync. You provide guidance on Compose Multiplatform patterns, KMP expect/actual declarations, iOS platform APIs (UIKit, Foundation, Keychain), SKIE interop, and ensuring shared code compiles correctly for both targets. CRITICAL: You MUST cross-check your knowledge by researching online (WebSearch/WebFetch) before giving advice. Never rely solely on training data — always verify current best practices for CMP, KMP, and iOS platform conventions. Return researched guidance to teammates who ask." |
|
||||
| **implementer** | Writes code changes to mobile app following existing patterns and conventions | "You are the implementer for a LibreChat Mobile upstream sync. Your job is to write code changes following existing architecture patterns. Always read the module's CLAUDE.md before touching it. Follow safeApiCall, Koin DI, UDF, Ktor, @Serializable patterns. Before making significant architectural decisions, consult the android-expert or ios-kmp-expert teammate." |
|
||||
| **verifier** | Checks implementation correctness, runs builds, validates changes match proposal | "You are the verifier for a LibreChat Mobile upstream sync. Your job is to independently validate that implementation matches the approved proposal. Run builds, review changes, and flag issues. Message the implementer directly if fixes are needed." |
|
||||
|
||||
**Teammate interaction pattern:**
|
||||
- **investigator** works independently on Phase A and B (diff + gap analysis)
|
||||
- **android-expert** is consulted by the implementer before architectural decisions and by the
|
||||
lead when the proposal involves patterns that may have better modern alternatives. The
|
||||
android-expert MUST search online to verify recommendations — do not accept advice that
|
||||
- **android-expert** is consulted for Android-specific architecture, Compose, and Material 3 decisions.
|
||||
The android-expert MUST search online to verify recommendations — do not accept advice that
|
||||
hasn't been cross-checked against current documentation.
|
||||
- **implementer** does all code changes, consulting android-expert for non-trivial patterns
|
||||
- **ios-kmp-expert** is consulted for KMP shared code, expect/actual patterns, iOS platform APIs,
|
||||
and Compose Multiplatform concerns. Same online-verification requirement as android-expert.
|
||||
- **implementer** does all code changes, consulting android-expert or ios-kmp-expert for non-trivial patterns
|
||||
- **verifier** validates after implementer finishes, messages implementer for fixes
|
||||
|
||||
**Important:** Teammates retain context across messages. Reuse them for follow-ups — do NOT
|
||||
|
|
@ -45,7 +47,7 @@ Run these checks yourself (lightweight, no codebase reading):
|
|||
|
||||
### 1. Submodule check
|
||||
```bash
|
||||
cd LibreChat-Android && git submodule status
|
||||
cd Librechat-Mobile && git submodule status
|
||||
```
|
||||
If `upstream/` is missing:
|
||||
```bash
|
||||
|
|
@ -61,7 +63,7 @@ If missing, create from current state:
|
|||
```bash
|
||||
VERSION=$(grep 'SUPPORTED_BACKEND_VERSION' core/common/src/main/kotlin/com/garfiec/librechat/core/common/BackendVersion.kt | grep -o '"[^"]*"' | tr -d '"')
|
||||
COMMIT=$(cd upstream && git rev-parse HEAD)
|
||||
echo "# Upstream LibreChat version this Android build tracks." > UPSTREAM_VERSION
|
||||
echo "# Upstream LibreChat version this mobile build tracks." > UPSTREAM_VERSION
|
||||
echo "# Updated by the sync-upstream skill. Do not edit manually." >> UPSTREAM_VERSION
|
||||
echo "tag=v${VERSION}" >> UPSTREAM_VERSION
|
||||
echo "commit=${COMMIT}" >> UPSTREAM_VERSION
|
||||
|
|
@ -126,7 +128,7 @@ Create a task for the investigator with this prompt:
|
|||
> - **API changes**: New/modified/removed routes, controller logic
|
||||
> - **Type/schema changes**: New/modified data types, request/response shapes
|
||||
> - **UI changes**: New components, modified user flows
|
||||
> - **Bug fixes**: Fixes that may need Android equivalents
|
||||
> - **Bug fixes**: Fixes that may need mobile equivalents
|
||||
> - **Infrastructure**: Build, config, deps (usually not relevant)
|
||||
> 6. Report back a structured summary table.
|
||||
|
||||
|
|
@ -149,14 +151,14 @@ Once investigator reports back:
|
|||
|
||||
### B1. Send follow-up to investigator
|
||||
|
||||
> Now cross-reference the upstream changes you found with the Android codebase.
|
||||
> Now cross-reference the upstream changes you found with the mobile codebase.
|
||||
>
|
||||
> 1. Read these mapping files from `${CLAUDE_SKILL_DIR}/reference/`:
|
||||
> - `api-mapping.md` — official routes to Android *Api.kt files
|
||||
> - `api-mapping.md` — official routes to mobile *Api.kt files
|
||||
> - `model-mapping.md` — official TS types to Kotlin data classes
|
||||
> - `ui-mapping.md` — web components to Android feature modules
|
||||
> - `ui-mapping.md` — web components to mobile feature modules
|
||||
> 2. For each API change from Phase A:
|
||||
> - Grep the Android codebase (`core/network/src/`) for the corresponding endpoint
|
||||
> - Grep the mobile codebase (`core/network/src/`) for the corresponding endpoint
|
||||
> - Note if it exists, needs updating, or is missing
|
||||
> 3. For each type/schema change:
|
||||
> - Check `core/model/src/` for matching Kotlin data class
|
||||
|
|
@ -168,11 +170,11 @@ Once investigator reports back:
|
|||
> - **Breaking** (must fix): Changed request/response shapes, removed/renamed endpoints, auth changes
|
||||
> - **Additive** (new feature): New endpoints, new UI features, new optional fields
|
||||
> - **Cosmetic** (polish): UI improvements, a11y, i18n
|
||||
> 6. Report the categorized gap list with specific file paths for both upstream and Android.
|
||||
> 6. Report the categorized gap list with specific file paths for both upstream and mobile.
|
||||
|
||||
### B2. Receive gap report
|
||||
|
||||
The investigator now has full context of both the upstream diff AND the Android gaps.
|
||||
The investigator now has full context of both the upstream diff AND the mobile gaps.
|
||||
Keep the investigator alive for follow-up questions during Phase C.
|
||||
|
||||
**Done when:** You have the categorized gap list from the investigator.
|
||||
|
|
@ -191,42 +193,43 @@ Take the investigator's gap report and present it as a structured proposal:
|
|||
### Breaking Changes ({count}) — must fix before updating version
|
||||
For each:
|
||||
- What changed upstream (with file reference)
|
||||
- What Android file(s) need updating
|
||||
- What Mobile file(s) need updating
|
||||
- Proposed change
|
||||
|
||||
### New Features ({count}) — recommended
|
||||
For each:
|
||||
- What was added upstream
|
||||
- Proposed Android implementation approach
|
||||
- Proposed mobile implementation approach
|
||||
- Which module(s) would be affected
|
||||
|
||||
### UI Changes Needing User Input ({count})
|
||||
For each:
|
||||
- What the web app does (with file reference)
|
||||
- Why it doesn't translate directly to Android/Compose
|
||||
- Why it doesn't translate directly to mobile/Compose
|
||||
- 2-3 concrete options for the user to choose from
|
||||
|
||||
### Deferred Items ({count}) — can wait for a future sync
|
||||
Items that are low priority or require significant new infrastructure.
|
||||
```
|
||||
|
||||
### Consult android-expert on non-trivial items
|
||||
### Consult experts on non-trivial items
|
||||
|
||||
Before presenting to the user, for any proposed change that involves:
|
||||
- New architectural patterns (e.g., adding a new module, new DI scope)
|
||||
- UI patterns that don't have an existing equivalent in the codebase
|
||||
- Performance-sensitive changes (e.g., new list rendering, image loading)
|
||||
- Navigation changes
|
||||
- KMP shared code or expect/actual patterns
|
||||
|
||||
Send these items to the **android-expert** teammate:
|
||||
Send Android-specific items to **android-expert** and KMP/iOS items to **ios-kmp-expert**:
|
||||
|
||||
> Review these proposed Android changes for best practices. For each item,
|
||||
> Review these proposed mobile changes for best practices. For each item,
|
||||
> research online to verify the recommended approach is current (especially
|
||||
> for Compose, Material 3, Hilt, and Ktor). Flag any items where modern
|
||||
> for Compose, Material 3, Koin, and Ktor). Flag any items where modern
|
||||
> best practices differ from what we're proposing.
|
||||
> {list of non-trivial items}
|
||||
|
||||
Incorporate the android-expert's feedback into the proposal before showing the user.
|
||||
Incorporate the experts' feedback into the proposal before showing the user.
|
||||
|
||||
### Approval gate
|
||||
|
||||
|
|
@ -268,8 +271,8 @@ Create a task for the implementer with the approved change list:
|
|||
> - Ktor client patterns in `core/network/`
|
||||
>
|
||||
> **Before making non-trivial architectural decisions** (new patterns, new modules,
|
||||
> complex UI components), message the **android-expert** teammate for guidance.
|
||||
> The android-expert will research current best practices online and advise.
|
||||
> complex UI components), message the **android-expert** or **ios-kmp-expert** teammate for guidance.
|
||||
> They will research current best practices online and advise.
|
||||
>
|
||||
> **Approved changes:**
|
||||
> {paste the approved change list here}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Android Architecture Reference
|
||||
# LibreChat Mobile Architecture Reference
|
||||
|
||||
Condensed architecture guide for the LibreChat Android app. Read module-specific `CLAUDE.md` files for full details.
|
||||
Condensed architecture guide for the LibreChat Mobile app. Read module-specific `CLAUDE.md` files for full details.
|
||||
|
||||
## Module Dependency Graph
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ Two-phase protocol:
|
|||
- Room entity: `{Domain}Entity.kt`
|
||||
- Room DAO: `{Domain}Dao.kt`
|
||||
- DI module: `{Domain}Module.kt`
|
||||
- Convention plugins: `librechat.android.{type}` (e.g., `librechat.android.feature`)
|
||||
- Convention plugins: `librechat.mobile.{type}` (e.g., `librechat.mobile.feature`)
|
||||
|
||||
## Build System
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# API Route Mapping: Official → Android
|
||||
# API Route Mapping: Official → Mobile
|
||||
|
||||
Maps official LibreChat API route files to their Android `*Api.kt` counterparts.
|
||||
Maps official LibreChat API route files to their mobile `*Api.kt` counterparts.
|
||||
|
||||
## Implemented
|
||||
|
||||
| Official Route | Android API File | Notes |
|
||||
| Official Route | Mobile API File | Notes |
|
||||
|---------------|-----------------|-------|
|
||||
| `routes/auth.js` | `AuthApi.kt` | Login, register, refresh, logout, 2FA |
|
||||
| `routes/oauth.js` | `AuthApi.kt` | OAuth flows (shared file) |
|
||||
|
|
@ -28,15 +28,15 @@ Maps official LibreChat API route files to their Android `*Api.kt` counterparts.
|
|||
| N/A | `SpeechApi.kt` | Text-to-speech |
|
||||
| N/A | `ApiKeysApi.kt` | API key management |
|
||||
|
||||
## Gaps (no Android counterpart yet)
|
||||
## Gaps (no mobile counterpart yet)
|
||||
|
||||
| Official Route | What It Does | Priority |
|
||||
|---------------|-------------|----------|
|
||||
| `routes/categories.js` | Agent categories | Low — categories embedded in agent responses |
|
||||
| `routes/endpoints.js` | List available endpoints | Medium — Android uses config response instead |
|
||||
| `routes/models.js` | List available models per endpoint | Medium — Android uses config response instead |
|
||||
| `routes/endpoints.js` | List available endpoints | Medium — Mobile uses config response instead |
|
||||
| `routes/models.js` | List available models per endpoint | Medium — Mobile uses config response instead |
|
||||
| `routes/roles.js` | Role-based access control (admin) | Low — admin feature |
|
||||
| `routes/settings.js` | User settings CRUD | Medium — Android uses local DataStore |
|
||||
| `routes/settings.js` | User settings CRUD | Medium — Mobile uses local DataStore |
|
||||
| `routes/actions.js` | Custom actions/plugins | Low — plugin system |
|
||||
| `routes/assistants/` (dir) | OpenAI Assistants API | Low — agents supersede assistants |
|
||||
| `routes/accessPermissions.js` | File access permissions | Low — admin feature |
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# UI Mapping: Official React Components → Android Feature Modules
|
||||
# UI Mapping: Official React Components → Mobile Feature Modules
|
||||
|
||||
Maps web client component directories to Android Compose feature modules.
|
||||
Maps web client component directories to mobile Compose feature modules.
|
||||
|
||||
## Implemented
|
||||
|
||||
| Web Component Dir | Android Module | Coverage |
|
||||
| Web Component Dir | Mobile Module | Coverage |
|
||||
|-------------------|---------------|----------|
|
||||
| `components/Chat/` | `feature/chat/` | Core chat UI, message list, input |
|
||||
| `components/Messages/` | `feature/chat/` | Message rendering, branching, siblings |
|
||||
|
|
@ -17,11 +17,11 @@ Maps web client component directories to Android Compose feature modules.
|
|||
| `components/Banners/` | `app/` | System banner display |
|
||||
| `components/Endpoints/` | `feature/chat/` | Model/endpoint selector bottom sheet |
|
||||
|
||||
## Gaps (no Android counterpart)
|
||||
## Gaps (no mobile counterpart)
|
||||
|
||||
| Web Component Dir | What It Does | Priority | Notes |
|
||||
|-------------------|-------------|----------|-------|
|
||||
| `components/Prompts/` | Prompts library with CRUD, categories, sharing | Medium | Android has PromptsApi but no dedicated UI |
|
||||
| `components/Prompts/` | Prompts library with CRUD, categories, sharing | Medium | Mobile has PromptsApi but no dedicated UI |
|
||||
| `components/Artifacts/` | Code/document artifact viewer and editor | Medium | New feature in recent versions |
|
||||
| `components/MCP/` | MCP server configuration UI | Low | Admin-oriented feature |
|
||||
| `components/MCPUIResource/` | MCP UI resource rendering | Low | Depends on MCP support |
|
||||
|
|
@ -33,13 +33,13 @@ Maps web client component directories to Android Compose feature modules.
|
|||
| `components/Audio/` | Voice input/output, TTS | Medium | SpeechApi exists, no UI |
|
||||
| `components/Plugins/` | Legacy plugin system | N/A | Superseded by agents |
|
||||
| `components/Tools/` | Tool configuration and management | Low | Part of agent setup |
|
||||
| `components/OAuth/` | OAuth provider buttons | Low | Android uses Chrome Custom Tabs |
|
||||
| `components/OAuth/` | OAuth provider buttons | Low | Mobile uses Chrome Custom Tabs |
|
||||
| `components/Web/` | Web search integration | Low | Agent tool feature |
|
||||
| `components/System/` | System-level UI (error boundaries, etc.) | Low | Android has own error handling |
|
||||
| `components/System/` | System-level UI (error boundaries, etc.) | Low | Mobile has own error handling |
|
||||
|
||||
## Key Web Patterns → Android Equivalents
|
||||
## Key Web Patterns → Mobile Equivalents
|
||||
|
||||
| Web Pattern | Android Equivalent |
|
||||
| Web Pattern | Mobile Equivalent |
|
||||
|------------|-------------------|
|
||||
| Recoil atoms (`store/`) | ViewModel state (StateFlow) |
|
||||
| React Query hooks (`hooks/`) | Repository + ViewModel |
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
# Upstream Paths to Watch
|
||||
|
||||
These are the directories in the `upstream/` submodule that matter for Android parity.
|
||||
These are the directories in the `upstream/` submodule that matter for mobile parity.
|
||||
Use these paths when generating focused diffs between tags.
|
||||
|
||||
| Path | What It Contains | Why It Matters |
|
||||
|------|-----------------|----------------|
|
||||
| `api/server/routes/` | Express route definitions (REST endpoints) | Defines the API contract the Android app calls |
|
||||
| `api/server/routes/` | Express route definitions (REST endpoints) | Defines the API contract the mobile app calls |
|
||||
| `api/server/controllers/` | Request handlers and business logic | Shows request/response shapes and validation |
|
||||
| `packages/data-provider/src/` | Shared types, schemas, API client, config | Canonical type definitions; Android models must match |
|
||||
| `packages/data-provider/src/` | Shared types, schemas, API client, config | Canonical type definitions; Mobile models must match |
|
||||
| `packages/data-provider/src/types/` | TypeScript type subdirectory (queries, mutations, agents, etc.) | React Query hook types that define API shapes |
|
||||
| `packages/data-schemas/src/` | Mongoose schemas and DB models | Database schema changes that affect API responses |
|
||||
| `client/src/components/` | React UI components by feature area | Reference for Android UI feature parity |
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# LibreChat Android
|
||||
# LibreChat Mobile
|
||||
|
||||
Native Android client for LibreChat. Connects to existing LibreChat backend servers (no backend changes). Users specify server URL during onboarding.
|
||||
Native mobile client for LibreChat (Android & iOS). Connects to existing LibreChat backend servers (no backend changes). Users specify server URL during onboarding.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ Each module has its own `CLAUDE.md` with specific guidance.
|
|||
## Adding a New Feature Module
|
||||
|
||||
1. Create the module directory under `feature/`
|
||||
2. Apply the `librechat.android.feature` convention plugin in `build.gradle.kts` — this auto-applies Koin + Compose deps
|
||||
2. Apply the `librechat.mobile.feature` convention plugin in `build.gradle.kts` — this auto-applies Koin + Compose deps
|
||||
3. Create `di/<Feature>Module.kt` with a Koin `module { }` containing `viewModelOf(::YourViewModel)` definitions
|
||||
4. Register the module in `LibreChatApplication.kt`'s `startKoin { modules(...) }` list
|
||||
5. Use `koinViewModel()` in screen composables to inject ViewModels
|
||||
|
|
@ -58,6 +58,6 @@ Each module has its own `CLAUDE.md` with specific guidance.
|
|||
## Upstream Sync
|
||||
|
||||
- **`upstream/`** — Git submodule of the [official LibreChat repo](https://github.com/danny-avila/LibreChat). Read-only reference for API and web app parity. Do not modify.
|
||||
- **`UPSTREAM_VERSION`** — Tracks which official tag/commit this Android build is based on. Updated by the `/sync-upstream` skill.
|
||||
- **`UPSTREAM_VERSION`** — Tracks which official tag/commit this mobile build is based on. Updated by the `/sync-upstream` skill.
|
||||
- **`BackendVersion.kt`** (`core/common/`) — `SUPPORTED_BACKEND_VERSION` constant must match the tag in `UPSTREAM_VERSION` (without `v` prefix).
|
||||
- **`/sync-upstream`** — Claude Code skill to diff upstream releases, identify gaps, propose changes, and implement them with user approval. Uses Agent Teams (investigator, android-expert, implementer, verifier).
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
```bash
|
||||
# Clone with submodules (upstream LibreChat server reference)
|
||||
git clone --recursive https://github.com/anthropics/LibreChat-Android.git
|
||||
cd LibreChat-Android
|
||||
git clone --recursive https://github.com/garfiec/Librechat-Mobile.git
|
||||
cd Librechat-Mobile
|
||||
```
|
||||
|
||||
### Android
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# LibreChat Android - Discovery & Context Document
|
||||
# LibreChat Mobile - Discovery & Context Document
|
||||
|
||||
## Project Goal
|
||||
Build a native Android app (LibreChat-Android) 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.
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# LibreChat Android
|
||||
# LibreChat Mobile
|
||||
|
||||
[](https://github.com/danny-avila/LibreChat/releases/tag/v0.8.4)
|
||||
|
||||
A third-party native Android client for [LibreChat](https://www.librechat.ai/). Not affiliated with the official LibreChat project — this is an independent app that connects to any self-hosted LibreChat server, no backend modifications required.
|
||||
A third-party native mobile client for [LibreChat](https://www.librechat.ai/) (Android & iOS). Not affiliated with the official LibreChat project — this is an independent app that connects to any self-hosted LibreChat server, no backend modifications required.
|
||||
|
||||
## Features
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ Add the following to your LibreChat server's `.env` file:
|
|||
NON_BROWSER_VIOLATION_SCORE=0
|
||||
```
|
||||
|
||||
Without this setting, the server's violation system may accumulate ban points against the Android client if the User-Agent check fails, eventually locking the account out.
|
||||
Without this setting, the server's violation system may accumulate ban points against the mobile client if the User-Agent check fails, eventually locking the account out.
|
||||
|
||||
### Notes
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Upstream LibreChat version this Android build tracks.
|
||||
# Upstream LibreChat version this mobile build tracks.
|
||||
# Updated by the sync-upstream skill. Do not edit manually.
|
||||
tag=v0.8.4
|
||||
commit=0736ff26686e911c9785a237c63a799db1813f0b
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ Conversations are integrated into the drawer body. Agents, Files, and Settings a
|
|||
## Dependencies
|
||||
|
||||
This module depends on all `:core:*` and all `:feature:*` modules.
|
||||
It applies convention plugins: `librechat.android.application`, `librechat.android.compose`, `librechat.android.koin`.
|
||||
It applies convention plugins: `librechat.mobile.application`, `librechat.mobile.compose`, `librechat.mobile.koin`.
|
||||
|
||||
### Server-Synced Favorites
|
||||
- `NavHostViewModel` exposes `favorites: StateFlow<Set<String>>` and `toggleFavorite()`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
plugins {
|
||||
id("librechat.android.application")
|
||||
id("librechat.android.compose")
|
||||
id("librechat.android.koin")
|
||||
id("librechat.mobile.application")
|
||||
id("librechat.mobile.compose")
|
||||
id("librechat.mobile.koin")
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
|||
2
app/proguard-rules.pro
vendored
2
app/proguard-rules.pro
vendored
|
|
@ -1,4 +1,4 @@
|
|||
# LibreChat Android ProGuard Rules
|
||||
# LibreChat Mobile ProGuard Rules
|
||||
|
||||
# Keep Kotlin serialization
|
||||
-keepattributes *Annotation*, InnerClasses
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ Convention plugins that apply consistent Gradle configuration across all modules
|
|||
|
||||
| Plugin ID | Class | What it does |
|
||||
|-----------|-------|-------------|
|
||||
| `librechat.android.application` | `AndroidApplicationConventionPlugin` | AGP application plugin, compileSdk 35, minSdk 26, JDK 17 |
|
||||
| `librechat.android.library` | `AndroidLibraryConventionPlugin` | AGP library plugin, same SDK/JDK config |
|
||||
| `librechat.android.compose` | `AndroidComposeConventionPlugin` | Compose compiler, Compose BOM, Material 3 |
|
||||
| `librechat.android.koin` | `AndroidKoinConventionPlugin` | Koin core + Android dependencies |
|
||||
| `librechat.android.feature` | `AndroidFeatureConventionPlugin` | Auto-applies: library + compose + koin + serialization |
|
||||
| `librechat.android.room` | `AndroidRoomConventionPlugin` | Room + KSP, schema export config |
|
||||
| `librechat.mobile.application` | `AndroidApplicationConventionPlugin` | AGP application plugin, compileSdk 35, minSdk 26, JDK 17 |
|
||||
| `librechat.mobile.library` | `AndroidLibraryConventionPlugin` | AGP library plugin, same SDK/JDK config |
|
||||
| `librechat.mobile.compose` | `AndroidComposeConventionPlugin` | Compose compiler, Compose BOM, Material 3 |
|
||||
| `librechat.mobile.koin` | `AndroidKoinConventionPlugin` | Koin core + Android dependencies |
|
||||
| `librechat.mobile.feature` | `AndroidFeatureConventionPlugin` | Auto-applies: library + compose + koin + serialization |
|
||||
| `librechat.mobile.room` | `AndroidRoomConventionPlugin` | Room + KSP, schema export config |
|
||||
| `librechat.kotlin.serialization` | `KotlinSerializationConventionPlugin` | Kotlinx Serialization plugin + JSON dependency |
|
||||
|
||||
## Critical: apply() Signature
|
||||
|
|
@ -32,6 +32,6 @@ build.gradle.kts files. Use `libs.` accessors (e.g., `libs.koin.android`, `libs.
|
|||
|
||||
## Feature Module Convention
|
||||
|
||||
Feature modules use `id("librechat.android.feature")` which auto-applies library, compose,
|
||||
Feature modules use `id("librechat.mobile.feature")` which auto-applies library, compose,
|
||||
koin, and serialization. They only need to add feature-specific dependencies.
|
||||
Feature modules depend on `:core:*` only, never on other feature modules.
|
||||
|
|
|
|||
|
|
@ -16,27 +16,27 @@ dependencies {
|
|||
gradlePlugin {
|
||||
plugins {
|
||||
register("androidApplication") {
|
||||
id = "librechat.android.application"
|
||||
id = "librechat.mobile.application"
|
||||
implementationClass = "AndroidApplicationConventionPlugin"
|
||||
}
|
||||
register("androidLibrary") {
|
||||
id = "librechat.android.library"
|
||||
id = "librechat.mobile.library"
|
||||
implementationClass = "AndroidLibraryConventionPlugin"
|
||||
}
|
||||
register("androidCompose") {
|
||||
id = "librechat.android.compose"
|
||||
id = "librechat.mobile.compose"
|
||||
implementationClass = "AndroidComposeConventionPlugin"
|
||||
}
|
||||
register("androidFeature") {
|
||||
id = "librechat.android.feature"
|
||||
id = "librechat.mobile.feature"
|
||||
implementationClass = "AndroidFeatureConventionPlugin"
|
||||
}
|
||||
register("androidRoom") {
|
||||
id = "librechat.android.room"
|
||||
id = "librechat.mobile.room"
|
||||
implementationClass = "AndroidRoomConventionPlugin"
|
||||
}
|
||||
register("androidKoin") {
|
||||
id = "librechat.android.koin"
|
||||
id = "librechat.mobile.koin"
|
||||
implementationClass = "AndroidKoinConventionPlugin"
|
||||
}
|
||||
register("kotlinSerialization") {
|
||||
|
|
@ -44,7 +44,7 @@ gradlePlugin {
|
|||
implementationClass = "KotlinSerializationConventionPlugin"
|
||||
}
|
||||
register("androidDetekt") {
|
||||
id = "librechat.android.detekt"
|
||||
id = "librechat.mobile.detekt"
|
||||
implementationClass = "AndroidDetektConventionPlugin"
|
||||
}
|
||||
register("kmpLibrary") {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class AndroidApplicationConventionPlugin : Plugin<Project> {
|
|||
with(target) {
|
||||
pluginManager.apply("com.android.application")
|
||||
pluginManager.apply("org.jetbrains.kotlin.android")
|
||||
pluginManager.apply("librechat.android.detekt")
|
||||
pluginManager.apply("librechat.mobile.detekt")
|
||||
pluginManager.apply("org.jetbrains.kotlinx.kover")
|
||||
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import org.gradle.kotlin.dsl.dependencies
|
|||
class AndroidFeatureConventionPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("librechat.android.library")
|
||||
pluginManager.apply("librechat.android.compose")
|
||||
pluginManager.apply("librechat.android.koin")
|
||||
pluginManager.apply("librechat.mobile.library")
|
||||
pluginManager.apply("librechat.mobile.compose")
|
||||
pluginManager.apply("librechat.mobile.koin")
|
||||
|
||||
dependencies {
|
||||
add("implementation", project(":core:ui"))
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
|
|||
with(target) {
|
||||
pluginManager.apply("com.android.library")
|
||||
pluginManager.apply("org.jetbrains.kotlin.android")
|
||||
pluginManager.apply("librechat.android.detekt")
|
||||
pluginManager.apply("librechat.mobile.detekt")
|
||||
pluginManager.apply("org.jetbrains.kotlinx.kover")
|
||||
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class KmpLibraryConventionPlugin : Plugin<Project> {
|
|||
with(target) {
|
||||
pluginManager.apply("com.android.library")
|
||||
pluginManager.apply("org.jetbrains.kotlin.multiplatform")
|
||||
pluginManager.apply("librechat.android.detekt")
|
||||
pluginManager.apply("librechat.mobile.detekt")
|
||||
pluginManager.apply("org.jetbrains.kotlinx.kover")
|
||||
|
||||
extensions.configure<KotlinMultiplatformExtension> {
|
||||
|
|
|
|||
|
|
@ -37,4 +37,4 @@ This lives here (not in `:core:network`) because repositories in `:core:data` ca
|
|||
- **Pure Kotlin preferred.** Minimal Android dependencies (only what ConnectivityObserver and Koin require).
|
||||
- **No network or data dependencies.** This module must not depend on `:core:network`, `:core:data`, or `:core:model`.
|
||||
- Dependencies: `coroutines-core`, `coroutines-android`, Koin.
|
||||
- Convention plugin: `librechat.android.library` + `librechat.android.koin`.
|
||||
- Convention plugin: `librechat.mobile.library` + `librechat.mobile.koin`.
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ Wrap `EncryptedSharedPreferences` in try/catch -- some OEM devices have broken K
|
|||
## Rules
|
||||
|
||||
- Dependencies: `:core:network`, `:core:model`, `:core:common`, Room, DataStore, security-crypto, Ktor, kotlinx-serialization, Timber, Koin.
|
||||
- Convention plugins: `librechat.android.library` + `librechat.android.koin` + `librechat.android.room` + `librechat.kotlin.serialization`.
|
||||
- Convention plugins: `librechat.mobile.library` + `librechat.mobile.koin` + `librechat.mobile.room` + `librechat.kotlin.serialization`.
|
||||
- Repositories must use `safeApiCall` from `:core:common` for all network calls.
|
||||
- Entities are internal to this module -- feature modules work with domain models from `:core:model`.
|
||||
- All DAO read methods that the UI observes should return `Flow`, not suspend functions.
|
||||
|
|
|
|||
|
|
@ -27,4 +27,4 @@ All `@Serializable` data classes -- domain models, DTOs, request/response wrappe
|
|||
- Only dependency beyond `:core:common` is `kotlinx-serialization-json`.
|
||||
- Use `@Serializable` on every data class. Use `@SerialName` for snake_case JSON fields.
|
||||
- Use `JsonObject` / `JsonElement` for truly polymorphic/mixed-type fields (e.g., `Agent.avatar`, `Feedback.tag`).
|
||||
- Convention plugins: `librechat.android.library` + `librechat.kotlin.serialization`.
|
||||
- Convention plugins: `librechat.mobile.library` + `librechat.kotlin.serialization`.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,6 @@ On reconnection, append `?resume=true` to get a `sync` event with `runSteps[]` +
|
|||
## Rules
|
||||
|
||||
- Dependencies: `:core:model`, `:core:common`, Ktor bundles, kotlinx-serialization, Timber, Koin.
|
||||
- Convention plugins: `librechat.android.library` + `librechat.android.koin` + `librechat.kotlin.serialization`.
|
||||
- Convention plugins: `librechat.mobile.library` + `librechat.mobile.koin` + `librechat.kotlin.serialization`.
|
||||
- API services must not contain business logic -- they are thin HTTP wrappers.
|
||||
- All `arg`-wrapped endpoints must match the backend pattern: `setBody(mapOf("arg" to mapOf(...)))`.
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ Material 3 theme and shared Compose components used across all feature modules.
|
|||
- Components accept domain models from `:core:model` as parameters and render them.
|
||||
- All components must be stateless or hoist state to the caller.
|
||||
- Dependencies: `:core:model`, `:core:common`, Coil for image loading, Compose libraries.
|
||||
- Convention plugins: `librechat.android.library` + `librechat.android.compose`.
|
||||
- Convention plugins: `librechat.mobile.library` + `librechat.mobile.compose`.
|
||||
- No DI in this module (no Koin modules, no injected classes).
|
||||
- Use `@Preview` annotations on all components for Android Studio preview support.
|
||||
- During SSE streaming, buffer markdown re-renders to ~100ms intervals to avoid frame drops.
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ package com.garfiec.librechat.core.ui.components
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import com.garfiec.librechat.core.model.EModelEndpoint
|
||||
import librechat_android.core.ui.generated.resources.Res
|
||||
import librechat_android.core.ui.generated.resources.ic_agents
|
||||
import librechat_android.core.ui.generated.resources.ic_anthropic
|
||||
import librechat_android.core.ui.generated.resources.ic_azure
|
||||
import librechat_android.core.ui.generated.resources.ic_bedrock
|
||||
import librechat_android.core.ui.generated.resources.ic_google
|
||||
import librechat_android.core.ui.generated.resources.ic_openai
|
||||
import librechat_mobile.core.ui.generated.resources.Res
|
||||
import librechat_mobile.core.ui.generated.resources.ic_agents
|
||||
import librechat_mobile.core.ui.generated.resources.ic_anthropic
|
||||
import librechat_mobile.core.ui.generated.resources.ic_azure
|
||||
import librechat_mobile.core.ui.generated.resources.ic_bedrock
|
||||
import librechat_mobile.core.ui.generated.resources.ic_google
|
||||
import librechat_mobile.core.ui.generated.resources.ic_openai
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import androidx.compose.ui.semantics.contentDescription
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.AsyncImage
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
@Composable
|
||||
actual fun AgentAvatarPicker(
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ import com.garfiec.librechat.core.model.ActionAuth
|
|||
import com.garfiec.librechat.core.model.ActionMetadata
|
||||
import com.garfiec.librechat.core.model.request.FunctionTool
|
||||
import com.garfiec.librechat.feature.agents.AgentActionDisplayData
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
import com.garfiec.librechat.feature.agents.util.OpenApiSpecParser
|
||||
import com.garfiec.librechat.feature.agents.util.ParsedFunctionInfo
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
data class AgentAdvancedSettings(
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
data class AgentCapabilities(
|
||||
val artifacts: Boolean = false,
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import com.garfiec.librechat.core.model.AgentCategory
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
/**
|
||||
* Maps category values to human-readable English labels.
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun AgentCodeInterpreterSection(
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun AgentFileSearchSection(
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.feature.agents.AgentHandoffDisplayData
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun AgentHandoffConfig(
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.model.mcp.McpTool
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
/** Hierarchical MCP tool picker grouped by server with checkbox selection. */
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
data class ModelOption(
|
||||
val id: String,
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
enum class AgentVisibility(val label: String) {
|
||||
PRIVATE("Private"),
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
@androidx.compose.runtime.Immutable
|
||||
data class SupportContactState(
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
data class AgentVersion(
|
||||
val version: Int,
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ import androidx.compose.ui.window.Dialog
|
|||
import androidx.compose.ui.window.DialogProperties
|
||||
import coil3.compose.AsyncImage
|
||||
import com.garfiec.librechat.feature.agents.AgentToolDisplayData
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
|
||||
/**
|
||||
* Full-screen dialog for selecting agent tools, matching the web app's ToolSelectDialog.
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ import com.garfiec.librechat.core.ui.components.AvatarImage
|
|||
import com.garfiec.librechat.core.ui.components.endpointIconPainter
|
||||
import com.garfiec.librechat.core.ui.components.ErrorBanner
|
||||
import com.garfiec.librechat.core.ui.components.LoadingIndicator
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
import com.garfiec.librechat.feature.agents.viewmodel.AgentDetailEvent
|
||||
import com.garfiec.librechat.feature.agents.viewmodel.AgentDetailViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.garfiec.librechat.core.ui.components.ErrorBanner
|
||||
import com.garfiec.librechat.core.ui.components.LoadingIndicator
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
import com.garfiec.librechat.feature.agents.components.AgentActionsPanel
|
||||
import com.garfiec.librechat.feature.agents.components.AgentAdvancedPanel
|
||||
import com.garfiec.librechat.feature.agents.components.AgentAvatarPicker
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ import com.garfiec.librechat.core.ui.components.ErrorBanner
|
|||
import com.garfiec.librechat.core.ui.components.LibreChatTopBar
|
||||
import com.garfiec.librechat.core.ui.components.LoadingIndicator
|
||||
import com.garfiec.librechat.feature.agents.AgentCardDisplayData
|
||||
import librechat_android.feature.agents.generated.resources.Res
|
||||
import librechat_android.feature.agents.generated.resources.*
|
||||
import librechat_mobile.feature.agents.generated.resources.Res
|
||||
import librechat_mobile.feature.agents.generated.resources.*
|
||||
import com.garfiec.librechat.feature.agents.viewmodel.AgentMarketplaceViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import librechat_android.feature.auth.generated.resources.Res
|
||||
import librechat_android.feature.auth.generated.resources.*
|
||||
import librechat_mobile.feature.auth.generated.resources.Res
|
||||
import librechat_mobile.feature.auth.generated.resources.*
|
||||
import com.garfiec.librechat.feature.auth.viewmodel.ForgotPasswordViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import librechat_android.feature.auth.generated.resources.Res
|
||||
import librechat_android.feature.auth.generated.resources.*
|
||||
import librechat_mobile.feature.auth.generated.resources.Res
|
||||
import librechat_mobile.feature.auth.generated.resources.*
|
||||
import com.garfiec.librechat.feature.auth.viewmodel.LoginViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import librechat_android.feature.auth.generated.resources.Res
|
||||
import librechat_android.feature.auth.generated.resources.*
|
||||
import librechat_mobile.feature.auth.generated.resources.Res
|
||||
import librechat_mobile.feature.auth.generated.resources.*
|
||||
import com.garfiec.librechat.feature.auth.viewmodel.RegisterViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import librechat_android.feature.auth.generated.resources.Res
|
||||
import librechat_android.feature.auth.generated.resources.*
|
||||
import librechat_mobile.feature.auth.generated.resources.Res
|
||||
import librechat_mobile.feature.auth.generated.resources.*
|
||||
import com.garfiec.librechat.feature.auth.viewmodel.ResetPasswordViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ import androidx.compose.ui.semantics.heading
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import librechat_android.feature.auth.generated.resources.Res
|
||||
import librechat_android.feature.auth.generated.resources.*
|
||||
import librechat_mobile.feature.auth.generated.resources.Res
|
||||
import librechat_mobile.feature.auth.generated.resources.*
|
||||
import com.garfiec.librechat.feature.auth.viewmodel.ServerUrlViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import librechat_android.feature.auth.generated.resources.Res
|
||||
import librechat_android.feature.auth.generated.resources.*
|
||||
import librechat_mobile.feature.auth.generated.resources.Res
|
||||
import librechat_mobile.feature.auth.generated.resources.*
|
||||
import com.garfiec.librechat.feature.auth.viewmodel.TermsViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ import androidx.compose.ui.text.input.KeyboardType
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import librechat_android.feature.auth.generated.resources.Res
|
||||
import librechat_android.feature.auth.generated.resources.*
|
||||
import librechat_mobile.feature.auth.generated.resources.Res
|
||||
import librechat_mobile.feature.auth.generated.resources.*
|
||||
import com.garfiec.librechat.feature.auth.viewmodel.TwoFactorViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import librechat_android.feature.auth.generated.resources.Res
|
||||
import librechat_android.feature.auth.generated.resources.*
|
||||
import librechat_mobile.feature.auth.generated.resources.Res
|
||||
import librechat_mobile.feature.auth.generated.resources.*
|
||||
import com.garfiec.librechat.feature.auth.viewmodel.VerifyEmailViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import kotlinx.coroutines.delay
|
||||
import co.touchlab.kermit.Logger
|
||||
import java.io.File
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.core.content.FileProvider
|
||||
import com.garfiec.librechat.feature.chat.McpServerDisplayData
|
||||
import com.garfiec.librechat.feature.chat.PromptMentionDisplayData
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import java.io.File
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ import com.garfiec.librechat.core.common.ToolConstants
|
|||
import com.garfiec.librechat.core.model.AgentToolCall
|
||||
import com.garfiec.librechat.core.model.ContentType
|
||||
import com.garfiec.librechat.core.model.MessageContentPart
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import com.garfiec.librechat.feature.chat.components.artifact.ArtifactButton
|
||||
import com.garfiec.librechat.feature.chat.components.artifact.ArtifactPanel
|
||||
import com.garfiec.librechat.feature.chat.components.artifact.ArtifactSegment
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ import coil3.compose.AsyncImage
|
|||
import coil3.SingletonImageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.toBitmap
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ import androidx.compose.ui.unit.isSpecified
|
|||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import com.mikepenz.markdown.m3.Markdown
|
||||
import com.mikepenz.markdown.m3.markdownColor
|
||||
import com.mikepenz.markdown.m3.markdownTypography
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import co.touchlab.kermit.Logger
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import com.garfiec.librechat.core.model.Message
|
|||
import com.garfiec.librechat.core.ui.components.AvatarImage
|
||||
import com.garfiec.librechat.core.ui.components.endpointIconPainter
|
||||
import com.garfiec.librechat.core.ui.components.isMonochromeEndpointIcon
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
private const val ACTION_AUTO_HIDE_MILLIS = 30_000L
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import androidx.compose.ui.viewinterop.AndroidView
|
|||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.ui.PlayerView
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@Composable
|
||||
actual fun VideoContent(
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.media3.common.MediaItem
|
|||
import androidx.media3.common.Player
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.ui.PlayerView
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/** Plays video via ExoPlayer (media3) in a 16:9 card. Releases player on dispose via DisposableEffect. */
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import com.garfiec.librechat.feature.chat.components.CodeBlock
|
||||
import kotlinx.coroutines.launch
|
||||
import co.touchlab.kermit.Logger
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ import com.garfiec.librechat.core.model.ContentType
|
|||
import com.garfiec.librechat.core.model.MessageContentPart
|
||||
import com.garfiec.librechat.core.ui.components.LoadingIndicator
|
||||
import com.garfiec.librechat.core.ui.components.ModelParameterSheet
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import com.garfiec.librechat.feature.chat.components.ChatInput
|
||||
import com.garfiec.librechat.feature.chat.components.ComparisonDualPane
|
||||
import com.garfiec.librechat.feature.chat.components.ComparisonTabBar
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Data class representing an agent handoff event.
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ import androidx.compose.ui.unit.dp
|
|||
import coil3.compose.AsyncImage
|
||||
import com.garfiec.librechat.core.common.ToolConstants
|
||||
import com.garfiec.librechat.feature.chat.McpServerDisplayData
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Floating row of Material 3 chips above the chat input field.
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.common.ToolConstants
|
||||
import com.garfiec.librechat.feature.chat.McpServerDisplayData
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
data class ToolToggle(
|
||||
val id: String,
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.common.ToolConstants
|
||||
import com.garfiec.librechat.feature.chat.McpServerDisplayData
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Popup
|
||||
import androidx.compose.ui.window.PopupProperties
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Parsed citation found in message text.
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ import androidx.compose.ui.text.font.FontStyle
|
|||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ import androidx.compose.ui.semantics.role
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Data class representing a code execution result parsed from tool call output.
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.feature.chat.McpServerDisplayData
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.cd_send_message
|
||||
import librechat_android.feature.chat.generated.resources.cd_start_voice_recording
|
||||
import librechat_android.feature.chat.generated.resources.cd_stop_generation
|
||||
import librechat_android.feature.chat.generated.resources.hint_message
|
||||
import librechat_android.feature.chat.generated.resources.hint_message_model
|
||||
import librechat_android.feature.chat.generated.resources.recording
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.cd_send_message
|
||||
import librechat_mobile.feature.chat.generated.resources.cd_start_voice_recording
|
||||
import librechat_mobile.feature.chat.generated.resources.cd_stop_generation
|
||||
import librechat_mobile.feature.chat.generated.resources.hint_message
|
||||
import librechat_mobile.feature.chat.generated.resources.hint_message_model
|
||||
import librechat_mobile.feature.chat.generated.resources.recording
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
@Immutable
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Tablet-layout comparison view with two side-by-side panes.
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Dialog shown when a user taps thumbs-down on an AI message.
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.model.request.ForkOption
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ import androidx.compose.ui.semantics.role
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.SubcomposeAsyncImage
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
data class ImageGenResult(
|
||||
val imageUrl: String? = null,
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import androidx.compose.ui.semantics.contentDescription
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import org.jetbrains.compose.resources.stringResource
|
|||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun InlineEditInput(
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import kotlin.time.Clock
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ import androidx.compose.ui.semantics.role
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
data class LogContent(
|
||||
val title: String = "Log Output",
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Data class representing an MCP resource parsed from tool call output.
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.feature.chat.McpServerDisplayData
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun McpServerSelector(
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Data class representing a memory artifact parsed from tool call output.
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.layout.LayoutCoordinates
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.model.Message
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.SubcomposeAsyncImage
|
||||
import com.garfiec.librechat.core.model.FileReference
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Renders files attached to a message. Splits files into images (shown as
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ import org.jetbrains.compose.resources.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.common.ChatLayoutConstants
|
||||
import com.garfiec.librechat.core.model.FeedbackRating
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import com.garfiec.librechat.feature.chat.util.MessageNode
|
||||
import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall
|
||||
import com.garfiec.librechat.feature.chat.viewmodel.SearchMatch
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun ModelSelectorButton(
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ import com.garfiec.librechat.core.model.EndpointConfig
|
|||
import com.garfiec.librechat.core.ui.components.endpointIconPainter
|
||||
import com.garfiec.librechat.core.ui.components.isMonochromeEndpointIcon
|
||||
import com.garfiec.librechat.feature.chat.util.FuzzyMatch
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
private val IconSize = 20.dp
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import org.jetbrains.compose.resources.stringResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.feature.chat.PresetDisplayData
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun SavePresetDialog(
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.common.ChatLayoutConstants
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import com.garfiec.librechat.feature.chat.util.MessageNode
|
||||
import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ import org.jetbrains.compose.resources.stringResource
|
|||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.stateDescription
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun SiblingNavigator(
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import androidx.compose.ui.semantics.semantics
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Blinking cursor indicator shown during streaming. Displays a pipe character (|)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import com.garfiec.librechat.core.common.ToolConstants
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
private data class ToolMenuItem(
|
||||
val id: String,
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.SubcomposeAsyncImage
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* Data class representing a single web search result parsed from tool call output.
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ import org.jetbrains.compose.resources.stringResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
@Composable
|
||||
fun ArtifactButton(
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/** Prev/next version navigation for artifacts. [currentIndex] is 0-based; display shows 1-based "v1/N". */
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.ui.Modifier
|
|||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.ui.components.LibreChatTopBar
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import com.garfiec.librechat.feature.chat.prompts.components.PromptPreviewPanel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.garfiec.librechat.core.ui.components.LoadingIndicator
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
private val VARIABLE_REGEX = Regex("\\{\\{\\s*(\\w+)\\s*\\}\\}")
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ import org.jetbrains.compose.resources.stringResource
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.garfiec.librechat.core.model.Prompt
|
||||
import librechat_android.feature.chat.generated.resources.Res
|
||||
import librechat_android.feature.chat.generated.resources.*
|
||||
import librechat_mobile.feature.chat.generated.resources.Res
|
||||
import librechat_mobile.feature.chat.generated.resources.*
|
||||
|
||||
/**
|
||||
* A ModalBottomSheet that shows the version history of prompts within a group.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue