@meistrari/chat-nuxt 4.10.0-rc.2 → 4.10.0-rc.20

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 (134) hide show
  1. package/README.md +8 -6
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +2 -0
  4. package/dist/runtime/conversations/components/chat-conversation-export-modal.d.vue.ts +10 -0
  5. package/dist/runtime/conversations/components/chat-conversation-export-modal.vue +126 -0
  6. package/dist/runtime/conversations/components/chat-conversation-export-modal.vue.d.ts +10 -0
  7. package/dist/runtime/conversations/components/chat-conversation-list.vue +8 -1
  8. package/dist/runtime/{rendering/components/openui/bar-chart.d.vue.ts → conversations/components/chat-export-document.d.vue.ts} +2 -5
  9. package/dist/runtime/conversations/components/chat-export-document.vue +26 -0
  10. package/dist/runtime/{rendering/components/openui/bar-chart.vue.d.ts → conversations/components/chat-export-document.vue.d.ts} +2 -5
  11. package/dist/runtime/{rendering/components/openui/checkbox.d.vue.ts → conversations/components/chat-export-file.d.vue.ts} +1 -1
  12. package/dist/runtime/conversations/components/chat-export-file.vue +12 -0
  13. package/dist/runtime/{rendering/components/openui/checkbox.vue.d.ts → conversations/components/chat-export-file.vue.d.ts} +1 -1
  14. package/dist/runtime/{rendering/components/openui/buttons.d.vue.ts → conversations/components/chat-export-message.d.vue.ts} +2 -3
  15. package/dist/runtime/conversations/components/chat-export-message.vue +84 -0
  16. package/dist/runtime/{rendering/components/openui/bar.vue.d.ts → conversations/components/chat-export-message.vue.d.ts} +2 -5
  17. package/dist/runtime/{rendering/components/openui/bar.d.vue.ts → conversations/components/chat-export-openui.d.vue.ts} +3 -4
  18. package/dist/runtime/conversations/components/chat-export-openui.vue +19 -0
  19. package/dist/runtime/conversations/components/chat-export-openui.vue.d.ts +9 -0
  20. package/dist/runtime/{rendering/components/openui/callout.d.vue.ts → conversations/components/chat-export-questions.d.vue.ts} +12 -4
  21. package/dist/runtime/conversations/components/chat-export-questions.vue +22 -0
  22. package/dist/runtime/{rendering/components/openui/callout.vue.d.ts → conversations/components/chat-export-questions.vue.d.ts} +12 -4
  23. package/dist/runtime/conversations/composables/conversation-list.d.ts +2 -1
  24. package/dist/runtime/conversations/composables/conversation-list.js +4 -13
  25. package/dist/runtime/conversations/export-document.d.ts +1 -0
  26. package/dist/runtime/conversations/export-document.js +154 -0
  27. package/dist/runtime/conversations/export.d.ts +4 -0
  28. package/dist/runtime/conversations/export.js +69 -4
  29. package/dist/runtime/embed/components/chat-embed-inner.vue +81 -7
  30. package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +3 -2
  31. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue +2 -0
  32. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +3 -2
  33. package/dist/runtime/embed/execution-controls.d.ts +2 -1
  34. package/dist/runtime/embed/execution-controls.js +2 -2
  35. package/dist/runtime/messages/components/chat-execution-mode-selector.vue +10 -6
  36. package/dist/runtime/messages/components/chat-message-bubble.vue +7 -0
  37. package/dist/runtime/messages/components/chat-message-input.d.vue.ts +2 -0
  38. package/dist/runtime/messages/components/chat-message-input.vue +18 -1
  39. package/dist/runtime/messages/components/chat-message-input.vue.d.ts +2 -0
  40. package/dist/runtime/messages/composables/chat.d.ts +15 -0
  41. package/dist/runtime/messages/composables/chat.js +49 -5
  42. package/dist/runtime/messages/composer-draft.d.ts +16 -0
  43. package/dist/runtime/messages/composer-draft.js +61 -0
  44. package/dist/runtime/messages/composer-pending-send.d.ts +8 -0
  45. package/dist/runtime/messages/composer-pending-send.js +34 -0
  46. package/dist/runtime/messages/conversation-timeline.js +1 -1
  47. package/dist/runtime/rendering/components/openui/{markdown.d.vue.ts → markdown-prose.d.vue.ts} +1 -3
  48. package/dist/runtime/rendering/components/openui/{markdown.vue → markdown-prose.vue} +3 -3
  49. package/dist/runtime/rendering/components/openui/{markdown.vue.d.ts → markdown-prose.vue.d.ts} +1 -3
  50. package/dist/runtime/rendering/components/openui-block.vue +26 -52
  51. package/dist/runtime/rendering/openui/context.d.ts +2 -17
  52. package/dist/runtime/rendering/openui/context.js +0 -2
  53. package/dist/runtime/server/utils/chat-api-proxy.js +3 -2
  54. package/dist/runtime/types/composer.d.ts +6 -0
  55. package/dist/runtime/types/schemas/chat/chat-config.d.ts +6 -2
  56. package/dist/runtime/types/schemas/chat/chat-config.js +1 -0
  57. package/dist/runtime/types/schemas/chat/conversation-runtime.d.ts +8 -0
  58. package/dist/runtime/types/schemas/chat/conversations.d.ts +8 -0
  59. package/dist/runtime/types/schemas/chat/messages.d.ts +12 -0
  60. package/dist/runtime/types/schemas/chat/ui-language.d.ts +19 -2
  61. package/dist/runtime/types/schemas/chat/ui-language.js +8 -3
  62. package/dist/runtime/types/schemas/chat/v3.d.ts +160 -2
  63. package/dist/runtime/types/schemas/chat/v3.js +91 -5
  64. package/dist/runtime/types/schemas/integrations/slack-apps.d.ts +53 -0
  65. package/dist/runtime/types/schemas/integrations/slack-apps.js +6 -0
  66. package/dist/runtime/types/schemas/integrations/slack-identity.d.ts +26 -0
  67. package/dist/runtime/types/schemas/integrations/slack-identity.js +23 -0
  68. package/dist/runtime/types/schemas/integrations/tela-agent-api.d.ts +40 -0
  69. package/dist/runtime/types/schemas/integrations/tela-agent-api.js +3 -0
  70. package/dist/runtime/types/schemas/integrations/tela-api.d.ts +11 -0
  71. package/dist/runtime/types/schemas/integrations/tela-api.js +8 -0
  72. package/dist/runtime/types/schemas/integrations/tela-auth.d.ts +39 -0
  73. package/dist/runtime/types/schemas/integrations/tela-auth.js +12 -0
  74. package/dist/runtime/types/schemas/slack/apps.d.ts +144 -0
  75. package/dist/runtime/types/schemas/slack/apps.js +53 -0
  76. package/dist/runtime/types/schemas/slack/identities.d.ts +58 -0
  77. package/dist/runtime/types/schemas/slack/identities.js +19 -0
  78. package/dist/runtime/types/schemas/slack/installations.d.ts +39 -0
  79. package/dist/runtime/types/schemas/slack/installations.js +18 -0
  80. package/package.json +2 -2
  81. package/dist/runtime/rendering/components/openui/bar-chart.vue +0 -39
  82. package/dist/runtime/rendering/components/openui/bar.vue +0 -12
  83. package/dist/runtime/rendering/components/openui/button.d.vue.ts +0 -11
  84. package/dist/runtime/rendering/components/openui/button.vue +0 -30
  85. package/dist/runtime/rendering/components/openui/button.vue.d.ts +0 -11
  86. package/dist/runtime/rendering/components/openui/buttons.vue +0 -14
  87. package/dist/runtime/rendering/components/openui/buttons.vue.d.ts +0 -8
  88. package/dist/runtime/rendering/components/openui/callout.vue +0 -27
  89. package/dist/runtime/rendering/components/openui/card.d.vue.ts +0 -9
  90. package/dist/runtime/rendering/components/openui/card.vue +0 -19
  91. package/dist/runtime/rendering/components/openui/card.vue.d.ts +0 -9
  92. package/dist/runtime/rendering/components/openui/checkbox.vue +0 -26
  93. package/dist/runtime/rendering/components/openui/col.d.vue.ts +0 -10
  94. package/dist/runtime/rendering/components/openui/col.vue +0 -16
  95. package/dist/runtime/rendering/components/openui/col.vue.d.ts +0 -10
  96. package/dist/runtime/rendering/components/openui/form.d.vue.ts +0 -10
  97. package/dist/runtime/rendering/components/openui/form.vue +0 -60
  98. package/dist/runtime/rendering/components/openui/form.vue.d.ts +0 -10
  99. package/dist/runtime/rendering/components/openui/input.d.vue.ts +0 -10
  100. package/dist/runtime/rendering/components/openui/input.vue +0 -23
  101. package/dist/runtime/rendering/components/openui/input.vue.d.ts +0 -10
  102. package/dist/runtime/rendering/components/openui/metric.d.vue.ts +0 -11
  103. package/dist/runtime/rendering/components/openui/metric.vue +0 -20
  104. package/dist/runtime/rendering/components/openui/metric.vue.d.ts +0 -11
  105. package/dist/runtime/rendering/components/openui/option.d.vue.ts +0 -10
  106. package/dist/runtime/rendering/components/openui/option.vue +0 -12
  107. package/dist/runtime/rendering/components/openui/option.vue.d.ts +0 -10
  108. package/dist/runtime/rendering/components/openui/question.d.vue.ts +0 -11
  109. package/dist/runtime/rendering/components/openui/question.vue +0 -15
  110. package/dist/runtime/rendering/components/openui/question.vue.d.ts +0 -11
  111. package/dist/runtime/rendering/components/openui/questions.d.vue.ts +0 -9
  112. package/dist/runtime/rendering/components/openui/questions.vue +0 -91
  113. package/dist/runtime/rendering/components/openui/questions.vue.d.ts +0 -9
  114. package/dist/runtime/rendering/components/openui/select.d.vue.ts +0 -10
  115. package/dist/runtime/rendering/components/openui/select.vue +0 -27
  116. package/dist/runtime/rendering/components/openui/select.vue.d.ts +0 -10
  117. package/dist/runtime/rendering/components/openui/stack.d.vue.ts +0 -9
  118. package/dist/runtime/rendering/components/openui/stack.vue +0 -18
  119. package/dist/runtime/rendering/components/openui/stack.vue.d.ts +0 -9
  120. package/dist/runtime/rendering/components/openui/table.d.vue.ts +0 -9
  121. package/dist/runtime/rendering/components/openui/table.vue +0 -41
  122. package/dist/runtime/rendering/components/openui/table.vue.d.ts +0 -9
  123. package/dist/runtime/rendering/openui/actions.d.ts +0 -15
  124. package/dist/runtime/rendering/openui/actions.js +0 -40
  125. package/dist/runtime/rendering/openui/form-fields.d.ts +0 -10
  126. package/dist/runtime/rendering/openui/form-fields.js +0 -30
  127. package/dist/runtime/rendering/openui/program.d.ts +0 -15
  128. package/dist/runtime/rendering/openui/program.js +0 -74
  129. package/dist/runtime/rendering/openui/registry.d.ts +0 -5
  130. package/dist/runtime/rendering/openui/registry.js +0 -44
  131. package/dist/runtime/rendering/openui/render.d.ts +0 -21
  132. package/dist/runtime/rendering/openui/render.js +0 -45
  133. package/dist/runtime/rendering/openui/use-openui-context.d.ts +0 -2
  134. package/dist/runtime/rendering/openui/use-openui-context.js +0 -8
