Merge pull request #693 from jellydn/feat/llamacpp-support

feat(api): add llama.cpp support as local model provider
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-03-09 05:24:46 -04:00
commit 163f40be8a
10 files changed
+103 -30

No files matched your search

@@ -38,6 +38,7 @@ import {
PROVIDER_PRESETS,
getPresetsByCategory,
getPresetById,
resolvePresetApiKeyValue,
type ProviderPreset,
} from '@/lib/provider-presets';
import {
@@ -257,8 +258,7 @@ export function ProfileCreateDialog({
// Use user-provided baseUrl (allows customization of preset URLs)
const finalData = {
...data,
// Use provided API key, or empty string if not provided (for optional auth providers)
apiKey: data.apiKey || '',
apiKey: resolvePresetApiKeyValue(currentPreset, data.apiKey),
};
try {
await createMutation.mutateAsync(finalData);
@@ -459,7 +459,7 @@ export function ProfileCreateDialog({
<p className="text-xs text-destructive">{errors.apiKey.message}</p>
) : currentPreset?.requiresApiKey === false ? (
<p className="text-xs text-muted-foreground">
Only needed if you have configured Ollama authentication
Only needed if your local endpoint has authentication enabled
</p>
) : (
currentPreset?.apiKeyHint && (
+17 -21
View File
@@ -1,6 +1,6 @@
/**
* Provider Presets Configuration
* Shared catalog from backend source-of-truth with UI-only presentation overrides.
* Shared catalog from backend source-of-truth.
*/
import {
@@ -9,7 +9,6 @@ import {
normalizeProviderPresetId,
type PresetCategory,
type ProviderPresetDefinition,
type ProviderPresetId,
} from '../../../src/shared/provider-preset-catalog';
export { OPENROUTER_BASE_URL };
@@ -17,30 +16,27 @@ export type { PresetCategory };
export type ProviderPreset = ProviderPresetDefinition;
/**
* UI-only overrides for presentation details that differ from CLI semantics.
* Keep this tiny; provider data itself belongs in shared catalog.
*/
type UiPresetOverride = Pick<ProviderPreset, 'apiKeyPlaceholder'>;
const UI_PRESET_OVERRIDES: Readonly<Partial<Record<ProviderPresetId, UiPresetOverride>>> =
Object.freeze({
ollama: {
apiKeyPlaceholder: '',
},
});
function withUiOverrides(preset: ProviderPresetDefinition): ProviderPreset {
const overrides = UI_PRESET_OVERRIDES[preset.id];
return overrides ? { ...preset, ...overrides } : { ...preset };
}
const BASE_PROVIDER_PRESETS = createProviderPresetDefinitions();
export const PROVIDER_PRESETS: readonly ProviderPreset[] = Object.freeze(
BASE_PROVIDER_PRESETS.map(withUiOverrides)
BASE_PROVIDER_PRESETS.map((preset) => ({ ...preset }))
);
export function resolvePresetApiKeyValue(
preset: ProviderPreset | null | undefined,
apiKey: string
): string {
if (apiKey) {
return apiKey;
}
if (preset?.requiresApiKey === false) {
return preset.apiKeyPlaceholder || preset.id;
}
return '';
}
/** Get presets by category */
export function getPresetsByCategory(category: PresetCategory): ProviderPreset[] {
return PROVIDER_PRESETS.filter((preset) => preset.category === category);
@@ -0,0 +1,24 @@
import { describe, expect, it } from 'vitest';
import { getPresetById, resolvePresetApiKeyValue } from '@/lib/provider-presets';
describe('resolvePresetApiKeyValue', () => {
it('keeps an explicit API key when one is provided', () => {
const preset = getPresetById('llamacpp');
expect(resolvePresetApiKeyValue(preset, 'custom-token')).toBe('custom-token');
});
it('uses the local-provider sentinel for Ollama when no API key is provided', () => {
const preset = getPresetById('ollama');
expect(resolvePresetApiKeyValue(preset, '')).toBe('ollama');
});
it('uses the local-provider sentinel for llama.cpp when no API key is provided', () => {
const preset = getPresetById('llamacpp');
expect(resolvePresetApiKeyValue(preset, '')).toBe('llamacpp');
});
it('returns an empty string for API-key providers when input is empty', () => {
const preset = getPresetById('openrouter');
expect(resolvePresetApiKeyValue(preset, '')).toBe('');
});
});