diff --git a/packages/backend/server/src/base/error/def.ts b/packages/backend/server/src/base/error/def.ts index c763922aaa..5cbdfc6c28 100644 --- a/packages/backend/server/src/base/error/def.ts +++ b/packages/backend/server/src/base/error/def.ts @@ -653,12 +653,19 @@ export const USER_FRIENDLY_ERRORS = { }, no_copilot_provider_available: { type: 'internal_server_error', - message: `No copilot provider available.`, + args: { modelId: 'string' }, + message: ({ modelId }) => `No copilot provider available: ${modelId}`, }, copilot_failed_to_generate_text: { type: 'internal_server_error', message: `Failed to generate text.`, }, + copilot_failed_to_generate_embedding: { + type: 'internal_server_error', + args: { provider: 'string', message: 'string' }, + message: ({ provider, message }) => + `Failed to generate embedding with ${provider}: ${message}`, + }, copilot_failed_to_create_message: { type: 'internal_server_error', message: `Failed to create chat message.`, diff --git a/packages/backend/server/src/base/error/errors.gen.ts b/packages/backend/server/src/base/error/errors.gen.ts index 709a797438..0400572f1e 100644 --- a/packages/backend/server/src/base/error/errors.gen.ts +++ b/packages/backend/server/src/base/error/errors.gen.ts @@ -668,10 +668,14 @@ export class CopilotSessionDeleted extends UserFriendlyError { super('action_forbidden', 'copilot_session_deleted', message); } } +@ObjectType() +class NoCopilotProviderAvailableDataType { + @Field() modelId!: string +} export class NoCopilotProviderAvailable extends UserFriendlyError { - constructor(message?: string) { - super('internal_server_error', 'no_copilot_provider_available', message); + constructor(args: NoCopilotProviderAvailableDataType, message?: string | ((args: NoCopilotProviderAvailableDataType) => string)) { + super('internal_server_error', 'no_copilot_provider_available', message, args); } } @@ -680,6 +684,17 @@ export class CopilotFailedToGenerateText extends UserFriendlyError { super('internal_server_error', 'copilot_failed_to_generate_text', message); } } +@ObjectType() +class CopilotFailedToGenerateEmbeddingDataType { + @Field() provider!: string + @Field() message!: string +} + +export class CopilotFailedToGenerateEmbedding extends UserFriendlyError { + constructor(args: CopilotFailedToGenerateEmbeddingDataType, message?: string | ((args: CopilotFailedToGenerateEmbeddingDataType) => string)) { + super('internal_server_error', 'copilot_failed_to_generate_embedding', message, args); + } +} export class CopilotFailedToCreateMessage extends UserFriendlyError { constructor(message?: string) { @@ -1179,6 +1194,7 @@ export enum ErrorNames { COPILOT_SESSION_DELETED, NO_COPILOT_PROVIDER_AVAILABLE, COPILOT_FAILED_TO_GENERATE_TEXT, + COPILOT_FAILED_TO_GENERATE_EMBEDDING, COPILOT_FAILED_TO_CREATE_MESSAGE, UNSPLASH_IS_NOT_CONFIGURED, COPILOT_ACTION_TAKEN, @@ -1239,5 +1255,5 @@ registerEnumType(ErrorNames, { export const ErrorDataUnionType = createUnionType({ name: 'ErrorDataUnion', types: () => - [GraphqlBadRequestDataType, HttpRequestErrorDataType, QueryTooLongDataType, ValidationErrorDataType, WrongSignInCredentialsDataType, UnknownOauthProviderDataType, InvalidOauthCallbackCodeDataType, MissingOauthQueryParameterDataType, InvalidOauthResponseDataType, InvalidEmailDataType, InvalidPasswordLengthDataType, WorkspacePermissionNotFoundDataType, SpaceNotFoundDataType, MemberNotFoundInSpaceDataType, NotInSpaceDataType, AlreadyInSpaceDataType, SpaceAccessDeniedDataType, SpaceOwnerNotFoundDataType, SpaceShouldHaveOnlyOneOwnerDataType, DocNotFoundDataType, DocActionDeniedDataType, DocUpdateBlockedDataType, VersionRejectedDataType, InvalidHistoryTimestampDataType, DocHistoryNotFoundDataType, BlobNotFoundDataType, ExpectToGrantDocUserRolesDataType, ExpectToRevokeDocUserRolesDataType, ExpectToUpdateDocUserRoleDataType, NoMoreSeatDataType, UnsupportedSubscriptionPlanDataType, SubscriptionAlreadyExistsDataType, SubscriptionNotExistsDataType, SameSubscriptionRecurringDataType, SubscriptionPlanNotFoundDataType, CopilotDocNotFoundDataType, CopilotMessageNotFoundDataType, CopilotPromptNotFoundDataType, CopilotProviderNotSupportedDataType, CopilotProviderSideErrorDataType, CopilotInvalidContextDataType, CopilotContextFileNotSupportedDataType, CopilotFailedToModifyContextDataType, CopilotFailedToMatchContextDataType, CopilotFailedToMatchGlobalContextDataType, CopilotFailedToAddWorkspaceFileEmbeddingDataType, RuntimeConfigNotFoundDataType, InvalidRuntimeConfigTypeDataType, InvalidLicenseToActivateDataType, InvalidLicenseUpdateParamsDataType, UnsupportedClientVersionDataType, MentionUserDocAccessDeniedDataType, InvalidAppConfigDataType, InvalidAppConfigInputDataType, InvalidSearchProviderRequestDataType, InvalidIndexerInputDataType] as const, + [GraphqlBadRequestDataType, HttpRequestErrorDataType, QueryTooLongDataType, ValidationErrorDataType, WrongSignInCredentialsDataType, UnknownOauthProviderDataType, InvalidOauthCallbackCodeDataType, MissingOauthQueryParameterDataType, InvalidOauthResponseDataType, InvalidEmailDataType, InvalidPasswordLengthDataType, WorkspacePermissionNotFoundDataType, SpaceNotFoundDataType, MemberNotFoundInSpaceDataType, NotInSpaceDataType, AlreadyInSpaceDataType, SpaceAccessDeniedDataType, SpaceOwnerNotFoundDataType, SpaceShouldHaveOnlyOneOwnerDataType, DocNotFoundDataType, DocActionDeniedDataType, DocUpdateBlockedDataType, VersionRejectedDataType, InvalidHistoryTimestampDataType, DocHistoryNotFoundDataType, BlobNotFoundDataType, ExpectToGrantDocUserRolesDataType, ExpectToRevokeDocUserRolesDataType, ExpectToUpdateDocUserRoleDataType, NoMoreSeatDataType, UnsupportedSubscriptionPlanDataType, SubscriptionAlreadyExistsDataType, SubscriptionNotExistsDataType, SameSubscriptionRecurringDataType, SubscriptionPlanNotFoundDataType, NoCopilotProviderAvailableDataType, CopilotFailedToGenerateEmbeddingDataType, CopilotDocNotFoundDataType, CopilotMessageNotFoundDataType, CopilotPromptNotFoundDataType, CopilotProviderNotSupportedDataType, CopilotProviderSideErrorDataType, CopilotInvalidContextDataType, CopilotContextFileNotSupportedDataType, CopilotFailedToModifyContextDataType, CopilotFailedToMatchContextDataType, CopilotFailedToMatchGlobalContextDataType, CopilotFailedToAddWorkspaceFileEmbeddingDataType, RuntimeConfigNotFoundDataType, InvalidRuntimeConfigTypeDataType, InvalidLicenseToActivateDataType, InvalidLicenseUpdateParamsDataType, UnsupportedClientVersionDataType, MentionUserDocAccessDeniedDataType, InvalidAppConfigDataType, InvalidAppConfigInputDataType, InvalidSearchProviderRequestDataType, InvalidIndexerInputDataType] as const, }); diff --git a/packages/backend/server/src/models/copilot-context.ts b/packages/backend/server/src/models/copilot-context.ts index ef9213afc4..908e0f7b2e 100644 --- a/packages/backend/server/src/models/copilot-context.ts +++ b/packages/backend/server/src/models/copilot-context.ts @@ -165,6 +165,13 @@ export class CopilotContextModel extends BaseModel { fileId: string, embeddings: Embedding[] ) { + if (embeddings.length === 0) { + this.logger.warn( + `No embeddings provided for contextId: ${contextId}, fileId: ${fileId}. Skipping insertion.` + ); + return; + } + const values = this.processEmbeddings(contextId, fileId, embeddings); await this.db.$executeRaw` @@ -204,6 +211,13 @@ export class CopilotContextModel extends BaseModel { docId: string, embeddings: Embedding[] ) { + if (embeddings.length === 0) { + this.logger.warn( + `No embeddings provided for workspaceId: ${workspaceId}, docId: ${docId}. Skipping insertion.` + ); + return; + } + const values = this.processEmbeddings( workspaceId, docId, diff --git a/packages/backend/server/src/models/copilot-workspace.ts b/packages/backend/server/src/models/copilot-workspace.ts index 4032ec4fde..84cb0907ca 100644 --- a/packages/backend/server/src/models/copilot-workspace.ts +++ b/packages/backend/server/src/models/copilot-workspace.ts @@ -283,6 +283,13 @@ export class CopilotWorkspaceConfigModel extends BaseModel { fileId: string, embeddings: Embedding[] ) { + if (embeddings.length === 0) { + this.logger.warn( + `No embeddings provided for workspaceId: ${workspaceId}, fileId: ${fileId}. Skipping insertion.` + ); + return; + } + const values = this.processEmbeddings(workspaceId, fileId, embeddings); await this.db.$executeRaw` INSERT INTO "ai_workspace_file_embeddings" diff --git a/packages/backend/server/src/plugins/copilot/context/service.ts b/packages/backend/server/src/plugins/copilot/context/service.ts index 9d2e55658c..8631283365 100644 --- a/packages/backend/server/src/plugins/copilot/context/service.ts +++ b/packages/backend/server/src/plugins/copilot/context/service.ts @@ -125,7 +125,10 @@ export class CopilotContextService implements OnApplicationBootstrap { async get(id: string): Promise { if (!this.embeddingClient) { - throw new NoCopilotProviderAvailable('embedding client not configured'); + throw new NoCopilotProviderAvailable( + { modelId: 'embedding' }, + 'embedding client not configured' + ); } const context = await this.getCachedSession(id); diff --git a/packages/backend/server/src/plugins/copilot/controller.ts b/packages/backend/server/src/plugins/copilot/controller.ts index 38d4dfe992..8bd66878f8 100644 --- a/packages/backend/server/src/plugins/copilot/controller.ts +++ b/packages/backend/server/src/plugins/copilot/controller.ts @@ -124,7 +124,7 @@ export class CopilotController implements BeforeApplicationShutdown { modelId: model, }); if (!provider) { - throw new NoCopilotProviderAvailable(); + throw new NoCopilotProviderAvailable({ modelId: model }); } return { provider, model, hasAttachment }; diff --git a/packages/backend/server/src/plugins/copilot/embedding/client.ts b/packages/backend/server/src/plugins/copilot/embedding/client.ts index 1ca8bd082b..5b796e375c 100644 --- a/packages/backend/server/src/plugins/copilot/embedding/client.ts +++ b/packages/backend/server/src/plugins/copilot/embedding/client.ts @@ -5,6 +5,7 @@ import { CopilotPromptNotFound, CopilotProviderNotSupported, } from '../../../base'; +import { CopilotFailedToGenerateEmbedding } from '../../../base/error/errors.gen'; import { ChunkSimilarity, Embedding } from '../../../models'; import { PromptService } from '../prompt'; import { @@ -74,6 +75,12 @@ class ProductionEmbeddingClient extends EmbeddingClient { input, { dimensions: EMBEDDING_DIMENSIONS } ); + if (embeddings.length !== input.length) { + throw new CopilotFailedToGenerateEmbedding({ + provider: provider.type, + message: `Expected ${input.length} embeddings, got ${embeddings.length}`, + }); + } return Array.from(embeddings.entries()).map(([index, embedding]) => ({ index, diff --git a/packages/backend/server/src/plugins/copilot/session.ts b/packages/backend/server/src/plugins/copilot/session.ts index 3efbf6da0f..43d4abbac4 100644 --- a/packages/backend/server/src/plugins/copilot/session.ts +++ b/packages/backend/server/src/plugins/copilot/session.ts @@ -569,7 +569,7 @@ export class ChatSessionService { }); if (!provider) { - throw new NoCopilotProviderAvailable(); + throw new NoCopilotProviderAvailable({ modelId: prompt.model }); } return provider.text(cond, [...prompt.finish({}), msg], config); diff --git a/packages/backend/server/src/plugins/copilot/transcript/service.ts b/packages/backend/server/src/plugins/copilot/transcript/service.ts index 885bfac5e1..d4411be9b5 100644 --- a/packages/backend/server/src/plugins/copilot/transcript/service.ts +++ b/packages/backend/server/src/plugins/copilot/transcript/service.ts @@ -171,7 +171,7 @@ export class CopilotTranscriptionService { ); if (!provider) { - throw new NoCopilotProviderAvailable(); + throw new NoCopilotProviderAvailable({ modelId }); } return provider; diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index 08adb84d1a..160f798137 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -291,6 +291,11 @@ type CopilotFailedToAddWorkspaceFileEmbeddingDataType { message: String! } +type CopilotFailedToGenerateEmbeddingDataType { + message: String! + provider: String! +} + type CopilotFailedToMatchContextDataType { content: String! contextId: String! @@ -616,7 +621,7 @@ type EditorType { name: String! } -union ErrorDataUnion = AlreadyInSpaceDataType | BlobNotFoundDataType | CopilotContextFileNotSupportedDataType | CopilotDocNotFoundDataType | CopilotFailedToAddWorkspaceFileEmbeddingDataType | CopilotFailedToMatchContextDataType | CopilotFailedToMatchGlobalContextDataType | CopilotFailedToModifyContextDataType | CopilotInvalidContextDataType | CopilotMessageNotFoundDataType | CopilotPromptNotFoundDataType | CopilotProviderNotSupportedDataType | CopilotProviderSideErrorDataType | DocActionDeniedDataType | DocHistoryNotFoundDataType | DocNotFoundDataType | DocUpdateBlockedDataType | ExpectToGrantDocUserRolesDataType | ExpectToRevokeDocUserRolesDataType | ExpectToUpdateDocUserRoleDataType | GraphqlBadRequestDataType | HttpRequestErrorDataType | InvalidAppConfigDataType | InvalidAppConfigInputDataType | InvalidEmailDataType | InvalidHistoryTimestampDataType | InvalidIndexerInputDataType | InvalidLicenseToActivateDataType | InvalidLicenseUpdateParamsDataType | InvalidOauthCallbackCodeDataType | InvalidOauthResponseDataType | InvalidPasswordLengthDataType | InvalidRuntimeConfigTypeDataType | InvalidSearchProviderRequestDataType | MemberNotFoundInSpaceDataType | MentionUserDocAccessDeniedDataType | MissingOauthQueryParameterDataType | NoMoreSeatDataType | NotInSpaceDataType | QueryTooLongDataType | RuntimeConfigNotFoundDataType | SameSubscriptionRecurringDataType | SpaceAccessDeniedDataType | SpaceNotFoundDataType | SpaceOwnerNotFoundDataType | SpaceShouldHaveOnlyOneOwnerDataType | SubscriptionAlreadyExistsDataType | SubscriptionNotExistsDataType | SubscriptionPlanNotFoundDataType | UnknownOauthProviderDataType | UnsupportedClientVersionDataType | UnsupportedSubscriptionPlanDataType | ValidationErrorDataType | VersionRejectedDataType | WorkspacePermissionNotFoundDataType | WrongSignInCredentialsDataType +union ErrorDataUnion = AlreadyInSpaceDataType | BlobNotFoundDataType | CopilotContextFileNotSupportedDataType | CopilotDocNotFoundDataType | CopilotFailedToAddWorkspaceFileEmbeddingDataType | CopilotFailedToGenerateEmbeddingDataType | CopilotFailedToMatchContextDataType | CopilotFailedToMatchGlobalContextDataType | CopilotFailedToModifyContextDataType | CopilotInvalidContextDataType | CopilotMessageNotFoundDataType | CopilotPromptNotFoundDataType | CopilotProviderNotSupportedDataType | CopilotProviderSideErrorDataType | DocActionDeniedDataType | DocHistoryNotFoundDataType | DocNotFoundDataType | DocUpdateBlockedDataType | ExpectToGrantDocUserRolesDataType | ExpectToRevokeDocUserRolesDataType | ExpectToUpdateDocUserRoleDataType | GraphqlBadRequestDataType | HttpRequestErrorDataType | InvalidAppConfigDataType | InvalidAppConfigInputDataType | InvalidEmailDataType | InvalidHistoryTimestampDataType | InvalidIndexerInputDataType | InvalidLicenseToActivateDataType | InvalidLicenseUpdateParamsDataType | InvalidOauthCallbackCodeDataType | InvalidOauthResponseDataType | InvalidPasswordLengthDataType | InvalidRuntimeConfigTypeDataType | InvalidSearchProviderRequestDataType | MemberNotFoundInSpaceDataType | MentionUserDocAccessDeniedDataType | MissingOauthQueryParameterDataType | NoCopilotProviderAvailableDataType | NoMoreSeatDataType | NotInSpaceDataType | QueryTooLongDataType | RuntimeConfigNotFoundDataType | SameSubscriptionRecurringDataType | SpaceAccessDeniedDataType | SpaceNotFoundDataType | SpaceOwnerNotFoundDataType | SpaceShouldHaveOnlyOneOwnerDataType | SubscriptionAlreadyExistsDataType | SubscriptionNotExistsDataType | SubscriptionPlanNotFoundDataType | UnknownOauthProviderDataType | UnsupportedClientVersionDataType | UnsupportedSubscriptionPlanDataType | ValidationErrorDataType | VersionRejectedDataType | WorkspacePermissionNotFoundDataType | WrongSignInCredentialsDataType enum ErrorNames { ACCESS_DENIED @@ -645,6 +650,7 @@ enum ErrorNames { COPILOT_EMBEDDING_UNAVAILABLE COPILOT_FAILED_TO_ADD_WORKSPACE_FILE_EMBEDDING COPILOT_FAILED_TO_CREATE_MESSAGE + COPILOT_FAILED_TO_GENERATE_EMBEDDING COPILOT_FAILED_TO_GENERATE_TEXT COPILOT_FAILED_TO_MATCH_CONTEXT COPILOT_FAILED_TO_MATCH_GLOBAL_CONTEXT @@ -1336,6 +1342,10 @@ type Mutation { verifyEmail(token: String!): Boolean! } +type NoCopilotProviderAvailableDataType { + modelId: String! +} + type NoMoreSeatDataType { spaceId: String! } diff --git a/packages/common/graphql/src/schema.ts b/packages/common/graphql/src/schema.ts index 46ae300198..ff1cdf8d36 100644 --- a/packages/common/graphql/src/schema.ts +++ b/packages/common/graphql/src/schema.ts @@ -375,6 +375,12 @@ export interface CopilotFailedToAddWorkspaceFileEmbeddingDataType { message: Scalars['String']['output']; } +export interface CopilotFailedToGenerateEmbeddingDataType { + __typename?: 'CopilotFailedToGenerateEmbeddingDataType'; + message: Scalars['String']['output']; + provider: Scalars['String']['output']; +} + export interface CopilotFailedToMatchContextDataType { __typename?: 'CopilotFailedToMatchContextDataType'; content: Scalars['String']['output']; @@ -737,6 +743,7 @@ export type ErrorDataUnion = | CopilotContextFileNotSupportedDataType | CopilotDocNotFoundDataType | CopilotFailedToAddWorkspaceFileEmbeddingDataType + | CopilotFailedToGenerateEmbeddingDataType | CopilotFailedToMatchContextDataType | CopilotFailedToMatchGlobalContextDataType | CopilotFailedToModifyContextDataType @@ -769,6 +776,7 @@ export type ErrorDataUnion = | MemberNotFoundInSpaceDataType | MentionUserDocAccessDeniedDataType | MissingOauthQueryParameterDataType + | NoCopilotProviderAvailableDataType | NoMoreSeatDataType | NotInSpaceDataType | QueryTooLongDataType @@ -816,6 +824,7 @@ export enum ErrorNames { COPILOT_EMBEDDING_UNAVAILABLE = 'COPILOT_EMBEDDING_UNAVAILABLE', COPILOT_FAILED_TO_ADD_WORKSPACE_FILE_EMBEDDING = 'COPILOT_FAILED_TO_ADD_WORKSPACE_FILE_EMBEDDING', COPILOT_FAILED_TO_CREATE_MESSAGE = 'COPILOT_FAILED_TO_CREATE_MESSAGE', + COPILOT_FAILED_TO_GENERATE_EMBEDDING = 'COPILOT_FAILED_TO_GENERATE_EMBEDDING', COPILOT_FAILED_TO_GENERATE_TEXT = 'COPILOT_FAILED_TO_GENERATE_TEXT', COPILOT_FAILED_TO_MATCH_CONTEXT = 'COPILOT_FAILED_TO_MATCH_CONTEXT', COPILOT_FAILED_TO_MATCH_GLOBAL_CONTEXT = 'COPILOT_FAILED_TO_MATCH_GLOBAL_CONTEXT', @@ -1881,6 +1890,11 @@ export interface MutationVerifyEmailArgs { token: Scalars['String']['input']; } +export interface NoCopilotProviderAvailableDataType { + __typename?: 'NoCopilotProviderAvailableDataType'; + modelId: Scalars['String']['output']; +} + export interface NoMoreSeatDataType { __typename?: 'NoMoreSeatDataType'; spaceId: Scalars['String']['output']; diff --git a/packages/frontend/i18n/src/i18n.gen.ts b/packages/frontend/i18n/src/i18n.gen.ts index 91f8040ee3..9640462b6e 100644 --- a/packages/frontend/i18n/src/i18n.gen.ts +++ b/packages/frontend/i18n/src/i18n.gen.ts @@ -8706,13 +8706,22 @@ export function useAFFiNEI18N(): { */ ["error.COPILOT_SESSION_DELETED"](): string; /** - * `No copilot provider available.` + * `No copilot provider available: {{modelId}}` */ - ["error.NO_COPILOT_PROVIDER_AVAILABLE"](): string; + ["error.NO_COPILOT_PROVIDER_AVAILABLE"](options: { + readonly modelId: string; + }): string; /** * `Failed to generate text.` */ ["error.COPILOT_FAILED_TO_GENERATE_TEXT"](): string; + /** + * `Failed to generate embedding with {{provider}}: {{message}}` + */ + ["error.COPILOT_FAILED_TO_GENERATE_EMBEDDING"](options: Readonly<{ + provider: string; + message: string; + }>): string; /** * `Failed to create chat message.` */ diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index cd9e8f5523..aa241af582 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -2164,8 +2164,9 @@ "error.COPILOT_SESSION_NOT_FOUND": "Copilot session not found.", "error.COPILOT_SESSION_INVALID_INPUT": "Copilot session input is invalid.", "error.COPILOT_SESSION_DELETED": "Copilot session has been deleted.", - "error.NO_COPILOT_PROVIDER_AVAILABLE": "No copilot provider available.", + "error.NO_COPILOT_PROVIDER_AVAILABLE": "No copilot provider available: {{modelId}}", "error.COPILOT_FAILED_TO_GENERATE_TEXT": "Failed to generate text.", + "error.COPILOT_FAILED_TO_GENERATE_EMBEDDING": "Failed to generate embedding with {{provider}}: {{message}}", "error.COPILOT_FAILED_TO_CREATE_MESSAGE": "Failed to create chat message.", "error.UNSPLASH_IS_NOT_CONFIGURED": "Unsplash is not configured.", "error.COPILOT_ACTION_TAKEN": "Action has been taken, no more messages allowed.",