@meistrari/chat-nuxt 3.14.2-rc.2 → 3.15.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -0
  2. package/dist/module.d.mts +1 -1
  3. package/dist/module.json +1 -1
  4. package/dist/runtime/conversations/composables/conversations.js +37 -25
  5. package/dist/runtime/embed/components/chat-embed-inner.vue +65 -32
  6. package/dist/runtime/embed/components/chat-embed.vue +2 -0
  7. package/dist/runtime/embed/components/meistrari-chat-embed.d.vue.ts +2 -2
  8. package/dist/runtime/embed/components/meistrari-chat-embed.vue +2 -0
  9. package/dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts +2 -2
  10. package/dist/runtime/embed/composables/embed-config.d.ts +3 -0
  11. package/dist/runtime/embed/composables/embed-config.js +4 -0
  12. package/dist/runtime/embed/types.d.ts +8 -0
  13. package/dist/runtime/messages/components/chat-model-selector.vue +23 -12
  14. package/dist/runtime/messages/composables/chat.d.ts +1 -1
  15. package/dist/runtime/messages/composables/chat.js +73 -43
  16. package/dist/runtime/messages/model-availability.d.ts +6 -0
  17. package/dist/runtime/messages/model-availability.js +28 -0
  18. package/dist/runtime/server/api/chat/conversations/generate-title.d.ts +2 -0
  19. package/dist/runtime/server/api/chat/conversations/generate-title.js +3 -0
  20. package/dist/runtime/server/api/chat/conversations/groups/[groupId].d.ts +2 -0
  21. package/dist/runtime/server/api/chat/conversations/groups/[groupId].js +6 -0
  22. package/dist/runtime/server/api/chat/conversations/groups.d.ts +2 -0
  23. package/dist/runtime/server/api/chat/conversations/groups.js +3 -0
  24. package/dist/runtime/server/api/chat/conversations/metadata.d.ts +2 -0
  25. package/dist/runtime/server/api/chat/conversations/metadata.js +3 -0
  26. package/dist/runtime/types/embed.d.ts +1 -1
  27. package/dist/runtime/types/schemas/chat/conversations.d.ts +2 -0
  28. package/dist/runtime/types/schemas/chat/models.d.ts +2 -1
  29. package/dist/runtime/types/schemas/chat/models.js +1 -0
  30. package/dist/runtime/types/schemas/chat/ui.d.ts +10 -0
  31. package/dist/runtime/types/schemas/chat/ui.js +1 -0
  32. package/dist/runtime/types/schemas/integrations/tela-agent-api.d.ts +1 -0
  33. package/dist/types.d.mts +1 -1
  34. package/package.json +1 -1
package/README.md CHANGED
@@ -55,6 +55,7 @@ Declared in `src/runtime/embed/types.ts`; prop, feature-flag, and event payload
55
55
  | `initialConversationId` | `string \| null` | `null` | Conversation to open once on mount when `conversationId` is uncontrolled |
56
56
  | `conversationScope` | `string \| null` | `null` | Isolate conversation history by technical scope within the current workspace and runtime. Scoped embeds only see same-scope conversations; values are trimmed, blank becomes `null`, and the server accepts 1-200 chars from `A-Z`, `a-z`, `0-9`, `.`, `_`, `:`, `/`, `-` |
57
57
  | `defaultConversationCreatorFilter` | `'all' \| 'mine'` | `'all'` | Initial sidebar creator filter: every conversation in scope, or only the current user's |
58
+ | `availableModels` | `AvailableChatModels` | Full catalog | Non-empty ordered list of models this embed may display and execute. A missing or invalid restored selection falls back to the first entry; an empty list fails fast |
58
59
  | `conversationCreatorFilter` | `'all' \| 'mine'` | — | Controlled sidebar creator filter; use with `v-model:conversation-creator-filter` when the host changes it at runtime |
59
60
  | `hideConversationCreatorFilter` | `boolean` | `false` | Hide the creator selector without changing the active filter |
