mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
feat(server): add read doc tool (#12811)
close AI-186 #### PR Dependency Tree * **PR #12811** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a new tool enabling users to read document content and metadata within a workspace, with enforced access control. - **Improvements** - Updated tool interfaces and outputs to support the document reading functionality seamlessly. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { tool } from 'ai';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { DocReader } from '../../../core/doc';
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import { Models, publicUserSelect } from '../../../models';
|
||||
import type { CopilotChatOptions } from '../providers';
|
||||
import { toolError } from './error';
|
||||
|
||||
const logger = new Logger('DocReadTool');
|
||||
|
||||
export const buildDocContentGetter = (
|
||||
ac: AccessController,
|
||||
docReader: DocReader,
|
||||
models: Models
|
||||
) => {
|
||||
const getDoc = async (options: CopilotChatOptions, docId?: string) => {
|
||||
if (!options?.user || !options?.workspace || !docId) {
|
||||
return;
|
||||
}
|
||||
const canAccess = await ac
|
||||
.user(options.user)
|
||||
.workspace(options.workspace)
|
||||
.doc(docId)
|
||||
.can('Doc.Read');
|
||||
if (!canAccess) {
|
||||
logger.warn(
|
||||
`User ${options.user} does not have access to doc ${docId} in workspace ${options.workspace}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const docMeta = await models.doc.getSnapshot(options.workspace, docId, {
|
||||
select: {
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
createdByUser: {
|
||||
select: publicUserSelect,
|
||||
},
|
||||
updatedByUser: {
|
||||
select: publicUserSelect,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!docMeta) {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = await docReader.getDocMarkdown(options.workspace, docId);
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
title: content.title,
|
||||
markdown: content.markdown,
|
||||
createdAt: docMeta.createdAt,
|
||||
updatedAt: docMeta.updatedAt,
|
||||
createdByUser: docMeta.createdByUser,
|
||||
updatedByUser: docMeta.updatedByUser,
|
||||
};
|
||||
};
|
||||
return getDoc;
|
||||
};
|
||||
|
||||
export const createDocReadTool = (
|
||||
getDoc: (targetId?: string) => Promise<object | undefined>
|
||||
) => {
|
||||
return tool({
|
||||
description: 'Read the content of a doc in the current workspace',
|
||||
parameters: z.object({
|
||||
doc_id: z.string().describe('The target doc to read'),
|
||||
}),
|
||||
execute: async ({ doc_id }) => {
|
||||
try {
|
||||
const doc = await getDoc(doc_id);
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
return { ...doc };
|
||||
} catch (err: any) {
|
||||
logger.error(`Failed to read the doc ${doc_id}`, err);
|
||||
return toolError('Doc Read Failed', err.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user