diff --git a/legacy/examples/llm-with-search.ts b/legacy/examples/llm-with-search.ts index 95097089..5a08aa9d 100644 --- a/legacy/examples/llm-with-search.ts +++ b/legacy/examples/llm-with-search.ts @@ -2,43 +2,32 @@ import { OpenAIClient } from '@agentic/openai-fetch' import 'dotenv/config' import { z } from 'zod' -import { Agentic, MetaphorSearchTool } from '@/index' +import { Agentic, SerpAPITool } from '@/index' async function main() { const openai = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! }) - const $ = new Agentic({ openai }) - const metaphorSearch = new MetaphorSearchTool({ agentic: $ }) + const agentic = new Agentic({ openai }) - const { results: searchResults } = await metaphorSearch.call({ - query: 'news from today, 2023', - numResults: 5 - }) - - console.log('searchResults', searchResults) - - const res = await $.gpt4( - `Give me a summary of today's news. Here is what I got back from a search engine: \n{{#searchResults}}{{title}}\n{{/searchResults}}` - ) + const res = await agentic + .gpt4( + `Can you summarize the top {{numResults}} results for today's news about {{topic}}?` + ) + .tools([new SerpAPITool()]) .input( z.object({ - searchResults: z.any() // TODO + topic: z.string(), + numResults: z.number().default(3) }) ) .output( z.object({ - summary: z.string(), - linkToLearnMore: z.string(), - metadata: z.object({ - title: z.string(), - keyTopics: z.string().array(), - datePublished: z.string() - }), - isWorthFollowingUp: z.boolean() + summary: z.string() }) ) .call({ - searchResults + topic: 'OpenAI' }) + console.log(res) } diff --git a/legacy/src/tools/index.ts b/legacy/src/tools/index.ts index f77d1edc..2bb73cba 100644 --- a/legacy/src/tools/index.ts +++ b/legacy/src/tools/index.ts @@ -1,4 +1,5 @@ export * from './calculator' export * from './metaphor' export * from './novu' +export * from './serpapi' export * from './weather' diff --git a/legacy/src/tools/serpapi.ts b/legacy/src/tools/serpapi.ts new file mode 100644 index 00000000..186d7436 --- /dev/null +++ b/legacy/src/tools/serpapi.ts @@ -0,0 +1,91 @@ +import { z } from 'zod' + +import * as types from '@/types' +import { SerpAPIClient } from '@/services/serpapi' +import { BaseTask } from '@/task' + +export const SerpAPIInputSchema = z.object({ + query: z.string().describe('search query'), + numResults: z.number().int().positive().default(10).optional() +}) +export type SerpAPIInput = z.infer + +export const SerpAPIOrganicSearchResult = z.object({ + position: z.number(), + title: z.string(), + link: z.string(), + displayed_link: z.string(), + snippet: z.string(), + source: z.string().optional(), + date: z.string().optional() +}) + +export const SerpAPIAnswerBox = z.object({ + type: z.string(), + title: z.string(), + link: z.string(), + displayed_link: z.string(), + snippet: z.string() +}) + +export const SerpAPIKnowledgeGraph = z.object({ + type: z.string(), + description: z.string() +}) + +export const SerpAPIOutputSchema = z.object({ + knowledgeGraph: SerpAPIKnowledgeGraph.optional(), + answerBox: SerpAPIAnswerBox.optional(), + organicResults: z.array(SerpAPIOrganicSearchResult) +}) +export type SerpAPIOutput = z.infer + +export class SerpAPITool extends BaseTask { + protected _serpapiClient: SerpAPIClient + + constructor( + opts: { + serpapi?: SerpAPIClient + } & types.BaseTaskOptions = {} + ) { + super(opts) + + this._serpapiClient = + opts.serpapi ?? new SerpAPIClient({ ky: opts.agentic?.ky }) + } + + public override get inputSchema() { + return SerpAPIInputSchema + } + + public override get outputSchema() { + return SerpAPIOutputSchema + } + + public override get nameForModel(): string { + return 'googleWebSearch' + } + + public override get nameForHuman(): string { + return 'SerpAPI' + } + + public override get descForModel(): string { + return 'Uses Google to search the web and return the most relevant results.' + } + + protected override async _call( + ctx: types.TaskCallContext + ): Promise { + const res = await this._serpapiClient.search({ + q: ctx.input!.query, + num: ctx.input!.numResults + }) + + return this.outputSchema.parse({ + knowledgeGraph: res.knowledge_graph, + answerBox: res.answer_box, + organicResults: res.organic_results + }) + } +}