@@ -11,26 +11,6 @@ const props = defineProps<{
11
11
message: ChatMessage ;
12
12
}>();
13
13
14
- // Define interfaces for content items
15
- interface BaseContentItem {
16
- type: string ;
17
- content: string ;
18
- isStreaming? : boolean ;
19
- }
20
-
21
- interface TextContentItem extends BaseContentItem {
22
- type: ' text' ;
23
- }
24
-
25
- interface ActionContentItem extends BaseContentItem {
26
- type: ' action' ;
27
- action: string ;
28
- action_status: string ;
29
- action_id? : string ;
30
- }
31
-
32
- type ContentItem = TextContentItem | ActionContentItem ;
33
-
34
14
const md = markdownit ({
35
15
html: true ,
36
16
linkify: true ,
@@ -81,79 +61,9 @@ watch(
81
61
{ immediate: true }
82
62
);
83
63
84
- // Function to get action status icon
85
- const getActionStatusIcon = (status : string ) => {
86
- switch (status ) {
87
- case ' pending' :
88
- return [' fas' , ' circle-notch' ];
89
- case ' success' :
90
- return [' fas' , ' check-circle' ];
91
- case ' failed' :
92
- return [' fas' , ' times-circle' ];
93
- default :
94
- return [' fas' , ' circle-notch' ];
95
- }
96
- };
97
-
98
- // Function to get action status color
99
- const getActionStatusColor = (status : string ) => {
100
- switch (status ) {
101
- case ' pending' :
102
- return ' var(--el-color-warning)' ;
103
- case ' success' :
104
- return ' var(--el-color-success)' ;
105
- case ' failed' :
106
- return ' var(--el-color-danger)' ;
107
- default :
108
- return ' var(--el-color-info)' ;
109
- }
110
- };
111
-
112
- // Function to format action name for display
113
- const formatActionName = (action : string ) => {
114
- return action
115
- .replace (/ [_:] / g , ' ' )
116
- .replace (/ \b \w / g , char => char .toUpperCase ());
117
- };
118
-
119
- // Compute content items from message
120
- const contentItems = computed ((): ContentItem [] => {
121
- const items: ContentItem [] = [];
122
-
123
- // First check for structured content items
124
- if (props .message .contents && props .message .contents .length > 0 ) {
125
- // Use the pre-structured content items from the message
126
- props .message .contents .forEach (content => {
127
- if (content .type === ' action' ) {
128
- items .push ({
129
- type: ' action' ,
130
- content: content .content || ' ' ,
131
- action: content .action || ' ' ,
132
- action_status: content .action_status || ' pending' ,
133
- action_id: content .key ,
134
- isStreaming: false ,
135
- } as ActionContentItem );
136
- } else {
137
- items .push ({
138
- type: ' text' ,
139
- content: content .content || ' ' ,
140
- isStreaming: false ,
141
- } as TextContentItem );
142
- }
143
- });
144
- return items ;
145
- }
146
-
147
- // Add the main text content if it exists
148
- if (props .message .content ) {
149
- items .push ({
150
- type: ' text' ,
151
- content: props .message .content ,
152
- isStreaming: props .message .isStreaming ,
153
- } as TextContentItem );
154
- }
155
-
156
- return items ;
64
+ const filteredContents = computed <ChatMessageContent []>(() => {
65
+ const { message } = props ;
66
+ return message .contents ?.filter (content => ! content .hidden ) || [];
157
67
});
158
68
159
69
defineOptions ({ name: ' ClChatMessage' });
@@ -165,42 +75,17 @@ defineOptions({ name: 'ClChatMessage' });
165
75
<template v-if =" message .content " >
166
76
<div v-html =" renderMarkdown(message.content)" ></div >
167
77
</template >
78
+
168
79
<!-- Iterate through content items in order -->
169
80
<div v-else class =" content-items" >
170
- <template v-for =" (content , index ) in message . contents " :key =" index " >
81
+ <template v-for =" (content , index ) in filteredContents " :key =" index " >
171
82
<!-- Action content -->
172
- <div
83
+ <cl-chat-message-action
173
84
v-if =" content.type === 'action'"
174
- class =" action-item"
175
- :class =" `action-status-${content.action_status}`"
176
- >
177
- <div class =" action-header" >
178
- <cl-icon
179
- :icon =" getActionStatusIcon(content.action_status!)"
180
- :style =" {
181
- color: getActionStatusColor(content.action_status!),
182
- }"
183
- class =" action-icon"
184
- :class =" {
185
- spinning: content.action_status === 'pending',
186
- }"
187
- />
188
- <span class =" action-name" >{{
189
- formatActionName(content.action!)
190
- }}</span >
191
- <span
192
- class =" action-status"
193
- :style =" {
194
- color: getActionStatusColor(content.action_status!),
195
- }"
196
- >
197
- {{ content.action_status }}
198
- </span >
199
- </div >
200
- <div v-if =" content.content" class =" action-content" >
201
- {{ content.content }}
202
- </div >
203
- </div >
85
+ :action =" content.action!"
86
+ :action-status =" content.action_status!"
87
+ :content =" content.content"
88
+ />
204
89
205
90
<!-- Text content -->
206
91
<div v-else-if =" content.type === 'text'" class =" text-content" >
@@ -467,6 +352,7 @@ defineOptions({ name: 'ClChatMessage' });
467
352
.typing-text {
468
353
display : inline-block ;
469
354
color : var (--el-color-primary );
355
+ animation : fade 3s infinite ;
470
356
}
471
357
472
358
@keyframes blink {
@@ -479,64 +365,13 @@ defineOptions({ name: 'ClChatMessage' });
479
365
}
480
366
}
481
367
482
- /* Action styles */
483
- .action-item {
484
- padding : 8px 12px ;
485
- border-radius : 6px ;
486
- background-color : var (--el-fill-color-light );
487
- border-left : 3px solid var (--el-color-info );
488
- }
489
-
490
- .action-item.action-status-pending {
491
- border-left-color : var (--el-color-warning );
492
- }
493
-
494
- .action-item.action-status-success {
495
- border-left-color : var (--el-color-success );
496
- }
497
-
498
- .action-item.action-status-failed {
499
- border-left-color : var (--el-color-danger );
500
- }
501
-
502
- .action-header {
503
- display : flex ;
504
- align-items : center ;
505
- gap : 8px ;
506
- margin-bottom : 4px ;
507
- }
508
-
509
- .action-icon {
510
- font-size : 14px ;
511
- }
512
-
513
- .spinning {
514
- animation : spin 1s linear infinite ;
515
- }
516
-
517
- .action-name {
518
- flex : 1 ;
519
- font-weight : 500 ;
520
- color : var (--el-text-color-primary );
521
- }
522
-
523
- .action-status {
524
- font-size : 12px ;
525
- text-transform : capitalize ;
526
- }
527
-
528
- .action-content {
529
- font-size : 13px ;
530
- color : var (--el-text-color-secondary );
531
- margin-left : 24px ;
532
- }
533
-
534
- @keyframes spin {
535
- 0% {
536
- transform : rotate (0deg );
537
- }
368
+ @keyframes fade {
369
+ 0% ,
538
370
100% {
539
- transform : rotate (360deg );
371
+ opacity : 1 ;
372
+ }
373
+ 50% {
374
+ opacity : 0.7 ;
540
375
}
541
376
}
542
377
</style >
0 commit comments