feat: add SerpAPI as tool

old-agentic-v1^2
Travis Fischer 2023-06-14 22:11:30 -07:00
rodzic 487db113ab
commit 30e0d21e31
3 zmienionych plików z 104 dodań i 23 usunięć

Wyświetl plik

@ -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)
}

Wyświetl plik

@ -1,4 +1,5 @@
export * from './calculator'
export * from './metaphor'
export * from './novu'
export * from './serpapi'
export * from './weather'

Wyświetl plik

@ -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<typeof SerpAPIInputSchema>
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<typeof SerpAPIOutputSchema>
export class SerpAPITool extends BaseTask<SerpAPIInput, SerpAPIOutput> {
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<SerpAPIInput>
): Promise<SerpAPIOutput> {
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
})
}
}