diff --git a/packages/ai/streams/assistant-response.ts b/packages/ai/streams/assistant-response.ts index c4d872483c8f..40e4f83a880a 100644 --- a/packages/ai/streams/assistant-response.ts +++ b/packages/ai/streams/assistant-response.ts @@ -92,6 +92,7 @@ export function AssistantResponse( textEncoder.encode( formatStreamPart('assistant_message', { id: value.data.id, + createdAt: value.data.created_at ? new Date(value.data.created_at * 1000) : undefined, role: 'assistant', content: [{ type: 'text', text: { value: '' } }], }), diff --git a/packages/react/src/use-assistant.ts b/packages/react/src/use-assistant.ts index 7a366f451fe3..b3ead342bda7 100644 --- a/packages/react/src/use-assistant.ts +++ b/packages/react/src/use-assistant.ts @@ -186,6 +186,7 @@ export function useAssistant({ { id: value.id, role: value.role, + createdAt: value.createdAt, content: value.content[0].text.value, }, ]); @@ -201,6 +202,7 @@ export function useAssistant({ { id: lastMessage.id, role: lastMessage.role, + createdAt: lastMessage.createdAt, content: lastMessage.content + value, }, ]; diff --git a/packages/react/src/use-assistant.ui.test.tsx b/packages/react/src/use-assistant.ui.test.tsx index 37dd58405b49..80f6164946f1 100644 --- a/packages/react/src/use-assistant.ui.test.tsx +++ b/packages/react/src/use-assistant.ui.test.tsx @@ -23,6 +23,7 @@ describe('stream data stream', () => {
{m.role === 'user' ? 'User: ' : 'AI: '} {m.content} + {m.createdAt && ` (Created at: ${m.createdAt})`}
))} @@ -85,6 +86,91 @@ describe('stream data stream', () => { ); }); + it('should show streamed response with createdAt', async () => { + const { requestBody } = mockFetchDataStream({ + url: 'https://example.com/api/assistant', + chunks: [ + formatStreamPart('assistant_control_data', { + threadId: 't0', + messageId: 'm0', + }), + formatStreamPart('assistant_message', { + id: 'm0', + role: 'assistant', + createdAt: new Date(1727703377 * 1000), + content: [{ type: 'text', text: { value: '' } }], + }), + // text parts: + '0:"Hello"\n', + '0:","\n', + '0:" world"\n', + '0:"."\n', + ], + }); + + await userEvent.click(screen.getByTestId('do-append')); + + await screen.findByTestId('message-0'); + expect(screen.getByTestId('message-0')).toHaveTextContent('User: hi'); + + await screen.findByTestId('message-1'); + const messageContent = screen.getByTestId('message-1').textContent; + console.log(messageContent); + + expect(messageContent).toContain('AI: Hello, world.'); + expect(messageContent).toContain(`Created at: ${new Date(1727703377 * 1000).toISOString()}`); + + // check that correct information was sent to the server: + expect(await requestBody).toStrictEqual( + JSON.stringify({ + threadId: null, + message: 'hi', + }), + ); + }); + + it('should show streamed response without createdAt', async () => { + const { requestBody } = mockFetchDataStream({ + url: 'https://example.com/api/assistant', + chunks: [ + formatStreamPart('assistant_control_data', { + threadId: 't0', + messageId: 'm0', + }), + formatStreamPart('assistant_message', { + id: 'm0', + role: 'assistant', + content: [{ type: 'text', text: { value: '' } }], + }), + // text parts: + '0:"Hello"\n', + '0:","\n', + '0:" world"\n', + '0:"."\n', + ], + }); + + await userEvent.click(screen.getByTestId('do-append')); + + await screen.findByTestId('message-0'); + expect(screen.getByTestId('message-0')).toHaveTextContent('User: hi'); + + await screen.findByTestId('message-1'); + const messageContent = screen.getByTestId('message-1').textContent; + console.log(messageContent); + + expect(messageContent).toContain('AI: Hello, world.'); + expect(messageContent).not.toContain('Created at:'); + + // check that correct information was sent to the server: + expect(await requestBody).toStrictEqual( + JSON.stringify({ + threadId: null, + message: 'hi', + }), + ); + }); + it('should show error response', async () => { mockFetchError({ statusCode: 500, errorMessage: 'Internal Error' }); diff --git a/packages/ui-utils/src/stream-parts.ts b/packages/ui-utils/src/stream-parts.ts index 4b5470943ad8..b169c66c7fdb 100644 --- a/packages/ui-utils/src/stream-parts.ts +++ b/packages/ui-utils/src/stream-parts.ts @@ -121,7 +121,7 @@ const assistantMessageStreamPart: StreamPart< return { type: 'assistant_message', - value: value as AssistantMessage, + value: value as unknown as AssistantMessage, }; }, }; diff --git a/packages/ui-utils/src/types.ts b/packages/ui-utils/src/types.ts index df59a5d42e34..53a30dd95a8e 100644 --- a/packages/ui-utils/src/types.ts +++ b/packages/ui-utils/src/types.ts @@ -604,6 +604,7 @@ export type JSONValue = export type AssistantMessage = { id: string; role: 'assistant'; + createdAt?: Date; content: Array<{ type: 'text'; text: {