@meistrari/chat-nuxt 4.5.0-rc.0 → 4.5.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/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "4.5.0-rc.0",
4
+ "version": "4.5.0-rc.1",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -19,29 +19,29 @@ type __VLS_Props = {
19
19
  user?: EmbedUser | null;
20
20
  features?: Partial<ChatFeatureConfig>;
21
21
  };
22
- declare var __VLS_6: {}, __VLS_80: {}, __VLS_93: {
22
+ declare var __VLS_14: {}, __VLS_88: {}, __VLS_101: {
23
23
  message: useChatAuth;
24
- }, __VLS_105: {}, __VLS_133: {}, __VLS_142: {}, __VLS_206: {}, __VLS_225: {
24
+ }, __VLS_113: {}, __VLS_141: {}, __VLS_150: {}, __VLS_214: {}, __VLS_233: {
25
25
  message: useChatAuth;
26
- }, __VLS_237: {};
26
+ }, __VLS_245: {};
27
27
  type __VLS_Slots = {} & {
28
- 'sidebar-bottom'?: (props: typeof __VLS_6) => any;
28
+ 'sidebar-bottom'?: (props: typeof __VLS_14) => any;
29
29
  } & {
30
- 'composer-bottom'?: (props: typeof __VLS_80) => any;
30
+ 'composer-bottom'?: (props: typeof __VLS_88) => any;
31
31
  } & {
32
- 'failed-message-actions'?: (props: typeof __VLS_93) => any;
32
+ 'failed-message-actions'?: (props: typeof __VLS_101) => any;
33
33
  } & {
34
- 'composer-bottom'?: (props: typeof __VLS_105) => any;
34
+ 'composer-bottom'?: (props: typeof __VLS_113) => any;
35
35
  } & {
36
- 'topbar-leading'?: (props: typeof __VLS_133) => any;
36
+ 'topbar-leading'?: (props: typeof __VLS_141) => any;
37
37
  } & {
38
- 'topbar-leading'?: (props: typeof __VLS_142) => any;
38
+ 'topbar-leading'?: (props: typeof __VLS_150) => any;
39
39
  } & {
40
- 'composer-bottom'?: (props: typeof __VLS_206) => any;
40
+ 'composer-bottom'?: (props: typeof __VLS_214) => any;
41
41
  } & {
42
- 'failed-message-actions'?: (props: typeof __VLS_225) => any;
42
+ 'failed-message-actions'?: (props: typeof __VLS_233) => any;
43
43
  } & {
44
- 'composer-bottom'?: (props: typeof __VLS_237) => any;
44
+ 'composer-bottom'?: (props: typeof __VLS_245) => any;
45
45
  };
46
46
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
47
47
  "update:conversationId": (value: string | null) => any;
