2026-04-23 20:09:34 +00:00
import { Effect , Schema } from "effect"
2026-04-10 15:30:38 +00:00
import { HttpClient } from "effect/unstable/http"
2026-04-16 03:56:54 +00:00
import * as Tool from "./tool"
2026-04-10 15:30:38 +00:00
import * as McpExa from "./mcp-exa"
2025-11-10 21:39:40 +00:00
import DESCRIPTION from "./websearch.txt"
2026-04-23 20:09:34 +00:00
export const Parameters = Schema . Struct ( {
query : Schema.String.annotate ( { description : "Websearch query" } ) ,
numResults : Schema.optional ( Schema . Number ) . annotate ( {
description : "Number of search results to return (default: 8)" ,
} ) ,
livecrawl : Schema.optional ( Schema . Literals ( [ "fallback" , "preferred" ] ) ) . annotate ( {
description :
2026-04-07 23:48:12 +00:00
"Live crawl mode - 'fallback': use live crawling as backup if cached content unavailable, 'preferred': prioritize live crawling (default: 'fallback')" ,
2026-04-23 20:09:34 +00:00
} ) ,
type : Schema . optional ( Schema . Literals ( [ "auto" , "fast" , "deep" ] ) ) . annotate ( {
description : "Search type - 'auto': balanced search (default), 'fast': quick results, 'deep': comprehensive search" ,
} ) ,
contextMaxCharacters : Schema.optional ( Schema . Number ) . annotate ( {
description : "Maximum characters for context string optimized for LLMs (default: 10000)" ,
} ) ,
2026-04-07 23:48:12 +00:00
} )
2026-04-11 02:36:02 +00:00
export const WebSearchTool = Tool . define (
2026-04-10 15:30:38 +00:00
"websearch" ,
Effect . gen ( function * ( ) {
const http = yield * HttpClient . HttpClient
return {
get description() {
return DESCRIPTION . replace ( "{{year}}" , new Date ( ) . getFullYear ( ) . toString ( ) )
} ,
parameters : Parameters ,
2026-04-23 20:09:34 +00:00
execute : ( params : Schema.Schema.Type < typeof Parameters > , ctx : Tool.Context ) = >
2026-04-10 15:30:38 +00:00
Effect . gen ( function * ( ) {
2026-04-11 02:36:02 +00:00
yield * ctx . ask ( {
permission : "websearch" ,
patterns : [ params . query ] ,
always : [ "*" ] ,
metadata : {
query : params.query ,
numResults : params.numResults ,
livecrawl : params.livecrawl ,
type : params . type ,
contextMaxCharacters : params.contextMaxCharacters ,
} ,
} )
2026-04-10 15:30:38 +00:00
const result = yield * McpExa . call (
http ,
"web_search_exa" ,
McpExa . SearchArgs ,
{
query : params.query ,
type : params . type || "auto" ,
numResults : params.numResults || 8 ,
livecrawl : params.livecrawl || "fallback" ,
contextMaxCharacters : params.contextMaxCharacters ,
} ,
"25 seconds" ,
)
return {
output : result ? ? "No search results found. Please try a different query." ,
title : ` Web search: ${ params . query } ` ,
metadata : { } ,
2025-11-10 21:39:40 +00:00
}
2026-04-11 02:36:02 +00:00
} ) . pipe ( Effect . orDie ) ,
2026-04-10 15:30:38 +00:00
}
} ) ,
)