Skip to content

Commit 4a67cd3

Browse files
authored
refactor: reorganize project structure (#9)
- Extract pure settings reads from AuthManager into config.ts (`getBaseUrl`, `getApiModelId`, `getMaxTokens`) - Centralize all compile-time constants into consts.ts (9 constants from 5 files), group by chapter with JSDoc - Inline findModel helper - Replace `import * as vscode` with default import (`esModuleInterop`) - Remove `MODELS` from `types.ts` → `consts.ts` for cleaner type-only module
1 parent de132ca commit 4a67cd3

10 files changed

Lines changed: 153 additions & 107 deletions

File tree

src/auth.ts

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import * as vscode from 'vscode';
2-
3-
const API_KEY_SECRET = 'deepseek-copilot.apiKey';
1+
import vscode from 'vscode';
2+
import { API_KEY_SECRET } from './consts';
43

54
/**
65
* Manages DeepSeek API key via VS Code SecretStorage (secure) with
@@ -81,32 +80,4 @@ export class AuthManager {
8180

8281
return false;
8382
}
84-
85-
/**
86-
* Get base URL from settings.
87-
*/
88-
getBaseUrl(): string {
89-
const config = vscode.workspace.getConfiguration('deepseek-copilot');
90-
return config.get<string>('baseUrl') || 'https://api.deepseek.com';
91-
}
92-
93-
/**
94-
* Resolve the API model ID to send to the DeepSeek endpoint.
95-
* Users can override the default IDs via settings to support compatible APIs.
96-
*/
97-
getApiModelId(vscodeModelId: string): string {
98-
const config = vscode.workspace.getConfiguration('deepseek-copilot');
99-
const overrides = config.get<Record<string, string>>('modelIdOverrides');
100-
const override = overrides?.[vscodeModelId]?.trim();
101-
return override || vscodeModelId;
102-
}
103-
104-
/**
105-
* Get max tokens limit (0 = no limit).
106-
*/
107-
getMaxTokens(): number | undefined {
108-
const config = vscode.workspace.getConfiguration('deepseek-copilot');
109-
const value = config.get<number>('maxTokens', 0);
110-
return value > 0 ? value : undefined;
111-
}
11283
}

src/config.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import vscode from 'vscode';
2+
import { CONFIG_SECTION } from './consts';
3+
4+
/**
5+
* Get DeepSeek API base URL from settings.
6+
* Falls back to the official endpoint when not configured.
7+
*/
8+
export function getBaseUrl(): string {
9+
const config = vscode.workspace.getConfiguration(CONFIG_SECTION);
10+
return config.get<string>('baseUrl') || 'https://api.deepseek.com';
11+
}
12+
13+
/**
14+
* Resolve the API model ID to send to the endpoint.
15+
*
16+
* Users can override model IDs via the `modelIdOverrides` setting object
17+
* (e.g. for third-party API proxies). Falls back to the VS Code model ID
18+
* when no override is configured.
19+
*/
20+
export function getApiModelId(vscodeModelId: string): string {
21+
const config = vscode.workspace.getConfiguration(CONFIG_SECTION);
22+
const overrides = config.get<Record<string, string>>('modelIdOverrides');
23+
const override = overrides?.[vscodeModelId]?.trim();
24+
return override || vscodeModelId;
25+
}
26+
27+
/**
28+
* Get the configured max output tokens limit.
29+
* Returns `undefined` when set to 0 (API default — no limit).
30+
*/
31+
export function getMaxTokens(): number | undefined {
32+
const config = vscode.workspace.getConfiguration(CONFIG_SECTION);
33+
const value = config.get<number>('maxTokens', 0);
34+
return value > 0 ? value : undefined;
35+
}

