@meistrari/chat-nuxt 1.8.1 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +1 -0
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/components/MeistrariChatEmbed.vue +3 -0
  4. package/dist/runtime/components/chat/conversation-creator-filter.d.vue.ts +3 -0
  5. package/dist/runtime/components/chat/conversation-creator-filter.vue +95 -0
  6. package/dist/runtime/components/chat/conversation-creator-filter.vue.d.ts +3 -0
  7. package/dist/runtime/components/chat/conversation-item.d.vue.ts +1 -0
  8. package/dist/runtime/components/chat/conversation-item.vue +142 -63
  9. package/dist/runtime/components/chat/conversation-item.vue.d.ts +1 -0
  10. package/dist/runtime/components/chat/conversation-list.d.vue.ts +2 -0
  11. package/dist/runtime/components/chat/conversation-list.vue +35 -9
  12. package/dist/runtime/components/chat/conversation-list.vue.d.ts +2 -0
  13. package/dist/runtime/components/chat/conversation-search.d.vue.ts +16 -0
  14. package/dist/runtime/components/chat/conversation-search.vue +35 -0
  15. package/dist/runtime/components/chat/conversation-search.vue.d.ts +16 -0
  16. package/dist/runtime/components/chat/mobile/shell/drawer.vue +16 -5
  17. package/dist/runtime/components/chat/mobile/shell/header.d.vue.ts +4 -4
  18. package/dist/runtime/components/chat/mobile/shell/header.vue.d.ts +4 -4
  19. package/dist/runtime/components/chat/mobile/shell/shell.d.vue.ts +14 -14
  20. package/dist/runtime/components/chat/mobile/shell/shell.vue.d.ts +14 -14
  21. package/dist/runtime/components/chat/topbar.d.vue.ts +8 -8
  22. package/dist/runtime/components/chat/topbar.vue +29 -11
  23. package/dist/runtime/components/chat/topbar.vue.d.ts +8 -8
  24. package/dist/runtime/composables/useConversations.d.ts +2 -0
  25. package/dist/runtime/composables/useConversations.js +81 -36
  26. package/dist/runtime/composables/useEmbedConfig.d.ts +3 -0
  27. package/dist/runtime/composables/useEmbedConfig.js +4 -0
  28. package/dist/runtime/embed/components/ChatEmbed.vue +2 -0
  29. package/dist/runtime/embed/components/ChatEmbedInner.vue +11 -30
  30. package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.d.vue.ts +4 -4
  31. package/dist/runtime/embed/components/configuration/ChatConfigurationContextFilesTab.vue.d.ts +4 -4
  32. package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.d.vue.ts +2 -2
  33. package/dist/runtime/embed/components/configuration/ChatConfigurationMobileShell.vue.d.ts +2 -2
  34. package/dist/runtime/server/api/conversations/index.get.js +5 -4
  35. package/dist/runtime/server/utils/conversation-list.d.ts +4 -0
  36. package/dist/runtime/server/utils/conversation-list.js +28 -0
  37. package/dist/runtime/types/chat.d.ts +8 -0
  38. package/dist/runtime/types/chat.js +4 -0
  39. package/dist/runtime/types/embed.d.ts +3 -0
  40. package/dist/runtime/utils/conversation-creator-filter.d.ts +5 -0
  41. package/dist/runtime/utils/conversation-creator-filter.js +24 -0
  42. package/dist/runtime/utils/conversation-search.d.ts +8 -0
  43. package/dist/runtime/utils/conversation-search.js +11 -0
  44. package/dist/runtime/utils/conversation-title.d.ts +1 -0
  45. package/dist/runtime/utils/conversation-title.js +6 -0
  46. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
  import { formatRelativeTime } from "../../../../utils/format-time";
3
3
  import { conversationListSkeletonRows } from "../../../../utils/conversation-list-skeleton";
