Merge pull request 'fix: update DeepSeek direct models to v4' (#33) from codex/fix-deepseek-v4-models into main
Memind CI / Test, build, and release guards (push) Successful in 2m57s

This commit was merged in pull request #33.
This commit is contained in:
2026-07-25 01:23:05 +00:00
3 changed files with 36 additions and 29 deletions
+2 -2
View File
@@ -21,8 +21,8 @@ export const LLM_PROVIDER_CATALOG = [
label: 'DeepSeek',
kind: 'builtin',
apiKeyEnv: 'DEEPSEEK_API_KEY',
defaultModel: 'deepseek-chat',
models: ['deepseek-chat', 'deepseek-reasoner'],
defaultModel: 'deepseek-v4-pro',
models: ['deepseek-v4-pro', 'deepseek-v4-flash'],
},
{
id: 'openai',
+30 -23
View File
@@ -129,7 +129,7 @@ test('createKey selects first profile and syncs to goosed', async () => {
providerId: 'custom_deepseek',
name: 'DeepSeek 主账号',
apiKey: 'sk-deepseek-test',
defaultModel: 'deepseek-chat',
defaultModel: 'deepseek-v4-pro',
});
assert.equal(result.ok, true);
assert.equal(result.key.isSelected, true);
@@ -220,7 +220,7 @@ test('selectKey rejects disabled profile', async () => {
api_key_ciphertext: encryptSecret('sk-x', 'unit-test-secret').ciphertext,
api_key_iv: encryptSecret('sk-x', 'unit-test-secret').iv,
api_key_tag: encryptSecret('sk-x', 'unit-test-secret').tag,
default_model: 'deepseek-chat',
default_model: 'deepseek-v4-pro',
status: 'disabled',
is_selected: 0,
created_at: 1,
@@ -250,6 +250,13 @@ test('catalog includes custom provider template', () => {
assert.equal(custom.kind, 'custom');
});
test('DeepSeek catalog uses the currently supported V4 model names', () => {
const deepseek = LLM_PROVIDER_CATALOG.find((item) => item.id === 'custom_deepseek');
assert.ok(deepseek);
assert.equal(deepseek.defaultModel, 'deepseek-v4-pro');
assert.deepEqual(deepseek.models, ['deepseek-v4-pro', 'deepseek-v4-flash']);
});
test('listExecutorBindings returns all executor placeholders', async () => {
const pool = {
async query(sql) {
@@ -295,7 +302,7 @@ test('testKey checks builtin DeepSeek through OpenAI compatible endpoint', async
api_key_ciphertext: encrypted.ciphertext,
api_key_iv: encrypted.iv,
api_key_tag: encrypted.tag,
default_model: 'deepseek-chat',
default_model: 'deepseek-v4-pro',
status: 'active',
is_selected: 1,
created_at: 1,
@@ -324,11 +331,11 @@ test('testKey checks builtin DeepSeek through OpenAI compatible endpoint', async
encryptionKey: 'unit-test-secret',
apiFetchImpl: mockFetch,
});
const result = await service.testKey('key-deepseek', 'deepseek-chat');
const result = await service.testKey('key-deepseek', 'deepseek-v4-pro');
assert.equal(result.ok, true);
assert.equal(calls[0].url, 'https://api.deepseek.com/v1/chat/completions');
assert.equal(calls[0].init.headers.Authorization, 'Bearer sk-deepseek-test');
assert.equal(calls[0].body.model, 'deepseek-chat');
assert.equal(calls[0].body.model, 'deepseek-v4-pro');
});
test('createChatCompletion uses selected OpenAI-compatible provider', async () => {
@@ -477,7 +484,7 @@ test('getExecutorRuntimeConfig resolves aider env from binding', async () => {
api_key_ciphertext: encrypted.ciphertext,
api_key_iv: encrypted.iv,
api_key_tag: encrypted.tag,
default_model: 'deepseek-chat',
default_model: 'deepseek-v4-pro',
status: 'active',
is_selected: 1,
created_at: 1,
@@ -488,7 +495,7 @@ test('getExecutorRuntimeConfig resolves aider env from binding', async () => {
executor: 'aider',
purpose: 'default',
provider_key_id: 'key-deepseek',
model: 'deepseek-reasoner',
model: 'deepseek-v4-flash',
enabled: 1,
created_at: 1,
updated_at: 1,
@@ -510,8 +517,8 @@ test('getExecutorRuntimeConfig resolves aider env from binding', async () => {
});
const runtime = await service.getExecutorRuntimeConfig('aider');
assert.equal(runtime.ok, true);
assert.equal(runtime.model, 'deepseek-reasoner');
assert.equal(runtime.env.AIDER_MODEL, 'deepseek/deepseek-reasoner');
assert.equal(runtime.model, 'deepseek-v4-flash');
assert.equal(runtime.env.AIDER_MODEL, 'deepseek/deepseek-v4-flash');
assert.equal(runtime.env.DEEPSEEK_API_KEY, '[hidden]');
});
@@ -522,8 +529,8 @@ test('buildExecutorLaunchPlan creates openhands headless command', () => {
executorLabel: 'OpenHands',
purpose: 'default',
providerName: 'DeepSeek 主账号',
model: 'deepseek-reasoner',
env: { LLM_MODEL: 'deepseek-reasoner', LLM_API_KEY: '[hidden]' },
model: 'deepseek-v4-flash',
env: { LLM_MODEL: 'deepseek-v4-flash', LLM_API_KEY: '[hidden]' },
}, {
mode: 'headless',
cwd: '/repo/memind',
@@ -543,8 +550,8 @@ test('buildExecutorLaunchPlan creates openhands serve command', () => {
executorLabel: 'OpenHands',
purpose: 'default',
providerName: 'DeepSeek 主账号',
model: 'deepseek-reasoner',
env: { LLM_MODEL: 'deepseek-reasoner', LLM_API_KEY: '[hidden]' },
model: 'deepseek-v4-flash',
env: { LLM_MODEL: 'deepseek-v4-flash', LLM_API_KEY: '[hidden]' },
}, {
mode: 'serve',
cwd: '/repo/memind',
@@ -561,9 +568,9 @@ test('buildExecutorLaunchPlan adds aider one-shot message when provided', () =>
executorLabel: 'Aider',
purpose: 'default',
providerName: 'DeepSeek 主账号',
model: 'deepseek-chat',
model: 'deepseek-v4-pro',
env: {
AIDER_MODEL: 'deepseek/deepseek-chat',
AIDER_MODEL: 'deepseek/deepseek-v4-pro',
OPENAI_API_KEY: '[hidden]',
TKMIND_EXECUTOR_PROVIDER: 'custom_deepseek',
},
@@ -573,7 +580,7 @@ test('buildExecutorLaunchPlan adds aider one-shot message when provided', () =>
});
assert.equal(plan.ok, true);
assert.equal(plan.command, 'aider');
assert.deepEqual(plan.args.slice(0, 2), ['--model', 'deepseek/deepseek-chat']);
assert.deepEqual(plan.args.slice(0, 2), ['--model', 'deepseek/deepseek-v4-pro']);
assert.ok(plan.args.includes('--message'));
assert.ok(plan.args.includes('fix login button'));
});
@@ -585,8 +592,8 @@ test('buildExecutorLaunchPlan rejects openhands headless without instruction', (
executorLabel: 'OpenHands',
purpose: 'default',
providerName: 'DeepSeek 主账号',
model: 'deepseek-reasoner',
env: { LLM_MODEL: 'deepseek-reasoner', LLM_API_KEY: '[hidden]' },
model: 'deepseek-v4-flash',
env: { LLM_MODEL: 'deepseek-v4-flash', LLM_API_KEY: '[hidden]' },
}, {
mode: 'headless',
cwd: '/repo/memind',
@@ -637,7 +644,7 @@ test('launchExecutor returns friendly error when command is missing', async () =
api_key_ciphertext: encryptedKey.ciphertext,
api_key_iv: encryptedKey.iv,
api_key_tag: encryptedKey.tag,
default_model: 'deepseek-chat',
default_model: 'deepseek-v4-pro',
status: 'active',
is_selected: 1,
created_at: 1,
@@ -648,7 +655,7 @@ test('launchExecutor returns friendly error when command is missing', async () =
executor: 'aider',
purpose: 'default',
provider_key_id: 'key-1',
model: 'deepseek-chat',
model: 'deepseek-v4-pro',
enabled: 1,
created_at: 1,
updated_at: 1,
@@ -735,7 +742,7 @@ test('syncProfileToGoosed writes provider, model and secret keys for builtin', a
{
providerKind: 'builtin',
providerId: 'custom_deepseek',
defaultModel: 'deepseek-chat',
defaultModel: 'deepseek-v4-pro',
apiKey: 'sk-test',
},
mockFetch,
@@ -755,14 +762,14 @@ test('syncSelectedToGoosed writes selected provider to every configured target',
name: 'DeepSeek',
api_url: null,
base_path: null,
models_json: JSON.stringify(['deepseek-chat']),
models_json: JSON.stringify(['deepseek-v4-pro']),
goosed_provider_id: null,
engine: 'openai',
relay_provider: null,
api_key_ciphertext: encrypted.ciphertext,
api_key_iv: encrypted.iv,
api_key_tag: encrypted.tag,
default_model: 'deepseek-chat',
default_model: 'deepseek-v4-pro',
status: 'active',
is_selected: 1,
created_at: 1,
+4 -4
View File
@@ -40,14 +40,14 @@ const CONFIG_NAME = 'DeepSeek 直连';
async function testDirectDeepSeek() {
const dispatcher = new Agent({ connect: { rejectUnauthorized: true } });
const started = Date.now();
const res = await fetch('https://api.deepseek.com/chat/completions', {
const res = await fetch('https://api.deepseek.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: 'deepseek-chat',
model: 'deepseek-v4-pro',
messages: [{ role: 'user', content: 'Hello' }],
stream: false,
}),
@@ -78,7 +78,7 @@ if (rowId) {
const updated = await svc.updateKey(rowId, {
name: CONFIG_NAME,
apiKey,
defaultModel: 'deepseek-chat',
defaultModel: 'deepseek-v4-pro',
});
if (!updated.ok) {
console.error('更新 DeepSeek 配置失败:', updated.message);
@@ -90,7 +90,7 @@ if (rowId) {
providerId: 'custom_deepseek',
name: CONFIG_NAME,
apiKey,
defaultModel: 'deepseek-chat',
defaultModel: 'deepseek-v4-pro',
});
if (!created.ok) {
console.error('创建 DeepSeek 配置失败:', created.message);