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
35 changes: 30 additions & 5 deletions packages/cli/src/ui/auth/AuthDialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1234,15 +1234,20 @@ describe('AuthDialog', { timeout: 15000 }, () => {
await pressEnterAndWaitFor(
stdin,
lastFrame,
'Alibaba ModelStudio · Step 1/2 · API Key',
'Alibaba ModelStudio · Step 1/3 · Region',
);
await pressEnterAndWaitFor(
stdin,
lastFrame,
'Alibaba ModelStudio · Step 2/3 · API Key',
);

await typeText(stdin, 'sk-token-plan');

await pressEnterAndWaitFor(
stdin,
lastFrame,
'Alibaba ModelStudio · Step 2/2 · Model IDs',
'Alibaba ModelStudio · Step 3/3 · Model IDs',
);
stdin.write('\r');
await vi.waitFor(
Expand Down Expand Up @@ -1309,15 +1314,20 @@ describe('AuthDialog', { timeout: 15000 }, () => {
await pressEnterAndWaitFor(
stdin,
lastFrame,
'Alibaba ModelStudio · Step 1/2 · API Key',
'Alibaba ModelStudio · Step 1/3 · Region',
);
await pressEnterAndWaitFor(
stdin,
lastFrame,
'Alibaba ModelStudio · Step 2/3 · API Key',
);

await typeText(stdin, 'sk-token-plan');

await pressEnterAndWaitFor(
stdin,
lastFrame,
'Alibaba ModelStudio · Step 2/2 · Model IDs',
'Alibaba ModelStudio · Step 3/3 · Model IDs',
);

// The Model IDs input is pre-filled with the saved custom model id
Expand Down Expand Up @@ -1373,7 +1383,22 @@ describe('AuthDialog', { timeout: 15000 }, () => {
await pressEnterAndWaitFor(
stdin,
lastFrame,
'Alibaba ModelStudio · Step 1/2 · API Key',
'Alibaba ModelStudio · Step 1/3 · Region',
);
await pressEnterAndWaitFor(
stdin,
lastFrame,
'Alibaba ModelStudio · Step 2/3 · API Key',
);
stdin.write('\u001b');

await vi.waitFor(
() => {
expect(lastFrame()).toContain(
'Alibaba ModelStudio · Step 1/3 · Region',
);
},
{ timeout: WAIT_FOR_TIMEOUT },
);
stdin.write('\u001b');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@
*/

import { describe, expect, it } from 'vitest';
import { AuthType } from '../../../core/contentGenerator.js';
import {
AuthType,
TOKEN_PLAN_ENV_KEY,
TOKEN_PLAN_BASE_URL,
TOKEN_PLAN_CHINA_BASE_URL,
TOKEN_PLAN_GLOBAL_BASE_URL,
tokenPlanProvider,
} from '../../presets/alibaba-token-plan.js';
import {
buildInstallPlan,
buildProviderTemplate,
computeModelListVersion,
getDefaultModelIds,
resolveBaseUrl,
providerMatchesCredentials,
} from '@qwen-code/qwen-code-core';
} from '../../provider-config.js';

describe('token plan provider', () => {
it('creates a Token Plan install plan', () => {
Expand Down Expand Up @@ -93,7 +97,44 @@ describe('token plan provider', () => {
]);
expect(plan.providerState).toEqual({
'providerMetadata.token-plan': {
baseUrl: TOKEN_PLAN_BASE_URL,
baseUrl: TOKEN_PLAN_CHINA_BASE_URL,
version,
},
});
});

it('creates a Token Plan install plan for the Singapore region', () => {
expect(TOKEN_PLAN_GLOBAL_BASE_URL).toBe(
'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1',
);
expect(tokenPlanProvider.uiLabels?.baseUrlStepTitle).toBe('Region');

const template = buildProviderTemplate(
tokenPlanProvider,
TOKEN_PLAN_GLOBAL_BASE_URL,
);
const version = computeModelListVersion(template);
const baseUrl = resolveBaseUrl(
tokenPlanProvider,
TOKEN_PLAN_GLOBAL_BASE_URL,
);

const plan = buildInstallPlan(tokenPlanProvider, {
baseUrl,
apiKey: 'sk-token',
modelIds: getDefaultModelIds(tokenPlanProvider),
});

expect(baseUrl).toBe(TOKEN_PLAN_GLOBAL_BASE_URL);
const firstModel = template[0]!;
expect(firstModel).toMatchObject({
name: `[ModelStudio Token Plan for Global/Intl] ${firstModel.id}`,
baseUrl: TOKEN_PLAN_GLOBAL_BASE_URL,
envKey: TOKEN_PLAN_ENV_KEY,
});
expect(plan.providerState).toEqual({
'providerMetadata.token-plan': {
baseUrl: TOKEN_PLAN_GLOBAL_BASE_URL,
version,
},
});
Expand All @@ -107,6 +148,20 @@ describe('token plan provider', () => {
TOKEN_PLAN_ENV_KEY,
),
).toBe(true);
expect(
providerMatchesCredentials(
tokenPlanProvider,
TOKEN_PLAN_CHINA_BASE_URL,
TOKEN_PLAN_ENV_KEY,
),
).toBe(true);
expect(
providerMatchesCredentials(
tokenPlanProvider,
TOKEN_PLAN_GLOBAL_BASE_URL,
TOKEN_PLAN_ENV_KEY,
),
).toBe(true);
expect(
providerMatchesCredentials(
tokenPlanProvider,
Expand All @@ -115,4 +170,43 @@ describe('token plan provider', () => {
),
).toBe(false);
});

it('owns Token Plan models from both registered regions', () => {
expect(
tokenPlanProvider.ownsModel?.({
id: 'token-model',
baseUrl: TOKEN_PLAN_CHINA_BASE_URL,
envKey: TOKEN_PLAN_ENV_KEY,
}),
).toBe(true);
expect(
tokenPlanProvider.ownsModel?.({
id: 'token-model',
baseUrl: TOKEN_PLAN_GLOBAL_BASE_URL,
envKey: TOKEN_PLAN_ENV_KEY,
}),
).toBe(true);
expect(
tokenPlanProvider.ownsModel?.({
id: 'custom-model',
baseUrl: 'https://custom.example.com/v1',
envKey: TOKEN_PLAN_ENV_KEY,
}),
).toBe(false);
Comment on lines +189 to +195

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The ownsModel negative case only exercises the baseUrl mismatch branch; the envKey guard is never independently tested. — Concrete cost: if a future edit removes model.envKey === TOKEN_PLAN_ENV_KEY && from ownsModel, all three existing tests still pass (both positives use the correct envKey; the sole negative fails on baseUrl). A model registered under a different provider's API key but sharing a Token Plan base URL would be incorrectly claimed by the token-plan provider.

Suggested change
expect(
tokenPlanProvider.ownsModel?.({
id: 'custom-model',
baseUrl: 'https://custom.example.com/v1',
envKey: TOKEN_PLAN_ENV_KEY,
}),
).toBe(false);
expect(
tokenPlanProvider.ownsModel?.({
id: 'custom-model',
baseUrl: 'https://custom.example.com/v1',
envKey: TOKEN_PLAN_ENV_KEY,
}),
).toBe(false);
expect(
tokenPlanProvider.ownsModel?.({
id: 'token-model',
baseUrl: TOKEN_PLAN_CHINA_BASE_URL,
envKey: 'SOME_OTHER_API_KEY',
}),
).toBe(false);

— qwen3.8-max-preview via Qwen Code /review

expect(
tokenPlanProvider.ownsModel?.({
id: 'legacy-token-model',
name: '[ModelStudio Token Plan] legacy-token-model',
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
envKey: TOKEN_PLAN_ENV_KEY,
}),
).toBe(true);
expect(
tokenPlanProvider.ownsModel?.({
id: 'token-model',
baseUrl: TOKEN_PLAN_CHINA_BASE_URL,
envKey: 'SOME_OTHER_API_KEY',
}),
).toBe(false);
});
});
29 changes: 26 additions & 3 deletions packages/core/src/providers/__tests__/provider-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ import {
computeModelListVersion,
findExistingProviderModels,
findProviderByCredentials,
getAllProviderBaseUrls,
getDefaultModelIds,
resolveBaseUrl,
shouldShowStep,
providerMatchesCredentials,
type ProviderConfig,
} from '@qwen-code/qwen-code-core';
import {
TOKEN_PLAN_CHINA_BASE_URL,
TOKEN_PLAN_ENV_KEY,
TOKEN_PLAN_GLOBAL_BASE_URL,
} from '../presets/alibaba-token-plan.js';

function makeConfig(overrides: Partial<ProviderConfig> = {}): ProviderConfig {
return {
Expand Down Expand Up @@ -621,27 +625,46 @@ describe('findProviderByCredentials', () => {
expect(china?.id).toBe('coding-plan');
expect(intl?.id).toBe('coding-plan');
});

it('matches Token Plan credentials against both registered region URLs', () => {
const china = findProviderByCredentialsSrc(
TOKEN_PLAN_CHINA_BASE_URL,
TOKEN_PLAN_ENV_KEY,
);
const intl = findProviderByCredentialsSrc(
TOKEN_PLAN_GLOBAL_BASE_URL,
TOKEN_PLAN_ENV_KEY,
);
expect(china?.id).toBe('token-plan');
expect(intl?.id).toBe('token-plan');
});
});

describe('getAllProviderBaseUrls', () => {
it('returns a non-empty list including known preset URLs', () => {
const urls = getAllProviderBaseUrls();
const urls = getAllProviderBaseUrlsSrc();
expect(urls.length).toBeGreaterThan(0);
expect(urls).toContain('https://api.deepseek.com');
expect(urls).toContain('https://openrouter.ai/api/v1');
});

it('expands BaseUrlOption[] presets into each option URL', () => {
const urls = getAllProviderBaseUrls();
const urls = getAllProviderBaseUrlsSrc();
// coding-plan has China + Singapore options
expect(urls).toContain('https://coding.dashscope.aliyuncs.com/v1');
expect(urls).toContain('https://coding-intl.dashscope.aliyuncs.com/v1');
expect(urls).toContain(TOKEN_PLAN_CHINA_BASE_URL);
expect(urls).toContain(TOKEN_PLAN_GLOBAL_BASE_URL);
});
});

// The package-name imports above resolve to dist/, which lags the source on a
// branch that hasn't been built yet. Re-import via the relative source path so
// these new edge-case tests exercise the in-tree implementation.
import {
findProviderByCredentials as findProviderByCredentialsSrc,
getAllProviderBaseUrls as getAllProviderBaseUrlsSrc,
} from '../all-providers.js';
import {
resolveBaseUrl as resolveBaseUrlSrc,
providerMatchesCredentials as providerMatchesCredentialsSrc,
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ export {
} from './presets/alibaba-coding-plan.js';
export {
TOKEN_PLAN_BASE_URL,
TOKEN_PLAN_CHINA_BASE_URL,
TOKEN_PLAN_ENV_KEY,
TOKEN_PLAN_GLOBAL_BASE_URL,
} from './presets/alibaba-token-plan.js';
export { GROK_BASE_URL, GROK_ENV_KEY } from './presets/grok.js';
export {
Expand Down
36 changes: 32 additions & 4 deletions packages/core/src/providers/presets/alibaba-token-plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import type { ProviderConfig, ModelSpec } from '../types.js';
// ---------------------------------------------------------------------------

export const TOKEN_PLAN_ENV_KEY = 'BAILIAN_TOKEN_PLAN_API_KEY';
export const TOKEN_PLAN_BASE_URL =
export const TOKEN_PLAN_CHINA_BASE_URL =
'https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1';
export const TOKEN_PLAN_GLOBAL_BASE_URL =
'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1';
export const TOKEN_PLAN_BASE_URL = TOKEN_PLAN_CHINA_BASE_URL;

const TOKEN_PLAN_MODELS: ModelSpec[] = [
{
Expand Down Expand Up @@ -76,11 +79,36 @@ export const tokenPlanProvider: ProviderConfig = {
description:
'For teams and companies · Usage-based billing with dedicated endpoint',
protocol: AuthType.USE_OPENAI,
baseUrl: TOKEN_PLAN_BASE_URL,
baseUrl: [
{
id: 'cn-beijing',
label: 'China (Beijing)',
url: TOKEN_PLAN_CHINA_BASE_URL,
documentationUrl:
'https://bailian.console.aliyun.com/cn-beijing?tab=doc#/doc/?type=model&url=3028856',
},
{
id: 'ap-southeast-1',
label: 'Singapore (International)',
url: TOKEN_PLAN_GLOBAL_BASE_URL,
documentationUrl:
'https://modelstudio.console.alibabacloud.com/ap-southeast-1?tab=doc#/doc/?type=model',
},
],
envKey: TOKEN_PLAN_ENV_KEY,
models: TOKEN_PLAN_MODELS,
modelsEditable: true,
modelNamePrefix: 'ModelStudio Token Plan',
modelNamePrefix: (baseUrl) =>
baseUrl === TOKEN_PLAN_GLOBAL_BASE_URL
? 'ModelStudio Token Plan for Global/Intl'
: 'ModelStudio Token Plan',
ownsModel: (model) =>
model.envKey === TOKEN_PLAN_ENV_KEY &&
((typeof model.baseUrl === 'string' &&
(model.baseUrl === TOKEN_PLAN_CHINA_BASE_URL ||
model.baseUrl === TOKEN_PLAN_GLOBAL_BASE_URL)) ||
(typeof model.name === 'string' &&
model.name.startsWith('[ModelStudio Token Plan]'))),
uiGroup: 'alibaba',
uiLabels: { flowTitle: 'Alibaba ModelStudio' },
uiLabels: { flowTitle: 'Alibaba ModelStudio', baseUrlStepTitle: 'Region' },
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

import { describe, expect, it } from 'vitest';

import { getSubscriptionPlanConfig } from './subscriptionPlanDefinitions.js';
import {
CodingPlanRegion,
getSubscriptionPlanConfig,
} from './subscriptionPlanDefinitions.js';

describe('subscription plan definitions', () => {
it('keeps Token Plan on its dedicated model list', () => {
Expand Down Expand Up @@ -38,4 +41,31 @@ describe('subscription plan definitions', () => {
?.generationConfig,
).toEqual({ contextWindowSize: 1000000 });
});

it('defaults Token Plan to China and supports the Singapore region', () => {
const china = getSubscriptionPlanConfig('token');
const global = getSubscriptionPlanConfig('token', CodingPlanRegion.GLOBAL);

expect(china.region).toBe(CodingPlanRegion.CHINA);
expect(china.baseUrl).toBe(
'https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1',
);
const firstChinaModel = china.template[0]!;
expect(firstChinaModel).toMatchObject({
name: `[ModelStudio Token Plan] ${firstChinaModel.id}`,
baseUrl:
'https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1',
});

expect(global.region).toBe(CodingPlanRegion.GLOBAL);
expect(global.baseUrl).toBe(
'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1',
);
const firstGlobalModel = global.template[0]!;
expect(firstGlobalModel).toMatchObject({
name: `[ModelStudio Token Plan for Global/Intl] ${firstGlobalModel.id}`,
baseUrl:
'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1',
});
});
});
Loading
Loading