@iblai/iblai-js 2.2.8 → 2.2.10

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.
@@ -1,9 +1,9 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import React__default, { useState, useEffect, forwardRef, createElement as createElement$3, useLayoutEffect, createContext, useContext, useMemo, useCallback, useReducer, useRef, useImperativeHandle, isValidElement, Children, PureComponent, cloneElement, Component as Component$1, useId as useId$2, useDebugValue, lazy, Suspense } from 'react';
3
+ import React__default, { useState, useEffect, forwardRef, createElement as createElement$3, useLayoutEffect, createContext, useContext, useMemo, useReducer, useRef, useImperativeHandle, useCallback, isValidElement, Children, PureComponent, cloneElement, Component as Component$1, useId as useId$2, useDebugValue, lazy, Suspense } from 'react';
4
4
  import * as dataLayer from '@iblai/data-layer';
5
- 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, useGetLearnerDetailsQuery, useGetUserEnrolledCoursesQuery, useGetUserEnrolledProgramsQuery, useGetUserCatalogPathwaysQuery, useGetUsersAsAssertionsQuery, useGetUserEarnedSkillsQuery, useGetUserReportedSkillsQuery, useGetUserDesiredSkillsQuery, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, 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, useGetRbacActionsDefinitionQuery, useGetRbacResourceDiscoveryQuery, useGetRbacResourceListQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useGetApplicationFormsQuery, useGetApplicationFormDetailQuery, useCreateApplicationFormMutation, useUpdateApplicationFormMutation, useGetApplicationAdminDetailQuery, useInviteApplicationCandidateMutation, useLazyGetApplicationAttachmentFileQuery, useCreateApplicationWaiverMutation, useDeleteApplicationWaiverMutation, useSubmitApplicationOverrideMutation, useUpdateApplicationPlacementMutation, useDeleteApplicationCourseAssignmentMutation, useCreateApplicationNoteMutation, useUpdateApplicationNoteMutation, useDeleteApplicationNoteMutation, useTransitionApplicationMutation, useLinkApplicationCandidateMutation, useCreateApplicationPlacementsMutation, useGetCustomMentorsQuery, useCreateApplicationCourseAssignmentsMutation, useGetApplicationBlocksQuery, useDeleteApplicationBlockMutation, useGetApplicationsPipelineStatsQuery, useGetApplicationsPipelineQuery, useDeleteApiKeyMutation, useGetApiKeysQuery, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useUpdateTenantMetadataMutation, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useStarMentorMutation, useUnstarMentorMutation, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, LOGO_ENDPOINTS, useCreateEvalDatasetMutation, useAddEvalDatasetItemsMutation, useUploadEvalDatasetCsvMutation, useDeleteEvalDatasetItemMutation, useListEvalDatasetItemsQuery, evalTotalPages, useListEvalDatasetsQuery, useGetUserProjectsQuery, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetTenantChatPrivacyConfigQuery as useGetTenantChatPrivacyConfigQuery$1, useGetCallConfigurationsQuery, useCreateCallConfigurationMutation, useUpdateCallConfigurationMutation, chatPrivacyApiSlice, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetVoicesQuery, useGetVoiceQuery, useGetMentorGraderConfigurationQuery, useListGraderCriteriaQuery, useCreateMentorGraderConfigurationMutation, useUpdateMentorGraderConfigurationMutation, useCreateGraderCriterionMutation, useUpdateGraderCriterionMutation, useDeleteGraderCriterionMutation, useGetMentorPublicSettingsQuery, useGetChatHistoryFilterQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useGetSupportTicketsQuery, useGetSupportTicketMessagesQuery, useCreateSupportTicketMessageMutation, usePatchSupportTicketMutation, useCloseSupportTicketMutation, useCreateLtiMentorMutation, useUpdateLtiMentorMutation, useGetLtiMentorsQuery, useCreateLtiKeyMutation, useUpdateLtiKeyMutation, useDeleteLtiKeyMutation, useGetLtiKeysQuery, useCreateLtiToolMutation, useUpdateLtiToolMutation, useGetLtiToolsQuery, useGetPlatformInfoQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStartEvalRunMutation, useEvaluateEvalRunMutation, useGetEvalRunQuery, useDeleteEvalScoreMutation, useListEvalRunJudgesQuery, useCreateEvalScoreMutation, useDeleteEvalRunMutation, useExportEvalRunMutation, useListEvalRunsQuery, useLazyGetEvalRunQuery, evaluationsApiSlice, EVALUATIONS_TAGS, useGetPersonnalizedMentorsQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetPublicMentorsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
6
- import { getInitials, useTenantMetadata, WithPermissions, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, selectNumberOfActiveChatMessages, useUsername, 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, chatActions, WithFormPermissions, useTenantContext, TimeTracker, advancedTabsProperties, defaultSessionIds, pickWritableFields, ANONYMOUS_USERNAME as ANONYMOUS_USERNAME$3, 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';
5
+ 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, useGetLearnerDetailsQuery, useGetUserEnrolledCoursesQuery, useGetUserEnrolledProgramsQuery, useGetUserCatalogPathwaysQuery, useGetUsersAsAssertionsQuery, useGetUserEarnedSkillsQuery, useGetUserReportedSkillsQuery, useGetUserDesiredSkillsQuery, useCreateGlobalMemoryMutation, useGetMemsearchStatusQuery, useGetUserMemorySettingsQuery, useUpdateUserMemorySettingsMutation, useGetGlobalMemoriesQuery, useDeleteGlobalMemoryMutation, useInviteUserMutation, usePlatformInvitationsQuery, useCreateCatalogInvitationCourseBulkMutation, useGetCatalogInvitationsCourseQuery, useLazyPlatformUsersQuery, useLazyPlatformUserGroupsQuery, useGetPersonnalizedSearchQuery, useCreateCatalogInvitationProgramBulkMutation, useGetCatalogInvitationsProgramQuery, 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, useGetRbacActionsDefinitionQuery, useGetRbacResourceDiscoveryQuery, useGetRbacResourceListQuery, useGetRbacPoliciesQuery, useCreateRbacPolicyMutation, useUpdateRbacPolicyMutation, useDeleteRbacPolicyMutation, useGetRbacPolicyDetailsQuery, useGetWatchedGroupsQuery, useCreateWatchedGroupMutation, useUpdateWatchedGroupMutation, useDeleteWatchedGroupMutation, useAddWatchedUserMutation, useRemoveWatchedUserMutation, useAddWatcherMutation, useUpdateWatcherMutation, useDeleteWatcherMutation, useGetWatchedUsersQuery, useGetWatchersQuery, WATCHER_NOTIFICATION_EVENTS, WATCHER_NOTIFICATION_EVENT_LABELS, useGetApplicationFormsQuery, useGetApplicationFormDetailQuery, useCreateApplicationFormMutation, useUpdateApplicationFormMutation, useGetApplicationAdminDetailQuery, useInviteApplicationCandidateMutation, useLazyGetApplicationAttachmentFileQuery, useCreateApplicationWaiverMutation, useDeleteApplicationWaiverMutation, useSubmitApplicationOverrideMutation, useUpdateApplicationPlacementMutation, useDeleteApplicationCourseAssignmentMutation, useCreateApplicationNoteMutation, useUpdateApplicationNoteMutation, useDeleteApplicationNoteMutation, useTransitionApplicationMutation, useLinkApplicationCandidateMutation, useCreateApplicationPlacementsMutation, useGetCustomMentorsQuery, useCreateApplicationCourseAssignmentsMutation, useGetApplicationBlocksQuery, useDeleteApplicationBlockMutation, useGetApplicationsPipelineStatsQuery, useGetApplicationsPipelineQuery, useDeleteApiKeyMutation, useGetApiKeysQuery, useCreateApiKeyMutation, useCreateLLMCredentialMutation, useGetCredentialsSchemaQuery, useGetMaskedLLMCredentialsQuery, useGetLlmsQuery, useDeleteIntegrationCredentialMutation, useDeleteCredentialMutation, useCreateIntegrationCredentialMutation, useGetIntegrationCredentialsSchemaQuery, useGetMaskedIntegrationCredentialsQuery, useGetAccountBillingInfoQuery, useUpdateAutoRechargeInfoMutation, useTriggerAutoRechargeMutation, useCreateStripeCustomerPortalMutation, useSetPlatformConfigurationsMutation, useGetPlatformConfigurationsQuery, useUpdatePlatformMembershipMutation, useGetPlatformMembershipQuery, useGetCustomDomainsQuery, useCreateCustomDomainMutation, useDeleteCustomDomainMutation, useGetStudentMentorCreationStatusQuery, useSetStudentMentorCreationStatusMutation, coreApiSlice, recommendationPromptTypeEnum, useGetRecommendedPromptsListQuery, useCreateRecommendedPromptMutation, useUpdateRecommendedPromptMutation, useDeleteRecommendedPromptMutation, useLazyGetPublicPlatformImageAssetFileUrlQuery, useUpdateTenantMetadataMutation, useCreatePlatformImageAssetMutation, useGetProviderConfigQuery, useCreateProviderConfigMutation, useDeleteProviderConfigMutation, useGetExternalMappingQuery, useGetCredentialsListQuery, useCreateExternalMappingMutation, useDeleteExternalMappingMutation, useGetMemsearchConfigQuery, useUpdateMemsearchConfigMutation, useGetStripeConnectStatusQuery, useStartStripeConnectOnboardingMutation, useLazyGetStripeConnectDashboardQuery, useGetAiSearchMentorsQuery, useListPaywallsQuery, useListPricesQuery, useCreatePriceMutation, useUpdatePriceMutation, useDeletePriceMutation, useGetPaywallConfigQuery, useEnablePaywallMutation, useUpdatePaywallMutation, useLazyGetCourseMetaDataQuery, useLazyGetCourseCompletionOutlinesQuery, useLazyGetCourseEligibilityQuery, useLazyGetEdxSSOTokenQuery, useCreateCourseEnrollmentMutation, useCreateStripeCheckoutSessionMutation, useLazyGetCourseProgressQuery, useLazyGetCourseCompletionQuery, useUpdateExamAttemptMutation, useStartExamMutation, useLazyGetExamInfoQuery, useGetAgentSkillResourcesQuery, useCreateAgentSkillResourceMutation, useUpdateAgentSkillResourceMutation, useUploadAgentSkillResourceAssetMutation, useDeleteAgentSkillResourceMutation, useGetAgentSkillsQuery, useGetMentorSkillAssignmentsQuery, useCreateMentorSkillAssignmentMutation, useUpdateMentorSkillAssignmentMutation, useDeleteMentorSkillAssignmentMutation, useCreateAgentSkillMutation, useUpdateAgentSkillMutation, useDeleteAgentSkillMutation, resolveEffectiveAgentSkills, filterSlashSkills, useUpdateUserProjectMutation, useGetTrainingDocumentsQuery, useGetVectorDocumentsQuery, useGetMentorMemoriesListQuery, useGetMemoryCategoriesAdminQuery, useDeleteMentorMemoryMutation, useUpdateMentorMemoryMutation, useCreateMentorMemoryMutation, useLazyGetConnectedServiceAuthUrlQuery, useStarMentorMutation, useUnstarMentorMutation, useCreateUserProjectMutation, useDeleteUserProjectMutation, useGetUserProjectDetailsQuery, useEditTrainingDocumentMutation, useAddTrainingDocumentMutation, useLazyGetCredentialsQuery, useGetMentorSettingsQuery, useEditMentorMutation, useUploadLightLogoMutation, useUploadDarkLogoMutation, useUpdatePlatformInfoMutation, LOGO_ENDPOINTS, useCreateEvalDatasetMutation, useAddEvalDatasetItemsMutation, useUploadEvalDatasetCsvMutation, useDeleteEvalDatasetItemMutation, useListEvalDatasetItemsQuery, evalTotalPages, useListEvalDatasetsQuery, useGetUserProjectsQuery, useCreateSessionIdMutation, useGetMentorCategoriesQuery, useGetTenantChatPrivacyConfigQuery as useGetTenantChatPrivacyConfigQuery$1, useGetCallConfigurationsQuery, useCreateCallConfigurationMutation, useUpdateCallConfigurationMutation, chatPrivacyApiSlice, useDeleteMentorMutation, useForkMentorMutation, useGetToolsQuery, useLazyGetMCPServersQuery, useOauthFindMutation, useLazyStartOAuthFlowQuery, useCreateMCPServerMutation, usePartialUpdateMCPServerMutation, useCreateMCPServerConnectionMutation, usePatchMCPServerConnectionMutation, useGetConnectedServicesQuery, useGetMCPServersQuery, useGetMCPServerConnectionsQuery, useUpdateMCPServerMutation, useDeleteMCPServerMutation, useEditMentorJsonMutation, useDisconnectServiceMutation, useGetPromptCategoriesQuery, PRIVACY_ACTIONS, PRIVACY_ENTITY_TYPES, useGetVoicesQuery, useGetVoiceQuery, isBaseAgentMentor, useGetMentorGraderConfigurationQuery, useListGraderCriteriaQuery, useCreateMentorGraderConfigurationMutation, useUpdateMentorGraderConfigurationMutation, useCreateGraderCriterionMutation, useUpdateGraderCriterionMutation, useDeleteGraderCriterionMutation, useGetMentorPublicSettingsQuery, useGetChatHistoryFilterQuery, useGetChatHistoryQuery, useGetMentorSummariesQuery, useGetConversationMemoriesQuery, useGetSupportTicketsQuery, useGetSupportTicketMessagesQuery, useCreateSupportTicketMessageMutation, usePatchSupportTicketMutation, useCloseSupportTicketMutation, useCreateLtiMentorMutation, useUpdateLtiMentorMutation, useGetLtiMentorsQuery, useCreateLtiKeyMutation, useUpdateLtiKeyMutation, useDeleteLtiKeyMutation, useGetLtiKeysQuery, useCreateLtiToolMutation, useUpdateLtiToolMutation, useGetLtiToolsQuery, useGetPlatformInfoQuery, useCreatePromptMutation, useGetPromptsSearchQuery, useUpdatePromptMutation, useCreateRedirectTokenMutation, useGetShareableLinkQuery, useCreateShareableLinkMutation, useUpdateShareableLinkMutation, useCreateDisclaimerMutation, useUpdateDisclaimerMutation, useGetDisclaimersQuery, useUpdateRbacMentorAccessMutation, useGetRbacMentorAccessListQuery, useStartEvalRunMutation, useEvaluateEvalRunMutation, useGetEvalRunQuery, useDeleteEvalScoreMutation, useListEvalRunJudgesQuery, useCreateEvalScoreMutation, useDeleteEvalRunMutation, useExportEvalRunMutation, useListEvalRunsQuery, useLazyGetEvalRunQuery, evaluationsApiSlice, EVALUATIONS_TAGS, useGetPersonnalizedMentorsQuery, useCreateCallCredentialsMutation, useGetGuidedPromptsQuery, useUpdateChatSessionSharedMutation, useUpdateMessageFeedbackMutation, useLazyGetPromptsSearchQuery, useLazyGetGuidedPromptsQuery, useGetPublicMentorsQuery, useGetPeriodicAgentsQuery, useGetPeriodicAgentLogsListQuery, useCreatePeriodicAgentMutation, useDeletePeriodicAgentMutation, useDeletePromptMutation, useDeleteTrainingDocumentMutation, useGetTrainingDocumentRetrainScheduleQuery, useCreateTrainingDocumentRetrainScheduleMutation, useCreateMemoryCategoryMutation, useUpdateMemoryCategoryMutation, useDeleteMemoryCategoryMutation, useUpdateArtifactMutation, useLazyGetArtifactVersionQuery, useLazyListArtifactVersionsQuery, useSetCurrentVersionMutation, useListArtifactVersionsQuery, useLazyGetArtifactQuery, useLazyListArtifactsQuery, useEditSessionMutation } from '@iblai/data-layer';
6
+ import { getInitials, useTenantMetadata, WithPermissions, useStripeUpgrade, openExternalUrl, CHAT_AREA_SIZE, isAlphaNumeric32, checkRbacPermission, selectNumberOfActiveChatMessages, useUsername, selectStreaming, isLoggedIn, TOOLS, hasRemoteAiConfig, isSafariBrowser, useShowAttachment, useShowVoiceCall, useShowVoiceRecorder, useMentorSettings, selectShowingSharedChat, selectRbacPermissions, useShowFreeTrialDialog, useEmbedMode, chatInputSliceSelectors, useResponsive, useAccessingPublicRoute, useVisitingTenant, useModelFileUploadCapabilities, useChatFileUpload, useVoiceChat, selectAttachedFiles, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, removeFile, chatInputSliceActions, chatActions, WithFormPermissions, useTenantContext, TimeTracker, advancedTabsProperties, defaultSessionIds, pickWritableFields, ANONYMOUS_USERNAME as ANONYMOUS_USERNAME$3, 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';
7
7
  import { useDispatch, useSelector } from 'react-redux';
8
8
  import { toast } from 'sonner';
9
9
  import { useSearchParams, useParams, useRouter, usePathname } from 'next/navigation';
@@ -98069,118 +98069,6 @@ var gradebookGradebookTab$3 = {
98069
98069
  previousPage: "Previous",
98070
98070
  nextPage: "Next"
98071
98071
  };
98072
- var graderTabLabels$3 = {
98073
- header: {
98074
- title: "Grader",
98075
- description: "Set up how your agent grades work against a rubric you define."
98076
- },
98077
- capability: {
98078
- title: "Grading",
98079
- description: "Let your agent grade work. When this is on, the agent scores what people submit against the rubric you set up below and shares the result as feedback — great for essays, projects, and practice exercises.",
98080
- offHint: "Turn it on to write grading instructions and build your rubric. Anything you set up here is kept safe if you later turn it off."
98081
- },
98082
- subTabs: {
98083
- setup: "Grading setup",
98084
- rubric: "Rubric"
98085
- },
98086
- denied: {
98087
- title: "No access to grading settings",
98088
- description: "You don't have permission to view this agent's grading setup. Ask an administrator for access."
98089
- },
98090
- warnings: {
98091
- noConfig: "Grading is on but not set up yet — the agent will fail when asked to grade. Save your grading instructions in Grading setup to finish.",
98092
- noCriteria: "Grading is on but the rubric is empty — the agent will fail when asked to grade. Add at least one criterion in the Rubric tab."
98093
- },
98094
- config: {
98095
- sectionTitle: "Grading setup",
98096
- gradingMode: {
98097
- label: "What gets graded",
98098
- options: {
98099
- submission: "A submission",
98100
- conversation: "The conversation"
98101
- },
98102
- help: {
98103
- submission: "The agent grades a piece of work the person hands in, like an essay or answer.",
98104
- conversation: "The agent grades how the whole conversation went."
98105
- }
98106
- },
98107
- feedbackMode: {
98108
- label: "Feedback shared with the person",
98109
- options: {
98110
- overall: "Overall feedback only",
98111
- perCriteria: "Feedback per criterion",
98112
- both: "Overall + per criterion"
98113
- },
98114
- help: "The overall score is always calculated — this only controls how much detail is shared back."
98115
- },
98116
- instructions: {
98117
- label: "Grading instructions",
98118
- placeholder: "Describe what's being graded and anything the grader should know beyond the rubric. E.g. 'You are grading a 500-word persuasive essay on climate policy written by a high-school student. Be encouraging but honest.'",
98119
- help: "Required. This is the context the agent uses every time it grades."
98120
- },
98121
- saveButton: "Save",
98122
- savingButton: "Saving…"
98123
- },
98124
- criteria: {
98125
- sectionTitle: "Rubric",
98126
- description: "Each row is one thing the agent looks for and how many points it is worth. The overall score is points earned out of the total.",
98127
- needsConfigHint: "Save your grading setup first, then add rubric criteria here.",
98128
- emptyState: "No criteria yet. Add your first one — for example \"Clarity\", 10 points.",
98129
- addButton: "Add criterion",
98130
- columns: {
98131
- name: "Name",
98132
- criteria: "Criteria",
98133
- points: "Points"
98134
- },
98135
- actionsAria: "Actions for {name}",
98136
- edit: "Edit",
98137
- "delete": "Delete",
98138
- totalPoints: "Total possible points: {total}",
98139
- scoreHint: "Overall score = points earned ÷ {total}.",
98140
- lastCriterionHint: "A rubric needs at least one criterion — add another before removing this one.",
98141
- modal: {
98142
- addTitle: "Add criterion",
98143
- editTitle: "Edit criterion",
98144
- name: {
98145
- label: "Name",
98146
- placeholder: "e.g. Clarity",
98147
- required: "Name is required"
98148
- },
98149
- criteria: {
98150
- label: "Criteria",
98151
- placeholder: "e.g. The argument is easy to follow and each paragraph makes one clear point.",
98152
- required: "Criteria is required"
98153
- },
98154
- points: {
98155
- label: "Points",
98156
- placeholder: "10",
98157
- positive: "Points must be a positive number"
98158
- },
98159
- save: "Save",
98160
- saving: "Saving…",
98161
- cancel: "Cancel"
98162
- },
98163
- deleteModal: {
98164
- title: "Delete criterion",
98165
- confirmationPrefix: "Are you sure you want to remove",
98166
- confirmationSuffix: " from the rubric?",
98167
- cancel: "Cancel",
98168
- "delete": "Delete",
98169
- deleting: "Deleting…"
98170
- }
98171
- },
98172
- toasts: {
98173
- toggleOn: "Grading turned on",
98174
- toggleOff: "Grading turned off — your rubric is kept for next time",
98175
- toggleError: "Couldn't update grading",
98176
- configSaved: "Grading setup saved",
98177
- configError: "Couldn't save grading setup",
98178
- criterionAdded: "Criterion added",
98179
- criterionUpdated: "Criterion updated",
98180
- criterionDeleted: "Criterion deleted",
98181
- criterionError: "Couldn't update the rubric"
98182
- }
98183
- };
98184
98072
  var careerExperienceDialog$3 = {
98185
98073
  pleaseSelectACompany: "Please select a company",
98186
98074
  endDateCannotBeBeforeStartDate: "End date cannot be before start date",
@@ -98334,6 +98222,9 @@ var chatInputFormInsideButtons$3 = {
98334
98222
  studyMode: "Study Mode",
98335
98223
  deepResearch: "Deep Research",
98336
98224
  memory: "Memory",
98225
+ cowork: "Cowork",
98226
+ coworkNeedsBackend: "Enable a large local model or sign in to a workspace to use Cowork.",
98227
+ coworkModelTooSmall: "Your local model is too small for Cowork. Pick a model of at least 14GB in Local Models.",
98337
98228
  moreOptions: "More options"
98338
98229
  };
98339
98230
  var chatInputFormMemoryMenu$3 = {
@@ -98491,7 +98382,57 @@ var clawSandboxAgentSkills$3 = {
98491
98382
  fieldVersionPlaceholder: "e.g. 1.0.0",
98492
98383
  fieldDescription: "Description",
98493
98384
  fieldDescriptionPlaceholder: "e.g. Search the web for information",
98494
- fieldInstruction: "Instruction"
98385
+ fieldInstruction: "Instruction",
98386
+ sessionNote: "Skills added or removed here apply to new chat sessions only. Edits to a skill's instructions apply immediately, including in conversations already in progress.",
98387
+ effectiveHeading: "This agent's skills",
98388
+ catalogHeading: "Available skills",
98389
+ noEffectiveSkills: "No skills enabled for this agent yet. Add one from the available skills below.",
98390
+ addToAgent: "Add",
98391
+ addToAgentLabel: "Add {name} to this agent",
98392
+ removeFromAgent: "Remove from agent",
98393
+ skillAdded: "{name} added",
98394
+ skillRemoved: "{name} removed",
98395
+ featuredBadge: "Featured",
98396
+ nativeBadge: "Native",
98397
+ privateBadge: "Only this agent",
98398
+ fieldCategory: "Category",
98399
+ fieldCategoryPlaceholder: "e.g. web, code, data",
98400
+ privateToAgent: "Only this agent",
98401
+ privateToAgentHint: "Private skills are available to this agent only and take precedence over platform skills with the same slug.",
98402
+ instructionHint: "The playbook the agent follows when the skill is used. Edits apply immediately, including in conversations already in progress.",
98403
+ filesHint: "Optional resources the agent can use with this skill. References and scripts are text files; assets are uploaded files.",
98404
+ filesAfterCreateHint: "You can attach resources to this skill after creating it (reopen it with Edit).",
98405
+ noFiles: "No resources attached yet.",
98406
+ loadingFiles: "Loading resources...",
98407
+ fileTypeLabel: "Type",
98408
+ fileTypeReference: "Reference",
98409
+ fileTypeScript: "Script",
98410
+ fileTypeAsset: "Asset",
98411
+ fileNameLabel: "File name",
98412
+ fileNamePlaceholder: "e.g. rubric.md",
98413
+ fileContentLabel: "Content",
98414
+ fileContentPlaceholder: "The file's text content",
98415
+ addFileButton: "Add resource",
98416
+ adding: "Adding...",
98417
+ uploading: "Uploading...",
98418
+ fileAdded: "Resource added",
98419
+ fileUploaded: "Resource uploaded",
98420
+ fileSaved: "Resource saved",
98421
+ fileDeleted: "Resource deleted",
98422
+ failedToSaveFile: "Failed to save resource",
98423
+ failedToUploadFile: "Failed to upload resource",
98424
+ failedToDeleteFile: "Failed to delete resource",
98425
+ detailsTab: "General",
98426
+ filesTab: "Resources",
98427
+ newFile: "New Resource",
98428
+ newFileDialogTitle: "New Resource",
98429
+ editFileDialogTitle: "Edit Resource",
98430
+ deleteFileDialogTitle: "Delete Resource",
98431
+ deleteFileConfirmation: "Are you sure you want to delete {name}? This action cannot be undone.",
98432
+ chooseFile: "Choose file",
98433
+ upload: "Upload",
98434
+ download: "Download",
98435
+ resourcesItemLabel: "resources"
98495
98436
  };
98496
98437
  var clawSandboxHelpers$3 = {
98497
98438
  unknown: "Unknown",
@@ -100756,7 +100697,7 @@ var safetyTabLabels$3 = {
100756
100697
  };
100757
100698
  var screenshareTabLabels$3 = {
100758
100699
  header: {
100759
- title: "Screen Share",
100700
+ title: "Screen",
100760
100701
  description: "How your agent behaves when a user shares their screen during a voice call."
100761
100702
  },
100762
100703
  capability: {
@@ -102395,6 +102336,19 @@ var platformNavbar$3 = {
102395
102336
  placementExamsHeader: "Placement exams",
102396
102337
  placementExamFallback: "Placement exam"
102397
102338
  };
102339
+ var slashSkillPicker$3 = {
102340
+ listLabel: "Agent skills",
102341
+ resultsAnnouncement: "{count} skills available. Use arrow keys to browse and Enter to select.",
102342
+ loading: "Loading..."
102343
+ };
102344
+ var skillsTabLabels$3 = {
102345
+ header: {
102346
+ title: "Skills",
102347
+ description: "Reusable playbooks you can attach to this agent — each one is a set of instructions for a job. In chat, type / to use one."
102348
+ },
102349
+ notBaseAgent: "Skills are only available to Base Agents.",
102350
+ loading: "Loading..."
102351
+ };
102398
102352
  var placementExam$3 = {
102399
102353
  title: "Placement exam",
102400
102354
  back: "Back"
@@ -102691,6 +102645,118 @@ var profileApplicationsQuestionsEditor$3 = {
102691
102645
  collapseSection: "Collapse section",
102692
102646
  expandSection: "Expand section"
102693
102647
  };
102648
+ var graderTabLabels$3 = {
102649
+ header: {
102650
+ title: "Grader",
102651
+ description: "Set up how your agent grades work against a rubric you define."
102652
+ },
102653
+ capability: {
102654
+ title: "Grading",
102655
+ description: "Let your agent grade work. When this is on, the agent scores what people submit against the rubric you set up below and shares the result as feedback — great for essays, projects, and practice exercises.",
102656
+ offHint: "Turn it on to write grading instructions and build your rubric. Anything you set up here is kept safe if you later turn it off."
102657
+ },
102658
+ subTabs: {
102659
+ setup: "Grading setup",
102660
+ rubric: "Rubric"
102661
+ },
102662
+ denied: {
102663
+ title: "No access to grading settings",
102664
+ description: "You don't have permission to view this agent's grading setup. Ask an administrator for access."
102665
+ },
102666
+ warnings: {
102667
+ noConfig: "Grading is on but not set up yet — the agent will fail when asked to grade. Save your grading instructions in Grading setup to finish.",
102668
+ noCriteria: "Grading is on but the rubric is empty — the agent will fail when asked to grade. Add at least one criterion in the Rubric tab."
102669
+ },
102670
+ config: {
102671
+ sectionTitle: "Grading setup",
102672
+ gradingMode: {
102673
+ label: "What gets graded",
102674
+ options: {
102675
+ submission: "A submission",
102676
+ conversation: "The conversation"
102677
+ },
102678
+ help: {
102679
+ submission: "The agent grades a piece of work the person hands in, like an essay or answer.",
102680
+ conversation: "The agent grades how the whole conversation went."
102681
+ }
102682
+ },
102683
+ feedbackMode: {
102684
+ label: "Feedback shared with the person",
102685
+ options: {
102686
+ overall: "Overall feedback only",
102687
+ perCriteria: "Feedback per criterion",
102688
+ both: "Overall + per criterion"
102689
+ },
102690
+ help: "The overall score is always calculated — this only controls how much detail is shared back."
102691
+ },
102692
+ instructions: {
102693
+ label: "Grading instructions",
102694
+ placeholder: "Describe what's being graded and anything the grader should know beyond the rubric. E.g. 'You are grading a 500-word persuasive essay on climate policy written by a high-school student. Be encouraging but honest.'",
102695
+ help: "Required. This is the context the agent uses every time it grades."
102696
+ },
102697
+ saveButton: "Save",
102698
+ savingButton: "Saving…"
102699
+ },
102700
+ criteria: {
102701
+ sectionTitle: "Rubric",
102702
+ description: "Each row is one thing the agent looks for and how many points it is worth. The overall score is points earned out of the total.",
102703
+ needsConfigHint: "Save your grading setup first, then add rubric criteria here.",
102704
+ emptyState: "No criteria yet. Add your first one — for example \"Clarity\", 10 points.",
102705
+ addButton: "Add criterion",
102706
+ columns: {
102707
+ name: "Name",
102708
+ criteria: "Criteria",
102709
+ points: "Points"
102710
+ },
102711
+ actionsAria: "Actions for {name}",
102712
+ edit: "Edit",
102713
+ "delete": "Delete",
102714
+ totalPoints: "Total possible points: {total}",
102715
+ scoreHint: "Overall score = points earned ÷ {total}.",
102716
+ lastCriterionHint: "A rubric needs at least one criterion — add another before removing this one.",
102717
+ modal: {
102718
+ addTitle: "Add criterion",
102719
+ editTitle: "Edit criterion",
102720
+ name: {
102721
+ label: "Name",
102722
+ placeholder: "e.g. Clarity",
102723
+ required: "Name is required"
102724
+ },
102725
+ criteria: {
102726
+ label: "Criteria",
102727
+ placeholder: "e.g. The argument is easy to follow and each paragraph makes one clear point.",
102728
+ required: "Criteria is required"
102729
+ },
102730
+ points: {
102731
+ label: "Points",
102732
+ placeholder: "10",
102733
+ positive: "Points must be a positive number"
102734
+ },
102735
+ save: "Save",
102736
+ saving: "Saving…",
102737
+ cancel: "Cancel"
102738
+ },
102739
+ deleteModal: {
102740
+ title: "Delete criterion",
102741
+ confirmationPrefix: "Are you sure you want to remove",
102742
+ confirmationSuffix: " from the rubric?",
102743
+ cancel: "Cancel",
102744
+ "delete": "Delete",
102745
+ deleting: "Deleting…"
102746
+ }
102747
+ },
102748
+ toasts: {
102749
+ toggleOn: "Grading turned on",
102750
+ toggleOff: "Grading turned off — your rubric is kept for next time",
102751
+ toggleError: "Couldn't update grading",
102752
+ configSaved: "Grading setup saved",
102753
+ configError: "Couldn't save grading setup",
102754
+ criterionAdded: "Criterion added",
102755
+ criterionUpdated: "Criterion updated",
102756
+ criterionDeleted: "Criterion deleted",
102757
+ criterionError: "Couldn't update the rubric"
102758
+ }
102759
+ };
102694
102760
  var en = {
102695
102761
  accessTabAddAccess: accessTabAddAccess$3,
102696
102762
  accessTabLabels: accessTabLabels$3,
@@ -102745,7 +102811,6 @@ var en = {
102745
102811
  careerEducationDialog: careerEducationDialog$3,
102746
102812
  careerEducationTab: careerEducationTab$3,
102747
102813
  gradebookGradebookTab: gradebookGradebookTab$3,
102748
- graderTabLabels: graderTabLabels$3,
102749
102814
  careerExperienceDialog: careerExperienceDialog$3,
102750
102815
  careerExperienceTab: careerExperienceTab$3,
102751
102816
  careerInstitutionDialog: careerInstitutionDialog$3,
@@ -102939,10 +103004,13 @@ var en = {
102939
103004
  benchmarksAddItemsModal: benchmarksAddItemsModal$3,
102940
103005
  platformSidebar: platformSidebar$3,
102941
103006
  platformNavbar: platformNavbar$3,
103007
+ slashSkillPicker: slashSkillPicker$3,
103008
+ skillsTabLabels: skillsTabLabels$3,
102942
103009
  placementExam: placementExam$3,
102943
103010
  applyApplyWizard: applyApplyWizard$3,
102944
103011
  profileApplicationsTab: profileApplicationsTab$3,
102945
- profileApplicationsQuestionsEditor: profileApplicationsQuestionsEditor$3
103012
+ profileApplicationsQuestionsEditor: profileApplicationsQuestionsEditor$3,
103013
+ graderTabLabels: graderTabLabels$3
102946
103014
  };
102947
103015
 
102948
103016
  var accessTabAddAccess$2 = {
@@ -104452,6 +104520,9 @@ var chatInputFormInsideButtons$2 = {
104452
104520
  studyMode: "Mode Étude",
104453
104521
  deepResearch: "Recherche Approfondie",
104454
104522
  memory: "Mémoire",
104523
+ cowork: "Cowork",
104524
+ coworkNeedsBackend: "Activez un grand modèle local ou connectez-vous à un espace de travail pour utiliser Cowork.",
104525
+ coworkModelTooSmall: "Votre modèle local est trop petit pour Cowork. Choisissez un modèle d’au moins 14 Go dans Modèles Locaux.",
104455
104526
  moreOptions: "Plus d'options"
104456
104527
  };
104457
104528
  var chatInputFormMemoryMenu$2 = {
@@ -104609,7 +104680,57 @@ var clawSandboxAgentSkills$2 = {
104609
104680
  fieldVersionPlaceholder: "ex. 1.0.0",
104610
104681
  fieldDescription: "Description",
104611
104682
  fieldDescriptionPlaceholder: "ex. Rechercher des informations sur le web",
104612
- fieldInstruction: "Instruction"
104683
+ fieldInstruction: "Instruction",
104684
+ sessionNote: "Les compétences ajoutées ou supprimées ici ne s'appliquent qu'aux nouvelles sessions de chat. Les modifications des instructions d'une compétence s'appliquent immédiatement, y compris dans les conversations en cours.",
104685
+ effectiveHeading: "Compétences de cet agent",
104686
+ catalogHeading: "Compétences disponibles",
104687
+ noEffectiveSkills: "Cet agent n'a pas encore de compétences activées. Ajoutez-en une depuis les compétences disponibles.",
104688
+ addToAgent: "Ajouter",
104689
+ addToAgentLabel: "Ajouter {name} à cet agent",
104690
+ removeFromAgent: "Retirer de l'agent",
104691
+ skillAdded: "{name} ajoutée",
104692
+ skillRemoved: "{name} retirée",
104693
+ featuredBadge: "En vedette",
104694
+ nativeBadge: "Native",
104695
+ privateBadge: "Cet agent uniquement",
104696
+ fieldCategory: "Catégorie",
104697
+ fieldCategoryPlaceholder: "p. ex. web, code, données",
104698
+ privateToAgent: "Cet agent uniquement",
104699
+ privateToAgentHint: "Les compétences privées ne sont disponibles que pour cet agent et priment sur les compétences de la plateforme portant le même slug.",
104700
+ instructionHint: "Le guide que l'agent suit lorsque la compétence est utilisée. Les modifications s'appliquent immédiatement, y compris dans les conversations en cours.",
104701
+ filesHint: "Ressources facultatives que l'agent peut utiliser avec cette compétence. Les références et les scripts sont des fichiers texte ; les assets sont des fichiers téléversés.",
104702
+ filesAfterCreateHint: "Vous pouvez joindre des ressources à cette compétence après sa création (rouvrez-la avec Modifier).",
104703
+ noFiles: "Aucune ressource jointe pour le moment.",
104704
+ loadingFiles: "Chargement des ressources...",
104705
+ fileTypeLabel: "Type",
104706
+ fileTypeReference: "Référence",
104707
+ fileTypeScript: "Script",
104708
+ fileTypeAsset: "Ressource",
104709
+ fileNameLabel: "Nom du fichier",
104710
+ fileNamePlaceholder: "p. ex. grille.md",
104711
+ fileContentLabel: "Contenu",
104712
+ fileContentPlaceholder: "Le contenu texte du fichier",
104713
+ addFileButton: "Ajouter la ressource",
104714
+ adding: "Ajout...",
104715
+ uploading: "Téléversement...",
104716
+ fileAdded: "Ressource ajoutée",
104717
+ fileUploaded: "Ressource téléversée",
104718
+ fileSaved: "Ressource enregistrée",
104719
+ fileDeleted: "Ressource supprimée",
104720
+ failedToSaveFile: "Impossible d'enregistrer la ressource",
104721
+ failedToUploadFile: "Impossible de téléverser la ressource",
104722
+ failedToDeleteFile: "Impossible de supprimer la ressource",
104723
+ detailsTab: "Général",
104724
+ filesTab: "Ressources",
104725
+ newFile: "Nouvelle ressource",
104726
+ newFileDialogTitle: "Nouvelle ressource",
104727
+ editFileDialogTitle: "Modifier la ressource",
104728
+ deleteFileDialogTitle: "Supprimer la ressource",
104729
+ deleteFileConfirmation: "Voulez-vous vraiment supprimer {name} ? Cette action est irréversible.",
104730
+ chooseFile: "Choisir un fichier",
104731
+ upload: "Téléverser",
104732
+ download: "Télécharger",
104733
+ resourcesItemLabel: "ressources"
104613
104734
  };
104614
104735
  var clawSandboxHelpers$2 = {
104615
104736
  unknown: "Inconnu",
@@ -106874,7 +106995,7 @@ var safetyTabLabels$2 = {
106874
106995
  };
106875
106996
  var screenshareTabLabels$2 = {
106876
106997
  header: {
106877
- title: "Partage d’écran",
106998
+ title: "Écran",
106878
106999
  description: "Comment votre agent se comporte lorsqu’un utilisateur partage son écran pendant un appel vocal."
106879
107000
  },
106880
107001
  capability: {
@@ -108809,6 +108930,19 @@ var profileApplicationsQuestionsEditor$2 = {
108809
108930
  collapseSection: "Réduire la section",
108810
108931
  expandSection: "Développer la section"
108811
108932
  };
108933
+ var slashSkillPicker$2 = {
108934
+ listLabel: "Compétences de l'agent",
108935
+ resultsAnnouncement: "{count} compétences disponibles. Utilisez les flèches pour parcourir et Entrée pour sélectionner.",
108936
+ loading: "Chargement..."
108937
+ };
108938
+ var skillsTabLabels$2 = {
108939
+ header: {
108940
+ title: "Compétences",
108941
+ description: "Des guides réutilisables à attacher à cet agent — chacun est un ensemble d'instructions pour une tâche. Dans le chat, tapez / pour en utiliser un."
108942
+ },
108943
+ notBaseAgent: "Les compétences ne sont disponibles que pour les agents de base.",
108944
+ loading: "Chargement..."
108945
+ };
108812
108946
  var fr = {
108813
108947
  accessTabAddAccess: accessTabAddAccess$2,
108814
108948
  accessTabLabels: accessTabLabels$2,
@@ -109060,7 +109194,9 @@ var fr = {
109060
109194
  placementExam: placementExam$2,
109061
109195
  applyApplyWizard: applyApplyWizard$2,
109062
109196
  profileApplicationsTab: profileApplicationsTab$2,
109063
- profileApplicationsQuestionsEditor: profileApplicationsQuestionsEditor$2
109197
+ profileApplicationsQuestionsEditor: profileApplicationsQuestionsEditor$2,
109198
+ slashSkillPicker: slashSkillPicker$2,
109199
+ skillsTabLabels: skillsTabLabels$2
109064
109200
  };
109065
109201
 
109066
109202
  var accessTabAddAccess$1 = {
@@ -110570,6 +110706,9 @@ var chatInputFormInsideButtons$1 = {
110570
110706
  studyMode: "Modo Estudio",
110571
110707
  deepResearch: "Investigación Profunda",
110572
110708
  memory: "Memoria",
110709
+ cowork: "Cowork",
110710
+ coworkNeedsBackend: "Activa un modelo local grande o inicia sesión en un espacio de trabajo para usar Cowork.",
110711
+ coworkModelTooSmall: "Tu modelo local es demasiado pequeño para Cowork. Elige un modelo de al menos 14 GB en Modelos Locales.",
110573
110712
  moreOptions: "Más opciones"
110574
110713
  };
110575
110714
  var chatInputFormMemoryMenu$1 = {
@@ -110727,7 +110866,57 @@ var clawSandboxAgentSkills$1 = {
110727
110866
  fieldVersionPlaceholder: "ej. 1.0.0",
110728
110867
  fieldDescription: "Descripción",
110729
110868
  fieldDescriptionPlaceholder: "ej. Buscar información en la web",
110730
- fieldInstruction: "Instrucción"
110869
+ fieldInstruction: "Instrucción",
110870
+ sessionNote: "Las habilidades añadidas o eliminadas aquí solo se aplican a las nuevas sesiones de chat. Los cambios en las instrucciones de una habilidad se aplican de inmediato, incluso en conversaciones en curso.",
110871
+ effectiveHeading: "Habilidades de este agente",
110872
+ catalogHeading: "Habilidades disponibles",
110873
+ noEffectiveSkills: "Este agente aún no tiene habilidades habilitadas. Añade una desde las habilidades disponibles.",
110874
+ addToAgent: "Añadir",
110875
+ addToAgentLabel: "Añadir {name} a este agente",
110876
+ removeFromAgent: "Quitar del agente",
110877
+ skillAdded: "{name} añadida",
110878
+ skillRemoved: "{name} eliminada",
110879
+ featuredBadge: "Destacada",
110880
+ nativeBadge: "Nativa",
110881
+ privateBadge: "Solo este agente",
110882
+ fieldCategory: "Categoría",
110883
+ fieldCategoryPlaceholder: "p. ej. web, código, datos",
110884
+ privateToAgent: "Solo este agente",
110885
+ privateToAgentHint: "Las habilidades privadas solo están disponibles para este agente y tienen prioridad sobre las habilidades de la plataforma con el mismo slug.",
110886
+ instructionHint: "La guía que sigue el agente cuando se usa la habilidad. Los cambios se aplican de inmediato, incluso en conversaciones en curso.",
110887
+ filesHint: "Recursos opcionales que el agente puede usar con esta habilidad. Las referencias y los scripts son archivos de texto; los assets son archivos subidos.",
110888
+ filesAfterCreateHint: "Puedes adjuntar recursos a esta habilidad después de crearla (vuelve a abrirla con Editar).",
110889
+ noFiles: "Aún no hay recursos adjuntos.",
110890
+ loadingFiles: "Cargando recursos...",
110891
+ fileTypeLabel: "Tipo",
110892
+ fileTypeReference: "Referencia",
110893
+ fileTypeScript: "Script",
110894
+ fileTypeAsset: "Recurso",
110895
+ fileNameLabel: "Nombre del archivo",
110896
+ fileNamePlaceholder: "p. ej. rubrica.md",
110897
+ fileContentLabel: "Contenido",
110898
+ fileContentPlaceholder: "El contenido de texto del archivo",
110899
+ addFileButton: "Añadir recurso",
110900
+ adding: "Añadiendo...",
110901
+ uploading: "Subiendo...",
110902
+ fileAdded: "Recurso añadido",
110903
+ fileUploaded: "Recurso subido",
110904
+ fileSaved: "Recurso guardado",
110905
+ fileDeleted: "Recurso eliminado",
110906
+ failedToSaveFile: "No se pudo guardar el recurso",
110907
+ failedToUploadFile: "No se pudo subir el recurso",
110908
+ failedToDeleteFile: "No se pudo eliminar el recurso",
110909
+ detailsTab: "General",
110910
+ filesTab: "Recursos",
110911
+ newFile: "Nuevo recurso",
110912
+ newFileDialogTitle: "Nuevo recurso",
110913
+ editFileDialogTitle: "Editar recurso",
110914
+ deleteFileDialogTitle: "Eliminar recurso",
110915
+ deleteFileConfirmation: "¿Seguro que quieres eliminar {name}? Esta acción no se puede deshacer.",
110916
+ chooseFile: "Elegir archivo",
110917
+ upload: "Subir",
110918
+ download: "Descargar",
110919
+ resourcesItemLabel: "recursos"
110731
110920
  };
110732
110921
  var clawSandboxHelpers$1 = {
110733
110922
  unknown: "Desconocido",
@@ -112992,7 +113181,7 @@ var safetyTabLabels$1 = {
112992
113181
  };
112993
113182
  var screenshareTabLabels$1 = {
112994
113183
  header: {
112995
- title: "Pantalla compartida",
113184
+ title: "Pantalla",
112996
113185
  description: "Cómo se comporta tu agente cuando un usuario comparte su pantalla durante una llamada de voz."
112997
113186
  },
112998
113187
  capability: {
@@ -114927,6 +115116,19 @@ var profileApplicationsQuestionsEditor$1 = {
114927
115116
  collapseSection: "Contraer sección",
114928
115117
  expandSection: "Expandir sección"
114929
115118
  };
115119
+ var slashSkillPicker$1 = {
115120
+ listLabel: "Habilidades del agente",
115121
+ resultsAnnouncement: "{count} habilidades disponibles. Usa las flechas para navegar y Enter para seleccionar.",
115122
+ loading: "Cargando..."
115123
+ };
115124
+ var skillsTabLabels$1 = {
115125
+ header: {
115126
+ title: "Habilidades",
115127
+ description: "Guías reutilizables que puedes adjuntar a este agente: cada una es un conjunto de instrucciones para una tarea. En el chat, escribe / para usar una."
115128
+ },
115129
+ notBaseAgent: "Las habilidades solo están disponibles para los agentes base.",
115130
+ loading: "Cargando..."
115131
+ };
114930
115132
  var es = {
114931
115133
  accessTabAddAccess: accessTabAddAccess$1,
114932
115134
  accessTabLabels: accessTabLabels$1,
@@ -115178,7 +115380,9 @@ var es = {
115178
115380
  placementExam: placementExam$1,
115179
115381
  applyApplyWizard: applyApplyWizard$1,
115180
115382
  profileApplicationsTab: profileApplicationsTab$1,
115181
- profileApplicationsQuestionsEditor: profileApplicationsQuestionsEditor$1
115383
+ profileApplicationsQuestionsEditor: profileApplicationsQuestionsEditor$1,
115384
+ slashSkillPicker: slashSkillPicker$1,
115385
+ skillsTabLabels: skillsTabLabels$1
115182
115386
  };
115183
115387
 
115184
115388
  var accessTabAddAccess = {
@@ -116688,6 +116892,9 @@ var chatInputFormInsideButtons = {
116688
116892
  studyMode: "学习模式",
116689
116893
  deepResearch: "深度研究",
116690
116894
  memory: "记忆",
116895
+ cowork: "Cowork",
116896
+ coworkNeedsBackend: "启用大型本地模型或登录工作区即可使用 Cowork。",
116897
+ coworkModelTooSmall: "您的本地模型太小,无法用于 Cowork。请在“本地模型”中选择至少 14GB 的模型。",
116691
116898
  moreOptions: "更多选项"
116692
116899
  };
116693
116900
  var chatInputFormMemoryMenu = {
@@ -116845,7 +117052,57 @@ var clawSandboxAgentSkills = {
116845
117052
  fieldVersionPlaceholder: "例如:1.0.0",
116846
117053
  fieldDescription: "描述",
116847
117054
  fieldDescriptionPlaceholder: "例如:在网络上搜索信息",
116848
- fieldInstruction: "指令"
117055
+ fieldInstruction: "指令",
117056
+ sessionNote: "在此添加或移除的技能仅对新的聊天会话生效。技能指令的修改会立即生效,包括正在进行的对话。",
117057
+ effectiveHeading: "此智能体的技能",
117058
+ catalogHeading: "可用技能",
117059
+ noEffectiveSkills: "此智能体尚未启用任何技能。请从下方的可用技能中添加。",
117060
+ addToAgent: "添加",
117061
+ addToAgentLabel: "将 {name} 添加到此智能体",
117062
+ removeFromAgent: "从智能体中移除",
117063
+ skillAdded: "已添加 {name}",
117064
+ skillRemoved: "已移除 {name}",
117065
+ featuredBadge: "精选",
117066
+ nativeBadge: "原生",
117067
+ privateBadge: "仅此智能体",
117068
+ fieldCategory: "分类",
117069
+ fieldCategoryPlaceholder: "例如 web、代码、数据",
117070
+ privateToAgent: "仅此智能体",
117071
+ privateToAgentHint: "私有技能仅对此智能体可用,并优先于具有相同 slug 的平台技能。",
117072
+ instructionHint: "使用该技能时智能体遵循的操作指南。修改会立即生效,包括正在进行的对话。",
117073
+ filesHint: "智能体在使用此技能时可参考的可选资源。参考资料和脚本是文本文件;资产是上传的文件。",
117074
+ filesAfterCreateHint: "创建技能后即可附加资源(通过“编辑”重新打开)。",
117075
+ noFiles: "尚未附加任何资源。",
117076
+ loadingFiles: "正在加载资源...",
117077
+ fileTypeLabel: "类型",
117078
+ fileTypeReference: "参考资料",
117079
+ fileTypeScript: "脚本",
117080
+ fileTypeAsset: "资源",
117081
+ fileNameLabel: "文件名",
117082
+ fileNamePlaceholder: "例如 rubric.md",
117083
+ fileContentLabel: "内容",
117084
+ fileContentPlaceholder: "文件的文本内容",
117085
+ addFileButton: "添加资源",
117086
+ adding: "添加中...",
117087
+ uploading: "上传中...",
117088
+ fileAdded: "资源已添加",
117089
+ fileUploaded: "资源已上传",
117090
+ fileSaved: "资源已保存",
117091
+ fileDeleted: "资源已删除",
117092
+ failedToSaveFile: "保存资源失败",
117093
+ failedToUploadFile: "上传资源失败",
117094
+ failedToDeleteFile: "删除资源失败",
117095
+ detailsTab: "常规",
117096
+ filesTab: "资源",
117097
+ newFile: "新建资源",
117098
+ newFileDialogTitle: "新建资源",
117099
+ editFileDialogTitle: "编辑资源",
117100
+ deleteFileDialogTitle: "删除资源",
117101
+ deleteFileConfirmation: "确定要删除 {name} 吗?此操作无法撤销。",
117102
+ chooseFile: "选择文件",
117103
+ upload: "上传",
117104
+ download: "下载",
117105
+ resourcesItemLabel: "资源"
116849
117106
  };
116850
117107
  var clawSandboxHelpers = {
116851
117108
  unknown: "未知",
@@ -119110,7 +119367,7 @@ var safetyTabLabels = {
119110
119367
  };
119111
119368
  var screenshareTabLabels = {
119112
119369
  header: {
119113
- title: "屏幕共享",
119370
+ title: "屏幕",
119114
119371
  description: "当用户在语音通话中共享屏幕时,您的智能体的表现方式。"
119115
119372
  },
119116
119373
  capability: {
@@ -121045,6 +121302,19 @@ var profileApplicationsQuestionsEditor = {
121045
121302
  collapseSection: "折叠板块",
121046
121303
  expandSection: "展开板块"
121047
121304
  };
121305
+ var slashSkillPicker = {
121306
+ listLabel: "智能体技能",
121307
+ resultsAnnouncement: "{count} 个技能可用。使用方向键浏览,按 Enter 选择。",
121308
+ loading: "加载中..."
121309
+ };
121310
+ var skillsTabLabels = {
121311
+ header: {
121312
+ title: "技能",
121313
+ description: "可附加到此智能体的可复用操作指南——每个技能都是完成一项任务的指令集。在聊天中输入 / 即可使用。"
121314
+ },
121315
+ notBaseAgent: "技能仅适用于基础智能体。",
121316
+ loading: "加载中..."
121317
+ };
121048
121318
  var zh = {
121049
121319
  accessTabAddAccess: accessTabAddAccess,
121050
121320
  accessTabLabels: accessTabLabels,
@@ -121296,7 +121566,9 @@ var zh = {
121296
121566
  placementExam: placementExam,
121297
121567
  applyApplyWizard: applyApplyWizard,
121298
121568
  profileApplicationsTab: profileApplicationsTab,
121299
- profileApplicationsQuestionsEditor: profileApplicationsQuestionsEditor
121569
+ profileApplicationsQuestionsEditor: profileApplicationsQuestionsEditor,
121570
+ slashSkillPicker: slashSkillPicker,
121571
+ skillsTabLabels: skillsTabLabels
121300
121572
  };
121301
121573
 
121302
121574
  /**
@@ -127458,344 +127730,8 @@ var Indicator$2 = ProgressIndicator;
127458
127730
  const Progress = React.forwardRef(({ className, value, ...props }, ref) => (jsx(Root$9, { ref: ref, className: cn('bg-secondary relative h-4 w-full overflow-hidden rounded-full', className), ...props, children: jsx(Indicator$2, { className: "bg-primary h-full w-full flex-1 transition-all", style: { transform: `translateX(-${100 - (value || 0)}%)` } }) })));
127459
127731
  Progress.displayName = Root$9.displayName;
127460
127732
 
127461
- var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
127462
- // @__NO_SIDE_EFFECTS__
127463
- function createSlottable(ownerName) {
127464
- const Slottable2 = ({ children }) => {
127465
- return /* @__PURE__ */ jsx(Fragment$1, { children });
127466
- };
127467
- Slottable2.displayName = `${ownerName}.Slottable`;
127468
- Slottable2.__radixId = SLOTTABLE_IDENTIFIER;
127469
- return Slottable2;
127470
- }
127471
-
127472
- var ROOT_NAME = "AlertDialog";
127473
- var [createAlertDialogContext] = createContextScope$1(ROOT_NAME, [
127474
- createDialogScope
127475
- ]);
127476
- var useDialogScope = createDialogScope();
127477
- var AlertDialog$1 = (props) => {
127478
- const { __scopeAlertDialog, ...alertDialogProps } = props;
127479
- const dialogScope = useDialogScope(__scopeAlertDialog);
127480
- return /* @__PURE__ */ jsx(DialogPrimitive.Root, { ...dialogScope, ...alertDialogProps, modal: true });
127481
- };
127482
- AlertDialog$1.displayName = ROOT_NAME;
127483
- var TRIGGER_NAME$3 = "AlertDialogTrigger";
127484
- var AlertDialogTrigger = React.forwardRef(
127485
- (props, forwardedRef) => {
127486
- const { __scopeAlertDialog, ...triggerProps } = props;
127487
- const dialogScope = useDialogScope(__scopeAlertDialog);
127488
- return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { ...dialogScope, ...triggerProps, ref: forwardedRef });
127489
- }
127490
- );
127491
- AlertDialogTrigger.displayName = TRIGGER_NAME$3;
127492
- var PORTAL_NAME$2 = "AlertDialogPortal";
127493
- var AlertDialogPortal$1 = (props) => {
127494
- const { __scopeAlertDialog, ...portalProps } = props;
127495
- const dialogScope = useDialogScope(__scopeAlertDialog);
127496
- return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { ...dialogScope, ...portalProps });
127497
- };
127498
- AlertDialogPortal$1.displayName = PORTAL_NAME$2;
127499
- var OVERLAY_NAME = "AlertDialogOverlay";
127500
- var AlertDialogOverlay$1 = React.forwardRef(
127501
- (props, forwardedRef) => {
127502
- const { __scopeAlertDialog, ...overlayProps } = props;
127503
- const dialogScope = useDialogScope(__scopeAlertDialog);
127504
- return /* @__PURE__ */ jsx(DialogPrimitive.Overlay, { ...dialogScope, ...overlayProps, ref: forwardedRef });
127505
- }
127506
- );
127507
- AlertDialogOverlay$1.displayName = OVERLAY_NAME;
127508
- var CONTENT_NAME$4 = "AlertDialogContent";
127509
- var [AlertDialogContentProvider, useAlertDialogContentContext] = createAlertDialogContext(CONTENT_NAME$4);
127510
- var Slottable = createSlottable("AlertDialogContent");
127511
- var AlertDialogContent$1 = React.forwardRef(
127512
- (props, forwardedRef) => {
127513
- const { __scopeAlertDialog, children, ...contentProps } = props;
127514
- const dialogScope = useDialogScope(__scopeAlertDialog);
127515
- const contentRef = React.useRef(null);
127516
- const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
127517
- const cancelRef = React.useRef(null);
127518
- return /* @__PURE__ */ jsx(
127519
- DialogPrimitive.WarningProvider,
127520
- {
127521
- contentName: CONTENT_NAME$4,
127522
- titleName: TITLE_NAME,
127523
- docsSlug: "alert-dialog",
127524
- children: /* @__PURE__ */ jsx(AlertDialogContentProvider, { scope: __scopeAlertDialog, cancelRef, children: /* @__PURE__ */ jsxs(
127525
- DialogPrimitive.Content,
127526
- {
127527
- role: "alertdialog",
127528
- ...dialogScope,
127529
- ...contentProps,
127530
- ref: composedRefs,
127531
- onOpenAutoFocus: composeEventHandlers$2(contentProps.onOpenAutoFocus, (event) => {
127532
- event.preventDefault();
127533
- cancelRef.current?.focus({ preventScroll: true });
127534
- }),
127535
- onPointerDownOutside: (event) => event.preventDefault(),
127536
- onInteractOutside: (event) => event.preventDefault(),
127537
- children: [
127538
- /* @__PURE__ */ jsx(Slottable, { children }),
127539
- /* @__PURE__ */ jsx(DescriptionWarning, { contentRef })
127540
- ]
127541
- }
127542
- ) })
127543
- }
127544
- );
127545
- }
127546
- );
127547
- AlertDialogContent$1.displayName = CONTENT_NAME$4;
127548
- var TITLE_NAME = "AlertDialogTitle";
127549
- var AlertDialogTitle$1 = React.forwardRef(
127550
- (props, forwardedRef) => {
127551
- const { __scopeAlertDialog, ...titleProps } = props;
127552
- const dialogScope = useDialogScope(__scopeAlertDialog);
127553
- return /* @__PURE__ */ jsx(DialogPrimitive.Title, { ...dialogScope, ...titleProps, ref: forwardedRef });
127554
- }
127555
- );
127556
- AlertDialogTitle$1.displayName = TITLE_NAME;
127557
- var DESCRIPTION_NAME = "AlertDialogDescription";
127558
- var AlertDialogDescription$1 = React.forwardRef((props, forwardedRef) => {
127559
- const { __scopeAlertDialog, ...descriptionProps } = props;
127560
- const dialogScope = useDialogScope(__scopeAlertDialog);
127561
- return /* @__PURE__ */ jsx(DialogPrimitive.Description, { ...dialogScope, ...descriptionProps, ref: forwardedRef });
127562
- });
127563
- AlertDialogDescription$1.displayName = DESCRIPTION_NAME;
127564
- var ACTION_NAME = "AlertDialogAction";
127565
- var AlertDialogAction$1 = React.forwardRef(
127566
- (props, forwardedRef) => {
127567
- const { __scopeAlertDialog, ...actionProps } = props;
127568
- const dialogScope = useDialogScope(__scopeAlertDialog);
127569
- return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...actionProps, ref: forwardedRef });
127570
- }
127571
- );
127572
- AlertDialogAction$1.displayName = ACTION_NAME;
127573
- var CANCEL_NAME = "AlertDialogCancel";
127574
- var AlertDialogCancel$1 = React.forwardRef(
127575
- (props, forwardedRef) => {
127576
- const { __scopeAlertDialog, ...cancelProps } = props;
127577
- const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog);
127578
- const dialogScope = useDialogScope(__scopeAlertDialog);
127579
- const ref = useComposedRefs$1(forwardedRef, cancelRef);
127580
- return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...cancelProps, ref });
127581
- }
127582
- );
127583
- AlertDialogCancel$1.displayName = CANCEL_NAME;
127584
- var DescriptionWarning = ({ contentRef }) => {
127585
- const MESSAGE = `\`${CONTENT_NAME$4}\` requires a description for the component to be accessible for screen reader users.
127586
-
127587
- You can add a description to the \`${CONTENT_NAME$4}\` by passing a \`${DESCRIPTION_NAME}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
127588
-
127589
- Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${CONTENT_NAME$4}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.
127590
-
127591
- For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;
127592
- React.useEffect(() => {
127593
- const hasDescription = document.getElementById(
127594
- contentRef.current?.getAttribute("aria-describedby")
127595
- );
127596
- if (!hasDescription) console.warn(MESSAGE);
127597
- }, [MESSAGE, contentRef]);
127598
- return null;
127599
- };
127600
- var Root2$4 = AlertDialog$1;
127601
- var Portal2 = AlertDialogPortal$1;
127602
- var Overlay2 = AlertDialogOverlay$1;
127603
- var Content2$2 = AlertDialogContent$1;
127604
- var Action = AlertDialogAction$1;
127605
- var Cancel = AlertDialogCancel$1;
127606
- var Title2 = AlertDialogTitle$1;
127607
- var Description2 = AlertDialogDescription$1;
127608
-
127609
- const AlertDialog = Root2$4;
127610
- const AlertDialogPortal = Portal2;
127611
- const AlertDialogOverlay = React.forwardRef(({ className, ...props }, ref) => (jsx(Overlay2, { className: cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', className), ...props, ref: ref })));
127612
- AlertDialogOverlay.displayName = Overlay2.displayName;
127613
- const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => (jsxs(AlertDialogPortal, { children: [jsx(AlertDialogOverlay, {}), jsx(Content2$2, { ref: ref, className: cn('bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg', className), ...props })] })));
127614
- AlertDialogContent.displayName = Content2$2.displayName;
127615
- const AlertDialogHeader = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col space-y-2 text-center sm:text-left', className), ...props }));
127616
- AlertDialogHeader.displayName = 'AlertDialogHeader';
127617
- const AlertDialogFooter = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className), ...props }));
127618
- AlertDialogFooter.displayName = 'AlertDialogFooter';
127619
- const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => (jsx(Title2, { ref: ref, className: cn('text-lg font-semibold', className), ...props })));
127620
- AlertDialogTitle.displayName = Title2.displayName;
127621
- const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => (jsx(Description2, { ref: ref, className: cn('text-muted-foreground text-sm', className), ...props })));
127622
- AlertDialogDescription.displayName = Description2.displayName;
127623
- const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => (jsx(Action, { ref: ref, className: cn(buttonVariants(), className), ...props })));
127624
- AlertDialogAction.displayName = Action.displayName;
127625
- const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (jsx(Cancel, { ref: ref, className: cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className), ...props })));
127626
- AlertDialogCancel.displayName = Cancel.displayName;
127627
-
127628
- // Tauri types for model download functionality
127629
- /**
127630
- * Initial state for model download
127631
- */
127632
- const initialModelDownloadState = {
127633
- status: 'idle',
127634
- progress: 0,
127635
- message: '',
127636
- logs: [],
127637
- lastUpdated: new Date().toISOString(),
127638
- };
127639
- /**
127640
- * Check if the app is running inside Tauri
127641
- * In Tauri 2.0, the global is __TAURI_INTERNALS__ (with withGlobalTauri: true)
127642
- * We also check for __TAURI__ for backwards compatibility
127643
- */
127644
- const isTauriApp$1 = () => {
127645
- if (typeof window === 'undefined')
127646
- return false;
127647
- return '__TAURI_INTERNALS__' in window || '__TAURI__' in window;
127648
- };
127649
- /**
127650
- * Tauri event names
127651
- */
127652
- const TAURI_EVENTS = {
127653
- DOWNLOAD_PROGRESS: 'model:download-progress',
127654
- INSTALLATION_LOG: 'model:installation-log',
127655
- DISK_SPACE_ERROR: 'model:disk-space-error',
127656
- OLLAMA_STATUS: 'model:ollama-status',
127657
- };
127658
- /**
127659
- * Tauri command names
127660
- */
127661
- const TAURI_COMMANDS = {
127662
- INSTALL_OLLAMA: 'install_ollama',
127663
- STOP_OLLAMA: 'stop_ollama',
127664
- CHECK_OLLAMA_STATUS: 'check_ollama_status',
127665
- CHECK_DISK_SPACE: 'check_disk_space_for_model',
127666
- GET_SYSTEM_MEMORY: 'get_system_memory',
127667
- DOWNLOAD_MODEL: 'download_model',
127668
- CANCEL_DOWNLOAD: 'cancel_model_download',
127669
- CHECK_NETWORK_STATUS: 'check_network_status',
127670
- GET_OS_TYPE: 'get_os_type',
127671
- CHECK_FOUNDRY_STATUS: 'check_foundry_local_status',
127672
- START_FOUNDRY_SERVICE: 'start_foundry_local_service',
127673
- LOAD_FOUNDRY_MODEL: 'load_foundry_local_model',
127674
- SET_SELECTED_FOUNDRY_MODEL: 'set_selected_foundry_model',
127675
- GET_SELECTED_FOUNDRY_MODEL: 'get_selected_foundry_model',
127676
- INSTALL_FOUNDRY: 'install_foundry',
127677
- DOWNLOAD_FOUNDRY_MODEL: 'download_foundry_model_cmd',
127678
- GET_RECOMMENDED_FOUNDRY_MODELS: 'get_recommended_foundry_models',
127679
- LOG_STDOUT: 'log_stdout',
127680
- };
127681
- /**
127682
- * Initial state for the System Control install flow.
127683
- */
127684
- const initialGhostOsInstallState = {
127685
- status: 'idle',
127686
- progress: 0,
127687
- message: '',
127688
- logs: [],
127689
- lastUpdated: new Date().toISOString(),
127690
- };
127691
- /**
127692
- * Tauri event names emitted by the host during GhostOS install/setup.
127693
- */
127694
- const GHOST_OS_TAURI_EVENTS = {
127695
- INSTALL_PROGRESS: 'ghost-os:install-progress',
127696
- INSTALLATION_LOG: 'ghost-os:installation-log',
127697
- STATUS: 'ghost-os:status',
127698
- };
127699
- /**
127700
- * Tauri command names the host implements for GhostOS install/setup. The web
127701
- * layer invokes these; the native side performs the clone + setup.
127702
- */
127703
- const GHOST_OS_TAURI_COMMANDS = {
127704
- /** Install and set up GhostOS (clone repo + run setup). */
127705
- INSTALL_GHOST_OS: 'install_ghost_os',
127706
- /** Stop the running GhostOS manager. */
127707
- STOP_GHOST_OS: 'stop_ghost_os',
127708
- /** Report current {@link GhostOsStatus}. */
127709
- CHECK_GHOST_OS_STATUS: 'check_ghost_os_status',
127710
- };
127711
- /**
127712
- * Tauri command strings exposed by `tauri-plugin-macos-permissions`
127713
- * (https://github.com/ayangweb/tauri-plugin-macos-permissions). GhostOS needs
127714
- * macOS Accessibility permission to control the device, so the System Control
127715
- * card surfaces it. These are invoked directly via `useTauri().invoke(...)` —
127716
- * no extra npm dependency. The host must register the plugin in its Tauri app
127717
- * (`tauri_plugin_macos_permissions::init()`). Each `CHECK_*` returns a boolean;
127718
- * each `REQUEST_*` prompts / opens the relevant System Settings pane.
127719
- */
127720
- const MACOS_PERMISSIONS_COMMANDS = {
127721
- CHECK_ACCESSIBILITY: 'plugin:macos-permissions|check_accessibility_permission',
127722
- REQUEST_ACCESSIBILITY: 'plugin:macos-permissions|request_accessibility_permission',
127723
- CHECK_SCREEN_RECORDING: 'plugin:macos-permissions|check_screen_recording_permission',
127724
- REQUEST_SCREEN_RECORDING: 'plugin:macos-permissions|request_screen_recording_permission',
127725
- CHECK_INPUT_MONITORING: 'plugin:macos-permissions|check_input_monitoring_permission',
127726
- REQUEST_INPUT_MONITORING: 'plugin:macos-permissions|request_input_monitoring_permission',
127727
- CHECK_FULL_DISK_ACCESS: 'plugin:macos-permissions|check_full_disk_access_permission',
127728
- REQUEST_FULL_DISK_ACCESS: 'plugin:macos-permissions|request_full_disk_access_permission',
127729
- };
127730
-
127731
- /**
127732
- * Dynamically import Tauri APIs to avoid SSR issues
127733
- */
127734
- const getTauriAPIs = async () => {
127735
- try {
127736
- const { invoke } = await import('@tauri-apps/api/core');
127737
- const { listen } = await import('@tauri-apps/api/event');
127738
- return { invoke, listen };
127739
- }
127740
- catch (error) {
127741
- console.error('Failed to load Tauri APIs:', error);
127742
- return null;
127743
- }
127744
- };
127745
- /**
127746
- * Hook to access Tauri APIs with SSR safety
127747
- *
127748
- * @returns Object with isAvailable flag and Tauri invoke/listen functions
127749
- */
127750
- function useTauri() {
127751
- const [isAvailable, setIsAvailable] = useState(false);
127752
- const [apis, setApis] = useState(null);
127753
- useEffect(() => {
127754
- // Check if we're in a Tauri environment
127755
- const inTauri = isTauriApp$1();
127756
- if (inTauri) {
127757
- getTauriAPIs().then((result) => {
127758
- setApis(result);
127759
- setIsAvailable(!!result);
127760
- });
127761
- }
127762
- }, []);
127763
- /**
127764
- * Invoke a Tauri command
127765
- */
127766
- const invoke = useCallback(async (command, args) => {
127767
- if (!(apis === null || apis === void 0 ? void 0 : apis.invoke)) {
127768
- throw new Error('Tauri is not available');
127769
- }
127770
- return apis.invoke(command, args);
127771
- }, [apis]);
127772
- /**
127773
- * Listen to a Tauri event
127774
- * Returns an unlisten function that should be called on cleanup
127775
- */
127776
- const listen = useCallback(async (event, handler) => {
127777
- // The synchronous global (`__TAURI_INTERNALS__`) exposes `invoke` but
127778
- // frequently NOT `event.listen`, so `apis.listen` can be undefined even
127779
- // though Tauri is fully available. Fall back to the real event API via
127780
- // dynamic import so download progress/completion events are actually
127781
- // delivered — otherwise the UI never leaves the "downloading" state.
127782
- let listenFn = apis === null || apis === void 0 ? void 0 : apis.listen;
127783
- if (!listenFn) {
127784
- const { listen: importedListen } = await import('@tauri-apps/api/event');
127785
- listenFn = importedListen;
127786
- }
127787
- return listenFn(event, (e) => handler(e.payload));
127788
- }, [apis]);
127789
- return {
127790
- isAvailable,
127791
- invoke,
127792
- listen,
127793
- };
127794
- }
127795
-
127796
127733
  const LOCAL_LLM_ENABLED_KEY = 'ibl_local_llm_enabled';
127797
127734
  const LOCAL_LLM_MODEL_KEY = 'ibl_local_llm_model';
127798
- const LOCAL_LLM_TOOL_SUPPORT_KEY = 'ibl_local_llm_tool_support';
127799
127735
  /**
127800
127736
  * Curated catalog of small, on-device-friendly models from the Ollama library
127801
127737
  * (https://ollama.com/library). The model manager itself (Ollama) is not a
@@ -127828,8 +127764,8 @@ const LOCAL_MODELS = [
127828
127764
  },
127829
127765
  { name: 'Granite 4.1', provider: 'IBM', id: 'granite4.1:8b', size: '5.3 GB', tool_support: true },
127830
127766
  { name: 'GPT-OSS 20B', provider: 'OpenAI', id: 'gpt-oss:20b', size: '14 GB', tool_support: true },
127831
- // Larger models. Sizes use "GB" so they parse for the System Control size gate
127832
- // (only models above the configured gate can use System Control).
127767
+ // Larger models. Sizes use "GB" so they parse for the Cowork size gate
127768
+ // (only models above the configured gate can use Cowork).
127833
127769
  {
127834
127770
  name: 'Qwen 3.6',
127835
127771
  provider: 'Alibaba',
@@ -127853,34 +127789,6 @@ const LOCAL_MODELS = [
127853
127789
  tool_support: true,
127854
127790
  },
127855
127791
  ];
127856
- /** The model wired to the existing single-model download flow (default selection). */
127857
- const PRIMARY_MODEL_ID = 'phi4-mini:latest';
127858
- /**
127859
- * Whether a catalog model id (e.g. "llama3.2", "phi3:mini") is present among the
127860
- * installed Ollama tags reported by the backend (e.g. "llama3.2:latest"). Matches
127861
- * an exact tag or the same base model with any tag suffix, so a model pulled as
127862
- * `<id>:latest` still counts as installed.
127863
- */
127864
- function isModelInstalled(modelId, installedTags) {
127865
- if (!installedTags)
127866
- return false;
127867
- return installedTags.some((tag) => tag === modelId || tag.startsWith(`${modelId}:`));
127868
- }
127869
- /**
127870
- * Whether a model id is an Ollama cloud-hosted model — either the plain ":cloud"
127871
- * tag (e.g. "glm-5.2:cloud") or a sized cloud tag (e.g. "gemma4:31b-cloud").
127872
- * Cloud models run on Ollama's servers, so they are available by default — never
127873
- * downloaded, no local memory required, always "ready".
127874
- */
127875
- function isCloudModelId(modelId) {
127876
- return modelId.endsWith(':cloud') || (modelId.includes(':') && modelId.endsWith('-cloud'));
127877
- }
127878
- /**
127879
- * Fraction of the machine's memory above which a model is treated as "too large"
127880
- * and a confirmation is required before downloading. TESTING VALUE — set low (1%)
127881
- * so the warning is easy to trigger; raise toward real capacity (e.g. 0.8) later.
127882
- */
127883
- const MODEL_SIZE_WARN_FRACTION = 0.01;
127884
127792
  /** Multipliers for the size units used in the catalog (binary / 1024-based). */
127885
127793
  const SIZE_UNIT_BYTES = {
127886
127794
  B: 1,
@@ -127902,54 +127810,19 @@ function parseModelSizeBytes(size) {
127902
127810
  return null;
127903
127811
  return value * ((_a = SIZE_UNIT_BYTES[match[2].toUpperCase()]) !== null && _a !== void 0 ? _a : 1);
127904
127812
  }
127905
- /** Format a byte count as a short, human-readable size (e.g. "16.0 GB"). */
127906
- function formatBytes(bytes) {
127907
- if (bytes <= 0)
127908
- return '0 GB';
127909
- const gb = bytes / 1024 ** 3;
127910
- if (gb >= 1)
127911
- return `${gb.toFixed(1)} GB`;
127912
- return `${Math.round(bytes / 1024 ** 2)} MB`;
127913
- }
127914
127813
  /**
127915
- * The memory a model can use on this machine: the larger of system RAM and GPU
127916
- * VRAM (a model runs in one or the other). Returns 0 when memory is unknown.
127917
- */
127918
- function usableMemoryBytes(systemMemory) {
127919
- if (!systemMemory)
127920
- return 0;
127921
- return Math.max(systemMemory.ram_total, systemMemory.vram_total);
127922
- }
127923
- /**
127924
- * Whether `model` is large enough relative to this machine's memory to warrant a
127925
- * "might not run" confirmation. False when memory or the model size is unknown,
127926
- * so the download simply proceeds rather than warning on incomplete data.
127927
- */
127928
- function modelExceedsCapacity(model, systemMemory) {
127929
- const capacity = usableMemoryBytes(systemMemory);
127930
- const modelBytes = parseModelSizeBytes(model.size);
127931
- if (modelBytes == null)
127932
- return false;
127933
- // Unknown memory (capacity 0) → don't warn; the download simply proceeds
127934
- // rather than blocking on incomplete data.
127935
- if (capacity <= 0)
127936
- return false;
127937
- return modelBytes > capacity * MODEL_SIZE_WARN_FRACTION;
127938
- }
127939
- /**
127940
- * Default minimum model size (GB) that can use the System Control Manager
127814
+ * Default minimum model size (GB) that can use the Cowork
127941
127815
  * (GhostOS MCP/tools). Smaller models don't support tools/MCP well, so the
127942
- * manager is gated to models above this size. Per-app overridable via the
127943
- * System Control card's `requiredSizeGb` prop (see SystemControlTabProps).
127816
+ * manager is gated to models above this size.
127944
127817
  */
127945
- const DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB = 12;
127818
+ const DEFAULT_COWORK_REQUIRED_SIZE_GB = 12;
127946
127819
  /**
127947
127820
  * Whether the given model (by Ollama id) is large enough to use the System
127948
127821
  * Control Manager — i.e. its catalog size exceeds `gb` (default
127949
- * {@link DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB}). Unknown ids or unparseable
127822
+ * {@link DEFAULT_COWORK_REQUIRED_SIZE_GB}). Unknown ids or unparseable
127950
127823
  * sizes return false (gated off).
127951
127824
  */
127952
- function modelSupportsSystemControl(modelId, gb = DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB) {
127825
+ function modelSupportsCowork(modelId, gb = DEFAULT_COWORK_REQUIRED_SIZE_GB) {
127953
127826
  if (!modelId)
127954
127827
  return false;
127955
127828
  const model = LOCAL_MODELS.find((m) => m.id === modelId);
@@ -127960,22 +127833,6 @@ function modelSupportsSystemControl(modelId, gb = DEFAULT_SYSTEM_CONTROL_REQUIRE
127960
127833
  return false;
127961
127834
  return bytes > gb * 1024 ** 3;
127962
127835
  }
127963
- /**
127964
- * The smallest catalog model that can use the System Control Manager (size
127965
- * exceeds `gb`), or null if none qualify. Used by the "Upgrade" action to pick
127966
- * the lightest capable model. Ties / unparseable sizes sort last.
127967
- */
127968
- function smallestSystemControlModel(gb = DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB) {
127969
- const usable = LOCAL_MODELS.filter((m) => modelSupportsSystemControl(m.id, gb));
127970
- if (usable.length === 0)
127971
- return null;
127972
- return usable.reduce((smallest, m) => {
127973
- var _a, _b;
127974
- const a = (_a = parseModelSizeBytes(m.size)) !== null && _a !== void 0 ? _a : Infinity;
127975
- const b = (_b = parseModelSizeBytes(smallest.size)) !== null && _b !== void 0 ? _b : Infinity;
127976
- return a < b ? m : smallest;
127977
- });
127978
- }
127979
127836
  /**
127980
127837
  * Check if local LLM is enabled from localStorage
127981
127838
  */
@@ -128000,57 +127857,21 @@ function getLocalLLMModel() {
128000
127857
  return null;
128001
127858
  return localStorage.getItem(LOCAL_LLM_MODEL_KEY);
128002
127859
  }
128003
- /**
128004
- * Set the model the user has chosen to chat with (Ollama pull id).
128005
- */
128006
- function setLocalLLMModel(modelId) {
128007
- if (typeof window === 'undefined')
128008
- return;
128009
- localStorage.setItem(LOCAL_LLM_MODEL_KEY, modelId);
128010
- }
128011
- /**
128012
- * Persist whether the selected model supports tools (set when a model is chosen).
128013
- */
128014
- function setLocalLLMToolSupport(toolSupport) {
128015
- if (typeof window === 'undefined')
128016
- return;
128017
- localStorage.setItem(LOCAL_LLM_TOOL_SUPPORT_KEY, String(toolSupport));
128018
- }
128019
- function LocalLLMTab({ isAvailable, state, ollamaStatus, systemMemory, isUsingFoundry = false, foundryModels = [], selectedFoundryModel = null, foundryStatus, onStartDownload, onCancelDownload, onInstallOllama, onStopManager, onInstallFoundry, onCheckStatus, onResetState, onSelectFoundryModel, }) {
128020
- var _a, _b, _c, _d, _e, _f, _g;
127860
+ function LocalLLMTab({ isAvailable, state, ollamaStatus, isUsingFoundry = false, foundryModels = [], selectedFoundryModel = null, foundryStatus, onInstallOllama, onStopManager, onInstallFoundry, onCheckStatus, onSelectFoundryModel, }) {
127861
+ var _a, _b, _c, _d, _e;
128021
127862
  const t = useT();
128022
- // Direct Tauri access so the model-size check can read system memory fresh at
128023
- // download-click time (the threaded `systemMemory` prop is only a fast path).
128024
- const { invoke } = useTauri();
128025
127863
  const isDownloading = state.status === 'downloading';
128026
127864
  const isManagerInstalling = state.managerInstalling || (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installing);
128027
127865
  // User preference state - independent of whether model is installed
128028
127866
  const [isEnabled, setIsEnabled] = useState(() => isLocalLLMEnabled());
128029
- // Which model the shared download flow currently targets. Prefer the model
128030
- // recorded in the persisted download state, so the correct row shows progress
128031
- // even after the dialog is closed and reopened mid-download; fall back to a
128032
- // local value for immediate feedback the instant a Download button is clicked.
128033
- const [localActiveModelId, setLocalActiveModelId] = useState(PRIMARY_MODEL_ID);
128034
- const activeModelId = state.status === 'downloading' && state.activeModel ? state.activeModel : localActiveModelId;
128035
- // Which model the user has chosen to chat with (exclusive selection).
128036
- const [selectedModelId, setSelectedModelId] = useState(() => getLocalLLMModel() || PRIMARY_MODEL_ID);
128037
- // A model the user asked to download that is large relative to this machine's
128038
- // memory. Set when we need the user to confirm a "might not run" warning before
128039
- // starting the download; null when no confirmation is pending.
128040
- const [pendingModel, setPendingModel] = useState(null);
128041
127867
  // "Enable Local Models" === run the model manager (Ollama). The toggle is a
128042
127868
  // user preference that is always operable: turning it on installs (if needed)
128043
- // and starts the manager; turning it off stops it. The card + model table are
128044
- // shown whenever the toggle is on (or mid-install), independent of install
128045
- // state, so the user always gets feedback for their choice.
127869
+ // and starts the manager; turning it off stops it. Only the manager status
127870
+ // card is shown here (whenever the toggle is on or mid-install) the per-model
127871
+ // list lives in Agent settings LLM tab, where local models are picked and
127872
+ // downloaded alongside cloud models.
128046
127873
  const managerRunning = (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.running) === true;
128047
127874
  const localModelsEnabled = isEnabled || isManagerInstalling;
128048
- // A model can be chosen for chat only once it is downloaded/ready. The backend
128049
- // reports every installed model tag, so any downloaded model qualifies.
128050
- const selectedModelReady = isCloudModelId(selectedModelId) ||
128051
- isModelInstalled(selectedModelId, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models) ||
128052
- (selectedModelId === PRIMARY_MODEL_ID &&
128053
- (state.status === 'completed' || (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true));
128054
127875
  // Track previous model installation state to detect when it first becomes installed
128055
127876
  const [, setWasModelInstalled] = useState(() => {
128056
127877
  return (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true;
@@ -128164,62 +127985,6 @@ function LocalLLMTab({ isAvailable, state, ollamaStatus, systemMemory, isUsingFo
128164
127985
  onStopManager === null || onStopManager === void 0 ? void 0 : onStopManager();
128165
127986
  }
128166
127987
  };
128167
- const startDownloadNow = (modelId) => {
128168
- setLocalActiveModelId(modelId);
128169
- onStartDownload(modelId);
128170
- };
128171
- const handleDownloadModel = async (modelId) => {
128172
- // Always read system memory FIRST — this is the call that hits the backend
128173
- // `get_system_memory`. Doing it before the catalog lookup guarantees it runs
128174
- // on every Download click (falling back to the value fetched on mount).
128175
- const model = LOCAL_MODELS.find((m) => modelId.startsWith(m.id));
128176
- if (!model) {
128177
- await invoke(TAURI_COMMANDS.LOG_STDOUT, {
128178
- s: `[Local Models] -> Download: bad download request, model ${model}`,
128179
- });
128180
- console.log(`[Local Models] -> Download: bad download request, model ${model}`);
128181
- return;
128182
- }
128183
- let mem = null;
128184
- try {
128185
- mem = await invoke(TAURI_COMMANDS.GET_SYSTEM_MEMORY);
128186
- }
128187
- catch (e) {
128188
- await invoke(TAURI_COMMANDS.LOG_STDOUT, {
128189
- s: `[Local Models] -> Download: couldn't detect system memory ${modelId} ${e}`,
128190
- });
128191
- console.log(`[Local Models] -> Download: couldn't detect system memory {e}`);
128192
- return;
128193
- }
128194
- const exceeds = modelExceedsCapacity(model, mem);
128195
- console.warn('[Local Models] -> Download: download click', {
128196
- modelId,
128197
- systemMemory: mem,
128198
- capacityBytes: usableMemoryBytes(mem),
128199
- modelBytes: parseModelSizeBytes(model.size),
128200
- thresholdBytes: usableMemoryBytes(mem) * MODEL_SIZE_WARN_FRACTION,
128201
- exceeds,
128202
- });
128203
- if (exceeds) {
128204
- setPendingModel(model);
128205
- return;
128206
- }
128207
- startDownloadNow(modelId);
128208
- };
128209
- const confirmPendingDownload = () => {
128210
- if (pendingModel) {
128211
- startDownloadNow(pendingModel.id);
128212
- }
128213
- setPendingModel(null);
128214
- };
128215
- const handleSelectModel = (modelId) => {
128216
- var _a, _b;
128217
- setSelectedModelId(modelId);
128218
- setLocalLLMModel(modelId);
128219
- // Persist the model's tool-calling support so the host can route chat to the
128220
- // MCP/tool proxy (:8000) vs plain Ollama (:11434).
128221
- setLocalLLMToolSupport((_b = (_a = LOCAL_MODELS.find((m) => m.id === modelId)) === null || _a === void 0 ? void 0 : _a.tool_support) !== null && _b !== void 0 ? _b : false);
128222
- };
128223
127988
  // For Ollama the switch reflects the user's toggle preference (always
128224
127989
  // operable, so it can be turned off). Foundry additionally requires a
128225
127990
  // downloaded model to be considered "on".
@@ -128233,54 +127998,16 @@ function LocalLLMTab({ isAvailable, state, ollamaStatus, systemMemory, isUsingFo
128233
127998
  const switchDisabled = isUsingFoundry
128234
127999
  ? !hasDownloadedFoundryModel || isDownloading || state.status === 'checking'
128235
128000
  : isDownloading || isManagerInstalling || state.status === 'checking';
128236
- return (jsxs("div", { className: "space-y-6", children: [jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: t('localLlmLocalLlmTab.enableLocalLlm') }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('localLlmLocalLlmTab.moreInfoAriaLabel'), className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium max-w-xs text-white shadow-sm transition-opacity duration-300 z-50", children: jsxs("div", { className: "space-y-2", children: [jsx("p", { children: t('localLlmLocalLlmTab.tooltipWorkOffline') }), (foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("p", { className: "text-xs text-gray-300", children: t('localLlmLocalLlmTab.tooltipFoundrySupported') }))] }) })] }) })] }), jsxs("div", { className: "flex items-center gap-2", children: [isManagerInstalling && !isUsingFoundry && (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500", "aria-label": t('localLlmLocalLlmTab.startingModelManagerAriaLabel') })), jsx(Switch, { checked: switchChecked, onCheckedChange: handleToggle, disabled: switchDisabled, "aria-label": t('localLlmLocalLlmTab.switchAriaLabel', {
128237
- state: switchChecked
128238
- ? t('localLlmLocalLlmTab.switchStateEnabled')
128239
- : t('localLlmLocalLlmTab.switchStateDisabled'),
128240
- }), className: "cursor-pointer data-[state=checked]:bg-blue-500" })] })] }), shouldShowFoundryInstall ? (jsx("div", { className: "rounded-lg border px-6 py-4 bg-blue-50/30 dark:bg-blue-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "flex items-start gap-3", children: jsxs("div", { className: "flex items-center gap-2 flex-shrink-0 mt-0.5", children: [jsx(Star$1, { className: "h-5 w-5 text-blue-600 fill-blue-600" }), jsx("span", { className: "px-2 py-0.5 text-xs font-semibold bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 rounded-full", children: t('localLlmLocalLlmTab.preferredBadge') })] }) }), jsxs("div", { className: "flex items-start gap-3", children: [jsx(Info$3, { className: "h-5 w-5 text-blue-500 flex-shrink-0 mt-0.5" }), jsxs("div", { className: "flex-1", children: [jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: t('localLlmLocalLlmTab.settingUpOfflineAi') }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('localLlmLocalLlmTab.foundryInstallDescription') })] })] }), state.status === 'downloading' || state.status === 'checking' ? (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: state.message || t('localLlmLocalLlmTab.preparingDownload') })] }), state.progress > 0 && jsx(Progress, { value: state.progress, className: "h-2" })] })) : state.status === 'error' ? (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2 text-red-600 dark:text-red-400", children: [jsx(CircleX, { className: "h-4 w-4" }), jsx("span", { className: "text-sm", children: state.error || t('localLlmLocalLlmTab.downloadFailed') })] }), jsx("div", { className: "flex gap-2", children: jsxs(Button$1, { onClick: onInstallFoundry, size: "sm", variant: "outline", children: [jsx(RefreshCw, { className: "h-4 w-4 mr-2" }), t('localLlmLocalLlmTab.tryAgain')] }) })] })) : (jsx("div", { className: "space-y-2", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: t('localLlmLocalLlmTab.startingDownload') })] }) })), jsxs("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: [jsx("p", { className: "font-medium mb-1", children: t('localLlmLocalLlmTab.downloadSize') }), jsx("p", { children: t('localLlmLocalLlmTab.oneTimeSetup') })] })] }) })) : /* Requirements Table - Hidden when using Foundry Local */ !isUsingFoundry ? (jsxs(Fragment$1, { children: [(foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("div", { className: "rounded-lg border px-4 py-3 bg-blue-50/20 dark:bg-blue-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "flex items-start gap-2", children: [jsx(Info$3, { className: "h-4 w-4 text-blue-600 flex-shrink-0 mt-0.5" }), jsxs("div", { className: "text-xs text-gray-600 dark:text-gray-400", children: [jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100", children: t('localLlmLocalLlmTab.noteLabel') }), ' ', t('localLlmLocalLlmTab.foundryAlternativeNote')] })] }) })), localModelsEnabled && (jsxs("div", { className: "rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(Server, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }), jsxs("div", { children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: t('localLlmLocalLlmTab.modelManagerName') }), jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('localLlmLocalLlmTab.modelManagerDescription') })] })] }), jsx("div", { className: "flex items-center gap-2", children: managerRunning ? (jsxs(Fragment$1, { children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(CircleCheckBig, { className: "h-3 w-3" }), t('localLlmLocalLlmTab.running')] }), jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", "aria-label": t('localLlmLocalLlmTab.refreshManagerStatusAriaLabel'), children: jsx(RefreshCw, { className: "h-4 w-4" }) })] })) : (jsxs(Fragment$1, { children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), t('localLlmLocalLlmTab.starting')] }), jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", "aria-label": t('localLlmLocalLlmTab.refreshManagerStatusAriaLabel'), children: jsx(RefreshCw, { className: "h-4 w-4" }) })] })) })] }), isManagerInstalling && (jsx("div", { className: "mt-3 w-full max-w-[240px]", children: jsx(Progress, { value: state.managerInstallProgress || 0, className: "h-1.5" }) }))] })), localModelsEnabled && (jsxs("div", { className: "rounded-lg border overflow-hidden", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("table", { className: "w-full", children: [jsx("thead", { children: jsxs("tr", { className: "bg-gray-50 dark:bg-gray-800/50", children: [jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-12", children: t('localLlmLocalLlmTab.tableHeaderUse') }), jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: t('localLlmLocalLlmTab.tableHeaderModel') }), jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: t('localLlmLocalLlmTab.tableHeaderStatus') }), jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: t('localLlmLocalLlmTab.tableHeaderAction') })] }) }), jsx("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-800", children: LOCAL_MODELS.map((model) => {
128241
- const isPrimary = model.id === PRIMARY_MODEL_ID;
128242
- const isActive = activeModelId === model.id;
128243
- // Cloud-hosted models are always available — they run on
128244
- // Ollama's cloud, so there's nothing to download.
128245
- const isCloud = isCloudModelId(model.id);
128246
- // A model is ready once Ollama reports its tag as installed.
128247
- // Fall back to (a) this row's own download having just
128248
- // completed — so it flips to "Ready" before the status
128249
- // refresh lands — and (b) the primary-model status flag.
128250
- // Cloud models are ready by default.
128251
- const isInstalled = isCloud ||
128252
- isModelInstalled(model.id, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models) ||
128253
- (isActive && state.status === 'completed') ||
128254
- (isPrimary && (ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.model_installed) === true);
128255
- // An installed model must never render a download/cancel
128256
- // state — guards against a stale persisted "downloading"
128257
- // status making an already-ready model look like it's
128258
- // still downloading (and wrongly cancellable) on reopen.
128259
- const rowDownloading = isActive && isDownloading && !isInstalled;
128260
- const rowChecking = isActive && state.status === 'checking';
128261
- const rowError = isActive && state.status === 'error';
128262
- const rowCancelled = isActive && state.status === 'cancelled';
128263
- const canDownload = !!(ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed) &&
128264
- !isInstalled &&
128265
- !rowDownloading &&
128266
- !rowChecking;
128267
- const isSelected = selectedModelId === model.id;
128268
- return (jsxs("tr", { className: isSelected ? 'bg-blue-50/40 dark:bg-blue-950/20' : undefined, children: [jsx("td", { className: "px-6 py-4", children: jsx("input", { type: "radio", name: "local-llm-model", checked: isSelected, disabled: !isInstalled, onChange: () => handleSelectModel(model.id), "aria-label": t('localLlmLocalLlmTab.useModelForChatAriaLabel', {
128269
- name: model.name,
128270
- }), title: isInstalled
128271
- ? undefined
128272
- : t('localLlmLocalLlmTab.downloadToChatTitle'), className: isInstalled
128273
- ? 'h-4 w-4 cursor-pointer accent-blue-500'
128274
- : 'h-4 w-4 cursor-not-allowed opacity-40' }) }), jsxs("td", { className: "px-6 py-4 whitespace-nowrap", 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: model.name }), jsx("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: model.size })] }), jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: model.provider })] }), jsx("td", { className: "px-6 py-4", children: jsx("div", { className: "space-y-2", children: isCloud ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(Cloud, { className: "h-3 w-3" }), t('localLlmLocalLlmTab.cloud')] })) : rowDownloading ? (jsxs("div", { className: "space-y-2", children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), Math.round(state.progress), "%"] }), jsx("div", { className: "w-full max-w-[200px]", children: jsx(Progress, { value: state.progress, className: "h-1.5" }) })] })) : rowChecking ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), t('localLlmLocalLlmTab.checking')] })) : isInstalled ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(CircleCheckBig, { className: "h-3 w-3" }), t('localLlmLocalLlmTab.ready')] })) : rowError ? (jsxs("div", { className: "space-y-1", children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300 rounded-full", children: [jsx(CircleX, { className: "h-3 w-3" }), t('localLlmLocalLlmTab.error')] }), state.error && (jsx("p", { className: "text-xs text-red-600 dark:text-red-400 max-w-[200px]", children: state.error }))] })) : rowCancelled ? (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: [jsx(X$2, { className: "h-3 w-3" }), t('localLlmLocalLlmTab.cancelled')] })) : (jsx("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300 rounded-full", children: t('localLlmLocalLlmTab.notDownloaded') })) }) }), jsx("td", { className: "px-6 py-4 text-right", children: jsxs("div", { className: "flex items-center justify-end gap-2", children: [rowDownloading && (jsxs(Button$1, { onClick: onCancelDownload, variant: "outline", size: "sm", children: [jsx(X$2, { className: "h-4 w-4 mr-2" }), t('localLlmLocalLlmTab.cancel')] })), canDownload && (jsxs(Button$1, { onClick: () => handleDownloadModel(model.id), size: "sm", variant: "outline", children: [jsx(Download, { className: "h-4 w-4 mr-2" }), t('localLlmLocalLlmTab.download')] })), rowError && (jsx(Button$1, { onClick: onResetState, variant: "ghost", size: "sm", children: t('localLlmLocalLlmTab.reset') })), isInstalled && !isCloud && (jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", children: jsx(RefreshCw, { className: "h-4 w-4" }) }))] }) })] }, model.id));
128275
- }) })] }), jsx("div", { className: "px-6 py-3 border-t text-xs text-gray-500 dark:text-gray-400", style: { borderColor: 'oklch(.922 0 0)' }, children: selectedModelReady ? (jsxs(Fragment$1, { children: [t('localLlmLocalLlmTab.chattingWith'), ' ', jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100", children: (_c = (_b = LOCAL_MODELS.find((m) => m.id === selectedModelId)) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : selectedModelId })] })) : (jsx(Fragment$1, { children: t('localLlmLocalLlmTab.noModelSelectedHint') })) })] }))] })) : (jsx("div", { className: "rounded-lg border px-6 py-4 bg-green-50/30 dark:bg-green-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "flex items-center justify-between", children: jsxs("div", { className: "flex items-center gap-3", children: [jsx(CircleCheckBig, { className: "h-8 w-8 text-green-500 flex-shrink-0" }), jsxs("div", { className: "flex-1", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: t('localLlmLocalLlmTab.offlineAiReady') }), jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-semibold bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 rounded-full", children: [jsx(Star$1, { className: "h-3 w-3 fill-blue-700 dark:fill-blue-300" }), t('localLlmLocalLlmTab.preferredBadge')] })] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('localLlmLocalLlmTab.foundryReadyDescription') })] })] }) }), foundryModels.length > 0 && (jsxs("div", { className: "space-y-2", children: [jsx("label", { className: "text-xs font-medium text-gray-700 dark:text-gray-300", children: t('localLlmLocalLlmTab.selectModelLabel') }), jsxs(Select$1, { value: selectedFoundryModel || ((_d = foundryModels[0]) === null || _d === void 0 ? void 0 : _d.id), onValueChange: (value) => onSelectFoundryModel === null || onSelectFoundryModel === void 0 ? void 0 : onSelectFoundryModel(value), children: [jsx(SelectTrigger, { className: "w-full bg-gray-50 border-gray-200 dark:bg-gray-800 dark:border-gray-700", children: jsx(SelectValue, { placeholder: t('localLlmLocalLlmTab.selectModelPlaceholder') }) }), jsx(SelectContent, { children: foundryModels.map((model) => (jsx(SelectItem, { value: model.id, children: jsxs("div", { className: "flex items-center justify-between w-full gap-4", children: [jsx("span", { className: "font-medium", children: model.name || model.id }), jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [model.device && (jsx("span", { className: "px-2 py-0.5 bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 rounded", children: model.device })), model.size && jsx("span", { children: model.size }), !model.is_downloaded && (jsx("span", { className: "px-2 py-0.5 bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300 rounded", children: t('localLlmLocalLlmTab.notDownloaded') })), model.is_downloaded && (jsx("span", { className: "px-2 py-0.5 bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300 rounded", children: t('localLlmLocalLlmTab.downloaded') }))] })] }) }, model.id))) })] }), jsxs("div", { className: "flex flex-col gap-1", children: [jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('localLlmLocalLlmTab.modelsAvailable', { count: foundryModels.length }) }), selectedFoundryModel && (jsxs("div", { className: "flex items-center gap-1.5 text-xs text-green-600 dark:text-green-400", children: [jsx(CircleCheckBig, { className: "h-3.5 w-3.5" }), jsxs("span", { children: [t('localLlmLocalLlmTab.usingModelPrefix'), ' ', ((_e = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _e === void 0 ? void 0 : _e.name) ||
128276
- selectedFoundryModel, ((_f = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _f === void 0 ? void 0 : _f.device) && (jsxs("span", { className: "ml-1 text-gray-500 dark:text-gray-400", children: ["(", (_g = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _g === void 0 ? void 0 : _g.device, ")"] }))] })] }))] })] })), state.status === 'downloading' && (jsxs("div", { className: "mt-4 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("div", { className: "animate-spin h-5 w-5 border-2 border-blue-600 dark:border-blue-400 border-t-transparent rounded-full" }), jsxs("div", { className: "flex-1", children: [jsx("p", { className: "text-sm font-medium text-blue-900 dark:text-blue-100", children: state.message }), state.progress > 0 && (jsx("div", { className: "mt-2 w-full bg-blue-200 dark:bg-blue-800 rounded-full h-2", children: jsx("div", { className: "bg-blue-600 dark:bg-blue-400 h-2 rounded-full transition-all duration-300", style: { width: `${state.progress}%` } }) }))] })] }), state.logs.length > 0 && (jsx("div", { className: "mt-3 max-h-32 overflow-y-auto bg-white dark:bg-gray-800 rounded border border-blue-200 dark:border-blue-700 p-2", children: state.logs.slice(-10).map((log, idx) => (jsx("div", { className: `text-xs font-mono ${log.level === 'error'
128277
- ? 'text-red-600 dark:text-red-400'
128278
- : log.level === 'warn'
128279
- ? 'text-yellow-600 dark:text-yellow-400'
128280
- : 'text-gray-700 dark:text-gray-300'}`, children: log.message }, idx))) }))] }))] }) }))] }), jsx(AlertDialog, { open: !!pendingModel, onOpenChange: (open) => {
128281
- if (!open)
128282
- setPendingModel(null);
128283
- }, children: jsxs(AlertDialogContent, { children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: "This model may be too large for your system" }), jsxs(AlertDialogDescription, { children: [pendingModel === null || pendingModel === void 0 ? void 0 : pendingModel.name, " needs about ", pendingModel === null || pendingModel === void 0 ? void 0 : pendingModel.size, ", but your system has", ' ', formatBytes(usableMemoryBytes(systemMemory)), " of memory available to run it. It may run very slowly or fail to load. Download anyway?"] })] }), jsxs(AlertDialogFooter, { children: [jsx(AlertDialogCancel, { onClick: () => setPendingModel(null), children: "Cancel" }), jsx(AlertDialogAction, { onClick: confirmPendingDownload, children: "Download anyway" })] })] }) })] }));
128001
+ return (jsx("div", { className: "space-y-6", children: jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: t('localLlmLocalLlmTab.enableLocalLlm') }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": t('localLlmLocalLlmTab.moreInfoAriaLabel'), className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium max-w-xs text-white shadow-sm transition-opacity duration-300 z-50", children: jsxs("div", { className: "space-y-2", children: [jsx("p", { children: t('localLlmLocalLlmTab.tooltipWorkOffline') }), (foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("p", { className: "text-xs text-gray-300", children: t('localLlmLocalLlmTab.tooltipFoundrySupported') }))] }) })] }) })] }), jsxs("div", { className: "flex items-center gap-2", children: [isManagerInstalling && !isUsingFoundry && (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500", "aria-label": t('localLlmLocalLlmTab.startingModelManagerAriaLabel') })), jsx(Switch, { checked: switchChecked, onCheckedChange: handleToggle, disabled: switchDisabled, "aria-label": t('localLlmLocalLlmTab.switchAriaLabel', {
128002
+ state: switchChecked
128003
+ ? t('localLlmLocalLlmTab.switchStateEnabled')
128004
+ : t('localLlmLocalLlmTab.switchStateDisabled'),
128005
+ }), className: "cursor-pointer data-[state=checked]:bg-blue-500" })] })] }), shouldShowFoundryInstall ? (jsx("div", { className: "rounded-lg border px-6 py-4 bg-blue-50/30 dark:bg-blue-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "flex items-start gap-3", children: jsxs("div", { className: "flex items-center gap-2 flex-shrink-0 mt-0.5", children: [jsx(Star$1, { className: "h-5 w-5 text-blue-600 fill-blue-600" }), jsx("span", { className: "px-2 py-0.5 text-xs font-semibold bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 rounded-full", children: t('localLlmLocalLlmTab.preferredBadge') })] }) }), jsxs("div", { className: "flex items-start gap-3", children: [jsx(Info$3, { className: "h-5 w-5 text-blue-500 flex-shrink-0 mt-0.5" }), jsxs("div", { className: "flex-1", children: [jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: t('localLlmLocalLlmTab.settingUpOfflineAi') }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('localLlmLocalLlmTab.foundryInstallDescription') })] })] }), state.status === 'downloading' || state.status === 'checking' ? (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: state.message || t('localLlmLocalLlmTab.preparingDownload') })] }), state.progress > 0 && jsx(Progress, { value: state.progress, className: "h-2" })] })) : state.status === 'error' ? (jsxs("div", { className: "space-y-2", children: [jsxs("div", { className: "flex items-center gap-2 text-red-600 dark:text-red-400", children: [jsx(CircleX, { className: "h-4 w-4" }), jsx("span", { className: "text-sm", children: state.error || t('localLlmLocalLlmTab.downloadFailed') })] }), jsx("div", { className: "flex gap-2", children: jsxs(Button$1, { onClick: onInstallFoundry, size: "sm", variant: "outline", children: [jsx(RefreshCw, { className: "h-4 w-4 mr-2" }), t('localLlmLocalLlmTab.tryAgain')] }) })] })) : (jsx("div", { className: "space-y-2", children: jsxs("div", { className: "flex items-center gap-2", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: t('localLlmLocalLlmTab.startingDownload') })] }) })), jsxs("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: [jsx("p", { className: "font-medium mb-1", children: t('localLlmLocalLlmTab.downloadSize') }), jsx("p", { children: t('localLlmLocalLlmTab.oneTimeSetup') })] })] }) })) : /* Requirements Table - Hidden when using Foundry Local */ !isUsingFoundry ? (jsxs(Fragment$1, { children: [(foundryStatus === null || foundryStatus === void 0 ? void 0 : foundryStatus.is_supported) && (jsx("div", { className: "rounded-lg border px-4 py-3 bg-blue-50/20 dark:bg-blue-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "flex items-start gap-2", children: [jsx(Info$3, { className: "h-4 w-4 text-blue-600 flex-shrink-0 mt-0.5" }), jsxs("div", { className: "text-xs text-gray-600 dark:text-gray-400", children: [jsx("span", { className: "font-medium text-gray-900 dark:text-gray-100", children: t('localLlmLocalLlmTab.noteLabel') }), ' ', t('localLlmLocalLlmTab.foundryAlternativeNote')] })] }) })), localModelsEnabled && (jsxs("div", { className: "rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx(Server, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }), jsxs("div", { children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: t('localLlmLocalLlmTab.modelManagerName') }), jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('localLlmLocalLlmTab.modelManagerDescription') })] })] }), jsx("div", { className: "flex items-center gap-2", children: managerRunning ? (jsxs(Fragment$1, { children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 rounded-full", children: [jsx(CircleCheckBig, { className: "h-3 w-3" }), t('localLlmLocalLlmTab.running')] }), jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", "aria-label": t('localLlmLocalLlmTab.refreshManagerStatusAriaLabel'), children: jsx(RefreshCw, { className: "h-4 w-4" }) })] })) : (jsxs(Fragment$1, { children: [jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 rounded-full", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), t('localLlmLocalLlmTab.starting')] }), jsx(Button$1, { onClick: onCheckStatus, variant: "ghost", size: "sm", "aria-label": t('localLlmLocalLlmTab.refreshManagerStatusAriaLabel'), children: jsx(RefreshCw, { className: "h-4 w-4" }) })] })) })] }), isManagerInstalling && (jsx("div", { className: "mt-3 w-full max-w-[240px]", children: jsx(Progress, { value: state.managerInstallProgress || 0, className: "h-1.5" }) }))] }))] })) : (jsx("div", { className: "rounded-lg border px-6 py-4 bg-green-50/30 dark:bg-green-950/10", style: { borderColor: 'oklch(.922 0 0)' }, children: jsxs("div", { className: "space-y-4", children: [jsx("div", { className: "flex items-center justify-between", children: jsxs("div", { className: "flex items-center gap-3", children: [jsx(CircleCheckBig, { className: "h-8 w-8 text-green-500 flex-shrink-0" }), jsxs("div", { className: "flex-1", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: t('localLlmLocalLlmTab.offlineAiReady') }), jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 text-xs font-semibold bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300 rounded-full", children: [jsx(Star$1, { className: "h-3 w-3 fill-blue-700 dark:fill-blue-300" }), t('localLlmLocalLlmTab.preferredBadge')] })] }), jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400 mt-1", children: t('localLlmLocalLlmTab.foundryReadyDescription') })] })] }) }), foundryModels.length > 0 && (jsxs("div", { className: "space-y-2", children: [jsx("label", { className: "text-xs font-medium text-gray-700 dark:text-gray-300", children: t('localLlmLocalLlmTab.selectModelLabel') }), jsxs(Select$1, { value: selectedFoundryModel || ((_b = foundryModels[0]) === null || _b === void 0 ? void 0 : _b.id), onValueChange: (value) => onSelectFoundryModel === null || onSelectFoundryModel === void 0 ? void 0 : onSelectFoundryModel(value), children: [jsx(SelectTrigger, { className: "w-full bg-gray-50 border-gray-200 dark:bg-gray-800 dark:border-gray-700", children: jsx(SelectValue, { placeholder: t('localLlmLocalLlmTab.selectModelPlaceholder') }) }), jsx(SelectContent, { children: foundryModels.map((model) => (jsx(SelectItem, { value: model.id, children: jsxs("div", { className: "flex items-center justify-between w-full gap-4", children: [jsx("span", { className: "font-medium", children: model.name || model.id }), jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [model.device && (jsx("span", { className: "px-2 py-0.5 bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 rounded", children: model.device })), model.size && jsx("span", { children: model.size }), !model.is_downloaded && (jsx("span", { className: "px-2 py-0.5 bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300 rounded", children: t('localLlmLocalLlmTab.notDownloaded') })), model.is_downloaded && (jsx("span", { className: "px-2 py-0.5 bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300 rounded", children: t('localLlmLocalLlmTab.downloaded') }))] })] }) }, model.id))) })] }), jsxs("div", { className: "flex flex-col gap-1", children: [jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t('localLlmLocalLlmTab.modelsAvailable', { count: foundryModels.length }) }), selectedFoundryModel && (jsxs("div", { className: "flex items-center gap-1.5 text-xs text-green-600 dark:text-green-400", children: [jsx(CircleCheckBig, { className: "h-3.5 w-3.5" }), jsxs("span", { children: [t('localLlmLocalLlmTab.usingModelPrefix'), ' ', ((_c = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _c === void 0 ? void 0 : _c.name) ||
128006
+ selectedFoundryModel, ((_d = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _d === void 0 ? void 0 : _d.device) && (jsxs("span", { className: "ml-1 text-gray-500 dark:text-gray-400", children: ["(", (_e = foundryModels.find((m) => m.id === selectedFoundryModel)) === null || _e === void 0 ? void 0 : _e.device, ")"] }))] })] }))] })] })), state.status === 'downloading' && (jsxs("div", { className: "mt-4 p-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("div", { className: "animate-spin h-5 w-5 border-2 border-blue-600 dark:border-blue-400 border-t-transparent rounded-full" }), jsxs("div", { className: "flex-1", children: [jsx("p", { className: "text-sm font-medium text-blue-900 dark:text-blue-100", children: state.message }), state.progress > 0 && (jsx("div", { className: "mt-2 w-full bg-blue-200 dark:bg-blue-800 rounded-full h-2", children: jsx("div", { className: "bg-blue-600 dark:bg-blue-400 h-2 rounded-full transition-all duration-300", style: { width: `${state.progress}%` } }) }))] })] }), state.logs.length > 0 && (jsx("div", { className: "mt-3 max-h-32 overflow-y-auto bg-white dark:bg-gray-800 rounded border border-blue-200 dark:border-blue-700 p-2", children: state.logs.slice(-10).map((log, idx) => (jsx("div", { className: `text-xs font-mono ${log.level === 'error'
128007
+ ? 'text-red-600 dark:text-red-400'
128008
+ : log.level === 'warn'
128009
+ ? 'text-yellow-600 dark:text-yellow-400'
128010
+ : 'text-gray-700 dark:text-gray-300'}`, children: log.message }, idx))) }))] }))] }) }))] }) }));
128284
128011
  }
128285
128012
 
128286
128013
  function LocalModelsContent(props) {
@@ -128291,195 +128018,6 @@ function LocalModelsContent(props) {
128291
128018
  return (jsxs("div", { className: "rounded-lg px-6 py-5 border border-gray-200 dark:border-gray-700", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: "Local Models" }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": "More info about Local Models", className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium max-w-xs text-white shadow-sm transition-opacity duration-300 z-50", children: jsx("p", { children: "Manage on-device AI models for offline use." }) })] }) })] }), jsx("button", { type: "button", onClick: () => setIsCollapsed((previous) => !previous), className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1", "aria-label": isCollapsed ? 'Expand Local Models' : 'Collapse Local Models', children: isCollapsed ? (jsx(ChevronDown, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" })) : (jsx(ChevronUp, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" })) })] }), !isCollapsed && (jsx("div", { className: "mt-4", children: jsx(LocalLLMTab, { ...props }) }))] }));
128292
128019
  }
128293
128020
 
128294
- const SYSTEM_CONTROL_ENABLED_KEY = 'ibl_system_control_enabled';
128295
- /**
128296
- * Whether the Computer Assistant is enabled, read from localStorage. This is a
128297
- * user preference (mirrors {@link isLocalLLMEnabled}); it reflects the toggle the
128298
- * user last chose, independent of whether the helper is installed yet.
128299
- */
128300
- function isSystemControlEnabled() {
128301
- if (typeof window === 'undefined')
128302
- return false;
128303
- return localStorage.getItem(SYSTEM_CONTROL_ENABLED_KEY) === 'true';
128304
- }
128305
- /**
128306
- * Persist the Computer Assistant enabled preference to localStorage.
128307
- */
128308
- function setSystemControlEnabled(enabled) {
128309
- if (typeof window === 'undefined')
128310
- return;
128311
- localStorage.setItem(SYSTEM_CONTROL_ENABLED_KEY, String(enabled));
128312
- }
128313
- /** Green "done" pill. */
128314
- function DonePill({ children }) {
128315
- return (jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800 dark:bg-green-900/30 dark:text-green-300", children: [jsx(Check, { className: "h-3 w-3" }), children] }));
128316
- }
128317
- /** Blue "in progress" pill. */
128318
- function WorkingPill({ children }) {
128319
- return (jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-800 dark:bg-blue-900/30 dark:text-blue-300", children: [jsx(LoaderCircle, { className: "h-3 w-3 animate-spin" }), children] }));
128320
- }
128321
- /** A single numbered step row. */
128322
- function Step$2({ number, done, title, description, action, }) {
128323
- return (jsxs("div", { className: "flex items-start justify-between gap-3", children: [jsxs("div", { className: "flex items-start gap-3", children: [jsx("span", { className: `flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full text-xs font-semibold ${done
128324
- ? 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300'
128325
- : 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400'}`, "aria-hidden": "true", children: done ? jsx(Check, { className: "h-3.5 w-3.5" }) : number }), jsxs("div", { children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: title }), jsx("div", { className: "mt-0.5 text-xs text-gray-500 dark:text-gray-400", children: description })] })] }), jsx("div", { className: "flex-shrink-0", children: action })] }));
128326
- }
128327
- /**
128328
- * Body of the "Computer Assistant" card: a plain-language on/off with two simple
128329
- * steps — set up, then allow control — so non-technical users can follow along.
128330
- * Mirrors the Local Models tab so the two cards behave the same.
128331
- */
128332
- function SystemControlTab({ isAvailable, state, status, requiredSizeGb = DEFAULT_SYSTEM_CONTROL_REQUIRED_SIZE_GB, ollamaStatus, systemMemory, accessibilityPermission, onInstall, onStop, onCheckStatus, onResetState, onRequestAccessibilityPermission, onDownloadModel, }) {
128333
- const isInstalling = state.status === 'installing' || (status === null || status === void 0 ? void 0 : status.installing) === true;
128334
- // User preference — independent of whether the helper is installed. Always
128335
- // operable so the user can turn it off again.
128336
- const [isEnabled, setIsEnabled] = useState(() => isSystemControlEnabled());
128337
- // The currently-selected local model (persisted by the Local Models card).
128338
- // Polled so a selection change in the sibling card is reflected here without a
128339
- // remount. The assistant only works well with larger models, so it's gated to
128340
- // a selected model above the size threshold.
128341
- const [selectedModel, setSelectedModel] = useState(() => getLocalLLMModel());
128342
- // Whether "Local Models" is turned on. The assistant runs on a local model, so
128343
- // it's gated off until Local Models is enabled. Polled alongside the model so a
128344
- // toggle in the sibling card is reflected without a remount.
128345
- const [localModelsEnabled, setLocalModelsEnabled] = useState(() => isLocalLLMEnabled());
128346
- useEffect(() => {
128347
- const id = setInterval(() => {
128348
- setSelectedModel(getLocalLLMModel());
128349
- setLocalModelsEnabled(isLocalLLMEnabled());
128350
- }, 1500);
128351
- return () => clearInterval(id);
128352
- }, []);
128353
- const localModelsOff = !localModelsEnabled;
128354
- const modelTooSmall = !modelSupportsSystemControl(selectedModel, requiredSizeGb);
128355
- // "Upgrade" target: the smallest catalog model that clears the size gate.
128356
- const upgradeTarget = smallestSystemControlModel(requiredSizeGb);
128357
- // Set while an upgrade is downloading a model, before we auto-enable.
128358
- const [pendingEnableModelId, setPendingEnableModelId] = useState(null);
128359
- // Model awaiting a RAM/VRAM "may be too large" confirmation before download.
128360
- const [pendingCapacityModel, setPendingCapacityModel] = useState(null);
128361
- const isUpgrading = pendingEnableModelId !== null;
128362
- const managerRunning = (status === null || status === void 0 ? void 0 : status.running) === true;
128363
- // Steps are shown whenever the toggle is on (or mid-setup), so the user always
128364
- // gets feedback for their choice.
128365
- const managerEnabled = isEnabled || isInstalling;
128366
- // Permission is known (macOS + plugin wired) and granted.
128367
- const permissionKnown = typeof accessibilityPermission === 'boolean';
128368
- const permissionGranted = accessibilityPermission === true;
128369
- const allSet = managerRunning && (!permissionKnown || permissionGranted);
128370
- // Keep the app-facing preference flag in sync with the toggle.
128371
- useEffect(() => {
128372
- setSystemControlEnabled(isEnabled);
128373
- }, [isEnabled]);
128374
- // While enabled but not yet running, keep polling so the step flips to "Ready"
128375
- // as soon as the host reports the helper is up.
128376
- useEffect(() => {
128377
- if (!isEnabled || managerRunning)
128378
- return;
128379
- const id = setInterval(() => onCheckStatus(), 2500);
128380
- return () => clearInterval(id);
128381
- }, [isEnabled, managerRunning, onCheckStatus]);
128382
- // While permission isn't granted yet, keep re-checking (the grant happens in
128383
- // System Settings) so the step flips to "Allowed" on its own.
128384
- useEffect(() => {
128385
- if (accessibilityPermission !== false)
128386
- return;
128387
- const id = setInterval(() => onCheckStatus(), 2500);
128388
- return () => clearInterval(id);
128389
- }, [accessibilityPermission, onCheckStatus]);
128390
- // After an upgrade kicks off a download, turn the assistant on once the model
128391
- // finishes downloading (it shows up in the installed list).
128392
- useEffect(() => {
128393
- if (!pendingEnableModelId)
128394
- return;
128395
- if (isModelInstalled(pendingEnableModelId, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models)) {
128396
- setPendingEnableModelId(null);
128397
- setIsEnabled(true);
128398
- onInstall();
128399
- }
128400
- }, [pendingEnableModelId, ollamaStatus, onInstall]);
128401
- if (!isAvailable) {
128402
- return (jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "The Computer Assistant is only available in the desktop app." }));
128403
- }
128404
- const handleToggle = (checked) => {
128405
- // Guard: needs Local Models on and a large-enough model.
128406
- if (checked && (localModelsOff || modelTooSmall))
128407
- return;
128408
- setIsEnabled(checked);
128409
- if (checked) {
128410
- if (!isInstalling)
128411
- onInstall();
128412
- }
128413
- else {
128414
- onStop === null || onStop === void 0 ? void 0 : onStop();
128415
- }
128416
- };
128417
- // Upgrade = switch to the smallest usable model: select it, then (if it isn't
128418
- // already downloaded) download it and auto-enable the assistant once it's
128419
- // ready. The RAM/VRAM check is preserved via the confirm below.
128420
- const runUpgrade = (model) => {
128421
- setLocalLLMModel(model.id);
128422
- setLocalLLMToolSupport(model.tool_support);
128423
- setLocalLLMEnabled(true);
128424
- setSelectedModel(model.id); // recompute the size gate immediately
128425
- if (isModelInstalled(model.id, ollamaStatus === null || ollamaStatus === void 0 ? void 0 : ollamaStatus.installed_models)) {
128426
- // Already downloaded → enable now.
128427
- setIsEnabled(true);
128428
- if (!isInstalling)
128429
- onInstall();
128430
- }
128431
- else {
128432
- // Not downloaded → download, then auto-enable when it lands (effect above).
128433
- setPendingEnableModelId(model.id);
128434
- onDownloadModel === null || onDownloadModel === void 0 ? void 0 : onDownloadModel(model.id);
128435
- }
128436
- };
128437
- const handleUpgrade = () => {
128438
- if (!upgradeTarget)
128439
- return;
128440
- // Keep the RAM/VRAM check: confirm before pulling a model that may not fit.
128441
- if (modelExceedsCapacity(upgradeTarget, systemMemory)) {
128442
- setPendingCapacityModel(upgradeTarget);
128443
- return;
128444
- }
128445
- runUpgrade(upgradeTarget);
128446
- };
128447
- const switchChecked = isEnabled;
128448
- const switchDisabled = isInstalling ||
128449
- state.status === 'checking' ||
128450
- ((localModelsOff || modelTooSmall) && !isEnabled);
128451
- return (jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border px-6 py-4", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { children: [jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: "Let your assistant control this computer" }), jsx("div", { className: "mt-0.5 text-xs text-gray-500 dark:text-gray-400", children: "It can click, type, and open apps to do tasks for you. You stay in control and can turn this off anytime." })] }), jsxs("div", { className: "flex flex-shrink-0 items-center gap-2", children: [isInstalling && (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500", "aria-label": "Setting up" })), jsx(Switch, { checked: switchChecked, onCheckedChange: handleToggle, disabled: switchDisabled, "aria-label": "Let your assistant control this computer", className: "cursor-pointer data-[state=checked]:bg-blue-500" })] })] }), localModelsOff && (jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 dark:border-amber-900/40 dark:bg-amber-900/10", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-amber-600", "aria-hidden": "true" }), jsx("p", { className: "text-xs text-amber-800 dark:text-amber-300", children: "Turn on \u201CLocal Models\u201D above first \u2014 the Computer Assistant uses a local AI model to do its work." })] })), !localModelsOff && modelTooSmall && (jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 dark:border-amber-900/40 dark:bg-amber-900/10", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-amber-600", "aria-hidden": "true" }), jsxs("div", { className: "flex-1", children: [jsxs("p", { className: "text-xs text-amber-800 dark:text-amber-300", children: ["Your current AI model is too small for this.", ' ', upgradeTarget && onDownloadModel
128452
- ? `Upgrade to ${upgradeTarget.name} (${upgradeTarget.size}) to use it.`
128453
- : 'Pick a larger one under “Local Models” above, then come back.'] }), upgradeTarget && onDownloadModel && (jsx(Button$1, { onClick: handleUpgrade, size: "sm", className: "mt-2", disabled: isUpgrading, "aria-label": `Upgrade to ${upgradeTarget.name}`, children: isUpgrading ? (jsxs(Fragment$1, { children: [jsx(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Upgrading\u2026"] })) : (jsxs(Fragment$1, { children: [jsx(CircleArrowUp, { className: "mr-2 h-4 w-4" }), "Upgrade to ", upgradeTarget.name] })) }))] })] })), isUpgrading && !modelTooSmall && (jsxs("div", { className: "flex items-start gap-2 rounded-lg border px-4 py-3", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsx(LoaderCircle, { className: "mt-0.5 h-4 w-4 flex-shrink-0 animate-spin text-blue-500", "aria-hidden": "true" }), jsx("p", { className: "text-xs text-gray-600 dark:text-gray-300", children: "Downloading your new model\u2026 it\u2019ll turn on automatically when it\u2019s ready. You can watch progress under \u201CLocal Models\u201D above." })] })), managerEnabled && (jsxs("div", { className: "space-y-4 rounded-lg border px-6 py-5", style: { borderColor: 'oklch(.922 0 0)' }, children: [allSet ? (jsxs("div", { className: "flex items-start gap-2", children: [jsx(Check, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-green-600", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-gray-700 dark:text-gray-300", children: "You\u2019re all set \u2014 your assistant can now help out on this computer." })] })) : (jsx("div", { className: "text-xs font-medium uppercase tracking-wide text-gray-400", children: "A couple of quick steps" })), jsx(Step$2, { number: 1, done: managerRunning, title: "Set up your assistant", description: "A quick, one-time setup so it can work on this computer.", action: managerRunning ? (jsx(DonePill, { children: "Ready" })) : (jsx(WorkingPill, { children: isInstalling ? 'Setting up…' : 'Starting…' })) }), (state.status === 'installing' || state.status === 'checking') && state.progress > 0 && (jsx(Progress, { value: state.progress, className: "h-1.5" })), permissionKnown && (jsx(Step$2, { number: 2, done: permissionGranted, title: "Allow it to control the computer", description: "Your Mac will ask you to confirm. This lets your assistant move the mouse and type for you.", action: permissionGranted ? (jsx(DonePill, { children: "Allowed" })) : onRequestAccessibilityPermission ? (jsx(Button$1, { onClick: onRequestAccessibilityPermission, size: "sm", "aria-label": "Allow your assistant to control the computer", children: "Allow" })) : (jsx("span", { className: "inline-flex items-center rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-800 dark:bg-amber-900/30 dark:text-amber-300", children: "Needed" })) }))] })), state.status === 'error' && (jsxs("div", { className: "rounded-lg border border-red-200 bg-red-50 px-4 py-3 dark:border-red-900/40 dark:bg-red-900/10", children: [jsxs("div", { className: "flex items-center gap-2 text-sm text-red-700 dark:text-red-300", children: [jsx(CircleX, { className: "h-4 w-4 flex-shrink-0" }), jsx("span", { children: "Something went wrong while setting up. Please try again." })] }), jsxs(Button$1, { onClick: () => {
128454
- onResetState();
128455
- onInstall();
128456
- }, size: "sm", variant: "outline", className: "mt-3", children: [jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Try again"] })] })), jsx(AlertDialog, { open: pendingCapacityModel !== null, onOpenChange: (open) => {
128457
- if (!open)
128458
- setPendingCapacityModel(null);
128459
- }, children: jsxs(AlertDialogContent, { children: [jsxs(AlertDialogHeader, { children: [jsx(AlertDialogTitle, { children: "This model may be large for your computer" }), jsxs(AlertDialogDescription, { children: [pendingCapacityModel === null || pendingCapacityModel === void 0 ? void 0 : pendingCapacityModel.name, " (", pendingCapacityModel === null || pendingCapacityModel === void 0 ? void 0 : pendingCapacityModel.size, ") may be more than your computer\u2019s memory can handle, so it could run slowly or fail to load. Download and use it anyway?"] })] }), jsxs(AlertDialogFooter, { children: [jsx(AlertDialogCancel, { children: "Cancel" }), jsx(AlertDialogAction, { onClick: () => {
128460
- const model = pendingCapacityModel;
128461
- setPendingCapacityModel(null);
128462
- if (model)
128463
- runUpgrade(model);
128464
- }, children: "Download anyway" })] })] }) })] }));
128465
- }
128466
-
128467
- /**
128468
- * Collapsible "System Control" card for the UserProfile → Advanced section.
128469
- * Mirrors {@link LocalModelsContent}: a purely presentational, titled,
128470
- * collapsible container whose body is the {@link SystemControlTab}. Availability
128471
- * and handlers are threaded in (see UserProfileDropdown, which falls back to
128472
- * {@link useGhostOs} when the host doesn't supply them). Renders nothing outside
128473
- * the desktop app.
128474
- */
128475
- function SystemControlContent(props) {
128476
- const [isCollapsed, setIsCollapsed] = useState(true);
128477
- if (!props.isAvailable) {
128478
- return null;
128479
- }
128480
- return (jsxs("div", { className: "rounded-lg px-6 py-5 border border-gray-200 dark:border-gray-700", style: { borderColor: 'oklch(.922 0 0)' }, children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: "text-sm font-medium text-[#646464]", children: "Computer Assistant" }), jsx(TooltipProvider, { children: jsxs(Tooltip$1, { children: [jsx(TooltipTrigger, { "aria-label": "More info about the Computer Assistant", className: "hidden sm:block", children: jsx(Info$3, { className: "h-4 w-4 text-gray-400" }) }), jsx(TooltipContent, { className: "rounded-lg bg-gray-700 px-3 py-2 text-sm font-medium max-w-xs text-white shadow-sm transition-opacity duration-300 z-50", children: jsx("p", { children: "Let your assistant do things on your computer \u2014 click, type, and open apps. You stay in control and can turn it off anytime." }) })] }) })] }), jsx("button", { type: "button", onClick: () => setIsCollapsed((previous) => !previous), className: "p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1", "aria-label": isCollapsed ? 'Expand Computer Assistant' : 'Collapse Computer Assistant', children: isCollapsed ? (jsx(ChevronDown, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" })) : (jsx(ChevronUp, { className: "h-5 w-5 text-gray-400", "aria-hidden": "true" })) })] }), !isCollapsed && (jsx("div", { className: "mt-4", children: jsx(SystemControlTab, { ...props }) }))] }));
128481
- }
128482
-
128483
128021
  // src/primitive.tsx
128484
128022
  var NODES = [
128485
128023
  "a",
@@ -176503,6 +176041,26 @@ function ChatPrivacyTab({ org, username }) {
176503
176041
  }) })] }));
