feat(server): workspace doc update event from indexer (#12186)

fix AI-108
fix AI-109
fix AI-13
This commit is contained in:
darkskygit
2025-05-09 07:35:47 +00:00
parent 918b3b2dab
commit 5f5de8e89d
6 changed files with 66 additions and 8 deletions

View File

@@ -0,0 +1,11 @@
# Snapshot report for `src/__tests__/models/copilot-context.spec.ts`
The actual snapshot is saved in `copilot-context.spec.ts.snap`.
Generated by [AVA](https://avajs.dev).
## should insert embedding by doc id
> should return empty array when embedding deleted
[]

View File

@@ -116,7 +116,7 @@ test('should insert embedding by doc id', async t => {
}
{
await t.context.copilotContext.deleteEmbedding(contextId, 'file-id');
await t.context.copilotContext.deleteFileEmbedding(contextId, 'file-id');
const ret = await t.context.copilotContext.matchFileEmbedding(
Array.from({ length: 1024 }, () => 0.9),
contextId,
@@ -169,6 +169,20 @@ test('should insert embedding by doc id', async t => {
t.is(ret.length, 1);
t.is(ret[0].content, 'content');
}
{
await t.context.copilotContext.deleteWorkspaceEmbedding(
workspace.id,
docId
);
const ret = await t.context.copilotContext.matchWorkspaceEmbedding(
Array.from({ length: 1024 }, () => 0.9),
workspace.id,
1,
1
);
t.snapshot(ret, 'should return empty array when embedding deleted');
}
}
});

View File

@@ -168,6 +168,12 @@ export class CopilotContextModel extends BaseModel {
`;
}
async deleteFileEmbedding(contextId: string, fileId: string) {
await this.db.aiContextEmbedding.deleteMany({
where: { contextId, fileId },
});
}
async matchFileEmbedding(
embedding: number[],
contextId: string,
@@ -205,6 +211,12 @@ export class CopilotContextModel extends BaseModel {
`;
}
async deleteWorkspaceEmbedding(workspaceId: string, docId: string) {
await this.db.aiWorkspaceEmbedding.deleteMany({
where: { workspaceId, docId },
});
}
async matchWorkspaceEmbedding(
embedding: number[],
workspaceId: string,
@@ -222,10 +234,4 @@ export class CopilotContextModel extends BaseModel {
`;
return similarityChunks.filter(c => Number(c.distance) <= threshold);
}
async deleteEmbedding(contextId: string, fileId: string) {
await this.db.aiContextEmbedding.deleteMany({
where: { contextId, fileId },
});
}
}

View File

@@ -87,6 +87,30 @@ export class CopilotContextDocJob {
}
}
// @OnEvent('doc.indexer.updated')
async addDocEmbeddingQueueFromEvent(
// TODO(@darkskygit): replace this with real event type
doc: { workspaceId: string; docId: string } //Events['doc.indexer.updated'],
) {
if (!this.supportEmbedding) return;
await this.queue.add('copilot.embedding.docs', {
workspaceId: doc.workspaceId,
docId: doc.workspaceId,
});
}
// @OnEvent('doc.indexer.deleted')
async deleteDocEmbeddingQueueFromEvent(
// TODO(@darkskygit): replace this with real event type
doc: { workspaceId: string; docId: string } //Events['doc.indexer.deleted'],
) {
await this.models.copilotContext.deleteWorkspaceEmbedding(
doc.workspaceId,
doc.docId
);
}
async readCopilotBlob(
userId: string,
workspaceId: string,

View File

@@ -164,7 +164,10 @@ export class ContextSession implements AsyncDisposable {
}
async removeFile(fileId: string): Promise<boolean> {
await this.models.copilotContext.deleteEmbedding(this.contextId, fileId);
await this.models.copilotContext.deleteFileEmbedding(
this.contextId,
fileId
);
this.config.files = this.config.files.filter(f => f.id !== fileId);
await this.save();
return true;