4
+ import { filterConversationsByTitle } from "../../../../utils/conversation-search";
4
5
  const props = defineProps({
5
6
  open: { type: Boolean, required: true },
6
7
  conversations: { type: null, required: true },
@@ -15,6 +16,14 @@ const initial = computed(() => {
15
16
  const source = props.userName ?? props.userEmail ?? "U";
16
17
  return source.charAt(0).toUpperCase();
17
18
  });
19
+ const conversationSearch = ref("");
20
+ const filteredConversations = computed(
21
+ () => filterConversationsByTitle(props.conversations, conversationSearch.value, {
22
+ fallbackTitle: "Nova conversa",
23
+ shouldInclude: (conversation) => !conversation.title && conversation.id === props.activeId
24
+ })
25
+ );
26
+ const hasConversationSearchQuery = computed(() => conversationSearch.value.trim().length > 0);
18
27
  function handleSelect(id) {
19
28
  emit("select", id);
20
29
  emit("close");
@@ -74,7 +83,7 @@ function handleNew() {
74
83
  </button>
75
84
  </div>
76
85
 
77
- <div p-12px>
86
+ <div p-12px flex="~ col" gap-8px>
78
87
  <button
79
88
  flex items-center justify-center gap-6px
80
89
  w-full px-12px py-10px rounded-10px
@@ -88,6 +97,8 @@ function handleNew() {
88
97
  Nova conversa
89
98
  </span>
90
99
  </button>
100
+ <ChatConversationSearch v-model="conversationSearch" />
101
+ <ChatConversationCreatorFilter />
91
102
  </div>
92
103
 
93
104
  <div px-14px pt-4px pb-4px>
@@ -95,7 +106,7 @@ function handleNew() {
95
106
  text-12px font-medium uppercase text-neutral-400
96
107
  style="letter-spacing: 0.5px"
97
108
  >
98
- Recentes
109
+ {{ hasConversationSearchQuery ? "Resultados" : "Recentes" }}
99
110
  </span>
100
111
  </div>
101
112
 
@@ -109,14 +120,14 @@ function handleNew() {
109
120
  <TelaSkeleton rounded-6px bg-neutral-200 :style="{ width: row.width, height: '13px' }" />
110
121
  </div>
111
122
  </div>
112
- <div v-else-if="conversations.length === 0" p-16px text-center>
123
+ <div v-else-if="filteredConversations.length === 0" p-16px text-center>
113
124
  <p text-14px text-neutral-400>
114
- Nenhuma conversa ainda
125
+ {{ hasConversationSearchQuery ? "Nenhuma conversa encontrada" : "Nenhuma conversa ainda" }}
115
126
  </p>
116
127
  </div>
117
128
  <div v-else flex="~ col" gap-1px>
118
129
  <button
119
- v-for="conv in conversations"
130
+ v-for="conv in filteredConversations"
120
131
  :key="conv.id"
121
132
  flex="~ col" gap-2px
122
133
  w-full px-12px py-10px rounded-10px text-left
@@ -15,24 +15,24 @@ type __VLS_Props = {
15
15
  };
16
16
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
17
17
  delete: () => any;
18
+ openDrawer: () => any;
19
+ openOutdatedSettings: () => any;
18
20
  rename: () => any;
19
21
  duplicate: () => any;
20
22
  export: () => any;
21
23
  copyLink: () => any;
22
24
  debug: () => any;
23
25
  tabChange: (tab: TopbarTab) => any;
24
- openDrawer: () => any;
25
- openOutdatedSettings: () => any;
26
26
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
27
27
  onDelete?: (() => any) | undefined;
28
+ onOpenDrawer?: (() => any) | undefined;
29
+ onOpenOutdatedSettings?: (() => any) | undefined;
28
30
  onRename?: (() => any) | undefined;
29
31
  onDuplicate?: (() => any) | undefined;
30
32
  onExport?: (() => any) | undefined;
31
33
  onCopyLink?: (() => any) | undefined;
32
34
  onDebug?: (() => any) | undefined;
33
35
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
34
- onOpenDrawer?: (() => any) | undefined;
35
- onOpenOutdatedSettings?: (() => any) | undefined;
36
36
  }>, {
37
37
  showDrawerButton: boolean;
38
38
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -15,24 +15,24 @@ type __VLS_Props = {
15
15
  };
16
16
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
17
17
  delete: () => any;
18
+ openDrawer: () => any;
19
+ openOutdatedSettings: () => any;
18
20
  rename: () => any;
19
21
  duplicate: () => any;
20
22
  export: () => any;
21
23
  copyLink: () => any;
22
24
  debug: () => any;
23
25
  tabChange: (tab: TopbarTab) => any;
24
- openDrawer: () => any;
25
- openOutdatedSettings: () => any;
26
26
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
27
27
  onDelete?: (() => any) | undefined;
28
+ onOpenDrawer?: (() => any) | undefined;
29
+ onOpenOutdatedSettings?: (() => any) | undefined;
28
30
  onRename?: (() => any) | undefined;
29
31
  onDuplicate?: (() => any) | undefined;
30
32
  onExport?: (() => any) | undefined;
31
33
  onCopyLink?: (() => any) | undefined;
32
34
  onDebug?: (() => any) | undefined;
33
35
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
34
- onOpenDrawer?: (() => any) | undefined;
35
- onOpenOutdatedSettings?: (() => any) | undefined;
36
36
  }>, {
37
37
  showDrawerButton: boolean;
38
38
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -50,10 +50,7 @@ type __VLS_Slots = {} & {
50
50
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
51
51
  delete: () => any;
52
52
  cancel: () => any;
53
- rename: () => any;
54
- duplicate: () => any;
55
- export: () => any;
56
- saveTitle: () => any;
53
+ settings: () => any;
57
54
  send: (content: string, files: FileUploadInput[], model?: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6" | undefined, agentInputs?: ({
58
55
  type: "file";
59
56
  name: string;
@@ -66,26 +63,26 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
66
63
  content: string;
67
64
  })[] | undefined) => any;
68
65
  "update:model": (value: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6") => any;
69
- settings: () => any;
70
- "update:editTitle": (value: string) => any;
71
- cancelEditing: () => any;
66
+ rename: () => any;
67
+ duplicate: () => any;
68
+ export: () => any;
72
69
  copyLink: () => any;
73
70
  debug: () => any;
74
71
  tabChange: (tab: TopbarTab) => any;
75
72
  newConversation: () => any;
76
73
  switchWorkspace: () => any;
77
74
  signout: () => any;
75
+ cancelEditing: () => any;
78
76
  dismissOutdatedBanner: () => any;
77
+ saveTitle: () => any;
79
78
  selectConversation: (id: string) => any;
80
79
  "update:drawerOpen": (value: boolean) => any;
80
+ "update:editTitle": (value: string) => any;
81
81
  "update:workspaceSheetOpen": (value: boolean) => any;
82
82
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
83
83
  onDelete?: (() => any) | undefined;
84
84
  onCancel?: (() => any) | undefined;
85
- onRename?: (() => any) | undefined;
86
- onDuplicate?: (() => any) | undefined;
87
- onExport?: (() => any) | undefined;
88
- onSaveTitle?: (() => any) | undefined;
85
+ onSettings?: (() => any) | undefined;
89
86
  onSend?: ((content: string, files: FileUploadInput[], model?: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6" | undefined, agentInputs?: ({
90
87
  type: "file";
91
88
  name: string;
@@ -98,18 +95,21 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
98
95
  content: string;
99
96
  })[] | undefined) => any) | undefined;
100
97
  "onUpdate:model"?: ((value: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6") => any) | undefined;
101
- onSettings?: (() => any) | undefined;
102
- "onUpdate:editTitle"?: ((value: string) => any) | undefined;
103
- onCancelEditing?: (() => any) | undefined;
98
+ onRename?: (() => any) | undefined;
99
+ onDuplicate?: (() => any) | undefined;
100
+ onExport?: (() => any) | undefined;
104
101
  onCopyLink?: (() => any) | undefined;
105
102
  onDebug?: (() => any) | undefined;
106
103
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
107
104
  onNewConversation?: (() => any) | undefined;
108
105
  onSwitchWorkspace?: (() => any) | undefined;
109
106
  onSignout?: (() => any) | undefined;
107
+ onCancelEditing?: (() => any) | undefined;
110
108
  onDismissOutdatedBanner?: (() => any) | undefined;
109
+ onSaveTitle?: (() => any) | undefined;
111
110
  onSelectConversation?: ((id: string) => any) | undefined;
112
111
  "onUpdate:drawerOpen"?: ((value: boolean) => any) | undefined;
112
+ "onUpdate:editTitle"?: ((value: string) => any) | undefined;
113
113
  "onUpdate:workspaceSheetOpen"?: ((value: boolean) => any) | undefined;
114
114
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
115
115
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -50,10 +50,7 @@ type __VLS_Slots = {} & {
50
50
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
51
51
  delete: () => any;
52
52
  cancel: () => any;
53
- rename: () => any;
54
- duplicate: () => any;
55
- export: () => any;
56
- saveTitle: () => any;
53
+ settings: () => any;
57
54
  send: (content: string, files: FileUploadInput[], model?: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6" | undefined, agentInputs?: ({
58
55
  type: "file";
59
56
  name: string;
@@ -66,26 +63,26 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
66
63
  content: string;
67
64
  })[] | undefined) => any;
68
65
  "update:model": (value: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6") => any;
69
- settings: () => any;
70
- "update:editTitle": (value: string) => any;
71
- cancelEditing: () => any;
66
+ rename: () => any;
67
+ duplicate: () => any;
68
+ export: () => any;
72
69
  copyLink: () => any;
73
70
  debug: () => any;
74
71
  tabChange: (tab: TopbarTab) => any;
75
72
  newConversation: () => any;
76
73
  switchWorkspace: () => any;
77
74
  signout: () => any;
75
+ cancelEditing: () => any;
78
76
  dismissOutdatedBanner: () => any;
77
+ saveTitle: () => any;
79
78
  selectConversation: (id: string) => any;
80
79
  "update:drawerOpen": (value: boolean) => any;
80
+ "update:editTitle": (value: string) => any;
81
81
  "update:workspaceSheetOpen": (value: boolean) => any;
82
82
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
83
83
  onDelete?: (() => any) | undefined;
84
84
  onCancel?: (() => any) | undefined;
85
- onRename?: (() => any) | undefined;
86
- onDuplicate?: (() => any) | undefined;
87
- onExport?: (() => any) | undefined;
88
- onSaveTitle?: (() => any) | undefined;
85
+ onSettings?: (() => any) | undefined;
89
86
  onSend?: ((content: string, files: FileUploadInput[], model?: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6" | undefined, agentInputs?: ({
90
87
  type: "file";
91
88
  name: string;
@@ -98,18 +95,21 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
98
95
  content: string;
99
96
  })[] | undefined) => any) | undefined;
100
97
  "onUpdate:model"?: ((value: "claude-sonnet-4-5" | "claude-sonnet-4-6" | "claude-haiku-4-5" | "claude-opus-4-5" | "claude-opus-4-6") => any) | undefined;
101
- onSettings?: (() => any) | undefined;
102
- "onUpdate:editTitle"?: ((value: string) => any) | undefined;
103
- onCancelEditing?: (() => any) | undefined;
98
+ onRename?: (() => any) | undefined;
99
+ onDuplicate?: (() => any) | undefined;
100
+ onExport?: (() => any) | undefined;
104
101
  onCopyLink?: (() => any) | undefined;
105
102
  onDebug?: (() => any) | undefined;
106
103
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
107
104
  onNewConversation?: (() => any) | undefined;
108
105
  onSwitchWorkspace?: (() => any) | undefined;
109
106
  onSignout?: (() => any) | undefined;
107
+ onCancelEditing?: (() => any) | undefined;
110
108
  onDismissOutdatedBanner?: (() => any) | undefined;
109
+ onSaveTitle?: (() => any) | undefined;
111
110
  onSelectConversation?: ((id: string) => any) | undefined;
112
111
  "onUpdate:drawerOpen"?: ((value: boolean) => any) | undefined;
112
+ "onUpdate:editTitle"?: ((value: string) => any) | undefined;
113
113
  "onUpdate:workspaceSheetOpen"?: ((value: boolean) => any) | undefined;
114
114
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
115
115
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -19,25 +19,25 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
19
19
  rename: () => any;
20
20
  duplicate: () => any;
21
21
  export: () => any;
22
- saveTitle: () => any;
23
- "update:isEditing": (value: boolean) => any;
24
- "update:editTitle": (value: string) => any;
25
- cancelEditing: () => any;
26
22
  copyLink: () => any;
27
23
  debug: () => any;
28
24
  tabChange: (tab: TopbarTab) => any;
25
+ cancelEditing: () => any;
26
+ saveTitle: () => any;
27
+ "update:editTitle": (value: string) => any;
28
+ "update:isEditing": (value: boolean) => any;
29
29
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
30
30
  onDelete?: (() => any) | undefined;
31
31
  onRename?: (() => any) | undefined;
32
32
  onDuplicate?: (() => any) | undefined;
33
33
  onExport?: (() => any) | undefined;
34
- onSaveTitle?: (() => any) | undefined;
35
- "onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
36
- "onUpdate:editTitle"?: ((value: string) => any) | undefined;
37
- onCancelEditing?: (() => any) | undefined;
38
34
  onCopyLink?: (() => any) | undefined;
39
35
  onDebug?: (() => any) | undefined;
40
36
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
37
+ onCancelEditing?: (() => any) | undefined;
38
+ onSaveTitle?: (() => any) | undefined;
39
+ "onUpdate:editTitle"?: ((value: string) => any) | undefined;
40
+ "onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
41
41
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
42
42
  declare const _default: typeof __VLS_export;
43
43
  export default _default;
@@ -19,6 +19,7 @@ const props = defineProps({
19
19
  const emit = defineEmits(["update:isEditing", "update:editTitle", "saveTitle", "cancelEditing", "rename", "duplicate", "export", "copyLink", "debug", "delete", "tabChange"]);
20
20
  const titleInputRef = ref(null);
21
21
  const currentTab = computed(() => props.activeTab ?? "chat");
22
+ const titleInputWidth = computed(() => `${Math.max(props.editTitle.length + 2, 8)}ch`);
22
23
  const headerMenuItems = computed(() => {
23
24
  const items = [
24
25
  {
@@ -87,19 +88,36 @@ watch(() => props.isEditing, (editing) => {
87
88
  :style="{ left: 'var(--chat-panel-offset)' }"
88
89
  >
89
90
  <div flex="~ col 1" gap-4px min-w-0>
90
- <input
91
+ <div
91
92
  v-if="isEditing"
92
- ref="titleInputRef"
93
- :value="editTitle"
94
- type="text"
95
- heading-h4-semibold text-primary
96
- bg-white border border-gray-200 rounded-6px px-8px py-2px
97
- outline-none focus:border-gray-400
98
- @input="emit('update:editTitle', $event.target.value)"
99
- @keydown="handleTitleKeydown"
100
- @blur="emit('saveTitle')"
93
+ flex items-center
94
+ text-primary
95
+ w-fit max-w-full
96
+ pb-1px
97
+ b-b=".5px solid #A3A3A3"
98
+ :style="{ width: titleInputWidth }"
99
+ >
100
+ <input
101
+ ref="titleInputRef"
102
+ :value="editTitle"
103
+ type="text"
104
+ autocomplete="off"
105
+ aria-label="Nome da conversa"
106
+ w-full min-w-0 max-w-full
107
+ bg-transparent border-none outline-none
108
+ text-16px font-580 text-primary leading-20px tracking="-.2px"
109
+ p-0
110
+ @input="emit('update:editTitle', $event.target.value)"
111
+ @keydown="handleTitleKeydown"
112
+ @blur="emit('saveTitle')"
113
+ >
114
+ </div>
115
+ <p
116
+ v-else
117
+ text-16px font-580 text-primary leading-20px tracking="-.2px"
118
+ truncate cursor-text
119
+ @dblclick.prevent.stop="emit('rename')"
101
120
  >
102
- <p v-else text-16px font-580 text-primary leading-20px tracking="-.2px" truncate>
103
121
  {{ capitalizeFirst(title) }}<span v-if="generatingTitle" class="typing-cursor">|</span>
104
122
  </p>
105
123
 
@@ -19,25 +19,25 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
19
19
  rename: () => any;
20
20
  duplicate: () => any;
21
21
  export: () => any;
22
- saveTitle: () => any;
23
- "update:isEditing": (value: boolean) => any;
24
- "update:editTitle": (value: string) => any;
25
- cancelEditing: () => any;
26
22
  copyLink: () => any;
27
23
  debug: () => any;
28
24
  tabChange: (tab: TopbarTab) => any;
25
+ cancelEditing: () => any;
26
+ saveTitle: () => any;
27
+ "update:editTitle": (value: string) => any;
28
+ "update:isEditing": (value: boolean) => any;
29
29
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
30
30
  onDelete?: (() => any) | undefined;
31
31
  onRename?: (() => any) | undefined;
32
32
  onDuplicate?: (() => any) | undefined;
33
33
  onExport?: (() => any) | undefined;
34
- onSaveTitle?: (() => any) | undefined;
35
- "onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
36
- "onUpdate:editTitle"?: ((value: string) => any) | undefined;
37
- onCancelEditing?: (() => any) | undefined;
38
34
  onCopyLink?: (() => any) | undefined;
39
35
  onDebug?: (() => any) | undefined;
40
36
  onTabChange?: ((tab: TopbarTab) => any) | undefined;
37
+ onCancelEditing?: (() => any) | undefined;
38
+ onSaveTitle?: (() => any) | undefined;
39
+ "onUpdate:editTitle"?: ((value: string) => any) | undefined;
40
+ "onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
41
41
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
42
42
  declare const _default: typeof __VLS_export;
43
43
  export default _default;
@@ -14,5 +14,7 @@ export declare function useConversations(): {
14
14
  deleteConversation: (id: string) => Promise<boolean>;
15
15
  renameConversation: (id: string, title: string) => Promise<boolean>;
16
16
  duplicateConversation: (id: string) => Promise<ConversationWithMessages | null>;
17
+ conversationCreatorFilter: any;
18
+ conversationCreatorFilterCounts: any;
17
19
  updateConversationInList: (updated: Conversation | DeepReadonly<Conversation>) => void;
18
20
  };
@@ -24,10 +24,19 @@ export function mergeFetchedConversations(fetchedConversations, localConversatio
24
24
  }
25
25
  return sortConversationsByUpdatedAt([...mergedById.values()]);
26
26
  }
27
+ function bucketValue(bucket, key, fallback) {
28
+ return bucket.value[key] ?? fallback;
29
+ }
30
+ function setBucketValue(bucket, key, value) {
31
+ bucket.value = {
32
+ ...bucket.value,
33
+ [key]: value
34
+ };
35
+ }
27
36
  export function useConversations() {
28
37
  const chatApi = useChatApi();
29
38
  const embedConfig = useEmbedConfig();
30
- const { activeOrganization } = useChatAuth();
39
+ const { user: authUser, activeOrganization } = useChatAuth();
31
40
  const conversationBuckets = useState("conversations", () => ({}));
32
41
  const loadingBuckets = useState("conversations-loading", () => ({}));
33
42
  const errorBuckets = useState("conversations-error", () => ({}));
@@ -35,12 +44,27 @@ export function useConversations() {
35
44
  const mutationVersionBuckets = useState("conversations-mutation-version", () => ({}));
36
45
  const deletedIdBuckets = useState("conversations-deleted-ids", () => ({}));
37
46
  const mutatedIdBuckets = useState("conversations-mutated-ids", () => ({}));
47
+ const conversationCreatorFilter = useState(
48
+ "conversation-creator-filter",
49
+ () => embedConfig?.defaultConversationCreatorFilter?.value ?? "all"
50
+ );
38
51
  const isTelaAgentMode = computed(() => !!embedConfig?.telaAgentId.value);
39
- const workspaceScope = computed(() => resolveChatStateScope(
52
+ const runtimeScope = computed(() => resolveChatStateScope(
40
53
  embedConfig?.workspaceId.value || activeOrganization.value?.id,
41
54
  embedConfig?.telaAgentId.value,
42
55
  embedConfig?.conversationScope?.value
43
56
  ));
57
+ const workspaceScope = computed(() => `${runtimeScope.value}:creator:${conversationCreatorFilter.value}`);
58
+ const conversationBucketKey = (filter) => `${runtimeScope.value}:creator:${filter}`;
59
+ const conversationCreatorFilterCounts = computed(() => {
60
+ const allConversations = conversationBuckets.value[conversationBucketKey("all")] ?? [];
61
+ const mineConversations = conversationBuckets.value[conversationBucketKey("mine")];
62
+ const authUserId = authUser.value?.id;
63
+ return {
64
+ all: allConversations.length,
65
+ mine: mineConversations?.length ?? (authUserId ? allConversations.filter((conversation) => conversation.userId === authUserId).length : 0)
66
+ };
67
+ });
44
68
  const conversations = computed({
45
69
  get: () => conversationBuckets.value[workspaceScope.value] ?? [],
46
70
  set: (value) => {
@@ -95,15 +119,6 @@ export function useConversations() {
95
119
  };
96
120
  }
97
121
  });
98
- const hasFetched = computed({
99
- get: () => fetchedBuckets.value[workspaceScope.value] ?? false,
100
- set: (value) => {
101
- fetchedBuckets.value = {
102
- ...fetchedBuckets.value,
103
- [workspaceScope.value]: value
104
- };
105
- }
106
- });
107
122
  function markMutated(id) {
108
123
  mutationVersion.value = mutationVersion.value + 1;
109
124
  if (id) {
@@ -114,6 +129,33 @@ export function useConversations() {
114
129
  conversations.value = sortConversationsByUpdatedAt(nextConversations);
115
130
  markMutated(mutatedId);
116
131
  }
132
+ function commitConversationsToScope(scope, nextConversations, mutatedId) {
133
+ setBucketValue(conversationBuckets, scope, sortConversationsByUpdatedAt(nextConversations));
134
+ setBucketValue(mutationVersionBuckets, scope, bucketValue(mutationVersionBuckets, scope, 0) + 1);
135
+ if (mutatedId) {
136
+ setBucketValue(mutatedIdBuckets, scope, [
137
+ .../* @__PURE__ */ new Set([...bucketValue(mutatedIdBuckets, scope, []), mutatedId])
138
+ ]);
139
+ }
140
+ }
141
+ function upsertCreatedConversation(conversation) {
142
+ const allScope = conversationBucketKey("all");
143
+ const allConversations = bucketValue(conversationBuckets, allScope, []);
144
+ commitConversationsToScope(
145
+ allScope,
146
+ [conversation, ...allConversations.filter((item) => item.id !== conversation.id)],
147
+ conversation.id
148
+ );
149
+ if (authUser.value?.id === conversation.userId || conversationCreatorFilter.value === "mine") {
150
+ const mineScope = conversationBucketKey("mine");
151
+ const mineConversations = bucketValue(conversationBuckets, mineScope, []);
152
+ commitConversationsToScope(
153
+ mineScope,
154
+ [conversation, ...mineConversations.filter((item) => item.id !== conversation.id)],
155
+ conversation.id
156
+ );
157
+ }
158
+ }
117
159
  function addDeletedConversationId(id) {
118
160
  deletedConversationIds.value = [.../* @__PURE__ */ new Set([...deletedConversationIds.value, id])];
119
161
  markMutated();
@@ -122,48 +164,49 @@ export function useConversations() {
122
164
  deletedConversationIds.value = deletedConversationIds.value.filter((deletedId) => deletedId !== id);
123
165
  markMutated();
124
166
  }
125
- function pruneDeletedConversationIds(serverConversations) {
126
- const returnedIds = new Set(serverConversations.map((conversation) => conversation.id));
127
- deletedConversationIds.value = deletedConversationIds.value.filter((id) => returnedIds.has(id));
128
- }
129
167
  function cloneAppliedSettingsSnapshot(snapshot) {
130
168
  if (!snapshot)
131
169
  return null;
132
170
  return JSON.parse(JSON.stringify(snapshot));
133
171
  }
134
172
  const fetchConversations = async (options = {}) => {
135
- if (loading.value || hasFetched.value && !options.force) {
173
+ const requestScope = workspaceScope.value;
174
+ const requestCreatorFilter = conversationCreatorFilter.value;
175
+ if (bucketValue(loadingBuckets, requestScope, false) || bucketValue(fetchedBuckets, requestScope, false) && !options.force) {
136
176
  return;
137
177
  }
138
- loading.value = true;
139
- error.value = null;
140
- const mutationVersionAtStart = mutationVersion.value;
178
+ setBucketValue(loadingBuckets, requestScope, true);
179
+ setBucketValue(errorBuckets, requestScope, null);
180
+ const mutationVersionAtStart = bucketValue(mutationVersionBuckets, requestScope, 0);
141
181
  try {
142
182
  const data = await $fetch(
143
183
  chatApi.path("/conversations"),
144
- chatApi.withChatHeaders()
184
+ chatApi.withChatHeaders(requestCreatorFilter === "mine" ? { query: { creator: "me" } } : void 0)
145
185
  );
146
- const visibleData = data.filter((conversation) => !deletedConversationIds.value.includes(conversation.id));
147
- if (mutationVersion.value === mutationVersionAtStart) {
148
- conversations.value = sortConversationsByUpdatedAt(visibleData);
149
- mutatedConversationIds.value = [];
186
+ const currentDeletedIds = bucketValue(deletedIdBuckets, requestScope, []);
187
+ const currentMutatedIds = bucketValue(mutatedIdBuckets, requestScope, []);
188
+ const visibleData = data.filter((conversation) => !currentDeletedIds.includes(conversation.id));
189
+ if (bucketValue(mutationVersionBuckets, requestScope, 0) === mutationVersionAtStart) {
190
+ setBucketValue(conversationBuckets, requestScope, sortConversationsByUpdatedAt(visibleData));
191
+ setBucketValue(mutatedIdBuckets, requestScope, []);
150
192
  } else {
151
- conversations.value = mergeFetchedConversations(
193
+ setBucketValue(conversationBuckets, requestScope, mergeFetchedConversations(
152
194
  visibleData,
153
- conversations.value,
154
- deletedConversationIds.value,
155
- mutatedConversationIds.value
156
- );
157
- mutatedConversationIds.value = [];
195
+ bucketValue(conversationBuckets, requestScope, []),
196
+ currentDeletedIds,
197
+ currentMutatedIds
198
+ ));
199
+ setBucketValue(mutatedIdBuckets, requestScope, []);
158
200
  }
159
- pruneDeletedConversationIds(data);
160
- hasFetched.value = true;
201
+ const returnedIds = new Set(data.map((conversation) => conversation.id));
202
+ setBucketValue(deletedIdBuckets, requestScope, currentDeletedIds.filter((id) => returnedIds.has(id)));
203
+ setBucketValue(fetchedBuckets, requestScope, true);
161
204
  } catch (err) {
162
205
  const message = err instanceof Error ? err.message : "Erro ao carregar conversas";
163
- error.value = message;
206
+ setBucketValue(errorBuckets, requestScope, message);
164
207
  Sentry.captureException(err);
165
208
  } finally {
166
- loading.value = false;
209
+ setBucketValue(loadingBuckets, requestScope, false);
167
210
  }
168
211
  };
169
212
  const createConversation = async (options) => {
@@ -176,7 +219,7 @@ export function useConversations() {
176
219
  body: !isTelaAgentMode.value && options?.model ? { model: options.model } : void 0
177
220
  })
178
221
  );
179
- commitConversations([conversation, ...conversations.value], conversation.id);
222
+ upsertCreatedConversation(conversation);
180
223
  return conversation;
181
224
  } catch (err) {
182
225
  const message = err instanceof Error ? err.message : "Erro ao criar conversa";
@@ -272,7 +315,7 @@ export function useConversations() {
272
315
  method: "POST"
273
316
  })
274
317
  );
275
- commitConversations([duplicated, ...conversations.value], duplicated.id);
318
+ upsertCreatedConversation(duplicated);
276
319
  statusToast.update({
277
320
  text: "Conversa duplicada",
278
321
  icon: "i-ph-check"
@@ -297,6 +340,8 @@ export function useConversations() {
297
340
  deleteConversation,
298
341
  renameConversation,
299
342
  duplicateConversation,
343
+ conversationCreatorFilter,
344
+ conversationCreatorFilterCounts,
300
345
  updateConversationInList
301
346
  };
302
347
  }
@@ -1,4 +1,5 @@
1
1
  import type { Component, DeepReadonly, MaybeRefOrGetter, Ref } from 'vue';
2
+ import type { ConversationCreatorFilter } from '../types/chat.js';
2
3
  import type { TelaAgentExecutionInput } from '../types/tela-agent.js';
3
4
  import type { WorkspaceSettings } from '../types/workspace-settings-data.js';
4
5
  import type { ChatLoadingMessageMode } from '../utils/chat-loading-messages.js';
@@ -7,6 +8,7 @@ export type EmbedConfig = {
7
8
  workspaceId: Ref<string>;
8
9
  telaAgentId: Ref<string | null>;
9
10
  conversationScope: Ref<string | null>;
11
+ defaultConversationCreatorFilter: Ref<ConversationCreatorFilter>;
10
12
  telaAgentInputs: Ref<ConfiguredTelaAgentInputs>;
11
13
  workspaceSettings: Ref<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
12
14
  hideSidebar: Ref<boolean>;
@@ -20,6 +22,7 @@ type EmbedConfigInput = {
20
22
  workspaceId: MaybeRefOrGetter<string>;
21
23
  telaAgentId?: MaybeRefOrGetter<string | null | undefined>;
22
24
  conversationScope?: MaybeRefOrGetter<string | null | undefined>;
25
+ defaultConversationCreatorFilter?: MaybeRefOrGetter<ConversationCreatorFilter | null | undefined>;
23
26
  telaAgentInputs?: MaybeRefOrGetter<ConfiguredTelaAgentInputs>;
24
27
  workspaceSettings?: MaybeRefOrGetter<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
25
28
  hideSidebar?: MaybeRefOrGetter<boolean | undefined>;
@@ -11,6 +11,7 @@ function useGlobalEmbedConfigState() {
11
11
  workspaceId: useState("chat-embed-config-workspace-id", () => ""),
12
12
  telaAgentId: useState("chat-embed-config-tela-agent-id", () => null),
13
13
  conversationScope: useState("chat-embed-config-conversation-scope", () => null),
14
+ defaultConversationCreatorFilter: useState("chat-embed-config-default-conversation-creator-filter", () => void 0),
14
15
  telaAgentInputs: useState("chat-embed-config-tela-agent-inputs", () => void 0),
15
16
  workspaceSettings: useState("chat-embed-config-workspace-settings", () => void 0),
16
17
  hideSidebar: useState("chat-embed-config-hide-sidebar", () => void 0),
@@ -26,6 +27,7 @@ export function provideEmbedConfig(input, options = {}) {
26
27
  workspaceId: computed(() => toValue(input.workspaceId)),
27
28
  telaAgentId: computed(() => toValue(input.telaAgentId) ?? null),
28
29
  conversationScope: computed(() => normalizeConversationScope(toValue(input.conversationScope))),
30
+ defaultConversationCreatorFilter: computed(() => toValue(input.defaultConversationCreatorFilter) ?? "all"),
29
31
  telaAgentInputs: computed(() => toValue(input.telaAgentInputs)),
30
32
  workspaceSettings: computed(() => toValue(input.workspaceSettings)),
31
33
  hideSidebar: computed(() => toValue(input.hideSidebar) ?? true),
@@ -42,6 +44,7 @@ export function provideEmbedConfig(input, options = {}) {
42
44
  globalConfig.workspaceId.value = config.workspaceId.value;
43
45
  globalConfig.telaAgentId.value = config.telaAgentId.value;
44
46
  globalConfig.conversationScope.value = config.conversationScope.value;
47
+ globalConfig.defaultConversationCreatorFilter.value = config.defaultConversationCreatorFilter.value;
45
48
  globalConfig.telaAgentInputs.value = config.telaAgentInputs.value;
46
49
  globalConfig.workspaceSettings.value = config.workspaceSettings.value;
47
50
  globalConfig.hideSidebar.value = config.hideSidebar.value;
@@ -65,6 +68,7 @@ export function useEmbedConfig() {
65
68
  workspaceId: computed(() => globalConfig.workspaceId.value),
66
69
  telaAgentId: computed(() => globalConfig.telaAgentId.value),
67
70
  conversationScope: computed(() => globalConfig.conversationScope.value),
71
+ defaultConversationCreatorFilter: computed(() => globalConfig.defaultConversationCreatorFilter.value ?? "all"),
68
72
  telaAgentInputs: computed(() => globalConfig.telaAgentInputs.value),
69
73
  workspaceSettings: computed(() => globalConfig.workspaceSettings.value),
70
74
  hideSidebar: computed(() => globalConfig.hideSidebar.value ?? true),