feat(core): add exa url crawl tool (#12277)

Close [AI-126](https://linear.app/affine-design/issue/AI-126)

![截屏2025-05-14 17.01.19.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/sJGviKxfE3Ap685cl5bj/1a86ac68-f9f1-4740-8ddb-2293838682d2.png)

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

## Summary by CodeRabbit

- **New Features**
  - Introduced a new web crawling tool, allowing users to extract live content from specific web pages in addition to traditional web search.
- **Improvements**
  - Enhanced error handling for web search and web crawl operations, providing clearer failure messages.
  - Updated terminology in AI prompts and user-facing messages to reflect the new web search/crawl capabilities.
  - Improved formatting of web search and crawl results for better readability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
akumatus
2025-05-15 05:22:55 +00:00
parent fcc9b31da9
commit fabcdd3b2c
4 changed files with 80 additions and 24 deletions
@@ -14,21 +14,58 @@ export const createExaSearchTool = (config: Config) => {
.describe('The mode to search the web for.'),
}),
execute: async ({ query, mode }) => {
const { key } = config.copilot.exa;
const exa = new Exa(key);
const result = await exa.searchAndContents(query, {
numResults: 10,
summary: true,
livecrawl: mode === 'MUST' ? 'always' : undefined,
});
return result.results.map(data => ({
title: data.title,
url: data.url,
summary: data.summary,
favicon: data.favicon,
publishedDate: data.publishedDate,
author: data.author,
}));
try {
const { key } = config.copilot.exa;
const exa = new Exa(key);
const result = await exa.searchAndContents(query, {
numResults: 10,
summary: true,
livecrawl: mode === 'MUST' ? 'always' : undefined,
});
return result.results.map(data => ({
title: data.title,
url: data.url,
content: data.summary,
favicon: data.favicon,
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';
}
},
});
};