diff --git a/README.md b/README.md index c028e26..bfd8ece 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ **Pick DeepSeek V4 from the Copilot Chat model picker — and keep everything else Copilot already gives you.**

- DeepSeek V4 Pro and Flash in the Copilot Chat model picker, with the per-model Thinking Effort dropdown (None / High / Max) + DeepSeek V4 Pro and Flash in the Copilot Chat model picker, with a per-model Thinking Effort dropdown

Love DeepSeek's price-performance but don't want to give up GitHub Copilot's agent mode, tool calling, and polished UI? This extension drops **DeepSeek V4 Pro & Flash** straight into the Copilot Chat model selector — with **vision**, **thinking mode**, and your own API key. @@ -45,7 +45,7 @@ This proxy is a compatibility bridge; if DeepSeek native vision becomes availabl

### Thinking Mode with Reasoning Effort Control -Full support for DeepSeek V4's `reasoning_content`. Use Copilot Chat's native model picker menu to choose `none` (off), `high` (balanced, default), or `max` (deep reasoning for hard agent tasks). +Full support for DeepSeek V4's `reasoning_content`. DeepSeek V4 Flash offers `none` (off), `low` (light reasoning), `high` (balanced, default), and `max` (deep reasoning for hard agent tasks). DeepSeek V4 Pro currently offers `none`, `high`, and `max`, matching the effort levels implemented by the official API. ### Inherits Every Copilot Capability Because this plugs into Copilot's native provider API, you get the full stack for free: @@ -88,10 +88,10 @@ Install from the registry used by your editor: ## Models -| Model | Best For | -|---|---| -| **DeepSeek V4 Flash** | Fast everyday coding, quick edits, cheap iteration | -| **DeepSeek V4 Pro** | Complex refactors, agent tasks, deep reasoning | +| Model | Thinking Effort | Best For | +|---|---|---| +| **DeepSeek V4 Flash** | `none` / `low` / `high` / `max` | Fast everyday coding, quick edits, cheap iteration | +| **DeepSeek V4 Pro** | `none` / `high` / `max` | Complex refactors, agent tasks, deep reasoning | Both support optional thinking mode, tool calling, and 1M token context. diff --git a/README.zh-cn.md b/README.zh-cn.md index cac586a..aad256f 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -18,7 +18,7 @@ **在 Copilot Chat 模型选择器中直接使用 DeepSeek V4——无需离开你熟悉的 Copilot 工作流。**

- DeepSeek V4 Pro 和 Flash 出现在 Copilot Chat 模型选择器中,带有可按模型独立设置的思考深度下拉菜单(停用 / 标准 / 深度) + DeepSeek V4 Pro 和 Flash 出现在 Copilot Chat 模型选择器中,带有可按模型独立设置的思考深度下拉菜单

喜欢 DeepSeek 的性价比,但不想放弃 GitHub Copilot 的 Agent 模式、工具调用和成熟的交互体验?本扩展将 **DeepSeek V4 Pro 和 Flash** 直接接入 Copilot Chat 模型选择器,支持**视觉识别**、**思考模式**,使用你自己的 API Key。 @@ -45,7 +45,7 @@ DeepSeek V4 是纯文本模型。将截图拖入聊天,本扩展会自动将

### 思考模式与推理深度控制 -完整支持 DeepSeek V4 的 `reasoning_content`。通过 Copilot Chat 模型选择器的菜单选择 `停用`、`标准`(均衡,默认)或 `深度`(适用于复杂 Agent 任务)。 +完整支持 DeepSeek V4 的 `reasoning_content`。DeepSeek V4 Flash 可选择 `停用`、`轻量`、`标准`(均衡,默认)或 `深度`(适用于复杂 Agent 任务);DeepSeek V4 Pro 目前提供 `停用`、`标准` 和 `深度`,与官方 API 已实现的推理档位保持一致。 ### 继承全部 Copilot 能力 由于本扩展接入的是 Copilot 的原生 provider API,你免费获得完整能力栈: @@ -88,10 +88,10 @@ API Key 存储在 VS Code 的 `SecretStorage` 中(macOS 钥匙串 / Windows ## 模型 -| 模型 | 适用场景 | -|---|---| -| **DeepSeek V4 Flash** | 日常快速编码、小改动、低成本迭代 | -| **DeepSeek V4 Pro** | 复杂重构、Agent 任务、深度推理 | +| 模型 | 思考深度 | 适用场景 | +|---|---|---| +| **DeepSeek V4 Flash** | `停用` / `轻量` / `标准` / `深度` | 日常快速编码、小改动、低成本迭代 | +| **DeepSeek V4 Pro** | `停用` / `标准` / `深度` | 复杂重构、Agent 任务、深度推理 | 两者均支持可选的思考模式、工具调用和 1M Token 上下文。 diff --git a/src/consts.ts b/src/consts.ts index b087544..92c9362 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -59,7 +59,11 @@ export const MODELS: ModelDefinition[] = [ capabilities: { toolCalling: DEEPSEEK_TOOLS_LIMIT, imageInput: true, - thinking: true, + thinking: { + supportedEfforts: ['low', 'high', 'max'], + defaultEffort: 'high', + canDisable: true, + }, }, requiresThinkingParam: true, pricing: { @@ -79,7 +83,11 @@ export const MODELS: ModelDefinition[] = [ capabilities: { toolCalling: DEEPSEEK_TOOLS_LIMIT, imageInput: true, - thinking: true, + thinking: { + supportedEfforts: ['high', 'max'], + defaultEffort: 'high', + canDisable: true, + }, }, requiresThinkingParam: true, pricing: { diff --git a/src/i18n.ts b/src/i18n.ts index 847eac4..d5bb9a6 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -37,6 +37,8 @@ const zh: Translations = { 'status.thinking': '思考模式', 'thinking.none': '停用', 'thinking.none.desc': '停用思考,响应更快', + 'thinking.low': '轻量', + 'thinking.low.desc': '轻量推理,适合快速编辑和简单任务', 'thinking.high': '标准', 'thinking.high.desc': '推荐日常使用', 'thinking.max': '深度', @@ -227,6 +229,8 @@ const en: Translations = { 'status.thinking': 'Thinking Effort', 'thinking.none': 'None', 'thinking.none.desc': 'Disable thinking for faster responses', + 'thinking.low': 'Low', + 'thinking.low.desc': 'Light reasoning for quick edits and simple tasks', 'thinking.high': 'High', 'thinking.high.desc': 'Recommended for most tasks', 'thinking.max': 'Max', diff --git a/src/provider/models.ts b/src/provider/models.ts index 010e30b..4a9de50 100644 --- a/src/provider/models.ts +++ b/src/provider/models.ts @@ -1,6 +1,11 @@ import vscode from 'vscode'; import { t } from '../i18n'; -import type { ModelDefinition, PricingCurrency } from '../types'; +import type { + ModelDefinition, + PricingCurrency, + ReasoningEffort, + ThinkingCapability, +} from '../types'; import { toModelCostInfo, type ModelCostInformation } from './pricing/costs'; /** @@ -14,7 +19,7 @@ import { toModelCostInfo, type ModelCostInformation } from './pricing/costs'; * metadata and per-model configuration controls. */ -export type ThinkingEffort = 'none' | 'high' | 'max'; +export type ThinkingEffort = 'none' | ReasoningEffort; export type ModelConfigurationOptions = vscode.ProvideLanguageModelChatResponseOptions & { readonly modelConfiguration?: Record; @@ -38,6 +43,7 @@ export function toChatInfo( ): ModelPickerChatInformation { const modelDetail = resolveModelText(m, 'detail') ?? m.detail; const modelTooltip = resolveModelText(m, 'tooltip'); + const thinkingCapability = m.capabilities.thinking; return { id: m.id, name: m.name, @@ -55,45 +61,58 @@ export function toChatInfo( imageInput: m.capabilities.imageInput, }, ...toModelCostInfo(m, pricingCurrency), - ...(m.capabilities.thinking ? { configurationSchema: buildThinkingEffortSchema() } : {}), + ...(thinkingCapability + ? { configurationSchema: buildThinkingEffortSchema(thinkingCapability) } + : {}), }; } -export function getConfiguredThinkingEffort(options: ModelConfigurationOptions): ThinkingEffort { +export function getConfiguredThinkingEffort( + options: ModelConfigurationOptions, + thinkingCapability: ThinkingCapability, +): ThinkingEffort { const configuredEffort = options.modelConfiguration?.reasoningEffort ?? options.configuration?.reasoningEffort; - if (configuredEffort === 'none') { + if (configuredEffort === 'none' && thinkingCapability.canDisable) { return 'none'; } - if (configuredEffort === 'high') { - return 'high'; + if (isSupportedReasoningEffort(configuredEffort, thinkingCapability)) { + return configuredEffort; } - return configuredEffort === 'max' ? 'max' : 'high'; + return thinkingCapability.defaultEffort; } -function buildThinkingEffortSchema() { +function buildThinkingEffortSchema(thinkingCapability: ThinkingCapability) { + const efforts: ThinkingEffort[] = [ + ...(thinkingCapability.canDisable ? (['none'] as const) : []), + ...thinkingCapability.supportedEfforts, + ]; + return { properties: { reasoningEffort: { type: 'string', title: t('status.thinking'), - enum: ['none', 'high', 'max'], - enumItemLabels: [t('thinking.none'), t('thinking.high'), t('thinking.max')], - enumDescriptions: [ - t('thinking.none.desc'), - t('thinking.high.desc'), - t('thinking.max.desc'), - ], - default: 'high', + enum: efforts, + enumItemLabels: efforts.map((effort) => t(`thinking.${effort}`)), + enumDescriptions: efforts.map((effort) => t(`thinking.${effort}.desc`)), + default: thinkingCapability.defaultEffort, group: 'navigation', }, }, } as const; } +function isSupportedReasoningEffort( + value: unknown, + thinkingCapability: ThinkingCapability, +): value is ReasoningEffort { + return thinkingCapability.supportedEfforts.some((effort) => effort === value); +} + function resolveModelText(m: ModelDefinition, field: 'detail' | 'tooltip'): string | undefined { const suffix = m.id.startsWith('deepseek-v4-') ? m.id.slice('deepseek-v4-'.length) : m.id; const key = `model.${suffix}.${field}`; diff --git a/src/provider/request.ts b/src/provider/request.ts index c143325..0ee62a8 100644 --- a/src/provider/request.ts +++ b/src/provider/request.ts @@ -64,7 +64,8 @@ export async function prepareChatRequest({ const baseUrl = getBaseUrl(); const client = new DeepSeekClient(baseUrl, apiKey); const modelDef = MODELS.find((m) => m.id === modelInfo.id); - const isThinkingModel = modelDef?.capabilities.thinking ?? false; + const thinkingCapability = modelDef?.capabilities.thinking; + const isThinkingModel = Boolean(thinkingCapability); const maxTokens = getMaxTokens(); const visionResolution = await resolveImageMessages(messages, token, getVisionDescriber); @@ -85,9 +86,9 @@ export async function prepareChatRequest({ request: baseRequest, inputMessages: messages, }); - const configuredThinkingEffort = getConfiguredThinkingEffort( - options as ModelConfigurationOptions, - ); + const configuredThinkingEffort = thinkingCapability + ? getConfiguredThinkingEffort(options as ModelConfigurationOptions, thinkingCapability) + : 'none'; // Only force helper requests into disabled thinking on the official API. // Custom endpoints keep their configured effort to preserve pre-#137 request shape. const forceNoneThinking = diff --git a/src/types.ts b/src/types.ts index f9e9689..92e19cf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,6 +4,9 @@ // ---- API request/response types ---- +/** API-level reasoning efforts. Disabling thinking is modeled separately. */ +export type ReasoningEffort = 'low' | 'high' | 'max'; + export interface DeepSeekMessage { role: 'system' | 'user' | 'assistant' | 'tool'; content: string; @@ -48,7 +51,7 @@ export interface DeepSeekRequest { tools?: DeepSeekTool[]; tool_choice?: 'none' | 'auto' | 'required'; thinking?: { type: 'enabled' | 'disabled' }; - reasoning_effort?: 'high' | 'max'; + reasoning_effort?: ReasoningEffort; stream_options?: { include_usage: boolean; }; @@ -103,6 +106,13 @@ export interface ModelPricing { output: number; } +export interface ThinkingCapability { + /** Effort values this model implements and may receive in API requests. */ + supportedEfforts: readonly ReasoningEffort[]; + defaultEffort: ReasoningEffort; + canDisable: boolean; +} + export interface ModelDefinition { id: string; name: string; @@ -114,7 +124,7 @@ export interface ModelDefinition { capabilities: { toolCalling: boolean | number; imageInput: boolean; - thinking: boolean; + thinking: ThinkingCapability | false; }; requiresThinkingParam: boolean; pricing?: Readonly>;