src/consts.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import type { ModelDefinition } from './types';
2+
3+
/**
4+
* Compile-time constants shared across the extension.
5+
*
6+
* These do NOT depend on the VS Code runtime (no workspace configuration,
7+
* no secrets API). For run-time settings reads see `config.ts`.
8+
*/
9+
10+
/** VS Code configuration section prefix for all extension settings. */
11+
export const CONFIG_SECTION = 'deepseek-copilot';
12+
13+
// ---- Secret keys ----
14+
15+
/** SecretStorage key for the DeepSeek API key. */
16+
export const API_KEY_SECRET = 'deepseek-copilot.apiKey';
17+
18+
/** memento key tracking whether the welcome walkthrough has been shown. */
19+
export const WELCOME_SHOWN_KEY = 'deepseek-copilot.welcomeShown';
20+
21+
// ---- Walkthrough ----
22+
23+
/** Walkthrough contribution ID. */
24+
export const WALKTHROUGH_ID = 'Vizards.deepseek-v4-for-copilot#deepseekGettingStarted';
25+
26+
// ---- Model picker ----
27+
28+
/** Detail text shown in the model picker when no API key is configured. */
29+
export const API_KEY_REQUIRED_DETAIL = 'Please run DeepSeek: Set API Key to configure.';
30+
31+
/** Per-model configuration schema consumed by Copilot Chat's model picker. */
32+
export const THINKING_EFFORT_CONFIGURATION_SCHEMA = {
33+
properties: {
34+
reasoningEffort: {
35+
type: 'string',
36+
title: 'Thinking Effort',
37+
enum: ['none', 'high', 'max'],
38+
enumItemLabels: ['None', 'High', 'Max'],
39+
enumDescriptions: [
40+
'Disable thinking for faster responses',
41+
'Recommended for most tasks',
42+
'Maximum reasoning depth for complex agent tasks',
43+
],
44+
default: 'high',
45+
group: 'navigation',
46+
},
47+
},
48+
} as const;
49+
50+
// ---- Vision proxy ----
51+
52+
/** Default model ID used for the vision proxy when auto-detection is enabled. */
53+
export const DEFAULT_VISION_MODEL_ID = 'oswe-vscode-prime';
54+
55+
/**
56+
* Prompt sent to the vision proxy model when describing image attachments
57+
* before forwarding them to text-only DeepSeek models.
58+
*/
59+
export const IMAGE_DESCRIPTION_PROMPT =
60+
'Describe the visual contents of this image in detail, including any text, objects, people, or context that would be relevant for understanding it. Focus on factual visual elements.';
61+
62+
// ---- Cache ----
63+
64+
/** Max entries in the reasoning-content cache before eviction kicks in. */
65+
export const MAX_CACHE_SIZE = 200;
66+
67+
// ---- Model registry ----
68+
69+
/** Available DeepSeek models exposed through the language model provider. */
70+
export const MODELS: ModelDefinition[] = [
71+
{
72+
id: 'deepseek-v4-flash',
73+
name: 'DeepSeek V4 Flash',
74+
family: 'deepseek',
75+
version: 'v4',
76+
detail: 'Fast, general-purpose model',
77+
maxInputTokens: 1048576,
78+
maxOutputTokens: 393216,
79+
capabilities: {
80+
toolCalling: true,
81+
imageInput: true,
82+
thinking: true,
83+
},
84+
requiresThinkingParam: true,
85+
},
86+
{
87+
id: 'deepseek-v4-pro',
88+
name: 'DeepSeek V4 Pro',
89+
family: 'deepseek',
90+
version: 'v4',
91+
detail: 'Most capable reasoning model',
92+
maxInputTokens: 1048576,
93+
maxOutputTokens: 393216,
94+
capabilities: {
95+
toolCalling: true,
96+
imageInput: true,
97+
thinking: true,
98+
},
99+
requiresThinkingParam: true,
100+
},
101+
];

src/extension.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import * as vscode from 'vscode';
1+
import vscode from 'vscode';
2+
import { WALKTHROUGH_ID, WELCOME_SHOWN_KEY } from './consts';
23
import { logger } from './logger';
34
import { DeepSeekChatProvider } from './provider';
45

5-
const WELCOME_SHOWN_KEY = 'deepseek-copilot.welcomeShown';
6-
const WALKTHROUGH_ID = 'Vizards.deepseek-v4-for-copilot#deepseekGettingStarted';
7-
86
let activeProvider: DeepSeekChatProvider | undefined;
97

108
export function activate(context: vscode.ExtensionContext) {

src/logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as vscode from 'vscode';
1+
import vscode from 'vscode';
22

33
let channel: vscode.OutputChannel | undefined;
44

src/provider/cache.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { MAX_CACHE_SIZE } from '../consts';
2+
13
/**
24
* Reasoning cache: persists across turns so multi-turn tool-call conversations
35
* can inject reasoning_content back into prior assistant messages.
@@ -14,8 +16,6 @@ export interface ReasoningEntry {
1416
timestamp: number;
1517
}
1618

17-
export const MAX_CACHE_SIZE = 200;
18-
1919
export function pruneReasoningCache(
2020
cache: Map<string, ReasoningEntry>,
2121
clearAll: boolean,

src/provider/convert.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as vscode from 'vscode';
1+
import vscode from 'vscode';
22
import type { DeepSeekMessage, DeepSeekTool, DeepSeekToolCall } from '../types';
33
import type { ReasoningEntry } from './cache';
44

src/provider/index.ts

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import * as vscode from 'vscode';
1+
import vscode from 'vscode';
22
import { AuthManager } from '../auth';
33
import { DeepSeekClient } from '../client';
4+
import { getApiModelId, getBaseUrl, getMaxTokens } from '../config';
5+
import { API_KEY_REQUIRED_DETAIL, MODELS, THINKING_EFFORT_CONFIGURATION_SCHEMA } from '../consts';
46
import { logger } from '../logger';
57
import type {
68
DeepSeekToolCall,
79
ModelDefinition
810
} from '../types';
9-
import { MODELS } from '../types';
1011
import { type ReasoningEntry, pruneReasoningCache } from './cache';
1112
import { convertMessages, convertTools, countMessageChars } from './convert';
1213
import {
@@ -15,8 +16,6 @@ import {
1516
setVisionProxyModel,
1617
} from './vision';
1718

18-
const API_KEY_REQUIRED_DETAIL = 'Please run DeepSeek: Set API Key to configure.';
19-
2019
/**
2120
* NOTE: Non-public API surface.
2221
*
@@ -30,23 +29,6 @@ const API_KEY_REQUIRED_DETAIL = 'Please run DeepSeek: Set API Key to configure.'
3029
* If/when VS Code stabilizes these as proposed API, switch to the official
3130
* types and drop the casts below.
3231
*/
33-
const THINKING_EFFORT_CONFIGURATION_SCHEMA = {
34-
properties: {
35-
reasoningEffort: {
36-
type: 'string',
37-
title: 'Thinking Effort',
38-
enum: ['none', 'high', 'max'],
39-
enumItemLabels: ['None', 'High', 'Max'],
40-
enumDescriptions: [
41-
'Disable thinking for faster responses',
42-
'Recommended for most tasks',
43-
'Maximum reasoning depth for complex agent tasks',
44-
],
45-
default: 'high',
46-
group: 'navigation',
47-
},
48-
},
49-
} as const;
5032

5133
type ThinkingEffort = 'none' | 'high' | 'max';
5234

@@ -194,13 +176,13 @@ export class DeepSeekChatProvider implements vscode.LanguageModelChatProvider {
194176
);
195177
}
196178

