From 0cfd2d3d2adf404d4ad7f68dcc37c8074c14e900 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 2 Jul 2026 09:42:08 +0800 Subject: [PATCH] fix: map deepseek models for aider --- llm-providers.mjs | 17 +++++++++++++++-- llm-providers.test.mjs | 22 +++++++++++++++++----- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/llm-providers.mjs b/llm-providers.mjs index 3ff25c4..317d196 100644 --- a/llm-providers.mjs +++ b/llm-providers.mjs @@ -386,9 +386,10 @@ function executorEnvForProfile(executor, profile, model, { includeSecret = false if (includeSecret) common.TKMIND_EXECUTOR_API_KEY = profile.apiKey; if (executor === 'aider') { + const aiderModel = aiderModelNameForProvider(providerId, model); const env = { ...common, - AIDER_MODEL: model, + AIDER_MODEL: aiderModel, }; if (providerId === 'anthropic') { env.AIDER_ANTHROPIC_API_KEY = apiKeyValue; @@ -428,6 +429,17 @@ function executorEnvForProfile(executor, profile, model, { includeSecret = false }; } +function aiderModelNameForProvider(providerId, model) { + const normalizedModel = String(model ?? '').trim(); + if (!normalizedModel) return normalizedModel; + if (String(providerId ?? '').trim() === 'custom_deepseek') { + return normalizedModel.startsWith('deepseek/') + ? normalizedModel + : `deepseek/${normalizedModel}`; + } + return normalizedModel; +} + function launchLogDir() { return path.join(os.tmpdir(), 'memindadm-launches'); } @@ -561,6 +573,7 @@ export function buildExecutorLaunchPlan(runtime, options = {}) { if (runtime.executor === 'aider') { const hasInstruction = Boolean(instruction); const command = resolveExecutorCommand('aider'); + const model = aiderModelNameForProvider(env.TKMIND_EXECUTOR_PROVIDER, runtime.model); return { ok: true, executor: 'aider', @@ -568,7 +581,7 @@ export function buildExecutorLaunchPlan(runtime, options = {}) { command, args: [ '--model', - runtime.model, + model, ...(hasInstruction ? ['--message', instruction] : []), '--yes-always', ], diff --git a/llm-providers.test.mjs b/llm-providers.test.mjs index e840977..ace745d 100644 --- a/llm-providers.test.mjs +++ b/llm-providers.test.mjs @@ -375,7 +375,7 @@ 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-reasoner'); + assert.equal(runtime.env.AIDER_MODEL, 'deepseek/deepseek-reasoner'); assert.equal(runtime.env.DEEPSEEK_API_KEY, '[hidden]'); }); @@ -426,13 +426,18 @@ test('buildExecutorLaunchPlan adds aider one-shot message when provided', () => purpose: 'default', providerName: 'DeepSeek 主账号', model: 'deepseek-chat', - env: { AIDER_MODEL: 'deepseek-chat', OPENAI_API_KEY: '[hidden]' }, + env: { + AIDER_MODEL: 'deepseek/deepseek-chat', + OPENAI_API_KEY: '[hidden]', + TKMIND_EXECUTOR_PROVIDER: 'custom_deepseek', + }, }, { cwd: '/repo/memind', instruction: 'fix login button', }); assert.equal(plan.ok, true); assert.equal(plan.command, 'aider'); + assert.deepEqual(plan.args.slice(0, 2), ['--model', 'deepseek/deepseek-chat']); assert.ok(plan.args.includes('--message')); assert.ok(plan.args.includes('fix login button')); }); @@ -529,9 +534,16 @@ test('launchExecutor returns friendly error when command is missing', async () = apiSecret: 'secret', encryptionKey: 'unit-test-secret', }); - const result = await service.launchExecutor('aider', { instruction: 'hello' }); - assert.equal(result.ok, false); - assert.match(result.message ?? '', /aider .*PATH|aider 未安装/); + const oldAiderBin = process.env.AIDER_BIN; + process.env.AIDER_BIN = '/definitely/missing/aider'; + try { + const result = await service.launchExecutor('aider', { instruction: 'hello' }); + assert.equal(result.ok, false); + assert.match(result.message ?? '', /PATH|未安装/); + } finally { + if (oldAiderBin == null) delete process.env.AIDER_BIN; + else process.env.AIDER_BIN = oldAiderBin; + } }); test('testRelayConnection surfaces 401 as token error', async () => {