@meistrari/chat-nuxt 1.7.0 → 1.8.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.
Files changed (92) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +2 -0
  3. package/dist/runtime/components/MeistrariChatEmbed.vue +5 -1
  4. package/dist/runtime/components/chat/bash-widget.vue +3 -3
  5. package/dist/runtime/components/chat/doc-sdk-widget.vue +3 -3
  6. package/dist/runtime/components/chat/files-view.vue +3 -64
  7. package/dist/runtime/components/chat/generic-tool-widget.vue +3 -3
  8. package/dist/runtime/components/chat/grep-widget.vue +3 -3
  9. package/dist/runtime/components/chat/message-bubble.vue +1 -1
  10. package/dist/runtime/components/chat/message-input.d.vue.ts +2 -0
  11. package/dist/runtime/components/chat/message-input.vue +21 -5
  12. package/dist/runtime/components/chat/message-input.vue.d.ts +2 -0
  13. package/dist/runtime/components/chat/message-list.vue +1 -1
  14. package/dist/runtime/components/chat/mobile/files/file-preview.d.vue.ts +11 -0
  15. package/dist/runtime/components/chat/mobile/files/file-preview.vue +112 -0
  16. package/dist/runtime/components/chat/mobile/files/file-preview.vue.d.ts +11 -0
  17. package/dist/runtime/components/chat/mobile/files/files-view.d.vue.ts +10 -0
  18. package/dist/runtime/components/chat/mobile/files/files-view.vue +384 -0
  19. package/dist/runtime/components/chat/mobile/files/files-view.vue.d.ts +10 -0
  20. package/dist/runtime/components/chat/mobile/home/header.d.vue.ts +19 -0
  21. package/dist/runtime/components/chat/mobile/home/header.vue +55 -0
  22. package/dist/runtime/components/chat/mobile/home/header.vue.d.ts +19 -0
  23. package/dist/runtime/components/chat/mobile/home/recents.d.vue.ts +14 -0
  24. package/dist/runtime/components/chat/mobile/home/recents.vue +48 -0
  25. package/dist/runtime/components/chat/mobile/home/recents.vue.d.ts +14 -0
  26. package/dist/runtime/components/chat/mobile/home/suggestions.d.vue.ts +7 -0
  27. package/dist/runtime/components/chat/mobile/home/suggestions.vue +31 -0
  28. package/dist/runtime/components/chat/mobile/home/suggestions.vue.d.ts +7 -0
  29. package/dist/runtime/components/chat/mobile/primitives/bottom-sheet.d.vue.ts +21 -0
  30. package/dist/runtime/components/chat/mobile/primitives/bottom-sheet.vue +48 -0
  31. package/dist/runtime/components/chat/mobile/primitives/bottom-sheet.vue.d.ts +21 -0
  32. package/dist/runtime/components/chat/mobile/primitives/info-bubble.d.vue.ts +6 -0
  33. package/dist/runtime/components/chat/mobile/primitives/info-bubble.vue +50 -0
  34. package/dist/runtime/components/chat/mobile/primitives/info-bubble.vue.d.ts +6 -0
  35. package/dist/runtime/components/chat/mobile/shell/drawer.d.vue.ts +22 -0
  36. package/dist/runtime/components/chat/mobile/shell/drawer.vue +143 -0
  37. package/dist/runtime/components/chat/mobile/shell/drawer.vue.d.ts +22 -0
  38. package/dist/runtime/components/chat/mobile/shell/header.d.vue.ts +40 -0
  39. package/dist/runtime/components/chat/mobile/shell/header.vue +139 -0
  40. package/dist/runtime/components/chat/mobile/shell/header.vue.d.ts +40 -0
  41. package/dist/runtime/components/chat/mobile/shell/outdated-settings-sheet.d.vue.ts +14 -0
  42. package/dist/runtime/components/chat/mobile/shell/outdated-settings-sheet.vue +47 -0
  43. package/dist/runtime/components/chat/mobile/shell/outdated-settings-sheet.vue.d.ts +14 -0
  44. package/dist/runtime/components/chat/mobile/shell/shell.d.vue.ts +122 -0
  45. package/dist/runtime/components/chat/mobile/shell/shell.vue +283 -0
  46. package/dist/runtime/components/chat/mobile/shell/shell.vue.d.ts +122 -0
  47. package/dist/runtime/components/chat/mobile/shell/workspace-sheet.d.vue.ts +19 -0
  48. package/dist/runtime/components/chat/mobile/shell/workspace-sheet.vue +51 -0
  49. package/dist/runtime/components/chat/mobile/shell/workspace-sheet.vue.d.ts +19 -0
  50. package/dist/runtime/components/chat/mobile/usage/usage-view.d.vue.ts +8 -0
  51. package/dist/runtime/components/chat/mobile/usage/usage-view.vue +243 -0
  52. package/dist/runtime/components/chat/mobile/usage/usage-view.vue.d.ts +8 -0
  53. package/dist/runtime/components/chat/model-selector.vue +6 -0
  54. package/dist/runtime/components/chat/read-widget.vue +3 -3
  55. package/dist/runtime/components/chat/reasoning-step-item.vue +1 -1
  56. package/dist/runtime/components/chat/reasoning-steps.vue +1 -1
  57. package/dist/runtime/components/chat/reasoning-thought.vue +2 -3
  58. package/dist/runtime/components/chat/tela-skill-widget.vue +3 -3
  59. package/dist/runtime/components/chat/thinking-widget.vue +3 -3
  60. package/dist/runtime/components/chat/usage-view.vue +20 -101
  61. package/dist/runtime/components/chat/web-search-widget.vue +3 -3
  62. package/dist/runtime/components/chat/workstation-query-widget.vue +6 -6
  63. package/dist/runtime/components/chat/write-widget.vue +3 -3
  64. package/dist/runtime/composables/useConversationFileDownloads.d.ts +6 -0
  65. package/dist/runtime/composables/useConversationFileDownloads.js +50 -0
  66. package/dist/runtime/composables/useConversationUsage.d.ts +13 -0
  67. package/dist/runtime/composables/useConversationUsage.js +121 -0
  68. package/dist/runtime/composables/useEmbedConfig.d.ts +2 -0
  69. package/dist/runtime/composables/useEmbedConfig.js +4 -0
  70. package/dist/runtime/composables/useMentionAutocomplete.d.ts +6 -0
  71. package/dist/runtime/composables/useMentionAutocomplete.js +71 -23
  72. package/dist/runtime/composables/usePdf.js +2 -2
  73. package/dist/runtime/composables/useWorkspaceSwitchModal.d.ts +5 -0
  74. package/dist/runtime/composables/useWorkspaceSwitchModal.js +14 -0
  75. package/dist/runtime/embed/components/ChatConfigurationModal.vue +119 -13
  76. package/dist/runtime/embed/components/ChatEmbed.vue +4 -0
  77. package/dist/runtime/embed/components/ChatEmbedInner.d.vue.ts +2 -0
  78. package/dist/runtime/embed/components/ChatEmbedInner.vue +201 -11
  79. package/dist/runtime/embed/components/ChatEmbedInner.vue.d.ts +2 -0
  80. package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.d.vue.ts +34 -0
  81. package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.vue +95 -0
  82. package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.vue.d.ts +34 -0
  83. package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.js +3 -1
  84. package/dist/runtime/server/api/conversations/[id]/messages/index.get.js +29 -5
  85. package/dist/runtime/server/utils/conversation-agent-turn.js +4 -0
  86. package/dist/runtime/server/utils/conversation-message-sync.d.ts +8 -2
  87. package/dist/runtime/server/utils/conversation-message-sync.js +52 -6
  88. package/dist/runtime/types/chat-auth.d.ts +1 -0
  89. package/dist/runtime/types/embed.d.ts +2 -0
  90. package/dist/runtime/utils/breakpoints.d.ts +1 -0
  91. package/dist/runtime/utils/breakpoints.js +1 -0
  92. package/package.json +1 -1
