@meistrari/chat-nuxt 3.9.2 → 3.11.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.
Files changed (106) hide show
  1. package/README.md +50 -440
  2. package/dist/module.d.mts +1 -1
  3. package/dist/module.json +1 -1
  4. package/dist/runtime/assets/css/markstream.css +1 -1
  5. package/dist/runtime/conversations/components/chat-conversation-creator-filter.vue +11 -67
  6. package/dist/runtime/conversations/components/chat-conversation-item.d.vue.ts +2 -1
  7. package/dist/runtime/conversations/components/chat-conversation-item.vue +29 -33
  8. package/dist/runtime/conversations/components/chat-conversation-item.vue.d.ts +2 -1
  9. package/dist/runtime/conversations/components/chat-conversation-list.d.vue.ts +0 -1
  10. package/dist/runtime/conversations/components/chat-conversation-list.vue +117 -158
  11. package/dist/runtime/conversations/components/chat-conversation-list.vue.d.ts +0 -1
  12. package/dist/runtime/conversations/components/chat-conversation-new-group-button.vue +34 -73
  13. package/dist/runtime/conversations/components/chat-conversation-search.vue +1 -21
  14. package/dist/runtime/conversations/components/chat-widget-history-list.d.vue.ts +12 -0
  15. package/dist/runtime/conversations/components/chat-widget-history-list.vue +27 -0
  16. package/dist/runtime/conversations/components/chat-widget-history-list.vue.d.ts +12 -0
  17. package/dist/runtime/conversations/composables/conversation-groups.d.ts +1 -0
  18. package/dist/runtime/conversations/composables/conversation-groups.js +2 -0
  19. package/dist/runtime/conversations/composables/conversation-item.js +4 -4
  20. package/dist/runtime/conversations/composables/conversation-list.js +14 -5
  21. package/dist/runtime/embed/components/chat-configuration-modal.d.vue.ts +3 -3
  22. package/dist/runtime/embed/components/chat-configuration-modal.vue.d.ts +3 -3
  23. package/dist/runtime/embed/components/chat-embed-inner.d.vue.ts +6 -3
  24. package/dist/runtime/embed/components/chat-embed-inner.vue +442 -174
  25. package/dist/runtime/embed/components/chat-embed-inner.vue.d.ts +6 -3
  26. package/dist/runtime/embed/components/chat-embed.d.vue.ts +31 -4
  27. package/dist/runtime/embed/components/chat-embed.vue +10 -4
  28. package/dist/runtime/embed/components/chat-embed.vue.d.ts +31 -4
  29. package/dist/runtime/embed/components/chat-topbar.vue +83 -85
  30. package/dist/runtime/embed/components/meistrari-chat-embed.d.vue.ts +5 -3
  31. package/dist/runtime/embed/components/meistrari-chat-embed.vue +118 -57
  32. package/dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts +5 -3
  33. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.d.vue.ts +0 -1
  34. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue +2 -45
  35. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue.d.ts +0 -1
  36. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.d.vue.ts +9 -5
  37. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.vue +14 -25
  38. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.vue.d.ts +9 -5
  39. package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +4 -4
  40. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue +2 -4
  41. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +4 -4
  42. package/dist/runtime/embed/composables/use-agent-wake.d.ts +23 -0
  43. package/dist/runtime/embed/composables/use-agent-wake.js +182 -0
  44. package/dist/runtime/embed/feature-config.d.ts +7 -0
  45. package/dist/runtime/embed/feature-config.js +2 -1
  46. package/dist/runtime/embed/loading-messages.d.ts +16 -0
  47. package/dist/runtime/embed/loading-messages.js +10 -0
  48. package/dist/runtime/embed/types.d.ts +47 -8
  49. package/dist/runtime/files/icons.d.ts +1 -1
  50. package/dist/runtime/files/icons.js +1 -1
  51. package/dist/runtime/messages/components/chat-mention-dropdown.d.vue.ts +6 -1
  52. package/dist/runtime/messages/components/chat-mention-dropdown.vue +46 -22
  53. package/dist/runtime/messages/components/chat-mention-dropdown.vue.d.ts +6 -1
  54. package/dist/runtime/messages/components/chat-message-bubble.d.vue.ts +10 -1
  55. package/dist/runtime/messages/components/chat-message-bubble.vue +69 -76
  56. package/dist/runtime/messages/components/chat-message-bubble.vue.d.ts +10 -1
  57. package/dist/runtime/messages/components/chat-message-feedback.vue +25 -229
  58. package/dist/runtime/messages/components/chat-message-input.vue +176 -134
  59. package/dist/runtime/messages/components/chat-message-list.d.vue.ts +12 -1
  60. package/dist/runtime/messages/components/chat-message-list.vue +37 -24
  61. package/dist/runtime/messages/components/chat-message-list.vue.d.ts +12 -1
  62. package/dist/runtime/messages/components/chat-model-selector.vue +10 -22
  63. package/dist/runtime/messages/components/reasoning/chat-reasoning-message.vue +2 -3
  64. package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.d.vue.ts +2 -1
  65. package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue +69 -77
  66. package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue.d.ts +2 -1
  67. package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.vue +3 -9
  68. package/dist/runtime/messages/components/widgets/chat-bash-widget.vue +3 -12
  69. package/dist/runtime/messages/components/widgets/chat-doc-sdk-widget.vue +3 -12
  70. package/dist/runtime/messages/components/widgets/chat-generic-tool-widget.vue +3 -12
  71. package/dist/runtime/messages/components/widgets/chat-grep-widget.vue +7 -17
  72. package/dist/runtime/messages/components/widgets/chat-read-widget.vue +7 -17
  73. package/dist/runtime/messages/components/widgets/chat-tela-skill-widget.vue +4 -13
  74. package/dist/runtime/messages/components/widgets/chat-thinking-widget.vue +11 -22
  75. package/dist/runtime/messages/components/widgets/chat-web-search-widget.vue +13 -40
  76. package/dist/runtime/messages/components/widgets/chat-workstation-query-widget.vue +52 -65
  77. package/dist/runtime/messages/components/widgets/chat-write-widget.vue +8 -18
  78. package/dist/runtime/messages/composables/chat.d.ts +8 -2
  79. package/dist/runtime/messages/composables/chat.js +180 -25
  80. package/dist/runtime/messages/composables/mention-autocomplete.js +4 -0
  81. package/dist/runtime/messages/composables/use-direct-stream.d.ts +41 -0
  82. package/dist/runtime/messages/composables/use-direct-stream.js +263 -0
  83. package/dist/runtime/messages/message-state.js +1 -0
  84. package/dist/runtime/messages/reasoning.d.ts +7 -0
  85. package/dist/runtime/messages/reasoning.js +5 -0
  86. package/dist/runtime/public/files/generic.svg +2 -5
  87. package/dist/runtime/public/files/image.svg +2 -1
  88. package/dist/runtime/types/embed.d.ts +1 -1
  89. package/dist/runtime/types/schemas/chat/conversations.d.ts +4 -0
  90. package/dist/runtime/types/schemas/chat/conversations.js +3 -0
  91. package/dist/runtime/types/schemas/chat/messages.d.ts +43 -0
  92. package/dist/runtime/types/schemas/chat/messages.js +31 -0
  93. package/dist/runtime/types/schemas/chat/models.d.ts +3 -2
  94. package/dist/runtime/types/schemas/chat/models.js +2 -1
  95. package/dist/runtime/types/schemas/chat/ui.d.ts +10 -0
  96. package/dist/runtime/types/schemas/chat/ui.js +1 -0
  97. package/dist/runtime/types/schemas/integrations/tela-agent-api.d.ts +35 -0
  98. package/dist/runtime/types/schemas/integrations/tela-agent-api.js +17 -0
  99. package/dist/types.d.mts +1 -1
  100. package/package.json +5 -4
  101. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.d.vue.ts +0 -23
  102. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.vue +0 -75
  103. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.vue.d.ts +0 -23
  104. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.d.vue.ts +0 -37
  105. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.vue +0 -125
  106. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.vue.d.ts +0 -37
