@dainprotocol/cli 1.1.21 → 1.1.27

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.
@@ -59,18 +59,35 @@ var path_1 = __importDefault(require("path"));
59
59
  var miniflare_1 = require("miniflare");
60
60
  var build_1 = __importDefault(require("./build"));
61
61
  var fs_extra_1 = __importDefault(require("fs-extra"));
62
+ var net_1 = require("net");
62
63
  var childProcess = null;
63
64
  var watcher = null;
64
65
  var mf = null;
65
- function startProcess(command, env) {
66
+ var tunnelUrl = null;
67
+ function isPortAvailable(port) {
68
+ return new Promise(function (resolve) {
69
+ var server = (0, net_1.createServer)()
70
+ .listen(port, function () {
71
+ server.close();
72
+ resolve(true);
73
+ })
74
+ .on('error', function () {
75
+ resolve(false);
76
+ });
77
+ });
78
+ }
79
+ function startProcess(command, options) {
66
80
  var _a, _b;
67
81
  if (childProcess) {
68
82
  childProcess.kill();
69
83
  }
70
84
  var spinner = (0, ora_1.default)('Starting development server...').start();
71
- childProcess = (0, child_process_1.exec)(command, { env: __assign(__assign({}, process.env), env) });
85
+ childProcess = (0, child_process_1.exec)(command, options);
72
86
  (_a = childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', function (data) {
73
87
  spinner.succeed('Development server started.');
88
+ if (tunnelUrl) {
89
+ (0, utils_1.displayTunnelUrl)(tunnelUrl);
90
+ }
74
91
  console.log(data);
75
92
  });
76
93
  (_b = childProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', function (data) {
@@ -101,11 +118,33 @@ function cleanup() {
101
118
  }
102
119
  function dev(options) {
103
120
  return __awaiter(this, void 0, void 0, function () {
104
- var config, runtime, tsNodePath, command, envVars, proxyServer, watchPaths, dainDir, outFile, MFconfig_1, debounceTimer_1, watchDirs, error_1;
121
+ var config, portSource, port, portNumber, runtime, tsNodePath, command, envVars, proxyServer, portNumber_1, proxySetup, watchPaths, dainDir, outFile, MFconfig_1, debounceTimer_1, watchDirs, error_1;
105
122
  return __generator(this, function (_a) {
106
123
  switch (_a.label) {
107
124
  case 0:
108
125
  config = (0, utils_1.getDainConfig)(options.config);
126
+ if (process.env.PORT) {
127
+ port = process.env.PORT;
128
+ portSource = '.env file';
129
+ }
130
+ else if (options.port) {
131
+ port = options.port;
132
+ portSource = 'command line argument';
133
+ }
134
+ else {
135
+ port = '2022';
136
+ portSource = 'default value';
137
+ }
138
+ portNumber = parseInt(port);
139
+ if (isNaN(portNumber) || portNumber < 0 || portNumber > 65535) {
140
+ (0, utils_1.logError)('Invalid port number. Using default port 2022');
141
+ options.port = '2022';
142
+ portSource = 'default value (after invalid port)';
143
+ }
144
+ else {
145
+ options.port = port;
146
+ }
147
+ (0, utils_1.logInfo)("Using port ".concat(options.port, " (from ").concat(portSource, ")"));
109
148
  console.log('Config: ' + JSON.stringify(config));
110
149
  runtime = options.runtime || config.runtime || 'node';
111
150
  console.log('Runtime: ' + runtime);
@@ -121,19 +160,29 @@ function dev(options) {
121
160
  proxyServer = null;
122
161
  _a.label = 1;
123
162
  case 1:
124
- _a.trys.push([1, 8, , 9]);
125
- if (!!options.noproxy) return [3 /*break*/, 3];
163
+ _a.trys.push([1, 9, , 10]);
164
+ portNumber_1 = parseInt(options.port);
165
+ return [4 /*yield*/, isPortAvailable(portNumber_1)];
166
+ case 2:
167
+ if (!(_a.sent())) {
168
+ (0, utils_1.logError)("Port ".concat(portNumber_1, " is already in use. Please use a different port with --port option."));
169
+ process.exit(1);
170
+ }
171
+ process.env.PORT = portNumber_1.toString();
172
+ if (!!options.noproxy) return [3 /*break*/, 4];
126
173
  if (!config['api-key']) {
127
174
  throw new Error("'api-key' is required when using development proxy");
128
175
  }
129
176
  return [4 /*yield*/, (0, utils_1.setupProxy)(options.port, config['api-key'], config)];
130
- case 2:
131
- proxyServer = _a.sent();
132
- _a.label = 3;
133
177
  case 3:
134
- if (!(runtime === 'node')) return [3 /*break*/, 4];
178
+ proxySetup = _a.sent();
179
+ proxyServer = proxySetup.client;
180
+ tunnelUrl = proxySetup.tunnelUrl;
181
+ _a.label = 4;
182
+ case 4:
183
+ if (!(runtime === 'node')) return [3 /*break*/, 5];
135
184
  // Existing Node.js development process
136
- startProcess(command, envVars);
185
+ startProcess(command, { env: __assign(__assign({}, process.env), envVars) });
137
186
  watchPaths = [
138
187
  path_1.default.dirname(config['main-file']),
139
188
  config['static-dir']
@@ -146,7 +195,7 @@ function dev(options) {
146
195
  });
147
196
  watcher.on('change', function (path) {
148
197
  (0, utils_1.logInfo)("File ".concat(path, " has been changed. Restarting..."));
149
- startProcess(command, envVars);
198
+ startProcess(command, { env: __assign(__assign({}, process.env), envVars) });
150
199
  });
151
200
  (0, utils_1.logInfo)('Watching for file changes...');
152
201
  // Add signal handlers for graceful shutdown
@@ -201,14 +250,14 @@ function dev(options) {
201
250
  process.exit(1);
202
251
  }, 500);
203
252
  });
204
- return [3 /*break*/, 7];
205
- case 4:
206
- if (!(runtime === 'workers')) return [3 /*break*/, 6];
253
+ return [3 /*break*/, 8];
254
+ case 5:
255
+ if (!(runtime === 'workers')) return [3 /*break*/, 7];
207
256
  dainDir = path_1.default.join(process.cwd(), '.dain');
208
257
  outFile = path_1.default.join(dainDir, path_1.default.basename(config['main-file'], '.ts') + '.mjs');
209
258
  // Start the build process in watch mode
210
259
  return [4 /*yield*/, (0, build_1.default)({ config: options.config, runtime: 'workers', watch: true })];
211
- case 5:
260
+ case 6:
212
261
  // Start the build process in watch mode
213
262
  _a.sent();
214
263
  MFconfig_1 = {
@@ -234,10 +283,10 @@ function dev(options) {
234
283
  });
235
284
  });
236
285
  (0, utils_1.logInfo)('Watching for file changes in source and build directories...');
237
- return [3 /*break*/, 7];
238
- case 6: throw new Error("Unsupported runtime: ".concat(runtime));
239
- case 7: return [3 /*break*/, 9];
240
- case 8:
286
+ return [3 /*break*/, 8];
287
+ case 7: throw new Error("Unsupported runtime: ".concat(runtime));
288
+ case 8: return [3 /*break*/, 10];
289
+ case 9:
241
290
  error_1 = _a.sent();
242
291
  (0, utils_1.logError)("Error in dev process for ".concat(runtime, " runtime:"), error_1);
243
292
  cleanup();
@@ -246,8 +295,8 @@ function dev(options) {
246
295
  setTimeout(function () {
247
296
  process.exit(1);
248
297
  }, 500);
249
- return [3 /*break*/, 9];
250
- case 9: return [2 /*return*/];
298
+ return [3 /*break*/, 10];
299
+ case 10: return [2 /*return*/];
251
300
  }
252
301
  });
253
302
  });