176504
176042
  }
176505
176043
 
176044
+ const COWORK_ENABLED_KEY = 'ibl_cowork_enabled';
176045
+ /**
176046
+ * Whether Cowork is enabled, read from localStorage. This is a user preference
176047
+ * (mirrors isLocalLLMEnabled); it reflects the toggle the user last chose,
176048
+ * independent of whether the assistant is installed yet.
176049
+ */
176050
+ function isCoworkEnabled() {
176051
+ if (typeof window === 'undefined')
176052
+ return false;
176053
+ return localStorage.getItem(COWORK_ENABLED_KEY) === 'true';
176054
+ }
176055
+ /**
176056
+ * Persist the Cowork enabled preference to localStorage.
176057
+ */
176058
+ function setCoworkEnabled(enabled) {
176059
+ if (typeof window === 'undefined')
176060
+ return;
176061
+ localStorage.setItem(COWORK_ENABLED_KEY, String(enabled));
176062
+ }
176063
+
176506
176064
  const renderLucideIcon = (Icon) => function RenderedIcon(props) {
176507
176065
  return jsx(Icon, { ...props });
176508
176066
  };
@@ -176529,7 +176087,7 @@ const TAB_DESC_PREVIEW_KEYS = {
176529
176087
  memory: 'descMemoryPreview',
176530
176088
  privacy: 'descPrivacyPreview',
176531
176089
  };
