mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 02:14:32 +00:00
Merge pull request #1308 from simonsmh/feat/add-qoder-provider
feat(cliproxy): Qoder provider
This commit is contained in:
21 files changed
+236
-1
No files matched your search
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8317/api/provider/qoder",
|
||||
"ANTHROPIC_AUTH_TOKEN": "ccs-internal-managed",
|
||||
"ANTHROPIC_MODEL": "qoder/auto",
|
||||
"ANTHROPIC_DEFAULT_OPUS_MODEL": "qoder/ultimate",
|
||||
"ANTHROPIC_DEFAULT_SONNET_MODEL": "qoder/performance",
|
||||
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "qoder/efficient"
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ describe('provider-capabilities', () => {
|
||||
'gitlab',
|
||||
'codebuddy',
|
||||
'kilo',
|
||||
'qoder',
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -66,6 +67,7 @@ describe('provider-capabilities', () => {
|
||||
'cursor',
|
||||
'codebuddy',
|
||||
'kilo',
|
||||
'qoder',
|
||||
]);
|
||||
expect(getProvidersByOAuthFlow('authorization_code')).toEqual([
|
||||
'gemini',
|
||||
@@ -85,6 +87,7 @@ describe('provider-capabilities', () => {
|
||||
'kimi',
|
||||
'codebuddy',
|
||||
'kilo',
|
||||
'qoder',
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -306,6 +306,13 @@ export const OAUTH_CONFIGS: Record<CLIProxyProvider, ProviderOAuthConfig> = {
|
||||
scopes: [],
|
||||
authFlag: '--kilo-login',
|
||||
},
|
||||
qoder: {
|
||||
provider: 'qoder',
|
||||
displayName: 'Qoder',
|
||||
authUrl: 'https://qoder.com/device/selectAccounts',
|
||||
scopes: [],
|
||||
authFlag: '--qoder-login',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ describe('base-config-loader new providers', () => {
|
||||
['gitlab', '/api/provider/gitlab', 'gitlab-duo'],
|
||||
['codebuddy', '/api/provider/codebuddy', 'auto'],
|
||||
['kilo', '/api/provider/kilo', 'kilo/auto'],
|
||||
['qoder', '/api/provider/qoder', 'qoder/auto'],
|
||||
] as const)('loads base settings for %s', (provider, baseUrlPath, defaultModel) => {
|
||||
const config = loadBaseConfig(provider);
|
||||
|
||||
|
||||
@@ -265,6 +265,68 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
||||
},
|
||||
],
|
||||
},
|
||||
qoder: {
|
||||
provider: 'qoder',
|
||||
displayName: 'Qoder',
|
||||
defaultModel: 'qoder/auto',
|
||||
models: [
|
||||
{
|
||||
id: 'qoder/auto',
|
||||
name: 'Qoder Auto',
|
||||
description: 'Auto selects the best Qoder model for your prompt',
|
||||
},
|
||||
{
|
||||
id: 'qoder/ultimate',
|
||||
name: 'Qoder Ultimate',
|
||||
description: 'Highest quality Qoder tier',
|
||||
},
|
||||
{
|
||||
id: 'qoder/performance',
|
||||
name: 'Qoder Performance',
|
||||
description: 'Balanced quality and speed',
|
||||
},
|
||||
{
|
||||
id: 'qoder/efficient',
|
||||
name: 'Qoder Efficient',
|
||||
description: 'Cost-efficient Qoder tier',
|
||||
},
|
||||
{
|
||||
id: 'qoder/lite',
|
||||
name: 'Qoder Lite',
|
||||
description: 'Fastest and most affordable Qoder tier',
|
||||
},
|
||||
{
|
||||
id: 'qoder/qmodel',
|
||||
name: 'Qwen 3.6 Plus (via Qoder)',
|
||||
description: 'Qwen 3.6 Plus frontier model',
|
||||
},
|
||||
{
|
||||
id: 'qoder/dmodel',
|
||||
name: 'DeepSeek V4 Pro (via Qoder)',
|
||||
description: 'DeepSeek V4 Pro frontier model',
|
||||
},
|
||||
{
|
||||
id: 'qoder/dfmodel',
|
||||
name: 'DeepSeek V4 Flash (via Qoder)',
|
||||
description: 'DeepSeek V4 Flash frontier model',
|
||||
},
|
||||
{
|
||||
id: 'qoder/gm51model',
|
||||
name: 'GLM 5.1 (via Qoder)',
|
||||
description: 'GLM 5.1 frontier model',
|
||||
},
|
||||
{
|
||||
id: 'qoder/kmodel',
|
||||
name: 'Kimi K2.6 (via Qoder)',
|
||||
description: 'Kimi K2.6 frontier model',
|
||||
},
|
||||
{
|
||||
id: 'qoder/mmodel',
|
||||
name: 'MiniMax M2.7 (via Qoder)',
|
||||
description: 'MiniMax M2.7 frontier model',
|
||||
},
|
||||
],
|
||||
},
|
||||
kimi: {
|
||||
provider: 'kimi',
|
||||
displayName: 'Kimi (Moonshot)',
|
||||
|
||||
@@ -182,6 +182,18 @@ export const PROVIDER_CAPABILITIES: Record<CLIProxyProvider, ProviderCapabilitie
|
||||
tokenTypeValues: ['kilo'],
|
||||
aliases: [],
|
||||
},
|
||||
qoder: {
|
||||
displayName: 'Qoder',
|
||||
description: 'Qoder AI coding assistant',
|
||||
oauthFlow: 'device_code',
|
||||
callbackPort: null,
|
||||
callbackProviderName: 'qoder',
|
||||
authUrlProviderName: 'qoder',
|
||||
refreshOwnership: 'unsupported',
|
||||
authFilePrefixes: ['qoder-'],
|
||||
tokenTypeValues: ['qoder'],
|
||||
aliases: [],
|
||||
},
|
||||
};
|
||||
|
||||
export const CLIPROXY_PROVIDER_IDS = Object.freeze(
|
||||
|
||||
@@ -38,6 +38,7 @@ const CHANNEL_TO_PROVIDER: Record<string, CLIProxyProvider> = {
|
||||
kimi: 'kimi',
|
||||
kiro: 'kiro',
|
||||
'github-copilot': 'ghcp',
|
||||
qoder: 'qoder',
|
||||
};
|
||||
|
||||
/** CCS provider → channel name mapping (reverse) */
|
||||
|
||||
@@ -16,7 +16,8 @@ export type CLIProxyProvider =
|
||||
| 'cursor'
|
||||
| 'gitlab'
|
||||
| 'codebuddy'
|
||||
| 'kilo';
|
||||
| 'kilo'
|
||||
| 'qoder';
|
||||
|
||||
/** CLIProxy backend selection */
|
||||
export type CLIProxyBackend = 'original' | 'plus';
|
||||
@@ -32,6 +33,7 @@ export const PLUS_ONLY_PROVIDERS: CLIProxyProvider[] = [
|
||||
'gitlab',
|
||||
'codebuddy',
|
||||
'kilo',
|
||||
'qoder',
|
||||
];
|
||||
|
||||
/** Model mapping for each provider */
|
||||
|
||||
@@ -205,6 +205,7 @@ export const BUILTIN_PROVIDER_SHORTCUTS: readonly ShortcutEntry[] = CLIPROXY_PRO
|
||||
gitlab: 'GitLab Duo via CLIProxy OAuth',
|
||||
codebuddy: 'CodeBuddy via CLIProxy OAuth',
|
||||
kilo: 'Kilo AI via CLIProxy OAuth',
|
||||
qoder: 'Qoder AI via CLIProxy OAuth',
|
||||
}[name] || 'CLIProxy OAuth provider',
|
||||
})
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@ export const RESERVED_PROFILE_NAMES = [
|
||||
'gitlab',
|
||||
'codebuddy',
|
||||
'kilo',
|
||||
'qoder',
|
||||
// Copilot API (GitHub Copilot proxy)
|
||||
'copilot',
|
||||
// Cursor IDE (Cursor proxy daemon)
|
||||
|
||||
@@ -57,6 +57,7 @@ const PROVIDER_OWNER_HINTS: Record<string, string[]> = {
|
||||
kimi: ['kimi', 'moonshot'],
|
||||
kiro: ['kiro', 'aws'],
|
||||
ghcp: ['github', 'copilot'],
|
||||
qoder: ['qoder'],
|
||||
};
|
||||
|
||||
function normalize(value: string | null | undefined): string {
|
||||
|
||||
@@ -97,6 +97,7 @@ describe('ProfileDetector', () => {
|
||||
expect(detector.detectProfileType('gitlab').provider).toBe('gitlab');
|
||||
expect(detector.detectProfileType('codebuddy').provider).toBe('codebuddy');
|
||||
expect(detector.detectProfileType('kilo').provider).toBe('kilo');
|
||||
expect(detector.detectProfileType('qoder').provider).toBe('qoder');
|
||||
});
|
||||
|
||||
it('should detect settings-based profile from unified config', () => {
|
||||
|
||||
@@ -85,6 +85,7 @@ describe('completion backend', () => {
|
||||
expect(values).toContain('gitlab');
|
||||
expect(values).toContain('codebuddy');
|
||||
expect(values).toContain('kilo');
|
||||
expect(values).toContain('qoder');
|
||||
expect(values).toContain('localglm');
|
||||
expect(values).toContain('work');
|
||||
expect(values).toContain('my-codex');
|
||||
|
||||
@@ -61,6 +61,7 @@ describe('help command parity', () => {
|
||||
expect(rendered.includes('gitlab')).toBe(true);
|
||||
expect(rendered.includes('codebuddy')).toBe(true);
|
||||
expect(rendered.includes('kilo')).toBe(true);
|
||||
expect(rendered.includes('qoder')).toBe(true);
|
||||
expect(rendered.includes('--gitlab-token-login')).toBe(true);
|
||||
expect(rendered.includes('--token-login')).toBe(true);
|
||||
expect(rendered.includes('--gitlab-url <url>')).toBe(true);
|
||||
|
||||
@@ -18,6 +18,7 @@ describe('cliproxy-auth-routes start-url guard', () => {
|
||||
"Provider 'codebuddy' uses Device Code flow"
|
||||
);
|
||||
expect(getStartUrlUnsupportedReason('kilo')).toContain("Provider 'kilo' uses Device Code flow");
|
||||
expect(getStartUrlUnsupportedReason('qoder')).toContain("Provider 'qoder' uses Device Code flow");
|
||||
});
|
||||
|
||||
it('allows Cursor browser URL auth on start-url', () => {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="180" height="180" viewBox="0 0 180 180"><defs><clipPath id="master_svg0_381_5952"><rect x="0" y="0" width="180" height="180" rx="40"/></clipPath><clipPath id="master_svg1_381_5952/255_01913"><rect x="18" y="18" width="144" height="144" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_381_5952)"><rect x="0" y="0" width="180" height="180" rx="40" fill="#111113" fill-opacity="1"/><g clip-path="url(#master_svg1_381_5952/255_01913)"><g><path d="M147.59971253967285,101.41062772064208L147.59971253967285,81.42072772064209C147.59971253967285,70.06382772064208,142.65821253967283,60.949927720642094,134.05571253967287,56.41322772064209L89.62531253967285,32.98532772064209L89.40251253967284,33.41064472064209L89.17971253967285,33.83596072064209C97.45821253967284,38.20051772064209,102.20761253967285,47.00562772064209,102.20761253967285,57.992927720642086L102.20761253967285,77.98282772064209C102.20761253967285,78.58532772064208,102.19241253967286,79.21822772064209,102.16201253967284,79.8511277206421C102.15691253967285,79.9726277206421,102.14681253967285,80.0942277206421,102.13671253967286,80.22072772064209L102.11641253967285,80.51952772064209C102.09111253967285,80.9195277206421,102.06581253967286,81.3245277206421,102.02531253967285,81.72452772064209C102.01011253967286,81.88662772064208,101.98981253967285,82.05372772064209,101.96961253967285,82.21572772064209L101.92401253967284,82.59542772064209C101.88351253967285,82.92962772064209,101.84811253967285,83.2587277206421,101.79741253967285,83.59292772064208C101.77211253967286,83.78022772064209,101.74171253967285,83.9625277206421,101.71141253967285,84.1499277206421L101.66581253967286,84.4385277206421C101.61011253967285,84.77772772064209,101.55441253967285,85.11692772064208,101.48861253967286,85.45622772064209C101.39241253967285,85.9625277206421,101.29111253967285,86.46382772064209,101.17971253967285,86.9650277206421L101.14431253967285,87.11192772064209C101.03291253967285,87.59802772064208,100.91141253967285,88.07902772064209,100.77971253967286,88.5600277206421L100.66331253967286,88.98532772064209C100.52661253967285,89.47142772064208,100.38481253967285,89.95742772064209,100.23291253967285,90.4435277206421L100.09621253967285,90.86382772064209C99.92401253967284,91.39542772064209,99.74171253967285,91.92712772064209,99.54931253967285,92.45372772064209C99.49871253967285,92.59542772064209,99.44301253967285,92.7321277206421,99.38731253967285,92.87392772064209L99.30121253967286,93.10182772064209C99.14431253967285,93.5068277206421,98.98731253967284,93.9170277206421,98.82021253967285,94.3220277206421C98.72401253967286,94.5600277206421,98.61771253967285,94.7980277206421,98.51641253967284,95.03592772064209L98.48101253967286,95.12202772064208C98.34931253967285,95.43092772064209,98.21261253967285,95.7397277206421,98.07081253967286,96.04352772064209C97.94931253967286,96.31702772064209,97.81771253967285,96.58532772064208,97.69111253967284,96.8537277206421C97.54431253967286,97.1575277206421,97.40251253967284,97.45622772064209,97.25061253967286,97.75492772064209C97.10881253967285,98.0334277206421,96.96701253967285,98.30682772064209,96.82021253967285,98.58022772064209C96.67841253967285,98.84862772064209,96.53161253967285,99.1220277206421,96.38481253967285,99.3904277206421C96.23291253967285,99.66382772064209,96.07591253967286,99.93722772064208,95.91891253967285,100.2106277206421C95.76701253967286,100.4739277206421,95.61521253967285,100.7423277206421,95.45311253967284,101.00052772064208C95.29111253967285,101.27392772064209,95.12401253967286,101.54232772064209,94.95191253967286,101.81062772064209C94.78981253967285,102.0689277206421,94.63291253967284,102.32202772064208,94.46581253967285,102.57522772064209C94.29361253967285,102.84352772064209,94.11641253967285,103.10182772064209,93.91391253967285,103.40562772064209C93.75191253967284,103.64352772064208,93.58981253967285,103.88152772064208,93.42781253967286,104.11442772064208C93.25571253967286,104.3575277206421,93.08351253967285,104.59542772064209,92.88101253967285,104.87392772064209C92.69361253967284,105.13212772064209,92.50631253967285,105.3853277206421,92.31391253967286,105.63852772064209C92.12651253967286,105.8866277206421,91.93921253967285,106.1246277206421,91.74681253967285,106.36762772064209C91.54931253967285,106.61572772064208,91.35191253967285,106.86892772064209,91.15441253967285,107.11192772064209C90.98221253967284,107.32462772064208,90.80501253967284,107.53222772064208,90.62781253967285,107.7397277206421L90.59241253967285,107.78032772064209C90.35951253967285,108.0587277206421,90.12151253967285,108.33212772064209,89.87841253967285,108.60562772064209C89.68601253967284,108.82332772064208,89.49361253967285,109.0360277206421,89.30121253967286,109.24862772064209C89.05821253967285,109.51702772064209,88.81521253967284,109.77522772064209,88.56711253967285,110.0385277206421C88.37971253967285,110.2359277206421,88.18731253967286,110.4Line truncated
|
||||
|
After Width: | Height: | Size: 38 KiB |
@@ -93,6 +93,7 @@ export function ProviderEditor({
|
||||
qwen: ['alibaba', 'qwen'],
|
||||
iflow: ['iflow'],
|
||||
kilo: ['kilo'],
|
||||
qoder: ['qoder'],
|
||||
kiro: ['kiro', 'aws'],
|
||||
ghcp: ['github', 'copilot'],
|
||||
kimi: ['kimi', 'moonshot'],
|
||||
|
||||
@@ -25,6 +25,7 @@ const WIZARD_PROVIDER_ORDER: CLIProxyProvider[] = [
|
||||
'iflow',
|
||||
'kilo',
|
||||
'kiro',
|
||||
'qoder',
|
||||
];
|
||||
|
||||
export const PROVIDERS: ProviderOption[] = WIZARD_PROVIDER_ORDER.map((id) => ({
|
||||
|
||||
@@ -454,6 +454,128 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
||||
},
|
||||
],
|
||||
},
|
||||
qoder: {
|
||||
provider: 'qoder',
|
||||
displayName: 'Qoder',
|
||||
defaultModel: 'qoder/auto',
|
||||
models: [
|
||||
{
|
||||
id: 'qoder/auto',
|
||||
name: 'Qoder Auto',
|
||||
description: 'Auto selects the best Qoder model for your prompt',
|
||||
presetMapping: {
|
||||
default: 'qoder/auto',
|
||||
opus: 'qoder/auto',
|
||||
sonnet: 'qoder/auto',
|
||||
haiku: 'qoder/auto',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/ultimate',
|
||||
name: 'Qoder Ultimate',
|
||||
description: 'Highest quality Qoder tier',
|
||||
presetMapping: {
|
||||
default: 'qoder/ultimate',
|
||||
opus: 'qoder/ultimate',
|
||||
sonnet: 'qoder/ultimate',
|
||||
haiku: 'qoder/ultimate',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/performance',
|
||||
name: 'Qoder Performance',
|
||||
description: 'Balanced quality and speed',
|
||||
presetMapping: {
|
||||
default: 'qoder/performance',
|
||||
opus: 'qoder/performance',
|
||||
sonnet: 'qoder/performance',
|
||||
haiku: 'qoder/performance',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/efficient',
|
||||
name: 'Qoder Efficient',
|
||||
description: 'Cost-efficient Qoder tier',
|
||||
presetMapping: {
|
||||
default: 'qoder/efficient',
|
||||
opus: 'qoder/efficient',
|
||||
sonnet: 'qoder/efficient',
|
||||
haiku: 'qoder/efficient',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/lite',
|
||||
name: 'Qoder Lite',
|
||||
description: 'Fastest and most affordable Qoder tier',
|
||||
presetMapping: {
|
||||
default: 'qoder/lite',
|
||||
opus: 'qoder/lite',
|
||||
sonnet: 'qoder/lite',
|
||||
haiku: 'qoder/lite',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/qmodel',
|
||||
name: 'Qwen 3.6 Plus (via Qoder)',
|
||||
description: 'Qwen 3.6 Plus frontier model',
|
||||
presetMapping: {
|
||||
default: 'qoder/qmodel',
|
||||
opus: 'qoder/qmodel',
|
||||
sonnet: 'qoder/qmodel',
|
||||
haiku: 'qoder/qmodel',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/dmodel',
|
||||
name: 'DeepSeek V4 Pro (via Qoder)',
|
||||
description: 'DeepSeek V4 Pro frontier model',
|
||||
presetMapping: {
|
||||
default: 'qoder/dmodel',
|
||||
opus: 'qoder/dmodel',
|
||||
sonnet: 'qoder/dmodel',
|
||||
haiku: 'qoder/dfmodel',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/dfmodel',
|
||||
name: 'DeepSeek V4 Flash (via Qoder)',
|
||||
description: 'DeepSeek V4 Flash frontier model',
|
||||
},
|
||||
{
|
||||
id: 'qoder/gm51model',
|
||||
name: 'GLM 5.1 (via Qoder)',
|
||||
description: 'GLM 5.1 frontier model',
|
||||
presetMapping: {
|
||||
default: 'qoder/gm51model',
|
||||
opus: 'qoder/gm51model',
|
||||
sonnet: 'qoder/gm51model',
|
||||
haiku: 'qoder/gm51model',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/kmodel',
|
||||
name: 'Kimi K2.6 (via Qoder)',
|
||||
description: 'Kimi K2.6 frontier model',
|
||||
presetMapping: {
|
||||
default: 'qoder/kmodel',
|
||||
opus: 'qoder/kmodel',
|
||||
sonnet: 'qoder/kmodel',
|
||||
haiku: 'qoder/kmodel',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'qoder/mmodel',
|
||||
name: 'MiniMax M2.7 (via Qoder)',
|
||||
description: 'MiniMax M2.7 frontier model',
|
||||
presetMapping: {
|
||||
default: 'qoder/mmodel',
|
||||
opus: 'qoder/mmodel',
|
||||
sonnet: 'qoder/mmodel',
|
||||
haiku: 'qoder/mmodel',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
kimi: {
|
||||
provider: 'kimi',
|
||||
displayName: 'Kimi (Moonshot)',
|
||||
|
||||
@@ -105,6 +105,7 @@ export const PROVIDER_ASSETS: Partial<Record<ProviderVisualId, string>> = {
|
||||
gitlab: '/assets/providers/gitlab.svg',
|
||||
codebuddy: '/assets/providers/codebuddy.png',
|
||||
kilo: '/assets/providers/kilo.png',
|
||||
qoder: '/assets/providers/qoder.svg',
|
||||
ghcp: '/assets/providers/copilot.svg',
|
||||
claude: '/assets/providers/claude.svg',
|
||||
kimi: '/assets/providers/kimi.svg',
|
||||
@@ -135,6 +136,7 @@ export const PROVIDER_FALLBACK_VISUALS: Record<ProviderVisualId, ProviderFallbac
|
||||
gitlab: { textClass: 'text-orange-600', letter: 'G' },
|
||||
codebuddy: { textClass: 'text-blue-600', letter: 'B' },
|
||||
kilo: { textClass: 'text-rose-600', letter: 'K' },
|
||||
qoder: { textClass: 'text-amber-600', letter: 'Q' },
|
||||
ghcp: { textClass: 'text-green-600', letter: 'C' },
|
||||
kimi: { textClass: 'text-orange-500', letter: 'K' },
|
||||
openai: { textClass: 'text-slate-900', letter: 'O' },
|
||||
@@ -272,6 +274,7 @@ export const PROVIDER_COLORS: Record<string, string> = {
|
||||
gitlab: '#FC6D26',
|
||||
codebuddy: '#2563EB',
|
||||
kilo: '#E11D48',
|
||||
qoder: '#D97706',
|
||||
ghcp: '#43aa8b',
|
||||
claude: '#D97757',
|
||||
kimi: '#FF6B35',
|
||||
|
||||
@@ -68,6 +68,7 @@ describe('provider presentation metadata', () => {
|
||||
'gitlab',
|
||||
'codebuddy',
|
||||
'kilo',
|
||||
'qoder',
|
||||
]);
|
||||
expect(getProviderSection('gitlab')?.id).toBe('plus-extra');
|
||||
expect(getProviderSection('gemini')?.id).toBe('core');
|
||||
@@ -128,6 +129,7 @@ describe('provider presentation metadata', () => {
|
||||
'/assets/providers/codebuddy.png',
|
||||
],
|
||||
['kilo', 'Kilo AI', 'Kilo AI coding assistant', '/assets/providers/kilo.png'],
|
||||
['qoder', 'Qoder', 'Qoder AI coding assistant', '/assets/providers/qoder.svg'],
|
||||
])('recognizes %s across dashboard display helpers', (provider, name, description, asset) => {
|
||||
expect(getProviderDisplayName(provider)).toBe(name);
|
||||
expect(getProviderDescription(provider)).toBe(description);
|
||||
|
||||
Reference in new issue
Block a user