import test from 'node:test'; import assert from 'node:assert/strict'; import { buildAutoChatSkillPrefix, buildChatSkillPrompt, CHAT_SKILL_DEFINITIONS, filterChatSkills, extractAiderDevelopmentTask, isExcelAnalysisIntent, isPageDataDevIntent, isPageDataIntent, isPageGenerationIntent, isGenericPageGenerationRequest, mergeChatSkillPromptWithInput, } from './chat-skills.mjs'; test('filterChatSkills shows summarize and analyze without granted skills', () => { const visible = filterChatSkills(CHAT_SKILL_DEFINITIONS, { canPublish: false }); assert.ok(visible.some((item) => item.id === 'summarize')); assert.ok(visible.some((item) => item.id === 'analyze')); assert.equal(visible.some((item) => item.id === 'generate-page'), false); }); test('filterChatSkills gates platform skills by grantedSkills', () => { const visible = filterChatSkills(CHAT_SKILL_DEFINITIONS, { canPublish: false, grantedSkills: ['web', 'search'], }); assert.ok(visible.some((item) => item.id === 'web-search')); assert.ok(visible.some((item) => item.id === 'code-search')); assert.equal(visible.some((item) => item.id === 'form-collect'), false); assert.equal(visible.some((item) => item.id === 'service-integration-smoke'), false); assert.equal(visible.some((item) => item.id === 'product-campaign-page'), false); }); test('filterChatSkills shows product campaign page when granted', () => { const visible = filterChatSkills(CHAT_SKILL_DEFINITIONS, { canPublish: false, grantedSkills: ['product-campaign-page'], }); assert.ok(visible.some((item) => item.id === 'product-campaign-page')); }); test('filterChatSkills shows service integration smoke when granted', () => { const visible = filterChatSkills(CHAT_SKILL_DEFINITIONS, { canPublish: false, grantedSkills: ['service-integration-smoke'], }); assert.ok(visible.some((item) => item.id === 'service-integration-smoke')); }); test('Aider development skill prefills instead of submitting an empty template', () => { const aider = CHAT_SKILL_DEFINITIONS.find((item) => item.id === 'aider-development'); assert.equal(aider?.prefillOnly, true); }); test('mergeChatSkillPromptWithInput preserves an existing user task', () => { const prompt = buildChatSkillPrompt('aider-development', 'aider-development'); const task = '帮我设计一个简单下单系统,不要支付,可以有简单后台'; assert.equal(mergeChatSkillPromptWithInput(prompt, task), `${prompt}${task}`); assert.equal(mergeChatSkillPromptWithInput(prompt, `${prompt}${task}`), `${prompt}${task}`); }); test('extractAiderDevelopmentTask rejects the template-only submission', () => { const prompt = buildChatSkillPrompt('aider-development', 'aider-development'); assert.equal( extractAiderDevelopmentTask({ metadata: { displayText: prompt }, content: [{ type: 'text', text: prompt }], }), '', ); assert.equal( extractAiderDevelopmentTask({ metadata: { displayText: `${prompt}修复页面` }, content: [{ type: 'text', text: `${prompt}修复页面` }], }), '修复页面', ); }); test('filterChatSkills only shows Aider development when granted', () => { const hidden = filterChatSkills(CHAT_SKILL_DEFINITIONS, { canPublish: false, grantedSkills: [], }); assert.equal(hidden.some((item) => item.id === 'aider-development'), false); const visible = filterChatSkills(CHAT_SKILL_DEFINITIONS, { canPublish: false, grantedSkills: ['aider-development'], }); assert.ok(visible.some((item) => item.id === 'aider-development')); }); test('filterChatSkills shows page-data-collect when granted without static publish', () => { const visible = filterChatSkills(CHAT_SKILL_DEFINITIONS, { canPublish: false, grantedSkills: ['page-data-collect'], }); assert.ok(visible.some((item) => item.id === 'page-data-collect')); }); test('filterChatSkills shows generate-page when publish is allowed', () => { const visible = filterChatSkills(CHAT_SKILL_DEFINITIONS, { canPublish: true }); assert.ok(visible.some((item) => item.id === 'generate-page')); }); test('buildChatSkillPrompt includes skill name for platform skills', () => { const webPrompt = buildChatSkillPrompt('web', 'web'); assert.match(webPrompt, /请使用 web 技能/); assert.match(webPrompt, /tkmind_search/); assert.match(webPrompt, /web_search/); const enhancedPrompt = buildChatSkillPrompt('search-enhanced', 'search-enhanced'); assert.match(enhancedPrompt, /tkmind_search/); assert.match(enhancedPrompt, /web_search/); assert.match(buildChatSkillPrompt('service-integration-smoke'), /标准联调流程/); assert.match(buildChatSkillPrompt('aider-development'), /必须由 Aider code run/); assert.match(buildChatSkillPrompt('aider-development'), /禁止回退/); assert.match(buildChatSkillPrompt('product-campaign-page'), /商品宣传 \/ 活动页/); assert.match(buildChatSkillPrompt('image-generation'), /asset\.htmlSrc/); assert.match(buildChatSkillPrompt('image-generation'), /workspaceRelativePath 只用于文件操作/); assert.match(buildChatSkillPrompt('generate-page'), /static-page-publish/); assert.match(buildChatSkillPrompt('generate-page'), /docx-generate/); assert.match(buildChatSkillPrompt('generate-page'), /public\/\*\.docx/); assert.match(buildChatSkillPrompt('generate-page'), /long-image-download/); assert.match(buildChatSkillPrompt('generate-page'), /generate_long_image/); assert.match(buildChatSkillPrompt('page-data-collect'), /Page Data API/); assert.match(buildChatSkillPrompt('page-data-collect'), /禁止自建 Express/); }); test('prefillOnly is set for open-ended chat skills', () => { assert.equal(CHAT_SKILL_DEFINITIONS.find((item) => item.id === 'web-search')?.prefillOnly, true); assert.equal(CHAT_SKILL_DEFINITIONS.find((item) => item.id === 'generate-page')?.prefillOnly, true); }); test('generate-page selection preserves an existing news-page request for the next submit', () => { const skill = CHAT_SKILL_DEFINITIONS.find((item) => item.id === 'generate-page'); const prompt = buildChatSkillPrompt(skill?.promptKey, skill?.skillName); const task = '帮我整理今天的新闻做成页面'; assert.equal(skill?.prefillOnly, true); assert.equal(mergeChatSkillPromptWithInput(prompt, task), `${prompt}${task}`); }); test('buildAutoChatSkillPrefix enables web for news-like queries', () => { assert.match( buildAutoChatSkillPrefix('帮我搜索今天热点新闻', ['web', 'search']), /先搜索今天\/最新相关的新闻与热点/, ); assert.equal(buildAutoChatSkillPrefix('帮我总结一下这段话', ['web', 'search']), ''); assert.equal(buildAutoChatSkillPrefix('帮我搜索今天热点新闻', ['search']), ''); }); test('buildAutoChatSkillPrefix routes an uploaded xlsx only when Excel Analyst is granted', () => { const text = '帮我分析一下\n\n[文件1: sales.xlsx]: /api/mindspace/v1/assets/asset-1/download'; assert.match( buildAutoChatSkillPrefix(text, ['excel-analyst']), /excel_inspect/, ); assert.equal(buildAutoChatSkillPrefix(text, []), ''); assert.equal(isExcelAnalysisIntent('请分析这份工作簿的销售趋势'), true); assert.equal(isExcelAnalysisIntent('请总结这段普通文字'), false); }); test('manifest enhanced search route is opt-in and uses the MindSearch skill prompt', () => { const routes = [{ skillName: 'search-enhanced', promptKey: 'search-enhanced', keywords: ['最新资料'], priority: 30 }]; assert.match(buildAutoChatSkillPrefix('请搜索最新资料:Goose MCP', ['search-enhanced'], { skillRouterV2: true, manifestRoutes: routes }), /tkmind-search/); assert.equal(buildAutoChatSkillPrefix('请搜索最新资料:Goose MCP', [], { skillRouterV2: true, manifestRoutes: routes }), ''); }); test('buildAutoChatSkillPrefix enables publish for page generation requests', () => { const prefix = buildAutoChatSkillPrefix('帮我做一个 Hello 糖的 H5 页面', ['static-page-publish']); assert.match(prefix, /static-page-publish/); assert.match(prefix, /write_file\/edit_file/); assert.match(prefix, /禁止只给本地路径/); assert.equal(buildAutoChatSkillPrefix('帮我做一个 Hello 糖的 H5 页面', []), ''); }); test('isPageGenerationIntent matches implicit travel guide page requests', () => { assert.equal(isPageGenerationIntent('苏州攻略页面'), true); assert.equal(isPageGenerationIntent('帮我看看苏州攻略,1日攻略,做一个页面'), true); assert.equal(isPageGenerationIntent('你好'), false); }); test('isGenericPageGenerationRequest only matches page requests without a subject', () => { assert.equal(isGenericPageGenerationRequest('帮我生成一个页面吧'), true); assert.equal(isGenericPageGenerationRequest('Please create a web page'), true); assert.equal(isGenericPageGenerationRequest('帮我做一个秋夜诗的 H5 页面'), false); assert.equal(isGenericPageGenerationRequest('苏州攻略页面'), false); assert.equal(isGenericPageGenerationRequest('你好'), false); }); test('buildAutoChatSkillPrefix prefers page-data-collect for survey requests', () => { const text = '帮我在这个页面增加一个调查问卷,出三个问题,密码 888 查看提交记录'; const prefix = buildAutoChatSkillPrefix(text, ['page-data-collect', 'static-page-publish']); assert.match(prefix, /page-data-collect/); assert.doesNotMatch(prefix, /static-page-publish 技能:在我的专属 MindSpace 发布目录生成静态 HTML/); }); test('isPageDataIntent matches survey and backend keywords', () => { assert.equal(isPageDataIntent('增加调查问卷和后台入口,密码 888'), true); assert.equal( isPageDataIntent('帮我做一个家庭记账页面,我每天可以记录日期、收入、支出、分类和备注,日期默认当天。再做一个管理页面,可以查看所有记录和收支汇总。'), true, ); assert.equal(isPageDataIntent('帮我做一个苏州攻略页面'), false); }); test('isPageDataIntent treats storefront ordering plus product administration as Page Data', () => { assert.equal( isPageDataIntent('我要做一个页面,里面可以下单,后台可以上架产品'), true, ); assert.equal( isPageDataIntent('做一个后台上架和管理库存的商城,顾客可以购物车下单'), true, ); }); test('isPageDataIntent recognizes order systems with an admin backend', () => { assert.equal( isPageDataIntent('帮我设计一个简单下单系统,不要支付,可以有简单后台管理订单'), true, ); }); test('isPageDataIntent matches implicit interactive sticky-note app requests', () => { const text = '帮我设计一个便签提醒,可以写便签提交,时间轴来显示'; assert.equal(isPageDataIntent(text), true); assert.match( buildAutoChatSkillPrefix(text, ['page-data-collect', 'static-page-publish']), /page-data-collect/, ); }); test('isPageDataIntent does not steal a simple schedule reminder', () => { assert.equal(isPageDataIntent('明天上午9点提醒我开会'), false); assert.equal(isPageDataIntent('创建一个待办'), false); }); test('buildAutoChatSkillPrefix routes ordinary household ledger language to Page Data', () => { const text = '帮我做一个家庭记账页面,我每天可以记录日期、收入、支出、分类和备注,日期默认当天。再做一个管理页面,可以查看所有记录和收支汇总。'; const prefix = buildAutoChatSkillPrefix(text, ['page-data-collect', 'static-page-publish']); assert.match(prefix, /page-data-collect/); assert.match(prefix, /同一轮继续执行/); assert.match(prefix, /禁止 localStorage/); assert.doesNotMatch(prefix, /static-page-publish 技能/); }); test('buildAutoChatSkillPrefix enables publish for implicit page requests', () => { const prefix = buildAutoChatSkillPrefix('苏州攻略页面', ['static-page-publish']); assert.match(prefix, /static-page-publish/); assert.match(prefix, /禁止询问是否还要发布/); }); test('isPageDataDevIntent matches repair phrases but not new survey creation', () => { assert.equal(isPageDataDevIntent('修复问卷 insert 403 columns_not_allowed'), true); assert.equal(isPageDataDevIntent('page-data-dev 修 policy 白名单'), true); assert.equal(isPageDataDevIntent('帮我做一个报名问卷'), false); assert.equal(isPageDataIntent('帮我做一个报名问卷'), true); assert.equal(isPageDataIntent('修复问卷 insert 403 columns_not_allowed'), false); });