@toothfairyai/cli 1.0.14 → 1.0.15

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/bin/toothfairy.js CHANGED
@@ -114,6 +114,10 @@ program
114
114
  .option("--customer-id <id>", "Customer ID")
115
115
  .option("--provider-id <id>", "SMS provider ID")
116
116
  .option("--customer-info <json>", "Customer info as JSON string")
117
+ .option("--image <path>", "Path to image file (png, jpg, jpeg, gif, bmp, svg)")
118
+ .option("--audio <path>", "Path to audio file (wav, mp3, aac, ogg, flac)")
119
+ .option("--video <path>", "Path to video file (mp4, avi, mov, wmv, flv, webm)")
120
+ .option("--file <path...>", "Path to document files (max 5)")
117
121
  .option("-o, --output <format>", "Output format (json|text)", "text")
118
122
  .option("-v, --verbose", "Show detailed response information")
119
123
  .action(async (message, options, command) => {
@@ -137,12 +141,27 @@ program
137
141
  try {
138
142
  customerInfo = JSON.parse(options.customerInfo);
139
143
  } catch (error) {
140
- console.error(chalk.red("Invalid JSON in customer-info"));
144
+ console.error(chalk.red('Invalid JSON in customer-info'));
141
145
  process.exit(1);
142
146
  }
143
147
  }
144
148
 
145
- const spinner = ora("Sending message to agent...").start();
149
+ // Process file attachments if provided
150
+ const attachments = {};
151
+ if (options.image) {
152
+ attachments.images = [options.image];
153
+ }
154
+ if (options.audio) {
155
+ attachments.audios = [options.audio];
156
+ }
157
+ if (options.video) {
158
+ attachments.videos = [options.video];
159
+ }
160
+ if (options.file) {
161
+ attachments.files = Array.isArray(options.file) ? options.file : [options.file];
162
+ }
163
+
164
+ const spinner = ora('Sending message to agent...').start();
146
165
 
147
166
  const response = await api.sendMessageToAgent(
148
167
  message,
@@ -150,7 +169,8 @@ program
150
169
  options.phoneNumber,
151
170
  options.customerId,
152
171
  options.providerId,
153
- customerInfo
172
+ customerInfo,
173
+ attachments
154
174
  );
155
175
 
156
176
  spinner.stop();
@@ -221,6 +241,10 @@ program
221
241
  .option("--customer-id <id>", "Customer ID")
222
242
  .option("--provider-id <id>", "SMS provider ID")
223
243
  .option("--customer-info <json>", "Customer info as JSON string")
244
+ .option('--image <path>', 'Path to image file (PNG, max 1)')
245
+ .option('--audio <path>', 'Path to audio file (WAV, max 1)')
246
+ .option('--video <path>', 'Path to video file (MP4, max 1)')
247
+ .option('--file <path>', 'Path to file (max 5, can be used multiple times)', (value, previous) => previous.concat([value]), [])
224
248
  .option("-o, --output <format>", "Output format (json|text)", "text")
225
249
  .option("-v, --verbose", "Show detailed streaming information")
226
250
  .option("--show-progress", "Show agent processing status updates")
@@ -270,6 +294,21 @@ program
270
294
  }
271
295
  }
272
296
 
297
+ // Process file attachments if provided
298
+ const attachments = {};
299
+ if (options.image) {
300
+ attachments.images = [options.image];
301
+ }
302
+ if (options.audio) {
303
+ attachments.audios = [options.audio];
304
+ }
305
+ if (options.video) {
306
+ attachments.videos = [options.video];
307
+ }
308
+ if (options.file) {
309
+ attachments.files = Array.isArray(options.file) ? options.file : [options.file];
310
+ }
311
+
273
312
  console.log(
274
313
  chalk.cyan(`Streaming message to agent ${options.agentId}...`)
275
314
  );
@@ -341,6 +380,7 @@ program
341
380
  options.customerId,
342
381
  options.providerId,
343
382
  customerInfo,
