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 numberDiff line numberDiff line change
Expand Up@@ -330,6 +330,36 @@ for (const stepfun of [
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Volcengine Ark China 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('Volcengine');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="volcengine-ark"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Volcengine Ark \(China\)/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('volcengine-ark');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://ark.cn-beijing.volces.com/api/v3');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('doubao-seed-2-0-pro-260215');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Volcengine Ark (China)', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="volcengine-ark"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('doubao-seed-2-0-pro-260215', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('restores keyboard focus across provider child pages', 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 numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ const NVIDIA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/ass
const TENCENT_HUNYUAN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/hunyuan.svg');
const TENCENT_CLOUD_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/tencentcloud.svg');
const STEPFUN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/stepfun.svg');
const VOLCENGINE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/volcengine.svg');
const DESKTOP_PACKAGE_FILE = resolve(REPO_ROOT, 'apps/desktop/package.json');
const THIRD_PARTY_NOTICES_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt');
const ONBOARDING_HERO_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/OnboardingHero.tsx');
Expand DownExpand Up@@ -430,6 +431,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'stepfun':\s*return <ProviderAssetMask src=\{stepfunBrandMark\} \/>/);
});

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

assert.equal(
createHash('sha256').update(volcengineMark).digest('hex'),
'f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33',
'the vendored Volcengine mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 volcengine.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/volcengine\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/volcengine\.svg[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
'Volcengine must append byte-exact provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import volcengineBrandMark from '\.\.\/assets\/provider-brands\/volcengine\.svg';/);
assert.match(
componentSrc,
/Volcengine 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\/volcengine\.svg[\s\S]*MIT[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
);
assert.match(componentSrc, /case 'volcengine-ark':\s*return <ProviderAssetMask src=\{volcengineBrandMark\} \/>/);
});

it('vendors and routes the byte-exact Tencent Cloud mark for Tencent Coding Plan', async () => {
const [tencentCloudMark, componentSrc, notices] = await Promise.all([
readFile(TENCENT_CLOUD_BRAND_MARK_FILE),
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 numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/stepfun.svg`
- SHA-256: `f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c`
- `apps/desktop/src/renderer/assets/provider-brands/volcengine.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/volcengine.svg`
- SHA-256: `f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33`

MIT License

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import mistralBrandMark from '../assets/provider-brands/mistral.svg';
import togetherBrandMark from '../assets/provider-brands/together.svg';
import nvidiaMarkUrl from '../assets/provider-brands/nvidia.svg';
import stepfunBrandMark from '../assets/provider-brands/stepfun.svg';
import volcengineBrandMark from '../assets/provider-brands/volcengine.svg';
import xaiMarkUrl from '../assets/provider-brands/xai.svg';

// Real xAI/Grok mark vendored byte-for-byte from Lobe Icons:
Expand DownExpand Up@@ -92,6 +93,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c

// Volcengine 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/volcengine.svg
// - license: MIT (repository LICENSE)
// - SHA-256: f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33

function ProviderAssetMask({ src }: { src: string }): ReactElement {
const mask = `url("${src}")`;
return <span className="providerAssetMask" style={{ maskImage: mask, WebkitMaskImage: mask }} aria-hidden="true" />;
Expand DownExpand Up@@ -278,6 +287,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
case 'stepfun-ai':
case 'stepfun':
return <ProviderAssetMask src={stepfunBrandMark} />;
case 'volcengine-ark':
return <ProviderAssetMask src={volcengineBrandMark} />;
default:
return <GenericProviderMark />;
}
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,30 @@ import type { LlmConnection } from '@maka/core/llm-connections';
import { listReadyModelChoices, resolveDefaultSessionTarget } from '../connection-target.js';

describe('default session target resolver', () => {
test('resolves Volcengine Ark credentials without rewriting the snapshot model id', async () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const connection = makeConnection({
slug: 'volcengine-ark',
name: 'Volcengine Ark (China)',
providerType: 'volcengine-ark',
defaultModel: modelId,
});

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

assert.equal(target.connection.providerType, 'volcengine-ark');
assert.equal(target.apiKey, 'ark-test-key');
assert.equal(target.model, modelId);
});

test('resolves Fireworks credentials without rewriting the exact model path', async () => {
const connection = makeConnection({
slug: 'fireworks-ai',
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ describe('provider compatibility contract', () => {
'tencent-tokenhub',
'stepfun',
'stepfun-ai',
'volcengine-ark',
'ollama',
'lm-studio',
'openai-compatible',
Expand DownExpand Up@@ -80,6 +81,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand All@@ -106,6 +108,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand DownExpand Up@@ -371,6 +374,23 @@ describe('provider compatibility contract', () => {
'step-3.5-flash',
]);
});

it('owns Volcengine Ark China direct API behavior under the stable volcengine-ark id', () => {
const ark = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>)['volcengine-ark'];

assert.ok(ark, 'Volcengine Ark China direct API must have its own persisted provider id');
assert.equal(ark.label, 'Volcengine Ark (China)');
assert.equal(ark.baseUrl, 'https://ark.cn-beijing.volces.com/api/v3');
assert.equal(ark.authKind, 'api_key');
assert.equal(ark.protocol, 'openai');
assert.deepEqual(ark.runtimeAdapter, { kind: 'openai-compatible', name: 'provider' });
assert.deepEqual(ark.modelDiscovery, { kind: 'fallback' });
assert.equal(ark.category, 'domestic');
assert.equal(ark.catalogGroup, 'api');
assert.equal(ark.signupUrl, 'https://console.volcengine.com/ark/region:ark+cn-beijing/model');
assert.equal(ark.modelsDevId, undefined);
assert.deepEqual(ark.fallbackModels, ['doubao-seed-2-0-pro-260215']);
});
});

describe('validateConnectionBaseUrl (PR-UI-IPC-1, @kenji msg 35260e29)', () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,25 @@ describe('ModelCatalogEntry', () => {
});
});

it('uses the official Volcengine Ark snapshot without inventing live model discovery', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'volcengine-ark',
providerType: 'volcengine-ark',
defaultModel: 'doubao-seed-2-0-pro-260215',
},
});

assert.deepEqual(entries.map((entry) => entry.id), ['doubao-seed-2-0-pro-260215']);
assert.equal(entries[0]?.displayName, 'Doubao Seed 2.0 Pro');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.deepEqual(entries[0]?.capabilities, {
reasoning: true,
functionCalling: true,
});
});

it('uses the checked-in StepFun China snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/provider-auth.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,19 @@ describe('ProviderAuth contract', () => {
expect(contract.actionAvailability.fetch_models).toBe('available');
});

test('Volcengine Ark China uses the shared API-key credential and snapshot-model flow', () => {
const contract = deriveProviderAuthContract({
providerType: 'volcengine-ark',
hasSecret: true,
});

expect(contract.providerType).toBe('volcengine-ark');
expect(contract.setupMode).toBe('api_key');
expect(contract.requiresSecret).toBe(true);
expect(contract.actionAvailability.test_credentials).toBe('available');
expect(contract.actionAvailability.fetch_models).toBe('hidden');
});

test('Together AI uses the shared API-key credential flow under its stable provider id', () => {
const contract = deriveProviderAuthContract({
providerType: 'togetherai',
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/model-metadata.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,6 +118,19 @@ const STATIC_MODEL_METADATA: Partial<Record<ProviderType, Record<string, ModelMe
'tencent-coding-plan': {
'kimi-k2.5': { capabilities: { vision: false } },
},
'volcengine-ark': {
'doubao-seed-2-0-pro-260215': {
displayName: 'Doubao Seed 2.0 Pro',
lifecycle: 'active',
docsUrl: 'https://www.volcengine.com/docs/82379',
capabilities: { reasoning: true, functionCalling: true },
thinkingOptions: {
efforts: ['minimal', 'low', 'medium', 'high'],
toggle: true,
offBehavior: 'volcengine-thinking-disabled',
},
},
},
deepseek: {
'deepseek-v4-flash': { thinkingOptions: { efforts: ['high', 'max'], toggle: true } },
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/model-thinking.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ export function isThinkingLevel(value: unknown): value is ThinkingLevel {
*/
export type ThinkingOffBehavior =
| 'anthropic-thinking-disabled'
| 'google-thinking-budget-zero';
| 'google-thinking-budget-zero'
| 'volcengine-thinking-disabled';

export interface ThinkingOptions {
readonly efforts?: readonly string[];
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/provider-registry.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -580,6 +580,24 @@ const providerRegistry = {
readyOrder: 24,
catalogOrder: 24,
},
'volcengine-ark': {
label: 'Volcengine Ark (China)',
description: 'Volcengine Ark direct API for reasoning and tool-use agents in China.',
baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
authKind: 'api_key',
backendKind: 'ai-sdk',
fallbackModels: ['doubao-seed-2-0-pro-260215'],
status: 'ready',
protocol: 'openai',
runtimeAdapter: { kind: 'openai-compatible', name: 'provider' },
modelDiscovery: { kind: 'fallback' },
category: 'domestic',
catalogGroup: 'api',
catalogBadge: 'API',
signupUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/model',
readyOrder: 25,
catalogOrder: 25,
},
ollama: {
label: 'Ollama',
description: 'Local models from Ollama on localhost.',
Expand Down
27 changes: 27 additions & 0 deletions packages/headless/src/__tests__/harbor-cell.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2362,6 +2362,33 @@ setTimeout(() => {
assert.equal(missing.apiKey, '');
});

test('resolves Volcengine Ark only from its official direct API credential env', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const resolved = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: {
ARK_API_KEY: 'ark-key',
ARK_BASE_URL: 'https://ark.cn-shanghai.volces.com/api/v3',
OPENAI_API_KEY: 'openai-key',
},
ts: 1,
});

assert.equal(resolved.apiKey, 'ark-key');
assert.equal(resolved.connection.providerType, 'volcengine-ark');
assert.equal(resolved.connection.defaultModel, modelId);
assert.equal(resolved.connection.baseUrl, 'https://ark.cn-shanghai.volces.com/api/v3');

const missing = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: { OPENAI_API_KEY: 'must-not-cross-provider-boundary' },
ts: 1,
});
assert.equal(missing.apiKey, '');
});

test('resolves Cerebras only from Cerebras credential env without rewriting the model id', () => {
const resolved = resolveHarborCellAiSdkEnv({
provider: 'cerebras',
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/__tests__/provider-env.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,3 +94,11 @@ test('StepFun Global keeps direct API credentials separate from China and plan i
baseUrls: ['STEPFUN_AI_BASE_URL'],
});
});

test('Volcengine Ark direct API uses its official credential namespace', () => {
assert.deepEqual(providerCredentialEnv('volcengine-ark'), {
apiKeys: ['ARK_API_KEY'],
apiKeyFile: 'ARK_API_KEY_FILE',
baseUrls: ['ARK_BASE_URL'],
});
});
1 change: 1 addition & 0 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@ const PROVIDER_CREDENTIAL_ENV = {
'tencent-tokenhub': env('TENCENT_TOKENHUB', ['TENCENT_TOKENHUB_BASE_URL']),
stepfun: env('STEPFUN', ['STEPFUN_BASE_URL']),
'stepfun-ai': env('STEPFUN_AI', ['STEPFUN_AI_BASE_URL']),
'volcengine-ark': env('ARK', ['ARK_BASE_URL']),
'openai-compatible': env('OPENAI', ['OPENAI_BASE_URL']),
'claude-subscription': env('ANTHROPIC'),
} satisfies Partial<Record<ProviderType, ProviderCredentialEnv>>;
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime/src/__tests__/model-factory-thinking.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,6 +71,20 @@ describe('buildProviderOptions: thinking level', () => {
assert.deepEqual(buildProviderOptions(conn('deepseek'), 'deepseek-chat', 'high'), {});
});

test('Volcengine Ark sends its official thinking object and optional reasoning effort', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
assert.deepEqual([...thinkingVariantsForModel('volcengine-ark', modelId)], ['off', 'minimal', 'low', 'medium', 'high']);
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId), {
'volcengine-ark': { thinking: { type: 'enabled' } },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'high'), {
'volcengine-ark': { thinking: { type: 'enabled' }, reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'off'), {
'volcengine-ark': { thinking: { type: 'disabled' } },
});
});

test('a level the model does not support is dropped (defensive)', () => {
assert.deepEqual(buildProviderOptions(conn('openai'), 'gpt-4o', 'high'), { openai: {} });
assert.deepEqual(buildProviderOptions(conn('anthropic'), 'claude-haiku-4-5', 'max'), { anthropic: {} });
Expand DownExpand Up@@ -115,6 +129,7 @@ describe('buildProviderOptions: resolver/options drift guard', () => {
{ providerType: 'google', model: 'gemini-3.5-flash' },
{ providerType: 'deepseek', model: 'deepseek-v4-flash' },
{ providerType: 'zai-coding-plan', model: 'glm-5.2', slug: 'zai-coding-plan' },
{ providerType: 'volcengine-ark', model: 'doubao-seed-2-0-pro-260215' },
];
for (const { providerType, model, slug } of cases) {
test(`every effort level for ${providerType}/${model} maps to a non-empty fragment`, () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
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 numberDiff line numberDiff line change
Expand Up@@ -330,6 +330,36 @@ for (const stepfun of [
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Volcengine Ark China 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('Volcengine');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="volcengine-ark"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Volcengine Ark \(China\)/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('volcengine-ark');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://ark.cn-beijing.volces.com/api/v3');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('doubao-seed-2-0-pro-260215');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Volcengine Ark (China)', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="volcengine-ark"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('doubao-seed-2-0-pro-260215', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('restores keyboard focus across provider child pages', 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 numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ const NVIDIA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/ass
const TENCENT_HUNYUAN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/hunyuan.svg');
const TENCENT_CLOUD_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/tencentcloud.svg');
const STEPFUN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/stepfun.svg');
const VOLCENGINE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/volcengine.svg');
const DESKTOP_PACKAGE_FILE = resolve(REPO_ROOT, 'apps/desktop/package.json');
const THIRD_PARTY_NOTICES_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt');
const ONBOARDING_HERO_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/OnboardingHero.tsx');
Expand DownExpand Up@@ -430,6 +431,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'stepfun':\s*return <ProviderAssetMask src=\{stepfunBrandMark\} \/>/);
});

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

assert.equal(
createHash('sha256').update(volcengineMark).digest('hex'),
'f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33',
'the vendored Volcengine mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 volcengine.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/volcengine\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/volcengine\.svg[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
'Volcengine must append byte-exact provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import volcengineBrandMark from '\.\.\/assets\/provider-brands\/volcengine\.svg';/);
assert.match(
componentSrc,
/Volcengine 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\/volcengine\.svg[\s\S]*MIT[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
);
assert.match(componentSrc, /case 'volcengine-ark':\s*return <ProviderAssetMask src=\{volcengineBrandMark\} \/>/);
});

it('vendors and routes the byte-exact Tencent Cloud mark for Tencent Coding Plan', async () => {
const [tencentCloudMark, componentSrc, notices] = await Promise.all([
readFile(TENCENT_CLOUD_BRAND_MARK_FILE),
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 numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/stepfun.svg`
- SHA-256: `f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c`
- `apps/desktop/src/renderer/assets/provider-brands/volcengine.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/volcengine.svg`
- SHA-256: `f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33`

MIT License

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import mistralBrandMark from '../assets/provider-brands/mistral.svg';
import togetherBrandMark from '../assets/provider-brands/together.svg';
import nvidiaMarkUrl from '../assets/provider-brands/nvidia.svg';
import stepfunBrandMark from '../assets/provider-brands/stepfun.svg';
import volcengineBrandMark from '../assets/provider-brands/volcengine.svg';
import xaiMarkUrl from '../assets/provider-brands/xai.svg';

// Real xAI/Grok mark vendored byte-for-byte from Lobe Icons:
Expand DownExpand Up@@ -92,6 +93,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c

// Volcengine 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/volcengine.svg
// - license: MIT (repository LICENSE)
// - SHA-256: f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33

function ProviderAssetMask({ src }: { src: string }): ReactElement {
const mask = `url("${src}")`;
return <span className="providerAssetMask" style={{ maskImage: mask, WebkitMaskImage: mask }} aria-hidden="true" />;
Expand DownExpand Up@@ -278,6 +287,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
case 'stepfun-ai':
case 'stepfun':
return <ProviderAssetMask src={stepfunBrandMark} />;
case 'volcengine-ark':
return <ProviderAssetMask src={volcengineBrandMark} />;
default:
return <GenericProviderMark />;
}
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,30 @@ import type { LlmConnection } from '@maka/core/llm-connections';
import { listReadyModelChoices, resolveDefaultSessionTarget } from '../connection-target.js';

describe('default session target resolver', () => {
test('resolves Volcengine Ark credentials without rewriting the snapshot model id', async () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const connection = makeConnection({
slug: 'volcengine-ark',
name: 'Volcengine Ark (China)',
providerType: 'volcengine-ark',
defaultModel: modelId,
});

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

assert.equal(target.connection.providerType, 'volcengine-ark');
assert.equal(target.apiKey, 'ark-test-key');
assert.equal(target.model, modelId);
});

test('resolves Fireworks credentials without rewriting the exact model path', async () => {
const connection = makeConnection({
slug: 'fireworks-ai',
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ describe('provider compatibility contract', () => {
'tencent-tokenhub',
'stepfun',
'stepfun-ai',
'volcengine-ark',
'ollama',
'lm-studio',
'openai-compatible',
Expand DownExpand Up@@ -80,6 +81,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand All@@ -106,6 +108,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand DownExpand Up@@ -371,6 +374,23 @@ describe('provider compatibility contract', () => {
'step-3.5-flash',
]);
});

it('owns Volcengine Ark China direct API behavior under the stable volcengine-ark id', () => {
const ark = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>)['volcengine-ark'];

assert.ok(ark, 'Volcengine Ark China direct API must have its own persisted provider id');
assert.equal(ark.label, 'Volcengine Ark (China)');
assert.equal(ark.baseUrl, 'https://ark.cn-beijing.volces.com/api/v3');
assert.equal(ark.authKind, 'api_key');
assert.equal(ark.protocol, 'openai');
assert.deepEqual(ark.runtimeAdapter, { kind: 'openai-compatible', name: 'provider' });
assert.deepEqual(ark.modelDiscovery, { kind: 'fallback' });
assert.equal(ark.category, 'domestic');
assert.equal(ark.catalogGroup, 'api');
assert.equal(ark.signupUrl, 'https://console.volcengine.com/ark/region:ark+cn-beijing/model');
assert.equal(ark.modelsDevId, undefined);
assert.deepEqual(ark.fallbackModels, ['doubao-seed-2-0-pro-260215']);
});
});

describe('validateConnectionBaseUrl (PR-UI-IPC-1, @kenji msg 35260e29)', () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,25 @@ describe('ModelCatalogEntry', () => {
});
});

it('uses the official Volcengine Ark snapshot without inventing live model discovery', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'volcengine-ark',
providerType: 'volcengine-ark',
defaultModel: 'doubao-seed-2-0-pro-260215',
},
});

assert.deepEqual(entries.map((entry) => entry.id), ['doubao-seed-2-0-pro-260215']);
assert.equal(entries[0]?.displayName, 'Doubao Seed 2.0 Pro');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.deepEqual(entries[0]?.capabilities, {
reasoning: true,
functionCalling: true,
});
});

it('uses the checked-in StepFun China snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/provider-auth.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,19 @@ describe('ProviderAuth contract', () => {
expect(contract.actionAvailability.fetch_models).toBe('available');
});