package/dist/index.js CHANGED
@@ -33,7 +33,7 @@ program
33
33
  program
34
34
  .command('dev')
35
35
  .description('Run the project in development mode')
36
- .option('--port <port>', 'Set the port number', '2022')
36
+ .option('--port <port>', 'Set the port number')
37
37
  .option('--noproxy', 'Disable localtunnel proxy')
38
38
  .option('-c, --config <path>', 'Path to custom configuration file')
39
39
  .option('--runtime <runtime>', 'Specify the runtime (node or workers)')
@@ -10,8 +10,8 @@
10
10
  "deploy": "dain deploy"
11
11
  },
12
12
  "dependencies": {
13
- "@dainprotocol/service-sdk": "^1.0.93",
14
- "@dainprotocol/utils": "^0.0.48",
13
+ "@dainprotocol/service-sdk": "^1.0.95",
14
+ "@dainprotocol/utils": "^0.0.49",
15
15
  "zod": "^3.23.8",
16
16
  "hono": "^4.6.3",
17
17
  "ts-node": "^10.4.0",
@@ -19,6 +19,6 @@
19
19
  "@types/express": "^4.17.13",
20
20
  "@types/node": "^22.5.4",
21
21
  "axios": "^1.7.5",
22
- "@dainprotocol/cli": "^1.0.31"
22
+ "@dainprotocol/cli": "^1.1.26"
23
23
  }
24
24
  }
@@ -3,20 +3,22 @@
3
3
  import { z } from "zod";
4
4
  import axios from "axios";
5
5
 
6
- import {
7
- defineDAINService,
8
- ToolConfig,
9
- } from "@dainprotocol/service-sdk";
6
+ import { defineDAINService, ToolConfig } from "@dainprotocol/service-sdk";
10
7
 
11
- import { CardUIBuilder, TableUIBuilder, MapUIBuilder } from "@dainprotocol/utils";
8
+ import {
9
+ CardUIBuilder,
10
+ TableUIBuilder,
11
+ MapUIBuilder,
12
+ LayoutUIBuilder,
13
+ } from "@dainprotocol/utils";
12
14
 
13
15
  const getWeatherEmoji = (temperature: number): string => {
14
- if (temperature <= 0) return '🥶';
15
- if (temperature <= 10) return '❄️';
16
- if (temperature <= 20) return '';
17
- if (temperature <= 25) return '☀️';
18
- if (temperature <= 30) return '🌞';
19
- return '🔥';
16
+ if (temperature <= 0) return "🥶";
17
+ if (temperature <= 10) return "❄️";
18
+ if (temperature <= 20) return "";
19
+ if (temperature <= 25) return "☀️";
20
+ if (temperature <= 30) return "🌞";
21
+ return "🔥";
20
22
  };
21
23
 
22
24
  const getWeatherConfig: ToolConfig = {
@@ -37,12 +39,15 @@ const getWeatherConfig: ToolConfig = {
37
39
  })
38
40
  .describe("Current weather information"),
39
41
  pricing: { pricePerUse: 0, currency: "USD" },
