@iblai/iblai-js 1.12.3 → 1.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-layer/playwright/index.d.ts +4 -0
- package/dist/data-layer/playwright/screenshare-tab-helpers.d.ts +57 -0
- package/dist/data-layer/playwright/voice-tab-helpers.d.ts +194 -0
- package/dist/playwright/index.cjs +523 -2
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.d.ts +253 -2
- package/dist/playwright/index.esm.js +485 -3
- package/dist/playwright/index.esm.js.map +1 -1
- package/dist/playwright/playwright/index.d.ts +4 -0
- package/dist/playwright/playwright/screenshare-tab-helpers.d.ts +57 -0
- package/dist/playwright/playwright/voice-tab-helpers.d.ts +194 -0
- package/dist/web-containers/playwright/index.d.ts +4 -0
- package/dist/web-containers/playwright/screenshare-tab-helpers.d.ts +57 -0
- package/dist/web-containers/playwright/voice-tab-helpers.d.ts +194 -0
- package/dist/web-containers/source/next/index.esm.js +908 -21
- package/dist/web-utils/playwright/index.d.ts +4 -0
- package/dist/web-utils/playwright/screenshare-tab-helpers.d.ts +57 -0
- package/dist/web-utils/playwright/voice-tab-helpers.d.ts +194 -0
- package/package.json +5 -5
|
@@ -7,7 +7,7 @@ import Link$2 from 'next/link';
|
|
|
7
7
|
import * as ReactDOM from 'react-dom';
|
|
8
8
|
import ReactDOM__default from 'react-dom';
|
|
9
9
|
import { z as z$3 } from 'zod';
|
|
10
|
-
import { useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useUpdateUserMetadataMutation, useUpdateUserMetadataEdxMutation, useUploadProfileImageMutation, useResetPasswordMutation, useSelfRetireMutation, useCreateUserInstitutionMutation, useGetUserInstitutionsQuery, useCreateUserEducationMutation, useUpdateUserEducationMutation, useDeleteUserEducationMutation, useGetUserEducationQuery, useCreateUserCompanyMutation, useGetUserCompaniesQuery, useCreateUserExperienceMutation, useUpdateUserExperienceMutation, useDeleteUserExperienceMutation, useGetUserExperienceQuery, useGetUserResumeQuery, useCreateUserResumeMutation, useGetMySubscriptionsQuery, useGetItemSubscriptionQuery, useCancelSubscriptionMutation, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useUpdateUserRoleMutation, useUpdateUserStatusMutation, useUpdatePlatformUserRoleWithPoliciesMutation, usePlatformUsersQuery, isPoliciesResponse, platformApiSlice, featureTags, useLazyGetRbacTeamsAccessListQuery, useCreateRbacTeamsAccessMutation, useGetRbacGroupsQuery, usePlatformUserGroupsQuery, useCreateRbacGroupMutation, useUpdateRbacGroupMutation, useDeleteRbacGroupMutation, useCreatePlatformUserGroupMutation, useUpdatePlatformUserGroupMutation, useDeletePlatformUserGroupMutation, useGetRbacGroupDetailsQuery, useGetPlatformUserGroupDetailsQuery, useGetRbacPermissionsMutation, useGetRbacRolesQuery, useCreateRbacRoleMutation, useUpdateRbacRoleMutation, useDeleteRbacRoleMutation, useGetRbacRoleDetailsQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, useUpdateTenantMetadataMutation, LOGO_ENDPOINTS, useDeleteApiKeyMutation, useGetApiKeysQuery, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetCustomMentorsQuery, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useGetUserProjectsQuery, useGetMentorsQuery, useGetPublicMentorsQuery, useCreateUserProjectMutation, useUpdateUserProjectMutation, useDeleteUserProjectMutation, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetMentorSettingsQuery, useEditMentorMutation, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetMentorPublicSettingsQuery, useGetChatHistoryFilterQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useEditTrainingDocumentMutation, useGetTrainingDocumentsQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStarMentorMutation, useUnstarMentorMutation, useGetPersonnalizedMentorsQuery, useGetVectorDocumentsQuery, useLazyGetConnectedServiceAuthUrlQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetUserProjectDetailsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useDeletePromptMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
|
|
10
|
+
import { useGetUserMetadataQuery, useGetUserMetadataEdxQuery, useUpdateUserMetadataMutation, useUpdateUserMetadataEdxMutation, useUploadProfileImageMutation, useResetPasswordMutation, useSelfRetireMutation, useCreateUserInstitutionMutation, useGetUserInstitutionsQuery, useCreateUserEducationMutation, useUpdateUserEducationMutation, useDeleteUserEducationMutation, useGetUserEducationQuery, useCreateUserCompanyMutation, useGetUserCompaniesQuery, useCreateUserExperienceMutation, useUpdateUserExperienceMutation, useDeleteUserExperienceMutation, useGetUserExperienceQuery, useGetUserResumeQuery, useCreateUserResumeMutation, useGetMySubscriptionsQuery, useGetItemSubscriptionQuery, useCancelSubscriptionMutation, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useUpdateUserRoleMutation, useUpdateUserStatusMutation, useUpdatePlatformUserRoleWithPoliciesMutation, usePlatformUsersQuery, isPoliciesResponse, platformApiSlice, featureTags, useLazyGetRbacTeamsAccessListQuery, useCreateRbacTeamsAccessMutation, useGetRbacGroupsQuery, usePlatformUserGroupsQuery, useCreateRbacGroupMutation, useUpdateRbacGroupMutation, useDeleteRbacGroupMutation, useCreatePlatformUserGroupMutation, useUpdatePlatformUserGroupMutation, useDeletePlatformUserGroupMutation, useGetRbacGroupDetailsQuery, useGetPlatformUserGroupDetailsQuery, useGetRbacPermissionsMutation, useGetRbacRolesQuery, useCreateRbacRoleMutation, useUpdateRbacRoleMutation, useDeleteRbacRoleMutation, useGetRbacRoleDetailsQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, useUpdateTenantMetadataMutation, LOGO_ENDPOINTS, useDeleteApiKeyMutation, useGetApiKeysQuery, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetCustomMentorsQuery, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useGetUserProjectsQuery, useGetMentorsQuery, useGetPublicMentorsQuery, useCreateUserProjectMutation, useUpdateUserProjectMutation, useDeleteUserProjectMutation, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetMentorSettingsQuery, useEditMentorMutation, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetVoicesQuery, useGetVoiceQuery, useGetCallConfigurationsQuery, useCreateCallConfigurationMutation, useUpdateCallConfigurationMutation, useGetMentorPublicSettingsQuery, useGetChatHistoryFilterQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useEditTrainingDocumentMutation, useGetTrainingDocumentsQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStarMentorMutation, useUnstarMentorMutation, useGetPersonnalizedMentorsQuery, useGetVectorDocumentsQuery, useLazyGetConnectedServiceAuthUrlQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetUserProjectDetailsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useDeletePromptMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
|
|
11
11
|
import { toast, Toaster as Toaster$1 } from 'sonner';
|
|
12
12
|
import { getInitials, useTenantMetadata, isAlphaNumeric32, checkRbacPermission, WithPermissions, useTenantContext, useStripeUpgrade, CHAT_AREA_SIZE, useUsername, chatActions, TimeTracker, advancedTabsProperties, defaultSessionIds, WithFormPermissions, selectNumberOfActiveChatMessages, selectStreaming, isLoggedIn, TOOLS, isSafariBrowser, useShowAttachment, useShowVoiceCall, useShowVoiceRecorder, useMentorSettings, selectShowingSharedChat, selectRbacPermissions, useShowFreeTrialDialog, useEmbedMode, chatInputSliceSelectors, useResponsive, useAccessingPublicRoute, useVisitingTenant, useModelFileUploadCapabilities, useChatFileUpload, useVoiceChat, selectAttachedFiles, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, removeFile, chatInputSliceActions, ANONYMOUS_USERNAME as ANONYMOUS_USERNAME$2, redirectToAuthSpaJoinTenant, selectActiveTab, useAxdToken, useWelcomeMessage, markdownToPlainText, useCachedSessionId, use402ErrorCheck, selectTokenEnabled, selectToken, useServiceWorker, useUserAgreement, useAdvancedChat, sendMessageToParentWebsite, useMentorTools, useFileDragDrop, eventBus, RemoteEvents, selectEnableChatActionsPopup, advancedTabs, isInIframe, getAuthSpaJoinUrl, addMessage, clearFiles, MENTOR_VISIBILITY } from '@iblai/web-utils';
|
|
13
13
|
import { MentorVisibilityEnum, TransportEnum, PromptVisibilityEnum } from '@iblai/iblai-api';
|
|
@@ -197747,7 +197747,7 @@ function PoliciesTab({ tenant }) {
|
|
|
197747
197747
|
}), className: "w-full text-left px-3 py-2 hover:bg-gray-100 dark:hover:bg-gray-700", children: jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: group.name }) }, group.id))) }))] })] })] })] }), jsxs(DialogFooter, { className: "mt-6", children: [jsx(Button$1, { variant: "outline", onClick: () => setIsOpen(false), children: "Cancel" }), jsx(TooltipProvider, { children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("span", { tabIndex: 0, children: jsx(Button$1, { onClick: onSubmit, disabled: policyDetails === null || policyDetails === void 0 ? void 0 : policyDetails.is_internal, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] hover:opacity-90 text-white", children: editing ? 'Save Policy' : 'Create Policy' }) }) }), editing && (policyDetails === null || policyDetails === void 0 ? void 0 : policyDetails.is_internal) && (jsx(TooltipContent, { children: jsx("p", { children: "Cannot edit internal policies" }) }))] }) })] })] }) })] }));
|
|
197748
197748
|
}
|
|
197749
197749
|
|
|
197750
|
-
const PAGE_SIZE$
|
|
197750
|
+
const PAGE_SIZE$3 = 10;
|
|
197751
197751
|
function normalizeEvents(events) {
|
|
197752
197752
|
if (!events)
|
|
197753
197753
|
return [];
|
|
@@ -197795,8 +197795,8 @@ function AlertsTab({ tenant }) {
|
|
|
197795
197795
|
const { data: watchedGroupsData, isLoading, isError, refetch, } = useGetWatchedGroupsQuery({
|
|
197796
197796
|
params: {
|
|
197797
197797
|
platform_key: tenant,
|
|
197798
|
-
limit: PAGE_SIZE$
|
|
197799
|
-
offset: (page - 1) * PAGE_SIZE$
|
|
197798
|
+
limit: PAGE_SIZE$3,
|
|
197799
|
+
offset: (page - 1) * PAGE_SIZE$3,
|
|
197800
197800
|
},
|
|
197801
197801
|
});
|
|
197802
197802
|
const groups = useMemo(() => {
|
|
@@ -197809,7 +197809,7 @@ function AlertsTab({ tenant }) {
|
|
|
197809
197809
|
return results;
|
|
197810
197810
|
}, [watchedGroupsData, debouncedSearchQuery]);
|
|
197811
197811
|
const totalPages = watchedGroupsData
|
|
197812
|
-
? Math.max(1, Math.ceil(watchedGroupsData.count / PAGE_SIZE$
|
|
197812
|
+
? Math.max(1, Math.ceil(watchedGroupsData.count / PAGE_SIZE$3))
|
|
197813
197813
|
: 0;
|
|
197814
197814
|
const handlePageChange = async (newPage) => {
|
|
197815
197815
|
setPage(newPage);
|
|
@@ -201249,7 +201249,7 @@ function PaywalledItemsList({ platformKey, onSelectItem, onAddCustomItem, }) {
|
|
|
201249
201249
|
: 'No items configured yet. Search and select an item above.' }))] })] }));
|
|
201250
201250
|
}
|
|
201251
201251
|
|
|
201252
|
-
const EMPTY_FORM = {
|
|
201252
|
+
const EMPTY_FORM$1 = {
|
|
201253
201253
|
name: '',
|
|
201254
201254
|
amount: '',
|
|
201255
201255
|
currency: 'usd',
|
|
@@ -201299,7 +201299,7 @@ function PriceManagement({ platformKey, itemType, itemId }) {
|
|
|
201299
201299
|
const [deletePrice] = useDeletePriceMutation();
|
|
201300
201300
|
const [showCreateForm, setShowCreateForm] = useState(false);
|
|
201301
201301
|
const [editingPriceId, setEditingPriceId] = useState(null);
|
|
201302
|
-
const [formData, setFormData] = useState(EMPTY_FORM);
|
|
201302
|
+
const [formData, setFormData] = useState(EMPTY_FORM$1);
|
|
201303
201303
|
const [deletingId, setDeletingId] = useState(null);
|
|
201304
201304
|
const handleCreate = async () => {
|
|
201305
201305
|
try {
|
|
@@ -201318,7 +201318,7 @@ function PriceManagement({ platformKey, itemType, itemId }) {
|
|
|
201318
201318
|
}).unwrap();
|
|
201319
201319
|
toast.success('Price created');
|
|
201320
201320
|
setShowCreateForm(false);
|
|
201321
|
-
setFormData(EMPTY_FORM);
|
|
201321
|
+
setFormData(EMPTY_FORM$1);
|
|
201322
201322
|
refetch();
|
|
201323
201323
|
}
|
|
201324
201324
|
catch (_a) {
|
|
@@ -201360,7 +201360,7 @@ function PriceManagement({ platformKey, itemType, itemId }) {
|
|
|
201360
201360
|
}).unwrap();
|
|
201361
201361
|
toast.success('Price updated');
|
|
201362
201362
|
setEditingPriceId(null);
|
|
201363
|
-
setFormData(EMPTY_FORM);
|
|
201363
|
+
setFormData(EMPTY_FORM$1);
|
|
201364
201364
|
refetch();
|
|
201365
201365
|
}
|
|
201366
201366
|
catch (_a) {
|
|
@@ -201388,16 +201388,16 @@ function PriceManagement({ platformKey, itemType, itemId }) {
|
|
|
201388
201388
|
};
|
|
201389
201389
|
return (jsxs("div", { className: "space-y-3", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("h4", { className: "text-sm font-medium text-gray-700 dark:text-gray-300", children: "Pricing Tiers" }), !showCreateForm && !editingPriceId && (jsxs(Button$1, { onClick: () => {
|
|
201390
201390
|
setShowCreateForm(true);
|
|
201391
|
-
setFormData(EMPTY_FORM);
|
|
201391
|
+
setFormData(EMPTY_FORM$1);
|
|
201392
201392
|
setEditingPriceId(null);
|
|
201393
201393
|
}, variant: "outline", size: "sm", className: "cursor-pointer", children: [jsx(Plus, { className: "h-3 w-3 mr-1" }), "Add Price"] }))] }), showCreateForm && (jsx(PriceForm, { form: formData, onChange: setFormData, onSave: handleCreate, onCancel: () => {
|
|
201394
201394
|
setShowCreateForm(false);
|
|
201395
|
-
setFormData(EMPTY_FORM);
|
|
201395
|
+
setFormData(EMPTY_FORM$1);
|
|
201396
201396
|
}, isSaving: isCreating, isEdit: false })), isLoading ? (jsx("div", { className: "space-y-2", children: [1, 2].map((i) => (jsx(Skeleton, { className: "h-20 w-full" }, i))) })) : prices && prices.length > 0 ? (jsx("div", { className: "space-y-2", children: prices.map((price) => {
|
|
201397
201397
|
var _a;
|
|
201398
201398
|
return editingPriceId === price.id ? (jsx(PriceForm, { form: formData, onChange: setFormData, onSave: handleUpdate, onCancel: () => {
|
|
201399
201399
|
setEditingPriceId(null);
|
|
201400
|
-
setFormData(EMPTY_FORM);
|
|
201400
|
+
setFormData(EMPTY_FORM$1);
|
|
201401
201401
|
}, isSaving: isUpdating, isEdit: true }, price.id)) : (jsx(Card, { className: "shadow-sm border", style: { borderColor: 'oklch(.922 0 0)' }, children: jsx(CardContent, { className: "p-4", children: jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(Tag, { className: "h-4 w-4 text-gray-400" }), jsxs("div", { children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: price.name }), jsxs("span", { className: "text-sm font-semibold text-blue-600", children: ["$", price.amount, " ", formatInterval(price.interval)] }), !price.is_active && (jsx(Badge, { variant: "secondary", className: "text-xs", children: "Inactive" }))] }), price.description && (jsx("p", { className: "text-xs text-gray-400 mt-0.5", children: price.description })), ((_a = price.features) === null || _a === void 0 ? void 0 : _a.length) > 0 && (jsx("div", { className: "flex flex-wrap gap-1 mt-1", children: price.features.map((f, i) => (jsx(Badge, { variant: "outline", className: "text-xs font-normal", children: f }, i))) }))] })] }), jsxs("div", { className: "flex gap-1 flex-shrink-0", children: [jsx(Button$1, { onClick: () => handleStartEdit(price), variant: "ghost", size: "sm", className: "h-8 w-8 p-0 cursor-pointer", children: jsx(Pencil, { className: "h-3 w-3" }) }), jsx(Button$1, { onClick: () => handleDelete(price.id), variant: "ghost", size: "sm", disabled: deletingId === price.id, className: "h-8 w-8 p-0 text-red-500 hover:text-red-700 cursor-pointer", children: deletingId === price.id ? (jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" })) : (jsx(Trash2, { className: "h-3 w-3" })) })] })] }) }) }, price.id));
|
|
201402
201402
|
}) })) : (jsx("p", { className: "text-xs text-gray-400 text-center py-4", children: "No pricing tiers yet. Add one to start accepting payments." }))] }));
|
|
201403
201403
|
}
|
|
@@ -206776,7 +206776,7 @@ const BulkDeleteMemoryModal$1 = dynamic(() => Promise.resolve().then(function ()
|
|
|
206776
206776
|
const ManageCategoriesModal$1 = dynamic(() => Promise.resolve().then(function () { return manageCategoriesModal; }).then((module) => ({
|
|
206777
206777
|
default: module.ManageCategoriesModal,
|
|
206778
206778
|
})), { ssr: false });
|
|
206779
|
-
const PAGE_SIZE$
|
|
206779
|
+
const PAGE_SIZE$2 = 20;
|
|
206780
206780
|
const SNAPSHOT_PAGE_SIZE = 1000;
|
|
206781
206781
|
function ManageMemories({ tenantKey, username, mentorId }) {
|
|
206782
206782
|
var _a, _b, _c, _d, _e;
|
|
@@ -206790,7 +206790,7 @@ function ManageMemories({ tenantKey, username, mentorId }) {
|
|
|
206790
206790
|
setPage(1);
|
|
206791
206791
|
}, [selectedLearner, dateRange, selectedCategorySlug]);
|
|
206792
206792
|
const listParams = useMemo(() => {
|
|
206793
|
-
const params = { page, page_size: PAGE_SIZE$
|
|
206793
|
+
const params = { page, page_size: PAGE_SIZE$2 };
|
|
206794
206794
|
if (selectedLearner)
|
|
206795
206795
|
params.email = selectedLearner;
|
|
206796
206796
|
if (selectedCategorySlug !== 'all')
|
|
@@ -206809,7 +206809,7 @@ function ManageMemories({ tenantKey, username, mentorId }) {
|
|
|
206809
206809
|
}, {
|
|
206810
206810
|
skip: !tenantKey || !username || !mentorId,
|
|
206811
206811
|
});
|
|
206812
|
-
const totalPages = Math.max(1, Math.ceil(((_a = listResponse === null || listResponse === void 0 ? void 0 : listResponse.count) !== null && _a !== void 0 ? _a : 0) / PAGE_SIZE$
|
|
206812
|
+
const totalPages = Math.max(1, Math.ceil(((_a = listResponse === null || listResponse === void 0 ? void 0 : listResponse.count) !== null && _a !== void 0 ? _a : 0) / PAGE_SIZE$2));
|
|
206813
206813
|
const { data: adminCategories } = useGetMemoryCategoriesAdminQuery({
|
|
206814
206814
|
org: tenantKey,
|
|
206815
206815
|
mentorId,
|
|
@@ -209108,9 +209108,9 @@ function AgentPrivacyTab({ labels: labelsOverride, tenantKey: tenantKeyProp, men
|
|
|
209108
209108
|
}
|
|
209109
209109
|
return (jsxs(Fragment$1, { children: [jsx("div", { className: "flex hidden h-[73px] flex-shrink-0 items-center border-b border-gray-200 bg-white p-4 lg:block", children: jsxs("div", { children: [jsx("h3", { className: "mb-1 text-base font-medium text-gray-900", children: labels.header.title }), jsx("p", { className: "text-xs text-gray-700", children: labels.header.description })] }) }), jsxs("div", { className: "flex-1 space-y-6 p-3 lg:p-4", style: { overflowY: 'auto', overflowX: 'hidden' }, children: [jsx(WithFormPermissions, { name: "enable_privacy_router",
|
|
209110
209110
|
// @ts-ignore
|
|
209111
|
-
permissions: (_h = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _h === void 0 ? void 0 : _h.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: labels.fields.enableRouter.label }), jsx(FieldTooltip, { text: labels.fields.enableRouter.tooltip })] }), jsx(CustomSwitch, { checked: enabled, onCheckedChange: (checked) => void updateField('enable_privacy_router', checked), disabled: isDisabled || disabled, "aria-label": `Privacy router ${enabled ? 'enabled' : 'disabled'}` })] })) }), enabled && (jsxs(Fragment$1, { children: [jsx(WithFormPermissions, { name: "privacy_action",
|
|
209111
|
+
permissions: (_h = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _h === void 0 ? void 0 : _h.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: labels.fields.enableRouter.label }), jsx(FieldTooltip$1, { text: labels.fields.enableRouter.tooltip })] }), jsx(CustomSwitch, { checked: enabled, onCheckedChange: (checked) => void updateField('enable_privacy_router', checked), disabled: isDisabled || disabled, "aria-label": `Privacy router ${enabled ? 'enabled' : 'disabled'}` })] })) }), enabled && (jsxs(Fragment$1, { children: [jsx(WithFormPermissions, { name: "privacy_action",
|
|
209112
209112
|
// @ts-ignore
|
|
209113
|
-
permissions: (_j = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _j === void 0 ? void 0 : _j.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: labels.fields.action.label }), jsx(FieldTooltip, { text: labels.fields.action.tooltip })] }), jsxs(Select$1, { value: action, onValueChange: (v) => void updateField('privacy_action', v), disabled: isDisabled || disabled, children: [jsx(SelectTrigger, { "aria-label": labels.fields.action.label, children: jsx(SelectValue, {}) }), jsx(SelectContent, { children: PRIVACY_ACTIONS.map((opt) => (jsx(SelectItem, { value: opt, children: labels.fields.action.options[opt] }, opt))) })] }), jsx("p", { className: "text-xs text-gray-500", children: labels.fields.action.descriptions[action] })] })) }), action === 'block' && (jsx(WithFormPermissions, { name: "privacy_response",
|
|
209113
|
+
permissions: (_j = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _j === void 0 ? void 0 : _j.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: labels.fields.action.label }), jsx(FieldTooltip$1, { text: labels.fields.action.tooltip })] }), jsxs(Select$1, { value: action, onValueChange: (v) => void updateField('privacy_action', v), disabled: isDisabled || disabled, children: [jsx(SelectTrigger, { "aria-label": labels.fields.action.label, children: jsx(SelectValue, {}) }), jsx(SelectContent, { children: PRIVACY_ACTIONS.map((opt) => (jsx(SelectItem, { value: opt, children: labels.fields.action.options[opt] }, opt))) })] }), jsx("p", { className: "text-xs text-gray-500", children: labels.fields.action.descriptions[action] })] })) }), action === 'block' && (jsx(WithFormPermissions, { name: "privacy_response",
|
|
209114
209114
|
// @ts-ignore
|
|
209115
209115
|
permissions: (_k = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _k === void 0 ? void 0 : _k.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: labels.fields.blockMessage.label }), jsx(Textarea, { value: localResponse, onChange: (e) => setLocalResponse(e.target.value), onBlur: () => {
|
|
209116
209116
|
if (localResponse !== responseText) {
|
|
@@ -209118,14 +209118,14 @@ function AgentPrivacyTab({ labels: labelsOverride, tenantKey: tenantKeyProp, men
|
|
|
209118
209118
|
}
|
|
209119
209119
|
}, placeholder: labels.fields.blockMessage.placeholder, className: "min-h-[100px]", disabled: isDisabled || disabled, "aria-label": labels.fields.blockMessage.label })] })) })), jsx(WithFormPermissions, { name: "privacy_entities",
|
|
209120
209120
|
// @ts-ignore
|
|
209121
|
-
permissions: (_l = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _l === void 0 ? void 0 : _l.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: labels.fields.entities.label }), jsx(FieldTooltip, { text: labels.fields.entities.tooltip })] }), jsx("div", { className: "flex flex-wrap gap-2", children: PRIVACY_ENTITY_TYPES.map((entity) => {
|
|
209121
|
+
permissions: (_l = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _l === void 0 ? void 0 : _l.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: labels.fields.entities.label }), jsx(FieldTooltip$1, { text: labels.fields.entities.tooltip })] }), jsx("div", { className: "flex flex-wrap gap-2", children: PRIVACY_ENTITY_TYPES.map((entity) => {
|
|
209122
209122
|
var _a;
|
|
209123
209123
|
return (jsx(EntityChip, { entity: entity, label: (_a = labels.fields.entities.labels[entity]) !== null && _a !== void 0 ? _a : entity, selected: entities.includes(entity), disabled: isDisabled || disabled, onToggle: (checked) => toggleEntity(entity, checked) }, entity));
|
|
209124
209124
|
}) }), entities.length === 0 && (jsx("p", { className: "text-xs text-gray-500", children: labels.fields.entities.emptyHint }))] })) }), jsx(WithFormPermissions, { name: "enable_privacy_output_filter",
|
|
209125
209125
|
// @ts-ignore
|
|
209126
|
-
permissions: (_m = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _m === void 0 ? void 0 : _m.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: labels.fields.outputFilter.label }), jsx(FieldTooltip, { text: labels.fields.outputFilter.tooltip })] }), jsx(CustomSwitch, { checked: outputFilter, onCheckedChange: (checked) => void updateField('enable_privacy_output_filter', checked), disabled: isDisabled || disabled, "aria-label": `Output filter ${outputFilter ? 'enabled' : 'disabled'}` })] })) })] }))] })] }));
|
|
209126
|
+
permissions: (_m = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _m === void 0 ? void 0 : _m.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: labels.fields.outputFilter.label }), jsx(FieldTooltip$1, { text: labels.fields.outputFilter.tooltip })] }), jsx(CustomSwitch, { checked: outputFilter, onCheckedChange: (checked) => void updateField('enable_privacy_output_filter', checked), disabled: isDisabled || disabled, "aria-label": `Output filter ${outputFilter ? 'enabled' : 'disabled'}` })] })) })] }))] })] }));
|
|
209127
209127
|
}
|
|
209128
|
-
function FieldTooltip({ text }) {
|
|
209128
|
+
function FieldTooltip$1({ text }) {
|
|
209129
209129
|
return (jsx(TooltipProvider, { children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { type: "button", "aria-label": "More info", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "ibl-tooltip-content", children: jsx("p", { children: text }) })] }) }));
|
|
209130
209130
|
}
|
|
209131
209131
|
function EntityChip({ entity, label, selected, disabled, onToggle }) {
|
|
@@ -209134,6 +209134,893 @@ function EntityChip({ entity, label, selected, disabled, onToggle }) {
|
|
|
209134
209134
|
: 'border-gray-300 bg-white text-gray-700 hover:bg-gray-50', disabled && 'cursor-not-allowed opacity-50'), "data-entity": entity, children: label }));
|
|
209135
209135
|
}
|
|
209136
209136
|
|
|
209137
|
+
const AGENT_VOICE_TAB_LABELS = {
|
|
209138
|
+
header: {
|
|
209139
|
+
title: 'Voice',
|
|
209140
|
+
description: 'Choose the voice your agent uses and how voice calls work.',
|
|
209141
|
+
},
|
|
209142
|
+
subTabs: {
|
|
209143
|
+
voice: 'Voice',
|
|
209144
|
+
callConfig: 'Voice call',
|
|
209145
|
+
},
|
|
209146
|
+
mentorVoice: {
|
|
209147
|
+
title: 'Agent Voice',
|
|
209148
|
+
description: 'The voice your agent uses to read out replies in chat.',
|
|
209149
|
+
providerLabel: 'Voice source',
|
|
209150
|
+
providerTooltip: "Browser uses the listener's own device to speak. OpenAI and Google use a custom voice you pick below.",
|
|
209151
|
+
providerOptions: {
|
|
209152
|
+
browser: {
|
|
209153
|
+
label: 'Browser',
|
|
209154
|
+
description: "Speak through the user's own device. No setup needed.",
|
|
209155
|
+
},
|
|
209156
|
+
openai: {
|
|
209157
|
+
label: 'OpenAI',
|
|
209158
|
+
description: 'High-quality voices from OpenAI.',
|
|
209159
|
+
},
|
|
209160
|
+
google: {
|
|
209161
|
+
label: 'Google',
|
|
209162
|
+
description: 'Natural-sounding voices from Google.',
|
|
209163
|
+
},
|
|
209164
|
+
},
|
|
209165
|
+
voicePickerLabel: {
|
|
209166
|
+
openai: 'OpenAI voice',
|
|
209167
|
+
google: 'Google voice',
|
|
209168
|
+
},
|
|
209169
|
+
searchPlaceholder: 'Search voices…',
|
|
209170
|
+
emptyState: 'No voices match your search.',
|
|
209171
|
+
errorState: "Couldn't load voices. Try again.",
|
|
209172
|
+
previewAria: (voiceName, action) => `${action === 'play' ? 'Preview' : 'Stop'} ${voiceName} voice`,
|
|
209173
|
+
saveButton: 'Save voice',
|
|
209174
|
+
savingButton: 'Saving…',
|
|
209175
|
+
},
|
|
209176
|
+
callConfig: {
|
|
209177
|
+
title: 'Voice call',
|
|
209178
|
+
description: 'Customize how voice calls work. Screen sharing always uses live conversation.',
|
|
209179
|
+
info: 'Live conversation streams the call end-to-end and feels more natural. Step-by-step mode transcribes the user, has the agent think, then speaks — slower, with more time between turns. Screen sharing always uses live conversation.',
|
|
209180
|
+
fields: {
|
|
209181
|
+
mode: {
|
|
209182
|
+
label: 'Call style',
|
|
209183
|
+
tooltip: 'Live conversation feels faster and more natural. Step-by-step gives the agent more time to think between each turn.',
|
|
209184
|
+
options: { realtime: 'Live conversation', inference: 'Step-by-step' },
|
|
209185
|
+
},
|
|
209186
|
+
language: {
|
|
209187
|
+
label: 'Spoken language',
|
|
209188
|
+
tooltip: 'The language used during voice calls.',
|
|
209189
|
+
placeholder: 'English',
|
|
209190
|
+
},
|
|
209191
|
+
llmProvider: {
|
|
209192
|
+
label: 'AI provider',
|
|
209193
|
+
tooltip: 'Which company powers the AI during calls.',
|
|
209194
|
+
placeholder: 'Use agent default',
|
|
209195
|
+
},
|
|
209196
|
+
// TTS / STT are hidden in the UI today — labels kept for completeness
|
|
209197
|
+
// in case a host wants to surface them.
|
|
209198
|
+
ttsProvider: {
|
|
209199
|
+
label: 'Text-to-speech provider',
|
|
209200
|
+
tooltip: 'Auto-matched to the AI provider above.',
|
|
209201
|
+
placeholder: 'Match AI provider',
|
|
209202
|
+
},
|
|
209203
|
+
sttProvider: {
|
|
209204
|
+
label: 'Speech-to-text provider',
|
|
209205
|
+
tooltip: 'Auto-matched to the AI provider above.',
|
|
209206
|
+
placeholder: 'Match AI provider',
|
|
209207
|
+
},
|
|
209208
|
+
useFunctionCalling: {
|
|
209209
|
+
label: 'Look things up only when needed',
|
|
209210
|
+
tooltip: "On (recommended): the agent decides when to check its training materials before answering. Off: the agent checks before every reply — slower but never skips a lookup.",
|
|
209211
|
+
},
|
|
209212
|
+
enableVideo: {
|
|
209213
|
+
label: 'Allow screen sharing on a call',
|
|
209214
|
+
tooltip: "Let users share their screen so the agent can see what they're doing and guide them. Only works in Live conversation mode.",
|
|
209215
|
+
},
|
|
209216
|
+
},
|
|
209217
|
+
resetButton: 'Reset',
|
|
209218
|
+
saveCreate: 'Save',
|
|
209219
|
+
saveUpdate: 'Save changes',
|
|
209220
|
+
savingButton: 'Saving…',
|
|
209221
|
+
},
|
|
209222
|
+
toasts: {
|
|
209223
|
+
voiceSaved: 'Voice saved',
|
|
209224
|
+
voiceError: "Couldn't save voice settings",
|
|
209225
|
+
callConfigSaved: 'Voice call settings saved',
|
|
209226
|
+
callConfigError: "Couldn't save voice call settings",
|
|
209227
|
+
},
|
|
209228
|
+
};
|
|
209229
|
+
function resolveVoiceTabLabels(override) {
|
|
209230
|
+
if (!override)
|
|
209231
|
+
return AGENT_VOICE_TAB_LABELS;
|
|
209232
|
+
return deepMerge(AGENT_VOICE_TAB_LABELS, override);
|
|
209233
|
+
}
|
|
209234
|
+
|
|
209235
|
+
/**
|
|
209236
|
+
* Single-track audio preview hook. Calling `play()` for a new id stops the
|
|
209237
|
+
* currently-playing clip first; calling it again for the same id toggles
|
|
209238
|
+
* stop. Cleans up on unmount.
|
|
209239
|
+
*/
|
|
209240
|
+
function useAudioPreview() {
|
|
209241
|
+
const audioRef = React__default.useRef(null);
|
|
209242
|
+
const [playingId, setPlayingId] = React__default.useState(null);
|
|
209243
|
+
const [isLoading, setIsLoading] = React__default.useState(false);
|
|
209244
|
+
React__default.useEffect(() => {
|
|
209245
|
+
return () => {
|
|
209246
|
+
if (audioRef.current) {
|
|
209247
|
+
audioRef.current.pause();
|
|
209248
|
+
audioRef.current.src = '';
|
|
209249
|
+
audioRef.current = null;
|
|
209250
|
+
}
|
|
209251
|
+
};
|
|
209252
|
+
}, []);
|
|
209253
|
+
const stop = React__default.useCallback(() => {
|
|
209254
|
+
if (audioRef.current) {
|
|
209255
|
+
audioRef.current.pause();
|
|
209256
|
+
audioRef.current.currentTime = 0;
|
|
209257
|
+
}
|
|
209258
|
+
setPlayingId(null);
|
|
209259
|
+
setIsLoading(false);
|
|
209260
|
+
}, []);
|
|
209261
|
+
const play = React__default.useCallback((id, url) => {
|
|
209262
|
+
if (!url)
|
|
209263
|
+
return;
|
|
209264
|
+
if (playingId === id && audioRef.current && !audioRef.current.paused) {
|
|
209265
|
+
stop();
|
|
209266
|
+
return;
|
|
209267
|
+
}
|
|
209268
|
+
if (audioRef.current) {
|
|
209269
|
+
audioRef.current.pause();
|
|
209270
|
+
}
|
|
209271
|
+
const audio = new Audio(url);
|
|
209272
|
+
audioRef.current = audio;
|
|
209273
|
+
setIsLoading(true);
|
|
209274
|
+
setPlayingId(id);
|
|
209275
|
+
audio.addEventListener('canplay', () => setIsLoading(false));
|
|
209276
|
+
audio.addEventListener('ended', () => setPlayingId(null));
|
|
209277
|
+
audio.addEventListener('error', () => {
|
|
209278
|
+
setIsLoading(false);
|
|
209279
|
+
setPlayingId(null);
|
|
209280
|
+
});
|
|
209281
|
+
// Older browsers / jsdom return void from play(); guard against
|
|
209282
|
+
// that so we don't crash with "Cannot read properties of undefined
|
|
209283
|
+
// (reading 'catch')".
|
|
209284
|
+
const result = audio.play();
|
|
209285
|
+
if (result && typeof result.catch === 'function') {
|
|
209286
|
+
result.catch(() => {
|
|
209287
|
+
setIsLoading(false);
|
|
209288
|
+
setPlayingId(null);
|
|
209289
|
+
});
|
|
209290
|
+
}
|
|
209291
|
+
}, [playingId, stop]);
|
|
209292
|
+
return { playingId, isLoading, play, stop };
|
|
209293
|
+
}
|
|
209294
|
+
|
|
209295
|
+
/**
|
|
209296
|
+
* Voices come back from the API in inconsistent casing (e.g. "alloy",
|
|
209297
|
+
* "Alloy", "ALLOY"). Display them title-cased so the UI stays consistent
|
|
209298
|
+
* regardless of the upstream catalogue.
|
|
209299
|
+
*/
|
|
209300
|
+
function toTitleCase(name) {
|
|
209301
|
+
if (!name)
|
|
209302
|
+
return name;
|
|
209303
|
+
return name
|
|
209304
|
+
.split(/\s+/)
|
|
209305
|
+
.map((word) => word.length > 0 ? word[0].toUpperCase() + word.slice(1).toLowerCase() : word)
|
|
209306
|
+
.join(' ');
|
|
209307
|
+
}
|
|
209308
|
+
|
|
209309
|
+
const PAGE_SIZE$1 = 20;
|
|
209310
|
+
function VoicePicker({ org, userId, provider, selectedVoiceId, onSelect, disabled, labels, }) {
|
|
209311
|
+
var _a, _b;
|
|
209312
|
+
const [search, setSearch] = React__default.useState('');
|
|
209313
|
+
const [debouncedSearch, setDebouncedSearch] = React__default.useState('');
|
|
209314
|
+
const [page, setPage] = React__default.useState(1);
|
|
209315
|
+
// Reset paging when the user types a new search OR switches provider.
|
|
209316
|
+
React__default.useEffect(() => {
|
|
209317
|
+
setPage(1);
|
|
209318
|
+
}, [debouncedSearch, provider]);
|
|
209319
|
+
React__default.useEffect(() => {
|
|
209320
|
+
const handle = setTimeout(() => setDebouncedSearch(search), 300);
|
|
209321
|
+
return () => clearTimeout(handle);
|
|
209322
|
+
}, [search]);
|
|
209323
|
+
const { data, isFetching, isError } = useGetVoicesQuery({
|
|
209324
|
+
org,
|
|
209325
|
+
userId,
|
|
209326
|
+
provider,
|
|
209327
|
+
page,
|
|
209328
|
+
pageSize: PAGE_SIZE$1,
|
|
209329
|
+
...(debouncedSearch ? { search: debouncedSearch } : {}),
|
|
209330
|
+
}, { skip: !org || !userId });
|
|
209331
|
+
const paginated = data;
|
|
209332
|
+
const voices = (_a = paginated === null || paginated === void 0 ? void 0 : paginated.results) !== null && _a !== void 0 ? _a : [];
|
|
209333
|
+
const total = (_b = paginated === null || paginated === void 0 ? void 0 : paginated.count) !== null && _b !== void 0 ? _b : 0;
|
|
209334
|
+
const totalPages = total > 0 ? Math.ceil(total / PAGE_SIZE$1) : 1;
|
|
209335
|
+
// Whenever a voice id is saved on the mentor settings, fetch it directly
|
|
209336
|
+
// so we can pin it at the top of the list. Otherwise the user can land
|
|
209337
|
+
// on a page that doesn't contain the selected voice and the selection
|
|
209338
|
+
// appears lost.
|
|
209339
|
+
const { data: pinnedVoiceData } = useGetVoiceQuery({
|
|
209340
|
+
id: selectedVoiceId !== null && selectedVoiceId !== void 0 ? selectedVoiceId : 0,
|
|
209341
|
+
org,
|
|
209342
|
+
userId,
|
|
209343
|
+
}, { skip: !org || !userId || selectedVoiceId == null });
|
|
209344
|
+
const pinnedVoice = pinnedVoiceData;
|
|
209345
|
+
// Only pin a voice from the same provider — otherwise switching from
|
|
209346
|
+
// google → openai would briefly show the leftover google voice.
|
|
209347
|
+
const showPinned = pinnedVoice != null &&
|
|
209348
|
+
pinnedVoice.provider === provider &&
|
|
209349
|
+
!voices.some((v) => v.id === pinnedVoice.id);
|
|
209350
|
+
const { playingId, isLoading: isPreviewLoading, play, stop } = useAudioPreview();
|
|
209351
|
+
React__default.useEffect(() => () => stop(), [provider, stop]);
|
|
209352
|
+
return (jsxs("div", { className: "space-y-3", children: [jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" }), jsx(Input, { type: "search", placeholder: labels.searchPlaceholder, className: "w-full pl-9", value: search, onChange: (e) => setSearch(e.target.value), disabled: disabled, "aria-label": labels.searchPlaceholder, "data-testid": "voice-picker-search" })] }), isError && jsx("p", { className: "text-sm text-red-500", children: labels.errorState }), isFetching ? (jsx("div", { className: "flex items-center justify-center py-8", children: jsx(Spinner, {}) })) : voices.length === 0 && !showPinned ? (jsx("div", { className: "rounded-md border border-dashed border-gray-200 py-8 text-center text-sm text-gray-500", children: labels.emptyState })) : (jsxs(Fragment$1, { children: [showPinned && pinnedVoice && (jsx("div", { className: "rounded-md bg-blue-50/40 p-2", "data-testid": "pinned-voice-row", children: jsx(VoiceRow, { voice: pinnedVoice, isSelected: true, isPlaying: playingId === pinnedVoice.id, showPlayLoader: playingId === pinnedVoice.id && isPreviewLoading, disabled: !!disabled, onSelect: onSelect, play: play, labels: labels }) })), jsx("div", {
|
|
209353
|
+
// Padding (`p-1`) prevents the selected border from being
|
|
209354
|
+
// clipped by `overflow-y-auto` on the first/last rows.
|
|
209355
|
+
className: "grid max-h-[360px] grid-cols-1 gap-2 overflow-y-auto p-1 sm:grid-cols-2", role: "radiogroup", "aria-label": "Available voices", children: voices.map((voice) => (jsx(VoiceRow, { voice: voice, isSelected: selectedVoiceId === voice.id, isPlaying: playingId === voice.id, showPlayLoader: playingId === voice.id && isPreviewLoading, disabled: !!disabled, onSelect: onSelect, play: play, labels: labels }, voice.id))) }), totalPages > 1 && (jsxs("div", { className: "flex items-center justify-between gap-2 border-t border-gray-100 pt-3 text-xs text-gray-600", "data-testid": "voice-pagination", children: [jsxs("span", { "aria-live": "polite", children: ["Page ", jsx("strong", { children: page }), " of ", jsx("strong", { children: totalPages }), jsxs("span", { className: "ml-1 text-gray-400", children: ["\u00B7 ", total, " voices"] })] }), jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Button$1, { type: "button", variant: "outline", size: "sm", disabled: disabled || page <= 1, onClick: () => setPage((p) => Math.max(1, p - 1)), "aria-label": "Previous page of voices", "data-testid": "voice-prev-page", children: [jsx(ChevronLeft, { className: "h-4 w-4" }), "Prev"] }), jsxs(Button$1, { type: "button", variant: "outline", size: "sm", disabled: disabled || page >= totalPages, onClick: () => setPage((p) => Math.min(totalPages, p + 1)), "aria-label": "Next page of voices", "data-testid": "voice-next-page", children: ["Next", jsx(ChevronRight, { className: "h-4 w-4" })] })] })] }))] }))] }));
|
|
209356
|
+
}
|
|
209357
|
+
/**
|
|
209358
|
+
* A single voice row. Rendered as a `<div role="radio">` so the inner
|
|
209359
|
+
* preview `<button>` doesn't trip HTML's "no nested button" rule.
|
|
209360
|
+
* Keyboard behaviour mirrors a real radio: Space/Enter selects.
|
|
209361
|
+
*
|
|
209362
|
+
* Uses `border-2` (not `ring`) for the selected outline so it never gets
|
|
209363
|
+
* clipped by the parent scroll container's `overflow-y-auto`.
|
|
209364
|
+
*/
|
|
209365
|
+
function VoiceRow({ voice, isSelected, isPlaying, showPlayLoader, disabled, onSelect, play, labels, }) {
|
|
209366
|
+
return (jsxs("div", { role: "radio", tabIndex: disabled ? -1 : 0, "aria-checked": isSelected, "aria-disabled": disabled || undefined, "aria-label": toTitleCase(voice.name), "data-voice-id": voice.id, "data-selected": isSelected || undefined, onClick: () => !disabled && onSelect(voice), onKeyDown: (e) => {
|
|
209367
|
+
if (disabled)
|
|
209368
|
+
return;
|
|
209369
|
+
if (e.key === ' ' || e.key === 'Enter') {
|
|
209370
|
+
e.preventDefault();
|
|
209371
|
+
onSelect(voice);
|
|
209372
|
+
}
|
|
209373
|
+
}, className: cn('flex cursor-pointer items-start gap-3 rounded-lg border-2 p-3 text-left transition-all hover:shadow-sm focus-visible:outline-blue-500', isSelected
|
|
209374
|
+
? 'border-blue-500 bg-blue-50/40'
|
|
209375
|
+
: 'border-gray-200 bg-white hover:border-gray-300', disabled && 'cursor-not-allowed opacity-60'), children: [jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-blue-50 text-blue-600", children: jsx(Volume2, { className: "h-4 w-4", "aria-hidden": "true" }) }), jsxs("div", { className: "min-w-0 flex-1", children: [jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsx("span", { className: "truncate text-sm font-medium text-gray-900", children: toTitleCase(voice.name) }), voice.audio_url && (jsx(Button$1, { type: "button", variant: "ghost", size: "icon", className: "h-7 w-7 flex-shrink-0 text-gray-500 hover:text-blue-600", onClick: (e) => {
|
|
209376
|
+
e.stopPropagation();
|
|
209377
|
+
play(voice.id, voice.audio_url);
|
|
209378
|
+
}, disabled: disabled, "aria-label": labels.previewAria(toTitleCase(voice.name), isPlaying ? 'stop' : 'play'), children: showPlayLoader ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" })) : isPlaying ? (jsx(Pause, { className: "h-4 w-4" })) : (jsx(Play, { className: "h-4 w-4" })) }))] }), (voice.language || voice.description) && (jsx("p", { className: "mt-1 line-clamp-2 text-xs text-gray-500", children: [voice.language, voice.description].filter(Boolean).join(' · ') }))] })] }));
|
|
209379
|
+
}
|
|
209380
|
+
|
|
209381
|
+
/**
|
|
209382
|
+
* Modal-style voice picker. Wraps the inline `VoicePicker` (search +
|
|
209383
|
+
* pagination + audio preview) in a Dialog. Used by both the Voice tab
|
|
209384
|
+
* (mentor voice) and the Call Configuration sub-tab so we don't end up
|
|
209385
|
+
* with two divergent UIs for choosing a voice.
|
|
209386
|
+
*/
|
|
209387
|
+
function VoicePickerModal({ isOpen, onClose, org, userId, provider, selectedVoiceId, onSelect, labels, title = 'Select a voice', description = 'Search, browse, and listen to a sample before you pick.', }) {
|
|
209388
|
+
return (jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: jsxs(DialogContent, { className: "max-w-3xl space-y-4 p-4", "data-testid": "voice-picker-modal", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { className: "ibl-dialog-title", children: title }), jsx(DialogDescription, { className: "text-xs text-gray-600", children: description })] }), jsx(VoicePicker, { org: org, userId: userId, provider: provider, selectedVoiceId: selectedVoiceId,
|
|
209389
|
+
// Auto-close on selection — picking a voice in the modal is the
|
|
209390
|
+
// explicit "done" action. The parent receives the new voice and
|
|
209391
|
+
// closes us via `isOpen={false}`.
|
|
209392
|
+
onSelect: (v) => {
|
|
209393
|
+
onSelect(v);
|
|
209394
|
+
onClose();
|
|
209395
|
+
}, labels: labels })] }) }));
|
|
209396
|
+
}
|
|
209397
|
+
/**
|
|
209398
|
+
* Combobox-style trigger that shows the currently selected voice (name +
|
|
209399
|
+
* audio glyph + inline Play button) and opens the modal picker on click.
|
|
209400
|
+
* Visual pattern mirrors the LLM provider card on the LLM tab — a
|
|
209401
|
+
* card-style row with the currently picked item up front and a chevron at
|
|
209402
|
+
* the end.
|
|
209403
|
+
*
|
|
209404
|
+
* Clicking the Play button previews the voice without opening the modal;
|
|
209405
|
+
* clicking anywhere else opens it.
|
|
209406
|
+
*/
|
|
209407
|
+
function VoicePickerTrigger({ org, userId, provider, selectedVoice, onSelect, disabled, labels, emptyLabel = 'Select a voice', modalTitle, modalDescription, testId, }) {
|
|
209408
|
+
var _a;
|
|
209409
|
+
const [isOpen, setIsOpen] = React__default.useState(false);
|
|
209410
|
+
const { playingId, isLoading: isPreviewLoading, play, stop } = useAudioPreview();
|
|
209411
|
+
// Stop preview when the trigger unmounts or when the modal opens —
|
|
209412
|
+
// the modal has its own preview state and we don't want both playing
|
|
209413
|
+
// at once.
|
|
209414
|
+
React__default.useEffect(() => {
|
|
209415
|
+
if (isOpen)
|
|
209416
|
+
stop();
|
|
209417
|
+
}, [isOpen, stop]);
|
|
209418
|
+
const displayName = selectedVoice ? toTitleCase(selectedVoice.name) : null;
|
|
209419
|
+
const language = (selectedVoice === null || selectedVoice === void 0 ? void 0 : selectedVoice.language) || null;
|
|
209420
|
+
const audioUrl = (selectedVoice === null || selectedVoice === void 0 ? void 0 : selectedVoice.audio_url) || '';
|
|
209421
|
+
const isPlaying = selectedVoice != null && playingId === selectedVoice.id;
|
|
209422
|
+
const showPlayLoader = isPlaying && isPreviewLoading;
|
|
209423
|
+
return (jsxs(Fragment$1, { children: [jsxs("div", { className: cn('flex w-full items-center gap-2 rounded-lg border-2 border-gray-200 bg-white p-3 transition-colors', !disabled &&
|
|
209424
|
+
'hover:border-blue-300 focus-within:border-blue-500', disabled && 'cursor-not-allowed opacity-60'), "data-testid": testId !== null && testId !== void 0 ? testId : 'voice-picker-trigger', children: [jsxs("button", { type: "button", disabled: disabled, onClick: () => setIsOpen(true), "aria-haspopup": "dialog", "aria-expanded": isOpen, className: "flex min-w-0 flex-1 items-center gap-3 text-left focus-visible:outline-none", "data-testid": testId ? `${testId}-open` : 'voice-picker-trigger-open', children: [jsx("span", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-blue-50 text-blue-600", children: jsx(Volume2, { className: "h-4 w-4", "aria-hidden": "true" }) }), jsxs("span", { className: "flex min-w-0 flex-col", children: [jsx("span", { className: "truncate text-sm font-medium text-gray-900", children: displayName !== null && displayName !== void 0 ? displayName : emptyLabel }), language && (jsx("span", { className: "truncate text-xs text-gray-500", children: language }))] })] }), audioUrl && selectedVoice && (jsx(Button$1, { type: "button", variant: "ghost", size: "icon", className: "h-8 w-8 flex-shrink-0 text-gray-500 hover:text-blue-600", disabled: disabled, onClick: (e) => {
|
|
209425
|
+
e.stopPropagation();
|
|
209426
|
+
play(selectedVoice.id, audioUrl);
|
|
209427
|
+
}, "aria-label": labels.previewAria(displayName !== null && displayName !== void 0 ? displayName : '', isPlaying ? 'stop' : 'play'), "data-testid": testId ? `${testId}-preview` : 'voice-picker-trigger-preview', children: showPlayLoader ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" })) : isPlaying ? (jsx(Pause, { className: "h-4 w-4" })) : (jsx(Play, { className: "h-4 w-4" })) })), jsx(ChevronDown, { className: "h-4 w-4 flex-shrink-0 text-gray-400", "aria-hidden": "true" })] }), jsx(VoicePickerModal, { isOpen: isOpen, onClose: () => setIsOpen(false), org: org, userId: userId, provider: provider, selectedVoiceId: (_a = selectedVoice === null || selectedVoice === void 0 ? void 0 : selectedVoice.id) !== null && _a !== void 0 ? _a : null, onSelect: onSelect, labels: labels, title: modalTitle, description: modalDescription })] }));
|
|
209428
|
+
}
|
|
209429
|
+
|
|
209430
|
+
/**
|
|
209431
|
+
* Resolve a voice by its display name. The mentor settings endpoint
|
|
209432
|
+
* returns voice references as raw strings (e.g. `"alloy"`, `"Fenrir"`)
|
|
209433
|
+
* rather than ids, so we have to look them up in the voices catalogue
|
|
209434
|
+
* before we can render the trigger (with id, audio_url, etc.) or send
|
|
209435
|
+
* an id back on save.
|
|
209436
|
+
*
|
|
209437
|
+
* Returns `{ voice, isResolving }`. While the lookup is in flight the
|
|
209438
|
+
* caller should keep showing whatever placeholder makes sense.
|
|
209439
|
+
*
|
|
209440
|
+
* The query is scoped by provider so two different providers can each
|
|
209441
|
+
* have a "Standard" voice without colliding.
|
|
209442
|
+
*/
|
|
209443
|
+
function useResolveVoiceByName(args) {
|
|
209444
|
+
var _a, _b;
|
|
209445
|
+
const { org, userId, provider, name } = args;
|
|
209446
|
+
const enabled = !!org && !!userId && !!name;
|
|
209447
|
+
const { data, isFetching } = useGetVoicesQuery({
|
|
209448
|
+
org,
|
|
209449
|
+
userId,
|
|
209450
|
+
provider,
|
|
209451
|
+
search: name !== null && name !== void 0 ? name : '',
|
|
209452
|
+
pageSize: 25, // search may return close matches; keep the window small
|
|
209453
|
+
}, { skip: !enabled });
|
|
209454
|
+
if (!enabled)
|
|
209455
|
+
return { voice: null, isResolving: false };
|
|
209456
|
+
const results = ((_a = data === null || data === void 0 ? void 0 : data.results) !== null && _a !== void 0 ? _a : []);
|
|
209457
|
+
const lowered = (name !== null && name !== void 0 ? name : '').trim().toLowerCase();
|
|
209458
|
+
const match = (_b = results.find((v) => { var _a; return ((_a = v.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === lowered && v.provider === provider; })) !== null && _b !== void 0 ? _b : null;
|
|
209459
|
+
return { voice: match, isResolving: isFetching };
|
|
209460
|
+
}
|
|
209461
|
+
|
|
209462
|
+
/**
|
|
209463
|
+
* Map an LLM provider to the voice provider used by the picker. Azure
|
|
209464
|
+
* OpenAI shares the same voice catalogue as OpenAI, so both surfaces
|
|
209465
|
+
* point at the `openai` voice list.
|
|
209466
|
+
*/
|
|
209467
|
+
function llmProviderToVoiceProvider(llm) {
|
|
209468
|
+
if (llm === 'openai' || llm === 'azure_openai')
|
|
209469
|
+
return 'openai';
|
|
209470
|
+
if (llm === 'google')
|
|
209471
|
+
return 'google';
|
|
209472
|
+
return null;
|
|
209473
|
+
}
|
|
209474
|
+
/**
|
|
209475
|
+
* Derive a sensible TTS / STT provider from the LLM choice. The UI no
|
|
209476
|
+
* longer exposes these fields directly — keeping them aligned with the
|
|
209477
|
+
* LLM provider keeps the backend stack consistent and matches the
|
|
209478
|
+
* product expectation that "Microsoft" / OpenAI / Google all reach for
|
|
209479
|
+
* their native voice + speech APIs by default.
|
|
209480
|
+
*
|
|
209481
|
+
* If the user previously customised these manually they're kept as-is
|
|
209482
|
+
* (see `withDerivedProviders`); we only fill the field when it's empty.
|
|
209483
|
+
*/
|
|
209484
|
+
function defaultTtsProviderFor(llm) {
|
|
209485
|
+
if (llm === 'azure_openai')
|
|
209486
|
+
return 'azure_openai';
|
|
209487
|
+
if (llm === 'google')
|
|
209488
|
+
return 'google';
|
|
209489
|
+
if (llm === 'openai')
|
|
209490
|
+
return 'openai';
|
|
209491
|
+
return '';
|
|
209492
|
+
}
|
|
209493
|
+
function defaultSttProviderFor(llm) {
|
|
209494
|
+
if (llm === 'azure_openai')
|
|
209495
|
+
return 'azure_openai';
|
|
209496
|
+
if (llm === 'google')
|
|
209497
|
+
return 'google';
|
|
209498
|
+
if (llm === 'openai')
|
|
209499
|
+
return 'openai';
|
|
209500
|
+
return '';
|
|
209501
|
+
}
|
|
209502
|
+
/**
|
|
209503
|
+
* Fill in any missing TTS / STT provider from the active LLM. Used on
|
|
209504
|
+
* save so the API always gets a complete triple even though the UI no
|
|
209505
|
+
* longer surfaces TTS/STT pickers.
|
|
209506
|
+
*/
|
|
209507
|
+
function withDerivedProviders(form) {
|
|
209508
|
+
return {
|
|
209509
|
+
...form,
|
|
209510
|
+
tts_provider: form.tts_provider || defaultTtsProviderFor(form.llm_provider),
|
|
209511
|
+
stt_provider: form.stt_provider || defaultSttProviderFor(form.llm_provider),
|
|
209512
|
+
};
|
|
209513
|
+
}
|
|
209514
|
+
/**
|
|
209515
|
+
* Friendly display name for an LLM provider. Used by both the field
|
|
209516
|
+
* label "Voice (Microsoft / OpenAI / Google)" and any tooltips that
|
|
209517
|
+
* mention the picked provider.
|
|
209518
|
+
*/
|
|
209519
|
+
function llmProviderDisplayName(llm) {
|
|
209520
|
+
if (llm === 'azure_openai')
|
|
209521
|
+
return 'Microsoft';
|
|
209522
|
+
if (llm === 'google')
|
|
209523
|
+
return 'Google';
|
|
209524
|
+
if (llm === 'openai')
|
|
209525
|
+
return 'OpenAI';
|
|
209526
|
+
return '';
|
|
209527
|
+
}
|
|
209528
|
+
/**
|
|
209529
|
+
* Top languages we expose in the picker. The backend accepts any ISO 639
|
|
209530
|
+
* code as free text, but the dropdown keeps the common cases one click
|
|
209531
|
+
* away. Add to this list when product asks.
|
|
209532
|
+
*/
|
|
209533
|
+
const LANGUAGE_OPTIONS = [
|
|
209534
|
+
{ value: 'en', label: 'English' },
|
|
209535
|
+
{ value: 'fr', label: 'French' },
|
|
209536
|
+
{ value: 'es', label: 'Spanish' },
|
|
209537
|
+
{ value: 'pt', label: 'Portuguese' },
|
|
209538
|
+
{ value: 'nl', label: 'Dutch' },
|
|
209539
|
+
];
|
|
209540
|
+
const EMPTY_FORM = {
|
|
209541
|
+
mode: 'realtime',
|
|
209542
|
+
tts_provider: '',
|
|
209543
|
+
stt_provider: '',
|
|
209544
|
+
llm_provider: '',
|
|
209545
|
+
language: 'en',
|
|
209546
|
+
use_function_calling_for_rag: false,
|
|
209547
|
+
enable_video: false,
|
|
209548
|
+
screensharing_system_prompt: '',
|
|
209549
|
+
screensharing_proactive_prompt: '',
|
|
209550
|
+
openai_voice_id: null,
|
|
209551
|
+
google_voice_id: null,
|
|
209552
|
+
};
|
|
209553
|
+
/**
|
|
209554
|
+
* The voice fields on `CallConfiguration` can arrive in two shapes:
|
|
209555
|
+
* - `openai_voice_id: number | null` (the canonical id)
|
|
209556
|
+
* - `openai_voice: Voice | number | null` (a fully serialized voice)
|
|
209557
|
+
*
|
|
209558
|
+
* `readCallConfigVoiceId` collapses both into a plain id.
|
|
209559
|
+
*/
|
|
209560
|
+
function readCallConfigVoiceId(config, field) {
|
|
209561
|
+
if (!config)
|
|
209562
|
+
return null;
|
|
209563
|
+
const idField = field === 'openai' ? 'openai_voice_id' : 'google_voice_id';
|
|
209564
|
+
const objField = field === 'openai' ? 'openai_voice' : 'google_voice';
|
|
209565
|
+
const id = config[idField];
|
|
209566
|
+
if (typeof id === 'number')
|
|
209567
|
+
return id;
|
|
209568
|
+
const obj = config[objField];
|
|
209569
|
+
if (obj == null)
|
|
209570
|
+
return null;
|
|
209571
|
+
if (typeof obj === 'number')
|
|
209572
|
+
return obj;
|
|
209573
|
+
if (typeof obj === 'object' && 'id' in obj)
|
|
209574
|
+
return obj.id;
|
|
209575
|
+
return null;
|
|
209576
|
+
}
|
|
209577
|
+
function toFormState(config) {
|
|
209578
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
209579
|
+
if (!config)
|
|
209580
|
+
return EMPTY_FORM;
|
|
209581
|
+
return {
|
|
209582
|
+
mode: (_a = config.mode) !== null && _a !== void 0 ? _a : 'realtime',
|
|
209583
|
+
tts_provider: (_b = config.tts_provider) !== null && _b !== void 0 ? _b : '',
|
|
209584
|
+
stt_provider: (_c = config.stt_provider) !== null && _c !== void 0 ? _c : '',
|
|
209585
|
+
llm_provider: (_d = config.llm_provider) !== null && _d !== void 0 ? _d : '',
|
|
209586
|
+
language: (_e = config.language) !== null && _e !== void 0 ? _e : 'en',
|
|
209587
|
+
use_function_calling_for_rag: !!config.use_function_calling_for_rag,
|
|
209588
|
+
enable_video: !!config.enable_video,
|
|
209589
|
+
screensharing_system_prompt: (_f = config.screensharing_system_prompt) !== null && _f !== void 0 ? _f : '',
|
|
209590
|
+
screensharing_proactive_prompt: (_g = config.screensharing_proactive_prompt) !== null && _g !== void 0 ? _g : '',
|
|
209591
|
+
openai_voice_id: readCallConfigVoiceId(config, 'openai'),
|
|
209592
|
+
google_voice_id: readCallConfigVoiceId(config, 'google'),
|
|
209593
|
+
};
|
|
209594
|
+
}
|
|
209595
|
+
function toRequestBody(form) {
|
|
209596
|
+
const derived = withDerivedProviders(form);
|
|
209597
|
+
return {
|
|
209598
|
+
mode: derived.mode,
|
|
209599
|
+
...(derived.tts_provider ? { tts_provider: derived.tts_provider } : {}),
|
|
209600
|
+
...(derived.stt_provider ? { stt_provider: derived.stt_provider } : {}),
|
|
209601
|
+
...(derived.llm_provider ? { llm_provider: derived.llm_provider } : {}),
|
|
209602
|
+
language: derived.language || 'en',
|
|
209603
|
+
use_function_calling_for_rag: derived.use_function_calling_for_rag,
|
|
209604
|
+
enable_video: derived.enable_video,
|
|
209605
|
+
screensharing_system_prompt: derived.screensharing_system_prompt,
|
|
209606
|
+
screensharing_proactive_prompt: derived.screensharing_proactive_prompt,
|
|
209607
|
+
openai_voice_id: derived.openai_voice_id,
|
|
209608
|
+
google_voice_id: derived.google_voice_id,
|
|
209609
|
+
};
|
|
209610
|
+
}
|
|
209611
|
+
function CallConfigSection({ org, userId, mentorId, isDisabled, labels, voicePickerLabels, toastLabels, initialConfig, renderPromptContent: _renderPromptContent, // currently unused — kept for ABI stability
|
|
209612
|
+
}) {
|
|
209613
|
+
const hasInitial = initialConfig !== undefined;
|
|
209614
|
+
// Fall back to the list endpoint only when no inline config was supplied.
|
|
209615
|
+
// When `initialConfig` is provided (even as `null`), skip the network call
|
|
209616
|
+
// entirely so the section renders synchronously.
|
|
209617
|
+
const { data: configs, isLoading, isFetching, } = useGetCallConfigurationsQuery({ org, userId, mentor: mentorId }, { skip: hasInitial || !org || !userId || !mentorId });
|
|
209618
|
+
const existing = hasInitial
|
|
209619
|
+
? initialConfig
|
|
209620
|
+
: configs === null || configs === void 0 ? void 0 : configs[0];
|
|
209621
|
+
const [form, setForm] = React__default.useState(() => toFormState(existing));
|
|
209622
|
+
const [initialForm, setInitialForm] = React__default.useState(() => toFormState(existing));
|
|
209623
|
+
// Track the full Voice object the user picked this session so we can
|
|
209624
|
+
// show its name + audio_url in the trigger immediately, before the
|
|
209625
|
+
// call-config refetches. When `null`, the trigger falls back to the
|
|
209626
|
+
// serialized voice object embedded in the call_configuration response
|
|
209627
|
+
// (`existing.openai_voice` / `existing.google_voice`).
|
|
209628
|
+
const [pickedOpenaiVoice, setPickedOpenaiVoice] = React__default.useState(null);
|
|
209629
|
+
const [pickedGoogleVoice, setPickedGoogleVoice] = React__default.useState(null);
|
|
209630
|
+
React__default.useEffect(() => {
|
|
209631
|
+
const next = toFormState(existing);
|
|
209632
|
+
setForm(next);
|
|
209633
|
+
setInitialForm(next);
|
|
209634
|
+
setPickedOpenaiVoice(null);
|
|
209635
|
+
setPickedGoogleVoice(null);
|
|
209636
|
+
}, [existing === null || existing === void 0 ? void 0 : existing.id, existing]);
|
|
209637
|
+
const [createCallConfig, { isLoading: isCreating }] = useCreateCallConfigurationMutation();
|
|
209638
|
+
const [updateCallConfig, { isLoading: isUpdating }] = useUpdateCallConfigurationMutation();
|
|
209639
|
+
const isSaving = isCreating || isUpdating;
|
|
209640
|
+
const disabled = Boolean(isDisabled) || isLoading || isSaving;
|
|
209641
|
+
const isDirty = JSON.stringify(form) !== JSON.stringify(initialForm);
|
|
209642
|
+
const updateField = (key, value) => {
|
|
209643
|
+
setForm((prev) => ({ ...prev, [key]: value }));
|
|
209644
|
+
};
|
|
209645
|
+
const handleSave = async () => {
|
|
209646
|
+
try {
|
|
209647
|
+
const body = toRequestBody(form);
|
|
209648
|
+
if (existing === null || existing === void 0 ? void 0 : existing.id) {
|
|
209649
|
+
await updateCallConfig({
|
|
209650
|
+
org,
|
|
209651
|
+
userId,
|
|
209652
|
+
id: existing.id,
|
|
209653
|
+
requestBody: body,
|
|
209654
|
+
}).unwrap();
|
|
209655
|
+
}
|
|
209656
|
+
else {
|
|
209657
|
+
await createCallConfig({
|
|
209658
|
+
org,
|
|
209659
|
+
userId,
|
|
209660
|
+
requestBody: { ...body, mentor: mentorId },
|
|
209661
|
+
}).unwrap();
|
|
209662
|
+
}
|
|
209663
|
+
toast.success(toastLabels.saved);
|
|
209664
|
+
setInitialForm(form);
|
|
209665
|
+
}
|
|
209666
|
+
catch (error) {
|
|
209667
|
+
console.error('[CallConfigSection] save error', error);
|
|
209668
|
+
toast.error(toastLabels.error);
|
|
209669
|
+
}
|
|
209670
|
+
};
|
|
209671
|
+
const handleReset = () => setForm(initialForm);
|
|
209672
|
+
if (isLoading) {
|
|
209673
|
+
return (jsx("div", { className: "flex items-center justify-center py-8", "data-testid": "call-config-loading", children: jsx(Spinner, {}) }));
|
|
209674
|
+
}
|
|
209675
|
+
return (jsxs("div", { className: "space-y-5", "data-testid": "call-config-form", children: [jsx("div", { className: "rounded-md border border-blue-100 bg-blue-50/50 p-3 text-xs text-gray-700", children: labels.info }), jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [jsx(FieldWrap, { label: labels.fields.mode.label, tooltip: labels.fields.mode.tooltip, children: jsxs(Select$1, { value: form.mode, onValueChange: (v) => updateField('mode', v), disabled: disabled, children: [jsx(SelectTrigger, { "aria-label": labels.fields.mode.label, children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "realtime", children: labels.fields.mode.options.realtime }), jsx(SelectItem, { value: "inference", children: labels.fields.mode.options.inference })] })] }) }), jsx(FieldWrap, { label: labels.fields.language.label, tooltip: labels.fields.language.tooltip, children: jsxs(Select$1, { value: form.language, onValueChange: (v) => updateField('language', v), disabled: disabled, children: [jsx(SelectTrigger, { "aria-label": labels.fields.language.label, children: jsx(SelectValue, { placeholder: labels.fields.language.placeholder }) }), jsx(SelectContent, { children: LANGUAGE_OPTIONS.map((opt) => (jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value))) })] }) }), jsx(FieldWrap, { label: labels.fields.llmProvider.label, tooltip: labels.fields.llmProvider.tooltip, children: jsxs(Select$1, { value: form.llm_provider, onValueChange: (v) => updateField('llm_provider', v), disabled: disabled, children: [jsx(SelectTrigger, { "aria-label": labels.fields.llmProvider.label, children: jsx(SelectValue, { placeholder: labels.fields.llmProvider.placeholder }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "openai", children: "OpenAI" }), jsx(SelectItem, { value: "google", children: "Google" }), jsx(SelectItem, { value: "azure_openai", children: "Microsoft" })] })] }) })] }), (() => {
|
|
209676
|
+
const voiceProvider = llmProviderToVoiceProvider(form.llm_provider);
|
|
209677
|
+
if (!voiceProvider)
|
|
209678
|
+
return null;
|
|
209679
|
+
const isOpenAiVoice = voiceProvider === 'openai';
|
|
209680
|
+
const inlineVoice = (isOpenAiVoice
|
|
209681
|
+
? existing === null || existing === void 0 ? void 0 : existing.openai_voice
|
|
209682
|
+
: existing === null || existing === void 0 ? void 0 : existing.google_voice);
|
|
209683
|
+
// The API can return either the full Voice object or just the id
|
|
209684
|
+
// depending on serializer version. We only pin it as the display
|
|
209685
|
+
// value when it has a `name` (i.e. the full-object shape).
|
|
209686
|
+
const inlineVoiceObject = inlineVoice != null && typeof inlineVoice === 'object' && 'name' in inlineVoice
|
|
209687
|
+
? inlineVoice
|
|
209688
|
+
: null;
|
|
209689
|
+
const selectedVoice = isOpenAiVoice
|
|
209690
|
+
? pickedOpenaiVoice !== null && pickedOpenaiVoice !== void 0 ? pickedOpenaiVoice : inlineVoiceObject
|
|
209691
|
+
: pickedGoogleVoice !== null && pickedGoogleVoice !== void 0 ? pickedGoogleVoice : inlineVoiceObject;
|
|
209692
|
+
const providerDisplayName = llmProviderDisplayName(form.llm_provider);
|
|
209693
|
+
return (jsxs("div", { className: "space-y-2 rounded-lg border border-gray-200 p-4", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: "Voice" }), jsxs("p", { className: "text-xs text-gray-500", children: ["The voice your agent uses on calls \u2014 from ", providerDisplayName, "."] }), jsx(VoicePickerTrigger, { org: org, userId: userId, provider: voiceProvider, selectedVoice: selectedVoice, onSelect: (v) => {
|
|
209694
|
+
if (isOpenAiVoice) {
|
|
209695
|
+
setPickedOpenaiVoice(v);
|
|
209696
|
+
updateField('openai_voice_id', v.id);
|
|
209697
|
+
}
|
|
209698
|
+
else {
|
|
209699
|
+
setPickedGoogleVoice(v);
|
|
209700
|
+
updateField('google_voice_id', v.id);
|
|
209701
|
+
}
|
|
209702
|
+
}, disabled: disabled, labels: voicePickerLabels, modalTitle: `Select a ${providerDisplayName} voice`, modalDescription: "Search, browse, and listen to a sample before you pick.", testId: "call-config-voice-trigger" })] }));
|
|
209703
|
+
})(), jsxs("div", { className: "flex items-center justify-end gap-2 border-t border-gray-100 pt-3", children: [isFetching && !isLoading && (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-gray-400", "aria-label": "Refreshing" })), jsx(Button$1, { type: "button", variant: "outline", onClick: handleReset, disabled: disabled || !isDirty, children: labels.resetButton }), jsx(Button$1, { type: "button", onClick: handleSave, disabled: disabled || !isDirty, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isSaving
|
|
209704
|
+
? labels.savingButton
|
|
209705
|
+
: existing
|
|
209706
|
+
? labels.saveUpdate
|
|
209707
|
+
: labels.saveCreate })] })] }));
|
|
209708
|
+
}
|
|
209709
|
+
function FieldWrap({ label, tooltip, children }) {
|
|
209710
|
+
return (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: label }), tooltip && (jsx(TooltipProvider, { children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { type: "button", "aria-label": `More info about ${label}`, children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { side: "top", align: "start", sideOffset: 6, collisionPadding: 16, className: "ibl-tooltip-content z-50 max-w-[300px]", children: jsx("p", { className: "text-xs leading-relaxed whitespace-normal", children: tooltip }) })] }) }))] }), children] }));
|
|
209711
|
+
}
|
|
209712
|
+
|
|
209713
|
+
const SUB_TAB_VALUES = {
|
|
209714
|
+
voice: 'voice',
|
|
209715
|
+
callConfig: 'call-config',
|
|
209716
|
+
};
|
|
209717
|
+
/**
|
|
209718
|
+
* Pull a voice **name** out of the mentor settings response, which can
|
|
209719
|
+
* return a plain string, a numeric id, or a serialized object with a
|
|
209720
|
+
* `name` key depending on the backend version.
|
|
209721
|
+
*/
|
|
209722
|
+
function readVoiceName(value) {
|
|
209723
|
+
if (value == null)
|
|
209724
|
+
return null;
|
|
209725
|
+
if (typeof value === 'string')
|
|
209726
|
+
return value;
|
|
209727
|
+
if (typeof value === 'object' && 'name' in value && typeof value.name === 'string') {
|
|
209728
|
+
return value.name;
|
|
209729
|
+
}
|
|
209730
|
+
return null;
|
|
209731
|
+
}
|
|
209732
|
+
function AgentVoiceTab({ labels: labelsOverride, defaultSubTab = 'voice', renderPromptContent, tenantKey: tenantKeyProp, mentorId: mentorIdProp, username: usernameProp, enableRBAC: enableRBACProp, }) {
|
|
209733
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
209734
|
+
const ctx = useAgentSettingsOptional();
|
|
209735
|
+
const tenantKey = (_a = tenantKeyProp !== null && tenantKeyProp !== void 0 ? tenantKeyProp : ctx === null || ctx === void 0 ? void 0 : ctx.tenantKey) !== null && _a !== void 0 ? _a : '';
|
|
209736
|
+
const mentorId = (_b = mentorIdProp !== null && mentorIdProp !== void 0 ? mentorIdProp : ctx === null || ctx === void 0 ? void 0 : ctx.mentorId) !== null && _b !== void 0 ? _b : '';
|
|
209737
|
+
const username = (_c = usernameProp !== null && usernameProp !== void 0 ? usernameProp : ctx === null || ctx === void 0 ? void 0 : ctx.username) !== null && _c !== void 0 ? _c : '';
|
|
209738
|
+
const enableRBAC = (_d = enableRBACProp !== null && enableRBACProp !== void 0 ? enableRBACProp : ctx === null || ctx === void 0 ? void 0 : ctx.enableRBAC) !== null && _d !== void 0 ? _d : false;
|
|
209739
|
+
const labels = React__default.useMemo(() => resolveVoiceTabLabels(labelsOverride), [labelsOverride]);
|
|
209740
|
+
const { data: rawMentorSettings, isLoading: isMentorSettingsLoading } = useGetMentorSettingsQuery({
|
|
209741
|
+
mentor: mentorId,
|
|
209742
|
+
org: tenantKey,
|
|
209743
|
+
// @ts-expect-error userId is accepted at runtime
|
|
209744
|
+
userId: username,
|
|
209745
|
+
}, { skip: !username || !mentorId || !tenantKey });
|
|
209746
|
+
const mentorSettings = rawMentorSettings;
|
|
209747
|
+
const initialProvider = (_e = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.voice_provider) !== null && _e !== void 0 ? _e : 'browser';
|
|
209748
|
+
// Backend returns voice references as *name strings* on the mentor
|
|
209749
|
+
// settings endpoint (e.g. `"alloy"`, `"Fenrir"`). Resolve each one to a
|
|
209750
|
+
// full Voice via the voices catalogue so we can render the trigger
|
|
209751
|
+
// (with audio_url for the play button) and send the id on save.
|
|
209752
|
+
const savedOpenaiName = (_f = readVoiceName(mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.openai_voice)) !== null && _f !== void 0 ? _f : null;
|
|
209753
|
+
const savedGoogleName = (_g = readVoiceName(mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.google_voice)) !== null && _g !== void 0 ? _g : null;
|
|
209754
|
+
const { voice: resolvedOpenaiVoice } = useResolveVoiceByName({
|
|
209755
|
+
org: tenantKey,
|
|
209756
|
+
userId: username,
|
|
209757
|
+
provider: 'openai',
|
|
209758
|
+
name: savedOpenaiName,
|
|
209759
|
+
});
|
|
209760
|
+
const { voice: resolvedGoogleVoice } = useResolveVoiceByName({
|
|
209761
|
+
org: tenantKey,
|
|
209762
|
+
userId: username,
|
|
209763
|
+
provider: 'google',
|
|
209764
|
+
name: savedGoogleName,
|
|
209765
|
+
});
|
|
209766
|
+
// Picked voices override the resolved server values once the user
|
|
209767
|
+
// makes a choice. Null means "use what came from the server".
|
|
209768
|
+
const [provider, setProvider] = React__default.useState(initialProvider);
|
|
209769
|
+
const [pickedOpenaiVoice, setPickedOpenaiVoice] = React__default.useState(null);
|
|
209770
|
+
const [pickedGoogleVoice, setPickedGoogleVoice] = React__default.useState(null);
|
|
209771
|
+
React__default.useEffect(() => {
|
|
209772
|
+
setProvider(initialProvider);
|
|
209773
|
+
setPickedOpenaiVoice(null);
|
|
209774
|
+
setPickedGoogleVoice(null);
|
|
209775
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
209776
|
+
}, [mentorId, rawMentorSettings]);
|
|
209777
|
+
const effectiveOpenaiVoice = (_h = pickedOpenaiVoice !== null && pickedOpenaiVoice !== void 0 ? pickedOpenaiVoice : resolvedOpenaiVoice) !== null && _h !== void 0 ? _h : null;
|
|
209778
|
+
const effectiveGoogleVoice = (_j = pickedGoogleVoice !== null && pickedGoogleVoice !== void 0 ? pickedGoogleVoice : resolvedGoogleVoice) !== null && _j !== void 0 ? _j : null;
|
|
209779
|
+
const [editMentor, { isLoading: isSavingMentor }] = useEditMentorMutation();
|
|
209780
|
+
const isDisabled = isMentorSettingsLoading || isSavingMentor;
|
|
209781
|
+
const isDirty = provider !== initialProvider ||
|
|
209782
|
+
pickedOpenaiVoice != null ||
|
|
209783
|
+
pickedGoogleVoice != null;
|
|
209784
|
+
/**
|
|
209785
|
+
* Provider chips. We reuse the OpenAI / Google logos already shipped in
|
|
209786
|
+
* the host's static-root (see `getLLMProviderDetails` for the canonical
|
|
209787
|
+
* paths). Browser falls back to a Lucide globe — there's no vendor logo
|
|
209788
|
+
* for "device speech engine".
|
|
209789
|
+
*/
|
|
209790
|
+
const providerOptions = [
|
|
209791
|
+
{
|
|
209792
|
+
value: 'browser',
|
|
209793
|
+
label: labels.mentorVoice.providerOptions.browser.label,
|
|
209794
|
+
description: labels.mentorVoice.providerOptions.browser.description,
|
|
209795
|
+
logo: { type: 'icon', Icon: Globe },
|
|
209796
|
+
},
|
|
209797
|
+
{
|
|
209798
|
+
value: 'openai',
|
|
209799
|
+
label: labels.mentorVoice.providerOptions.openai.label,
|
|
209800
|
+
description: labels.mentorVoice.providerOptions.openai.description,
|
|
209801
|
+
logo: { type: 'image', src: '/llm-openai-provider-2.svg', alt: 'OpenAI' },
|
|
209802
|
+
},
|
|
209803
|
+
{
|
|
209804
|
+
value: 'google',
|
|
209805
|
+
label: labels.mentorVoice.providerOptions.google.label,
|
|
209806
|
+
description: labels.mentorVoice.providerOptions.google.description,
|
|
209807
|
+
logo: { type: 'image', src: '/llm-google-provider.svg', alt: 'Google' },
|
|
209808
|
+
},
|
|
209809
|
+
];
|
|
209810
|
+
const handleSaveVoice = async () => {
|
|
209811
|
+
try {
|
|
209812
|
+
const formData = { voice_provider: provider };
|
|
209813
|
+
// Only send a voice id when the user actually picked something this
|
|
209814
|
+
// session. If they didn't, leave the existing server-side value
|
|
209815
|
+
// alone — the backend interprets an absent field as "no change".
|
|
209816
|
+
if (provider === 'openai' && pickedOpenaiVoice) {
|
|
209817
|
+
formData.openai_voice = pickedOpenaiVoice.id;
|
|
209818
|
+
}
|
|
209819
|
+
if (provider === 'google' && pickedGoogleVoice) {
|
|
209820
|
+
formData.google_voice = pickedGoogleVoice.id;
|
|
209821
|
+
}
|
|
209822
|
+
await editMentor({
|
|
209823
|
+
mentor: mentorId,
|
|
209824
|
+
org: tenantKey,
|
|
209825
|
+
// @ts-expect-error userId is accepted at runtime
|
|
209826
|
+
userId: username,
|
|
209827
|
+
formData,
|
|
209828
|
+
}).unwrap();
|
|
209829
|
+
toast.success(labels.toasts.voiceSaved);
|
|
209830
|
+
}
|
|
209831
|
+
catch (error) {
|
|
209832
|
+
console.error('[AgentVoiceTab] save error', error);
|
|
209833
|
+
toast.error(labels.toasts.voiceError);
|
|
209834
|
+
}
|
|
209835
|
+
};
|
|
209836
|
+
const selectedVoice = provider === 'openai'
|
|
209837
|
+
? effectiveOpenaiVoice
|
|
209838
|
+
: provider === 'google'
|
|
209839
|
+
? effectiveGoogleVoice
|
|
209840
|
+
: null;
|
|
209841
|
+
const onSelectVoice = (voice) => {
|
|
209842
|
+
if (provider === 'openai')
|
|
209843
|
+
setPickedOpenaiVoice(voice);
|
|
209844
|
+
else if (provider === 'google')
|
|
209845
|
+
setPickedGoogleVoice(voice);
|
|
209846
|
+
};
|
|
209847
|
+
return (jsxs(Fragment$1, { children: [jsx("div", { className: "flex h-[73px] flex-shrink-0 items-center border-b border-gray-200 bg-white p-4 lg:block", children: jsxs("div", { children: [jsx("h3", { className: "mb-1 text-base font-medium text-gray-900", children: labels.header.title }), jsx("p", { className: "text-xs text-gray-600", children: labels.header.description })] }) }), jsx("div", { className: "flex-1 space-y-4 p-3 lg:p-4", style: { overflowY: 'auto', overflowX: 'hidden' }, "data-testid": "voice-tab-body", children: isMentorSettingsLoading ? (jsx("div", { className: "flex items-center justify-center py-12", "data-testid": "voice-tab-loading", children: jsx(Spinner, {}) })) : (jsxs(Tabs, { defaultValue: SUB_TAB_VALUES[defaultSubTab], className: "w-full", children: [jsxs(TabsList, { "aria-label": labels.header.title, "data-testid": "voice-sub-tabs", children: [jsx(TabsTrigger, { value: SUB_TAB_VALUES.voice, "data-testid": "voice-sub-tab-voice", children: labels.subTabs.voice }), jsx(TabsTrigger, { value: SUB_TAB_VALUES.callConfig, "data-testid": "voice-sub-tab-call-config", children: labels.subTabs.callConfig })] }), jsxs(TabsContent, { value: SUB_TAB_VALUES.voice, className: "space-y-4", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.mentorVoice.description }), jsx(WithFormPermissions, { name: "voice_provider",
|
|
209848
|
+
// @ts-expect-error permissions.field is opaque
|
|
209849
|
+
permissions: (_k = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _k === void 0 ? void 0 : _k.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: labels.mentorVoice.providerLabel }), jsx(FieldTooltip, { text: labels.mentorVoice.providerTooltip })] }), jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-3", role: "radiogroup", "aria-label": labels.mentorVoice.providerLabel, children: providerOptions.map((option) => {
|
|
209850
|
+
const isSelected = provider === option.value;
|
|
209851
|
+
const isDisabledOption = isDisabled || disabled;
|
|
209852
|
+
return (jsxs("button", { type: "button", role: "radio", "aria-checked": isSelected, "aria-label": option.label, disabled: isDisabledOption, "data-testid": `voice-provider-${option.value}`, "data-voice-provider": option.value, onClick: () => setProvider(option.value), className: cn('flex flex-col items-start gap-2 rounded-lg border-2 p-3 text-left transition-all hover:shadow-sm', isSelected
|
|
209853
|
+
? 'border-blue-500 bg-blue-50/40'
|
|
209854
|
+
: 'border-gray-200 bg-white hover:border-gray-300', isDisabledOption && 'cursor-not-allowed opacity-60'), children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center", children: option.logo.type === 'image' ? (jsx(Image$4, { src: option.logo.src, alt: option.logo.alt, width: 24, height: 24, className: "h-6 w-6 object-contain" })) : (jsx(option.logo.Icon, { className: "h-5 w-5 text-blue-600", "aria-hidden": "true" })) }), jsx("span", { className: "text-sm font-medium text-gray-900", children: option.label })] }), jsx("p", { className: "text-xs text-gray-500", children: option.description })] }, option.value));
|
|
209855
|
+
}) })] })) }), (provider === 'openai' || provider === 'google') && (jsx(WithFormPermissions, { name: provider === 'openai' ? 'openai_voice' : 'google_voice',
|
|
209856
|
+
// @ts-expect-error permissions.field is opaque
|
|
209857
|
+
permissions: (_l = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.permissions) === null || _l === void 0 ? void 0 : _l.field, enableRBAC: enableRBAC, children: ({ disabled }) => (jsxs("div", { className: "space-y-2", children: [jsx(Label, { className: "text-sm font-medium text-[#646464]", children: labels.mentorVoice.voicePickerLabel[provider] }), jsx(VoicePickerTrigger, { org: tenantKey, userId: username, provider: provider, selectedVoice: selectedVoice, onSelect: onSelectVoice, disabled: isDisabled || disabled, labels: labels.mentorVoice, modalTitle: `Select ${labels.mentorVoice.voicePickerLabel[provider]}`, modalDescription: "Search, browse, and listen to a sample before you pick.", testId: "mentor-voice-trigger" })] })) })), jsx("div", { className: "flex items-center justify-end border-t border-gray-100 pt-3", children: jsx(Button$1, { type: "button", onClick: handleSaveVoice, disabled: isDisabled || !isDirty, "data-testid": "voice-save-button", className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isSavingMentor
|
|
209858
|
+
? labels.mentorVoice.savingButton
|
|
209859
|
+
: labels.mentorVoice.saveButton }) })] }), jsxs(TabsContent, { value: SUB_TAB_VALUES.callConfig, className: "space-y-4", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.callConfig.description }), mentorId && username && tenantKey && (jsx(CallConfigSection, { org: tenantKey, userId: username, mentorId: mentorId, isDisabled: isDisabled, labels: labels.callConfig, voicePickerLabels: labels.mentorVoice, initialConfig: (_m = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.call_configuration) !== null && _m !== void 0 ? _m : null, renderPromptContent: renderPromptContent, toastLabels: {
|
|
209860
|
+
saved: labels.toasts.callConfigSaved,
|
|
209861
|
+
error: labels.toasts.callConfigError,
|
|
209862
|
+
} }))] })] })) })] }));
|
|
209863
|
+
}
|
|
209864
|
+
function FieldTooltip({ text }) {
|
|
209865
|
+
return (jsx(TooltipProvider, { delayDuration: 200, children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { type: "button", "aria-label": "More info", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { side: "top", align: "start", sideOffset: 6, collisionPadding: 16, className: "ibl-tooltip-content z-50 max-w-[300px]", children: jsx("p", { className: "text-xs leading-relaxed whitespace-normal", children: text }) })] }) }));
|
|
209866
|
+
}
|
|
209867
|
+
|
|
209868
|
+
/**
|
|
209869
|
+
* Display-only card for a single prompt. Mirrors the visual pattern
|
|
209870
|
+
* used by `AgentPromptsTab` (System Prompt / Proactive Prompt cards):
|
|
209871
|
+
* a header, a 📝-prefixed body, and Edit + Copy action buttons at the
|
|
209872
|
+
* bottom. "Edit" is wired by the parent (typically opens the shared
|
|
209873
|
+
* `EditPromptModal`); the new value is written back via the parent's
|
|
209874
|
+
* `onEdit` handler.
|
|
209875
|
+
*/
|
|
209876
|
+
function PromptCard$1({ label, placeholder, value, disabled, renderContent, onEdit, }) {
|
|
209877
|
+
const isEmpty = !value || value.trim() === '';
|
|
209878
|
+
return (jsxs("div", { className: "overflow-hidden rounded-lg bg-gray-50", "data-testid": "screensharing-prompt-card", children: [jsx("div", { className: "flex items-center justify-between border-b border-gray-200 p-[1.12rem]", children: jsx("div", { className: "flex items-center gap-2", children: jsx("h3", { className: "text-sm font-medium text-gray-900", children: label }) }) }), jsxs("div", { className: "flex items-start gap-2 p-4", children: [jsx("div", { className: "mt-1 flex-shrink-0", "aria-hidden": "true", children: "\uD83D\uDCDD" }), jsx("div", { className: "flex h-[180px] flex-1 flex-col", children: jsx("div", { className: "mb-4 flex-grow overflow-y-auto", tabIndex: 0, role: "region", "aria-label": `${label} content`, children: isEmpty ? (jsx("p", { className: "text-sm text-gray-400 italic", children: placeholder })) : (renderContent(value)) }) })] }), jsxs("div", { className: "flex w-full gap-2 px-4 pb-4", children: [jsxs(Button$1, { variant: "outline", size: "sm", className: "h-8 flex-1 py-5", disabled: disabled, onClick: onEdit, "aria-label": `Edit ${label}`, children: [jsx(SquarePen, { className: "mr-2 h-4 w-4" }), "Edit"] }), jsx(CopyButton, { text: value, disabled: disabled })] })] }));
|
|
209879
|
+
}
|
|
209880
|
+
|
|
209881
|
+
const AGENT_SCREENSHARE_TAB_LABELS = {
|
|
209882
|
+
header: {
|
|
209883
|
+
title: 'Screen Share',
|
|
209884
|
+
description: 'How your agent behaves when a user shares their screen during a voice call.',
|
|
209885
|
+
},
|
|
209886
|
+
disabledHint: 'Screen sharing is currently turned off for this agent. These prompts will be saved but only take effect once it’s turned on.',
|
|
209887
|
+
fields: {
|
|
209888
|
+
systemPrompt: {
|
|
209889
|
+
label: 'Instructions during screen sharing',
|
|
209890
|
+
placeholder: "Tell the agent how to behave while a user shares their screen. E.g. 'Walk through one step at a time and wait for the user to confirm before moving on.'",
|
|
209891
|
+
},
|
|
209892
|
+
proactivePrompt: {
|
|
209893
|
+
label: 'What the agent says when screen sharing starts',
|
|
209894
|
+
placeholder: "E.g. 'I can see your screen now — what would you like help with first?'",
|
|
209895
|
+
},
|
|
209896
|
+
},
|
|
209897
|
+
saveButton: 'Save',
|
|
209898
|
+
savingButton: 'Saving…',
|
|
209899
|
+
toasts: {
|
|
209900
|
+
saved: 'Screen sharing prompts saved',
|
|
209901
|
+
error: "Couldn't save screen sharing prompts",
|
|
209902
|
+
},
|
|
209903
|
+
};
|
|
209904
|
+
function resolveScreenShareTabLabels(override) {
|
|
209905
|
+
if (!override)
|
|
209906
|
+
return AGENT_SCREENSHARE_TAB_LABELS;
|
|
209907
|
+
return deepMerge(AGENT_SCREENSHARE_TAB_LABELS, override);
|
|
209908
|
+
}
|
|
209909
|
+
|
|
209910
|
+
/**
|
|
209911
|
+
* Standalone top-level tab for editing the two screen-sharing prompts
|
|
209912
|
+
* (`screensharing_system_prompt`, `screensharing_proactive_prompt`) that
|
|
209913
|
+
* live on the mentor's CallConfiguration.
|
|
209914
|
+
*
|
|
209915
|
+
* Visibility in the host's edit-mentor modal is the host's call — this
|
|
209916
|
+
* component only renders an in-place off-state hint when
|
|
209917
|
+
* `call_configuration.enable_video` is false, so users know prompts they
|
|
209918
|
+
* author here won't take effect until screen sharing is turned on
|
|
209919
|
+
* (toggle lives on the Settings tab).
|
|
209920
|
+
*/
|
|
209921
|
+
function AgentScreenShareTab({ labels: labelsOverride, renderPromptContent, tenantKey: tenantKeyProp, mentorId: mentorIdProp, username: usernameProp, }) {
|
|
209922
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
209923
|
+
const ctx = useAgentSettingsOptional();
|
|
209924
|
+
const tenantKey = (_a = tenantKeyProp !== null && tenantKeyProp !== void 0 ? tenantKeyProp : ctx === null || ctx === void 0 ? void 0 : ctx.tenantKey) !== null && _a !== void 0 ? _a : '';
|
|
209925
|
+
const mentorId = (_b = mentorIdProp !== null && mentorIdProp !== void 0 ? mentorIdProp : ctx === null || ctx === void 0 ? void 0 : ctx.mentorId) !== null && _b !== void 0 ? _b : '';
|
|
209926
|
+
const username = (_c = usernameProp !== null && usernameProp !== void 0 ? usernameProp : ctx === null || ctx === void 0 ? void 0 : ctx.username) !== null && _c !== void 0 ? _c : '';
|
|
209927
|
+
const labels = React__default.useMemo(() => resolveScreenShareTabLabels(labelsOverride), [labelsOverride]);
|
|
209928
|
+
const { data: rawMentorSettings, isLoading: isMentorSettingsLoading } = useGetMentorSettingsQuery({
|
|
209929
|
+
mentor: mentorId,
|
|
209930
|
+
org: tenantKey,
|
|
209931
|
+
// @ts-expect-error userId is accepted at runtime
|
|
209932
|
+
userId: username,
|
|
209933
|
+
}, { skip: !username || !mentorId || !tenantKey });
|
|
209934
|
+
const mentorSettings = rawMentorSettings;
|
|
209935
|
+
const inlineConfig = (_d = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.call_configuration) !== null && _d !== void 0 ? _d : null;
|
|
209936
|
+
const hasInline = inlineConfig !== null;
|
|
209937
|
+
// Fall back to the list endpoint only when we don't have an inline
|
|
209938
|
+
// call-config from the mentor-settings response.
|
|
209939
|
+
const { data: configs, isLoading: isLoadingList } = useGetCallConfigurationsQuery({ org: tenantKey, userId: username, mentor: mentorId }, { skip: hasInline || !tenantKey || !username || !mentorId });
|
|
209940
|
+
const existing = hasInline
|
|
209941
|
+
? inlineConfig
|
|
209942
|
+
: configs === null || configs === void 0 ? void 0 : configs[0];
|
|
209943
|
+
const initialSystemPrompt = (_e = existing === null || existing === void 0 ? void 0 : existing.screensharing_system_prompt) !== null && _e !== void 0 ? _e : '';
|
|
209944
|
+
const initialProactivePrompt = (_f = existing === null || existing === void 0 ? void 0 : existing.screensharing_proactive_prompt) !== null && _f !== void 0 ? _f : '';
|
|
209945
|
+
const enableVideo = (existing === null || existing === void 0 ? void 0 : existing.enable_video) === true;
|
|
209946
|
+
const [systemPrompt, setSystemPrompt] = React__default.useState(initialSystemPrompt);
|
|
209947
|
+
const [proactivePrompt, setProactivePrompt] = React__default.useState(initialProactivePrompt);
|
|
209948
|
+
const [selectedPrompt, setSelectedPrompt] = React__default.useState(null);
|
|
209949
|
+
// Rehydrate from server values whenever the underlying config changes.
|
|
209950
|
+
React__default.useEffect(() => {
|
|
209951
|
+
setSystemPrompt(initialSystemPrompt);
|
|
209952
|
+
setProactivePrompt(initialProactivePrompt);
|
|
209953
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
209954
|
+
}, [existing === null || existing === void 0 ? void 0 : existing.id, initialSystemPrompt, initialProactivePrompt]);
|
|
209955
|
+
const [createCallConfig, { isLoading: isCreating }] = useCreateCallConfigurationMutation();
|
|
209956
|
+
const [updateCallConfig, { isLoading: isUpdating }] = useUpdateCallConfigurationMutation();
|
|
209957
|
+
const isSaving = isCreating || isUpdating;
|
|
209958
|
+
const isLoading = isMentorSettingsLoading || isLoadingList;
|
|
209959
|
+
const isDirty = systemPrompt !== initialSystemPrompt || proactivePrompt !== initialProactivePrompt;
|
|
209960
|
+
const handleSave = async () => {
|
|
209961
|
+
try {
|
|
209962
|
+
const body = {
|
|
209963
|
+
screensharing_system_prompt: systemPrompt,
|
|
209964
|
+
screensharing_proactive_prompt: proactivePrompt,
|
|
209965
|
+
};
|
|
209966
|
+
if (existing === null || existing === void 0 ? void 0 : existing.id) {
|
|
209967
|
+
await updateCallConfig({
|
|
209968
|
+
org: tenantKey,
|
|
209969
|
+
userId: username,
|
|
209970
|
+
id: existing.id,
|
|
209971
|
+
requestBody: body,
|
|
209972
|
+
}).unwrap();
|
|
209973
|
+
}
|
|
209974
|
+
else {
|
|
209975
|
+
// No CallConfiguration row yet — POST one with these prompts.
|
|
209976
|
+
await createCallConfig({
|
|
209977
|
+
org: tenantKey,
|
|
209978
|
+
userId: username,
|
|
209979
|
+
requestBody: { ...body, mentor: mentorId },
|
|
209980
|
+
}).unwrap();
|
|
209981
|
+
}
|
|
209982
|
+
toast.success(labels.toasts.saved);
|
|
209983
|
+
}
|
|
209984
|
+
catch (error) {
|
|
209985
|
+
console.error('[AgentScreenShareTab] save error', error);
|
|
209986
|
+
toast.error(labels.toasts.error);
|
|
209987
|
+
}
|
|
209988
|
+
};
|
|
209989
|
+
const openEditor = (field) => {
|
|
209990
|
+
setSelectedPrompt({
|
|
209991
|
+
label: field === 'screensharing_system_prompt'
|
|
209992
|
+
? labels.fields.systemPrompt.label
|
|
209993
|
+
: labels.fields.proactivePrompt.label,
|
|
209994
|
+
isSystem: true,
|
|
209995
|
+
name: field,
|
|
209996
|
+
prompt: field === 'screensharing_system_prompt' ? systemPrompt : proactivePrompt,
|
|
209997
|
+
});
|
|
209998
|
+
};
|
|
209999
|
+
const renderContent = (text) => {
|
|
210000
|
+
if (renderPromptContent)
|
|
210001
|
+
return renderPromptContent(text);
|
|
210002
|
+
return jsx("p", { className: "text-sm whitespace-pre-wrap text-gray-700", children: text });
|
|
210003
|
+
};
|
|
210004
|
+
return (jsxs(Fragment$1, { children: [jsx("div", { className: "flex h-[73px] flex-shrink-0 items-center border-b border-gray-200 bg-white p-4 lg:block", children: jsxs("div", { children: [jsx("h3", { className: "mb-1 text-base font-medium text-gray-900", children: labels.header.title }), jsx("p", { className: "text-xs text-gray-600", children: labels.header.description })] }) }), jsx("div", { className: "flex-1 space-y-4 p-3 lg:p-4", style: { overflowY: 'auto', overflowX: 'hidden' }, "data-testid": "screenshare-tab-body", children: isLoading ? (jsx("div", { className: "flex items-center justify-center py-12", "data-testid": "screenshare-tab-loading", children: jsx(Spinner, {}) })) : (jsxs(Fragment$1, { children: [!enableVideo && (jsx("div", { className: "rounded-md border border-amber-200 bg-amber-50 p-3 text-xs text-amber-800", "data-testid": "screenshare-disabled-hint", role: "status", children: labels.disabledHint })), jsxs("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [jsx(PromptCard$1, { label: labels.fields.systemPrompt.label, placeholder: labels.fields.systemPrompt.placeholder, value: systemPrompt, disabled: isSaving, renderContent: renderContent, onEdit: () => openEditor('screensharing_system_prompt') }), jsx(PromptCard$1, { label: labels.fields.proactivePrompt.label, placeholder: labels.fields.proactivePrompt.placeholder, value: proactivePrompt, disabled: isSaving, renderContent: renderContent, onEdit: () => openEditor('screensharing_proactive_prompt') })] }), jsx("div", { className: "flex items-center justify-end border-t border-gray-100 pt-3", children: jsx("button", { type: "button", onClick: handleSave, disabled: isSaving || !isDirty, "data-testid": "screenshare-save-button", className: "inline-flex items-center gap-2 rounded-md bg-gradient-to-r from-[#2563EB] to-[#93C5FD] px-4 py-2 text-sm font-medium text-white hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50", children: isSaving ? labels.savingButton : labels.saveButton }) }), selectedPrompt && (
|
|
210005
|
+
// EditPromptModal calls strict `useAgentSettings()` to read
|
|
210006
|
+
// `tenantKey` / `username` / `executeGatedAction`. The host
|
|
210007
|
+
// app may not have wrapped this tab in `<AgentSettingsProvider>`
|
|
210008
|
+
// (older integrations pass identity via props), so we wrap
|
|
210009
|
+
// the modal here with whatever we resolved — props,
|
|
210010
|
+
// surrounding context, or empty fallbacks. When the host
|
|
210011
|
+
// *did* wrap, this re-provider just re-emits the same
|
|
210012
|
+
// values (idempotent).
|
|
210013
|
+
jsx(AgentSettingsProvider, { tenantKey: tenantKey, mentorId: mentorId, username: username, enableRBAC: (_g = ctx === null || ctx === void 0 ? void 0 : ctx.enableRBAC) !== null && _g !== void 0 ? _g : false, rbacPermissions: ctx === null || ctx === void 0 ? void 0 : ctx.rbacPermissions, executeGatedAction: ctx === null || ctx === void 0 ? void 0 : ctx.executeGatedAction, visibilityOptions: ctx === null || ctx === void 0 ? void 0 : ctx.visibilityOptions, children: jsx(EditPromptModal$1, { isOpen: true, onClose: () => setSelectedPrompt(null), selectedPrompt: selectedPrompt, isEditing: isSaving, handleSave: (prompt, values) => {
|
|
210014
|
+
if (prompt.name === 'screensharing_system_prompt') {
|
|
210015
|
+
setSystemPrompt(values.prompt);
|
|
210016
|
+
}
|
|
210017
|
+
else if (prompt.name === 'screensharing_proactive_prompt') {
|
|
210018
|
+
setProactivePrompt(values.prompt);
|
|
210019
|
+
}
|
|
210020
|
+
setSelectedPrompt(null);
|
|
210021
|
+
} }) }))] })) })] }));
|
|
210022
|
+
}
|
|
210023
|
+
|
|
209137
210024
|
function ApiKeyModal({ isOpen, onClose, apiKey, labels }) {
|
|
209138
210025
|
const { copy, status } = useCopyToClipboard(800);
|
|
209139
210026
|
const Icon = status === 'success' ? Check : Copy;
|
|
@@ -268725,5 +269612,5 @@ var index_es = /*#__PURE__*/Object.freeze({
|
|
|
268725
269612
|
vectorsRatio: vectorsRatio
|
|
268726
269613
|
});
|
|
268727
269614
|
|
|
268728
|
-
export { AGENT_ACCESS_TAB_LABELS, AGENT_API_TAB_LABELS, AGENT_DATASETS_TAB_LABELS, AGENT_DISCLAIMERS_TAB_LABELS, AGENT_EMBED_TAB_LABELS, AGENT_HISTORY_TAB_LABELS, AGENT_LLM_TAB_LABELS, AGENT_MEMORY_TAB_LABELS, AGENT_PICKER_LABELS, AGENT_PRIVACY_TAB_LABELS, AGENT_PROMPTS_TAB_LABELS, AGENT_SAFETY_TAB_LABELS, AGENT_SEARCH_LABELS, AGENT_SETTINGS_TAB_LABELS, AGENT_TASKS_TAB_LABELS, AGENT_TOOLS_TAB_LABELS, Account, AgentAccessTab, AgentApiTab, AgentCard, AgentDatasetsTab, AgentDisclaimersTab, AgentEmbedTab, AgentEmptyState, AgentHistoryTab, AgentLLMTab, AgentMemoryTab, AgentPrivacyTab, AgentPromptsTab, AgentSafetyTab, AgentSearch, AgentSearchFilters, AgentSearchInput, AgentSettingsProvider, AgentSettingsTab, AgentTasksTab, AgentToolsTab, AppSidebar, Chat, ClientErrorPage, ConversationStarters$1 as ConversationStarters, CopyButton, CopyMentorModal, CourseBox, CourseContentLayout, CourseContentTabPage, CreatePathwayModal, CreateProjectModal, CredentialDetailModal, CredentialMiniBox, DeleteMentorModal, DeleteProjectModal, EMPTY_PROGRAM_SETTINGS_FORM, EdxIframe, ErrorPage, GreetingMethod, McpTab, MediaBox, MentorSelectionGrid, NavBar, OrganizationTab, PathwayDetailModal, ProfileInfoCards, ProfileTabs, ProgramDetailModal, ProjectsSidebarDropdown, RenameProjectModal, SidebarInset, SidebarProvider, SidebarTrigger, SsoLogin, StarButton, UserProfileDropdown, UserProfileModal, formatDateString, getLLMProviderDetails, initializeLocalStorageWithObject, resolveAgentPickerLabels, resolveAgentSearchLabels, resolveSettingsTabLabels, useAgentSearch, useAgentSearchWithPagination, useAgentSettings, useAgentStar, useGetChatDetails, useSidebar, useTimeTracker };
|
|
269615
|
+
export { AGENT_ACCESS_TAB_LABELS, AGENT_API_TAB_LABELS, AGENT_DATASETS_TAB_LABELS, AGENT_DISCLAIMERS_TAB_LABELS, AGENT_EMBED_TAB_LABELS, AGENT_HISTORY_TAB_LABELS, AGENT_LLM_TAB_LABELS, AGENT_MEMORY_TAB_LABELS, AGENT_PICKER_LABELS, AGENT_PRIVACY_TAB_LABELS, AGENT_PROMPTS_TAB_LABELS, AGENT_SAFETY_TAB_LABELS, AGENT_SCREENSHARE_TAB_LABELS, AGENT_SEARCH_LABELS, AGENT_SETTINGS_TAB_LABELS, AGENT_TASKS_TAB_LABELS, AGENT_TOOLS_TAB_LABELS, AGENT_VOICE_TAB_LABELS, Account, AgentAccessTab, AgentApiTab, AgentCard, AgentDatasetsTab, AgentDisclaimersTab, AgentEmbedTab, AgentEmptyState, AgentHistoryTab, AgentLLMTab, AgentMemoryTab, AgentPrivacyTab, AgentPromptsTab, AgentSafetyTab, AgentScreenShareTab, AgentSearch, AgentSearchFilters, AgentSearchInput, AgentSettingsProvider, AgentSettingsTab, AgentTasksTab, AgentToolsTab, AgentVoiceTab, AppSidebar, Chat, ClientErrorPage, ConversationStarters$1 as ConversationStarters, CopyButton, CopyMentorModal, CourseBox, CourseContentLayout, CourseContentTabPage, CreatePathwayModal, CreateProjectModal, CredentialDetailModal, CredentialMiniBox, DeleteMentorModal, DeleteProjectModal, EMPTY_PROGRAM_SETTINGS_FORM, EdxIframe, ErrorPage, GreetingMethod, McpTab, MediaBox, MentorSelectionGrid, NavBar, OrganizationTab, PathwayDetailModal, ProfileInfoCards, ProfileTabs, ProgramDetailModal, ProjectsSidebarDropdown, RenameProjectModal, SidebarInset, SidebarProvider, SidebarTrigger, SsoLogin, StarButton, UserProfileDropdown, UserProfileModal, formatDateString, getLLMProviderDetails, initializeLocalStorageWithObject, resolveAgentPickerLabels, resolveAgentSearchLabels, resolveSettingsTabLabels, useAgentSearch, useAgentSearchWithPagination, useAgentSettings, useAgentStar, useGetChatDetails, useSidebar, useTimeTracker };
|
|
268729
269616
|
//# sourceMappingURL=index.esm.js.map
|