test('Volcengine Ark China uses the shared API-key credential and snapshot-model flow', () => {
const contract = deriveProviderAuthContract({
providerType: 'volcengine-ark',
hasSecret: true,
});

expect(contract.providerType).toBe('volcengine-ark');
expect(contract.setupMode).toBe('api_key');
expect(contract.requiresSecret).toBe(true);
expect(contract.actionAvailability.test_credentials).toBe('available');
expect(contract.actionAvailability.fetch_models).toBe('hidden');
});

test('Together AI uses the shared API-key credential flow under its stable provider id', () => {
const contract = deriveProviderAuthContract({
providerType: 'togetherai',
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/model-metadata.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,6 +118,19 @@ const STATIC_MODEL_METADATA: Partial<Record<ProviderType, Record<string, ModelMe
'tencent-coding-plan': {
'kimi-k2.5': { capabilities: { vision: false } },
},
'volcengine-ark': {
'doubao-seed-2-0-pro-260215': {
displayName: 'Doubao Seed 2.0 Pro',
lifecycle: 'active',
docsUrl: 'https://www.volcengine.com/docs/82379',
capabilities: { reasoning: true, functionCalling: true },
thinkingOptions: {
efforts: ['minimal', 'low', 'medium', 'high'],
toggle: true,
offBehavior: 'volcengine-thinking-disabled',
},
},
},
deepseek: {
'deepseek-v4-flash': { thinkingOptions: { efforts: ['high', 'max'], toggle: true } },
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/model-thinking.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ export function isThinkingLevel(value: unknown): value is ThinkingLevel {
*/
export type ThinkingOffBehavior =
| 'anthropic-thinking-disabled'
| 'google-thinking-budget-zero';
| 'google-thinking-budget-zero'
| 'volcengine-thinking-disabled';

export interface ThinkingOptions {
readonly efforts?: readonly string[];
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/provider-registry.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -580,6 +580,24 @@ const providerRegistry = {
readyOrder: 24,
catalogOrder: 24,
},
'volcengine-ark': {
label: 'Volcengine Ark (China)',
description: 'Volcengine Ark direct API for reasoning and tool-use agents in China.',
baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
authKind: 'api_key',
backendKind: 'ai-sdk',
fallbackModels: ['doubao-seed-2-0-pro-260215'],
status: 'ready',
protocol: 'openai',
runtimeAdapter: { kind: 'openai-compatible', name: 'provider' },
modelDiscovery: { kind: 'fallback' },
category: 'domestic',
catalogGroup: 'api',
catalogBadge: 'API',
signupUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/model',
readyOrder: 25,
catalogOrder: 25,
},
ollama: {
label: 'Ollama',
description: 'Local models from Ollama on localhost.',
Expand Down
27 changes: 27 additions & 0 deletions packages/headless/src/__tests__/harbor-cell.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2362,6 +2362,33 @@ setTimeout(() => {
assert.equal(missing.apiKey, '');
});

test('resolves Volcengine Ark only from its official direct API credential env', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const resolved = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: {
ARK_API_KEY: 'ark-key',
ARK_BASE_URL: 'https://ark.cn-shanghai.volces.com/api/v3',
OPENAI_API_KEY: 'openai-key',
},
ts: 1,
});

assert.equal(resolved.apiKey, 'ark-key');
assert.equal(resolved.connection.providerType, 'volcengine-ark');
assert.equal(resolved.connection.defaultModel, modelId);
assert.equal(resolved.connection.baseUrl, 'https://ark.cn-shanghai.volces.com/api/v3');

const missing = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: { OPENAI_API_KEY: 'must-not-cross-provider-boundary' },
ts: 1,
});
assert.equal(missing.apiKey, '');
});

test('resolves Cerebras only from Cerebras credential env without rewriting the model id', () => {
const resolved = resolveHarborCellAiSdkEnv({
provider: 'cerebras',
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/__tests__/provider-env.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,3 +94,11 @@ test('StepFun Global keeps direct API credentials separate from China and plan i
baseUrls: ['STEPFUN_AI_BASE_URL'],
});
});

test('Volcengine Ark direct API uses its official credential namespace', () => {
assert.deepEqual(providerCredentialEnv('volcengine-ark'), {
apiKeys: ['ARK_API_KEY'],
apiKeyFile: 'ARK_API_KEY_FILE',
baseUrls: ['ARK_BASE_URL'],
});
});
1 change: 1 addition & 0 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@ const PROVIDER_CREDENTIAL_ENV = {
'tencent-tokenhub': env('TENCENT_TOKENHUB', ['TENCENT_TOKENHUB_BASE_URL']),
stepfun: env('STEPFUN', ['STEPFUN_BASE_URL']),
'stepfun-ai': env('STEPFUN_AI', ['STEPFUN_AI_BASE_URL']),
'volcengine-ark': env('ARK', ['ARK_BASE_URL']),
'openai-compatible': env('OPENAI', ['OPENAI_BASE_URL']),
'claude-subscription': env('ANTHROPIC'),
} satisfies Partial<Record<ProviderType, ProviderCredentialEnv>>;
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime/src/__tests__/model-factory-thinking.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,6 +71,20 @@ describe('buildProviderOptions: thinking level', () => {
assert.deepEqual(buildProviderOptions(conn('deepseek'), 'deepseek-chat', 'high'), {});
});

test('Volcengine Ark sends its official thinking object and optional reasoning effort', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
assert.deepEqual([...thinkingVariantsForModel('volcengine-ark', modelId)], ['off', 'minimal', 'low', 'medium', 'high']);
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId), {
'volcengine-ark': { thinking: { type: 'enabled' } },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'high'), {
'volcengine-ark': { thinking: { type: 'enabled' }, reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'off'), {
'volcengine-ark': { thinking: { type: 'disabled' } },
});
});

test('a level the model does not support is dropped (defensive)', () => {
assert.deepEqual(buildProviderOptions(conn('openai'), 'gpt-4o', 'high'), { openai: {} });
assert.deepEqual(buildProviderOptions(conn('anthropic'), 'claude-haiku-4-5', 'max'), { anthropic: {} });
Expand DownExpand Up@@ -115,6 +129,7 @@ describe('buildProviderOptions: resolver/options drift guard', () => {
{ providerType: 'google', model: 'gemini-3.5-flash' },
{ providerType: 'deepseek', model: 'deepseek-v4-flash' },
{ providerType: 'zai-coding-plan', model: 'glm-5.2', slug: 'zai-coding-plan' },
{ providerType: 'volcengine-ark', model: 'doubao-seed-2-0-pro-260215' },
];
for (const { providerType, model, slug } of cases) {
test(`every effort level for ${providerType}/${model} maps to a non-empty fragment`, () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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 numberDiff line numberDiff line change
Expand Up@@ -330,6 +330,36 @@ for (const stepfun of [
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Volcengine Ark China 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('Volcengine');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="volcengine-ark"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Volcengine Ark \(China\)/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('volcengine-ark');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://ark.cn-beijing.volces.com/api/v3');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('doubao-seed-2-0-pro-260215');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Volcengine Ark (China)', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="volcengine-ark"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('doubao-seed-2-0-pro-260215', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('restores keyboard focus across provider child pages', 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 numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ const NVIDIA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/ass
const TENCENT_HUNYUAN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/hunyuan.svg');
const TENCENT_CLOUD_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/tencentcloud.svg');
const STEPFUN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/stepfun.svg');
const VOLCENGINE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/volcengine.svg');
const DESKTOP_PACKAGE_FILE = resolve(REPO_ROOT, 'apps/desktop/package.json');
const THIRD_PARTY_NOTICES_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt');
const ONBOARDING_HERO_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/OnboardingHero.tsx');
Expand DownExpand Up@@ -430,6 +431,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'stepfun':\s*return <ProviderAssetMask src=\{stepfunBrandMark\} \/>/);
});

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

assert.equal(
createHash('sha256').update(volcengineMark).digest('hex'),
'f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33',
'the vendored Volcengine mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 volcengine.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/volcengine\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/volcengine\.svg[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
'Volcengine must append byte-exact provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import volcengineBrandMark from '\.\.\/assets\/provider-brands\/volcengine\.svg';/);
assert.match(
componentSrc,
/Volcengine 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\/volcengine\.svg[\s\S]*MIT[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
);
assert.match(componentSrc, /case 'volcengine-ark':\s*return <ProviderAssetMask src=\{volcengineBrandMark\} \/>/);
});

it('vendors and routes the byte-exact Tencent Cloud mark for Tencent Coding Plan', async () => {
const [tencentCloudMark, componentSrc, notices] = await Promise.all([
readFile(TENCENT_CLOUD_BRAND_MARK_FILE),
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 numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/stepfun.svg`
- SHA-256: `f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c`
- `apps/desktop/src/renderer/assets/provider-brands/volcengine.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/volcengine.svg`
- SHA-256: `f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33`

MIT License

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import mistralBrandMark from '../assets/provider-brands/mistral.svg';
import togetherBrandMark from '../assets/provider-brands/together.svg';
import nvidiaMarkUrl from '../assets/provider-brands/nvidia.svg';
import stepfunBrandMark from '../assets/provider-brands/stepfun.svg';
import volcengineBrandMark from '../assets/provider-brands/volcengine.svg';
import xaiMarkUrl from '../assets/provider-brands/xai.svg';

// Real xAI/Grok mark vendored byte-for-byte from Lobe Icons:
Expand DownExpand Up@@ -92,6 +93,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c

// Volcengine 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/volcengine.svg
// - license: MIT (repository LICENSE)
// - SHA-256: f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33

function ProviderAssetMask({ src }: { src: string }): ReactElement {
const mask = `url("${src}")`;
return <span className="providerAssetMask" style={{ maskImage: mask, WebkitMaskImage: mask }} aria-hidden="true" />;
Expand DownExpand Up@@ -278,6 +287,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
case 'stepfun-ai':
case 'stepfun':
return <ProviderAssetMask src={stepfunBrandMark} />;
case 'volcengine-ark':
return <ProviderAssetMask src={volcengineBrandMark} />;
default:
return <GenericProviderMark />;
}
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,30 @@ import type { LlmConnection } from '@maka/core/llm-connections';
import { listReadyModelChoices, resolveDefaultSessionTarget } from '../connection-target.js';

describe('default session target resolver', () => {
test('resolves Volcengine Ark credentials without rewriting the snapshot model id', async () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const connection = makeConnection({
slug: 'volcengine-ark',
name: 'Volcengine Ark (China)',
providerType: 'volcengine-ark',
defaultModel: modelId,
});

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

assert.equal(target.connection.providerType, 'volcengine-ark');
assert.equal(target.apiKey, 'ark-test-key');
assert.equal(target.model, modelId);
});

test('resolves Fireworks credentials without rewriting the exact model path', async () => {
const connection = makeConnection({
slug: 'fireworks-ai',
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ describe('provider compatibility contract', () => {
'tencent-tokenhub',
'stepfun',
'stepfun-ai',
'volcengine-ark',
'ollama',
'lm-studio',
'openai-compatible',
Expand DownExpand Up@@ -80,6 +81,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand All@@ -106,6 +108,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand DownExpand Up@@ -371,6 +374,23 @@ describe('provider compatibility contract', () => {
'step-3.5-flash',
]);
});

it('owns Volcengine Ark China direct API behavior under the stable volcengine-ark id', () => {
const ark = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>)['volcengine-ark'];

assert.ok(ark, 'Volcengine Ark China direct API must have its own persisted provider id');
assert.equal(ark.label, 'Volcengine Ark (China)');
assert.equal(ark.baseUrl, 'https://ark.cn-beijing.volces.com/api/v3');
assert.equal(ark.authKind, 'api_key');
assert.equal(ark.protocol, 'openai');
assert.deepEqual(ark.runtimeAdapter, { kind: 'openai-compatible', name: 'provider' });
assert.deepEqual(ark.modelDiscovery, { kind: 'fallback' });
assert.equal(ark.category, 'domestic');
assert.equal(ark.catalogGroup, 'api');
assert.equal(ark.signupUrl, 'https://console.volcengine.com/ark/region:ark+cn-beijing/model');
assert.equal(ark.modelsDevId, undefined);
assert.deepEqual(ark.fallbackModels, ['doubao-seed-2-0-pro-260215']);
});
});

describe('validateConnectionBaseUrl (PR-UI-IPC-1, @kenji msg 35260e29)', () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,25 @@ describe('ModelCatalogEntry', () => {
});
});

it('uses the official Volcengine Ark snapshot without inventing live model discovery', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'volcengine-ark',
providerType: 'volcengine-ark',
defaultModel: 'doubao-seed-2-0-pro-260215',
},
});

assert.deepEqual(entries.map((entry) => entry.id), ['doubao-seed-2-0-pro-260215']);
assert.equal(entries[0]?.displayName, 'Doubao Seed 2.0 Pro');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.deepEqual(entries[0]?.capabilities, {
reasoning: true,
functionCalling: true,
});
});

it('uses the checked-in StepFun China snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/provider-auth.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,19 @@ describe('ProviderAuth contract', () => {
expect(contract.actionAvailability.fetch_models).toBe('available');
});

test('Volcengine Ark China uses the shared API-key credential and snapshot-model flow', () => {
const contract = deriveProviderAuthContract({
providerType: 'volcengine-ark',
hasSecret: true,
});

expect(contract.providerType).toBe('volcengine-ark');
expect(contract.setupMode).toBe('api_key');
expect(contract.requiresSecret).toBe(true);
expect(contract.actionAvailability.test_credentials).toBe('available');
expect(contract.actionAvailability.fetch_models).toBe('hidden');
});

test('Together AI uses the shared API-key credential flow under its stable provider id', () => {
const contract = deriveProviderAuthContract({
providerType: 'togetherai',
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/model-metadata.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,6 +118,19 @@ const STATIC_MODEL_METADATA: Partial<Record<ProviderType, Record<string, ModelMe
'tencent-coding-plan': {
'kimi-k2.5': { capabilities: { vision: false } },
},
'volcengine-ark': {
'doubao-seed-2-0-pro-260215': {
displayName: 'Doubao Seed 2.0 Pro',
lifecycle: 'active',
docsUrl: 'https://www.volcengine.com/docs/82379',
capabilities: { reasoning: true, functionCalling: true },
thinkingOptions: {
efforts: ['minimal', 'low', 'medium', 'high'],
toggle: true,
offBehavior: 'volcengine-thinking-disabled',
},
},
},
deepseek: {
'deepseek-v4-flash': { thinkingOptions: { efforts: ['high', 'max'], toggle: true } },
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/model-thinking.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ export function isThinkingLevel(value: unknown): value is ThinkingLevel {
*/
export type ThinkingOffBehavior =
| 'anthropic-thinking-disabled'
| 'google-thinking-budget-zero';
| 'google-thinking-budget-zero'
| 'volcengine-thinking-disabled';

export interface ThinkingOptions {
readonly efforts?: readonly string[];
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/provider-registry.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -580,6 +580,24 @@ const providerRegistry = {
readyOrder: 24,
catalogOrder: 24,
},
'volcengine-ark': {
label: 'Volcengine Ark (China)',
description: 'Volcengine Ark direct API for reasoning and tool-use agents in China.',
baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
authKind: 'api_key',
backendKind: 'ai-sdk',
fallbackModels: ['doubao-seed-2-0-pro-260215'],
status: 'ready',
protocol: 'openai',
runtimeAdapter: { kind: 'openai-compatible', name: 'provider' },
modelDiscovery: { kind: 'fallback' },
category: 'domestic',
catalogGroup: 'api',
catalogBadge: 'API',
signupUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/model',
readyOrder: 25,
catalogOrder: 25,
},
ollama: {
label: 'Ollama',
description: 'Local models from Ollama on localhost.',
Expand Down
27 changes: 27 additions & 0 deletions packages/headless/src/__tests__/harbor-cell.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2362,6 +2362,33 @@ setTimeout(() => {
assert.equal(missing.apiKey, '');
});

test('resolves Volcengine Ark only from its official direct API credential env', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const resolved = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: {
ARK_API_KEY: 'ark-key',
ARK_BASE_URL: 'https://ark.cn-shanghai.volces.com/api/v3',
OPENAI_API_KEY: 'openai-key',
},
ts: 1,
});

assert.equal(resolved.apiKey, 'ark-key');
assert.equal(resolved.connection.providerType, 'volcengine-ark');
assert.equal(resolved.connection.defaultModel, modelId);
assert.equal(resolved.connection.baseUrl, 'https://ark.cn-shanghai.volces.com/api/v3');

const missing = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: { OPENAI_API_KEY: 'must-not-cross-provider-boundary' },
ts: 1,
});
assert.equal(missing.apiKey, '');
});

test('resolves Cerebras only from Cerebras credential env without rewriting the model id', () => {
const resolved = resolveHarborCellAiSdkEnv({
provider: 'cerebras',
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/__tests__/provider-env.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,3 +94,11 @@ test('StepFun Global keeps direct API credentials separate from China and plan i
baseUrls: ['STEPFUN_AI_BASE_URL'],
});
});

test('Volcengine Ark direct API uses its official credential namespace', () => {
assert.deepEqual(providerCredentialEnv('volcengine-ark'), {
apiKeys: ['ARK_API_KEY'],
apiKeyFile: 'ARK_API_KEY_FILE',
baseUrls: ['ARK_BASE_URL'],
});
});
1 change: 1 addition & 0 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@ const PROVIDER_CREDENTIAL_ENV = {
'tencent-tokenhub': env('TENCENT_TOKENHUB', ['TENCENT_TOKENHUB_BASE_URL']),
stepfun: env('STEPFUN', ['STEPFUN_BASE_URL']),
'stepfun-ai': env('STEPFUN_AI', ['STEPFUN_AI_BASE_URL']),
'volcengine-ark': env('ARK', ['ARK_BASE_URL']),
'openai-compatible': env('OPENAI', ['OPENAI_BASE_URL']),
'claude-subscription': env('ANTHROPIC'),
} satisfies Partial<Record<ProviderType, ProviderCredentialEnv>>;
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime/src/__tests__/model-factory-thinking.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,6 +71,20 @@ describe('buildProviderOptions: thinking level', () => {
assert.deepEqual(buildProviderOptions(conn('deepseek'), 'deepseek-chat', 'high'), {});
});

test('Volcengine Ark sends its official thinking object and optional reasoning effort', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
assert.deepEqual([...thinkingVariantsForModel('volcengine-ark', modelId)], ['off', 'minimal', 'low', 'medium', 'high']);
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId), {
'volcengine-ark': { thinking: { type: 'enabled' } },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'high'), {
'volcengine-ark': { thinking: { type: 'enabled' }, reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'off'), {
'volcengine-ark': { thinking: { type: 'disabled' } },
});
});

test('a level the model does not support is dropped (defensive)', () => {
assert.deepEqual(buildProviderOptions(conn('openai'), 'gpt-4o', 'high'), { openai: {} });
assert.deepEqual(buildProviderOptions(conn('anthropic'), 'claude-haiku-4-5', 'max'), { anthropic: {} });
Expand DownExpand Up@@ -115,6 +129,7 @@ describe('buildProviderOptions: resolver/options drift guard', () => {
{ providerType: 'google', model: 'gemini-3.5-flash' },
{ providerType: 'deepseek', model: 'deepseek-v4-flash' },
{ providerType: 'zai-coding-plan', model: 'glm-5.2', slug: 'zai-coding-plan' },
{ providerType: 'volcengine-ark', model: 'doubao-seed-2-0-pro-260215' },
];
for (const { providerType, model, slug } of cases) {
test(`every effort level for ${providerType}/${model} maps to a non-empty fragment`, () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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 numberDiff line numberDiff line change
Expand Up@@ -330,6 +330,36 @@ for (const stepfun of [
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Volcengine Ark China 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('Volcengine');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="volcengine-ark"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Volcengine Ark \(China\)/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('volcengine-ark');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://ark.cn-beijing.volces.com/api/v3');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('doubao-seed-2-0-pro-260215');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Volcengine Ark (China)', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="volcengine-ark"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('doubao-seed-2-0-pro-260215', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('restores keyboard focus across provider child pages', 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 numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ const NVIDIA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/ass
const TENCENT_HUNYUAN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/hunyuan.svg');
const TENCENT_CLOUD_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/tencentcloud.svg');
const STEPFUN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/stepfun.svg');
const VOLCENGINE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/volcengine.svg');
const DESKTOP_PACKAGE_FILE = resolve(REPO_ROOT, 'apps/desktop/package.json');
const THIRD_PARTY_NOTICES_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt');
const ONBOARDING_HERO_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/OnboardingHero.tsx');
Expand DownExpand Up@@ -430,6 +431,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'stepfun':\s*return <ProviderAssetMask src=\{stepfunBrandMark\} \/>/);
});

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

assert.equal(
createHash('sha256').update(volcengineMark).digest('hex'),
'f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33',
'the vendored Volcengine mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 volcengine.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/volcengine\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/volcengine\.svg[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
'Volcengine must append byte-exact provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import volcengineBrandMark from '\.\.\/assets\/provider-brands\/volcengine\.svg';/);
assert.match(
componentSrc,
/Volcengine 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\/volcengine\.svg[\s\S]*MIT[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
);
assert.match(componentSrc, /case 'volcengine-ark':\s*return <ProviderAssetMask src=\{volcengineBrandMark\} \/>/);
});

it('vendors and routes the byte-exact Tencent Cloud mark for Tencent Coding Plan', async () => {
const [tencentCloudMark, componentSrc, notices] = await Promise.all([
readFile(TENCENT_CLOUD_BRAND_MARK_FILE),
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 numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/stepfun.svg`
- SHA-256: `f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c`
- `apps/desktop/src/renderer/assets/provider-brands/volcengine.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/volcengine.svg`
- SHA-256: `f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33`

MIT License

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import mistralBrandMark from '../assets/provider-brands/mistral.svg';
import togetherBrandMark from '../assets/provider-brands/together.svg';
import nvidiaMarkUrl from '../assets/provider-brands/nvidia.svg';
import stepfunBrandMark from '../assets/provider-brands/stepfun.svg';
import volcengineBrandMark from '../assets/provider-brands/volcengine.svg';
import xaiMarkUrl from '../assets/provider-brands/xai.svg';

// Real xAI/Grok mark vendored byte-for-byte from Lobe Icons:
Expand DownExpand Up@@ -92,6 +93,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c

// Volcengine 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/volcengine.svg
// - license: MIT (repository LICENSE)
// - SHA-256: f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33

function ProviderAssetMask({ src }: { src: string }): ReactElement {
const mask = `url("${src}")`;
return <span className="providerAssetMask" style={{ maskImage: mask, WebkitMaskImage: mask }} aria-hidden="true" />;
Expand DownExpand Up@@ -278,6 +287,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
case 'stepfun-ai':
case 'stepfun':
return <ProviderAssetMask src={stepfunBrandMark} />;
case 'volcengine-ark':
return <ProviderAssetMask src={volcengineBrandMark} />;
default:
return <GenericProviderMark />;
}
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,30 @@ import type { LlmConnection } from '@maka/core/llm-connections';
import { listReadyModelChoices, resolveDefaultSessionTarget } from '../connection-target.js';

describe('default session target resolver', () => {
test('resolves Volcengine Ark credentials without rewriting the snapshot model id', async () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const connection = makeConnection({
slug: 'volcengine-ark',
name: 'Volcengine Ark (China)',
providerType: 'volcengine-ark',
defaultModel: modelId,
});

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

assert.equal(target.connection.providerType, 'volcengine-ark');
assert.equal(target.apiKey, 'ark-test-key');
assert.equal(target.model, modelId);
});

test('resolves Fireworks credentials without rewriting the exact model path', async () => {
const connection = makeConnection({
slug: 'fireworks-ai',
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ describe('provider compatibility contract', () => {
'tencent-tokenhub',
'stepfun',
'stepfun-ai',
'volcengine-ark',
'ollama',
'lm-studio',
'openai-compatible',
Expand DownExpand Up@@ -80,6 +81,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand All@@ -106,6 +108,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand DownExpand Up@@ -371,6 +374,23 @@ describe('provider compatibility contract', () => {
'step-3.5-flash',
]);
});

it('owns Volcengine Ark China direct API behavior under the stable volcengine-ark id', () => {
const ark = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>)['volcengine-ark'];

assert.ok(ark, 'Volcengine Ark China direct API must have its own persisted provider id');
assert.equal(ark.label, 'Volcengine Ark (China)');
assert.equal(ark.baseUrl, 'https://ark.cn-beijing.volces.com/api/v3');
assert.equal(ark.authKind, 'api_key');
assert.equal(ark.protocol, 'openai');
assert.deepEqual(ark.runtimeAdapter, { kind: 'openai-compatible', name: 'provider' });
assert.deepEqual(ark.modelDiscovery, { kind: 'fallback' });
assert.equal(ark.category, 'domestic');
assert.equal(ark.catalogGroup, 'api');
assert.equal(ark.signupUrl, 'https://console.volcengine.com/ark/region:ark+cn-beijing/model');
assert.equal(ark.modelsDevId, undefined);
assert.deepEqual(ark.fallbackModels, ['doubao-seed-2-0-pro-260215']);
});
});

describe('validateConnectionBaseUrl (PR-UI-IPC-1, @kenji msg 35260e29)', () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,25 @@ describe('ModelCatalogEntry', () => {
});
});

it('uses the official Volcengine Ark snapshot without inventing live model discovery', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'volcengine-ark',
providerType: 'volcengine-ark',
defaultModel: 'doubao-seed-2-0-pro-260215',
},
});

assert.deepEqual(entries.map((entry) => entry.id), ['doubao-seed-2-0-pro-260215']);
assert.equal(entries[0]?.displayName, 'Doubao Seed 2.0 Pro');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.deepEqual(entries[0]?.capabilities, {
reasoning: true,
functionCalling: true,
});
});

it('uses the checked-in StepFun China snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/provider-auth.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,19 @@ describe('ProviderAuth contract', () => {
expect(contract.actionAvailability.fetch_models).toBe('available');
});

test('Volcengine Ark China uses the shared API-key credential and snapshot-model flow', () => {
const contract = deriveProviderAuthContract({
providerType: 'volcengine-ark',
hasSecret: true,
});

expect(contract.providerType).toBe('volcengine-ark');
expect(contract.setupMode).toBe('api_key');
expect(contract.requiresSecret).toBe(true);
expect(contract.actionAvailability.test_credentials).toBe('available');
expect(contract.actionAvailability.fetch_models).toBe('hidden');
});

test('Together AI uses the shared API-key credential flow under its stable provider id', () => {
const contract = deriveProviderAuthContract({
providerType: 'togetherai',
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/model-metadata.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,6 +118,19 @@ const STATIC_MODEL_METADATA: Partial<Record<ProviderType, Record<string, ModelMe
'tencent-coding-plan': {
'kimi-k2.5': { capabilities: { vision: false } },
},
'volcengine-ark': {
'doubao-seed-2-0-pro-260215': {
displayName: 'Doubao Seed 2.0 Pro',
lifecycle: 'active',
docsUrl: 'https://www.volcengine.com/docs/82379',
capabilities: { reasoning: true, functionCalling: true },
thinkingOptions: {
efforts: ['minimal', 'low', 'medium', 'high'],
toggle: true,
offBehavior: 'volcengine-thinking-disabled',
},
},
},
deepseek: {
'deepseek-v4-flash': { thinkingOptions: { efforts: ['high', 'max'], toggle: true } },
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/model-thinking.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ export function isThinkingLevel(value: unknown): value is ThinkingLevel {
*/
export type ThinkingOffBehavior =
| 'anthropic-thinking-disabled'
| 'google-thinking-budget-zero';
| 'google-thinking-budget-zero'
| 'volcengine-thinking-disabled';

export interface ThinkingOptions {
readonly efforts?: readonly string[];
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/provider-registry.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -580,6 +580,24 @@ const providerRegistry = {
readyOrder: 24,
catalogOrder: 24,
},
'volcengine-ark': {
label: 'Volcengine Ark (China)',
description: 'Volcengine Ark direct API for reasoning and tool-use agents in China.',
baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
authKind: 'api_key',
backendKind: 'ai-sdk',
fallbackModels: ['doubao-seed-2-0-pro-260215'],
status: 'ready',
protocol: 'openai',
runtimeAdapter: { kind: 'openai-compatible', name: 'provider' },
modelDiscovery: { kind: 'fallback' },
category: 'domestic',
catalogGroup: 'api',
catalogBadge: 'API',
signupUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/model',
readyOrder: 25,
catalogOrder: 25,
},
ollama: {
label: 'Ollama',
description: 'Local models from Ollama on localhost.',
Expand Down
27 changes: 27 additions & 0 deletions packages/headless/src/__tests__/harbor-cell.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2362,6 +2362,33 @@ setTimeout(() => {
assert.equal(missing.apiKey, '');
});

test('resolves Volcengine Ark only from its official direct API credential env', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const resolved = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: {
ARK_API_KEY: 'ark-key',
ARK_BASE_URL: 'https://ark.cn-shanghai.volces.com/api/v3',
OPENAI_API_KEY: 'openai-key',
},
ts: 1,
});

assert.equal(resolved.apiKey, 'ark-key');
assert.equal(resolved.connection.providerType, 'volcengine-ark');
assert.equal(resolved.connection.defaultModel, modelId);
assert.equal(resolved.connection.baseUrl, 'https://ark.cn-shanghai.volces.com/api/v3');

const missing = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: { OPENAI_API_KEY: 'must-not-cross-provider-boundary' },
ts: 1,
});
assert.equal(missing.apiKey, '');
});

test('resolves Cerebras only from Cerebras credential env without rewriting the model id', () => {
const resolved = resolveHarborCellAiSdkEnv({
provider: 'cerebras',
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/__tests__/provider-env.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,3 +94,11 @@ test('StepFun Global keeps direct API credentials separate from China and plan i
baseUrls: ['STEPFUN_AI_BASE_URL'],
});
});

test('Volcengine Ark direct API uses its official credential namespace', () => {
assert.deepEqual(providerCredentialEnv('volcengine-ark'), {
apiKeys: ['ARK_API_KEY'],
apiKeyFile: 'ARK_API_KEY_FILE',
baseUrls: ['ARK_BASE_URL'],
});
});
1 change: 1 addition & 0 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@ const PROVIDER_CREDENTIAL_ENV = {
'tencent-tokenhub': env('TENCENT_TOKENHUB', ['TENCENT_TOKENHUB_BASE_URL']),
stepfun: env('STEPFUN', ['STEPFUN_BASE_URL']),
'stepfun-ai': env('STEPFUN_AI', ['STEPFUN_AI_BASE_URL']),
'volcengine-ark': env('ARK', ['ARK_BASE_URL']),
'openai-compatible': env('OPENAI', ['OPENAI_BASE_URL']),
'claude-subscription': env('ANTHROPIC'),
} satisfies Partial<Record<ProviderType, ProviderCredentialEnv>>;
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime/src/__tests__/model-factory-thinking.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,6 +71,20 @@ describe('buildProviderOptions: thinking level', () => {
assert.deepEqual(buildProviderOptions(conn('deepseek'), 'deepseek-chat', 'high'), {});
});

test('Volcengine Ark sends its official thinking object and optional reasoning effort', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
assert.deepEqual([...thinkingVariantsForModel('volcengine-ark', modelId)], ['off', 'minimal', 'low', 'medium', 'high']);
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId), {
'volcengine-ark': { thinking: { type: 'enabled' } },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'high'), {
'volcengine-ark': { thinking: { type: 'enabled' }, reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'off'), {
'volcengine-ark': { thinking: { type: 'disabled' } },
});
});

test('a level the model does not support is dropped (defensive)', () => {
assert.deepEqual(buildProviderOptions(conn('openai'), 'gpt-4o', 'high'), { openai: {} });
assert.deepEqual(buildProviderOptions(conn('anthropic'), 'claude-haiku-4-5', 'max'), { anthropic: {} });
Expand DownExpand Up@@ -115,6 +129,7 @@ describe('buildProviderOptions: resolver/options drift guard', () => {
{ providerType: 'google', model: 'gemini-3.5-flash' },
{ providerType: 'deepseek', model: 'deepseek-v4-flash' },
{ providerType: 'zai-coding-plan', model: 'glm-5.2', slug: 'zai-coding-plan' },
{ providerType: 'volcengine-ark', model: 'doubao-seed-2-0-pro-260215' },
];
for (const { providerType, model, slug } of cases) {
test(`every effort level for ${providerType}/${model} maps to a non-empty fragment`, () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
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 numberDiff line numberDiff line change
Expand Up@@ -330,6 +330,36 @@ for (const stepfun of [
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Volcengine Ark China 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('Volcengine');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="volcengine-ark"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Volcengine Ark \(China\)/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('volcengine-ark');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://ark.cn-beijing.volces.com/api/v3');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('doubao-seed-2-0-pro-260215');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Volcengine Ark (China)', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="volcengine-ark"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('doubao-seed-2-0-pro-260215', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('restores keyboard focus across provider child pages', 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 numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ const NVIDIA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/ass
const TENCENT_HUNYUAN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/hunyuan.svg');
const TENCENT_CLOUD_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/tencentcloud.svg');
const STEPFUN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/stepfun.svg');
const VOLCENGINE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/volcengine.svg');
const DESKTOP_PACKAGE_FILE = resolve(REPO_ROOT, 'apps/desktop/package.json');
const THIRD_PARTY_NOTICES_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt');
const ONBOARDING_HERO_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/OnboardingHero.tsx');
Expand DownExpand Up@@ -430,6 +431,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'stepfun':\s*return <ProviderAssetMask src=\{stepfunBrandMark\} \/>/);
});

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

assert.equal(
createHash('sha256').update(volcengineMark).digest('hex'),
'f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33',
'the vendored Volcengine mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 volcengine.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/volcengine\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/volcengine\.svg[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
'Volcengine must append byte-exact provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import volcengineBrandMark from '\.\.\/assets\/provider-brands\/volcengine\.svg';/);
assert.match(
componentSrc,
/Volcengine 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\/volcengine\.svg[\s\S]*MIT[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
);
assert.match(componentSrc, /case 'volcengine-ark':\s*return <ProviderAssetMask src=\{volcengineBrandMark\} \/>/);
});

it('vendors and routes the byte-exact Tencent Cloud mark for Tencent Coding Plan', async () => {
const [tencentCloudMark, componentSrc, notices] = await Promise.all([
readFile(TENCENT_CLOUD_BRAND_MARK_FILE),
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 numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/stepfun.svg`
- SHA-256: `f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c`
- `apps/desktop/src/renderer/assets/provider-brands/volcengine.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/volcengine.svg`
- SHA-256: `f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33`

MIT License

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import mistralBrandMark from '../assets/provider-brands/mistral.svg';
import togetherBrandMark from '../assets/provider-brands/together.svg';
import nvidiaMarkUrl from '../assets/provider-brands/nvidia.svg';
import stepfunBrandMark from '../assets/provider-brands/stepfun.svg';
import volcengineBrandMark from '../assets/provider-brands/volcengine.svg';
import xaiMarkUrl from '../assets/provider-brands/xai.svg';

// Real xAI/Grok mark vendored byte-for-byte from Lobe Icons:
Expand DownExpand Up@@ -92,6 +93,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c

// Volcengine 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/volcengine.svg
// - license: MIT (repository LICENSE)
// - SHA-256: f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33

function ProviderAssetMask({ src }: { src: string }): ReactElement {
const mask = `url("${src}")`;
return <span className="providerAssetMask" style={{ maskImage: mask, WebkitMaskImage: mask }} aria-hidden="true" />;
Expand DownExpand Up@@ -278,6 +287,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
case 'stepfun-ai':
case 'stepfun':
return <ProviderAssetMask src={stepfunBrandMark} />;
case 'volcengine-ark':
return <ProviderAssetMask src={volcengineBrandMark} />;
default:
return <GenericProviderMark />;
}
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,30 @@ import type { LlmConnection } from '@maka/core/llm-connections';
import { listReadyModelChoices, resolveDefaultSessionTarget } from '../connection-target.js';

describe('default session target resolver', () => {
test('resolves Volcengine Ark credentials without rewriting the snapshot model id', async () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const connection = makeConnection({
slug: 'volcengine-ark',
name: 'Volcengine Ark (China)',
providerType: 'volcengine-ark',
defaultModel: modelId,
});

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

assert.equal(target.connection.providerType, 'volcengine-ark');
assert.equal(target.apiKey, 'ark-test-key');
assert.equal(target.model, modelId);
});

test('resolves Fireworks credentials without rewriting the exact model path', async () => {
const connection = makeConnection({
slug: 'fireworks-ai',
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ describe('provider compatibility contract', () => {
'tencent-tokenhub',
'stepfun',
'stepfun-ai',
'volcengine-ark',
'ollama',
'lm-studio',
'openai-compatible',
Expand DownExpand Up@@ -80,6 +81,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand All@@ -106,6 +108,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand DownExpand Up@@ -371,6 +374,23 @@ describe('provider compatibility contract', () => {
'step-3.5-flash',
]);
});

it('owns Volcengine Ark China direct API behavior under the stable volcengine-ark id', () => {
const ark = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>)['volcengine-ark'];

assert.ok(ark, 'Volcengine Ark China direct API must have its own persisted provider id');
assert.equal(ark.label, 'Volcengine Ark (China)');
assert.equal(ark.baseUrl, 'https://ark.cn-beijing.volces.com/api/v3');
assert.equal(ark.authKind, 'api_key');
assert.equal(ark.protocol, 'openai');
assert.deepEqual(ark.runtimeAdapter, { kind: 'openai-compatible', name: 'provider' });
assert.deepEqual(ark.modelDiscovery, { kind: 'fallback' });
assert.equal(ark.category, 'domestic');
assert.equal(ark.catalogGroup, 'api');
assert.equal(ark.signupUrl, 'https://console.volcengine.com/ark/region:ark+cn-beijing/model');
assert.equal(ark.modelsDevId, undefined);
assert.deepEqual(ark.fallbackModels, ['doubao-seed-2-0-pro-260215']);
});
});

describe('validateConnectionBaseUrl (PR-UI-IPC-1, @kenji msg 35260e29)', () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,25 @@ describe('ModelCatalogEntry', () => {
});
});

it('uses the official Volcengine Ark snapshot without inventing live model discovery', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'volcengine-ark',
providerType: 'volcengine-ark',
defaultModel: 'doubao-seed-2-0-pro-260215',
},
});

assert.deepEqual(entries.map((entry) => entry.id), ['doubao-seed-2-0-pro-260215']);
assert.equal(entries[0]?.displayName, 'Doubao Seed 2.0 Pro');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.deepEqual(entries[0]?.capabilities, {
reasoning: true,
functionCalling: true,
});
});

it('uses the checked-in StepFun China snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/provider-auth.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,19 @@ describe('ProviderAuth contract', () => {
expect(contract.actionAvailability.fetch_models).toBe('available');
});

test('Volcengine Ark China uses the shared API-key credential and snapshot-model flow', () => {
const contract = deriveProviderAuthContract({
providerType: 'volcengine-ark',
hasSecret: true,
});

expect(contract.providerType).toBe('volcengine-ark');
expect(contract.setupMode).toBe('api_key');
expect(contract.requiresSecret).toBe(true);
expect(contract.actionAvailability.test_credentials).toBe('available');
expect(contract.actionAvailability.fetch_models).toBe('hidden');
});

test('Together AI uses the shared API-key credential flow under its stable provider id', () => {
const contract = deriveProviderAuthContract({
providerType: 'togetherai',
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/model-metadata.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,6 +118,19 @@ const STATIC_MODEL_METADATA: Partial<Record<ProviderType, Record<string, ModelMe
'tencent-coding-plan': {
'kimi-k2.5': { capabilities: { vision: false } },
},
'volcengine-ark': {
'doubao-seed-2-0-pro-260215': {
displayName: 'Doubao Seed 2.0 Pro',
lifecycle: 'active',
docsUrl: 'https://www.volcengine.com/docs/82379',
capabilities: { reasoning: true, functionCalling: true },
thinkingOptions: {
efforts: ['minimal', 'low', 'medium', 'high'],
toggle: true,
offBehavior: 'volcengine-thinking-disabled',
},
},
},
deepseek: {
'deepseek-v4-flash': { thinkingOptions: { efforts: ['high', 'max'], toggle: true } },
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/model-thinking.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ export function isThinkingLevel(value: unknown): value is ThinkingLevel {
*/
export type ThinkingOffBehavior =
| 'anthropic-thinking-disabled'
| 'google-thinking-budget-zero';
| 'google-thinking-budget-zero'
| 'volcengine-thinking-disabled';

export interface ThinkingOptions {
readonly efforts?: readonly string[];
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/provider-registry.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -580,6 +580,24 @@ const providerRegistry = {
readyOrder: 24,
catalogOrder: 24,
},
'volcengine-ark': {
label: 'Volcengine Ark (China)',
description: 'Volcengine Ark direct API for reasoning and tool-use agents in China.',
baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
authKind: 'api_key',
backendKind: 'ai-sdk',
fallbackModels: ['doubao-seed-2-0-pro-260215'],
status: 'ready',
protocol: 'openai',
runtimeAdapter: { kind: 'openai-compatible', name: 'provider' },
modelDiscovery: { kind: 'fallback' },
category: 'domestic',
catalogGroup: 'api',
catalogBadge: 'API',
signupUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/model',
readyOrder: 25,
catalogOrder: 25,
},
ollama: {
label: 'Ollama',
description: 'Local models from Ollama on localhost.',
Expand Down
27 changes: 27 additions & 0 deletions packages/headless/src/__tests__/harbor-cell.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2362,6 +2362,33 @@ setTimeout(() => {
assert.equal(missing.apiKey, '');
});

test('resolves Volcengine Ark only from its official direct API credential env', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const resolved = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: {
ARK_API_KEY: 'ark-key',
ARK_BASE_URL: 'https://ark.cn-shanghai.volces.com/api/v3',
OPENAI_API_KEY: 'openai-key',
},
ts: 1,
});

assert.equal(resolved.apiKey, 'ark-key');
assert.equal(resolved.connection.providerType, 'volcengine-ark');
assert.equal(resolved.connection.defaultModel, modelId);
assert.equal(resolved.connection.baseUrl, 'https://ark.cn-shanghai.volces.com/api/v3');

const missing = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: { OPENAI_API_KEY: 'must-not-cross-provider-boundary' },
ts: 1,
});
assert.equal(missing.apiKey, '');
});

test('resolves Cerebras only from Cerebras credential env without rewriting the model id', () => {
const resolved = resolveHarborCellAiSdkEnv({
provider: 'cerebras',
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/__tests__/provider-env.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,3 +94,11 @@ test('StepFun Global keeps direct API credentials separate from China and plan i
baseUrls: ['STEPFUN_AI_BASE_URL'],
});
});

test('Volcengine Ark direct API uses its official credential namespace', () => {
assert.deepEqual(providerCredentialEnv('volcengine-ark'), {
apiKeys: ['ARK_API_KEY'],
apiKeyFile: 'ARK_API_KEY_FILE',
baseUrls: ['ARK_BASE_URL'],
});
});
1 change: 1 addition & 0 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@ const PROVIDER_CREDENTIAL_ENV = {
'tencent-tokenhub': env('TENCENT_TOKENHUB', ['TENCENT_TOKENHUB_BASE_URL']),
stepfun: env('STEPFUN', ['STEPFUN_BASE_URL']),
'stepfun-ai': env('STEPFUN_AI', ['STEPFUN_AI_BASE_URL']),
'volcengine-ark': env('ARK', ['ARK_BASE_URL']),
'openai-compatible': env('OPENAI', ['OPENAI_BASE_URL']),
'claude-subscription': env('ANTHROPIC'),
} satisfies Partial<Record<ProviderType, ProviderCredentialEnv>>;
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime/src/__tests__/model-factory-thinking.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,6 +71,20 @@ describe('buildProviderOptions: thinking level', () => {
assert.deepEqual(buildProviderOptions(conn('deepseek'), 'deepseek-chat', 'high'), {});
});

test('Volcengine Ark sends its official thinking object and optional reasoning effort', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
assert.deepEqual([...thinkingVariantsForModel('volcengine-ark', modelId)], ['off', 'minimal', 'low', 'medium', 'high']);
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId), {
'volcengine-ark': { thinking: { type: 'enabled' } },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'high'), {
'volcengine-ark': { thinking: { type: 'enabled' }, reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'off'), {
'volcengine-ark': { thinking: { type: 'disabled' } },
});
});

test('a level the model does not support is dropped (defensive)', () => {
assert.deepEqual(buildProviderOptions(conn('openai'), 'gpt-4o', 'high'), { openai: {} });
assert.deepEqual(buildProviderOptions(conn('anthropic'), 'claude-haiku-4-5', 'max'), { anthropic: {} });
Expand DownExpand Up@@ -115,6 +129,7 @@ describe('buildProviderOptions: resolver/options drift guard', () => {
{ providerType: 'google', model: 'gemini-3.5-flash' },
{ providerType: 'deepseek', model: 'deepseek-v4-flash' },
{ providerType: 'zai-coding-plan', model: 'glm-5.2', slug: 'zai-coding-plan' },
{ providerType: 'volcengine-ark', model: 'doubao-seed-2-0-pro-260215' },
];
for (const { providerType, model, slug } of cases) {
test(`every effort level for ${providerType}/${model} maps to a non-empty fragment`, () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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 numberDiff line numberDiff line change
Expand Up@@ -330,6 +330,36 @@ for (const stepfun of [
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Volcengine Ark China 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('Volcengine');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="volcengine-ark"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Volcengine Ark \(China\)/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('volcengine-ark');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://ark.cn-beijing.volces.com/api/v3');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('doubao-seed-2-0-pro-260215');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Volcengine Ark (China)', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="volcengine-ark"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('doubao-seed-2-0-pro-260215', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('restores keyboard focus across provider child pages', 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 numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ const NVIDIA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/ass
const TENCENT_HUNYUAN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/hunyuan.svg');
const TENCENT_CLOUD_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/tencentcloud.svg');
const STEPFUN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/stepfun.svg');
const VOLCENGINE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/volcengine.svg');
const DESKTOP_PACKAGE_FILE = resolve(REPO_ROOT, 'apps/desktop/package.json');
const THIRD_PARTY_NOTICES_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt');
const ONBOARDING_HERO_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/OnboardingHero.tsx');
Expand DownExpand Up@@ -430,6 +431,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'stepfun':\s*return <ProviderAssetMask src=\{stepfunBrandMark\} \/>/);
});

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

assert.equal(
createHash('sha256').update(volcengineMark).digest('hex'),
'f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33',
'the vendored Volcengine mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 volcengine.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/volcengine\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/volcengine\.svg[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
'Volcengine must append byte-exact provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import volcengineBrandMark from '\.\.\/assets\/provider-brands\/volcengine\.svg';/);
assert.match(
componentSrc,
/Volcengine 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\/volcengine\.svg[\s\S]*MIT[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
);
assert.match(componentSrc, /case 'volcengine-ark':\s*return <ProviderAssetMask src=\{volcengineBrandMark\} \/>/);
});

it('vendors and routes the byte-exact Tencent Cloud mark for Tencent Coding Plan', async () => {
const [tencentCloudMark, componentSrc, notices] = await Promise.all([
readFile(TENCENT_CLOUD_BRAND_MARK_FILE),
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 numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/stepfun.svg`
- SHA-256: `f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c`
- `apps/desktop/src/renderer/assets/provider-brands/volcengine.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/volcengine.svg`
- SHA-256: `f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33`

MIT License

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import mistralBrandMark from '../assets/provider-brands/mistral.svg';
import togetherBrandMark from '../assets/provider-brands/together.svg';
import nvidiaMarkUrl from '../assets/provider-brands/nvidia.svg';
import stepfunBrandMark from '../assets/provider-brands/stepfun.svg';
import volcengineBrandMark from '../assets/provider-brands/volcengine.svg';
import xaiMarkUrl from '../assets/provider-brands/xai.svg';

// Real xAI/Grok mark vendored byte-for-byte from Lobe Icons:
Expand DownExpand Up@@ -92,6 +93,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c

// Volcengine 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/volcengine.svg
// - license: MIT (repository LICENSE)
// - SHA-256: f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33

function ProviderAssetMask({ src }: { src: string }): ReactElement {
const mask = `url("${src}")`;
return <span className="providerAssetMask" style={{ maskImage: mask, WebkitMaskImage: mask }} aria-hidden="true" />;
Expand DownExpand Up@@ -278,6 +287,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
case 'stepfun-ai':
case 'stepfun':
return <ProviderAssetMask src={stepfunBrandMark} />;
case 'volcengine-ark':
return <ProviderAssetMask src={volcengineBrandMark} />;
default:
return <GenericProviderMark />;
}
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,30 @@ import type { LlmConnection } from '@maka/core/llm-connections';
import { listReadyModelChoices, resolveDefaultSessionTarget } from '../connection-target.js';

describe('default session target resolver', () => {
test('resolves Volcengine Ark credentials without rewriting the snapshot model id', async () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const connection = makeConnection({
slug: 'volcengine-ark',
name: 'Volcengine Ark (China)',
providerType: 'volcengine-ark',
defaultModel: modelId,
});

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

assert.equal(target.connection.providerType, 'volcengine-ark');
assert.equal(target.apiKey, 'ark-test-key');
assert.equal(target.model, modelId);
});

test('resolves Fireworks credentials without rewriting the exact model path', async () => {
const connection = makeConnection({
slug: 'fireworks-ai',
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ describe('provider compatibility contract', () => {
'tencent-tokenhub',
'stepfun',
'stepfun-ai',
'volcengine-ark',
'ollama',
'lm-studio',
'openai-compatible',
Expand DownExpand Up@@ -80,6 +81,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand All@@ -106,6 +108,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand DownExpand Up@@ -371,6 +374,23 @@ describe('provider compatibility contract', () => {
'step-3.5-flash',
]);
});

it('owns Volcengine Ark China direct API behavior under the stable volcengine-ark id', () => {
const ark = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>)['volcengine-ark'];

assert.ok(ark, 'Volcengine Ark China direct API must have its own persisted provider id');
assert.equal(ark.label, 'Volcengine Ark (China)');
assert.equal(ark.baseUrl, 'https://ark.cn-beijing.volces.com/api/v3');
assert.equal(ark.authKind, 'api_key');
assert.equal(ark.protocol, 'openai');
assert.deepEqual(ark.runtimeAdapter, { kind: 'openai-compatible', name: 'provider' });
assert.deepEqual(ark.modelDiscovery, { kind: 'fallback' });
assert.equal(ark.category, 'domestic');
assert.equal(ark.catalogGroup, 'api');
assert.equal(ark.signupUrl, 'https://console.volcengine.com/ark/region:ark+cn-beijing/model');
assert.equal(ark.modelsDevId, undefined);
assert.deepEqual(ark.fallbackModels, ['doubao-seed-2-0-pro-260215']);
});
});

describe('validateConnectionBaseUrl (PR-UI-IPC-1, @kenji msg 35260e29)', () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,25 @@ describe('ModelCatalogEntry', () => {
});
});

it('uses the official Volcengine Ark snapshot without inventing live model discovery', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'volcengine-ark',
providerType: 'volcengine-ark',
defaultModel: 'doubao-seed-2-0-pro-260215',
},
});

assert.deepEqual(entries.map((entry) => entry.id), ['doubao-seed-2-0-pro-260215']);
assert.equal(entries[0]?.displayName, 'Doubao Seed 2.0 Pro');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.deepEqual(entries[0]?.capabilities, {
reasoning: true,
functionCalling: true,
});
});

it('uses the checked-in StepFun China snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/provider-auth.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,19 @@ describe('ProviderAuth contract', () => {
expect(contract.actionAvailability.fetch_models).toBe('available');
});

test('Volcengine Ark China uses the shared API-key credential and snapshot-model flow', () => {
const contract = deriveProviderAuthContract({
providerType: 'volcengine-ark',
hasSecret: true,
});

expect(contract.providerType).toBe('volcengine-ark');
expect(contract.setupMode).toBe('api_key');
expect(contract.requiresSecret).toBe(true);
expect(contract.actionAvailability.test_credentials).toBe('available');
expect(contract.actionAvailability.fetch_models).toBe('hidden');
});

test('Together AI uses the shared API-key credential flow under its stable provider id', () => {
const contract = deriveProviderAuthContract({
providerType: 'togetherai',
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/model-metadata.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,6 +118,19 @@ const STATIC_MODEL_METADATA: Partial<Record<ProviderType, Record<string, ModelMe
'tencent-coding-plan': {
'kimi-k2.5': { capabilities: { vision: false } },
},
'volcengine-ark': {
'doubao-seed-2-0-pro-260215': {
displayName: 'Doubao Seed 2.0 Pro',
lifecycle: 'active',
docsUrl: 'https://www.volcengine.com/docs/82379',
capabilities: { reasoning: true, functionCalling: true },
thinkingOptions: {
efforts: ['minimal', 'low', 'medium', 'high'],
toggle: true,
offBehavior: 'volcengine-thinking-disabled',
},
},
},
deepseek: {
'deepseek-v4-flash': { thinkingOptions: { efforts: ['high', 'max'], toggle: true } },
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/model-thinking.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ export function isThinkingLevel(value: unknown): value is ThinkingLevel {
*/
export type ThinkingOffBehavior =
| 'anthropic-thinking-disabled'
| 'google-thinking-budget-zero';
| 'google-thinking-budget-zero'
| 'volcengine-thinking-disabled';

export interface ThinkingOptions {
readonly efforts?: readonly string[];
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/provider-registry.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -580,6 +580,24 @@ const providerRegistry = {
readyOrder: 24,
catalogOrder: 24,
},
'volcengine-ark': {
label: 'Volcengine Ark (China)',
description: 'Volcengine Ark direct API for reasoning and tool-use agents in China.',
baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
authKind: 'api_key',
backendKind: 'ai-sdk',
fallbackModels: ['doubao-seed-2-0-pro-260215'],
status: 'ready',
protocol: 'openai',
runtimeAdapter: { kind: 'openai-compatible', name: 'provider' },
modelDiscovery: { kind: 'fallback' },
category: 'domestic',
catalogGroup: 'api',
catalogBadge: 'API',
signupUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/model',
readyOrder: 25,
catalogOrder: 25,
},
ollama: {
label: 'Ollama',
description: 'Local models from Ollama on localhost.',
Expand Down
27 changes: 27 additions & 0 deletions packages/headless/src/__tests__/harbor-cell.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2362,6 +2362,33 @@ setTimeout(() => {
assert.equal(missing.apiKey, '');
});

test('resolves Volcengine Ark only from its official direct API credential env', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const resolved = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: {
ARK_API_KEY: 'ark-key',
ARK_BASE_URL: 'https://ark.cn-shanghai.volces.com/api/v3',
OPENAI_API_KEY: 'openai-key',
},
ts: 1,
});

assert.equal(resolved.apiKey, 'ark-key');
assert.equal(resolved.connection.providerType, 'volcengine-ark');
assert.equal(resolved.connection.defaultModel, modelId);
assert.equal(resolved.connection.baseUrl, 'https://ark.cn-shanghai.volces.com/api/v3');

const missing = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: { OPENAI_API_KEY: 'must-not-cross-provider-boundary' },
ts: 1,
});
assert.equal(missing.apiKey, '');
});

test('resolves Cerebras only from Cerebras credential env without rewriting the model id', () => {
const resolved = resolveHarborCellAiSdkEnv({
provider: 'cerebras',
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/__tests__/provider-env.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,3 +94,11 @@ test('StepFun Global keeps direct API credentials separate from China and plan i
baseUrls: ['STEPFUN_AI_BASE_URL'],
});
});

test('Volcengine Ark direct API uses its official credential namespace', () => {
assert.deepEqual(providerCredentialEnv('volcengine-ark'), {
apiKeys: ['ARK_API_KEY'],
apiKeyFile: 'ARK_API_KEY_FILE',
baseUrls: ['ARK_BASE_URL'],
});
});
1 change: 1 addition & 0 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@ const PROVIDER_CREDENTIAL_ENV = {
'tencent-tokenhub': env('TENCENT_TOKENHUB', ['TENCENT_TOKENHUB_BASE_URL']),
stepfun: env('STEPFUN', ['STEPFUN_BASE_URL']),
'stepfun-ai': env('STEPFUN_AI', ['STEPFUN_AI_BASE_URL']),
'volcengine-ark': env('ARK', ['ARK_BASE_URL']),
'openai-compatible': env('OPENAI', ['OPENAI_BASE_URL']),
'claude-subscription': env('ANTHROPIC'),
} satisfies Partial<Record<ProviderType, ProviderCredentialEnv>>;
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime/src/__tests__/model-factory-thinking.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,6 +71,20 @@ describe('buildProviderOptions: thinking level', () => {
assert.deepEqual(buildProviderOptions(conn('deepseek'), 'deepseek-chat', 'high'), {});
});

test('Volcengine Ark sends its official thinking object and optional reasoning effort', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
assert.deepEqual([...thinkingVariantsForModel('volcengine-ark', modelId)], ['off', 'minimal', 'low', 'medium', 'high']);
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId), {
'volcengine-ark': { thinking: { type: 'enabled' } },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'high'), {
'volcengine-ark': { thinking: { type: 'enabled' }, reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'off'), {
'volcengine-ark': { thinking: { type: 'disabled' } },
});
});

test('a level the model does not support is dropped (defensive)', () => {
assert.deepEqual(buildProviderOptions(conn('openai'), 'gpt-4o', 'high'), { openai: {} });
assert.deepEqual(buildProviderOptions(conn('anthropic'), 'claude-haiku-4-5', 'max'), { anthropic: {} });
Expand DownExpand Up@@ -115,6 +129,7 @@ describe('buildProviderOptions: resolver/options drift guard', () => {
{ providerType: 'google', model: 'gemini-3.5-flash' },
{ providerType: 'deepseek', model: 'deepseek-v4-flash' },
{ providerType: 'zai-coding-plan', model: 'glm-5.2', slug: 'zai-coding-plan' },
{ providerType: 'volcengine-ark', model: 'doubao-seed-2-0-pro-260215' },
];
for (const { providerType, model, slug } of cases) {
test(`every effort level for ${providerType}/${model} maps to a non-empty fragment`, () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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 numberDiff line numberDiff line change
Expand Up@@ -330,6 +330,36 @@ for (const stepfun of [
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Volcengine Ark China 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('Volcengine');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="volcengine-ark"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Volcengine Ark \(China\)/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('volcengine-ark');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://ark.cn-beijing.volces.com/api/v3');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('doubao-seed-2-0-pro-260215');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Volcengine Ark (China)', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="volcengine-ark"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('doubao-seed-2-0-pro-260215', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('restores keyboard focus across provider child pages', 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 numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ const NVIDIA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/ass
const TENCENT_HUNYUAN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/hunyuan.svg');
const TENCENT_CLOUD_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/tencentcloud.svg');
const STEPFUN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/stepfun.svg');
const VOLCENGINE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/volcengine.svg');
const DESKTOP_PACKAGE_FILE = resolve(REPO_ROOT, 'apps/desktop/package.json');
const THIRD_PARTY_NOTICES_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt');
const ONBOARDING_HERO_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/OnboardingHero.tsx');
Expand DownExpand Up@@ -430,6 +431,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'stepfun':\s*return <ProviderAssetMask src=\{stepfunBrandMark\} \/>/);
});

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

assert.equal(
createHash('sha256').update(volcengineMark).digest('hex'),
'f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33',
'the vendored Volcengine mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 volcengine.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/volcengine\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/volcengine\.svg[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
'Volcengine must append byte-exact provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import volcengineBrandMark from '\.\.\/assets\/provider-brands\/volcengine\.svg';/);
assert.match(
componentSrc,
/Volcengine 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\/volcengine\.svg[\s\S]*MIT[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
);
assert.match(componentSrc, /case 'volcengine-ark':\s*return <ProviderAssetMask src=\{volcengineBrandMark\} \/>/);
});

it('vendors and routes the byte-exact Tencent Cloud mark for Tencent Coding Plan', async () => {
const [tencentCloudMark, componentSrc, notices] = await Promise.all([
readFile(TENCENT_CLOUD_BRAND_MARK_FILE),
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 numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/stepfun.svg`
- SHA-256: `f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c`
- `apps/desktop/src/renderer/assets/provider-brands/volcengine.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/volcengine.svg`
- SHA-256: `f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33`

MIT License

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import mistralBrandMark from '../assets/provider-brands/mistral.svg';
import togetherBrandMark from '../assets/provider-brands/together.svg';
import nvidiaMarkUrl from '../assets/provider-brands/nvidia.svg';
import stepfunBrandMark from '../assets/provider-brands/stepfun.svg';
import volcengineBrandMark from '../assets/provider-brands/volcengine.svg';
import xaiMarkUrl from '../assets/provider-brands/xai.svg';

// Real xAI/Grok mark vendored byte-for-byte from Lobe Icons:
Expand DownExpand Up@@ -92,6 +93,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c

// Volcengine 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/volcengine.svg
// - license: MIT (repository LICENSE)
// - SHA-256: f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33

function ProviderAssetMask({ src }: { src: string }): ReactElement {
const mask = `url("${src}")`;
return <span className="providerAssetMask" style={{ maskImage: mask, WebkitMaskImage: mask }} aria-hidden="true" />;
Expand DownExpand Up@@ -278,6 +287,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
case 'stepfun-ai':
case 'stepfun':
return <ProviderAssetMask src={stepfunBrandMark} />;
case 'volcengine-ark':
return <ProviderAssetMask src={volcengineBrandMark} />;
default:
return <GenericProviderMark />;
}
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,30 @@ import type { LlmConnection } from '@maka/core/llm-connections';
import { listReadyModelChoices, resolveDefaultSessionTarget } from '../connection-target.js';

describe('default session target resolver', () => {
test('resolves Volcengine Ark credentials without rewriting the snapshot model id', async () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const connection = makeConnection({
slug: 'volcengine-ark',
name: 'Volcengine Ark (China)',
providerType: 'volcengine-ark',
defaultModel: modelId,
});

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

assert.equal(target.connection.providerType, 'volcengine-ark');
assert.equal(target.apiKey, 'ark-test-key');
assert.equal(target.model, modelId);
});

test('resolves Fireworks credentials without rewriting the exact model path', async () => {
const connection = makeConnection({
slug: 'fireworks-ai',
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ describe('provider compatibility contract', () => {
'tencent-tokenhub',
'stepfun',
'stepfun-ai',
'volcengine-ark',
'ollama',
'lm-studio',
'openai-compatible',
Expand DownExpand Up@@ -80,6 +81,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand All@@ -106,6 +108,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand DownExpand Up@@ -371,6 +374,23 @@ describe('provider compatibility contract', () => {
'step-3.5-flash',
]);
});

it('owns Volcengine Ark China direct API behavior under the stable volcengine-ark id', () => {
const ark = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>)['volcengine-ark'];

assert.ok(ark, 'Volcengine Ark China direct API must have its own persisted provider id');
assert.equal(ark.label, 'Volcengine Ark (China)');
assert.equal(ark.baseUrl, 'https://ark.cn-beijing.volces.com/api/v3');
assert.equal(ark.authKind, 'api_key');
assert.equal(ark.protocol, 'openai');
assert.deepEqual(ark.runtimeAdapter, { kind: 'openai-compatible', name: 'provider' });
assert.deepEqual(ark.modelDiscovery, { kind: 'fallback' });
assert.equal(ark.category, 'domestic');
assert.equal(ark.catalogGroup, 'api');
assert.equal(ark.signupUrl, 'https://console.volcengine.com/ark/region:ark+cn-beijing/model');
assert.equal(ark.modelsDevId, undefined);
assert.deepEqual(ark.fallbackModels, ['doubao-seed-2-0-pro-260215']);
});
});

describe('validateConnectionBaseUrl (PR-UI-IPC-1, @kenji msg 35260e29)', () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,25 @@ describe('ModelCatalogEntry', () => {
});
});

it('uses the official Volcengine Ark snapshot without inventing live model discovery', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'volcengine-ark',
providerType: 'volcengine-ark',
defaultModel: 'doubao-seed-2-0-pro-260215',
},
});

assert.deepEqual(entries.map((entry) => entry.id), ['doubao-seed-2-0-pro-260215']);
assert.equal(entries[0]?.displayName, 'Doubao Seed 2.0 Pro');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.deepEqual(entries[0]?.capabilities, {
reasoning: true,
functionCalling: true,
});
});

it('uses the checked-in StepFun China snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/provider-auth.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,19 @@ describe('ProviderAuth contract', () => {
expect(contract.actionAvailability.fetch_models).toBe('available');
});

test('Volcengine Ark China uses the shared API-key credential and snapshot-model flow', () => {
const contract = deriveProviderAuthContract({
providerType: 'volcengine-ark',
hasSecret: true,
});

expect(contract.providerType).toBe('volcengine-ark');
expect(contract.setupMode).toBe('api_key');
expect(contract.requiresSecret).toBe(true);
expect(contract.actionAvailability.test_credentials).toBe('available');
expect(contract.actionAvailability.fetch_models).toBe('hidden');
});

test('Together AI uses the shared API-key credential flow under its stable provider id', () => {
const contract = deriveProviderAuthContract({
providerType: 'togetherai',
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/model-metadata.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,6 +118,19 @@ const STATIC_MODEL_METADATA: Partial<Record<ProviderType, Record<string, ModelMe
'tencent-coding-plan': {
'kimi-k2.5': { capabilities: { vision: false } },
},
'volcengine-ark': {
'doubao-seed-2-0-pro-260215': {
displayName: 'Doubao Seed 2.0 Pro',
lifecycle: 'active',
docsUrl: 'https://www.volcengine.com/docs/82379',
capabilities: { reasoning: true, functionCalling: true },
thinkingOptions: {
efforts: ['minimal', 'low', 'medium', 'high'],
toggle: true,
offBehavior: 'volcengine-thinking-disabled',
},
},
},
deepseek: {
'deepseek-v4-flash': { thinkingOptions: { efforts: ['high', 'max'], toggle: true } },
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/model-thinking.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ export function isThinkingLevel(value: unknown): value is ThinkingLevel {
*/
export type ThinkingOffBehavior =
| 'anthropic-thinking-disabled'
| 'google-thinking-budget-zero';
| 'google-thinking-budget-zero'
| 'volcengine-thinking-disabled';

export interface ThinkingOptions {
readonly efforts?: readonly string[];
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/provider-registry.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -580,6 +580,24 @@ const providerRegistry = {
readyOrder: 24,
catalogOrder: 24,
},
'volcengine-ark': {
label: 'Volcengine Ark (China)',
description: 'Volcengine Ark direct API for reasoning and tool-use agents in China.',
baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
authKind: 'api_key',
backendKind: 'ai-sdk',
fallbackModels: ['doubao-seed-2-0-pro-260215'],
status: 'ready',
protocol: 'openai',
runtimeAdapter: { kind: 'openai-compatible', name: 'provider' },
modelDiscovery: { kind: 'fallback' },
category: 'domestic',
catalogGroup: 'api',
catalogBadge: 'API',
signupUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/model',
readyOrder: 25,
catalogOrder: 25,
},
ollama: {
label: 'Ollama',
description: 'Local models from Ollama on localhost.',
Expand Down
27 changes: 27 additions & 0 deletions packages/headless/src/__tests__/harbor-cell.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2362,6 +2362,33 @@ setTimeout(() => {
assert.equal(missing.apiKey, '');
});

test('resolves Volcengine Ark only from its official direct API credential env', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const resolved = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: {
ARK_API_KEY: 'ark-key',
ARK_BASE_URL: 'https://ark.cn-shanghai.volces.com/api/v3',
OPENAI_API_KEY: 'openai-key',
},
ts: 1,
});

assert.equal(resolved.apiKey, 'ark-key');
assert.equal(resolved.connection.providerType, 'volcengine-ark');
assert.equal(resolved.connection.defaultModel, modelId);
assert.equal(resolved.connection.baseUrl, 'https://ark.cn-shanghai.volces.com/api/v3');

const missing = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: { OPENAI_API_KEY: 'must-not-cross-provider-boundary' },
ts: 1,
});
assert.equal(missing.apiKey, '');
});

test('resolves Cerebras only from Cerebras credential env without rewriting the model id', () => {
const resolved = resolveHarborCellAiSdkEnv({
provider: 'cerebras',
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/__tests__/provider-env.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,3 +94,11 @@ test('StepFun Global keeps direct API credentials separate from China and plan i
baseUrls: ['STEPFUN_AI_BASE_URL'],
});
});

test('Volcengine Ark direct API uses its official credential namespace', () => {
assert.deepEqual(providerCredentialEnv('volcengine-ark'), {
apiKeys: ['ARK_API_KEY'],
apiKeyFile: 'ARK_API_KEY_FILE',
baseUrls: ['ARK_BASE_URL'],
});
});
1 change: 1 addition & 0 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@ const PROVIDER_CREDENTIAL_ENV = {
'tencent-tokenhub': env('TENCENT_TOKENHUB', ['TENCENT_TOKENHUB_BASE_URL']),
stepfun: env('STEPFUN', ['STEPFUN_BASE_URL']),
'stepfun-ai': env('STEPFUN_AI', ['STEPFUN_AI_BASE_URL']),
'volcengine-ark': env('ARK', ['ARK_BASE_URL']),
'openai-compatible': env('OPENAI', ['OPENAI_BASE_URL']),
'claude-subscription': env('ANTHROPIC'),
} satisfies Partial<Record<ProviderType, ProviderCredentialEnv>>;
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime/src/__tests__/model-factory-thinking.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,6 +71,20 @@ describe('buildProviderOptions: thinking level', () => {
assert.deepEqual(buildProviderOptions(conn('deepseek'), 'deepseek-chat', 'high'), {});
});

test('Volcengine Ark sends its official thinking object and optional reasoning effort', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
assert.deepEqual([...thinkingVariantsForModel('volcengine-ark', modelId)], ['off', 'minimal', 'low', 'medium', 'high']);
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId), {
'volcengine-ark': { thinking: { type: 'enabled' } },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'high'), {
'volcengine-ark': { thinking: { type: 'enabled' }, reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'off'), {
'volcengine-ark': { thinking: { type: 'disabled' } },
});
});

test('a level the model does not support is dropped (defensive)', () => {
assert.deepEqual(buildProviderOptions(conn('openai'), 'gpt-4o', 'high'), { openai: {} });
assert.deepEqual(buildProviderOptions(conn('anthropic'), 'claude-haiku-4-5', 'max'), { anthropic: {} });
Expand DownExpand Up@@ -115,6 +129,7 @@ describe('buildProviderOptions: resolver/options drift guard', () => {
{ providerType: 'google', model: 'gemini-3.5-flash' },
{ providerType: 'deepseek', model: 'deepseek-v4-flash' },
{ providerType: 'zai-coding-plan', model: 'glm-5.2', slug: 'zai-coding-plan' },
{ providerType: 'volcengine-ark', model: 'doubao-seed-2-0-pro-260215' },
];
for (const { providerType, model, slug } of cases) {
test(`every effort level for ${providerType}/${model} maps to a non-empty fragment`, () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
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 numberDiff line numberDiff line change
Expand Up@@ -330,6 +330,36 @@ for (const stepfun of [
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('adds Volcengine Ark China 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('Volcengine');
const catalogMark = page.locator(
'.providerCatalogRow[data-provider="volcengine-ark"] .providerLogo .providerAssetMask',
);
await expect(catalogMark).toBeVisible();
expect(await catalogMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await page.getByRole('button', { name: /添加模型供应商:Volcengine Ark \(China\)/ }).click();

await expect(page.getByLabel('模型供应商连接标识')).toHaveValue('volcengine-ark');
await expect(page.getByLabel('模型供应商服务地址')).toHaveValue('https://ark.cn-beijing.volces.com/api/v3');
await expect(page.getByLabel('模型供应商默认模型')).toHaveValue('doubao-seed-2-0-pro-260215');
await page.getByRole('button', { name: '保存供应商' }).click();

await expect(page.getByRole('heading', { name: 'Volcengine Ark (China)', exact: true }).first()).toBeVisible();
const detailMark = page.locator(
'.providerSubpageHeader .providerLogo[data-provider="volcengine-ark"] .providerAssetMask',
);
await expect(detailMark).toBeVisible();
expect(await detailMark.evaluate(maskRenderContract)).toEqual({ usesAssetMask: true, followsForeground: true });
await expect(page.getByText('doubao-seed-2-0-pro-260215', { exact: true }).first()).toBeVisible();
await expect(page.getByRole('textbox', { name: '模型密钥' })).toBeVisible();
});

test('restores keyboard focus across provider child pages', 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 numberDiff line numberDiff line change
Expand Up@@ -46,6 +46,7 @@ const NVIDIA_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/ass
const TENCENT_HUNYUAN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/hunyuan.svg');
const TENCENT_CLOUD_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/tencentcloud.svg');
const STEPFUN_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/stepfun.svg');
const VOLCENGINE_BRAND_MARK_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/assets/provider-brands/volcengine.svg');
const DESKTOP_PACKAGE_FILE = resolve(REPO_ROOT, 'apps/desktop/package.json');
const THIRD_PARTY_NOTICES_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/public/THIRD_PARTY_LICENSES.txt');
const ONBOARDING_HERO_FILE = resolve(REPO_ROOT, 'apps/desktop/src/renderer/OnboardingHero.tsx');
Expand DownExpand Up@@ -430,6 +431,31 @@ describe('icon + typography governance contract', () => {
assert.match(componentSrc, /case 'stepfun':\s*return <ProviderAssetMask src=\{stepfunBrandMark\} \/>/);
});

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

assert.equal(
createHash('sha256').update(volcengineMark).digest('hex'),
'f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33',
'the vendored Volcengine mark must remain byte-identical to @lobehub/icons-static-svg@1.91.0 volcengine.svg',
);
assert.match(
notices,
/apps\/desktop\/src\/renderer\/assets\/provider-brands\/volcengine\.svg[\s\S]*e4302041fbb3039608d25f9f618bd462783b875e[\s\S]*packages\/static-svg\/icons\/volcengine\.svg[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
'Volcengine must append byte-exact provenance to the existing Lobe Icons notice entry',
);
assert.match(componentSrc, /import volcengineBrandMark from '\.\.\/assets\/provider-brands\/volcengine\.svg';/);
assert.match(
componentSrc,
/Volcengine 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\/volcengine\.svg[\s\S]*MIT[\s\S]*f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33/,
);
assert.match(componentSrc, /case 'volcengine-ark':\s*return <ProviderAssetMask src=\{volcengineBrandMark\} \/>/);
});

it('vendors and routes the byte-exact Tencent Cloud mark for Tencent Coding Plan', async () => {
const [tencentCloudMark, componentSrc, notices] = await Promise.all([
readFile(TENCENT_CLOUD_BRAND_MARK_FILE),
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 numberDiff line numberDiff line change
Expand Up@@ -53,6 +53,10 @@ This file records notices for third-party source assets vendored into the Maka d
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/stepfun.svg`
- SHA-256: `f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c`
- `apps/desktop/src/renderer/assets/provider-brands/volcengine.svg`
- Upstream commit: `e4302041fbb3039608d25f9f618bd462783b875e`
- Upstream path: `packages/static-svg/icons/volcengine.svg`
- SHA-256: `f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33`

MIT License

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/renderer/settings/provider-brand-marks.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,7 @@ import mistralBrandMark from '../assets/provider-brands/mistral.svg';
import togetherBrandMark from '../assets/provider-brands/together.svg';
import nvidiaMarkUrl from '../assets/provider-brands/nvidia.svg';
import stepfunBrandMark from '../assets/provider-brands/stepfun.svg';
import volcengineBrandMark from '../assets/provider-brands/volcengine.svg';
import xaiMarkUrl from '../assets/provider-brands/xai.svg';

// Real xAI/Grok mark vendored byte-for-byte from Lobe Icons:
Expand DownExpand Up@@ -92,6 +93,14 @@ function XAI(): ReactElement {
// - license: MIT (repository LICENSE)
// - SHA-256: f46fbd1eee00a3dc7874395484bcc3e25a803e9eb4b79f07b7eec377a1e2f25c

// Volcengine 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/volcengine.svg
// - license: MIT (repository LICENSE)
// - SHA-256: f29d0bdc284b33d8664ef221add7fbf06a5b370ef92767fa33f6020c914d3d33

function ProviderAssetMask({ src }: { src: string }): ReactElement {
const mask = `url("${src}")`;
return <span className="providerAssetMask" style={{ maskImage: mask, WebkitMaskImage: mask }} aria-hidden="true" />;
Expand DownExpand Up@@ -278,6 +287,8 @@ export function ProviderBrandMark({ type }: { type: ProviderType }): ReactElemen
case 'stepfun-ai':
case 'stepfun':
return <ProviderAssetMask src={stepfunBrandMark} />;
case 'volcengine-ark':
return <ProviderAssetMask src={volcengineBrandMark} />;
default:
return <GenericProviderMark />;
}
Expand Down
24 changes: 24 additions & 0 deletions packages/cli/src/__tests__/connection-target.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,30 @@ import type { LlmConnection } from '@maka/core/llm-connections';
import { listReadyModelChoices, resolveDefaultSessionTarget } from '../connection-target.js';

describe('default session target resolver', () => {
test('resolves Volcengine Ark credentials without rewriting the snapshot model id', async () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const connection = makeConnection({
slug: 'volcengine-ark',
name: 'Volcengine Ark (China)',
providerType: 'volcengine-ark',
defaultModel: modelId,
});

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

assert.equal(target.connection.providerType, 'volcengine-ark');
assert.equal(target.apiKey, 'ark-test-key');
assert.equal(target.model, modelId);
});

test('resolves Fireworks credentials without rewriting the exact model path', async () => {
const connection = makeConnection({
slug: 'fireworks-ai',
Expand Down
20 changes: 20 additions & 0 deletions packages/core/src/__tests__/llm-connections.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,7 @@ describe('provider compatibility contract', () => {
'tencent-tokenhub',
'stepfun',
'stepfun-ai',
'volcengine-ark',
'ollama',
'lm-studio',
'openai-compatible',
Expand DownExpand Up@@ -80,6 +81,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);
assert.deepEqual(CATALOG_PROVIDER_TYPES, [
'kimi-coding-plan',
Expand All@@ -106,6 +108,7 @@ describe('provider compatibility contract', () => {
'stepfun',
'tencent-coding-plan',
'stepfun-ai',
'volcengine-ark',
]);

for (const orderField of ['readyOrder', 'catalogOrder', 'recommendedOrder'] as const) {
Expand DownExpand Up@@ -371,6 +374,23 @@ describe('provider compatibility contract', () => {
'step-3.5-flash',
]);
});

it('owns Volcengine Ark China direct API behavior under the stable volcengine-ark id', () => {
const ark = (PROVIDER_REGISTRY as Partial<Record<string, (typeof PROVIDER_REGISTRY)[keyof typeof PROVIDER_REGISTRY]>>)['volcengine-ark'];

assert.ok(ark, 'Volcengine Ark China direct API must have its own persisted provider id');
assert.equal(ark.label, 'Volcengine Ark (China)');
assert.equal(ark.baseUrl, 'https://ark.cn-beijing.volces.com/api/v3');
assert.equal(ark.authKind, 'api_key');
assert.equal(ark.protocol, 'openai');
assert.deepEqual(ark.runtimeAdapter, { kind: 'openai-compatible', name: 'provider' });
assert.deepEqual(ark.modelDiscovery, { kind: 'fallback' });
assert.equal(ark.category, 'domestic');
assert.equal(ark.catalogGroup, 'api');
assert.equal(ark.signupUrl, 'https://console.volcengine.com/ark/region:ark+cn-beijing/model');
assert.equal(ark.modelsDevId, undefined);
assert.deepEqual(ark.fallbackModels, ['doubao-seed-2-0-pro-260215']);
});
});

describe('validateConnectionBaseUrl (PR-UI-IPC-1, @kenji msg 35260e29)', () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/__tests__/model-catalog.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,6 +34,25 @@ describe('ModelCatalogEntry', () => {
});
});

it('uses the official Volcengine Ark snapshot without inventing live model discovery', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
slug: 'volcengine-ark',
providerType: 'volcengine-ark',
defaultModel: 'doubao-seed-2-0-pro-260215',
},
});

assert.deepEqual(entries.map((entry) => entry.id), ['doubao-seed-2-0-pro-260215']);
assert.equal(entries[0]?.displayName, 'Doubao Seed 2.0 Pro');
assert.equal(entries[0]?.source, 'static_catalog');
assert.equal(entries[0]?.provenance.modelSource, 'fallback');
assert.deepEqual(entries[0]?.capabilities, {
reasoning: true,
functionCalling: true,
});
});

it('uses the checked-in StepFun China snapshot until account discovery succeeds', () => {
const entries = buildConnectionModelCatalogEntries({
connection: {
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/__tests__/provider-auth.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,19 @@ describe('ProviderAuth contract', () => {
expect(contract.actionAvailability.fetch_models).toBe('available');
});

test('Volcengine Ark China uses the shared API-key credential and snapshot-model flow', () => {
const contract = deriveProviderAuthContract({
providerType: 'volcengine-ark',
hasSecret: true,
});

expect(contract.providerType).toBe('volcengine-ark');
expect(contract.setupMode).toBe('api_key');
expect(contract.requiresSecret).toBe(true);
expect(contract.actionAvailability.test_credentials).toBe('available');
expect(contract.actionAvailability.fetch_models).toBe('hidden');
});

test('Together AI uses the shared API-key credential flow under its stable provider id', () => {
const contract = deriveProviderAuthContract({
providerType: 'togetherai',
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/model-metadata.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -118,6 +118,19 @@ const STATIC_MODEL_METADATA: Partial<Record<ProviderType, Record<string, ModelMe
'tencent-coding-plan': {
'kimi-k2.5': { capabilities: { vision: false } },
},
'volcengine-ark': {
'doubao-seed-2-0-pro-260215': {
displayName: 'Doubao Seed 2.0 Pro',
lifecycle: 'active',
docsUrl: 'https://www.volcengine.com/docs/82379',
capabilities: { reasoning: true, functionCalling: true },
thinkingOptions: {
efforts: ['minimal', 'low', 'medium', 'high'],
toggle: true,
offBehavior: 'volcengine-thinking-disabled',
},
},
},
deepseek: {
'deepseek-v4-flash': { thinkingOptions: { efforts: ['high', 'max'], toggle: true } },
},
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/model-thinking.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,8 @@ export function isThinkingLevel(value: unknown): value is ThinkingLevel {
*/
export type ThinkingOffBehavior =
| 'anthropic-thinking-disabled'
| 'google-thinking-budget-zero';
| 'google-thinking-budget-zero'
| 'volcengine-thinking-disabled';

export interface ThinkingOptions {
readonly efforts?: readonly string[];
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/provider-registry.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -580,6 +580,24 @@ const providerRegistry = {
readyOrder: 24,
catalogOrder: 24,
},
'volcengine-ark': {
label: 'Volcengine Ark (China)',
description: 'Volcengine Ark direct API for reasoning and tool-use agents in China.',
baseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
authKind: 'api_key',
backendKind: 'ai-sdk',
fallbackModels: ['doubao-seed-2-0-pro-260215'],
status: 'ready',
protocol: 'openai',
runtimeAdapter: { kind: 'openai-compatible', name: 'provider' },
modelDiscovery: { kind: 'fallback' },
category: 'domestic',
catalogGroup: 'api',
catalogBadge: 'API',
signupUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/model',
readyOrder: 25,
catalogOrder: 25,
},
ollama: {
label: 'Ollama',
description: 'Local models from Ollama on localhost.',
Expand Down
27 changes: 27 additions & 0 deletions packages/headless/src/__tests__/harbor-cell.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -2362,6 +2362,33 @@ setTimeout(() => {
assert.equal(missing.apiKey, '');
});

test('resolves Volcengine Ark only from its official direct API credential env', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
const resolved = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: {
ARK_API_KEY: 'ark-key',
ARK_BASE_URL: 'https://ark.cn-shanghai.volces.com/api/v3',
OPENAI_API_KEY: 'openai-key',
},
ts: 1,
});

assert.equal(resolved.apiKey, 'ark-key');
assert.equal(resolved.connection.providerType, 'volcengine-ark');
assert.equal(resolved.connection.defaultModel, modelId);
assert.equal(resolved.connection.baseUrl, 'https://ark.cn-shanghai.volces.com/api/v3');

const missing = resolveHarborCellAiSdkEnv({
provider: 'volcengine-ark',
model: modelId,
env: { OPENAI_API_KEY: 'must-not-cross-provider-boundary' },
ts: 1,
});
assert.equal(missing.apiKey, '');
});

test('resolves Cerebras only from Cerebras credential env without rewriting the model id', () => {
const resolved = resolveHarborCellAiSdkEnv({
provider: 'cerebras',
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/__tests__/provider-env.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -94,3 +94,11 @@ test('StepFun Global keeps direct API credentials separate from China and plan i
baseUrls: ['STEPFUN_AI_BASE_URL'],
});
});

test('Volcengine Ark direct API uses its official credential namespace', () => {
assert.deepEqual(providerCredentialEnv('volcengine-ark'), {
apiKeys: ['ARK_API_KEY'],
apiKeyFile: 'ARK_API_KEY_FILE',
baseUrls: ['ARK_BASE_URL'],
});
});
1 change: 1 addition & 0 deletions packages/headless/src/provider-env.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@ const PROVIDER_CREDENTIAL_ENV = {
'tencent-tokenhub': env('TENCENT_TOKENHUB', ['TENCENT_TOKENHUB_BASE_URL']),
stepfun: env('STEPFUN', ['STEPFUN_BASE_URL']),
'stepfun-ai': env('STEPFUN_AI', ['STEPFUN_AI_BASE_URL']),
'volcengine-ark': env('ARK', ['ARK_BASE_URL']),
'openai-compatible': env('OPENAI', ['OPENAI_BASE_URL']),
'claude-subscription': env('ANTHROPIC'),
} satisfies Partial<Record<ProviderType, ProviderCredentialEnv>>;
Expand Down
15 changes: 15 additions & 0 deletions packages/runtime/src/__tests__/model-factory-thinking.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -71,6 +71,20 @@ describe('buildProviderOptions: thinking level', () => {
assert.deepEqual(buildProviderOptions(conn('deepseek'), 'deepseek-chat', 'high'), {});
});

test('Volcengine Ark sends its official thinking object and optional reasoning effort', () => {
const modelId = 'doubao-seed-2-0-pro-260215';
assert.deepEqual([...thinkingVariantsForModel('volcengine-ark', modelId)], ['off', 'minimal', 'low', 'medium', 'high']);
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId), {
'volcengine-ark': { thinking: { type: 'enabled' } },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'high'), {
'volcengine-ark': { thinking: { type: 'enabled' }, reasoningEffort: 'high' },
});
assert.deepEqual(buildProviderOptions(conn('volcengine-ark'), modelId, 'off'), {
'volcengine-ark': { thinking: { type: 'disabled' } },
});
});

test('a level the model does not support is dropped (defensive)', () => {
assert.deepEqual(buildProviderOptions(conn('openai'), 'gpt-4o', 'high'), { openai: {} });
assert.deepEqual(buildProviderOptions(conn('anthropic'), 'claude-haiku-4-5', 'max'), { anthropic: {} });
Expand DownExpand Up@@ -115,6 +129,7 @@ describe('buildProviderOptions: resolver/options drift guard', () => {
{ providerType: 'google', model: 'gemini-3.5-flash' },
{ providerType: 'deepseek', model: 'deepseek-v4-flash' },
{ providerType: 'zai-coding-plan', model: 'glm-5.2', slug: 'zai-coding-plan' },
{ providerType: 'volcengine-ark', model: 'doubao-seed-2-0-pro-260215' },
];
for (const { providerType, model, slug } of cases) {
test(`every effort level for ${providerType}/${model} maps to a non-empty fragment`, () => {
Expand Down
Loading
Loading