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
+75 -4
View File
@@ -5,6 +5,10 @@ import os from 'node:os';
import path from 'node:path';
import {
buildInitialUserMemoryProfile,
buildTaskRoutingAgentText,
resolveCodeExecutorRouting,
renderCodeExecutorGuidance,
suggestCodeExecutorForTask,
buildSessionMemoryEntries,
ensureUserMemoryProfile,
hasMemoryStore,
@@ -57,17 +61,29 @@ test('buildSessionMemoryEntries injects sandbox, guidance, and profile', () => {
displayName: 'Bob',
username: 'bob',
});
const sessionPolicy = buildAgentExtensionPolicy(DEFAULT_USER_CAPABILITIES);
const sessionPolicy = {
...buildAgentExtensionPolicy({
...DEFAULT_USER_CAPABILITIES,
aider: true,
openhands: true,
}),
policies: {
code_delegate_executor: 'openhands',
code_task_routing: 'split',
},
};
const entries = buildSessionMemoryEntries({
workingDir: root,
sessionPolicy,
sandboxConstraints: '## sandbox',
userContext: { userId: 'user-2', displayName: 'Bob', username: 'bob' },
});
assert.equal(entries.length, 3);
assert.equal(entries.length, 4);
assert.equal(entries[0].title, 'TKMind 用户空间沙箱');
assert.match(entries[1].content, /长期记忆/);
assert.match(entries[2].content, /Bob/);
assert.equal(entries[1].title, 'TKMind 代码委托策略');
assert.match(entries[1].content, /openhands/);
assert.match(entries[2].content, /长期记忆/);
assert.match(entries[3].content, /Bob/);
});
test('renderMemoryStoreGuidance scopes memory to one user', () => {
@@ -87,3 +103,58 @@ test('buildInitialUserMemoryProfile seeds defaults', () => {
assert.equal(profile.responseStyle, 'balanced');
assert.deepEqual(profile.preferences, []);
});
test('renderCodeExecutorGuidance reflects preferred executor and fallback', () => {
const text = renderCodeExecutorGuidance({
extensionOverrides: [
{ name: 'aider' },
{ name: 'openhands' },
],
policies: {
code_delegate_executor: 'aider',
code_task_routing: 'force_aider',
},
});
assert.match(text, /aider/i);
assert.match(text, /openhands/i);
assert.match(text, /优先使用/);
assert.match(text, /统一走 `aider`/);
});
test('resolveCodeExecutorRouting falls back when preferred executor is unavailable', () => {
const routing = resolveCodeExecutorRouting({
extensionOverrides: [{ name: 'aider' }],
policies: {
code_delegate_executor: 'openhands',
code_task_routing: 'split',
},
});
assert.deepEqual(routing.available, ['aider']);
assert.equal(routing.preferred, 'auto');
assert.equal(routing.routing, 'split');
assert.match(routing.rules[0], /auto/);
});
test('suggestCodeExecutorForTask prefers openhands for repo refactor style tasks', () => {
const suggestion = suggestCodeExecutorForTask(
'请帮我重构这个仓库里的认证流程,涉及多文件并跑一下测试',
{
extensionOverrides: [{ name: 'aider' }, { name: 'openhands' }],
policies: { code_delegate_executor: 'auto', code_task_routing: 'split' },
},
);
assert.equal(suggestion?.suggestedExecutor, 'openhands');
});
test('buildTaskRoutingAgentText preserves task body and adds hidden routing hint', () => {
const text = buildTaskRoutingAgentText(
'请修复这个按钮点击无效的 bug,改一下前端代码',
{
extensionOverrides: [{ name: 'aider' }, { name: 'openhands' }],
policies: { code_delegate_executor: 'aider', code_task_routing: 'force_aider' },
},
);
assert.match(text, /TKMind 路由提示/);
assert.match(text, /aider/i);
assert.match(text, /请修复这个按钮点击无效的 bug,改一下前端代码/);
});