diff --git a/src/__tests__/unit/provider-preset.test.ts b/src/__tests__/unit/provider-preset.test.ts index 10c4135f..8c21ffb1 100644 --- a/src/__tests__/unit/provider-preset.test.ts +++ b/src/__tests__/unit/provider-preset.test.ts @@ -1,6 +1,14 @@ import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; -import { VENDOR_PRESETS, PresetSchema, getDefaultModelsForProvider, getEffectiveProviderProtocol, isValidProtocol } from '../../lib/provider-catalog'; +import { + VENDOR_PRESETS, + PresetSchema, + findMatchingPresetForRecord, + getDefaultModelsForProvider, + getEffectiveProviderProtocol, + isValidProtocol, +} from '../../lib/provider-catalog'; +import { getProviderCompat } from '../../lib/runtime-compat'; describe('Preset Schema Validation', () => { for (const preset of VENDOR_PRESETS) { @@ -85,6 +93,35 @@ describe('Preset Schema Validation', () => { assert.notEqual(p!.sdkProxyOnly, true, 'openai-compatible uses the AI SDK path, not the Claude Code subprocess'); assert.notEqual(p!.meta?.claudeCodeVerified, true, 'claudeCodeVerified is only meaningful for anthropic presets'); }); + + it('atlascloud preset uses the OpenAI-compatible runtime path with live-verified defaults', () => { + const p = VENDOR_PRESETS.find(v => v.key === 'atlascloud'); + assert.ok(p, 'Atlas Cloud preset must exist'); + assert.equal(p!.protocol, 'openai-compatible'); + assert.equal(p!.authStyle, 'api_key'); + assert.equal(p!.baseUrl, 'https://api.atlascloud.ai/v1'); + assert.deepEqual(p!.fields, ['api_key']); + assert.equal(p!.sdkProxyOnly, undefined, 'Atlas Cloud uses the AI SDK path, not the Claude Code subprocess'); + assert.equal(p!.defaultRoleModels?.default, 'qwen/qwen3.5-flash'); + assert.equal(p!.defaultRoleModels?.reasoning, 'deepseek-ai/deepseek-v4-pro'); + assert.deepEqual( + p!.defaultModels.map(m => m.modelId), + ['qwen/qwen3.5-flash', 'deepseek-ai/deepseek-v4-pro'], + ); + + const models = getDefaultModelsForProvider('openai-compatible', 'https://api.atlascloud.ai/v1'); + assert.deepEqual(models.map(m => m.modelId), ['qwen/qwen3.5-flash', 'deepseek-ai/deepseek-v4-pro']); + + const match = findMatchingPresetForRecord({ + provider_type: 'openai-compatible', + base_url: 'https://api.atlascloud.ai/v1', + }); + assert.equal(match?.key, 'atlascloud'); + assert.equal( + getProviderCompat({ provider_type: 'openai-compatible', base_url: 'https://api.atlascloud.ai/v1' }), + 'codepilot_only', + ); + }); }); describe('toClaudeCodeEnv: env shape after CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST removal', () => { diff --git a/src/lib/provider-catalog.ts b/src/lib/provider-catalog.ts index 1326ebf0..56489f74 100644 --- a/src/lib/provider-catalog.ts +++ b/src/lib/provider-catalog.ts @@ -616,6 +616,38 @@ export const VENDOR_PRESETS: VendorPreset[] = [ }, }, + // ── Atlas Cloud ── + { + key: 'atlascloud', + name: 'Atlas Cloud', + description: 'Atlas Cloud OpenAI-compatible chat API (CodePilot / Codex runtimes)', + descriptionZh: 'Atlas Cloud OpenAI 兼容聊天 API(用于 CodePilot / Codex 运行时)', + protocol: 'openai-compatible', + authStyle: 'api_key', + baseUrl: 'https://api.atlascloud.ai/v1', + defaultEnvOverrides: {}, + defaultModels: [ + { modelId: 'qwen/qwen3.5-flash', displayName: 'Qwen3.5 Flash' }, + { + modelId: 'deepseek-ai/deepseek-v4-pro', + displayName: 'DeepSeek V4 Pro', + role: 'reasoning', + capabilities: { reasoning: true }, + }, + ], + defaultRoleModels: { + default: 'qwen/qwen3.5-flash', + reasoning: 'deepseek-ai/deepseek-v4-pro', + }, + fields: ['api_key'], + iconKey: 'server', + meta: { + apiKeyUrl: 'https://www.atlascloud.ai/console/api-keys', + docsUrl: 'https://api.atlascloud.ai/v1', + billingModel: 'pay_as_you_go', + }, + }, + // ── OpenRouter ── { key: 'openrouter',