From 0ca6428554be9057926988ef4af0b95a958ca17e Mon Sep 17 00:00:00 2001 From: Huynh Duc Dung Date: Thu, 5 Mar 2026 12:29:49 +0800 Subject: [PATCH 1/3] feat(api): add llama.cpp support as local model provider - Add llamacpp provider preset to provider-presets.ts - Add base-llamacpp.settings.json configuration - Update help-command.ts with ccs llamacpp documentation - Update UI provider presets for dashboard parity llama.cpp is a popular C++ inference engine for LLaMA models. This complements existing Ollama support for local inference. Usage: ccs llamacpp (requires llama.cpp server on port 8080) Closes #690 --- config/base-llamacpp.settings.json | 10 ++++++++++ src/api/services/provider-presets.ts | 12 ++++++++++++ src/commands/help-command.ts | 1 + ui/bun.lock | 1 + ui/src/lib/provider-presets.ts | 15 +++++++++++++++ 5 files changed, 39 insertions(+) create mode 100644 config/base-llamacpp.settings.json diff --git a/config/base-llamacpp.settings.json b/config/base-llamacpp.settings.json new file mode 100644 index 00000000..48de05dc --- /dev/null +++ b/config/base-llamacpp.settings.json @@ -0,0 +1,10 @@ +{ + "env": { + "ANTHROPIC_BASE_URL": "http://127.0.0.1:8080", + "ANTHROPIC_AUTH_TOKEN": "llamacpp", + "ANTHROPIC_MODEL": "llama3-8b", + "ANTHROPIC_DEFAULT_OPUS_MODEL": "llama3-70b", + "ANTHROPIC_DEFAULT_SONNET_MODEL": "llama3-8b", + "ANTHROPIC_DEFAULT_HAIKU_MODEL": "llama3-2b" + } +} diff --git a/src/api/services/provider-presets.ts b/src/api/services/provider-presets.ts index 510246e4..97760b24 100644 --- a/src/api/services/provider-presets.ts +++ b/src/api/services/provider-presets.ts @@ -58,6 +58,18 @@ export const PROVIDER_PRESETS: ProviderPreset[] = [ category: 'recommended', requiresApiKey: false, }, + { + id: 'llamacpp', + name: 'llama.cpp (Local)', + description: 'Local inference via llama.cpp (LLaMA models)', + baseUrl: 'http://127.0.0.1:8080', + defaultProfileName: 'llamacpp', + defaultModel: 'llama3-8b', + apiKeyPlaceholder: 'llamacpp', + apiKeyHint: 'Run llama.cpp server: ./server --host 0.0.0.0 --port 8080 -m model.gguf', + category: 'recommended', + requiresApiKey: false, + }, // Alternative providers { id: 'glm', diff --git a/src/commands/help-command.ts b/src/commands/help-command.ts index ae632fb9..201849af 100644 --- a/src/commands/help-command.ts +++ b/src/commands/help-command.ts @@ -128,6 +128,7 @@ Run ${color('ccs config', 'command')} for web dashboard`.trim(); ['ccs glmt', 'GLM with thinking mode'], ['ccs kimi', 'Kimi for Coding (API key)'], ['ccs ollama', 'Local Ollama (http://localhost:11434)'], + ['ccs llamacpp', 'Local llama.cpp (http://127.0.0.1:8080)'], ['ccs ollama-cloud', 'Ollama Cloud (API key required)'], ['', ''], // Spacer ['ccs api create', 'Create custom API profile'], diff --git a/ui/bun.lock b/ui/bun.lock index 2756da98..c2e29de1 100644 --- a/ui/bun.lock +++ b/ui/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "ui", diff --git a/ui/src/lib/provider-presets.ts b/ui/src/lib/provider-presets.ts index d6d35486..1ce5274a 100644 --- a/ui/src/lib/provider-presets.ts +++ b/ui/src/lib/provider-presets.ts @@ -60,6 +60,21 @@ export const PROVIDER_PRESETS: ProviderPreset[] = [ apiKeyHint: 'No API key required for local Ollama', category: 'recommended', }, + // Recommended - llama.cpp (Local) + { + id: 'llamacpp', + name: 'llama.cpp (Local)', + description: 'Local inference via llama.cpp (LLaMA models)', + baseUrl: 'http://127.0.0.1:8080', + defaultProfileName: 'llamacpp', + badge: 'Local', + featured: true, + defaultModel: 'llama3-8b', + requiresApiKey: false, + apiKeyPlaceholder: 'llamacpp', + apiKeyHint: 'Run llama.cpp server: ./server --host 0.0.0.0 --port 8080 -m model.gguf', + category: 'recommended', + }, // Alternative providers - GLM/GLMT/Kimi { id: 'glm', From 6078de78f2a7e31ec141a49c057a8b4cb1a6d601 Mon Sep 17 00:00:00 2001 From: Huynh Duc Dung Date: Thu, 5 Mar 2026 12:36:39 +0800 Subject: [PATCH 2/3] fix(ui): use preset apiKeyPlaceholder when creating profiles Fixes profile creation for local providers (llamacpp, ollama) where apiKey is not required but server validation requires a truthy value. Changes: - Set apiKey to preset.apiKeyPlaceholder when selecting a preset - Use preset.apiKeyPlaceholder as fallback in onSubmit - Ensures sentinel values (e.g., "llamacpp", "ollama") are sent Fixes user-reported error when creating llamacpp profile via dashboard. --- ui/src/components/profiles/profile-create-dialog.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ui/src/components/profiles/profile-create-dialog.tsx b/ui/src/components/profiles/profile-create-dialog.tsx index 2c3d283a..10258033 100644 --- a/ui/src/components/profiles/profile-create-dialog.tsx +++ b/ui/src/components/profiles/profile-create-dialog.tsx @@ -146,6 +146,7 @@ export function ProfileCreateDialog({ setTimeout(() => { setValue('name', openrouterPreset.defaultProfileName); setValue('baseUrl', openrouterPreset.baseUrl); + setValue('apiKey', openrouterPreset.apiKeyPlaceholder || ''); }, 0); } } @@ -159,6 +160,7 @@ export function ProfileCreateDialog({ if (preset) { setValue('name', preset.defaultProfileName); setValue('baseUrl', preset.baseUrl); + setValue('apiKey', preset.apiKeyPlaceholder || ''); if (preset.defaultModel) { setValue('model', preset.defaultModel); setValue('opusModel', preset.defaultModel); @@ -169,6 +171,7 @@ export function ProfileCreateDialog({ // Custom setValue('name', ''); setValue('baseUrl', ''); + setValue('apiKey', ''); setValue('model', ''); } }; @@ -215,8 +218,8 @@ 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 || '', + // Use provided API key, or preset placeholder, or empty string + apiKey: data.apiKey || currentPreset?.apiKeyPlaceholder || '', }; try { await createMutation.mutateAsync(finalData); From 9bcb195e7c82a85e94e9de39530f185efad60ecd Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Sat, 7 Mar 2026 16:01:22 +0700 Subject: [PATCH 3/3] test: cover llama.cpp help parity --- tests/unit/commands/help-command-parity.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/unit/commands/help-command-parity.test.ts b/tests/unit/commands/help-command-parity.test.ts index c65ee978..285e6585 100644 --- a/tests/unit/commands/help-command-parity.test.ts +++ b/tests/unit/commands/help-command-parity.test.ts @@ -27,4 +27,17 @@ describe('help command parity', () => { expect(rendered.includes('ccs cliproxy quota --provider ')).toBe(true); expect(rendered.includes('ccs llamacpp')).toBe(true); }); + + test('root help documents llama.cpp as a local API profile', async () => { + const lines: string[] = []; + console.log = (...args: unknown[]) => { + lines.push(args.map((arg) => String(arg)).join(' ')); + }; + + await handleHelpCommand(); + + const rendered = stripAnsi(lines.join('\n')); + expect(rendered.includes('ccs llamacpp')).toBe(true); + expect(rendered.includes('http://127.0.0.1:8080')).toBe(true); + }); });