@meistrari/chat-nuxt 3.11.1 → 3.12.0-rc.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 +1 -1
- package/dist/module.json +1 -1
- package/dist/runtime/assets/css/markstream.css +1 -1
- package/dist/runtime/embed/components/chat-embed-inner.vue +76 -17
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +2 -2
- package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +2 -2
- package/dist/runtime/embed/composables/use-agent-wake.d.ts +1 -1
- package/dist/runtime/embed/composables/use-agent-wake.js +18 -8
- package/dist/runtime/embed/feature-config.d.ts +2 -0
- package/dist/runtime/embed/feature-config.js +2 -1
- package/dist/runtime/messages/components/chat-message-bubble.vue +4 -4
- package/dist/runtime/messages/components/chat-message-input.d.vue.ts +8 -2
- package/dist/runtime/messages/components/chat-message-input.vue +51 -2
- package/dist/runtime/messages/components/chat-message-input.vue.d.ts +8 -2
- package/dist/runtime/messages/components/chat-message-list.vue +3 -5
- package/dist/runtime/messages/components/reasoning/chat-reasoning-steps.vue +1 -1
- package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue +14 -66
- package/dist/runtime/messages/composables/chat-message-terminal.js +3 -3
- package/dist/runtime/messages/composables/chat.d.ts +17 -3
- package/dist/runtime/messages/composables/chat.js +246 -23
- package/dist/runtime/messages/composables/outbound-queue.d.ts +23 -0
- package/dist/runtime/messages/composables/outbound-queue.js +28 -0
- package/dist/runtime/messages/composables/use-direct-stream.d.ts +7 -1
- package/dist/runtime/messages/composables/use-direct-stream.js +30 -7
- package/dist/runtime/server/utils/chat-api-proxy.js +3 -1
- package/dist/runtime/shared/chat-api-error.d.ts +7 -0
- package/dist/runtime/shared/chat-api-error.js +24 -4
- package/dist/runtime/types/schemas/chat/chat-config.d.ts +1 -0
- package/dist/runtime/types/schemas/chat/chat-config.js +1 -0
- package/dist/runtime/types/schemas/chat/messages.d.ts +14 -0
- package/dist/runtime/types/schemas/chat/messages.js +6 -1
- package/dist/runtime/types/schemas/chat/ui.d.ts +2 -2
- package/dist/runtime/types/schemas/chat/ui.js +2 -2
- package/dist/runtime/types/schemas/index.d.ts +1 -0
- package/dist/runtime/types/schemas/index.js +1 -0
- package/dist/runtime/types/schemas/integrations/tela-agent-api.d.ts +46 -0
- package/dist/runtime/types/schemas/integrations/tela-agent-api.js +26 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ Installing `@meistrari/chat-nuxt` installs the runtime packages used by the laye
|
|
|
101
101
|
|
|
102
102
|
| Package | Version | Purpose |
|
|
103
103
|
|---------|---------|---------|
|
|
104
|
-
| `@meistrari/auth-nuxt` | `3.
|
|
104
|
+
| `@meistrari/auth-nuxt` | `3.31.0` | Authentication (required) |
|
|
105
105
|
| `@meistrari/logger` | `^2.1.3` | Structured logging for the server proxy routes |
|
|
106
106
|
| `@meistrari/tela-build` | `^1.30.0` | UI component library (Nuxt layer) |
|
|
107
107
|
| `@sentry/nuxt` | `^10.0.0` | Client-side error capture used by chat composables |
|
package/dist/module.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.markstream-vue{color:#171717;font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:16px;font-weight:400;letter-spacing:-.15px;line-height:24px;--list-item-marker:#a3a3a3}.markstream-vue code,.markstream-vue kbd,.markstream-vue pre,.markstream-vue samp{font-family:Geist Mono Variable,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:13px;font-variation-settings:normal;line-height:1.5}.markstream-vue ol,.markstream-vue ul{margin:8px 0;padding-left:1.5em}.markstream-vue .hr-node{border-color:#e5e5e5;border-top-width:.5px;margin-bottom:24px;margin-top:24px}.markstream-vue .strong-node{font-weight:580}.markstream-vue .list-node.list-node{margin-bottom:8px;margin-left:4px;margin-top:8px;padding-left:1em}.markstream-vue ul{list-style:disc;list-style-position:outside}.markstream-vue ol{list-style:decimal;list-style-position:outside}.markstream-vue li{margin:4px 0}.markstream-vue .paragraph-node{margin:0}.markstream-vue .my-8{margin-bottom:8px;margin-top:8px}.markstream-vue .heading-node.heading-1,.markstream-vue h1{font-size:24px;font-weight:540;letter-spacing:-.8px;line-height:28px;margin:24px 0 16px}.markstream-vue .heading-node.heading-2,.markstream-vue h2{font-size:20px;font-weight:540;letter-spacing:-.5px;line-height:24px;margin:20px 0 12px}.markstream-vue .heading-node.heading-3,.markstream-vue h3{font-size:20px;font-weight:540;letter-spacing:-.5px;line-height:24px;margin:16px 0 8px}.markstream-vue .heading-node.heading-4,.markstream-vue h4{font-size:16px;font-weight:540;letter-spacing:-.2px;line-height:20px;margin:12px 0 6px}.markstream-vue .heading-node.heading-5,.markstream-vue h5{font-size:14px;font-weight:540;letter-spacing:-.15px;line-height:16px;margin:8px 0 4px}.markstream-vue .heading-node.heading-6,.markstream-vue h6{font-size:12px;font-weight:540;letter-spacing:-.1px;line-height:14px;margin:8px 0 4px}.markstream-vue [class*=tooltip],[class*=tooltip-element]{background-color:var(--neutral-900,#1a1a1a)!important;border-radius:4px;color:#fff!important;font-size:12px;padding:4px 8px}.mention-tag{align-items:center;border-radius:9999px;display:inline-flex;font-size:.875em;font-weight:500;gap:4px;padding:2px 8px;vertical-align:middle;white-space:nowrap}.mention-tag-file{background-color:rgba(127,189,247,.12);color:#7fbdf7}.mention-tag-skill{background-color:rgba(155,111,222,.12);color:#9b6fde}.mention-tag-canvas{background-color:rgba(234,161,65,.12);color:#d4882e}.mention-tag>span[class*=i-ph]{flex-shrink:0}
|
|
1
|
+
.markstream-vue{color:#171717;font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:16px;font-weight:400;letter-spacing:-.15px;line-height:24px;--list-item-marker:#a3a3a3;--list-item-counter-marker:#262626}.markstream-vue code,.markstream-vue kbd,.markstream-vue pre,.markstream-vue samp{font-family:Geist Mono Variable,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:13px;font-variation-settings:normal;line-height:1.5}.markstream-vue ol,.markstream-vue ul{margin:8px 0;padding-left:1.5em}.markstream-vue .hr-node{border-color:#e5e5e5;border-top-width:.5px;margin-bottom:24px;margin-top:24px}.markstream-vue .strong-node{font-weight:580}.markstream-vue .list-node.list-node{margin-bottom:8px;margin-left:4px;margin-top:8px;padding-left:1em}.markstream-vue ul{list-style:disc;list-style-position:outside}.markstream-vue ol{list-style:decimal;list-style-position:outside}.markstream-vue li{margin:4px 0}.markstream-vue .paragraph-node{margin:0}.markstream-vue .my-8{margin-bottom:8px;margin-top:8px}.markstream-vue .heading-node.heading-1,.markstream-vue h1{font-size:24px;font-weight:540;letter-spacing:-.8px;line-height:28px;margin:24px 0 16px}.markstream-vue .heading-node.heading-2,.markstream-vue h2{font-size:20px;font-weight:540;letter-spacing:-.5px;line-height:24px;margin:20px 0 12px}.markstream-vue .heading-node.heading-3,.markstream-vue h3{font-size:20px;font-weight:540;letter-spacing:-.5px;line-height:24px;margin:16px 0 8px}.markstream-vue .heading-node.heading-4,.markstream-vue h4{font-size:16px;font-weight:540;letter-spacing:-.2px;line-height:20px;margin:12px 0 6px}.markstream-vue .heading-node.heading-5,.markstream-vue h5{font-size:14px;font-weight:540;letter-spacing:-.15px;line-height:16px;margin:8px 0 4px}.markstream-vue .heading-node.heading-6,.markstream-vue h6{font-size:12px;font-weight:540;letter-spacing:-.1px;line-height:14px;margin:8px 0 4px}.markstream-vue [class*=tooltip],[class*=tooltip-element]{background-color:var(--neutral-900,#1a1a1a)!important;border-radius:4px;color:#fff!important;font-size:12px;padding:4px 8px}.mention-tag{align-items:center;border-radius:9999px;display:inline-flex;font-size:.875em;font-weight:500;gap:4px;padding:2px 8px;vertical-align:middle;white-space:nowrap}.mention-tag-file{background-color:rgba(127,189,247,.12);color:#7fbdf7}.mention-tag-skill{background-color:rgba(155,111,222,.12);color:#9b6fde}.mention-tag-canvas{background-color:rgba(234,161,65,.12);color:#d4882e}.mention-tag>span[class*=i-ph]{flex-shrink:0}
|
|
@@ -143,6 +143,9 @@ function applySuggestion(prompt) {
|
|
|
143
143
|
const breakpoints = useBreakpoints({ mobile: CHAT_MOBILE_BREAKPOINT });
|
|
144
144
|
const isMobile = breakpoints.smaller("mobile");
|
|
145
145
|
const drawerOpen = ref(false);
|
|
146
|
+
function restoreQueuedSend(send) {
|
|
147
|
+
messageInputRef.value?.restoreDraft(send);
|
|
148
|
+
}
|
|
146
149
|
const { isDragging, setupDropZone } = useFileDrop({
|
|
147
150
|
onDrop: (files) => {
|
|
148
151
|
messageInputRef.value?.addFiles(files);
|
|
@@ -155,7 +158,10 @@ const {
|
|
|
155
158
|
loading,
|
|
156
159
|
generatingTitle,
|
|
157
160
|
animatedTitle,
|
|
158
|
-
|
|
161
|
+
composerLocked,
|
|
162
|
+
outboundOccupied,
|
|
163
|
+
sessionReady,
|
|
164
|
+
agentSessionRewakeable,
|
|
159
165
|
streamingActiveMessageId,
|
|
160
166
|
preparingSteps,
|
|
161
167
|
loadConversation,
|
|
@@ -164,12 +170,18 @@ const {
|
|
|
164
170
|
setConversationModel,
|
|
165
171
|
pendingModelSelection,
|
|
166
172
|
sendMessage,
|
|
173
|
+
flushOutboundQueue,
|
|
174
|
+
failOutboundQueue,
|
|
167
175
|
retryMessage,
|
|
168
176
|
cancelConversation,
|
|
169
177
|
startPolling,
|
|
170
178
|
clearConversation,
|
|
171
179
|
error: chatError
|
|
172
|
-
} = useChat(
|
|
180
|
+
} = useChat({
|
|
181
|
+
outboundQueueEnabled: computed(() => resolvedFeatures.value.chatOutboundQueue),
|
|
182
|
+
onQueuedSendCancelled: restoreQueuedSend,
|
|
183
|
+
onQueuedSendFailed: restoreQueuedSend
|
|
184
|
+
});
|
|
173
185
|
const agentWake = useAgentWake();
|
|
174
186
|
const modelUpdateInFlight = ref(null);
|
|
175
187
|
watch(chatError, (message) => {
|
|
@@ -186,9 +198,11 @@ const selectedModel = computed({
|
|
|
186
198
|
if (conversation && conversation.model !== value) {
|
|
187
199
|
const previousModel = conversation.model;
|
|
188
200
|
setConversationModel(value);
|
|
189
|
-
const update = updateConversationModel(conversation.id, value).then((updated) => {
|
|
201
|
+
const update = updateConversationModel(conversation.id, value).then(async (updated) => {
|
|
190
202
|
if (!updated && currentConversation.value?.id === conversation.id && currentConversation.value.model === value) {
|
|
191
203
|
setConversationModel(previousModel);
|
|
204
|
+
} else if (updated && value) {
|
|
205
|
+
await agentWake.wake(conversation.threadSessionId ?? void 0, value);
|
|
192
206
|
}
|
|
193
207
|
return updated;
|
|
194
208
|
});
|
|
@@ -239,7 +253,8 @@ function updateConversationId(nextConversationId) {
|
|
|
239
253
|
async function ensureConversationLoaded(conversationId) {
|
|
240
254
|
if (currentConversation.value?.id === conversationId) {
|
|
241
255
|
void agentWake.wake(
|
|
242
|
-
currentConversation.value.threadSessionId ?? void 0
|
|
256
|
+
currentConversation.value.threadSessionId ?? void 0,
|
|
257
|
+
selectedModel.value
|
|
243
258
|
);
|
|
244
259
|
startPolling();
|
|
245
260
|
return;
|
|
@@ -259,7 +274,8 @@ async function ensureConversationLoaded(conversationId) {
|
|
|
259
274
|
return;
|
|
260
275
|
}
|
|
261
276
|
void agentWake.wake(
|
|
262
|
-
currentConversation.value.threadSessionId ?? void 0
|
|
277
|
+
currentConversation.value.threadSessionId ?? void 0,
|
|
278
|
+
selectedModel.value
|
|
263
279
|
);
|
|
264
280
|
startPolling();
|
|
265
281
|
} finally {
|
|
@@ -270,7 +286,7 @@ async function ensureConversationLoaded(conversationId) {
|
|
|
270
286
|
}
|
|
271
287
|
function resetConversation(shouldEmit = true) {
|
|
272
288
|
clearConversation();
|
|
273
|
-
void agentWake.wake();
|
|
289
|
+
void agentWake.wake(void 0, selectedModel.value);
|
|
274
290
|
activeTab.value = "chat";
|
|
275
291
|
closeFilesPanel();
|
|
276
292
|
closePreview();
|
|
@@ -453,13 +469,56 @@ async function handleSend(content, files, agentInputs) {
|
|
|
453
469
|
const conversation = currentConversation.value;
|
|
454
470
|
if (!conversation)
|
|
455
471
|
throw new Error("Erro ao preparar conversa");
|
|
456
|
-
if (
|
|
472
|
+
if (conversation.threadSessionId && resolvedFeatures.value.chatOutboundQueue && sessionReady.value === false) {
|
|
473
|
+
if (!agentSessionRewakeable.value)
|
|
474
|
+
return { defer: true };
|
|
475
|
+
const wake = await agentWake.wake(conversation.threadSessionId, selectedModel.value);
|
|
476
|
+
if (wake.status !== "ready")
|
|
477
|
+
throw new Error("N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.");
|
|
478
|
+
return {};
|
|
479
|
+
}
|
|
480
|
+
if (!conversation.threadSessionId) {
|
|
457
481
|
await agentWake.waitUntilSettled(signal);
|
|
482
|
+
if (agentWake.state.value === "idle")
|
|
483
|
+
await agentWake.wake(void 0, selectedModel.value);
|
|
484
|
+
else if (agentWake.state.value === "ready")
|
|
485
|
+
await agentWake.wake(void 0, selectedModel.value);
|
|
486
|
+
}
|
|
458
487
|
claimedWakeSessionId = claimableWakeSessionId();
|
|
488
|
+
if (!conversation.threadSessionId && !claimedWakeSessionId)
|
|
489
|
+
throw new Error("N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.");
|
|
459
490
|
return claimedWakeSessionId ? { wakeSessionId: claimedWakeSessionId } : {};
|
|
460
491
|
});
|
|
461
492
|
if (sent && claimedWakeSessionId)
|
|
462
493
|
agentWake.consume();
|
|
494
|
+
if (!sent)
|
|
495
|
+
restoreQueuedSend({ content, files, agentInputs: resolvedAgentInputs });
|
|
496
|
+
}
|
|
497
|
+
watch(
|
|
498
|
+
[outboundOccupied, agentWake.state],
|
|
499
|
+
async ([occupied, wakeState]) => {
|
|
500
|
+
if (!occupied)
|
|
501
|
+
return;
|
|
502
|
+
if (wakeState === "ready") {
|
|
503
|
+
const wakeSessionId = claimableWakeSessionId();
|
|
504
|
+
const sent = await flushOutboundQueue(wakeSessionId);
|
|
505
|
+
if (sent && wakeSessionId)
|
|
506
|
+
agentWake.consume();
|
|
507
|
+
} else if (wakeState === "unavailable" && (agentSessionRewakeable.value || sessionReady.value === null)) {
|
|
508
|
+
failOutboundQueue("N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.");
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
);
|
|
512
|
+
watch(
|
|
513
|
+
[outboundOccupied, agentSessionRewakeable],
|
|
514
|
+
([occupied, rewakeable]) => {
|
|
515
|
+
const sessionId = currentConversation.value?.threadSessionId;
|
|
516
|
+
if (occupied && rewakeable && sessionId && agentWake.state.value !== "waking")
|
|
517
|
+
void agentWake.wake(sessionId, selectedModel.value);
|
|
518
|
+
}
|
|
519
|
+
);
|
|
520
|
+
async function handleCancel() {
|
|
521
|
+
await cancelConversation();
|
|
463
522
|
}
|
|
464
523
|
async function handleRetry(messageId) {
|
|
465
524
|
if (!currentConversation.value?.threadSessionId)
|
|
@@ -751,7 +810,7 @@ async function handleDelete() {
|
|
|
751
810
|
:files-count="filesCount"
|
|
752
811
|
:generating-title="generatingTitle"
|
|
753
812
|
:has-messages="hasMessages"
|
|
754
|
-
:has-pending-message="
|
|
813
|
+
:has-pending-message="composerLocked"
|
|
755
814
|
:hide-settings="hideSettings"
|
|
756
815
|
:hide-sidebar="hideSidebar"
|
|
757
816
|
:is-editing="isEditing"
|
|
@@ -770,7 +829,7 @@ async function handleDelete() {
|
|
|
770
829
|
:workspace-logo="workspaceLogo"
|
|
771
830
|
:workspace-name="workspaceName"
|
|
772
831
|
:workspace-settings="effectiveWorkspaceSettings"
|
|
773
|
-
@cancel="
|
|
832
|
+
@cancel="handleCancel"
|
|
774
833
|
@cancel-editing="cancelEditing"
|
|
775
834
|
@copy-link="handleShare"
|
|
776
835
|
@debug="showDebugModal = true"
|
|
@@ -829,7 +888,7 @@ async function handleDelete() {
|
|
|
829
888
|
<ChatMessageInput
|
|
830
889
|
ref="messageInputRef"
|
|
831
890
|
v-model:selected-model="selectedModel"
|
|
832
|
-
:loading="
|
|
891
|
+
:loading="composerLocked"
|
|
833
892
|
:creator-name="currentUser?.name ?? void 0"
|
|
834
893
|
:creator-email="
|
|
835
894
|
currentConversation?.createdBy ?? currentUser?.email ?? void 0
|
|
@@ -845,7 +904,7 @@ async function handleDelete() {
|
|
|
845
904
|
:show-cancel-button="resolvedFeatures.showCancelButton"
|
|
846
905
|
centered
|
|
847
906
|
@send="handleSend"
|
|
848
|
-
@cancel="
|
|
907
|
+
@cancel="handleCancel"
|
|
849
908
|
/>
|
|
850
909
|
</template>
|
|
851
910
|
</TelaChatEmptyState>
|
|
@@ -862,7 +921,7 @@ async function handleDelete() {
|
|
|
862
921
|
<ChatMessageInput
|
|
863
922
|
ref="messageInputRef"
|
|
864
923
|
v-model:selected-model="selectedModel"
|
|
865
|
-
:loading="
|
|
924
|
+
:loading="composerLocked"
|
|
866
925
|
:creator-name="currentUser?.name ?? void 0"
|
|
867
926
|
:creator-email="
|
|
868
927
|
currentConversation?.createdBy ?? currentUser?.email ?? void 0
|
|
@@ -878,7 +937,7 @@ async function handleDelete() {
|
|
|
878
937
|
:show-cancel-button="resolvedFeatures.showCancelButton"
|
|
879
938
|
has-disclaimer
|
|
880
939
|
@send="handleSend"
|
|
881
|
-
@cancel="
|
|
940
|
+
@cancel="handleCancel"
|
|
882
941
|
/>
|
|
883
942
|
</ChatMobileShell>
|
|
884
943
|
|
|
@@ -1026,7 +1085,7 @@ async function handleDelete() {
|
|
|
1026
1085
|
<ChatMessageInput
|
|
1027
1086
|
ref="messageInputRef"
|
|
1028
1087
|
v-model:selected-model="selectedModel"
|
|
1029
|
-
:loading="
|
|
1088
|
+
:loading="composerLocked"
|
|
1030
1089
|
:creator-name="currentUser?.name ?? void 0"
|
|
1031
1090
|
:creator-email="
|
|
1032
1091
|
currentConversation?.createdBy ?? currentUser?.email ?? void 0
|
|
@@ -1042,7 +1101,7 @@ async function handleDelete() {
|
|
|
1042
1101
|
:show-cancel-button="resolvedFeatures.showCancelButton"
|
|
1043
1102
|
centered
|
|
1044
1103
|
@send="handleSend"
|
|
1045
|
-
@cancel="
|
|
1104
|
+
@cancel="handleCancel"
|
|
1046
1105
|
/>
|
|
1047
1106
|
</template>
|
|
1048
1107
|
</TelaChatEmptyState>
|
|
@@ -1062,7 +1121,7 @@ async function handleDelete() {
|
|
|
1062
1121
|
<ChatMessageInput
|
|
1063
1122
|
ref="messageInputRef"
|
|
1064
1123
|
v-model:selected-model="selectedModel"
|
|
1065
|
-
:loading="
|
|
1124
|
+
:loading="composerLocked"
|
|
1066
1125
|
:creator-name="currentUser?.name ?? void 0"
|
|
1067
1126
|
:creator-email="
|
|
1068
1127
|
currentConversation?.createdBy ?? currentUser?.email ?? void 0
|
|
@@ -1078,7 +1137,7 @@ async function handleDelete() {
|
|
|
1078
1137
|
:show-cancel-button="resolvedFeatures.showCancelButton"
|
|
1079
1138
|
has-disclaimer
|
|
1080
1139
|
@send="handleSend"
|
|
1081
|
-
@cancel="
|
|
1140
|
+
@cancel="handleCancel"
|
|
1082
1141
|
/>
|
|
1083
1142
|
</TelaChatBody>
|
|
1084
1143
|
|
|
@@ -57,12 +57,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
57
57
|
"update:selectedModel": (value: string | null) => any;
|
|
58
58
|
} & {
|
|
59
59
|
delete: () => any;
|
|
60
|
+
cancel: () => any;
|
|
60
61
|
rename: () => any;
|
|
61
62
|
duplicate: () => any;
|
|
62
63
|
export: () => any;
|
|
63
64
|
copyLink: () => any;
|
|
64
65
|
selectConversation: (id: string) => any;
|
|
65
|
-
cancel: () => any;
|
|
66
66
|
settings: () => any;
|
|
67
67
|
send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
|
|
68
68
|
debug: () => any;
|
|
@@ -78,12 +78,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
78
78
|
"update:workspaceSheetOpen": (value: boolean) => any;
|
|
79
79
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
80
80
|
onDelete?: (() => any) | undefined;
|
|
81
|
+
onCancel?: (() => any) | undefined;
|
|
81
82
|
onRename?: (() => any) | undefined;
|
|
82
83
|
onDuplicate?: (() => any) | undefined;
|
|
83
84
|
onExport?: (() => any) | undefined;
|
|
84
85
|
onCopyLink?: (() => any) | undefined;
|
|
85
86
|
onSelectConversation?: ((id: string) => any) | undefined;
|
|
86
|
-
onCancel?: (() => any) | undefined;
|
|
87
87
|
onSettings?: (() => any) | undefined;
|
|
88
88
|
onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
|
|
89
89
|
"onUpdate:selectedModel"?: ((value: string | null) => any) | undefined;
|
|
@@ -57,12 +57,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
57
57
|
"update:selectedModel": (value: string | null) => any;
|
|
58
58
|
} & {
|
|
59
59
|
delete: () => any;
|
|
60
|
+
cancel: () => any;
|
|
60
61
|
rename: () => any;
|
|
61
62
|
duplicate: () => any;
|
|
62
63
|
export: () => any;
|
|
63
64
|
copyLink: () => any;
|
|
64
65
|
selectConversation: (id: string) => any;
|
|
65
|
-
cancel: () => any;
|
|
66
66
|
settings: () => any;
|
|
67
67
|
send: (content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any;
|
|
68
68
|
debug: () => any;
|
|
@@ -78,12 +78,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
78
78
|
"update:workspaceSheetOpen": (value: boolean) => any;
|
|
79
79
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
80
80
|
onDelete?: (() => any) | undefined;
|
|
81
|
+
onCancel?: (() => any) | undefined;
|
|
81
82
|
onRename?: (() => any) | undefined;
|
|
82
83
|
onDuplicate?: (() => any) | undefined;
|
|
83
84
|
onExport?: (() => any) | undefined;
|
|
84
85
|
onCopyLink?: (() => any) | undefined;
|
|
85
86
|
onSelectConversation?: ((id: string) => any) | undefined;
|
|
86
|
-
onCancel?: (() => any) | undefined;
|
|
87
87
|
onSettings?: (() => any) | undefined;
|
|
88
88
|
onSend?: ((content: string, files: FileUploadInput[], agentInputs?: TelaAgentExecutionInput[] | undefined) => any) | undefined;
|
|
89
89
|
"onUpdate:selectedModel"?: ((value: string | null) => any) | undefined;
|
|
@@ -15,7 +15,7 @@ export declare function pollAgentWake(options: {
|
|
|
15
15
|
export declare function useAgentWake(): {
|
|
16
16
|
state: any;
|
|
17
17
|
sessionId: any;
|
|
18
|
-
wake: (requestedSessionId?: string) => Promise<TelaAgentWakeResponse>;
|
|
18
|
+
wake: (requestedSessionId?: string, model?: string | null) => Promise<TelaAgentWakeResponse>;
|
|
19
19
|
skip: () => void;
|
|
20
20
|
consume: () => void;
|
|
21
21
|
waitUntilSettled: (signal?: AbortSignal) => Promise<AgentWakeSnapshot>;
|
|
@@ -21,21 +21,30 @@ export async function pollAgentWake(options) {
|
|
|
21
21
|
else
|
|
22
22
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
23
23
|
}));
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
let unavailableAttempts = 0;
|
|
25
|
+
while (!options.signal?.aborted && now() <= deadline) {
|
|
26
|
+
try {
|
|
26
27
|
const response = await options.request();
|
|
27
28
|
options.onResponse?.(response);
|
|
29
|
+
if (response.status === "unavailable" && unavailableAttempts < 2) {
|
|
30
|
+
unavailableAttempts += 1;
|
|
31
|
+
await wait(Math.min(500 * 2 ** (unavailableAttempts - 1), Math.max(0, deadline - now())), options.signal);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
28
34
|
if (response.status !== "waking")
|
|
29
35
|
return response;
|
|
30
36
|
const remaining = deadline - now();
|
|
31
37
|
if (remaining <= 0)
|
|
32
38
|
break;
|
|
33
39
|
await wait(Math.min(options.pollIntervalMs ?? WAKE_POLL_INTERVAL_MS, remaining), options.signal);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error instanceof DOMException && error.name === "AbortError")
|
|
42
|
+
throw error;
|
|
43
|
+
if (unavailableAttempts >= 2)
|
|
44
|
+
return { status: "unavailable" };
|
|
45
|
+
unavailableAttempts += 1;
|
|
46
|
+
await wait(Math.min(500 * 2 ** (unavailableAttempts - 1), Math.max(0, deadline - now())), options.signal);
|
|
34
47
|
}
|
|
35
|
-
} catch (error) {
|
|
36
|
-
if (error instanceof DOMException && error.name === "AbortError")
|
|
37
|
-
throw error;
|
|
38
|
-
return { status: "unavailable" };
|
|
39
48
|
}
|
|
40
49
|
return { status: "unavailable" };
|
|
41
50
|
}
|
|
@@ -67,7 +76,7 @@ export function useAgentWake() {
|
|
|
67
76
|
activeWake = null;
|
|
68
77
|
setSnapshot({ state: "idle" });
|
|
69
78
|
}
|
|
70
|
-
async function wake(requestedSessionId) {
|
|
79
|
+
async function wake(requestedSessionId, model) {
|
|
71
80
|
generation++;
|
|
72
81
|
const currentGeneration = generation;
|
|
73
82
|
abortController?.abort();
|
|
@@ -93,7 +102,8 @@ export function useAgentWake() {
|
|
|
93
102
|
method: "POST",
|
|
94
103
|
signal: controller.signal,
|
|
95
104
|
body: {
|
|
96
|
-
...wakeSessionId ? { sessionId: wakeSessionId } : {}
|
|
105
|
+
...wakeSessionId ? { sessionId: wakeSessionId } : {},
|
|
106
|
+
...model ? { model } : {}
|
|
97
107
|
}
|
|
98
108
|
})
|
|
99
109
|
),
|
|
@@ -8,11 +8,13 @@ export type ChatFeatureConfig = {
|
|
|
8
8
|
showCancelButton?: boolean;
|
|
9
9
|
/** Time to first token shown in assistant message metadata. Defaults to true. */
|
|
10
10
|
showTtft?: boolean;
|
|
11
|
+
chatOutboundQueue?: boolean;
|
|
11
12
|
};
|
|
12
13
|
export type ResolvedChatFeatureConfig = {
|
|
13
14
|
showUsageTab: boolean;
|
|
14
15
|
showDebugOption: boolean;
|
|
15
16
|
showCancelButton: boolean;
|
|
16
17
|
showTtft: boolean;
|
|
18
|
+
chatOutboundQueue: boolean;
|
|
17
19
|
};
|
|
18
20
|
export declare function resolveChatFeatures(features?: Partial<ChatFeatureConfig>): ResolvedChatFeatureConfig;
|
|
@@ -3,6 +3,7 @@ export function resolveChatFeatures(features) {
|
|
|
3
3
|
showUsageTab: features?.showUsageTab ?? false,
|
|
4
4
|
showDebugOption: features?.showDebugOption ?? false,
|
|
5
5
|
showCancelButton: features?.showCancelButton ?? false,
|
|
6
|
-
showTtft: features?.showTtft ?? true
|
|
6
|
+
showTtft: features?.showTtft ?? true,
|
|
7
|
+
chatOutboundQueue: features?.chatOutboundQueue ?? false
|
|
7
8
|
};
|
|
8
9
|
}
|
|
@@ -111,13 +111,13 @@ const hasDetectedFiles = computed(() => contentSegments.value.some((s) => s.type
|
|
|
111
111
|
<template>
|
|
112
112
|
<TelaChatMessage
|
|
113
113
|
:from="message.role === 'user' ? 'user' : 'assistant'"
|
|
114
|
-
:align="
|
|
114
|
+
:align="message.role === 'user' ? 'end' : 'start'"
|
|
115
115
|
>
|
|
116
116
|
<template v-if="message.role === 'user'">
|
|
117
117
|
<div
|
|
118
118
|
max-w-prose
|
|
119
119
|
flex="~ col"
|
|
120
|
-
|
|
120
|
+
items-end
|
|
121
121
|
>
|
|
122
122
|
<div
|
|
123
123
|
v-if="!isOwnMessage"
|
|
@@ -138,7 +138,7 @@ const hasDetectedFiles = computed(() => contentSegments.value.some((s) => s.type
|
|
|
138
138
|
|
|
139
139
|
<TelaChatMessageContent
|
|
140
140
|
variant="contained"
|
|
141
|
-
|
|
141
|
+
align="end"
|
|
142
142
|
:class="isPending && 'op-80'"
|
|
143
143
|
>
|
|
144
144
|
<div v-if="hasFiles" flex="~ col" gap-4px mb-8px>
|
|
@@ -171,7 +171,7 @@ const hasDetectedFiles = computed(() => contentSegments.value.some((s) => s.type
|
|
|
171
171
|
mt-8px
|
|
172
172
|
body-10-regular
|
|
173
173
|
text-tertiary
|
|
174
|
-
|
|
174
|
+
self-end
|
|
175
175
|
>
|
|
176
176
|
{{ formatTime(message.createdAt) }}
|
|
177
177
|
</div>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DeepReadonly } from 'vue';
|
|
2
2
|
import type { Message } from '../../types/schemas/chat/conversations.js';
|
|
3
|
-
import type { ConversationFile } from '../../types/schemas/chat/files.js';
|
|
3
|
+
import type { ConversationFile, FileUploadInput } from '../../types/schemas/chat/files.js';
|
|
4
4
|
import type { WorkspaceSettingsResponse as WorkspaceSettings } from '../../types/schemas/chat/workspace-settings.js';
|
|
5
|
-
import type { TelaAgentContextFile, TelaAgentInputVariable, TelaAgentSkill } from '../../types/schemas/integrations/tela-agent-api.js';
|
|
5
|
+
import type { TelaAgentContextFile, TelaAgentExecutionInput, TelaAgentInputVariable, TelaAgentSkill } from '../../types/schemas/integrations/tela-agent-api.js';
|
|
6
6
|
type __VLS_Props = {
|
|
7
7
|
disabled?: boolean;
|
|
8
8
|
loading?: boolean;
|
|
@@ -21,6 +21,11 @@ type __VLS_Props = {
|
|
|
21
21
|
showCancelButton?: boolean;
|
|
22
22
|
};
|
|
23
23
|
declare function addFiles(files: File[], inputName?: string): void;
|
|
24
|
+
declare function restoreDraft(draft: {
|
|
25
|
+
content: string;
|
|
26
|
+
files?: FileUploadInput[];
|
|
27
|
+
agentInputs?: TelaAgentExecutionInput[];
|
|
28
|
+
}): void;
|
|
24
29
|
declare function setDraft(text: string): void;
|
|
25
30
|
type __VLS_ModelProps = {
|
|
26
31
|
'selectedModel'?: string | null;
|
|
@@ -28,6 +33,7 @@ type __VLS_ModelProps = {
|
|
|
28
33
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
29
34
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
30
35
|
addFiles: typeof addFiles;
|
|
36
|
+
restoreDraft: typeof restoreDraft;
|
|
31
37
|
setDraft: typeof setDraft;
|
|
32
38
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
33
39
|
"update:selectedModel": (value: string | null) => any;
|
|
@@ -196,6 +196,15 @@ function handleFileSelect(event) {
|
|
|
196
196
|
function createPendingFile(file, inputName) {
|
|
197
197
|
return {
|
|
198
198
|
id: `${file.name}-${file.lastModified}-${file.size}-${Math.random().toString(36).slice(2)}`,
|
|
199
|
+
source: "browser",
|
|
200
|
+
file,
|
|
201
|
+
inputName
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function createUploadedPendingFile(file, inputName) {
|
|
205
|
+
return {
|
|
206
|
+
id: `${file.vaultReference ?? file.url}-${Math.random().toString(36).slice(2)}`,
|
|
207
|
+
source: "uploaded",
|
|
199
208
|
file,
|
|
200
209
|
inputName
|
|
201
210
|
};
|
|
@@ -231,6 +240,22 @@ function handleVariableDrop(event, inputName) {
|
|
|
231
240
|
function getVaultRef(file) {
|
|
232
241
|
return file.vaultReference?.trim() || (file.url.startsWith("vault://") ? file.url : null);
|
|
233
242
|
}
|
|
243
|
+
function getPendingFileMimeType(file) {
|
|
244
|
+
return file.source === "browser" ? file.file.type : file.file.mimeType;
|
|
245
|
+
}
|
|
246
|
+
async function resolvePendingFiles(files) {
|
|
247
|
+
const browserFiles = files.filter((file) => file.source === "browser");
|
|
248
|
+
const uploadedBrowserFiles = browserFiles.length > 0 ? await uploadFiles(browserFiles.map((file) => file.file)) : [];
|
|
249
|
+
let uploadedIndex = 0;
|
|
250
|
+
return files.map((file) => {
|
|
251
|
+
if (file.source === "uploaded")
|
|
252
|
+
return file.file;
|
|
253
|
+
const uploaded = uploadedBrowserFiles[uploadedIndex++];
|
|
254
|
+
if (!uploaded)
|
|
255
|
+
throw new Error("Falha ao preparar anexo");
|
|
256
|
+
return uploaded;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
234
259
|
function buildAgentInputs(files, queuedFiles) {
|
|
235
260
|
if (!hasAgentInputs.value)
|
|
236
261
|
return [];
|
|
@@ -266,7 +291,7 @@ async function handleSend() {
|
|
|
266
291
|
const queuedFiles = [...pendingFiles.value];
|
|
267
292
|
if (queuedFiles.length > 0) {
|
|
268
293
|
try {
|
|
269
|
-
files = await
|
|
294
|
+
files = await resolvePendingFiles(queuedFiles);
|
|
270
295
|
} catch {
|
|
271
296
|
return;
|
|
272
297
|
}
|
|
@@ -470,6 +495,29 @@ function addFiles(files, inputName) {
|
|
|
470
495
|
});
|
|
471
496
|
queueFiles(validFiles, inputName);
|
|
472
497
|
}
|
|
498
|
+
function restoreDraft(draft) {
|
|
499
|
+
setDraft(draft.content);
|
|
500
|
+
const textInputs = (draft.agentInputs ?? []).filter((input) => input.type === "text");
|
|
501
|
+
agentInputTexts.value = {
|
|
502
|
+
...agentInputTexts.value,
|
|
503
|
+
...Object.fromEntries(textInputs.map((input) => [input.name, input.content]))
|
|
504
|
+
};
|
|
505
|
+
const availableSlots = MAX_FILES - pendingFiles.value.length;
|
|
506
|
+
if (availableSlots <= 0 || !draft.files?.length)
|
|
507
|
+
return;
|
|
508
|
+
const fileInputs = (draft.agentInputs ?? []).filter((input) => input.type === "file");
|
|
509
|
+
const claimedInputs = /* @__PURE__ */ new Set();
|
|
510
|
+
const restoredFiles = draft.files.slice(0, availableSlots).map((file) => {
|
|
511
|
+
const vaultRef = getVaultRef(file);
|
|
512
|
+
const inputIndex = fileInputs.findIndex(
|
|
513
|
+
(input, index) => !claimedInputs.has(index) && input.vaultRef === vaultRef
|
|
514
|
+
);
|
|
515
|
+
if (inputIndex >= 0)
|
|
516
|
+
claimedInputs.add(inputIndex);
|
|
517
|
+
return createUploadedPendingFile(file, inputIndex >= 0 ? fileInputs[inputIndex]?.name : void 0);
|
|
518
|
+
});
|
|
519
|
+
pendingFiles.value = [...pendingFiles.value, ...restoredFiles];
|
|
520
|
+
}
|
|
473
521
|
function setDraft(text) {
|
|
474
522
|
content.value = text;
|
|
475
523
|
if (editorRef.value) {
|
|
@@ -488,6 +536,7 @@ function setDraft(text) {
|
|
|
488
536
|
}
|
|
489
537
|
defineExpose({
|
|
490
538
|
addFiles,
|
|
539
|
+
restoreDraft,
|
|
491
540
|
setDraft
|
|
492
541
|
});
|
|
493
542
|
</script>
|
|
@@ -641,7 +690,7 @@ defineExpose({
|
|
|
641
690
|
v-for="pendingFile in pendingFiles"
|
|
642
691
|
:key="pendingFile.id"
|
|
643
692
|
:name="pendingFile.file.name"
|
|
644
|
-
:icon="getFileIcon(pendingFile
|
|
693
|
+
:icon="getFileIcon(getPendingFileMimeType(pendingFile))"
|
|
645
694
|
:meta="formatFileSize(pendingFile.file.size)"
|
|
646
695
|
remove-label="Remover anexo"
|
|
647
696
|
@remove="removeFile(pendingFile.id)"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { DeepReadonly } from 'vue';
|
|
2
2
|
import type { Message } from '../../types/schemas/chat/conversations.js';
|
|
3
|
-
import type { ConversationFile } from '../../types/schemas/chat/files.js';
|
|
3
|
+
import type { ConversationFile, FileUploadInput } from '../../types/schemas/chat/files.js';
|
|
4
4
|
import type { WorkspaceSettingsResponse as WorkspaceSettings } from '../../types/schemas/chat/workspace-settings.js';
|
|
5
|
-
import type { TelaAgentContextFile, TelaAgentInputVariable, TelaAgentSkill } from '../../types/schemas/integrations/tela-agent-api.js';
|
|
5
|
+
import type { TelaAgentContextFile, TelaAgentExecutionInput, TelaAgentInputVariable, TelaAgentSkill } from '../../types/schemas/integrations/tela-agent-api.js';
|
|
6
6
|
type __VLS_Props = {
|
|
7
7
|
disabled?: boolean;
|
|
8
8
|
loading?: boolean;
|
|
@@ -21,6 +21,11 @@ type __VLS_Props = {
|
|
|
21
21
|
showCancelButton?: boolean;
|
|
22
22
|
};
|
|
23
23
|
declare function addFiles(files: File[], inputName?: string): void;
|
|
24
|
+
declare function restoreDraft(draft: {
|
|
25
|
+
content: string;
|
|
26
|
+
files?: FileUploadInput[];
|
|
27
|
+
agentInputs?: TelaAgentExecutionInput[];
|
|
28
|
+
}): void;
|
|
24
29
|
declare function setDraft(text: string): void;
|
|
25
30
|
type __VLS_ModelProps = {
|
|
26
31
|
'selectedModel'?: string | null;
|
|
@@ -28,6 +33,7 @@ type __VLS_ModelProps = {
|
|
|
28
33
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
29
34
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
30
35
|
addFiles: typeof addFiles;
|
|
36
|
+
restoreDraft: typeof restoreDraft;
|
|
31
37
|
setDraft: typeof setDraft;
|
|
32
38
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
33
39
|
"update:selectedModel": (value: string | null) => any;
|
|
@@ -18,9 +18,6 @@ const skeletonMessages = [
|
|
|
18
18
|
function scrollToBottom() {
|
|
19
19
|
conversationRef.value?.scrollToBottom();
|
|
20
20
|
}
|
|
21
|
-
const hasPendingMessage = computed(
|
|
22
|
-
() => props.messages.some((message) => message.status === "pending")
|
|
23
|
-
);
|
|
24
21
|
watch(
|
|
25
22
|
() => [props.messages.length, props.messages.at(-1)?.content.length ?? 0],
|
|
26
23
|
scrollToBottom
|
|
@@ -36,7 +33,7 @@ onMounted(scrollToBottom);
|
|
|
36
33
|
'pt-72px pb-24px px-16px': variant === 'mobile'
|
|
37
34
|
}"
|
|
38
35
|
>
|
|
39
|
-
<TelaChatConversationContent class="max-w-700px!">
|
|
36
|
+
<TelaChatConversationContent class="max-w-700px! min-h-full">
|
|
40
37
|
<template v-if="loading">
|
|
41
38
|
<div
|
|
42
39
|
v-for="message in skeletonMessages"
|
|
@@ -59,7 +56,8 @@ onMounted(scrollToBottom);
|
|
|
59
56
|
@retry="emit('retry', $event)"
|
|
60
57
|
/>
|
|
61
58
|
<p
|
|
62
|
-
v-if="messages.length > 0
|
|
59
|
+
v-if="messages.length > 0"
|
|
60
|
+
mt-auto mb--6px
|
|
63
61
|
text-center body-11-regular text-tertiary
|
|
64
62
|
>
|
|
65
63
|
As respostas podem conter erros. Verifique documentos originais.
|
|
@@ -24,7 +24,7 @@ defineExpose({
|
|
|
24
24
|
</script>
|
|
25
25
|
|
|
26
26
|
<template>
|
|
27
|
-
<div v-if="groupedReasoning.length > 0" flex="~ col" w-full
|
|
27
|
+
<div v-if="groupedReasoning.length > 0" flex="~ col" w-full>
|
|
28
28
|
<ChatReasoningMessage
|
|
29
29
|
v-for="(step, index) in groupedReasoning"
|
|
30
30
|
:key="getStepKey(step, index)"
|