mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-15 19:24:23 +08:00
feat(ai): add Atlas Cloud provider preset (#915)
## Background GoNavi supports OpenAI-compatible providers, but Atlas Cloud currently requires users to enter the endpoint and model manually. This adds a first-class preset while keeping the existing OpenAI-compatible runtime and remote model discovery path. ## Changes - add an Atlas Cloud provider preset with the default API endpoint and `qwen/qwen3.8-max` - recognize saved Atlas Cloud endpoints when reopening AI settings - add localized provider labels and descriptions for all supported locales - cover preset metadata and endpoint matching with focused tests ## Impact The change is additive. Existing providers and custom OpenAI-compatible configurations are unchanged. Users still supply their own API key. ## Validation - frontend focused tests: 39 passed - frontend full test suite: passed - frontend production build: passed - `go test ./internal/ai/provider ./internal/ai/service`: passed - Atlas Cloud `/models`: HTTP 200 and `qwen/qwen3.8-max` present - Atlas Cloud Chat Completions smoke test: HTTP 200 - `git diff --check`: passed ## Risk and rollback Risk is limited to the additive preset metadata and endpoint matching. Reverting this commit removes the preset without changing persisted provider schema or backend behavior.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
ATLAS_CLOUD_BASE_URL,
|
||||
ATLAS_CLOUD_DEFAULT_MODEL,
|
||||
QWEN_CODING_PLAN_ANTHROPIC_BASE_URL,
|
||||
resolvePresetBaseURL,
|
||||
resolvePresetTransport,
|
||||
@@ -53,6 +55,21 @@ describe('aiSettingsModalConfig', () => {
|
||||
expect(preset.key).toBe('cursor');
|
||||
});
|
||||
|
||||
it('exposes and recognizes the Atlas Cloud preset', () => {
|
||||
const preset = findPreset('atlascloud');
|
||||
|
||||
expect(preset).toMatchObject({
|
||||
label: 'Atlas Cloud',
|
||||
backendType: 'openai',
|
||||
defaultBaseUrl: ATLAS_CLOUD_BASE_URL,
|
||||
defaultModel: ATLAS_CLOUD_DEFAULT_MODEL,
|
||||
});
|
||||
expect(matchProviderPreset({
|
||||
type: 'openai',
|
||||
baseUrl: ATLAS_CLOUD_BASE_URL,
|
||||
}).key).toBe('atlascloud');
|
||||
});
|
||||
|
||||
it('supports every configured MiniMax region and protocol endpoint', () => {
|
||||
const preset = findPreset('minimax');
|
||||
|
||||
@@ -125,6 +142,7 @@ describe('aiSettingsModalConfig', () => {
|
||||
});
|
||||
|
||||
it('keeps the provider preset list available for the settings modal', () => {
|
||||
expect(PROVIDER_PRESETS.some((item) => item.key === 'atlascloud')).toBe(true);
|
||||
expect(PROVIDER_PRESETS.some((item) => item.key === 'codex')).toBe(true);
|
||||
expect(PROVIDER_PRESETS.some((item) => item.key === 'claude-subscription')).toBe(true);
|
||||
expect(PROVIDER_PRESETS.some((item) => item.key === 'codebuddy')).toBe(true);
|
||||
|
||||
@@ -16,6 +16,8 @@ import type {
|
||||
AIUserPromptSettings,
|
||||
} from '../../types';
|
||||
import {
|
||||
ATLAS_CLOUD_BASE_URL,
|
||||
ATLAS_CLOUD_DEFAULT_MODEL,
|
||||
QWEN_BAILIAN_ANTHROPIC_BASE_URL,
|
||||
QWEN_CODING_PLAN_ANTHROPIC_BASE_URL,
|
||||
QWEN_CODING_PLAN_MODELS,
|
||||
@@ -50,6 +52,7 @@ export const MINIMAX_ENDPOINTS: ProviderPresetEndpoint[] = [
|
||||
|
||||
export const PROVIDER_PRESETS: ProviderPreset[] = [
|
||||
{ key: 'openai', label: 'OpenAI', labelKey: 'ai_settings.provider_preset.openai.label', icon: <ApiOutlined />, desc: 'GPT-5.4 / 5.3 series', descKey: 'ai_settings.provider_preset.openai.desc', color: '#10b981', backendType: 'openai', defaultBaseUrl: 'https://api.openai.com/v1', defaultModel: 'gpt-4o', models: [] },
|
||||
{ key: 'atlascloud', label: 'Atlas Cloud', labelKey: 'ai_settings.provider_preset.atlascloud.label', icon: <CloudOutlined />, desc: 'Qwen3.8 Max / OpenAI-compatible', descKey: 'ai_settings.provider_preset.atlascloud.desc', color: '#0891b2', backendType: 'openai', defaultBaseUrl: ATLAS_CLOUD_BASE_URL, defaultModel: ATLAS_CLOUD_DEFAULT_MODEL, models: [] },
|
||||
{ key: 'codex', label: 'Codex Subscription', labelKey: 'ai_settings.provider_preset.codex.label', icon: <ApiOutlined />, desc: 'Local Codex CLI / ChatGPT subscription login', descKey: 'ai_settings.provider_preset.codex.desc', color: '#111827', backendType: 'custom', fixedApiFormat: 'codex-cli', authMode: 'local-cli', defaultBaseUrl: '', defaultModel: '', models: [] },
|
||||
{ key: 'deepseek', label: 'DeepSeek', labelKey: 'ai_settings.provider_preset.deepseek.label', icon: <ThunderboltOutlined />, desc: 'DeepSeek-V4 / R1', descKey: 'ai_settings.provider_preset.deepseek.desc', color: '#3b82f6', backendType: 'openai', defaultBaseUrl: 'https://api.deepseek.com/v1', defaultModel: 'deepseek-chat', models: [] },
|
||||
{ key: 'qwen-bailian', label: 'Qwen (Bailian General)', labelKey: 'ai_settings.provider_preset.qwen_bailian.label', icon: <CloudOutlined />, desc: 'Bailian Anthropic-compatible endpoint / remote model list', descKey: 'ai_settings.provider_preset.qwen_bailian.desc', color: '#6366f1', backendType: 'anthropic', defaultBaseUrl: QWEN_BAILIAN_ANTHROPIC_BASE_URL, defaultModel: '', models: [] },
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import type { AIProviderAuthMode, AIProviderType } from '../types';
|
||||
import {
|
||||
ATLAS_CLOUD_BASE_URL,
|
||||
LEGACY_QWEN_CODING_PLAN_OPENAI_BASE_URL,
|
||||
QWEN_BAILIAN_ANTHROPIC_BASE_URL,
|
||||
QWEN_BAILIAN_MODELS_BASE_URL,
|
||||
@@ -24,6 +25,7 @@ type PresetMatcher = {
|
||||
|
||||
const PRESETS: PresetMatcher[] = [
|
||||
{ key: 'openai', backendType: 'openai', defaultBaseUrl: 'https://api.openai.com/v1' },
|
||||
{ key: 'atlascloud', backendType: 'openai', defaultBaseUrl: ATLAS_CLOUD_BASE_URL },
|
||||
{ key: 'qwen-bailian', backendType: 'anthropic', defaultBaseUrl: QWEN_BAILIAN_ANTHROPIC_BASE_URL },
|
||||
{
|
||||
key: 'qwen-coding-plan',
|
||||
@@ -212,6 +214,13 @@ describe('ai provider preset helpers', () => {
|
||||
});
|
||||
|
||||
describe('resolveProviderPresetKey', () => {
|
||||
it('recognizes Atlas Cloud by its OpenAI-compatible endpoint', () => {
|
||||
expect(resolveProviderPresetKey({
|
||||
type: 'openai',
|
||||
baseUrl: `${ATLAS_CLOUD_BASE_URL}/`,
|
||||
}, PRESETS, 'custom')).toBe('atlascloud');
|
||||
});
|
||||
|
||||
it('不会把自定义 OpenAI 端点误识别成千问 Coding Plan', () => {
|
||||
const key = resolveProviderPresetKey(
|
||||
{
|
||||
|
||||
@@ -5,6 +5,8 @@ export const LEGACY_QWEN_CODING_PLAN_OPENAI_BASE_URL = 'https://coding.dashscope
|
||||
export const QWEN_BAILIAN_ANTHROPIC_BASE_URL = 'https://dashscope.aliyuncs.com/apps/anthropic';
|
||||
export const QWEN_CODING_PLAN_ANTHROPIC_BASE_URL = 'https://coding.dashscope.aliyuncs.com/apps/anthropic';
|
||||
export const QWEN_BAILIAN_MODELS_BASE_URL = LEGACY_QWEN_BAILIAN_OPENAI_BASE_URL;
|
||||
export const ATLAS_CLOUD_BASE_URL = 'https://api.atlascloud.ai/v1';
|
||||
export const ATLAS_CLOUD_DEFAULT_MODEL = 'qwen/qwen3.8-max';
|
||||
|
||||
export const QWEN_CODING_PLAN_MODELS = [
|
||||
'qwen3.5-plus',
|
||||
|
||||
@@ -2352,6 +2352,8 @@
|
||||
"ai_settings.provider.no_model": "Kein Modell ausgewählt",
|
||||
"ai_settings.provider_preset.anthropic.desc": "Claude Opus/Sonnet Modelle",
|
||||
"ai_settings.provider_preset.anthropic.label": "Claude",
|
||||
"ai_settings.provider_preset.atlascloud.desc": "Qwen3.8 Max / OpenAI-kompatibel",
|
||||
"ai_settings.provider_preset.atlascloud.label": "Atlas Cloud",
|
||||
"ai_settings.provider_preset.claude_subscription.desc": "Lokale Claude Code CLI / Claude-Abonnementanmeldung",
|
||||
"ai_settings.provider_preset.claude_subscription.label": "Claude-Abonnement",
|
||||
"ai_settings.provider_preset.codex.desc": "Lokale Codex CLI / ChatGPT-Abonnementanmeldung",
|
||||
|
||||
@@ -2352,6 +2352,8 @@
|
||||
"ai_settings.provider.no_model": "No model selected",
|
||||
"ai_settings.provider_preset.anthropic.desc": "Claude Opus/Sonnet",
|
||||
"ai_settings.provider_preset.anthropic.label": "Claude",
|
||||
"ai_settings.provider_preset.atlascloud.desc": "Qwen3.8 Max / OpenAI-compatible",
|
||||
"ai_settings.provider_preset.atlascloud.label": "Atlas Cloud",
|
||||
"ai_settings.provider_preset.claude_subscription.desc": "Local Claude Code CLI / Claude subscription login",
|
||||
"ai_settings.provider_preset.claude_subscription.label": "Claude Subscription",
|
||||
"ai_settings.provider_preset.codex.desc": "Local Codex CLI / ChatGPT subscription login",
|
||||
|
||||
@@ -2352,6 +2352,8 @@
|
||||
"ai_settings.provider.no_model": "モデル未選択",
|
||||
"ai_settings.provider_preset.anthropic.desc": "Claude Opus/Sonnet モデル",
|
||||
"ai_settings.provider_preset.anthropic.label": "Claude",
|
||||
"ai_settings.provider_preset.atlascloud.desc": "Qwen3.8 Max / OpenAI 互換",
|
||||
"ai_settings.provider_preset.atlascloud.label": "Atlas Cloud",
|
||||
"ai_settings.provider_preset.claude_subscription.desc": "ローカル Claude Code CLI / Claude サブスクリプションログイン",
|
||||
"ai_settings.provider_preset.claude_subscription.label": "Claude サブスクリプション",
|
||||
"ai_settings.provider_preset.codex.desc": "ローカル Codex CLI / ChatGPT サブスクリプションログイン",
|
||||
|
||||
@@ -2352,6 +2352,8 @@
|
||||
"ai_settings.provider.no_model": "Модель не выбрана",
|
||||
"ai_settings.provider_preset.anthropic.desc": "Модели Claude Opus/Sonnet",
|
||||
"ai_settings.provider_preset.anthropic.label": "Claude",
|
||||
"ai_settings.provider_preset.atlascloud.desc": "Qwen3.8 Max / совместимо с OpenAI",
|
||||
"ai_settings.provider_preset.atlascloud.label": "Atlas Cloud",
|
||||
"ai_settings.provider_preset.claude_subscription.desc": "Локальный Claude Code CLI / вход по подписке Claude",
|
||||
"ai_settings.provider_preset.claude_subscription.label": "Подписка Claude",
|
||||
"ai_settings.provider_preset.codex.desc": "Локальный Codex CLI / вход по подписке ChatGPT",
|
||||
|
||||
@@ -2352,6 +2352,8 @@
|
||||
"ai_settings.provider.no_model": "未选择模型",
|
||||
"ai_settings.provider_preset.anthropic.desc": "Claude Opus/Sonnet 模型",
|
||||
"ai_settings.provider_preset.anthropic.label": "Claude",
|
||||
"ai_settings.provider_preset.atlascloud.desc": "Qwen3.8 Max / OpenAI 兼容",
|
||||
"ai_settings.provider_preset.atlascloud.label": "Atlas Cloud",
|
||||
"ai_settings.provider_preset.claude_subscription.desc": "本机 Claude Code CLI / Claude 订阅登录态",
|
||||
"ai_settings.provider_preset.claude_subscription.label": "Claude 订阅",
|
||||
"ai_settings.provider_preset.codex.desc": "本机 Codex CLI / ChatGPT 订阅登录态",
|
||||
|
||||
@@ -2352,6 +2352,8 @@
|
||||
"ai_settings.provider.no_model": "尚未選擇模型",
|
||||
"ai_settings.provider_preset.anthropic.desc": "Claude Opus/Sonnet 模型",
|
||||
"ai_settings.provider_preset.anthropic.label": "Claude",
|
||||
"ai_settings.provider_preset.atlascloud.desc": "Qwen3.8 Max / OpenAI 相容",
|
||||
"ai_settings.provider_preset.atlascloud.label": "Atlas Cloud",
|
||||
"ai_settings.provider_preset.claude_subscription.desc": "本機 Claude Code CLI / Claude 訂閱登入狀態",
|
||||
"ai_settings.provider_preset.claude_subscription.label": "Claude 訂閱",
|
||||
"ai_settings.provider_preset.codex.desc": "本機 Codex CLI / ChatGPT 訂閱登入狀態",
|
||||
|
||||
Reference in New Issue
Block a user