@surph_ai/cli 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.js CHANGED
@@ -183,6 +183,8 @@ program.command('manifest')
183
183
  try {
184
184
  const manifestJson = require('../../../manifest.json')
185
185
  const slug = Object.keys(manifestJson)[0]
186
+ // console.log('TEST: ' + JSON.stringify(manifestJson))
187
+ // console.log('FIRST KEY: ' + slug)
186
188
  const manifest = manifestJson[slug]
187
189
  if (!manifest) {
188
190
  throw new Error('manifest.json not found')
@@ -218,6 +220,8 @@ program.command('manifest')
218
220
  })
219
221
 
220
222
  const { response } = await resp.json()
223
+ console.log('SLUG: ' + slug)
224
+ console.log('MANIFEST: ' + JSON.stringify(response))
221
225
  utils.write('manifest.json', JSON.stringify({[slug]: response}, null, 2) + '\n')
222
226
  console.log(colors.white('\n\nManifest updated. Check manifest.json for changes.\n'))
223
227
  } catch (error) {
@@ -437,6 +441,7 @@ program.command('deploy')
437
441
  }
438
442
  */
439
443
 
444
+ /*
440
445
  const { SURPH_TOOL = null } = dotenv.parse(utils.readFile('.env') ?? '')
441
446
 
442
447
  if (SURPH_TOOL === null) {
@@ -444,6 +449,16 @@ program.command('deploy')
444
449
  }
445
450
 
446
451
  await deploy.tool({ SURPH_TOOL_SLUG: SURPH_TOOL })
452
+ */
453
+
454
+ const manifest = require('../../../manifest.json')
455
+ if (!manifest) {
456
+ throw new Error('manifest.json not found')
457
+ }
458
+
459
+ const keys = Object.keys(manifest);
460
+ const SURPH_TOOL = keys[0]
461
+ await deploy.tool({ SURPH_TOOL_SLUG: SURPH_TOOL })
447
462
  } catch (error) {
448
463
  utils.printError(error)
449
464
  program.error(`Unexpected error: ${error}`, ERRORS.UNSPECIFIED)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@surph_ai/cli",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "types": "./types.d.ts",
package/scaffold/index.js CHANGED
@@ -68,6 +68,19 @@ module.exports = (name, type = 'app') => {
68
68
  shell.mkdir('-p', 'tools')
69
69
  shell.cp('-R', path.join(__dirname, `tool/tools/index.ts`), 'tools/index.ts')
70
70
 
71
+ shell.mkdir('-p', 'examples')
72
+ shell.cp('-R', path.join(__dirname, `tool/examples/README.md`), 'examples/README.md')
73
+
74
+ shell.mkdir('-p', 'examples/population')
75
+ shell.cp('-R', path.join(__dirname, `tool/examples/population/index.ts`), 'examples/population/index.ts')
76
+ shell.cp('-R', path.join(__dirname, `tool/examples/population/manifest.json`), 'examples/population/manifest.json')
77
+
78
+ shell.mkdir('-p', 'examples/weather')
79
+ shell.cp('-R', path.join(__dirname, `tool/examples/weather/index.ts`), 'examples/weather/index.ts')
80
+ shell.cp('-R', path.join(__dirname, `tool/examples/weather/manifest.json`), 'examples/weather/manifest.json')
81
+
82
+
83
+
71
84
  utils.write('manifest-example.json', JSON.stringify({
72
85
  name: 'youtube-transcript',
73
86
  slug: 'y2script',
@@ -0,0 +1 @@
1
+ README
@@ -0,0 +1,31 @@
1
+ import type { ToolHandler } from '@surph_ai/sdk';
2
+
3
+ const cities: Record<string, number> = {
4
+ 'chicago': 3000000,
5
+ 'new york': 8500000,
6
+ 'los angeles': 4000000
7
+ }
8
+
9
+ // your custom tool args goes here
10
+ type ToolArgs = {
11
+ city: string
12
+ };
13
+
14
+ const handler: ToolHandler<ToolArgs> = async ({ args, user, context }: Record<string, any>) => {
15
+ try {
16
+ // your custom tool code goes here
17
+ const { city } = args
18
+
19
+ const population: number = cities[city.toLowerCase()]
20
+ if (!population) {
21
+ throw new Error(`${city} population not found.`)
22
+ }
23
+
24
+ return population
25
+ } catch (error) {
26
+ throw error
27
+ }
28
+ };
29
+
30
+ export default handler;
31
+
@@ -0,0 +1,20 @@
1
+ {
2
+ "city-population-0d6v8oad": {
3
+ "name": "city-population",
4
+ "slug": "city-population-0d6v8oad",
5
+ "type": "custom",
6
+ "description": "Return the population of a specified city. Use this whenever the user asks for a city's population, including questions such as \"What is the population of Tokyo?\" or requests that provide a city name directly. The city input may include a country, state, or other region to disambiguate cities with the same name.",
7
+ "parameters": {
8
+ "type": "object",
9
+ "properties": {
10
+ "city": {
11
+ "type": "string",
12
+ "description": "The city whose population is requested, provided as a city name; it may optionally include a state, province, country, or other geographic qualifier, such as \"Paris, France\" or \"Springfield, Illinois\"."
13
+ }
14
+ },
15
+ "required": [
16
+ "city"
17
+ ]
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,127 @@
1
+ import type { ToolHandler } from '@surph_ai/sdk';
2
+
3
+ // Define interfaces for API responses
4
+ interface GeocodingResult {
5
+ id: number;
6
+ name: string;
7
+ latitude: number;
8
+ longitude: number;
9
+ country?: string;
10
+ country_code?: string;
11
+ }
12
+
13
+ interface GeocodingResponse {
14
+ results?: GeocodingResult[];
15
+ }
16
+
17
+ interface CurrentWeather {
18
+ time: string;
19
+ interval: number;
20
+ temperature_2m: number;
21
+ relative_humidity_2m: number;
22
+ apparent_temperature: number;
23
+ precipitation: number;
24
+ weather_code: number;
25
+ wind_speed_10m: number;
26
+ }
27
+
28
+ interface CurrentUnits {
29
+ temperature_2m: string;
30
+ relative_humidity_2m: string;
31
+ apparent_temperature: string;
32
+ precipitation: string;
33
+ wind_speed_10m: string;
34
+ }
35
+
36
+ interface WeatherResponse {
37
+ latitude: number;
38
+ longitude: number;
39
+ current?: CurrentWeather;
40
+ current_units?: CurrentUnits;
41
+ }
42
+
43
+ /**
44
+ * Fetches current weather conditions for a specified city name.
45
+ */
46
+ async function getCityWeather(cityName: string): Promise<any> {
47
+ try {
48
+ // Step 1: Get coordinates for the city using the Geocoding API
49
+ const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(cityName)}&count=1`;
50
+ const geoRes = await fetch(geoUrl);
51
+
52
+ if (!geoRes.ok) {
53
+ throw new Error(`Geocoding HTTP error! Status: ${geoRes.status}`);
54
+ }
55
+
56
+ const geoData = (await geoRes.json()) as GeocodingResponse;
57
+
58
+ if (!geoData.results || geoData.results.length === 0) {
59
+ console.log(`City "${cityName}" not found.`);
60
+ return;
61
+ }
62
+
63
+ const location = geoData.results[0];
64
+ const { latitude, longitude, name, country = '' } = location;
65
+
66
+ console.log(`Found: ${name}, ${country} (Lat: ${latitude}, Lon: ${longitude})`);
67
+
68
+ // Step 2: Get weather data using the retrieved coordinates
69
+ const weatherParams = new URLSearchParams({
70
+ latitude: latitude.toString(),
71
+ longitude: longitude.toString(),
72
+ current: 'temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,wind_speed_10m'
73
+ });
74
+
75
+ const weatherUrl = `https://api.open-meteo.com/v1/forecast?${weatherParams.toString()}`;
76
+ const weatherRes = await fetch(weatherUrl);
77
+
78
+ if (!weatherRes.ok) {
79
+ throw new Error(`Weather HTTP error! Status: ${weatherRes.status}`);
80
+ }
81
+
82
+ const weatherData = (await weatherRes.json()) as WeatherResponse;
83
+ const { current, current_units: units } = weatherData;
84
+
85
+ if (!current || !units) {
86
+ console.log('No current weather data available.');
87
+ return;
88
+ }
89
+
90
+ // Display the formatted results
91
+ console.log(`Current Temperature: ${current.temperature_2m} ${units.temperature_2m}`);
92
+ console.log(`Feels Like: ${current.apparent_temperature} ${units.apparent_temperature}`);
93
+ console.log(`Humidity: ${current.relative_humidity_2m} ${units.relative_humidity_2m}`);
94
+ console.log(`Wind Speed: ${current.wind_speed_10m} ${units.wind_speed_10m}`);
95
+
96
+ return {
97
+ temperature: `${current.temperature_2m} ${units.temperature_2m}`,
98
+ humidity: `${current.relative_humidity_2m} ${units.relative_humidity_2m}`,
99
+ wind: `${current.wind_speed_10m} ${units.wind_speed_10m}`,
100
+ }
101
+ } catch (error) {
102
+ console.error('Failed to fetch weather data:', error);
103
+ }
104
+ }
105
+
106
+
107
+ // your custom tool args goes here
108
+ type ToolArgs = {
109
+ location: string
110
+ };
111
+
112
+ const handler: ToolHandler<ToolArgs> = async ({ args, user, context }: Record<string, any>) => {
113
+ try {
114
+ const { location } = args;
115
+ if (!location) {
116
+ throw new Error(`location argument required.`)
117
+ }
118
+
119
+ const weahter = await getCityWeather(location)
120
+ return weahter
121
+ } catch (error) {
122
+ throw error
123
+ }
124
+ };
125
+
126
+ export default handler;
127
+
@@ -0,0 +1,20 @@
1
+ {
2
+ "weather-forecast-q9je7jou": {
3
+ "name": "weather-forecast",
4
+ "slug": "weather-forecast-q9je7jou",
5
+ "type": "custom",
6
+ "description": "Return current weather conditions and the forecast for a specified location. Use this whenever the user asks about the weather, temperature, conditions, rain, snow, wind, or upcoming forecast for a place, including when the location is provided as a city, region, country, postal code, address, or coordinates.",
7
+ "parameters": {
8
+ "type": "object",
9
+ "properties": {
10
+ "location": {
11
+ "type": "string",
12
+ "description": "The location to retrieve weather for. Accept a city or town, region/state and country, postal or ZIP code, street address, landmark, or latitude/longitude coordinates."
13
+ }
14
+ },
15
+ "required": [
16
+ "location"
17
+ ]
18
+ }
19
+ }
20
+ }
@@ -70,9 +70,10 @@ router.get('/', async (req, res, next) => {
70
70
 
71
71
  router.get('/test', async (req, res, next) => {
72
72
  try {
73
- if (Object.keys(req.query).length === 0) {
74
- throw new Error('No arguments provided.')
75
- }
73
+ // this should be enforced at the tool level, not here:
74
+ // if (Object.keys(req.query).length === 0) {
75
+ // throw new Error('No arguments provided.')
76
+ // }
76
77
 
77
78
  const context = req.query._context || null
78
79
  const user = req.query._user || null
@@ -94,9 +95,9 @@ router.get('/test', async (req, res, next) => {
94
95
  router.post('/custom', async (req, res, next) => {
95
96
  try {
96
97
  const { name, args, tool, user = null, context = null } = req.body;
97
- if (process.env.SURPH_TOOL !== tool.slug) {
98
- throw new Error(`Invalid tool ${tool.slug}. Check .env file.`)
99
- }
98
+ // if (process.env.SURPH_TOOL !== tool.slug) {
99
+ // throw new Error(`Invalid tool ${tool.slug}. Check .env file.`)
100
+ // }
100
101
 
101
102
  const toolRunner = await loadTool()
102
103
  const response = await handler({ args, context, user }, toolRunner)