package/README.md CHANGED
@@ -101,7 +101,7 @@ Declared in `src/runtime/embed/types.ts`; prop, feature-flag, and event payload
101
101
  | `defaultConversationCreatorFilter` | `'all' \| 'mine'` | `'all'` | Initial sidebar creator filter: every conversation in scope, or only the current user's |
102
102
  | `availableModels` | `AvailableChatModels` | Harness catalog | Visual filter and ordering for catalog options. Unknown ids are omitted; if no ids match, the full catalog is shown. Does not change defaults, restored selections or execution. The Agent validates availability |
103
103
  | `defaultModel` | `ChatModel` | Package default | Initial model for untouched drafts. Explicit selections and existing conversations take precedence; `availableModels` only filters the selector |
104
- | `executionControls` | `ChatExecutionControls` | Legacy feature flags | Choose `hidden`, `simple` (Padrão / Aprofundar), or `advanced` (model and effort pickers). See below |
104
+ | `executionControls` | `ChatExecutionControls` | Legacy feature flags | Choose `hidden`, `simple` (Padrão / Aprofundado, plus optional Intensivo), or `advanced` (model and effort pickers). See below |
105
105
  | `defaultReasoningEffort` | `ChatReasoningEffort` | Automatic (`null`) | Initial reasoning effort for untouched drafts. Explicit user choices (including automatic) take precedence |