60
61
  | `telaAgentId` | `string` | — | Use Tela agent mode for this embed |
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 { 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, 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,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "3.14.2-rc.2",
4
+ "version": "3.15.0-rc.1",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -56,6 +56,7 @@ function createOptimisticConversationId() {
56
56
  return `optimistic-${Date.now()}-${Math.random().toString(36).slice(2)}`;
57
57
  }
58
58
  export function useConversations() {
59
+ const nuxtApp = useNuxtApp();
59
60
  const chatApi = useChatApi();
60
61
  const embedConfig = useEmbedConfig();
61
62
  const { user: authUser, activeOrganization } = useChatAuth();
@@ -69,6 +70,7 @@ export function useConversations() {
69
70
  const metadataBuckets = useState("conversations-metadata", () => ({}));
70
71
  const metadataLoadingBuckets = useState("conversations-metadata-loading", () => ({}));
71
72
  const metadataFetchedBuckets = useState("conversations-metadata-fetched", () => ({}));
73
+ const modelUpdateTails = nuxtApp._chatConversationModelUpdateTails ??= /* @__PURE__ */ new Map();
72
74
  const providedConversationCreatorFilter = useProvidedConversationCreatorFilterState();
73
75
  const conversationCreatorFilter = providedConversationCreatorFilter ?? useState(
74
76
  "conversation-creator-filter",
@@ -462,31 +464,41 @@ export function useConversations() {
462
464
  return false;
463
465
  }
464
466
  };
465
- const updateConversationModel = async (id, model) => {
466
- error.value = null;
467
- const requestRuntimeScope = runtimeScope.value;
468
- const affectedScopes = activeAndLoadedRuntimeConversationScopes(requestRuntimeScope);
469
- const conversationSnapshot = snapshotConversationBuckets(affectedScopes);
470
- const conversation = findConversationInLoadedBuckets(id, requestRuntimeScope);
471
- if (conversation)
472
- updateConversationInLoadedBuckets({ ...conversation, model, updatedAt: /* @__PURE__ */ new Date() }, requestRuntimeScope);
473
- try {
474
- const updated = await $fetch(
475
- chatApi.path(`/conversations/${id}`),
476
- chatApi.withChatHeaders({
477
- method: "PATCH",
478
- body: { model }
479
- })
480
- );
481
- updateConversationInLoadedBuckets(updated, requestRuntimeScope);
482
- return true;
483
- } catch (err) {
484
- restoreConversationBuckets(conversationSnapshot, id);
485
- const message = err instanceof Error ? err.message : "Erro ao atualizar modelo da conversa";
486
- error.value = message;
487
- Sentry.captureException(err);
488
- return false;
489
- }
467
+ const updateConversationModel = (id, model) => {
468
+ const previousUpdate = modelUpdateTails.get(id) ?? Promise.resolve(true);
469
+ const update = previousUpdate.catch(() => false).then(async () => {
470
+ error.value = null;
471
+ const requestRuntimeScope = runtimeScope.value;
472
+ const affectedScopes = activeAndLoadedRuntimeConversationScopes(requestRuntimeScope);
473
+ const conversationSnapshot = snapshotConversationBuckets(affectedScopes);
474
+ const conversation = findConversationInLoadedBuckets(id, requestRuntimeScope);
475
+ if (conversation)
476
+ updateConversationInLoadedBuckets({ ...conversation, model, updatedAt: /* @__PURE__ */ new Date() }, requestRuntimeScope);
477
+ try {
478
+ const updated = await $fetch(
479
+ chatApi.path(`/conversations/${id}`),
480
+ chatApi.withChatHeaders({
481
+ method: "PATCH",
482
+ body: { model }
483
+ })
484
+ );
485
+ updateConversationInLoadedBuckets(updated, requestRuntimeScope);
486
+ return true;
487
+ } catch (err) {
488
+ restoreConversationBuckets(conversationSnapshot, id);
489
+ const message = err instanceof Error ? err.message : "Erro ao atualizar modelo da conversa";
490
+ error.value = message;
491
+ Sentry.captureException(err);
492
+ return false;
493
+ }
494
+ });
495
+ const clearUpdate = () => {
496
+ if (modelUpdateTails.get(id) === update)
497
+ modelUpdateTails.delete(id);
498
+ };
499
+ modelUpdateTails.set(id, update);
500
+ void update.then(clearUpdate, clearUpdate);
501
+ return update;
490
502
  };
491
503
  const duplicateConversation = async (id) => {
492
504
  error.value = null;
@@ -15,6 +15,11 @@ import {
15
15
  resolveTelaAgentInputs,
16
16
  useChat
17
17
  } from "../../messages/composables/chat";
18
+ import {
19
+ ensureConversationUsesSelectedModel,
20
+ MODEL_UPDATE_FAILED_MESSAGE,
21
+ resolveChatModelSelection
22
+ } from "../../messages/model-availability";
18
23
  import { useChatAction } from "../../messages/composables/chat-action";
19
24
  import { useChatApi } from "../../shared/composables/chat-api";
20
25
  import { useConversationFiles } from "../../files/composables/conversation-files";
@@ -201,30 +206,45 @@ watch(chatError, (message) => {
201
206
  });
202
207
  const conversationIdRef = computed(() => currentConversation.value?.id ?? null);
203
208
  const { total, files: conversationFiles } = useConversationFiles(conversationIdRef);
209
+ function persistConversationModel(conversation, value, wakeAgent) {
210
+ const previousModel = conversation.model;
211
+ setConversationModel(value);
212
+ const update = updateConversationModel(conversation.id, value).then(async (updated) => {
213
+ if (!updated && currentConversation.value?.id === conversation.id && currentConversation.value.model === value) {
214
+ setConversationModel(previousModel);
215
+ } else if (updated && value && wakeAgent) {
216
+ if (conversation.threadSessionId)
217
+ await agentWake.ensureReady(conversation.threadSessionId, value);
218
+ else
219
+ await agentWake.wake(void 0, value);
220
+ }
221
+ return updated;
222
+ });
223
+ const trackedUpdate = update.finally(() => {
224
+ if (modelUpdateInFlight.value === trackedUpdate)
225
+ modelUpdateInFlight.value = null;
226
+ });
227
+ modelUpdateInFlight.value = trackedUpdate;
228
+ return trackedUpdate;
229
+ }
230
+ async function waitForPendingModelUpdate() {
231
+ while (modelUpdateInFlight.value) {
232
+ const update = modelUpdateInFlight.value;
233
+ if (!await update)
234
+ throw new Error(MODEL_UPDATE_FAILED_MESSAGE);
235
+ }
236
+ }
204
237
  const selectedModel = computed({
205
- get: () => currentConversation.value ? currentConversation.value.model : pendingModelSelection.value,
238
+ get: () => resolveChatModelSelection(
239
+ currentConversation.value ? currentConversation.value.model : pendingModelSelection.value,
240
+ embedConfig?.availableModels.value
241
+ ),
206
242
  set: (value) => {
207
- pendingModelSelection.value = value;
243
+ const resolvedValue = resolveChatModelSelection(value, embedConfig?.availableModels.value);
244
+ pendingModelSelection.value = resolvedValue;
208
245
  const conversation = currentConversation.value;
209
- if (conversation && conversation.model !== value) {
210
- const previousModel = conversation.model;
211
- setConversationModel(value);
212
- const update = updateConversationModel(conversation.id, value).then(async (updated) => {
213
- if (!updated && currentConversation.value?.id === conversation.id && currentConversation.value.model === value) {
214
- setConversationModel(previousModel);
215
- } else if (updated && value) {
216
- if (conversation.threadSessionId)
217
- await agentWake.ensureReady(conversation.threadSessionId, value);
218
- else
219
- await agentWake.wake(void 0, value);
220
- }
221
- return updated;
222
- });
223
- modelUpdateInFlight.value = update.finally(() => {
224
- if (modelUpdateInFlight.value === update)
225
- modelUpdateInFlight.value = null;
226
- });
227
- }
246
+ if (conversation && conversation.model !== resolvedValue)
247
+ void persistConversationModel(conversation, resolvedValue, true);
228
248
  }
229
249
  });
230
250
  const filesCount = computed(() => total.value);
@@ -479,11 +499,15 @@ async function handleSend(content, files, agentInputs) {
479
499
  adoptConversation(grouped ? { ...conversation2, groupId } : conversation2);
480
500
  updateConversationId(conversation2.id);
481
501
  }
482
- if (modelUpdateInFlight.value)
483
- await modelUpdateInFlight.value;
502
+ await waitForPendingModelUpdate();
484
503
  const conversation = currentConversation.value;
485
504
  if (!conversation)
486
505
  throw new Error("Erro ao preparar conversa");
506
+ await ensureConversationUsesSelectedModel(
507
+ conversation.model,
508
+ selectedModel.value,
509
+ (value) => persistConversationModel(conversation, value, false)
510
+ );
487
511
  if (conversation.threadSessionId && resolvedFeatures.value.chatOutboundQueue) {
488
512
  const wake = await agentWake.ensureReady(conversation.threadSessionId, selectedModel.value);
489
513
  if (wake.status !== "ready") {
@@ -535,16 +559,25 @@ async function handleCancel() {
535
559
  await cancelConversation();
536
560
  }
537
561
  async function handleRetry(messageId) {
538
- if (currentConversation.value?.threadSessionId) {
539
- const wake = await agentWake.ensureReady(currentConversation.value.threadSessionId, selectedModel.value);
540
- if (wake.status !== "ready") {
541
- statusToast.update({ text: "N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.", icon: "i-ph-warning" });
542
- return;
562
+ await retryMessage(messageId, async () => {
563
+ await waitForPendingModelUpdate();
564
+ const conversation = currentConversation.value;
565
+ if (!conversation)
566
+ throw new Error("Erro ao preparar conversa");
567
+ await ensureConversationUsesSelectedModel(
568
+ conversation.model,
569
+ selectedModel.value,
570
+ (value) => persistConversationModel(conversation, value, false)
571
+ );
572
+ if (conversation.threadSessionId) {
573
+ const wake = await agentWake.ensureReady(conversation.threadSessionId, selectedModel.value);
574
+ if (wake.status !== "ready")
575
+ throw new Error("N\xE3o foi poss\xEDvel acordar o agente. Tente novamente.");
576
+ } else {
577
+ await agentWake.waitUntilSettled();
543
578
  }
544
- } else {
545
- await agentWake.waitUntilSettled();
546
- }
547
- await retryMessage(messageId, claimableWakeSessionId());
579
+ return claimableWakeSessionId();
580
+ });
548
581
  }
549
582
  async function handleNewConversation(groupId) {
550
583
  setPendingConversationGroup(groupId);
@@ -13,6 +13,7 @@ const props = defineProps({
13
13
  initialConversationId: { type: [String, null], required: false },
14
14
  conversationScope: { type: [String, null], required: false },
15
15
  defaultConversationCreatorFilter: { type: null, required: false },
16
+ availableModels: { type: Array, required: false },
16
17
  conversationCreatorFilter: { type: null, required: false },
17
18
  hideConversationCreatorFilter: { type: Boolean, required: false },
18
19
  hideSidebar: { type: Boolean, required: false },
@@ -53,6 +54,7 @@ provideEmbedConfig({
53
54
  telaAgentId: normalizedTelaAgentId,
54
55
  conversationScope: normalizedConversationScope,
55
56
  defaultConversationCreatorFilter: computed(() => props.defaultConversationCreatorFilter),
57
+ availableModels: computed(() => props.availableModels),
56
58
  conversationCreatorFilter: computed(() => props.conversationCreatorFilter),
57
59
  telaAgentInputs: computed(() => props.telaAgentInputs),
58
60
  workspaceSettings: computed(() => props.workspaceSettings),
@@ -3,7 +3,7 @@ import type { ChatActionPayload } from '../../messages/composables/chat-action.j
3
3
  import type { MessageFeedbackPayload } from '../../messages/composables/chat-feedback.js';
4
4
  import type { ChatMessageTerminalPayload } from '../../messages/composables/chat-message-terminal.js';
5
5
  import type { ChatFeatureConfig } from '../feature-config.js';
6
- import type { ChatEmbedVariant, ChatEmbedVariantProps, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, TelaAgentChatEmbedProps } from '../types.js';
6
+ import type { AvailableChatModels, ChatEmbedVariant, ChatEmbedVariantProps, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, TelaAgentChatEmbedProps } from '../types.js';
7
7
 
8
8
  type MeistrariChatEmbedEmits = {
9
9
  /** Fired when the active conversation changes. Pairs with `v-model:conversation-id`. */
@@ -54,4 +54,4 @@ type MeistrariChatEmbedSlots = SlotsType<{
54
54
  declare const MeistrariChatEmbed: DefineSetupFnComponent<MeistrariChatEmbedProps, MeistrariChatEmbedEmits, MeistrariChatEmbedSlots>;
55
55
 
56
56
  export default MeistrariChatEmbed;
57
- export type { ChatActionPayload, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, MessageFeedbackPayload, TelaAgentChatEmbedProps };
57
+ export type { AvailableChatModels, ChatActionPayload, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, MessageFeedbackPayload, TelaAgentChatEmbedProps };
@@ -6,6 +6,7 @@ const { hideSidebar = void 0, ...props } = defineProps({
6
6
  initialConversationId: { type: [String, null], required: false },
7
7
  conversationScope: { type: [String, null], required: false },
8
8
  defaultConversationCreatorFilter: { type: null, required: false },
9
+ availableModels: { type: Array, required: false },
9
10
  conversationCreatorFilter: { type: null, required: false },
10
11
  hideConversationCreatorFilter: { type: Boolean, required: false },
11
12
  hideSidebar: { type: Boolean, required: false },
@@ -62,6 +63,7 @@ const sharedEmbedProps = computed(() => ({
62
63
  initialConversationId: props.initialConversationId,
63
64
  conversationScope: props.conversationScope,
64
65
  defaultConversationCreatorFilter: props.defaultConversationCreatorFilter,
66
+ availableModels: props.availableModels,
65
67
  conversationCreatorFilter: props.conversationCreatorFilter,
66
68
  hideConversationCreatorFilter: props.hideConversationCreatorFilter,
67
69
  hideSettings: hideSettings.value,
@@ -3,7 +3,7 @@ import type { ChatActionPayload } from '../../messages/composables/chat-action.j
3
3
  import type { MessageFeedbackPayload } from '../../messages/composables/chat-feedback.js';
4
4
  import type { ChatMessageTerminalPayload } from '../../messages/composables/chat-message-terminal.js';
5
5
  import type { ChatFeatureConfig } from '../feature-config.js';
6
- import type { ChatEmbedVariant, ChatEmbedVariantProps, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, TelaAgentChatEmbedProps } from '../types.js';
6
+ import type { AvailableChatModels, ChatEmbedVariant, ChatEmbedVariantProps, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, TelaAgentChatEmbedProps } from '../types.js';
7
7
 
8
8
  type MeistrariChatEmbedEmits = {
9
9
  /** Fired when the active conversation changes. Pairs with `v-model:conversation-id`. */
@@ -54,4 +54,4 @@ type MeistrariChatEmbedSlots = SlotsType<{
54
54
  declare const MeistrariChatEmbed: DefineSetupFnComponent<MeistrariChatEmbedProps, MeistrariChatEmbedEmits, MeistrariChatEmbedSlots>;
55
55
 
56
56
  export default MeistrariChatEmbed;
57
- export type { ChatActionPayload, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, MessageFeedbackPayload, TelaAgentChatEmbedProps };
57
+ export type { AvailableChatModels, ChatActionPayload, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, MessageFeedbackPayload, TelaAgentChatEmbedProps };
@@ -5,6 +5,7 @@ import type { TelaAgentExecutionInput } from '../../types/schemas/integrations/t
5
5
  import type { ChatLoadingMessageMode } from '../loading-messages.js';
6
6
  import type { ChatCitationsConfig } from '../../citations/types.js';
7
7
  import type { MessageFeedbackConfig, MessageFeedbackRating } from '../../messages/composables/chat-feedback.js';
8
+ import type { AvailableChatModels } from '../../messages/model-availability.js';
8
9
  type ConfiguredTelaAgentInputs = DeepReadonly<TelaAgentExecutionInput[]> | null | undefined;
9
10
  type ConfiguredMessageFeedback = Readonly<Record<string, MessageFeedbackRating>> | null | undefined;
10
11
  export type EmbedConfig = {
@@ -12,6 +13,7 @@ export type EmbedConfig = {
12
13
  telaAgentId: Ref<string | null>;
13
14
  conversationScope: Ref<string | null>;
14
15
  defaultConversationCreatorFilter: Ref<ConversationCreatorFilter>;
16
+ availableModels: Ref<AvailableChatModels | undefined>;
15
17
  conversationCreatorFilter: Ref<ConversationCreatorFilter | undefined>;
16
18
  telaAgentInputs: Ref<ConfiguredTelaAgentInputs>;
17
19
  workspaceSettings: Ref<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
@@ -31,6 +33,7 @@ type EmbedConfigInput = {
31
33
  telaAgentId?: MaybeRefOrGetter<string | null | undefined>;
32
34
  conversationScope?: MaybeRefOrGetter<string | null | undefined>;
33
35
  defaultConversationCreatorFilter?: MaybeRefOrGetter<ConversationCreatorFilter | null | undefined>;
36
+ availableModels?: MaybeRefOrGetter<AvailableChatModels | undefined>;
34
37
  conversationCreatorFilter?: MaybeRefOrGetter<ConversationCreatorFilter | undefined>;
35
38
  telaAgentInputs?: MaybeRefOrGetter<ConfiguredTelaAgentInputs>;
36
39
  workspaceSettings?: MaybeRefOrGetter<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
@@ -22,6 +22,7 @@ function useGlobalEmbedConfigState() {
22
22
  telaAgentId: useState("chat-embed-config-tela-agent-id", () => null),
23
23
  conversationScope: useState("chat-embed-config-conversation-scope", () => null),
24
24
  defaultConversationCreatorFilter: useState("chat-embed-config-default-conversation-creator-filter", () => void 0),
25
+ availableModels: useState("chat-embed-config-available-models", () => void 0),
25
26
  conversationCreatorFilter: useState("chat-embed-config-conversation-creator-filter", () => void 0),
26
27
  telaAgentInputs: useState("chat-embed-config-tela-agent-inputs", () => void 0),
27
28
  workspaceSettings: useState("chat-embed-config-workspace-settings", () => void 0),
@@ -43,6 +44,7 @@ export function provideEmbedConfig(input, options = {}) {
43
44
  telaAgentId: computed(() => toValue(input.telaAgentId) ?? null),
44
45
  conversationScope: computed(() => normalizeConversationScope(toValue(input.conversationScope))),
45
46
  defaultConversationCreatorFilter: computed(() => toValue(input.defaultConversationCreatorFilter) ?? "all"),
47
+ availableModels: computed(() => toValue(input.availableModels)),
46
48
  conversationCreatorFilter: computed(() => toValue(input.conversationCreatorFilter)),
47
49
  telaAgentInputs: computed(() => toValue(input.telaAgentInputs)),
48
50
  workspaceSettings: computed(() => toValue(input.workspaceSettings)),
@@ -65,6 +67,7 @@ export function provideEmbedConfig(input, options = {}) {
65
67
  globalConfig.telaAgentId.value = config.telaAgentId.value;
66
68
  globalConfig.conversationScope.value = config.conversationScope.value;
67
69
  globalConfig.defaultConversationCreatorFilter.value = config.defaultConversationCreatorFilter.value;
70
+ globalConfig.availableModels.value = config.availableModels.value;
68
71
  globalConfig.conversationCreatorFilter.value = config.conversationCreatorFilter.value;
69
72
  globalConfig.telaAgentInputs.value = config.telaAgentInputs.value;
70
73
  globalConfig.workspaceSettings.value = config.workspaceSettings.value;
@@ -94,6 +97,7 @@ export function useEmbedConfig() {
94
97
  telaAgentId: computed(() => globalConfig.telaAgentId.value),
95
98
  conversationScope: computed(() => globalConfig.conversationScope.value),
96
99
  defaultConversationCreatorFilter: computed(() => globalConfig.defaultConversationCreatorFilter.value ?? "all"),
100
+ availableModels: computed(() => globalConfig.availableModels.value),
97
101
  conversationCreatorFilter: computed(() => globalConfig.conversationCreatorFilter.value),
98
102
  telaAgentInputs: computed(() => globalConfig.telaAgentInputs.value),
99
103
  workspaceSettings: computed(() => globalConfig.workspaceSettings.value),
@@ -6,6 +6,8 @@ import type { ChatLoadingMessageMode } from './loading-messages.js';
6
6
  import type { ChatFeatureConfig } from './feature-config.js';
7
7
  import type { ChatCitationsConfig } from '../citations/types.js';
8
8
  import type { MessageFeedbackConfig, MessageFeedbackRating } from '../messages/composables/chat-feedback.js';
9
+ import type { AvailableChatModels } from '../messages/model-availability.js';
10
+ export type { AvailableChatModels } from '../messages/model-availability.js';
9
11
  export type ChatEmbedVariant = 'page' | 'floating' | 'sidepanel';
10
12
  export type ChatSuggestion = {
11
13
  /** Short label rendered on the suggestion pill. */
@@ -55,6 +57,12 @@ export type ChatEmbedSharedProps = {
55
57
  * conversation in scope, `'mine'` shows only those created by the current user.
56
58
  */
57
59
  defaultConversationCreatorFilter?: ConversationCreatorFilter;
60
+ /**
61
+ * Non-empty ordered list of models this embed may display and execute.
62
+ * When omitted, the full chat catalog remains available. The first model is
63
+ * used when a new or restored selection is not allowed by this list.
64
+ */
65
+ availableModels?: AvailableChatModels;
58
66
  /** Controlled creator filter. Use with `v-model:conversation-creator-filter` when the host changes it at runtime. */
59
67
  conversationCreatorFilter?: ConversationCreatorFilter;
60
68
  /** Hide the conversation creator filter while preserving its active value. */
@@ -1,5 +1,7 @@
1
1
  <script setup>
2
2
  import { chatModelOptions } from "../../types/schemas/chat/ui.js";
3
+ import { useEmbedConfig } from "../../embed/composables/embed-config";
4
+ import { resolveAvailableChatModels } from "../model-availability";
3
5
  import TelaChatIconsAnthropic from "@meistrari/tela-build/components/tela/chat/icons/anthropic.vue";
4
6
  import TelaChatIconsGemini from "@meistrari/tela-build/components/tela/chat/icons/gemini.vue";
5
7
  import TelaChatIconsOpenai from "@meistrari/tela-build/components/tela/chat/icons/openai.vue";
@@ -7,23 +9,32 @@ defineProps({
7
9
  disabled: { type: Boolean, required: false }
8
10
  });
9
11
  const model = defineModel({ type: [String, null], ...{ default: null } });
12
+ const embedConfig = useEmbedConfig();
10
13
  const providerIcons = {
11
14
  Anthropic: TelaChatIconsAnthropic,
12
15
  OpenAI: TelaChatIconsOpenai,
13
16
  Google: TelaChatIconsGemini
14
17
  };
15
- const options = chatModelOptions.map((option) => ({
16
- value: option.value,
17
- label: option.label,
18
- description: option.description,
19
- group: option.provider,
20
- icon: providerIcons[option.provider],
21
- cost: option.cost,
22
- maxInputTokens: option.maxInputTokens,
23
- maxOutputTokens: option.maxOutputTokens,
24
- isMultiModal: option.isMultiModal,
25
- tabs: [...option.tabs]
26
- }));
18
+ const options = computed(() => {
19
+ const availableModels = resolveAvailableChatModels(embedConfig?.availableModels.value);
20
+ return availableModels.map((model2) => {
21
+ const option = chatModelOptions.find((candidate) => candidate.value === model2);
22
+ if (!option)
23
+ throw new Error(`${model2} is missing from the chat model catalog`);
24
+ return {
25
+ value: option.value,
26
+ label: option.label,
27
+ description: option.description,
28
+ group: option.provider,
29
+ icon: providerIcons[option.provider],
30
+ cost: option.cost,
31
+ maxInputTokens: option.maxInputTokens,
32
+ maxOutputTokens: option.maxOutputTokens,
33
+ isMultiModal: option.isMultiModal,
34
+ tabs: [...option.tabs]
35
+ };
36
+ });
37
+ });
27
38
  const tabLabels = {
28
39
  all: "Todos",
29
40
  advanced: "Avan\xE7ados",
@@ -40,7 +40,7 @@ export declare function useChat(options?: {
40
40
  }>, queuedSend?: QueuedSend) => Promise<Message | null>;
41
41
  flushOutboundQueue: (wakeSessionId?: string) => Promise<Message | null>;
42
42
  failOutboundQueue: (message: string) => boolean;
43
- retryMessage: (messageId: string, wakeSessionId?: string) => Promise<boolean>;
43
+ retryMessage: (messageId: string, prepare?: () => Promise<string | undefined>) => Promise<boolean>;
44
44
  cancelConversation: () => Promise<boolean>;
45
45
  startPolling: () => void;
46
46
  stopPolling: () => void;
@@ -16,6 +16,7 @@ import {
16
16
  CANCELLATION_FAILED_TEXT,
17
17
  GENERATION_FAILED_TEXT
18
18
  } from "../message-state.js";
19
+ import { useConversations } from "../../conversations/composables/conversations.js";
19
20
  import { exportConversationToMarkdown } from "../../conversations/export.js";
20
21
  import { resolveChatStateScope } from "../../conversations/scope.js";
21
22
  import { getChatApiErrorCode, getChatApiErrorMessage, getChatApiErrorStatus } from "../../shared/chat-api-error.js";
@@ -45,6 +46,7 @@ export function useChat(options = {}) {
45
46
  const embedConfig = useEmbedConfig();
46
47
  const { user: authUser, activeOrganization } = useChatAuth();
47
48
  const { addFilesToConversation } = useConversationFileActions();
49
+ const { updateConversationInList } = useConversations();
48
50
  const chatScope = computed(() => resolveChatStateScope(
49
51
  embedConfig?.workspaceId.value || activeOrganization.value?.id,
50
52
  embedConfig?.telaAgentId.value,
@@ -118,9 +120,26 @@ export function useChat(options = {}) {
118
120
  schedulePreparingStep(0);
119
121
  }
120
122
  const error = ref(null);
121
- const titleGenerated = ref(false);
122
- const generatingTitle = ref(false);
123
- const animatedTitle = ref(null);
123
+ const titleGeneratedBuckets = useState("chat-title-generated", () => ({}));
124
+ const generatingTitleBuckets = useState("chat-generating-title", () => ({}));
125
+ const animatedTitleBuckets = useState("chat-animated-title", () => ({}));
126
+ const generatingTitle = computed(() => {
127
+ const conversationId = currentConversation.value?.id;
128
+ return conversationId ? generatingTitleBuckets.value[conversationId] ?? false : false;
129
+ });
130
+ const animatedTitle = computed(() => {
131
+ const conversationId = currentConversation.value?.id;
132
+ return conversationId ? animatedTitleBuckets.value[conversationId] ?? null : null;
133
+ });
134
+ function markTitleGenerated(conversationId, generated) {
135
+ titleGeneratedBuckets.value = { ...titleGeneratedBuckets.value, [conversationId]: generated };
136
+ }
137
+ function setGeneratingTitle(conversationId, generating) {
138
+ generatingTitleBuckets.value = { ...generatingTitleBuckets.value, [conversationId]: generating };
139
+ }
140
+ function setAnimatedTitle(conversationId, title) {
141
+ animatedTitleBuckets.value = { ...animatedTitleBuckets.value, [conversationId]: title };
142
+ }
124
143
  const hasPendingMessage = computed(
125
144
  () => messages.value.some((m) => m.status === "pending")
126
145
  );
@@ -338,7 +357,6 @@ export function useChat(options = {}) {
338
357
  };
339
358
  const adoptConversation = (conv) => {
340
359
  currentConversation.value = { ...conv, messages: messages.value };
341
- titleGenerated.value = false;
342
360
  };
343
361
  const setConversation = (conv) => {
344
362
  if (currentConversation.value && currentConversation.value.id !== conv.id) {
@@ -353,13 +371,11 @@ export function useChat(options = {}) {
353
371
  agentSessionStatus.value = null;
354
372
  agentSessionExecutable.value = false;
355
373
  agentSessionRewakeable.value = false;
356
- titleGenerated.value = false;
357
374
  error.value = null;
358
375
  };
359
376
  const loadConversation = async (id) => {
360
377
  loading.value = true;
361
378
  error.value = null;
362
- titleGenerated.value = false;
363
379
  try {
364
380
  const data = await $fetch(
365
381
  chatApi.path(`/conversations/${id}`),
@@ -369,9 +385,8 @@ export function useChat(options = {}) {
369
385
  messages.value = data.messages;
370
386
  pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
371
387
  pendingRealResultIds.value = /* @__PURE__ */ new Set();
372
- if (shouldTreatLoadedConversationTitleAsGenerated(data.messages)) {
373
- titleGenerated.value = true;
374
- }
388
+ if (shouldTreatLoadedConversationTitleAsGenerated(data.messages))
389
+ markTitleGenerated(data.id, true);
375
390
  const pendingAssistant = data.messages.findLast((m) => m.role === "assistant" && m.status === "pending");
376
391
  if (pendingAssistant) {
377
392
  streamingMessageId.value = pendingAssistant.id;
@@ -713,19 +728,24 @@ export function useChat(options = {}) {
713
728
  return false;
714
729
  }
715
730
  };
716
- const retryMessage = async (messageId, wakeSessionId) => {
731
+ const retryMessage = async (messageId, prepare) => {
717
732
  if (!currentConversation.value)
718
733
  return false;
734
+ const conversationId = currentConversation.value.id;
719
735
  error.value = null;
720
- const retry = beginAssistantMessageRetry(messages.value, messageId);
721
- if (!retry)
722
- return false;
723
- messages.value = retry.messages;
724
- streamingMessageId.value = messageId;
725
- directStream.beginMessage();
736
+ let retry = null;
726
737
  try {
738
+ const wakeSessionId = prepare ? await prepare() : void 0;
739
+ if (currentConversation.value?.id !== conversationId)
740
+ return false;
741
+ retry = beginAssistantMessageRetry(messages.value, messageId);
742
+ if (!retry)
743
+ return false;
744
+ messages.value = retry.messages;
745
+ streamingMessageId.value = messageId;
746
+ directStream.beginMessage();
727
747
  await $fetch(
728
- chatApi.path(`/conversations/${currentConversation.value.id}/messages/${messageId}/retry`),
748
+ chatApi.path(`/conversations/${conversationId}/messages/${messageId}/retry`),
729
749
  chatApi.withChatHeaders({
730
750
  method: "POST",
731
751
  body: wakeSessionId ? { wakeSessionId } : {}
@@ -734,39 +754,46 @@ export function useChat(options = {}) {
734
754
  startPolling();
735
755
  return true;
736
756
  } catch (err) {
737
- messages.value = restoreAssistantMessageAfterRetryFailure(messages.value, retry.originalMessage);
738
- streamingMessageId.value = null;
739
- directStream.disconnect();
757
+ if (retry) {
758
+ messages.value = restoreAssistantMessageAfterRetryFailure(messages.value, retry.originalMessage);
759
+ streamingMessageId.value = null;
760
+ directStream.disconnect();
761
+ }
740
762
  const errorMessage = getChatApiErrorCode(err) === "workspace_agent_not_ready" ? WORKSPACE_AGENT_NOT_READY_TEXT : err instanceof Error ? err.message : "Erro ao reenviar mensagem";
741
763
  error.value = errorMessage;
742
764
  Sentry.captureException(err);
743
765
  return false;
744
766
  }
745
767
  };
746
- const animateTitle = (title) => {
768
+ const animateTitle = (title, conversationId) => {
747
769
  return new Promise((resolve) => {
748
- animatedTitle.value = "";
770
+ setAnimatedTitle(conversationId, "");
749
771
  let index = 0;
750
772
  const interval = setInterval(() => {
751
- if (index < title.length) {
752
- animatedTitle.value = title.slice(0, index + 1);
773
+ if (currentConversation.value?.id !== conversationId) {
774
+ clearInterval(interval);
775
+ setAnimatedTitle(conversationId, null);
776
+ resolve(false);
777
+ } else if (index < title.length) {
778
+ setAnimatedTitle(conversationId, title.slice(0, index + 1));
753
779
  index++;
754
780
  } else {
755
781
  clearInterval(interval);
756
- animatedTitle.value = null;
757
- resolve();
782
+ setAnimatedTitle(conversationId, null);
783
+ resolve(true);
758
784
  }
759
785
  }, 30);
760
786
  });
761
787
  };
762
788
  const generateTitle = async () => {
763
- if (!currentConversation.value || titleGenerated.value)
789
+ const conversation = currentConversation.value;
790
+ if (!conversation || titleGeneratedBuckets.value[conversation.id])
764
791
  return;
765
792
  const titleMessages = selectTitleGenerationMessages(messages.value);
766
793
  if (!titleMessages)
767
794
  return;
768
- titleGenerated.value = true;
769
- generatingTitle.value = true;
795
+ markTitleGenerated(conversation.id, true);
796
+ setGeneratingTitle(conversation.id, true);
770
797
  try {
771
798
  const { title } = await $fetch(
772
799
  chatApi.path("/conversations/generate-title"),
@@ -778,24 +805,27 @@ export function useChat(options = {}) {
778
805
  }
779
806
  })
780
807
  );
781
- if (title && currentConversation.value) {
782
- await animateTitle(title);
783
- await $fetch(chatApi.path(`/conversations/${currentConversation.value.id}`), {
784
- ...chatApi.withChatHeaders({
785
- method: "PATCH",
786
- body: { title }
787
- })
788
- });
789
- currentConversation.value = {
790
- ...currentConversation.value,
791
- title
792
- };
808
+ if (!title)
809
+ return;
810
+ const updated = await $fetch(
811
+ chatApi.path(`/conversations/${conversation.id}`),
812
+ chatApi.withChatHeaders({
813
+ method: "PATCH",
814
+ body: { title }
815
+ })
816
+ );
817
+ updateConversationInList(updated);
818
+ if (currentConversation.value?.id === conversation.id && await animateTitle(title, conversation.id)) {
819
+ const current = currentConversation.value;
820
+ if (current?.id === conversation.id)
821
+ currentConversation.value = { ...current, title };
793
822
  }
794
823
  } catch (err) {
824
+ markTitleGenerated(conversation.id, false);
795
825
  Sentry.captureException(err);
796
826
  } finally {
797
- generatingTitle.value = false;
798
- animatedTitle.value = null;
827
+ setGeneratingTitle(conversation.id, false);
828
+ setAnimatedTitle(conversation.id, null);
799
829
  }
800
830
  };
801
831
  const exportToMarkdown = () => {
@@ -0,0 +1,6 @@
1
+ import type { ChatModel } from '../types/schemas/chat/models.js';
2
+ export type AvailableChatModels = readonly [ChatModel, ...ChatModel[]];
3
+ export declare const MODEL_UPDATE_FAILED_MESSAGE = "N\u00E3o foi poss\u00EDvel atualizar o modelo da conversa";
4
+ export declare function resolveAvailableChatModels(availableModels?: readonly ChatModel[]): readonly ChatModel[];
5
+ export declare function resolveChatModelSelection(selectedModel: string | null, availableModels?: readonly ChatModel[]): string | null;
6
+ export declare function ensureConversationUsesSelectedModel(conversationModel: string | null, selectedModel: string | null, updateModel: (model: string | null) => Promise<boolean>): Promise<void>;
@@ -0,0 +1,28 @@
1
+ import { chatModelIds, isValidChatModel } from "../types/schemas/chat/models.js";
2
+ export const MODEL_UPDATE_FAILED_MESSAGE = "N\xE3o foi poss\xEDvel atualizar o modelo da conversa";
3
+ export function resolveAvailableChatModels(availableModels) {
4
+ if (availableModels === void 0)
5
+ return chatModelIds;
6
+ if (availableModels.length === 0)
7
+ throw new Error("availableModels must contain at least one model");
8
+ const uniqueModels = [];
9
+ for (const model of availableModels) {
10
+ if (!isValidChatModel(model))
11
+ throw new Error(`${model} is not a supported chat model`);
12
+ if (!uniqueModels.includes(model))
13
+ uniqueModels.push(model);
14
+ }
15
+ return uniqueModels;
16
+ }
17
+ export function resolveChatModelSelection(selectedModel, availableModels) {
18
+ if (availableModels === void 0)
19
+ return selectedModel;
20
+ const resolvedModels = resolveAvailableChatModels(availableModels);
21
+ return selectedModel && resolvedModels.includes(selectedModel) ? selectedModel : resolvedModels[0];
22
+ }
23
+ export async function ensureConversationUsesSelectedModel(conversationModel, selectedModel, updateModel) {
24
+ if (conversationModel === selectedModel)
25
+ return;
26
+ if (!await updateModel(selectedModel))
27
+ throw new Error(MODEL_UPDATE_FAILED_MESSAGE);
28
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,3 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { proxyChatApiRequest } from "../../../utils/chat-api-proxy.js";
3
+ export default defineEventHandler((event) => proxyChatApiRequest(event, "conversations/generate-title"));
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { defineEventHandler, getRouterParam } from "h3";
2
+ import { prefixProxyPath, proxyChatApiRequest } from "../../../../utils/chat-api-proxy.js";
3
+ export default defineEventHandler((event) => {
4
+ const groupId = getRouterParam(event, "groupId") || "";
5
+ return proxyChatApiRequest(event, prefixProxyPath("conversations/groups", groupId));
6
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,3 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { proxyChatApiRequest } from "../../../utils/chat-api-proxy.js";
3
+ export default defineEventHandler((event) => proxyChatApiRequest(event, "conversations/groups"));
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,3 @@
1
+ import { defineEventHandler } from "h3";
2
+ import { proxyChatApiRequest } from "../../../utils/chat-api-proxy.js";
3
+ export default defineEventHandler((event) => proxyChatApiRequest(event, "conversations/metadata"));
@@ -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 { ChatActor, ChatEmbedSharedProps, ChatEmbedVariant, ChatEmbedVariantProps, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, TelaAgentChatEmbedProps, } from '../embed/types.js';
3
+ export type { AvailableChatModels, ChatActor, ChatEmbedSharedProps, ChatEmbedVariant, ChatEmbedVariantProps, 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';
@@ -216,6 +216,7 @@ export declare const createConversationRequestSchema: z.ZodObject<{
216
216
  "claude-opus-5": "claude-opus-5";
217
217
  "claude-opus-4-8": "claude-opus-4-8";
218
218
  "claude-sonnet-5": "claude-sonnet-5";
219
+ "claude-sonnet-4-6": "claude-sonnet-4-6";
219
220
  "claude-haiku-4-5": "claude-haiku-4-5";
220
221
  }>>>;
221
222
  agentInputs: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -253,6 +254,7 @@ export declare const updateConversationRequestSchema: z.ZodObject<{
253
254
  "claude-opus-5": "claude-opus-5";
254
255
  "claude-opus-4-8": "claude-opus-4-8";
255
256
  "claude-sonnet-5": "claude-sonnet-5";
257
+ "claude-sonnet-4-6": "claude-sonnet-4-6";
256
258
  "claude-haiku-4-5": "claude-haiku-4-5";
257
259
  }>>>;
258
260
  }, z.core.$strict>;
@@ -1,9 +1,10 @@
1
1
  import { z } from 'zod';
2
- export declare const chatModelIds: readonly ["claude-opus-5", "claude-opus-4-8", "claude-sonnet-5", "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"];
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
+ "claude-sonnet-4-6": "claude-sonnet-4-6";
7
8
  "claude-haiku-4-5": "claude-haiku-4-5";
8
9
  }>;
9
10
  export type ChatModel = z.infer<typeof chatModelSchema>;
@@ -3,6 +3,7 @@ export const chatModelIds = [
3
3
  'claude-opus-5',
4
4
  'claude-opus-4-8',
5
5
  'claude-sonnet-5',
6
+ 'claude-sonnet-4-6',
6
7
  'claude-haiku-4-5',
7
8
  ];
8
9
  export const chatModelSchema = z.enum(chatModelIds);
@@ -49,6 +49,16 @@ export declare const chatModelOptions: readonly [{
49
49
  readonly maxOutputTokens: 64000;
50
50
  readonly isMultiModal: true;
51
51
  readonly tabs: readonly ["all", "advanced", "multimodal"];
52
+ }, {
53
+ readonly value: "claude-sonnet-4-6";
54
+ readonly label: "Claude 4.6 Sonnet";
55
+ readonly description: "Agente rápido para tarefas avançadas";
56
+ readonly provider: "Anthropic";
57
+ readonly cost: 4;
58
+ readonly maxInputTokens: 1000000;
59
+ readonly maxOutputTokens: 64000;
60
+ readonly isMultiModal: true;
61
+ readonly tabs: readonly ["all", "advanced", "multimodal"];
52
62
  }, {
53
63
  readonly value: "claude-haiku-4-5";
54
64
  readonly label: "Claude 4.5 Haiku";
@@ -9,6 +9,7 @@ export const chatModelOptions = [
9
9
  { value: 'claude-opus-5', label: 'Claude Opus 5', description: 'Agente de ponta para trabalho complexo', provider: 'Anthropic', cost: 5, maxInputTokens: 1_000_000, maxOutputTokens: 128_000, isMultiModal: true, tabs: ['all', 'advanced', 'multimodal'] },
10
10
  { value: 'claude-opus-4-8', label: 'Claude 4.8 Opus', description: 'Agente de ponta para tarefas complexas', provider: 'Anthropic', cost: 4, maxInputTokens: 1_000_000, maxOutputTokens: 128_000, isMultiModal: true, tabs: ['all', 'advanced', 'multimodal'] },
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
+ { 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'] },
12
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'] },
13
14
  ];
14
15
  export const topbarTabs = ['chat', 'files', 'usage'];
@@ -278,6 +278,7 @@ export declare const telaAgentWakeRequestSchema: z.ZodObject<{
278
278
  "claude-opus-5": "claude-opus-5";
279
279
  "claude-opus-4-8": "claude-opus-4-8";
280
280
  "claude-sonnet-5": "claude-sonnet-5";
281
+ "claude-sonnet-4-6": "claude-sonnet-4-6";
281
282
  "claude-haiku-4-5": "claude-haiku-4-5";
282
283
  }>>;
283
284
  }, z.core.$strip>;
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 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 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.14.2-rc.2",
3
+ "version": "3.15.0-rc.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {