mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-15 14:16:16 +00:00
Merge pull request #693 from jellydn/feat/llamacpp-support
feat(api): add llama.cpp support as local model provider
This commit is contained in:
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 && (
|
||||
|
||||
@@ -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('');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user