/** * 回归测试:graph-console 底部聊天条的上下文注入不变式—— * context 变了才拼上下文行,没变就原样发,不能每条消息都刷一遍。 */ import { describe, it, expect } from 'vitest'; import { contextKey, buildOutgoingMessage } from './chatContextInjection.js'; const ctxA = { taskId: 'T-1', taskTitle: '任务A', taskStatus: 'running', goalId: 'G-1', goalTitle: '目标A' }; const ctxB = { taskId: 'T-2', taskTitle: '任务B', taskStatus: 'pending', goalId: 'G-2', goalTitle: '目标B' }; describe('chatContextInjection · buildOutgoingMessage', () => { it('首次发送(lastSentKey 为空)带上下文时要拼上下文行', () => { const { payload, nextKey } = buildOutgoingMessage('你好', ctxA, ''); expect(payload).toContain('T-1'); expect(payload).toContain('任务A'); expect(payload.endsWith('你好')).toBe(true); expect(nextKey).toBe(contextKey(ctxA)); }); it('context 跟上次相同时不重复拼上下文行,原样发送用户文本', () => { const first = buildOutgoingMessage('第一条', ctxA, ''); const second = buildOutgoingMessage('第二条', ctxA, first.nextKey); expect(second.payload).toBe('第二条'); expect(second.nextKey).toBe(first.nextKey); }); it('context 换了(task 或 goal 变化)要重新拼一次', () => { const first = buildOutgoingMessage('第一条', ctxA, ''); const second = buildOutgoingMessage('切到另一个任务了', ctxB, first.nextKey); expect(second.payload).toContain('T-2'); expect(second.payload).toContain('任务B'); expect(second.nextKey).toBe(contextKey(ctxB)); expect(second.nextKey).not.toBe(first.nextKey); }); it('没有 context(没选中任务)时原样发送,不拼任何说明', () => { const { payload, nextKey } = buildOutgoingMessage('随便聊聊', null, 'stale-key'); expect(payload).toBe('随便聊聊'); expect(nextKey).toBe('stale-key'); // 透传,不产生新 key }); }); describe('chatContextInjection · contextKey', () => { it('null context 的 key 是空字符串', () => { expect(contextKey(null)).toBe(''); }); it('taskId/goalId 相同则 key 相同,跟 title/status 无关', () => { const same = { ...ctxA, taskTitle: '改了标题', taskStatus: 'completed' }; expect(contextKey(same)).toBe(contextKey(ctxA)); }); });