@quidgest/chatbot 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +1 -2
  2. package/dist/components/ChatBot/types.d.ts +3 -1
  3. package/dist/components/ChatBotInput/ChatBotInput.vue.d.ts +3 -3
  4. package/dist/components/ChatBotInput/__tests__/ChatBotInput.spec.d.ts +1 -0
  5. package/dist/components/ChatBotInput/index.d.ts +2 -2
  6. package/dist/components/ChatBotInput/types.d.ts +4 -4
  7. package/dist/components/ChatBotMessage/__tests__/ChatBotMessage.spec.d.ts +1 -0
  8. package/dist/components/ChatBotMessage/__tests__/ChatBotMessageButtons.spec.d.ts +1 -0
  9. package/dist/components/ChatBotMessage/types.d.ts +3 -2
  10. package/dist/components/ChatToolBar/__tests__/ChatToolBar.spec.d.ts +1 -0
  11. package/dist/components/FieldPreview/__tests__/FieldPreview.spec.d.ts +1 -0
  12. package/dist/components/MarkdownRender/__tests__/MarkdownRender.spec.d.ts +1 -0
  13. package/dist/components/PulseDots/__tests__/PulseDots.spec.d.ts +1 -0
  14. package/dist/composables/__tests__/useChatMessages.spec.d.ts +1 -0
  15. package/dist/composables/__tests__/useSSE.spec.d.ts +1 -0
  16. package/dist/composables/useChatMessages.d.ts +2 -1
  17. package/dist/composables/useSSE.d.ts +1 -2
  18. package/dist/composables/useTexts.d.ts +2 -0
  19. package/dist/index.js +16 -16
  20. package/dist/index.mjs +2924 -1770
  21. package/dist/style.css +1 -1
  22. package/dist/test/setup.d.ts +1 -0
  23. package/dist/utils/__tests__/parseFieldValue.spec.d.ts +1 -0
  24. package/package.json +27 -5
  25. package/src/assets/styles/preview-file.scss +70 -0
  26. package/src/assets/styles/styles.scss +190 -222
  27. package/src/components/ChatBot/ChatBot.vue +345 -368
  28. package/src/components/ChatBot/types.ts +35 -33
  29. package/src/components/ChatBotInput/ChatBotInput.vue +188 -190
  30. package/src/components/ChatBotInput/__tests__/ChatBotInput.spec.ts +279 -0
  31. package/src/components/ChatBotInput/__tests__/__snapshots__/ChatBotInput.spec.ts.snap +25 -0
  32. package/src/components/ChatBotInput/index.ts +2 -2
  33. package/src/components/ChatBotInput/types.ts +25 -25
  34. package/src/components/ChatBotMessage/ChatBotMessage.vue +159 -134
  35. package/src/components/ChatBotMessage/ChatBotMessageButtons.vue +179 -164
  36. package/src/components/ChatBotMessage/__tests__/ChatBotMessage.spec.ts +256 -0
  37. package/src/components/ChatBotMessage/__tests__/ChatBotMessageButtons.spec.ts +199 -0
  38. package/src/components/ChatBotMessage/__tests__/__snapshots__/ChatBotMessage.spec.ts.snap +35 -0
  39. package/src/components/ChatBotMessage/__tests__/__snapshots__/ChatBotMessageButtons.spec.ts.snap +25 -0
  40. package/src/components/ChatBotMessage/types.ts +54 -53
  41. package/src/components/ChatToolBar/ChatToolBar.vue +68 -64
  42. package/src/components/ChatToolBar/__tests__/ChatToolBar.spec.ts +118 -0
  43. package/src/components/ChatToolBar/__tests__/__snapshots__/ChatToolBar.spec.ts.snap +11 -0
  44. package/src/components/ChatToolBar/types.ts +12 -12
  45. package/src/components/FieldPreview/FieldPreview.vue +56 -58
  46. package/src/components/FieldPreview/__tests__/FieldPreview.spec.ts +72 -0
  47. package/src/components/FieldPreview/__tests__/__snapshots__/FieldPreview.spec.ts.snap +25 -0
  48. package/src/components/FieldPreview/field-preview.scss +26 -26
  49. package/src/components/FieldPreview/types.ts +5 -5
  50. package/src/components/MarkdownRender/MarkdownRender.vue +15 -15
  51. package/src/components/MarkdownRender/__tests__/MarkdownRender.spec.ts +68 -0
  52. package/src/components/MarkdownRender/__tests__/__snapshots__/MarkdownRender.spec.ts.snap +8 -0
  53. package/src/components/MarkdownRender/markdown-render.scss +19 -20
  54. package/src/components/MarkdownRender/types.ts +3 -3
  55. package/src/components/PulseDots/PulseDots.vue +17 -17
  56. package/src/components/PulseDots/__tests__/PulseDots.spec.ts +35 -0
  57. package/src/components/PulseDots/__tests__/__snapshots__/PulseDots.spec.ts.snap +7 -0
  58. package/src/components/PulseDots/__tests__/__snapshots__/pulse-dots.spec.ts.snap +7 -0
  59. package/src/components/PulseDots/pulse-dots.scss +24 -23
  60. package/src/composables/__tests__/useChatMessages.spec.ts +51 -0
  61. package/src/composables/__tests__/useSSE.spec.ts +132 -0
  62. package/src/composables/useChatApi.ts +128 -134
  63. package/src/composables/useChatMessages.ts +46 -48
  64. package/src/composables/useSSE.ts +75 -76
  65. package/src/composables/useTexts.ts +30 -30
  66. package/src/test/setup.ts +36 -0
  67. package/src/utils/__tests__/parseFieldValue.spec.ts +27 -0
  68. package/src/utils/parseFieldValue.ts +12 -0
  69. package/src/utils/helper.ts +0 -12
  70. /package/dist/utils/{helper.d.ts → parseFieldValue.d.ts} +0 -0