@@ -0,0 +1,50 @@
1
+ import { useClipboard } from "@vueuse/core";
2
+ export function useConversationFileDownloads() {
3
+ const statusToast = useStatusToast();
4
+ const { copy } = useClipboard();
5
+ async function resolveDownloadUrl(file) {
6
+ if (file.url.startsWith("vault://")) {
7
+ const { url } = await $fetch("/api/vault/resolve", {
8
+ method: "POST",
9
+ body: { reference: file.url }
10
+ });
11
+ return url;
12
+ }
13
+ return file.url;
14
+ }
15
+ async function downloadFile(file) {
16
+ statusToast.update({ text: "Baixando arquivo...", loading: true });
17
+ try {
18
+ const downloadUrl = await resolveDownloadUrl(file);
19
+ const response = await fetch(downloadUrl);
20
+ const blob = await response.blob();
21
+ const blobUrl = URL.createObjectURL(blob);
22
+ const link = document.createElement("a");
23
+ link.href = blobUrl;
24
+ link.download = file.name;
25
+ document.body.appendChild(link);
26
+ link.click();
27
+ document.body.removeChild(link);
28
+ URL.revokeObjectURL(blobUrl);
29
+ statusToast.update({ text: "Download conclu\xEDdo", icon: "i-ph-check" });
30
+ } catch (error) {
31
+ console.error("Failed to download file:", error);
32
+ statusToast.update({ text: "Erro ao baixar arquivo", icon: "i-ph-warning" });
33
+ }
34
+ }
35
+ async function copyFileLink(file) {
36
+ try {
37
+ const publicUrl = await resolveDownloadUrl(file);
38
+ await copy(publicUrl);
39
+ statusToast.update({ text: "Link copiado", icon: "i-ph-check" });
40
+ } catch (error) {
41
+ console.error("Failed to copy link:", error);
42
+ statusToast.update({ text: "Erro ao copiar link", icon: "i-ph-warning" });
43
+ }
44
+ }
45
+ return {
46
+ resolveDownloadUrl,
47
+ downloadFile,
48
+ copyFileLink
49
+ };
50
+ }
@@ -0,0 +1,13 @@
1
+ import type { Ref } from 'vue';
2
+ export declare function useConversationUsage(conversationId: Ref<string | null | undefined>): {
3
+ usageData: any;
4
+ billing: any;
5
+ loading: any;
6
+ error: any;
7
+ cacheInsight: any;
8
+ costBreakdown: any;
9
+ modelRows: any;
10
+ costBarSegments: any;
11
+ formatBillingCost: (cost: number) => string;
12
+ fetchUsage: () => Promise<void>;
13
+ };
@@ -0,0 +1,121 @@
1
+ import { formatCost, formatCredits, formatModelName, formatTokenCount } from "../utils/calculate-usage.js";
2
+ export function useConversationUsage(conversationId) {
3
+ const chatApi = useChatApi();
4
+ const usageData = ref(null);
5
+ const billing = ref(null);
6
+ const loading = ref(false);
7
+ const error = ref(null);
8
+ function formatBillingCost(cost) {
9
+ if (!billing.value || billing.value.mode === "credits") {
10
+ return formatCredits(cost);
11
+ }
12
+ return formatCost(cost);
13
+ }
14
+ async function fetchUsage() {
15
+ const id = conversationId.value;
16
+ if (!id) {
17
+ return;
18
+ }
19
+ loading.value = true;
20
+ error.value = null;
21
+ try {
22
+ const response = await $fetch(
23
+ chatApi.path(`/conversations/${id}/usage`),
24
+ chatApi.withChatHeaders()
25
+ );
26
+ if (response.error) {
27
+ error.value = response.error;
28
+ } else {
29
+ usageData.value = response.usage;
30
+ billing.value = response.billing;
31
+ }
32
+ } catch (err) {
33
+ console.error("Failed to fetch usage data:", err);
34
+ error.value = "Falha ao carregar dados de uso";
35
+ } finally {
36
+ loading.value = false;
37
+ }
38
+ }
39
+ const cacheInsight = computed(() => {
40
+ if (!usageData.value) {
41
+ return { percentage: 0, reusedTokens: 0, storedTokens: 0, hasData: false };
42
+ }
43
+ const hasData = usageData.value.tokens.cacheRead > 0 || usageData.value.tokens.cacheCreation > 0;
44
+ return {
45
+ percentage: Math.round(usageData.value.metrics.cacheHitRate * 100),
46
+ reusedTokens: usageData.value.tokens.cacheRead,
47
+ storedTokens: usageData.value.tokens.cacheCreation,
48
+ hasData
49
+ };
50
+ });
51
+ const costBreakdown = computed(() => {
52
+ if (!usageData.value) {
53
+ return [];
54
+ }
55
+ const total = usageData.value.cost.total;
56
+ return [
57
+ {
58
+ key: "input",
59
+ label: "Envio",
60
+ tooltip: "Texto enviado ao modelo: perguntas, contexto e instru\xE7\xF5es",
61
+ tokens: usageData.value.tokens.prompt,
62
+ cost: usageData.value.cost.prompt,
63
+ percentage: total > 0 ? Math.round(usageData.value.cost.prompt / total * 100) : 0
64
+ },
65
+ {
66
+ key: "output",
67
+ label: "Respostas",
68
+ tooltip: "Texto gerado pelo modelo",
69
+ tokens: usageData.value.tokens.completion,
70
+ cost: usageData.value.cost.completion,
71
+ percentage: total > 0 ? Math.round(usageData.value.cost.completion / total * 100) : 0
72
+ }
73
+ ];
74
+ });
75
+ const modelRows = computed(() => {
76
+ if (!usageData.value) {
77
+ return [];
78
+ }
79
+ const totalCost = usageData.value.cost.total;
80
+ return usageData.value.models.map((m) => {
81
+ const totalTokens = m.inputTokens + m.outputTokens + m.cacheReadTokens + m.cacheCreationTokens;
82
+ return {
83
+ modelId: m.model,
84
+ modelName: formatModelName(m.model),
85
+ tokens: formatTokenCount(totalTokens),
86
+ cost: formatBillingCost(m.cost),
87
+ costShare: totalCost > 0 ? m.cost / totalCost * 100 : 0
88
+ };
89
+ });
90
+ });
91
+ const costBarSegments = computed(() => {
92
+ if (!usageData.value || usageData.value.cost.total === 0) {
93
+ return [];
94
+ }
95
+ const total = usageData.value.cost.total;
96
+ return [
97
+ {
98
+ key: "input",
99
+ label: "Envio",
100
+ percentage: usageData.value.cost.prompt / total * 100
101
+ },
102
+ {
103
+ key: "output",
104
+ label: "Respostas",
105
+ percentage: usageData.value.cost.completion / total * 100
106
+ }
107
+ ];
108
+ });
109
+ return {
110
+ usageData,
111
+ billing,
112
+ loading,
113
+ error,
114
+ cacheInsight,
115
+ costBreakdown,
116
+ modelRows,
117
+ costBarSegments,
118
+ formatBillingCost,
119
+ fetchUsage
120
+ };
121
+ }
@@ -10,6 +10,7 @@ export type EmbedConfig = {
10
10
  telaAgentInputs: Ref<ConfiguredTelaAgentInputs>;
11
11
  workspaceSettings: Ref<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
12
12
  hideSidebar: Ref<boolean>;
13
+ hideSettings: Ref<boolean>;
13
14
  loadingMessages: Ref<readonly string[] | null | undefined>;
14
15
  loadingMessagesMode: Ref<ChatLoadingMessageMode | null | undefined>;
15
16
  customComponents: Ref<Record<string, Component> | undefined>;
@@ -22,6 +23,7 @@ type EmbedConfigInput = {
22
23
  telaAgentInputs?: MaybeRefOrGetter<ConfiguredTelaAgentInputs>;
23
24
  workspaceSettings?: MaybeRefOrGetter<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
24
25
  hideSidebar?: MaybeRefOrGetter<boolean | undefined>;
26
+ hideSettings?: MaybeRefOrGetter<boolean | undefined>;
25
27
  loadingMessages?: MaybeRefOrGetter<readonly string[] | null | undefined>;
26
28
  loadingMessagesMode?: MaybeRefOrGetter<ChatLoadingMessageMode | null | undefined>;
27
29
  customComponents?: MaybeRefOrGetter<Record<string, Component> | undefined>;
@@ -14,6 +14,7 @@ function useGlobalEmbedConfigState() {
14
14
  telaAgentInputs: useState("chat-embed-config-tela-agent-inputs", () => void 0),
15
15
  workspaceSettings: useState("chat-embed-config-workspace-settings", () => void 0),
16
16
  hideSidebar: useState("chat-embed-config-hide-sidebar", () => void 0),
17
+ hideSettings: useState("chat-embed-config-hide-settings", () => void 0),
17
18
  loadingMessages: useState("chat-embed-config-loading-messages", () => void 0),
18
19
  loadingMessagesMode: useState("chat-embed-config-loading-messages-mode", () => void 0),
19
20
  customComponents: useGlobalCustomComponentsState(),
@@ -28,6 +29,7 @@ export function provideEmbedConfig(input, options = {}) {
28
29
  telaAgentInputs: computed(() => toValue(input.telaAgentInputs)),
29
30
  workspaceSettings: computed(() => toValue(input.workspaceSettings)),
30
31
  hideSidebar: computed(() => toValue(input.hideSidebar) ?? true),
32
+ hideSettings: computed(() => toValue(input.hideSettings) ?? false),
31
33
  loadingMessages: computed(() => toValue(input.loadingMessages)),
32
34
  loadingMessagesMode: computed(() => toValue(input.loadingMessagesMode)),
33
35
  customComponents: computed(() => toValue(input.customComponents)),
@@ -43,6 +45,7 @@ export function provideEmbedConfig(input, options = {}) {
43
45
  globalConfig.telaAgentInputs.value = config.telaAgentInputs.value;
44
46
  globalConfig.workspaceSettings.value = config.workspaceSettings.value;
45
47
  globalConfig.hideSidebar.value = config.hideSidebar.value;
48
+ globalConfig.hideSettings.value = config.hideSettings.value;
46
49
  globalConfig.loadingMessages.value = config.loadingMessages.value;
47
50
  globalConfig.loadingMessagesMode.value = config.loadingMessagesMode.value;
48
51
  globalConfig.customComponents.value = config.customComponents.value;
@@ -65,6 +68,7 @@ export function useEmbedConfig() {
65
68
  telaAgentInputs: computed(() => globalConfig.telaAgentInputs.value),
66
69
  workspaceSettings: computed(() => globalConfig.workspaceSettings.value),
67
70
  hideSidebar: computed(() => globalConfig.hideSidebar.value ?? true),
71
+ hideSettings: computed(() => globalConfig.hideSettings.value ?? false),
68
72
  loadingMessages: computed(() => globalConfig.loadingMessages.value),
69
73
  loadingMessagesMode: computed(() => globalConfig.loadingMessagesMode.value),
70
74
  customComponents: computed(() => globalConfig.customComponents.value),
@@ -6,5 +6,11 @@ type UseMentionAutocompleteOptions = {
6
6
  disabled?: Ref<boolean | undefined>;
7
7
  onInsert?: () => void;
8
8
  };
9
+ export declare function isMentionTriggerBoundary(textBeforeTrigger: string): boolean;
10
+ export declare function findMentionTrigger(textBeforeCursor: string): {
11
+ trigger: '@' | '/';
12
+ query: string;
13
+ offset: number;
14
+ } | null;
9
15
  export declare function useMentionAutocomplete(options: UseMentionAutocompleteOptions): any;
10
16
  export {};
@@ -1,3 +1,26 @@
1
+ export function isMentionTriggerBoundary(textBeforeTrigger) {
2
+ if (textBeforeTrigger.length === 0)
3
+ return true;
4
+ const previousChar = textBeforeTrigger[textBeforeTrigger.length - 1];
5
+ return previousChar === " " || previousChar === "\n" || previousChar === "\xA0";
6
+ }
7
+ export function findMentionTrigger(textBeforeCursor) {
8
+ for (let i = textBeforeCursor.length - 1; i >= 0; i--) {
9
+ const char = textBeforeCursor[i];
10
+ if (char === " " || char === "\n" || char === "\xA0")
11
+ return null;
12
+ if (char === "@" || char === "/") {
13
+ if (!isMentionTriggerBoundary(textBeforeCursor.slice(0, i)))
14
+ return null;
15
+ return {
16
+ trigger: char,
17
+ query: textBeforeCursor.slice(i + 1),
18
+ offset: i
19
+ };
20
+ }
21
+ }
22
+ return null;
23
+ }
1
24
  export function useMentionAutocomplete(options) {
2
25
  const { editorRef, fileItems, skillItems, disabled, onInsert } = options;
3
26
  const activeTrigger = ref(null);
@@ -22,36 +45,59 @@ export function useMentionAutocomplete(options) {
22
45
  if (!sel || sel.rangeCount === 0 || !editorRef.value)
23
46
  return "";
24
47
  const range = sel.getRangeAt(0);
25
- const preRange = document.createRange();
26
- preRange.selectNodeContents(editorRef.value);
27
- preRange.setEnd(range.startContainer, range.startOffset);
28
- return preRange.toString();
48
+ const editor = editorRef.value;
49
+ let text = "";
50
+ function walkNode(node) {
51
+ if (node === range.startContainer) {
52
+ if (node.nodeType === Node.TEXT_NODE) {
53
+ text += (node.textContent ?? "").slice(0, range.startOffset);
54
+ return true;
55
+ }
56
+ for (const child of Array.from(node.childNodes).slice(0, range.startOffset)) {
57
+ if (walkNode(child))
58
+ return true;
59
+ }
60
+ return true;
61
+ }
62
+ if (node.nodeType === Node.TEXT_NODE) {
63
+ text += node.textContent ?? "";
64
+ return false;
65
+ }
66
+ if (node.nodeName === "BR") {
67
+ if (!node.dataset?.sentinel)
68
+ text += "\n";
69
+ return false;
70
+ }
71
+ if (node.nodeType === Node.ELEMENT_NODE && node.contentEditable === "false") {
72
+ text += node.textContent ?? "";
73
+ return false;
74
+ }
75
+ for (const child of node.childNodes) {
76
+ if (walkNode(child))
77
+ return true;
78
+ }
79
+ return false;
80
+ }
81
+ walkNode(editor);
82
+ return text;
29
83
  }
30
84
  function detectTrigger() {
31
85
  if (disabled?.value) {
32
86
  activeTrigger.value = null;
33
87
  return;
34
88
  }
35
- const textBefore = getTextBeforeCursor();
36
- for (let i = textBefore.length - 1; i >= 0; i--) {
37
- const char = textBefore[i];
38
- if (char === " " || char === "\n" || char === "\xA0") {
39
- activeTrigger.value = null;
40
- return;
41
- }
42
- if (char === "@" || char === "/") {
43
- activeTrigger.value = char;
44
- triggerTextOffset = i;
45
- const newQuery = textBefore.slice(i + 1);
46
- if (newQuery !== lastQuery.value) {
47
- highlightedIndex.value = -1;
48
- lastQuery.value = newQuery;
49
- }
50
- query.value = newQuery;
51
- return;
52
- }
89
+ const mentionTrigger = findMentionTrigger(getTextBeforeCursor());
90
+ if (!mentionTrigger) {
91
+ activeTrigger.value = null;
92
+ return;
53
93
  }
54
- activeTrigger.value = null;
94
+ activeTrigger.value = mentionTrigger.trigger;
95
+ triggerTextOffset = mentionTrigger.offset;
96
+ if (mentionTrigger.query !== lastQuery.value) {
97
+ highlightedIndex.value = -1;
98
+ lastQuery.value = mentionTrigger.query;
99
+ }
100
+ query.value = mentionTrigger.query;
55
101
  }
56
102
  function getCaretRangeAtOffset(offset) {
57
103
  const editor = editorRef.value;
@@ -71,6 +117,8 @@ export function useMentionAutocomplete(options) {
71
117
  return null;
72
118
  }
73
119
  if (node.nodeName === "BR") {
120
+ if (!node.dataset?.sentinel)
121
+ current += 1;
74
122
  return null;
75
123
  }
76
124
  if (node.nodeType === Node.ELEMENT_NODE && node.contentEditable === "false") {
@@ -5,8 +5,8 @@ async function loadPdfjs() {
5
5
  if (!import.meta.client)
6
6
  return null;
7
7
  if (!pdfjsLibPromise) {
8
- pdfjsLibPromise = import("pdfjs-dist").then((lib) => {
9
- lib.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${lib.version}/build/pdf.worker.min.mjs`;
8
+ pdfjsLibPromise = import("pdfjs-dist/legacy/build/pdf.mjs").then((lib) => {
9
+ lib.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${lib.version}/legacy/build/pdf.worker.min.mjs`;
10
10
  return lib;
11
11
  });
12
12
  }
@@ -0,0 +1,5 @@
1
+ export declare function useWorkspaceSwitchModal(): {
2
+ isOpen: any;
3
+ openModal: () => void;
4
+ closeModal: () => void;
5
+ };
@@ -0,0 +1,14 @@
1
+ export function useWorkspaceSwitchModal() {
2
+ const isOpen = useState("chat-nuxt:workspace-switch-modal-open", () => false);
3
+ function openModal() {
4
+ isOpen.value = true;
5
+ }
6
+ function closeModal() {
7
+ isOpen.value = false;
8
+ }
9
+ return {
10
+ isOpen,
11
+ openModal,
12
+ closeModal
13
+ };
14
+ }
@@ -1,5 +1,7 @@
1
1
  <script setup>
2
- import { useMagicKeys } from "@vueuse/core";
2
+ import { useBreakpoints, useMagicKeys } from "@vueuse/core";
3
+ import { CHAT_MOBILE_BREAKPOINT } from "../../utils/breakpoints";
4
+ import ChatConfigurationMobileShell from "./configuration/ChatConfigurationMobileShell.vue";
3
5
  const props = defineProps({
4
6
  open: { type: Boolean, required: true },
5
7
  settings: { type: null, required: false },
@@ -11,6 +13,8 @@ const { uploadFiles, uploading } = useFileUpload();
11
13
  const { canvas, projects, workstations, loadingWorkstations } = useTela();
12
14
  const { setKnowledgeSources } = useKnowledgeSources();
13
15
  const statusToast = useStatusToast();
16
+ const breakpoints = useBreakpoints({ mobile: CHAT_MOBILE_BREAKPOINT });
17
+ const isMobile = breakpoints.smaller("mobile");
14
18
  const { escape } = useMagicKeys();
15
19
  const {
16
20
  settings: workspaceSettings,
@@ -21,6 +25,7 @@ const {
21
25
  const features = useChatNuxtFeatures();
22
26
  const searchQuery = ref("");
23
27
  const activeTab = ref(props.initialTab);
28
+ const activeMobileTab = ref(null);
24
29
  const showDiscardConfirm = ref(false);
25
30
  const loadingInitialSettings = ref(false);
26
31
  const hasSettingsOverride = computed(() => props.settings !== void 0);
@@ -56,6 +61,7 @@ watch(() => props.open, (isOpen) => {
56
61
  if (isOpen) {
57
62
  searchQuery.value = "";
58
63
  activateTab(props.initialTab);
64
+ activeMobileTab.value = null;
59
65
  if (!hasSettingsOverride.value && !mutableSettings.value) {
60
66
  void loadSettings();
61
67
  return;
@@ -91,6 +97,10 @@ function activateTab(tab) {
91
97
  if (activeTab.value === "external-skills")
92
98
  void externalSkills.fetchGitHubConnection();
93
99
  }
100
+ function activateMobileTab(tab) {
101
+ activateTab(tab);
102
+ activeMobileTab.value = activeTab.value;
103
+ }
94
104
  async function loadSettings() {
95
105
  loadingInitialSettings.value = true;
96
106
  try {
@@ -182,7 +192,103 @@ function cancelDiscard() {
182
192
  </script>
183
193
 
184
194
  <template>
195
+ <Teleport to="body">
196
+ <ChatConfigurationMobileShell
197
+ v-if="isMobile && open"
198
+ :tabs="settingsTabs"
199
+ :active-tab="activeMobileTab"
200
+ :has-changes="hasChanges"
201
+ :is-busy="isBusy"
202
+ @select-tab="activateMobileTab"
203
+ @back="activeMobileTab = null"
204
+ @close="handleClose"
205
+ @save="handleSave"
206
+ >
207
+ <div
208
+ v-if="loadingInitialSettings"
209
+ h-full min-h-320px flex="~ col" items-center justify-center gap-12px
210
+ >
211
+ <div i-ph-spinner animate-spin text-24px text-gray-500 />
212
+ <p text-14px text-gray-500>
213
+ Carregando configurações...
214
+ </p>
215
+ </div>
216
+
217
+ <ChatConfigurationPersonalizationTab
218
+ v-else-if="activeTab === 'personalization'"
219
+ v-model:system-message="personalization.localSystemMessage.value"
220
+ />
221
+
222
+ <ChatConfigurationContextFilesTab
223
+ v-else-if="activeTab === 'context-files'"
224
+ :search-query="searchQuery"
225
+ :filtered-context-files="contextFiles.filteredContextFiles.value"
226
+ :filtered-pending-files="contextFiles.filteredPendingFiles.value"
227
+ :current-file-count="contextFiles.currentFileCount.value"
228
+ :max-files="contextFiles.maxFiles"
229
+ :get-file-type="contextFiles.getFileType"
230
+ @update:search-query="searchQuery = $event"
231
+ @handle-file-select="contextFiles.handleFileSelect"
232
+ @remove-pending-file="contextFiles.removePendingFile"
233
+ @remove-context-file="contextFiles.removeContextFile"
234
+ />
235
+
236
+ <ChatConfigurationKnowledgeSourcesTab
237
+ v-else-if="activeTab === 'knowledge-sources'"
238
+ :search-query="searchQuery"
239
+ :workstations="workstations"
240
+ :loading-workstations="loadingWorkstations"
241
+ :filtered-workstations="knowledgeSources.filteredWorkstations.value"
242
+ :selected-ids="knowledgeSources.selectedKnowledgeSourceIds.value"
243
+ :get-project-name-for-workstation="knowledgeSources.getProjectNameForWorkstation"
244
+ @update:search-query="searchQuery = $event"
245
+ @toggle="knowledgeSources.toggleKnowledgeSource"
246
+ />
247
+
248
+ <ChatConfigurationTelaToolsTab
249
+ v-else-if="activeTab === 'tela-tools'"
250
+ :search-query="searchQuery"
251
+ :canvas="canvas"
252
+ :filtered-canvas-tools="telaTools.filteredCanvasTools.value"
253
+ :selected-tool-ids="telaTools.selectedToolIds.value"
254
+ :all-tools-selected="telaTools.allToolsSelected.value"
255
+ :get-project-name="telaTools.getProjectName"
256
+ @update:search-query="searchQuery = $event"
257
+ @toggle-tool="telaTools.toggleCanvasTool"
258
+ @toggle-all="telaTools.toggleAllTools"
259
+ />
260
+
261
+ <ChatConfigurationExternalSkillsTab
262
+ v-else-if="activeTab === 'external-skills'"
263
+ :search-query="searchQuery"
264
+ :displayed-skills="externalSkills.displayedSkills.value"
265
+ :filtered-skills="externalSkills.filteredSkills.value"
266
+ :has-changes="externalSkills.hasChanges.value"
267
+ :is-pending="externalSkills.isPending"
268
+ :skill-modal-open="externalSkills.skillModalOpen.value"
269
+ :skill-ref-input="externalSkills.skillRefInput.value"
270
+ :skill-error="externalSkills.skillError.value"
271
+ :discovering-skills="externalSkills.discoveringSkills.value"
272
+ :git-hub-button-text="gitHubButtonText"
273
+ @update:search-query="searchQuery = $event"
274
+ @update:skill-modal-open="externalSkills.skillModalOpen.value = $event"
275
+ @update:skill-ref-input="externalSkills.skillRefInput.value = $event"
276
+ @remove-skill="externalSkills.removeSkill"
277
+ @close-skill-modal="externalSkills.closeSkillModal"
278
+ @handle-add-skill-and-close="externalSkills.handleAddSkillAndClose"
279
+ @connect-git-hub="externalSkills.connectGitHub"
280
+ />
281
+
282
+ <ChatConfigurationCredentialsTab
283
+ v-else-if="activeTab === 'credentials' && features.credentials"
284
+ :search-query="searchQuery"
285
+ @update:search-query="searchQuery = $event"
286
+ />
287
+ </ChatConfigurationMobileShell>
288
+ </Teleport>
289
+
185
290
  <TelaModal
291
+ v-if="!isMobile"
186
292
  :model-value="open"
187
293
  modal-width="lg"
188
294
  compact
@@ -359,17 +465,17 @@ function cancelDiscard() {
359
465
  </div>
360
466
  </div>
361
467
  </div>
362
-
363
- <TelaConfirmationModal
364
- v-model:open="showDiscardConfirm"
365
- title="Descartar alterações?"
366
- variant="danger"
367
- confirm-button-text="Descartar"
368
- cancel-button-text="Continuar editando"
369
- @confirm="confirmDiscard"
370
- @cancel="cancelDiscard"
371
- >
372
- Você tem alterações não salvas. Deseja descartá-las?
373
- </TelaConfirmationModal>
374
468
  </TelaModal>
469
+
470
+ <TelaConfirmationModal
471
+ v-model:open="showDiscardConfirm"
472
+ title="Descartar alterações?"
473
+ variant="danger"
474
+ confirm-button-text="Descartar"
475
+ cancel-button-text="Continuar editando"
476
+ @confirm="confirmDiscard"
477
+ @cancel="cancelDiscard"
478
+ >
479
+ Você tem alterações não salvas. Deseja descartá-las?
480
+ </TelaConfirmationModal>
375
481
  </template>
@@ -9,6 +9,7 @@ const props = defineProps({
9
9
  initialConversationId: { type: [String, null], required: false },
10
10
  conversationScope: { type: [String, null], required: false },
11
11
  hideSidebar: { type: Boolean, required: false },
12
+ hideSettings: { type: Boolean, required: false },
12
13
  loadingMessages: { type: [Array, null], required: false },
13
14
  loadingMessagesMode: { type: [String, null], required: false },
14
15
  customComponents: { type: Object, required: false },
@@ -25,6 +26,7 @@ const { activeOrganization } = useChatAuth();
25
26
  const workspaceId = computed(() => activeOrganization.value?.id?.trim() ?? "");
26
27
  const normalizedTelaAgentId = computed(() => normalizeTelaAgentId(props.telaAgentId));
27
28
  const normalizedConversationScope = computed(() => normalizeConversationScope(props.conversationScope));
29
+ const hideSettings = computed(() => props.hideSettings ?? false);
28
30
  const ignoredPropsWarningKey = ref(null);
29
31
  provideEmbedConfig({
30
32
  workspaceId,
@@ -33,6 +35,7 @@ provideEmbedConfig({
33
35
  telaAgentInputs: computed(() => props.telaAgentInputs),
34
36
  workspaceSettings: computed(() => props.workspaceSettings),
35
37
  hideSidebar: computed(() => props.hideSidebar),
38
+ hideSettings,
36
39
  loadingMessages: computed(() => props.loadingMessages),
37
40
  loadingMessagesMode: computed(() => props.loadingMessagesMode),
38
41
  customComponents: computed(() => props.customComponents),
@@ -69,6 +72,7 @@ provideChatAction((payload) => {
69
72
  :conversation-id="conversationId"
70
73
  :initial-conversation-id="initialConversationId"
71
74
  :hide-sidebar="hideSidebar"
75
+ :hide-settings="hideSettings"
72
76
  :user="normalizedTelaAgentId ? null : user"
73
77
  :features="features"
74
78
  @update:conversation-id="$emit('update:conversationId', $event)"
@@ -4,6 +4,7 @@ type __VLS_Props = {
4
4
  conversationId?: string | null;
5
5
  initialConversationId?: string | null;
6
6
  hideSidebar?: boolean;
7
+ hideSettings?: boolean;
7
8
  user?: EmbedUser | null;
8
9
  features?: Partial<ChatFeatureConfig>;
9
10
  };
@@ -14,6 +15,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
14
15
  }>, {
15
16
  initialConversationId: string | null;
16
17
  hideSidebar: boolean;
18
+ hideSettings: boolean;
17
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
20
  declare const _default: typeof __VLS_export;
19
21
  export default _default;