6bf8bebf51
CI / Test and Build (push) Failing after 1s
CI / Migrate Dev DB (push) Has been skipped
CI / Migrate DB (push) Has been skipped
CodeQL / Analyze actions (push) Has been cancelled
CodeQL / Analyze javascript-typescript (push) Has been cancelled
CI / Detect Version (push) Has been cancelled
CI / Detect Desktop Changes (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/cron.Dockerfile, ubuntu-latest, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build AMD64 (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/cron.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/db.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/pii.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/realtime.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-8vcpu-ubuntu-2404-arm, ./docker/app.Dockerfile, linux-arm64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
Helm Chart / Lint, test, and validate chart (push) Has been cancelled
Helm Chart / Chart version bumped (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Build Dev ECR (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core) (push) Has been cancelled
CI / Promote Images (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/cron) (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 / Build Dev ECR (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Check Desktop Signing Secrets (push) Has been cancelled
CI / Desktop Release (push) Has been cancelled
CI / Create Desktop Prerelease (push) Has been cancelled
CI / Desktop Prerelease Build (push) Has been cancelled
CI / Publish Desktop Prerelease (push) Has been cancelled
CI / Prune Desktop Prereleases (push) Has been cancelled
Helm Chart / Install on kind and run helm test (push) Has been cancelled
164 lines
4.9 KiB
TypeScript
164 lines
4.9 KiB
TypeScript
import type { SearchParams, SearchResponse, SearchResult } from '@/tools/serper/types'
|
|
import { SERPER_SEARCH_RESULT_OUTPUT_PROPERTIES } from '@/tools/serper/types'
|
|
import type { ToolConfig } from '@/tools/types'
|
|
|
|
export const searchTool: ToolConfig<SearchParams, SearchResponse> = {
|
|
id: 'serper_search',
|
|
name: 'Web Search',
|
|
description:
|
|
'A powerful web search tool that provides access to Google search results through Serper.dev API. Supports different types of searches including regular web search, news, places, images, videos, and shopping. Returns comprehensive results including organic results, knowledge graph, answer box, people also ask, related searches, and top stories.',
|
|
version: '1.0.0',
|
|
|
|
params: {
|
|
query: {
|
|
type: 'string',
|
|
required: true,
|
|
visibility: 'user-or-llm',
|
|
description: 'The search query (e.g., "latest AI news", "best restaurants in NYC")',
|
|
},
|
|
num: {
|
|
type: 'number',
|
|
required: false,
|
|
visibility: 'user-or-llm',
|
|
description: 'Number of results to return (e.g., 10, 20, 50)',
|
|
},
|
|
gl: {
|
|
type: 'string',
|
|
required: false,
|
|
visibility: 'user-or-llm',
|
|
description: 'Country code for search results (e.g., "us", "uk", "de", "fr")',
|
|
},
|
|
hl: {
|
|
type: 'string',
|
|
required: false,
|
|
visibility: 'user-or-llm',
|
|
description: 'Language code for search results (e.g., "en", "es", "de", "fr")',
|
|
},
|
|
type: {
|
|
type: 'string',
|
|
required: false,
|
|
visibility: 'user-or-llm',
|
|
description:
|
|
'Type of search to perform (e.g., "search", "news", "images", "videos", "places", "shopping")',
|
|
},
|
|
apiKey: {
|
|
type: 'string',
|
|
required: true,
|
|
visibility: 'user-only',
|
|
description: 'Serper API Key',
|
|
},
|
|
},
|
|
|
|
hosting: {
|
|
envKeyPrefix: 'SERPER_API_KEY',
|
|
apiKeyParam: 'apiKey',
|
|
byokProviderId: 'serper',
|
|
pricing: {
|
|
type: 'custom',
|
|
getCost: (params, output) => {
|
|
if (!Array.isArray(output.searchResults)) {
|
|
throw new Error('Serper response missing searchResults, cannot determine cost')
|
|
}
|
|
const num = Number(params.num) || 10
|
|
const credits = num > 10 ? 2 : 1
|
|
const cost = credits * 0.001
|
|
return { cost, metadata: { num, credits } }
|
|
},
|
|
},
|
|
rateLimit: {
|
|
mode: 'per_request',
|
|
requestsPerMinute: 100,
|
|
},
|
|
},
|
|
|
|
request: {
|
|
url: (params) => `https://google.serper.dev/${params.type || 'search'}`,
|
|
method: 'POST',
|
|
headers: (params) => ({
|
|
'X-API-KEY': params.apiKey,
|
|
'Content-Type': 'application/json',
|
|
}),
|
|
body: (params) => {
|
|
const body: Record<string, any> = {
|
|
q: params.query,
|
|
}
|
|
|
|
// Only include optional parameters if they are explicitly set
|
|
if (params.num) body.num = Number(params.num)
|
|
if (params.gl) body.gl = params.gl
|
|
if (params.hl) body.hl = params.hl
|
|
|
|
return body
|
|
},
|
|
},
|
|
|
|
transformResponse: async (response: Response) => {
|
|
const data = await response.json()
|
|
|
|
const searchType = response.url.split('/').pop() || 'search'
|
|
let searchResults: SearchResult[] = []
|
|
|
|
if (searchType === 'news') {
|
|
searchResults =
|
|
data.news?.map((item: any, index: number) => ({
|
|
title: item.title,
|
|
link: item.link,
|
|
snippet: item.snippet,
|
|
position: index + 1,
|
|
date: item.date,
|
|
imageUrl: item.imageUrl,
|
|
})) || []
|
|
} else if (searchType === 'places') {
|
|
searchResults =
|
|
data.places?.map((item: any, index: number) => ({
|
|
title: item.title,
|
|
link: item.link,
|
|
snippet: item.snippet,
|
|
position: index + 1,
|
|
rating: item.rating,
|
|
reviews: item.reviews,
|
|
address: item.address,
|
|
})) || []
|
|
} else if (searchType === 'images') {
|
|
searchResults =
|
|
data.images?.map((item: any, index: number) => ({
|
|
title: item.title,
|
|
link: item.link,
|
|
snippet: item.snippet,
|
|
position: index + 1,
|
|
imageUrl: item.imageUrl,
|
|
})) || []
|
|
} else {
|
|
searchResults =
|
|
data.organic?.map((item: any, index: number) => ({
|
|
title: item.title,
|
|
link: item.link,
|
|
snippet: item.snippet,
|
|
position: index + 1,
|
|
// Google reports a date on many organic results, and the output schema has always declared
|
|
// it optional — dropping it here was silently discarding it for web searches alone.
|
|
date: item.date,
|
|
})) || []
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
output: {
|
|
searchResults,
|
|
},
|
|
}
|
|
},
|
|
|
|
outputs: {
|
|
searchResults: {
|
|
type: 'array',
|
|
description:
|
|
'Search results with titles, links, snippets, and type-specific metadata (date for news, rating for places, imageUrl for images)',
|
|
items: {
|
|
type: 'object',
|
|
properties: SERPER_SEARCH_RESULT_OUTPUT_PROPERTIES,
|
|
},
|
|
},
|
|
},
|
|
}
|