@@ -1,37 +1,38 @@
1
1
  .pulsing-dots {
2
- display: flex;
3
- align-items: center;
4
- justify-content: center;
5
- flex-direction: row;
6
- gap: 0.25rem;
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ flex-direction: row;
6
+ gap: 0.25rem;
7
7
  }
8
8
 
9
9
  .generating-text {
10
- font-size: 0.9rem;
11
- color: var(--q-theme-primary);
10
+ font-size: 0.9rem;
11
+ color: var(--q-theme-primary);
12
12
  }
13
13
 
14
14
  .dots-container {
15
- display: flex;
16
- align-items: center;
17
- gap: 0.1rem;
15
+ display: flex;
16
+ align-items: center;
17
+ gap: 0.1rem;
18
18
  }
19
19
 
20
20
  .dot {
21
- font-size: 16px;
22
- line-height: 1;
23
- animation: pulse 1s infinite;
24
- color: var(--q-theme-primary);
21
+ font-size: 16px;
22
+ line-height: 1;
23
+ animation: pulse 1s infinite;
24
+ color: var(--q-theme-primary);
25
25
  }
26
26
 
27
27
  @keyframes pulse {
28
- 0%,
29
- 100% {
30
- transform: scale(0.8);
31
- opacity: 0.6;
32
- }
33
- 50% {
34
- transform: scale(1);
35
- opacity: 1;
36
- }
28
+ 0%,
29
+ 100% {
30
+ transform: scale(0.8);
31
+ opacity: 0.6;
32
+ }
33
+
34
+ 50% {
35
+ transform: scale(1);
36
+ opacity: 1;
37
+ }
37
38
  }