@@ -8,13 +8,17 @@ import ChatMobileShell from "./mobile/chat-mobile-shell.vue";
8
8
  import { normalizeConversationId } from "../../conversations/scope";
9
9
  import { resolveChatFeatures } from "../feature-config";
10
10
  import { resolveConversationCreator } from "../../conversations/creator";
11
- import { resolveTelaAgentInputs, useChat } from "../../messages/composables/chat";
11
+ import {
12
+ resolveTelaAgentInputs,
13
+ useChat
14
+ } from "../../messages/composables/chat";
12
15
  import { useChatAction } from "../../messages/composables/chat-action";
13
16
  import { useChatApi } from "../../shared/composables/chat-api";
14
17
  import { useConversationFiles } from "../../files/composables/conversation-files";
15
18
  import { useConversationFilesPanel } from "../../files/composables/conversation-files-panel";
16
19
  import { useConversations } from "../../conversations/composables/conversations";
17
20
  import { useEmbedConfig } from "../composables/embed-config";
21
+ import { useAgentWake } from "../composables/use-agent-wake";
18
22
  import { useFileDrop } from "../../files/composables/file-drop";
19
23
  import { useFilePreviewPanel } from "../../files/composables/file-preview-panel";
20
24
  import { usePendingConversationGroup } from "../../conversations/composables/pending-conversation-group";
@@ -30,17 +34,22 @@ const props = defineProps({
30
34
  hideSidebar: { type: Boolean, required: false, default: true },
31
35
  sidebar: { type: Object, required: false },
32
36
  hideSettings: { type: Boolean, required: false, default: false },
33
- hideFolderHint: { type: Boolean, required: false, default: false },
37
+ compact: { type: Boolean, required: false, default: false },
38
+ suggestions: { type: [Array, null], required: false },
34
39
  user: { type: [Object, null], required: false },
35
40
  features: { type: Object, required: false }
36
41
  });
37
- const emit = defineEmits(["update:conversationId"]);
42
+ const emit = defineEmits(["update:conversationId", "update:conversationTitle"]);
38
43
  const sidebarPosition = computed(() => props.sidebar?.position ?? "left");
39
44
  const sidebarWidth = computed(() => props.sidebar?.width ?? 240);
40
- const sidebarBottomHeight = computed(() => Math.min(100, Math.max(0, props.sidebar?.bottomHeight ?? 50)));
45
+ const sidebarBottomHeight = computed(
46
+ () => Math.min(100, Math.max(0, props.sidebar?.bottomHeight ?? 50))
47
+ );
41
48
  const sidebarCollapsible = computed(() => props.sidebar?.collapsible ?? false);
42
49
  const isSidebarCollapsed = ref(props.sidebar?.defaultCollapsed ?? false);