176532
- function Profile({ tenant, username, tenants, onClose, customization = {}, isAdmin = false, targetTab = 'basic', onAccountDeleted, enableMemoryTab = false, localLLMProps, systemControlProps, currentSPA = '', }) {
176090
+ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdmin = false, targetTab = 'basic', onAccountDeleted, enableMemoryTab = false, localLLMProps, currentSPA = '', }) {
176533
176091
  var _a, _b, _c, _d, _e, _f, _g, _h;
176534
176092
  const t = useT();
176535
176093
  const { data: memsearchStatus, isError: isMemsearchStatusError } = useGetMemsearchStatusQuery({ org: tenant, userId: username }, { skip: !enableMemoryTab });
@@ -176606,9 +176164,8 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
176606
176164
  ]
176607
176165
  : []),
176608
176166
  ];
176609
- // Add Advanced tab only when in Tauri app (Local Models or System Control is
176610
- // provided and available)
176611
- const isAdvancedAvailable = (localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable) === true || (systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.isAvailable) === true;
176167
+ // Add Advanced tab only when in Tauri app (Local Models is provided and available)
176168
+ const isAdvancedAvailable = (localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable) === true;
176612
176169
  const TABS = isAdvancedAvailable
176613
176170
  ? [
176614
176171
  ...baseTabs,
@@ -176774,7 +176331,7 @@ function Profile({ tenant, username, tenants, onClose, customization = {}, isAdm
176774
176331
  var _a;
176775
176332
  return (jsxs(Fragment$1, { children: [jsxs("div", { className: "relative mb-0", children: [jsx("div", { className: "absolute inset-y-0 left-4 flex items-center pointer-events-none", "aria-hidden": "true", children: jsx("div", { className: "bg-black text-white rounded w-8 h-8 flex items-center justify-center", children: jsx("span", { className: "font-bold text-sm", children: "X" }) }) }), jsx(Input, { id: "x", className: "w-full bg-gray-50 border-gray-200 focus:ring-blue-500 focus:border-blue-500 text-base py-3 pl-16 h-10", placeholder: t('profileIndex.placeholderX'), value: field.state.value, onChange: (e) => handleSocialLinkChange(e.target.value, field.handleChange, X_URL_PREFIX), disabled: socialForm.state.isSubmitting || isReadOnly })] }), jsx("p", { className: "text-red-500 dark:text-gray-400 text-sm", role: ((_a = field.state.meta.errors) === null || _a === void 0 ? void 0 : _a.length) ? 'alert' : undefined, "aria-live": "polite", children: field.state.meta.errors })] }));
176776
176333
  },
176777
- })] })] }) })), activeTab === 'education' && (jsxs(Tabs, { value: educationSubTab, onValueChange: setEducationSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "education", children: t('profileIndex.tabEducation') }), jsx(TabsTrigger, { value: "credentials", children: t('gradebookGradebookTab.typeCredentials') }), jsx(TabsTrigger, { value: "skills", children: t('gradebookGradebookTab.typeSkills') })] }), headerAddButton] }), jsx(TabsContent, { value: "education", children: jsx(EducationTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "credentials", children: jsx(CredentialsList, { org: tenant, username: username }) }), jsx(TabsContent, { value: "skills", children: jsx(SkillsList, { org: tenant, username: username }) })] })), activeTab === 'gradebook' && jsx(GradebookTab, { org: tenant, username: username }), activeTab === 'experience' && (jsxs(Tabs, { value: experienceSubTab, onValueChange: setExperienceSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "experience", children: t('profileIndex.tabExperience') }), jsx(TabsTrigger, { value: "resume", children: t('profileIndex.tabResume') })] }), headerAddButton] }), jsx(TabsContent, { value: "experience", children: jsx(ExperienceTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "resume", children: jsx(ResumeTab, { org: tenant, username: username }) })] })), activeTab === 'purchases' && jsx(PurchasesTab, { org: tenant, username: username }), activeTab === 'memory' && jsx(MemoryTab, { org: tenant, username: username }), activeTab === 'privacy' && jsx(ChatPrivacyTab, { org: tenant, username: username }), !isReadOnly && activeTab === 'security' && (jsx(Security, { app: currentSPA || '', email: (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email) || '', platformKey: tenant, onAccountDeleted: onAccountDeleted })), activeTab === 'advanced' && (localLLMProps || systemControlProps) && (jsxs("div", { className: "space-y-6", children: [localLLMProps && (jsx(LocalModelsContent, { isAvailable: localLLMProps.isAvailable, state: localLLMProps.state, ollamaStatus: localLLMProps.ollamaStatus, systemMemory: localLLMProps.systemMemory, isUsingFoundry: localLLMProps.isUsingFoundry, foundryModels: localLLMProps.foundryModels, selectedFoundryModel: localLLMProps.selectedFoundryModel, foundryStatus: localLLMProps.foundryStatus, onStartDownload: localLLMProps.onStartDownload, onCancelDownload: localLLMProps.onCancelDownload, onInstallOllama: localLLMProps.onInstallOllama, onStopManager: localLLMProps.onStopManager, onInstallFoundry: localLLMProps.onInstallFoundry, onCheckStatus: localLLMProps.onCheckStatus, onResetState: localLLMProps.onResetState, onSelectFoundryModel: localLLMProps.onSelectFoundryModel })), systemControlProps && (jsx(SystemControlContent, { isAvailable: systemControlProps.isAvailable, state: systemControlProps.state, status: systemControlProps.status, requiredSizeGb: systemControlProps.requiredSizeGb, ollamaStatus: systemControlProps.ollamaStatus, systemMemory: systemControlProps.systemMemory, accessibilityPermission: systemControlProps.accessibilityPermission, onInstall: systemControlProps.onInstall, onStop: systemControlProps.onStop, onCheckStatus: systemControlProps.onCheckStatus, onResetState: systemControlProps.onResetState, onRequestAccessibilityPermission: systemControlProps.onRequestAccessibilityPermission, onDownloadModel: systemControlProps.onDownloadModel }))] }))] }), !isReadOnly && ['basic', 'social'].includes(activeTab) && (jsx("div", { className: "flex-shrink-0 border-t border-gray-200 p-6 bg-white dark:bg-gray-900", children: jsxs("div", { className: "flex justify-end gap-3", children: [jsx(Button$1, { onClick: onClose, variant: "outline", children: t('profileIndex.buttonCancel') }), jsx(Button$1, { onClick: () => {
176334
+ })] })] }) })), activeTab === 'education' && (jsxs(Tabs, { value: educationSubTab, onValueChange: setEducationSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "education", children: t('profileIndex.tabEducation') }), jsx(TabsTrigger, { value: "credentials", children: t('gradebookGradebookTab.typeCredentials') }), jsx(TabsTrigger, { value: "skills", children: t('gradebookGradebookTab.typeSkills') })] }), headerAddButton] }), jsx(TabsContent, { value: "education", children: jsx(EducationTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "credentials", children: jsx(CredentialsList, { org: tenant, username: username }) }), jsx(TabsContent, { value: "skills", children: jsx(SkillsList, { org: tenant, username: username }) })] })), activeTab === 'gradebook' && jsx(GradebookTab, { org: tenant, username: username }), activeTab === 'experience' && (jsxs(Tabs, { value: experienceSubTab, onValueChange: setExperienceSubTab, className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxs(TabsList, { children: [jsx(TabsTrigger, { value: "experience", children: t('profileIndex.tabExperience') }), jsx(TabsTrigger, { value: "resume", children: t('profileIndex.tabResume') })] }), headerAddButton] }), jsx(TabsContent, { value: "experience", children: jsx(ExperienceTab, { org: tenant, username: username }) }), jsx(TabsContent, { value: "resume", children: jsx(ResumeTab, { org: tenant, username: username }) })] })), activeTab === 'purchases' && jsx(PurchasesTab, { org: tenant, username: username }), activeTab === 'memory' && jsx(MemoryTab, { org: tenant, username: username }), activeTab === 'privacy' && jsx(ChatPrivacyTab, { org: tenant, username: username }), !isReadOnly && activeTab === 'security' && (jsx(Security, { app: currentSPA || '', email: (userMetadata === null || userMetadata === void 0 ? void 0 : userMetadata.email) || '', platformKey: tenant, onAccountDeleted: onAccountDeleted })), activeTab === 'advanced' && localLLMProps && (jsx("div", { className: "space-y-6", children: jsx(LocalModelsContent, { isAvailable: localLLMProps.isAvailable, state: localLLMProps.state, ollamaStatus: localLLMProps.ollamaStatus, systemMemory: localLLMProps.systemMemory, isUsingFoundry: localLLMProps.isUsingFoundry, foundryModels: localLLMProps.foundryModels, selectedFoundryModel: localLLMProps.selectedFoundryModel, foundryStatus: localLLMProps.foundryStatus, onStartDownload: localLLMProps.onStartDownload, onCancelDownload: localLLMProps.onCancelDownload, onInstallOllama: localLLMProps.onInstallOllama, onStopManager: localLLMProps.onStopManager, onInstallFoundry: localLLMProps.onInstallFoundry, onCheckStatus: localLLMProps.onCheckStatus, onResetState: localLLMProps.onResetState, onSelectFoundryModel: localLLMProps.onSelectFoundryModel }) }))] }), !isReadOnly && ['basic', 'social'].includes(activeTab) && (jsx("div", { className: "flex-shrink-0 border-t border-gray-200 p-6 bg-white dark:bg-gray-900", children: jsxs("div", { className: "flex justify-end gap-3", children: [jsx(Button$1, { onClick: onClose, variant: "outline", children: t('profileIndex.buttonCancel') }), jsx(Button$1, { onClick: () => {
176778
176335
  if (activeTab === 'basic') {
176779
176336
  basicForm.handleSubmit();
176780
176337
  }
@@ -178253,11 +177810,11 @@ var PopoverAnchor$1 = React.forwardRef(
178253
177810
  }
178254
177811
  );
178255
177812
  PopoverAnchor$1.displayName = ANCHOR_NAME$1;
178256
- var TRIGGER_NAME$2 = "PopoverTrigger";
177813
+ var TRIGGER_NAME$3 = "PopoverTrigger";
178257
177814
  var PopoverTrigger$1 = React.forwardRef(
178258
177815
  (props, forwardedRef) => {
178259
177816
  const { __scopePopover, ...triggerProps } = props;
178260
- const context = usePopoverContext(TRIGGER_NAME$2, __scopePopover);
177817
+ const context = usePopoverContext(TRIGGER_NAME$3, __scopePopover);
178261
177818
  const popperScope = usePopperScope$1(__scopePopover);
178262
177819
  const composedTriggerRef = useComposedRefs$1(forwardedRef, context.triggerRef);
178263
177820
  const trigger = /* @__PURE__ */ jsx(
@@ -178276,31 +177833,31 @@ var PopoverTrigger$1 = React.forwardRef(
178276
177833
  return context.hasCustomAnchor ? trigger : /* @__PURE__ */ jsx(Anchor$3, { asChild: true, ...popperScope, children: trigger });
178277
177834
  }
178278
177835
  );
178279
- PopoverTrigger$1.displayName = TRIGGER_NAME$2;
178280
- var PORTAL_NAME$1 = "PopoverPortal";
178281
- var [PortalProvider$1, usePortalContext$1] = createPopoverContext(PORTAL_NAME$1, {
177836
+ PopoverTrigger$1.displayName = TRIGGER_NAME$3;
177837
+ var PORTAL_NAME$2 = "PopoverPortal";
177838
+ var [PortalProvider$1, usePortalContext$1] = createPopoverContext(PORTAL_NAME$2, {
178282
177839
  forceMount: void 0
178283
177840
  });
178284
177841
  var PopoverPortal = (props) => {
178285
177842
  const { __scopePopover, forceMount, children, container } = props;
178286
- const context = usePopoverContext(PORTAL_NAME$1, __scopePopover);
177843
+ const context = usePopoverContext(PORTAL_NAME$2, __scopePopover);
178287
177844
  return /* @__PURE__ */ jsx(PortalProvider$1, { scope: __scopePopover, forceMount, children: /* @__PURE__ */ jsx(Presence$3, { present: forceMount || context.open, children: /* @__PURE__ */ jsx(Portal$7, { asChild: true, container, children }) }) });
178288
177845
  };
178289
- PopoverPortal.displayName = PORTAL_NAME$1;
178290
- var CONTENT_NAME$3 = "PopoverContent";
177846
+ PopoverPortal.displayName = PORTAL_NAME$2;
177847
+ var CONTENT_NAME$4 = "PopoverContent";
178291
177848
  var PopoverContent$1 = React.forwardRef(
178292
177849
  (props, forwardedRef) => {
178293
- const portalContext = usePortalContext$1(CONTENT_NAME$3, props.__scopePopover);
177850
+ const portalContext = usePortalContext$1(CONTENT_NAME$4, props.__scopePopover);
178294
177851
  const { forceMount = portalContext.forceMount, ...contentProps } = props;
178295
- const context = usePopoverContext(CONTENT_NAME$3, props.__scopePopover);
177852
+ const context = usePopoverContext(CONTENT_NAME$4, props.__scopePopover);
178296
177853
  return /* @__PURE__ */ jsx(Presence$3, { present: forceMount || context.open, children: context.modal ? /* @__PURE__ */ jsx(PopoverContentModal, { ...contentProps, ref: forwardedRef }) : /* @__PURE__ */ jsx(PopoverContentNonModal, { ...contentProps, ref: forwardedRef }) });
178297
177854
  }
178298
177855
  );
178299
- PopoverContent$1.displayName = CONTENT_NAME$3;
177856
+ PopoverContent$1.displayName = CONTENT_NAME$4;
178300
177857
  var Slot = createSlot$1("PopoverContent.RemoveScroll");
178301
177858
  var PopoverContentModal = React.forwardRef(
178302
177859
  (props, forwardedRef) => {
178303
- const context = usePopoverContext(CONTENT_NAME$3, props.__scopePopover);
177860
+ const context = usePopoverContext(CONTENT_NAME$4, props.__scopePopover);
178304
177861
  const contentRef = React.useRef(null);
178305
177862
  const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
178306
177863
  const isRightClickOutsideRef = React.useRef(false);
@@ -178340,7 +177897,7 @@ var PopoverContentModal = React.forwardRef(
178340
177897
  );
178341
177898
  var PopoverContentNonModal = React.forwardRef(
178342
177899
  (props, forwardedRef) => {
178343
- const context = usePopoverContext(CONTENT_NAME$3, props.__scopePopover);
177900
+ const context = usePopoverContext(CONTENT_NAME$4, props.__scopePopover);
178344
177901
  const hasInteractedOutsideRef = React.useRef(false);
178345
177902
  const hasPointerDownOutsideRef = React.useRef(false);
178346
177903
  return /* @__PURE__ */ jsx(
@@ -178392,7 +177949,7 @@ var PopoverContentImpl = React.forwardRef(
178392
177949
  onInteractOutside,
178393
177950
  ...contentProps
178394
177951
  } = props;
178395
- const context = usePopoverContext(CONTENT_NAME$3, __scopePopover);
177952
+ const context = usePopoverContext(CONTENT_NAME$4, __scopePopover);
178396
177953
  const popperScope = usePopperScope$1(__scopePopover);
178397
177954
  useFocusGuards();
178398
177955
  return /* @__PURE__ */ jsx(
@@ -178470,26 +178027,26 @@ PopoverArrow.displayName = ARROW_NAME$2;
178470
178027
  function getState$2(open) {
178471
178028
  return open ? "open" : "closed";
178472
178029
  }
178473
- var Root2$3 = Popover$1;
178030
+ var Root2$4 = Popover$1;
178474
178031
  var Anchor2 = PopoverAnchor$1;
178475
178032
  var Trigger$1 = PopoverTrigger$1;
178476
178033
  var Portal$1 = PopoverPortal;
178477
- var Content2$1 = PopoverContent$1;
178034
+ var Content2$2 = PopoverContent$1;
178478
178035
 
178479
- const Popover = Root2$3;
178036
+ const Popover = Root2$4;
178480
178037
  const PopoverTrigger = Trigger$1;
178481
178038
  const PopoverAnchor = Anchor2;
178482
178039
  const PopoverContent = React.forwardRef(({ className, align = 'center', sideOffset = 4, portalled = true, container, ...props }, ref) => {
178483
178040
  var _a;
178484
178041
  const portalContainer = useFloatingPortalContainer();
178485
178042
  const resolvedContainer = (_a = container !== null && container !== void 0 ? container : portalContainer) !== null && _a !== void 0 ? _a : undefined;
178486
- const content = (jsx(Content2$1, { ref: ref, "data-iblai-dialog-interaction-layer": true, align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', className), ...props }));
178043
+ const content = (jsx(Content2$2, { ref: ref, "data-iblai-dialog-interaction-layer": true, align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none', className), ...props }));
178487
178044
  if (!portalled) {
178488
178045
  return content;
178489
178046
  }
178490
178047
  return jsx(Portal$1, { container: resolvedContainer, children: content });
178491
178048
  });
178492
- PopoverContent.displayName = Content2$1.displayName;
178049
+ PopoverContent.displayName = Content2$2.displayName;
178493
178050
 
178494
178051
  function UsersTab({ tenant, onInviteClick, currentSpa, showGradebookTab = false, }) {
178495
178052
  const t = useT();
@@ -180371,11 +179928,11 @@ var Collapsible$1 = React.forwardRef(
180371
179928
  }
180372
179929
  );
180373
179930
  Collapsible$1.displayName = COLLAPSIBLE_NAME;
180374
- var TRIGGER_NAME$1 = "CollapsibleTrigger";
179931
+ var TRIGGER_NAME$2 = "CollapsibleTrigger";
180375
179932
  var CollapsibleTrigger$1 = React.forwardRef(
180376
179933
  (props, forwardedRef) => {
180377
179934
  const { __scopeCollapsible, ...triggerProps } = props;
180378
- const context = useCollapsibleContext(TRIGGER_NAME$1, __scopeCollapsible);
179935
+ const context = useCollapsibleContext(TRIGGER_NAME$2, __scopeCollapsible);
180379
179936
  return /* @__PURE__ */ jsx(
180380
179937
  Primitive$2.button,
180381
179938
  {
@@ -180392,19 +179949,19 @@ var CollapsibleTrigger$1 = React.forwardRef(
180392
179949
  );
180393
179950
  }
180394
179951
  );
180395
- CollapsibleTrigger$1.displayName = TRIGGER_NAME$1;
180396
- var CONTENT_NAME$2 = "CollapsibleContent";
179952
+ CollapsibleTrigger$1.displayName = TRIGGER_NAME$2;
179953
+ var CONTENT_NAME$3 = "CollapsibleContent";
180397
179954
  var CollapsibleContent$1 = React.forwardRef(
180398
179955
  (props, forwardedRef) => {
180399
179956
  const { forceMount, ...contentProps } = props;
180400
- const context = useCollapsibleContext(CONTENT_NAME$2, props.__scopeCollapsible);
179957
+ const context = useCollapsibleContext(CONTENT_NAME$3, props.__scopeCollapsible);
180401
179958
  return /* @__PURE__ */ jsx(Presence$2, { present: forceMount || context.open, children: ({ present }) => /* @__PURE__ */ jsx(CollapsibleContentImpl, { ...contentProps, ref: forwardedRef, present }) });
180402
179959
  }
180403
179960
  );
180404
- CollapsibleContent$1.displayName = CONTENT_NAME$2;
179961
+ CollapsibleContent$1.displayName = CONTENT_NAME$3;
180405
179962
  var CollapsibleContentImpl = React.forwardRef((props, forwardedRef) => {
180406
179963
  const { __scopeCollapsible, present, children, ...contentProps } = props;
180407
- const context = useCollapsibleContext(CONTENT_NAME$2, __scopeCollapsible);
179964
+ const context = useCollapsibleContext(CONTENT_NAME$3, __scopeCollapsible);
180408
179965
  const [isPresent, setIsPresent] = React.useState(present);
180409
179966
  const ref = React.useRef(null);
180410
179967
  const composedRefs = useComposedRefs$1(forwardedRef, ref);
@@ -203640,7 +203197,7 @@ var joinTextblockForward = () => ({ state, dispatch }) => {
203640
203197
  };
203641
203198
 
203642
203199
  // src/utilities/isMacOS.ts
203643
- function isMacOS() {
203200
+ function isMacOS$1() {
203644
203201
  return typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
203645
203202
  }
203646
203203
 
@@ -203666,7 +203223,7 @@ function normalizeKeyName(name) {
203666
203223
  } else if (/^s(hift)?$/i.test(mod)) {
203667
203224
  shift = true;
203668
203225
  } else if (/^mod$/i.test(mod)) {
203669
- if (isiOS() || isMacOS()) {
203226
+ if (isiOS() || isMacOS$1()) {
203670
203227
  meta = true;
203671
203228
  } else {
203672
203229
  ctrl = true;
@@ -206643,7 +206200,7 @@ var Keymap = Extension.create({
206643
206200
  "Ctrl-a": () => this.editor.commands.selectTextblockStart(),
206644
206201
  "Ctrl-e": () => this.editor.commands.selectTextblockEnd()
206645
206202
  };
206646
- if (isiOS() || isMacOS()) {
206203
+ if (isiOS() || isMacOS$1()) {
206647
206204
  return macKeymap;
206648
206205
  }
206649
206206
  return pcKeymap;
@@ -217172,17 +216729,184 @@ var RadioGroupIndicator = React.forwardRef(
217172
216729
  }
217173
216730
  );
217174
216731
  RadioGroupIndicator.displayName = INDICATOR_NAME2;
217175
- var Root2$2 = RadioGroup$1;
216732
+ var Root2$3 = RadioGroup$1;
217176
216733
  var Item2 = RadioGroupItem$1;
217177
216734
  var Indicator = RadioGroupIndicator;
217178
216735
 
217179
216736
  function RadioGroup({ className, ...props }) {
217180
- return (jsx(Root2$2, { "data-slot": "radio-group", className: cn('grid gap-3', className), ...props }));
216737
+ return (jsx(Root2$3, { "data-slot": "radio-group", className: cn('grid gap-3', className), ...props }));
217181
216738
  }
217182
216739
  function RadioGroupItem({ className, ...props }) {
217183
216740
  return (jsx(Item2, { "data-slot": "radio-group-item", className: cn('border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', className), ...props, children: jsx(Indicator, { "data-slot": "radio-group-indicator", className: "relative flex items-center justify-center", children: jsx(Circle, { className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" }) }) }));
217184
216741
  }
217185
216742
 
216743
+ var SLOTTABLE_IDENTIFIER = Symbol("radix.slottable");
216744
+ // @__NO_SIDE_EFFECTS__
216745
+ function createSlottable(ownerName) {
216746
+ const Slottable2 = ({ children }) => {
216747
+ return /* @__PURE__ */ jsx(Fragment$1, { children });
216748
+ };
216749
+ Slottable2.displayName = `${ownerName}.Slottable`;
216750
+ Slottable2.__radixId = SLOTTABLE_IDENTIFIER;
216751
+ return Slottable2;
216752
+ }
216753
+
216754
+ var ROOT_NAME = "AlertDialog";
216755
+ var [createAlertDialogContext] = createContextScope$1(ROOT_NAME, [
216756
+ createDialogScope
216757
+ ]);
216758
+ var useDialogScope = createDialogScope();
216759
+ var AlertDialog$1 = (props) => {
216760
+ const { __scopeAlertDialog, ...alertDialogProps } = props;
216761
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216762
+ return /* @__PURE__ */ jsx(DialogPrimitive.Root, { ...dialogScope, ...alertDialogProps, modal: true });
216763
+ };
216764
+ AlertDialog$1.displayName = ROOT_NAME;
216765
+ var TRIGGER_NAME$1 = "AlertDialogTrigger";
216766
+ var AlertDialogTrigger = React.forwardRef(
216767
+ (props, forwardedRef) => {
216768
+ const { __scopeAlertDialog, ...triggerProps } = props;
216769
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216770
+ return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { ...dialogScope, ...triggerProps, ref: forwardedRef });
216771
+ }
216772
+ );
216773
+ AlertDialogTrigger.displayName = TRIGGER_NAME$1;
216774
+ var PORTAL_NAME$1 = "AlertDialogPortal";
216775
+ var AlertDialogPortal$1 = (props) => {
216776
+ const { __scopeAlertDialog, ...portalProps } = props;
216777
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216778
+ return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { ...dialogScope, ...portalProps });
216779
+ };
216780
+ AlertDialogPortal$1.displayName = PORTAL_NAME$1;
216781
+ var OVERLAY_NAME = "AlertDialogOverlay";
216782
+ var AlertDialogOverlay$1 = React.forwardRef(
216783
+ (props, forwardedRef) => {
216784
+ const { __scopeAlertDialog, ...overlayProps } = props;
216785
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216786
+ return /* @__PURE__ */ jsx(DialogPrimitive.Overlay, { ...dialogScope, ...overlayProps, ref: forwardedRef });
216787
+ }
216788
+ );
216789
+ AlertDialogOverlay$1.displayName = OVERLAY_NAME;
216790
+ var CONTENT_NAME$2 = "AlertDialogContent";
216791
+ var [AlertDialogContentProvider, useAlertDialogContentContext] = createAlertDialogContext(CONTENT_NAME$2);
216792
+ var Slottable = createSlottable("AlertDialogContent");
216793
+ var AlertDialogContent$1 = React.forwardRef(
216794
+ (props, forwardedRef) => {
216795
+ const { __scopeAlertDialog, children, ...contentProps } = props;
216796
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216797
+ const contentRef = React.useRef(null);
216798
+ const composedRefs = useComposedRefs$1(forwardedRef, contentRef);
216799
+ const cancelRef = React.useRef(null);
216800
+ return /* @__PURE__ */ jsx(
216801
+ DialogPrimitive.WarningProvider,
216802
+ {
216803
+ contentName: CONTENT_NAME$2,
216804
+ titleName: TITLE_NAME,
216805
+ docsSlug: "alert-dialog",
216806
+ children: /* @__PURE__ */ jsx(AlertDialogContentProvider, { scope: __scopeAlertDialog, cancelRef, children: /* @__PURE__ */ jsxs(
216807
+ DialogPrimitive.Content,
216808
+ {
216809
+ role: "alertdialog",
216810
+ ...dialogScope,
216811
+ ...contentProps,
216812
+ ref: composedRefs,
216813
+ onOpenAutoFocus: composeEventHandlers$2(contentProps.onOpenAutoFocus, (event) => {
216814
+ event.preventDefault();
216815
+ cancelRef.current?.focus({ preventScroll: true });
216816
+ }),
216817
+ onPointerDownOutside: (event) => event.preventDefault(),
216818
+ onInteractOutside: (event) => event.preventDefault(),
216819
+ children: [
216820
+ /* @__PURE__ */ jsx(Slottable, { children }),
216821
+ /* @__PURE__ */ jsx(DescriptionWarning, { contentRef })
216822
+ ]
216823
+ }
216824
+ ) })
216825
+ }
216826
+ );
216827
+ }
216828
+ );
216829
+ AlertDialogContent$1.displayName = CONTENT_NAME$2;
216830
+ var TITLE_NAME = "AlertDialogTitle";
216831
+ var AlertDialogTitle$1 = React.forwardRef(
216832
+ (props, forwardedRef) => {
216833
+ const { __scopeAlertDialog, ...titleProps } = props;
216834
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216835
+ return /* @__PURE__ */ jsx(DialogPrimitive.Title, { ...dialogScope, ...titleProps, ref: forwardedRef });
216836
+ }
216837
+ );
216838
+ AlertDialogTitle$1.displayName = TITLE_NAME;
216839
+ var DESCRIPTION_NAME = "AlertDialogDescription";
216840
+ var AlertDialogDescription$1 = React.forwardRef((props, forwardedRef) => {
216841
+ const { __scopeAlertDialog, ...descriptionProps } = props;
216842
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216843
+ return /* @__PURE__ */ jsx(DialogPrimitive.Description, { ...dialogScope, ...descriptionProps, ref: forwardedRef });
216844
+ });
216845
+ AlertDialogDescription$1.displayName = DESCRIPTION_NAME;
216846
+ var ACTION_NAME = "AlertDialogAction";
216847
+ var AlertDialogAction$1 = React.forwardRef(
216848
+ (props, forwardedRef) => {
216849
+ const { __scopeAlertDialog, ...actionProps } = props;
216850
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216851
+ return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...actionProps, ref: forwardedRef });
216852
+ }
216853
+ );
216854
+ AlertDialogAction$1.displayName = ACTION_NAME;
216855
+ var CANCEL_NAME = "AlertDialogCancel";
216856
+ var AlertDialogCancel$1 = React.forwardRef(
216857
+ (props, forwardedRef) => {
216858
+ const { __scopeAlertDialog, ...cancelProps } = props;
216859
+ const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog);
216860
+ const dialogScope = useDialogScope(__scopeAlertDialog);
216861
+ const ref = useComposedRefs$1(forwardedRef, cancelRef);
216862
+ return /* @__PURE__ */ jsx(DialogPrimitive.Close, { ...dialogScope, ...cancelProps, ref });
216863
+ }
216864
+ );
216865
+ AlertDialogCancel$1.displayName = CANCEL_NAME;
216866
+ var DescriptionWarning = ({ contentRef }) => {
216867
+ const MESSAGE = `\`${CONTENT_NAME$2}\` requires a description for the component to be accessible for screen reader users.
216868
+
216869
+ You can add a description to the \`${CONTENT_NAME$2}\` by passing a \`${DESCRIPTION_NAME}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
216870
+
216871
+ Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${CONTENT_NAME$2}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.
216872
+
216873
+ For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;
216874
+ React.useEffect(() => {
216875
+ const hasDescription = document.getElementById(
216876
+ contentRef.current?.getAttribute("aria-describedby")
216877
+ );
216878
+ if (!hasDescription) console.warn(MESSAGE);
216879
+ }, [MESSAGE, contentRef]);
216880
+ return null;
216881
+ };
216882
+ var Root2$2 = AlertDialog$1;
216883
+ var Portal2 = AlertDialogPortal$1;
216884
+ var Overlay2 = AlertDialogOverlay$1;
216885
+ var Content2$1 = AlertDialogContent$1;
216886
+ var Action = AlertDialogAction$1;
216887
+ var Cancel = AlertDialogCancel$1;
216888
+ var Title2 = AlertDialogTitle$1;
216889
+ var Description2 = AlertDialogDescription$1;
216890
+
216891
+ const AlertDialog = Root2$2;
216892
+ const AlertDialogPortal = Portal2;
216893
+ const AlertDialogOverlay = React.forwardRef(({ className, ...props }, ref) => (jsx(Overlay2, { className: cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', className), ...props, ref: ref })));
216894
+ AlertDialogOverlay.displayName = Overlay2.displayName;
216895
+ const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => (jsxs(AlertDialogPortal, { children: [jsx(AlertDialogOverlay, {}), jsx(Content2$1, { ref: ref, className: cn('bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg', className), ...props })] })));
216896
+ AlertDialogContent.displayName = Content2$1.displayName;
216897
+ const AlertDialogHeader = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col space-y-2 text-center sm:text-left', className), ...props }));
216898
+ AlertDialogHeader.displayName = 'AlertDialogHeader';
216899
+ const AlertDialogFooter = ({ className, ...props }) => (jsx("div", { className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className), ...props }));
216900
+ AlertDialogFooter.displayName = 'AlertDialogFooter';
216901
+ const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => (jsx(Title2, { ref: ref, className: cn('text-lg font-semibold', className), ...props })));
216902
+ AlertDialogTitle.displayName = Title2.displayName;
216903
+ const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => (jsx(Description2, { ref: ref, className: cn('text-muted-foreground text-sm', className), ...props })));
216904
+ AlertDialogDescription.displayName = Description2.displayName;
216905
+ const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => (jsx(Action, { ref: ref, className: cn(buttonVariants(), className), ...props })));
216906
+ AlertDialogAction.displayName = Action.displayName;
216907
+ const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (jsx(Cancel, { ref: ref, className: cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className), ...props })));
216908
+ AlertDialogCancel.displayName = Cancel.displayName;
216909
+
217186
216910
  const THEMES = { light: '', dark: '.dark' };
217187
216911
  const ChartContext = React.createContext(null);
217188
216912
  function useChart() {
@@ -252992,6 +252716,543 @@ function getLLMProviderDetails(llmProvider, llmName) {
252992
252716
  }
252993
252717
  }
252994
252718
 
252719
+ function OverlayModal({ open, onClose, title, description, className, children, }) {
252720
+ const t = useT();
252721
+ const [mounted, setMounted] = useState(false);
252722
+ const [dialogPanel, setDialogPanel] = useState(null);
252723
+ useEffect(() => {
252724
+ setMounted(true);
252725
+ }, []);
252726
+ const handleOpenChange = (nextOpen) => {
252727
+ if (!nextOpen)
252728
+ onClose();
252729
+ };
252730
+ if (!mounted || typeof document === 'undefined') {
252731
+ return null;
252732
+ }
252733
+ // Nested Radix Dialog on document.body: viewport-fixed overlay + its own scroll lock,
252734
+ // independent of any parent modal. Requires the app to resolve the same
252735
+ // `@radix-ui/react-dialog` instance as this package (peer dependency + Rollup external).
252736
+ return (jsx(DialogPrimitive.Root, { open: open, onOpenChange: handleOpenChange, modal: true, children: jsxs(DialogPrimitive.Portal, { container: document.body, children: [jsx(DialogPrimitive.Overlay, { "data-iblai-dialog-interaction-layer": true, className: cn('pointer-events-auto fixed inset-0 z-[100] bg-black/60', 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0') }), jsx(DialogPrimitive.Content, { ref: setDialogPanel, "data-iblai-dialog-interaction-layer": true, ...(!description ? { 'aria-describedby': undefined } : {}), className: cn('pointer-events-auto fixed left-[50%] top-[50%] z-[100] grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background shadow-lg duration-200', 'max-h-[min(90dvh,calc(100dvh-2rem))] max-w-[calc(100vw-2rem)] overflow-y-auto overscroll-contain rounded-lg p-6 sm:rounded-lg', 'pt-[max(1.5rem,env(safe-area-inset-top))] pb-[max(1.5rem,env(safe-area-inset-bottom))]', 'pl-[max(1.5rem,env(safe-area-inset-left))] pr-[max(1.5rem,env(safe-area-inset-right))]', 'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]', 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', className), children: jsxs(FloatingPortalContainerContext.Provider, { value: dialogPanel, children: [jsx(DialogPrimitive.Close, { type: "button", className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", "aria-label": t('clawSandboxOverlayModal.close'), children: jsx(X$2, { className: "h-4 w-4" }) }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex flex-col space-y-1.5 pr-8 text-center sm:text-left", children: [jsx(DialogPrimitive.Title, { className: "text-lg font-semibold leading-none tracking-tight", children: title }), description ? (jsx(DialogPrimitive.Description, { className: "text-sm text-muted-foreground", children: description })) : null] }), children] })] }) })] }) }));
252737
+ }
252738
+
252739
+ /** Page size for the resources list inside the Edit Skill dialog. */
252740
+ const RESOURCES_PAGE_SIZE = 20;
252741
+ const EMPTY_RESOURCE_FORM = {
252742
+ file_type: 'reference',
252743
+ filename: '',
252744
+ content: '',
252745
+ };
252746
+ /**
252747
+ * File attachments for a skill (agent-skill-resources). `reference`/`script`
252748
+ * files are text (filename + content); `asset` files are binary uploads.
252749
+ * Rendered as the Files tab of the Edit Skill dialog: a list with row
252750
+ * actions, a New File popup for add/edit, and a delete confirmation.
252751
+ */
252752
+ function SkillResourcesSection({ platformKey, skillId }) {
252753
+ var _a, _b, _c;
252754
+ const t = useT();
252755
+ const [page, setPage] = useState(1);
252756
+ const { data: resourcePage, isLoading } = useGetAgentSkillResourcesQuery({
252757
+ org: platformKey,
252758
+ skill: skillId,
252759
+ limit: RESOURCES_PAGE_SIZE,
252760
+ offset: (page - 1) * RESOURCES_PAGE_SIZE,
252761
+ });
252762
+ const resources = (_a = resourcePage === null || resourcePage === void 0 ? void 0 : resourcePage.results) !== null && _a !== void 0 ? _a : [];
252763
+ const totalCount = (_b = resourcePage === null || resourcePage === void 0 ? void 0 : resourcePage.count) !== null && _b !== void 0 ? _b : 0;
252764
+ const totalPages = Math.max(1, Math.ceil(totalCount / RESOURCES_PAGE_SIZE));
252765
+ // Deleting the last item of the last page leaves the page out of range —
252766
+ // snap back to the new last page.
252767
+ useEffect(() => {
252768
+ if (page > totalPages)
252769
+ setPage(totalPages);
252770
+ }, [page, totalPages]);
252771
+ const [createResource, { isLoading: isCreating }] = useCreateAgentSkillResourceMutation();
252772
+ const [updateResource, { isLoading: isUpdating }] = useUpdateAgentSkillResourceMutation();
252773
+ const [uploadAsset, { isLoading: isUploading }] = useUploadAgentSkillResourceAssetMutation();
252774
+ const [deleteResource, { isLoading: isDeleting }] = useDeleteAgentSkillResourceMutation();
252775
+ const [showFileDialog, setShowFileDialog] = useState(false);
252776
+ const [editingResource, setEditingResource] = useState(null);
252777
+ const [deletingResource, setDeletingResource] = useState(null);
252778
+ const [form, setForm] = useState(EMPTY_RESOURCE_FORM);
252779
+ const [assetFile, setAssetFile] = useState(null);
252780
+ const fileInputRef = useRef(null);
252781
+ const isSaving = isCreating || isUpdating || isUploading;
252782
+ const isAssetForm = form.file_type === 'asset' && !editingResource;
252783
+ const canSubmitFile = isAssetForm ? !!assetFile : !!form.filename && !!form.content;
252784
+ const typeLabel = (fileType) => {
252785
+ switch (fileType) {
252786
+ case 'script':
252787
+ return t('clawSandboxAgentSkills.fileTypeScript');
252788
+ case 'asset':
252789
+ return t('clawSandboxAgentSkills.fileTypeAsset');
252790
+ default:
252791
+ return t('clawSandboxAgentSkills.fileTypeReference');
252792
+ }
252793
+ };
252794
+ const openNewFileDialog = () => {
252795
+ setForm(EMPTY_RESOURCE_FORM);
252796
+ setAssetFile(null);
252797
+ setEditingResource(null);
252798
+ setShowFileDialog(true);
252799
+ };
252800
+ const openEditFileDialog = (resource) => {
252801
+ var _a, _b;
252802
+ setForm({
252803
+ file_type: (_a = resource.file_type) !== null && _a !== void 0 ? _a : 'reference',
252804
+ filename: resource.filename,
252805
+ content: (_b = resource.content) !== null && _b !== void 0 ? _b : '',
252806
+ });
252807
+ setAssetFile(null);
252808
+ setEditingResource(resource);
252809
+ setShowFileDialog(true);
252810
+ };
252811
+ const closeFileDialog = () => {
252812
+ setShowFileDialog(false);
252813
+ setEditingResource(null);
252814
+ setForm(EMPTY_RESOURCE_FORM);
252815
+ setAssetFile(null);
252816
+ };
252817
+ const handleSubmitFile = async () => {
252818
+ try {
252819
+ if (editingResource) {
252820
+ await updateResource({
252821
+ org: platformKey,
252822
+ id: editingResource.id,
252823
+ filename: form.filename,
252824
+ content: form.content,
252825
+ }).unwrap();
252826
+ toast.success(t('clawSandboxAgentSkills.fileSaved'));
252827
+ }
252828
+ else if (isAssetForm) {
252829
+ if (!assetFile)
252830
+ return;
252831
+ await uploadAsset({
252832
+ org: platformKey,
252833
+ skill: skillId,
252834
+ file: assetFile,
252835
+ filename: assetFile.name,
252836
+ }).unwrap();
252837
+ toast.success(t('clawSandboxAgentSkills.fileUploaded'));
252838
+ }
252839
+ else {
252840
+ await createResource({
252841
+ org: platformKey,
252842
+ skill: skillId,
252843
+ file_type: form.file_type,
252844
+ filename: form.filename,
252845
+ content: form.content,
252846
+ }).unwrap();
252847
+ toast.success(t('clawSandboxAgentSkills.fileAdded'));
252848
+ }
252849
+ closeFileDialog();
252850
+ }
252851
+ catch (_a) {
252852
+ toast.error(t(isAssetForm
252853
+ ? 'clawSandboxAgentSkills.failedToUploadFile'
252854
+ : 'clawSandboxAgentSkills.failedToSaveFile'));
252855
+ }
252856
+ };
252857
+ const handleDeleteFile = async () => {
252858
+ if (!deletingResource)
252859
+ return;
252860
+ try {
252861
+ await deleteResource({ org: platformKey, id: deletingResource.id }).unwrap();
252862
+ toast.success(t('clawSandboxAgentSkills.fileDeleted'));
252863
+ setDeletingResource(null);
252864
+ }
252865
+ catch (_a) {
252866
+ toast.error(t('clawSandboxAgentSkills.failedToDeleteFile'));
252867
+ }
252868
+ };
252869
+ const submitLabel = () => {
252870
+ if (editingResource) {
252871
+ return isUpdating ? t('clawSandboxAgentSkills.saving') : t('clawSandboxAgentSkills.save');
252872
+ }
252873
+ if (isAssetForm) {
252874
+ return isUploading
252875
+ ? t('clawSandboxAgentSkills.uploading')
252876
+ : t('clawSandboxAgentSkills.upload');
252877
+ }
252878
+ return isCreating ? t('clawSandboxAgentSkills.adding') : t('clawSandboxAgentSkills.addFileButton');
252879
+ };
252880
+ return (jsxs("div", { className: "space-y-4", "data-testid": "skill-resources-section", children: [jsxs("div", { className: "flex items-start justify-between gap-4", children: [jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.filesHint') }), jsxs(Button$1, { onClick: openNewFileDialog, size: "sm", className: "shrink-0 cursor-pointer bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.newFile')] })] }), isLoading ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingFiles') })] })) : resources.length === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noFiles') }) })) : (jsxs("div", { className: "space-y-3", children: [resources.map((resource) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", children: [jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [jsx(Paperclip, { className: "h-4 w-4 shrink-0 text-gray-400" }), jsx("span", { className: "truncate text-sm font-medium text-gray-700", children: resource.filename }), jsx("span", { className: "rounded-full bg-gray-100 px-2 py-0.5 text-[0.625rem] text-gray-500", children: typeLabel(resource.file_type) })] }), jsx(FloatingPortalContainerContext.Provider, { value: null, children: jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('clawSandboxAgentSkills.skillActions', {
252881
+ name: resource.filename,
252882
+ }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", className: "z-[110]", children: [resource.file_type === 'asset' && resource.file && (jsx(DropdownMenuItem, { asChild: true, className: "cursor-pointer", children: jsxs("a", { href: resource.file, target: "_blank", rel: "noreferrer", download: true, children: [jsx(Download, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.download')] }) })), resource.file_type !== 'asset' && (jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => openEditFileDialog(resource), children: [jsx(Pen, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.edit')] })), jsxs(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", onClick: () => setDeletingResource(resource), children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.delete')] })] })] }) })] }, resource.id))), jsx(AdvancedPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, totalCount: totalCount, itemsPerPage: RESOURCES_PAGE_SIZE, itemLabel: t('clawSandboxAgentSkills.resourcesItemLabel') })] })), jsxs(OverlayModal, { open: showFileDialog, onClose: closeFileDialog, title: t(editingResource
252883
+ ? 'clawSandboxAgentSkills.editFileDialogTitle'
252884
+ : 'clawSandboxAgentSkills.newFileDialogTitle'), className: "max-w-lg", children: [jsxs("div", { className: "mt-4 grid gap-4", children: [!editingResource && (jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "resource-type", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fileTypeLabel') }), jsxs(Select$1, { value: form.file_type, onValueChange: (value) => setForm({ ...form, file_type: value }), children: [jsx(SelectTrigger, { id: "resource-type", className: "w-full", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "reference", children: t('clawSandboxAgentSkills.fileTypeReference') }), jsx(SelectItem, { value: "script", children: t('clawSandboxAgentSkills.fileTypeScript') }), jsx(SelectItem, { value: "asset", children: t('clawSandboxAgentSkills.fileTypeAsset') })] })] })] })), isAssetForm ? (jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "resource-file", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fileNameLabel') }), jsx("input", { ref: fileInputRef, id: "resource-file", type: "file", className: "hidden", onChange: (e) => { var _a, _b; return setAssetFile((_b = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null); }, "data-testid": "resource-file-input" }), jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Button$1, { variant: "outline", size: "sm", onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, children: [jsx(Paperclip, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.chooseFile')] }), assetFile && (jsx("span", { className: "truncate text-sm text-gray-600", children: assetFile.name }))] })] })) : (jsxs(Fragment$1, { children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "resource-filename", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fileNameLabel') }), jsx(Input, { id: "resource-filename", name: "resource-filename", value: form.filename, onChange: (e) => setForm({ ...form, filename: e.target.value }), placeholder: t('clawSandboxAgentSkills.fileNamePlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "resource-content", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fileContentLabel') }), jsx(Textarea, { id: "resource-content", name: "resource-content", value: form.content, onChange: (e) => setForm({ ...form, content: e.target.value }), placeholder: t('clawSandboxAgentSkills.fileContentPlaceholder'), rows: 6 })] })] }))] }), jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [jsx(Button$1, { variant: "outline", onClick: closeFileDialog, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleSubmitFile, disabled: isSaving || !canSubmitFile, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: submitLabel() })] })] }), jsxs(OverlayModal, { open: !!deletingResource, onClose: () => setDeletingResource(null), title: t('clawSandboxAgentSkills.deleteFileDialogTitle'), className: "max-w-md", children: [jsx("p", { className: "mt-2 text-sm text-gray-600", children: t('clawSandboxAgentSkills.deleteFileConfirmation', {
252885
+ name: (_c = deletingResource === null || deletingResource === void 0 ? void 0 : deletingResource.filename) !== null && _c !== void 0 ? _c : '',
252886
+ }) }), jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [jsx(Button$1, { variant: "outline", onClick: () => setDeletingResource(null), children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleDeleteFile, disabled: isDeleting, className: "bg-red-600 text-white hover:bg-red-700", children: isDeleting
252887
+ ? t('clawSandboxAgentSkills.deleting')
252888
+ : t('clawSandboxAgentSkills.delete') })] })] })] }));
252889
+ }
252890
+
252891
+ const EMPTY_SKILL_FORM = {
252892
+ name: '',
252893
+ slug: '',
252894
+ description: '',
252895
+ version: '1.0.0',
252896
+ category: '',
252897
+ instruction: '',
252898
+ privateToAgent: false,
252899
+ };
252900
+ // The builder resolves the effective skill set client-side, which needs the
252901
+ // complete catalog and assignment lists. Request one explicit large page so
252902
+ // the result is deterministic even if the backend later configures a default
252903
+ // page size (the list endpoints unwrap paginated envelopes to `results`).
252904
+ const FULL_LIST_LIMIT = 1000;
252905
+ function AgentSkills({ platformKey, mentorUniqueId }) {
252906
+ var _a;
252907
+ const t = useT();
252908
+ // Skills are managed independently of the sandbox connection — org-level
252909
+ // skills and the mentor's assignments both resolve without a wired Claw
252910
+ // instance, so we always fetch and let admins add/assign skills freely.
252911
+ // Always fetch — the backend enforces read access; RBAC here only gates
252912
+ // the write affordances (a partial permissions map must not blank the UI).
252913
+ const { data: availableSkills, isLoading: isLoadingSkills } = useGetAgentSkillsQuery({
252914
+ org: platformKey,
252915
+ limit: FULL_LIST_LIMIT,
252916
+ offset: 0,
252917
+ });
252918
+ const { data: assignments, isLoading: isLoadingAssignments } = useGetMentorSkillAssignmentsQuery({
252919
+ org: platformKey,
252920
+ mentorUniqueId,
252921
+ limit: FULL_LIST_LIMIT,
252922
+ offset: 0,
252923
+ });
252924
+ // Assignment mutations (attach/detach/toggle on the agent)
252925
+ const [createAssignment, { isLoading: isCreatingAssignment }] = useCreateMentorSkillAssignmentMutation();
252926
+ const [updateAssignment, { isLoading: isUpdatingAssignment }] = useUpdateMentorSkillAssignmentMutation();
252927
+ const [deleteAssignment, { isLoading: isDeletingAssignment }] = useDeleteMentorSkillAssignmentMutation();
252928
+ // Skill CRUD mutations (platform-level)
252929
+ const [createSkill, { isLoading: isCreatingSkill }] = useCreateAgentSkillMutation();
252930
+ const [updateSkill, { isLoading: isUpdatingSkill }] = useUpdateAgentSkillMutation();
252931
+ const [deleteSkill, { isLoading: isDeletingSkill }] = useDeleteAgentSkillMutation();
252932
+ const [showNewDialog, setShowNewDialog] = useState(false);
252933
+ const [editingSkill, setEditingSkill] = useState(null);
252934
+ const [deletingSkill, setDeletingSkill] = useState(null);
252935
+ const [form, setForm] = useState(EMPTY_SKILL_FORM);
252936
+ const isLoading = isLoadingSkills || isLoadingAssignments;
252937
+ const isMutatingAgentSkill = isCreatingAssignment || isUpdatingAssignment || isDeletingAssignment || isUpdatingSkill;
252938
+ const allSkills = availableSkills !== null && availableSkills !== void 0 ? availableSkills : [];
252939
+ const effectiveSkills = resolveEffectiveAgentSkills(allSkills, assignments !== null && assignments !== void 0 ? assignments : [], mentorUniqueId);
252940
+ const effectiveUniqueIds = new Set(effectiveSkills.map((s) => s.unique_id));
252941
+ const effectiveSlugs = new Set(effectiveSkills.map((s) => s.slug));
252942
+ // Catalog skills this agent could still attach: enabled, platform-wide
252943
+ // (never another agent's private skills), and not already effective. A
252944
+ // skill whose slug is already effective (e.g. shadowed by a private skill)
252945
+ // would dedupe away after attaching — don't offer an Add that does nothing.
252946
+ const attachableSkills = allSkills.filter((skill) => skill.enabled &&
252947
+ !skill.mentor &&
252948
+ !effectiveUniqueIds.has(skill.unique_id) &&
252949
+ !effectiveSlugs.has(skill.slug));
252950
+ // Featured skills from the `main` platform are read-only for tenants — the
252951
+ // API 404s writes against them, so hide the edit/delete affordances.
252952
+ const isSkillEditable = (skill) => {
252953
+ if (!skill)
252954
+ return false;
252955
+ return skill.platform_key ? skill.platform_key === platformKey : !skill.is_featured;
252956
+ };
252957
+ const resetForm = () => setForm(EMPTY_SKILL_FORM);
252958
+ const handleToggleEffective = async (effective, shouldEnable) => {
252959
+ try {
252960
+ if (effective.origin === 'private' && effective.skill) {
252961
+ await updateSkill({
252962
+ org: platformKey,
252963
+ id: effective.skill.id,
252964
+ enabled: shouldEnable,
252965
+ }).unwrap();
252966
+ }
252967
+ else if (effective.assignmentId !== undefined) {
252968
+ await updateAssignment({
252969
+ org: platformKey,
252970
+ mentorUniqueId,
252971
+ assignmentPk: effective.assignmentId,
252972
+ enabled: shouldEnable,
252973
+ }).unwrap();
252974
+ }
252975
+ toast.success(t(shouldEnable
252976
+ ? 'clawSandboxAgentSkills.skillEnabled'
252977
+ : 'clawSandboxAgentSkills.skillDisabled', { name: effective.name }));
252978
+ }
252979
+ catch (_a) {
252980
+ toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name: effective.name }));
252981
+ }
252982
+ };
252983
+ const handleAttach = async (skill) => {
252984
+ try {
252985
+ await createAssignment({
252986
+ org: platformKey,
252987
+ mentorUniqueId,
252988
+ skill: skill.unique_id,
252989
+ enabled: true,
252990
+ }).unwrap();
252991
+ toast.success(t('clawSandboxAgentSkills.skillAdded', { name: skill.name }));
252992
+ }
252993
+ catch (_a) {
252994
+ toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name: skill.name }));
252995
+ }
252996
+ };
252997
+ const handleDetach = async (effective) => {
252998
+ if (effective.assignmentId === undefined)
252999
+ return;
253000
+ try {
253001
+ await deleteAssignment({
253002
+ org: platformKey,
253003
+ mentorUniqueId,
253004
+ assignmentPk: effective.assignmentId,
253005
+ }).unwrap();
253006
+ toast.success(t('clawSandboxAgentSkills.skillRemoved', { name: effective.name }));
253007
+ }
253008
+ catch (_a) {
253009
+ toast.error(t('clawSandboxAgentSkills.failedToUpdateSkill', { name: effective.name }));
253010
+ }
253011
+ };
253012
+ const openNewSkillDialog = () => {
253013
+ resetForm();
253014
+ setShowNewDialog(true);
253015
+ };
253016
+ const openEditSkillDialog = (skill) => {
253017
+ var _a;
253018
+ setForm({
253019
+ name: skill.name,
253020
+ slug: skill.slug,
253021
+ description: skill.description,
253022
+ version: skill.version,
253023
+ category: (_a = skill.category) !== null && _a !== void 0 ? _a : '',
253024
+ instruction: skill.instruction,
253025
+ privateToAgent: skill.mentor === mentorUniqueId,
253026
+ });
253027
+ setEditingSkill(skill);
253028
+ };
253029
+ const closeAllDialogs = () => {
253030
+ setShowNewDialog(false);
253031
+ setEditingSkill(null);
253032
+ resetForm();
253033
+ };
253034
+ const handleCreateSkill = async () => {
253035
+ if (!form.name || !form.slug) {
253036
+ toast.error(t('clawSandboxAgentSkills.nameAndSlugRequired'));
253037
+ return;
253038
+ }
253039
+ try {
253040
+ await createSkill({
253041
+ org: platformKey,
253042
+ name: form.name,
253043
+ slug: form.slug,
253044
+ description: form.description,
253045
+ version: form.version || '1.0.0',
253046
+ ...(form.category && { category: form.category }),
253047
+ ...(form.privateToAgent && { mentor: mentorUniqueId }),
253048
+ instruction: form.instruction,
253049
+ enabled: true,
253050
+ }).unwrap();
253051
+ toast.success(t('clawSandboxAgentSkills.skillCreated'));
253052
+ closeAllDialogs();
253053
+ }
253054
+ catch (_a) {
253055
+ toast.error(t('clawSandboxAgentSkills.failedToCreateSkill'));
253056
+ }
253057
+ };
253058
+ const handleUpdateSkill = async () => {
253059
+ if (!editingSkill)
253060
+ return;
253061
+ if (!form.name || !form.slug) {
253062
+ toast.error(t('clawSandboxAgentSkills.nameAndSlugRequired'));
253063
+ return;
253064
+ }
253065
+ try {
253066
+ await updateSkill({
253067
+ org: platformKey,
253068
+ id: editingSkill.id,
253069
+ name: form.name,
253070
+ slug: form.slug,
253071
+ description: form.description,
253072
+ version: form.version,
253073
+ category: form.category,
253074
+ instruction: form.instruction,
253075
+ }).unwrap();
253076
+ toast.success(t('clawSandboxAgentSkills.skillUpdated'));
253077
+ closeAllDialogs();
253078
+ }
253079
+ catch (_a) {
253080
+ toast.error(t('clawSandboxAgentSkills.failedToUpdateSkillGeneric'));
253081
+ }
253082
+ };
253083
+ const handleDeleteSkill = async () => {
253084
+ if (!deletingSkill)
253085
+ return;
253086
+ try {
253087
+ await deleteSkill({ org: platformKey, id: deletingSkill.id }).unwrap();
253088
+ toast.success(t('clawSandboxAgentSkills.skillDeleted'));
253089
+ setDeletingSkill(null);
253090
+ }
253091
+ catch (_a) {
253092
+ toast.error(t('clawSandboxAgentSkills.failedToDeleteSkill'));
253093
+ }
253094
+ };
253095
+ const renderBadges = (skill, effective) => {
253096
+ var _a, _b, _c;
253097
+ const category = (_a = effective === null || effective === void 0 ? void 0 : effective.category) !== null && _a !== void 0 ? _a : skill === null || skill === void 0 ? void 0 : skill.category;
253098
+ const skillType = (_b = effective === null || effective === void 0 ? void 0 : effective.skill_type) !== null && _b !== void 0 ? _b : skill === null || skill === void 0 ? void 0 : skill.skill_type;
253099
+ const isFeatured = (_c = effective === null || effective === void 0 ? void 0 : effective.is_featured) !== null && _c !== void 0 ? _c : skill === null || skill === void 0 ? void 0 : skill.is_featured;
253100
+ return (jsxs("span", { className: "flex flex-wrap items-center gap-1", children: [category && (jsx("span", { className: "rounded-full bg-gray-100 px-2 py-0.5 text-[0.625rem] text-gray-500", children: category })), skillType === 'native' && (jsx("span", { className: "rounded-full bg-purple-50 px-2 py-0.5 text-[0.625rem] text-purple-600", children: t('clawSandboxAgentSkills.nativeBadge') })), isFeatured && (jsx("span", { className: "rounded-full bg-amber-50 px-2 py-0.5 text-[0.625rem] text-amber-600", children: t('clawSandboxAgentSkills.featuredBadge') })), (effective === null || effective === void 0 ? void 0 : effective.origin) === 'private' && (jsx("span", { className: "rounded-full bg-blue-50 px-2 py-0.5 text-[0.625rem] text-blue-600", children: t('clawSandboxAgentSkills.privateBadge') }))] }));
253101
+ };
253102
+ const renderSkillMenu = (skill, effective) => {
253103
+ var _a, _b;
253104
+ const editable = isSkillEditable(skill);
253105
+ const showEdit = editable;
253106
+ const showDelete = editable;
253107
+ const detachable = (effective === null || effective === void 0 ? void 0 : effective.origin) === 'assignment';
253108
+ if (!showEdit && !showDelete && !detachable)
253109
+ return null;
253110
+ const name = (_b = (_a = effective === null || effective === void 0 ? void 0 : effective.name) !== null && _a !== void 0 ? _a : skill === null || skill === void 0 ? void 0 : skill.name) !== null && _b !== void 0 ? _b : '';
253111
+ return (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { variant: "ghost", size: "sm", "aria-label": t('clawSandboxAgentSkills.skillActions', { name }), children: jsx(Ellipsis, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [detachable && (jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => effective && handleDetach(effective), children: [jsx(CircleMinus$1, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.removeFromAgent')] })), showEdit && skill && (jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => openEditSkillDialog(skill), children: [jsx(Pen, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.edit')] })), showDelete && skill && (jsxs(DropdownMenuItem, { variant: "destructive", className: "cursor-pointer", onClick: () => setDeletingSkill(skill), children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), t('clawSandboxAgentSkills.delete')] }))] })] }));
253112
+ };
253113
+ if (isLoading) {
253114
+ return (jsxs("div", { className: "flex items-center gap-2 p-4", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.loadingSkills') })] }));
253115
+ }
253116
+ return (jsxs("div", { className: "space-y-4", "data-testid": "agent-skills-content", children: [jsxs("div", { className: "flex items-start justify-between gap-4", children: [jsxs("p", { className: "flex items-start gap-2 text-xs text-gray-500", children: [jsx(Info$3, { className: "mt-0.5 h-4 w-4 shrink-0 text-gray-400" }), jsx("span", { children: t('clawSandboxAgentSkills.sessionNote') })] }), jsxs(Button$1, { onClick: openNewSkillDialog, size: "sm", className: "shrink-0 cursor-pointer bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.newSkill')] })] }), jsxs("div", { className: "space-y-2", children: [jsx("h3", { className: "text-sm font-semibold text-gray-700", children: t('clawSandboxAgentSkills.effectiveHeading') }), effectiveSkills.length === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noEffectiveSkills') }) })) : (jsx("div", { className: "space-y-3", children: effectiveSkills.map((effective) => {
253117
+ var _a;
253118
+ return (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", children: [jsxs("div", { className: "min-w-0 space-y-1", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: effective.name }), ((_a = effective.skill) === null || _a === void 0 ? void 0 : _a.version) && (jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["v", effective.skill.version] })), renderBadges(effective.skill, effective)] }), effective.description && (jsx("p", { className: "line-clamp-2 text-xs text-gray-500", children: effective.description }))] }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [jsx(Switch, { checked: effective.enabled, onCheckedChange: (checked) => handleToggleEffective(effective, checked), disabled: isMutatingAgentSkill, className: "cursor-pointer data-[state=checked]:bg-blue-500", "aria-label": t(effective.enabled
253119
+ ? 'clawSandboxAgentSkills.skillEnabledLabel'
253120
+ : 'clawSandboxAgentSkills.skillDisabledLabel', { name: effective.name }) }), renderSkillMenu(effective.skill, effective)] })] }, effective.unique_id));
253121
+ }) }))] }), jsxs("div", { className: "space-y-2", children: [jsx("h3", { className: "text-sm font-semibold text-gray-700", children: t('clawSandboxAgentSkills.catalogHeading') }), attachableSkills.length === 0 ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: t('clawSandboxAgentSkills.noSkillsAvailable') }) })) : (jsx("div", { className: "space-y-3", children: attachableSkills.map((skill) => (jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border p-4", children: [jsxs("div", { className: "min-w-0 space-y-1", children: [jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-700", children: skill.name }), jsxs("span", { className: "hidden text-xs text-gray-400 sm:inline", children: ["v", skill.version] }), renderBadges(skill)] }), skill.description && (jsx("p", { className: "line-clamp-2 text-xs text-gray-500", children: skill.description }))] }), jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [jsxs(Button$1, { variant: "outline", size: "sm", className: "cursor-pointer", disabled: isMutatingAgentSkill, onClick: () => handleAttach(skill), "aria-label": t('clawSandboxAgentSkills.addToAgentLabel', { name: skill.name }), children: [jsx(Plus, { className: "h-4 w-4" }), t('clawSandboxAgentSkills.addToAgent')] }), renderSkillMenu(skill)] })] }, skill.id))) }))] }), jsx(OverlayModal, { open: showNewDialog, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.newSkillDialogTitle'), className: "max-w-2xl", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: [jsx(SkillForm, { form: form, onChange: setForm, showPrivateToggle: true }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.filesAfterCreateHint') })] }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleCreateSkill, disabled: isCreatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isCreatingSkill
253122
+ ? t('clawSandboxAgentSkills.creating')
253123
+ : t('clawSandboxAgentSkills.create') })] })] }) }), jsx(OverlayModal, { open: !!editingSkill, onClose: closeAllDialogs, title: t('clawSandboxAgentSkills.editSkillDialogTitle'), className: "max-w-2xl", children: jsxs(Tabs, { defaultValue: "details", className: "w-full", children: [jsxs(TabsList, { "aria-label": t('clawSandboxAgentSkills.editSkillDialogTitle'), "data-testid": "skill-dialog-tabs", children: [jsx(TabsTrigger, { value: "details", "data-testid": "skill-dialog-tab-details", children: t('clawSandboxAgentSkills.detailsTab') }), jsx(TabsTrigger, { value: "files", "data-testid": "skill-dialog-tab-files", children: t('clawSandboxAgentSkills.filesTab') })] }), jsx(TabsContent, { value: "details", children: jsxs("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: [jsx("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: jsx(SkillForm, { form: form, onChange: setForm }) }), jsxs("div", { className: "flex justify-end gap-2 border-t pt-4", children: [jsx(Button$1, { variant: "outline", onClick: closeAllDialogs, children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleUpdateSkill, disabled: isUpdatingSkill || !form.name || !form.slug, className: "bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: isUpdatingSkill
253124
+ ? t('clawSandboxAgentSkills.saving')
253125
+ : t('clawSandboxAgentSkills.save') })] })] }) }), jsx(TabsContent, { value: "files", children: jsx("div", { className: "flex h-[min(75dvh,46rem)] flex-col", children: jsx("div", { className: "flex-1 space-y-4 overflow-y-auto pb-4 pr-1", children: editingSkill && (jsx(SkillResourcesSection, { platformKey: platformKey, skillId: editingSkill.id })) }) }) })] }) }), jsxs(OverlayModal, { open: !!deletingSkill, onClose: () => setDeletingSkill(null), title: t('clawSandboxAgentSkills.deleteSkillDialogTitle'), className: "max-w-md", children: [jsx("p", { className: "mt-2 text-sm text-gray-600", children: t('clawSandboxAgentSkills.deleteConfirmation', { name: (_a = deletingSkill === null || deletingSkill === void 0 ? void 0 : deletingSkill.name) !== null && _a !== void 0 ? _a : '' }) }), jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [jsx(Button$1, { variant: "outline", onClick: () => setDeletingSkill(null), children: t('clawSandboxAgentSkills.cancel') }), jsx(Button$1, { onClick: handleDeleteSkill, disabled: isDeletingSkill, className: "bg-red-600 text-white hover:bg-red-700", children: isDeletingSkill
253126
+ ? t('clawSandboxAgentSkills.deleting')
253127
+ : t('clawSandboxAgentSkills.delete') })] })] })] }));
253128
+ }
253129
+ // ── Shared Skill Form ────────────────────────────────────────────────────────
253130
+ function SkillForm({ form, onChange, showPrivateToggle = false, }) {
253131
+ const t = useT();
253132
+ return (jsxs("div", { className: "mt-4 grid gap-4", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-name", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldName') }), jsx(Input, { id: "skill-name", name: "skill-name", value: form.name, onChange: (e) => onChange({ ...form, name: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldNamePlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-slug", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldSlug') }), jsx(Input, { id: "skill-slug", name: "skill-slug", value: form.slug, onChange: (e) => onChange({ ...form, slug: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldSlugPlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-version", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldVersion') }), jsx(Input, { id: "skill-version", name: "skill-version", value: form.version, onChange: (e) => onChange({ ...form, version: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldVersionPlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-category", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldCategory') }), jsx(Input, { id: "skill-category", name: "skill-category", value: form.category, onChange: (e) => onChange({ ...form, category: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldCategoryPlaceholder'), className: "py-6" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$1, { htmlFor: "skill-description", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldDescription') }), jsx(Input, { id: "skill-description", name: "skill-description", value: form.description, onChange: (e) => onChange({ ...form, description: e.target.value }), placeholder: t('clawSandboxAgentSkills.fieldDescriptionPlaceholder'), className: "py-6" })] }), showPrivateToggle && (jsxs("div", { className: "flex items-center justify-between rounded-lg border p-4", children: [jsxs("div", { className: "space-y-1", children: [jsx(Label$1, { htmlFor: "skill-private", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.privateToAgent') }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.privateToAgentHint') })] }), jsx(Switch, { id: "skill-private", checked: form.privateToAgent, onCheckedChange: (checked) => onChange({ ...form, privateToAgent: checked }), className: "cursor-pointer data-[state=checked]:bg-blue-500" })] })), jsxs("div", { className: "space-y-2 overflow-hidden", children: [jsx(Label$1, { htmlFor: "skill-instruction", className: "text-sm font-medium text-[#646464]", children: t('clawSandboxAgentSkills.fieldInstruction') }), jsx("p", { className: "text-xs text-gray-500", children: t('clawSandboxAgentSkills.instructionHint') }), jsx(RichTextEditor, { value: form.instruction, onChange: (value) => onChange({ ...form, instruction: value }) })] })] }));
253133
+ }
253134
+
253135
+ /** Distance (px) from the list bottom at which the next page is requested. */
253136
+ const LOAD_MORE_THRESHOLD_PX = 48;
253137
+ /**
253138
+ * Listbox half of the chat `/` skill combobox. The composer textarea owns
253139
+ * focus and keyboard handling (see `useSlashSkillPicker`); options here are
253140
+ * referenced via `aria-activedescendant` and selected on click. Scrolling
253141
+ * near the bottom lazily loads the next page of skills.
253142
+ */
253143
+ function SlashSkillPicker({ skills, activeIndex, listboxId, onSelect, onActiveIndexChange, isLoading = false, isFetchingMore = false, hasMore = false, onLoadMore, }) {
253144
+ const t = useT();
253145
+ const listRef = useRef(null);
253146
+ // Keep the active option scrolled into view during arrow-key browsing.
253147
+ useEffect(() => {
253148
+ var _a;
253149
+ const option = (_a = listRef.current) === null || _a === void 0 ? void 0 : _a.children[activeIndex];
253150
+ option === null || option === void 0 ? void 0 : option.scrollIntoView({ block: 'nearest' });
253151
+ }, [activeIndex]);
253152
+ if (skills.length === 0 && !isLoading)
253153
+ return null;
253154
+ const handleScroll = (event) => {
253155
+ if (!hasMore || isFetchingMore || !onLoadMore)
253156
+ return;
253157
+ const el = event.currentTarget;
253158
+ if (el.scrollTop + el.clientHeight >= el.scrollHeight - LOAD_MORE_THRESHOLD_PX) {
253159
+ onLoadMore();
253160
+ }
253161
+ };
253162
+ return (jsxs("div", { className: "absolute right-0 bottom-full left-0 z-50 mb-2", children: [jsx("div", { "aria-live": "polite", className: "sr-only", children: isLoading
253163
+ ? t('slashSkillPicker.loading')
253164
+ : t('slashSkillPicker.resultsAnnouncement', { count: skills.length }) }), isLoading ? (jsxs("div", { role: "status", className: "flex items-center gap-2 rounded-xl border border-gray-200 bg-white px-3 py-3 shadow-lg", "data-testid": "slash-skill-picker-loading", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: t('slashSkillPicker.loading') })] })) : (jsxs("ul", { ref: listRef, id: listboxId, role: "listbox", "aria-label": t('slashSkillPicker.listLabel'), onScroll: handleScroll, className: "max-h-64 overflow-y-auto rounded-xl border border-gray-200 bg-white p-1 shadow-lg", "data-testid": "slash-skill-picker", children: [skills.map((skill, index) => (jsxs("li", { id: `${listboxId}-option-${index}`, role: "option", "aria-selected": index === activeIndex, className: cn('flex cursor-pointer flex-col gap-0.5 rounded-lg px-3 py-2', index === activeIndex ? 'bg-blue-50' : 'hover:bg-gray-50'), onMouseEnter: () => onActiveIndexChange(index),
253165
+ // onMouseDown so selection wins over the textarea losing focus.
253166
+ onMouseDown: (e) => {
253167
+ e.preventDefault();
253168
+ onSelect(skill);
253169
+ }, children: [jsxs("span", { className: "flex items-baseline gap-2", children: [jsx("span", { className: "text-sm font-medium text-gray-800", children: skill.name }), jsxs("span", { className: "text-xs text-gray-400", children: ["/", skill.slug] }), skill.category && (jsx("span", { className: "ml-auto rounded-full bg-gray-100 px-2 py-0.5 text-[0.625rem] text-gray-500", children: skill.category }))] }), skill.description && (jsx("span", { className: "line-clamp-2 text-xs text-gray-500", children: skill.description }))] }, skill.unique_id))), isFetchingMore && (jsxs("li", { role: "presentation", className: "flex items-center gap-2 px-3 py-2", "data-testid": "slash-skill-picker-loading-more", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-xs text-gray-500", children: t('slashSkillPicker.loading') })] }))] }))] }));
253170
+ }
253171
+
253172
+ /** Matches a composer value that is a single `/`-prefixed token (no whitespace). */
253173
+ const SLASH_TOKEN_RE = /^\/\S*$/;
253174
+ /**
253175
+ * State machine for the chat `/` skill picker. Opens while the composer holds
253176
+ * a single `/`-prefixed token and at least one enabled skill matches; `Esc`
253177
+ * dismisses until the token is cleared, so plain text starting with `/` is
253178
+ * never blocked.
253179
+ */
253180
+ function useSlashSkillPicker({ inputValue, setInputValue, skills, isLoading = false, }) {
253181
+ const listboxId = useId$2();
253182
+ const [dismissed, setDismissed] = useState(false);
253183
+ const [activeIndex, setActiveIndex] = useState(0);
253184
+ const isSlashToken = SLASH_TOKEN_RE.test(inputValue);
253185
+ const query = isSlashToken ? inputValue.slice(1) : '';
253186
+ const filteredSkills = useMemo(() => (isSlashToken ? filterSlashSkills(skills, query) : []), [isSlashToken, skills, query]);
253187
+ // Loading keeps the picker open (with a loading row) so the user knows
253188
+ // something is coming; once loaded, zero matches closes it.
253189
+ const open = isSlashToken && !dismissed && (filteredSkills.length > 0 || isLoading);
253190
+ // Re-arm the picker once the slash token is gone (text sent or cleared).
253191
+ useEffect(() => {
253192
+ if (!isSlashToken && dismissed)
253193
+ setDismissed(false);
253194
+ }, [isSlashToken, dismissed]);
253195
+ // Keep the active option valid as the query narrows the list.
253196
+ const filteredLength = filteredSkills.length;
253197
+ const previousLength = useRef(filteredLength);
253198
+ useEffect(() => {
253199
+ if (previousLength.current !== filteredLength) {
253200
+ previousLength.current = filteredLength;
253201
+ setActiveIndex(0);
253202
+ }
253203
+ }, [filteredLength]);
253204
+ const selectSkill = (skill) => {
253205
+ setInputValue(`/${skill.slug} `);
253206
+ setActiveIndex(0);
253207
+ };
253208
+ const handleKeyDown = (event) => {
253209
+ if (!open)
253210
+ return false;
253211
+ switch (event.key) {
253212
+ case 'ArrowDown':
253213
+ if (!filteredSkills.length)
253214
+ return false;
253215
+ event.preventDefault();
253216
+ setActiveIndex((index) => (index + 1) % filteredSkills.length);
253217
+ return true;
253218
+ case 'ArrowUp':
253219
+ if (!filteredSkills.length)
253220
+ return false;
253221
+ event.preventDefault();
253222
+ setActiveIndex((index) => (index - 1 + filteredSkills.length) % filteredSkills.length);
253223
+ return true;
253224
+ case 'Enter':
253225
+ if (event.shiftKey || !filteredSkills.length)
253226
+ return false;
253227
+ event.preventDefault();
253228
+ selectSkill(filteredSkills[activeIndex]);
253229
+ return true;
253230
+ case 'Tab':
253231
+ if (!filteredSkills.length)
253232
+ return false;
253233
+ event.preventDefault();
253234
+ selectSkill(filteredSkills[activeIndex]);
253235
+ return true;
253236
+ case 'Escape':
253237
+ event.preventDefault();
253238
+ setDismissed(true);
253239
+ return true;
253240
+ default:
253241
+ return false;
253242
+ }
253243
+ };
253244
+ return {
253245
+ open,
253246
+ filteredSkills,
253247
+ activeIndex,
253248
+ setActiveIndex,
253249
+ listboxId,
253250
+ activeOptionId: open && filteredSkills.length > 0 ? `${listboxId}-option-${activeIndex}` : undefined,
253251
+ selectSkill,
253252
+ handleKeyDown,
253253
+ };
253254
+ }
253255
+
252995
253256
  function c$3(e,u,c){var i=this,a=useRef(null),o=useRef(0),f=useRef(null),l=useRef([]),v=useRef(),m=useRef(),d=useRef(e),g=useRef(true);d.current=e;var p="undefined"!=typeof window,w=!u&&0!==u&&p;if("function"!=typeof e)throw new TypeError("Expected a function");u=+u||0;var s=!!(c=c||{}).leading,x=!("trailing"in c)||!!c.trailing,h="maxWait"in c,y="debounceOnServer"in c&&!!c.debounceOnServer,F=h?Math.max(+c.maxWait||0,u):null;useEffect(function(){return g.current=true,function(){g.current=false;}},[]);var A=useMemo(function(){var r=function(r){var n=l.current,t=v.current;return l.current=v.current=null,o.current=r,m.current=d.current.apply(t,n)},n=function(r,n){w&&cancelAnimationFrame(f.current),f.current=w?requestAnimationFrame(r):setTimeout(r,n);},t=function(r){if(!g.current)return false;var n=r-a.current;return !a.current||n>=u||n<0||h&&r-o.current>=F},e=function(n){return f.current=null,x&&l.current?r(n):(l.current=v.current=null,m.current)},c=function r(){var c=Date.now();if(t(c))return e(c);if(g.current){var i=u-(c-a.current),f=h?Math.min(i,F-(c-o.current)):i;n(r,f);}},A=function(){if(p||y){var e=Date.now(),d=t(e);if(l.current=[].slice.call(arguments),v.current=i,a.current=e,d){if(!f.current&&g.current)return o.current=a.current,n(c,u),s?r(a.current):m.current;if(h)return n(c,u),r(a.current)}return f.current||n(c,u),m.current}};return A.cancel=function(){f.current&&(w?cancelAnimationFrame(f.current):clearTimeout(f.current)),o.current=0,l.current=a.current=v.current=f.current=null;},A.isPending=function(){return !!f.current},A.flush=function(){return f.current?e(Date.now()):m.current},A},[s,h,u,F,x,w,p,y]);return A}function i$8(r,n){return r===n}function a$3(n,t,a){var o=i$8,f=useRef(n),l=useState({})[1],v=c$3(useCallback(function(r){f.current=r,l({});},[l]),t,a),m=useRef(n);return o(m.current,n)||(v(n),m.current=n),[f.current,v]}
252996
253257
 
252997
253258
  lazy(() => Promise.resolve().then(function () { return createProjectModal; }).then((mod) => ({
@@ -253699,7 +253960,7 @@ const CSS_CLASS_NAMES = {
253699
253960
  },
253700
253961
  };
253701
253962
 
253702
- const AutoResizeTextarea = ({ allowEmptySubmit = false, value, onChange, onSubmit, disabled = false, placeholder = '', sessionId = null, isPreviewMode = false, textAreaRows = 3, className = '', style = {}, allowAnonymousAccess = false, embedMode = false, ...props }) => {
253963
+ const AutoResizeTextarea = ({ allowEmptySubmit = false, value, onChange, onSubmit, onComposerKeyDown, disabled = false, placeholder = '', sessionId = null, isPreviewMode = false, textAreaRows = 3, className = '', style = {}, allowAnonymousAccess = false, embedMode = false, ...props }) => {
253703
253964
  const textareaRef = useRef(null);
253704
253965
  const [isResizing, setIsResizing] = useState(false);
253705
253966
  const numberOfMessages = useSelector(selectNumberOfActiveChatMessages);
@@ -253747,6 +254008,8 @@ const AutoResizeTextarea = ({ allowEmptySubmit = false, value, onChange, onSubmi
253747
254008
  const handleKeyDown = (e) => {
253748
254009
  if (isPreviewMode && !allowAnonymousAccess)
253749
254010
  return;
254011
+ if (onComposerKeyDown === null || onComposerKeyDown === void 0 ? void 0 : onComposerKeyDown(e))
254012
+ return;
253750
254013
  if (e.key === 'Enter' && !e.shiftKey) {
253751
254014
  e.preventDefault();
253752
254015
  if (value.trim() || allowEmptySubmit) {
@@ -254021,8 +254284,501 @@ function MemoryButton({ mentorId, tenantKey, username }) {
254021
254284
  } }))] }) }), jsx(PopoverContent, { className: "w-96 rounded-lg border border-gray-200 bg-white p-0 shadow-xl", children: jsx(MemoryMenu, { onClose: () => setIsOpen(false), mentorId: mentorId, tenantKey: tenantKey, username: username }) })] }));
254022
254285
  }
254023
254286
 
254287
+ // Tauri types for model download functionality
254288
+ /**
254289
+ * Initial state for model download
254290
+ */
254291
+ const initialModelDownloadState = {
254292
+ status: 'idle',
254293
+ progress: 0,
254294
+ message: '',
254295
+ logs: [],
254296
+ lastUpdated: new Date().toISOString(),
254297
+ };
254298
+ /**
254299
+ * Check if the app is running inside Tauri
254300
+ * In Tauri 2.0, the global is __TAURI_INTERNALS__ (with withGlobalTauri: true)
254301
+ * We also check for __TAURI__ for backwards compatibility
254302
+ */
254303
+ const isTauriApp$1 = () => {
254304
+ if (typeof window === 'undefined')
254305
+ return false;
254306
+ return '__TAURI_INTERNALS__' in window || '__TAURI__' in window;
254307
+ };
254308
+ /**
254309
+ * Tauri event names
254310
+ */
254311
+ const TAURI_EVENTS = {
254312
+ DOWNLOAD_PROGRESS: 'model:download-progress',
254313
+ INSTALLATION_LOG: 'model:installation-log',
254314
+ DISK_SPACE_ERROR: 'model:disk-space-error',
254315
+ OLLAMA_STATUS: 'model:ollama-status',
254316
+ };
254317
+ /**
254318
+ * Tauri command names
254319
+ */
254320
+ const TAURI_COMMANDS = {
254321
+ INSTALL_OLLAMA: 'install_ollama',
254322
+ STOP_OLLAMA: 'stop_ollama',
254323
+ CHECK_OLLAMA_STATUS: 'check_ollama_status',
254324
+ CHECK_DISK_SPACE: 'check_disk_space_for_model',
254325
+ GET_SYSTEM_MEMORY: 'get_system_memory',
254326
+ DOWNLOAD_MODEL: 'download_model',
254327
+ CANCEL_DOWNLOAD: 'cancel_model_download',
254328
+ CHECK_NETWORK_STATUS: 'check_network_status',
254329
+ GET_OS_TYPE: 'get_os_type',
254330
+ CHECK_FOUNDRY_STATUS: 'check_foundry_local_status',
254331
+ START_FOUNDRY_SERVICE: 'start_foundry_local_service',
254332
+ LOAD_FOUNDRY_MODEL: 'load_foundry_local_model',
254333
+ SET_SELECTED_FOUNDRY_MODEL: 'set_selected_foundry_model',
254334
+ GET_SELECTED_FOUNDRY_MODEL: 'get_selected_foundry_model',
254335
+ INSTALL_FOUNDRY: 'install_foundry',
254336
+ DOWNLOAD_FOUNDRY_MODEL: 'download_foundry_model_cmd',
254337
+ GET_RECOMMENDED_FOUNDRY_MODELS: 'get_recommended_foundry_models',
254338
+ LOG_STDOUT: 'log_stdout',
254339
+ };
254340
+ /**
254341
+ * Initial state for the Cowork install flow.
254342
+ */
254343
+ const initialGhostOsInstallState = {
254344
+ status: 'idle',
254345
+ progress: 0,
254346
+ message: '',
254347
+ logs: [],
254348
+ lastUpdated: new Date().toISOString(),
254349
+ };
254350
+ /**
254351
+ * Tauri event names emitted by the host during GhostOS install/setup.
254352
+ */
254353
+ const GHOST_OS_TAURI_EVENTS = {
254354
+ INSTALL_PROGRESS: 'ghost-os:install-progress',
254355
+ INSTALLATION_LOG: 'ghost-os:installation-log',
254356
+ STATUS: 'ghost-os:status',
254357
+ };
254358
+ /**
254359
+ * Tauri command names the host implements for GhostOS install/setup. The web
254360
+ * layer invokes these; the native side performs the clone + setup.
254361
+ */
254362
+ const GHOST_OS_TAURI_COMMANDS = {
254363
+ /** Install and set up GhostOS (clone repo + run setup). */
254364
+ INSTALL_GHOST_OS: 'install_ghost_os',
254365
+ /** Stop the running GhostOS manager. */
254366
+ STOP_GHOST_OS: 'stop_ghost_os',
254367
+ /** Report current {@link GhostOsStatus}. */
254368
+ CHECK_GHOST_OS_STATUS: 'check_ghost_os_status',
254369
+ };
254370
+ /**
254371
+ * Tauri command strings exposed by `tauri-plugin-macos-permissions`
254372
+ * (https://github.com/ayangweb/tauri-plugin-macos-permissions). GhostOS needs
254373
+ * macOS Accessibility permission to control the device, so the Cowork
254374
+ * card surfaces it. These are invoked directly via `useTauri().invoke(...)` —
254375
+ * no extra npm dependency. The host must register the plugin in its Tauri app
254376
+ * (`tauri_plugin_macos_permissions::init()`). Each `CHECK_*` returns a boolean;
254377
+ * each `REQUEST_*` prompts / opens the relevant System Settings pane.
254378
+ */
254379
+ const MACOS_PERMISSIONS_COMMANDS = {
254380
+ CHECK_ACCESSIBILITY: 'plugin:macos-permissions|check_accessibility_permission',
254381
+ REQUEST_ACCESSIBILITY: 'plugin:macos-permissions|request_accessibility_permission',
254382
+ CHECK_SCREEN_RECORDING: 'plugin:macos-permissions|check_screen_recording_permission',
254383
+ REQUEST_SCREEN_RECORDING: 'plugin:macos-permissions|request_screen_recording_permission',
254384
+ CHECK_INPUT_MONITORING: 'plugin:macos-permissions|check_input_monitoring_permission',
254385
+ REQUEST_INPUT_MONITORING: 'plugin:macos-permissions|request_input_monitoring_permission',
254386
+ CHECK_FULL_DISK_ACCESS: 'plugin:macos-permissions|check_full_disk_access_permission',
254387
+ REQUEST_FULL_DISK_ACCESS: 'plugin:macos-permissions|request_full_disk_access_permission',
254388
+ };
254389
+
254390
+ /**
254391
+ * Dynamically import Tauri APIs to avoid SSR issues
254392
+ */
254393
+ const getTauriAPIs = async () => {
254394
+ try {
254395
+ const { invoke } = await import('@tauri-apps/api/core');
254396
+ const { listen } = await import('@tauri-apps/api/event');
254397
+ return { invoke, listen };
254398
+ }
254399
+ catch (error) {
254400
+ console.error('Failed to load Tauri APIs:', error);
254401
+ return null;
254402
+ }
254403
+ };
254404
+ /**
254405
+ * Hook to access Tauri APIs with SSR safety
254406
+ *
254407
+ * @returns Object with isAvailable flag and Tauri invoke/listen functions
254408
+ */
254409
+ function useTauri() {
254410
+ const [isAvailable, setIsAvailable] = useState(false);
254411
+ const [apis, setApis] = useState(null);
254412
+ useEffect(() => {
254413
+ // Check if we're in a Tauri environment
254414
+ const inTauri = isTauriApp$1();
254415
+ if (inTauri) {
254416
+ getTauriAPIs().then((result) => {
254417
+ setApis(result);
254418
+ setIsAvailable(!!result);
254419
+ });
254420
+ }
254421
+ }, []);
254422
+ /**
254423
+ * Invoke a Tauri command
254424
+ */
254425
+ const invoke = useCallback(async (command, args) => {
254426
+ if (!(apis === null || apis === void 0 ? void 0 : apis.invoke)) {
254427
+ throw new Error('Tauri is not available');
254428
+ }
254429
+ return apis.invoke(command, args);
254430
+ }, [apis]);
254431
+ /**
254432
+ * Listen to a Tauri event
254433
+ * Returns an unlisten function that should be called on cleanup
254434
+ */
254435
+ const listen = useCallback(async (event, handler) => {
254436
+ // The synchronous global (`__TAURI_INTERNALS__`) exposes `invoke` but
254437
+ // frequently NOT `event.listen`, so `apis.listen` can be undefined even
254438
+ // though Tauri is fully available. Fall back to the real event API via
254439
+ // dynamic import so download progress/completion events are actually
254440
+ // delivered — otherwise the UI never leaves the "downloading" state.
254441
+ let listenFn = apis === null || apis === void 0 ? void 0 : apis.listen;
254442
+ if (!listenFn) {
254443
+ const { listen: importedListen } = await import('@tauri-apps/api/event');
254444
+ listenFn = importedListen;
254445
+ }
254446
+ return listenFn(event, (e) => handler(e.payload));
254447
+ }, [apis]);
254448
+ return {
254449
+ isAvailable,
254450
+ invoke,
254451
+ listen,
254452
+ };
254453
+ }
254454
+
254455
+ const IS_SERVER = typeof window === 'undefined';
254456
+ /**
254457
+ * A simplified useLocalStorage hook for persisting state to localStorage
254458
+ * with SSR safety.
254459
+ */
254460
+ function useLocalStorage(key, initialValue) {
254461
+ // Get the initial value
254462
+ const getInitialValue = useCallback(() => {
254463
+ const initial = initialValue instanceof Function ? initialValue() : initialValue;
254464
+ if (IS_SERVER) {
254465
+ return initial;
254466
+ }
254467
+ try {
254468
+ const item = window.localStorage.getItem(key);
254469
+ if (item === null) {
254470
+ return initial;
254471
+ }
254472
+ return JSON.parse(item);
254473
+ }
254474
+ catch (error) {
254475
+ console.warn(`Error reading localStorage key "${key}":`, error);
254476
+ return initial;
254477
+ }
254478
+ }, [key, initialValue]);
254479
+ const [storedValue, setStoredValue] = useState(getInitialValue);
254480
+ // Update stored value when key changes
254481
+ useEffect(() => {
254482
+ setStoredValue(getInitialValue());
254483
+ }, [key, getInitialValue]);
254484
+ // Persist to localStorage
254485
+ const setValue = useCallback((value) => {
254486
+ if (IS_SERVER) {
254487
+ console.warn(`Tried setting localStorage key "${key}" even though environment is not a client`);
254488
+ return;
254489
+ }
254490
+ try {
254491
+ const valueToStore = value instanceof Function ? value(storedValue) : value;
254492
+ setStoredValue(valueToStore);
254493
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
254494
+ }
254495
+ catch (error) {
254496
+ console.warn(`Error setting localStorage key "${key}":`, error);
254497
+ }
254498
+ }, [key, storedValue]);
254499
+ // Remove from localStorage
254500
+ const removeValue = useCallback(() => {
254501
+ if (IS_SERVER) {
254502
+ console.warn(`Tried removing localStorage key "${key}" even though environment is not a client`);
254503
+ return;
254504
+ }
254505
+ try {
254506
+ const initial = initialValue instanceof Function ? initialValue() : initialValue;
254507
+ window.localStorage.removeItem(key);
254508
+ setStoredValue(initial);
254509
+ }
254510
+ catch (error) {
254511
+ console.warn(`Error removing localStorage key "${key}":`, error);
254512
+ }
254513
+ }, [key, initialValue]);
254514
+ return [storedValue, setValue, removeValue];
254515
+ }
254516
+
254517
+ const LOCAL_STORAGE_KEY$1 = 'ghost_os_install_state';
254518
+ /**
254519
+ * Manage installing & setting up GhostOS (https://github.com/ghostwright/ghost-os)
254520
+ * via the Tauri host. This is the self-contained backing hook for the System
254521
+ * Control card and deliberately mirrors `useModelDownload`:
254522
+ *
254523
+ * - checks GhostOS install/run status through the host
254524
+ * - installs/sets up GhostOS with real-time progress + logs
254525
+ * - persists state across app restarts
254526
+ *
254527
+ * Outside the desktop (Tauri) app every action is a no-op and `isAvailable` is
254528
+ * false, so the card hides itself.
254529
+ */
254530
+ function useGhostOs() {
254531
+ const { isAvailable, invoke, listen } = useTauri();
254532
+ const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY$1, initialGhostOsInstallState);
254533
+ const [status, setStatus] = useState(null);
254534
+ // macOS Accessibility permission, which GhostOS needs to control the device.
254535
+ // null = unknown/not-yet-checked or unsupported (non-macOS / plugin absent).
254536
+ const [accessibilityPermission, setAccessibilityPermission] = useState(null);
254537
+ const unlistenRefs = useRef([]);
254538
+ const hasCheckedStatus = useRef(false);
254539
+ /**
254540
+ * Refresh the macOS Accessibility permission via tauri-plugin-macos-permissions.
254541
+ * Independent of the GhostOS status check so a missing host command for one
254542
+ * doesn't suppress the other. Stays null where unsupported.
254543
+ */
254544
+ const refreshAccessibilityPermission = useCallback(async () => {
254545
+ if (!isAvailable)
254546
+ return;
254547
+ try {
254548
+ const granted = await invoke(MACOS_PERMISSIONS_COMMANDS.CHECK_ACCESSIBILITY);
254549
+ setAccessibilityPermission(granted);
254550
+ }
254551
+ catch (error) {
254552
+ // Plugin not registered or non-macOS host — leave permission unknown.
254553
+ console.warn('[useGhostOs] Accessibility permission check unavailable:', error);
254554
+ setAccessibilityPermission(null);
254555
+ }
254556
+ }, [isAvailable, invoke]);
254557
+ /**
254558
+ * Open the Accessibility pane / prompt so the user can grant permission, then
254559
+ * re-check (the grant happens in System Settings, so we refresh after).
254560
+ */
254561
+ const requestAccessibilityPermission = useCallback(async () => {
254562
+ if (!isAvailable)
254563
+ return;
254564
+ try {
254565
+ await invoke(MACOS_PERMISSIONS_COMMANDS.REQUEST_ACCESSIBILITY);
254566
+ }
254567
+ catch (error) {
254568
+ console.error('[useGhostOs] Failed to request accessibility permission:', error);
254569
+ }
254570
+ await refreshAccessibilityPermission();
254571
+ }, [isAvailable, invoke, refreshAccessibilityPermission]);
254572
+ const addLog = useCallback((log) => {
254573
+ setState((prev) => ({
254574
+ ...prev,
254575
+ logs: [...prev.logs.slice(-99), log],
254576
+ lastUpdated: new Date().toISOString(),
254577
+ }));
254578
+ }, [setState]);
254579
+ /**
254580
+ * Query GhostOS status from the host.
254581
+ */
254582
+ const checkStatus = useCallback(async () => {
254583
+ if (!isAvailable)
254584
+ return;
254585
+ // Refresh the accessibility permission alongside install status (independent).
254586
+ refreshAccessibilityPermission();
254587
+ try {
254588
+ setState((prev) => ({ ...prev, status: 'checking' }));
254589
+ const result = await invoke(GHOST_OS_TAURI_COMMANDS.CHECK_GHOST_OS_STATUS);
254590
+ setStatus(result);
254591
+ setState((prev) => ({
254592
+ ...prev,
254593
+ status: result.installed ? 'completed' : 'idle',
254594
+ progress: result.installed ? 100 : prev.progress,
254595
+ lastUpdated: new Date().toISOString(),
254596
+ }));
254597
+ }
254598
+ catch (error) {
254599
+ console.error('[useGhostOs] Failed to check status:', error);
254600
+ setState((prev) => ({ ...prev, status: 'idle' }));
254601
+ }
254602
+ }, [isAvailable, invoke, setState, refreshAccessibilityPermission]);
254603
+ /**
254604
+ * Install and set up GhostOS. The host clones the repo + runs setup and emits
254605
+ * progress/log/status events along the way.
254606
+ */
254607
+ const install = useCallback(async () => {
254608
+ if (!isAvailable)
254609
+ return;
254610
+ try {
254611
+ setState((prev) => ({
254612
+ ...prev,
254613
+ status: 'installing',
254614
+ progress: 0,
254615
+ message: 'Setting up your assistant…',
254616
+ error: undefined,
254617
+ logs: [],
254618
+ }));
254619
+ addLog({
254620
+ timestamp: new Date().toISOString(),
254621
+ level: 'info',
254622
+ message: 'Starting setup…',
254623
+ });
254624
+ const result = await invoke(GHOST_OS_TAURI_COMMANDS.INSTALL_GHOST_OS);
254625
+ addLog({
254626
+ timestamp: new Date().toISOString(),
254627
+ level: 'info',
254628
+ message: typeof result === 'string' && result ? result : 'Setup complete',
254629
+ });
254630
+ setState((prev) => ({
254631
+ ...prev,
254632
+ status: 'completed',
254633
+ progress: 100,
254634
+ message: 'Your assistant is ready',
254635
+ lastUpdated: new Date().toISOString(),
254636
+ }));
254637
+ await checkStatus();
254638
+ }
254639
+ catch (error) {
254640
+ const message = error instanceof Error ? error.message : String(error);
254641
+ setState((prev) => ({
254642
+ ...prev,
254643
+ status: 'error',
254644
+ error: message,
254645
+ message: 'Setup didn’t finish',
254646
+ lastUpdated: new Date().toISOString(),
254647
+ }));
254648
+ addLog({
254649
+ timestamp: new Date().toISOString(),
254650
+ level: 'error',
254651
+ message: `Install failed: ${message}`,
254652
+ });
254653
+ }
254654
+ }, [isAvailable, invoke, addLog, checkStatus, setState]);
254655
+ /**
254656
+ * Stop the running GhostOS manager.
254657
+ */
254658
+ const stop = useCallback(async () => {
254659
+ if (!isAvailable)
254660
+ return;
254661
+ try {
254662
+ await invoke(GHOST_OS_TAURI_COMMANDS.STOP_GHOST_OS);
254663
+ await checkStatus();
254664
+ }
254665
+ catch (error) {
254666
+ console.error('[useGhostOs] Failed to stop GhostOS:', error);
254667
+ }
254668
+ }, [isAvailable, invoke, checkStatus]);
254669
+ /**
254670
+ * Reset the install state (for retrying after an error).
254671
+ */
254672
+ const resetState = useCallback(() => {
254673
+ setState(initialGhostOsInstallState);
254674
+ }, [setState]);
254675
+ // Wire up host event listeners (progress / logs / status).
254676
+ useEffect(() => {
254677
+ if (!isAvailable)
254678
+ return;
254679
+ const setupListeners = async () => {
254680
+ try {
254681
+ const unlistenProgress = await listen(GHOST_OS_TAURI_EVENTS.INSTALL_PROGRESS, (payload) => {
254682
+ const nextStatus = payload.status === 'completed'
254683
+ ? 'completed'
254684
+ : payload.status === 'cancelled'
254685
+ ? 'cancelled'
254686
+ : payload.status === 'error'
254687
+ ? 'error'
254688
+ : 'installing';
254689
+ setState((prev) => ({
254690
+ ...prev,
254691
+ status: nextStatus,
254692
+ progress: payload.percentage,
254693
+ message: payload.message,
254694
+ lastUpdated: new Date().toISOString(),
254695
+ }));
254696
+ });
254697
+ unlistenRefs.current.push(unlistenProgress);
254698
+ const unlistenLogs = await listen(GHOST_OS_TAURI_EVENTS.INSTALLATION_LOG, addLog);
254699
+ unlistenRefs.current.push(unlistenLogs);
254700
+ const unlistenStatus = await listen(GHOST_OS_TAURI_EVENTS.STATUS, setStatus);
254701
+ unlistenRefs.current.push(unlistenStatus);
254702
+ }
254703
+ catch (error) {
254704
+ console.error('[useGhostOs] Failed to setup event listeners:', error);
254705
+ }
254706
+ };
254707
+ setupListeners();
254708
+ return () => {
254709
+ unlistenRefs.current.forEach((unlisten) => unlisten());
254710
+ unlistenRefs.current = [];
254711
+ };
254712
+ }, [isAvailable, listen, setState, addLog]);
254713
+ // Check status once on mount (in the desktop app).
254714
+ useEffect(() => {
254715
+ if (!isAvailable || hasCheckedStatus.current)
254716
+ return;
254717
+ hasCheckedStatus.current = true;
254718
+ checkStatus();
254719
+ }, [isAvailable, checkStatus]);
254720
+ // Only expose the feature as available inside the desktop (Tauri) app.
254721
+ const finalIsAvailable = isAvailable && isTauriApp$1();
254722
+ return {
254723
+ isAvailable: finalIsAvailable,
254724
+ state,
254725
+ status,
254726
+ accessibilityPermission,
254727
+ install,
254728
+ stop,
254729
+ checkStatus,
254730
+ resetState,
254731
+ requestAccessibilityPermission,
254732
+ };
254733
+ }
254734
+
254735
+ // Cowork is macOS-only in prod; the env flag bypasses the OS check so the
254736
+ // toggle can be exercised on Linux/Windows desktop builds during testing.
254737
+ const isMacOS = () => {
254738
+ if (typeof navigator === 'undefined')
254739
+ return false;
254740
+ return /mac/i.test(navigator.userAgent || '');
254741
+ };
254742
+ const allowNonMacOSCowork = () => process.env.NEXT_PUBLIC_ALLOW_NON_MACOS_COMPUTER_USE_TOGGLE === 'true';
254743
+ // 14GB floor per spec; modelSupportsCowork gates size > gb, so a model of
254744
+ // exactly 14GB is also off (no 14.0GB model in the catalog). Only the local-model
254745
+ // backend needs this; the remote AI has no size requirement.
254746
+ const COWORK_MIN_MODEL_GB = 14;
254024
254747
  const InsideButtons = ({ activeOptions, onOptionClick, deepResearch, studyMode, artifactsEnabled, containerWidth, disabled = false, onOpenPromptGallery, embedMode = false, promptsIsEnabled = false, memoryEnabled = false, mentorId, tenantKey, username, }) => {
254025
254748
  const t = useT();
254749
+ // Cowork = the Tauri GhostOS assistant. GhostOS runs the tools on-device;
254750
+ // the "brain" is EITHER a large local model (Local Models / Ollama) OR the
254751
+ // remote AI (DM OpenAI-compatible endpoint), whichever is set up. useGhostOs
254752
+ // handles install/stop; the localStorage pref (isCoworkEnabled) is read
254753
+ // by the chat hook to route the turn. Reads the pref on mount.
254754
+ // Local state is `coworkOn` so it doesn't shadow the imported setCoworkEnabled.
254755
+ const ghostOs = useGhostOs();
254756
+ const [coworkOn, setCoworkOn] = useState(isCoworkEnabled);
254757
+ const toggleCowork = () => {
254758
+ const next = !coworkOn;
254759
+ // Guard only when turning on. Cowork runs on either a large local model
254760
+ // or the remote AI — allow enabling when either backend is ready (the local
254761
+ // model + Cowork combo still works). The chatbox has no inline notice
254762
+ // space, so remind via toast. (RBAC is enforced separately: this button is
254763
+ // `disabled` when the user lacks the mentor `#chat` permission — see
254764
+ // chat-input-form's isChatDisabledByRbac.)
254765
+ if (next) {
254766
+ const localReady = isLocalLLMEnabled() &&
254767
+ modelSupportsCowork(getLocalLLMModel(), COWORK_MIN_MODEL_GB);
254768
+ if (!localReady && !hasRemoteAiConfig()) {
254769
+ toast.warning(isLocalLLMEnabled()
254770
+ ? t('chatInputFormInsideButtons.coworkModelTooSmall')
254771
+ : t('chatInputFormInsideButtons.coworkNeedsBackend'));
254772
+ return;
254773
+ }
254774
+ }
254775
+ setCoworkOn(next);
254776
+ setCoworkEnabled(next);
254777
+ if (next)
254778
+ ghostOs.install();
254779
+ else
254780
+ ghostOs.stop();
254781
+ };
254026
254782
  const allInsideButtons = [
254027
254783
  {
254028
254784
  name: 'Canvas',
@@ -254066,6 +254822,14 @@ const InsideButtons = ({ activeOptions, onOptionClick, deepResearch, studyMode,
254066
254822
  action: /* istanbul ignore next */ () => onOptionClick(TOOLS.MEMORY),
254067
254823
  isEnabled: memoryEnabled && !embedMode && !!username,
254068
254824
  },
254825
+ {
254826
+ name: 'Cowork',
254827
+ label: t('chatInputFormInsideButtons.cowork'),
254828
+ icon: jsx(Monitor, { className: "h-4 w-4" }),
254829
+ isActive: coworkOn,
254830
+ action: toggleCowork,
254831
+ isEnabled: ghostOs.isAvailable && (isMacOS() || allowNonMacOSCowork()),
254832
+ },
254069
254833
  ].filter((item) => item.isEnabled);
254070
254834
  // Get visible inside buttons based on screen size
254071
254835
  // Active buttons are always visible, inactive ones are hidden based on available width
@@ -254583,7 +255347,7 @@ function SubmitMessageButton({ isPreviewMode, allowAnonymousAccess, isUploading,
254583
255347
  const PromptGalleryModal$1 = dynamic(() => Promise.resolve().then(function () { return promptGalleryModal; }).then((mod) => mod.PromptGalleryModal), {
254584
255348
  ssr: false,
254585
255349
  });
254586
- function ChatInputForm({ onSubmit, onScreenSharingClick, isScreenSharingModalOpen, onPhoneCallClick, sessionId, stopGenerating, mentorId, tenantKey, isPublicRoute, userIsStudent, username, isPreviewMode, enableWebBrowsing, isStreaming, updateSessionTools, setSessionTools, activeTools, screenSharing, deepResearch, studyMode, imageGeneration, codeInterpreter, promptsIsEnabled, googleSlidesIsEnabled, googleDocumentIsEnabled, artifactsEnabled, compactMode = false, chatAreaMaxWidth, isConnecting = false, stopStreamingButtonRef, }) {
255350
+ function ChatInputForm({ onSubmit, onScreenSharingClick, isScreenSharingModalOpen, onPhoneCallClick, sessionId, stopGenerating, mentorId, tenantKey, isPublicRoute, userIsStudent, username, isPreviewMode, enableWebBrowsing, isStreaming, updateSessionTools, setSessionTools, activeTools, screenSharing, deepResearch, studyMode, imageGeneration, codeInterpreter, promptsIsEnabled, googleSlidesIsEnabled, googleDocumentIsEnabled, artifactsEnabled, compactMode = false, chatAreaMaxWidth, isConnecting = false, stopStreamingButtonRef, slashSkills, slashSkillsLoading = false, }) {
254587
255351
  var _a, _b, _c, _d, _e;
254588
255352
  const t = useT();
254589
255353
  const dispatch = useDispatch();
@@ -254637,6 +255401,15 @@ function ChatInputForm({ onSubmit, onScreenSharingClick, isScreenSharingModalOpe
254637
255401
  const setInputValue = (input) => {
254638
255402
  dispatch(chatInputSliceActions.setTextareaInput(input));
254639
255403
  };
255404
+ // `/` skill picker — active only when the host supplies the agent's
255405
+ // effective skills (or reports them loading). No fetching happens here.
255406
+ const effectiveSlashSkills = slashSkills !== null && slashSkills !== void 0 ? slashSkills : [];
255407
+ const slashPicker = useSlashSkillPicker({
255408
+ inputValue,
255409
+ setInputValue,
255410
+ skills: effectiveSlashSkills,
255411
+ isLoading: slashSkillsLoading,
255412
+ });
254640
255413
  const handleSelectPrompt = (promptText) => {
254641
255414
  setInputValue(promptText);
254642
255415
  setIsPromptGalleryOpen(false);
@@ -254701,9 +255474,18 @@ function ChatInputForm({ onSubmit, onScreenSharingClick, isScreenSharingModalOpe
254701
255474
  }
254702
255475
  return persistentChatInputLabel ? '' : t('chatInputForm.askAnything');
254703
255476
  };
254704
- return (jsxs(Fragment$1, { children: [isTabletOrMobile && !isPreviewMode && !embedMode && !compactMode && (jsx("div", { className: "mx-auto flex w-full justify-end pt-4 pl-4", style: chatAreaMaxWidth ? { maxWidth: `${chatAreaMaxWidth}px` } : undefined, children: jsx(RetrievedDocumentsButton, { sessionId: sessionId }) })), ((_c = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.data) === null || _c === void 0 ? void 0 : _c.disclaimer) && !compactMode && (jsx("div", { className: "mx-auto mt-1 w-full pb-1", style: chatAreaMaxWidth ? { maxWidth: `${chatAreaMaxWidth}px` } : undefined, children: jsx("p", { id: "chat-input-disclaimer", className: "text-center text-[0.625rem] text-gray-500 italic", children: (_d = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.data) === null || _d === void 0 ? void 0 : _d.disclaimer }) })), jsxs("form", { ref: containerRef, onSubmit: handleSubmit, className: cn('mx-auto mt-4 w-full pb-2', CSS_CLASS_NAMES.CHAT.TEXTAREA), style: chatAreaMaxWidth ? { maxWidth: `${chatAreaMaxWidth}px` } : undefined, children: [jsxs("div", { className: "relative overflow-hidden rounded-2xl border border-gray-200 bg-[#fbfbfb] pb-3 shadow-xs", children: [jsx(FileAttachmentsList, { attachedFiles: attachedFiles, onRemoveFile: handleRemoveFile, onRetryFile: retryUpload }), fileAddedNotification && (jsxs("div", { className: "animate-in slide-in-from-bottom-5 absolute top-0 right-0 left-0 -mt-10 flex items-center gap-2 rounded-md bg-blue-50 p-2 text-xs text-blue-600 duration-300", children: [jsx(FileText, { className: "h-3 w-3" }), jsx("span", { className: "truncate", children: fileAddedNotification })] })), jsxs("div", { className: "grid", children: [jsx("label", { id: "chat-input-label", htmlFor: "chat-input-textarea", className: cn(persistentChatInputLabel
255477
+ return (jsxs(Fragment$1, { children: [isTabletOrMobile && !isPreviewMode && !embedMode && !compactMode && (jsx("div", { className: "mx-auto flex w-full justify-end pt-4 pl-4", style: chatAreaMaxWidth ? { maxWidth: `${chatAreaMaxWidth}px` } : undefined, children: jsx(RetrievedDocumentsButton, { sessionId: sessionId }) })), ((_c = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.data) === null || _c === void 0 ? void 0 : _c.disclaimer) && !compactMode && (jsx("div", { className: "mx-auto mt-1 w-full pb-1", style: chatAreaMaxWidth ? { maxWidth: `${chatAreaMaxWidth}px` } : undefined, children: jsx("p", { id: "chat-input-disclaimer", className: "text-center text-[0.625rem] text-gray-500 italic", children: (_d = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.data) === null || _d === void 0 ? void 0 : _d.disclaimer }) })), jsxs("form", { ref: containerRef, onSubmit: handleSubmit, className: cn('relative mx-auto mt-4 w-full pb-2', CSS_CLASS_NAMES.CHAT.TEXTAREA), style: chatAreaMaxWidth ? { maxWidth: `${chatAreaMaxWidth}px` } : undefined, children: [slashPicker.open && (jsx(SlashSkillPicker, { skills: slashPicker.filteredSkills, activeIndex: slashPicker.activeIndex, listboxId: slashPicker.listboxId, onSelect: slashPicker.selectSkill, onActiveIndexChange: slashPicker.setActiveIndex, isLoading: slashSkillsLoading })), jsxs("div", { className: "relative overflow-hidden rounded-2xl border border-gray-200 bg-[#fbfbfb] pb-3 shadow-xs", children: [jsx(FileAttachmentsList, { attachedFiles: attachedFiles, onRemoveFile: handleRemoveFile, onRetryFile: retryUpload }), fileAddedNotification && (jsxs("div", { className: "animate-in slide-in-from-bottom-5 absolute top-0 right-0 left-0 -mt-10 flex items-center gap-2 rounded-md bg-blue-50 p-2 text-xs text-blue-600 duration-300", children: [jsx(FileText, { className: "h-3 w-3" }), jsx("span", { className: "truncate", children: fileAddedNotification })] })), jsxs("div", { className: "grid", children: [jsx("label", { id: "chat-input-label", htmlFor: "chat-input-textarea", className: cn(persistentChatInputLabel
254705
255478
  ? 'block px-[18.5px] pt-3 text-xs font-medium text-gray-600'
254706
- : 'sr-only'), children: t('chatInputForm.askAnything') }), jsx(AutoResizeTextarea, { id: "chat-input-textarea", "aria-labelledby": "chat-input-label", "aria-describedby": ((_e = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.data) === null || _e === void 0 ? void 0 : _e.disclaimer) ? 'chat-input-disclaimer' : undefined, value: inputValue, onChange: handleInputChange, onSubmit: handleSubmit, sessionId: sessionId, isPreviewMode: isPreviewMode, textAreaRows: textAreaRows, placeholder: isChatDisabledByRbac ? t('chatInputForm.noChatPermission') : textAreaPlaceholder(), disabled: isChatDisabledByRbac || hasUploadingFiles, allowEmptySubmit: attachedFiles.length > 0, allowAnonymousAccess: isMentorViewableByAnyone || showingSharedChat || !!userIsVisiting, embedMode: embedMode }), jsxs("div", { className: "flex items-center gap-2 px-2", children: [visibleToLoggedInUsersOnly && !compactMode && (jsx(UploadMenu, { onFileInputTrigger: () => executeWithTrialCheck(triggerFileInput), disabled: isChatDisabledByRbac || !sessionId, mentorId: mentorId, tenantKey: tenantKey, isPublicRoute: isPublicRoute })), visibleToLoggedInUsersOnly && !compactMode && (jsx(InsideButtons, { containerWidth: containerWidth, activeOptions: activeTools, onOptionClick: updateSessionTools, deepResearch: deepResearch, artifactsEnabled: artifactsEnabled, disabled: isChatDisabledByRbac, onOpenPromptGallery: openPromptGallery, embedMode: embedMode, promptsIsEnabled: promptsIsEnabled, studyMode: studyMode, memoryEnabled: mentorSettings.data.memoryEnabled, mentorId: mentorId, tenantKey: tenantKey, username: username })), jsxs("div", { className: "ml-auto flex", children: [visibleToLoggedInUsersOnly && !compactMode && (jsx(ScreenSharingButton, { onClick: onScreenSharingClick, isScreenSharingModalOpen: isScreenSharingModalOpen, screenSharing: screenSharing, isPreviewMode: isPreviewMode, disabled: isChatDisabledByRbac })), visibleToLoggedInUsersOnly && !compactMode && (jsx(VoiceChatButton, { isPreviewMode: isPreviewMode, handleMicrophoneBtnClick: () => executeWithTrialCheck(handleMicrophoneBtnClick), processing: processing, recording: recording, disabled: isChatDisabledByRbac, mentorId: mentorId, tenantKey: tenantKey, isPublicRoute: isPublicRoute })), visibleToLoggedInUsersOnly && !compactMode && (jsx(VoiceCallButton, { isPreviewMode: isPreviewMode, onClick: () => executeWithTrialCheck(onPhoneCallClick), disabled: isChatDisabledByRbac, mentorId: mentorId, tenantKey: tenantKey, isPublicRoute: isPublicRoute })), isStreaming ? (jsx(StopStreamingButton, { ref: stopStreamingButtonRef, stopGenerating: stopGenerating })) : (jsx(SubmitMessageButton, { isPreviewMode: isPreviewMode, allowAnonymousAccess: isMentorViewableByAnyone, isUploading: hasUploadingFiles, disabled: isChatDisabledByRbac || !sessionId, isConnecting: isConnecting }))] })] })] }), jsx("input", { type: "file", ref: fileUploadInputRef, className: "hidden", onChange: handleFileInputChange, accept: fileUploadCapabilities.allSupportedTypes.length > 0
255479
+ : 'sr-only'), children: t('chatInputForm.askAnything') }), jsx(AutoResizeTextarea, { id: "chat-input-textarea", "aria-labelledby": "chat-input-label", "aria-describedby": ((_e = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.data) === null || _e === void 0 ? void 0 : _e.disclaimer) ? 'chat-input-disclaimer' : undefined, ...((effectiveSlashSkills.length > 0 || slashPicker.open) && {
255480
+ role: 'combobox',
255481
+ 'aria-expanded': slashPicker.open,
255482
+ 'aria-haspopup': 'listbox',
255483
+ 'aria-controls': slashPicker.open && slashPicker.filteredSkills.length > 0
255484
+ ? slashPicker.listboxId
255485
+ : undefined,
255486
+ 'aria-activedescendant': slashPicker.activeOptionId,
255487
+ 'aria-autocomplete': 'list',
255488
+ }), value: inputValue, onChange: handleInputChange, onSubmit: handleSubmit, onComposerKeyDown: slashPicker.handleKeyDown, sessionId: sessionId, isPreviewMode: isPreviewMode, textAreaRows: textAreaRows, placeholder: isChatDisabledByRbac ? t('chatInputForm.noChatPermission') : textAreaPlaceholder(), disabled: isChatDisabledByRbac || hasUploadingFiles, allowEmptySubmit: attachedFiles.length > 0, allowAnonymousAccess: isMentorViewableByAnyone || showingSharedChat || !!userIsVisiting, embedMode: embedMode }), jsxs("div", { className: "flex items-center gap-2 px-2", children: [visibleToLoggedInUsersOnly && !compactMode && (jsx(UploadMenu, { onFileInputTrigger: () => executeWithTrialCheck(triggerFileInput), disabled: isChatDisabledByRbac || !sessionId, mentorId: mentorId, tenantKey: tenantKey, isPublicRoute: isPublicRoute })), visibleToLoggedInUsersOnly && !compactMode && (jsx(InsideButtons, { containerWidth: containerWidth, activeOptions: activeTools, onOptionClick: updateSessionTools, deepResearch: deepResearch, artifactsEnabled: artifactsEnabled, disabled: isChatDisabledByRbac, onOpenPromptGallery: openPromptGallery, embedMode: embedMode, promptsIsEnabled: promptsIsEnabled, studyMode: studyMode, memoryEnabled: mentorSettings.data.memoryEnabled, mentorId: mentorId, tenantKey: tenantKey, username: username })), jsxs("div", { className: "ml-auto flex", children: [visibleToLoggedInUsersOnly && !compactMode && (jsx(ScreenSharingButton, { onClick: onScreenSharingClick, isScreenSharingModalOpen: isScreenSharingModalOpen, screenSharing: screenSharing, isPreviewMode: isPreviewMode, disabled: isChatDisabledByRbac })), visibleToLoggedInUsersOnly && !compactMode && (jsx(VoiceChatButton, { isPreviewMode: isPreviewMode, handleMicrophoneBtnClick: () => executeWithTrialCheck(handleMicrophoneBtnClick), processing: processing, recording: recording, disabled: isChatDisabledByRbac, mentorId: mentorId, tenantKey: tenantKey, isPublicRoute: isPublicRoute })), visibleToLoggedInUsersOnly && !compactMode && (jsx(VoiceCallButton, { isPreviewMode: isPreviewMode, onClick: () => executeWithTrialCheck(onPhoneCallClick), disabled: isChatDisabledByRbac, mentorId: mentorId, tenantKey: tenantKey, isPublicRoute: isPublicRoute })), isStreaming ? (jsx(StopStreamingButton, { ref: stopStreamingButtonRef, stopGenerating: stopGenerating })) : (jsx(SubmitMessageButton, { isPreviewMode: isPreviewMode, allowAnonymousAccess: isMentorViewableByAnyone, isUploading: hasUploadingFiles, disabled: isChatDisabledByRbac || !sessionId, isConnecting: isConnecting }))] })] })] }), jsx("input", { type: "file", ref: fileUploadInputRef, className: "hidden", onChange: handleFileInputChange, accept: fileUploadCapabilities.allSupportedTypes.length > 0
254707
255489
  ? fileUploadCapabilities.allSupportedTypes.join(',')
254708
255490
  : MENTOR_CHAT_DOCUMENTS_EXTENSIONS.join(','), multiple: true, disabled: isChatDisabledByRbac || !sessionId })] }), visibleToLoggedInUsersOnly && !compactMode && (jsx("div", { className: "flex w-full justify-center", children: jsx(OutsideButtons, { activeOptions: activeTools, onOptionClick: updateSessionTools, setSessionTools: setSessionTools, onCrossClick: updateSessionTools, containerWidth: containerWidth, enableWebBrowsing: enableWebBrowsing, imageGeneration: imageGeneration, codeInterpreter: codeInterpreter, googleSlidesIsEnabled: googleSlidesIsEnabled, googleDocumentIsEnabled: googleDocumentIsEnabled, tenantKey: tenantKey, userId: username, disabled: isChatDisabledByRbac }) }))] }), isPromptGalleryOpen && (jsx(PromptGalleryModal$1, { isOpen: isPromptGalleryOpen, onClose: () => setIsPromptGalleryOpen(false), onSelectPrompt: handleSelectPrompt, mentorId: mentorId, tenantKey: tenantKey, userIsStudent: userIsStudent })), isFreeTrialModalOpen && FreeTrialDialog && (jsx(FreeTrialDialog, { isOpen: isFreeTrialModalOpen, onClose: closeFreeTrialModal }))] }));
254709
255491
  }
@@ -257344,7 +258126,7 @@ function Account({ tenant, tenants = [], username, onInviteClick, email, mainPla
257344
258126
  }, children: [jsxs("div", { className: "lg:hidden mb-6", children: [jsx("h3", { className: "text-lg font-medium text-gray-900 dark:text-gray-100 mb-2", children: (_d = (_c = TABS.find((t) => t.id === activeTab)) === null || _c === void 0 ? void 0 : _c.label) !== null && _d !== void 0 ? _d : activeTab }), jsxs("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: [activeTab === 'basic' && t('profileAccount.descBasic'), activeTab === 'social' && t('profileAccount.descSocial'), activeTab === 'security' && t('profileAccount.descSecurity'), activeTab === 'management' && t('profileAccount.descManagement'), activeTab === 'organization' && t('profileAccount.descOrganization'), activeTab === 'monetization' && t('profileAccount.descMonetization'), activeTab === 'datasets' && t('profileAccount.descBenchmarks'), activeTab === 'advanced' && t('profileAccount.descAdvanced')] })] }), activeTab === 'management' && hasManagementPermissions && (jsx(Admin, { authSpaUrl: authURL, onInviteClick: onInviteClick, tenant: tenant, currentSpa: currentSPA, hasUserTabPermission: hasUserTabPermission, hasGroupsTabPermission: hasGroupsTabPermission, hasPoliciesTabPermission: hasPoliciesTabPermission, hasRolesTabPermission: hasRolesTabPermission, hasTeamsTabPermission: hasTeamsTabPermission, hasInviteUserPermission: hasInviteUserPermission, hasCreateTeamPermission: hasCreateTeamPermission, onLoadGroupPermissions: onLoadGroupPermissions, hasAlertsTabPermission: hasAlertsTabPermission, rbacPermissions: rbacPermissions, enableRbac: enableRbac, showGradebookTab: showGradebookTab })), activeTab === 'organization' && (jsx(OrganizationTab, { platformKey: tenant, tenant: tenants.find((ten) => ten.key === tenant), onTenantUpdate: onTenantUpdate, setOrganizationLogoFromOutside: setOrganizationLogo, defaultSupportPhone: defaultSupportPhone, enableSupportPhone: enableSupportPhone })), activeTab === 'integrations' && (jsx(IntegrationsTab, { tenantKey: tenant, username: username })), activeTab === 'billing' && (jsx(BillingTab, { tenant: tenant, userActiveApp: userActiveApp, username: username, currentUserEmail: email, mainPlatformKey: mainPlatformKey })), activeTab === 'monetization' && (jsx(MonetizationTab, { platformKey: tenant, authURL: authURL })), activeTab === 'datasets' && showBenchmarks && (jsx(BenchmarksTab, { tenantKey: tenant, username: username })), activeTab === 'advanced' && (jsx(AdvancedTab, { platformKey: tenant, currentSPA: currentSPA, username: username, authURL: authURL, currentPlatformBaseDomain: currentPlatformBaseDomain }))] })] }), jsx(ToastProvider, {})] }));
257345
258127
  }
257346
258128
 
257347
- function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, showMentorAIDisplayCheckbox = false, showLeaderboardDisplayCheckbox = false, showGradebookTab = false, showUsernameField = false, showPlatformName = false, useGravatarPicFallback = true, enableCatalogInvite = false, targetTab = 'basic', currentPlan = '', currentSPA = '', userActiveApp = null, authURL, tenants = [], onTenantUpdate, currentPlatformBaseDomain = '', rbacPermissions = {}, enableRbac = false, onLoadGroupPermissions, onTabChange, defaultSupportPhone = '', onBillingTabRequest, onAccountDeleted, enableMemoryTab = false, showBenchmarks = false, localLLMProps, systemControlProps, enableSupportPhone, }) {
258129
+ function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, showMentorAIDisplayCheckbox = false, showLeaderboardDisplayCheckbox = false, showGradebookTab = false, showUsernameField = false, showPlatformName = false, useGravatarPicFallback = true, enableCatalogInvite = false, targetTab = 'basic', currentPlan = '', currentSPA = '', userActiveApp = null, authURL, tenants = [], onTenantUpdate, currentPlatformBaseDomain = '', rbacPermissions = {}, enableRbac = false, onLoadGroupPermissions, onTabChange, defaultSupportPhone = '', onBillingTabRequest, onAccountDeleted, enableMemoryTab = false, showBenchmarks = false, localLLMProps, enableSupportPhone, }) {
257348
258130
  const t = useT();
257349
258131
  console.log('[UserProfileModal] localLLMProps received:', {
257350
258132
  isAvailable: localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.isAvailable,
@@ -257410,7 +258192,7 @@ function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, sho
257410
258192
  showPlatformName: showPlatformName,
257411
258193
  useGravatarPicFallback: useGravatarPicFallback,
257412
258194
  showGradebookTab: showGradebookTab,
257413
- }, isAdmin: params.isAdmin, targetTab: targetTab, onClose: onClose, onAccountDeleted: onAccountDeleted, enableMemoryTab: enableMemoryTab, localLLMProps: localLLMProps, systemControlProps: systemControlProps })), [
258195
+ }, isAdmin: params.isAdmin, targetTab: targetTab, onClose: onClose, onAccountDeleted: onAccountDeleted, enableMemoryTab: enableMemoryTab, localLLMProps: localLLMProps })), [
257414
258196
  'organization',
257415
258197
  'management',
257416
258198
  'integrations',
@@ -257420,69 +258202,7 @@ function UserProfileModal({ isOpen, onClose, params, email, mainPlatformKey, sho
257420
258202
  ].includes(targetTab) && (jsxs(Fragment$1, { children: [jsx(Account, { onInviteClick: () => setIsInviteUserDialogOpen(true), tenant: params.tenantKey, tenants: tenants, username: getUserName$1(), email: email, mainPlatformKey: mainPlatformKey, showUsernameField: showUsernameField, showPlatformName: showPlatformName, useGravatarPicFallback: useGravatarPicFallback, onClose: onClose, isAdmin: params.isAdmin, targetTab: targetTab, currentPlan: currentPlan, currentSPA: currentSPA, userActiveApp: userActiveApp, authURL: authURL, onTenantUpdate: onTenantUpdate, currentPlatformBaseDomain: currentPlatformBaseDomain, rbacPermissions: rbacPermissions, enableRbac: enableRbac, onLoadGroupPermissions: onLoadGroupPermissions, onTabChange: onTabChange, defaultSupportPhone: defaultSupportPhone, showBenchmarks: showBenchmarks, enableSupportPhone: enableSupportPhone, showGradebookTab: showGradebookTab }), isInviteUserDialogOpen && (jsx(InviteUserDialog, { tenant: params.tenantKey, onClose: () => setIsInviteUserDialogOpen(false), isOpen: isInviteUserDialogOpen, enableCatalogInvite: enableCatalogInvite, hasManageUsersPermission: hasManageUsersPermission })), isInvitedUsersDialogOpen && (jsx(InvitedUsersDialog, { onClose: () => setIsInvitedUsersDialogOpen(false), tenant: params.tenantKey }))] }))] }) }) }));
257421
258203
  }
257422
258204
 
257423
- const IS_SERVER = typeof window === 'undefined';
257424
- /**
257425
- * A simplified useLocalStorage hook for persisting state to localStorage
257426
- * with SSR safety.
257427
- */
257428
- function useLocalStorage(key, initialValue) {
257429
- // Get the initial value
257430
- const getInitialValue = useCallback(() => {
257431
- const initial = initialValue instanceof Function ? initialValue() : initialValue;
257432
- if (IS_SERVER) {
257433
- return initial;
257434
- }
257435
- try {
257436
- const item = window.localStorage.getItem(key);
257437
- if (item === null) {
257438
- return initial;
257439
- }
257440
- return JSON.parse(item);
257441
- }
257442
- catch (error) {
257443
- console.warn(`Error reading localStorage key "${key}":`, error);
257444
- return initial;
257445
- }
257446
- }, [key, initialValue]);
257447
- const [storedValue, setStoredValue] = useState(getInitialValue);
257448
- // Update stored value when key changes
257449
- useEffect(() => {
257450
- setStoredValue(getInitialValue());
257451
- }, [key, getInitialValue]);
257452
- // Persist to localStorage
257453
- const setValue = useCallback((value) => {
257454
- if (IS_SERVER) {
257455
- console.warn(`Tried setting localStorage key "${key}" even though environment is not a client`);
257456
- return;
257457
- }
257458
- try {
257459
- const valueToStore = value instanceof Function ? value(storedValue) : value;
257460
- setStoredValue(valueToStore);
257461
- window.localStorage.setItem(key, JSON.stringify(valueToStore));
257462
- }
257463
- catch (error) {
257464
- console.warn(`Error setting localStorage key "${key}":`, error);
257465
- }
257466
- }, [key, storedValue]);
257467
- // Remove from localStorage
257468
- const removeValue = useCallback(() => {
257469
- if (IS_SERVER) {
257470
- console.warn(`Tried removing localStorage key "${key}" even though environment is not a client`);
257471
- return;
257472
- }
257473
- try {
257474
- const initial = initialValue instanceof Function ? initialValue() : initialValue;
257475
- window.localStorage.removeItem(key);
257476
- setStoredValue(initial);
257477
- }
257478
- catch (error) {
257479
- console.warn(`Error removing localStorage key "${key}":`, error);
257480
- }
257481
- }, [key, initialValue]);
257482
- return [storedValue, setValue, removeValue];
257483
- }
257484
-
257485
- const LOCAL_STORAGE_KEY$1 = 'model_download_state';
258205
+ const LOCAL_STORAGE_KEY = 'model_download_state';
257486
258206
  const FIRST_LAUNCH_DISMISSED_KEY = 'model_download_prompt_dismissed';
257487
258207
  // Manager/download status is authoritative from Tauri, never the persisted
257488
258208
  // snapshot. This flips true the first time any hook instance mounts in a page
@@ -257502,7 +258222,7 @@ let didResetPersistedState = false;
257502
258222
  */
257503
258223
  function useModelDownload() {
257504
258224
  const { isAvailable, invoke, listen } = useTauri();
257505
- const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY$1, initialModelDownloadState);
258225
+ const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY, initialModelDownloadState);
257506
258226
  const [ollamaStatus, setOllamaStatus] = useState(null);
257507
258227
  const [systemMemory, setSystemMemory] = useState(null);
257508
258228
  const [isFirstLaunchDismissed, setIsFirstLaunchDismissed] = useLocalStorage(FIRST_LAUNCH_DISMISSED_KEY, false);
@@ -257930,224 +258650,6 @@ function useModelDownload() {
257930
258650
  };
257931
258651
  }
257932
258652
 
257933
- const LOCAL_STORAGE_KEY = 'ghost_os_install_state';
257934
- /**
257935
- * Manage installing & setting up GhostOS (https://github.com/ghostwright/ghost-os)
257936
- * via the Tauri host. This is the self-contained backing hook for the System
257937
- * Control card and deliberately mirrors `useModelDownload`:
257938
- *
257939
- * - checks GhostOS install/run status through the host
257940
- * - installs/sets up GhostOS with real-time progress + logs
257941
- * - persists state across app restarts
257942
- *
257943
- * Outside the desktop (Tauri) app every action is a no-op and `isAvailable` is
257944
- * false, so the card hides itself.
257945
- */
257946
- function useGhostOs() {
257947
- const { isAvailable, invoke, listen } = useTauri();
257948
- const [state, setState] = useLocalStorage(LOCAL_STORAGE_KEY, initialGhostOsInstallState);
257949
- const [status, setStatus] = useState(null);
257950
- // macOS Accessibility permission, which GhostOS needs to control the device.
257951
- // null = unknown/not-yet-checked or unsupported (non-macOS / plugin absent).
257952
- const [accessibilityPermission, setAccessibilityPermission] = useState(null);
257953
- const unlistenRefs = useRef([]);
257954
- const hasCheckedStatus = useRef(false);
257955
- /**
257956
- * Refresh the macOS Accessibility permission via tauri-plugin-macos-permissions.
257957
- * Independent of the GhostOS status check so a missing host command for one
257958
- * doesn't suppress the other. Stays null where unsupported.
257959
- */
257960
- const refreshAccessibilityPermission = useCallback(async () => {
257961
- if (!isAvailable)
257962
- return;
257963
- try {
257964
- const granted = await invoke(MACOS_PERMISSIONS_COMMANDS.CHECK_ACCESSIBILITY);
257965
- setAccessibilityPermission(granted);
257966
- }
257967
- catch (error) {
257968
- // Plugin not registered or non-macOS host — leave permission unknown.
257969
- console.warn('[useGhostOs] Accessibility permission check unavailable:', error);
257970
- setAccessibilityPermission(null);
257971
- }
257972
- }, [isAvailable, invoke]);
257973
- /**
257974
- * Open the Accessibility pane / prompt so the user can grant permission, then
257975
- * re-check (the grant happens in System Settings, so we refresh after).
257976
- */
257977
- const requestAccessibilityPermission = useCallback(async () => {
257978
- if (!isAvailable)
257979
- return;
257980
- try {
257981
- await invoke(MACOS_PERMISSIONS_COMMANDS.REQUEST_ACCESSIBILITY);
257982
- }
257983
- catch (error) {
257984
- console.error('[useGhostOs] Failed to request accessibility permission:', error);
257985
- }
257986
- await refreshAccessibilityPermission();
257987
- }, [isAvailable, invoke, refreshAccessibilityPermission]);
257988
- const addLog = useCallback((log) => {
257989
- setState((prev) => ({
257990
- ...prev,
257991
- logs: [...prev.logs.slice(-99), log],
257992
- lastUpdated: new Date().toISOString(),
257993
- }));
257994
- }, [setState]);
257995
- /**
257996
- * Query GhostOS status from the host.
257997
- */
257998
- const checkStatus = useCallback(async () => {
257999
- if (!isAvailable)
258000
- return;
258001
- // Refresh the accessibility permission alongside install status (independent).
258002
- refreshAccessibilityPermission();
258003
- try {
258004
- setState((prev) => ({ ...prev, status: 'checking' }));
258005
- const result = await invoke(GHOST_OS_TAURI_COMMANDS.CHECK_GHOST_OS_STATUS);
258006
- setStatus(result);
258007
- setState((prev) => ({
258008
- ...prev,
258009
- status: result.installed ? 'completed' : 'idle',
258010
- progress: result.installed ? 100 : prev.progress,
258011
- lastUpdated: new Date().toISOString(),
258012
- }));
258013
- }
258014
- catch (error) {
258015
- console.error('[useGhostOs] Failed to check status:', error);
258016
- setState((prev) => ({ ...prev, status: 'idle' }));
258017
- }
258018
- }, [isAvailable, invoke, setState, refreshAccessibilityPermission]);
258019
- /**
258020
- * Install and set up GhostOS. The host clones the repo + runs setup and emits
258021
- * progress/log/status events along the way.
258022
- */
258023
- const install = useCallback(async () => {
258024
- if (!isAvailable)
258025
- return;
258026
- try {
258027
- setState((prev) => ({
258028
- ...prev,
258029
- status: 'installing',
258030
- progress: 0,
258031
- message: 'Setting up your assistant…',
258032
- error: undefined,
258033
- logs: [],
258034
- }));
258035
- addLog({
258036
- timestamp: new Date().toISOString(),
258037
- level: 'info',
258038
- message: 'Starting setup…',
258039
- });
258040
- const result = await invoke(GHOST_OS_TAURI_COMMANDS.INSTALL_GHOST_OS);
258041
- addLog({
258042
- timestamp: new Date().toISOString(),
258043
- level: 'info',
258044
- message: typeof result === 'string' && result ? result : 'Setup complete',
258045
- });
258046
- setState((prev) => ({
258047
- ...prev,
258048
- status: 'completed',
258049
- progress: 100,
258050
- message: 'Your assistant is ready',
258051
- lastUpdated: new Date().toISOString(),
258052
- }));
258053
- await checkStatus();
258054
- }
258055
- catch (error) {
258056
- const message = error instanceof Error ? error.message : String(error);
258057
- setState((prev) => ({
258058
- ...prev,
258059
- status: 'error',
258060
- error: message,
258061
- message: 'Setup didn’t finish',
258062
- lastUpdated: new Date().toISOString(),
258063
- }));
258064
- addLog({
258065
- timestamp: new Date().toISOString(),
258066
- level: 'error',
258067
- message: `Install failed: ${message}`,
258068
- });
258069
- }
258070
- }, [isAvailable, invoke, addLog, checkStatus, setState]);
258071
- /**
258072
- * Stop the running GhostOS manager.
258073
- */
258074
- const stop = useCallback(async () => {
258075
- if (!isAvailable)
258076
- return;
258077
- try {
258078
- await invoke(GHOST_OS_TAURI_COMMANDS.STOP_GHOST_OS);
258079
- await checkStatus();
258080
- }
258081
- catch (error) {
258082
- console.error('[useGhostOs] Failed to stop GhostOS:', error);
258083
- }
258084
- }, [isAvailable, invoke, checkStatus]);
258085
- /**
258086
- * Reset the install state (for retrying after an error).
258087
- */
258088
- const resetState = useCallback(() => {
258089
- setState(initialGhostOsInstallState);
258090
- }, [setState]);
258091
- // Wire up host event listeners (progress / logs / status).
258092
- useEffect(() => {
258093
- if (!isAvailable)
258094
- return;
258095
- const setupListeners = async () => {
258096
- try {
258097
- const unlistenProgress = await listen(GHOST_OS_TAURI_EVENTS.INSTALL_PROGRESS, (payload) => {
258098
- const nextStatus = payload.status === 'completed'
258099
- ? 'completed'
258100
- : payload.status === 'cancelled'
258101
- ? 'cancelled'
258102
- : payload.status === 'error'
258103
- ? 'error'
258104
- : 'installing';
258105
- setState((prev) => ({
258106
- ...prev,
258107
- status: nextStatus,
258108
- progress: payload.percentage,
258109
- message: payload.message,
258110
- lastUpdated: new Date().toISOString(),
258111
- }));
258112
- });
258113
- unlistenRefs.current.push(unlistenProgress);
258114
- const unlistenLogs = await listen(GHOST_OS_TAURI_EVENTS.INSTALLATION_LOG, addLog);
258115
- unlistenRefs.current.push(unlistenLogs);
258116
- const unlistenStatus = await listen(GHOST_OS_TAURI_EVENTS.STATUS, setStatus);
258117
- unlistenRefs.current.push(unlistenStatus);
258118
- }
258119
- catch (error) {
258120
- console.error('[useGhostOs] Failed to setup event listeners:', error);
258121
- }
258122
- };
258123
- setupListeners();
258124
- return () => {
258125
- unlistenRefs.current.forEach((unlisten) => unlisten());
258126
- unlistenRefs.current = [];
258127
- };
258128
- }, [isAvailable, listen, setState, addLog]);
258129
- // Check status once on mount (in the desktop app).
258130
- useEffect(() => {
258131
- if (!isAvailable || hasCheckedStatus.current)
258132
- return;
258133
- hasCheckedStatus.current = true;
258134
- checkStatus();
258135
- }, [isAvailable, checkStatus]);
258136
- // Only expose the feature as available inside the desktop (Tauri) app.
258137
- const finalIsAvailable = isAvailable && isTauriApp$1();
258138
- return {
258139
- isAvailable: finalIsAvailable,
258140
- state,
258141
- status,
258142
- accessibilityPermission,
258143
- install,
258144
- stop,
258145
- checkStatus,
258146
- resetState,
258147
- requestAccessibilityPermission,
258148
- };
258149
- }
258150
-
258151
258653
  function UserProfileDropdown({ email, mainPlatformKey,
258152
258654
  // User data
258153
258655
  username, userIsAdmin = false, userIsStudent = false, userIsVisiting = false,
@@ -258171,11 +258673,9 @@ metadata, metadataLoaded = false,
258171
258673
  currentSPA = '', showMentorAIDisplayCheckbox = false, showLeaderboardDisplayCheckbox = false, showGradebookTab = false, showUsernameField = false, showPlatformName = false, enableCatalogInvite = false, authURL, onTenantUpdate, currentPlatformBaseDomain = '', rbacPermissions = {}, enableRbac = false, onLoadGroupPermissions, defaultSupportPhone = '', enableSupportPhone,
258172
258674
  // Local LLM props
258173
258675
  localLLMProps,
258174
- // System Control props
258175
- systemControlProps,
258176
258676
  // Controlled modal state
258177
258677
  isModalOpen, onModalOpenChange, defaultActiveTab, onAccountDeleted, enableMemoryTab, showBenchmarks = false, }) {
258178
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
258678
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
258179
258679
  const t = useT();
258180
258680
  // Use hooks to fetch user metadata
258181
258681
  const { data: userMetadata } = useGetUserMetadataQuery({
@@ -258203,17 +258703,6 @@ isModalOpen, onModalOpenChange, defaultActiveTab, onAccountDeleted, enableMemory
258203
258703
  const selectedFoundryModel = localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.selectedFoundryModel;
258204
258704
  const foundryStatus = localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.foundryStatus;
258205
258705
  const onSelectFoundryModel = localLLMProps === null || localLLMProps === void 0 ? void 0 : localLLMProps.onSelectFoundryModel;
258206
- // System Control (GhostOS) state from props (if provided) or from hook (fallback)
258207
- const ghostOsData = useGhostOs();
258208
- const isSystemControlAvailable = (_l = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.isAvailable) !== null && _l !== void 0 ? _l : ghostOsData.isAvailable;
258209
- const systemControlState = (_m = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.state) !== null && _m !== void 0 ? _m : ghostOsData.state;
258210
- const systemControlStatus = (_o = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.status) !== null && _o !== void 0 ? _o : ghostOsData.status;
258211
- const accessibilityPermission = (_p = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.accessibilityPermission) !== null && _p !== void 0 ? _p : ghostOsData.accessibilityPermission;
258212
- const installGhostOs = (_q = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onInstall) !== null && _q !== void 0 ? _q : ghostOsData.install;
258213
- const stopGhostOs = (_r = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onStop) !== null && _r !== void 0 ? _r : ghostOsData.stop;
258214
- const checkGhostOsStatus = (_s = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onCheckStatus) !== null && _s !== void 0 ? _s : ghostOsData.checkStatus;
258215
- const resetGhostOsState = (_t = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onResetState) !== null && _t !== void 0 ? _t : ghostOsData.resetState;
258216
- const requestAccessibilityPermission = (_u = systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.onRequestAccessibilityPermission) !== null && _u !== void 0 ? _u : ghostOsData.requestAccessibilityPermission;
258217
258706
  // Support controlled modal state
258218
258707
  const [internalIsUserProfileOpen, setInternalIsUserProfileOpen] = useState(false);
258219
258708
  const isUserProfileOpen = isModalOpen !== null && isModalOpen !== void 0 ? isModalOpen : internalIsUserProfileOpen;
@@ -258390,23 +258879,6 @@ isModalOpen, onModalOpenChange, defaultActiveTab, onAccountDeleted, enableMemory
258390
258879
  onResetState: resetState,
258391
258880
  onSelectFoundryModel,
258392
258881
  },
258393
- systemControlProps: {
258394
- isAvailable: isSystemControlAvailable,
258395
- state: systemControlState,
258396
- status: systemControlStatus,
258397
- requiredSizeGb: systemControlProps === null || systemControlProps === void 0 ? void 0 : systemControlProps.requiredSizeGb,
258398
- // Local-model status/memory + downloader, so the "Upgrade" action can
258399
- // check what's installed, keep the RAM/VRAM check, and pull a model.
258400
- ollamaStatus,
258401
- systemMemory,
258402
- accessibilityPermission,
258403
- onInstall: installGhostOs,
258404
- onStop: stopGhostOs,
258405
- onCheckStatus: checkGhostOsStatus,
258406
- onResetState: resetGhostOsState,
258407
- onRequestAccessibilityPermission: requestAccessibilityPermission,
258408
- onDownloadModel: startDownload,
258409
- },
258410
258882
  onAccountDeleted,
258411
258883
  enableMemoryTab,
258412
258884
  showBenchmarks,
@@ -267188,7 +267660,9 @@ function PromptCard$1({ label, placeholder, value, disabled, renderContent, onEd
267188
267660
 
267189
267661
  const AGENT_SCREENSHARE_TAB_LABELS = {
267190
267662
  header: {
267191
- title: 'Screen Share',
267663
+ // Title is deliberately just "Screen" — the description below carries the
267664
+ // screen-sharing wording.
267665
+ title: 'Screen',
267192
267666
  description: 'How your agent behaves when a user shares their screen during a voice call.',
267193
267667
  },
267194
267668
  capability: {
@@ -267408,6 +267882,86 @@ function AgentScreenShareTab({ labels: labelsOverride, renderPromptContent, tena
267408
267882
  } }) }))] })) })] }));
267409
267883
  }
267410
267884
 
267885
+ const AGENT_SKILLS_TAB_LABELS = {
267886
+ header: {
267887
+ title: 'Skills',
267888
+ description: 'Reusable playbooks you can attach to this agent — each one is a set of instructions for a job. In chat, type / to use one.',
267889
+ },
267890
+ notBaseAgent: 'Skills are only available to Base Agents.',
267891
+ loading: 'Loading...',
267892
+ };
267893
+ function buildSkillsTabLabels(t) {
267894
+ return {
267895
+ header: {
267896
+ title: t('skillsTabLabels.header.title'),
267897
+ description: t('skillsTabLabels.header.description'),
267898
+ },
267899
+ notBaseAgent: t('skillsTabLabels.notBaseAgent'),
267900
+ loading: t('skillsTabLabels.loading'),
267901
+ };
267902
+ }
267903
+ function resolveSkillsTabLabels(override, t) {
267904
+ const base = t ? buildSkillsTabLabels(t) : AGENT_SKILLS_TAB_LABELS;
267905
+ if (!override)
267906
+ return base;
267907
+ return deepMerge(base, override);
267908
+ }
267909
+
267910
+ /**
267911
+ * Best-effort slug extraction from the `template_mentor` field, whose shape
267912
+ * is untyped on the settings serializer (string slug or nested object).
267913
+ */
267914
+ function templateMentorSlug(template) {
267915
+ if (typeof template === 'string')
267916
+ return template;
267917
+ if (template && typeof template === 'object') {
267918
+ const record = template;
267919
+ for (const key of ['slug', 'mentor_slug', 'template_slug']) {
267920
+ if (typeof record[key] === 'string')
267921
+ return record[key];
267922
+ }
267923
+ }
267924
+ return undefined;
267925
+ }
267926
+ /**
267927
+ * The Skills section of the agent configuration modal. Resolves the agent's
267928
+ * UUID from mentor settings and renders the AgentSkills manager (effective
267929
+ * skills + attachable catalog). Skills only apply to Base Agents — when the
267930
+ * settings identify another agent type, an informational note renders
267931
+ * instead. Hosts should also hide the tab for non-Base-Agents when they can.
267932
+ */
267933
+ function AgentSkillsTab({ labels: labelsOverride, tenantKey: tenantKeyProp, mentorId: mentorIdProp, username: usernameProp, userIsStudent: userIsStudentProp, }) {
267934
+ var _a, _b, _c, _d, _e;
267935
+ const t = useT();
267936
+ const labels = React__default.useMemo(() => resolveSkillsTabLabels(labelsOverride, t), [labelsOverride, t]);
267937
+ const ctx = useAgentSettingsOptional();
267938
+ const tenantKey = (_a = tenantKeyProp !== null && tenantKeyProp !== void 0 ? tenantKeyProp : ctx === null || ctx === void 0 ? void 0 : ctx.tenantKey) !== null && _a !== void 0 ? _a : '';
267939
+ const mentorId = (_b = mentorIdProp !== null && mentorIdProp !== void 0 ? mentorIdProp : ctx === null || ctx === void 0 ? void 0 : ctx.mentorId) !== null && _b !== void 0 ? _b : '';
267940
+ const username = (_c = usernameProp !== null && usernameProp !== void 0 ? usernameProp : ctx === null || ctx === void 0 ? void 0 : ctx.username) !== null && _c !== void 0 ? _c : '';
267941
+ // Agent Skills are admin-only: render nothing for learners even if a host
267942
+ // registers the tab or deep-links to it. Prop overrides context.
267943
+ const userIsStudent = (_d = userIsStudentProp !== null && userIsStudentProp !== void 0 ? userIsStudentProp : ctx === null || ctx === void 0 ? void 0 : ctx.userIsStudent) !== null && _d !== void 0 ? _d : false;
267944
+ const { data: mentorSettings, isLoading: isSettingsLoading } = useGetMentorSettingsQuery({
267945
+ mentor: mentorId,
267946
+ org: tenantKey,
267947
+ }, { skip: !username || !mentorId || !tenantKey || userIsStudent });
267948
+ const settings = mentorSettings;
267949
+ const mentorUniqueId = (_e = settings === null || settings === void 0 ? void 0 : settings.mentor_unique_id) !== null && _e !== void 0 ? _e : '';
267950
+ const templateSlug = templateMentorSlug(settings === null || settings === void 0 ? void 0 : settings.template_mentor);
267951
+ // Only block when the template positively identifies a non-Base-Agent type;
267952
+ // with no template evidence (custom mentors carry their own slug), render
267953
+ // the manager and let the backend enforce.
267954
+ const knownNotBaseAgent = !!settings &&
267955
+ templateSlug !== undefined &&
267956
+ !isBaseAgentMentor({ mentorSlug: settings.mentor_slug, templateMentorSlug: templateSlug });
267957
+ if (userIsStudent)
267958
+ return null;
267959
+ return (jsxs(Fragment$1, { children: [jsx("div", { className: "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 })] }) }), jsx("div", { className: "flex-1 space-y-4 p-3", style: {
267960
+ overflowY: 'auto',
267961
+ overflowX: 'hidden',
267962
+ }, children: isSettingsLoading || !mentorUniqueId ? (jsxs("div", { className: "flex items-center gap-2 p-4", role: "status", children: [jsx(LoaderCircle, { className: "h-4 w-4 animate-spin text-blue-500" }), jsx("span", { className: "text-sm text-gray-500", children: labels.loading })] })) : knownNotBaseAgent ? (jsx("div", { className: "flex items-center justify-center rounded-lg border p-6", children: jsx("p", { className: "text-sm text-gray-500", children: labels.notBaseAgent }) })) : (jsx(AgentSkills, { platformKey: tenantKey, mentorUniqueId: mentorUniqueId })) })] }));
267963
+ }
267964
+
267411
267965
  const AGENT_GRADER_TAB_LABELS = {
267412
267966
  header: {
267413
267967
  title: 'Grader',
@@ -269491,7 +270045,7 @@ function AgentLinksSection({ identity, labels, }) {
269491
270045
  event.stopPropagation();
269492
270046
  setEditingLink(link);
269493
270047
  }, children: jsx(Pencil, { className: "h-4 w-4" }) }) })] }, link.id));
269494
- }) })] }) }), isFetching && (jsx("p", { className: "px-3 py-2 text-xs text-gray-400", children: labels.common.refreshing }))] })), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: busy || isFetching }), showCreate && (jsx(AgentLinkModal, { isOpen: showCreate, onClose: () => setShowCreate(false), platformKey: platformKey, mentorId: mentorId, mentorUniqueId: mentorUniqueId, username: username, isLtiAccessible: isLtiAccessible, labels: labels })), editingLink && (jsx(AgentLinkModal, { isOpen: Boolean(editingLink), onClose: () => setEditingLink(null), platformKey: platformKey, mentorId: mentorId, mentorUniqueId: mentorUniqueId, username: username, isLtiAccessible: isLtiAccessible, link: editingLink, labels: labels }))] }));
270048
+ }) })] }) }), isFetching && (jsx("p", { className: "px-3 py-2 text-xs text-gray-400", children: labels.common.refreshing }))] })), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: busy }), showCreate && (jsx(AgentLinkModal, { isOpen: showCreate, onClose: () => setShowCreate(false), platformKey: platformKey, mentorId: mentorId, mentorUniqueId: mentorUniqueId, username: username, isLtiAccessible: isLtiAccessible, labels: labels })), editingLink && (jsx(AgentLinkModal, { isOpen: Boolean(editingLink), onClose: () => setEditingLink(null), platformKey: platformKey, mentorId: mentorId, mentorUniqueId: mentorUniqueId, username: username, isLtiAccessible: isLtiAccessible, link: editingLink, labels: labels }))] }));
269495
270049
  }
