@meistrari/chat-nuxt 4.12.0-rc.1 → 4.12.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 +10 -0
- package/dist/module.json +1 -1
- package/dist/runtime/embed/components/chat-embed-inner.d.vue.ts +27 -11
- package/dist/runtime/embed/components/chat-embed-inner.vue +55 -6
- package/dist/runtime/embed/components/chat-embed-inner.vue.d.ts +27 -11
- package/dist/runtime/embed/components/chat-embed.d.vue.ts +7 -5
- package/dist/runtime/embed/components/chat-embed.vue +17 -1
- package/dist/runtime/embed/components/chat-embed.vue.d.ts +7 -5
- package/dist/runtime/embed/components/meistrari-chat-embed.d.vue.ts +7 -1
- package/dist/runtime/embed/components/meistrari-chat-embed.vue +27 -1
- package/dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts +7 -1
- package/dist/runtime/embed/components/mobile/chat-mobile-outdated-settings-sheet.d.vue.ts +2 -2
- package/dist/runtime/embed/components/mobile/chat-mobile-outdated-settings-sheet.vue.d.ts +2 -2
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +5 -5
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue +1 -0
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +5 -5
- package/dist/runtime/files/composables/conversation-files.d.ts +1 -0
- package/dist/runtime/files/composables/conversation-files.js +18 -5
- package/dist/runtime/lightweight/embed/components/chat-embed-adapter.d.vue.ts +7 -3
- package/dist/runtime/lightweight/embed/components/chat-embed-adapter.vue +7 -1
- package/dist/runtime/lightweight/embed/components/chat-embed-adapter.vue.d.ts +7 -3
- package/dist/runtime/lightweight/messages/composables/chat.d.ts +1 -1
- package/dist/runtime/messages/components/chat-message-bubble.d.vue.ts +7 -0
- package/dist/runtime/messages/components/chat-message-bubble.vue +6 -4
- package/dist/runtime/messages/components/chat-message-bubble.vue.d.ts +7 -0
- package/dist/runtime/messages/components/chat-message-input.d.vue.ts +2 -0
- package/dist/runtime/messages/components/chat-message-input.vue +20 -3
- package/dist/runtime/messages/components/chat-message-input.vue.d.ts +2 -0
- package/dist/runtime/messages/components/chat-message-list.d.vue.ts +3 -0
- package/dist/runtime/messages/components/chat-message-list.vue +3 -0
- package/dist/runtime/messages/components/chat-message-list.vue.d.ts +3 -0
- package/dist/runtime/messages/composables/chat.d.ts +1 -1
- package/dist/runtime/messages/composables/chat.js +34 -12
- package/dist/runtime/messages/message-state.d.ts +1 -0
- package/dist/runtime/messages/message-state.js +1 -1
- package/dist/runtime/types/embed.d.ts +8 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -240,3 +240,13 @@ Advanced picker flags default to `true`. Import `ChatExecutionControls` and
|
|
|
240
240
|
`ChatExecutionProfile` from `@meistrari/chat-nuxt/types/embed` when declaring host
|
|
241
241
|
configuration separately. `defaultModel` and `defaultReasoningEffort` are not
|
|
242
242
|
deprecated.
|
|
243
|
+
|
|
244
|
+
### Host chat controls
|
|
245
|
+
|
|
246
|
+
The public embed exposes `sendMessage`, `cancel` and `clear` for host applications.
|
|
247
|
+
|
|
248
|
+
### Create a new conversation
|
|
249
|
+
|
|
250
|
+
Every embed offers `/new` (“Criar uma nova conversa”). Typing the command, selecting it from the menu or calling `sendMessage('/new')` opens a fresh chat. Like the sidebar action, it creates the new conversation on the first send. Previous conversations retain their messages and attachments.
|
|
251
|
+
|
|
252
|
+
Hosts can call `ChatEmbedHost.clear(): Promise<boolean>` and listen for `@conversation-cleared="onCleared"` (payload: the unchanged conversation ID) to discard their own session state. The event fires only after a successful reset. On failure, history remains visible and the host can retry the clear. Clear is serialized against turn/wake admission; stale polling and wake completions cannot restore the previous session.
|
package/dist/module.json
CHANGED
|
@@ -19,33 +19,49 @@ type __VLS_Props = {
|
|
|
19
19
|
user?: EmbedUser | null;
|
|
20
20
|
features?: Partial<ChatFeatureConfig>;
|
|
21
21
|
};
|
|
22
|
-
declare
|
|
22
|
+
declare function clearThread(): Promise<boolean>;
|
|
23
|
+
declare function handleCancel(): Promise<void>;
|
|
24
|
+
declare var __VLS_14: {}, __VLS_100: {}, __VLS_115: {
|
|
23
25
|
message: useChatAuth;
|
|
24
|
-
},
|
|
26
|
+
}, __VLS_118: {
|
|
25
27
|
message: useChatAuth;
|
|
26
|
-
},
|
|
28
|
+
}, __VLS_132: {}, __VLS_141: {}, __VLS_213: {}, __VLS_234: {
|
|
29
|
+
message: useChatAuth;
|
|
30
|
+
}, __VLS_237: {
|
|
31
|
+
message: useChatAuth;
|
|
32
|
+
}, __VLS_251: {};
|
|
27
33
|
type __VLS_Slots = {} & {
|
|
28
34
|
'sidebar-bottom'?: (props: typeof __VLS_14) => any;
|
|
29
35
|
} & {
|
|
30
|
-
'composer-bottom'?: (props: typeof
|
|
36
|
+
'composer-bottom'?: (props: typeof __VLS_100) => any;
|
|
37
|
+
} & {
|
|
38
|
+
'failed-message-actions'?: (props: typeof __VLS_115) => any;
|
|
39
|
+
} & {
|
|
40
|
+
'user-message'?: (props: typeof __VLS_118) => any;
|
|
31
41
|
} & {
|
|
32
|
-
'
|
|
42
|
+
'composer-bottom'?: (props: typeof __VLS_132) => any;
|
|
33
43
|
} & {
|
|
34
|
-
'
|
|
44
|
+
'topbar-leading'?: (props: typeof __VLS_141) => any;
|
|
35
45
|
} & {
|
|
36
|
-
'
|
|
46
|
+
'composer-bottom'?: (props: typeof __VLS_213) => any;
|
|
37
47
|
} & {
|
|
38
|
-
'
|
|
48
|
+
'failed-message-actions'?: (props: typeof __VLS_234) => any;
|
|
39
49
|
} & {
|
|
40
|
-
'
|
|
50
|
+
'user-message'?: (props: typeof __VLS_237) => any;
|
|
41
51
|
} & {
|
|
42
|
-
'composer-bottom'?: (props: typeof
|
|
52
|
+
'composer-bottom'?: (props: typeof __VLS_251) => any;
|
|
43
53
|
};
|
|
44
|
-
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
54
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
55
|
+
clear: typeof clearThread;
|
|
56
|
+
sendMessage: (content: string, messageId?: string) => Promise<boolean>;
|
|
57
|
+
cancel: typeof handleCancel;
|
|
58
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
59
|
+
conversationCleared: (conversationId: string) => any;
|
|
45
60
|
"update:conversationId": (value: string | null) => any;
|
|
46
61
|
"update:conversationTitle": (value: string | null) => any;
|
|
47
62
|
"update:conversationCreatorFilter": (value: ConversationCreatorFilter) => any;
|
|
48
63
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
64
|
+
onConversationCleared?: ((conversationId: string) => any) | undefined;
|
|
49
65
|
"onUpdate:conversationId"?: ((value: string | null) => any) | undefined;
|
|
50
66
|
"onUpdate:conversationTitle"?: ((value: string | null) => any) | undefined;
|
|
51
67
|
"onUpdate:conversationCreatorFilter"?: ((value: ConversationCreatorFilter) => any) | undefined;
|
|
@@ -60,7 +60,7 @@ const props = defineProps({
|
|
|
60
60
|
user: { type: [Object, null], required: false },
|
|
61
61
|
features: { type: Object, required: false }
|
|
62
62
|
});
|
|
63
|
-
const emit = defineEmits(["update:conversationId", "update:conversationTitle", "update:conversationCreatorFilter"]);
|
|
63
|
+
const emit = defineEmits(["conversationCleared", "update:conversationId", "update:conversationTitle", "update:conversationCreatorFilter"]);
|
|
64
64
|
const sidebarPosition = computed(() => props.sidebar?.position ?? "left");
|
|
65
65
|
const sidebarWidth = computed(() => props.sidebar?.width ?? 240);
|
|
66
66
|
const sidebarBottomHeight = computed(
|
|
@@ -300,6 +300,7 @@ const {
|
|
|
300
300
|
startPolling,
|
|
301
301
|
reconnect,
|
|
302
302
|
clearConversation,
|
|
303
|
+
clearConversationThread,
|
|
303
304
|
error: chatError
|
|
304
305
|
} = createChat({
|
|
305
306
|
outboundQueueEnabled: computed(() => resolvedFeatures.value.chatOutboundQueue),
|
|
@@ -314,7 +315,7 @@ watch(chatError, (message) => {
|
|
|
314
315
|
if (message)
|
|
315
316
|
statusToast.update({ text: message, icon: "i-ph-warning" });
|
|
316
317
|
});
|
|
317
|
-
const { total, files: conversationFiles, loading: conversationFilesLoading } = useConversationFiles(activeConversationId);
|
|
318
|
+
const { total, files: conversationFiles, loading: conversationFilesLoading, clearFiles } = useConversationFiles(activeConversationId);
|
|
318
319
|
function resolveSelectedModel(value) {
|
|
319
320
|
return nativeModels ? nativeModels.resolve(value) : value;
|
|
320
321
|
}
|
|
@@ -606,12 +607,38 @@ const pendingFork = computed(() => {
|
|
|
606
607
|
return fork && fork.status !== "ready" ? fork : null;
|
|
607
608
|
});
|
|
608
609
|
const forkBlocked = computed(() => Boolean(pendingFork.value));
|
|
610
|
+
const clearRevision = ref(0);
|
|
609
611
|
function claimableWakeSessionId() {
|
|
610
612
|
return agentWake?.state.value === "ready" && !currentConversation.value?.threadSessionId ? agentWake.sessionId.value : void 0;
|
|
611
613
|
}
|
|
614
|
+
async function clearThread() {
|
|
615
|
+
const conversationId = currentConversation.value?.id;
|
|
616
|
+
if (!conversationId || forkBlocked.value)
|
|
617
|
+
return false;
|
|
618
|
+
const cleared = await clearConversationThread();
|
|
619
|
+
if (cleared && activeConversationId.value === conversationId && currentConversation.value?.id === conversationId) {
|
|
620
|
+
agentWake?.consume();
|
|
621
|
+
const key = composerKey(conversationId);
|
|
622
|
+
if (key) {
|
|
623
|
+
writeComposerDraft(key, "");
|
|
624
|
+
writeComposerDraft(`${key}:pending-send`, "");
|
|
625
|
+
}
|
|
626
|
+
unconfirmedDraft = null;
|
|
627
|
+
clearFiles();
|
|
628
|
+
closeFilesPanel();
|
|
629
|
+
clearRevision.value++;
|
|
630
|
+
}
|
|
631
|
+
if (cleared)
|
|
632
|
+
emit("conversationCleared", conversationId);
|
|
633
|
+
return cleared;
|
|
634
|
+
}
|
|
612
635
|
async function handleSend(content, files, agentInputs) {
|
|
613
636
|
if (forkBlocked.value)
|
|
614
637
|
return;
|
|
638
|
+
if (content.trim() === "/new") {
|
|
639
|
+
await handleNewConversation();
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
615
642
|
const prepared = composerExtension?.prepareSend?.(content);
|
|
616
643
|
const outbound = prepared?.content ?? content;
|
|
617
644
|
unconfirmedDraft = {
|
|
@@ -627,7 +654,7 @@ async function handleSend(content, files, agentInputs) {
|
|
|
627
654
|
if (!sent)
|
|
628
655
|
restoreQueuedSend({ content: prepared?.retryContent?.() ?? content, files, agentInputs: resolvedAgentInputs });
|
|
629
656
|
}
|
|
630
|
-
async function dispatchMessage(outbound, files, resolvedAgentInputs) {
|
|
657
|
+
async function dispatchMessage(outbound, files, resolvedAgentInputs, messageId) {
|
|
631
658
|
const executionSettings = { model: selectedModel.value, reasoningEffort: selectedReasoningEffort.value };
|
|
632
659
|
if (props.sendBlocked)
|
|
633
660
|
return false;
|
|
@@ -681,7 +708,7 @@ async function dispatchMessage(outbound, files, resolvedAgentInputs) {
|
|
|
681
708
|
if (!conversation.threadSessionId && !claimedWakeSessionId)
|
|
682
709
|
throw new Error("N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.");
|
|
683
710
|
return { executionSettings, ...claimedWakeSessionId ? { wakeSessionId: claimedWakeSessionId } : {} };
|
|
684
|
-
});
|
|
711
|
+
}, void 0, messageId);
|
|
685
712
|
if (sent && claimedWakeSessionId)
|
|
686
713
|
agentWake?.consume();
|
|
687
714
|
return sent;
|
|
@@ -833,11 +860,12 @@ const displayConversationEvents = computed(() => [...new Map([
|
|
|
833
860
|
].filter((event) => event.conversationId === currentConversation.value?.id).map((event) => [event.id, event])).values()]);
|
|
834
861
|
watch([
|
|
835
862
|
() => currentConversation.value?.id,
|
|
863
|
+
() => clearRevision.value,
|
|
836
864
|
() => JSON.stringify(chatApi.withChatHeaders().headers),
|
|
837
865
|
() => JSON.stringify(messages.value.filter((message) => message.role === "user").map((message) => [message.id, message.createdAt, message.externalUuid])),
|
|
838
866
|
() => isPolling.value
|
|
839
|
-
], async ([conversationId], previous, onCleanup) => {
|
|
840
|
-
if (conversationId !== previous?.[0] ||
|
|
867
|
+
], async ([conversationId, revision, headers], previous, onCleanup) => {
|
|
868
|
+
if (conversationId !== previous?.[0] || revision !== previous?.[1] || headers !== previous?.[2])
|
|
841
869
|
persistedConversationEvents.value = [];
|
|
842
870
|
if (!conversationId)
|
|
843
871
|
return;
|
|
@@ -958,6 +986,11 @@ async function handleDelete() {
|
|
|
958
986
|
await handleNewConversation();
|
|
959
987
|
}
|
|
960
988
|
}
|
|
989
|
+
defineExpose({
|
|
990
|
+
clear: clearThread,
|
|
991
|
+
sendMessage: async (content, messageId) => content.trim() === "/new" ? handleNewConversation().then(() => true) : Boolean(await dispatchMessage(content, [], void 0, messageId)),
|
|
992
|
+
cancel: handleCancel
|
|
993
|
+
});
|
|
961
994
|
</script>
|
|
962
995
|
|
|
963
996
|
<template>
|
|
@@ -1136,6 +1169,7 @@ async function handleDelete() {
|
|
|
1136
1169
|
variant="mobile"
|
|
1137
1170
|
/>
|
|
1138
1171
|
<ChatMessageInput
|
|
1172
|
+
:key="clearRevision"
|
|
1139
1173
|
v-model:selected-model="selectedModel"
|
|
1140
1174
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
1141
1175
|
:disabled="true"
|
|
@@ -1180,6 +1214,7 @@ async function handleDelete() {
|
|
|
1180
1214
|
|
|
1181
1215
|
<template #input>
|
|
1182
1216
|
<ChatMessageInput
|
|
1217
|
+
:key="clearRevision"
|
|
1183
1218
|
ref="messageInputRef"
|
|
1184
1219
|
v-model:selected-model="selectedModel"
|
|
1185
1220
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
@@ -1206,6 +1241,7 @@ async function handleDelete() {
|
|
|
1206
1241
|
centered
|
|
1207
1242
|
@select-execution-profile="selectExecutionProfile"
|
|
1208
1243
|
@send="handleSend"
|
|
1244
|
+
@new-conversation="handleNewConversation"
|
|
1209
1245
|
@cancel="handleCancel"
|
|
1210
1246
|
/>
|
|
1211
1247
|
<div v-if="$slots['composer-bottom']" data-chat-composer-bottom w-full>
|
|
@@ -1236,10 +1272,14 @@ async function handleDelete() {
|
|
|
1236
1272
|
<template v-if="$slots['failed-message-actions']" #failed-message-actions="slotProps">
|
|
1237
1273
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
1238
1274
|
</template>
|
|
1275
|
+
<template v-if="$slots['user-message']" #user-message="slotProps">
|
|
1276
|
+
<slot name="user-message" v-bind="slotProps" />
|
|
1277
|
+
</template>
|
|
1239
1278
|
</ChatMessageList>
|
|
1240
1279
|
<div ref="composerRef" data-chat-composer flex="~ col" gap-12px min-h-0>
|
|
1241
1280
|
<div :ref="setAnswerTarget" data-chat-answer-dock class="empty:hidden max-h-[50dvh] overflow-y-auto" />
|
|
1242
1281
|
<ChatMessageInput
|
|
1282
|
+
:key="clearRevision"
|
|
1243
1283
|
ref="messageInputRef"
|
|
1244
1284
|
v-model:selected-model="selectedModel"
|
|
1245
1285
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
@@ -1267,6 +1307,7 @@ async function handleDelete() {
|
|
|
1267
1307
|
has-disclaimer
|
|
1268
1308
|
@select-execution-profile="selectExecutionProfile"
|
|
1269
1309
|
@send="handleSend"
|
|
1310
|
+
@new-conversation="handleNewConversation"
|
|
1270
1311
|
@cancel="handleCancel"
|
|
1271
1312
|
/>
|
|
1272
1313
|
<div v-if="$slots['composer-bottom']" data-chat-composer-bottom w-full max-w-700px mx-auto mt--12px>
|
|
@@ -1358,6 +1399,7 @@ async function handleDelete() {
|
|
|
1358
1399
|
:variant="compact ? 'widget' : 'page'"
|
|
1359
1400
|
/>
|
|
1360
1401
|
<ChatMessageInput
|
|
1402
|
+
:key="clearRevision"
|
|
1361
1403
|
v-model:selected-model="selectedModel"
|
|
1362
1404
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
1363
1405
|
:disabled="true"
|
|
@@ -1408,6 +1450,7 @@ async function handleDelete() {
|
|
|
1408
1450
|
|
|
1409
1451
|
<template #input>
|
|
1410
1452
|
<ChatMessageInput
|
|
1453
|
+
:key="clearRevision"
|
|
1411
1454
|
ref="messageInputRef"
|
|
1412
1455
|
v-model:selected-model="selectedModel"
|
|
1413
1456
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
@@ -1434,6 +1477,7 @@ async function handleDelete() {
|
|
|
1434
1477
|
centered
|
|
1435
1478
|
@select-execution-profile="selectExecutionProfile"
|
|
1436
1479
|
@send="handleSend"
|
|
1480
|
+
@new-conversation="handleNewConversation"
|
|
1437
1481
|
@cancel="handleCancel"
|
|
1438
1482
|
/>
|
|
1439
1483
|
<div v-if="$slots['composer-bottom']" data-chat-composer-bottom w-full>
|
|
@@ -1467,10 +1511,14 @@ async function handleDelete() {
|
|
|
1467
1511
|
<template v-if="$slots['failed-message-actions']" #failed-message-actions="slotProps">
|
|
1468
1512
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
1469
1513
|
</template>
|
|
1514
|
+
<template v-if="$slots['user-message']" #user-message="slotProps">
|
|
1515
|
+
<slot name="user-message" v-bind="slotProps" />
|
|
1516
|
+
</template>
|
|
1470
1517
|
</ChatMessageList>
|
|
1471
1518
|
<div ref="composerRef" data-chat-composer flex="~ col" gap-12px min-h-0>
|
|
1472
1519
|
<div :ref="setAnswerTarget" data-chat-answer-dock class="empty:hidden max-h-[50dvh] overflow-y-auto" />
|
|
1473
1520
|
<ChatMessageInput
|
|
1521
|
+
:key="clearRevision"
|
|
1474
1522
|
ref="messageInputRef"
|
|
1475
1523
|
v-model:selected-model="selectedModel"
|
|
1476
1524
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
@@ -1498,6 +1546,7 @@ async function handleDelete() {
|
|
|
1498
1546
|
has-disclaimer
|
|
1499
1547
|
@select-execution-profile="selectExecutionProfile"
|
|
1500
1548
|
@send="handleSend"
|
|
1549
|
+
@new-conversation="handleNewConversation"
|
|
1501
1550
|
@cancel="handleCancel"
|
|
1502
1551
|
/>
|
|
1503
1552
|
<div v-if="$slots['composer-bottom']" data-chat-composer-bottom w-full max-w-700px mx-auto mt--12px>
|
|
@@ -19,33 +19,49 @@ type __VLS_Props = {
|
|
|
19
19
|
user?: EmbedUser | null;
|
|
20
20
|
features?: Partial<ChatFeatureConfig>;
|
|
21
21
|
};
|
|
22
|
-
declare
|
|
22
|
+
declare function clearThread(): Promise<boolean>;
|
|
23
|
+
declare function handleCancel(): Promise<void>;
|
|
24
|
+
declare var __VLS_14: {}, __VLS_100: {}, __VLS_115: {
|
|
23
25
|
message: useChatAuth;
|
|
24
|
-
},
|
|
26
|
+
}, __VLS_118: {
|
|
25
27
|
message: useChatAuth;
|
|
26
|
-
},
|
|
28
|
+
}, __VLS_132: {}, __VLS_141: {}, __VLS_213: {}, __VLS_234: {
|
|
29
|
+
message: useChatAuth;
|
|
30
|
+
}, __VLS_237: {
|
|
31
|
+
message: useChatAuth;
|
|
32
|
+
}, __VLS_251: {};
|
|
27
33
|
type __VLS_Slots = {} & {
|
|
28
34
|
'sidebar-bottom'?: (props: typeof __VLS_14) => any;
|
|
29
35
|
} & {
|
|
30
|
-
'composer-bottom'?: (props: typeof
|
|
36
|
+
'composer-bottom'?: (props: typeof __VLS_100) => any;
|
|
37
|
+
} & {
|
|
38
|
+
'failed-message-actions'?: (props: typeof __VLS_115) => any;
|
|
39
|
+
} & {
|
|
40
|
+
'user-message'?: (props: typeof __VLS_118) => any;
|
|
31
41
|
} & {
|
|
32
|
-
'
|
|
42
|
+
'composer-bottom'?: (props: typeof __VLS_132) => any;
|
|
33
43
|
} & {
|
|
34
|
-
'
|
|
44
|
+
'topbar-leading'?: (props: typeof __VLS_141) => any;
|
|
35
45
|
} & {
|
|
36
|
-
'
|
|
46
|
+
'composer-bottom'?: (props: typeof __VLS_213) => any;
|
|
37
47
|
} & {
|
|
38
|
-
'
|
|
48
|
+
'failed-message-actions'?: (props: typeof __VLS_234) => any;
|
|
39
49
|
} & {
|
|
40
|
-
'
|
|
50
|
+
'user-message'?: (props: typeof __VLS_237) => any;
|
|
41
51
|
} & {
|
|
42
|
-
'composer-bottom'?: (props: typeof
|
|
52
|
+
'composer-bottom'?: (props: typeof __VLS_251) => any;
|
|
43
53
|
};
|
|
44
|
-
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
54
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
55
|
+
clear: typeof clearThread;
|
|
56
|
+
sendMessage: (content: string, messageId?: string) => Promise<boolean>;
|
|
57
|
+
cancel: typeof handleCancel;
|
|
58
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
59
|
+
conversationCleared: (conversationId: string) => any;
|
|
45
60
|
"update:conversationId": (value: string | null) => any;
|
|
46
61
|
"update:conversationTitle": (value: string | null) => any;
|
|
47
62
|
"update:conversationCreatorFilter": (value: ConversationCreatorFilter) => any;
|
|
48
63
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
64
|
+
onConversationCleared?: ((conversationId: string) => any) | undefined;
|
|
49
65
|
"onUpdate:conversationId"?: ((value: string | null) => any) | undefined;
|
|
50
66
|
"onUpdate:conversationTitle"?: ((value: string | null) => any) | undefined;
|
|
51
67
|
"onUpdate:conversationCreatorFilter"?: ((value: ConversationCreatorFilter) => any) | undefined;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
declare var
|
|
1
|
+
declare var __VLS_29: {}, __VLS_32: {}, __VLS_35: {}, __VLS_38: any, __VLS_41: any;
|
|
2
2
|
type __VLS_Slots = {} & {
|
|
3
|
-
'sidebar-bottom'?: (props: typeof
|
|
3
|
+
'sidebar-bottom'?: (props: typeof __VLS_29) => any;
|
|
4
4
|
} & {
|
|
5
|
-
'topbar-leading'?: (props: typeof
|
|
5
|
+
'topbar-leading'?: (props: typeof __VLS_32) => any;
|
|
6
6
|
} & {
|
|
7
|
-
'composer-bottom'?: (props: typeof
|
|
7
|
+
'composer-bottom'?: (props: typeof __VLS_35) => any;
|
|
8
8
|
} & {
|
|
9
|
-
'failed-message-actions'?: (props: typeof
|
|
9
|
+
'failed-message-actions'?: (props: typeof __VLS_38) => any;
|
|
10
|
+
} & {
|
|
11
|
+
'user-message'?: (props: typeof __VLS_41) => any;
|
|
10
12
|
};
|
|
11
13
|
declare const __VLS_base: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
|
|
12
14
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -50,7 +50,7 @@ const props = defineProps({
|
|
|
50
50
|
keepMounted: { type: Boolean, required: false },
|
|
51
51
|
launcherLabel: { type: String, required: false }
|
|
52
52
|
});
|
|
53
|
-
const emit = defineEmits(["update:conversationId", "update:conversationTitle", "update:conversationCreatorFilter", "action", "messageFeedback", "messageTerminal", "messageSent"]);
|
|
53
|
+
const emit = defineEmits(["conversationCleared", "update:conversationId", "update:conversationTitle", "update:conversationCreatorFilter", "action", "messageFeedback", "messageTerminal", "messageSent"]);
|
|
54
54
|
const LightweightAdapter = defineAsyncComponent(() => import("../../lightweight/embed/components/chat-embed-adapter.vue"));
|
|
55
55
|
const parentEmbedConfig = useEmbedConfig();
|
|
56
56
|
const { activeOrganization } = useChatAuth();
|
|
@@ -145,6 +145,17 @@ provideChatMessageTerminal((payload) => {
|
|
|
145
145
|
provideChatMessageSent((payload) => {
|
|
146
146
|
emit("messageSent", payload);
|
|
147
147
|
});
|
|
148
|
+
const host = ref(null);
|
|
149
|
+
function requireHost() {
|
|
150
|
+
if (!host.value)
|
|
151
|
+
throw new Error("Chat is not ready");
|
|
152
|
+
return host.value;
|
|
153
|
+
}
|
|
154
|
+
defineExpose({
|
|
155
|
+
sendMessage: (content, messageId) => requireHost().sendMessage(content, messageId),
|
|
156
|
+
cancel: () => requireHost().cancel(),
|
|
157
|
+
clear: () => requireHost().clear()
|
|
158
|
+
});
|
|
148
159
|
</script>
|
|
149
160
|
|
|
150
161
|
<template>
|
|
@@ -162,6 +173,7 @@ provideChatMessageSent((payload) => {
|
|
|
162
173
|
<component
|
|
163
174
|
:is="harnessComponent"
|
|
164
175
|
v-if="workspaceId && harnessComponent"
|
|
176
|
+
ref="host"
|
|
165
177
|
:key="`${harness}:${workspaceId}:${normalizedTelaAgentId ?? 'default-chat'}:branch:${telaAgentBranch ?? ''}:scope:${resolveConversationScopeKeySegment(normalizedConversationScope)}`"
|
|
166
178
|
:sync-browser-state="syncBrowserState"
|
|
167
179
|
:conversation-id="selectedConversationId"
|
|
@@ -176,6 +188,7 @@ provideChatMessageSent((payload) => {
|
|
|
176
188
|
:suggestions="suggestions"
|
|
177
189
|
:user="normalizedTelaAgentId ? null : user"
|
|
178
190
|
:features="features"
|
|
191
|
+
@conversation-cleared="emit('conversationCleared', $event)"
|
|
179
192
|
@update:conversation-id="selectConversation"
|
|
180
193
|
@update:conversation-title="$emit('update:conversationTitle', $event)"
|
|
181
194
|
@update:conversation-creator-filter="$emit('update:conversationCreatorFilter', $event)"
|
|
@@ -192,6 +205,9 @@ provideChatMessageSent((payload) => {
|
|
|
192
205
|
<template v-if="$slots['failed-message-actions']" #failed-message-actions="slotProps">
|
|
193
206
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
194
207
|
</template>
|
|
208
|
+
<template v-if="$slots['user-message']" #user-message="slotProps">
|
|
209
|
+
<slot name="user-message" v-bind="slotProps" />
|
|
210
|
+
</template>
|
|
195
211
|
</component>
|
|
196
212
|
<TelaChatEmptyState v-else-if="workspaceId && harnessLoading" compact role="status" aria-live="polite">
|
|
197
213
|
<TelaChatTextShimmer>Carregando agente…</TelaChatTextShimmer>
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
declare var
|
|
1
|
+
declare var __VLS_29: {}, __VLS_32: {}, __VLS_35: {}, __VLS_38: any, __VLS_41: any;
|
|
2
2
|
type __VLS_Slots = {} & {
|
|
3
|
-
'sidebar-bottom'?: (props: typeof
|
|
3
|
+
'sidebar-bottom'?: (props: typeof __VLS_29) => any;
|
|
4
4
|
} & {
|
|
5
|
-
'topbar-leading'?: (props: typeof
|
|
5
|
+
'topbar-leading'?: (props: typeof __VLS_32) => any;
|
|
6
6
|
} & {
|
|
7
|
-
'composer-bottom'?: (props: typeof
|
|
7
|
+
'composer-bottom'?: (props: typeof __VLS_35) => any;
|
|
8
8
|
} & {
|
|
9
|
-
'failed-message-actions'?: (props: typeof
|
|
9
|
+
'failed-message-actions'?: (props: typeof __VLS_38) => any;
|
|
10
|
+
} & {
|
|
11
|
+
'user-message'?: (props: typeof __VLS_41) => any;
|
|
10
12
|
};
|
|
11
13
|
declare const __VLS_base: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
|
|
12
14
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DefineSetupFnComponent, SlotsType } from 'vue';
|
|
2
|
+
import type { ChatEmbedHost } from '../../types/embed.js';
|
|
2
3
|
import type { ChatActionPayload } from '../../messages/composables/chat-action.js';
|
|
3
4
|
import type { MessageFeedbackPayload } from '../../messages/composables/chat-feedback.js';
|
|
4
5
|
import type { ChatMessageTerminalPayload } from '../../messages/composables/chat-message-terminal.js';
|
|
@@ -22,6 +23,8 @@ type MeistrariChatEmbedEmits = {
|
|
|
22
23
|
'messageTerminal': (payload: ChatMessageTerminalPayload) => any;
|
|
23
24
|
/** Fired once the server accepts a user message, including retries of a failed answer. */
|
|
24
25
|
'messageSent': (payload: ChatMessageSentPayload) => any;
|
|
26
|
+
/** Fired after an in-place reset; the conversation ID is unchanged. */
|
|
27
|
+
'conversationCleared': (conversationId: string) => any;
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
type MeistrariChatEmbedSlots = SlotsType<{
|
|
@@ -33,6 +36,8 @@ type MeistrariChatEmbedSlots = SlotsType<{
|
|
|
33
36
|
'composer-bottom'?: () => any;
|
|
34
37
|
/** Rendered inside a failed assistant message's error box, next to "Tentar novamente"; receives the failed message. */
|
|
35
38
|
'failed-message-actions'?: (props: { message: Message }) => any;
|
|
39
|
+
/** Replaces the text of a user message, keeping its attachments, sender and timestamp; render nothing to keep the default text. */
|
|
40
|
+
'user-message'?: (props: { message: Message }) => any;
|
|
36
41
|
}>;
|
|
37
42
|
|
|
38
43
|
/**
|
|
@@ -61,7 +66,8 @@ type MeistrariChatEmbedSlots = SlotsType<{
|
|
|
61
66
|
* </template>
|
|
62
67
|
* ```
|
|
63
68
|
*/
|
|
64
|
-
|
|
69
|
+
type EmbedComponent = DefineSetupFnComponent<MeistrariChatEmbedProps, MeistrariChatEmbedEmits, MeistrariChatEmbedSlots>;
|
|
70
|
+
declare const MeistrariChatEmbed: EmbedComponent & { new (): InstanceType<EmbedComponent> & ChatEmbedHost };
|
|
65
71
|
|
|
66
72
|
export default MeistrariChatEmbed;
|
|
67
73
|
export type { AvailableChatModels, ChatActionPayload, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatMessageSentPayload, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, Message, MessageFeedbackPayload, TelaAgentChatEmbedProps };
|
|
@@ -41,7 +41,7 @@ const { hideSidebar = void 0, syncBrowserState = true, closeOnOutsideClick = tru
|
|
|
41
41
|
keepMounted: { type: Boolean, required: false },
|
|
42
42
|
launcherLabel: { type: String, required: false }
|
|
43
43
|
});
|
|
44
|
-
const emit = defineEmits(["update:conversationId", "update:conversationCreatorFilter", "update:open", "action", "messageFeedback", "messageTerminal", "messageSent"]);
|
|
44
|
+
const emit = defineEmits(["conversationCleared", "update:conversationId", "update:conversationCreatorFilter", "update:open", "action", "messageFeedback", "messageTerminal", "messageSent"]);
|
|
45
45
|
defineSlots();
|
|
46
46
|
provideConversationCreatorFilterState({
|
|
47
47
|
defaultConversationCreatorFilter: () => props.defaultConversationCreatorFilter,
|
|
@@ -107,11 +107,23 @@ const widgetEmbedProps = computed(() => ({
|
|
|
107
107
|
conversationId: widgetConversationId.value,
|
|
108
108
|
hideSidebar: hideSidebar ?? true
|
|
109
109
|
}));
|
|
110
|
+
const host = ref(null);
|
|
111
|
+
function requireHost() {
|
|
112
|
+
if (!host.value)
|
|
113
|
+
throw new Error("Chat is not ready");
|
|
114
|
+
return host.value;
|
|
115
|
+
}
|
|
116
|
+
defineExpose({
|
|
117
|
+
sendMessage: (content, messageId) => requireHost().sendMessage(content, messageId),
|
|
118
|
+
cancel: () => requireHost().cancel(),
|
|
119
|
+
clear: () => requireHost().clear()
|
|
120
|
+
});
|
|
110
121
|
</script>
|
|
111
122
|
|
|
112
123
|
<template>
|
|
113
124
|
<ChatEmbed
|
|
114
125
|
v-if="variant === 'page'"
|
|
126
|
+
ref="host"
|
|
115
127
|
v-bind="pageEmbedProps"
|
|
116
128
|
@update:conversation-id="emit('update:conversationId', $event)"
|
|
117
129
|
@update:conversation-creator-filter="emit('update:conversationCreatorFilter', $event)"
|
|
@@ -119,6 +131,7 @@ const widgetEmbedProps = computed(() => ({
|
|
|
119
131
|
@message-feedback="emit('messageFeedback', $event)"
|
|
120
132
|
@message-terminal="emit('messageTerminal', $event)"
|
|
121
133
|
@message-sent="emit('messageSent', $event)"
|
|
134
|
+
@conversation-cleared="emit('conversationCleared', $event)"
|
|
122
135
|
>
|
|
123
136
|
<template v-if="$slots['sidebar-bottom']" #sidebar-bottom>
|
|
124
137
|
<slot name="sidebar-bottom" />
|
|
@@ -132,6 +145,9 @@ const widgetEmbedProps = computed(() => ({
|
|
|
132
145
|
<template v-if="$slots['failed-message-actions']" #failed-message-actions="slotProps">
|
|
133
146
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
134
147
|
</template>
|
|
148
|
+
<template v-if="$slots['user-message']" #user-message="slotProps">
|
|
149
|
+
<slot name="user-message" v-bind="slotProps" />
|
|
150
|
+
</template>
|
|
135
151
|
</ChatEmbed>
|
|
136
152
|
|
|
137
153
|
<ClientOnly v-else>
|
|
@@ -153,6 +169,7 @@ const widgetEmbedProps = computed(() => ({
|
|
|
153
169
|
</TelaChatWidgetHeader>
|
|
154
170
|
<div flex-1 min-h-0>
|
|
155
171
|
<ChatEmbed
|
|
172
|
+
ref="host"
|
|
156
173
|
v-bind="widgetEmbedProps"
|
|
157
174
|
compact
|
|
158
175
|
@update:conversation-id="handleWidgetConversationIdChange"
|
|
@@ -162,10 +179,14 @@ const widgetEmbedProps = computed(() => ({
|
|
|
162
179
|
@message-feedback="emit('messageFeedback', $event)"
|
|
163
180
|
@message-terminal="emit('messageTerminal', $event)"
|
|
164
181
|
@message-sent="emit('messageSent', $event)"
|
|
182
|
+
@conversation-cleared="emit('conversationCleared', $event)"
|
|
165
183
|
>
|
|
166
184
|
<template v-if="$slots['failed-message-actions']" #failed-message-actions="slotProps">
|
|
167
185
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
168
186
|
</template>
|
|
187
|
+
<template v-if="$slots['user-message']" #user-message="slotProps">
|
|
188
|
+
<slot name="user-message" v-bind="slotProps" />
|
|
189
|
+
</template>
|
|
169
190
|
</ChatEmbed>
|
|
170
191
|
</div>
|
|
171
192
|
</TelaChatFloatingWindow>
|
|
@@ -183,6 +204,7 @@ const widgetEmbedProps = computed(() => ({
|
|
|
183
204
|
</TelaChatWidgetHeader>
|
|
184
205
|
<div flex-1 min-h-0>
|
|
185
206
|
<ChatEmbed
|
|
207
|
+
ref="host"
|
|
186
208
|
v-bind="widgetEmbedProps"
|
|
187
209
|
compact
|
|
188
210
|
@update:conversation-id="handleWidgetConversationIdChange"
|
|
@@ -192,10 +214,14 @@ const widgetEmbedProps = computed(() => ({
|
|
|
192
214
|
@message-feedback="emit('messageFeedback', $event)"
|
|
193
215
|
@message-terminal="emit('messageTerminal', $event)"
|
|
194
216
|
@message-sent="emit('messageSent', $event)"
|
|
217
|
+
@conversation-cleared="emit('conversationCleared', $event)"
|
|
195
218
|
>
|
|
196
219
|
<template v-if="$slots['failed-message-actions']" #failed-message-actions="slotProps">
|
|
197
220
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
198
221
|
</template>
|
|
222
|
+
<template v-if="$slots['user-message']" #user-message="slotProps">
|
|
223
|
+
<slot name="user-message" v-bind="slotProps" />
|
|
224
|
+
</template>
|
|
199
225
|
</ChatEmbed>
|
|
200
226
|
</div>
|
|
201
227
|
</TelaChatSidepanelWindow>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DefineSetupFnComponent, SlotsType } from 'vue';
|
|
2
|
+
import type { ChatEmbedHost } from '../../types/embed.js';
|
|
2
3
|
import type { ChatActionPayload } from '../../messages/composables/chat-action.js';
|
|
3
4
|
import type { MessageFeedbackPayload } from '../../messages/composables/chat-feedback.js';
|
|
4
5
|
import type { ChatMessageTerminalPayload } from '../../messages/composables/chat-message-terminal.js';
|
|
@@ -22,6 +23,8 @@ type MeistrariChatEmbedEmits = {
|
|
|
22
23
|
'messageTerminal': (payload: ChatMessageTerminalPayload) => any;
|
|
23
24
|
/** Fired once the server accepts a user message, including retries of a failed answer. */
|
|
24
25
|
'messageSent': (payload: ChatMessageSentPayload) => any;
|
|
26
|
+
/** Fired after an in-place reset; the conversation ID is unchanged. */
|
|
27
|
+
'conversationCleared': (conversationId: string) => any;
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
type MeistrariChatEmbedSlots = SlotsType<{
|
|
@@ -33,6 +36,8 @@ type MeistrariChatEmbedSlots = SlotsType<{
|
|
|
33
36
|
'composer-bottom'?: () => any;
|
|
34
37
|
/** Rendered inside a failed assistant message's error box, next to "Tentar novamente"; receives the failed message. */
|
|
35
38
|
'failed-message-actions'?: (props: { message: Message }) => any;
|
|
39
|
+
/** Replaces the text of a user message, keeping its attachments, sender and timestamp; render nothing to keep the default text. */
|
|
40
|
+
'user-message'?: (props: { message: Message }) => any;
|
|
36
41
|
}>;
|
|
37
42
|
|
|
38
43
|
/**
|
|
@@ -61,7 +66,8 @@ type MeistrariChatEmbedSlots = SlotsType<{
|
|
|
61
66
|
* </template>
|
|
62
67
|
* ```
|
|
63
68
|
*/
|
|
64
|
-
|
|
69
|
+
type EmbedComponent = DefineSetupFnComponent<MeistrariChatEmbedProps, MeistrariChatEmbedEmits, MeistrariChatEmbedSlots>;
|
|
70
|
+
declare const MeistrariChatEmbed: EmbedComponent & { new (): InstanceType<EmbedComponent> & ChatEmbedHost };
|
|
65
71
|
|
|
66
72
|
export default MeistrariChatEmbed;
|
|
67
73
|
export type { AvailableChatModels, ChatActionPayload, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatMessageSentPayload, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, Message, MessageFeedbackPayload, TelaAgentChatEmbedProps };
|
|
@@ -3,12 +3,12 @@ type __VLS_Props = {
|
|
|
3
3
|
};
|
|
4
4
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
5
5
|
close: () => any;
|
|
6
|
-
dismiss: () => any;
|
|
7
6
|
newConversation: () => any;
|
|
7
|
+
dismiss: () => any;
|
|
8
8
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
9
9
|
onClose?: (() => any) | undefined;
|
|
10
|
-
onDismiss?: (() => any) | undefined;
|
|
11
10
|
onNewConversation?: (() => any) | undefined;
|
|
11
|
+
onDismiss?: (() => any) | undefined;
|
|
12
12
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
13
|
declare const _default: typeof __VLS_export;
|
|
14
14
|
export default _default;
|
|
@@ -3,12 +3,12 @@ type __VLS_Props = {
|
|
|
3
3
|
};
|
|
4
4
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
5
5
|
close: () => any;
|
|
6
|
-
dismiss: () => any;
|
|
7
6
|
newConversation: () => any;
|
|
7
|
+
dismiss: () => any;
|
|
8
8
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
9
9
|
onClose?: (() => any) | undefined;
|
|
10
|
-
onDismiss?: (() => any) | undefined;
|
|
11
10
|
onNewConversation?: (() => any) | undefined;
|
|
11
|
+
onDismiss?: (() => any) | undefined;
|
|
12
12
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
13
|
declare const _default: typeof __VLS_export;
|
|
14
14
|
export default _default;
|
|
@@ -52,13 +52,13 @@ type __VLS_ModelProps = {
|
|
|
52
52
|
'selectedReasoningEffort'?: ChatReasoningEffort | null;
|
|
53
53
|
};
|
|
54
54
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
55
|
-
declare var __VLS_54: {},
|
|
55
|
+
declare var __VLS_54: {}, __VLS_101: {}, __VLS_103: {};
|
|
56
56
|
type __VLS_Slots = {} & {
|
|
57
57
|
loading?: (props: typeof __VLS_54) => any;
|
|
58
58
|
} & {
|
|
59
|
-
empty?: (props: typeof
|
|
59
|
+
empty?: (props: typeof __VLS_101) => any;
|
|
60
60
|
} & {
|
|
61
|
-
default?: (props: typeof
|
|
61
|
+
default?: (props: typeof __VLS_103) => any;
|
|
62
62
|
};
|
|
63
63
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
64
64
|
"update:selectedModel": (value: string | null) => any;
|
|
@@ -74,9 +74,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
74
74
|
selectConversation: (id: string) => any;
|
|
75
75
|
send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
|
|
76
76
|
settings: () => any;
|
|
77
|
+
newConversation: (groupId?: string | null | undefined) => any;
|
|
77
78
|
selectExecutionProfile: (profile: ChatExecutionProfile) => any;
|
|
78
79
|
tabChange: (tab: TopbarTab) => any;
|
|
79
|
-
newConversation: (groupId?: string | null | undefined) => any;
|
|
80
80
|
switchWorkspace: () => any;
|
|
81
81
|
signout: () => any;
|
|
82
82
|
cancelEditing: () => any;
|
|
@@ -96,11 +96,11 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
96
96
|
onSelectConversation?: ((id: string) => any) | undefined;
|
|
97
97
|
onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
|
|
98
98
|
onSettings?: (() => any) | undefined;
|
|
99
|
+
onNewConversation?: ((groupId?: string | null | undefined) => any) | undefined;
|
|
99
100
|
onSelectExecutionProfile?: ((profile: ChatExecutionProfile) => any) | undefined;
|
|
100
101
|
"onUpdate:selectedModel"?: ((value: string | null) => any) | undefined;
|
|
101
102
|
"onUpdate:selectedReasoningEffort"?: ((value: any) => any) | undefined;
|
|
102
103
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
103
|
-
onNewConversation?: ((groupId?: string | null | undefined) => any) | undefined;
|
|
104
104
|
onSwitchWorkspace?: (() => any) | undefined;
|
|
105
105
|
onSignout?: (() => any) | undefined;
|
|
106
106
|
onCancelEditing?: (() => any) | undefined;
|
|
@@ -253,6 +253,7 @@ function startNewConversationFromOutdatedSettings() {
|
|
|
253
253
|
:execution-controls-disabled="executionControlsDisabled"
|
|
254
254
|
centered
|
|
255
255
|
@select-execution-profile="emit('selectExecutionProfile', $event)"
|
|
256
|
+
@new-conversation="emit('newConversation')"
|
|
256
257
|
@send="(content, files, agentInputs) => emit('send', content, files, agentInputs)"
|
|
257
258
|
@cancel="emit('cancel')"
|
|
258
259
|
/>
|
|
@@ -52,13 +52,13 @@ type __VLS_ModelProps = {
|
|
|
52
52
|
'selectedReasoningEffort'?: ChatReasoningEffort | null;
|
|
53
53
|
};
|
|
54
54
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
55
|
-
declare var __VLS_54: {},
|
|
55
|
+
declare var __VLS_54: {}, __VLS_101: {}, __VLS_103: {};
|
|
56
56
|
type __VLS_Slots = {} & {
|
|
57
57
|
loading?: (props: typeof __VLS_54) => any;
|
|
58
58
|
} & {
|
|
59
|
-
empty?: (props: typeof
|
|
59
|
+
empty?: (props: typeof __VLS_101) => any;
|
|
60
60
|
} & {
|
|
61
|
-
default?: (props: typeof
|
|
61
|
+
default?: (props: typeof __VLS_103) => any;
|
|
62
62
|
};
|
|
63
63
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
64
64
|
"update:selectedModel": (value: string | null) => any;
|
|
@@ -74,9 +74,9 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
74
74
|
selectConversation: (id: string) => any;
|
|
75
75
|
send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
|
|
76
76
|
settings: () => any;
|
|
77
|
+
newConversation: (groupId?: string | null | undefined) => any;
|
|
77
78
|
selectExecutionProfile: (profile: ChatExecutionProfile) => any;
|
|
78
79
|
tabChange: (tab: TopbarTab) => any;
|
|
79
|
-
newConversation: (groupId?: string | null | undefined) => any;
|
|
80
80
|
switchWorkspace: () => any;
|
|
81
81
|
signout: () => any;
|
|
82
82
|
cancelEditing: () => any;
|
|
@@ -96,11 +96,11 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
96
96
|
onSelectConversation?: ((id: string) => any) | undefined;
|
|
97
97
|
onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
|
|
98
98
|
onSettings?: (() => any) | undefined;
|
|
99
|
+
onNewConversation?: ((groupId?: string | null | undefined) => any) | undefined;
|
|
99
100
|
onSelectExecutionProfile?: ((profile: ChatExecutionProfile) => any) | undefined;
|
|
100
101
|
"onUpdate:selectedModel"?: ((value: string | null) => any) | undefined;
|
|
101
102
|
"onUpdate:selectedReasoningEffort"?: ((value: any) => any) | undefined;
|
|
102
103
|
onTabChange?: ((tab: TopbarTab) => any) | undefined;
|
|
103
|
-
onNewConversation?: ((groupId?: string | null | undefined) => any) | undefined;
|
|
104
104
|
onSwitchWorkspace?: (() => any) | undefined;
|
|
105
105
|
onSignout?: (() => any) | undefined;
|
|
106
106
|
onCancelEditing?: (() => any) | undefined;
|
|
@@ -4,7 +4,8 @@ function useConversationFilesState() {
|
|
|
4
4
|
return {
|
|
5
5
|
files: useState("conversationFiles", () => ({})),
|
|
6
6
|
loading: useState("conversationFilesLoading", () => ({})),
|
|
7
|
-
error: useState("conversationFilesError", () => ({}))
|
|
7
|
+
error: useState("conversationFilesError", () => ({})),
|
|
8
|
+
revisions: useState("conversationFilesRevisions", () => ({}))
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
11
|
function addFilesToConversationState(state, conversationId, newFiles, messageId, messageRole) {
|
|
@@ -57,6 +58,7 @@ export function useConversationFiles(conversationId) {
|
|
|
57
58
|
const id = conversationId.value;
|
|
58
59
|
if (!id)
|
|
59
60
|
return;
|
|
61
|
+
const revision = state.revisions.value[id] ?? 0;
|
|
60
62
|
const fetchId = ++currentFetchId;
|
|
61
63
|
state.loading.value = { ...state.loading.value, [id]: true };
|
|
62
64
|
state.error.value = { ...state.error.value, [id]: null };
|
|
@@ -65,11 +67,11 @@ export function useConversationFiles(conversationId) {
|
|
|
65
67
|
chatApi.path(`/conversations/${id}/files`),
|
|
66
68
|
chatApi.withChatHeaders()
|
|
67
69
|
);
|
|
68
|
-
if (fetchId === currentFetchId) {
|
|
70
|
+
if (fetchId === currentFetchId && revision === (state.revisions.value[id] ?? 0)) {
|
|
69
71
|
state.files.value = { ...state.files.value, [id]: response.files };
|
|
70
72
|
}
|
|
71
73
|
} catch (err) {
|
|
72
|
-
if (fetchId === currentFetchId) {
|
|
74
|
+
if (fetchId === currentFetchId && revision === (state.revisions.value[id] ?? 0)) {
|
|
73
75
|
state.error.value = {
|
|
74
76
|
...state.error.value,
|
|
75
77
|
[id]: err instanceof Error ? err.message : "Falha ao buscar arquivos"
|
|
@@ -77,11 +79,21 @@ export function useConversationFiles(conversationId) {
|
|
|
77
79
|
state.files.value = { ...state.files.value, [id]: [] };
|
|
78
80
|
}
|
|
79
81
|
} finally {
|
|
80
|
-
if (fetchId === currentFetchId) {
|
|
82
|
+
if (fetchId === currentFetchId && revision === (state.revisions.value[id] ?? 0)) {
|
|
81
83
|
state.loading.value = { ...state.loading.value, [id]: false };
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
}
|
|
87
|
+
function clearFiles() {
|
|
88
|
+
currentFetchId++;
|
|
89
|
+
const id = conversationId.value;
|
|
90
|
+
if (!id)
|
|
91
|
+
return;
|
|
92
|
+
state.revisions.value = { ...state.revisions.value, [id]: (state.revisions.value[id] ?? 0) + 1 };
|
|
93
|
+
state.files.value = { ...state.files.value, [id]: [] };
|
|
94
|
+
state.loading.value = { ...state.loading.value, [id]: false };
|
|
95
|
+
state.error.value = { ...state.error.value, [id]: null };
|
|
96
|
+
}
|
|
85
97
|
const hasFiles = computed(() => files.value.length > 0);
|
|
86
98
|
const imageFiles = computed(
|
|
87
99
|
() => files.value.filter((f) => f.mimeType.startsWith("image/"))
|
|
@@ -108,6 +120,7 @@ export function useConversationFiles(conversationId) {
|
|
|
108
120
|
imageFiles,
|
|
109
121
|
documentFiles,
|
|
110
122
|
otherFiles,
|
|
111
|
-
fetchFiles
|
|
123
|
+
fetchFiles,
|
|
124
|
+
clearFiles
|
|
112
125
|
};
|
|
113
126
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
declare var
|
|
1
|
+
declare var __VLS_11: string, __VLS_12: any;
|
|
2
2
|
type __VLS_Slots = {} & {
|
|
3
|
-
[K in NonNullable<typeof
|
|
3
|
+
[K in NonNullable<typeof __VLS_11>]?: (props: typeof __VLS_12) => any;
|
|
4
4
|
};
|
|
5
|
-
declare const __VLS_base: import("vue").DefineComponent<{}, {
|
|
5
|
+
declare const __VLS_base: import("vue").DefineComponent<{}, {
|
|
6
|
+
clear: () => any;
|
|
7
|
+
sendMessage: (content: string, messageId?: string) => any;
|
|
8
|
+
cancel: () => any;
|
|
9
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
6
10
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
7
11
|
declare const _default: typeof __VLS_export;
|
|
8
12
|
export default _default;
|
|
@@ -4,6 +4,12 @@ import { provideChatHarnessAdapter } from "../../../embed/composables/harness-ad
|
|
|
4
4
|
import { useChat } from "../../messages/composables/chat";
|
|
5
5
|
import { useLightweightModelSelection } from "../composables/model-selection";
|
|
6
6
|
defineOptions({ inheritAttrs: false });
|
|
7
|
+
const host = ref(null);
|
|
8
|
+
defineExpose({
|
|
9
|
+
clear: () => host.value?.clear() ?? Promise.resolve(false),
|
|
10
|
+
sendMessage: (content, messageId) => host.value?.sendMessage(content, messageId) ?? Promise.resolve(false),
|
|
11
|
+
cancel: () => host.value?.cancel() ?? Promise.resolve()
|
|
12
|
+
});
|
|
7
13
|
provideChatHarnessAdapter({
|
|
8
14
|
useChat,
|
|
9
15
|
useModelSelection: useLightweightModelSelection,
|
|
@@ -12,7 +18,7 @@ provideChatHarnessAdapter({
|
|
|
12
18
|
</script>
|
|
13
19
|
|
|
14
20
|
<template>
|
|
15
|
-
<ChatEmbedInner v-bind="$attrs">
|
|
21
|
+
<ChatEmbedInner ref="host" v-bind="$attrs">
|
|
16
22
|
<template v-for="(_, name) in $slots" #[name]="slotProps">
|
|
17
23
|
<slot :name="name" v-bind="slotProps || {}" />
|
|
18
24
|
</template>
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
declare var
|
|
1
|
+
declare var __VLS_11: string, __VLS_12: any;
|
|
2
2
|
type __VLS_Slots = {} & {
|
|
3
|
-
[K in NonNullable<typeof
|
|
3
|
+
[K in NonNullable<typeof __VLS_11>]?: (props: typeof __VLS_12) => any;
|
|
4
4
|
};
|
|
5
|
-
declare const __VLS_base: import("vue").DefineComponent<{}, {
|
|
5
|
+
declare const __VLS_base: import("vue").DefineComponent<{}, {
|
|
6
|
+
clear: () => any;
|
|
7
|
+
sendMessage: (content: string, messageId?: string) => any;
|
|
8
|
+
cancel: () => any;
|
|
9
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
6
10
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
7
11
|
declare const _default: typeof __VLS_export;
|
|
8
12
|
export default _default;
|
|
@@ -34,7 +34,7 @@ export declare function useChat(options?: Parameters<typeof useSharedChat>[0]):
|
|
|
34
34
|
wakeSessionId?: string;
|
|
35
35
|
defer?: boolean;
|
|
36
36
|
executionSettings?: ExecutionSettings;
|
|
37
|
-
}>, queuedSend?: import("../../../messages/composables/outbound-queue.js").QueuedSend) => Promise<Message | null>;
|
|
37
|
+
}>, queuedSend?: import("../../../messages/composables/outbound-queue.js").QueuedSend, messageId?: string) => Promise<Message | null>;
|
|
38
38
|
flushOutboundQueue: (wakeSessionId?: string) => Promise<Message | null>;
|
|
39
39
|
failOutboundQueue: (message: string) => boolean;
|
|
40
40
|
retryMessage: (messageId: string, prepare?: () => Promise<{
|
|
@@ -20,6 +20,13 @@ type __VLS_Slots = {
|
|
|
20
20
|
'failed-message-actions'?: (props: {
|
|
21
21
|
message: Message;
|
|
22
22
|
}) => unknown;
|
|
23
|
+
/**
|
|
24
|
+
* Replaces the text of a user message. Attachments, sender and timestamp
|
|
25
|
+
* stay in place, and rendering nothing keeps the default text.
|
|
26
|
+
*/
|
|
27
|
+
'user-message'?: (props: {
|
|
28
|
+
message: Message;
|
|
29
|
+
}) => unknown;
|
|
23
30
|
};
|
|
24
31
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
25
32
|
retry: (messageId: string) => any;
|
|
@@ -196,10 +196,12 @@ const attachedFiles = computed(() => {
|
|
|
196
196
|
</template>
|
|
197
197
|
</div>
|
|
198
198
|
<div body-16-regular whitespace-pre-wrap break-words>
|
|
199
|
-
<
|
|
200
|
-
<
|
|
201
|
-
|
|
202
|
-
|
|
199
|
+
<slot name="user-message" :message="message">
|
|
200
|
+
<template v-for="(segment, index) in userContentSegments" :key="`${index}-${segment.type === 'citation' ? segment.citation.raw : 'text'}`">
|
|
201
|
+
<ChatCitation v-if="segment.type === 'citation'" :citation="segment.citation" :label="segment.label" />
|
|
202
|
+
<span v-else v-html="renderUserText(segment.content)" />
|
|
203
|
+
</template>
|
|
204
|
+
</slot>
|
|
203
205
|
</div>
|
|
204
206
|
</TelaChatMessageContent>
|
|
205
207
|
|
|
@@ -20,6 +20,13 @@ type __VLS_Slots = {
|
|
|
20
20
|
'failed-message-actions'?: (props: {
|
|
21
21
|
message: Message;
|
|
22
22
|
}) => unknown;
|
|
23
|
+
/**
|
|
24
|
+
* Replaces the text of a user message. Attachments, sender and timestamp
|
|
25
|
+
* stay in place, and rendering nothing keeps the default text.
|
|
26
|
+
*/
|
|
27
|
+
'user-message'?: (props: {
|
|
28
|
+
message: Message;
|
|
29
|
+
}) => unknown;
|
|
23
30
|
};
|
|
24
31
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
25
32
|
retry: (messageId: string) => any;
|
|
@@ -51,10 +51,12 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
51
51
|
} & {
|
|
52
52
|
cancel: () => any;
|
|
53
53
|
send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
|
|
54
|
+
newConversation: () => any;
|
|
54
55
|
selectExecutionProfile: (profile: ChatExecutionProfile) => any;
|
|
55
56
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
56
57
|
onCancel?: (() => any) | undefined;
|
|
57
58
|
onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
|
|
59
|
+
onNewConversation?: (() => any) | undefined;
|
|
58
60
|
onSelectExecutionProfile?: ((profile: ChatExecutionProfile) => any) | undefined;
|
|
59
61
|
"onUpdate:selectedModel"?: ((value: string | null) => any) | undefined;
|
|
60
62
|
"onUpdate:selectedReasoningEffort"?: ((value: any) => any) | undefined;
|
|
@@ -35,7 +35,7 @@ const props = defineProps({
|
|
|
35
35
|
sendBlocked: { type: Boolean, required: false },
|
|
36
36
|
draftStorageKey: { type: [String, null], required: false }
|
|
37
37
|
});
|
|
38
|
-
const emit = defineEmits(["send", "cancel", "selectExecutionProfile"]);
|
|
38
|
+
const emit = defineEmits(["send", "newConversation", "cancel", "selectExecutionProfile"]);
|
|
39
39
|
const selectedModel = defineModel("selectedModel", { type: [String, null], ...{ default: null } });
|
|
40
40
|
const composerExtension = inject(CHAT_COMPOSER_EXTENSION_KEY, null);
|
|
41
41
|
const selectedReasoningEffort = defineModel("selectedReasoningEffort", { type: null, ...{ default: null } });
|
|
@@ -125,7 +125,10 @@ const skillItems = computed(() => {
|
|
|
125
125
|
}
|
|
126
126
|
return items;
|
|
127
127
|
});
|
|
128
|
-
const commandItems = computed(() =>
|
|
128
|
+
const commandItems = computed(() => [
|
|
129
|
+
{ id: "new", label: "/new", description: "Criar uma nova conversa", icon: "i-ph-plus", run: startNewConversation },
|
|
130
|
+
...(composerExtension?.commands ?? []).filter((command) => command.id !== "new")
|
|
131
|
+
]);
|
|
129
132
|
const mentionAutocomplete = useMentionAutocomplete({
|
|
130
133
|
editorRef,
|
|
131
134
|
fileItems,
|
|
@@ -134,8 +137,18 @@ const mentionAutocomplete = useMentionAutocomplete({
|
|
|
134
137
|
disabled: isLocked,
|
|
135
138
|
onInsert: handleInput
|
|
136
139
|
});
|
|
140
|
+
function startNewConversation() {
|
|
141
|
+
if (isLocked.value || props.sendBlocked || uploading.value)
|
|
142
|
+
return;
|
|
143
|
+
setDraft("");
|
|
144
|
+
pendingFiles.value = [];
|
|
145
|
+
agentInputTexts.value = {};
|
|
146
|
+
mentionAutocomplete.resetMentions();
|
|
147
|
+
inputHistory.resetNavigation();
|
|
148
|
+
emit("newConversation");
|
|
149
|
+
}
|
|
137
150
|
const canSend = computed(
|
|
138
|
-
() => content.value.trim().length > 0 && !isLocked.value && !props.sendBlocked && !uploading.value && !props.agentInputSchemaLoading && agentInputReadiness.value.ready
|
|
151
|
+
() => content.value.trim().length > 0 && !isLocked.value && !props.sendBlocked && !uploading.value && (content.value.trim() === "/new" || !props.agentInputSchemaLoading && agentInputReadiness.value.ready)
|
|
139
152
|
);
|
|
140
153
|
const submitStatus = computed(() => {
|
|
141
154
|
if (uploading.value)
|
|
@@ -278,6 +291,10 @@ function buildAgentInputs(files, queuedFiles) {
|
|
|
278
291
|
async function handleSend() {
|
|
279
292
|
if (!canSend.value)
|
|
280
293
|
return;
|
|
294
|
+
if (content.value.trim() === "/new") {
|
|
295
|
+
startNewConversation();
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
281
298
|
let files = [];
|
|
282
299
|
const queuedFiles = [...pendingFiles.value];
|
|
283
300
|
if (queuedFiles.length > 0) {
|
|
@@ -51,10 +51,12 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
51
51
|
} & {
|
|
52
52
|
cancel: () => any;
|
|
53
53
|
send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
|
|
54
|
+
newConversation: () => any;
|
|
54
55
|
selectExecutionProfile: (profile: ChatExecutionProfile) => any;
|
|
55
56
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
56
57
|
onCancel?: (() => any) | undefined;
|
|
57
58
|
onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
|
|
59
|
+
onNewConversation?: (() => any) | undefined;
|
|
58
60
|
onSelectExecutionProfile?: ((profile: ChatExecutionProfile) => any) | undefined;
|
|
59
61
|
"onUpdate:selectedModel"?: ((value: string | null) => any) | undefined;
|
|
60
62
|
"onUpdate:selectedReasoningEffort"?: ((value: any) => any) | undefined;
|
|
@@ -22,6 +22,9 @@ type __VLS_Slots = {
|
|
|
22
22
|
'failed-message-actions'?: (props: {
|
|
23
23
|
message: Message;
|
|
24
24
|
}) => unknown;
|
|
25
|
+
'user-message'?: (props: {
|
|
26
|
+
message: Message;
|
|
27
|
+
}) => unknown;
|
|
25
28
|
};
|
|
26
29
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
27
30
|
isPinned: import("vue").Ref<boolean, boolean>;
|
|
@@ -153,6 +153,9 @@ defineExpose({
|
|
|
153
153
|
<template v-if="$slots['failed-message-actions']" #failed-message-actions="slotProps">
|
|
154
154
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
155
155
|
</template>
|
|
156
|
+
<template v-if="$slots['user-message']" #user-message="slotProps">
|
|
157
|
+
<slot name="user-message" v-bind="slotProps" />
|
|
158
|
+
</template>
|
|
156
159
|
</ChatMessageBubble>
|
|
157
160
|
</template>
|
|
158
161
|
<p
|
|
@@ -22,6 +22,9 @@ type __VLS_Slots = {
|
|
|
22
22
|
'failed-message-actions'?: (props: {
|
|
23
23
|
message: Message;
|
|
24
24
|
}) => unknown;
|
|
25
|
+
'user-message'?: (props: {
|
|
26
|
+
message: Message;
|
|
27
|
+
}) => unknown;
|
|
25
28
|
};
|
|
26
29
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
27
30
|
isPinned: import("vue").Ref<boolean, boolean>;
|
|
@@ -72,7 +72,7 @@ export declare function useChat(options?: {
|
|
|
72
72
|
wakeSessionId?: string;
|
|
73
73
|
defer?: boolean;
|
|
74
74
|
executionSettings?: ExecutionSettings;
|
|
75
|
-
}>, queuedSend?: QueuedSend) => Promise<Message | null>;
|
|
75
|
+
}>, queuedSend?: QueuedSend, messageId?: string) => Promise<Message | null>;
|
|
76
76
|
flushOutboundQueue: (wakeSessionId?: string) => Promise<Message | null>;
|
|
77
77
|
failOutboundQueue: (message: string) => boolean;
|
|
78
78
|
retryMessage: (messageId: string, prepare?: () => Promise<{
|
|
@@ -165,8 +165,9 @@ export function useChat(options = {}, adapter = {}) {
|
|
|
165
165
|
const streamingMessageId = ref(null);
|
|
166
166
|
const pendingStreamReconciliationIds = ref(/* @__PURE__ */ new Set());
|
|
167
167
|
const pendingRealResultIds = ref(/* @__PURE__ */ new Set());
|
|
168
|
+
const clearing = ref(false);
|
|
168
169
|
const composerLocked = computed(
|
|
169
|
-
() => hasPendingMessage.value || runtimeBlocked.value || pendingRealResultIds.value.size > 0 || outbound.occupied.value
|
|
170
|
+
() => clearing.value || hasPendingMessage.value || runtimeBlocked.value || pendingRealResultIds.value.size > 0 || outbound.occupied.value
|
|
170
171
|
);
|
|
171
172
|
const queuedMessageContent = computed(() => outbound.slot.value?.content ?? null);
|
|
172
173
|
let requestDurableRecovery = () => {
|
|
@@ -562,7 +563,9 @@ export function useChat(options = {}, adapter = {}) {
|
|
|
562
563
|
loading.value = false;
|
|
563
564
|
}
|
|
564
565
|
};
|
|
565
|
-
const sendMessage = async (content, files, agentInputs, prepare, queuedSend) => {
|
|
566
|
+
const sendMessage = async (content, files, agentInputs, prepare, queuedSend, messageId) => {
|
|
567
|
+
if (clearing.value)
|
|
568
|
+
return null;
|
|
566
569
|
if (!currentConversation.value && !prepare)
|
|
567
570
|
return null;
|
|
568
571
|
if (outboundQueueEnabled.value && outbound.occupied.value && !queuedSend)
|
|
@@ -579,6 +582,7 @@ export function useChat(options = {}, adapter = {}) {
|
|
|
579
582
|
const existingOptimisticUserMessage = queuedSend ? messages.value.find((message) => message.id === queuedSend.optimisticIds.user) : void 0;
|
|
580
583
|
const existingOptimisticAssistantMessage = queuedSend ? messages.value.find((message) => message.id === queuedSend.optimisticIds.assistant) : void 0;
|
|
581
584
|
const optimisticPair = createOptimisticMessagePair({
|
|
585
|
+
messageId,
|
|
582
586
|
conversationId,
|
|
583
587
|
content,
|
|
584
588
|
files: filesWithSource,
|
|
@@ -957,30 +961,48 @@ export function useChat(options = {}, adapter = {}) {
|
|
|
957
961
|
}
|
|
958
962
|
};
|
|
959
963
|
const clearConversationThread = async () => {
|
|
960
|
-
|
|
964
|
+
const conversationId = currentConversation.value?.id;
|
|
965
|
+
if (!conversationId || clearing.value || hasPendingMessage.value || sending.value || outbound.occupied.value)
|
|
961
966
|
return false;
|
|
967
|
+
const generation = loadGeneration;
|
|
968
|
+
const ownsView = () => generation === loadGeneration && currentConversation.value?.id === conversationId;
|
|
969
|
+
clearing.value = true;
|
|
962
970
|
error.value = null;
|
|
971
|
+
stopPolling();
|
|
963
972
|
try {
|
|
964
973
|
const updated = await $fetch(
|
|
965
|
-
chatApi.path(`/conversations/${
|
|
974
|
+
chatApi.path(`/conversations/${conversationId}/clear`),
|
|
966
975
|
chatApi.withChatHeaders({ method: "POST" })
|
|
967
976
|
);
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
977
|
+
if (!ownsView())
|
|
978
|
+
return true;
|
|
979
|
+
stopPolling();
|
|
980
|
+
loadGeneration++;
|
|
981
|
+
loading.value = false;
|
|
982
|
+
gateController?.abort();
|
|
983
|
+
outbound.clear();
|
|
984
|
+
uncertainSend = null;
|
|
985
|
+
clearPreparingSteps();
|
|
986
|
+
directStream.disconnect();
|
|
987
|
+
currentConversation.value = { ...currentConversation.value, ...updated, messages: [] };
|
|
973
988
|
messages.value = [];
|
|
989
|
+
runtimeBlocked.value = false;
|
|
974
990
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
|
|
975
991
|
pendingRealResultIds.value = /* @__PURE__ */ new Set();
|
|
976
992
|
streamingMessageId.value = null;
|
|
977
|
-
|
|
993
|
+
agentSessionStatus.value = null;
|
|
994
|
+
agentSessionExecutable.value = false;
|
|
995
|
+
agentSessionRewakeable.value = false;
|
|
978
996
|
return true;
|
|
979
997
|
} catch (err) {
|
|
980
|
-
|
|
981
|
-
|
|
998
|
+
if (ownsView()) {
|
|
999
|
+
error.value = err instanceof Error ? err.message : "Erro ao limpar conversa";
|
|
1000
|
+
startPolling();
|
|
1001
|
+
}
|
|
982
1002
|
Sentry.captureException(err);
|
|
983
1003
|
return false;
|
|
1004
|
+
} finally {
|
|
1005
|
+
clearing.value = false;
|
|
984
1006
|
}
|
|
985
1007
|
};
|
|
986
1008
|
const retryMessage = async (messageId, prepare) => {
|
|
@@ -7,7 +7,7 @@ export function createOptimisticMessagePair(input) {
|
|
|
7
7
|
const assistantCreatedAt = new Date(userCreatedAt.getTime() + 1);
|
|
8
8
|
return {
|
|
9
9
|
user: {
|
|
10
|
-
id: createId(),
|
|
10
|
+
id: input.messageId ?? createId(),
|
|
11
11
|
conversationId: input.conversationId,
|
|
12
12
|
role: "user",
|
|
13
13
|
content: input.content,
|
|
@@ -11,3 +11,11 @@ export type { ConversationEvent, Message } from './schemas/chat/conversations.js
|
|
|
11
11
|
export type { MessageOverviewResponse } from './schemas/chat/messages.js';
|
|
12
12
|
export type { ConversationCreatorFilter } from './schemas/chat/primitives.js';
|
|
13
13
|
export type { TelaAgentExecutionInput } from './schemas/integrations/tela-agent-api.js';
|
|
14
|
+
/** Host controls for a ready Claude/v4 embed; these add no recording UI. */
|
|
15
|
+
export interface ChatEmbedHost {
|
|
16
|
+
/** True transfers ownership to chat, including pending network reconciliation; do not submit it again. */
|
|
17
|
+
sendMessage: (content: string, messageId?: string) => Promise<boolean>;
|
|
18
|
+
/** Clear history and runtime bindings while preserving the conversation ID. */
|
|
19
|
+
clear: () => Promise<boolean>;
|
|
20
|
+
cancel: () => Promise<void>;
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/chat-nuxt",
|
|
3
|
-
"version": "4.12.0
|
|
3
|
+
"version": "4.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@iconify-json/ph": "^1.2.2",
|
|
53
53
|
"@iconify/vue": "^5.0.0",
|
|
54
54
|
"@meistrari/auth-nuxt": "3.31.0",
|
|
55
|
-
"@meistrari/chat-ui-lang": "0.6.0
|
|
55
|
+
"@meistrari/chat-ui-lang": "0.6.0",
|
|
56
56
|
"@meistrari/logger": "^2.1.3",
|
|
57
57
|
"@meistrari/tela-build": "^1.79.0",
|
|
58
58
|
"@openuidev/lang-core": "1.0.0",
|