dadJoke.ts
import { z } from 'zod'
import type { ToolFn } from '../../types'
import fetch from 'node-fetch'
export const dadJokeToolDefinition = {
name: 'dad_joke',
parameters: z.object({}),
}
type Args = z.infer<typeof dadJokeToolDefinition.parameters>
export const dadJoke: ToolFn<Args, string> = async ({ toolArgs }) => {
const res = await fetch('<https://icanhazdadjoke.com/>', {
headers: {
Accept: 'application/json',
},
})
return (await res.json()).joke
}
generateImage.ts
import type { ToolFn } from '../../types'
import { openai } from '../ai'
import { z } from 'zod'
export const generateImageToolDefinition = {
name: 'generate_image',
parameters: z
.object({
prompt: z
.string()
.describe(
'The prompt to use to generate the image with a diffusion model image generator like Dall-E'
),
})
.describe('Generates an image and returns the url of the image.'),
}
type Args = z.infer<typeof generateImageToolDefinition.parameters>
export const generateImage: ToolFn<Args, string> = async ({
toolArgs,
userMessage,
}) => {
const response = await openai.images.generate({
model: 'dall-e-3',
prompt: toolArgs.prompt,
n: 1,
size: '1024x1024',
})
const imageUrl = response.data[0].url!
return imageUrl
}
reddit.ts
import { z } from 'zod'
import type { ToolFn } from '../../types'
import fetch from 'node-fetch'
export const redditToolDefinition = {
name: 'reddit',
parameters: z
.object({})
.describe(
'Use this tool to get the latest posts from Reddit. It will return a JSON object with the title, link, subreddit, author, and upvotes of each post.'
),
}
type Args = z.infer<typeof redditToolDefinition.parameters>
export const reddit: ToolFn<Args, string> = async ({
toolArgs,
userMessage,
}) => {
const { data } = await fetch('<https://www.reddit.com/r/aww/.json>').then((res) =>
res.json()
)
const relevantInfo = data.children.map((child: any) => ({
title: child.data.title,
link: child.data.url,
subreddit: child.data.subreddit_name_prefixed,
author: child.data.author,
upvotes: child.data.ups,
}))
return JSON.stringify(relevantInfo, null, 2)
}
toolRunner.ts
import type OpenAI from 'openai'
import { generateImage } from './tools/generateImage'
import { reddit } from './tools/reddit'
import { dadJoke } from './tools/dadJoke'
export const runTool = async (
toolCall: OpenAI.Chat.Completions.ChatCompletionMessageToolCall,
userMessage: string
) => {
const input = {
userMessage,
toolArgs: JSON.parse(toolCall.function.arguments),
}
switch (toolCall.function.name) {
case 'generate_image':
const image = await generateImage(input)
return image
case 'dad_joke':
return dadJoke(input)
case 'reddit':
return reddit(input)
default:
throw new Error(`Unknown tool: ${toolCall.function.name}`)
}
}
/tools/index.ts
import { generateImageToolDefinition } from './generateImage'
import { redditToolDefinition } from './reddit'
import { dadJokeToolDefinition } from './dadJoke'
export const tools = [
generateImageToolDefinition,
redditToolDefinition,
dadJokeToolDefinition,
]
index.ts
import 'dotenv/config'
import { runAgent } from './src/agent'
import { tools } from './src/tools'
const userMessage = process.argv[2]
if (!userMessage) {
console.error('Please provide a message')
process.exit(1)
}
const messages = await runAgent({
userMessage,
tools,
})