| import { describe, it, expect } from 'vitest'; |
| import { |
| extractTextFromContent, |
| normalizeContentBlocks, |
| formatHistoryAsText, |
| convertHistoryToMessages, |
| } from '@automaker/utils'; |
| import { conversationHistoryFixture } from '../../fixtures/messages.js'; |
|
|
| describe('conversation-utils.ts', () => { |
| describe('extractTextFromContent', () => { |
| it('should return string content as-is', () => { |
| const result = extractTextFromContent('Hello world'); |
| expect(result).toBe('Hello world'); |
| }); |
|
|
| it('should extract text from single text block', () => { |
| const content = [{ type: 'text', text: 'Hello' }]; |
| const result = extractTextFromContent(content); |
| expect(result).toBe('Hello'); |
| }); |
|
|
| it('should extract and join multiple text blocks with newlines', () => { |
| const content = [ |
| { type: 'text', text: 'First block' }, |
| { type: 'text', text: 'Second block' }, |
| { type: 'text', text: 'Third block' }, |
| ]; |
| const result = extractTextFromContent(content); |
| expect(result).toBe('First block\nSecond block\nThird block'); |
| }); |
|
|
| it('should ignore non-text blocks', () => { |
| const content = [ |
| { type: 'text', text: 'Text content' }, |
| { type: 'image', source: { type: 'base64', data: 'abc' } }, |
| { type: 'text', text: 'More text' }, |
| { type: 'tool_use', name: 'bash', input: {} }, |
| ]; |
| const result = extractTextFromContent(content); |
| expect(result).toBe('Text content\nMore text'); |
| }); |
|
|
| it('should handle blocks without text property', () => { |
| const content = [ |
| { type: 'text', text: 'Valid' }, |
| { type: 'text' } as any, |
| { type: 'text', text: 'Also valid' }, |
| ]; |
| const result = extractTextFromContent(content); |
| expect(result).toBe('Valid\n\nAlso valid'); |
| }); |
|
|
| it('should handle empty array', () => { |
| const result = extractTextFromContent([]); |
| expect(result).toBe(''); |
| }); |
|
|
| it('should handle array with only non-text blocks', () => { |
| const content = [ |
| { type: 'image', source: {} }, |
| { type: 'tool_use', name: 'test' }, |
| ]; |
| const result = extractTextFromContent(content); |
| expect(result).toBe(''); |
| }); |
| }); |
|
|
| describe('normalizeContentBlocks', () => { |
| it('should convert string to content block array', () => { |
| const result = normalizeContentBlocks('Hello'); |
| expect(result).toEqual([{ type: 'text', text: 'Hello' }]); |
| }); |
|
|
| it('should return array content as-is', () => { |
| const content = [ |
| { type: 'text', text: 'Hello' }, |
| { type: 'image', source: {} }, |
| ]; |
| const result = normalizeContentBlocks(content); |
| expect(result).toBe(content); |
| expect(result).toHaveLength(2); |
| }); |
|
|
| it('should handle empty string', () => { |
| const result = normalizeContentBlocks(''); |
| expect(result).toEqual([{ type: 'text', text: '' }]); |
| }); |
| }); |
|
|
| describe('formatHistoryAsText', () => { |
| it('should return empty string for empty history', () => { |
| const result = formatHistoryAsText([]); |
| expect(result).toBe(''); |
| }); |
|
|
| it('should format single user message', () => { |
| const history = [{ role: 'user' as const, content: 'Hello' }]; |
| const result = formatHistoryAsText(history); |
|
|
| expect(result).toContain('Previous conversation:'); |
| expect(result).toContain('User: Hello'); |
| expect(result).toContain('---'); |
| }); |
|
|
| it('should format single assistant message', () => { |
| const history = [{ role: 'assistant' as const, content: 'Hi there' }]; |
| const result = formatHistoryAsText(history); |
|
|
| expect(result).toContain('Assistant: Hi there'); |
| }); |
|
|
| it('should format multiple messages with correct roles', () => { |
| const history = conversationHistoryFixture.slice(0, 2); |
| const result = formatHistoryAsText(history); |
|
|
| expect(result).toContain('User: Hello, can you help me?'); |
| expect(result).toContain('Assistant: Of course! How can I assist you today?'); |
| expect(result).toContain('---'); |
| }); |
|
|
| it('should handle messages with array content (multipart)', () => { |
| const history = [conversationHistoryFixture[2]]; |
| const result = formatHistoryAsText(history); |
|
|
| expect(result).toContain('What is in this image?'); |
| expect(result).not.toContain('base64'); |
| }); |
|
|
| it('should format all messages from fixture', () => { |
| const result = formatHistoryAsText(conversationHistoryFixture); |
|
|
| expect(result).toContain('Previous conversation:'); |
| expect(result).toContain('User: Hello, can you help me?'); |
| expect(result).toContain('Assistant: Of course!'); |
| expect(result).toContain('User: What is in this image?'); |
| expect(result).toContain('---'); |
| }); |
|
|
| it('should separate messages with double newlines', () => { |
| const history = [ |
| { role: 'user' as const, content: 'First' }, |
| { role: 'assistant' as const, content: 'Second' }, |
| ]; |
| const result = formatHistoryAsText(history); |
|
|
| expect(result).toMatch(/User: First\n\nAssistant: Second/); |
| }); |
| }); |
|
|
| describe('convertHistoryToMessages', () => { |
| it('should convert empty history', () => { |
| const result = convertHistoryToMessages([]); |
| expect(result).toEqual([]); |
| }); |
|
|
| it('should convert single message to SDK format', () => { |
| const history = [{ role: 'user' as const, content: 'Hello' }]; |
| const result = convertHistoryToMessages(history); |
|
|
| expect(result).toHaveLength(1); |
| expect(result[0]).toMatchObject({ |
| type: 'user', |
| session_id: '', |
| message: { |
| role: 'user', |
| content: [{ type: 'text', text: 'Hello' }], |
| }, |
| parent_tool_use_id: null, |
| }); |
| }); |
|
|
| it('should normalize string content to array', () => { |
| const history = [{ role: 'assistant' as const, content: 'Response' }]; |
| const result = convertHistoryToMessages(history); |
|
|
| expect(result[0].message.content).toEqual([{ type: 'text', text: 'Response' }]); |
| }); |
|
|
| it('should preserve array content', () => { |
| const history = [ |
| { |
| role: 'user' as const, |
| content: [ |
| { type: 'text', text: 'Hello' }, |
| { type: 'image', source: {} }, |
| ], |
| }, |
| ]; |
| const result = convertHistoryToMessages(history); |
|
|
| expect(result[0].message.content).toHaveLength(2); |
| expect(result[0].message.content[0]).toEqual({ type: 'text', text: 'Hello' }); |
| }); |
|
|
| it('should convert multiple messages', () => { |
| const history = conversationHistoryFixture.slice(0, 2); |
| const result = convertHistoryToMessages(history); |
|
|
| expect(result).toHaveLength(2); |
| expect(result[0].type).toBe('user'); |
| expect(result[1].type).toBe('assistant'); |
| }); |
|
|
| it('should set correct fields for SDK format', () => { |
| const history = [{ role: 'user' as const, content: 'Test' }]; |
| const result = convertHistoryToMessages(history); |
|
|
| expect(result[0].session_id).toBe(''); |
| expect(result[0].parent_tool_use_id).toBeNull(); |
| expect(result[0].type).toBe('user'); |
| expect(result[0].message.role).toBe('user'); |
| }); |
|
|
| it('should handle all messages from fixture', () => { |
| const result = convertHistoryToMessages(conversationHistoryFixture); |
|
|
| expect(result).toHaveLength(3); |
| expect(result[0].message.content).toBeInstanceOf(Array); |
| expect(result[1].message.content).toBeInstanceOf(Array); |
| expect(result[2].message.content).toBeInstanceOf(Array); |
| }); |
| }); |
| }); |
|
|