Skip to content

Commit 65b764c

Browse files
authored
Merge pull request #4529 from atomantic/cos/task-msy4iwje/agent-bc83157d
fix: link gated local models to Hugging Face terms
2 parents ea9fedb + 63f5b40 commit 65b764c

4 files changed

Lines changed: 38 additions & 7 deletions

File tree

client/src/components/settings/LocalLlmTab.jsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,7 @@ export function LocalLlmTab() {
887887
{group.models.map((m) => {
888888
const isHf = m.source === 'huggingface';
889889
const isAudio = m.category === 'audio';
890+
const repositoryUrl = m.repository ? `https://huggingface.co/${m.repository}` : null;
890891
// Multi-quant repos let the user trade their RAM for fidelity.
891892
// `chosenId` is the selected variant's install id (defaulting to
892893
// the server's RAM-aware pick `m.id`); the card's size/RAM/fit
@@ -1036,16 +1037,16 @@ export function LocalLlmTab() {
10361037
Sharded — use LM Studio or a smaller quant
10371038
</span>
10381039
)}
1039-
{isHf && m.repository && (
1040+
{repositoryUrl && (
10401041
<a
1041-
href={`https://huggingface.co/${m.repository}`}
1042+
href={repositoryUrl}
10421043
target="_blank"
10431044
rel="noopener noreferrer"
1044-
title="Open the model page on Hugging Face"
1045+
title={m.gated ? 'Open Hugging Face to accept repository terms' : 'Open the model page on Hugging Face'}
10451046
className="px-2.5 py-1 text-xs bg-port-border/60 hover:bg-port-border text-gray-300 rounded flex items-center gap-1"
10461047
>
10471048
<ExternalLink size={12} />
1048-
Visit
1049+
{m.gated ? 'Accept terms' : 'Visit'}
10491050
</a>
10501051
)}
10511052
</div>

client/src/components/settings/LocalLlmTab.test.jsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,30 @@ describe('LocalLlmTab installed models', () => {
121121
});
122122

123123
describe('LocalLlmTab recommendations', () => {
124+
it('links a gated curated model to Hugging Face so its terms can be accepted', async () => {
125+
getLocalLlmCatalog.mockResolvedValue({
126+
models: [{
127+
id: 'orcarouter/qwen3.8-27b-uncensored-mlx:4bit',
128+
key: 'qwen3.8-27b-uncensored-mlx',
129+
name: 'Qwen3.8 27B Uncensored MLX',
130+
category: 'general',
131+
recommendedFor: ['general'],
132+
params: '27B',
133+
size: '15 GB',
134+
description: 'A gated local evaluation model.',
135+
repository: 'orcarouter/Qwen3.8-27B-Uncensored-MLX',
136+
gated: true,
137+
capabilities: ['chat'],
138+
}],
139+
});
140+
141+
await renderTab();
142+
143+
const termsLink = await screen.findByRole('link', { name: 'Accept terms' });
144+
expect(termsLink).toHaveAttribute('href', 'https://huggingface.co/orcarouter/Qwen3.8-27B-Uncensored-MLX');
145+
expect(termsLink).toHaveAttribute('target', '_blank');
146+
});
147+
124148
it('highlights the flagship general model and surfaces it in its coding use-case filter', async () => {
125149
getLocalLlmCatalog.mockResolvedValue({
126150
models: [{

server/lib/localLlmCatalog.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const LOCAL_LLM_CATEGORIES = [
3838
];
3939

4040
// Each entry: { key, name, category, recommendedFor?, featured?, params, size,
41-
// family, description, note?, capabilities, context?, format?,
41+
// family, description, note?, repository?, gated?, capabilities, context?, format?,
4242
// appleSiliconOnly?, ollama?, lmstudio?, ollamaImport?, ollamaAliases?,
4343
// lmstudioAliases? }
4444
//
@@ -314,6 +314,8 @@ export const LOCAL_LLM_CATALOG = [
314314
family: 'qwen',
315315
description: 'OrcaRouter’s abliterated Qwen3.8 variant for red-team and unrestricted local evaluation, with 2-, 4-, 6-, and 8-bit MLX builds plus vision, tools, reasoning, and multilingual support.',
316316
note: 'Gated on Hugging Face — accept the repository terms and configure a Hugging Face token in Settings. Ollama imports the 4-bit build; LM Studio can select another quantization.',
317+
repository: 'orcarouter/Qwen3.8-27B-Uncensored-MLX',
318+
gated: true,
317319
capabilities: ['chat', 'code', 'reasoning', 'tools', 'vision', 'multilingual'],
318320
context: 262144,
319321
format: 'mlx',
@@ -726,7 +728,7 @@ export function getOllamaImportSpec(modelId) {
726728
* @param {string} backend - 'ollama' | 'lmstudio'
727729
* @param {string[]} [installedIds] - ids currently installed on that backend
728730
* @param {{ appleSilicon?: boolean }} [options] - host capabilities used for platform-gated entries
729-
* @returns {Array<{ id, key, name, category, recommendedFor, featured, params, size, family, description, note, capabilities, format, contextLength, installed }>}
731+
* @returns {Array<{ id, key, name, category, recommendedFor, featured, params, size, family, description, note, repository, gated, capabilities, format, contextLength, installed }>}
730732
*/
731733
export function getCatalog(backend, installedIds = [], { appleSilicon } = {}) {
732734
if (!isBackend(backend)) return [];
@@ -749,6 +751,8 @@ export function getCatalog(backend, installedIds = [], { appleSilicon } = {}) {
749751
family: entry.family,
750752
description: entry.description,
751753
note: entry.note || null,
754+
repository: entry.repository || null,
755+
gated: entry.gated === true,
752756
capabilities: entry.capabilities,
753757
format: entry.format || null,
754758
// Native context window (tokens), when it's a documented spec; null otherwise.

server/lib/localLlmCatalog.test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ describe('localLlmCatalog', () => {
7272
expect(getCatalog('lmstudio', [], { appleSilicon: true }).find((m) => m.key === uncensoredKey)).toMatchObject({
7373
format: 'mlx',
7474
id: 'https://huggingface.co/orcarouter/Qwen3.8-27B-Uncensored-MLX',
75-
note: expect.stringContaining('Gated on Hugging Face')
75+
note: expect.stringContaining('Gated on Hugging Face'),
76+
repository: 'orcarouter/Qwen3.8-27B-Uncensored-MLX',
77+
gated: true
7678
});
7779
expect(getCatalog('lmstudio', ['orcarouter/Qwen3.8-27B-Uncensored-MLX'], { appleSilicon: true })
7880
.find((m) => m.key === uncensoredKey)?.installed).toBe(true);

0 commit comments

Comments
 (0)