@meistrari/chat-nuxt 3.11.1 → 3.12.0-rc.1
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 +75 -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 +2 -1
- package/dist/runtime/embed/composables/use-agent-wake.js +28 -9
- 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 +289 -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 +8 -1
- package/dist/runtime/messages/composables/use-direct-stream.js +70 -11
- 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,8 @@ async function ensureConversationLoaded(conversationId) {
|
|
|
270
286
|
}
|
|
271
287
|
function resetConversation(shouldEmit = true) {
|
|
272
288
|
clearConversation();
|
|
273
|
-
|
|
289
|
+
agentWake.consume();
|
|
290
|
+
void agentWake.wake(void 0, selectedModel.value);
|
|
274
291
|
activeTab.value = "chat";
|
|
275
292
|
closeFilesPanel();
|
|
276
293
|
closePreview();
|
|
@@ -453,13 +470,54 @@ async function handleSend(content, files, agentInputs) {
|
|
|
453
470
|
const conversation = currentConversation.value;
|
|
454
471
|
if (!conversation)
|
|
455
472
|
throw new Error("Erro ao preparar conversa");
|
|
456
|
-
if (
|
|
473
|
+
if (conversation.threadSessionId && resolvedFeatures.value.chatOutboundQueue && sessionReady.value === false) {
|
|
474
|
+
if (!agentSessionRewakeable.value)
|
|
475
|
+
return { defer: true };
|
|
476
|
+
const wake = await agentWake.wake(conversation.threadSessionId, selectedModel.value);
|
|
477
|
+
if (wake.status !== "ready")
|
|
478
|
+
throw new Error("N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.");
|
|
479
|
+
return {};
|
|
480
|
+
}
|
|
481
|
+
if (!conversation.threadSessionId) {
|
|
457
482
|
await agentWake.waitUntilSettled(signal);
|
|
483
|
+
if (agentWake.state.value === "idle")
|
|
484
|
+
await agentWake.wake(void 0, selectedModel.value);
|
|
485
|
+
}
|
|
458
486
|
claimedWakeSessionId = claimableWakeSessionId();
|
|
487
|
+
if (!conversation.threadSessionId && !claimedWakeSessionId)
|
|
488
|
+
throw new Error("N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.");
|
|
459
489
|
return claimedWakeSessionId ? { wakeSessionId: claimedWakeSessionId } : {};
|
|
460
490
|
});
|
|
461
491
|
if (sent && claimedWakeSessionId)
|
|
462
492
|
agentWake.consume();
|
|
493
|
+
if (!sent)
|
|
494
|
+
restoreQueuedSend({ content, files, agentInputs: resolvedAgentInputs });
|
|
495
|
+
}
|
|
496
|
+
watch(
|
|
497
|
+
[outboundOccupied, agentWake.state],
|
|
498
|
+
async ([occupied, wakeState]) => {
|
|
499
|
+
if (!occupied)
|
|
500
|
+
return;
|
|
501
|
+
if (wakeState === "ready") {
|
|
502
|
+
const wakeSessionId = claimableWakeSessionId();
|
|
503
|
+
const sent = await flushOutboundQueue(wakeSessionId);
|
|
504
|
+
if (sent && wakeSessionId)
|
|
505
|
+
agentWake.consume();
|
|
506
|
+
} else if (wakeState === "unavailable" && (agentSessionRewakeable.value || sessionReady.value === null)) {
|
|
507
|
+
failOutboundQueue("N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.");
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
);
|
|
511
|
+
watch(
|
|
512
|
+
[outboundOccupied, agentSessionRewakeable],
|
|
513
|
+
([occupied, rewakeable]) => {
|
|
514
|
+
const sessionId = currentConversation.value?.threadSessionId;
|
|
515
|
+
if (occupied && rewakeable && sessionId && agentWake.state.value !== "waking")
|
|
516
|
+
void agentWake.wake(sessionId, selectedModel.value);
|
|
517
|
+
}
|
|
518
|
+
);
|
|
519
|
+
async function handleCancel() {
|
|
520
|
+
await cancelConversation();
|
|
463
521
|
}
|
|
464
522
|
async function handleRetry(messageId) {
|
|
465
523
|
if (!currentConversation.value?.threadSessionId)
|
|
@@ -751,7 +809,7 @@ async function handleDelete() {
|
|
|
751
809
|
:files-count="filesCount"
|
|
752
810
|
:generating-title="generatingTitle"
|
|
753
811
|
:has-messages="hasMessages"
|
|
754
|
-
:has-pending-message="
|
|
812
|
+
:has-pending-message="composerLocked"
|
|
755
813
|
:hide-settings="hideSettings"
|
|
756
814
|
:hide-sidebar="hideSidebar"
|
|
757
815
|
:is-editing="isEditing"
|
|
@@ -770,7 +828,7 @@ async function handleDelete() {
|
|
|
770
828
|
:workspace-logo="workspaceLogo"
|
|
771
829
|
:workspace-name="workspaceName"
|
|
772
830
|
:workspace-settings="effectiveWorkspaceSettings"
|
|
773
|
-
@cancel="
|
|
831
|
+
@cancel="handleCancel"
|
|
774
832
|
@cancel-editing="cancelEditing"
|
|
775
833
|
@copy-link="handleShare"
|
|
776
834
|
@debug="showDebugModal = true"
|
|
@@ -829,7 +887,7 @@ async function handleDelete() {
|
|
|
829
887
|
<ChatMessageInput
|
|
830
888
|
ref="messageInputRef"
|
|
831
889
|
v-model:selected-model="selectedModel"
|
|
832
|
-
:loading="
|
|
890
|
+
:loading="composerLocked"
|
|
833
891
|
:creator-name="currentUser?.name ?? void 0"
|
|
834
892
|
:creator-email="
|
|
835
893
|
currentConversation?.createdBy ?? currentUser?.email ?? void 0
|
|
@@ -845,7 +903,7 @@ async function handleDelete() {
|
|
|
845
903
|
:show-cancel-button="resolvedFeatures.showCancelButton"
|
|
846
904
|
centered
|
|
847
905
|
@send="handleSend"
|
|
848
|
-
@cancel="
|
|
906
|
+
@cancel="handleCancel"
|
|
849
907
|
/>
|
|
850
908
|
</template>
|
|
851
909
|
</TelaChatEmptyState>
|
|
@@ -862,7 +920,7 @@ async function handleDelete() {
|
|
|
862
920
|
<ChatMessageInput
|
|
863
921
|
ref="messageInputRef"
|
|
864
922
|
v-model:selected-model="selectedModel"
|
|
865
|
-
:loading="
|
|
923
|
+
:loading="composerLocked"
|
|
866
924
|
:creator-name="currentUser?.name ?? void 0"
|
|
867
925
|
:creator-email="
|
|
868
926
|
currentConversation?.createdBy ?? currentUser?.email ?? void 0
|
|
@@ -878,7 +936,7 @@ async function handleDelete() {
|
|
|
878
936
|
:show-cancel-button="resolvedFeatures.showCancelButton"
|
|
879
937
|
has-disclaimer
|
|
880
938
|
@send="handleSend"
|
|
881
|
-
@cancel="
|
|
939
|
+
@cancel="handleCancel"
|
|
882
940
|
/>
|
|
883
941
|
</ChatMobileShell>
|
|
884
942
|
|
|
@@ -1026,7 +1084,7 @@ async function handleDelete() {
|
|
|
1026
1084
|
<ChatMessageInput
|
|
1027
1085
|
ref="messageInputRef"
|
|
1028
1086
|
v-model:selected-model="selectedModel"
|
|
1029
|
-
:loading="
|
|
1087
|
+
:loading="composerLocked"
|
|
1030
1088
|
:creator-name="currentUser?.name ?? void 0"
|
|
1031
1089
|
:creator-email="
|
|
1032
1090
|
currentConversation?.createdBy ?? currentUser?.email ?? void 0
|
|
@@ -1042,7 +1100,7 @@ async function handleDelete() {
|
|
|
1042
1100
|
:show-cancel-button="resolvedFeatures.showCancelButton"
|
|
1043
1101
|
centered
|
|
1044
1102
|
@send="handleSend"
|
|
1045
|
-
@cancel="
|
|
1103
|
+
@cancel="handleCancel"
|
|
1046
1104
|
/>
|
|
1047
1105
|
</template>
|
|
1048
1106
|
</TelaChatEmptyState>
|
|
@@ -1062,7 +1120,7 @@ async function handleDelete() {
|
|
|
1062
1120
|
<ChatMessageInput
|
|
1063
1121
|
ref="messageInputRef"
|
|
1064
1122
|
v-model:selected-model="selectedModel"
|
|
1065
|
-
:loading="
|
|
1123
|
+
:loading="composerLocked"
|
|
1066
1124
|
:creator-name="currentUser?.name ?? void 0"
|
|
1067
1125
|
:creator-email="
|
|
1068
1126
|
currentConversation?.createdBy ?? currentUser?.email ?? void 0
|
|
@@ -1078,7 +1136,7 @@ async function handleDelete() {
|
|
|
1078
1136
|
:show-cancel-button="resolvedFeatures.showCancelButton"
|
|
1079
1137
|
has-disclaimer
|
|
1080
1138
|
@send="handleSend"
|
|
1081
|
-
@cancel="
|
|
1139
|
+
@cancel="handleCancel"
|
|
1082
1140
|
/>
|
|
1083
1141
|
</TelaChatBody>
|
|
1084
1142
|
|
|
@@ -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;
|
|
@@ -5,6 +5,7 @@ export type AgentWakeSnapshot = {
|
|
|
5
5
|
};
|
|
6
6
|
export declare function pollAgentWake(options: {
|
|
7
7
|
request: () => Promise<TelaAgentWakeResponse>;
|
|
8
|
+
requestStatus?: (sessionId: string) => Promise<TelaAgentWakeResponse>;
|
|
8
9
|
onResponse?: (response: TelaAgentWakeResponse) => void;
|
|
9
10
|
signal?: AbortSignal;
|
|
10
11
|
pollIntervalMs?: number;
|
|
@@ -15,7 +16,7 @@ export declare function pollAgentWake(options: {
|
|
|
15
16
|
export declare function useAgentWake(): {
|
|
16
17
|
state: any;
|
|
17
18
|
sessionId: any;
|
|
18
|
-
wake: (requestedSessionId?: string) => Promise<TelaAgentWakeResponse>;
|
|
19
|
+
wake: (requestedSessionId?: string, model?: string | null) => Promise<TelaAgentWakeResponse>;
|
|
19
20
|
skip: () => void;
|
|
20
21
|
consume: () => void;
|
|
21
22
|
waitUntilSettled: (signal?: AbortSignal) => Promise<AgentWakeSnapshot>;
|
|
@@ -21,21 +21,32 @@ export async function pollAgentWake(options) {
|
|
|
21
21
|
else
|
|
22
22
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
23
23
|
}));
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
let unavailableAttempts = 0;
|
|
25
|
+
let wakeSessionId;
|
|
26
|
+
while (!options.signal?.aborted && now() <= deadline) {
|
|
27
|
+
try {
|
|
28
|
+
const response = wakeSessionId && options.requestStatus ? await options.requestStatus(wakeSessionId) : await options.request();
|
|
29
|
+
wakeSessionId = response.sessionId ?? wakeSessionId;
|
|
27
30
|
options.onResponse?.(response);
|
|
31
|
+
if (response.status === "unavailable" && unavailableAttempts < 2) {
|
|
32
|
+
unavailableAttempts += 1;
|
|
33
|
+
await wait(Math.min(500 * 2 ** (unavailableAttempts - 1), Math.max(0, deadline - now())), options.signal);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
28
36
|
if (response.status !== "waking")
|
|
29
37
|
return response;
|
|
30
38
|
const remaining = deadline - now();
|
|
31
39
|
if (remaining <= 0)
|
|
32
40
|
break;
|
|
33
41
|
await wait(Math.min(options.pollIntervalMs ?? WAKE_POLL_INTERVAL_MS, remaining), options.signal);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (error instanceof DOMException && error.name === "AbortError")
|
|
44
|
+
throw error;
|
|
45
|
+
if (unavailableAttempts >= 2)
|
|
46
|
+
return { status: "unavailable" };
|
|
47
|
+
unavailableAttempts += 1;
|
|
48
|
+
await wait(Math.min(500 * 2 ** (unavailableAttempts - 1), Math.max(0, deadline - now())), options.signal);
|
|
34
49
|
}
|
|
35
|
-
} catch (error) {
|
|
36
|
-
if (error instanceof DOMException && error.name === "AbortError")
|
|
37
|
-
throw error;
|
|
38
|
-
return { status: "unavailable" };
|
|
39
50
|
}
|
|
40
51
|
return { status: "unavailable" };
|
|
41
52
|
}
|
|
@@ -67,7 +78,7 @@ export function useAgentWake() {
|
|
|
67
78
|
activeWake = null;
|
|
68
79
|
setSnapshot({ state: "idle" });
|
|
69
80
|
}
|
|
70
|
-
async function wake(requestedSessionId) {
|
|
81
|
+
async function wake(requestedSessionId, model) {
|
|
71
82
|
generation++;
|
|
72
83
|
const currentGeneration = generation;
|
|
73
84
|
abortController?.abort();
|
|
@@ -93,10 +104,18 @@ export function useAgentWake() {
|
|
|
93
104
|
method: "POST",
|
|
94
105
|
signal: controller.signal,
|
|
95
106
|
body: {
|
|
96
|
-
...wakeSessionId ? { sessionId: wakeSessionId } : {}
|
|
107
|
+
...wakeSessionId ? { sessionId: wakeSessionId } : {},
|
|
108
|
+
...model ? { model } : {}
|
|
97
109
|
}
|
|
98
110
|
})
|
|
99
111
|
),
|
|
112
|
+
requestStatus: (sessionId2) => $fetch(
|
|
113
|
+
chatApi.path(`/agent/wake/${encodeURIComponent(sessionId2)}/status`),
|
|
114
|
+
chatApi.withChatHeaders({
|
|
115
|
+
method: "GET",
|
|
116
|
+
signal: controller.signal
|
|
117
|
+
})
|
|
118
|
+
),
|
|
100
119
|
onResponse: (response) => {
|
|
101
120
|
if (currentGeneration !== generation)
|
|
102
121
|
return;
|
|
@@ -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)"
|