Skip to content

Commit 5cc0ea4

Browse files
authored
feat: add model/endpoint compatibility matrix page (#621)
* feat: accessibility and UX polish - Image zoom: docs screenshots are now click-to-enlarge via Fumadocs ImageZoom (passed a plain img so dimensionless MDX images keep working). - Reduced motion: a global prefers-reduced-motion reset neutralizes CSS animations/transitions and smooth scroll; the framer-motion feature fade now respects useReducedMotion. - Skip link: a keyboard-only "Skip to main content" link with matching #main-content targets on the home, blog, changelog, and docs layouts. Also points the site-wide default Open Graph image at the new /api/og generator. * fix: add skip-link target to every route The skip-to-content link is rendered globally from the root layout, but only the home/blog/changelog/docs layouts had an #main-content target. Add id="main-content" + tabIndex={-1} to the <main> of the remaining standalone routes (about, authors, privacy, tos, cookie, subscribe, unsubscribe, demo legal pages, error, not-found) so the skip link actually moves focus to the content on every page. * fix: render static-imported docs images in zoom remarkImage rewrites local docs images (/images/...) into Next static-import objects with dimensions. The zoom wrapper was spreading that object onto a plain <img>, rendering src="[object Object]". Let ImageZoom render the image through Fumadocs' next/image wrapper instead, which handles both the static-import object and string srcs. * feat: scaffold docs internationalization Add the i18n foundation so localized docs can be served as soon as translated MDX exists, without changing English content or URLs. - lib/i18n.ts: single source of truth for locales (en default, plus zh, es, fr, de, ja) with hideLocale 'default-locale', so English keeps its current /docs/... URLs and other locales are served at /<locale>/docs. - Make the docs loader i18n-aware and move the docs route under app/[lang]/docs; the layout renders the per-locale page tree, an I18nProvider, and a language switcher. - Integrate the Fumadocs locale middleware into proxy.ts, preserving the existing markdown content-negotiation and the raw .mdx route. - Pages without a translation fall back to English, so an automated translation workflow can fill in *.<locale>.mdx files incrementally. Note: localized pages still emit <html lang="en"> because only the docs subtree is nested under [lang]; full-site localization would move every route there. * fix: map docs search locales to supported tokenizers The i18n loader makes createFromSource build an Orama index per locale. Spanish/French/German tokenizers are built in, but Chinese and Japanese need @orama/tokenizers, so they threw LANGUAGE_NOT_SUPPORTED. Map each locale to a supported tokenizer (zh/ja fall back to english until CJK tokenizers are added) so indexing succeeds for every configured language. * feat: add announcement banner and full docs breadcrumbs - Wire Fumadocs's native Banner (dismissible, layout-aware) into the root layout for site announcements, carrying over the ClickHouse message and removing the unused Nextra-era components/Banner.tsx it replaces. - Show a full breadcrumb trail (root / section / page) on docs pages via the DocsPage breadcrumb option, giving a visible counterpart to the BreadcrumbList structured data. * feat: add model/endpoint compatibility matrix page Add a /docs/compatibility page with an accessible, data-driven matrix of which LibreChat capabilities each endpoint type supports (OpenAI, Azure, Anthropic, Google, Bedrock, Custom, Agents, Assistants). The table is a semantic <table> with per-cell screen-reader labels and a legend; values live in lib/compatibility-data.ts as the single source of truth, using coarse states (supported / not / model-dependent / via Agents) so model-specific capabilities aren't overstated. Marked as a manually maintained reference with a last-reviewed date.
1 parent 909087f commit 5cc0ea4

5 files changed

Lines changed: 325 additions & 0 deletions

File tree

‎components/CompatibilityMatrix.tsx‎

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import Link from 'next/link'
2+
import {
3+
endpoints,
4+
capabilities,
5+
matrix,
6+
SUPPORT_LEGEND,
7+
LAST_REVIEWED,
8+
type Support,
9+
} from '@/lib/compatibility-data'
10+
11+
const CELL_CLASS: Record<Support, string> = {
12+
yes: 'text-emerald-600 dark:text-emerald-400',
13+
no: 'text-fd-muted-foreground/50',
14+
model: 'text-amber-600 dark:text-amber-400',
15+
agents: 'text-sky-600 dark:text-sky-400',
16+
}
17+
18+
/**
19+
* Model/endpoint capability matrix. Server-rendered semantic table; each cell
20+
* carries a screen-reader label (the visible glyph is decorative). Data lives
21+
* in lib/compatibility-data.ts.
22+
*/
23+
export function CompatibilityMatrix() {
24+
return (
25+
<div className="not-prose my-6">
26+
{/* Legend */}
27+
<ul className="mb-4 flex flex-wrap gap-x-5 gap-y-2 text-sm" aria-label="Legend">
28+
{(Object.keys(SUPPORT_LEGEND) as Support[]).map((key) => (
29+
<li key={key} className="flex items-center gap-1.5">
30+
<span className={`font-semibold ${CELL_CLASS[key]}`} aria-hidden="true">
31+
{SUPPORT_LEGEND[key].symbol}
32+
</span>
33+
<span className="text-fd-muted-foreground">{SUPPORT_LEGEND[key].label}</span>
34+
</li>
35+
))}
36+
</ul>
37+
38+
<div className="overflow-x-auto rounded-lg border border-fd-border">
39+
<table className="w-full border-collapse text-sm">
40+
<caption className="sr-only">
41+
LibreChat capability support by endpoint type. Rows are capabilities, columns are
42+
endpoints.
43+
</caption>
44+
<thead>
45+
<tr className="border-b border-fd-border bg-fd-muted/50">
46+
<th scope="col" className="px-4 py-2.5 text-left font-semibold">
47+
Capability
48+
</th>
49+
{endpoints.map((endpoint) => (
50+
<th
51+
key={endpoint.id}
52+
scope="col"
53+
className="px-3 py-2.5 text-center font-semibold whitespace-nowrap"
54+
>
55+
{endpoint.href ? (
56+
<Link href={endpoint.href} className="hover:underline">
57+
{endpoint.name}
58+
</Link>
59+
) : (
60+
endpoint.name
61+
)}
62+
</th>
63+
))}
64+
</tr>
65+
</thead>
66+
<tbody>
67+
{capabilities.map((capability) => (
68+
<tr key={capability.id} className="border-b border-fd-border last:border-0">
69+
<th scope="row" className="px-4 py-2.5 text-left font-medium whitespace-nowrap">
70+
{capability.href ? (
71+
<Link href={capability.href} className="hover:underline">
72+
{capability.name}
73+
</Link>
74+
) : (
75+
capability.name
76+
)}
77+
</th>
78+
{endpoints.map((endpoint) => {
79+
const state = matrix[capability.id]?.[endpoint.id] ?? 'no'
80+
const legend = SUPPORT_LEGEND[state]
81+
return (
82+
<td key={endpoint.id} className="px-3 py-2.5 text-center">
83+
<span
84+
className={`text-base font-semibold ${CELL_CLASS[state]}`}
85+
aria-hidden="true"
86+
>
87+
{legend.symbol}
88+
</span>
89+
<span className="sr-only">{legend.label}</span>
90+
</td>
91+
)
92+
})}
93+
</tr>
94+
))}
95+
</tbody>
96+
</table>
97+
</div>
98+
99+
<p className="mt-3 text-xs text-fd-muted-foreground">
100+
Quick reference, maintained manually. &ldquo;Depends on the model&rdquo; means the
101+
capability is available when the selected model supports it. Verify against your deployed
102+
version. Last reviewed: {LAST_REVIEWED}.
103+
</p>
104+
</div>
105+
)
106+
}

‎content/docs/compatibility.mdx‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
title: Compatibility Matrix
3+
description: Which LibreChat capabilities are supported by each model endpoint type.
4+
---
5+
6+
LibreChat connects to many AI providers through a small set of **endpoint types**.
7+
This page summarizes which capabilities each endpoint supports. Many capabilities
8+
depend on the specific model you select, so those cells are marked as
9+
model-dependent rather than a hard yes or no.
10+
11+
<CompatibilityMatrix />
12+
13+
## Notes
14+
15+
- **Custom (OpenAI-compatible)** covers any provider configured through
16+
[custom endpoints](/docs/configuration/librechat_yaml/ai_endpoints), such as
17+
OpenRouter, Groq, Mistral, Ollama, DeepSeek, Perplexity, and others. Exact
18+
support depends on how closely the provider mirrors the OpenAI API and on the
19+
model you pick.
20+
- **Agents** is the most capable endpoint: it adds tool use,
21+
[MCP](/docs/features/mcp), [Code Interpreter](/docs/features/code_interpreter),
22+
file search, and [Image Generation](/docs/features/image_gen) on top of most
23+
base models. Reach for it when you need capabilities a plain chat endpoint
24+
doesn't expose.
25+
- **Vision** and **tools / function calling** are properties of the *model*, not
26+
the endpoint, so a capable model is required regardless of provider.
27+
- **Assistants** uses OpenAI's Assistants runtime, which provides its own file
28+
search and code execution but does not layer on LibreChat features such as
29+
Memory or Artifacts.
30+
31+
This is a manually maintained quick reference. If a value looks wrong for your
32+
release, please [open an issue or PR](https://github.com/LibreChat-AI/librechat.ai).

‎content/docs/meta.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"pages": [
33
"index",
44
"features",
5+
"compatibility",
56
"---Deploy---",
67
"local",
78
"remote",

‎lib/compatibility-data.ts‎

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/**
2+
* Data for the model/endpoint compatibility matrix (rendered by
3+
* components/CompatibilityMatrix.tsx on /docs/compatibility).
4+
*
5+
* This is a manually-maintained quick reference. Edit the `matrix` below when
6+
* support changes and bump `LAST_REVIEWED`. Cells use coarse states so the
7+
* table stays honest: capabilities that depend on the chosen model are marked
8+
* "model" rather than a hard yes/no.
9+
*/
10+
11+
export const LAST_REVIEWED = '2026-06-18'
12+
13+
export type Support = 'yes' | 'no' | 'model' | 'agents'
14+
15+
export const SUPPORT_LEGEND: Record<Support, { symbol: string; label: string }> = {
16+
yes: { symbol: '✓', label: 'Supported' },
17+
no: { symbol: '—', label: 'Not supported' },
18+
model: { symbol: '◐', label: 'Depends on the model' },
19+
agents: { symbol: '⚙', label: 'Via the Agents endpoint' },
20+
}
21+
22+
export interface Endpoint {
23+
id: string
24+
name: string
25+
href?: string
26+
}
27+
28+
export interface Capability {
29+
id: string
30+
name: string
31+
href?: string
32+
}
33+
34+
/** Columns: LibreChat endpoint types. */
35+
export const endpoints: Endpoint[] = [
36+
{ id: 'openai', name: 'OpenAI', href: '/docs/configuration/pre_configured_ai/openai' },
37+
{ id: 'azure', name: 'Azure OpenAI', href: '/docs/configuration/azure' },
38+
{ id: 'anthropic', name: 'Anthropic', href: '/docs/configuration/pre_configured_ai/anthropic' },
39+
{ id: 'google', name: 'Google', href: '/docs/configuration/pre_configured_ai/google' },
40+
{ id: 'bedrock', name: 'AWS Bedrock', href: '/docs/configuration/pre_configured_ai/bedrock' },
41+
{
42+
id: 'custom',
43+
name: 'Custom (OpenAI-compatible)',
44+
href: '/docs/configuration/librechat_yaml/ai_endpoints',
45+
},
46+
{ id: 'agents', name: 'Agents', href: '/docs/features/agents' },
47+
{
48+
id: 'assistants',
49+
name: 'Assistants',
50+
href: '/docs/configuration/pre_configured_ai/assistants',
51+
},
52+
]
53+
54+
/** Rows: LibreChat capabilities. */
55+
export const capabilities: Capability[] = [
56+
{ id: 'streaming', name: 'Streaming responses' },
57+
{ id: 'vision', name: 'Vision (image input)' },
58+
{ id: 'tools', name: 'Tools / function calling' },
59+
{ id: 'web_search', name: 'Web Search', href: '/docs/features/web_search' },
60+
{ id: 'code_interpreter', name: 'Code Interpreter', href: '/docs/features/code_interpreter' },
61+
{ id: 'artifacts', name: 'Artifacts', href: '/docs/features/artifacts' },
62+
{ id: 'file_search', name: 'File Search (RAG)', href: '/docs/features/rag_api' },
63+
{ id: 'image_gen', name: 'Image Generation', href: '/docs/features/image_gen' },
64+
{ id: 'ocr', name: 'OCR', href: '/docs/features/ocr' },
65+
{ id: 'memory', name: 'Memory', href: '/docs/features/memory' },
66+
{ id: 'mcp', name: 'MCP', href: '/docs/features/mcp' },
67+
]
68+
69+
/**
70+
* matrix[capabilityId][endpointId] = support state.
71+
* First-pass values — maintainers should verify against the current release.
72+
*/
73+
export const matrix: Record<string, Record<string, Support>> = {
74+
streaming: {
75+
openai: 'yes',
76+
azure: 'yes',
77+
anthropic: 'yes',
78+
google: 'yes',
79+
bedrock: 'yes',
80+
custom: 'yes',
81+
agents: 'yes',
82+
assistants: 'yes',
83+
},
84+
vision: {
85+
openai: 'model',
86+
azure: 'model',
87+
anthropic: 'model',
88+
google: 'model',
89+
bedrock: 'model',
90+
custom: 'model',
91+
agents: 'model',
92+
assistants: 'model',
93+
},
94+
tools: {
95+
openai: 'model',
96+
azure: 'model',
97+
anthropic: 'model',
98+
google: 'model',
99+
bedrock: 'model',
100+
custom: 'model',
101+
agents: 'yes',
102+
assistants: 'yes',
103+
},
104+
web_search: {
105+
openai: 'yes',
106+
azure: 'yes',
107+
anthropic: 'yes',
108+
google: 'yes',
109+
bedrock: 'yes',
110+
custom: 'yes',
111+
agents: 'yes',
112+
assistants: 'no',
113+
},
114+
code_interpreter: {
115+
openai: 'yes',
116+
azure: 'yes',
117+
anthropic: 'yes',
118+
google: 'yes',
119+
bedrock: 'yes',
120+
custom: 'yes',
121+
agents: 'yes',
122+
assistants: 'yes',
123+
},
124+
artifacts: {
125+
openai: 'yes',
126+
azure: 'yes',
127+
anthropic: 'yes',
128+
google: 'yes',
129+
bedrock: 'yes',
130+
custom: 'yes',
131+
agents: 'yes',
132+
assistants: 'no',
133+
},
134+
file_search: {
135+
openai: 'yes',
136+
azure: 'yes',
137+
anthropic: 'yes',
138+
google: 'yes',
139+
bedrock: 'yes',
140+
custom: 'yes',
141+
agents: 'yes',
142+
assistants: 'yes',
143+
},
144+
image_gen: {
145+
openai: 'agents',
146+
azure: 'agents',
147+
anthropic: 'agents',
148+
google: 'agents',
149+
bedrock: 'agents',
150+
custom: 'agents',
151+
agents: 'yes',
152+
assistants: 'agents',
153+
},
154+
ocr: {
155+
openai: 'yes',
156+
azure: 'yes',
157+
anthropic: 'yes',
158+
google: 'yes',
159+
bedrock: 'yes',
160+
custom: 'yes',
161+
agents: 'yes',
162+
assistants: 'yes',
163+
},
164+
memory: {
165+
openai: 'yes',
166+
azure: 'yes',
167+
anthropic: 'yes',
168+
google: 'yes',
169+
bedrock: 'yes',
170+
custom: 'yes',
171+
agents: 'yes',
172+
assistants: 'no',
173+
},
174+
mcp: {
175+
openai: 'agents',
176+
azure: 'agents',
177+
anthropic: 'agents',
178+
google: 'agents',
179+
bedrock: 'agents',
180+
custom: 'agents',
181+
agents: 'yes',
182+
assistants: 'no',
183+
},
184+
}

‎lib/mdx-components.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Carousel from '@/components/carousel/Carousel'
1515
import { TrackedLink, TrackedAnchor } from '@/components/TrackedLink'
1616
import { CredentialsGeneratorMDX } from '@/components/tools/CredentialsGeneratorMDX'
1717
import { YAMLValidatorMDX } from '@/components/tools/YAMLValidatorMDX'
18+
import { CompatibilityMatrix } from '@/components/CompatibilityMatrix'
1819
import type { ReactNode } from 'react'
1920

2021
function mapCalloutType(type?: string): 'info' | 'warn' | 'error' {
@@ -245,6 +246,7 @@ export const mdxComponents = {
245246
Accordion,
246247
Accordions,
247248
OptionTable,
249+
CompatibilityMatrix,
248250
Frame,
249251
Carousel,
250252
DocsHub,

0 commit comments

Comments
 (0)