refactor(ux): consolidate BMAD skills, update design system, and clean up Prisma generated client
This commit is contained in:
65
keep-notes/lib/ai/tools/web-search.tool.ts
Normal file
65
keep-notes/lib/ai/tools/web-search.tool.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Web Search Tool
|
||||
* Uses SearXNG or Brave Search API.
|
||||
*/
|
||||
|
||||
import { tool } from 'ai'
|
||||
import { z } from 'zod'
|
||||
import { toolRegistry } from './registry'
|
||||
|
||||
async function searchSearXNG(query: string, searxngUrl: string): Promise<any> {
|
||||
const url = `${searxngUrl.replace(/\/+$/, '')}/search?q=${encodeURIComponent(query)}&format=json`
|
||||
const response = await fetch(url, { headers: { 'Accept': 'application/json' } })
|
||||
if (!response.ok) throw new Error(`SearXNG error: ${response.status}`)
|
||||
const data = await response.json()
|
||||
return (data.results || []).slice(0, 8).map((r: any) => ({
|
||||
title: r.title,
|
||||
url: r.url,
|
||||
snippet: r.content || '',
|
||||
}))
|
||||
}
|
||||
|
||||
async function searchBrave(query: string, apiKey: string): Promise<any> {
|
||||
const url = `https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=8`
|
||||
const response = await fetch(url, {
|
||||
headers: { 'Accept': 'application/json', 'X-Subscription-Token': apiKey }
|
||||
})
|
||||
if (!response.ok) throw new Error(`Brave error: ${response.status}`)
|
||||
const data = await response.json()
|
||||
return (data.web?.results || []).map((r: any) => ({
|
||||
title: r.title,
|
||||
url: r.url,
|
||||
snippet: r.description || '',
|
||||
}))
|
||||
}
|
||||
|
||||
toolRegistry.register({
|
||||
name: 'web_search',
|
||||
description: 'Search the web for information. Returns a list of results with titles, URLs and snippets.',
|
||||
isInternal: false,
|
||||
buildTool: (ctx) =>
|
||||
tool({
|
||||
description: 'Search the web for information. Returns results with titles, URLs and snippets.',
|
||||
inputSchema: z.object({
|
||||
query: z.string().describe('The search query'),
|
||||
}),
|
||||
execute: async ({ query }) => {
|
||||
try {
|
||||
const provider = ctx.config.WEB_SEARCH_PROVIDER || 'searxng'
|
||||
|
||||
if (provider === 'brave' || provider === 'both') {
|
||||
const apiKey = ctx.config.BRAVE_SEARCH_API_KEY
|
||||
if (apiKey) {
|
||||
return await searchBrave(query, apiKey)
|
||||
}
|
||||
}
|
||||
|
||||
// Default: SearXNG
|
||||
const searxngUrl = ctx.config.SEARXNG_URL || 'http://localhost:8080'
|
||||
return await searchSearXNG(query, searxngUrl)
|
||||
} catch (e: any) {
|
||||
return { error: `Web search failed: ${e.message}` }
|
||||
}
|
||||
},
|
||||
}),
|
||||
})
|
||||
Reference in New Issue
Block a user