383
+ attachments,
344
384
  (eventType, eventData) => {
345
385
  allEvents.push({ event_type: eventType, event_data: eventData });
346
386
 
@@ -399,6 +439,7 @@ program
399
439
  options.customerId,
400
440
  options.providerId,
401
441
  customerInfo,
442
+ attachments,
402
443
  (eventType, eventData) => {
403
444
  if (options.verbose) {
404
445
  // Verbose mode: show all event details
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toothfairyai/cli",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "Command-line interface for ToothFairyAI API",
5
5
  "main": "index.js",
6
6
  "bin": {
package/src/api.js CHANGED
@@ -184,7 +184,8 @@ class ToothFairyAPI {
184
184
  phoneNumber = null,
185
185
  customerId = null,
186
186
  providerId = null,
187
- customerInfo = {}
187
+ customerInfo = {},
188
+ attachments = {}
188
189
  ) {
189
190
  try {
190
191
  // Use defaults for optional parameters
@@ -192,14 +193,17 @@ class ToothFairyAPI {
192
193
  customerId ||
193
194
  `cli-user-${
194
195
  Math.abs(
195
- message.split("").reduce((a, b) => {
196
+ message.split('').reduce((a, b) => {
196
197
  a = (a << 5) - a + b.charCodeAt(0);
197
198
  return a & a;
198
199
  }, 0)
199
200
  ) % 10000
200
201
  }`;
201
- phoneNumber = phoneNumber || "+1234567890";
202
- providerId = providerId || "default-sms-provider";
202
+ phoneNumber = phoneNumber || '+1234567890';
203
+ providerId = providerId || 'default-sms-provider';
204
+
205
+ // Process file attachments if provided
206
+ const processedAttachments = await this._processAttachments(attachments);
203
207
 
204
208
  const chatData = {
205
209
  name: customerId,
@@ -223,8 +227,9 @@ class ToothFairyAPI {
223
227
  const messageData = {
224
228
  chatID: createdChat.id,
225
229
  text: message,
226
- role: "user",
227
- userID: "CLI",
230
+ role: 'user',
231
+ userID: 'CLI',
232
+ ...processedAttachments,
228
233
  };
229
234
  const createdMessage = await this.createMessage(messageData);
230
235
  // console.log(`Message created: ${createdMessage.id}`);;
@@ -329,7 +334,8 @@ class ToothFairyAPI {
329
334
  customerId = null,
330
335
  providerId = null,
331
336
  customerInfo = {},
332
- onEvent
337
+ onEvent,
338
+ attachments = {}
333
339
  ) {
334
340
  try {
335
341
  // Use defaults for optional parameters
@@ -337,14 +343,17 @@ class ToothFairyAPI {
337
343
  customerId ||
338
344
  `cli-user-${
339
345
  Math.abs(
340
- message.split("").reduce((a, b) => {
346
+ message.split('').reduce((a, b) => {
341
347
  a = (a << 5) - a + b.charCodeAt(0);
342
348
  return a & a;
343
349
  }, 0)
344
350
  ) % 10000
345
351
  }`;
346
- phoneNumber = phoneNumber || "+1234567890";
347
- providerId = providerId || "default-sms-provider";
352
+ phoneNumber = phoneNumber || '+1234567890';
353
+ providerId = providerId || 'default-sms-provider';
354
+
355
+ // Process file attachments if provided
356
+ const processedAttachments = await this._processAttachments(attachments);
348
357
 
349
358
  // Create chat first
350
359
  const chatData = {
@@ -372,8 +381,9 @@ class ToothFairyAPI {
372
381
  const messageData = {
373
382
  chatID: createdChat.id,
374
383
  text: message,
375
- role: "user",
376
- userID: "CLI",
384
+ role: 'user',
385
+ userID: 'CLI',
386
+ ...processedAttachments,
377
387
  };
378
388
  const createdMessage = await this.createMessage(messageData);
379
389
  if (this.verbose) {
@@ -1676,6 +1686,92 @@ class ToothFairyAPI {
1676
1686
  throw error;
1677
1687
  }
1678
1688
  }
1689
+
1690
+ /**
1691
+ * Process file attachments and upload them for message inclusion
1692
+ *
1693
+ * @param {Object} attachments - Attachment configuration
1694
+ * @param {string[]} attachments.images - Array of image file paths (max 1)
1695
+ * @param {string[]} attachments.audios - Array of audio file paths (max 1)
1696
+ * @param {string[]} attachments.videos - Array of video file paths (max 1)
1697
+ * @param {string[]} attachments.files - Array of document file paths (max 5)
1698
+ * @returns {Promise<Object>} - Processed attachment data for message creation
1699
+ */
1700
+ async _processAttachments(attachments = {}) {
1701
+ const result = {};
1702
+
1703
+ if (!attachments || Object.keys(attachments).length === 0) {
1704
+ return result;
1705
+ }
1706
+
1707
+ try {
1708
+ // Validate attachment limits
1709
+ if (attachments.images && attachments.images.length > 1) {
1710
+ throw new Error('Maximum 1 image attachment allowed');
1711
+ }
1712
+ if (attachments.audios && attachments.audios.length > 1) {
1713
+ throw new Error('Maximum 1 audio attachment allowed');
1714
+ }
1715
+ if (attachments.videos && attachments.videos.length > 1) {
1716
+ throw new Error('Maximum 1 video attachment allowed');
1717
+ }
1718
+ if (attachments.files && attachments.files.length > 5) {
1719
+ throw new Error('Maximum 5 file attachments allowed');
1720
+ }
1721
+
1722
+ // Process images
1723
+ if (attachments.images && attachments.images.length > 0) {
1724
+ const imageResults = [];
1725
+ for (const imagePath of attachments.images) {
1726
+ const uploadResult = await this.uploadFile(imagePath, this.workspaceId);
1727
+ imageResults.push(uploadResult.filename);
1728
+ }
1729
+ result.images = imageResults;
1730
+ }
1731
+
1732
+ // Process audios
1733
+ if (attachments.audios && attachments.audios.length > 0) {
1734
+ const audioResults = [];
1735
+ for (const audioPath of attachments.audios) {
1736
+ const uploadResult = await this.uploadFile(audioPath, this.workspaceId);
1737
+ audioResults.push(uploadResult.filename);
1738
+ }
1739
+ result.audios = audioResults;
1740
+ }
1741
+
1742
+ // Process videos
1743
+ if (attachments.videos && attachments.videos.length > 0) {
1744
+ const videoResults = [];
1745
+ for (const videoPath of attachments.videos) {
1746
+ const uploadResult = await this.uploadFile(videoPath, this.workspaceId);
1747
+ videoResults.push(uploadResult.filename);
1748
+ }
1749
+ result.videos = videoResults;
1750
+ }
1751
+
1752
+ // Process files
1753
+ if (attachments.files && attachments.files.length > 0) {
1754
+ const fileResults = [];
1755
+ for (const filePath of attachments.files) {
1756
+ const uploadResult = await this.uploadFile(filePath, this.workspaceId);
1757
+ fileResults.push(uploadResult.filename);
1758
+ }
1759
+ result.files = fileResults;
1760
+ }
1761
+
1762
+ if (this.verbose) {
1763
+ const chalk = require('chalk');
1764
+ console.error(chalk.dim('\n--- Processed Attachments ---'));
1765
+ console.error(chalk.dim(`Result: ${JSON.stringify(result, null, 2)}`));
1766
+ console.error(chalk.dim('-----------------------------\n'));
1767
+ }
1768
+
1769
+ return result;
1770
+ } catch (error) {
1771
+ console.error(`Error processing attachments: ${error.message}`);
1772
+ throw error;
1773
+ }
1774
+ }
1679
1775
  }
1680
1776
 
1681
1777
  module.exports = ToothFairyAPI;