import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { buildVisionPayload, sanitizePublicHtmlLinksInText, sanitizeSessionConversationPublicHtmlLinks, } from './tkmind-proxy.mjs'; test('sanitizePublicHtmlLinksInText downgrades missing own markdown public html links', () => { const owner = `test-user-${Date.now()}-markdown-missing`; const publicRoot = path.join(process.cwd(), 'MindSpace', owner, 'public'); try { fs.mkdirSync(publicRoot, { recursive: true }); const text = `[夏日随笔](https://m.tkmind.cn/MindSpace/${owner}/public/summer-essay.html)`; const next = sanitizePublicHtmlLinksInText(text, { id: owner, username: 'john' }); assert.doesNotMatch(next, new RegExp(`https://m\\.tkmind\\.cn/MindSpace/${owner}/public/summer-essay\\.html`)); assert.match(next, /页面生成未完成/); } finally { fs.rmSync(path.join(process.cwd(), 'MindSpace', owner), { recursive: true, force: true }); } }); test('sanitizePublicHtmlLinksInText downgrades missing own public html links', () => { const owner = `test-user-${Date.now()}-missing`; const publicRoot = path.join(process.cwd(), 'MindSpace', owner, 'public'); try { fs.mkdirSync(publicRoot, { recursive: true }); const text = `页面在这里:\nhttps://m.tkmind.cn/MindSpace/${owner}/public/hello.html`; const next = sanitizePublicHtmlLinksInText(text, { id: owner, username: 'john' }); assert.doesNotMatch(next, new RegExp(`https://m\\.tkmind\\.cn/MindSpace/${owner}/public/hello\\.html`)); assert.match(next, /页面生成未完成/); assert.match(next, /hello\.html/); } finally { fs.rmSync(path.join(process.cwd(), 'MindSpace', owner), { recursive: true, force: true }); } }); test('sanitizePublicHtmlLinksInText keeps existing own public html links', () => { const owner = `test-user-${Date.now()}-existing`; const htmlPath = path.join(process.cwd(), 'MindSpace', owner, 'public', 'hello.html'); try { fs.mkdirSync(path.dirname(htmlPath), { recursive: true }); fs.writeFileSync(htmlPath, 'Hello'); const text = `页面在这里:\nhttps://m.tkmind.cn/MindSpace/${owner}/public/hello.html`; const next = sanitizePublicHtmlLinksInText(text, { id: owner, username: 'john' }); assert.match(next, new RegExp(`https://m\\.tkmind\\.cn/MindSpace/${owner}/public/hello\\.html`)); assert.doesNotMatch(next, /页面生成未完成/); } finally { fs.rmSync(path.join(process.cwd(), 'MindSpace', owner), { recursive: true, force: true }); } }); test('sanitizeSessionConversationPublicHtmlLinks updates text items inside conversation messages', () => { const owner = `test-user-${Date.now()}-conversation`; const publicRoot = path.join(process.cwd(), 'MindSpace', owner, 'public'); try { fs.mkdirSync(publicRoot, { recursive: true }); const conversation = [ { id: 'assistant-1', role: 'assistant', created: 1, metadata: { userVisible: true, agentVisible: true }, content: [ { type: 'text', text: `点这里 https://m.tkmind.cn/MindSpace/${owner}/public/hello.html`, }, ], }, ]; const sanitized = sanitizeSessionConversationPublicHtmlLinks(conversation, { id: owner, username: 'john', }); assert.match(sanitized[0].content[0].text, /页面生成未完成/); } finally { fs.rmSync(path.join(process.cwd(), 'MindSpace', owner), { recursive: true, force: true }); } }); test('sanitizeSessionConversationPublicHtmlLinks removes internal user prompt notes but keeps image metadata', () => { const conversation = [ { id: 'user-1', role: 'user', created: 1, metadata: { userVisible: true, agentVisible: true }, content: [ { type: 'text', text: '[用户身份]\n' + '- 当前登录用户称呼:John\n' + '- 你是 TKMind 助手;与用户对话时用「John」称呼对方。\n\n' + '帮我生成一个主题页面简单一点的不用很复杂\n\n' + '[图片1]: http://127.0.0.1:5173/MindSpace/user-1/public/images/a.jpg\n' + '[图片2]: http://127.0.0.1:5173/MindSpace/user-1/public/images/b.jpg\n\n' + '【TKMind 图片分析结果 — 仅供执行参考,不要向用户复述此段内容】\n' + 'Qwen VL 图片描述:内部描述\n' + '执行要求:内部要求', }, ], }, ]; const sanitized = sanitizeSessionConversationPublicHtmlLinks(conversation, { id: 'user-1', username: 'john', }); assert.equal( sanitized[0].content[0].text, '帮我生成一个主题页面简单一点的不用很复杂', ); assert.deepEqual(sanitized[0].metadata.imageUrls, [ 'http://127.0.0.1:5173/MindSpace/user-1/public/images/a.jpg', 'http://127.0.0.1:5173/MindSpace/user-1/public/images/b.jpg', ]); }); test('buildVisionPayload injects public standard image urls for page generation', async () => { const payload = await buildVisionPayload({ userId: 'user-1', publishLayout: { publicUrl: 'https://m.tkmind.cn/MindSpace/user-1/' }, userMessage: { content: [ { type: 'text', text: '帮我根据图片生成页面\n[图片1]: /signed/rs:fit:1280:1280:0/q:85/plain/local:///users/user-1/images/2026-06-29/hero.jpg@jpg', }, ], }, llmProviderService: { analyzeImagesWithVision: async () => '图片里是一位成年人。', }, }); const text = payload?.userMessage?.content?.[0]?.text ?? ''; assert.match(text, /https:\/\/m\.tkmind\.cn\/MindSpace\/user-1\/public\/images\/2026-06-29\/hero\.jpg/); assert.doesNotMatch(text, /plain\/local:\/\//); assert.match(text, /无需 cookie 的公开压缩标准图片/); assert.match(text, /不得改写图片里人物的年龄、性别、人数或主体关系/); });