269496
270050
 
269497
270051
  function KeyCreateModal({ isOpen, onClose, platformKey, labels }) {
@@ -269588,7 +270142,7 @@ function KeysSection({ identity, labels }) {
269588
270142
  const keys = React__default.useMemo(() => toArray(keysData), [keysData]);
269589
270143
  const totalPages = getTotalPages(keysData);
269590
270144
  const busy = !isReady || isLoading;
269591
- return (jsxs("div", { className: "space-y-4", "data-testid": "lti-keys-section", children: [jsxs("div", { className: "flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.keys.description }), jsxs(Button$1, { onClick: () => setShowCreate(true), size: "sm", "data-testid": "lti-key-create-button", className: "cursor-pointer whitespace-nowrap bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), labels.keys.createButton] })] }), busy ? (jsx("div", { className: "flex w-full items-center justify-center py-10", children: jsx(Spinner, {}) })) : keys.length === 0 ? (jsxs("div", { className: "flex flex-col items-center justify-center gap-3 rounded-md border border-dashed border-gray-200 py-12 text-center", "data-testid": "lti-keys-empty", children: [jsx(KeyRound, { className: "h-8 w-8 text-gray-300", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-[#646464]", children: labels.keys.empty })] })) : (jsxs("div", { className: "overflow-hidden rounded-md border", children: [jsx("div", { className: "overflow-x-auto", children: jsxs(Table$1, { className: "min-w-full", children: [jsx(TableHeader$1, { children: jsxs(TableRow$1, { className: "bg-muted/50 border-b", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.common.nameColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.keys.publicKeyColumn }), jsx(TableHead, { className: "p-3 text-right text-sm whitespace-nowrap text-[#646464]", children: labels.common.actionsColumn })] }) }), jsx(TableBody, { children: keys.map((key) => (jsxs(TableRow$1, { "data-testid": "lti-key-row", className: "border-b last:border-0 hover:bg-muted/40", children: [jsx(TableCell$1, { className: "p-3 text-sm font-medium text-gray-900", children: key.name }), jsx(TableCell$1, { className: "p-3 font-mono text-xs text-[#646464]", children: truncateMiddle(key.public_key, 40) }), jsx(TableCell$1, { className: "p-3 text-right", children: jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { type: "button", variant: "ghost", size: "icon", "aria-label": labels.keys.actionsAria(key.name), children: jsx(EllipsisVertical, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsxs(DropdownMenuItem, { onClick: () => setSelectedKey(key), children: [jsx(Pencil, { className: "mr-2 h-4 w-4" }), labels.common.edit] }), jsxs(DropdownMenuItem, { className: "text-red-600 focus:text-red-700", onClick: () => setKeyToDelete(key), children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), labels.common.delete] })] })] }) })] }, key.id))) })] }) }), isFetching && (jsx("p", { className: "px-3 py-2 text-xs text-gray-400", children: labels.common.refreshing }))] })), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: busy || isFetching }), showCreate && (jsx(KeyCreateModal, { isOpen: showCreate, onClose: () => setShowCreate(false), platformKey: platformKey, labels: labels })), selectedKey && (jsx(KeyDetailModal, { isOpen: Boolean(selectedKey), onClose: () => setSelectedKey(null), platformKey: platformKey, ltiKey: selectedKey, labels: labels })), keyToDelete && (jsx(KeyDeleteModal, { isOpen: Boolean(keyToDelete), onClose: () => setKeyToDelete(null), platformKey: platformKey, ltiKey: keyToDelete, labels: labels }))] }));
270145
+ return (jsxs("div", { className: "space-y-4", "data-testid": "lti-keys-section", children: [jsxs("div", { className: "flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.keys.description }), jsxs(Button$1, { onClick: () => setShowCreate(true), size: "sm", "data-testid": "lti-key-create-button", className: "cursor-pointer whitespace-nowrap bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), labels.keys.createButton] })] }), busy ? (jsx("div", { className: "flex w-full items-center justify-center py-10", children: jsx(Spinner, {}) })) : keys.length === 0 ? (jsxs("div", { className: "flex flex-col items-center justify-center gap-3 rounded-md border border-dashed border-gray-200 py-12 text-center", "data-testid": "lti-keys-empty", children: [jsx(KeyRound, { className: "h-8 w-8 text-gray-300", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-[#646464]", children: labels.keys.empty })] })) : (jsxs("div", { className: "overflow-hidden rounded-md border", children: [jsx("div", { className: "overflow-x-auto", children: jsxs(Table$1, { className: "min-w-full", children: [jsx(TableHeader$1, { children: jsxs(TableRow$1, { className: "bg-muted/50 border-b", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.common.nameColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.keys.publicKeyColumn }), jsx(TableHead, { className: "p-3 text-right text-sm whitespace-nowrap text-[#646464]", children: labels.common.actionsColumn })] }) }), jsx(TableBody, { children: keys.map((key) => (jsxs(TableRow$1, { "data-testid": "lti-key-row", className: "border-b last:border-0 hover:bg-muted/40", children: [jsx(TableCell$1, { className: "p-3 text-sm font-medium text-gray-900", children: key.name }), jsx(TableCell$1, { className: "p-3 font-mono text-xs text-[#646464]", children: truncateMiddle(key.public_key, 40) }), jsx(TableCell$1, { className: "p-3 text-right", children: jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button$1, { type: "button", variant: "ghost", size: "icon", "aria-label": labels.keys.actionsAria(key.name), children: jsx(EllipsisVertical, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsxs(DropdownMenuItem, { onClick: () => setSelectedKey(key), children: [jsx(Pencil, { className: "mr-2 h-4 w-4" }), labels.common.edit] }), jsxs(DropdownMenuItem, { className: "text-red-600 focus:text-red-700", onClick: () => setKeyToDelete(key), children: [jsx(Trash2, { className: "mr-2 h-4 w-4" }), labels.common.delete] })] })] }) })] }, key.id))) })] }) }), isFetching && (jsx("p", { className: "px-3 py-2 text-xs text-gray-400", children: labels.common.refreshing }))] })), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: busy }), showCreate && (jsx(KeyCreateModal, { isOpen: showCreate, onClose: () => setShowCreate(false), platformKey: platformKey, labels: labels })), selectedKey && (jsx(KeyDetailModal, { isOpen: Boolean(selectedKey), onClose: () => setSelectedKey(null), platformKey: platformKey, ltiKey: selectedKey, labels: labels })), keyToDelete && (jsx(KeyDeleteModal, { isOpen: Boolean(keyToDelete), onClose: () => setKeyToDelete(null), platformKey: platformKey, ltiKey: keyToDelete, labels: labels }))] }));
269592
270146
  }
269593
270147
 
269594
270148
  function FieldError({ field, }) {
@@ -269727,7 +270281,7 @@ function ToolsSection({ identity, labels }) {
269727
270281
  return (jsxs("div", { className: "space-y-4", "data-testid": "lti-tools-section", children: [jsxs("div", { className: "flex flex-col items-start justify-between gap-3 sm:flex-row sm:items-center", children: [jsx("p", { className: "text-xs text-gray-600", children: labels.tools.description }), jsxs(Button$1, { onClick: () => setShowCreate(true), size: "sm", "data-testid": "lti-tool-create-button", className: "cursor-pointer whitespace-nowrap bg-gradient-to-r from-[#2563EB] to-[#93C5FD] text-white hover:opacity-90", children: [jsx(Plus, { className: "h-4 w-4" }), labels.tools.createButton] })] }), busy ? (jsx("div", { className: "flex w-full items-center justify-center py-10", children: jsx(Spinner, {}) })) : !tools || tools.length === 0 ? (jsxs("div", { className: "flex flex-col items-center justify-center gap-3 rounded-md border border-dashed border-gray-200 py-12 text-center", "data-testid": "lti-tools-empty", children: [jsx(Wrench, { className: "h-8 w-8 text-gray-300", "aria-hidden": "true" }), jsx("p", { className: "text-sm text-[#646464]", children: labels.tools.empty })] })) : (jsxs("div", { className: "overflow-hidden rounded-md border", children: [jsx("div", { className: "overflow-x-auto", children: jsxs(Table$1, { className: "min-w-full", children: [jsx(TableHeader$1, { children: jsxs(TableRow$1, { className: "bg-muted/50 border-b", children: [jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.common.nameColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.tools.issuerColumn }), jsx(TableHead, { className: "p-3 text-left text-sm whitespace-nowrap text-[#646464]", children: labels.tools.clientIdColumn }), jsx(TableHead, { className: "p-3 text-right text-sm whitespace-nowrap text-[#646464]", children: labels.common.actionsColumn })] }) }), jsx(TableBody, { children: tools.map((tool) => (jsxs(TableRow$1, { "data-testid": "lti-tool-row", className: "cursor-pointer border-b last:border-0 hover:bg-muted/40", onClick: () => setEditingTool(tool), children: [jsx(TableCell$1, { className: "p-3 text-sm font-medium text-gray-900", children: tool.title }), jsx(TableCell$1, { className: "max-w-[260px] truncate p-3 text-sm text-[#646464]", children: tool.issuer }), jsx(TableCell$1, { className: "max-w-[200px] truncate p-3 text-sm text-[#646464]", children: tool.client_id }), jsx(TableCell$1, { className: "p-3 text-right", children: jsx(Button$1, { type: "button", variant: "outline", size: "icon", "aria-label": labels.tools.editAria(tool.title), onClick: (event) => {
269728
270282
  event.stopPropagation();
269729
270283
  setEditingTool(tool);
269730
- }, children: jsx(Pencil, { className: "h-4 w-4" }) }) })] }, tool.id))) })] }) }), isFetching && (jsx("p", { className: "px-3 py-2 text-xs text-gray-400", children: labels.common.refreshing }))] })), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: busy || isFetching }), showCreate && (jsx(ToolModal, { isOpen: showCreate, onClose: () => setShowCreate(false), platformKey: platformKey, labels: labels })), editingTool && (jsx(ToolModal, { isOpen: Boolean(editingTool), onClose: () => setEditingTool(null), platformKey: platformKey, tool: editingTool, labels: labels }))] }));
270284
+ }, children: jsx(Pencil, { className: "h-4 w-4" }) }) })] }, tool.id))) })] }) }), isFetching && (jsx("p", { className: "px-3 py-2 text-xs text-gray-400", children: labels.common.refreshing }))] })), jsx(IblPagination, { currentPage: page, totalPages: totalPages, onPageChange: setPage, disabled: busy }), showCreate && (jsx(ToolModal, { isOpen: showCreate, onClose: () => setShowCreate(false), platformKey: platformKey, labels: labels })), editingTool && (jsx(ToolModal, { isOpen: Boolean(editingTool), onClose: () => setEditingTool(null), platformKey: platformKey, tool: editingTool, labels: labels }))] }));
269731
270285
  }
269732
270286
 
269733
270287
  function ToolEndpointsSection({ identity, labels, }) {
@@ -273376,7 +273930,15 @@ function StatusBadge({ status }) {
273376
273930
  : 'bg-gray-100 text-gray-600';
273377
273931
  return (jsx("span", { className: cn('inline-flex rounded-full px-2 py-0.5 text-xs font-medium', color), children: upper !== null && upper !== void 0 ? upper : '—' }));
273378
273932
  }
273379
- function AgentEvaluationTab({ getLLMProviderDetails, labels: labelsOverride, PaginationComponent, }) {
273933
+ function AgentEvaluationTab({ userIsStudent: userIsStudentProp, ...props }) {
273934
+ var _a;
273935
+ const ctx = useAgentSettings();
273936
+ const userIsStudent = (_a = userIsStudentProp !== null && userIsStudentProp !== void 0 ? userIsStudentProp : ctx.userIsStudent) !== null && _a !== void 0 ? _a : false;
273937
+ if (userIsStudent)
273938
+ return null;
273939
+ return jsx(AgentEvaluationTabContent, { ...props });
273940
+ }
273941
+ function AgentEvaluationTabContent({ getLLMProviderDetails, labels: labelsOverride, PaginationComponent, }) {
273380
273942
  var _a, _b;
273381
273943
  const { tenantKey, mentorId, username } = useAgentSettings();
273382
273944
  const dispatch = useDispatch();
@@ -277517,7 +278079,7 @@ const CODE_FILE_EXTENSIONS = new Set([
277517
278079
  'css',
277518
278080
  'sh',
277519
278081
  ]);
277520
- function Chat({ mode = 'default', isPreviewMode = false, hasBorder = true, isInCanvasView = false, config, redirectToAuthSpa, username, userTenants, visitingTenant, axdToken, mentorId, tenantKey, userIsStudent, isPublicRoute, showConversationStarters = false, showExploreMentors = false, projectId, }) {
278082
+ function Chat({ mode = 'default', isPreviewMode = false, hasBorder = true, isInCanvasView = false, config, redirectToAuthSpa, username, userTenants, visitingTenant, axdToken, mentorId, tenantKey, userIsStudent, isPublicRoute, showConversationStarters = false, showExploreMentors = false, projectId, slashSkills, slashSkillsLoading = false, }) {
277521
278083
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
277522
278084
  const t = useT();
277523
278085
  const { metadata } = useTenantContext();
@@ -278546,7 +279108,7 @@ function Chat({ mode = 'default', isPreviewMode = false, hasBorder = true, isInC
278546
279108
  !(messages.length > 0 &&
278547
279109
  ((_g = messages[messages.length - 1]) === null || _g === void 0 ? void 0 : _g.role) === 'assistant' &&
278548
279110
  ((_h = messages[messages.length - 1]) === null || _h === void 0 ? void 0 : _h.artifactVersions) &&
278549
- ((_l = (_k = (_j = messages[messages.length - 1]) === null || _j === void 0 ? void 0 : _j.artifactVersions) === null || _k === void 0 ? void 0 : _k.length) !== null && _l !== void 0 ? _l : 0) > 0) && jsx(LoadingMessage, { mentorName: mentorName, profileImage: profileImage }), !showingSharedChat && guidedPrompts] }) }) }), jsx("div", { className: "flex-shrink-0 overflow-y-auto border-t border-gray-200 bg-white p-3 [scrollbar-gutter:stable]", children: jsx(ChatInputForm, { mentorId: mentorId, userIsStudent: userIsStudent, isPublicRoute: isPublicRoute, sessionId: sessionId, onSubmit: handleSubmit, stopGenerating: stopGenerating, onScreenSharingClick: () => {
279111
+ ((_l = (_k = (_j = messages[messages.length - 1]) === null || _j === void 0 ? void 0 : _j.artifactVersions) === null || _k === void 0 ? void 0 : _k.length) !== null && _l !== void 0 ? _l : 0) > 0) && jsx(LoadingMessage, { mentorName: mentorName, profileImage: profileImage }), !showingSharedChat && guidedPrompts] }) }) }), jsx("div", { className: "flex-shrink-0 overflow-y-auto border-t border-gray-200 bg-white p-3 [scrollbar-gutter:stable]", children: jsx(ChatInputForm, { mentorId: mentorId, userIsStudent: userIsStudent, isPublicRoute: isPublicRoute, slashSkills: slashSkills, slashSkillsLoading: slashSkillsLoading, sessionId: sessionId, onSubmit: handleSubmit, stopGenerating: stopGenerating, onScreenSharingClick: () => {
278550
279112
  var _a;
278551
279113
  if (enableChatPopupActions && isInIframe()) {
278552
279114
  sendMessageToParentWebsite({
@@ -278578,7 +279140,7 @@ function Chat({ mode = 'default', isPreviewMode = false, hasBorder = true, isInC
278578
279140
  height: '100%',
278579
279141
  }, children: [jsx(CanvasView$1, { canvasTitle: canvasState.title, canvasContent: canvasState.content, canvasType: canvasState.type, artifactId: canvasState.artifactId, org: canvasState.org, userId: canvasState.userId, fileExtension: canvasState.fileExtension, metadata: canvasState.metadata, sessionId: sessionId, tenantKey: tenantKey, refreshTrigger: canvasRefreshTrigger, sendMessage: (text, options) => {
278580
279142
  sendMessage(activeTab, text, options);
278581
- }, onClose: handleCloseCanvas }, `${(_m = canvasState.artifactId) !== null && _m !== void 0 ? _m : 'canvas'}-${canvasRefreshTrigger}`), jsx("div", { className: "flex-shrink-0 border-t border-gray-200 bg-white p-3 md:hidden", children: jsx(ChatInputForm, { mentorId: mentorId, userIsStudent: userIsStudent, isPublicRoute: isPublicRoute, sessionId: sessionId, onSubmit: handleSubmit, stopGenerating: stopGenerating, onScreenSharingClick: () => {
279143
+ }, onClose: handleCloseCanvas }, `${(_m = canvasState.artifactId) !== null && _m !== void 0 ? _m : 'canvas'}-${canvasRefreshTrigger}`), jsx("div", { className: "flex-shrink-0 border-t border-gray-200 bg-white p-3 md:hidden", children: jsx(ChatInputForm, { mentorId: mentorId, userIsStudent: userIsStudent, isPublicRoute: isPublicRoute, slashSkills: slashSkills, slashSkillsLoading: slashSkillsLoading, sessionId: sessionId, onSubmit: handleSubmit, stopGenerating: stopGenerating, onScreenSharingClick: () => {
278582
279144
  var _a;
278583
279145
  if (enableChatPopupActions && isInIframe()) {
278584
279146
  sendMessageToParentWebsite({
@@ -278625,7 +279187,7 @@ function Chat({ mode = 'default', isPreviewMode = false, hasBorder = true, isInC
278625
279187
  (isAdvancedMode ||
278626
279188
  isEmbeddedMode ||
278627
279189
  (messages.length > 0 &&
278628
- (messages[0].role === 'assistant' ? messages.slice(1) : messages).length > 0)) && (jsx("div", { className: "flex-shrink-0 overflow-y-auto pb-3.5 [scrollbar-gutter:stable]", children: jsx(ChatInputForm, { mentorId: mentorId, userIsStudent: userIsStudent, isPublicRoute: isPublicRoute, sessionId: (_u = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _u !== void 0 ? _u : sessionId, onSubmit: handleSubmit, stopGenerating: stopGenerating, onScreenSharingClick: () => {
279190
+ (messages[0].role === 'assistant' ? messages.slice(1) : messages).length > 0)) && (jsx("div", { className: "flex-shrink-0 overflow-y-auto pb-3.5 [scrollbar-gutter:stable]", children: jsx(ChatInputForm, { mentorId: mentorId, userIsStudent: userIsStudent, isPublicRoute: isPublicRoute, slashSkills: slashSkills, slashSkillsLoading: slashSkillsLoading, sessionId: (_u = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _u !== void 0 ? _u : sessionId, onSubmit: handleSubmit, stopGenerating: stopGenerating, onScreenSharingClick: () => {
278629
279191
  var _a;
278630
279192
  if (enableChatPopupActions && isInIframe()) {
278631
279193
  sendMessageToParentWebsite({
@@ -329934,5 +330496,5 @@ var index_es = /*#__PURE__*/Object.freeze({
329934
330496
  vectorsRatio: vectorsRatio
329935
330497
  });
329936
330498
 
329937
- export { AGENT_ACCESS_TAB_LABELS, AGENT_ANALYTICS_TAB_LABELS, AGENT_API_TAB_LABELS, AGENT_DATASETS_TAB_LABELS, AGENT_DISCLAIMERS_TAB_LABELS, AGENT_EMBED_TAB_LABELS, AGENT_EVALUATION_TAB_LABELS, AGENT_GRADER_TAB_LABELS, AGENT_HISTORY_TAB_LABELS, AGENT_HUMAN_SUPPORT_TAB_LABELS, AGENT_LLM_TAB_LABELS, AGENT_LTI_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, AgentAnalyticsTab, AgentApiTab, AgentCard, AgentDatasetsTab, AgentDisclaimersTab, AgentEmbedTab, AgentEmptyState, AgentEvaluationTab, AgentGraderTab, AgentHistoryTab, AgentHumanSupportTab, AgentLLMTab, AgentLtiTab, AgentMemoryTab, AgentPrivacyTab, AgentPromptsTab, AgentSafetyTab, AgentScreenShareTab, AgentSearch, AgentSearchFilters, AgentSearchInput, AgentSettingsProvider, AgentSettingsTab, AgentTasksTab, AgentToolsTab, AgentVoiceTab, AppSidebar, CATALOGS, Chat, ClientErrorPage, ConversationStarters$1 as ConversationStarters, CopyButton, CopyMentorModal, CourseBox, CourseContentLayout, CourseContentTabPage, CreatePathwayModal, CredentialDetailModal, CredentialMiniBox, DEFAULT_ANALYTICS_HUB_TABS, DEFAULT_LOCALE, DeleteMentorModal, EMPTY_PROGRAM_SETTINGS_FORM, EdxIframe, ErrorPage, GRADING_TOOL_NAME, GreetingMethod, McpTab, MediaBox, MentorSelectionGrid, NavBar, OrganizationTab, PLATFORM_SIDEBAR_FLYOUT_ITEM_COLOR, PLATFORM_SIDEBAR_FLYOUT_TITLE_COLOR, PLATFORM_SIDEBAR_NAV_ACTIVE_BG_OPEN, PLATFORM_SIDEBAR_NAV_MUTED, PathwayDetailModal, PlatformAccountSheet, PlatformSidebar, PlatformSidebarCollapsedLabelFlyout, PlatformSidebarCollapsedNavFlyout, PlatformSidebarFooter, PlatformSidebarNavDivider, PlatformSidebarNavSection, PlatformSidebarSubNavItem, ProfileInfoCards, ProfileTabs, ProgramDetailModal, ProjectsSidebarDropdown, SUPPORTED_LOCALES, SidebarInset, SidebarProvider, SidebarTrigger, SsoLogin, StarButton, UserProfileDropdown, UserProfileModal, WebContainersI18nProvider, formatDateString, getCatalog, getLLMProviderDetails, initializeLocalStorageWithObject, isValidLocale, resolveAgentPickerLabels, resolveAgentSearchLabels, resolveSettingsTabLabels, useAgentSearch, useAgentSearchWithPagination, useAgentSettings, useAgentStar, useGetChatDetails, usePlatformSidebarFooterActions, usePlatformSidebarNavCallback, useSidebar, useT, useTimeTracker, useWebContainersI18n, useWebContainersLocale };
330499
+ export { AGENT_ACCESS_TAB_LABELS, AGENT_ANALYTICS_TAB_LABELS, AGENT_API_TAB_LABELS, AGENT_DATASETS_TAB_LABELS, AGENT_DISCLAIMERS_TAB_LABELS, AGENT_EMBED_TAB_LABELS, AGENT_EVALUATION_TAB_LABELS, AGENT_GRADER_TAB_LABELS, AGENT_HISTORY_TAB_LABELS, AGENT_HUMAN_SUPPORT_TAB_LABELS, AGENT_LLM_TAB_LABELS, AGENT_LTI_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_SKILLS_TAB_LABELS, AGENT_TASKS_TAB_LABELS, AGENT_TOOLS_TAB_LABELS, AGENT_VOICE_TAB_LABELS, Account, AgentAccessTab, AgentAnalyticsTab, AgentApiTab, AgentCard, AgentDatasetsTab, AgentDisclaimersTab, AgentEmbedTab, AgentEmptyState, AgentEvaluationTab, AgentGraderTab, AgentHistoryTab, AgentHumanSupportTab, AgentLLMTab, AgentLtiTab, AgentMemoryTab, AgentPrivacyTab, AgentPromptsTab, AgentSafetyTab, AgentScreenShareTab, AgentSearch, AgentSearchFilters, AgentSearchInput, AgentSettingsProvider, AgentSettingsTab, AgentSkillsTab, AgentTasksTab, AgentToolsTab, AgentVoiceTab, AppSidebar, CATALOGS, Chat, ClientErrorPage, ConversationStarters$1 as ConversationStarters, CopyButton, CopyMentorModal, CourseBox, CourseContentLayout, CourseContentTabPage, CreatePathwayModal, CredentialDetailModal, CredentialMiniBox, DEFAULT_ANALYTICS_HUB_TABS, DEFAULT_LOCALE, DeleteMentorModal, EMPTY_PROGRAM_SETTINGS_FORM, EdxIframe, ErrorPage, GRADING_TOOL_NAME, GreetingMethod, McpTab, MediaBox, MentorSelectionGrid, NavBar, OrganizationTab, PLATFORM_SIDEBAR_FLYOUT_ITEM_COLOR, PLATFORM_SIDEBAR_FLYOUT_TITLE_COLOR, PLATFORM_SIDEBAR_NAV_ACTIVE_BG_OPEN, PLATFORM_SIDEBAR_NAV_MUTED, PathwayDetailModal, PlatformAccountSheet, PlatformSidebar, PlatformSidebarCollapsedLabelFlyout, PlatformSidebarCollapsedNavFlyout, PlatformSidebarFooter, PlatformSidebarNavDivider, PlatformSidebarNavSection, PlatformSidebarSubNavItem, ProfileInfoCards, ProfileTabs, ProgramDetailModal, ProjectsSidebarDropdown, SUPPORTED_LOCALES, SidebarInset, SidebarProvider, SidebarTrigger, SsoLogin, StarButton, UserProfileDropdown, UserProfileModal, WebContainersI18nProvider, formatDateString, getCatalog, getLLMProviderDetails, initializeLocalStorageWithObject, isValidLocale, resolveAgentPickerLabels, resolveAgentSearchLabels, resolveSettingsTabLabels, useAgentSearch, useAgentSearchWithPagination, useAgentSettings, useAgentStar, useGetChatDetails, usePlatformSidebarFooterActions, usePlatformSidebarNavCallback, useSidebar, useT, useTimeTracker, useWebContainersI18n, useWebContainersLocale };
329938
330500
  //# sourceMappingURL=index.esm.js.map