mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-01 22:48:16 +00:00
fix: adjust websearch tool to emphasize that it ISNT 2024, give more info as to current date
This commit is contained in:
@@ -36,109 +36,115 @@ interface McpSearchResponse {
|
||||
}
|
||||
}
|
||||
|
||||
export const WebSearchTool = Tool.define("websearch", {
|
||||
description: DESCRIPTION,
|
||||
parameters: z.object({
|
||||
query: z.string().describe("Websearch query"),
|
||||
numResults: z.number().optional().describe("Number of search results to return (default: 8)"),
|
||||
livecrawl: z
|
||||
.enum(["fallback", "preferred"])
|
||||
.optional()
|
||||
.describe(
|
||||
"Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')",
|
||||
),
|
||||
type: z
|
||||
.enum(["auto", "fast", "deep"])
|
||||
.optional()
|
||||
.describe("Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search"),
|
||||
contextMaxCharacters: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Maximum characters for context string optimized for LLMs (default: 10000)"),
|
||||
}),
|
||||
async execute(params, ctx) {
|
||||
await ctx.ask({
|
||||
permission: "websearch",
|
||||
patterns: [params.query],
|
||||
always: ["*"],
|
||||
metadata: {
|
||||
query: params.query,
|
||||
numResults: params.numResults,
|
||||
livecrawl: params.livecrawl,
|
||||
type: params.type,
|
||||
contextMaxCharacters: params.contextMaxCharacters,
|
||||
},
|
||||
})
|
||||
|
||||
const searchRequest: McpSearchRequest = {
|
||||
jsonrpc: "2.0",
|
||||
id: 1,
|
||||
method: "tools/call",
|
||||
params: {
|
||||
name: "web_search_exa",
|
||||
arguments: {
|
||||
export const WebSearchTool = Tool.define("websearch", async () => {
|
||||
return {
|
||||
get description() {
|
||||
return DESCRIPTION.replace("{{date}}", new Date().toISOString().slice(0, 10))
|
||||
},
|
||||
parameters: z.object({
|
||||
query: z.string().describe("Websearch query"),
|
||||
numResults: z.number().optional().describe("Number of search results to return (default: 8)"),
|
||||
livecrawl: z
|
||||
.enum(["fallback", "preferred"])
|
||||
.optional()
|
||||
.describe(
|
||||
"Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')",
|
||||
),
|
||||
type: z
|
||||
.enum(["auto", "fast", "deep"])
|
||||
.optional()
|
||||
.describe(
|
||||
"Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search",
|
||||
),
|
||||
contextMaxCharacters: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Maximum characters for context string optimized for LLMs (default: 10000)"),
|
||||
}),
|
||||
async execute(params, ctx) {
|
||||
await ctx.ask({
|
||||
permission: "websearch",
|
||||
patterns: [params.query],
|
||||
always: ["*"],
|
||||
metadata: {
|
||||
query: params.query,
|
||||
type: params.type || "auto",
|
||||
numResults: params.numResults || API_CONFIG.DEFAULT_NUM_RESULTS,
|
||||
livecrawl: params.livecrawl || "fallback",
|
||||
numResults: params.numResults,
|
||||
livecrawl: params.livecrawl,
|
||||
type: params.type,
|
||||
contextMaxCharacters: params.contextMaxCharacters,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout(() => controller.abort(), 25000)
|
||||
|
||||
try {
|
||||
const headers: Record<string, string> = {
|
||||
accept: "application/json, text/event-stream",
|
||||
"content-type": "application/json",
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.SEARCH}`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify(searchRequest),
|
||||
signal: AbortSignal.any([controller.signal, ctx.abort]),
|
||||
})
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Search error (${response.status}): ${errorText}`)
|
||||
const searchRequest: McpSearchRequest = {
|
||||
jsonrpc: "2.0",
|
||||
id: 1,
|
||||
method: "tools/call",
|
||||
params: {
|
||||
name: "web_search_exa",
|
||||
arguments: {
|
||||
query: params.query,
|
||||
type: params.type || "auto",
|
||||
numResults: params.numResults || API_CONFIG.DEFAULT_NUM_RESULTS,
|
||||
livecrawl: params.livecrawl || "fallback",
|
||||
contextMaxCharacters: params.contextMaxCharacters,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const responseText = await response.text()
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout(() => controller.abort(), 25000)
|
||||
|
||||
// Parse SSE response
|
||||
const lines = responseText.split("\n")
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("data: ")) {
|
||||
const data: McpSearchResponse = JSON.parse(line.substring(6))
|
||||
if (data.result && data.result.content && data.result.content.length > 0) {
|
||||
return {
|
||||
output: data.result.content[0].text,
|
||||
title: `Web search: ${params.query}`,
|
||||
metadata: {},
|
||||
try {
|
||||
const headers: Record<string, string> = {
|
||||
accept: "application/json, text/event-stream",
|
||||
"content-type": "application/json",
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.SEARCH}`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify(searchRequest),
|
||||
signal: AbortSignal.any([controller.signal, ctx.abort]),
|
||||
})
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Search error (${response.status}): ${errorText}`)
|
||||
}
|
||||
|
||||
const responseText = await response.text()
|
||||
|
||||
// Parse SSE response
|
||||
const lines = responseText.split("\n")
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("data: ")) {
|
||||
const data: McpSearchResponse = JSON.parse(line.substring(6))
|
||||
if (data.result && data.result.content && data.result.content.length > 0) {
|
||||
return {
|
||||
output: data.result.content[0].text,
|
||||
title: `Web search: ${params.query}`,
|
||||
metadata: {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
output: "No search results found. Please try a different query.",
|
||||
title: `Web search: ${params.query}`,
|
||||
metadata: {},
|
||||
}
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId)
|
||||
return {
|
||||
output: "No search results found. Please try a different query.",
|
||||
title: `Web search: ${params.query}`,
|
||||
metadata: {},
|
||||
}
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (error instanceof Error && error.name === "AbortError") {
|
||||
throw new Error("Search request timed out")
|
||||
}
|
||||
if (error instanceof Error && error.name === "AbortError") {
|
||||
throw new Error("Search request timed out")
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
},
|
||||
throw error
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,3 +9,6 @@ Usage notes:
|
||||
- Search types: 'auto' (balanced), 'fast' (quick results), 'deep' (comprehensive search)
|
||||
- Configurable context length for optimal LLM integration
|
||||
- Domain filtering and advanced search options available
|
||||
|
||||
Today's date is {{date}}. You MUST use this year when searching for recent information or current events
|
||||
- Example: If today is 2025-07-15 and the user asks for "latest AI news", search for "AI news 2025", NOT "AI news 2024"
|
||||
|
||||
Reference in New Issue
Block a user