diff --git a/README.md b/README.md index 0eb31be..1520f39 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Pure VS Code API + Node.js built-ins. No Python, no Docker, no local proxy serve - VS Code 1.116 or later. This extension relies on non-public Copilot Chat APIs that may break on newer VS Code versions — [report an issue](https://github.com/Vizards/deepseek-v4-for-copilot/issues) if you hit one. - GitHub Copilot subscription (Free / Pro / Enterprise — the free tier works) -- DeepSeek API key from [platform.deepseek.com](https://platform.deepseek.com), or a compatible provider token when using a custom `deepseek-copilot.baseUrl` +- DeepSeek API key from [platform.deepseek.com](https://platform.deepseek.com), a compatible provider token when using a custom `deepseek-copilot.baseUrl`, or an [OrcaRouter API key](https://www.orcarouter.ai/console/api-keys) when using the `orcarouter` provider ### Installation @@ -99,9 +99,10 @@ Both support optional thinking mode, tool calling, and 1M token context. | Setting | Default | Description | |---|---|---| -| `deepseek-copilot.baseUrl` | `https://api.deepseek.com` | API endpoint — change for self-hosted / proxied deployments | +| `deepseek-copilot.provider` | `deepseek` | API backend that serves the DeepSeek V4 models. `deepseek` uses the official API (or a custom `baseUrl`); `orcarouter` routes through the [OrcaRouter](https://www.orcarouter.ai) model gateway — set it and an OrcaRouter API key, and namespaced model IDs (`deepseek/deepseek-v4-flash`, `deepseek/deepseek-v4-pro`) are sent automatically | +| `deepseek-copilot.baseUrl` | `https://api.deepseek.com` | API endpoint — change for self-hosted / proxied deployments. Ignored when `deepseek-copilot.provider` is `orcarouter` | | `deepseek-copilot.maxTokens` | `0` | Max output tokens (`0` = no limit). Useful for cost control | -| `deepseek-copilot.modelIdOverrides` | prefilled official ID map | API model IDs to send for DeepSeek V4 Flash / Pro. Change only for compatible third-party APIs with different model names | +| `deepseek-copilot.modelIdOverrides` | prefilled official ID map | API model IDs to send for DeepSeek V4 Flash / Pro. Change only for compatible third-party APIs with different model names. Ignored when `deepseek-copilot.provider` is `orcarouter` | | `deepseek-copilot.debugMode` | `minimal` | Diagnostic mode: `minimal` for token usage only, `metadata` for privacy-preserving logs, or `verbose` for full request dumps and pipeline snapshots under extension global storage. Full dumps may include sensitive prompt text, tool schemas, file snippets, and image descriptions. Use `DeepSeek: Open Request Dumps Folder` to open the dump location | | `deepseek-copilot.visionModel` | *(auto)* | VS Code vision model used to proxy images. Configure from `DeepSeek: Configure Vision Proxy`; new saves use `vendor/id`, while legacy bare model IDs are still read | | `deepseek-copilot.visionPrompt` | *(built-in)* | Prompt used to describe image attachments | @@ -120,6 +121,18 @@ Example `settings.json` override for compatible API proxies: } ``` +### Use OrcaRouter as the backend + +Set `deepseek-copilot.provider` to `orcarouter` to serve DeepSeek V4 through [OrcaRouter](https://www.orcarouter.ai), an OpenAI-compatible model gateway that routes to the best available model and runs gateway-level, zero-trust security for AI agents — screening every prompt/response and governing every tool call on a default-deny basis, with no application code changes. + +```json +{ + "deepseek-copilot.provider": "orcarouter" +} +``` + +Then store your [OrcaRouter API key](https://www.orcarouter.ai/console/api-keys) with **DeepSeek: Set API Key**. Requests go to `https://api.orcarouter.ai/v1` with namespaced model IDs (`deepseek/deepseek-v4-flash`, `deepseek/deepseek-v4-pro`) and authentication failures link to the OrcaRouter console. The `deepseek-copilot.baseUrl` and `deepseek-copilot.modelIdOverrides` settings are ignored in this mode. + ## Compared to alternatives | | This extension | Local proxy (e.g. LiteLLM) | Standalone DeepSeek extensions | diff --git a/README.zh-cn.md b/README.zh-cn.md index 1dcbfa2..95dc478 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -70,7 +70,7 @@ API Key 存储在 VS Code 的 `SecretStorage` 中(macOS 钥匙串 / Windows - VS Code 1.116 及以上版本。本扩展依赖非公开的 Copilot Chat API,较新的 VS Code 版本可能存在兼容性问题——如遇到请[提交 Issue](https://github.com/Vizards/deepseek-v4-for-copilot/issues)。 - GitHub Copilot 订阅(Free / Pro / Enterprise——免费版即可使用) -- DeepSeek API Key,从 [platform.deepseek.com](https://platform.deepseek.com) 获取;使用自定义 `deepseek-copilot.baseUrl` 时也可使用兼容的 provider token +- DeepSeek API Key,从 [platform.deepseek.com](https://platform.deepseek.com) 获取;使用自定义 `deepseek-copilot.baseUrl` 时也可使用兼容的 provider token,或在使用 `orcarouter` provider 时使用 [OrcaRouter API Key](https://www.orcarouter.ai/console/api-keys) ### 安装方式 @@ -99,9 +99,10 @@ API Key 存储在 VS Code 的 `SecretStorage` 中(macOS 钥匙串 / Windows | 设置项 | 默认值 | 说明 | |---|---|---| -| `deepseek-copilot.baseUrl` | `https://api.deepseek.com` | API 端点——可改为自托管或代理部署地址 | +| `deepseek-copilot.provider` | `deepseek` | 为 DeepSeek V4 模型提供服务的 API 后端。`deepseek` 使用官方 API(或自定义 `baseUrl`);`orcarouter` 则通过 [OrcaRouter](https://www.orcarouter.ai) 模型网关路由——只需设置此项并填写 OrcaRouter API Key,模型 ID 会自动使用命名空间形式(`deepseek/deepseek-v4-flash`、`deepseek/deepseek-v4-pro`) | +| `deepseek-copilot.baseUrl` | `https://api.deepseek.com` | API 端点——可改为自托管或代理部署地址。当 `deepseek-copilot.provider` 为 `orcarouter` 时忽略此项 | | `deepseek-copilot.maxTokens` | `0` | 最大输出 Token 数(`0` = 不限制)。可用于成本控制 | -| `deepseek-copilot.modelIdOverrides` | 预填官方 ID 映射 | DeepSeek V4 Flash / Pro 对应的 API 模型 ID。仅在使用模型名不同的兼容第三方 API 时修改 | +| `deepseek-copilot.modelIdOverrides` | 预填官方 ID 映射 | DeepSeek V4 Flash / Pro 对应的 API 模型 ID。仅在使用模型名不同的兼容第三方 API 时修改。当 `deepseek-copilot.provider` 为 `orcarouter` 时忽略此项 | | `deepseek-copilot.debugMode` | `minimal` | 诊断模式:`minimal` 仅上报 token 用量,`metadata` 输出隐私安全日志,`verbose` 将完整请求 dump 和 pipeline snapshot 写入扩展 global storage。完整 dump 可能包含敏感提示词文本、工具定义、文件片段和图片描述。使用 `DeepSeek: 打开请求 Dump 目录` 打开 dump 位置 | | `deepseek-copilot.visionModel` | *(自动)* | 用作图片代理的 VS Code 视觉模型。请通过 `DeepSeek: 配置视觉代理` 设置;新版保存为 `vendor/id`,旧版裸模型 ID 仍兼容读取 | | `deepseek-copilot.visionPrompt` | *(内置)* | 用于描述图片附件的提示词 | @@ -120,6 +121,18 @@ API Key 存储在 VS Code 的 `SecretStorage` 中(macOS 钥匙串 / Windows } ``` +### 使用 OrcaRouter 作为后端 + +将 `deepseek-copilot.provider` 设为 `orcarouter`,即可通过 [OrcaRouter](https://www.orcarouter.ai) 调用 DeepSeek V4。OrcaRouter 是一个 OpenAI 兼容的模型网关,可路由到最优模型,并在网关层为 AI Agent 提供零信任安全——对每个提示词/响应进行筛查、对每次工具调用进行默认拒绝的管控,且无需改动任何应用代码。 + +```json +{ + "deepseek-copilot.provider": "orcarouter" +} +``` + +然后用 **DeepSeek: 设置 API Key** 保存你的 [OrcaRouter API Key](https://www.orcarouter.ai/console/api-keys)。请求将发送到 `https://api.orcarouter.ai/v1`,模型 ID 自动使用命名空间形式(`deepseek/deepseek-v4-flash`、`deepseek/deepseek-v4-pro`),认证失败时错误提示会链接到 OrcaRouter 控制台。此模式下 `deepseek-copilot.baseUrl` 与 `deepseek-copilot.modelIdOverrides` 设置会被忽略。 + ## 方案对比 | | 本扩展 | 本地代理(如 LiteLLM) | 独立 DeepSeek 扩展 | diff --git a/package.json b/package.json index c989e73..d9e2729 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "language model", "thinking", "reasoning", + "orcarouter", "ai", "chat" ], @@ -121,6 +122,23 @@ "default": "https://api.deepseek.com", "description": "%deepseek-copilot.config.baseUrl.description%" }, + "deepseek-copilot.provider": { + "type": "string", + "default": "deepseek", + "enum": [ + "deepseek", + "orcarouter" + ], + "enumItemLabels": [ + "%deepseek-copilot.config.provider.deepseek.label%", + "%deepseek-copilot.config.provider.orcarouter.label%" + ], + "markdownEnumDescriptions": [ + "%deepseek-copilot.config.provider.deepseek.description%", + "%deepseek-copilot.config.provider.orcarouter.description%" + ], + "markdownDescription": "%deepseek-copilot.config.provider.description%" + }, "deepseek-copilot.maxTokens": { "type": "number", "default": 0, diff --git a/package.nls.json b/package.nls.json index 31ad075..74f083e 100644 --- a/package.nls.json +++ b/package.nls.json @@ -15,7 +15,12 @@ "deepseek-copilot.walkthrough.advancedSettings.title": "Try advanced settings", "deepseek-copilot.walkthrough.advancedSettings.description": "Customize providers and model names, configure the vision proxy, enable experimental settings, and more in the extension settings.\n[Open settings](command:deepseek-copilot.openSettings)", "deepseek-copilot.config.title": "DeepSeek Copilot", - "deepseek-copilot.config.baseUrl.description": "DeepSeek API base URL. Defaults to official DeepSeek API endpoint.", + "deepseek-copilot.config.baseUrl.description": "DeepSeek API base URL. Defaults to official DeepSeek API endpoint. Ignored when `deepseek-copilot.provider` is `orcarouter`.", + "deepseek-copilot.config.provider.description": "API backend that serves the DeepSeek V4 models.\n\n- **DeepSeek** — Official DeepSeek API at `https://api.deepseek.com`. Use a [DeepSeek API key](https://platform.deepseek.com/api_keys).\n- **OrcaRouter** — Route DeepSeek V4 through [OrcaRouter](https://www.orcarouter.ai), an OpenAI-compatible model gateway. Use an [OrcaRouter API key](https://www.orcarouter.ai/console/api-keys); the model IDs `deepseek/deepseek-v4-flash` and `deepseek/deepseek-v4-pro` are sent automatically.", + "deepseek-copilot.config.provider.deepseek.label": "DeepSeek", + "deepseek-copilot.config.provider.deepseek.description": "Official DeepSeek API. Use a DeepSeek API key.", + "deepseek-copilot.config.provider.orcarouter.label": "OrcaRouter", + "deepseek-copilot.config.provider.orcarouter.description": "Route DeepSeek V4 through OrcaRouter. Use an OrcaRouter API key; model IDs are namespaced automatically.", "deepseek-copilot.config.maxTokens.description": "Maximum number of output tokens per request. Set to 0 to use the API default (no limit). Useful for controlling costs.", "deepseek-copilot.config.experimental.stabilizeToolList.description": "**Experimental**: improve DeepSeek context-cache hit rate by pre-activating available tools.\n- When the enabled tools list changes across turns, this may improve DeepSeek context-cache hit rate.\n- Requests will include more function definitions, so input tokens may increase. Cache-hit input tokens are billed at a lower price, but still count toward usage.\n- This may add internal preflight tool calls to the current Copilot chat history. If you switch to another model in the same conversation, that model provider may reject or mishandle the replayed history. Start a new chat if model switching behaves unexpectedly.\n\nUse [Configure Tools](command:workbench.action.chat.configureTools) to **view and manage** your tool list:\n\n- 64 or fewer enabled tools: usually no need to enable this unless the tool list still changes across turns.\n- More than 128 enabled tools: not recommended. DeepSeek supports at most 128 functions in one `tools` request. Consider disabling tools you rarely use.", "deepseek-copilot.config.debugMode.description": "Controls what diagnostic information DeepSeek Copilot writes. Token usage is always reported to Copilot regardless of this setting.\n\n- **Minimal** — Token usage only. No diagnostic logs or request dumps.\n- **Metadata** — Privacy-safe diagnostic metadata (request hashes, prefix overlap, tool schema changes). Does not contain prompt text — safe to share in public issue reports. View with [`DeepSeek: Show Logs`](command:deepseek-copilot.showLogs).\n- **Verbose** — Complete request payloads written to disk for local debugging. **Warning: contains sensitive prompt content.** View with [`DeepSeek: Open Request Dumps Folder`](command:deepseek-copilot.openRequestDumpsFolder).", @@ -25,7 +30,7 @@ "deepseek-copilot.config.debugMode.metadata.description": "Privacy-safe metadata. Safe to share publicly. View with `DeepSeek: Show Logs`.", "deepseek-copilot.config.debugMode.verbose.label": "Verbose", "deepseek-copilot.config.debugMode.verbose.description": "⚠️ Contains sensitive prompt content. For local debugging only.", - "deepseek-copilot.config.modelIdOverrides.description": "Override the API model ID sent for each DeepSeek model. Defaults are prefilled with official DeepSeek IDs; change them only when using a compatible third-party API that uses different model names.", + "deepseek-copilot.config.modelIdOverrides.description": "Override the API model ID sent for each DeepSeek model. Defaults are prefilled with official DeepSeek IDs; change them only when using a compatible third-party API that uses different model names. Ignored when `deepseek-copilot.provider` is `orcarouter`.", "deepseek-copilot.config.modelIdOverrides.deepseek-v4-flash.description": "API model ID for DeepSeek V4 Flash", "deepseek-copilot.config.modelIdOverrides.deepseek-v4-pro.description": "API model ID for DeepSeek V4 Pro", "deepseek-copilot.config.visionModel.description": "Compatibility setting managed by [Configure Vision Proxy](command:deepseek-copilot.setVisionModel). Stores the selected VS Code vision model as `vendor/id` when that source is active. Legacy bare model IDs are read for compatibility.", diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index b51354f..ea30d60 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -15,7 +15,12 @@ "deepseek-copilot.walkthrough.advancedSettings.title": "尝试高级设置", "deepseek-copilot.walkthrough.advancedSettings.description": "可以在插件设置中自定义提供方与模型名称、自定义视觉代理、开启实验性设置等。\n[打开设置](command:deepseek-copilot.openSettings)", "deepseek-copilot.config.title": "DeepSeek 助手", - "deepseek-copilot.config.baseUrl.description": "DeepSeek API 基础 URL,默认为官方 DeepSeek API 端点。", + "deepseek-copilot.config.baseUrl.description": "DeepSeek API 基础 URL,默认为官方 DeepSeek API 端点。当 `deepseek-copilot.provider` 为 `orcarouter` 时忽略此项。", + "deepseek-copilot.config.provider.description": "为 DeepSeek V4 模型提供服务的 API 后端。\n\n- **DeepSeek** — DeepSeek 官方 API(`https://api.deepseek.com`),使用 [DeepSeek API Key](https://platform.deepseek.com/api_keys)。\n- **OrcaRouter** — 通过 [OrcaRouter](https://www.orcarouter.ai) 模型网关调用 DeepSeek V4。使用 [OrcaRouter API Key](https://www.orcarouter.ai/console/api-keys),模型 ID 会自动使用命名空间形式(`deepseek/deepseek-v4-flash`、`deepseek/deepseek-v4-pro`)。", + "deepseek-copilot.config.provider.deepseek.label": "DeepSeek", + "deepseek-copilot.config.provider.deepseek.description": "DeepSeek 官方 API,使用 DeepSeek API Key。", + "deepseek-copilot.config.provider.orcarouter.label": "OrcaRouter", + "deepseek-copilot.config.provider.orcarouter.description": "通过 OrcaRouter 网关调用 DeepSeek V4,使用 OrcaRouter API Key,模型 ID 自动使用命名空间形式。", "deepseek-copilot.config.maxTokens.description": "每次请求的最大输出 Token 数,设为 0 则不限制,可用于控制成本。", "deepseek-copilot.config.experimental.stabilizeToolList.description": "**实验性功能**:通过预先激活可用的工具来提升 DeepSeek 上下文缓存命中率。\n- 当已启用工具列表跨轮次变化时,这可能提高 DeepSeek 上下文缓存命中率;\n- 请求中将包含更多函数工具定义,input tokens 可能增加,虽然缓存命中的 input tokens 单价更低,但仍会计入用量;\n- 此设置可能会在当前 Copilot 对话历史中加入内部预检工具调用。在同一对话中切换到其他模型时,部分模型提供方可能无法正确重放这段历史;如果切换模型后请求异常,请新建对话后重试。\n\n 通过 [配置工具](command:workbench.action.chat.configureTools) **查看和管理**工具列表:\n\n- 64 个或更少已启用工具时通常无需开启,除非工具列表仍在跨轮次变化;\n- 超过 128 个已启用工具时不建议开启:DeepSeek 单次 `tools` 请求最多支持 128 个 functions。考虑禁用部分不常用工具。", "deepseek-copilot.config.debugMode.description": "控制 DeepSeek Copilot 写入的诊断信息量。无论此设置如何,token 用量始终上报给 Copilot。\n\n- **基本** — 仅上报 token 用量,不输出诊断日志或请求 dump。\n- **元数据** — 隐私安全的诊断元数据(请求哈希、前缀重合度、工具定义变更)。不含提示词原文,可安全附在公开 issue 中反馈问题。使用 [`DeepSeek: 显示日志`](command:deepseek-copilot.showLogs) 查看。\n- **详细** — 将完整请求体写入磁盘,供本地调试。**警告:包含敏感的提示词内容。** 使用 [`DeepSeek: 打开请求 Dump 目录`](command:deepseek-copilot.openRequestDumpsFolder) 浏览。", @@ -25,7 +30,7 @@ "deepseek-copilot.config.debugMode.metadata.description": "隐私安全的元数据,可安全公开分享。使用 `DeepSeek: 显示日志` 查看。", "deepseek-copilot.config.debugMode.verbose.label": "详细", "deepseek-copilot.config.debugMode.verbose.description": "⚠️ 包含敏感的提示词内容,仅供本地调试。", - "deepseek-copilot.config.modelIdOverrides.description": "覆盖各 DeepSeek 模型实际使用的 API 模型 ID,默认使用官方 DeepSeek ID,仅在对接不同模型名称的第三方 API 时需要修改。", + "deepseek-copilot.config.modelIdOverrides.description": "覆盖各 DeepSeek 模型实际使用的 API 模型 ID,默认使用官方 DeepSeek ID,仅在对接不同模型名称的第三方 API 时需要修改。当 `deepseek-copilot.provider` 为 `orcarouter` 时忽略此项。", "deepseek-copilot.config.modelIdOverrides.deepseek-v4-flash.description": "DeepSeek V4 Flash 的 API 模型 ID。", "deepseek-copilot.config.modelIdOverrides.deepseek-v4-pro.description": "DeepSeek V4 Pro 的 API 模型 ID。", "deepseek-copilot.config.visionModel.description": "由[配置视觉代理](command:deepseek-copilot.setVisionModel)管理的兼容设置;当选择 VS Code 视觉模型来源时,以 `vendor/id` 保存所选模型。旧版裸模型 ID 仍会兼容读取。", diff --git a/src/client/consts.ts b/src/client/consts.ts index 91d40db..7d59c73 100644 --- a/src/client/consts.ts +++ b/src/client/consts.ts @@ -16,12 +16,20 @@ export const API_PROVIDER_HTTP_ERROR_LINKS: Readonly< labelKey: 'error.action.createApiKey', url: EXTERNAL_URLS.deepseek.apiKeys, }, + orcarouter: { + labelKey: 'error.action.createApiKey', + url: EXTERNAL_URLS.orcarouter.apiKeys, + }, }, 402: { deepseek: { labelKey: 'error.action.viewUsage', url: EXTERNAL_URLS.deepseek.usage, }, + orcarouter: { + labelKey: 'error.action.viewUsage', + url: EXTERNAL_URLS.orcarouter.usage, + }, }, '5xx': { deepseek: { diff --git a/src/client/error/index.ts b/src/client/error/index.ts index ac34bc3..3afbaf6 100644 --- a/src/client/error/index.ts +++ b/src/client/error/index.ts @@ -1,4 +1,4 @@ -import { isOfficialDeepSeekBaseUrl } from '../../endpoint'; +import { isOfficialDeepSeekBaseUrl, isOrcaRouterBaseUrl } 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,9 @@ function escapeBoldText(value: string): string { } function identifyApiProvider(baseUrl: string): ApiProviderId | undefined { - return isOfficialDeepSeekBaseUrl(baseUrl) ? 'deepseek' : undefined; + if (isOfficialDeepSeekBaseUrl(baseUrl)) return 'deepseek'; + if (isOrcaRouterBaseUrl(baseUrl)) return 'orcarouter'; + return undefined; } function getHttpErrorLinkStatusKey(status: number): HttpErrorLinkStatusKey | undefined { diff --git a/src/client/types.ts b/src/client/types.ts index 773932f..ca489e3 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' | 'orcarouter'; export type HttpErrorLinkStatusKey = 401 | 402 | '5xx'; export type DeepSeekRequestErrorKind = 'http' | 'network' | 'unknown'; diff --git a/src/config.ts b/src/config.ts index 477ca09..9cbca99 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,25 +1,64 @@ import vscode from 'vscode'; import { CONFIG_SECTION } from './consts'; +import { ORCAROUTER_API_BASE } from './endpoint'; export type DebugMode = 'minimal' | 'metadata' | 'verbose'; +/** API backend that serves the DeepSeek V4 models. */ +export type ProviderId = 'deepseek' | 'orcarouter'; + +/** + * Selected provider for the DeepSeek V4 models. + * + * `deepseek` uses the official API (or a custom `baseUrl`/`modelIdOverrides` + * for compatible third-party endpoints). `orcarouter` is a named preset that + * routes through the [OrcaRouter](https://www.orcarouter.ai) model gateway + * with namespaced model IDs and its own error links. + */ +export function getProvider(): ProviderId { + const config = vscode.workspace.getConfiguration(CONFIG_SECTION); + return config.get('provider') === 'orcarouter' ? 'orcarouter' : 'deepseek'; +} + /** * Get DeepSeek API base URL from settings. * Falls back to the official endpoint when not configured. + * + * The `orcarouter` provider always uses the OrcaRouter gateway endpoint. */ export function getBaseUrl(): string { const config = vscode.workspace.getConfiguration(CONFIG_SECTION); + if (getProvider() === 'orcarouter') { + return ORCAROUTER_API_BASE; + } return config.get('baseUrl') || 'https://api.deepseek.com'; } +/** + * Namespaced model IDs used by the OrcaRouter gateway. + * OrcaRouter rejects bare model names, so `deepseek-v4-flash` becomes + * `deepseek/deepseek-v4-flash` etc. + */ +const ORCAROUTER_MODEL_ID_MAP: Readonly> = { + 'deepseek-v4-flash': 'deepseek/deepseek-v4-flash', + 'deepseek-v4-pro': 'deepseek/deepseek-v4-pro', +}; + /** * Resolve the API model ID to send to the endpoint. * * Users can override model IDs via the `modelIdOverrides` setting object * (e.g. for third-party API proxies). Falls back to the VS Code model ID * when no override is configured. + * + * The `orcarouter` provider maps to namespaced gateway IDs automatically and + * ignores `modelIdOverrides`. */ export function getApiModelId(vscodeModelId: string): string { + if (getProvider() === 'orcarouter') { + return ORCAROUTER_MODEL_ID_MAP[vscodeModelId] ?? vscodeModelId; + } + const config = vscode.workspace.getConfiguration(CONFIG_SECTION); const overrides = config.get>('modelIdOverrides'); const override = overrides?.[vscodeModelId]?.trim(); diff --git a/src/consts.ts b/src/consts.ts index 52b93e5..7dce9e2 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -17,6 +17,10 @@ export const EXTERNAL_URLS = { usage: 'https://platform.deepseek.com/usage', status: 'https://status.deepseek.com', }, + orcarouter: { + apiKeys: 'https://www.orcarouter.ai/console/api-keys', + usage: 'https://www.orcarouter.ai/console', + }, } 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..3ac9da4 100644 --- a/src/endpoint.ts +++ b/src/endpoint.ts @@ -1,5 +1,11 @@ export const OFFICIAL_DEEPSEEK_API_HOST = 'api.deepseek.com'; +/** OrcaRouter model gateway host (OpenAI-compatible). */ +export const ORCAROUTER_API_HOST = 'api.orcarouter.ai'; + +/** OrcaRouter OpenAI-compatible endpoint used by the `orcarouter` provider. */ +export const ORCAROUTER_API_BASE = 'https://api.orcarouter.ai/v1'; + export function isOfficialDeepSeekBaseUrl(baseUrl: string): boolean { try { return new URL(baseUrl).hostname.toLowerCase() === OFFICIAL_DEEPSEEK_API_HOST; @@ -8,6 +14,14 @@ export function isOfficialDeepSeekBaseUrl(baseUrl: string): boolean { } } +export function isOrcaRouterBaseUrl(baseUrl: string): boolean { + try { + return new URL(baseUrl).hostname.toLowerCase() === ORCAROUTER_API_HOST; + } catch { + return false; + } +} + export function normalizeBaseUrl(baseUrl: string): string { return baseUrl.trim().replace(/\/+$/u, ''); } diff --git a/src/provider/index.ts b/src/provider/index.ts index 0456a58..924ac46 100644 --- a/src/provider/index.ts +++ b/src/provider/index.ts @@ -54,7 +54,8 @@ export class DeepSeekChatProvider implements vscode.LanguageModelChatProvider { vscode.workspace.onDidChangeConfiguration((e) => { if ( e.affectsConfiguration('deepseek-copilot.apiKey') || - e.affectsConfiguration('deepseek-copilot.baseUrl') + e.affectsConfiguration('deepseek-copilot.baseUrl') || + e.affectsConfiguration('deepseek-copilot.provider') ) { this.invalidateCurrencyAndRefreshModels(); }