@@ -0,0 +1,51 @@
1
+ // Composable
2
+ import { useChatMessages } from '../useChatMessages'
3
+
4
+ // Utils
5
+ import { describe, it, expect, beforeEach } from 'vitest'
6
+
7
+ const { addChatMessage, clearMessages, getMessages, getLastMessage } = useChatMessages()
8
+
9
+ beforeEach(() => {
10
+ // Reset chat messages before each test
11
+ clearMessages()
12
+ })
13
+
14
+ describe('useChatMessages', () => {
15
+ it('should add a chat message', () => {
16
+ addChatMessage('Hello, world!', 'user')
17
+
18
+ const messages = getMessages()
19
+ expect(messages.length).toBe(1)
20
+ expect(messages[0].message).toBe('Hello, world!')
21
+ expect(messages[0].sender).toBe('user')
22
+ })
23
+
24
+ it('should set default sender to bot', () => {
25
+ addChatMessage('Hello, world!')
26
+ const message = getLastMessage()
27
+
28
+ expect(message).toBeDefined()
29
+ expect(message?.sender).toBe('bot')
30
+ expect(message?.message).toBe('Hello, world!')
31
+ })
32
+
33
+ it('should get the last message', () => {
34
+ addChatMessage('First message', 'bot')
35
+ addChatMessage('Second message', 'user')
36
+
37
+ const lastMessage = getLastMessage()
38
+ expect(lastMessage).toBeDefined()
39
+ expect(lastMessage?.message).toBe('Second message')
40
+ expect(lastMessage?.sender).toBe('user')
41
+ })
42
+
43
+ it('should clear all messages', () => {
44
+ addChatMessage('Hello, world!', 'user')
45
+ clearMessages()
46
+
47
+ const messages = getMessages()
48
+ expect(messages).toEqual([])
49
+ expect(messages.length).toBe(0)
50
+ })
51
+ })
@@ -0,0 +1,132 @@
1
+ // Composables
2
+ import { useSSE } from '../useSSE'
3
+
4
+ // Utils
5
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
6
+ import axios from 'axios'
7
+
8
+ // Types
9
+ import type { SSEvents } from '../useSSE'
10
+
11
+ // Mocks
12
+ vi.mock('axios')
13
+ const mockedAxios = vi.mocked(axios)
14
+
15
+ // Utility to create a mock ReadableStream
16
+ function createMockStream(chunks: string[]) {
17
+ return new ReadableStream({
18
+ start(controller) {
19
+ for (const chunk of chunks) {
20
+ controller.enqueue(new TextEncoder().encode(chunk))
21
+ }
22
+ controller.close()
23
+ }
24
+ })
25
+ }
26
+
27
+ describe('useSSE', () => {
28
+ let handlers: SSEvents = {}
29
+
30
+ beforeEach(() => {
31
+ vi.clearAllMocks()
32
+ handlers = {
33
+ onMessage: vi.fn(),
34
+ onError: vi.fn(),
35
+ onFieldMetadata: vi.fn(),
36
+ onDone: vi.fn()
37
+ }
38
+ })
39
+
40
+ it('should handle a message event', async () => {
41
+ const stream = createMockStream(['event: message\ndata: {"value":"hello"}\n\n'])
42
+ mockedAxios.mockResolvedValue({ data: stream })
43
+
44
+ await useSSE({ url: '/sse' }, handlers)
45
+
46
+ expect(handlers.onMessage).toHaveBeenCalledWith('hello')
47
+ expect(handlers.onDone).toHaveBeenCalled()
48
+ })
49
+
50
+ it('should handle an error event', async () => {
51
+ const stream = createMockStream([
52
+ 'event: error\ndata: {"value":"Something went wrong"}\n\n'
53
+ ])
54
+ mockedAxios.mockResolvedValue({ data: stream })
55
+
56
+ await useSSE({ url: '/sse' }, handlers)
57
+
58
+ expect(handlers.onError).toHaveBeenCalled()
59
+
60
+ // We need to cast to access the mock calls
61
+ const onErrorHandler = handlers.onError as ReturnType<typeof vi.fn>
62
+ const errorArg = onErrorHandler.mock.calls[0][0]
63
+
64
+ expect(errorArg).toBeInstanceOf(Error)
65
+ expect(errorArg.message).toBe('Something went wrong')
66
+ })
67
+
68
+ it('should handle field metadata event', async () => {
69
+ const metadata = { foo: 'bar' }
70
+ const stream = createMockStream([
71
+ `event: field_metadata\ndata: ${JSON.stringify(metadata)}\n\n`
72
+ ])
73
+ mockedAxios.mockResolvedValue({ data: stream })
74
+ await useSSE({ url: '/sse' }, handlers)
75
+
76
+ expect(handlers.onFieldMetadata).toHaveBeenCalledWith(metadata)
77
+ expect(handlers.onDone).toHaveBeenCalled()
78
+ })
79
+
80
+ it('should handle a done event', async () => {
81
+ const stream = createMockStream(['event: done\ndata: {}\n\n'])
82
+ mockedAxios.mockResolvedValue({ data: stream })
83
+
84
+ await useSSE({ url: '/sse' }, handlers)
85
+
86
+ expect(handlers.onDone).toHaveBeenCalled()
87
+ })
88
+
89
+ it('should call onError on invalid JSON', async () => {
90
+ const stream = createMockStream(['event: message\ndata: {invalid json}\n\n'])
91
+ mockedAxios.mockResolvedValue({ data: stream })
92
+
93
+ // Suppress console.error for this test
94
+ const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
95
+
96
+ await useSSE({ url: '/sse' }, handlers)
97
+
98
+ expect(handlers.onError).toHaveBeenCalled()
99
+ const onErrorHandler = handlers.onError as ReturnType<typeof vi.fn>
100
+ const errorArg = onErrorHandler.mock.calls[0][0]
101
+
102
+ expect(errorArg).toBeInstanceOf(Error)
103
+ consoleErrorSpy.mockRestore()
104
+ })
105
+
106
+ it('should default to message event if name is missing', async () => {
107
+ const stream = createMockStream(['data: {"value":"default event"}\n\n'])
108
+ mockedAxios.mockResolvedValue({ data: stream })
109
+
110
+ await useSSE({ url: '/sse' }, handlers)
111
+
112
+ expect(handlers.onMessage).toHaveBeenCalledWith('default event')
113
+ expect(handlers.onDone).toHaveBeenCalled()
114
+ })
115
+
116
+ it('should throw an error for non-stream response', async () => {
117
+ mockedAxios.mockResolvedValue({ data: null })
118
+ const fn = useSSE({ url: '/sse' }, handlers)
119
+ await expect(fn).rejects.toThrow('Invalid stream response')
120
+ })
121
+
122
+ it('should warn on unknown event type', async () => {
123
+ const stream = createMockStream(['event: unknown_event\ndata: {"value":"something"}\n\n'])
124
+ mockedAxios.mockResolvedValue({ data: stream })
125
+
126
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
127
+ await useSSE({ url: '/sse' }, handlers)
128
+
129
+ expect(consoleWarnSpy).toHaveBeenCalledWith('Unknown event type: unknown_event')
130
+ consoleWarnSpy.mockRestore()
131
+ })
132
+ })
@@ -8,149 +8,143 @@ import { ChatBotMessageContent } from '@/components/ChatBot/types'
8
8
  import { useSSE } from './useSSE'
