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:
@@ -13,6 +13,7 @@ import {
|
||||
extractStaticPageLinks,
|
||||
findPublishHtml,
|
||||
injectHtmlBaseHref,
|
||||
resolveClosestHtmlRelativePath,
|
||||
resolveChatSaveAnalysis,
|
||||
sanitizeMessageContentForSave,
|
||||
} from './mindspace-chat-save.mjs';
|
||||
@@ -22,16 +23,17 @@ const USER_ID = 'a6fb1e97-2b0f-447b-b138-4561d8e5c53e';
|
||||
test('extractStaticPageLinks finds user-owned MindSpace html links', () => {
|
||||
const content = `
|
||||
页面已完成!
|
||||
https://g2.tkmind.cn/MindSpace/${USER_ID}/mapo-tofu.html
|
||||
https://m.tkmind.cn/MindSpace/${USER_ID}/mapo-tofu.html
|
||||
`;
|
||||
const links = extractStaticPageLinks(content, { userId: USER_ID });
|
||||
assert.equal(links.length, 1);
|
||||
assert.equal(links[0].filename, 'mapo-tofu.html');
|
||||
assert.equal(links[0].relativePath, 'mapo-tofu.html');
|
||||
assert.equal(links[0].relativePath, 'public/mapo-tofu.html');
|
||||
assert.equal(links[0].publicUrl, `https://m.tkmind.cn/MindSpace/${USER_ID}/public/mapo-tofu.html`);
|
||||
});
|
||||
|
||||
test('extractStaticPageLinks ignores other users', () => {
|
||||
const content = 'https://g2.tkmind.cn/MindSpace/other-id/report.html';
|
||||
const content = 'https://m.tkmind.cn/MindSpace/other-id/report.html';
|
||||
const links = extractStaticPageLinks(content, { userId: USER_ID });
|
||||
assert.equal(links.length, 0);
|
||||
});
|
||||
@@ -40,11 +42,27 @@ test('extractStaticPageLinks accepts legacy username urls when username provided
|
||||
const content = 'https://goo.tkmind.cn/MindSpace/john/report.html';
|
||||
const links = extractStaticPageLinks(content, { username: 'john' });
|
||||
assert.equal(links.length, 1);
|
||||
assert.equal(links[0].relativePath, 'public/report.html');
|
||||
assert.equal(links[0].publicUrl, 'https://goo.tkmind.cn/MindSpace/john/public/report.html');
|
||||
});
|
||||
|
||||
test('extractStaticPageLinks accepts uuid links when both user id and username are provided', () => {
|
||||
const content = `https://goo.tkmind.cn/MindSpace/${USER_ID}/public/report.html`;
|
||||
const links = extractStaticPageLinks(content, { userId: USER_ID, username: 'john' });
|
||||
assert.equal(links.length, 1);
|
||||
assert.equal(links[0].relativePath, 'public/report.html');
|
||||
});
|
||||
|
||||
test('extractStaticPageLinks accepts legacy username links when user id is available', () => {
|
||||
const content = 'https://goo.tkmind.cn/MindSpace/john/report.html';
|
||||
const links = extractStaticPageLinks(content, { userId: USER_ID, username: 'john' });
|
||||
assert.equal(links.length, 1);
|
||||
assert.equal(links[0].publicUrl, 'https://goo.tkmind.cn/MindSpace/john/public/report.html');
|
||||
});
|
||||
|
||||
test('analyzeChatMessageForSave prefers static html mode', () => {
|
||||
const analysis = analyzeChatMessageForSave({
|
||||
content: `链接 https://g2.tkmind.cn/MindSpace/${USER_ID}/report.html`,
|
||||
content: `链接 https://m.tkmind.cn/MindSpace/${USER_ID}/report.html`,
|
||||
userId: USER_ID,
|
||||
username: 'john',
|
||||
h5Root: '/tmp/h5',
|
||||
@@ -110,6 +128,29 @@ test('findPublishHtml resolves nested public html by basename', async () => {
|
||||
assert.match(loaded.content, /Welcome/);
|
||||
});
|
||||
|
||||
test('findPublishHtml resolves close html filename typos when match is unique', async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-chat-save-typo-'));
|
||||
const publishDir = path.join(root, 'MindSpace', USER_ID, 'public');
|
||||
await fs.mkdir(publishDir, { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(publishDir, 'memind-deep-analysis.html'),
|
||||
'<!DOCTYPE html><html><head><title>Deep Analysis</title></head><body>ok</body></html>',
|
||||
'utf8',
|
||||
);
|
||||
const loaded = await findPublishHtml(root, USER_ID, 'public/memind-dep-analysis.html');
|
||||
assert.equal(loaded.relativePath, 'public/memind-deep-analysis.html');
|
||||
assert.match(loaded.content, /Deep Analysis/);
|
||||
});
|
||||
|
||||
test('resolveClosestHtmlRelativePath ignores ambiguous typo matches', async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-chat-save-ambiguous-'));
|
||||
await fs.mkdir(path.join(root, 'public'), { recursive: true });
|
||||
await fs.writeFile(path.join(root, 'public', 'mindmap-plan.html'), '<html></html>', 'utf8');
|
||||
await fs.writeFile(path.join(root, 'public', 'mindmap-play.html'), '<html></html>', 'utf8');
|
||||
const resolved = await resolveClosestHtmlRelativePath(root, 'public/mindmap-plab.html');
|
||||
assert.equal(resolved, null);
|
||||
});
|
||||
|
||||
test('injectHtmlBaseHref adds base tag for relative assets', () => {
|
||||
const html = '<html><head><title>x</title></head><body></body></html>';
|
||||
const next = injectHtmlBaseHref(html, buildWorkspaceBaseHref(USER_ID, 'public/page.html'));
|
||||
|
||||
Reference in New Issue
Block a user