feat(server): improve context metadata & matching (#12064)

fix AI-20

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Enhanced file metadata with MIME type, blob ID, and file name across context and workspace, now visible in UI and API.
  - Added workspace-level matching for files and documents with configurable thresholds and workspace scoping in search queries.
  - Introduced a new error type and user-friendly messaging for global workspace context matching failures.

- **Bug Fixes**
  - Improved consistent handling of file MIME types and nullable context IDs for accurate metadata.

- **Documentation**
  - Updated GraphQL schema, queries, and mutations to include new metadata fields, optional parameters, and error types.

- **Style**
  - Added new localization strings for global context matching error messages.

- **Tests**
  - Extended test coverage with new and updated snapshot tests for metadata and matching logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
darkskygit
2025-05-14 06:32:29 +00:00
parent 04c5fd6dfc
commit cecf545590
36 changed files with 465 additions and 108 deletions

View File

@@ -109,10 +109,13 @@ export interface ContextMatchedDocChunk {
export interface ContextMatchedFileChunk {
__typename?: 'ContextMatchedFileChunk';
blobId: Scalars['String']['output'];
chunk: Scalars['SafeInt']['output'];
content: Scalars['String']['output'];
distance: Maybe<Scalars['Float']['output']>;
fileId: Scalars['String']['output'];
mimeType: Scalars['String']['output'];
name: Scalars['String']['output'];
}
export interface ContextWorkspaceEmbeddingStatus {
@@ -172,7 +175,7 @@ export interface CopilotContext {
docs: Array<CopilotContextDoc>;
/** list files in context */
files: Array<CopilotContextFile>;
id: Scalars['ID']['output'];
id: Maybe<Scalars['ID']['output']>;
/** match file in context */
matchFiles: Array<ContextMatchedFileChunk>;
/** match workspace docs */
@@ -185,6 +188,7 @@ export interface CopilotContext {
export interface CopilotContextMatchFilesArgs {
content: Scalars['String']['input'];
limit?: InputMaybe<Scalars['SafeInt']['input']>;
scopedThreshold?: InputMaybe<Scalars['Float']['input']>;
threshold?: InputMaybe<Scalars['Float']['input']>;
}
@@ -218,6 +222,7 @@ export interface CopilotContextFile {
createdAt: Scalars['SafeInt']['output'];
error: Maybe<Scalars['String']['output']>;
id: Scalars['ID']['output'];
mimeType: Scalars['String']['output'];
name: Scalars['String']['output'];
status: ContextEmbedStatus;
}
@@ -252,6 +257,13 @@ export interface CopilotFailedToMatchContextDataType {
message: Scalars['String']['output'];
}
export interface CopilotFailedToMatchGlobalContextDataType {
__typename?: 'CopilotFailedToMatchGlobalContextDataType';
content: Scalars['String']['output'];
message: Scalars['String']['output'];
workspaceId: Scalars['String']['output'];
}
export interface CopilotFailedToModifyContextDataType {
__typename?: 'CopilotFailedToModifyContextDataType';
contextId: Scalars['String']['output'];
@@ -383,6 +395,7 @@ export interface CopilotWorkspaceConfigIgnoredDocsArgs {
export interface CopilotWorkspaceFile {
__typename?: 'CopilotWorkspaceFile';
blobId: Scalars['String']['output'];
createdAt: Scalars['DateTime']['output'];
fileId: Scalars['String']['output'];
fileName: Scalars['String']['output'];
@@ -582,6 +595,7 @@ export type ErrorDataUnion =
| CopilotDocNotFoundDataType
| CopilotFailedToAddWorkspaceFileEmbeddingDataType
| CopilotFailedToMatchContextDataType
| CopilotFailedToMatchGlobalContextDataType
| CopilotFailedToModifyContextDataType
| CopilotInvalidContextDataType
| CopilotMessageNotFoundDataType
@@ -651,6 +665,7 @@ export enum ErrorNames {
COPILOT_FAILED_TO_CREATE_MESSAGE = 'COPILOT_FAILED_TO_CREATE_MESSAGE',
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',
COPILOT_FAILED_TO_MODIFY_CONTEXT = 'COPILOT_FAILED_TO_MODIFY_CONTEXT',
COPILOT_INVALID_CONTEXT = 'COPILOT_INVALID_CONTEXT',
COPILOT_MESSAGE_NOT_FOUND = 'COPILOT_MESSAGE_NOT_FOUND',
@@ -2876,6 +2891,7 @@ export type AddContextFileMutation = {
id: string;
createdAt: number;
name: string;
mimeType: string;
chunkSize: number;
error: string | null;
status: ContextEmbedStatus;
@@ -2917,6 +2933,7 @@ export type ListContextObjectQuery = {
__typename?: 'CopilotContextFile';
id: string;
name: string;
mimeType: string;
blobId: string;
chunkSize: number;
error: string | null;
@@ -2965,7 +2982,7 @@ export type ListContextQuery = {
__typename?: 'Copilot';
contexts: Array<{
__typename?: 'CopilotContext';
id: string;
id: string | null;
workspaceId: string;
}>;
};
@@ -2973,9 +2990,11 @@ export type ListContextQuery = {
};
export type MatchContextQueryVariables = Exact<{
contextId: Scalars['String']['input'];
contextId?: InputMaybe<Scalars['String']['input']>;
workspaceId?: InputMaybe<Scalars['String']['input']>;
content: Scalars['String']['input'];
limit?: InputMaybe<Scalars['SafeInt']['input']>;
scopedThreshold?: InputMaybe<Scalars['Float']['input']>;
threshold?: InputMaybe<Scalars['Float']['input']>;
}>;
@@ -2990,6 +3009,9 @@ export type MatchContextQuery = {
matchFiles: Array<{
__typename?: 'ContextMatchedFileChunk';
fileId: string;
blobId: string;
name: string;
mimeType: string;
chunk: number;
content: string;
distance: number | null;
@@ -3007,7 +3029,8 @@ export type MatchContextQuery = {
};
export type MatchWorkspaceDocsQueryVariables = Exact<{
contextId: Scalars['String']['input'];
contextId?: InputMaybe<Scalars['String']['input']>;
workspaceId?: InputMaybe<Scalars['String']['input']>;
content: Scalars['String']['input'];
limit?: InputMaybe<Scalars['SafeInt']['input']>;
scopedThreshold?: InputMaybe<Scalars['Float']['input']>;
@@ -3035,9 +3058,11 @@ export type MatchWorkspaceDocsQuery = {
};
export type MatchFilesQueryVariables = Exact<{
contextId: Scalars['String']['input'];
contextId?: InputMaybe<Scalars['String']['input']>;
workspaceId?: InputMaybe<Scalars['String']['input']>;
content: Scalars['String']['input'];
limit?: InputMaybe<Scalars['SafeInt']['input']>;
scopedThreshold?: InputMaybe<Scalars['Float']['input']>;
threshold?: InputMaybe<Scalars['Float']['input']>;
}>;
@@ -3052,6 +3077,7 @@ export type MatchFilesQuery = {
matchFiles: Array<{
__typename?: 'ContextMatchedFileChunk';
fileId: string;
blobId: string;
chunk: number;
content: string;
distance: number | null;
@@ -3321,6 +3347,7 @@ export type AddWorkspaceEmbeddingFilesMutation = {
__typename?: 'CopilotWorkspaceFile';
fileId: string;
fileName: string;
blobId: string;
mimeType: string;
size: number;
createdAt: string;
@@ -3352,6 +3379,7 @@ export type GetWorkspaceEmbeddingFilesQuery = {
__typename?: 'CopilotWorkspaceFile';
fileId: string;
fileName: string;
blobId: string;
mimeType: string;
size: number;
createdAt: string;