File size: 7,718 Bytes
1dbc34b | 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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | 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]]; // Has text + image
const result = formatHistoryAsText(history);
expect(result).toContain('What is in this image?');
expect(result).not.toContain('base64'); // Should not include image data
});
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);
});
});
});
|