Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions apps/desktop/e2e/providers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,36 @@ test('adds Mistral with its exact snapshot model, API-key field, and shared offi
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Cohere with its exact snapshot model, API-key field, and shared official mark', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await page.getByRole('button', { name: '添加服务商' }).click();

await page.getByRole('tab', { name: 'API', exact: true }).click();
await page.getByPlaceholder('搜索服务商').fill('Cohere');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="cohere"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Cohere/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('cohere');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://api.cohere.com/v2');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('command-a-plus-05-2026');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Cohere', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="cohere"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('command-a-plus-05-2026', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Tencent TokenHub with its exact snapshot model, API-key field, and shared official mark', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('button', { name: '设置' }).click();
Expand Down
26 changes: 26 additions & 0 deletions apps/desktop/src/main/__tests__/icon-governance-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const MINIMAX_BRAND_ASSET_FILE = resolve(
const XAI_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/xai.svg');
const CEREBRAS_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/cerebras.svg');
const MISTRAL_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/mistral.svg');
const COHERE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/cohere.svg');
const TOGETHER_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/together.svg');
const DEEPINFRA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/deepinfra.svg');
const FIREWORKS_BRAND_MARK_FILE = resolve(
Expand Down Expand Up @@ -387,6 +388,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'mistral':\s*return <ProviderAssetMask src=\{mistralBrandMark\} \/>/);
});

