@meistrari/chat-nuxt 3.9.1 → 3.10.0
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.
- package/README.md +50 -440
- package/dist/module.d.mts +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +56 -3
- package/dist/runtime/assets/css/markstream.css +1 -1
- package/dist/runtime/conversations/components/chat-conversation-creator-filter.vue +11 -67
- package/dist/runtime/conversations/components/chat-conversation-item.d.vue.ts +2 -1
- package/dist/runtime/conversations/components/chat-conversation-item.vue +29 -33
- package/dist/runtime/conversations/components/chat-conversation-item.vue.d.ts +2 -1
- package/dist/runtime/conversations/components/chat-conversation-list.d.vue.ts +0 -1
- package/dist/runtime/conversations/components/chat-conversation-list.vue +117 -158
- package/dist/runtime/conversations/components/chat-conversation-list.vue.d.ts +0 -1
- package/dist/runtime/conversations/components/chat-conversation-new-group-button.vue +34 -73
- package/dist/runtime/conversations/components/chat-conversation-search.vue +1 -21
- package/dist/runtime/conversations/components/chat-widget-history-list.d.vue.ts +12 -0
- package/dist/runtime/conversations/components/chat-widget-history-list.vue +27 -0
- package/dist/runtime/conversations/components/chat-widget-history-list.vue.d.ts +12 -0
- package/dist/runtime/conversations/composables/conversation-groups.d.ts +1 -0
- package/dist/runtime/conversations/composables/conversation-groups.js +2 -0
- package/dist/runtime/conversations/composables/conversation-item.js +4 -4
- package/dist/runtime/conversations/composables/conversation-list.js +14 -5
- package/dist/runtime/embed/components/chat-configuration-modal.d.vue.ts +3 -3
- package/dist/runtime/embed/components/chat-configuration-modal.vue.d.ts +3 -3
- package/dist/runtime/embed/components/chat-embed-inner.d.vue.ts +6 -3
- package/dist/runtime/embed/components/chat-embed-inner.vue +365 -152
- package/dist/runtime/embed/components/chat-embed-inner.vue.d.ts +6 -3
- package/dist/runtime/embed/components/chat-embed.d.vue.ts +31 -4
- package/dist/runtime/embed/components/chat-embed.vue +10 -4
- package/dist/runtime/embed/components/chat-embed.vue.d.ts +31 -4
- package/dist/runtime/embed/components/chat-topbar.vue +83 -85
- package/dist/runtime/embed/components/meistrari-chat-embed.d.vue.ts +5 -3
- package/dist/runtime/embed/components/meistrari-chat-embed.vue +118 -57
- package/dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts +5 -3
- package/dist/runtime/embed/components/mobile/chat-mobile-drawer.d.vue.ts +0 -1
- package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue +2 -45
- package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue.d.ts +0 -1
- package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.d.vue.ts +9 -5
- package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.vue +14 -25
- package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.vue.d.ts +9 -5
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +6 -6
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue +2 -3
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +6 -6
- package/dist/runtime/embed/feature-config.d.ts +7 -0
- package/dist/runtime/embed/types.d.ts +47 -8
- package/dist/runtime/files/icons.d.ts +1 -1
- package/dist/runtime/files/icons.js +1 -1
- package/dist/runtime/messages/components/chat-mention-dropdown.d.vue.ts +6 -1
- package/dist/runtime/messages/components/chat-mention-dropdown.vue +46 -22
- package/dist/runtime/messages/components/chat-mention-dropdown.vue.d.ts +6 -1
- package/dist/runtime/messages/components/chat-message-bubble.vue +53 -71
- package/dist/runtime/messages/components/chat-message-feedback.vue +25 -229
- package/dist/runtime/messages/components/chat-message-input.vue +176 -134
- package/dist/runtime/messages/components/chat-message-list.d.vue.ts +6 -0
- package/dist/runtime/messages/components/chat-message-list.vue +27 -23
- package/dist/runtime/messages/components/chat-message-list.vue.d.ts +6 -0
- package/dist/runtime/messages/components/chat-model-selector.vue +10 -22
- package/dist/runtime/messages/components/reasoning/chat-reasoning-message.vue +2 -3
- package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue +60 -69
- package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.vue +3 -9
- package/dist/runtime/messages/components/widgets/chat-bash-widget.vue +3 -12
- package/dist/runtime/messages/components/widgets/chat-doc-sdk-widget.vue +3 -12
- package/dist/runtime/messages/components/widgets/chat-generic-tool-widget.vue +3 -12
- package/dist/runtime/messages/components/widgets/chat-grep-widget.vue +7 -17
- package/dist/runtime/messages/components/widgets/chat-read-widget.vue +7 -17
- package/dist/runtime/messages/components/widgets/chat-tela-skill-widget.vue +4 -13
- package/dist/runtime/messages/components/widgets/chat-thinking-widget.vue +11 -22
- package/dist/runtime/messages/components/widgets/chat-web-search-widget.vue +13 -40
- package/dist/runtime/messages/components/widgets/chat-workstation-query-widget.vue +52 -65
- package/dist/runtime/messages/components/widgets/chat-write-widget.vue +8 -18
- package/dist/runtime/messages/composables/mention-autocomplete.js +4 -0
- package/dist/runtime/messages/message-reasoning.js +4 -0
- package/dist/runtime/messages/message-state.js +1 -0
- package/dist/runtime/public/files/generic.svg +2 -5
- package/dist/runtime/public/files/image.svg +2 -1
- package/dist/runtime/types/embed.d.ts +1 -1
- package/dist/runtime/types/schemas/chat/conversations.d.ts +2 -0
- package/dist/runtime/types/schemas/chat/conversations.js +3 -0
- package/dist/runtime/types/schemas/chat/messages.d.ts +4 -0
- package/dist/runtime/types/schemas/chat/messages.js +7 -0
- package/dist/types.d.mts +1 -1
- package/package.json +5 -4
- package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.d.vue.ts +0 -23
- package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.vue +0 -75
- package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.vue.d.ts +0 -23
- package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.d.vue.ts +0 -37
- package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.vue +0 -125
- package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.vue.d.ts +0 -37
|
@@ -5,7 +5,7 @@ import { useInputHistory } from "../composables/input-history";
|
|
|
5
5
|
import { useMentionAutocomplete } from "../composables/mention-autocomplete";
|
|
6
6
|
import { getAgentInputReadiness } from "../input-readiness";
|
|
7
7
|
import { formatFileSize } from "../../files/formatting";
|
|
8
|
-
import { getMimeIcon, getMimeLabel } from "../../files/icons";
|
|
8
|
+
import { getFileIcon, getMimeIcon, getMimeLabel } from "../../files/icons";
|
|
9
9
|
const props = defineProps({
|
|
10
10
|
disabled: { type: Boolean, required: false },
|
|
11
11
|
loading: { type: Boolean, required: false },
|
|
@@ -28,7 +28,8 @@ const selectedModel = defineModel("selectedModel", { type: [String, null], ...{
|
|
|
28
28
|
const { uploadFiles, uploading, uploadError } = useFileUpload();
|
|
29
29
|
const isCancelEnabled = computed(() => props.showCancelButton === true);
|
|
30
30
|
const content = ref("");
|
|
31
|
-
const
|
|
31
|
+
const promptTextareaRef = ref(null);
|
|
32
|
+
const editorRef = computed(() => promptTextareaRef.value?.el ?? null);
|
|
32
33
|
const fileInputRef = ref(null);
|
|
33
34
|
const pendingFiles = ref([]);
|
|
34
35
|
const selectedUploadInputName = ref(void 0);
|
|
@@ -69,6 +70,7 @@ const fileItems = computed(() => {
|
|
|
69
70
|
label: f.name,
|
|
70
71
|
description: getMimeLabel(f.mimeType),
|
|
71
72
|
icon: getMimeIcon(f.mimeType),
|
|
73
|
+
iconUrl: getFileIcon(f.mimeType),
|
|
72
74
|
category: "file"
|
|
73
75
|
});
|
|
74
76
|
}
|
|
@@ -81,6 +83,7 @@ const fileItems = computed(() => {
|
|
|
81
83
|
label: f.name,
|
|
82
84
|
description: "Contexto",
|
|
83
85
|
icon: getMimeIcon(f.mimeType),
|
|
86
|
+
iconUrl: getFileIcon(f.mimeType),
|
|
84
87
|
category: "file"
|
|
85
88
|
});
|
|
86
89
|
}
|
|
@@ -94,6 +97,7 @@ const fileItems = computed(() => {
|
|
|
94
97
|
label: f.name,
|
|
95
98
|
description: "Contexto do agente",
|
|
96
99
|
icon: getMimeIcon(),
|
|
100
|
+
iconUrl: getFileIcon(),
|
|
97
101
|
category: "file",
|
|
98
102
|
idKind: "path"
|
|
99
103
|
});
|
|
@@ -150,6 +154,16 @@ const mentionAutocomplete = useMentionAutocomplete({
|
|
|
150
154
|
const canSend = computed(
|
|
151
155
|
() => content.value.trim().length > 0 && !isLocked.value && !uploading.value && !props.agentInputSchemaLoading && agentInputReadiness.value.ready
|
|
152
156
|
);
|
|
157
|
+
const submitStatus = computed(() => {
|
|
158
|
+
if (uploading.value)
|
|
159
|
+
return "uploading";
|
|
160
|
+
if (props.loading && isCancelEnabled.value)
|
|
161
|
+
return "streaming";
|
|
162
|
+
return "ready";
|
|
163
|
+
});
|
|
164
|
+
const promptShellLocked = computed(
|
|
165
|
+
() => isLocked.value && submitStatus.value !== "streaming"
|
|
166
|
+
);
|
|
153
167
|
watch(agentInputVariables, (variables) => {
|
|
154
168
|
const variableNames = new Set(variables.map((input) => input.name));
|
|
155
169
|
agentInputTexts.value = Object.fromEntries(
|
|
@@ -407,10 +421,45 @@ function handlePaste(e) {
|
|
|
407
421
|
sel.addRange(range);
|
|
408
422
|
handleInput();
|
|
409
423
|
}
|
|
410
|
-
function
|
|
411
|
-
|
|
424
|
+
function insertMentionFromMenu(item) {
|
|
425
|
+
const editor = editorRef.value;
|
|
426
|
+
if (!editor || isLocked.value)
|
|
412
427
|
return;
|
|
413
|
-
|
|
428
|
+
const span = document.createElement("span");
|
|
429
|
+
span.className = `mention-tag mention-tag-${item.category}`;
|
|
430
|
+
span.contentEditable = "false";
|
|
431
|
+
span.dataset.mentionId = item.id;
|
|
432
|
+
span.dataset.mentionCategory = item.category;
|
|
433
|
+
span.dataset.mentionLabel = item.label;
|
|
434
|
+
if (item.idKind)
|
|
435
|
+
span.dataset.mentionIdKind = item.idKind;
|
|
436
|
+
if (item.description)
|
|
437
|
+
span.dataset.mentionDescription = item.description;
|
|
438
|
+
if (item.variables)
|
|
439
|
+
span.dataset.mentionVariables = JSON.stringify(item.variables);
|
|
440
|
+
const iconClass = item.category === "file" ? "i-ph-note-blank" : item.category === "canvas" ? "i-ph-wrench" : "i-ph-hexagon";
|
|
441
|
+
const icon = document.createElement("span");
|
|
442
|
+
icon.className = iconClass;
|
|
443
|
+
icon.setAttribute("aria-hidden", "true");
|
|
444
|
+
span.appendChild(icon);
|
|
445
|
+
span.appendChild(document.createTextNode(item.label));
|
|
446
|
+
const lastChild = editor.lastChild;
|
|
447
|
+
const needsSpaceBefore = lastChild?.nodeType === Node.TEXT_NODE ? !/[\s\u00A0]$/.test(lastChild.textContent ?? "") : lastChild !== null;
|
|
448
|
+
if (needsSpaceBefore)
|
|
449
|
+
editor.appendChild(document.createTextNode(" "));
|
|
450
|
+
editor.appendChild(span);
|
|
451
|
+
const space = document.createTextNode("\xA0");
|
|
452
|
+
editor.appendChild(space);
|
|
453
|
+
const range = document.createRange();
|
|
454
|
+
range.setStartAfter(space);
|
|
455
|
+
range.collapse(true);
|
|
456
|
+
const sel = window.getSelection();
|
|
457
|
+
sel?.removeAllRanges();
|
|
458
|
+
sel?.addRange(range);
|
|
459
|
+
handleInput();
|
|
460
|
+
nextTick(() => {
|
|
461
|
+
editorRef.value?.focus();
|
|
462
|
+
});
|
|
414
463
|
}
|
|
415
464
|
function addFiles(files, inputName) {
|
|
416
465
|
const validFiles = files.filter((file) => {
|
|
@@ -445,7 +494,7 @@ defineExpose({
|
|
|
445
494
|
|
|
446
495
|
<template>
|
|
447
496
|
<div :class="centered ? 'w-full' : hasDisclaimer ? 'px-24px' : 'px-24px pb-24px'" bg-transparent>
|
|
448
|
-
<div :class="centered ? 'w-full
|
|
497
|
+
<div :class="centered ? 'w-full' : ''" max-w-700px mx-auto>
|
|
449
498
|
<Transition name="agent-inputs-panel-motion" mode="out-in" appear>
|
|
450
499
|
<div
|
|
451
500
|
v-if="hasAgentInputs"
|
|
@@ -554,53 +603,6 @@ defineExpose({
|
|
|
554
603
|
</Transition>
|
|
555
604
|
</div>
|
|
556
605
|
</Transition>
|
|
557
|
-
<div v-if="pendingFiles.length > 0" flex flex-wrap gap-8px mb-12px>
|
|
558
|
-
<div
|
|
559
|
-
v-for="pendingFile in pendingFiles"
|
|
560
|
-
:key="pendingFile.id"
|
|
561
|
-
flex items-center gap-8px flex-wrap
|
|
562
|
-
px-12px py-8px
|
|
563
|
-
rounded-8px
|
|
564
|
-
bg-gray-100
|
|
565
|
-
b=".5px gray-200"
|
|
566
|
-
>
|
|
567
|
-
<div i-ph-file text-gray-600 text-16px />
|
|
568
|
-
<div flex="~ col" gap-2px>
|
|
569
|
-
<span body-12-medium text-black-700 max-w-150px truncate>{{ pendingFile.file.name }}</span>
|
|
570
|
-
<span body-11-regular text-gray-500>{{ formatFileSize(pendingFile.file.size) }}</span>
|
|
571
|
-
</div>
|
|
572
|
-
<select
|
|
573
|
-
v-if="fileInputVariables.length > 0"
|
|
574
|
-
class="agent-file-variable-select"
|
|
575
|
-
:value="pendingFile.inputName ?? ''"
|
|
576
|
-
:disabled="isLocked"
|
|
577
|
-
@change="updatePendingFileInput(pendingFile.id, $event)"
|
|
578
|
-
@click.stop
|
|
579
|
-
>
|
|
580
|
-
<option value="" disabled>
|
|
581
|
-
Selecionar variável
|
|
582
|
-
</option>
|
|
583
|
-
<option
|
|
584
|
-
v-for="input in fileInputVariables"
|
|
585
|
-
:key="input.id || input.name"
|
|
586
|
-
:value="input.name"
|
|
587
|
-
>
|
|
588
|
-
{{ input.name }}
|
|
589
|
-
</option>
|
|
590
|
-
</select>
|
|
591
|
-
<TelaIconButton
|
|
592
|
-
p-4px
|
|
593
|
-
icon="i-ph-x"
|
|
594
|
-
rounded-4px
|
|
595
|
-
color="secondary"
|
|
596
|
-
hover:bg-gray-200
|
|
597
|
-
transition
|
|
598
|
-
icon-class="text-gray-500 text-12px"
|
|
599
|
-
@click="removeFile(pendingFile.id)"
|
|
600
|
-
/>
|
|
601
|
-
</div>
|
|
602
|
-
</div>
|
|
603
|
-
|
|
604
606
|
<div v-if="hasUnmappedAgentFiles" text-orange-600 body-12-regular mb-8px>
|
|
605
607
|
Selecione uma variável para cada arquivo anexado.
|
|
606
608
|
</div>
|
|
@@ -617,102 +619,142 @@ defineExpose({
|
|
|
617
619
|
@change="handleFileSelect"
|
|
618
620
|
>
|
|
619
621
|
|
|
620
|
-
|
|
622
|
+
<!-- Deliberately NOT position:relative — TelaChatBody pins
|
|
623
|
+
[data-chat-prompt-input] with absolute left-0 right-0 against
|
|
624
|
+
its nearest positioned ancestor; a positioned wrapper here
|
|
625
|
+
would shrink the input. The dropdown positions itself fixed
|
|
626
|
+
from the caret rect, so it needs no relative ancestor. -->
|
|
627
|
+
<div>
|
|
621
628
|
<ChatMentionDropdown
|
|
622
629
|
v-if="mentionAutocomplete.isOpen"
|
|
623
630
|
:items="mentionAutocomplete.filteredItems"
|
|
624
631
|
:highlighted-index="mentionAutocomplete.highlightedIndex"
|
|
625
632
|
:trigger="mentionAutocomplete.activeTrigger"
|
|
626
633
|
:query="mentionAutocomplete.query"
|
|
634
|
+
:caret-rect="mentionAutocomplete.triggerCaretRect"
|
|
627
635
|
@select="mentionAutocomplete.selectItem"
|
|
628
636
|
/>
|
|
629
|
-
</div>
|
|
630
637
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
<
|
|
665
|
-
|
|
638
|
+
<TelaChatPromptInput :locked="promptShellLocked" :class="centered && 'bg-white'">
|
|
639
|
+
<TelaChatPromptInputAttachments v-if="pendingFiles.length > 0">
|
|
640
|
+
<TelaChatPromptInputAttachment
|
|
641
|
+
v-for="pendingFile in pendingFiles"
|
|
642
|
+
:key="pendingFile.id"
|
|
643
|
+
:name="pendingFile.file.name"
|
|
644
|
+
:icon="getFileIcon(pendingFile.file.type)"
|
|
645
|
+
:meta="formatFileSize(pendingFile.file.size)"
|
|
646
|
+
remove-label="Remover anexo"
|
|
647
|
+
@remove="removeFile(pendingFile.id)"
|
|
648
|
+
>
|
|
649
|
+
<select
|
|
650
|
+
v-if="fileInputVariables.length > 0"
|
|
651
|
+
class="agent-file-variable-select"
|
|
652
|
+
:value="pendingFile.inputName ?? ''"
|
|
653
|
+
:disabled="isLocked"
|
|
654
|
+
@change="updatePendingFileInput(pendingFile.id, $event)"
|
|
655
|
+
@click.stop
|
|
656
|
+
>
|
|
657
|
+
<option value="" disabled>
|
|
658
|
+
Selecionar variável
|
|
659
|
+
</option>
|
|
660
|
+
<option
|
|
661
|
+
v-for="input in fileInputVariables"
|
|
662
|
+
:key="input.id || input.name"
|
|
663
|
+
:value="input.name"
|
|
664
|
+
>
|
|
665
|
+
{{ input.name }}
|
|
666
|
+
</option>
|
|
667
|
+
</select>
|
|
668
|
+
</TelaChatPromptInputAttachment>
|
|
669
|
+
</TelaChatPromptInputAttachments>
|
|
670
|
+
|
|
671
|
+
<TelaChatPromptInputTextarea
|
|
672
|
+
ref="promptTextareaRef"
|
|
673
|
+
placeholder="Escreva sua mensagem..."
|
|
674
|
+
:empty="!content.trim()"
|
|
675
|
+
:flush="pendingFiles.length > 0"
|
|
666
676
|
:disabled="isLocked"
|
|
667
|
-
@
|
|
677
|
+
@keydown="handleKeydown"
|
|
678
|
+
@input="handleInput"
|
|
679
|
+
@paste="handlePaste"
|
|
680
|
+
@blur="handleBlur"
|
|
668
681
|
/>
|
|
669
|
-
|
|
670
|
-
<
|
|
671
|
-
<
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
682
|
+
|
|
683
|
+
<TelaChatPromptInputToolbar>
|
|
684
|
+
<TelaChatPromptInputTools>
|
|
685
|
+
<TelaChatPromptInputActionMenu>
|
|
686
|
+
<TelaChatPromptInputActionMenuTrigger :locked="isLocked" label="Abrir menu de ações" />
|
|
687
|
+
<TelaChatPromptInputActionMenuContent>
|
|
688
|
+
<TelaChatPromptInputActionMenuItem
|
|
689
|
+
icon="i-ph-paperclip"
|
|
690
|
+
:disabled="isLocked || pendingFiles.length >= MAX_FILES"
|
|
691
|
+
@click="openFileDialog()"
|
|
692
|
+
>
|
|
693
|
+
Adicionar arquivos ou fotos
|
|
694
|
+
</TelaChatPromptInputActionMenuItem>
|
|
695
|
+
<TelaChatPromptInputActionMenuSub>
|
|
696
|
+
<TelaChatPromptInputActionMenuSubTrigger icon="i-ph-clock-counter-clockwise">
|
|
697
|
+
Arquivos recentes
|
|
698
|
+
</TelaChatPromptInputActionMenuSubTrigger>
|
|
699
|
+
<TelaChatPromptInputActionMenuSubContent>
|
|
700
|
+
<TelaChatPromptInputActionMenuItem v-if="!fileItems.length" class="text-center" disabled>
|
|
701
|
+
Nenhum arquivo recente
|
|
702
|
+
</TelaChatPromptInputActionMenuItem>
|
|
703
|
+
<TelaChatPromptInputActionMenuItem
|
|
704
|
+
v-for="file in fileItems"
|
|
705
|
+
:key="file.id"
|
|
706
|
+
@click="insertMentionFromMenu(file)"
|
|
707
|
+
>
|
|
708
|
+
<img :src="file.iconUrl" class="w-16px h-16px mr-8px shrink-0" alt="">
|
|
709
|
+
<span class="min-w-0 max-w-200px truncate">{{ file.label }}</span>
|
|
710
|
+
</TelaChatPromptInputActionMenuItem>
|
|
711
|
+
</TelaChatPromptInputActionMenuSubContent>
|
|
712
|
+
</TelaChatPromptInputActionMenuSub>
|
|
713
|
+
<TelaMenubarSeparator />
|
|
714
|
+
<TelaChatPromptInputActionMenuSub>
|
|
715
|
+
<TelaChatPromptInputActionMenuSubTrigger icon="i-ph-notepad" icon-size="16px">
|
|
716
|
+
Skills
|
|
717
|
+
</TelaChatPromptInputActionMenuSubTrigger>
|
|
718
|
+
<TelaChatPromptInputActionMenuSubContent>
|
|
719
|
+
<TelaChatPromptInputActionMenuItem v-if="!skillItems.length" class="text-center" disabled>
|
|
720
|
+
Nenhuma skill disponível
|
|
721
|
+
</TelaChatPromptInputActionMenuItem>
|
|
722
|
+
<TelaChatPromptInputActionMenuItem
|
|
723
|
+
v-for="skill in skillItems"
|
|
724
|
+
:key="skill.id"
|
|
725
|
+
@click="insertMentionFromMenu(skill)"
|
|
726
|
+
>
|
|
727
|
+
<span class="min-w-0 max-w-200px truncate">{{ skill.label }}</span>
|
|
728
|
+
</TelaChatPromptInputActionMenuItem>
|
|
729
|
+
</TelaChatPromptInputActionMenuSubContent>
|
|
730
|
+
</TelaChatPromptInputActionMenuSub>
|
|
731
|
+
</TelaChatPromptInputActionMenuContent>
|
|
732
|
+
</TelaChatPromptInputActionMenu>
|
|
733
|
+
</TelaChatPromptInputTools>
|
|
734
|
+
|
|
735
|
+
<TelaChatPromptInputActions>
|
|
736
|
+
<ChatModelSelector
|
|
737
|
+
v-model="selectedModel"
|
|
738
|
+
:disabled="isLocked"
|
|
739
|
+
@click.stop
|
|
740
|
+
/>
|
|
741
|
+
<TelaChatPromptSubmitButton
|
|
742
|
+
:status="submitStatus"
|
|
743
|
+
:disabled="!canSend"
|
|
744
|
+
send-label="Enviar mensagem"
|
|
745
|
+
stop-label="Parar geração"
|
|
746
|
+
uploading-label="Enviando anexos"
|
|
747
|
+
@send="handleSend"
|
|
748
|
+
@stop="emit('cancel')"
|
|
749
|
+
/>
|
|
750
|
+
</TelaChatPromptInputActions>
|
|
751
|
+
</TelaChatPromptInputToolbar>
|
|
752
|
+
</TelaChatPromptInput>
|
|
711
753
|
</div>
|
|
712
754
|
</div>
|
|
713
755
|
</div>
|
|
714
756
|
</template>
|
|
715
757
|
|
|
716
758
|
<style scoped>
|
|
717
|
-
.
|
|
759
|
+
.agent-inputs-panel{box-shadow:0 3px 10px 0 hsla(0,0%,64%,.06);position:relative;transform-origin:bottom center;will-change:max-height,opacity,transform,filter;z-index:1}.agent-inputs-panel-motion-enter-active,.agent-inputs-panel-motion-leave-active{overflow:hidden;transition:max-height .26s cubic-bezier(.2,.8,.2,1),opacity .18s ease,transform .26s cubic-bezier(.2,.8,.2,1),filter .22s ease}.agent-inputs-panel-motion-enter-from,.agent-inputs-panel-motion-leave-to{filter:blur(2px);max-height:0;opacity:0;transform:translateY(46px) scale(.985)}.agent-inputs-panel-motion-enter-to,.agent-inputs-panel-motion-leave-from{filter:blur(0);max-height:560px;opacity:1;transform:translateY(0) scale(1)}.agent-inputs-content{transform-origin:bottom center;will-change:max-height,opacity,transform,filter}.agent-inputs-content-enter-active,.agent-inputs-content-leave-active{overflow:hidden;transition:max-height .22s cubic-bezier(.2,.8,.2,1),opacity .16s ease,transform .22s cubic-bezier(.2,.8,.2,1),filter .22s ease}.agent-inputs-content-enter-from,.agent-inputs-content-leave-to{filter:blur(2px);max-height:0;opacity:0;transform:translateY(14px) scale(.985)}.agent-inputs-content-enter-to,.agent-inputs-content-leave-from{filter:blur(0);max-height:900px;opacity:1;transform:translateY(0) scale(1)}.agent-text-input{border:.5px solid #e5e7eb;border-radius:8px;color:#111827;font-size:13px;line-height:18px;min-height:64px;outline:none;padding:8px 10px;resize:vertical;width:100%}.agent-text-input:focus{border-color:#d1d5db}.agent-text-input:disabled{background-color:#f3f4f6;cursor:not-allowed}.agent-file-variable-select{background:#fff;border:.5px solid #d1d5db;border-radius:6px;color:#374151;font-size:12px;height:28px;max-width:160px;outline:none;padding:0 8px}
|
|
718
760
|
</style>
|
|
@@ -2,6 +2,12 @@ import type { Message } from '../../types/schemas/chat/conversations.js';
|
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
messages: readonly Message[];
|
|
4
4
|
loading?: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Where the list renders: `page`/`widget` sit inside a `TelaChatBody` that
|
|
7
|
+
* owns the conversation padding; `mobile` renders standalone and keeps its
|
|
8
|
+
* own spacing. Defaults to `page`.
|
|
9
|
+
*/
|
|
10
|
+
variant?: 'page' | 'widget' | 'mobile';
|
|
5
11
|
};
|
|
6
12
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
13
|
retry: (messageId: string) => any;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
const props = defineProps({
|
|
3
3
|
messages: { type: Array, required: true },
|
|
4
|
-
loading: { type: Boolean, required: false }
|
|
4
|
+
loading: { type: Boolean, required: false },
|
|
5
|
+
variant: { type: String, required: false }
|
|
5
6
|
});
|
|
6
7
|
const emit = defineEmits(["retry"]);
|
|
7
|
-
const
|
|
8
|
+
const conversationRef = ref(null);
|
|
8
9
|
const skeletonMessages = [
|
|
9
10
|
{ id: "user-1", align: "end", width: "58%", height: "44px" },
|
|
10
11
|
{ id: "assistant-1", align: "start", width: "92%", height: "116px" },
|
|
@@ -12,46 +13,49 @@ const skeletonMessages = [
|
|
|
12
13
|
{ id: "assistant-2", align: "start", width: "84%", height: "92px" }
|
|
13
14
|
];
|
|
14
15
|
function scrollToBottom() {
|
|
15
|
-
|
|
16
|
-
if (containerRef.value) {
|
|
17
|
-
containerRef.value.scrollTop = containerRef.value.scrollHeight;
|
|
18
|
-
}
|
|
19
|
-
});
|
|
16
|
+
conversationRef.value?.scrollToBottom();
|
|
20
17
|
}
|
|
18
|
+
const hasPendingMessage = computed(
|
|
19
|
+
() => props.messages.some((message) => message.status === "pending")
|
|
20
|
+
);
|
|
21
21
|
watch(() => props.messages.length, scrollToBottom);
|
|
22
22
|
onMounted(scrollToBottom);
|
|
23
23
|
</script>
|
|
24
24
|
|
|
25
25
|
<template>
|
|
26
|
-
<
|
|
27
|
-
ref="
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
<TelaChatConversation
|
|
27
|
+
ref="conversationRef"
|
|
28
|
+
:class="{
|
|
29
|
+
'pt-72px!': (variant ?? 'page') === 'page',
|
|
30
|
+
'pt-72px pb-24px px-16px': variant === 'mobile'
|
|
31
|
+
}"
|
|
31
32
|
>
|
|
32
|
-
<
|
|
33
|
-
<
|
|
33
|
+
<TelaChatConversationContent class="max-w-700px!">
|
|
34
|
+
<template v-if="loading">
|
|
34
35
|
<div
|
|
35
36
|
v-for="message in skeletonMessages"
|
|
36
37
|
:key="message.id"
|
|
37
38
|
flex
|
|
38
39
|
:class="message.align === 'end' ? 'justify-end' : 'justify-start'"
|
|
39
40
|
>
|
|
40
|
-
<TelaSkeleton
|
|
41
|
-
rounded-16px
|
|
42
|
-
:style="{ width: message.width, height: message.height }"
|
|
43
|
-
/>
|
|
41
|
+
<TelaSkeleton :style="{ width: message.width, height: message.height }" />
|
|
44
42
|
</div>
|
|
45
|
-
</
|
|
43
|
+
</template>
|
|
46
44
|
|
|
47
|
-
<
|
|
45
|
+
<template v-else>
|
|
48
46
|
<ChatMessageBubble
|
|
49
47
|
v-for="message in messages"
|
|
50
48
|
:key="message.id"
|
|
51
49
|
:message="message"
|
|
52
50
|
@retry="emit('retry', $event)"
|
|
53
51
|
/>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
<p
|
|
53
|
+
v-if="messages.length > 0 && !hasPendingMessage"
|
|
54
|
+
text-center body-11-regular text-tertiary
|
|
55
|
+
>
|
|
56
|
+
As respostas podem conter erros. Verifique documentos originais.
|
|
57
|
+
</p>
|
|
58
|
+
</template>
|
|
59
|
+
</TelaChatConversationContent>
|
|
60
|
+
</TelaChatConversation>
|
|
57
61
|
</template>
|
|
@@ -2,6 +2,12 @@ import type { Message } from '../../types/schemas/chat/conversations.js';
|
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
messages: readonly Message[];
|
|
4
4
|
loading?: boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Where the list renders: `page`/`widget` sit inside a `TelaChatBody` that
|
|
7
|
+
* owns the conversation padding; `mobile` renders standalone and keeps its
|
|
8
|
+
* own spacing. Defaults to `page`.
|
|
9
|
+
*/
|
|
10
|
+
variant?: 'page' | 'widget' | 'mobile';
|
|
5
11
|
};
|
|
6
12
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
7
13
|
retry: (messageId: string) => any;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { chatModelOptions } from "../../types/schemas/chat/ui.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import TelaChatIconsAnthropic from "@meistrari/tela-build/components/tela/chat/icons/anthropic.vue";
|
|
4
|
+
import TelaChatIconsGemini from "@meistrari/tela-build/components/tela/chat/icons/gemini.vue";
|
|
5
|
+
import TelaChatIconsOpenai from "@meistrari/tela-build/components/tela/chat/icons/openai.vue";
|
|
6
6
|
defineProps({
|
|
7
7
|
disabled: { type: Boolean, required: false }
|
|
8
8
|
});
|
|
9
9
|
const model = defineModel({ type: [String, null], ...{ default: null } });
|
|
10
10
|
const providerIcons = {
|
|
11
|
-
Anthropic:
|
|
12
|
-
OpenAI:
|
|
13
|
-
Google:
|
|
11
|
+
Anthropic: TelaChatIconsAnthropic,
|
|
12
|
+
OpenAI: TelaChatIconsOpenai,
|
|
13
|
+
Google: TelaChatIconsGemini
|
|
14
14
|
};
|
|
15
15
|
const options = chatModelOptions.map((option) => ({
|
|
16
16
|
value: option.value,
|
|
@@ -30,27 +30,15 @@ const tabLabels = {
|
|
|
30
30
|
cheap: "Econ\xF4micos",
|
|
31
31
|
multimodal: "Multimodal"
|
|
32
32
|
};
|
|
33
|
-
function getTabLabel(tab) {
|
|
34
|
-
return tabLabels[tab] ?? tab;
|
|
35
|
-
}
|
|
36
33
|
</script>
|
|
37
34
|
|
|
38
35
|
<template>
|
|
39
|
-
<
|
|
40
|
-
|
|
36
|
+
<TelaChatModelSelector
|
|
37
|
+
v-model="model"
|
|
41
38
|
:options="options"
|
|
42
|
-
:
|
|
39
|
+
:disabled="disabled"
|
|
43
40
|
placeholder="Modelo"
|
|
44
41
|
input-placeholder="Buscar modelo..."
|
|
45
|
-
:
|
|
46
|
-
trigger-class="border-none!"
|
|
47
|
-
label-class="!text-14px !leading-18px !font-normal -tracking-0.01em! !text-gray-500"
|
|
48
|
-
icon-class="scale-110 mr-1px !text-gray-500"
|
|
49
|
-
label-item-class="!text-gray-500"
|
|
50
|
-
@update:model-value="model = $event ?? null"
|
|
42
|
+
:tab-labels="tabLabels"
|
|
51
43
|
/>
|
|
52
44
|
</template>
|
|
53
|
-
|
|
54
|
-
<style>
|
|
55
|
-
[role=option] svg{color:#6b7280}
|
|
56
|
-
</style>
|
|
@@ -5,7 +5,6 @@ import ChatDocSdkWidget from "../widgets/chat-doc-sdk-widget.vue";
|
|
|
5
5
|
import ChatGenericToolWidget from "../widgets/chat-generic-tool-widget.vue";
|
|
6
6
|
import ChatGrepWidget from "../widgets/chat-grep-widget.vue";
|
|
7
7
|
import ChatReadWidget from "../widgets/chat-read-widget.vue";
|
|
8
|
-
import ChatReasoningStepItem from "./chat-reasoning-step-item.vue";
|
|
9
8
|
import ChatTelaSkillWidget from "../widgets/chat-tela-skill-widget.vue";
|
|
10
9
|
import ChatThinkingWidget from "../widgets/chat-thinking-widget.vue";
|
|
11
10
|
import ChatWebSearchWidget from "../widgets/chat-web-search-widget.vue";
|
|
@@ -64,7 +63,7 @@ const isTitleSameAsContent = computed(() => {
|
|
|
64
63
|
</script>
|
|
65
64
|
|
|
66
65
|
<template>
|
|
67
|
-
<
|
|
66
|
+
<TelaChatReasoningStep
|
|
68
67
|
:title="stepTitle"
|
|
69
68
|
:icon="stepIcon"
|
|
70
69
|
:is-first="isFirst"
|
|
@@ -98,5 +97,5 @@ const isTitleSameAsContent = computed(() => {
|
|
|
98
97
|
/>
|
|
99
98
|
</div>
|
|
100
99
|
</div>
|
|
101
|
-
</
|
|
100
|
+
</TelaChatReasoningStep>
|
|
102
101
|
</template>
|