kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add WeatherTool
rodzic
64afe1d441
commit
8f4fde0260
|
@ -1,3 +1,4 @@
|
||||||
export * from './calculator'
|
export * from './calculator'
|
||||||
export * from './metaphor'
|
export * from './metaphor'
|
||||||
export * from './novu'
|
export * from './novu'
|
||||||
|
export * from './weather'
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
import * as types from '@/types'
|
||||||
|
import { WeatherClient } from '@/services/weather'
|
||||||
|
import { BaseTask } from '@/task'
|
||||||
|
|
||||||
|
export const WeatherInputSchema = z.object({
|
||||||
|
query: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
'Location to get the weather for. Can be a city name like "Paris", a zipcode like "53121", an international postal code like "SW1", or a latitude and longitude like "48.8567,2.3508"'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
export type WeatherInput = z.infer<typeof WeatherInputSchema>
|
||||||
|
|
||||||
|
const LocationSchema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
region: z.string(),
|
||||||
|
country: z.string(),
|
||||||
|
lat: z.number(),
|
||||||
|
lon: z.number(),
|
||||||
|
tz_id: z.string(),
|
||||||
|
localtime_epoch: z.number(),
|
||||||
|
localtime: z.string()
|
||||||
|
})
|
||||||
|
|
||||||
|
const ConditionSchema = z.object({
|
||||||
|
text: z.string(),
|
||||||
|
icon: z.string(),
|
||||||
|
code: z.number()
|
||||||
|
})
|
||||||
|
|
||||||
|
const CurrentSchema = z.object({
|
||||||
|
last_updated_epoch: z.number(),
|
||||||
|
last_updated: z.string(),
|
||||||
|
temp_c: z.number(),
|
||||||
|
temp_f: z.number(),
|
||||||
|
is_day: z.number(),
|
||||||
|
condition: ConditionSchema,
|
||||||
|
wind_mph: z.number(),
|
||||||
|
wind_kph: z.number(),
|
||||||
|
wind_degree: z.number(),
|
||||||
|
wind_dir: z.string(),
|
||||||
|
pressure_mb: z.number(),
|
||||||
|
pressure_in: z.number(),
|
||||||
|
precip_mm: z.number(),
|
||||||
|
precip_in: z.number(),
|
||||||
|
humidity: z.number(),
|
||||||
|
cloud: z.number(),
|
||||||
|
feelslike_c: z.number(),
|
||||||
|
feelslike_f: z.number(),
|
||||||
|
vis_km: z.number(),
|
||||||
|
vis_miles: z.number(),
|
||||||
|
uv: z.number(),
|
||||||
|
gust_mph: z.number(),
|
||||||
|
gust_kph: z.number()
|
||||||
|
})
|
||||||
|
|
||||||
|
export const WeatherOutputSchema = z.object({
|
||||||
|
location: LocationSchema,
|
||||||
|
current: CurrentSchema
|
||||||
|
})
|
||||||
|
export type WeatherOutput = z.infer<typeof WeatherOutputSchema>
|
||||||
|
|
||||||
|
export class WeatherTool extends BaseTask<WeatherInput, WeatherOutput> {
|
||||||
|
client: WeatherClient
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
opts: {
|
||||||
|
weather: WeatherClient
|
||||||
|
} & types.BaseTaskOptions
|
||||||
|
) {
|
||||||
|
super(opts)
|
||||||
|
|
||||||
|
this.client = opts.weather
|
||||||
|
}
|
||||||
|
|
||||||
|
public override get inputSchema() {
|
||||||
|
return WeatherInputSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
public override get outputSchema() {
|
||||||
|
return WeatherOutputSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
public override get nameForModel(): string {
|
||||||
|
return 'getCurrentWeather'
|
||||||
|
}
|
||||||
|
|
||||||
|
public override get nameForHuman(): string {
|
||||||
|
return 'Weather'
|
||||||
|
}
|
||||||
|
|
||||||
|
public override get descForModel(): string {
|
||||||
|
return 'Useful for getting the current weather at a location'
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async _call(
|
||||||
|
ctx: types.TaskCallContext<WeatherInput>
|
||||||
|
): Promise<WeatherOutput> {
|
||||||
|
return this.client.getCurrentWeather(ctx.input!.query)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
import test from 'ava'
|
import test from 'ava'
|
||||||
|
|
||||||
import { WeatherClient } from '@/services'
|
import { WeatherClient } from '@/services/weather'
|
||||||
|
import { WeatherTool } from '@/tools/weather'
|
||||||
|
|
||||||
import { ky } from '../_utils'
|
import { createTestAgenticRuntime, ky } from '../_utils'
|
||||||
|
|
||||||
test('WeatherClient.getCurrentWeather', async (t) => {
|
test('WeatherClient.getCurrentWeather', async (t) => {
|
||||||
if (!process.env.WEATHER_API_KEY) {
|
if (!process.env.WEATHER_API_KEY) {
|
||||||
|
@ -32,3 +33,22 @@ test('WeatherClient.ipInfo', async (t) => {
|
||||||
t.truthy(res.lat)
|
t.truthy(res.lat)
|
||||||
t.truthy(res.lon)
|
t.truthy(res.lon)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('WeatherTool.call', async (t) => {
|
||||||
|
if (!process.env.WEATHER_API_KEY) {
|
||||||
|
return t.pass()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.timeout(2 * 60 * 1000)
|
||||||
|
const agentic = createTestAgenticRuntime()
|
||||||
|
const weatherClient = new WeatherClient({ ky })
|
||||||
|
const tool = new WeatherTool({ agentic, weather: weatherClient })
|
||||||
|
|
||||||
|
const result = await tool.call({ query: '11201' })
|
||||||
|
// console.log(result)
|
||||||
|
t.truthy(result.current)
|
||||||
|
t.truthy(result.location)
|
||||||
|
t.is(result.location.name, 'Brooklyn')
|
||||||
|
t.is(result.location.region, 'New York')
|
||||||
|
t.is(result.location.country, 'USA')
|
||||||
|
})
|
||||||
|
|
Ładowanie…
Reference in New Issue