mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-24 18:02:47 +08:00
feat(server): add hints for context files (#13444)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Attachments (files) are now included in the conversation context, allowing users to reference files during chat sessions. * Added a new "blobRead" tool enabling secure, permission-checked reading of attachment content in chat sessions. * **Improvements** * Enhanced chat session preparation to always include relevant context files. * System messages now clearly display attached files and selected content only when available, improving context clarity for users. * Updated tool-calling guidelines to ensure user workspace is searched even when attachment content suffices. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { tool } from 'ai';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { AccessController } from '../../../core/permission';
|
||||
import type { ContextSession } from '../context/session';
|
||||
import type { CopilotChatOptions } from '../providers';
|
||||
import { toolError } from './error';
|
||||
|
||||
const logger = new Logger('ContextBlobReadTool');
|
||||
|
||||
export const buildBlobContentGetter = (
|
||||
ac: AccessController,
|
||||
context: ContextSession | null
|
||||
) => {
|
||||
const getBlobContent = async (
|
||||
options: CopilotChatOptions,
|
||||
blobId?: string,
|
||||
chunk?: number
|
||||
) => {
|
||||
if (!options?.user || !options?.workspace || !blobId || !context) {
|
||||
return;
|
||||
}
|
||||
const canAccess = await ac
|
||||
.user(options.user)
|
||||
.workspace(options.workspace)
|
||||
.allowLocal()
|
||||
.can('Workspace.Read');
|
||||
if (!canAccess || context.workspaceId !== options.workspace) {
|
||||
logger.warn(
|
||||
`User ${options.user} does not have access workspace ${options.workspace}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const content = await context?.getFileContent(blobId, chunk);
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
return { blobId, chunk, content };
|
||||
};
|
||||
return getBlobContent;
|
||||
};
|
||||
|
||||
export const createBlobReadTool = (
|
||||
getBlobContent: (
|
||||
targetId?: string,
|
||||
chunk?: number
|
||||
) => Promise<object | undefined>
|
||||
) => {
|
||||
return tool({
|
||||
description:
|
||||
'Return the content and basic metadata of a single attachment identified by blobId; more inclined to use search tools rather than this tool.',
|
||||
parameters: z.object({
|
||||
blob_id: z.string().describe('The target blob in context to read'),
|
||||
chunk: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe(
|
||||
'The chunk number to read, if not provided, read the whole content, start from 0'
|
||||
),
|
||||
}),
|
||||
execute: async ({ blob_id, chunk }) => {
|
||||
try {
|
||||
const blob = await getBlobContent(blob_id, chunk);
|
||||
if (!blob) {
|
||||
return;
|
||||
}
|
||||
return { ...blob };
|
||||
} catch (err: any) {
|
||||
logger.error(`Failed to read the blob ${blob_id} in context`, err);
|
||||
return toolError('Blob Read Failed', err.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user