mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-13 16:16:46 +08:00
feat(core): add ai tool call error type and ui (#12941)
<img width="775" alt="截屏2025-06-26 16 17 05" src="https://github.com/user-attachments/assets/ed6bcae3-94af-4eb1-81e8-710f36ef5e46" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced a tool to crawl web pages and extract key information. * Added a visual component to display tool call failures in the AI interface. * Enhanced error reporting for document and web search tools with structured error messages. * **Improvements** * Updated error handling across AI tools and components for more consistent and informative feedback. * Default values added for tool card components to improve reliability and display. * **Bug Fixes** * Improved handling of error and empty states in web crawl and web search result displays. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -4,6 +4,7 @@ import { z } from 'zod';
|
||||
import type { AccessController } from '../../../core/permission';
|
||||
import type { IndexerService, SearchDoc } from '../../indexer';
|
||||
import type { CopilotChatOptions } from '../providers';
|
||||
import { toolError } from './error';
|
||||
|
||||
export const buildDocKeywordSearchGetter = (
|
||||
ac: AccessController,
|
||||
@@ -56,8 +57,8 @@ export const createDocKeywordSearchTool = (
|
||||
createdByUser: doc.createdByUser,
|
||||
updatedByUser: doc.updatedByUser,
|
||||
}));
|
||||
} catch {
|
||||
return 'Failed to search documents.';
|
||||
} catch (e: any) {
|
||||
return toolError('Doc Keyword Search Failed', e.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { AccessController } from '../../../core/permission';
|
||||
import type { ChunkSimilarity } from '../../../models';
|
||||
import type { CopilotContextService } from '../context';
|
||||
import type { CopilotChatOptions } from '../providers';
|
||||
import { toolError } from './error';
|
||||
|
||||
export const buildDocSearchGetter = (
|
||||
ac: AccessController,
|
||||
@@ -46,8 +47,8 @@ export const createDocSemanticSearchTool = (
|
||||
execute: async ({ query }) => {
|
||||
try {
|
||||
return await searchDocs(query);
|
||||
} catch {
|
||||
return 'Failed to search documents.';
|
||||
} catch (e: any) {
|
||||
return toolError('Doc Semantic Search Failed', e.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export interface ToolError {
|
||||
type: 'error';
|
||||
name: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export const toolError = (name: string, message: string): ToolError => ({
|
||||
type: 'error',
|
||||
name,
|
||||
message,
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import { tool } from 'ai';
|
||||
import Exa from 'exa-js';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { Config } from '../../../base';
|
||||
import { toolError } from './error';
|
||||
|
||||
export const createExaCrawlTool = (config: Config) => {
|
||||
return tool({
|
||||
description: 'Crawl the web url for information',
|
||||
parameters: z.object({
|
||||
url: z
|
||||
.string()
|
||||
.describe('The URL to crawl (including http:// or https://)'),
|
||||
}),
|
||||
execute: async ({ url }) => {
|
||||
try {
|
||||
const { key } = config.copilot.exa;
|
||||
const exa = new Exa(key);
|
||||
const result = await exa.getContents([url], {
|
||||
livecrawl: 'always',
|
||||
text: {
|
||||
maxCharacters: 100000,
|
||||
},
|
||||
});
|
||||
return result.results.map(data => ({
|
||||
title: data.title,
|
||||
url: data.url,
|
||||
content: data.text,
|
||||
favicon: data.favicon,
|
||||
publishedDate: data.publishedDate,
|
||||
author: data.author,
|
||||
}));
|
||||
} catch (e: any) {
|
||||
return toolError('Exa Crawl Failed', e.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
+3
-35
@@ -3,6 +3,7 @@ import Exa from 'exa-js';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { Config } from '../../../base';
|
||||
import { toolError } from './error';
|
||||
|
||||
export const createExaSearchTool = (config: Config) => {
|
||||
return tool({
|
||||
@@ -30,41 +31,8 @@ export const createExaSearchTool = (config: Config) => {
|
||||
publishedDate: data.publishedDate,
|
||||
author: data.author,
|
||||
}));
|
||||
} catch {
|
||||
return 'Failed to search the web';
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const createExaCrawlTool = (config: Config) => {
|
||||
return tool({
|
||||
description: 'Crawl the web url for information',
|
||||
parameters: z.object({
|
||||
url: z
|
||||
.string()
|
||||
.describe('The URL to crawl (including http:// or https://)'),
|
||||
}),
|
||||
execute: async ({ url }) => {
|
||||
try {
|
||||
const { key } = config.copilot.exa;
|
||||
const exa = new Exa(key);
|
||||
const result = await exa.getContents([url], {
|
||||
livecrawl: 'always',
|
||||
text: {
|
||||
maxCharacters: 100000,
|
||||
},
|
||||
});
|
||||
return result.results.map(data => ({
|
||||
title: data.title,
|
||||
url: data.url,
|
||||
content: data.text,
|
||||
favicon: data.favicon,
|
||||
publishedDate: data.publishedDate,
|
||||
author: data.author,
|
||||
}));
|
||||
} catch {
|
||||
return 'Failed to crawl the web url';
|
||||
} catch (e: any) {
|
||||
return toolError('Exa Search Failed', e.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from './doc-keyword-search';
|
||||
export * from './doc-semantic-search';
|
||||
export * from './web-search';
|
||||
export * from './error';
|
||||
export * from './exa-crawl';
|
||||
export * from './exa-search';
|
||||
|
||||
Reference in New Issue
Block a user