40
- handler: async ({ locationName, latitude, longitude }, agentInfo, context) => {
42
+ handler: async (
43
+ { locationName, latitude, longitude },
44
+ agentInfo,
45
+ context
46
+ ) => {
41
47
  console.log(
42
48
  `User / Agent ${agentInfo.id} requested weather at ${locationName} (${latitude},${longitude})`
43
49
  );
44
50
 
45
-
46
51
  const response = await axios.get(
47
52
  `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,wind_speed_10m`
48
53
  );
@@ -59,20 +64,24 @@ const getWeatherConfig: ToolConfig = {
59
64
  ui: new CardUIBuilder()
60
65
  .setRenderMode("page")
61
66
  .title(`Current Weather in ${locationName} ${weatherEmoji}`)
62
- .addChild(new MapUIBuilder()
63
- .setInitialView(latitude, longitude, 10)
64
- .setMapStyle('mapbox://styles/mapbox/streets-v12')
65
- .addMarkers([
66
- {
67
- latitude,
68
- longitude,
69
- title: locationName,
70
- description: `Temperature: ${temperature_2m}°C\nWind: ${wind_speed_10m} km/h`,
71
- text: `${locationName} ${weatherEmoji}`,
72
- }
73
- ])
74
- .build())
75
- .content(`Temperature: ${temperature_2m}°C\nWind Speed: ${wind_speed_10m} km/h`)
67
+ .addChild(
68
+ new MapUIBuilder()
69
+ .setInitialView(latitude, longitude, 10)
70
+ .setMapStyle("mapbox://styles/mapbox/streets-v12")
71
+ .addMarkers([
72
+ {
73
+ latitude,
74
+ longitude,
75
+ title: locationName,
76
+ description: `Temperature: ${temperature_2m}°C\nWind: ${wind_speed_10m} km/h`,
77
+ text: `${locationName} ${weatherEmoji}`,
78
+ },
79
+ ])
80
+ .build()
81
+ )
82
+ .content(
83
+ `Temperature: ${temperature_2m}°C\nWind Speed: ${wind_speed_10m} km/h`
84
+ )
76
85
  .build(),
77
86
  };
78
87
  },
@@ -102,12 +111,15 @@ const getWeatherForecastConfig: ToolConfig = {
102
111
  })
103
112
  .describe("Hourly weather forecast"),
104
113
  pricing: { pricePerUse: 0, currency: "USD" },
105
- handler: async ({ locationName, latitude, longitude }, agentInfo, context) => {
114
+ handler: async (
115
+ { locationName, latitude, longitude },
116
+ agentInfo,
117
+ context
118
+ ) => {
106
119
  console.log(
107
120
  `User / Agent ${agentInfo.id} requested forecast at ${locationName} (${latitude},${longitude})`
108
121
  );
109
122
 
110
-
111
123
  const response = await axios.get(
112
124
  `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m`
113
125
  );
@@ -131,36 +143,46 @@ const getWeatherForecastConfig: ToolConfig = {
131
143
  windSpeeds: limitedWind,
132
144
  humidity: limitedHumidity,
133
145
  },
134
- ui: new CardUIBuilder()
146
+ ui: new LayoutUIBuilder()
135
147
  .setRenderMode("page")
136
- .title(`Weather Forecast for ${locationName} ${weatherEmoji}`)
137
- .addChild(new MapUIBuilder()
138
- .setInitialView(latitude, longitude, 10)
139
- .setMapStyle('mapbox://styles/mapbox/streets-v12')
140
- .addMarkers([
141
- {
142
- latitude,
143
- longitude,
144
- title: locationName,
145
- description: `Temperature: ${limitedTemp[0]}°C\nWind: ${limitedWind[0]} km/h`,
146
- text: `${locationName} ${weatherEmoji}`,
147
- }
148
- ])
149
- .build())
150
- .addChild(new TableUIBuilder()
151
- .addColumns([
152
- { key: 'time', header: 'Time', type: 'string' },
153
- { key: 'temperature', header: 'Temperature (°C)', type: 'number' },
154
- { key: 'windSpeed', header: 'Wind Speed (km/h)', type: 'number' },
155
- { key: 'humidity', header: 'Humidity (%)', type: 'number' },
156
- ])
157
- .rows(limitedTime.map((t: string, i: number) => ({
158
- time: new Date(t).toLocaleString(),
159
- temperature: limitedTemp[i],
160
- windSpeed: limitedWind[i],
161
- humidity: limitedHumidity[i],
162
- })))
163
- .build())
148
+ .setLayoutType("column")
149
+ .addChild(
150
+ new MapUIBuilder()
151
+ .setInitialView(latitude, longitude, 10)
152
+ .setMapStyle("mapbox://styles/mapbox/streets-v12")
153
+ .addMarkers([
154
+ {
155
+ latitude,
156
+ longitude,
157
+ title: locationName,
158
+ description: `Temperature: ${limitedTemp[0]}°C\nWind: ${limitedWind[0]} km/h`,
159
+ text: `${locationName} ${weatherEmoji}`,
160
+ },
161
+ ])
162
+ .build()
163
+ )
164
+ .addChild(
165
+ new TableUIBuilder()
166
+ .addColumns([
167
+ { key: "time", header: "Time", type: "string" },
168
+ {
169
+ key: "temperature",
170
+ header: "Temperature (°C)",
171
+ type: "number",
172
+ },
173
+ { key: "windSpeed", header: "Wind Speed (km/h)", type: "number" },
174
+ { key: "humidity", header: "Humidity (%)", type: "number" },
175
+ ])
176
+ .rows(
177
+ limitedTime.map((t: string, i: number) => ({
178
+ time: new Date(t).toLocaleString(),
179
+ temperature: limitedTemp[i],
180
+ windSpeed: limitedWind[i],
181
+ humidity: limitedHumidity[i],
182
+ }))
183
+ )
184
+ .build()
185
+ )
164
186
  .build(),
165
187
  };
166
188
  },