106
106
  | `conversationCreatorFilter` | `'all' \| 'mine'` | — | Controlled sidebar creator filter; use with `v-model:conversation-creator-filter` when the host changes it at runtime |
107
107
  | `hideConversationCreatorFilter` | `boolean` | `false` | Hide the creator selector without changing the active filter |
@@ -197,14 +197,16 @@ it takes precedence over both legacy flags as a whole.
197
197
  mode: 'simple',
198
198
  profiles: {
199
199
  default: { model: standardModelId, reasoningEffort: 'medium' },
200
- deep: { model: deepModelId, reasoningEffort: 'high' },
200
+ deep: { model: deepModelId, reasoningEffort: 'medium' },
201
+ intensive: { model: deepModelId, reasoningEffort: 'xhigh' },
201
202
  },
202
203
  }"
203
204
  />
204
205
  ```
205
206
 
206
207
  Supply model IDs available to the configured agent and effort levels supported
207
- by those models. Both profiles may use the same model. An explicit `null` effort
208
+ by those models. The `intensive` profile is optional: omit it to keep a two-mode
209
+ menu. All profiles may use the same model. An explicit `null` effort
208
210
  uses the agent's configured effort. Profile selection keeps both settings local
209
211
  until the next send or fresh retry. That request persists the settings and records
210
212
  each changed field in the conversation history. Reloading discards unsent choices;
@@ -219,10 +221,10 @@ selection still causes both fields to reset for a new conversation. Manually
219
221
  replacing both fields in advanced mode retains the existing behavior of carrying
220
222
  them over to new conversations.
221
223
  Restored conversations keep their settings: the control shows
222
- **Personalizado** when the saved model and effort do not match either profile.
223
- The menu still offers only **Padrão** and **Aprofundar**. Changes apply to subsequent
224
+ **Personalizado** when the saved model and effort do not match any configured profile.
225
+ The menu offers **Padrão** and **Aprofundado**, plus **Intensivo** when configured. Changes apply to subsequent
224
226
  messages and do not regenerate earlier responses. If profiles are identical,
225
- **Padrão** wins the label match.
227
+ **Padrão** wins the label match, followed by **Aprofundado**, then **Intensivo**.
226
228
 
227
229
  In `hidden` and `advanced` modes, the existing model and effort defaults and saved
228
230
  conversation settings retain their behavior. Hiding controls does not force a
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "4.10.0-rc.2",
4
+ "version": "4.10.0-rc.20",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -2,6 +2,7 @@ import { existsSync, readFileSync, mkdirSync, symlinkSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
3
  import { join, dirname, isAbsolute } from 'node:path';
4
4
  import { defineNuxtModule, createResolver, addTemplate, addTypeTemplate, addPlugin, addImportsDir, addComponent, addComponentsDir } from 'nuxt/kit';
5
+ import { registerOpenuiWidget } from '@meistrari/chat-ui-lang/nuxt';
5
6
  import { TOOL_ICON_SAFELIST } from '../dist/runtime/messages/tool-registry.js';
6
7
  export { ChatMessageStatus } from '../dist/runtime/types/message-status.js';
7
8
 
@@ -454,6 +455,7 @@ const module$1 = defineNuxtModule({
454
455
  const runtimeDirRegExp = new RegExp(runtimeDir.replace(/\\/g, "/").replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
455
456
  normalizedImports.transform.include.push(runtimeDirRegExp);
456
457
  }
458
+ registerOpenuiWidget(nuxt);
457
459
  const rc = nuxt.options.runtimeConfig;
458
460
  rc.chatApiUrl = options.chatApiUrl || rc.chatApiUrl || process.env.CHAT_API_URL || "";
459
461
  rc.public = rc.public || {};
@@ -0,0 +1,10 @@
1
+ type __VLS_Props = {
2
+ conversationId: string;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
5
+ close: () => any;
6
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
7
+ onClose?: (() => any) | undefined;
8
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const _default: typeof __VLS_export;
10
+ export default _default;
@@ -0,0 +1,126 @@
1
+ <script setup>
2
+ import { useChatApi } from "../../shared/composables/chat-api";
3
+ import { captureConversationDocument } from "../export-document";
4
+ import { conversationExportFilename, downloadConversationFile, exportConversationToMarkdown, renderedConversationToText } from "../export";
5
+ const props = defineProps({
6
+ conversationId: { type: String, required: true }
7
+ });
8
+ const emit = defineEmits(["close"]);
9
+ const chatApi = useChatApi();
10
+ const format = ref("pdf");
11
+ const preparing = ref(false);
12
+ const error = ref(null);
13
+ const conversation = shallowRef(null);
14
+ const documentContainer = ref(null);
15
+ let controller = null;
16
+ const formats = [
17
+ { value: "pdf", label: "PDF (.pdf)", description: "Conversa formatada, com os widgets renderizados." },
18
+ { value: "txt", label: "Texto (.txt)", description: "Texto simples, com o conte\xFAdo dos widgets." },
19
+ { value: "md", label: "Markdown (.md)", description: "Formata\xE7\xE3o Markdown e c\xF3digo original dos widgets." }
20
+ ];
21
+ onBeforeUnmount(() => controller?.abort());
22
+ function close() {
23
+ controller?.abort();
24
+ emit("close");
25
+ }
26
+ async function exportConversation() {
27
+ if (preparing.value)
28
+ return;
29
+ preparing.value = true;
30
+ error.value = null;
31
+ controller = new AbortController();
32
+ const signal = controller.signal;
33
+ const selectedFormat = format.value;
34
+ try {
35
+ const data = await $fetch(chatApi.path(`/conversations/${props.conversationId}`), chatApi.withChatHeaders({ signal }));
36
+ signal.throwIfAborted();
37
+ if (selectedFormat === "md") {
38
+ exportConversationToMarkdown(data);
39
+ } else {
40
+ conversation.value = data;
41
+ await nextTick();
42
+ const root = documentContainer.value?.querySelector("[data-export-document]");
43
+ if (!root)
44
+ throw new Error("N\xE3o foi poss\xEDvel preparar a conversa.");
45
+ const html = await captureConversationDocument(root, signal, selectedFormat === "pdf");
46
+ const blob = selectedFormat === "txt" ? new Blob([renderedConversationToText(html)], { type: "text/plain;charset=utf-8" }) : await $fetch(chatApi.path(`/conversations/${props.conversationId}/export/pdf`), chatApi.withChatHeaders({
47
+ method: "POST",
48
+ body: { html },
49
+ responseType: "blob",
50
+ signal,
51
+ retry: 0,
52
+ timeout: 45e3
53
+ }));
54
+ signal.throwIfAborted();
55
+ downloadConversationFile(blob, conversationExportFilename(data.title, selectedFormat));
56
+ }
57
+ emit("close");
58
+ } catch (cause) {
59
+ if (signal.aborted)
60
+ return;
61
+ const status = cause.statusCode;
62
+ error.value = status === 429 ? "H\xE1 outra exporta\xE7\xE3o de PDF em andamento. Aguarde um momento e tente novamente." : status === 413 ? "Esta conversa excede o tamanho permitido para PDF. Voc\xEA pode export\xE1-la como texto ou Markdown." : status === 504 ? "A gera\xE7\xE3o do PDF demorou mais que o esperado. Tente novamente." : "N\xE3o foi poss\xEDvel exportar a conversa. Tente novamente.";
63
+ } finally {
64
+ preparing.value = false;
65
+ conversation.value = null;
66
+ }
67
+ }
68
+ </script>
69
+
70
+ <template>
71
+ <TelaModal
72
+ :model-value="true"
73
+ modal-width="sm"
74
+ :compact="true"
75
+ :hide-dividers="true"
76
+ :is-close-icon="false"
77
+ class="chat-sidebar-floating"
78
+ @update:model-value="(value) => {
79
+ if (!value) close();
80
+ }"
81
+ >
82
+ <div flex="~ col" w-full gap-24px>
83
+ <div flex items-start justify-between gap-16px>
84
+ <div flex="~ col" gap-4px>
85
+ <h4 heading-h4-semibold text-primary>
86
+ Exportar conversa
87
+ </h4>
88
+ <p body-14-regular text-secondary>
89
+ Escolha o formato do arquivo.
90
+ </p>
91
+ </div>
92
+ <TelaIconButton icon="i-ph-x" size="md" color="secondary" aria-label="Fechar exportação" mt--12px mr--16px @click="close" />
93
+ </div>
94
+ <TelaRadioGroupRoot v-model="format" :disabled="preparing" aria-label="Formato do arquivo" flex="~ col" gap-12px w-full>
95
+ <label v-for="option in formats" :key="option.value" flex items-start gap-12px border rounded-12px p-12px cursor-pointer>
96
+ <TelaRadioGroupItem :value="option.value" mt-2px />
97
+ <span flex="~ col" gap-4px>
98
+ <span body-14-medium text-primary>{{ option.label }}</span>
99
+ <span body-12-regular text-secondary>{{ option.description }}</span>
100
+ </span>
101
+ </label>
102
+ </TelaRadioGroupRoot>
103
+ <p v-if="error" role="alert" body-14-regular text-red-600>
104
+ {{ error }}
105
+ </p>
106
+ <p v-if="preparing" role="status" body-14-regular text-secondary>
107
+ Preparando arquivo…
108
+ </p>
109
+ <div flex justify-end gap-8px>
110
+ <TelaButton variant="secondary" @click="close">
111
+ Cancelar
112
+ </TelaButton>
113
+ <TelaButton :loading="preparing" @click="exportConversation">
114
+ Exportar
115
+ </TelaButton>
116
+ </div>
117
+ </div>
118
+ </TelaModal>
119
+ <div v-if="conversation" ref="documentContainer" aria-hidden="true" inert class="chat-export-container">
120
+ <ChatExportDocument :conversation="conversation" />
121
+ </div>
122
+ </template>
123
+
124
+ <style scoped>
125
+ .chat-export-container{left:-10000px;pointer-events:none;position:fixed;top:0;width:672px}
126
+ </style>
@@ -0,0 +1,10 @@
1
+ type __VLS_Props = {
2
+ conversationId: string;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
5
+ close: () => any;
6
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
7
+ onClose?: (() => any) | undefined;
8
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const _default: typeof __VLS_export;
10
+ export default _default;
@@ -42,6 +42,7 @@ const {
42
42
  handleRename,
43
43
  handleDuplicate,
44
44
  handleExport,
45
+ exportConversationId,
45
46
  handleConversationDragStart,
46
47
  clearDragState,
47
48
  handleDragEnter,
@@ -313,7 +314,7 @@ function dropTargetClass(row) {
313
314
  Pastas
314
315
  </span>
315
316
  <TelaIconButton
316
- icon="i-ph-plus"
317
+ icon="i-ph-folder-plus"
317
318
  color="secondary"
318
319
  size="sm"
319
320
  button-class="p-3px! rounded-6px!"
@@ -498,6 +499,12 @@ function dropTargetClass(row) {
498
499
  {{ deleteGroupConversationsConfirmationMessage }}
499
500
  </TelaConfirmationModal>
500
501
 
502
+ <ChatConversationExportModal
503
+ v-if="exportConversationId"
504
+ :conversation-id="exportConversationId"
505
+ @close="exportConversationId = null"
506
+ />
507
+
501
508
  <ChatConversationDebugModal
502
509
  :open="!!debugConversation"
503
510
  :conversation="debugConversation"
@@ -1,9 +1,6 @@
1
+ import type { ConversationWithMessages } from '../../types/schemas/chat/conversations.js';
1
2
  type __VLS_Props = {
2
- props: {
3
- title: string;
4
- bars: unknown[];
5
- tone?: 'neutral' | 'positive' | 'negative';
6
- };
3
+ conversation: ConversationWithMessages;
7
4
  };
8
5
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
6
  declare const _default: typeof __VLS_export;
@@ -0,0 +1,26 @@
1
+ <script setup>
2
+ defineProps({
3
+ conversation: { type: null, required: true }
4
+ });
5
+ </script>
6
+
7
+ <template>
8
+ <div class="chat-export-document" data-export-document>
9
+ <header mb-24px>
10
+ <h1 heading-h3-semibold mb-12px>
11
+ {{ conversation.title || "Conversa" }}
12
+ </h1>
13
+ <p body-14-regular>
14
+ Criada por: {{ conversation.createdBy || "Desconhecido" }}
15
+ </p>
16
+ <p body-14-regular>
17
+ Criada em: {{ new Date(conversation.createdAt).toLocaleString("pt-BR") }}
18
+ </p>
19
+ </header>
20
+ <ChatExportMessage v-for="message in conversation.messages" :key="message.id" :message="message" />
21
+ </div>
22
+ </template>
23
+
24
+ <style scoped>
25
+ .chat-export-document{background:#fff;color:#202020;font-family:Arial,sans-serif;line-height:1.5;overflow-wrap:anywhere;width:672px}.chat-export-document :deep([data-export-message]){margin-bottom:24px}.chat-export-document :deep(button){pointer-events:none}.chat-export-document :deep(*){animation:none!important;text-overflow:clip!important;transition:none!important}.chat-export-document :deep(pre){white-space:pre-wrap}
26
+ </style>
@@ -1,9 +1,6 @@
1
+ import type { ConversationWithMessages } from '../../types/schemas/chat/conversations.js';
1
2
  type __VLS_Props = {
2
- props: {
3
- title: string;
4
- bars: unknown[];
5
- tone?: 'neutral' | 'positive' | 'negative';
6
- };
3
+ conversation: ConversationWithMessages;
7
4
  };
8
5
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
6
  declare const _default: typeof __VLS_export;
@@ -1,7 +1,7 @@
1
1
  type __VLS_Props = {
2
2
  props: {
3
3
  name: string;
4
- label: string;
4
+ vaultRef: string;
5
5
  };
6
6
  };
7
7
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -0,0 +1,12 @@
1
+ <script setup>
2
+ defineProps({
3
+ props: { type: Object, required: true }
4
+ });
5
+ </script>
6
+
7
+ <template>
8
+ <div data-openui="file-card" border rounded-8px p-12px flex="~ col" gap-4px>
9
+ <span body-14-medium>{{ props.name }}</span>
10
+ <span body-12-regular>{{ props.vaultRef }}</span>
11
+ </div>
12
+ </template>
@@ -1,7 +1,7 @@
1
1
  type __VLS_Props = {
2
2
  props: {
3
3
  name: string;
4
- label: string;
4
+ vaultRef: string;
5
5
  };
6
6
  };
7
7
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1,7 +1,6 @@
1
+ import type { Message } from '../../types/schemas/chat/conversations.js';
1
2
  type __VLS_Props = {
2
- props: {
3
- buttons: unknown[];
4
- };
3
+ message: Message;
5
4
  };
6
5
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
6
  declare const _default: typeof __VLS_export;
@@ -0,0 +1,84 @@
1
+ <script setup>
2
+ import { UI_LANG_FENCE } from "@meistrari/chat-ui-lang";
3
+ import { useEmbedConfig } from "../../embed/composables/embed-config";
4
+ import { CHAT_MESSAGE_CONTEXT_KEY, CHAT_MESSAGE_SEND_KEY } from "../../types/messages";
5
+ import { OPENUI_MARKDOWN_COMPONENTS_KEY } from "../../rendering/openui/context";
6
+ import { detectFilesInText, parseContentWithFiles } from "../../files/content-detection";
7
+ import { renderEscapedUserMentions } from "../../messages/user-mentions";
8
+ import ChatExportOpenui from "./chat-export-openui.vue";
9
+ import ChatVaultLink from "../../files/components/chat-vault-link.vue";
10
+ const props = defineProps({
11
+ message: { type: null, required: true }
12
+ });
13
+ const embed = useEmbedConfig();
14
+ provide(CHAT_MESSAGE_CONTEXT_KEY, {
15
+ messageId: props.message.id,
16
+ role: props.message.role,
17
+ isLatestMessage: ref(false),
18
+ streaming: ref(false)
19
+ });
20
+ provide(CHAT_MESSAGE_SEND_KEY, async () => false);
21
+ const customComponents = computed(() => ({
22
+ ...embed?.customComponents.value ?? {},
23
+ link: ChatVaultLink,
24
+ [UI_LANG_FENCE]: ChatExportOpenui
25
+ }));
26
+ provide(OPENUI_MARKDOWN_COMPONENTS_KEY, customComponents);
27
+ const segments = computed(() => parseContentWithFiles(props.message.content, { preserveMarkdownLinks: true }));
28
+ const attachedFiles = computed(() => {
29
+ if (props.message.role !== "assistant")
30
+ return props.message.files ?? [];
31
+ const seen = new Set(detectFilesInText(props.message.content).map((file) => file.reference.split("#")[0]));
32
+ return (props.message.files ?? []).filter((file) => {
33
+ const references = [file.url, file.vaultReference].filter(Boolean).map((reference) => reference.split("#")[0]);
34
+ const duplicate = references.some((reference) => seen.has(reference));
35
+ references.forEach((reference) => seen.add(reference));
36
+ return !duplicate;
37
+ });
38
+ });
39
+ const userContent = computed(() => renderEscapedUserMentions(props.message.content.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;")));
40
+ </script>
41
+
42
+ <template>
43
+ <article data-export-message>
44
+ <h2 heading-h5-semibold mb-8px>
45
+ {{ message.role === "user" ? message.createdBy || "Usu\xE1rio" : "Assistente" }}
46
+ </h2>
47
+ <p body-12-regular mb-12px>
48
+ {{ new Date(message.createdAt).toLocaleString("pt-BR") }}
49
+ </p>
50
+ <div v-if="message.role === 'user'" whitespace-pre-wrap v-html="userContent" />
51
+ <template v-else>
52
+ <template v-for="(segment, index) in segments" :key="index">
53
+ <AppMarkdownRender
54
+ v-if="segment.type === 'text'"
55
+ :content="segment.content"
56
+ :custom-components="customComponents"
57
+ :custom-html-tags="embed?.customHtmlTags.value ?? []"
58
+ :typewriter="false"
59
+ :batch-rendering="false"
60
+ :node-virtual="false"
61
+ :defer-nodes-until-visible="false"
62
+ :render-code-blocks-as-pre="true"
63
+ :fade="false"
64
+ :final="true"
65
+ />
66
+ <div v-else-if="segment.type === 'file'" border rounded-8px p-12px>
67
+ <p>{{ segment.file.name }}</p>
68
+ <p body-12-regular>
69
+ {{ segment.file.reference }}
70
+ </p>
71
+ </div>
72
+ <p v-else>
73
+ {{ segment.citation.id }}
74
+ </p>
75
+ </template>
76
+ </template>
77
+ <div v-for="(file, index) in attachedFiles" :key="index" border rounded-8px p-12px mt-12px>
78
+ <p>{{ file.name }}</p>
79
+ <p body-12-regular>
80
+ {{ file.vaultReference || file.url }}
81
+ </p>
82
+ </div>
83
+ </article>
84
+ </template>
@@ -1,9 +1,6 @@
1
+ import type { Message } from '../../types/schemas/chat/conversations.js';
1
2
  type __VLS_Props = {
2
- props: {
3
- label: string;
4
- value: number;
5
- display?: string;
6
- };
3
+ message: Message;
7
4
  };
8
5
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
6
  declare const _default: typeof __VLS_export;
@@ -1,8 +1,7 @@
1
+ import type { CustomMarkdownNode } from '../../rendering/markdown/custom-components.js';
1
2
  type __VLS_Props = {
2
- props: {
3
- label: string;
4
- value: number;
5
- display?: string;
3
+ node: CustomMarkdownNode & {
4
+ code?: string;
6
5
  };
7
6
  };
8
7
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -0,0 +1,19 @@
1
+ <script setup>
2
+ import OpenuiMarkdownProse from "../../rendering/components/openui/markdown-prose.vue";
3
+ import OpenuiImage from "../../rendering/components/openui/image.vue";
4
+ import OpenuiCitation from "../../rendering/components/openui/citation.vue";
5
+ import ChatExportQuestions from "./chat-export-questions.vue";
6
+ import ChatExportFile from "./chat-export-file.vue";
7
+ const props = defineProps({
8
+ node: { type: Object, required: true }
9
+ });
10
+ const code = computed(() => props.node.code ?? props.node.content ?? "");
11
+ const host = {
12
+ prose: OpenuiMarkdownProse,
13
+ components: { Questions: ChatExportQuestions, FileCard: ChatExportFile, Image: OpenuiImage, Citation: OpenuiCitation }
14
+ };
15
+ </script>
16
+
17
+ <template>
18
+ <OpenuiWidget :code="code" :complete="true" :interactive="false" :send="async () => false" :host="host" />
19
+ </template>
@@ -0,0 +1,9 @@
1
+ import type { CustomMarkdownNode } from '../../rendering/markdown/custom-components.js';
2
+ type __VLS_Props = {
3
+ node: CustomMarkdownNode & {
4
+ code?: string;
5
+ };
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -1,10 +1,18 @@
1
+ type Question = {
2
+ props?: {
3
+ title?: string;
4
+ options?: {
5
+ props?: {
6
+ label?: string;
7
+ description?: string;
8
+ };
9
+ }[];
10
+ };
11
+ };
1
12
  type __VLS_Props = {
2
13
  props: {
3
- text: string;
4
- tone?: 'info' | 'success' | 'warning' | 'error';
5
- title?: string;
14
+ questions?: Question[];
6
15
  };
7
- partial?: boolean;
8
16
  };
9
17
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
18
  declare const _default: typeof __VLS_export;
@@ -0,0 +1,22 @@
1
+ <script setup>
2
+ defineProps({
3
+ props: { type: Object, required: true }
4
+ });
5
+ </script>
6
+
7
+ <template>
8
+ <section data-openui="questions" flex="~ col" gap-16px>
9
+ <div v-for="(question, index) in props.questions ?? []" :key="index">
10
+ <p body-14-medium>
11
+ {{ question.props?.title }}
12
+ </p>
13
+ <ul pl-20px>
14
+ <li v-for="(option, optionIndex) in question.props?.options ?? []" :key="optionIndex" body-14-regular>
15
+ {{ option.props?.label }}<template v-if="option.props?.description">
16
+ — {{ option.props.description }}
17
+ </template>
18
+ </li>
19
+ </ul>
20
+ </div>
21
+ </section>
22
+ </template>
@@ -1,10 +1,18 @@
1
+ type Question = {
2
+ props?: {
3
+ title?: string;
4
+ options?: {
5
+ props?: {
6
+ label?: string;
7
+ description?: string;
8
+ };
9
+ }[];
10
+ };
11
+ };
1
12
  type __VLS_Props = {
2
13
  props: {
3
- text: string;
4
- tone?: 'info' | 'success' | 'warning' | 'error';
5
- title?: string;
14
+ questions?: Question[];
6
15
  };
7
- partial?: boolean;
8
16
  };
9
17
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
18
  declare const _default: typeof __VLS_export;
@@ -111,7 +111,8 @@ export declare function useConversationList(options: ConversationListOptions): {
111
111
  handleDelete: (id: string) => Promise<void>;
112
112
  handleRename: (id: string, title: string) => Promise<void>;
113
113
  handleDuplicate: (id: string) => Promise<void>;
114
- handleExport: (id: string) => Promise<void>;
114
+ handleExport: (id: string) => void;
115
+ exportConversationId: any;
115
116
  handleConversationDragStart: (id: string) => void;
116
117
  clearDragState: () => void;
117
118
  handleDragEnter: (groupId: string | null) => void;
@@ -1,24 +1,22 @@
1
1
  import { useChatAuth } from "#chat-auth";
2
- import { exportConversationToMarkdown } from "../export.js";
3
2
  import { groupConversationsByGroup } from "../groups.js";
4
3
  import { conversationListSkeletonRows } from "../list-skeleton.js";
5
4
  import { filterConversationsByTitle } from "../search.js";
6
5
  import { resolveChatStateScope } from "../scope.js";
7
6
  import { useChat } from "../../messages/composables/chat.js";
8
- import { useChatApi } from "../../shared/composables/chat-api.js";
9
7
  import { useConversationGroups } from "./conversation-groups.js";
10
8
  import { useConversations } from "./conversations.js";
11
9
  import { useConversationActions } from "./conversation-actions.js";
12
10
  import { useEmbedConfig } from "../../embed/composables/embed-config.js";
13
11
  const DRAG_OPEN_GROUP_DELAY_MS = 400;
14
12
  export function useConversationList(options) {
15
- const chatApi = useChatApi();
16
13
  const embedConfig = useEmbedConfig();
17
14
  const { activeOrganization } = useChatAuth();
18
15
  const { deleteConversation, renameConversation, duplicateConversation, moveConversationToGroup } = useConversations();
19
16
  const { copyConversationLink } = useConversationActions();
20
17
  const { groups, fetchGroups, createGroup, deleteGroup, renameGroup, error: groupError, pendingRenameGroupId } = useConversationGroups();
21
18
  const { setConversation, currentConversation } = useChat();
19
+ const exportConversationId = ref(null);
22
20
  const debugConversationId = ref(null);
23
21
  const debugConversation = computed(() => {
24
22
  const id = debugConversationId.value;
@@ -423,16 +421,8 @@ export function useConversationList(options) {
423
421
  }
424
422
  }
425
423
  }
426
- async function handleExport(id) {
427
- try {
428
- const conversation = await $fetch(
429
- chatApi.path(`/conversations/${id}`),
430
- chatApi.withChatHeaders()
431
- );
432
- exportConversationToMarkdown(conversation);
433
- } catch (err) {
434
- console.error("Failed to export conversation:", err);
435
- }
424
+ function handleExport(id) {
425
+ exportConversationId.value = id;
436
426
  }
437
427
  function handleConversationDragStart(id) {
438
428
  draggedConversationId.value = id;
@@ -598,6 +588,7 @@ export function useConversationList(options) {
598
588
  handleRename,
599
589
  handleDuplicate,
600
590
  handleExport,
591
+ exportConversationId,
601
592
  handleConversationDragStart,
602
593
  clearDragState,
603
594
  handleDragEnter,
@@ -0,0 +1 @@
1
+ export declare function captureConversationDocument(root: HTMLElement, signal: AbortSignal, includeImages: boolean): Promise<string>;