From e0df34f043dff166e4f1995d08b858ba17876d54 Mon Sep 17 00:00:00 2001 From: jax-novita Date: Thu, 6 Aug 2026 22:29:29 +0800 Subject: [PATCH] feat(client): recognize Novita as a compatible provider for error links The extension already supports pointing `deepseek-copilot.baseUrl` at any OpenAI-compatible endpoint. Add Novita's API-key, usage, and status URLs so users on `api.novita.ai` get the same provider-aware 401/402/5xx action links DeepSeek users get, instead of falling back to the generic message. --- src/client/consts.ts | 12 ++++++++++++ src/client/error/index.ts | 10 ++++++++-- src/client/types.ts | 2 +- src/consts.ts | 5 +++++ src/endpoint.ts | 13 +++++++++++-- src/i18n.ts | 2 ++ 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/client/consts.ts b/src/client/consts.ts index 91d40db..5b19a15 100644 --- a/src/client/consts.ts +++ b/src/client/consts.ts @@ -16,18 +16,30 @@ export const API_PROVIDER_HTTP_ERROR_LINKS: Readonly< labelKey: 'error.action.createApiKey', url: EXTERNAL_URLS.deepseek.apiKeys, }, + novita: { + labelKey: 'error.action.createApiKey', + url: EXTERNAL_URLS.novita.apiKeys, + }, }, 402: { deepseek: { labelKey: 'error.action.viewUsage', url: EXTERNAL_URLS.deepseek.usage, }, + novita: { + labelKey: 'error.action.viewUsage', + url: EXTERNAL_URLS.novita.usage, + }, }, '5xx': { deepseek: { labelKey: 'error.action.checkDeepSeekStatus', url: EXTERNAL_URLS.deepseek.status, }, + novita: { + labelKey: 'error.action.checkNovitaStatus', + url: EXTERNAL_URLS.novita.status, + }, }, }; diff --git a/src/client/error/index.ts b/src/client/error/index.ts index ac34bc3..3e3d5fa 100644 --- a/src/client/error/index.ts +++ b/src/client/error/index.ts @@ -1,4 +1,4 @@ -import { isOfficialDeepSeekBaseUrl } from '../../endpoint'; +import { isNovitaBaseUrl, isOfficialDeepSeekBaseUrl } from '../../endpoint'; import { t } from '../../i18n'; import { safeStringify } from '../../json'; import { API_PROVIDER_HTTP_ERROR_LINKS, MAX_DIAGNOSTIC_FIELD_LENGTH } from '../consts'; @@ -319,7 +319,13 @@ function escapeBoldText(value: string): string { } function identifyApiProvider(baseUrl: string): ApiProviderId | undefined { - return isOfficialDeepSeekBaseUrl(baseUrl) ? 'deepseek' : undefined; + if (isOfficialDeepSeekBaseUrl(baseUrl)) { + return 'deepseek'; + } + if (isNovitaBaseUrl(baseUrl)) { + return 'novita'; + } + return undefined; } function getHttpErrorLinkStatusKey(status: number): HttpErrorLinkStatusKey | undefined { diff --git a/src/client/types.ts b/src/client/types.ts index 773932f..34a26cc 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -20,7 +20,7 @@ export interface HttpErrorLinkDefinition { url: string; } -export type ApiProviderId = 'deepseek'; +export type ApiProviderId = 'deepseek' | 'novita'; export type HttpErrorLinkStatusKey = 401 | 402 | '5xx'; export type DeepSeekRequestErrorKind = 'http' | 'network' | 'unknown'; diff --git a/src/consts.ts b/src/consts.ts index 92c9362..13f0672 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -17,6 +17,11 @@ export const EXTERNAL_URLS = { usage: 'https://platform.deepseek.com/usage', status: 'https://status.deepseek.com', }, + novita: { + apiKeys: 'https://novita.ai/settings/key-management', + usage: 'https://novita.ai/billing', + status: 'https://status.novita.ai', + }, } as const; /** URI path handled by this extension to reveal the output log. */ diff --git a/src/endpoint.ts b/src/endpoint.ts index 019ce07..2f53976 100644 --- a/src/endpoint.ts +++ b/src/endpoint.ts @@ -1,10 +1,19 @@ export const OFFICIAL_DEEPSEEK_API_HOST = 'api.deepseek.com'; +export const NOVITA_API_HOST = 'api.novita.ai'; export function isOfficialDeepSeekBaseUrl(baseUrl: string): boolean { + return getBaseUrlHostname(baseUrl) === OFFICIAL_DEEPSEEK_API_HOST; +} + +export function isNovitaBaseUrl(baseUrl: string): boolean { + return getBaseUrlHostname(baseUrl) === NOVITA_API_HOST; +} + +function getBaseUrlHostname(baseUrl: string): string | undefined { try { - return new URL(baseUrl).hostname.toLowerCase() === OFFICIAL_DEEPSEEK_API_HOST; + return new URL(baseUrl).hostname.toLowerCase(); } catch { - return false; + return undefined; } } diff --git a/src/i18n.ts b/src/i18n.ts index d5bb9a6..286da0e 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -181,6 +181,7 @@ const zh: Translations = { 'error.action.createApiKey': '创建 API Key', 'error.action.viewUsage': '用量', 'error.action.checkDeepSeekStatus': 'DeepSeek 状态', + 'error.action.checkNovitaStatus': 'Novita 状态', 'error.action.viewDetails': '错误详情', 'error.network.dns': '[{0}] DNS 解析失败。请检查网络连接、防火墙或代理设置,以及自定义 baseUrl。', 'error.network.unreachable': @@ -396,6 +397,7 @@ const en: Translations = { 'error.action.createApiKey': 'Create API Key', 'error.action.viewUsage': 'Usage', 'error.action.checkDeepSeekStatus': 'DeepSeek Status', + 'error.action.checkNovitaStatus': 'Novita Status', 'error.action.viewDetails': 'Error Details', 'error.network.dns': '[{0}] DNS lookup failed. Check your network connection, firewall, or proxy settings, and your custom baseUrl.',