feat: check if label suggestion is enabled in hooks (#13331)
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
import { ref, provide } from 'vue';
|
import { ref, provide } from 'vue';
|
||||||
// composable
|
// composable
|
||||||
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
|
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
|
||||||
import { useCaptain } from 'dashboard/composables/useCaptain';
|
import { useLabelSuggestions } from 'dashboard/composables/useLabelSuggestions';
|
||||||
import { useSnakeCase } from 'dashboard/composables/useTransformKeys';
|
import { useSnakeCase } from 'dashboard/composables/useTransformKeys';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
@@ -59,7 +59,11 @@ export default {
|
|||||||
|
|
||||||
useKeyboardEvents(keyboardEvents);
|
useKeyboardEvents(keyboardEvents);
|
||||||
|
|
||||||
const { captainTasksEnabled, getLabelSuggestions } = useCaptain();
|
const {
|
||||||
|
captainTasksEnabled,
|
||||||
|
isLabelSuggestionFeatureEnabled,
|
||||||
|
getLabelSuggestions,
|
||||||
|
} = useLabelSuggestions();
|
||||||
|
|
||||||
provide('contextMenuElementTarget', conversationPanelRef);
|
provide('contextMenuElementTarget', conversationPanelRef);
|
||||||
|
|
||||||
@@ -67,6 +71,7 @@ export default {
|
|||||||
isPopOutReplyBox,
|
isPopOutReplyBox,
|
||||||
captainTasksEnabled,
|
captainTasksEnabled,
|
||||||
getLabelSuggestions,
|
getLabelSuggestions,
|
||||||
|
isLabelSuggestionFeatureEnabled,
|
||||||
conversationPanelRef,
|
conversationPanelRef,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -94,7 +99,10 @@ export default {
|
|||||||
},
|
},
|
||||||
shouldShowLabelSuggestions() {
|
shouldShowLabelSuggestions() {
|
||||||
return (
|
return (
|
||||||
this.isOpen && this.captainTasksEnabled && !this.messageSentSinceOpened
|
this.isOpen &&
|
||||||
|
this.captainTasksEnabled &&
|
||||||
|
this.isLabelSuggestionFeatureEnabled &&
|
||||||
|
!this.messageSentSinceOpened
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
inboxId() {
|
inboxId() {
|
||||||
@@ -282,7 +290,7 @@ export default {
|
|||||||
const existingLabels = this.currentChat?.labels || [];
|
const existingLabels = this.currentChat?.labels || [];
|
||||||
if (existingLabels.length > 0) return;
|
if (existingLabels.length > 0) return;
|
||||||
|
|
||||||
if (!this.captainTasksEnabled) {
|
if (!this.captainTasksEnabled || !this.isLabelSuggestionFeatureEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,18 +76,6 @@ describe('useCaptain', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gets label suggestions', async () => {
|
|
||||||
TasksAPI.labelSuggestion.mockResolvedValue({
|
|
||||||
data: { message: 'label1, label2' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const { getLabelSuggestions } = useCaptain();
|
|
||||||
const result = await getLabelSuggestions();
|
|
||||||
|
|
||||||
expect(TasksAPI.labelSuggestion).toHaveBeenCalledWith('123');
|
|
||||||
expect(result).toEqual(['label1', 'label2']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('rewrites content', async () => {
|
it('rewrites content', async () => {
|
||||||
TasksAPI.rewrite.mockResolvedValue({
|
TasksAPI.rewrite.mockResolvedValue({
|
||||||
data: { message: 'Rewritten content', follow_up_context: { id: 'ctx1' } },
|
data: { message: 'Rewritten content', follow_up_context: { id: 'ctx1' } },
|
||||||
@@ -193,21 +181,4 @@ describe('useCaptain', () => {
|
|||||||
await processEvent('improve', 'content', {});
|
await processEvent('improve', 'content', {});
|
||||||
expect(TasksAPI.rewrite).toHaveBeenCalled();
|
expect(TasksAPI.rewrite).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns empty array when no conversation ID for label suggestions', async () => {
|
|
||||||
useMapGetter.mockImplementation(getter => {
|
|
||||||
const mockValues = {
|
|
||||||
'accounts/getUIFlags': { isFetchingLimits: false },
|
|
||||||
getSelectedChat: { id: null },
|
|
||||||
'draftMessages/getReplyEditorMode': 'reply',
|
|
||||||
};
|
|
||||||
return { value: mockValues[getter] };
|
|
||||||
});
|
|
||||||
|
|
||||||
const { getLabelSuggestions } = useCaptain();
|
|
||||||
const result = await getLabelSuggestions();
|
|
||||||
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
expect(TasksAPI.labelSuggestion).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,20 +13,6 @@ import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
|||||||
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||||
import TasksAPI from 'dashboard/api/captain/tasks';
|
import TasksAPI from 'dashboard/api/captain/tasks';
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleans and normalizes a list of labels.
|
|
||||||
* @param {string} labels - A comma-separated string of labels.
|
|
||||||
* @returns {string[]} An array of cleaned and unique labels.
|
|
||||||
*/
|
|
||||||
const cleanLabels = labels => {
|
|
||||||
return labels
|
|
||||||
.toLowerCase()
|
|
||||||
.split(',')
|
|
||||||
.filter(label => label.trim())
|
|
||||||
.map(label => label.trim())
|
|
||||||
.filter((label, index, self) => self.indexOf(label) === index);
|
|
||||||
};
|
|
||||||
|
|
||||||
export function useCaptain() {
|
export function useCaptain() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -183,24 +169,6 @@ export function useCaptain() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets label suggestions for the current conversation.
|
|
||||||
* @returns {Promise<string[]>} An array of suggested labels.
|
|
||||||
*/
|
|
||||||
const getLabelSuggestions = async () => {
|
|
||||||
if (!conversationId.value) return [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await TasksAPI.labelSuggestion(conversationId.value);
|
|
||||||
const {
|
|
||||||
data: { message: labels },
|
|
||||||
} = result;
|
|
||||||
return cleanLabels(labels);
|
|
||||||
} catch {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a follow-up message to refine a previous AI task result.
|
* Sends a follow-up message to refine a previous AI task result.
|
||||||
* @param {Object} options - The follow-up options.
|
* @param {Object} options - The follow-up options.
|
||||||
@@ -264,7 +232,6 @@ export function useCaptain() {
|
|||||||
rewriteContent,
|
rewriteContent,
|
||||||
summarizeConversation,
|
summarizeConversation,
|
||||||
getReplySuggestion,
|
getReplySuggestion,
|
||||||
getLabelSuggestions,
|
|
||||||
followUp,
|
followUp,
|
||||||
processEvent,
|
processEvent,
|
||||||
|
|
||||||
|
|||||||
80
app/javascript/dashboard/composables/useLabelSuggestions.js
Normal file
80
app/javascript/dashboard/composables/useLabelSuggestions.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { computed, onMounted } from 'vue';
|
||||||
|
import { useMapGetter, useStore } from 'dashboard/composables/store';
|
||||||
|
import { useAccount } from 'dashboard/composables/useAccount';
|
||||||
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
|
import TasksAPI from 'dashboard/api/captain/tasks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans and normalizes a list of labels.
|
||||||
|
* @param {string} labels - A comma-separated string of labels.
|
||||||
|
* @returns {string[]} An array of cleaned and unique labels.
|
||||||
|
*/
|
||||||
|
const cleanLabels = labels => {
|
||||||
|
return labels
|
||||||
|
.toLowerCase()
|
||||||
|
.split(',')
|
||||||
|
.filter(label => label.trim())
|
||||||
|
.map(label => label.trim())
|
||||||
|
.filter((label, index, self) => self.indexOf(label) === index);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useLabelSuggestions() {
|
||||||
|
const store = useStore();
|
||||||
|
const { isCloudFeatureEnabled } = useAccount();
|
||||||
|
const appIntegrations = useMapGetter('integrations/getAppIntegrations');
|
||||||
|
const currentChat = useMapGetter('getSelectedChat');
|
||||||
|
const conversationId = computed(() => currentChat.value?.id);
|
||||||
|
|
||||||
|
const captainTasksEnabled = computed(() => {
|
||||||
|
return isCloudFeatureEnabled(FEATURE_FLAGS.CAPTAIN_TASKS);
|
||||||
|
});
|
||||||
|
|
||||||
|
const aiIntegration = computed(
|
||||||
|
() =>
|
||||||
|
appIntegrations.value.find(
|
||||||
|
integration => integration.id === 'openai' && !!integration.hooks.length
|
||||||
|
)?.hooks[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
const isLabelSuggestionFeatureEnabled = computed(() => {
|
||||||
|
if (aiIntegration.value) {
|
||||||
|
const { settings = {} } = aiIntegration.value || {};
|
||||||
|
return !!settings.label_suggestion;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchIntegrationsIfRequired = async () => {
|
||||||
|
if (!appIntegrations.value.length) {
|
||||||
|
await store.dispatch('integrations/get');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets label suggestions for the current conversation.
|
||||||
|
* @returns {Promise<string[]>} An array of suggested labels.
|
||||||
|
*/
|
||||||
|
const getLabelSuggestions = async () => {
|
||||||
|
if (!conversationId.value) return [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await TasksAPI.labelSuggestion(conversationId.value);
|
||||||
|
const {
|
||||||
|
data: { message: labels },
|
||||||
|
} = result;
|
||||||
|
return cleanLabels(labels);
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchIntegrationsIfRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
captainTasksEnabled,
|
||||||
|
isLabelSuggestionFeatureEnabled,
|
||||||
|
getLabelSuggestions,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user