Add smart ACK provider for WeChat MP replies

Replace fixed ackText with a rule-based AckProvider that picks
response templates by message type and intent (translate, summary,
rewrite, poster, ppt, mindmap, code, search, schedule). Pure sync,
zero I/O, auto-falls back to config.ackText on any error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
john
2026-06-26 15:19:03 +08:00
parent 9ed4fd48d7
commit 9b4a25799f
162 changed files with 17276 additions and 2054 deletions
+323
View File
@@ -3,12 +3,14 @@ import test from 'node:test';
import {
createLlmProviderService,
CUSTOM_PROVIDER_ID,
buildExecutorLaunchPlan,
decryptSecret,
encryptSecret,
LLM_PROVIDER_CATALOG,
LOCAL_LLM_FALLBACK,
maskApiKey,
normalizeApiUrl,
resolveApiBaseUrl,
parseModelList,
resolveChatCompletionsUrl,
testLocalLlmConnection,
@@ -248,6 +250,27 @@ test('catalog includes custom provider template', () => {
assert.equal(custom.kind, 'custom');
});
test('listExecutorBindings returns all executor placeholders', async () => {
const pool = {
async query(sql) {
if (sql.includes('ORDER BY is_selected DESC')) return [[]];
if (sql.includes('FROM h5_llm_executor_bindings')) return [[]];
throw new Error(`Unexpected SQL: ${sql}`);
},
};
const service = createLlmProviderService(pool, {
apiTarget: 'https://127.0.0.1:18006',
apiSecret: 'secret',
encryptionKey: 'unit-test-secret',
});
const bindings = await service.listExecutorBindings();
assert.deepEqual(
bindings.map((binding) => binding.executor),
['goose', 'aider', 'openhands'],
);
assert.equal(bindings[0].enabled, false);
});
test('resolveChatCompletionsUrl keeps full completions path', () => {
assert.equal(
resolveChatCompletionsUrl('http://127.0.0.1:18300/relay/buyer/v1/chat/completions'),
@@ -255,6 +278,261 @@ test('resolveChatCompletionsUrl keeps full completions path', () => {
);
});
test('resolveApiBaseUrl strips chat completions suffix', () => {
assert.equal(
resolveApiBaseUrl('http://127.0.0.1:18300/relay/buyer/v1/chat/completions'),
'http://127.0.0.1:18300/relay/buyer/v1',
);
});
test('testKey checks builtin DeepSeek through OpenAI compatible endpoint', async () => {
const encrypted = encryptSecret('sk-deepseek-test', 'unit-test-secret');
const row = {
id: 'key-deepseek',
provider_id: 'custom_deepseek',
provider_kind: 'builtin',
name: 'DeepSeek',
api_key_ciphertext: encrypted.ciphertext,
api_key_iv: encrypted.iv,
api_key_tag: encrypted.tag,
default_model: 'deepseek-chat',
status: 'active',
is_selected: 1,
created_at: 1,
updated_at: 1,
};
const pool = {
async query(sql, params = []) {
if (sql.includes('SELECT * FROM h5_llm_provider_keys WHERE id = ?')) {
assert.equal(params[0], 'key-deepseek');
return [[row]];
}
throw new Error(`Unexpected SQL: ${sql}`);
},
};
const calls = [];
const mockFetch = async (url, init) => {
calls.push({ url: String(url), init, body: JSON.parse(init.body) });
return {
ok: true,
text: async () => JSON.stringify({ choices: [{ message: { content: 'ok' } }] }),
};
};
const service = createLlmProviderService(pool, {
apiTarget: 'https://127.0.0.1:18006',
apiSecret: 'secret',
encryptionKey: 'unit-test-secret',
apiFetchImpl: mockFetch,
});
const result = await service.testKey('key-deepseek', 'deepseek-chat');
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');
});
test('getExecutorRuntimeConfig resolves aider env from binding', async () => {
const encrypted = encryptSecret('sk-deepseek-test', 'unit-test-secret');
const keyRow = {
id: 'key-deepseek',
provider_id: 'custom_deepseek',
provider_kind: 'builtin',
name: 'DeepSeek 主账号',
api_key_ciphertext: encrypted.ciphertext,
api_key_iv: encrypted.iv,
api_key_tag: encrypted.tag,
default_model: 'deepseek-chat',
status: 'active',
is_selected: 1,
created_at: 1,
updated_at: 1,
};
const bindingRow = {
id: 'binding-aider',
executor: 'aider',
purpose: 'default',
provider_key_id: 'key-deepseek',
model: 'deepseek-reasoner',
enabled: 1,
created_at: 1,
updated_at: 1,
};
const pool = {
async query(sql, params = []) {
if (sql.includes('SELECT * FROM h5_llm_executor_bindings')) return [[bindingRow]];
if (sql.includes('SELECT * FROM h5_llm_provider_keys WHERE id = ?')) {
assert.equal(params[0], 'key-deepseek');
return [[keyRow]];
}
throw new Error(`Unexpected SQL: ${sql}`);
},
};
const service = createLlmProviderService(pool, {
apiTarget: 'https://127.0.0.1:18006',
apiSecret: 'secret',
encryptionKey: 'unit-test-secret',
});
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.DEEPSEEK_API_KEY, '[hidden]');
});
test('buildExecutorLaunchPlan creates openhands headless command', () => {
const plan = buildExecutorLaunchPlan({
ok: true,
executor: 'openhands',
executorLabel: 'OpenHands',
purpose: 'default',
providerName: 'DeepSeek 主账号',
model: 'deepseek-reasoner',
env: { LLM_MODEL: 'deepseek-reasoner', LLM_API_KEY: '[hidden]' },
}, {
mode: 'headless',
cwd: '/repo/memind',
instruction: 'add search',
});
assert.equal(plan.ok, true);
assert.equal(plan.command, 'openhands');
assert.deepEqual(plan.args.slice(0, 3), ['--headless', '--json', '--override-with-envs']);
assert.equal(plan.cwd, '/repo/memind');
assert.ok(plan.args.includes('--task'));
});
test('buildExecutorLaunchPlan creates openhands serve command', () => {
const plan = buildExecutorLaunchPlan({
ok: true,
executor: 'openhands',
executorLabel: 'OpenHands',
purpose: 'default',
providerName: 'DeepSeek 主账号',
model: 'deepseek-reasoner',
env: { LLM_MODEL: 'deepseek-reasoner', LLM_API_KEY: '[hidden]' },
}, {
mode: 'serve',
cwd: '/repo/memind',
});
assert.equal(plan.ok, true);
assert.equal(plan.command, 'openhands');
assert.deepEqual(plan.args, ['serve', '--mount-cwd']);
});
test('buildExecutorLaunchPlan adds aider one-shot message when provided', () => {
const plan = buildExecutorLaunchPlan({
ok: true,
executor: 'aider',
executorLabel: 'Aider',
purpose: 'default',
providerName: 'DeepSeek 主账号',
model: 'deepseek-chat',
env: { AIDER_MODEL: 'deepseek-chat', OPENAI_API_KEY: '[hidden]' },
}, {
cwd: '/repo/memind',
instruction: 'fix login button',
});
assert.equal(plan.ok, true);
assert.equal(plan.command, 'aider');
assert.ok(plan.args.includes('--message'));
assert.ok(plan.args.includes('fix login button'));
});
test('buildExecutorLaunchPlan rejects openhands headless without instruction', () => {
const plan = buildExecutorLaunchPlan({
ok: true,
executor: 'openhands',
executorLabel: 'OpenHands',
purpose: 'default',
providerName: 'DeepSeek 主账号',
model: 'deepseek-reasoner',
env: { LLM_MODEL: 'deepseek-reasoner', LLM_API_KEY: '[hidden]' },
}, {
mode: 'headless',
cwd: '/repo/memind',
});
assert.equal(plan.ok, false);
assert.match(plan.message ?? '', /instruction/);
});
test('launchExecutor rejects goose launch path', async () => {
const pool = {
async query() {
throw new Error('should not query for goose launch');
},
};
const service = createLlmProviderService(pool, {
apiTarget: 'https://127.0.0.1:18006',
apiSecret: 'secret',
encryptionKey: 'unit-test-secret',
});
const result = await service.launchExecutor('goose');
assert.equal(result.ok, false);
assert.match(result.message ?? '', /Goose/);
});
test('launchExecutor rejects openhands headless without instruction', async () => {
const pool = {
async query() {
throw new Error('should not query for validation failure');
},
};
const service = createLlmProviderService(pool, {
apiTarget: 'https://127.0.0.1:18006',
apiSecret: 'secret',
encryptionKey: 'unit-test-secret',
});
const result = await service.launchExecutor('openhands', { mode: 'headless' });
assert.equal(result.ok, false);
assert.match(result.message ?? '', /instruction/);
});
test('launchExecutor returns friendly error when command is missing', async () => {
const keyRow = {
id: 'key-1',
provider_id: 'custom_deepseek',
provider_kind: 'builtin',
name: 'DeepSeek',
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',
status: 'active',
is_selected: 1,
created_at: 1,
updated_at: 1,
};
const bindingRow = {
id: 'binding-1',
executor: 'aider',
purpose: 'default',
provider_key_id: 'key-1',
model: 'deepseek-chat',
enabled: 1,
created_at: 1,
updated_at: 1,
};
const pool = {
async query(sql) {
if (sql.includes('SELECT * FROM h5_llm_executor_bindings')) return [[]];
if (sql.includes('SELECT * FROM h5_llm_provider_keys WHERE id = ?')) {
return [[keyRow]];
}
if (sql.includes('SELECT * FROM h5_llm_executor_bindings WHERE executor = ? AND purpose = ? LIMIT 1')) {
return [[bindingRow]];
}
throw new Error(`Unexpected SQL: ${sql}`);
},
};
const service = createLlmProviderService(pool, {
apiTarget: 'https://127.0.0.1:18006',
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 未安装/);
});
test('testRelayConnection surfaces 401 as token error', async () => {
const mockFetch = async () => ({
ok: false,
@@ -380,6 +658,7 @@ test('syncSelectedToGoosed does not auto-fallback to local when selected relay i
};
const pool = {
async query(sql) {
if (sql.includes('SELECT * FROM h5_llm_executor_bindings')) return [[]];
if (sql.includes('is_selected = 1')) return [[row]];
throw new Error(`Unexpected SQL: ${sql}`);
},
@@ -398,3 +677,47 @@ test('syncSelectedToGoosed does not auto-fallback to local when selected relay i
assert.equal(result.synced, false);
assert.ok(result.message);
});
test('ensureBootstrapRelay keeps existing selected provider', async () => {
const rows = [
{
id: 'key-deepseek',
provider_id: 'custom_deepseek',
provider_kind: 'builtin',
name: 'DeepSeek',
status: 'active',
is_selected: 1,
updated_at: 1,
},
{
id: 'key-relay',
provider_id: 'custom_relay_buyer_ollama_27',
provider_kind: 'custom',
name: 'Relay Buyer Ollama',
status: 'active',
is_selected: 0,
updated_at: 1,
},
];
const pool = {
async query(sql, params = []) {
if (sql.includes('SELECT id FROM h5_llm_provider_keys WHERE name = ?')) {
return [[rows.find((row) => row.name === params[0])].filter(Boolean)];
}
if (sql.includes('UPDATE h5_llm_provider_keys SET is_selected')) {
throw new Error('bootstrap relay should not change the selected provider');
}
throw new Error(`Unexpected SQL: ${sql}`);
},
};
const service = createLlmProviderService(pool, {
apiTarget: 'https://127.0.0.1:18006',
apiSecret: 'secret',
encryptionKey: 'unit-test-secret',
});
const result = await service.ensureBootstrapRelay();
assert.equal(result.ok, true);
assert.equal(result.created, false);
assert.equal(rows.find((row) => row.id === 'key-deepseek').is_selected, 1);
assert.equal(rows.find((row) => row.id === 'key-relay').is_selected, 0);
});