@meistrari/chat-nuxt 3.17.0-rc.8 → 4.0.0-rc.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.
- package/README.md +6 -2
- package/dist/module.d.mts +1 -1
- package/dist/module.json +1 -1
- package/dist/runtime/assets/css/markstream.css +1 -1
- package/dist/runtime/conversations/components/chat-conversation-search.d.vue.ts +2 -3
- package/dist/runtime/conversations/components/chat-conversation-search.vue +9 -2
- package/dist/runtime/conversations/components/chat-conversation-search.vue.d.ts +2 -3
- package/dist/runtime/embed/components/chat-embed-inner.vue +9 -2
- package/dist/runtime/embed/components/chat-embed.vue +2 -0
- package/dist/runtime/embed/components/meistrari-chat-embed.vue +4 -2
- package/dist/runtime/embed/composables/embed-config.d.ts +3 -0
- package/dist/runtime/embed/composables/embed-config.js +4 -0
- package/dist/runtime/embed/types.d.ts +8 -0
- package/dist/runtime/files/content-detection.d.ts +2 -0
- package/dist/runtime/files/content-detection.js +27 -20
- package/dist/runtime/files/mime.d.ts +0 -1
- package/dist/runtime/files/mime.js +0 -4
- package/dist/runtime/files/vault-links.js +1 -1
- package/dist/runtime/messages/components/chat-message-bubble.vue +1 -1
- package/dist/runtime/messages/components/chat-message-input.vue +16 -2
- package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue +2 -1
- package/dist/runtime/messages/composables/chat.js +34 -3
- package/dist/runtime/types/composer.d.ts +22 -0
- package/dist/runtime/types/composer.js +1 -0
- package/dist/runtime/types/embed.d.ts +1 -1
- package/dist/runtime/types/schemas/chat/conversations.d.ts +6 -0
- package/dist/runtime/types/schemas/chat/models.d.ts +4 -1
- package/dist/runtime/types/schemas/chat/models.js +3 -0
- package/dist/runtime/types/schemas/chat/ui.d.ts +30 -0
- package/dist/runtime/types/schemas/chat/ui.js +4 -0
- package/dist/runtime/types/schemas/integrations/tela-agent-api.d.ts +3 -0
- package/dist/runtime/usage/formatting.js +4 -0
- package/dist/types.d.mts +1 -1
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -28,7 +28,9 @@ Runtime internals under `src/runtime/**`, generated Nuxt aliases, and workspace-
|
|
|
28
28
|
| [Citations](docs/guides/citations.md) | `cite://` chips, metadata popover, document panel |
|
|
29
29
|
| [Feature flags](docs/guides/feature-flags.md) | Usage tab, debug entry, cancel button, PostHog wiring |
|
|
30
30
|
| [Message feedback](docs/guides/message-feedback.md) | 👍/👎 controls and host-owned persistence |
|
|
31
|
+
| [Composer extension](docs/guides/composer-extension.md) | Host actions, shared attachment strip, outbound content and retry lifecycle |
|
|
31
32
|
| [Workspace settings](docs/guides/workspace-settings.md) | Settings overrides, agent runtime ownership, `<ChatConfigurationModal>` |
|
|
33
|
+
| [Upgrading to 4.0](docs/guides/upgrading-to-4.md) | Required Chat API version for v2 sends, upgrade order, vue-i18n removal |
|
|
32
34
|
|
|
33
35
|
## API Reference
|
|
34
36
|
|
|
@@ -66,6 +68,7 @@ Declared in `src/runtime/embed/types.ts`; prop, feature-flag, and event payload
|
|
|
66
68
|
| `features` | `Partial<ChatFeatureConfig>` | `{}` | Toggle `showUsageTab`, `showDebugOption`, `showCancelButton`, `showTtft`, and `chatOutboundQueue`; all released features default to `true` |
|
|
67
69
|
| `loadingMessages` | `readonly string[] \| null` | Default chat messages | Override pending-response messages |
|
|
68
70
|
| `loadingMessagesMode` | `'ordered' \| 'random' \| null` | `'ordered'` | Rotate custom messages in order or at random; only applies when `loadingMessages` has a non-empty message |
|
|
71
|
+
| `labels` | `Partial<ChatLabels>` | Portuguese defaults | Override conversation-search text; see [UI labels](docs/guides/embedding.md#ui-labels) for supported keys and surfaces |
|
|
69
72
|
| `customComponents` | `Record<string, Component>` | `undefined` | Custom markdown renderers keyed by markdown node or tag name. Components receive `node` plus the parser lifecycle props `loading` and `autoClosed` |
|
|
70
73
|
| `customHtmlTags` | `readonly string[]` | `undefined` | Extra HTML tags allowed by the markdown renderer |
|
|
71
74
|
| `citations` | `ChatCitationsConfig \| null` | `undefined` | Enables `cite://` citations in assistant messages (see [Citations](docs/guides/citations.md)) |
|
|
@@ -107,7 +110,7 @@ Installing `@meistrari/chat-nuxt` installs the runtime packages used by the laye
|
|
|
107
110
|
|---------|---------|---------|
|
|
108
111
|
| `@meistrari/auth-nuxt` | `3.31.0` | Authentication (required) |
|
|
109
112
|
| `@meistrari/logger` | `^2.1.3` | Structured logging for the server proxy routes |
|
|
110
|
-
| `@meistrari/tela-build` | `^1.
|
|
113
|
+
| `@meistrari/tela-build` | `^1.70.2` | UI component library (Nuxt layer), with no global i18n requirement |
|
|
111
114
|
| `@sentry/nuxt` | `^10.0.0` | Client-side error capture used by chat composables |
|
|
112
115
|
| `@iconify/vue` + `@iconify-json/ph` | `^5.0.0` / `^1.2.2` | Icon rendering support (Phosphor set) |
|
|
113
116
|
| `@vueuse/core` | `^12.8.0` | Runtime composables used by chat UI |
|
|
@@ -121,10 +124,11 @@ Installing `@meistrari/chat-nuxt` installs the runtime packages used by the laye
|
|
|
121
124
|
| `posthog-js` | `^1.364.2` | Optional PostHog feature-flag helper |
|
|
122
125
|
| `stream-diffs` | `0.0.2` | Native markstream rich code and diff rendering |
|
|
123
126
|
| `virtua` | `^0.42.0` | Virtualized list runtime expected by shared UI |
|
|
124
|
-
| `vue-i18n` | `^11.0.0` | Internationalization runtime expected by shared UI |
|
|
125
127
|
| `xlsx` | `^0.18.5` | Spreadsheet file previews |
|
|
126
128
|
| `zod` | `^4.1.13` | Schema validation for API payloads |
|
|
127
129
|
|
|
130
|
+
The chat package does not declare or expect the host application to configure an i18n plugin. Hosts can override the supported conversation-search text through `labels`, using plain strings or their own translator. This is not a full-chat localization API; other UI text retains its existing defaults.
|
|
131
|
+
|
|
128
132
|
Peer dependencies:
|
|
129
133
|
|
|
130
134
|
| Package | Version | Purpose |
|
package/dist/module.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ChatMessageStatus } from '../dist/runtime/messages/composables/chat-message-terminal.js';
|
|
2
|
-
export { AvailableChatModels, ChatActionPayload, ChatActor, ChatEmbedSharedProps, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, MessageFeedbackConfig, MessageFeedbackPayload, MessageFeedbackRating, MessageFeedbackSubmitHandler, MessageFeedbackSubmitResult, MessageOverviewResponse, TelaAgentChatEmbedProps, TelaAgentExecutionInput } from '../dist/runtime/types/embed.js';
|
|
2
|
+
export { AvailableChatModels, ChatActionPayload, ChatActor, ChatEmbedSharedProps, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatLabels, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, MessageFeedbackConfig, MessageFeedbackPayload, MessageFeedbackRating, MessageFeedbackSubmitHandler, MessageFeedbackSubmitResult, MessageOverviewResponse, TelaAgentChatEmbedProps, TelaAgentExecutionInput } from '../dist/runtime/types/embed.js';
|
|
3
3
|
|
|
4
4
|
type ChatNuxtConfigValidationMode = false | 'warn' | 'error';
|
|
5
5
|
|
package/dist/module.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.markstream-vue{font-family:inherit;--at-apply:"body-16-regular leading-24px text-primary";--list-item-marker:#a3a3a3;--list-item-counter-marker:#262626}.markstream-vue code,.markstream-vue kbd,.markstream-vue pre,.markstream-vue samp{font-family:Geist Mono Variable,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:13px;font-variation-settings:normal;letter-spacing:0;line-height:1.5}.markstream-vue ol,.markstream-vue ul{margin:8px 0;padding-left:1.5em}.markstream-vue .hr-node{border-color:#e5e5e5;border-top-width:.5px;margin-bottom:24px;margin-top:24px}.markstream-vue .strong-node{--at-apply:"font-580"}.markstream-vue .list-node.list-node{margin-bottom:8px;margin-left:4px;margin-top:8px;padding-left:1em}.markstream-vue ul{list-style:disc;list-style-position:outside}.markstream-vue ol{list-style:decimal;list-style-position:outside}.markstream-vue li{margin:4px 0}.markstream-vue .paragraph-node{--at-apply:"body-16-regular leading-24px";margin:0}.markstream-vue>.node-slot[data-node-type=paragraph]:not(:first-child){margin-top:12px}@keyframes chat-stream-chunk-in{0%{opacity:0}to{opacity:1}}.markstream-vue .chat-stream-chunk{animation:chat-stream-chunk-in var(--chat-stream-fade-duration,.32s) cubic-bezier(.2,0,0,1) both}@media (prefers-reduced-motion:reduce){.markstream-vue .chat-stream-chunk{animation:none}}.markstream-vue .typewriter-cursor,.markstream-vue .typewriter-simple-cursor .typewriter-simple-cursor-target:after{display:none}.markstream-vue .my-8{margin-bottom:8px;margin-top:8px}.markstream-vue .heading-node.heading-1,.markstream-vue h1{--at-apply:"heading-h2-semibold text-primary";margin:24px 0 8px}.markstream-vue .heading-node.heading-2,.markstream-vue h2{--at-apply:"heading-h3-semibold text-primary";margin:24px 0 8px}.markstream-vue .heading-node.heading-3,.markstream-vue h3{--at-apply:"heading-h4-semibold text-primary";margin:20px 0 8px}.markstream-vue .heading-node.heading-4,.markstream-vue .heading-node.heading-5,.markstream-vue .heading-node.heading-6,.markstream-vue h4,.markstream-vue h5,.markstream-vue h6{--at-apply:"heading-h5-semibold text-primary";margin:16px 0 8px}.markstream-vue>.node-slot:first-child .heading-node{margin-top:0}.markstream-vue [class*=tooltip],[class*=tooltip-element]{background-color:var(--neutral-900,#1a1a1a)!important;border-radius:4px;color:#fff!important;font-size:12px;padding:4px 8px}.mention-tag{align-items:center;border-radius:9999px;display:inline-flex;font-size:.875em;font-weight:500;gap:4px;padding:2px 8px;vertical-align:middle;white-space:nowrap}.mention-tag-file{background-color:rgba(127,189,247,.12);color:#7fbdf7}.mention-tag-skill{background-color:rgba(155,111,222,.12);color:#9b6fde}.mention-tag-canvas{background-color:rgba(234,161,65,.12);color:#d4882e}.mention-tag>span[class*=i-ph]{flex-shrink:0}
|
|
1
|
+
.markstream-vue{font-family:inherit;--at-apply:"body-16-regular leading-24px text-primary";--list-item-marker:#a3a3a3;--list-item-counter-marker:#262626}.markstream-vue code,.markstream-vue kbd,.markstream-vue pre,.markstream-vue samp{font-family:Geist Mono Variable,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:13px;font-variation-settings:normal;letter-spacing:0;line-height:1.5}.markstream-vue ol,.markstream-vue ul{margin:8px 0;padding-left:1.5em}.markstream-vue .hr-node{border-color:#e5e5e5;border-top-width:.5px;margin-bottom:24px;margin-top:24px}.markstream-vue .strong-node{--at-apply:"font-580"}.markstream-vue .list-node.list-node{margin-bottom:8px;margin-left:4px;margin-top:8px;padding-left:1em}.markstream-vue ol.list-node.list-node{padding-left:3em}.markstream-vue ul{list-style:disc;list-style-position:outside}.markstream-vue ol{list-style:decimal;list-style-position:outside}.markstream-vue li{margin:4px 0}.markstream-vue .paragraph-node{--at-apply:"body-16-regular leading-24px";margin:0}.markstream-vue>.node-slot[data-node-type=paragraph]:not(:first-child){margin-top:12px}@keyframes chat-stream-chunk-in{0%{opacity:0}to{opacity:1}}.markstream-vue .chat-stream-chunk{animation:chat-stream-chunk-in var(--chat-stream-fade-duration,.32s) cubic-bezier(.2,0,0,1) both}@media (prefers-reduced-motion:reduce){.markstream-vue .chat-stream-chunk{animation:none}}.markstream-vue .typewriter-cursor,.markstream-vue .typewriter-simple-cursor .typewriter-simple-cursor-target:after{display:none}.markstream-vue .my-8{margin-bottom:8px;margin-top:8px}.markstream-vue .heading-node.heading-1,.markstream-vue h1{--at-apply:"heading-h2-semibold text-primary";margin:24px 0 8px}.markstream-vue .heading-node.heading-2,.markstream-vue h2{--at-apply:"heading-h3-semibold text-primary";margin:24px 0 8px}.markstream-vue .heading-node.heading-3,.markstream-vue h3{--at-apply:"heading-h4-semibold text-primary";margin:20px 0 8px}.markstream-vue .heading-node.heading-4,.markstream-vue .heading-node.heading-5,.markstream-vue .heading-node.heading-6,.markstream-vue h4,.markstream-vue h5,.markstream-vue h6{--at-apply:"heading-h5-semibold text-primary";margin:16px 0 8px}.markstream-vue>.node-slot:first-child .heading-node{margin-top:0}.markstream-vue [class*=tooltip],[class*=tooltip-element]{background-color:var(--neutral-900,#1a1a1a)!important;border-radius:4px;color:#fff!important;font-size:12px;padding:4px 8px}.mention-tag{align-items:center;border-radius:9999px;display:inline-flex;font-size:.875em;font-weight:500;gap:4px;padding:2px 8px;vertical-align:middle;white-space:nowrap}.mention-tag-file{background-color:rgba(127,189,247,.12);color:#7fbdf7}.mention-tag-skill{background-color:rgba(155,111,222,.12);color:#9b6fde}.mention-tag-canvas{background-color:rgba(234,161,65,.12);color:#d4882e}.mention-tag>span[class*=i-ph]{flex-shrink:0}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
type __VLS_Props = {
|
|
2
2
|
placeholder?: string;
|
|
3
|
+
clearLabel?: string;
|
|
3
4
|
};
|
|
4
5
|
type __VLS_ModelProps = {
|
|
5
6
|
modelValue: string;
|
|
@@ -9,8 +10,6 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
9
10
|
"update:modelValue": (value: string) => any;
|
|
10
11
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
11
12
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
12
|
-
}>, {
|
|
13
|
-
placeholder: string;
|
|
14
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
14
|
declare const _default: typeof __VLS_export;
|
|
16
15
|
export default _default;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { useEmbedConfig } from "../../embed/composables/embed-config";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
placeholder: { type: String, required: false },
|
|
5
|
+
clearLabel: { type: String, required: false }
|
|
4
6
|
});
|
|
7
|
+
const embedConfig = useEmbedConfig();
|
|
8
|
+
const placeholder = computed(() => props.placeholder ?? embedConfig?.labels.value?.conversationSearchPlaceholder ?? "Buscar conversas");
|
|
9
|
+
const clearLabel = computed(() => props.clearLabel ?? embedConfig?.labels.value?.conversationSearchClear ?? "Limpar");
|
|
5
10
|
const searchQuery = defineModel({ type: String, ...{ required: true } });
|
|
6
11
|
</script>
|
|
7
12
|
|
|
@@ -11,5 +16,7 @@ const searchQuery = defineModel({ type: String, ...{ required: true } });
|
|
|
11
16
|
icon="i-ph-magnifying-glass-bold"
|
|
12
17
|
:placeholder="placeholder"
|
|
13
18
|
autocomplete="off"
|
|
19
|
+
show-clear-button
|
|
20
|
+
:clear-label="clearLabel"
|
|
14
21
|
/>
|
|
15
22
|
</template>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
type __VLS_Props = {
|
|
2
2
|
placeholder?: string;
|
|
3
|
+
clearLabel?: string;
|
|
3
4
|
};
|
|
4
5
|
type __VLS_ModelProps = {
|
|
5
6
|
modelValue: string;
|
|
@@ -9,8 +10,6 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
9
10
|
"update:modelValue": (value: string) => any;
|
|
10
11
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
11
12
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
12
|
-
}>, {
|
|
13
|
-
placeholder: string;
|
|
14
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
14
|
declare const _default: typeof __VLS_export;
|
|
16
15
|
export default _default;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { inject } from "vue";
|
|
3
|
+
import { CHAT_COMPOSER_EXTENSION_KEY } from "../../types/composer";
|
|
2
4
|
import { useChatAuth } from "#chat-auth";
|
|
3
5
|
import { useBreakpoints } from "@vueuse/core";
|
|
4
6
|
import { useCitationPanel } from "../../citations/composables/citation-panel";
|
|
@@ -68,6 +70,7 @@ function toggleSidebarCollapsed() {
|
|
|
68
70
|
isSidebarCollapsed.value = !isSidebarCollapsed.value;
|
|
69
71
|
}
|
|
70
72
|
const chatApi = useChatApi();
|
|
73
|
+
const composerExtension = inject(CHAT_COMPOSER_EXTENSION_KEY, null);
|
|
71
74
|
const route = useRoute();
|
|
72
75
|
const embedConfig = useEmbedConfig();
|
|
73
76
|
const chatAction = useChatAction();
|
|
@@ -531,9 +534,11 @@ function claimableWakeSessionId() {
|
|
|
531
534
|
return agentWake.state.value === "ready" && !currentConversation.value?.threadSessionId ? agentWake.sessionId.value : void 0;
|
|
532
535
|
}
|
|
533
536
|
async function handleSend(content, files, agentInputs) {
|
|
537
|
+
const prepared = composerExtension?.prepareSend?.(content);
|
|
538
|
+
const outbound = prepared?.content ?? content;
|
|
534
539
|
const resolvedAgentInputs = resolveTelaAgentInputs(agentInputs, embedConfig?.telaAgentInputs?.value);
|
|
535
540
|
let claimedWakeSessionId;
|
|
536
|
-
const sent = await sendMessage(
|
|
541
|
+
const sent = await sendMessage(outbound, files.length > 0 ? files : void 0, resolvedAgentInputs, async (signal) => {
|
|
537
542
|
if (!activeConversationId.value || !currentConversation.value) {
|
|
538
543
|
const conversation2 = await createConversation({
|
|
539
544
|
model: selectedModel.value,
|
|
@@ -581,8 +586,10 @@ async function handleSend(content, files, agentInputs) {
|
|
|
581
586
|
});
|
|
582
587
|
if (sent && claimedWakeSessionId)
|
|
583
588
|
agentWake.consume();
|
|
589
|
+
if (sent)
|
|
590
|
+
prepared?.commit?.();
|
|
584
591
|
if (!sent)
|
|
585
|
-
restoreQueuedSend({ content, files, agentInputs: resolvedAgentInputs });
|
|
592
|
+
restoreQueuedSend({ content: prepared?.retryContent?.() ?? content, files, agentInputs: resolvedAgentInputs });
|
|
586
593
|
}
|
|
587
594
|
watch(
|
|
588
595
|
[outboundOccupied, agentWake.state],
|
|
@@ -26,6 +26,7 @@ const props = defineProps({
|
|
|
26
26
|
suggestions: { type: [Array, null], required: false },
|
|
27
27
|
loadingMessages: { type: [Array, null], required: false },
|
|
28
28
|
loadingMessagesMode: { type: [String, null], required: false },
|
|
29
|
+
labels: { type: Object, required: false },
|
|
29
30
|
customComponents: { type: Object, required: false },
|
|
30
31
|
customHtmlTags: { type: Array, required: false },
|
|
31
32
|
citations: { type: [Object, null], required: false },
|
|
@@ -67,6 +68,7 @@ provideEmbedConfig({
|
|
|
67
68
|
hideSettings,
|
|
68
69
|
loadingMessages: computed(() => props.loadingMessages),
|
|
69
70
|
loadingMessagesMode: computed(() => props.loadingMessagesMode),
|
|
71
|
+
labels: computed(() => props.labels),
|
|
70
72
|
customComponents: computed(() => props.customComponents),
|
|
71
73
|
customHtmlTags: computed(() => props.customHtmlTags),
|
|
72
74
|
citations: computed(() => props.citations),
|
|
@@ -19,6 +19,7 @@ const { hideSidebar = void 0, ...props } = defineProps({
|
|
|
19
19
|
suggestions: { type: [Array, null], required: false },
|
|
20
20
|
loadingMessages: { type: [Array, null], required: false },
|
|
21
21
|
loadingMessagesMode: { type: [String, null], required: false },
|
|
22
|
+
labels: { type: Object, required: false },
|
|
22
23
|
customComponents: { type: Object, required: false },
|
|
23
24
|
customHtmlTags: { type: Array, required: false },
|
|
24
25
|
citations: { type: [Object, null], required: false },
|
|
@@ -77,6 +78,7 @@ const sharedEmbedProps = computed(() => ({
|
|
|
77
78
|
features: props.features,
|
|
78
79
|
loadingMessages: props.loadingMessages,
|
|
79
80
|
loadingMessagesMode: props.loadingMessagesMode,
|
|
81
|
+
labels: props.labels,
|
|
80
82
|
customComponents: props.customComponents,
|
|
81
83
|
customHtmlTags: props.customHtmlTags,
|
|
82
84
|
citations: props.citations,
|
|
@@ -128,7 +130,7 @@ const widgetEmbedProps = computed(() => ({
|
|
|
128
130
|
@close="setOpen(false)"
|
|
129
131
|
>
|
|
130
132
|
<template #history>
|
|
131
|
-
<ChatWidgetHistoryList />
|
|
133
|
+
<ChatWidgetHistoryList :search-placeholder="props.labels?.conversationSearchPlaceholder" />
|
|
132
134
|
</template>
|
|
133
135
|
</TelaChatWidgetHeader>
|
|
134
136
|
<div flex-1 min-h-0>
|
|
@@ -157,7 +159,7 @@ const widgetEmbedProps = computed(() => ({
|
|
|
157
159
|
@select-conversation="handleWidgetConversationIdChange"
|
|
158
160
|
>
|
|
159
161
|
<template #history>
|
|
160
|
-
<ChatWidgetHistoryList />
|
|
162
|
+
<ChatWidgetHistoryList :search-placeholder="props.labels?.conversationSearchPlaceholder" />
|
|
161
163
|
</template>
|
|
162
164
|
</TelaChatWidgetHeader>
|
|
163
165
|
<div flex-1 min-h-0>
|
|
@@ -3,6 +3,7 @@ import type { ConversationCreatorFilter } from '../../types/schemas/chat/primiti
|
|
|
3
3
|
import type { WorkspaceSettingsResponse as WorkspaceSettings } from '../../types/schemas/chat/workspace-settings.js';
|
|
4
4
|
import type { TelaAgentExecutionInput } from '../../types/schemas/integrations/tela-agent-api.js';
|
|
5
5
|
import type { ChatLoadingMessageMode } from '../loading-messages.js';
|
|
6
|
+
import type { ChatLabels } from '../types.js';
|
|
6
7
|
import type { ChatCitationsConfig } from '../../citations/types.js';
|
|
7
8
|
import type { MessageFeedbackConfig, MessageFeedbackRating } from '../../messages/composables/chat-feedback.js';
|
|
8
9
|
import type { AvailableChatModels } from '../../messages/model-availability.js';
|
|
@@ -22,6 +23,7 @@ export type EmbedConfig = {
|
|
|
22
23
|
hideSettings: Ref<boolean>;
|
|
23
24
|
loadingMessages: Ref<readonly string[] | null | undefined>;
|
|
24
25
|
loadingMessagesMode: Ref<ChatLoadingMessageMode | null | undefined>;
|
|
26
|
+
labels: Ref<Partial<ChatLabels> | undefined>;
|
|
25
27
|
customComponents: Ref<Record<string, Component> | undefined>;
|
|
26
28
|
customHtmlTags: Ref<readonly string[] | undefined>;
|
|
27
29
|
citations: Ref<ChatCitationsConfig | null | undefined>;
|
|
@@ -42,6 +44,7 @@ type EmbedConfigInput = {
|
|
|
42
44
|
hideSettings?: MaybeRefOrGetter<boolean | undefined>;
|
|
43
45
|
loadingMessages?: MaybeRefOrGetter<readonly string[] | null | undefined>;
|
|
44
46
|
loadingMessagesMode?: MaybeRefOrGetter<ChatLoadingMessageMode | null | undefined>;
|
|
47
|
+
labels?: MaybeRefOrGetter<Partial<ChatLabels> | undefined>;
|
|
45
48
|
customComponents?: MaybeRefOrGetter<Record<string, Component> | undefined>;
|
|
46
49
|
customHtmlTags?: MaybeRefOrGetter<readonly string[] | undefined>;
|
|
47
50
|
citations?: MaybeRefOrGetter<ChatCitationsConfig | null | undefined>;
|
|
@@ -31,6 +31,7 @@ function useGlobalEmbedConfigState() {
|
|
|
31
31
|
hideSettings: useState("chat-embed-config-hide-settings", () => void 0),
|
|
32
32
|
loadingMessages: useState("chat-embed-config-loading-messages", () => void 0),
|
|
33
33
|
loadingMessagesMode: useState("chat-embed-config-loading-messages-mode", () => void 0),
|
|
34
|
+
labels: useState("chat-embed-config-labels", () => void 0),
|
|
34
35
|
customComponents: useGlobalCustomComponentsState(),
|
|
35
36
|
customHtmlTags: useState("chat-embed-config-custom-html-tags", () => void 0),
|
|
36
37
|
citations: useGlobalCitationsState(),
|
|
@@ -53,6 +54,7 @@ export function provideEmbedConfig(input, options = {}) {
|
|
|
53
54
|
hideSettings: computed(() => toValue(input.hideSettings) ?? false),
|
|
54
55
|
loadingMessages: computed(() => toValue(input.loadingMessages)),
|
|
55
56
|
loadingMessagesMode: computed(() => toValue(input.loadingMessagesMode)),
|
|
57
|
+
labels: computed(() => toValue(input.labels)),
|
|
56
58
|
customComponents: computed(() => toValue(input.customComponents)),
|
|
57
59
|
customHtmlTags: computed(() => toValue(input.customHtmlTags)),
|
|
58
60
|
citations: computed(() => toValue(input.citations)),
|
|
@@ -76,6 +78,7 @@ export function provideEmbedConfig(input, options = {}) {
|
|
|
76
78
|
globalConfig.hideSettings.value = config.hideSettings.value;
|
|
77
79
|
globalConfig.loadingMessages.value = config.loadingMessages.value;
|
|
78
80
|
globalConfig.loadingMessagesMode.value = config.loadingMessagesMode.value;
|
|
81
|
+
globalConfig.labels.value = config.labels.value;
|
|
79
82
|
globalConfig.customComponents.value = config.customComponents.value;
|
|
80
83
|
globalConfig.customHtmlTags.value = config.customHtmlTags.value;
|
|
81
84
|
globalConfig.citations.value = config.citations.value;
|
|
@@ -106,6 +109,7 @@ export function useEmbedConfig() {
|
|
|
106
109
|
hideSettings: computed(() => globalConfig.hideSettings.value ?? false),
|
|
107
110
|
loadingMessages: computed(() => globalConfig.loadingMessages.value),
|
|
108
111
|
loadingMessagesMode: computed(() => globalConfig.loadingMessagesMode.value),
|
|
112
|
+
labels: computed(() => globalConfig.labels.value),
|
|
109
113
|
customComponents: computed(() => globalConfig.customComponents.value),
|
|
110
114
|
customHtmlTags: computed(() => globalConfig.customHtmlTags.value),
|
|
111
115
|
citations: computed(() => globalConfig.citations.value),
|
|
@@ -10,6 +10,12 @@ import type { MessageFeedbackConfig, MessageFeedbackRating } from '../messages/c
|
|
|
10
10
|
import type { AvailableChatModels } from '../messages/model-availability.js';
|
|
11
11
|
export type { AvailableChatModels } from '../messages/model-availability.js';
|
|
12
12
|
export type ChatEmbedVariant = 'page' | 'floating' | 'sidepanel';
|
|
13
|
+
export type ChatLabels = {
|
|
14
|
+
/** Search placeholder in the sidebar, mobile drawer and widget history. Defaults to `Buscar conversas`. */
|
|
15
|
+
conversationSearchPlaceholder: string;
|
|
16
|
+
/** Clear-button tooltip in the sidebar and mobile drawer search. Defaults to `Limpar`. */
|
|
17
|
+
conversationSearchClear: string;
|
|
18
|
+
};
|
|
13
19
|
export type ChatSuggestion = {
|
|
14
20
|
/** Short label rendered on the suggestion pill. */
|
|
15
21
|
title: string;
|
|
@@ -100,6 +106,8 @@ export type ChatEmbedSharedProps = {
|
|
|
100
106
|
* non-empty message.
|
|
101
107
|
*/
|
|
102
108
|
loadingMessagesMode?: ChatLoadingMessageMode | null;
|
|
109
|
+
/** Override supported UI text. Omitted labels keep their Portuguese defaults; no i18n plugin is required. */
|
|
110
|
+
labels?: Partial<ChatLabels>;
|
|
103
111
|
/** Custom markdown component renderers keyed by markdown node or tag name. */
|
|
104
112
|
customComponents?: Record<string, Component>;
|
|
105
113
|
/** Extra HTML tags allowed by the markdown renderer. */
|
|
@@ -20,6 +20,8 @@ export type ContentSegment = {
|
|
|
20
20
|
export type ParseContentOptions = {
|
|
21
21
|
/** Detect bare `cite://` tokens as citation segments. Off by default: only hosts that configured citations opt in. */
|
|
22
22
|
detectCitations?: boolean;
|
|
23
|
+
/** Keep Markdown links in text so the Markdown renderer can preserve enclosing structures such as tables and lists. */
|
|
24
|
+
preserveMarkdownLinks?: boolean;
|
|
23
25
|
};
|
|
24
26
|
export declare function detectFilesInText(text: string): DetectedFile[];
|
|
25
27
|
export declare function parseContentWithFiles(text: string, options?: ParseContentOptions): ContentSegment[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CITE_REGEX, parseCitationUrl } from "../citations/citation-links.js";
|
|
2
|
-
import { getExtensionFromUrl, getMimeTypeFromExtension
|
|
2
|
+
import { getExtensionFromUrl, getMimeTypeFromExtension } from "./mime.js";
|
|
3
3
|
import {
|
|
4
4
|
getPermalinkId,
|
|
5
5
|
isVaultPermalink,
|
|
@@ -18,6 +18,20 @@ function getNameFromUrl(url) {
|
|
|
18
18
|
const parts = cleanUrl.split("/");
|
|
19
19
|
return parts[parts.length - 1] ?? url;
|
|
20
20
|
}
|
|
21
|
+
function detectExternalFileUrl(url) {
|
|
22
|
+
const ext = getExtensionFromUrl(url);
|
|
23
|
+
if (!ext)
|
|
24
|
+
return null;
|
|
25
|
+
const mimeType = getMimeTypeFromExtension(ext);
|
|
26
|
+
if (mimeType === "unknown" || mimeType === "text/html")
|
|
27
|
+
return null;
|
|
28
|
+
return {
|
|
29
|
+
type: "url",
|
|
30
|
+
reference: url,
|
|
31
|
+
name: getNameFromUrl(url),
|
|
32
|
+
mimeType
|
|
33
|
+
};
|
|
34
|
+
}
|
|
21
35
|
function getNameFromVaultReference(reference) {
|
|
22
36
|
const parts = reference.replace("vault://", "").split("/");
|
|
23
37
|
return parts[parts.length - 1] || "Arquivo";
|
|
@@ -116,27 +130,24 @@ export function detectFilesInText(text) {
|
|
|
116
130
|
});
|
|
117
131
|
continue;
|
|
118
132
|
}
|
|
119
|
-
|
|
133
|
+
const file = detectExternalFileUrl(match);
|
|
134
|
+
if (!file)
|
|
120
135
|
continue;
|
|
121
136
|
seen.add(match);
|
|
122
|
-
|
|
123
|
-
files.push({
|
|
124
|
-
type: "url",
|
|
125
|
-
reference: match,
|
|
126
|
-
name: getNameFromUrl(match),
|
|
127
|
-
mimeType: ext ? getMimeTypeFromExtension(ext) : "unknown"
|
|
128
|
-
});
|
|
137
|
+
files.push(file);
|
|
129
138
|
}
|
|
130
139
|
return files;
|
|
131
140
|
}
|
|
132
141
|
export function parseContentWithFiles(text, options) {
|
|
133
142
|
const segments = [];
|
|
134
|
-
const
|
|
143
|
+
const markdownFileLinkMatches = collectMarkdownFileLinkMatches(text);
|
|
144
|
+
const fileMatches = options?.preserveMarkdownLinks ? [] : [...markdownFileLinkMatches];
|
|
135
145
|
for (const match of text.matchAll(VAULT_REGEX)) {
|
|
136
146
|
const rawUrl = match[0];
|
|
137
147
|
const url = stripTrailingPunctuation(rawUrl);
|
|
138
|
-
if (overlapsFileMatch(match.index, match.index + url.length, fileMatches))
|
|
148
|
+
if (overlapsFileMatch(match.index, match.index + url.length, markdownFileLinkMatches) || overlapsFileMatch(match.index, match.index + url.length, fileMatches)) {
|
|
139
149
|
continue;
|
|
150
|
+
}
|
|
140
151
|
const hashParams = parseVaultHashParams(url);
|
|
141
152
|
const filenameExt = hashParams?.filename?.split(".").pop()?.toLowerCase();
|
|
142
153
|
const urlExt = getExtensionFromUrl(url);
|
|
@@ -156,8 +167,9 @@ export function parseContentWithFiles(text, options) {
|
|
|
156
167
|
for (const match of text.matchAll(URL_REGEX)) {
|
|
157
168
|
const rawUrl = match[0];
|
|
158
169
|
const url = stripTrailingPunctuation(rawUrl);
|
|
159
|
-
if (overlapsFileMatch(match.index, match.index + url.length, fileMatches))
|
|
170
|
+
if (overlapsFileMatch(match.index, match.index + url.length, markdownFileLinkMatches) || overlapsFileMatch(match.index, match.index + url.length, fileMatches)) {
|
|
160
171
|
continue;
|
|
172
|
+
}
|
|
161
173
|
if (isVaultS3Url(url)) {
|
|
162
174
|
const { name, mimeType } = getFileInfoFromVaultS3Url(url);
|
|
163
175
|
fileMatches.push({
|
|
@@ -185,17 +197,12 @@ export function parseContentWithFiles(text, options) {
|
|
|
185
197
|
});
|
|
186
198
|
continue;
|
|
187
199
|
}
|
|
188
|
-
|
|
189
|
-
|
|
200
|
+
const file = detectExternalFileUrl(url);
|
|
201
|
+
if (file) {
|
|
190
202
|
fileMatches.push({
|
|
191
203
|
start: match.index,
|
|
192
204
|
end: match.index + url.length,
|
|
193
|
-
file
|
|
194
|
-
type: "url",
|
|
195
|
-
reference: url,
|
|
196
|
-
name: getNameFromUrl(url),
|
|
197
|
-
mimeType: ext ? getMimeTypeFromExtension(ext) : "unknown"
|
|
198
|
-
}
|
|
205
|
+
file
|
|
199
206
|
});
|
|
200
207
|
}
|
|
201
208
|
}
|
|
@@ -3,4 +3,3 @@ export declare const MIME_TO_EXTENSION: Record<string, string>;
|
|
|
3
3
|
export declare function normalizeMimeType(mimeType: string): string;
|
|
4
4
|
export declare function getExtensionFromUrl(url: string): string | undefined;
|
|
5
5
|
export declare function getMimeTypeFromExtension(ext: string): string;
|
|
6
|
-
export declare function isFileUrl(url: string): boolean;
|
|
@@ -72,7 +72,3 @@ export function getExtensionFromUrl(url) {
|
|
|
72
72
|
export function getMimeTypeFromExtension(ext) {
|
|
73
73
|
return FILE_EXTENSIONS[ext] ?? "unknown";
|
|
74
74
|
}
|
|
75
|
-
export function isFileUrl(url) {
|
|
76
|
-
const ext = getExtensionFromUrl(url);
|
|
77
|
-
return ext !== void 0 && ext in FILE_EXTENSIONS;
|
|
78
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const URL_CHAR_CLASS = "[^\\s\"'<>`\\[\\]()*_~]+";
|
|
2
2
|
export const VAULT_REGEX = /(?<!\]\()vault:\/\/[^\s"'<>`\[\]()*_~]+/gi;
|
|
3
|
-
export const URL_REGEX = /https?:\/\/[^\s"'<>`\[\]()*_~]+/gi;
|
|
3
|
+
export const URL_REGEX = /(?<!\]\(|<)https?:\/\/[^\s"'<>`\[\]()*_~]+/gi;
|
|
4
4
|
export const VAULT_PATTERN = new RegExp(`vault://${URL_CHAR_CLASS}`, "gi");
|
|
5
5
|
export const VAULT_PERMALINK_PATTERN = new RegExp(`https://(?:[a-z0-9-]+\\.)*(?:vault|api)\\.tela(?:staging)?\\.com/(?:[a-z0-9_-]+/)*permalinks/${URL_CHAR_CLASS}`, "gi");
|
|
6
6
|
export function stripTrailingPunctuation(url) {
|
|
@@ -100,7 +100,7 @@ const contentSegments = computed(() => {
|
|
|
100
100
|
const content = displayContent.value;
|
|
101
101
|
if (!content)
|
|
102
102
|
return [];
|
|
103
|
-
return parseContentWithFiles(content);
|
|
103
|
+
return parseContentWithFiles(content, { preserveMarkdownLinks: true });
|
|
104
104
|
});
|
|
105
105
|
const hasDetectedFiles = computed(() => contentSegments.value.some((s) => s.type !== "text"));
|
|
106
106
|
</script>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { inject, unref } from "vue";
|
|
3
|
+
import { CHAT_COMPOSER_EXTENSION_KEY } from "../../types/composer";
|
|
2
4
|
import { useFileUpload } from "../../files/composables/file-upload";
|
|
3
5
|
import { MAX_FILE_SIZE, MAX_FILES } from "../../files/file-limits";
|
|
4
6
|
import { useInputHistory } from "../composables/input-history";
|
|
@@ -26,6 +28,7 @@ const props = defineProps({
|
|
|
26
28
|
});
|
|
27
29
|
const emit = defineEmits(["send", "cancel"]);
|
|
28
30
|
const selectedModel = defineModel("selectedModel", { type: [String, null], ...{ default: null } });
|
|
31
|
+
const composerExtension = inject(CHAT_COMPOSER_EXTENSION_KEY, null);
|
|
29
32
|
const selectedReasoningEffort = defineModel("selectedReasoningEffort", { type: null, ...{ default: null } });
|
|
30
33
|
const { uploadFiles, uploading, uploadError } = useFileUpload();
|
|
31
34
|
const isCancelEnabled = computed(() => props.showCancelButton === true);
|
|
@@ -34,6 +37,7 @@ const promptTextareaRef = ref(null);
|
|
|
34
37
|
const editorRef = computed(() => promptTextareaRef.value?.el ?? null);
|
|
35
38
|
const fileInputRef = ref(null);
|
|
36
39
|
const pendingFiles = ref([]);
|
|
40
|
+
const hasAttachments = computed(() => pendingFiles.value.length > 0 || !!unref(composerExtension?.hasAttachments));
|
|
37
41
|
const selectedUploadInputName = ref(void 0);
|
|
38
42
|
const agentInputTexts = ref({});
|
|
39
43
|
const isAgentInputsOpen = ref(false);
|
|
@@ -661,7 +665,7 @@ defineExpose({
|
|
|
661
665
|
/>
|
|
662
666
|
|
|
663
667
|
<TelaChatPromptInput :locked="promptShellLocked" :class="centered && 'bg-white'">
|
|
664
|
-
<TelaChatPromptInputAttachments v-if="
|
|
668
|
+
<TelaChatPromptInputAttachments v-if="hasAttachments">
|
|
665
669
|
<TelaChatPromptInputAttachment
|
|
666
670
|
v-for="pendingFile in pendingFiles"
|
|
667
671
|
:key="pendingFile.id"
|
|
@@ -691,13 +695,18 @@ defineExpose({
|
|
|
691
695
|
</option>
|
|
692
696
|
</select>
|
|
693
697
|
</TelaChatPromptInputAttachment>
|
|
698
|
+
<component
|
|
699
|
+
:is="composerExtension.attachmentsComponent"
|
|
700
|
+
v-if="composerExtension?.attachmentsComponent"
|
|
701
|
+
:disabled="isLocked"
|
|
702
|
+
/>
|
|
694
703
|
</TelaChatPromptInputAttachments>
|
|
695
704
|
|
|
696
705
|
<TelaChatPromptInputTextarea
|
|
697
706
|
ref="promptTextareaRef"
|
|
698
707
|
placeholder="Escreva sua mensagem..."
|
|
699
708
|
:empty="!content.trim()"
|
|
700
|
-
:flush="
|
|
709
|
+
:flush="hasAttachments"
|
|
701
710
|
:disabled="isLocked"
|
|
702
711
|
@keydown="handleKeydown"
|
|
703
712
|
@input="handleInput"
|
|
@@ -755,6 +764,11 @@ defineExpose({
|
|
|
755
764
|
</TelaChatPromptInputActionMenuSub>
|
|
756
765
|
</TelaChatPromptInputActionMenuContent>
|
|
757
766
|
</TelaChatPromptInputActionMenu>
|
|
767
|
+
<component
|
|
768
|
+
:is="composerExtension.component"
|
|
769
|
+
v-if="composerExtension?.component"
|
|
770
|
+
:disabled="isLocked"
|
|
771
|
+
/>
|
|
758
772
|
</TelaChatPromptInputTools>
|
|
759
773
|
|
|
760
774
|
<TelaChatPromptInputActions>
|
|
@@ -42,7 +42,8 @@ const thinkingDuration = computed(() => {
|
|
|
42
42
|
return null;
|
|
43
43
|
const start = new Date(props.createdAt).getTime();
|
|
44
44
|
const end = new Date(props.updatedAt).getTime();
|
|
45
|
-
|
|
45
|
+
const duration = end - start;
|
|
46
|
+
return Number.isFinite(duration) && duration >= 0 ? duration : null;
|
|
46
47
|
});
|
|
47
48
|
const formattedDuration = computed(() => {
|
|
48
49
|
if (!thinkingDuration.value)
|
|
@@ -259,6 +259,17 @@ export function useChat(options = {}) {
|
|
|
259
259
|
agentSessionExecutable.value = response.agentSession.executable;
|
|
260
260
|
agentSessionRewakeable.value = response.agentSession.rewakeable ?? false;
|
|
261
261
|
}
|
|
262
|
+
const queuedV2Send = chatApi.conversationV2Enabled ? outbound.slot.value : null;
|
|
263
|
+
if (queuedV2Send) {
|
|
264
|
+
const admitted = response.messages.some((message) => message.id === queuedV2Send.optimisticIds.user);
|
|
265
|
+
if (admitted) {
|
|
266
|
+
outbound.clear();
|
|
267
|
+
gateHolding.value = false;
|
|
268
|
+
} else {
|
|
269
|
+
void flushOutboundQueue();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
262
273
|
if (gateHolding.value)
|
|
263
274
|
return;
|
|
264
275
|
const currentMessagesById = new Map(messages.value.map((message) => [message.id, message]));
|
|
@@ -629,9 +640,29 @@ export function useChat(options = {}) {
|
|
|
629
640
|
const code = getChatApiErrorCode(err);
|
|
630
641
|
const status = getChatApiErrorStatus(err);
|
|
631
642
|
if (v2AdmissionRequested && !controller.signal.aborted && (status === null || status === 408 || status === 429 || status >= 500)) {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
643
|
+
const attempts = (queuedSend?.attempts ?? 0) + 1;
|
|
644
|
+
const queuedAt = queuedSend?.queuedAt ?? Date.now();
|
|
645
|
+
if (outboundQueueEnabled.value) {
|
|
646
|
+
if (attempts < 3 && Date.now() - queuedAt <= 9e4) {
|
|
647
|
+
outbound.replace({
|
|
648
|
+
content,
|
|
649
|
+
files,
|
|
650
|
+
agentInputs,
|
|
651
|
+
wakeSessionId: void 0,
|
|
652
|
+
optimisticIds: { user: optimisticUserMessage.id, assistant: optimisticAssistantMessage.id },
|
|
653
|
+
queuedAt,
|
|
654
|
+
attempts
|
|
655
|
+
});
|
|
656
|
+
gateHolding.value = true;
|
|
657
|
+
error.value = "Confirma\xE7\xE3o do envio pendente. Reconectando \xE0 conversa\u2026";
|
|
658
|
+
startPolling();
|
|
659
|
+
return optimisticUserMessage;
|
|
660
|
+
}
|
|
661
|
+
} else {
|
|
662
|
+
error.value = "Confirma\xE7\xE3o do envio pendente. Reconectando \xE0 conversa\u2026";
|
|
663
|
+
startPolling();
|
|
664
|
+
return optimisticUserMessage;
|
|
665
|
+
}
|
|
635
666
|
}
|
|
636
667
|
const queuedAttempts = (queuedSend?.attempts ?? 0) + 1;
|
|
637
668
|
const queuedAgeMs = Date.now() - (queuedSend?.queuedAt ?? Date.now());
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Component, MaybeRef } from 'vue';
|
|
2
|
+
/** Stable string key, also compatible with hosts providing the literal key. */
|
|
3
|
+
export declare const CHAT_COMPOSER_EXTENSION_KEY = "chat-composer-extension";
|
|
4
|
+
/** A synchronous, per-send snapshot owned by the host application. */
|
|
5
|
+
export interface ChatPreparedSend {
|
|
6
|
+
content: string;
|
|
7
|
+
/** Called only after acceptance, including acceptance into the outbound queue. */
|
|
8
|
+
commit?: () => void;
|
|
9
|
+
/** Read after rejection. Defaults to the original composer text when omitted. */
|
|
10
|
+
retryContent?: () => string;
|
|
11
|
+
}
|
|
12
|
+
/** Provide above MeistrariChatEmbed to extend its composer without replacing it. */
|
|
13
|
+
export interface ChatComposerExtension {
|
|
14
|
+
/** Action next to the file menu. Receives the composer's `disabled` state. */
|
|
15
|
+
component?: Component;
|
|
16
|
+
/** Items inside the shared attachment strip. Receives `disabled` as well. */
|
|
17
|
+
attachmentsComponent?: Component;
|
|
18
|
+
/** Controls attachment-strip visibility and the textarea's flush layout. */
|
|
19
|
+
hasAttachments?: MaybeRef<boolean>;
|
|
20
|
+
/** Prepare without consuming host state; commit after the send is accepted. */
|
|
21
|
+
prepareSend?: (content: string) => ChatPreparedSend | null | undefined;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CHAT_COMPOSER_EXTENSION_KEY = "chat-composer-extension";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { ChatCitationsConfig, CitationMeta, CitationRef, } from '../citations/types.js';
|
|
2
2
|
export type { ChatFeatureConfig } from '../embed/feature-config.js';
|
|
3
|
-
export type { AvailableChatModels, ChatActor, ChatEmbedSharedProps, ChatEmbedVariant, ChatEmbedVariantProps, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, TelaAgentChatEmbedProps, } from '../embed/types.js';
|
|
3
|
+
export type { AvailableChatModels, ChatActor, ChatEmbedSharedProps, ChatEmbedVariant, ChatEmbedVariantProps, ChatLabels, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, TelaAgentChatEmbedProps, } from '../embed/types.js';
|
|
4
4
|
export type { ChatActionPayload } from '../messages/composables/chat-action.js';
|
|
5
5
|
export type { MessageFeedbackConfig, MessageFeedbackPayload, MessageFeedbackRating, MessageFeedbackSubmitHandler, MessageFeedbackSubmitResult, } from '../messages/composables/chat-feedback.js';
|
|
6
6
|
export { ChatMessageStatus } from '../messages/composables/chat-message-terminal.js';
|
|
@@ -232,6 +232,9 @@ export declare const createConversationRequestSchema: z.ZodObject<{
|
|
|
232
232
|
"claude-sonnet-5": "claude-sonnet-5";
|
|
233
233
|
"claude-sonnet-4-6": "claude-sonnet-4-6";
|
|
234
234
|
"claude-haiku-4-5": "claude-haiku-4-5";
|
|
235
|
+
"openai/gpt-5.6-sol": "openai/gpt-5.6-sol";
|
|
236
|
+
"openai/gpt-5.6-terra": "openai/gpt-5.6-terra";
|
|
237
|
+
"openai/gpt-5.6-luna": "openai/gpt-5.6-luna";
|
|
235
238
|
}>>>;
|
|
236
239
|
reasoningEffort: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
237
240
|
low: "low";
|
|
@@ -407,6 +410,9 @@ export declare const updateConversationRequestSchema: z.ZodObject<{
|
|
|
407
410
|
"claude-sonnet-5": "claude-sonnet-5";
|
|
408
411
|
"claude-sonnet-4-6": "claude-sonnet-4-6";
|
|
409
412
|
"claude-haiku-4-5": "claude-haiku-4-5";
|
|
413
|
+
"openai/gpt-5.6-sol": "openai/gpt-5.6-sol";
|
|
414
|
+
"openai/gpt-5.6-terra": "openai/gpt-5.6-terra";
|
|
415
|
+
"openai/gpt-5.6-luna": "openai/gpt-5.6-luna";
|
|
410
416
|
}>>>;
|
|
411
417
|
reasoningEffort: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
412
418
|
low: "low";
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
export declare const chatModelIds: readonly ["claude-opus-5", "claude-opus-4-8", "claude-sonnet-5", "claude-sonnet-4-6", "claude-haiku-4-5"];
|
|
2
|
+
export declare const chatModelIds: readonly ["claude-opus-5", "claude-opus-4-8", "claude-sonnet-5", "claude-sonnet-4-6", "claude-haiku-4-5", "openai/gpt-5.6-sol", "openai/gpt-5.6-terra", "openai/gpt-5.6-luna"];
|
|
3
3
|
export declare const chatModelSchema: z.ZodEnum<{
|
|
4
4
|
"claude-opus-5": "claude-opus-5";
|
|
5
5
|
"claude-opus-4-8": "claude-opus-4-8";
|
|
6
6
|
"claude-sonnet-5": "claude-sonnet-5";
|
|
7
7
|
"claude-sonnet-4-6": "claude-sonnet-4-6";
|
|
8
8
|
"claude-haiku-4-5": "claude-haiku-4-5";
|
|
9
|
+
"openai/gpt-5.6-sol": "openai/gpt-5.6-sol";
|
|
10
|
+
"openai/gpt-5.6-terra": "openai/gpt-5.6-terra";
|
|
11
|
+
"openai/gpt-5.6-luna": "openai/gpt-5.6-luna";
|
|
9
12
|
}>;
|
|
10
13
|
export type ChatModel = z.infer<typeof chatModelSchema>;
|
|
11
14
|
export declare const defaultChatModel = "claude-opus-5";
|
|
@@ -5,6 +5,9 @@ export const chatModelIds = [
|
|
|
5
5
|
'claude-sonnet-5',
|
|
6
6
|
'claude-sonnet-4-6',
|
|
7
7
|
'claude-haiku-4-5',
|
|
8
|
+
'openai/gpt-5.6-sol',
|
|
9
|
+
'openai/gpt-5.6-terra',
|
|
10
|
+
'openai/gpt-5.6-luna',
|
|
8
11
|
];
|
|
9
12
|
export const chatModelSchema = z.enum(chatModelIds);
|
|
10
13
|
export const defaultChatModel = 'claude-opus-5';
|
|
@@ -69,6 +69,36 @@ export declare const chatModelOptions: readonly [{
|
|
|
69
69
|
readonly maxOutputTokens: 64000;
|
|
70
70
|
readonly isMultiModal: true;
|
|
71
71
|
readonly tabs: readonly ["all", "cheap", "multimodal"];
|
|
72
|
+
}, {
|
|
73
|
+
readonly value: "openai/gpt-5.6-sol";
|
|
74
|
+
readonly label: "GPT-5.6 Sol";
|
|
75
|
+
readonly description: "Modelo OpenAI para tarefas complexas";
|
|
76
|
+
readonly provider: "OpenAI";
|
|
77
|
+
readonly cost: 5;
|
|
78
|
+
readonly maxInputTokens: 1050000;
|
|
79
|
+
readonly maxOutputTokens: 128000;
|
|
80
|
+
readonly isMultiModal: true;
|
|
81
|
+
readonly tabs: readonly ["all", "advanced", "multimodal"];
|
|
82
|
+
}, {
|
|
83
|
+
readonly value: "openai/gpt-5.6-terra";
|
|
84
|
+
readonly label: "GPT-5.6 Terra";
|
|
85
|
+
readonly description: "Equilíbrio entre capacidade e custo";
|
|
86
|
+
readonly provider: "OpenAI";
|
|
87
|
+
readonly cost: 3;
|
|
88
|
+
readonly maxInputTokens: 1050000;
|
|
89
|
+
readonly maxOutputTokens: 128000;
|
|
90
|
+
readonly isMultiModal: true;
|
|
91
|
+
readonly tabs: readonly ["all", "advanced", "multimodal"];
|
|
92
|
+
}, {
|
|
93
|
+
readonly value: "openai/gpt-5.6-luna";
|
|
94
|
+
readonly label: "GPT-5.6 Luna";
|
|
95
|
+
readonly description: "Modelo OpenAI rápido e econômico";
|
|
96
|
+
readonly provider: "OpenAI";
|
|
97
|
+
readonly cost: 1;
|
|
98
|
+
readonly maxInputTokens: 1050000;
|
|
99
|
+
readonly maxOutputTokens: 128000;
|
|
100
|
+
readonly isMultiModal: true;
|
|
101
|
+
readonly tabs: readonly ["all", "cheap", "multimodal"];
|
|
72
102
|
}];
|
|
73
103
|
export type ChatReasoningEffortOption = {
|
|
74
104
|
value: ChatReasoningEffort;
|
|
@@ -11,6 +11,10 @@ export const chatModelOptions = [
|
|
|
11
11
|
{ value: 'claude-sonnet-5', label: 'Claude Sonnet 5', description: 'Agente rápido para tarefas avançadas', provider: 'Anthropic', cost: 4, maxInputTokens: 1_000_000, maxOutputTokens: 64_000, isMultiModal: true, tabs: ['all', 'advanced', 'multimodal'] },
|
|
12
12
|
{ value: 'claude-sonnet-4-6', label: 'Claude 4.6 Sonnet', description: 'Agente rápido para tarefas avançadas', provider: 'Anthropic', cost: 4, maxInputTokens: 1_000_000, maxOutputTokens: 64_000, isMultiModal: true, tabs: ['all', 'advanced', 'multimodal'] },
|
|
13
13
|
{ value: 'claude-haiku-4-5', label: 'Claude 4.5 Haiku', description: 'Agente rápido para tarefas simples', provider: 'Anthropic', cost: 3, maxInputTokens: 200_000, maxOutputTokens: 64_000, isMultiModal: true, tabs: ['all', 'cheap', 'multimodal'] },
|
|
14
|
+
// Agent API catalog: openai/ IDs select the existing gateway route; cost is its 1–5 tier.
|
|
15
|
+
{ value: 'openai/gpt-5.6-sol', label: 'GPT-5.6 Sol', description: 'Modelo OpenAI para tarefas complexas', provider: 'OpenAI', cost: 5, maxInputTokens: 1_050_000, maxOutputTokens: 128_000, isMultiModal: true, tabs: ['all', 'advanced', 'multimodal'] },
|
|
16
|
+
{ value: 'openai/gpt-5.6-terra', label: 'GPT-5.6 Terra', description: 'Equilíbrio entre capacidade e custo', provider: 'OpenAI', cost: 3, maxInputTokens: 1_050_000, maxOutputTokens: 128_000, isMultiModal: true, tabs: ['all', 'advanced', 'multimodal'] },
|
|
17
|
+
{ value: 'openai/gpt-5.6-luna', label: 'GPT-5.6 Luna', description: 'Modelo OpenAI rápido e econômico', provider: 'OpenAI', cost: 1, maxInputTokens: 1_050_000, maxOutputTokens: 128_000, isMultiModal: true, tabs: ['all', 'cheap', 'multimodal'] },
|
|
14
18
|
];
|
|
15
19
|
// Ordered from least to most effort so the composer can lay them out as slider stops.
|
|
16
20
|
export const chatReasoningEffortOptions = [
|
|
@@ -280,6 +280,9 @@ export declare const telaAgentWakeRequestSchema: z.ZodObject<{
|
|
|
280
280
|
"claude-sonnet-5": "claude-sonnet-5";
|
|
281
281
|
"claude-sonnet-4-6": "claude-sonnet-4-6";
|
|
282
282
|
"claude-haiku-4-5": "claude-haiku-4-5";
|
|
283
|
+
"openai/gpt-5.6-sol": "openai/gpt-5.6-sol";
|
|
284
|
+
"openai/gpt-5.6-terra": "openai/gpt-5.6-terra";
|
|
285
|
+
"openai/gpt-5.6-luna": "openai/gpt-5.6-luna";
|
|
283
286
|
}>>;
|
|
284
287
|
}, z.core.$strip>;
|
|
285
288
|
export type TelaAgentWakeRequest = z.infer<typeof telaAgentWakeRequestSchema>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { chatModelOptions } from "../types/schemas/chat/ui.js";
|
|
1
2
|
export function formatTokenCount(count) {
|
|
2
3
|
if (count >= 1e6) {
|
|
3
4
|
const val = count / 1e6;
|
|
@@ -19,6 +20,9 @@ export function formatCredits(credits) {
|
|
|
19
20
|
return `${Math.round(credits)} cr\xE9ditos`;
|
|
20
21
|
}
|
|
21
22
|
export function formatModelName(model) {
|
|
23
|
+
const openAiModel = chatModelOptions.find((option) => option.provider === "OpenAI" && (option.value === model || option.value === `openai/${model}`));
|
|
24
|
+
if (openAiModel)
|
|
25
|
+
return openAiModel.label;
|
|
22
26
|
const id = model.replace(/^claude-/, "");
|
|
23
27
|
const newFormat = id.match(/^(opus|sonnet|haiku)-(\d+)-(\d+)/);
|
|
24
28
|
if (newFormat) {
|
package/dist/types.d.mts
CHANGED
|
@@ -6,7 +6,7 @@ export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<
|
|
|
6
6
|
|
|
7
7
|
export { ChatMessageStatus } from '../dist/runtime/messages/composables/chat-message-terminal.js'
|
|
8
8
|
|
|
9
|
-
export { type AvailableChatModels, type ChatActionPayload, type ChatActor, type ChatEmbedSharedProps, type ChatEmbedVariant, type ChatEmbedVariantProps, type ChatFeatureConfig, type ChatMessageTerminalPayload, type ChatSidebarConfig, type ChatSuggestion, type DefaultChatEmbedProps, type MeistrariChatEmbedProps, type MessageFeedbackConfig, type MessageFeedbackPayload, type MessageFeedbackRating, type MessageFeedbackSubmitHandler, type MessageFeedbackSubmitResult, type MessageOverviewResponse, type TelaAgentChatEmbedProps, type TelaAgentExecutionInput } from '../dist/runtime/types/embed.js'
|
|
9
|
+
export { type AvailableChatModels, type ChatActionPayload, type ChatActor, type ChatEmbedSharedProps, type ChatEmbedVariant, type ChatEmbedVariantProps, type ChatFeatureConfig, type ChatLabels, type ChatMessageTerminalPayload, type ChatSidebarConfig, type ChatSuggestion, type DefaultChatEmbedProps, type MeistrariChatEmbedProps, type MessageFeedbackConfig, type MessageFeedbackPayload, type MessageFeedbackRating, type MessageFeedbackSubmitHandler, type MessageFeedbackSubmitResult, type MessageOverviewResponse, type TelaAgentChatEmbedProps, type TelaAgentExecutionInput } from '../dist/runtime/types/embed.js'
|
|
10
10
|
|
|
11
11
|
export { default } from './module.mjs'
|
|
12
12
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/chat-nuxt",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-rc.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@iconify/vue": "^5.0.0",
|
|
49
49
|
"@meistrari/auth-nuxt": "3.31.0",
|
|
50
50
|
"@meistrari/logger": "^2.1.3",
|
|
51
|
-
"@meistrari/tela-build": "^1.
|
|
51
|
+
"@meistrari/tela-build": "^1.70.2",
|
|
52
52
|
"@sentry/nuxt": "^10.0.0",
|
|
53
53
|
"@vueuse/components": "^12.8.0",
|
|
54
54
|
"@vueuse/core": "^12.8.0",
|
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
"stream-diffs": "0.0.2",
|
|
65
65
|
"tldts": "^7.4.10",
|
|
66
66
|
"virtua": "^0.42.0",
|
|
67
|
-
"vue-i18n": "^11.0.0",
|
|
68
67
|
"xlsx": "^0.18.5",
|
|
69
68
|
"zod": "^4.1.13"
|
|
70
69
|
},
|