import assert from 'node:assert/strict'; import test from 'node:test'; import { repairConversationToolHistory } from './chat-tool-history-repair.mjs'; function toolRequest(id, name = 'write_file') { return { role: 'assistant', content: [{ type: 'toolRequest', id, toolCall: { status: 'success', value: { name, arguments: {} } }, }], }; } function toolResponse(id) { return { role: 'user', content: [{ type: 'toolResponse', id, toolResult: { status: 'success', value: { content: [{ type: 'text', text: 'ok' }], isError: false }, }, }], }; } test('repairConversationToolHistory pairs interleaved and reversed tool responses', () => { const conversation = [ { role: 'user', content: [{ type: 'text', text: '生成页面' }] }, toolRequest('call-a'), toolRequest('call-b'), toolResponse('call-b'), { role: 'assistant', content: [{ type: 'text', text: '继续处理' }] }, toolResponse('call-a'), toolResponse('call-c'), toolRequest('call-c'), { role: 'assistant', content: [{ type: 'text', text: '完成' }] }, ]; const result = repairConversationToolHistory(conversation); assert.equal(result.changed, true); assert.deepEqual( result.conversation.map((message) => message.content[0]?.id ?? message.content[0]?.text), ['生成页面', 'call-a', 'call-a', 'call-b', 'call-b', '继续处理', 'call-c', 'call-c', '完成'], ); assert.equal(result.repairedToolResponses, 3); assert.equal(result.droppedToolRequests, 0); assert.equal(result.droppedOrphanResponses, 0); }); test('repairConversationToolHistory leaves valid tool history unchanged', () => { const conversation = [ { role: 'user', content: [{ type: 'text', text: '生成页面' }] }, toolRequest('call-a'), toolResponse('call-a'), { role: 'assistant', content: [{ type: 'text', text: '完成' }] }, ]; const result = repairConversationToolHistory(conversation); assert.equal(result.changed, false); assert.equal(result.conversation, conversation); }); test('repairConversationToolHistory drops unmatched requests and orphan responses', () => { const conversation = [ { role: 'user', content: [{ type: 'text', text: '生成页面' }] }, toolRequest('call-missing'), toolResponse('call-orphan'), { role: 'assistant', content: [{ type: 'text', text: '稍后继续' }] }, ]; const result = repairConversationToolHistory(conversation); assert.equal(result.changed, true); assert.deepEqual( result.conversation.map((message) => message.content[0]?.text), ['生成页面', '稍后继续'], ); assert.equal(result.droppedToolRequests, 1); assert.equal(result.droppedOrphanResponses, 1); });