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:
@@ -108,6 +108,89 @@ test('getSpace scopes space and categories to the authenticated user', async ()
|
||||
assert.deepEqual(calls[1].params, ['user-1', 'space-1']);
|
||||
});
|
||||
|
||||
test('getSpace includes schedule snapshot when schedule service is available', async () => {
|
||||
const pool = {
|
||||
async query(sql, params) {
|
||||
if (sql.includes('FROM h5_user_spaces')) {
|
||||
return [[{
|
||||
id: 'space-1',
|
||||
user_id: 'user-1',
|
||||
space_name: '我的空间',
|
||||
quota_bytes: 5 * 1024 * 1024,
|
||||
used_bytes: 1024,
|
||||
reserved_bytes: 2048,
|
||||
status: 'active',
|
||||
created_at: 10,
|
||||
updated_at: 20,
|
||||
}]];
|
||||
}
|
||||
if (sql.includes('FROM h5_space_categories')) {
|
||||
return [[{
|
||||
id: 'category-1',
|
||||
category_code: 'private',
|
||||
category_name: '私人区',
|
||||
visibility_policy: 'private',
|
||||
ai_access_policy: 'explicit_asset_grant',
|
||||
publish_policy: 'desensitized_copy_only',
|
||||
is_system: 1,
|
||||
sort_order: 20,
|
||||
item_count: 0,
|
||||
}]];
|
||||
}
|
||||
if (sql.includes('FROM h5_publish_records')) {
|
||||
return [[{ public_page_used: 0, monthly_view_used: 0 }]];
|
||||
}
|
||||
return [[]];
|
||||
},
|
||||
};
|
||||
const scheduleService = {
|
||||
async listTodayTodoItems({ userId }) {
|
||||
assert.equal(userId, 'user-1');
|
||||
return [
|
||||
{
|
||||
id: 'item-1',
|
||||
kind: 'task',
|
||||
title: '跟进报价单',
|
||||
description: '来自服务号',
|
||||
status: 'active',
|
||||
startAt: null,
|
||||
endAt: null,
|
||||
dueAt: Date.UTC(2026, 5, 18, 1, 30, 0),
|
||||
allDay: false,
|
||||
timezone: 'Asia/Shanghai',
|
||||
location: null,
|
||||
createdAt: 10,
|
||||
updatedAt: 20,
|
||||
},
|
||||
];
|
||||
},
|
||||
async listDigestSubscriptions({ userId, digestType, status }) {
|
||||
assert.equal(userId, 'user-1');
|
||||
assert.equal(digestType, 'todo_day');
|
||||
assert.deepEqual(status, ['active', 'locked']);
|
||||
return [
|
||||
{
|
||||
id: 'digest-1',
|
||||
hour: 7,
|
||||
minute: 0,
|
||||
timezone: 'Asia/Shanghai',
|
||||
channel: 'wechat',
|
||||
status: 'active',
|
||||
nextRunAt: Date.UTC(2026, 5, 18, 23, 0, 0),
|
||||
lastRunAt: null,
|
||||
attempts: 0,
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
const service = createMindSpaceService(pool, { scheduleService });
|
||||
const space = await service.getSpace('user-1');
|
||||
|
||||
assert.equal(space.schedule.todayTodoItems[0].title, '跟进报价单');
|
||||
assert.equal(space.schedule.digestSubscriptions[0].hour, 7);
|
||||
});
|
||||
|
||||
test('getSpace returns null when the user has no space', async () => {
|
||||
const service = createMindSpaceService({
|
||||
async query() {
|
||||
|
||||
Reference in New Issue
Block a user