@@ -177,14 +199,14 @@ const dainService = defineDAINService({
177
199
  logo: "https://cdn-icons-png.flaticon.com/512/252/252035.png",
178
200
  },
179
201
  exampleQueries: [
180
- {
181
- category: "Weather",
182
- queries: [
183
- "What is the weather in Tokyo?",
184
- "What is the weather in San Francisco?",
185
- "What is the weather in London?",
186
- ],
187
- }
202
+ {
203
+ category: "Weather",
204
+ queries: [
205
+ "What is the weather in Tokyo?",
206
+ "What is the weather in San Francisco?",
207
+ "What is the weather in London?",
208
+ ],
209
+ },
188
210
  ],
189
211
  identity: {
190
212
  apiKey: process.env.DAIN_API_KEY,
@@ -192,6 +214,6 @@ const dainService = defineDAINService({
192
214
  tools: [getWeatherConfig, getWeatherForecastConfig],
193
215
  });
194
216
 
195
- dainService.startNode({ port: 2022 }).then(() => {
196
- console.log("Weather DAIN Service is running on port 2022");
217
+ dainService.startNode().then(({ address }) => {
218
+ console.log("Weather DAIN Service is running at :" + address().port);
197
219
  });
package/dist/utils.js CHANGED
@@ -40,6 +40,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
40
40
  };
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.getDainConfig = getDainConfig;
43
+ exports.displayTunnelUrl = displayTunnelUrl;
43
44
  exports.setupProxy = setupProxy;
44
45
  exports.logError = logError;
45
46
  exports.logSuccess = logSuccess;
@@ -62,7 +63,7 @@ function loadEnvFiles() {
62
63
  });
63
64
  }
64
65
  function getDainConfig(configFile) {
65
- loadEnvFiles(); // Load environment variables from files
66
+ loadEnvFiles(); // Loads all env files first
66
67
  var defaultConfigPath = path_1.default.join(process.cwd(), 'dain.json');
67
68
  var configPath = configFile
68
69
  ? path_1.default.join(process.cwd(), configFile)
@@ -101,6 +102,15 @@ function getDainConfig(configFile) {
101
102
  throw new Error("Error reading or parsing configuration file: ".concat(error));
102
103
  }
103
104
  }
105
+ function displayTunnelUrl(tunnelUrl) {
106
+ var divider = chalk_1.default.green('------------------------------------------------------------');
107
+ var header = chalk_1.default.green('Your service is available publicly at:');
108
+ var url = chalk_1.default.cyan.underline(tunnelUrl);
109
+ var info = chalk_1.default.yellow('This service URL can be connected to by a DAIN client or assistant');
110
+ var subInfo = chalk_1.default.yellow('(such as butterfly in development mode)');
111
+ var warning = chalk_1.default.red('You should not visit this URL directly');
112
+ console.log("\n".concat(divider, "\n").concat(header, "\n").concat(url, "\n\n").concat(info, "\n").concat(subInfo, "\n\n").concat(warning, "\n").concat(divider, "\n"));
113
+ }
104
114
  function setupProxy(port, apiKey, config) {
105
115
  return __awaiter(this, void 0, void 0, function () {
106
116
  var spinner, client, tunnelUrl, error_1;
@@ -115,15 +125,14 @@ function setupProxy(port, apiKey, config) {
115
125
  return [4 /*yield*/, client.start(parseInt(port))];
116
126
  case 2:
117
127
  tunnelUrl = _a.sent();
118
- spinner.succeed(chalk_1.default.green("\n------------------------------------------------------------\nYour service is available publicly at: ") +
119
- chalk_1.default.cyan.underline("".concat(tunnelUrl)) +
120
- chalk_1.default.green("\n------------------------------------------------------------\n"));
121
- return [2 /*return*/, client];
128
+ spinner.succeed('Proxy setup complete');
129
+ displayTunnelUrl(tunnelUrl);
130
+ return [2 /*return*/, { client: client, tunnelUrl: tunnelUrl }];
122
131
  case 3:
123
132
  error_1 = _a.sent();
124
- spinner.fail(chalk_1.default.red('\nError setting up proxy'));
133
+ spinner.fail(chalk_1.default.red('Error setting up proxy'));
125
134
  console.error(chalk_1.default.red(error_1));
126
- return [3 /*break*/, 4];
135
+ throw error_1;
127
136
  case 4: return [2 /*return*/];
128
137
  }
129
138
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dainprotocol/cli",
3
- "version": "1.1.21",
3
+ "version": "1.1.27",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -10,8 +10,8 @@
10
10
  "deploy": "dain deploy"
11
11
  },
12
12
  "dependencies": {
13
- "@dainprotocol/service-sdk": "^1.0.93",
14
- "@dainprotocol/utils": "^0.0.48",
13
+ "@dainprotocol/service-sdk": "^1.0.95",
14
+ "@dainprotocol/utils": "^0.0.49",
15
15
  "zod": "^3.23.8",
16
16
  "hono": "^4.6.3",
17
17
  "ts-node": "^10.4.0",
@@ -19,6 +19,6 @@
19
19
  "@types/express": "^4.17.13",
20
20
  "@types/node": "^22.5.4",
21
21
  "axios": "^1.7.5",
22
- "@dainprotocol/cli": "^1.0.31"
22
+ "@dainprotocol/cli": "^1.1.26"
23
23
  }
24
24
  }
@@ -3,20 +3,22 @@
3
3
  import { z } from "zod";
4
4
  import axios from "axios";
5
5
 
6
- import {
7
- defineDAINService,
8
- ToolConfig,
9
- } from "@dainprotocol/service-sdk";
6
+ import { defineDAINService, ToolConfig } from "@dainprotocol/service-sdk";
10
7
 
11
- import { CardUIBuilder, TableUIBuilder, MapUIBuilder } from "@dainprotocol/utils";
8
+ import {
9
+ CardUIBuilder,
10
+ TableUIBuilder,
11
+ MapUIBuilder,
12
+ LayoutUIBuilder,
13
+ } from "@dainprotocol/utils";
12
14
 
13
15
  const getWeatherEmoji = (temperature: number): string => {
14
- if (temperature <= 0) return '🥶';
15
- if (temperature <= 10) return '❄️';
16
- if (temperature <= 20) return '';
17
- if (temperature <= 25) return '☀️';
18
- if (temperature <= 30) return '🌞';
19
- return '🔥';
16
+ if (temperature <= 0) return "🥶";
17
+ if (temperature <= 10) return "❄️";
18
+ if (temperature <= 20) return "";
19
+ if (temperature <= 25) return "☀️";
20
+ if (temperature <= 30) return "🌞";
21
+ return "🔥";
20
22
  };
21
23
 
22
24
  const getWeatherConfig: ToolConfig = {
@@ -37,12 +39,15 @@ const getWeatherConfig: ToolConfig = {
37
39
  })
38
40
  .describe("Current weather information"),
39
41
  pricing: { pricePerUse: 0, currency: "USD" },
40
- handler: async ({ locationName, latitude, longitude }, agentInfo, context) => {
42
+ handler: async (
43
+ { locationName, latitude, longitude },
44
+ agentInfo,
45
+ context
46
+ ) => {
41
47
  console.log(
42
48
  `User / Agent ${agentInfo.id} requested weather at ${locationName} (${latitude},${longitude})`
43
49
  );
44
50
 
45
-
46
51
  const response = await axios.get(
47
52
  `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,wind_speed_10m`
48
53
  );
@@ -59,20 +64,24 @@ const getWeatherConfig: ToolConfig = {
59
64
  ui: new CardUIBuilder()
60
65
  .setRenderMode("page")
61
66
  .title(`Current Weather in ${locationName} ${weatherEmoji}`)
62
- .addChild(new MapUIBuilder()
63
- .setInitialView(latitude, longitude, 10)
64
- .setMapStyle('mapbox://styles/mapbox/streets-v12')
65
- .addMarkers([
66
- {
67
- latitude,
68
- longitude,
69
- title: locationName,
70
- description: `Temperature: ${temperature_2m}°C\nWind: ${wind_speed_10m} km/h`,
71
- text: `${locationName} ${weatherEmoji}`,
72
- }
73
- ])
74
- .build())
75
- .content(`Temperature: ${temperature_2m}°C\nWind Speed: ${wind_speed_10m} km/h`)
67
+ .addChild(
68
+ new MapUIBuilder()
69
+ .setInitialView(latitude, longitude, 10)
70
+ .setMapStyle("mapbox://styles/mapbox/streets-v12")
71
+ .addMarkers([
72
+ {
73
+ latitude,
74
+ longitude,
75
+ title: locationName,
76
+ description: `Temperature: ${temperature_2m}°C\nWind: ${wind_speed_10m} km/h`,
77
+ text: `${locationName} ${weatherEmoji}`,
78
+ },
79
+ ])
80
+ .build()
81
+ )
82
+ .content(
83
+ `Temperature: ${temperature_2m}°C\nWind Speed: ${wind_speed_10m} km/h`
84
+ )
76
85
  .build(),
77
86
  };
78
87
  },
@@ -102,12 +111,15 @@ const getWeatherForecastConfig: ToolConfig = {
102
111
  })
103
112
  .describe("Hourly weather forecast"),
104
113
  pricing: { pricePerUse: 0, currency: "USD" },
105
- handler: async ({ locationName, latitude, longitude }, agentInfo, context) => {
114
+ handler: async (
115
+ { locationName, latitude, longitude },
116
+ agentInfo,
117
+ context
118
+ ) => {
106
119
  console.log(
107
120
  `User / Agent ${agentInfo.id} requested forecast at ${locationName} (${latitude},${longitude})`
108
121
  );
109
122
 
110
-
111
123
  const response = await axios.get(
112
124
  `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&hourly=temperature_2m,relative_humidity_2m,wind_speed_10m`
113
125
  );
@@ -131,36 +143,46 @@ const getWeatherForecastConfig: ToolConfig = {
131
143
  windSpeeds: limitedWind,
132
144
  humidity: limitedHumidity,
133
145
  },
134
- ui: new CardUIBuilder()
146
+ ui: new LayoutUIBuilder()
135
147
  .setRenderMode("page")
136
- .title(`Weather Forecast for ${locationName} ${weatherEmoji}`)
137
- .addChild(new MapUIBuilder()
138
- .setInitialView(latitude, longitude, 10)
139
- .setMapStyle('mapbox://styles/mapbox/streets-v12')
140
- .addMarkers([
141
- {
142
- latitude,
143
- longitude,
144
- title: locationName,
145
- description: `Temperature: ${limitedTemp[0]}°C\nWind: ${limitedWind[0]} km/h`,
146
- text: `${locationName} ${weatherEmoji}`,
147
- }
148
- ])
149
- .build())
150
- .addChild(new TableUIBuilder()
151
- .addColumns([
152
- { key: 'time', header: 'Time', type: 'string' },
153
- { key: 'temperature', header: 'Temperature (°C)', type: 'number' },
154
- { key: 'windSpeed', header: 'Wind Speed (km/h)', type: 'number' },
155
- { key: 'humidity', header: 'Humidity (%)', type: 'number' },
156
- ])
157
- .rows(limitedTime.map((t: string, i: number) => ({
158
- time: new Date(t).toLocaleString(),
159
- temperature: limitedTemp[i],
160
- windSpeed: limitedWind[i],
161
- humidity: limitedHumidity[i],
162
- })))
163
- .build())
148
+ .setLayoutType("column")
149
+ .addChild(
150
+ new MapUIBuilder()
151
+ .setInitialView(latitude, longitude, 10)
152
+ .setMapStyle("mapbox://styles/mapbox/streets-v12")
153
+ .addMarkers([
154
+ {
155
+ latitude,
156
+ longitude,
157
+ title: locationName,
158
+ description: `Temperature: ${limitedTemp[0]}°C\nWind: ${limitedWind[0]} km/h`,
159
+ text: `${locationName} ${weatherEmoji}`,
160
+ },
161
+ ])
162
+ .build()
163
+ )
164
+ .addChild(
165
+ new TableUIBuilder()
166
+ .addColumns([
167
+ { key: "time", header: "Time", type: "string" },
168
+ {
169
+ key: "temperature",
170
+ header: "Temperature (°C)",
171
+ type: "number",
172
+ },
173
+ { key: "windSpeed", header: "Wind Speed (km/h)", type: "number" },
174
+ { key: "humidity", header: "Humidity (%)", type: "number" },
175
+ ])
176
+ .rows(
177
+ limitedTime.map((t: string, i: number) => ({
178
+ time: new Date(t).toLocaleString(),
179
+ temperature: limitedTemp[i],
180
+ windSpeed: limitedWind[i],
181
+ humidity: limitedHumidity[i],
182
+ }))
183
+ )
184
+ .build()
185
+ )
164
186
  .build(),
165
187
  };
166
188
  },
@@ -177,14 +199,14 @@ const dainService = defineDAINService({
177
199
  logo: "https://cdn-icons-png.flaticon.com/512/252/252035.png",
178
200
  },
179
201
  exampleQueries: [
180
- {
181
- category: "Weather",
182
- queries: [
183
- "What is the weather in Tokyo?",
184
- "What is the weather in San Francisco?",
185
- "What is the weather in London?",
186
- ],
187
- }
202
+ {
203
+ category: "Weather",
204
+ queries: [
205
+ "What is the weather in Tokyo?",
206
+ "What is the weather in San Francisco?",
207
+ "What is the weather in London?",
208
+ ],
209
+ },
188
210
  ],
189
211
  identity: {
190
212
  apiKey: process.env.DAIN_API_KEY,
@@ -192,6 +214,6 @@ const dainService = defineDAINService({
192
214
  tools: [getWeatherConfig, getWeatherForecastConfig],
193
215
  });
194
216
 
195
- dainService.startNode({ port: 2022 }).then(() => {
196
- console.log("Weather DAIN Service is running on port 2022");
217
+ dainService.startNode().then(({ address }) => {
218
+ console.log("Weather DAIN Service is running at :" + address().port);
197
219
  });