agent-chat-history-context.test.js
2.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* Guard: 同一 convId 恢复上下文时(buildPrompt 场景 C)按模型上下文 token 预算动态注入历史,
* 不再是固定的 slice(-20) + 单条 500 字截断 —— 预算内整段塞进去,超预算才从最早的开始丢。
* 否则 ACP 进程重启/空闲超时后,早于第 20 条的历史会静默丢失,agent 会"忘了"之前聊过什么。
*/
const fs = require('fs');
const path = require('path');
const { buildPrompt, appendHistory, truncateHistoryToBudget, estimateTokens } = require('../../routes/agent-chat');
const agentId = 'master';
const agentDir = path.resolve(__dirname, `../../../system/agents/${agentId}`);
describe('agent-chat buildPrompt 场景 C:同 convId 恢复上下文', () => {
it('注入完整历史,不按 slice(-20) 或单条 500 字截断', () => {
const convId = `test-history-guard-${Date.now()}`;
const convDir = path.resolve(__dirname, `../../../system/agents/${agentId}/_global/conversations/${convId}`);
try {
const longFirstMessage = 'X'.repeat(600); // 超过原来单条 500 字截断阈值
appendHistory(agentId, convId, { role: 'user', content: longFirstMessage });
for (let i = 0; i < 25; i++) {
appendHistory(agentId, convId, { role: 'assistant', content: `filler-${i}` });
}
const prompt = buildPrompt(agentDir, agentId, convId, '新消息', true);
expect(prompt).toContain(longFirstMessage);
expect(prompt).not.toContain('...(截断)');
} finally {
fs.rmSync(convDir, { recursive: true, force: true });
}
});
});
describe('truncateHistoryToBudget:预算超支时按 token 从最早的开始丢', () => {
it('预算装不下全部历史时,丢最老的,留最近的', () => {
const history = [
{ role: 'user', content: 'oldest' },
{ role: 'assistant', content: 'middle' },
{ role: 'user', content: 'newest' },
];
const budget = estimateTokens('middle') + estimateTokens('newest'); // 刚好够后两条,装不下 oldest
const kept = truncateHistoryToBudget(history, budget);
expect(kept.map(m => m.content)).toEqual(['middle', 'newest']);
});
it('单条消息本身就超预算时,仍然至少保留最近一条,不会返回空', () => {
const history = [{ role: 'user', content: 'X'.repeat(10000) }];
const kept = truncateHistoryToBudget(history, 1);
expect(kept).toHaveLength(1);
});
});