43
- const sidebarCollapsed = computed(() => sidebarCollapsible.value && isSidebarCollapsed.value);
50
+ const sidebarCollapsed = computed(
51
+ () => sidebarCollapsible.value && isSidebarCollapsed.value
52
+ );
44
53
  const sidebarToggleIcon = computed(() => {
45
54
  const pointsRight = sidebarPosition.value === "right" ? !sidebarCollapsed.value : sidebarCollapsed.value;
46
55
  return pointsRight ? "i-ph-caret-right" : "i-ph-caret-left";
@@ -54,12 +63,32 @@ const chatAction = useChatAction();
54
63
  const { user: authUser, activeOrganization, logout } = useChatAuth();
55
64
  const { getMember, getMemberImage } = useWorkspaceMembers();
56
65
  const statusToast = useStatusToast();
57
- const { conversations, loading: conversationsLoading, fetchConversations, createConversation, deleteConversation, renameConversation, updateConversationModel, duplicateConversation, moveConversationToGroup, updateConversationInList } = useConversations();
66
+ const {
67
+ conversations,
68
+ loading: conversationsLoading,
69
+ fetchConversations,
70
+ createConversation,
71
+ deleteConversation,
72
+ renameConversation,
73
+ updateConversationModel,
74
+ duplicateConversation,
75
+ moveConversationToGroup,
76
+ updateConversationInList
77
+ } = useConversations();
58
78
  const { settings: workspaceSettingsState, fetchSettings } = useWorkspaceSettings();
59
- const { metadata: telaAgentMetadata, loading: telaAgentMetadataLoading, fetchAgentMetadata } = useTelaAgentMetadata();
60
- const { summary: workspaceAgentSummary, fetchSummary: fetchWorkspaceAgentSummary } = useWorkspaceAgentSummary();
79
+ const {
80
+ metadata: telaAgentMetadata,
81
+ loading: telaAgentMetadataLoading,
82
+ fetchAgentMetadata
83
+ } = useTelaAgentMetadata();
84
+ const {
85
+ summary: workspaceAgentSummary,
86
+ fetchSummary: fetchWorkspaceAgentSummary
87
+ } = useWorkspaceAgentSummary();
61
88
  const isTelaAgentMode = computed(() => !!embedConfig?.telaAgentId.value);
62
- const hasConfiguredTelaAgentInputs = computed(() => embedConfig?.telaAgentInputs?.value !== void 0 && embedConfig?.telaAgentInputs?.value !== null);
89
+ const hasConfiguredTelaAgentInputs = computed(
90
+ () => embedConfig?.telaAgentInputs?.value !== void 0 && embedConfig?.telaAgentInputs?.value !== null
91
+ );
63
92
  const shouldLoadTelaAgentMetadata = computed(() => isTelaAgentMode.value);
64
93
  const telaAgentInputSchema = computed(
65
94
  () => hasConfiguredTelaAgentInputs.value ? null : isTelaAgentMode.value ? telaAgentMetadata.value?.inputSchema ?? [] : null
@@ -80,7 +109,12 @@ const effectiveWorkspaceSettings = computed(() => {
80
109
  return embedConfig?.workspaceSettings.value !== void 0 ? embedConfig.workspaceSettings.value : workspaceSettingsState.value;
81
110
  });
82
111
  const { closePanel: closeFilesPanel } = useConversationFilesPanel();
83
- const { isOpen: isPreviewPanelOpen, panelWidth: previewPanelWidth, currentFile: currentPreviewFile, closePreview } = useFilePreviewPanel();
112
+ const {
113
+ isOpen: isPreviewPanelOpen,
114
+ panelWidth: previewPanelWidth,
115
+ currentFile: currentPreviewFile,
116
+ closePreview
117
+ } = useFilePreviewPanel();
84
118
  const { isOpen: isCitationPanelOpen } = useCitationPanel();
85
119
  const activeConversationId = ref(
86
120
  normalizeConversationId(props.conversationId) ?? normalizeConversationId(props.initialConversationId)
@@ -96,6 +130,16 @@ const resolvedFeatures = computed(() => resolveChatFeatures(props.features));
96
130
  const dropZoneRef = ref(null);
97
131
  const activeTab = ref("chat");
98
132
  const messageInputRef = ref(null);
133
+ const PROMPT_INPUT_HINTS = [
134
+ { icon: "i-ph-at-bold", label: "Para mencionar arquivos" },
135
+ { char: "/", label: "Para acionar skills" }
136
+ ];
137
+ const resolvedSuggestions = computed(
138
+ () => props.suggestions ?? []
139
+ );
140
+ function applySuggestion(prompt) {
141
+ messageInputRef.value?.setDraft(prompt);
142
+ }
99
143
  const breakpoints = useBreakpoints({ mobile: CHAT_MOBILE_BREAKPOINT });
100
144
  const isMobile = breakpoints.smaller("mobile");
101
145
  const drawerOpen = ref(false);
@@ -112,16 +156,26 @@ const {
112
156
  generatingTitle,
113
157
  animatedTitle,
114
158
  hasPendingMessage,
159
+ streamingActiveMessageId,
160
+ preparingSteps,
115
161
  loadConversation,
116
162
  setConversation,
163
+ adoptConversation,
117
164
  setConversationModel,
118
165
  pendingModelSelection,
119
166
  sendMessage,
120
167
  retryMessage,
121
168
  cancelConversation,
122
169
  startPolling,
123
- clearConversation
170
+ clearConversation,
171
+ error: chatError
124
172
  } = useChat();
173
+ const agentWake = useAgentWake();
174
+ const modelUpdateInFlight = ref(null);
175
+ watch(chatError, (message) => {
176
+ if (message)
177
+ statusToast.update({ text: message, icon: "i-ph-warning" });
178
+ });
125
179
  const conversationIdRef = computed(() => currentConversation.value?.id ?? null);
126
180
  const { total, files: conversationFiles } = useConversationFiles(conversationIdRef);
127
181
  const selectedModel = computed({
@@ -132,13 +186,24 @@ const selectedModel = computed({
132
186
  if (conversation && conversation.model !== value) {
133
187
  const previousModel = conversation.model;
134
188
  setConversationModel(value);
135
- void updateConversationModel(conversation.id, value).then((updated) => {
136
- if (!updated && currentConversation.value?.id === conversation.id && currentConversation.value.model === value)
189
+ const update = updateConversationModel(conversation.id, value).then((updated) => {
190
+ if (!updated && currentConversation.value?.id === conversation.id && currentConversation.value.model === value) {
137
191
  setConversationModel(previousModel);
192
+ }
193
+ return updated;
194
+ });
195
+ modelUpdateInFlight.value = update.finally(() => {
196
+ if (modelUpdateInFlight.value === update)
197
+ modelUpdateInFlight.value = null;
138
198
  });
139
199
  }
140
200
  }
141
201
  });
202
+ watch(selectedModel, (model, previousModel) => {
203
+ if (!isReady.value || model === previousModel || currentConversation.value?.threadSessionId)
204
+ return;
205
+ void agentWake.wake(model);
206
+ });
142
207
  const filesCount = computed(() => total.value);
143
208
  const hasMessages = computed(() => messages.value.length > 0);
144
209
  const mobilePreviewFile = computed(() => {
@@ -154,10 +219,16 @@ const mobilePreviewFile = computed(() => {
154
219
  size: file.fileSize
155
220
  };
156
221
  });
157
- const visibleTelaAgentInputSchema = computed(() => !hasMessages.value ? telaAgentInputSchema.value : null);
158
- const visibleTelaAgentInputSchemaLoading = computed(() => !hasMessages.value && isTelaAgentMode.value && !hasConfiguredTelaAgentInputs.value && telaAgentMetadataLoading.value);
222
+ const visibleTelaAgentInputSchema = computed(
223
+ () => !hasMessages.value ? telaAgentInputSchema.value : null
224
+ );
225
+ const visibleTelaAgentInputSchemaLoading = computed(
226
+ () => !hasMessages.value && isTelaAgentMode.value && !hasConfiguredTelaAgentInputs.value && telaAgentMetadataLoading.value
227
+ );
159
228
  const visibleConversations = computed(
160
- () => conversations.value.filter((conversation) => conversation.title || conversation.id === activeConversationId.value)
229
+ () => conversations.value.filter(
230
+ (conversation) => conversation.title || conversation.id === activeConversationId.value
231
+ )
161
232
  );
162
233
  function syncConversationId(nextConversationId) {
163
234
  activeConversationId.value = normalizeConversationId(nextConversationId);
@@ -172,6 +243,10 @@ function updateConversationId(nextConversationId) {
172
243
  }
173
244
  async function ensureConversationLoaded(conversationId) {
174
245
  if (currentConversation.value?.id === conversationId) {
246
+ void agentWake.wake(
247
+ currentConversation.value.model,
248
+ currentConversation.value.threadSessionId ?? void 0
249
+ );
175
250
  startPolling();
176
251
  return;
177
252
  }
@@ -182,9 +257,17 @@ async function ensureConversationLoaded(conversationId) {
182
257
  try {
183
258
  await loadConversation(conversationId);
184
259
  if (currentConversation.value?.id !== conversationId) {
185
- statusToast.update({ text: "Erro ao carregar conversa", icon: "i-ph-warning" });
260
+ agentWake.skip();
261
+ statusToast.update({
262
+ text: "Erro ao carregar conversa",
263
+ icon: "i-ph-warning"
264
+ });
186
265
  return;
187
266
  }
267
+ void agentWake.wake(
268
+ currentConversation.value.model,
269
+ currentConversation.value.threadSessionId ?? void 0
270
+ );
188
271
  startPolling();
189
272
  } finally {
190
273
  if (loadingConversationId.value === conversationId) {
@@ -194,6 +277,7 @@ async function ensureConversationLoaded(conversationId) {
194
277
  }
195
278
  function resetConversation(shouldEmit = true) {
196
279
  clearConversation();
280
+ void agentWake.wake(selectedModel.value);
197
281
  activeTab.value = "chat";
198
282
  closeFilesPanel();
199
283
  closePreview();
@@ -215,29 +299,32 @@ async function openConversation(nextConversationId) {
215
299
  updateConversationId(normalizedConversationId);
216
300
  await ensureConversationLoaded(normalizedConversationId);
217
301
  }
218
- watch(() => props.conversationId, async (nextConversationId) => {
219
- if (nextConversationId === void 0) {
220
- return;
221
- }
222
- const normalizedConversationId = normalizeConversationId(nextConversationId);
223
- if (normalizedConversationId) {
224
- clearPendingConversationGroup();
225
- }
226
- if (!isReady.value) {
302
+ watch(
303
+ () => props.conversationId,
304
+ async (nextConversationId) => {
305
+ if (nextConversationId === void 0) {
306
+ return;
307
+ }
308
+ const normalizedConversationId = normalizeConversationId(nextConversationId);
309
+ if (normalizedConversationId) {
310
+ clearPendingConversationGroup();
311
+ }
312
+ if (!isReady.value) {
313
+ syncConversationId(normalizedConversationId);
314
+ return;
315
+ }
316
+ if (normalizedConversationId === activeConversationId.value && currentConversation.value?.id === normalizedConversationId) {
317
+ return;
318
+ }
319
+ if (!normalizedConversationId) {
320
+ resetConversation(false);
321
+ return;
322
+ }
227
323
  syncConversationId(normalizedConversationId);
228
- return;
229
- }
230
- if (normalizedConversationId === activeConversationId.value && currentConversation.value?.id === normalizedConversationId) {
231
- return;
232
- }
233
- if (!normalizedConversationId) {
234
- resetConversation(false);
235
- return;
324
+ closePreview();
325
+ await ensureConversationLoaded(normalizedConversationId);
236
326
  }
237
- syncConversationId(normalizedConversationId);
238
- closePreview();
239
- await ensureConversationLoaded(normalizedConversationId);
240
- });
327
+ );
241
328
  onMounted(async () => {
242
329
  void fetchConversations();
243
330
  if (shouldLoadTelaAgentMetadata.value) {
@@ -277,23 +364,34 @@ const isSettingsOutdated = computed(() => {
277
364
  if (!rawAppliedAt)
278
365
  return false;
279
366
  const appliedAt = new Date(rawAppliedAt).getTime();
280
- const updatedAt = new Date(effectiveWorkspaceSettings.value.updatedAt).getTime();
367
+ const updatedAt = new Date(
368
+ effectiveWorkspaceSettings.value.updatedAt
369
+ ).getTime();
281
370
  return appliedAt < updatedAt;
282
371
  });
283
372
  const isBannerDismissed = computed(
284
373
  () => currentConversation.value ? dismissedChats.value.has(currentConversation.value.id) : false
285
374
  );
286
- const showOutdatedBanner = computed(() => isSettingsOutdated.value && !isBannerDismissed.value);
287
- const showOutdatedBadge = computed(() => isSettingsOutdated.value && isBannerDismissed.value);
375
+ const showOutdatedBanner = computed(
376
+ () => isSettingsOutdated.value && !isBannerDismissed.value
377
+ );
378
+ const showOutdatedBadge = computed(
379
+ () => isSettingsOutdated.value && isBannerDismissed.value
380
+ );
288
381
  function dismissOutdatedBanner() {
289
382
  if (!currentConversation.value)
290
383
  return;
291
384
  dismissedChats.value.delete(currentConversation.value.id);
292
385
  dismissedChats.value.add(currentConversation.value.id);
293
386
  const nextDismissedChats = [...dismissedChats.value];
294
- dismissedChats.value = new Set(nextDismissedChats.slice(-MAX_DISMISSED_CHAT_IDS));
387
+ dismissedChats.value = new Set(
388
+ nextDismissedChats.slice(-MAX_DISMISSED_CHAT_IDS)
389
+ );
295
390
  try {
296
- localStorage.setItem(dismissedStorageKey.value, JSON.stringify([...dismissedChats.value]));
391
+ localStorage.setItem(
392
+ dismissedStorageKey.value,
393
+ JSON.stringify([...dismissedChats.value])
394
+ );
297
395
  } catch {
298
396
  }
299
397
  }
@@ -306,7 +404,10 @@ const displayTitle = computed(() => {
306
404
  return currentConversation.value?.title ?? "";
307
405
  });
308
406
  watch(
309
- () => [currentConversation.value?.id ?? null, currentConversation.value?.title ?? null],
407
+ () => [
408
+ currentConversation.value?.id ?? null,
409
+ currentConversation.value?.title ?? null
410
+ ],
310
411
  ([conversationId, conversationTitle], [previousConversationId, previousTitle]) => {
311
412
  if (conversationId !== previousConversationId) {
312
413
  optimisticTitle.value = null;
@@ -320,6 +421,13 @@ watch(
320
421
  }
321
422
  }
322
423
  );
424
+ watch(
425
+ () => currentConversation.value?.title ?? null,
426
+ (title) => {
427
+ emit("update:conversationTitle", title);
428
+ },
429
+ { immediate: true }
430
+ );
323
431
  const currentUser = computed(() => props.user ?? authUser.value ?? null);
324
432
  const conversationCreator = computed(
325
433
  () => resolveConversationCreator(currentConversation.value?.userId, {
@@ -327,36 +435,55 @@ const conversationCreator = computed(
327
435
  getMember
328
436
  })
329
437
  );
438
+ function claimableWakeSessionId() {
439
+ return agentWake.state.value === "ready" && !currentConversation.value?.threadSessionId ? agentWake.sessionId.value : void 0;
440
+ }
330
441
  async function handleSend(content, files, agentInputs) {
331
- let createdConversationId = null;
332
442
  const resolvedAgentInputs = resolveTelaAgentInputs(agentInputs, embedConfig?.telaAgentInputs?.value);
333
- if (!activeConversationId.value || !currentConversation.value) {
334
- const conversation = await createConversation({
335
- model: selectedModel.value,
336
- ...resolvedAgentInputs !== void 0 ? { agentInputs: resolvedAgentInputs } : {}
337
- });
443
+ let claimedWakeSessionId;
444
+ const sent = await sendMessage(content, files.length > 0 ? files : void 0, resolvedAgentInputs, async (signal) => {
445
+ if (!activeConversationId.value || !currentConversation.value) {
446
+ const conversation2 = await createConversation({
447
+ model: selectedModel.value,
448
+ ...resolvedAgentInputs !== void 0 ? { agentInputs: resolvedAgentInputs } : {}
449
+ });
450
+ if (!conversation2)
451
+ throw new Error("Erro ao criar conversa");
452
+ const groupId = pendingConversationGroupId.value;
453
+ clearPendingConversationGroup();
454
+ const grouped = groupId && await moveConversationToGroup(conversation2.id, groupId);
455
+ adoptConversation(grouped ? { ...conversation2, groupId } : conversation2);
456
+ updateConversationId(conversation2.id);
457
+ }
458
+ if (modelUpdateInFlight.value)
459
+ await modelUpdateInFlight.value;
460
+ const conversation = currentConversation.value;
338
461
  if (!conversation)
339
- return;
340
- const groupId = pendingConversationGroupId.value;
341
- clearPendingConversationGroup();
342
- if (groupId && await moveConversationToGroup(conversation.id, groupId)) {
343
- const groupedConversation = { ...conversation, groupId };
344
- setConversation(groupedConversation);
462
+ throw new Error("Erro ao preparar conversa");
463
+ if (conversation.threadSessionId) {
464
+ await agentWake.wake(
465
+ conversation.model,
466
+ conversation.threadSessionId
467
+ );
345
468
  } else {
346
- setConversation(conversation);
469
+ await agentWake.waitUntilSettled(signal);
347
470
  }
348
- createdConversationId = conversation.id;
349
- }
350
- if (!currentConversation.value)
351
- return;
352
- const sendPromise = sendMessage(content, files.length > 0 ? files : void 0, resolvedAgentInputs);
353
- if (createdConversationId) {
354
- updateConversationId(createdConversationId);
355
- }
356
- await sendPromise;
471
+ claimedWakeSessionId = claimableWakeSessionId();
472
+ return claimedWakeSessionId ? { wakeSessionId: claimedWakeSessionId } : {};
473
+ });
474
+ if (sent && claimedWakeSessionId)
475
+ agentWake.consume();
357
476
  }
358
477
  async function handleRetry(messageId) {
359
- await retryMessage(messageId);
478
+ if (currentConversation.value?.threadSessionId) {
479
+ await agentWake.wake(
480
+ currentConversation.value.model,
481
+ currentConversation.value.threadSessionId
482
+ );
483
+ } else {
484
+ await agentWake.waitUntilSettled();
485
+ }
486
+ await retryMessage(messageId, claimableWakeSessionId());
360
487
  }
361
488
  async function handleNewConversation(groupId) {
362
489
  setPendingConversationGroup(groupId);
@@ -387,8 +514,12 @@ async function handleSignout() {
387
514
  chatAction.emit("signout");
388
515
  await logout();
389
516
  }
390
- const workspaceName = computed(() => activeOrganization.value?.name ?? "Workspace");
391
- const workspaceLogo = computed(() => activeOrganization.value?.logo ?? void 0);
517
+ const workspaceName = computed(
518
+ () => activeOrganization.value?.name ?? "Workspace"
519
+ );
520
+ const workspaceLogo = computed(
521
+ () => activeOrganization.value?.logo ?? void 0
522
+ );
392
523
  function handleTabChange(tab) {
393
524
  activeTab.value = tab;
394
525
  if (tab === "chat")
@@ -398,7 +529,9 @@ const isEditing = ref(false);
398
529
  const editTitle = ref("");
399
530
  const justStartedEditing = ref(false);
400
531
  const showDebugModal = ref(false);
401
- const debugSessionId = computed(() => currentConversation.value?.threadSessionId ?? "Sess\xE3o ainda n\xE3o criada");
532
+ const debugSessionId = computed(
533
+ () => currentConversation.value?.threadSessionId ?? "Sess\xE3o ainda n\xE3o criada"
534
+ );
402
535
  async function copyDebugInfo() {
403
536
  const conversation = currentConversation.value;
404
537
  const conversationId = conversation?.id ?? activeConversationId.value;
@@ -422,7 +555,10 @@ async function copyDebugInfo() {
422
555
  await navigator.clipboard.writeText(JSON.stringify(debugInfo, null, 2));
423
556
  statusToast.update({ text: "Dados de debug copiados", icon: "i-ph-check" });
424
557
  } catch {
425
- statusToast.update({ text: "Erro ao copiar dados de debug", icon: "i-ph-warning" });
558
+ statusToast.update({
559
+ text: "Erro ao copiar dados de debug",
560
+ icon: "i-ph-warning"
561
+ });
426
562
  }
427
563
  }
428
564
  function startEditing() {
@@ -439,7 +575,10 @@ async function saveTitle() {
439
575
  const trimmed = editTitle.value.trim();
440
576
  if (trimmed && trimmed !== currentConversation.value?.title && currentConversation.value) {
441
577
  optimisticTitle.value = trimmed;
442
- const success = await renameConversation(currentConversation.value.id, trimmed);
578
+ const success = await renameConversation(
579
+ currentConversation.value.id,
580
+ trimmed
581
+ );
443
582
  if (!success)
444
583
  optimisticTitle.value = null;
445
584
  }
@@ -510,27 +649,48 @@ async function handleDelete() {
510
649
  sidebarCollapsed ? 'chat-sidebar--collapsed' : ''
511
650
  ]"
512
651
  :style="{ '--chat-sidebar-width': `${sidebarWidth}px` }"
513
- h-full flex-shrink-0 relative
652
+ h-full
653
+ flex-shrink-0
654
+ relative
514
655
  >
515
656
  <div class="chat-sidebar__clip">
516
657
  <div
517
658
  class="chat-sidebar__panel"
518
659
  :inert="sidebarCollapsed || void 0"
519
- h-full flex="~ col"
660
+ h-full
661
+ flex="~ col"
520
662
  bg-neutral-50
521
663
  :style="{ width: `${sidebarWidth}px` }"
522
- :class="sidebarPosition === 'right' ? 'border-l-0.5px border-l-neutral-200' : 'border-r-0.5px border-r-neutral-200'"
664
+ :class="
665
+ sidebarPosition === 'right' ? 'border-l-0.5px border-l-neutral-200' : 'border-r-0.5px border-r-neutral-200'
666
+ "
523
667
  >
524
668
  <div px-12px pt-16px pb-8px flex gap-8px>
525
669
  <button
526
- flex items-center justify-center gap-6px
527
- h-32px px-12px flex-1 min-w-0
528
- bg-white b=".5px neutral-300" rounded-10px
529
- hover:bg-neutral-50 transition-colors cursor-pointer
670
+ flex
671
+ items-center
672
+ justify-center
673
+ gap-6px
674
+ h-32px
675
+ px-12px
676
+ flex-1
677
+ min-w-0
678
+ bg-white
679
+ b=".5px neutral-300"
680
+ rounded-10px
681
+ hover:bg-neutral-50
682
+ transition-colors
683
+ cursor-pointer
530
684
  @click="() => handleNewConversation()"
531
685
  >
532
686
  <span i-ph-chat-circle text-12px text-gray-900 />
533
- <span text-14px font-semibold text-neutral-900 tracking="-.15px" leading-18px>
687
+ <span
688
+ text-14px
689
+ font-semibold
690
+ text-neutral-900
691
+ tracking="-.15px"
692
+ leading-18px
693
+ >
534
694
  Nova conversa
535
695
  </span>
536
696
  </button>
@@ -538,9 +698,13 @@ async function handleDelete() {
538
698
  </div>
539
699
 
540
700
  <div
541
- min-h-0 overflow-y-auto px-4px
701
+ min-h-0
702
+ overflow-y-auto
703
+ px-4px
542
704
  :class="$slots['sidebar-bottom'] ? '' : 'flex-1'"
543
- :style="$slots['sidebar-bottom'] ? { flexGrow: 100 - sidebarBottomHeight, flexBasis: 0 } : void 0"
705
+ :style="
706
+ $slots['sidebar-bottom'] ? { flexGrow: 100 - sidebarBottomHeight, flexBasis: 0 } : void 0
707
+ "
544
708
  >
545
709
  <ChatConversationList
546
710
  :conversations="visibleConversations"
@@ -550,13 +714,13 @@ async function handleDelete() {
550
714
  :reset-conversation="handleNewConversation"
551
715
  :start-conversation="handleNewConversation"
552
716
  :loading="conversationsLoading"
553
- :hide-folder-hint="hideFolderHint"
554
717
  />
555
718
  </div>
556
719
 
557
720
  <div
558
721
  v-if="$slots['sidebar-bottom']"
559
- min-h-0 overflow-y-auto
722
+ min-h-0
723
+ overflow-y-auto
560
724
  b-t=".5px neutral-200"
561
725
  :style="{ flexGrow: sidebarBottomHeight, flexBasis: 0 }"
562
726
  >
@@ -569,7 +733,9 @@ async function handleDelete() {
569
733
  v-if="sidebarCollapsible"
570
734
  type="button"
571
735
  class="chat-sidebar__toggle"
572
- :aria-label="sidebarCollapsed ? 'Expandir conversas' : 'Recolher conversas'"
736
+ :aria-label="
737
+ sidebarCollapsed ? 'Expandir conversas' : 'Recolher conversas'
738
+ "
573
739
  :aria-expanded="!sidebarCollapsed"
574
740
  @click="toggleSidebarCollapsed"
575
741
  >
@@ -578,9 +744,14 @@ async function handleDelete() {
578
744
  </div>
579
745
 
580
746
  <!-- Main content -->
581
- <div flex-1 h-full flex="~ col" overflow-hidden relative style="--chat-panel-offset: 0px">
582
- <div v-if="loading && currentConversation" class="loading-bar" />
583
-
747
+ <div
748
+ flex-1
749
+ h-full
750
+ flex="~ col"
751
+ overflow-hidden
752
+ relative
753
+ style="--chat-panel-offset: 0px"
754
+ >
584
755
  <ChatMobileShell
585
756
  v-if="isMobile"
586
757
  v-model:drawer-open="drawerOpen"
@@ -602,8 +773,8 @@ async function handleDelete() {
602
773
  :has-pending-message="hasPendingMessage"
603
774
  :hide-settings="hideSettings"
604
775
  :hide-sidebar="hideSidebar"
605
- :hide-folder-hint="hideFolderHint"
606
776
  :is-editing="isEditing"
777
+ :suggestions="resolvedSuggestions"
607
778
  :loading="loading"
608
779
  :messages="messages"
609
780
  :agent-input-schema="visibleTelaAgentInputSchema"
@@ -639,7 +810,11 @@ async function handleDelete() {
639
810
  <template #loading>
640
811
  <ChatMessageList
641
812
  :messages="[]"
813
+ :streaming-active-message-id="streamingActiveMessageId"
814
+ :preparing-steps="preparingSteps"
815
+ :show-ttft="resolvedFeatures.showTtft"
642
816
  loading
817
+ variant="mobile"
643
818
  />
644
819
  <ChatMessageInput
645
820
  v-model:selected-model="selectedModel"
@@ -651,52 +826,66 @@ async function handleDelete() {
651
826
  </template>
652
827
 
653
828
  <template #empty>
654
- <div
655
- flex-1 flex="~ col" items-center justify-center gap-40px px-24px
656
- :class="currentConversation ? 'pt-64px' : ''"
829
+ <TelaChatEmptyState
830
+ compact
831
+ :title="`Ol\xE1, ${currentUser?.name?.split(' ')[0] ?? 'usu\xE1rio'}`"
832
+ description="Como posso te ajudar hoje?"
657
833
  >
658
- <div flex="~ col" items-center gap-8px text-center>
659
- <h1 text-24px font-semibold text-gray-800 leading-28px tracking="-.8px">
660
- Olá, {{ currentUser?.name?.split(" ")[0] ?? "usu\xE1rio" }}
661
- </h1>
662
- <p text-16px text-gray-500 leading-20px tracking="-.2px">
663
- Como posso te ajudar hoje?
664
- </p>
665
- </div>
666
- <ChatMessageInput
667
- ref="messageInputRef"
668
- v-model:selected-model="selectedModel"
669
- :disabled="hasPendingMessage"
670
- :loading="hasPendingMessage"
671
- :creator-name="currentUser?.name ?? void 0"
672
- :creator-email="currentConversation?.createdBy ?? currentUser?.email ?? void 0"
673
- :creator-image="currentUser?.image ?? void 0"
674
- :messages="messages"
675
- :conversation-files="conversationFiles"
676
- :workspace-settings="effectiveWorkspaceSettings"
677
- :agent-input-schema="visibleTelaAgentInputSchema"
678
- :agent-input-schema-loading="visibleTelaAgentInputSchemaLoading"
679
- :agent-skills="agentSkills"
680
- :agent-context-files="agentContextFiles"
681
- :show-cancel-button="resolvedFeatures.showCancelButton"
682
- centered
683
- @send="handleSend"
684
- @cancel="cancelConversation"
685
- />
686
- </div>
834
+ <TelaChatSuggestions v-if="resolvedSuggestions.length">
835
+ <TelaChatSuggestion
836
+ v-for="suggestion in resolvedSuggestions"
837
+ :key="suggestion.title"
838
+ :suggestion="suggestion.prompt"
839
+ @click="applySuggestion($event)"
840
+ >
841
+ {{ suggestion.title }}
842
+ </TelaChatSuggestion>
843
+ </TelaChatSuggestions>
844
+
845
+ <TelaChatPromptInputHints size="sm" :hints="PROMPT_INPUT_HINTS" />
846
+
847
+ <template #input>
848
+ <ChatMessageInput
849
+ ref="messageInputRef"
850
+ v-model:selected-model="selectedModel"
851
+ :loading="hasPendingMessage"
852
+ :creator-name="currentUser?.name ?? void 0"
853
+ :creator-email="
854
+ currentConversation?.createdBy ?? currentUser?.email ?? void 0
855
+ "
856
+ :creator-image="currentUser?.image ?? void 0"
857
+ :messages="messages"
858
+ :conversation-files="conversationFiles"
859
+ :workspace-settings="effectiveWorkspaceSettings"
860
+ :agent-input-schema="visibleTelaAgentInputSchema"
861
+ :agent-input-schema-loading="visibleTelaAgentInputSchemaLoading"
862
+ :agent-skills="agentSkills"
863
+ :agent-context-files="agentContextFiles"
864
+ :show-cancel-button="resolvedFeatures.showCancelButton"
865
+ centered
866
+ @send="handleSend"
867
+ @cancel="cancelConversation"
868
+ />
869
+ </template>
870
+ </TelaChatEmptyState>
687
871
  </template>
688
872
 
689
873
  <ChatMessageList
690
874
  :messages="messages"
875
+ :streaming-active-message-id="streamingActiveMessageId"
876
+ :preparing-steps="preparingSteps"
877
+ :show-ttft="resolvedFeatures.showTtft"
878
+ variant="mobile"
691
879
  @retry="handleRetry"
692
880
  />
693
881
  <ChatMessageInput
694
882
  ref="messageInputRef"
695
883
  v-model:selected-model="selectedModel"
696
- :disabled="hasPendingMessage"
697
884
  :loading="hasPendingMessage"
698
885
  :creator-name="currentUser?.name ?? void 0"
699
- :creator-email="currentConversation?.createdBy ?? currentUser?.email ?? void 0"
886
+ :creator-email="
887
+ currentConversation?.createdBy ?? currentUser?.email ?? void 0
888
+ "
700
889
  :creator-image="currentUser?.image ?? void 0"
701
890
  :messages="messages"
702
891
  :conversation-files="conversationFiles"
@@ -710,13 +899,10 @@ async function handleDelete() {
710
899
  @send="handleSend"
711
900
  @cancel="cancelConversation"
712
901
  />
713
- <p text-center text-12px font-400 leading-16px text-tertiary my-8px>
714
- As respostas podem conter erros. Verifique documentos originais.
715
- </p>
716
902
  </ChatMobileShell>
717
903
 
718
904
  <ChatTopbar
719
- v-if="currentConversation && !isMobile"
905
+ v-if="currentConversation && !isMobile && !compact"
720
906
  :title="displayTitle"
721
907
  :creator-name="conversationCreator?.name ?? void 0"
722
908
  :creator-email="currentConversation.createdBy ?? void 0"
@@ -745,7 +931,12 @@ async function handleDelete() {
745
931
 
746
932
  <div
747
933
  v-if="!isMobile && showOutdatedBanner"
748
- mt-64px flex items-center h-36px px-12px bg="#FFF1D8"
934
+ flex
935
+ items-center
936
+ h-36px
937
+ px-12px
938
+ bg="#FFF1D8"
939
+ :class="compact ? '' : 'mt-64px'"
749
940
  >
750
941
  <div flex items-center gap-8px flex-1>
751
942
  <span i-ph-warning text-12px text-gray-900 shrink-0 />
@@ -758,17 +949,27 @@ async function handleDelete() {
758
949
  </div>
759
950
  <div flex items-center gap-24px shrink-0>
760
951
  <button
761
- flex items-center gap-4px px-10px py-4px
762
- b=".5px gray-500" rounded-8px
763
- class="hover:bg-white/50" transition-colors
952
+ flex
953
+ items-center
954
+ gap-4px
955
+ px-10px
956
+ py-4px
957
+ b=".5px gray-500"
958
+ rounded-8px
959
+ class="hover:bg-white/50"
960
+ transition-colors
764
961
  @click="() => handleNewConversation()"
765
962
  >
766
963
  <span i-ph-plus text-12px text-gray-900 />
767
964
  <span text-12px font-580 text-gray-900 leading-16px>Nova conversa</span>
768
965
  </button>
769
966
  <button
770
- flex items-center justify-center
771
- class="hover:bg-black/5" transition-colors rounded-4px
967
+ flex
968
+ items-center
969
+ justify-center
970
+ class="hover:bg-black/5"
971
+ transition-colors
972
+ rounded-4px
772
973
  @click="dismissOutdatedBanner"
773
974
  >
774
975
  <span i-ph-x text-12px text-gray-900 />
@@ -776,11 +977,17 @@ async function handleDelete() {
776
977
  </div>
777
978
  </div>
778
979
 
779
- <template v-if="!isMobile && activeTab === 'files' && currentConversation">
980
+ <template
981
+ v-if="!isMobile && activeTab === 'files' && currentConversation"
982
+ >
780
983
  <ChatFilesView :conversation-id="currentConversation.id" />
781
984
  </template>
782
985
 
783
- <template v-else-if="!isMobile && activeTab === 'usage' && resolvedFeatures.showUsageTab && currentConversation">
986
+ <template
987
+ v-else-if="
988
+ !isMobile && activeTab === 'usage' && resolvedFeatures.showUsageTab && currentConversation
989
+ "
990
+ >
784
991
  <ChatUsageView
785
992
  :conversation-id="currentConversation.id"
786
993
  :created-at="currentConversation.createdAt"
@@ -788,10 +995,17 @@ async function handleDelete() {
788
995
  />
789
996
  </template>
790
997
 
791
- <template v-else-if="!isMobile && loading">
998
+ <TelaChatBody
999
+ v-else-if="!isMobile && loading"
1000
+ :variant="compact ? 'widget' : 'page'"
1001
+ >
792
1002
  <ChatMessageList
793
1003
  :messages="[]"
1004
+ :streaming-active-message-id="streamingActiveMessageId"
1005
+ :preparing-steps="preparingSteps"
1006
+ :show-ttft="resolvedFeatures.showTtft"
794
1007
  loading
1008
+ :variant="compact ? 'widget' : 'page'"
795
1009
  />
796
1010
  <ChatMessageInput
797
1011
  v-model:selected-model="selectedModel"
@@ -800,28 +1014,42 @@ async function handleDelete() {
800
1014
  :agent-input-schema-loading="visibleTelaAgentInputSchemaLoading"
801
1015
  :show-cancel-button="resolvedFeatures.showCancelButton"
802
1016
  />
803
- </template>
1017
+ </TelaChatBody>
804
1018
 
805
- <template v-else-if="!isMobile && !hasMessages">
806
- <div
807
- flex-1 flex="~ col" items-center justify-center gap-40px px-24px
808
- :class="currentConversation ? 'pt-64px' : ''"
809
- >
810
- <div flex="~ col" items-center gap-8px text-center>
811
- <h1 text-24px font-semibold text-gray-800 leading-28px tracking="-.8px">
812
- Olá, {{ currentUser?.name?.split(" ")[0] ?? "usu\xE1rio" }}
813
- </h1>
814
- <p text-16px text-gray-500 leading-20px tracking="-.2px">
815
- Como posso te ajudar hoje?
816
- </p>
817
- </div>
1019
+ <!-- Outside TelaChatBody on purpose: the body pins any [data-chat-prompt-input]
1020
+ to its bottom edge, which would tear the input out of the empty-state stack. -->
1021
+ <TelaChatEmptyState
1022
+ v-else-if="!isMobile && !hasMessages"
1023
+ :compact="compact"
1024
+ :title="`Ol\xE1, ${currentUser?.name?.split(' ')[0] ?? 'usu\xE1rio'}`"
1025
+ description="Como posso te ajudar hoje?"
1026
+ :class="currentConversation && !compact ? 'pt-64px' : ''"
1027
+ >
1028
+ <TelaChatSuggestions v-if="resolvedSuggestions.length">
1029
+ <TelaChatSuggestion
1030
+ v-for="suggestion in resolvedSuggestions"
1031
+ :key="suggestion.title"
1032
+ :suggestion="suggestion.prompt"
1033
+ @click="applySuggestion($event)"
1034
+ >
1035
+ {{ suggestion.title }}
1036
+ </TelaChatSuggestion>
1037
+ </TelaChatSuggestions>
1038
+
1039
+ <TelaChatPromptInputHints
1040
+ :size="compact ? 'sm' : 'md'"
1041
+ :hints="PROMPT_INPUT_HINTS"
1042
+ />
1043
+
1044
+ <template #input>
818
1045
  <ChatMessageInput
819
1046
  ref="messageInputRef"
820
1047
  v-model:selected-model="selectedModel"
821
- :disabled="hasPendingMessage"
822
1048
  :loading="hasPendingMessage"
823
1049
  :creator-name="currentUser?.name ?? void 0"
824
- :creator-email="currentConversation?.createdBy ?? currentUser?.email ?? void 0"
1050
+ :creator-email="
1051
+ currentConversation?.createdBy ?? currentUser?.email ?? void 0
1052
+ "
825
1053
  :creator-image="currentUser?.image ?? void 0"
826
1054
  :messages="messages"
827
1055
  :conversation-files="conversationFiles"
@@ -835,21 +1063,29 @@ async function handleDelete() {
835
1063
  @send="handleSend"
836
1064
  @cancel="cancelConversation"
837
1065
  />
838
- </div>
839
- </template>
1066
+ </template>
1067
+ </TelaChatEmptyState>
840
1068
 
841
- <template v-else-if="!isMobile">
1069
+ <TelaChatBody
1070
+ v-else-if="!isMobile"
1071
+ :variant="compact ? 'widget' : 'page'"
1072
+ >
842
1073
  <ChatMessageList
843
1074
  :messages="messages"
1075
+ :streaming-active-message-id="streamingActiveMessageId"
1076
+ :preparing-steps="preparingSteps"
1077
+ :show-ttft="resolvedFeatures.showTtft"
1078
+ :variant="compact ? 'widget' : 'page'"
844
1079
  @retry="handleRetry"
845
1080
  />
846
1081
  <ChatMessageInput
847
1082
  ref="messageInputRef"
848
1083
  v-model:selected-model="selectedModel"
849
- :disabled="hasPendingMessage"
850
1084
  :loading="hasPendingMessage"
851
1085
  :creator-name="currentUser?.name ?? void 0"
852
- :creator-email="currentConversation?.createdBy ?? currentUser?.email ?? void 0"
1086
+ :creator-email="
1087
+ currentConversation?.createdBy ?? currentUser?.email ?? void 0
1088
+ "
853
1089
  :creator-image="currentUser?.image ?? void 0"
854
1090
  :messages="messages"
855
1091
  :conversation-files="conversationFiles"
@@ -863,10 +1099,7 @@ async function handleDelete() {
863
1099
  @send="handleSend"
864
1100
  @cancel="cancelConversation"
865
1101
  />
866
- <p text-center text-12px font-400 leading-16px text-tertiary my-8px>
867
- As respostas podem conter erros. Verifique documentos originais.
868
- </p>
869
- </template>
1102
+ </TelaChatBody>
870
1103
 
871
1104
  <Transition name="fade">
872
1105
  <div
@@ -874,10 +1107,23 @@ async function handleDelete() {
874
1107
  class="absolute inset-0 z-50 flex items-center justify-center bg-white/90 backdrop-blur-sm"
875
1108
  >
876
1109
  <div
877
- flex="~ col" items-center gap-16px p-40px rounded-24px
878
- border="2 dashed gray-300" bg-gray-50
1110
+ flex="~ col"
1111
+ items-center
1112
+ gap-16px
1113
+ p-40px
1114
+ rounded-24px
1115
+ border="2 dashed gray-300"
1116
+ bg-gray-50
879
1117
  >
880
- <div w-64px h-64px rounded-full bg-gray-100 flex items-center justify-center>
1118
+ <div
1119
+ w-64px
1120
+ h-64px
1121
+ rounded-full
1122
+ bg-gray-100
1123
+ flex
1124
+ items-center
1125
+ justify-center
1126
+ >
881
1127
  <span i-ph-upload-simple text-32px text-gray-500 />
882
1128
  </div>
883
1129
  <div text-center>
@@ -901,7 +1147,8 @@ async function handleDelete() {
901
1147
  @confirm="handleDelete"
902
1148
  @cancel="showDeleteModal = false"
903
1149
  >
904
- Tem certeza que deseja excluir esta conversa? Esta ação não pode ser desfeita.
1150
+ Tem certeza que deseja excluir esta conversa? Esta ação não pode ser
1151
+ desfeita.
905
1152
  </TelaConfirmationModal>
906
1153
 
907
1154
  <TelaModal
@@ -918,11 +1165,13 @@ async function handleDelete() {
918
1165
  Conversation Id
919
1166
  </p>
920
1167
  <div
921
- px-12px py-10px
1168
+ px-12px
1169
+ py-10px
922
1170
  rounded-8px
923
1171
  bg-gray-50
924
1172
  justify-between
925
- flex items-center
1173
+ flex
1174
+ items-center
926
1175
  border="0.5px gray-200"
927
1176
  >
928
1177
  <p text-13px text-gray-700 break-all leading-18px>
@@ -936,11 +1185,13 @@ async function handleDelete() {
936
1185
  Session Id
937
1186
  </p>
938
1187
  <div
939
- px-12px py-10px
1188
+ px-12px
1189
+ py-10px
940
1190
  rounded-8px
941
1191
  bg-gray-50
942
1192
  justify-between
943
- flex items-center
1193
+ flex
1194
+ items-center
944
1195
  border="0.5px gray-200"
945
1196
  >
946
1197
  <p text-13px text-gray-700 break-all leading-18px>
@@ -955,7 +1206,13 @@ async function handleDelete() {
955
1206
  <p text-12px font-400 leading-16px text-tertiary>
956
1207
  Inclui os ids da conversa e os links de debug no Datadog e no Tela
957
1208
  </p>
958
- <TelaButton variant="primary" icon="i-ph-copy" leading flex-shrink-0 @click="copyDebugInfo">
1209
+ <TelaButton
1210
+ variant="primary"
1211
+ icon="i-ph-copy"
1212
+ leading
1213
+ flex-shrink-0
1214
+ @click="copyDebugInfo"
1215
+ >
959
1216
  Copiar dados completos
960
1217
  </TelaButton>
961
1218
  </div>
@@ -971,7 +1228,9 @@ async function handleDelete() {
971
1228
 
972
1229
  <div
973
1230
  v-if="isPreviewPanelOpen && !isMobile"
974
- h-full flex-shrink-0 pt-64px
1231
+ h-full
1232
+ flex-shrink-0
1233
+ pt-64px
975
1234
  :style="{ width: `${previewPanelWidth}px` }"
976
1235
  >
977
1236
  <FilePreviewPanel />
@@ -979,14 +1238,19 @@ async function handleDelete() {
979
1238
 
980
1239
  <div
981
1240
  v-if="isCitationPanelOpen && !isMobile"
982
- h-full flex-shrink-0 pt-64px
1241
+ h-full
1242
+ flex-shrink-0
1243
+ pt-64px
983
1244
  w-440px
984
1245
  >
985
1246
  <CitationDocumentPanel />
986
1247
  </div>
987
1248
  <div
988
1249
  v-else-if="isCitationPanelOpen && isMobile"
989
- fixed inset-0 z-50 bg-neutral-50
1250
+ fixed
1251
+ inset-0
1252
+ z-50
1253
+ bg-neutral-50
990
1254
  >
991
1255
  <CitationDocumentPanel />
992
1256
  </div>
@@ -994,5 +1258,9 @@ async function handleDelete() {
994
1258
  </template>
995
1259
 
996
1260
  <style scoped>
997
- .loading-bar{animation:loading-pulse 1.5s ease-in-out infinite;background:linear-gradient(90deg,transparent,#ea580b,#fb923c,#fdba74,transparent);background-size:200% 100%;height:4px;left:0;position:absolute;right:0;top:0;z-index:100}@keyframes loading-pulse{0%{background-position:200% 0}to{background-position:-200% 0}}.fade-enter-active,.fade-leave-active{transition:opacity .2s ease}.fade-enter-from,.fade-leave-to{opacity:0}.chat-sidebar{width:var(--chat-sidebar-width)}.chat-sidebar__clip{display:flex;height:100%;width:100%}.chat-sidebar__panel{flex:none}.chat-sidebar--collapsible{min-width:0;transition:width .26s cubic-bezier(.2,.8,.2,1)}.chat-sidebar--collapsible .chat-sidebar__clip{overflow:hidden}.chat-sidebar--collapsible.chat-sidebar--right .chat-sidebar__clip{justify-content:flex-end}.chat-sidebar--collapsible .chat-sidebar__panel{transition:opacity .2s ease}.chat-sidebar--collapsed{width:0}.chat-sidebar--collapsed .chat-sidebar__panel{opacity:0}.chat-sidebar__toggle{align-items:center;background:#fff;border:.5px solid #e5e5e5;border-radius:8px;box-shadow:0 1px 2px rgba(16,24,40,.06);cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;position:absolute;top:50%;transition:transform .26s cubic-bezier(.2,.8,.2,1),background-color .12s ease;width:20px;z-index:20}.chat-sidebar__toggle:hover{background:#fafafa}.chat-sidebar--right .chat-sidebar__toggle{left:0;transform:translate(-50%,-50%)}.chat-sidebar--right.chat-sidebar--collapsed .chat-sidebar__toggle{transform:translate(-100%,-50%)}.chat-sidebar--left .chat-sidebar__toggle{right:0;transform:translate(50%,-50%)}.chat-sidebar--left.chat-sidebar--collapsed .chat-sidebar__toggle{transform:translate(100%,-50%)}@media (prefers-reduced-motion:reduce){.chat-sidebar__clip,.chat-sidebar__panel,.chat-sidebar__toggle{transition:none}}
1261
+ .chat-sidebar{width:var(--chat-sidebar-width)}.chat-sidebar__clip{display:flex;height:100%;width:100%}.chat-sidebar__panel{flex:none}.chat-sidebar--collapsible{min-width:0;transition:width .26s cubic-bezier(.2,.8,.2,1)}.chat-sidebar--collapsible .chat-sidebar__clip{overflow:hidden}.chat-sidebar--collapsible.chat-sidebar--right .chat-sidebar__clip{justify-content:flex-end}.chat-sidebar--collapsible .chat-sidebar__panel{transition:opacity .2s ease}.chat-sidebar--collapsed{width:0}.chat-sidebar--collapsed .chat-sidebar__panel{opacity:0}.chat-sidebar__toggle{align-items:center;background:#fff;border:.5px solid #e5e5e5;border-radius:8px;box-shadow:0 1px 2px rgba(16,24,40,.06);cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;position:absolute;top:50%;transition:transform .26s cubic-bezier(.2,.8,.2,1),background-color .12s ease;width:20px;z-index:20}.chat-sidebar__toggle:hover{background:#fafafa}.chat-sidebar--right .chat-sidebar__toggle{left:0;transform:translate(-50%,-50%)}.chat-sidebar--right.chat-sidebar--collapsed .chat-sidebar__toggle{transform:translate(-100%,-50%)}.chat-sidebar--left .chat-sidebar__toggle{right:0;transform:translate(50%,-50%)}.chat-sidebar--left.chat-sidebar--collapsed .chat-sidebar__toggle{transform:translate(100%,-50%)}@media (prefers-reduced-motion:reduce){.chat-sidebar__clip,.chat-sidebar__panel,.chat-sidebar__toggle{transition:none}}
1262
+ </style>
1263
+
1264
+ <style>
1265
+ [data-chat-body][data-variant=page] [data-chat-prompt-input]{margin-inline:auto!important;max-width:700px}
998
1266
  </style>