9
9
 
10
10
  type RequestResponse<T> = {
11
- data: T | null
12
- error: Error | null
11
+ data: T | null
12
+ error: Error | null
13
13
  }
14
14
 
15
15
  export function useChatApi(apiEndpoint: string) {
16
- const isLoading = ref(false)
17
- const lastError = ref<Error | null>(null)
16
+ const isLoading = ref(false)
17
+ const lastError = ref<Error | null>(null)
18
18
 
19
- async function baseRequest<T>(
20
- config: AxiosRequestConfig
21
- ): Promise<RequestResponse<T>> {
22
- isLoading.value = true
23
- lastError.value = null
19
+ async function baseRequest<T>(config: AxiosRequestConfig): Promise<RequestResponse<T>> {
20
+ isLoading.value = true
21
+ lastError.value = null
24
22
 
25
- try {
26
- const response: AxiosResponse<T> = await axios({
27
- ...config,
28
- baseURL: apiEndpoint
29
- })
30
- return { data: response.data, error: null }
31
- } catch (error: any) {
32
- lastError.value = error
33
- console.error('Error in API request:', error)
34
- return { data: null, error }
35
- } finally {
36
- isLoading.value = false
37
- }
38
- }
23
+ try {
24
+ const response: AxiosResponse<T> = await axios({
25
+ ...config,
26
+ baseURL: apiEndpoint
27
+ })
28
+ return { data: response.data, error: null }
29
+ } catch (error: unknown) {
30
+ if (error instanceof Error) {
31
+ lastError.value = error
32
+ console.error('Error in API request:', error)
33
+ return { data: null, error }
34
+ }
35
+ } finally {
36
+ isLoading.value = false
37
+ }
39
38
 
40
- async function getChatData(
41
- username: string,
42
- project: string,
43
- agentID: string,
44
- formId: string
45
- ) {
46
- return await baseRequest<{
47
- success: boolean
48
- history: ChatBotMessageContent[]
49
- }>({
50
- method: 'POST',
51
- url: `/prompt/load`,
52
- data: {
53
- username,
54
- project,
55
- agentID,
56
- formId
57
- }
58
- })
59
- }
39
+ // This should never be reached, but TypeScript needs it
40
+ return { data: null, error: new Error('Unknown error occurred in baseRequest') }
41
+ }
60
42
 
61
- async function clearChatData(
62
- username: string,
63
- project: string,
64
- agentID: string,
65
- formId: string
66
- ) {
67
- return await baseRequest<{ success: boolean }>({
68
- method: 'POST',
69
- url: `/prompt/clear`,
70
- data: {
71
- username,
72
- project,
73
- agentID,
74
- formId
75
- }
76
- })
77
- }
43
+ async function getChatData(username: string, project: string, agentID: string, formId: string) {
44
+ return await baseRequest<{
45
+ success: boolean
46
+ history: ChatBotMessageContent[]
47
+ }>({
48
+ method: 'POST',
49
+ url: `/prompt/load`,
50
+ data: {
51
+ username,
52
+ project,
53
+ agentID,
54
+ formId
55
+ }
56
+ })
57
+ }
78
58
 
79
- async function sendPrompt(
80
- formData: FormData,
81
- onChunk: (chunk: string) => void,
82
- onError?: (error: Error) => void
83
- ) {
84
- isLoading.value = true
85
- return await useSSE(
86
- {
87
- method: 'POST',
88
- url: `${apiEndpoint}/prompt/submit`,
89
- data: formData
90
- },
91
- {
92
- onMessage: (data) => {
93
- onChunk(data)
94
- },
95
- onError: (error) => {
96
- lastError.value = error
97
- onError?.(error)
98
- console.error('Error in sendPrompt:', error)
99
- },
100
- onDone: () => (isLoading.value = false)
101
- }
102
- )
103
- }
59
+ async function clearChatData(
60
+ username: string,
61
+ project: string,
62
+ agentID: string,
63
+ formId: string
64
+ ) {
65
+ return await baseRequest<{ success: boolean }>({
66
+ method: 'POST',
67
+ url: `/prompt/clear`,
68
+ data: {
69
+ username,
70
+ project,
71
+ agentID,
72
+ formId
73
+ }
74
+ })
75
+ }
104
76
 
105
- async function getFieldSuggestionData(
106
- jobId: string,
107
- onChunk: (chunk: string) => void,
108
- onMetaData: (metadata: Record<string, unknown>) => void
109
- ) {
110
- isLoading.value = true
111
- return await useSSE(
112
- {
113
- method: 'POST',
114
- url: `${apiEndpoint}/get-job-result`,
115
- data: {
116
- jobId
117
- }
118
- },
119
- {
120
- onMessage: (data) => onChunk(data),
121
- onFieldMetadata: (metadata) => onMetaData(metadata),
122
- onError: (error) => {
123
- lastError.value = error
124
- console.error('Error in getFieldSuggestionData:', error)
125
- },
126
- onDone: () => (isLoading.value = false)
127
- }
128
- )
129
- }
77
+ async function sendPrompt(
78
+ formData: FormData,
79
+ onChunk: (chunk: string) => void,
80
+ onError?: (error: Error) => void
81
+ ) {
82
+ isLoading.value = true
83
+ return await useSSE(
84
+ {
85
+ method: 'POST',
86
+ url: `${apiEndpoint}/prompt/submit`,
87
+ data: formData
88
+ },
89
+ {
90
+ onMessage: (data) => {
91
+ onChunk(data)
92
+ },
93
+ onError: (error) => {
94
+ lastError.value = error
95
+ onError?.(error)
96
+ console.error('Error in sendPrompt:', error)
97
+ },
98
+ onDone: () => (isLoading.value = false)
99
+ }
100
+ )
101
+ }
130
102
 
131
- async function handleFeedback(
132
- feedback: number,
133
- comment: string,
134
- sessionID: string
135
- ) {
136
- return await baseRequest<{ success: boolean }>({
137
- method: 'POST',
138
- url: `/prompt/feedback`,
139
- data: {
140
- messageSessionID: sessionID,
141
- feedbackValue: feedback,
142
- feedbackComment: comment
143
- }
144
- })
145
- }
103
+ async function getFieldSuggestionData(
104
+ jobId: string,
105
+ onChunk: (chunk: string) => void,
106
+ onMetaData: (metadata: Record<string, unknown>) => void
107
+ ) {
108
+ isLoading.value = true
109
+ return await useSSE(
110
+ {
111
+ method: 'POST',
112
+ url: `${apiEndpoint}/get-job-result`,
113
+ data: {
114
+ jobId
115
+ }
116
+ },
117
+ {
118
+ onMessage: (data) => onChunk(data),
119
+ onFieldMetadata: (metadata) => onMetaData(metadata),
120
+ onError: (error) => {
121
+ lastError.value = error
122
+ console.error('Error in getFieldSuggestionData:', error)
123
+ },
124
+ onDone: () => (isLoading.value = false)
125
+ }
126
+ )
127
+ }
146
128
 
147
- return {
148
- isLoading,
149
- lastError,
150
- getChatData,
151
- clearChatData,
152
- getFieldSuggestionData,
153
- sendPrompt,
154
- handleFeedback
155
- }
129
+ async function handleFeedback(feedback: number, comment: string, sessionID: string) {
130
+ return await baseRequest<{ success: boolean }>({
131
+ method: 'POST',
132
+ url: `/prompt/feedback`,
133
+ data: {
134
+ messageSessionID: sessionID,
135
+ feedbackValue: feedback,
136
+ feedbackComment: comment
137
+ }
138
+ })
139
+ }
140
+
141
+ return {
142
+ isLoading,
143
+ lastError,
144
+ getChatData,
145
+ clearChatData,
146
+ getFieldSuggestionData,
147
+ sendPrompt,
148
+ handleFeedback
149
+ }
156
150
  }
@@ -2,57 +2,55 @@ import { ref } from 'vue'
2
2
  import { v4 as uuidv4 } from 'uuid'
3
3
 
4
4
  import type { Ref } from 'vue'
5
- import type {
6
- ChatMessage,
7
- ChatBotMessageSender
8
- } from '@/components/ChatBot/types'
5
+ import type { ChatMessage, ChatBotMessageSender } from '@/components/ChatBot/types'
6
+ import type { ChatBotFile } from '@/components/ChatBotInput'
9
7
 
10
8
  const messages: Ref<ChatMessage[]> = ref([])
11
9
  const nextMessageId = ref(1)
12
10
 
13
11
  export function useChatMessages() {
14
- function addChatMessage(
15
- message: string,
16
- sender?: ChatBotMessageSender,
17
- imagePreviewUrl?: string | null,
18
- sessionID?: string,
19
- isWelcomeMessage?: boolean
20
- ) {
21
- const newMessage: ChatMessage = {
22
- id: nextMessageId.value++,
23
- message,
24
- date: new Date(),
25
- sender: sender || 'bot',
26
- sessionID: sessionID || uuidv4(),
27
- imagePreviewUrl: imagePreviewUrl || undefined,
28
- isWelcomeMessage,
29
- fields: []
30
- }
31
-
32
- messages.value.push(newMessage)
33
- }
34
-
35
- function getLastMessage() {
36
- return messages.value.find(
37
- (m: ChatMessage) => m.id === nextMessageId.value - 1
38
- )
39
- }
40
-
41
- function clearMessages() {
42
- messages.value = []
43
- nextMessageId.value = 1
44
- }
45
-
46
- function getMessages() {
47
- return messages.value
48
- }
49
-
50
- return {
51
- messages,
52
- nextMessageId,
53
- addChatMessage,
54
- getLastMessage,
55
- clearMessages,
56
- getMessages
57
- }
12
+ function addChatMessage(
13
+ message: string,
14
+ sender?: ChatBotMessageSender,
15
+ file?: ChatBotFile,
16
+ sessionID?: string,
17
+ isWelcomeMessage?: boolean
18
+ ) {
19
+ const newMessage: ChatMessage = {
20
+ id: nextMessageId.value++,
21
+ message,
22
+ date: new Date(),
23
+ sender: sender || 'bot',
24
+ sessionID: sessionID || uuidv4(),
25
+ file: file,
26
+ isWelcomeMessage,
27
+ fields: []
28
+ }
29
+
30
+ messages.value.push(newMessage)
31
+
32
+ return newMessage
33
+ }
34
+
35
+ function getLastMessage() {
36
+ return messages.value.find((m: ChatMessage) => m.id === nextMessageId.value - 1)
37
+ }
38
+
39
+ function clearMessages() {
40
+ messages.value = []
41
+ nextMessageId.value = 1
42
+ }
43
+
44
+ function getMessages() {
45
+ return messages.value
46
+ }
47
+
48
+ return {
49
+ messages,
50
+ nextMessageId,
51
+ addChatMessage,
52
+ getLastMessage,
53
+ clearMessages,
54
+ getMessages
55
+ }
58
56
  }