Librechat-Mobile/VERSION_GATES.md
Garfie 89eaccb428 feat(common): include patch in backend version compatibility checks
Upstream LibreChat ships breaking API and SSE-shape changes inside patch
releases (e.g. 0.8.4 → 0.8.5 changed the SSE payload contract), so the
mobile compat surface must compare patch as well as major.minor.

- isCompatible: exact (major, minor, patch) equality
- isCompatibleOrNewer: lex compare over (major, minor, patch); fixes a
  silent bug where 0.8.5-only feature gates returned true on 0.8.4
- VERSION_GATES.md updated to reflect patch-aware semantics
- New BackendVersionTest covers parse, isCompatible, isCompatibleOrNewer,
  and extractVersionFromFooter
2026-04-27 01:01:37 -06:00

32 lines
2.9 KiB
Markdown

# Version Gates
LibreChat Mobile supports a range of backend server versions. This file catalogs every
place in the codebase where behavior branches based on the detected server version so
the compatibility surface is auditable. When the minimum supported server version is
raised, entries here can be simplified or removed.
The canonical API for version comparisons lives in
`core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/BackendVersion.kt`:
- `BackendVersion.parse(version)` — parse a loose semver string (`"v0.8.5"`, `"0.8"`, …).
- `BackendVersion.isCompatible(supported, actual)` — exact `major.minor.patch` match.
- `BackendVersion.isCompatibleOrNewer(actual, minimum)``actual ≥ minimum` by `(major, minor, patch)`.
- `BackendVersion.extractVersionFromFooter(footer)` — fallback parse from `customFooter`.
The detected server version is exposed via `ConfigRepository.detectedBackendVersion`
(populated once `checkBackendVersion()` runs on app startup / server-switch).
## Catalog
| Feature | Gated since | Behavior on older | Behavior on newer | File:line | Safe to remove when min supported server ≥ |
|---|---|---|---|---|---|
| `isCollaborative` agent toggle | v0.8.5 (2026-04-23) | Toggle visible; mobile sends `isCollaborative` + `projectIds` to server | Toggle hidden; inline hint "Access permissions are managed server-side in this version" rendered instead; fields not sent | `feature/agents/.../components/AgentSharingSection.kt` + `feature/agents/.../viewmodel/AgentEditorViewModel.kt` (`observeServerVersion`, `save`) | v0.8.5 |
| `xhigh` reasoning-effort dropdown value | v0.8.5 (2026-04-25) | `xhigh` filtered out of `reasoning_effort` and `effort` dropdowns (older Anthropic/Bedrock/OpenAI schemas reject the unknown enum) | `xhigh` shown alongside `low/medium/high/max` | `core/ui/.../components/EndpointParameterRegistry.kt` (`getDefinitions(xhighEffortSupported)`) + `feature/chat/.../viewmodel/ChatViewModel.kt` (xhigh observer in `init`) | v0.8.5 |
## Guidelines for adding a new gate
1. Call `BackendVersion.isCompatible(...)` or `BackendVersion.isCompatibleOrNewer(...)` — never parse versions ad hoc.
2. Default to **older-server behavior** when the version is unknown (`detectedBackendVersion == null`). The server may not advertise its version; failing open avoids hiding features from self-hosted installs with stripped customFooters.
3. Add a row to the table above. Include file + line anchors and the concrete minimum version at which the gate becomes dead code.
4. If the gated field is a request DTO field, omit it (send `null`) rather than sending a value the server will silently drop — unless you can verify round-trip parity. Silent drops lead to UI state that disagrees with server state.
5. Patch-version gates are supported. Upstream LibreChat regularly ships breaking API and SSE-shape changes inside a patch bump (the same-minor assumption broke us moving 0.8.4 → 0.8.5), so use the exact patch the feature shipped in.