354 lines
9.6 KiB
TypeScript
354 lines
9.6 KiB
TypeScript
import { parseComplexResponse } from './parse-complex-response';
|
|
|
|
function createTestReader(chunks: string[]) {
|
|
const readableStream = new ReadableStream<Uint8Array>({
|
|
async start(controller) {
|
|
for (const chunk of chunks) {
|
|
controller.enqueue(Buffer.from(chunk, 'utf-8'));
|
|
}
|
|
controller.close();
|
|
},
|
|
});
|
|
return readableStream.getReader();
|
|
}
|
|
|
|
function assistantTextMessage(text: string) {
|
|
return {
|
|
id: expect.any(String),
|
|
role: 'assistant',
|
|
content: text,
|
|
createdAt: expect.any(Date),
|
|
};
|
|
}
|
|
|
|
describe('parseComplexResponse function', () => {
|
|
it('should parse a single text message', async () => {
|
|
const mockUpdate = vi.fn();
|
|
|
|
const result = await parseComplexResponse({
|
|
reader: createTestReader(['0:"Hello"\n']),
|
|
abortControllerRef: { current: new AbortController() },
|
|
update: mockUpdate,
|
|
generateId: () => 'test-id',
|
|
getCurrentDate: () => new Date(0),
|
|
});
|
|
|
|
const expectedMessage = assistantTextMessage('Hello');
|
|
|
|
// check the mockUpdate call:
|
|
expect(mockUpdate).toHaveBeenCalledTimes(1);
|
|
expect(mockUpdate.mock.calls[0][0]).toEqual([expectedMessage]);
|
|
|
|
// check the result
|
|
expect(result).toEqual({
|
|
messages: [
|
|
{
|
|
content: 'Hello',
|
|
createdAt: new Date(0),
|
|
id: 'test-id',
|
|
role: 'assistant',
|
|
},
|
|
],
|
|
data: [],
|
|
});
|
|
});
|
|
|
|
it('should parse a sequence of text messages', async () => {
|
|
const mockUpdate = vi.fn();
|
|
|
|
const result = await parseComplexResponse({
|
|
reader: createTestReader([
|
|
'0:"Hello"\n',
|
|
'0:","\n',
|
|
'0:" world"\n',
|
|
'0:"."\n',
|
|
]),
|
|
abortControllerRef: { current: new AbortController() },
|
|
update: mockUpdate,
|
|
generateId: () => 'test-id',
|
|
getCurrentDate: () => new Date(0),
|
|
});
|
|
|
|
// check the mockUpdate call:
|
|
expect(mockUpdate).toHaveBeenCalledTimes(4);
|
|
expect(mockUpdate.mock.calls[0][0]).toEqual([
|
|
assistantTextMessage('Hello'),
|
|
]);
|
|
expect(mockUpdate.mock.calls[1][0]).toEqual([
|
|
assistantTextMessage('Hello,'),
|
|
]);
|
|
expect(mockUpdate.mock.calls[2][0]).toEqual([
|
|
assistantTextMessage('Hello, world'),
|
|
]);
|
|
expect(mockUpdate.mock.calls[3][0]).toEqual([
|
|
assistantTextMessage('Hello, world.'),
|
|
]);
|
|
|
|
// check the result
|
|
expect(result).toEqual({
|
|
messages: [
|
|
{
|
|
content: 'Hello, world.',
|
|
createdAt: new Date(0),
|
|
id: 'test-id',
|
|
role: 'assistant',
|
|
},
|
|
],
|
|
data: [],
|
|
});
|
|
});
|
|
|
|
it('should parse a function call', async () => {
|
|
const mockUpdate = vi.fn();
|
|
|
|
const result = await parseComplexResponse({
|
|
reader: createTestReader([
|
|
'1:{"function_call":{"name":"get_current_weather","arguments":"{\\n\\"location\\": \\"Charlottesville, Virginia\\",\\n\\"format\\": \\"celsius\\"\\n}"}}\n',
|
|
]),
|
|
abortControllerRef: { current: new AbortController() },
|
|
update: mockUpdate,
|
|
generateId: () => 'test-id',
|
|
getCurrentDate: () => new Date(0),
|
|
});
|
|
|
|
// check the mockUpdate call:
|
|
expect(mockUpdate).toHaveBeenCalledTimes(1);
|
|
expect(mockUpdate.mock.calls[0][0]).toEqual([
|
|
{
|
|
id: expect.any(String),
|
|
role: 'assistant',
|
|
content: '',
|
|
name: 'get_current_weather',
|
|
function_call: {
|
|
name: 'get_current_weather',
|
|
arguments:
|
|
'{\n"location": "Charlottesville, Virginia",\n"format": "celsius"\n}',
|
|
},
|
|
createdAt: expect.any(Date),
|
|
},
|
|
]);
|
|
|
|
// check the result
|
|
expect(result).toEqual({
|
|
messages: [
|
|
{
|
|
content: '',
|
|
createdAt: new Date(0),
|
|
id: 'test-id',
|
|
role: 'assistant',
|
|
function_call: {
|
|
name: 'get_current_weather',
|
|
arguments:
|
|
'{\n"location": "Charlottesville, Virginia",\n"format": "celsius"\n}',
|
|
},
|
|
name: 'get_current_weather',
|
|
},
|
|
],
|
|
data: [],
|
|
});
|
|
});
|
|
|
|
it('should parse a combination of a data and a text message', async () => {
|
|
const mockUpdate = vi.fn();
|
|
|
|
// Execute the parser function
|
|
const result = await parseComplexResponse({
|
|
reader: createTestReader([
|
|
'2:[{"t1":"v1"}]\n',
|
|
'0:"Sample text message."\n',
|
|
]),
|
|
abortControllerRef: { current: new AbortController() },
|
|
update: mockUpdate,
|
|
generateId: () => 'test-id',
|
|
getCurrentDate: () => new Date(0),
|
|
});
|
|
|
|
// check the mockUpdate call:
|
|
expect(mockUpdate).toHaveBeenCalledTimes(2);
|
|
|
|
expect(mockUpdate.mock.calls[0][0]).toEqual([]);
|
|
expect(mockUpdate.mock.calls[0][1]).toEqual([{ t1: 'v1' }]);
|
|
|
|
expect(mockUpdate.mock.calls[1][0]).toEqual([
|
|
assistantTextMessage('Sample text message.'),
|
|
]);
|
|
expect(mockUpdate.mock.calls[1][1]).toEqual([{ t1: 'v1' }]);
|
|
|
|
// check the result
|
|
expect(result).toEqual({
|
|
messages: [
|
|
{
|
|
content: 'Sample text message.',
|
|
createdAt: new Date(0),
|
|
id: 'test-id',
|
|
role: 'assistant',
|
|
},
|
|
],
|
|
data: [{ t1: 'v1' }],
|
|
});
|
|
});
|
|
|
|
it('should parse multiple data messages incl. primitive values', async () => {
|
|
const mockUpdate = vi.fn();
|
|
|
|
// Execute the parser function
|
|
const result = await parseComplexResponse({
|
|
reader: createTestReader([
|
|
'2:[{"t1":"v1"}, 3]\n',
|
|
'2:[null,false,"text"]\n',
|
|
]),
|
|
abortControllerRef: { current: new AbortController() },
|
|
update: mockUpdate,
|
|
generateId: () => 'test-id',
|
|
getCurrentDate: () => new Date(0),
|
|
});
|
|
|
|
// check the mockUpdate call:
|
|
expect(mockUpdate).toHaveBeenCalledTimes(2);
|
|
|
|
expect(mockUpdate.mock.calls[0][0]).toEqual([]);
|
|
expect(mockUpdate.mock.calls[0][1]).toEqual([{ t1: 'v1' }, 3]);
|
|
|
|
expect(mockUpdate.mock.calls[1][0]).toEqual([]);
|
|
expect(mockUpdate.mock.calls[1][1]).toEqual([
|
|
{ t1: 'v1' },
|
|
3,
|
|
null,
|
|
false,
|
|
'text',
|
|
]);
|
|
|
|
// check the result
|
|
expect(result).toEqual({
|
|
messages: [],
|
|
data: [{ t1: 'v1' }, 3, null, false, 'text'],
|
|
});
|
|
});
|
|
|
|
it('should parse a combination of a text message and message annotations', async () => {
|
|
const mockUpdate = vi.fn();
|
|
|
|
// Execute the parser function
|
|
const result = await parseComplexResponse({
|
|
reader: createTestReader([
|
|
'8:[{"key":"value"}, 2]\n',
|
|
'0:"Sample text message."\n',
|
|
]),
|
|
abortControllerRef: { current: new AbortController() },
|
|
update: mockUpdate,
|
|
generateId: () => 'test-id',
|
|
getCurrentDate: () => new Date(0),
|
|
});
|
|
|
|
// check the mockUpdate call:
|
|
expect(mockUpdate).toHaveBeenCalledTimes(2);
|
|
|
|
expect(mockUpdate.mock.calls[0][0]).toEqual([]);
|
|
|
|
expect(mockUpdate.mock.calls[1][0]).toEqual([
|
|
{
|
|
...assistantTextMessage('Sample text message.'),
|
|
annotations: [{ key: 'value' }, 2],
|
|
},
|
|
]);
|
|
|
|
// check the result
|
|
expect(result).toEqual({
|
|
messages: [
|
|
{
|
|
...assistantTextMessage('Sample text message.'),
|
|
annotations: [{ key: 'value' }, 2],
|
|
},
|
|
],
|
|
data: [],
|
|
});
|
|
});
|
|
|
|
it('should parse a combination of a function_call and message annotations', async () => {
|
|
const mockUpdate = vi.fn();
|
|
|
|
// Execute the parser function
|
|
const result = await parseComplexResponse({
|
|
reader: createTestReader([
|
|
'1:{"function_call":{"name":"get_current_weather","arguments":"{\\n\\"location\\": \\"Charlottesville, Virginia\\",\\n\\"format\\": \\"celsius\\"\\n}"}}\n',
|
|
'8:[{"key":"value"}, 2]\n',
|
|
'8:[null,false,"text"]\n',
|
|
]),
|
|
abortControllerRef: { current: new AbortController() },
|
|
update: mockUpdate,
|
|
generateId: () => 'test-id',
|
|
getCurrentDate: () => new Date(0),
|
|
});
|
|
|
|
// check the mockUpdate call:
|
|
expect(mockUpdate).toHaveBeenCalledTimes(3);
|
|
|
|
expect(mockUpdate.mock.calls[0][0]).toEqual([
|
|
{
|
|
content: '',
|
|
createdAt: new Date(0),
|
|
id: 'test-id',
|
|
role: 'assistant',
|
|
function_call: {
|
|
name: 'get_current_weather',
|
|
arguments:
|
|
'{\n"location": "Charlottesville, Virginia",\n"format": "celsius"\n}',
|
|
},
|
|
name: 'get_current_weather',
|
|
},
|
|
]);
|
|
|
|
expect(mockUpdate.mock.calls[1][0]).toEqual([
|
|
{
|
|
content: '',
|
|
createdAt: new Date(0),
|
|
id: 'test-id',
|
|
role: 'assistant',
|
|
function_call: {
|
|
name: 'get_current_weather',
|
|
arguments:
|
|
'{\n"location": "Charlottesville, Virginia",\n"format": "celsius"\n}',
|
|
},
|
|
name: 'get_current_weather',
|
|
annotations: [{ key: 'value' }, 2],
|
|
},
|
|
]);
|
|
|
|
expect(mockUpdate.mock.calls[2][0]).toEqual([
|
|
{
|
|
content: '',
|
|
createdAt: new Date(0),
|
|
id: 'test-id',
|
|
role: 'assistant',
|
|
function_call: {
|
|
name: 'get_current_weather',
|
|
arguments:
|
|
'{\n"location": "Charlottesville, Virginia",\n"format": "celsius"\n}',
|
|
},
|
|
name: 'get_current_weather',
|
|
annotations: [{ key: 'value' }, 2, null, false, 'text'],
|
|
},
|
|
]);
|
|
|
|
// check the result
|
|
expect(result).toEqual({
|
|
messages: [
|
|
{
|
|
content: '',
|
|
createdAt: new Date(0),
|
|
id: 'test-id',
|
|
role: 'assistant',
|
|
function_call: {
|
|
name: 'get_current_weather',
|
|
arguments:
|
|
'{\n"location": "Charlottesville, Virginia",\n"format": "celsius"\n}',
|
|
},
|
|
name: 'get_current_weather',
|
|
annotations: [{ key: 'value' }, 2, null, false, 'text'],
|
|
},
|
|
],
|
|
data: [],
|
|
});
|
|
});
|
|
});
|