diff --git a/src/core/__tests__/Cline.test.ts b/src/core/__tests__/Cline.test.ts index 161e46d..4e9b98b 100644 --- a/src/core/__tests__/Cline.test.ts +++ b/src/core/__tests__/Cline.test.ts @@ -1,6 +1,7 @@ import { Cline } from '../Cline'; import { ClineProvider } from '../webview/ClineProvider'; import { ApiConfiguration } from '../../shared/api'; +import { ApiStreamChunk } from '../../api/transform/stream'; import * as vscode from 'vscode'; // Mock all MCP-related modules @@ -419,5 +420,84 @@ describe('Cline', () => { expect(details).toContain('# Current Time'); expect(details).toMatch(/1\/1\/2024.*5:00:00 AM.*\(America\/Los_Angeles, UTC-7:00\)/); // Full time string format }); + + describe('API conversation handling', () => { + it('should clean conversation history before sending to API', async () => { + const cline = new Cline( + mockProvider, + mockApiConfig, + undefined, + false, + undefined, + 'test task' + ); + + // Mock the API's createMessage method to capture the conversation history + const createMessageSpy = jest.fn(); + const mockStream = { + async *[Symbol.asyncIterator]() { + yield { type: 'text', text: '' }; + }, + async next() { + return { done: true, value: undefined }; + }, + async return() { + return { done: true, value: undefined }; + }, + async throw(e: any) { + throw e; + }, + async [Symbol.asyncDispose]() { + // Cleanup + } + } as AsyncGenerator; + + jest.spyOn(cline.api, 'createMessage').mockImplementation((...args) => { + createMessageSpy(...args); + return mockStream; + }); + + // Add a message with extra properties to the conversation history + const messageWithExtra = { + role: 'user' as const, + content: [{ type: 'text' as const, text: 'test message' }], + ts: Date.now(), + extraProp: 'should be removed' + }; + cline.apiConversationHistory = [messageWithExtra]; + + // Trigger an API request + await cline.recursivelyMakeClineRequests([ + { type: 'text', text: 'test request' } + ]); + + // Get all calls to createMessage + const calls = createMessageSpy.mock.calls; + + // Find the call that includes our test message + const relevantCall = calls.find(call => + call[1]?.some((msg: any) => + msg.content?.[0]?.text === 'test message' + ) + ); + + // Verify the conversation history was cleaned in the relevant call + expect(relevantCall?.[1]).toEqual( + expect.arrayContaining([ + { + role: 'user', + content: [{ type: 'text', text: 'test message' }] + } + ]) + ); + + // Verify extra properties were removed + const passedMessage = relevantCall?.[1].find((msg: any) => + msg.content?.[0]?.text === 'test message' + ); + expect(passedMessage).not.toHaveProperty('ts'); + expect(passedMessage).not.toHaveProperty('extraProp'); + }); + }); }); });