feat(server): add doc keyword search tool (#12837)

close AI-185

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

- **New Features**
- Introduced a keyword-based document search tool, allowing users to
search for relevant documents within their workspace using keywords.
- Search results include document titles, summaries, and direct links,
enhancing document discovery and navigation.
- **Bug Fixes**
  - None.
- **Tests**
- Added new tests to verify document search by IDs and by keywords,
ensuring accurate and reliable search functionality.
- **Documentation**
  - None.
- **Chores**
- Updated configuration file organization for improved clarity; no
changes to functionality.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->








#### PR Dependency Tree


* **PR #12867**
  * **PR #12863**
    * **PR #12837** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
This commit is contained in:
fengmk2
2025-06-20 18:50:34 +08:00
committed by GitHub
parent 3a124b67bd
commit e978147a16
7 changed files with 148 additions and 26 deletions
@@ -10,9 +10,12 @@ import {
OnEvent,
} from '../../../base';
import { AccessController } from '../../../core/permission';
import { IndexerService } from '../../indexer';
import { CopilotContextService } from '../context';
import {
buildDocKeywordSearchGetter,
buildDocSearchGetter,
createDocKeywordSearchTool,
createDocSemanticSearchTool,
createExaCrawlTool,
createExaSearchTool,
@@ -125,6 +128,7 @@ export abstract class CopilotProvider<C = any> {
): Promise<ToolSet> {
const tools: ToolSet = {};
if (options?.tools?.length) {
this.logger.debug(`getTools: ${JSON.stringify(options.tools)}`);
for (const tool of options.tools) {
const toolDef = this.getProviderSpecificTools(tool, model);
if (toolDef) {
@@ -143,6 +147,24 @@ export abstract class CopilotProvider<C = any> {
);
break;
}
case 'docKeywordSearch': {
if (this.AFFiNEConfig.indexer.enabled) {
const ac = this.moduleRef.get(AccessController, {
strict: false,
});
const indexerService = this.moduleRef.get(IndexerService, {
strict: false,
});
const searchDocs = buildDocKeywordSearchGetter(
ac,
indexerService
);
tools.doc_keyword_search = createDocKeywordSearchTool(
searchDocs.bind(null, options)
);
}
break;
}
case 'webSearch': {
tools.web_search_exa = createExaSearchTool(this.AFFiNEConfig);
tools.web_crawl_exa = createExaCrawlTool(this.AFFiNEConfig);