it('vendors and routes the byte-exact upstream Cohere mark through the shared asset-mask seam', async () => {
const [cohereMark, componentSrc, notices] = await Promise.all([
readFile(COHERE_BRAND_MARK_FILE),
readFile(PROVIDER_BRAND_MARKS_FILE, 'utf8'),
readFile(THIRD_PARTY_NOTICES_FILE, 'utf8'),
]);

assert.equal(
createHash('sha256').update(cohereMark).digest('hex'),
'72851dd36d6ab017f535202744765eead8f99cfb5ced77e1840bfdb70db7a85c',
'the vendored Cohere mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 cohere.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/cohere\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/cohere\.svg[\s\S]*72851dd36d6ab017f535202744765eead8f99cfb5ced77e1840bfdb70db7a85c/,
'Cohere must append provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import cohereBrandMark from '\.\.\/assets\/provider-brands\/cohere\.svg';/);
assert.match(
componentSrc,
/Cohere mark vendored byte-for-byte from Lobe Icons:[\s\S]*@lobehub\/icons-static-svg@1\.91\.0[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/cohere\.svg[\s\S]*MIT[\s\S]*72851dd36d6ab017f535202744765eead8f99cfb5ced77e1840bfdb70db7a85c/,
);
assert.match(componentSrc, /case 'cohere':\s*return <ProviderAssetMask src=\{cohereBrandMark\} \/>/);
});

it('vendors the unmodified upstream NVIDIA mark with traceable provenance', async () => {
const [marks, notices, nvidiaMark] = await Promise.all([
readFile(PROVIDER_BRAND_MARKS_FILE, 'utf8'),
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `32f4083f7a20b67ecdc7b29c0af031ada5a29c52`
- Upstream path: `packages/static-svg/icons/mistral.svg`
- SHA-256: `a06cfa54e7deff7f7544175b006b7f8a03fbc5624c44f7d553a44d07ea96e629`
- `apps/desktop/src/renderer/assets/provider-brands/cohere.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/cohere.svg`
- SHA-256: `72851dd36d6ab017f535202744765eead8f99cfb5ced77e1840bfdb70db7a85c`
- `apps/desktop/src/renderer/assets/provider-brands/fireworks.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/fireworks.svg`
Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import type { ProviderType } from '@maka/core';
import type { ReactElement } from 'react';
import cerebrasMarkUrl from '../assets/provider-brands/cerebras.svg';
import cohereBrandMark from '../assets/provider-brands/cohere.svg';
import deepinfraBrandMark from '../assets/provider-brands/deepinfra.svg';
import fireworksMarkUrl from '../assets/provider-brands/fireworks.svg';
import hunyuanBrandMark from '../assets/provider-brands/hunyuan.svg';
Expand Down Expand Up @@ -86,6 +87,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: a06cfa54e7deff7f7544175b006b7f8a03fbc5624c44f7d553a44d07ea96e629

// Cohere mark vendored byte-for-byte from Lobe Icons:
// - repository: https://github.com/lobehub/lobe-icons
// - package/version: @lobehub/icons-static-svg@1.91.0
// - commit: e4302041fbb3039608d25f9f618bd462783b875e
// - path: packages/static-svg/icons/cohere.svg
// - license: MIT (repository LICENSE)
// - SHA-256: 72851dd36d6ab017f535202744765eead8f99cfb5ced77e1840bfdb70db7a85c

// Hunyuan mark vendored byte-for-byte from Lobe Icons:
// - repository: https://github.com/lobehub/lobe-icons
// - package/version: @lobehub/icons-static-svg@1.91.0
Expand Down Expand Up @@ -301,6 +310,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
return <ProviderAssetMask src={localAiBrandMark} />;
case 'mistral':
return <ProviderAssetMask src={mistralBrandMark} />;
case 'cohere':
return <ProviderAssetMask src={cohereBrandMark} />;
case 'tencent-tokenhub':
return <ProviderAssetMask src={hunyuanBrandMark} />;
case 'tencent-coding-plan':
Expand Down
46 changes: 46 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,29 @@ describe('default session target resolver', () => {
assert.equal(target.model, 'mistral-small-2603');
});

test('resolves a Cohere API-key connection without rewriting its exact model id', async () => {
const connection = makeConnection({
slug: 'cohere',
name: 'Cohere',
providerType: 'cohere',
defaultModel: 'command-a-plus-05-2026',
});

const target = await resolveDefaultSessionTarget({
connectionStore: {
getDefault: async () => 'cohere',
get: async (slug) => slug === 'cohere' ? connection : null,
},
credentialStore: {
getSecret: async (_slug, kind) => kind === 'api_key' ? 'cohere-test-key' : null,
},
});

assert.equal(target.connection.providerType, 'cohere');
assert.equal(target.apiKey, 'cohere-test-key');
assert.equal(target.model, 'command-a-plus-05-2026');
});

test('resolves a SiliconFlow registry connection without rewriting its model id', async () => {
const connection = makeConnection({
slug: 'siliconflow',
Expand Down
21 changes: 21 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ describe('provider compatibility contract', () => {
'xai',
'cerebras',
'mistral',
'cohere',
'togetherai',
'fireworks-ai',
'nvidia',
Expand Down Expand Up @@ -92,6 +93,7 @@ describe('provider compatibility contract', () => {
'tencent-token-plan',
'stepfun-step-plan',
'deepinfra',
'cohere',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand Down Expand Up @@ -124,6 +126,7 @@ describe('provider compatibility contract', () => {
'tencent-token-plan',
'stepfun-step-plan',
'deepinfra',
'cohere',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand Down Expand Up @@ -289,6 +292,24 @@ describe('provider compatibility contract', () => {
assert.ok(!deepinfra.fallbackModels.includes('BAAI/bge-m3'));
});

it('owns Cohere native API behavior under the stable cohere id', () => {
const cohere = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>).cohere;

assert.ok(cohere, 'Cohere must be available through the shared provider registry');
assert.equal(cohere.label, 'Cohere');
assert.equal(cohere.baseUrl, 'https://api.cohere.com/v2');
assert.equal(cohere.authKind, 'api_key');
assert.equal(cohere.protocol, 'cohere');
assert.deepEqual(cohere.runtimeAdapter, { kind: 'cohere' });
assert.deepEqual(cohere.modelDiscovery, { kind: 'cohere' });
assert.equal(cohere.category, 'overseas');
assert.equal(cohere.catalogGroup, 'api');
assert.equal(cohere.modelsDevId, 'cohere');
assert.equal(cohere.fallbackModels[0], 'command-a-plus-05-2026');
assert.ok(cohere.fallbackModels.includes('command-a-reasoning-08-2025'));
assert.ok(!cohere.fallbackModels.includes('c4ai-aya-expanse-32b'));
});

it('owns the complete Together AI provider contract under the stable togetherai id', () => {
const together = PROVIDER_REGISTRY.togetherai;

Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,29 @@ describe('ModelCatalogEntry', () => {
assert.ok(!entries.some((entry) => entry.id === 'mistral-embed'));
});

it('uses Cohere tool-capable snapshot models until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'cohere',
providerType: 'cohere',
defaultModel: 'command-a-plus-05-2026',
},
});

assert.equal(entries[0]?.id, 'command-a-plus-05-2026');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.equal(entries[0]?.contextWindow, 128_000);
assert.equal(entries[0]?.maxOutputTokens, 64_000);
assert.deepEqual(entries[0]?.capabilities, {
vision: true,
reasoning: true,
functionCalling: true,
});
assert.ok(entries.some((entry) => entry.id === 'command-a-reasoning-08-2025'));
assert.ok(!entries.some((entry) => entry.id === 'c4ai-aya-expanse-32b'));
});

it('uses the checked-in Together AI snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/__tests__/model-thinking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ describe('thinkingOptionsForModel', () => {
assert.deepEqual(thinkingOptionsForModel('deepseek', 'deepseek-v4-flash'), { efforts: ['high', 'max'], toggle: true });
});

test('Cohere reasoning models expose only the native disabled override', () => {
assert.deepEqual(thinkingOptionsForModel('cohere', 'command-a-plus-05-2026'), {
toggle: true,
offBehavior: 'cohere-thinking-disabled',
});
assert.deepEqual(thinkingOptionsForModel('cohere', 'command-a-reasoning-08-2025'), {
toggle: true,
offBehavior: 'cohere-thinking-disabled',
});
});

test('claude-subscription inherits anthropic thinking options (displayMetadataOnly preserves them)', () => {
assert.deepEqual(thinkingOptionsForModel('claude-subscription', 'claude-opus-4-8'), { efforts: ['low', 'medium', 'high', 'xhigh', 'max'] });
assert.deepEqual(thinkingOptionsForModel('claude-subscription', 'claude-haiku-4-5'), { toggle: true, offBehavior: 'anthropic-thinking-disabled' });
Expand Down Expand Up @@ -148,6 +159,12 @@ describe('thinkingVariantsForModel', () => {
assert.deepEqual([...thinkingVariantsForModel('deepseek', 'deepseek-chat')], []);
});

test('Cohere exposes off for native thinking models and no invented effort levels', () => {
assert.deepEqual([...thinkingVariantsForModel('cohere', 'command-a-plus-05-2026')], ['off']);
assert.deepEqual([...thinkingVariantsForModel('cohere', 'command-a-reasoning-08-2025')], ['off']);
assert.deepEqual([...thinkingVariantsForModel('cohere', 'command-a-03-2025')], []);
});

test('Tencent Token Plan HY 3 models expose the documented low/medium/high efforts', () => {
assert.deepEqual([...thinkingVariantsForModel('tencent-token-plan', 'hy3')], ['low', 'medium', 'high']);
assert.deepEqual([...thinkingVariantsForModel('tencent-token-plan', 'hy3-preview')], ['low', 'medium', 'high']);
Expand Down
Loading
Loading