@@ -203,6 +203,7 @@ const {
203
203
  generatingTitle,
204
204
  animatedTitle,
205
205
  composerLocked,
206
+ isPolling,
206
207
  outboundOccupied,
207
208
  sessionReady,
208
209
  agentSessionRewakeable,
@@ -221,6 +222,7 @@ const {
221
222
  retryMessage,
222
223
  cancelConversation,
223
224
  startPolling,
225
+ reconnect,
224
226
  clearConversation,
225
227
  error: chatError
226
228
  } = createChat({
@@ -906,6 +908,15 @@ async function handleDelete() {
906
908
  rounded-8px bg-error text-error p-12px body-14-regular
907
909
  >
908
910
  {{ chatError }}
911
+ <TelaButton
912
+ v-if="composerLocked && !isPolling"
913
+ variant="ghost-danger"
914
+ size="sm"
915
+ icon="i-ph-arrow-clockwise"
916
+ @click="reconnect"
917
+ >
918
+ Reconectar
919
+ </TelaButton>
909
920
  </div>
910
921
  <!-- Sidebar -->
911
922
  <div
@@ -19,29 +19,29 @@ type __VLS_Props = {
19
19
  user?: EmbedUser | null;
20
20
  features?: Partial<ChatFeatureConfig>;
21
21
  };
22
- declare var __VLS_6: {}, __VLS_80: {}, __VLS_93: {
22
+ declare var __VLS_14: {}, __VLS_88: {}, __VLS_101: {
23
23
  message: useChatAuth;
24
- }, __VLS_105: {}, __VLS_133: {}, __VLS_142: {}, __VLS_206: {}, __VLS_225: {
24
+ }, __VLS_113: {}, __VLS_141: {}, __VLS_150: {}, __VLS_214: {}, __VLS_233: {
25
25
  message: useChatAuth;
26
- }, __VLS_237: {};
26
+ }, __VLS_245: {};
27
27
  type __VLS_Slots = {} & {
28
- 'sidebar-bottom'?: (props: typeof __VLS_6) => any;
28
+ 'sidebar-bottom'?: (props: typeof __VLS_14) => any;
29
29
  } & {
30
- 'composer-bottom'?: (props: typeof __VLS_80) => any;
30
+ 'composer-bottom'?: (props: typeof __VLS_88) => any;
31
31
  } & {
32
- 'failed-message-actions'?: (props: typeof __VLS_93) => any;
32
+ 'failed-message-actions'?: (props: typeof __VLS_101) => any;
33
33
  } & {
34
- 'composer-bottom'?: (props: typeof __VLS_105) => any;
34
+ 'composer-bottom'?: (props: typeof __VLS_113) => any;
35
35
  } & {
36
- 'topbar-leading'?: (props: typeof __VLS_133) => any;
36
+ 'topbar-leading'?: (props: typeof __VLS_141) => any;
37
37
  } & {
38
- 'topbar-leading'?: (props: typeof __VLS_142) => any;
38
+ 'topbar-leading'?: (props: typeof __VLS_150) => any;
39
39
  } & {
40
- 'composer-bottom'?: (props: typeof __VLS_206) => any;
40
+ 'composer-bottom'?: (props: typeof __VLS_214) => any;
41
41
  } & {
42
- 'failed-message-actions'?: (props: typeof __VLS_225) => any;
42
+ 'failed-message-actions'?: (props: typeof __VLS_233) => any;
43
43
  } & {
44
- 'composer-bottom'?: (props: typeof __VLS_237) => any;
44
+ 'composer-bottom'?: (props: typeof __VLS_245) => any;
45
45
  };
46
46
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
47
47
  "update:conversationId": (value: string | null) => any;
@@ -35,6 +35,7 @@ export declare function useChat(options?: Parameters<typeof useSharedChat>[0]):
35
35
  retryMessage: (messageId: string, prepare?: () => Promise<void>) => Promise<boolean>;
36
36
  cancelConversation: () => Promise<boolean>;
37
37
  startPolling: () => void;
38
+ reconnect: () => void;
38
39
  stopPolling: () => void;
39
40
  clearConversation: () => void;
40
41
  clearConversationThread: () => Promise<boolean>;
@@ -57,6 +57,7 @@ export declare function useChat(options?: {
57
57
  retryMessage: (messageId: string, prepare?: () => Promise<void>) => Promise<boolean>;
58
58
  cancelConversation: () => Promise<boolean>;
59
59
  startPolling: () => void;
60
+ reconnect: () => void;
60
61
  stopPolling: () => void;
61
62
  clearConversation: () => void;
62
63
  clearConversationThread: () => Promise<boolean>;
@@ -28,6 +28,12 @@ import { usePolling } from "../../shared/composables/polling.js";
28
28
  import { ChatMessageStatus, terminalMessageTransitions, useChatMessageTerminal } from "./chat-message-terminal.js";
29
29
  import { useDirectStream } from "./use-direct-stream.js";
30
30
  import { useOutboundQueue } from "./outbound-queue.js";
31
+ const POLL_OUTAGE_NOTICE_FAILURES = 5;
32
+ const POLL_OUTAGE_BUDGET_MS = 6e4;
33
+ const POLL_INTERVAL_MS = 500;
34
+ const POLL_MAX_BACKOFF_MS = 5e3;
35
+ const CHAT_REQUEST_TIMEOUT_MS = 15e3;
36
+ const CHAT_UNAVAILABLE_TEXT = "Chat temporariamente indispon\xEDvel. Tente novamente.";
31
37
  const WORKSPACE_AGENT_NOT_READY_TEXT = "O agente deste workspace ainda n\xE3o foi configurado no Tela. Abra as configura\xE7\xF5es do workspace para criar o agente.";
32
38
  export function resolveTelaAgentInputs(messageInputs, configuredInputs) {
33
39
  const inputs = messageInputs ?? configuredInputs;
@@ -241,6 +247,9 @@ export function useChat(options = {}, adapter = {}) {
241
247
  }
242
248
  }
243
249
  let pollGeneration = 0;
250
+ let consecutivePollFailures = 0;
251
+ let pollOutageStartedAt = null;
252
+ const pollInterval = ref(POLL_INTERVAL_MS);
244
253
  const pollMessages = async () => {
245
254
  if (!currentConversation.value)
246
255
  return;
@@ -251,14 +260,17 @@ export function useChat(options = {}, adapter = {}) {
251
260
  try {
252
261
  const runtime = chatApi.conversationV2Enabled ? await $fetch(
253
262
  chatApi.runtimePath(`/conversations/${conversationId}/runtime`),
254
- chatApi.withChatHeaders()
263
+ chatApi.withChatHeaders({ timeout: CHAT_REQUEST_TIMEOUT_MS, retry: 0 })
255
264
  ) : null;
256
265
  const response = await $fetch(
257
266
  chatApi.path(`/conversations/${conversationId}/messages`),
258
- chatApi.withChatHeaders()
267
+ chatApi.withChatHeaders({ timeout: CHAT_REQUEST_TIMEOUT_MS, retry: 0 })
259
268
  );
260
269
  if (generation !== pollGeneration || currentConversation.value?.id !== conversationId)
261
270
  return;
271
+ resetPollOutage();
272
+ if (error.value === CHAT_UNAVAILABLE_TEXT)
273
+ error.value = null;
262
274
  if (runtime)
263
275
  runtimeBlocked.value = runtime.conversation.runtimeState === "blocked";
264
276
  if (response.agentSession) {
@@ -332,16 +344,28 @@ export function useChat(options = {}, adapter = {}) {
332
344
  Sentry.captureException(err);
333
345
  if (generation !== pollGeneration)
334
346
  return;
335
- const errorRecord = err && typeof err === "object" ? err : null;
336
- const statusCode = typeof errorRecord?.statusCode === "number" ? errorRecord.statusCode : typeof errorRecord?.status === "number" ? errorRecord.status : typeof errorRecord?.response?.status === "number" ? errorRecord.response.status : null;
337
- if (statusCode && statusCode >= 400 && statusCode < 500 && statusCode !== 408 && statusCode !== 429) {
347
+ const statusCode = getChatApiErrorStatus(err);
348
+ const terminalError = statusCode === 501 || statusCode !== null && statusCode >= 400 && statusCode < 500 && statusCode !== 408 && statusCode !== 429;
349
+ consecutivePollFailures++;
350
+ pollOutageStartedAt ??= Date.now();
351
+ pollInterval.value = Math.min(POLL_INTERVAL_MS * 2 ** consecutivePollFailures, POLL_MAX_BACKOFF_MS);
352
+ if (!terminalError && consecutivePollFailures >= POLL_OUTAGE_NOTICE_FAILURES)
353
+ error.value = CHAT_UNAVAILABLE_TEXT;
354
+ const outageExhausted = Date.now() - pollOutageStartedAt >= POLL_OUTAGE_BUDGET_MS;
355
+ if (terminalError || outageExhausted) {
356
+ const message = statusCode === 501 || !terminalError ? CHAT_UNAVAILABLE_TEXT : getChatApiErrorMessage(err) ?? "Erro ao atualizar mensagens";
357
+ if (!terminalError || statusCode === 501 || outbound.occupied.value) {
358
+ error.value = message;
359
+ stopPolling();
360
+ return;
361
+ }
338
362
  const previousMessages = messages.value;
339
- const failedMessages = markPendingAssistantMessagesFailed(previousMessages).map((message) => {
340
- if (message.role !== "assistant" || message.status !== ChatMessageStatus.Completed || !pendingStreamReconciliationIds.value.has(message.id)) {
341
- return message;
363
+ const failedMessages = markPendingAssistantMessagesFailed(previousMessages).map((message2) => {
364
+ if (message2.role !== "assistant" || message2.status !== ChatMessageStatus.Completed || !pendingStreamReconciliationIds.value.has(message2.id)) {
365
+ return message2;
342
366
  }
343
367
  return {
344
- ...message,
368
+ ...message2,
345
369
  content: GENERATION_FAILED_TEXT,
346
370
  status: ChatMessageStatus.Failed
347
371
  };
@@ -352,20 +376,30 @@ export function useChat(options = {}, adapter = {}) {
352
376
  messages.value = failedMessages;
353
377
  for (const terminalMessage of terminalMessages)
354
378
  chatMessageTerminal.emit(terminalMessage);
355
- error.value = getChatApiErrorMessage(err) ?? "Erro ao atualizar mensagens";
379
+ error.value = message;
356
380
  stopPolling();
357
381
  }
358
382
  }
359
383
  };
360
384
  const { isPolling, start: beginPolling, stop: endPolling } = usePolling({
361
385
  callback: pollMessages,
362
- interval: 500,
386
+ interval: pollInterval,
363
387
  stopCondition
364
388
  });
389
+ function resetPollOutage() {
390
+ consecutivePollFailures = 0;
391
+ pollOutageStartedAt = null;
392
+ pollInterval.value = POLL_INTERVAL_MS;
393
+ }
365
394
  function startPolling() {
395
+ resetPollOutage();
366
396
  pollGeneration++;
367
397
  beginPolling();
368
398
  }
399
+ function reconnect() {
400
+ error.value = null;
401
+ startPolling();
402
+ }
369
403
  function stopPolling() {
370
404
  pollGeneration++;
371
405
  endPolling();
@@ -614,7 +648,7 @@ export function useChat(options = {}, adapter = {}) {
614
648
  v2AdmissionRequested = true;
615
649
  const accepted = await $fetch(
616
650
  chatApi.runtimePath(`/conversations/${conversationId2}/messages`),
617
- chatApi.withChatHeaders({ method: "POST", body: v2Body, retry: 1 })
651
+ chatApi.withChatHeaders({ method: "POST", body: v2Body, retry: 1, timeout: CHAT_REQUEST_TIMEOUT_MS })
618
652
  );
619
653
  response = accepted;
620
654
  if (currentConversation.value?.id !== conversationId2)
@@ -661,7 +695,7 @@ export function useChat(options = {}, adapter = {}) {
661
695
  } catch (err) {
662
696
  const code = getChatApiErrorCode(err);
663
697
  const status = getChatApiErrorStatus(err);
664
- if (v2AdmissionRequested && !controller.signal.aborted && (status === null || status === 408 || status === 429 || status >= 500)) {
698
+ if (v2AdmissionRequested && !controller.signal.aborted && (status === null || status === 408 || status === 429 || status >= 500 && status !== 501)) {
665
699
  const attempts = (queuedSend?.attempts ?? 0) + 1;
666
700
  const queuedAt = queuedSend?.queuedAt ?? Date.now();
667
701
  if (outboundQueueEnabled.value) {
@@ -1029,6 +1063,7 @@ export function useChat(options = {}, adapter = {}) {
1029
1063
  retryMessage,
1030
1064
  cancelConversation,
1031
1065
  startPolling,
1066
+ reconnect,
1032
1067
  stopPolling,
1033
1068
  clearConversation,
1034
1069
  clearConversationThread,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
- "version": "4.5.0-rc.0",
3
+ "version": "4.5.0-rc.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {