import { describe, expect, it } from 'vitest' import { __kimiTestUtils } from './kimi' const { buildSourceItem, classifyKimiSources, isKimiAnswerComplete, isKimiPromotionalAnswerNoise, mergeKimiSourceLinksIntoContentSnapshot, normalizeUrl, } = __kimiTestUtils function buildSnapshot( overrides: Partial[0]>, ): Parameters[0] { return { url: 'https://www.kimi.com/chat/test', title: 'Kimi', currentModelLabel: 'K2.6 思考', loginRequired: false, loginReason: null, busy: false, busySignals: [], sendDisabled: null, answerText: '答案', answerBlocks: ['答案'], reasoningText: null, reasoningBlocks: [], capacityNotice: null, questionMatched: true, candidateAnswerCount: 1, candidateReasoningCount: 0, citationLinks: [], panelCitationLinks: [], inlineCitationCandidateLinks: [], searchResultLinks: [], signature: 'sig', ...overrides, } } describe('kimi adapter helpers', () => { it('unwraps Kimi redirect URLs before storing source items', () => { expect( normalizeUrl('https://www.kimi.com/redirect?url=https%3A%2F%2Fexample.com%2Fsource%23ref'), ).toBe('https://example.com/source') expect( buildSourceItem({ url: 'https://www.kimi.com/redirect?target=https%3A%2F%2Fsource.example.com%2Fnews%3Fid%3D1', title: '搜索结果标题', text: null, siteName: '来源站点', }), ).toMatchObject({ url: 'https://source.example.com/news?id=1', normalized_url: 'https://source.example.com/news?id=1', title: '搜索结果标题', site_name: '来源站点', host: 'source.example.com', }) }) it('uses search web results as citation sources and footer references as content citation candidates', () => { const classified = classifyKimiSources( buildSnapshot({ searchResultLinks: [ { url: 'https://search.example.com/a', title: '搜索网页 A', text: '搜索网页 A', siteName: '搜索站点', }, ], panelCitationLinks: [ { url: 'https://content.example.com/cited', title: '页尾引用文章', text: '页尾引用文章', siteName: '内容站点', }, ], inlineCitationCandidateLinks: [ { url: 'https://content.example.com/site', title: null, text: '内容站点', siteName: '内容站点', }, ], }), ) expect(classified.citations).toHaveLength(1) expect(classified.citations[0]?.url).toBe('https://search.example.com/a') expect(classified.searchResults[0]?.url).toBe('https://search.example.com/a') expect(classified.panelCitations[0]?.url).toBe('https://content.example.com/cited') expect(classified.inlineCitationCandidates.map((item) => item.url)).toEqual([ 'https://content.example.com/cited', 'https://content.example.com/site', ]) }) it('falls back to footer references as citation sources when no search web results are visible', () => { const classified = classifyKimiSources( buildSnapshot({ panelCitationLinks: [ { url: 'https://content.example.com/cited', title: '页尾引用文章', text: '页尾引用文章', siteName: '内容站点', }, ], }), ) expect(classified.searchResults).toHaveLength(0) expect(classified.citations).toHaveLength(1) expect(classified.citations[0]?.url).toBe('https://content.example.com/cited') }) it('keeps the answer text from the content snapshot when merging side-panel sources', () => { const merged = mergeKimiSourceLinksIntoContentSnapshot( buildSnapshot({ answerText: '真实回答正文', answerBlocks: ['真实回答正文'], }), buildSnapshot({ answerText: '搜索网页 48\nhttps://example.com/a 很长的侧栏文本', answerBlocks: ['搜索网页 48\nhttps://example.com/a 很长的侧栏文本'], searchResultLinks: [ { url: 'https://example.com/a', title: '搜索结果 A', text: '搜索结果 A', siteName: 'Example', }, ], }), ) expect(merged.answerText).toBe('真实回答正文') expect(merged.answerBlocks).toEqual(['真实回答正文']) expect(merged.searchResultLinks).toHaveLength(1) expect(merged.searchResultLinks[0]?.url).toBe('https://example.com/a') }) it('rejects Kimi K2.6 marketing copy as an answer', () => { const promotionalText = [ 'Kimi K2.6,已就位!', 'Coding、Agent 集群、Kimi Claw 同步升级', 'Agent 集群,升级了', '多技能调用,多产物类型一次性交付', 'Kimi Claw 已就位!', '一键部署 OpenClaw,Kimi 24小时为你干活', ].join('\n') expect(isKimiPromotionalAnswerNoise(promotionalText)).toBe(true) expect( isKimiAnswerComplete( buildSnapshot({ answerText: promotionalText, answerBlocks: [promotionalText], }), ), ).toBe(false) }) })