mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat: added exa ai blocks/tools
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
import { ExaAIIcon } from '@/components/icons'
|
||||
import {
|
||||
ExaAnswerResponse,
|
||||
ExaFindSimilarLinksResponse,
|
||||
ExaGetContentsResponse,
|
||||
ExaSearchResponse,
|
||||
} from '@/tools/exa/types'
|
||||
import { BlockConfig } from '../types'
|
||||
|
||||
type ExaResponse =
|
||||
| ExaSearchResponse
|
||||
| ExaGetContentsResponse
|
||||
| ExaFindSimilarLinksResponse
|
||||
| ExaAnswerResponse
|
||||
|
||||
export const ExaBlock: BlockConfig<ExaResponse> = {
|
||||
type: 'exa',
|
||||
name: 'Exa',
|
||||
description: 'Search with Exa AI',
|
||||
category: 'tools',
|
||||
bgColor: '#1F41ED',
|
||||
icon: ExaAIIcon,
|
||||
subBlocks: [
|
||||
// Operation selector
|
||||
{
|
||||
id: 'operation',
|
||||
title: 'Operation',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: [
|
||||
{ label: 'Search', id: 'exa_search' },
|
||||
{ label: 'Get Contents', id: 'exa_get_contents' },
|
||||
{ label: 'Find Similar Links', id: 'exa_find_similar_links' },
|
||||
{ label: 'Answer', id: 'exa_answer' },
|
||||
],
|
||||
value: () => 'exa_search',
|
||||
},
|
||||
// API Key (common)
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter your Exa API key',
|
||||
password: true,
|
||||
},
|
||||
// Search operation inputs
|
||||
{
|
||||
id: 'query',
|
||||
title: 'Search Query',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter your search query...',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
},
|
||||
{
|
||||
id: 'numResults',
|
||||
title: 'Number of Results',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '10',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
},
|
||||
{
|
||||
id: 'useAutoprompt',
|
||||
title: 'Use Autoprompt',
|
||||
type: 'switch',
|
||||
layout: 'full',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
},
|
||||
{
|
||||
id: 'type',
|
||||
title: 'Search Type',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: [
|
||||
{ label: 'Auto', id: 'auto' },
|
||||
{ label: 'Neural', id: 'neural' },
|
||||
{ label: 'Keyword', id: 'keyword' },
|
||||
{ label: 'Magic', id: 'magic' },
|
||||
],
|
||||
value: () => 'auto',
|
||||
condition: { field: 'operation', value: 'exa_search' },
|
||||
},
|
||||
// Get Contents operation inputs
|
||||
{
|
||||
id: 'urls',
|
||||
title: 'URLs',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter URLs to retrieve content from (comma-separated)...',
|
||||
condition: { field: 'operation', value: 'exa_get_contents' },
|
||||
},
|
||||
{
|
||||
id: 'text',
|
||||
title: 'Include Text',
|
||||
type: 'switch',
|
||||
layout: 'full',
|
||||
condition: { field: 'operation', value: 'exa_get_contents' },
|
||||
},
|
||||
{
|
||||
id: 'summaryQuery',
|
||||
title: 'Summary Query',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Optional: Enter a query to guide the summary generation...',
|
||||
condition: { field: 'operation', value: 'exa_get_contents' },
|
||||
},
|
||||
// Find Similar Links operation inputs
|
||||
{
|
||||
id: 'url',
|
||||
title: 'URL',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter URL to find similar links for...',
|
||||
condition: { field: 'operation', value: 'exa_find_similar_links' },
|
||||
},
|
||||
{
|
||||
id: 'numResults',
|
||||
title: 'Number of Results',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: '10',
|
||||
condition: { field: 'operation', value: 'exa_find_similar_links' },
|
||||
},
|
||||
{
|
||||
id: 'text',
|
||||
title: 'Include Text',
|
||||
type: 'switch',
|
||||
layout: 'full',
|
||||
condition: { field: 'operation', value: 'exa_find_similar_links' },
|
||||
},
|
||||
// Answer operation inputs
|
||||
{
|
||||
id: 'query',
|
||||
title: 'Question',
|
||||
type: 'long-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter your question...',
|
||||
condition: { field: 'operation', value: 'exa_answer' },
|
||||
},
|
||||
{
|
||||
id: 'text',
|
||||
title: 'Include Text',
|
||||
type: 'switch',
|
||||
layout: 'full',
|
||||
condition: { field: 'operation', value: 'exa_answer' },
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: ['exa_search', 'exa_get_contents', 'exa_find_similar_links', 'exa_answer'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
// Parse comma-separated URLs for Get Contents operation
|
||||
if (params.operation === 'exa_get_contents' && params.urls) {
|
||||
params.urls = params.urls
|
||||
.split(',')
|
||||
.map((url: string) => url.trim())
|
||||
.filter((url: string) => url.length > 0)
|
||||
}
|
||||
|
||||
// Convert numResults to a number for operations that use it
|
||||
if (params.numResults) {
|
||||
params.numResults = Number(params.numResults)
|
||||
}
|
||||
|
||||
switch (params.operation) {
|
||||
case 'exa_search':
|
||||
return 'exa_search'
|
||||
case 'exa_get_contents':
|
||||
return 'exa_get_contents'
|
||||
case 'exa_find_similar_links':
|
||||
return 'exa_find_similar_links'
|
||||
case 'exa_answer':
|
||||
return 'exa_answer'
|
||||
default:
|
||||
return 'exa_search'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
operation: { type: 'string', required: true },
|
||||
apiKey: { type: 'string', required: true },
|
||||
// Search operation
|
||||
query: { type: 'string', required: false },
|
||||
numResults: { type: 'number', required: false },
|
||||
useAutoprompt: { type: 'boolean', required: false },
|
||||
type: { type: 'string', required: false },
|
||||
// Get Contents operation
|
||||
urls: { type: 'string', required: false },
|
||||
text: { type: 'boolean', required: false },
|
||||
summaryQuery: { type: 'string', required: false },
|
||||
// Find Similar Links operation
|
||||
url: { type: 'string', required: false },
|
||||
},
|
||||
outputs: {
|
||||
response: {
|
||||
type: {
|
||||
// Search output
|
||||
results: 'json',
|
||||
// Find Similar Links output
|
||||
similarLinks: 'json',
|
||||
// Answer output
|
||||
answer: 'string',
|
||||
citations: 'json',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
+17
-14
@@ -4,6 +4,7 @@ import { ApiBlock } from './blocks/api'
|
||||
import { ConditionBlock } from './blocks/condition'
|
||||
import { CrewAIVisionBlock } from './blocks/crewai'
|
||||
import { EvaluatorBlock } from './blocks/evaluator'
|
||||
import { ExaBlock } from './blocks/exa'
|
||||
import { FirecrawlBlock } from './blocks/firecrawl'
|
||||
import { FunctionBlock } from './blocks/function'
|
||||
import { GitHubBlock } from './blocks/github'
|
||||
@@ -45,31 +46,33 @@ export {
|
||||
StarterBlock,
|
||||
PineconeBlock,
|
||||
OpenAIBlock,
|
||||
ExaBlock,
|
||||
}
|
||||
|
||||
// Registry of all block configurations
|
||||
// Registry of all block configurations, alphabetically sorted
|
||||
const blocks: Record<string, BlockConfig> = {
|
||||
agent: AgentBlock,
|
||||
api: ApiBlock,
|
||||
starter: StarterBlock,
|
||||
condition: ConditionBlock,
|
||||
function: FunctionBlock,
|
||||
router: RouterBlock,
|
||||
evaluator: EvaluatorBlock,
|
||||
crewai_vision: CrewAIVisionBlock,
|
||||
evaluator: EvaluatorBlock,
|
||||
exa: ExaBlock,
|
||||
firecrawl: FirecrawlBlock,
|
||||
jina: JinaBlock,
|
||||
translate: TranslateBlock,
|
||||
slack: SlackBlock,
|
||||
function: FunctionBlock,
|
||||
github: GitHubBlock,
|
||||
serper: SerperBlock,
|
||||
tavily: TavilyBlock,
|
||||
youtube: YouTubeBlock,
|
||||
notion: NotionBlock,
|
||||
gmail: GmailBlock,
|
||||
x: XBlock,
|
||||
pinecone: PineconeBlock,
|
||||
jina: JinaBlock,
|
||||
notion: NotionBlock,
|
||||
openai: OpenAIBlock,
|
||||
pinecone: PineconeBlock,
|
||||
router: RouterBlock,
|
||||
serper: SerperBlock,
|
||||
slack: SlackBlock,
|
||||
starter: StarterBlock,
|
||||
tavily: TavilyBlock,
|
||||
translate: TranslateBlock,
|
||||
x: XBlock,
|
||||
youtube: YouTubeBlock,
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
+20
-1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,73 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { ExaAnswerParams, ExaAnswerResponse } from './types'
|
||||
|
||||
export const answerTool: ToolConfig<ExaAnswerParams, ExaAnswerResponse> = {
|
||||
id: 'exa_answer',
|
||||
name: 'Exa Answer',
|
||||
description: 'Get an AI-generated answer to a question with citations from the web using Exa AI.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
query: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The question to answer',
|
||||
},
|
||||
text: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
description: 'Whether to include the full text of the answer',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Exa AI API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.exa.ai/answer',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': params.apiKey,
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {
|
||||
query: params.query,
|
||||
}
|
||||
|
||||
// Add optional parameters if provided
|
||||
if (params.text) body.text = params.text
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || data.error || 'Failed to generate answer')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
query: data.query || '',
|
||||
answer: data.answer || '',
|
||||
citations:
|
||||
data.citations?.map((citation: any) => ({
|
||||
title: citation.title || '',
|
||||
url: citation.url,
|
||||
text: citation.text || '',
|
||||
})) || [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return error instanceof Error ? error.message : 'An error occurred while generating an answer'
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { ExaFindSimilarLinksParams, ExaFindSimilarLinksResponse } from './types'
|
||||
|
||||
export const findSimilarLinksTool: ToolConfig<
|
||||
ExaFindSimilarLinksParams,
|
||||
ExaFindSimilarLinksResponse
|
||||
> = {
|
||||
id: 'exa_find_similar_links',
|
||||
name: 'Exa Find Similar Links',
|
||||
description:
|
||||
'Find webpages similar to a given URL using Exa AI. Returns a list of similar links with titles and text snippets.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
url: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The URL to find similar links for',
|
||||
},
|
||||
numResults: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Number of similar links to return (default: 10, max: 25)',
|
||||
},
|
||||
text: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
description: 'Whether to include the full text of the similar pages',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Exa AI API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.exa.ai/findSimilar',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': params.apiKey,
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {
|
||||
url: params.url,
|
||||
}
|
||||
|
||||
// Add optional parameters if provided
|
||||
if (params.numResults) body.numResults = params.numResults
|
||||
|
||||
// Add contents.text parameter if text is true
|
||||
if (params.text) {
|
||||
body.contents = {
|
||||
text: true,
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || data.error || 'Failed to find similar links')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
similarLinks: data.results.map((result: any) => ({
|
||||
title: result.title || '',
|
||||
url: result.url,
|
||||
text: result.text || '',
|
||||
score: result.score || 0,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return error instanceof Error ? error.message : 'An error occurred while finding similar links'
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { ExaGetContentsParams, ExaGetContentsResponse } from './types'
|
||||
|
||||
export const getContentsTool: ToolConfig<ExaGetContentsParams, ExaGetContentsResponse> = {
|
||||
id: 'exa_get_contents',
|
||||
name: 'Exa Get Contents',
|
||||
description:
|
||||
'Retrieve the contents of webpages using Exa AI. Returns the title, text content, and optional summaries for each URL.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
urls: {
|
||||
type: 'string[]',
|
||||
required: true,
|
||||
description: 'Array of URLs to retrieve content from',
|
||||
},
|
||||
text: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
description:
|
||||
'If true, returns full page text with default settings. If false, disables text return.',
|
||||
},
|
||||
summaryQuery: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Query to guide the summary generation',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Exa AI API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.exa.ai/contents',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': params.apiKey,
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {
|
||||
urls: params.urls,
|
||||
}
|
||||
|
||||
// Add optional parameters if provided
|
||||
if (params.text !== undefined) {
|
||||
body.text = params.text
|
||||
}
|
||||
|
||||
// Add summary with query if provided
|
||||
if (params.summaryQuery) {
|
||||
body.summary = {
|
||||
query: params.summaryQuery,
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || data.error || 'Failed to retrieve webpage contents')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
results: data.results.map((result: any) => ({
|
||||
url: result.url,
|
||||
title: result.title || '',
|
||||
text: result.text || '',
|
||||
summary: result.summary || '',
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return error instanceof Error
|
||||
? error.message
|
||||
: 'An error occurred while retrieving webpage contents'
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { ToolConfig } from '../types'
|
||||
import { ExaSearchParams, ExaSearchResponse } from './types'
|
||||
|
||||
export const searchTool: ToolConfig<ExaSearchParams, ExaSearchResponse> = {
|
||||
id: 'exa_search',
|
||||
name: 'Exa Search',
|
||||
description:
|
||||
'Search the web using Exa AI. Returns relevant search results with titles, URLs, and text snippets.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
query: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The search query to execute',
|
||||
},
|
||||
numResults: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Number of results to return (default: 10, max: 25)',
|
||||
},
|
||||
useAutoprompt: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
description: 'Whether to use autoprompt to improve the query (default: false)',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Search type: neural, keyword, auto or magic (default: auto)',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Exa AI API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.exa.ai/search',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': params.apiKey,
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {
|
||||
query: params.query,
|
||||
}
|
||||
|
||||
// Add optional parameters if provided
|
||||
if (params.numResults) body.numResults = params.numResults
|
||||
if (params.useAutoprompt !== undefined) body.useAutoprompt = params.useAutoprompt
|
||||
if (params.type) body.type = params.type
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || data.error || 'Failed to perform Exa search')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
results: data.results.map((result: any) => ({
|
||||
title: result.title || '',
|
||||
url: result.url,
|
||||
publishedDate: result.publishedDate,
|
||||
author: result.author,
|
||||
summary: result.summary,
|
||||
favicon: result.favicon,
|
||||
image: result.image,
|
||||
text: result.text,
|
||||
score: result.score,
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error) => {
|
||||
return error instanceof Error
|
||||
? error.message
|
||||
: 'An error occurred while performing the Exa search'
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// Common types for Exa AI tools
|
||||
import { ToolResponse } from '../types'
|
||||
|
||||
// Common parameters for all Exa AI tools
|
||||
export interface ExaBaseParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
// Search tool types
|
||||
export interface ExaSearchParams extends ExaBaseParams {
|
||||
query: string
|
||||
numResults?: number
|
||||
useAutoprompt?: boolean
|
||||
type?: 'auto' | 'neural' | 'keyword' | 'magic'
|
||||
}
|
||||
|
||||
export interface ExaSearchResult {
|
||||
title: string
|
||||
url: string
|
||||
publishedDate?: string
|
||||
author?: string
|
||||
summary?: string
|
||||
favicon?: string
|
||||
image?: string
|
||||
text: string
|
||||
score: number
|
||||
}
|
||||
|
||||
export interface ExaSearchResponse extends ToolResponse {
|
||||
output: {
|
||||
results: ExaSearchResult[]
|
||||
}
|
||||
}
|
||||
|
||||
// Get Contents tool types
|
||||
export interface ExaGetContentsParams extends ExaBaseParams {
|
||||
urls: string[]
|
||||
text?: boolean
|
||||
summaryQuery?: string
|
||||
}
|
||||
|
||||
export interface ExaGetContentsResult {
|
||||
url: string
|
||||
title: string
|
||||
text: string
|
||||
summary?: string
|
||||
}
|
||||
|
||||
export interface ExaGetContentsResponse extends ToolResponse {
|
||||
output: {
|
||||
results: ExaGetContentsResult[]
|
||||
}
|
||||
}
|
||||
|
||||
// Find Similar Links tool types
|
||||
export interface ExaFindSimilarLinksParams extends ExaBaseParams {
|
||||
url: string
|
||||
numResults?: number
|
||||
text?: boolean
|
||||
}
|
||||
|
||||
export interface ExaSimilarLink {
|
||||
title: string
|
||||
url: string
|
||||
text: string
|
||||
score: number
|
||||
}
|
||||
|
||||
export interface ExaFindSimilarLinksResponse extends ToolResponse {
|
||||
output: {
|
||||
similarLinks: ExaSimilarLink[]
|
||||
}
|
||||
}
|
||||
|
||||
// Answer tool types
|
||||
export interface ExaAnswerParams extends ExaBaseParams {
|
||||
query: string
|
||||
text?: boolean
|
||||
}
|
||||
|
||||
export interface ExaAnswerResponse extends ToolResponse {
|
||||
output: {
|
||||
answer: string
|
||||
citations: {
|
||||
title: string
|
||||
url: string
|
||||
text: string
|
||||
}[]
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useCustomToolsStore } from '@/stores/custom-tools/store'
|
||||
import { useEnvironmentStore } from '@/stores/settings/environment/store'
|
||||
import { visionTool as crewAIVision } from './crewai/vision'
|
||||
import { answerTool as exaAnswer } from './exa/answer'
|
||||
import { findSimilarLinksTool as exaFindSimilarLinks } from './exa/findSimilarLinks'
|
||||
import { getContentsTool as exaGetContents } from './exa/getContents'
|
||||
import { searchTool as exaSearch } from './exa/search'
|
||||
import { scrapeTool } from './firecrawl/scrape'
|
||||
import { functionExecuteTool as functionExecute } from './function/execute'
|
||||
import { webcontainerExecuteTool as webcontainerExecute } from './function/webcontainer'
|
||||
@@ -67,6 +71,10 @@ export const tools: Record<string, ToolConfig> = {
|
||||
pinecone_upsert_text: pineconeUpsertTextTool,
|
||||
github_pr: prTool,
|
||||
github_comment: commentTool,
|
||||
exa_search: exaSearch,
|
||||
exa_get_contents: exaGetContents,
|
||||
exa_find_similar_links: exaFindSimilarLinks,
|
||||
exa_answer: exaAnswer,
|
||||
}
|
||||
|
||||
// Get a tool by its ID
|
||||
|
||||
Reference in New Issue
Block a user