chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import type { CrawlResponse, TavilyCrawlParams } from '@/tools/tavily/types'
|
||||
import { TAVILY_CRAWL_RESULT_OUTPUT_PROPERTIES } from '@/tools/tavily/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const crawlTool: ToolConfig<TavilyCrawlParams, CrawlResponse> = {
|
||||
id: 'tavily_crawl',
|
||||
name: 'Tavily Crawl',
|
||||
description:
|
||||
"Systematically crawl and extract content from websites using Tavily's crawl API. Supports depth control, path filtering, domain restrictions, and natural language instructions for targeted crawling.",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
url: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The root URL to begin the crawl',
|
||||
},
|
||||
instructions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Natural language directions for the crawler (costs 2 credits per 10 pages)',
|
||||
},
|
||||
max_depth: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'How far from base URL to explore (1-5, default: 1)',
|
||||
},
|
||||
max_breadth: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Links followed per page level (≥1, default: 20)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Total links processed before stopping (≥1, default: 50)',
|
||||
},
|
||||
select_paths: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Comma-separated regex patterns to include specific URL paths (e.g., /docs/.*)',
|
||||
},
|
||||
select_domains: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Comma-separated regex patterns to restrict crawling to certain domains',
|
||||
},
|
||||
exclude_paths: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Comma-separated regex patterns to skip specific URL paths',
|
||||
},
|
||||
exclude_domains: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Comma-separated regex patterns to block certain domains',
|
||||
},
|
||||
allow_external: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include external domain links in results (default: true)',
|
||||
},
|
||||
include_images: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Incorporate images in crawl output',
|
||||
},
|
||||
extract_depth: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Extraction depth: basic (1 credit/5 pages) or advanced (2 credits/5 pages)',
|
||||
},
|
||||
format: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Output format: markdown or text (default: markdown)',
|
||||
},
|
||||
include_favicon: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add favicon URL for each result',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Tavily API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tavily.com/crawl',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {
|
||||
url: params.url,
|
||||
}
|
||||
|
||||
if (params.instructions) body.instructions = params.instructions
|
||||
if (params.max_depth) body.max_depth = Number(params.max_depth)
|
||||
if (params.max_breadth) body.max_breadth = Number(params.max_breadth)
|
||||
if (params.limit) body.limit = Number(params.limit)
|
||||
if (params.select_paths) {
|
||||
body.select_paths = params.select_paths.split(',').map((p) => p.trim())
|
||||
}
|
||||
if (params.select_domains) {
|
||||
body.select_domains = params.select_domains.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.exclude_paths) {
|
||||
body.exclude_paths = params.exclude_paths.split(',').map((p) => p.trim())
|
||||
}
|
||||
if (params.exclude_domains) {
|
||||
body.exclude_domains = params.exclude_domains.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.allow_external !== undefined) body.allow_external = params.allow_external
|
||||
if (params.include_images !== undefined) body.include_images = params.include_images
|
||||
if (params.extract_depth) body.extract_depth = params.extract_depth
|
||||
if (params.format) body.format = params.format
|
||||
if (params.include_favicon !== undefined) body.include_favicon = params.include_favicon
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
base_url: data.base_url,
|
||||
results: data.results || [],
|
||||
response_time: data.response_time,
|
||||
...(data.request_id && { request_id: data.request_id }),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
base_url: { type: 'string', description: 'The base URL that was crawled' },
|
||||
results: {
|
||||
type: 'array',
|
||||
description: 'Array of crawled pages with extracted content',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: TAVILY_CRAWL_RESULT_OUTPUT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
response_time: { type: 'number', description: 'Time taken for the crawl request in seconds' },
|
||||
request_id: {
|
||||
type: 'string',
|
||||
description: 'Unique identifier for support reference',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import type { TavilyExtractParams, TavilyExtractResponse } from '@/tools/tavily/types'
|
||||
import {
|
||||
TAVILY_EXTRACT_RESULT_OUTPUT_PROPERTIES,
|
||||
TAVILY_FAILED_RESULT_OUTPUT_PROPERTIES,
|
||||
} from '@/tools/tavily/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const extractTool: ToolConfig<TavilyExtractParams, TavilyExtractResponse> = {
|
||||
id: 'tavily_extract',
|
||||
name: 'Tavily Extract',
|
||||
description:
|
||||
"Extract raw content from multiple web pages simultaneously using Tavily's extraction API. Supports basic and advanced extraction depths with detailed error reporting for failed URLs.",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
urls: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'URL or array of URLs to extract content from',
|
||||
},
|
||||
extract_depth: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'The depth of extraction (basic=1 credit/5 URLs, advanced=2 credits/5 URLs)',
|
||||
},
|
||||
format: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Output format: markdown or text (default: markdown)',
|
||||
},
|
||||
include_images: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Incorporate images in extraction output',
|
||||
},
|
||||
include_favicon: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add favicon URL for each result',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Tavily API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tavily.com/extract',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {
|
||||
urls: typeof params.urls === 'string' ? [params.urls] : params.urls,
|
||||
}
|
||||
|
||||
if (params.extract_depth) body.extract_depth = params.extract_depth
|
||||
if (params.format) body.format = params.format
|
||||
if (params.include_images !== undefined) body.include_images = params.include_images
|
||||
if (params.include_favicon !== undefined) body.include_favicon = params.include_favicon
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
results: data.results || [],
|
||||
...(data.failed_results && { failed_results: data.failed_results }),
|
||||
response_time: data.response_time,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
results: {
|
||||
type: 'array',
|
||||
description: 'Successfully extracted content from URLs',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: TAVILY_EXTRACT_RESULT_OUTPUT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
failed_results: {
|
||||
type: 'array',
|
||||
description: 'URLs that failed to extract content',
|
||||
optional: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: TAVILY_FAILED_RESULT_OUTPUT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
response_time: {
|
||||
type: 'number',
|
||||
description: 'Time taken for the extraction request in seconds',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { crawlTool } from '@/tools/tavily/crawl'
|
||||
import { extractTool } from '@/tools/tavily/extract'
|
||||
import { mapTool } from '@/tools/tavily/map'
|
||||
import { searchTool } from '@/tools/tavily/search'
|
||||
|
||||
export const tavilyExtractTool = extractTool
|
||||
export const tavilySearchTool = searchTool
|
||||
export const tavilyCrawlTool = crawlTool
|
||||
export const tavilyMapTool = mapTool
|
||||
@@ -0,0 +1,146 @@
|
||||
import type { MapResponse, TavilyMapParams } from '@/tools/tavily/types'
|
||||
import { TAVILY_MAP_RESULT_OUTPUT_PROPERTIES } from '@/tools/tavily/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const mapTool: ToolConfig<TavilyMapParams, MapResponse> = {
|
||||
id: 'tavily_map',
|
||||
name: 'Tavily Map',
|
||||
description:
|
||||
"Discover and visualize website structure using Tavily's map API. Maps out all accessible URLs from a base URL with depth control, path filtering, and domain restrictions.",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
url: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The root URL to begin mapping',
|
||||
},
|
||||
instructions: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Natural language guidance for mapping behavior (costs 2 credits per 10 pages)',
|
||||
},
|
||||
max_depth: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'How far from base URL to explore (1-5, default: 1)',
|
||||
},
|
||||
max_breadth: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Links to follow per level (default: 20)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Total links to process (default: 50)',
|
||||
},
|
||||
select_paths: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Comma-separated regex patterns for URL path filtering (e.g., /docs/.*)',
|
||||
},
|
||||
select_domains: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Comma-separated regex patterns to restrict mapping to specific domains',
|
||||
},
|
||||
exclude_paths: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Comma-separated regex patterns to exclude specific URL paths',
|
||||
},
|
||||
exclude_domains: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Comma-separated regex patterns to exclude domains',
|
||||
},
|
||||
allow_external: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include external domain links in results (default: true)',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Tavily API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tavily.com/map',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {
|
||||
url: params.url,
|
||||
}
|
||||
|
||||
if (params.instructions) body.instructions = params.instructions
|
||||
if (params.max_depth) body.max_depth = Number(params.max_depth)
|
||||
if (params.max_breadth) body.max_breadth = Number(params.max_breadth)
|
||||
if (params.limit) body.limit = Number(params.limit)
|
||||
if (params.select_paths) {
|
||||
body.select_paths = params.select_paths.split(',').map((p) => p.trim())
|
||||
}
|
||||
if (params.select_domains) {
|
||||
body.select_domains = params.select_domains.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.exclude_paths) {
|
||||
body.exclude_paths = params.exclude_paths.split(',').map((p) => p.trim())
|
||||
}
|
||||
if (params.exclude_domains) {
|
||||
body.exclude_domains = params.exclude_domains.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.allow_external !== undefined) body.allow_external = params.allow_external
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
base_url: data.base_url,
|
||||
results: data.results || [],
|
||||
response_time: data.response_time,
|
||||
...(data.request_id && { request_id: data.request_id }),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
base_url: { type: 'string', description: 'The base URL that was mapped' },
|
||||
results: {
|
||||
type: 'array',
|
||||
description: 'Array of discovered URLs during mapping',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: TAVILY_MAP_RESULT_OUTPUT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
response_time: { type: 'number', description: 'Time taken for the map request in seconds' },
|
||||
request_id: {
|
||||
type: 'string',
|
||||
description: 'Unique identifier for support reference',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
import type { TavilySearchParams, TavilySearchResponse } from '@/tools/tavily/types'
|
||||
import {
|
||||
TAVILY_IMAGE_OUTPUT_PROPERTIES,
|
||||
TAVILY_SEARCH_RESULT_OUTPUT_PROPERTIES,
|
||||
} from '@/tools/tavily/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const searchTool: ToolConfig<TavilySearchParams, TavilySearchResponse> = {
|
||||
id: 'tavily_search',
|
||||
name: 'Tavily Search',
|
||||
description:
|
||||
"Perform AI-powered web searches using Tavily's search API. Returns structured results with titles, URLs, snippets, and optional raw content, optimized for relevance and accuracy.",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
query: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The search query to execute (e.g., "latest AI research papers 2024")',
|
||||
},
|
||||
max_results: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of results (1-20, e.g., 5)',
|
||||
},
|
||||
topic: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Category type: general, news, or finance (e.g., "news")',
|
||||
},
|
||||
search_depth: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search scope: basic (1 credit) or advanced (2 credits) (e.g., "advanced")',
|
||||
},
|
||||
include_answer: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'LLM-generated response: true/basic for quick answer or advanced for detailed (e.g., "advanced")',
|
||||
},
|
||||
include_raw_content: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Parsed HTML content: true/markdown or text format (e.g., "markdown")',
|
||||
},
|
||||
include_images: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include image search results',
|
||||
},
|
||||
include_image_descriptions: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add descriptive text for images',
|
||||
},
|
||||
include_favicon: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include favicon URLs',
|
||||
},
|
||||
chunks_per_source: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Maximum number of relevant chunks per source (1-3, default: 3)',
|
||||
},
|
||||
time_range: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter by recency: day/d, week/w, month/m, year/y',
|
||||
},
|
||||
start_date: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Earliest publication date (YYYY-MM-DD format)',
|
||||
},
|
||||
end_date: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Latest publication date (YYYY-MM-DD format)',
|
||||
},
|
||||
include_domains: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated list of domains to whitelist (e.g., "github.com,stackoverflow.com")',
|
||||
},
|
||||
exclude_domains: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated list of domains to blacklist (e.g., "pinterest.com,reddit.com")',
|
||||
},
|
||||
country: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Boost results from specified country (general topic only)',
|
||||
},
|
||||
auto_parameters: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Automatic parameter configuration based on query intent',
|
||||
},
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Tavily API Key',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.tavily.com/search',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, any> = {
|
||||
query: params.query,
|
||||
}
|
||||
|
||||
// Only include optional parameters if explicitly set
|
||||
if (params.max_results) body.max_results = Number(params.max_results)
|
||||
if (params.topic) body.topic = params.topic
|
||||
if (params.search_depth) body.search_depth = params.search_depth
|
||||
|
||||
// Handle include_answer: only include if not empty and not "false"
|
||||
if (
|
||||
params.include_answer &&
|
||||
params.include_answer !== 'false' &&
|
||||
params.include_answer !== ''
|
||||
) {
|
||||
// Accept "basic" or "advanced" as strings, convert "true" to boolean
|
||||
body.include_answer = params.include_answer === 'true' ? true : params.include_answer
|
||||
}
|
||||
|
||||
// Handle include_raw_content: only include if not empty and not "false"
|
||||
if (
|
||||
params.include_raw_content &&
|
||||
params.include_raw_content !== 'false' &&
|
||||
params.include_raw_content !== ''
|
||||
) {
|
||||
// Accept "markdown" or "text" as strings, convert "true" to boolean
|
||||
body.include_raw_content =
|
||||
params.include_raw_content === 'true' ? true : params.include_raw_content
|
||||
}
|
||||
|
||||
if (params.include_images !== undefined) body.include_images = params.include_images
|
||||
if (params.include_image_descriptions !== undefined)
|
||||
body.include_image_descriptions = params.include_image_descriptions
|
||||
if (params.include_favicon !== undefined) body.include_favicon = params.include_favicon
|
||||
if (params.chunks_per_source) body.chunks_per_source = Number(params.chunks_per_source)
|
||||
if (params.time_range) body.time_range = params.time_range
|
||||
if (params.start_date) body.start_date = params.start_date
|
||||
if (params.end_date) body.end_date = params.end_date
|
||||
if (params.include_domains) {
|
||||
body.include_domains = params.include_domains.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.exclude_domains) {
|
||||
body.exclude_domains = params.exclude_domains.split(',').map((d) => d.trim())
|
||||
}
|
||||
if (params.country) body.country = params.country
|
||||
if (params.auto_parameters !== undefined) body.auto_parameters = params.auto_parameters
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
query: data.query,
|
||||
results: (data.results ?? []).map((result: any) => ({
|
||||
title: result.title,
|
||||
url: result.url,
|
||||
content: result.content,
|
||||
...(result.score !== undefined && { score: result.score }),
|
||||
...(result.raw_content && { raw_content: result.raw_content }),
|
||||
...(result.favicon && { favicon: result.favicon }),
|
||||
})),
|
||||
...(data.answer && { answer: data.answer }),
|
||||
...(data.images && { images: data.images }),
|
||||
...(data.auto_parameters && { auto_parameters: data.auto_parameters }),
|
||||
response_time: data.response_time,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
query: { type: 'string', description: 'The search query that was executed' },
|
||||
results: {
|
||||
type: 'array',
|
||||
description:
|
||||
'Ranked search results with titles, URLs, content snippets, and optional metadata',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: TAVILY_SEARCH_RESULT_OUTPUT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
answer: {
|
||||
type: 'string',
|
||||
description: 'LLM-generated answer to the query (if requested)',
|
||||
optional: true,
|
||||
},
|
||||
images: {
|
||||
type: 'array',
|
||||
description: 'Query-related images (if requested)',
|
||||
optional: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: TAVILY_IMAGE_OUTPUT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
auto_parameters: {
|
||||
type: 'object',
|
||||
description: 'Automatically selected parameters based on query intent (if enabled)',
|
||||
optional: true,
|
||||
},
|
||||
response_time: { type: 'number', description: 'Time taken for the search request in seconds' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
import type { OutputProperty, ToolResponse } from '@/tools/types'
|
||||
|
||||
/**
|
||||
* Shared output property definitions for Tavily API responses.
|
||||
* Based on Tavily API documentation: https://docs.tavily.com/documentation/api-reference
|
||||
*/
|
||||
|
||||
/**
|
||||
* Output definition for search result items
|
||||
*/
|
||||
export const TAVILY_SEARCH_RESULT_OUTPUT_PROPERTIES = {
|
||||
title: { type: 'string', description: 'Result title' },
|
||||
url: { type: 'string', description: 'Result URL' },
|
||||
content: { type: 'string', description: 'Brief description or content snippet' },
|
||||
score: { type: 'number', description: 'Relevance score', optional: true },
|
||||
raw_content: {
|
||||
type: 'string',
|
||||
description: 'Full parsed HTML content (if requested)',
|
||||
optional: true,
|
||||
},
|
||||
favicon: { type: 'string', description: 'Favicon URL for the domain', optional: true },
|
||||
} as const satisfies Record<string, OutputProperty>
|
||||
|
||||
/**
|
||||
* Complete search result output definition
|
||||
*/
|
||||
export const TAVILY_SEARCH_RESULT_OUTPUT: OutputProperty = {
|
||||
type: 'object',
|
||||
description: 'Search result item',
|
||||
properties: TAVILY_SEARCH_RESULT_OUTPUT_PROPERTIES,
|
||||
}
|
||||
|
||||
/**
|
||||
* Output definition for image items in search results
|
||||
*/
|
||||
export const TAVILY_IMAGE_OUTPUT_PROPERTIES = {
|
||||
url: { type: 'string', description: 'Image URL' },
|
||||
description: { type: 'string', description: 'Image description', optional: true },
|
||||
} as const satisfies Record<string, OutputProperty>
|
||||
|
||||
/**
|
||||
* Complete image output definition
|
||||
*/
|
||||
export const TAVILY_IMAGE_OUTPUT: OutputProperty = {
|
||||
type: 'object',
|
||||
description: 'Image result',
|
||||
properties: TAVILY_IMAGE_OUTPUT_PROPERTIES,
|
||||
}
|
||||
|
||||
/**
|
||||
* Output definition for usage statistics
|
||||
*/
|
||||
export const TAVILY_USAGE_OUTPUT_PROPERTIES = {
|
||||
credits: { type: 'number', description: 'Number of credits consumed' },
|
||||
} as const satisfies Record<string, OutputProperty>
|
||||
|
||||
/**
|
||||
* Complete usage output definition
|
||||
*/
|
||||
export const TAVILY_USAGE_OUTPUT: OutputProperty = {
|
||||
type: 'object',
|
||||
description: 'Credit usage details',
|
||||
properties: TAVILY_USAGE_OUTPUT_PROPERTIES,
|
||||
}
|
||||
|
||||
/**
|
||||
* Output definition for extract result items
|
||||
*/
|
||||
export const TAVILY_EXTRACT_RESULT_OUTPUT_PROPERTIES = {
|
||||
url: { type: 'string', description: 'The source URL' },
|
||||
raw_content: { type: 'string', description: 'Full extracted content from the page' },
|
||||
images: {
|
||||
type: 'array',
|
||||
description: 'Image URLs (when include_images is true)',
|
||||
optional: true,
|
||||
items: { type: 'string' },
|
||||
},
|
||||
favicon: { type: 'string', description: 'Favicon URL for the result', optional: true },
|
||||
} as const satisfies Record<string, OutputProperty>
|
||||
|
||||
/**
|
||||
* Complete extract result output definition
|
||||
*/
|
||||
export const TAVILY_EXTRACT_RESULT_OUTPUT: OutputProperty = {
|
||||
type: 'object',
|
||||
description: 'Extracted content from URL',
|
||||
properties: TAVILY_EXTRACT_RESULT_OUTPUT_PROPERTIES,
|
||||
}
|
||||
|
||||
/**
|
||||
* Output definition for failed extraction items
|
||||
*/
|
||||
export const TAVILY_FAILED_RESULT_OUTPUT_PROPERTIES = {
|
||||
url: { type: 'string', description: 'The URL that failed extraction' },
|
||||
error: { type: 'string', description: 'Error message describing why extraction failed' },
|
||||
} as const satisfies Record<string, OutputProperty>
|
||||
|
||||
/**
|
||||
* Complete failed result output definition
|
||||
*/
|
||||
export const TAVILY_FAILED_RESULT_OUTPUT: OutputProperty = {
|
||||
type: 'object',
|
||||
description: 'Failed extraction result',
|
||||
properties: TAVILY_FAILED_RESULT_OUTPUT_PROPERTIES,
|
||||
}
|
||||
|
||||
/**
|
||||
* Output definition for crawl result items
|
||||
*/
|
||||
export const TAVILY_CRAWL_RESULT_OUTPUT_PROPERTIES = {
|
||||
url: { type: 'string', description: 'The crawled page URL' },
|
||||
raw_content: { type: 'string', description: 'Full extracted page content' },
|
||||
favicon: { type: 'string', description: 'Favicon URL for the result', optional: true },
|
||||
} as const satisfies Record<string, OutputProperty>
|
||||
|
||||
/**
|
||||
* Complete crawl result output definition
|
||||
*/
|
||||
export const TAVILY_CRAWL_RESULT_OUTPUT: OutputProperty = {
|
||||
type: 'object',
|
||||
description: 'Crawled page result',
|
||||
properties: TAVILY_CRAWL_RESULT_OUTPUT_PROPERTIES,
|
||||
}
|
||||
|
||||
/**
|
||||
* Output definition for map result items
|
||||
*/
|
||||
export const TAVILY_MAP_RESULT_OUTPUT_PROPERTIES = {
|
||||
url: { type: 'string', description: 'Discovered URL' },
|
||||
} as const satisfies Record<string, OutputProperty>
|
||||
|
||||
/**
|
||||
* Complete map result output definition
|
||||
*/
|
||||
export const TAVILY_MAP_RESULT_OUTPUT: OutputProperty = {
|
||||
type: 'object',
|
||||
description: 'Mapped URL result',
|
||||
properties: TAVILY_MAP_RESULT_OUTPUT_PROPERTIES,
|
||||
}
|
||||
|
||||
interface TavilySearchResult {
|
||||
title: string
|
||||
url: string
|
||||
content: string
|
||||
score?: number
|
||||
raw_content?: string
|
||||
favicon?: string
|
||||
}
|
||||
|
||||
interface TavilyImageResult {
|
||||
url: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface TavilySearchResponse extends ToolResponse {
|
||||
output: {
|
||||
query: string
|
||||
results: TavilySearchResult[]
|
||||
answer?: string
|
||||
images?: Array<string | TavilyImageResult>
|
||||
auto_parameters?: Record<string, unknown>
|
||||
response_time: number
|
||||
}
|
||||
}
|
||||
|
||||
interface TavilyExtractResultItem {
|
||||
url: string
|
||||
raw_content: string
|
||||
images?: string[]
|
||||
favicon?: string
|
||||
}
|
||||
|
||||
export interface TavilyExtractResponse extends ToolResponse {
|
||||
output: {
|
||||
results: TavilyExtractResultItem[]
|
||||
failed_results?: Array<{
|
||||
url: string
|
||||
error: string
|
||||
}>
|
||||
response_time: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface TavilyExtractParams {
|
||||
urls: string | string[]
|
||||
apiKey: string
|
||||
extract_depth?: 'basic' | 'advanced'
|
||||
format?: string
|
||||
include_images?: boolean
|
||||
include_favicon?: boolean
|
||||
}
|
||||
|
||||
export interface TavilySearchParams {
|
||||
query: string
|
||||
apiKey: string
|
||||
max_results?: number
|
||||
topic?: string
|
||||
search_depth?: string
|
||||
include_answer?: string
|
||||
include_raw_content?: string
|
||||
include_images?: boolean
|
||||
include_image_descriptions?: boolean
|
||||
include_favicon?: boolean
|
||||
chunks_per_source?: number
|
||||
time_range?: string
|
||||
start_date?: string
|
||||
end_date?: string
|
||||
include_domains?: string
|
||||
exclude_domains?: string
|
||||
country?: string
|
||||
auto_parameters?: boolean
|
||||
}
|
||||
|
||||
export type TavilyResponse = TavilySearchResponse | TavilyExtractResponse
|
||||
|
||||
/**
|
||||
* Parameters for the Tavily Crawl tool.
|
||||
*/
|
||||
export interface TavilyCrawlParams {
|
||||
url: string
|
||||
apiKey: string
|
||||
instructions?: string
|
||||
max_depth?: number
|
||||
max_breadth?: number
|
||||
limit?: number
|
||||
select_paths?: string
|
||||
select_domains?: string
|
||||
exclude_paths?: string
|
||||
exclude_domains?: string
|
||||
allow_external?: boolean
|
||||
include_images?: boolean
|
||||
extract_depth?: string
|
||||
format?: string
|
||||
include_favicon?: boolean
|
||||
}
|
||||
|
||||
interface CrawlResult {
|
||||
url: string
|
||||
raw_content: string
|
||||
favicon?: string
|
||||
}
|
||||
|
||||
export interface CrawlResponse extends ToolResponse {
|
||||
output: {
|
||||
base_url: string
|
||||
results: CrawlResult[]
|
||||
response_time: number
|
||||
request_id?: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for the Tavily Map tool.
|
||||
*/
|
||||
export interface TavilyMapParams {
|
||||
url: string
|
||||
apiKey: string
|
||||
instructions?: string
|
||||
max_depth?: number
|
||||
max_breadth?: number
|
||||
limit?: number
|
||||
select_paths?: string
|
||||
select_domains?: string
|
||||
exclude_paths?: string
|
||||
exclude_domains?: string
|
||||
allow_external?: boolean
|
||||
}
|
||||
|
||||
interface MapResult {
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface MapResponse extends ToolResponse {
|
||||
output: {
|
||||
base_url: string
|
||||
results: MapResult[]
|
||||
response_time: number
|
||||
request_id?: string
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user