197-
const baseUrl = this.authManager.getBaseUrl();
179+
const baseUrl = getBaseUrl();
198180
const client = new DeepSeekClient(baseUrl, apiKey);
199181

200-
const modelDef = findModel(modelInfo.id);
182+
const modelDef = MODELS.find(m => m.id === modelInfo.id);
201183
const isThinkingModel = modelDef?.capabilities.thinking ?? false;
202184
const thinkingEffort = getConfiguredThinkingEffort(options as ModelConfigurationOptions);
203-
const maxTokens = this.authManager.getMaxTokens();
185+
const maxTokens = getMaxTokens();
204186

205187
// Heuristic: detect conversation start to clear stale cache.
206188
if (messages.length <= 2) {
@@ -231,7 +213,7 @@ export class DeepSeekChatProvider implements vscode.LanguageModelChatProvider {
231213
return new Promise<void>((resolve, reject) => {
232214
client.streamChatCompletion(
233215
{
234-
model: this.authManager.getApiModelId(modelInfo.id),
216+
model: getApiModelId(modelInfo.id),
235217
messages: deepseekMessages,
236218
stream: true,
237219
tools,
@@ -370,10 +352,6 @@ export class DeepSeekChatProvider implements vscode.LanguageModelChatProvider {
370352

371353
// ---- Helpers ----
372354

373-
function findModel(id: string): ModelDefinition | undefined {
374-
return MODELS.find((m) => m.id === id);
375-
}
376-
377355
function toChatInfo(
378356
m: ModelDefinition,
379357
hasApiKey: boolean,

src/provider/vision.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import * as vscode from 'vscode';
1+
import vscode from 'vscode';
2+
import { DEFAULT_VISION_MODEL_ID, IMAGE_DESCRIPTION_PROMPT } from '../consts';
23
import { logger } from '../logger';
34

4-
const DEFAULT_VISION_MODEL_ID = 'oswe-vscode-prime';
5-
6-
export const IMAGE_DESCRIPTION_PROMPT =
7-
'Describe the visual contents of this image in detail, including any text, objects, people, or context that would be relevant for understanding it. Focus on factual visual elements.';
8-
95
/**
106
* Resolve any image parts in user messages by forwarding them to a vision
117
* model and replacing them with text descriptions. This lets text-only models

src/types.ts

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -106,36 +106,3 @@ export interface ModelDefinition {
106106
};
107107
requiresThinkingParam: boolean;
108108
}
109-
110-
export const MODELS: ModelDefinition[] = [
111-
{
112-
id: 'deepseek-v4-flash',
113-
name: 'DeepSeek V4 Flash',
114-
family: 'deepseek',
115-
version: 'v4',
116-
detail: 'Fast, general-purpose model',
117-
maxInputTokens: 1048576,
118-
maxOutputTokens: 393216,
119-
capabilities: {
120-
toolCalling: true,
121-
imageInput: true,
122-
thinking: true,
123-
},
124-
requiresThinkingParam: true,
125-
},
126-
{
127-
id: 'deepseek-v4-pro',
128-
name: 'DeepSeek V4 Pro',
129-
family: 'deepseek',
130-
version: 'v4',
131-
detail: 'Most capable reasoning model',
132-
maxInputTokens: 1048576,
133-
maxOutputTokens: 393216,
134-
capabilities: {
135-
toolCalling: true,
136-
imageInput: true,
137-
thinking: true,
138-
},
139-
requiresThinkingParam: true,
140-
},
141-
];

0 commit comments

Comments
 (0)