@toothfairyai/cli 1.0.7 β†’ 1.0.9

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.
Files changed (2) hide show
  1. package/bin/toothfairy.js +158 -64
  2. package/package.json +1 -1
package/bin/toothfairy.js CHANGED
@@ -244,18 +244,51 @@ program
244
244
  let finalResponse = null;
245
245
  let processingStatus = null;
246
246
 
247
- const formatStatusMessage = (status) => {
248
- const statusMessages = {
249
- connected: 'πŸ”— Connected to streaming server',
250
- init: 'πŸš€ Initializing agent...',
251
- initial_setup_completed: 'βœ… Agent setup completed',
252
- tools_processing_completed: 'πŸ› οΈ Tools processing finished',
253
- replying: 'πŸ’­ Agent is thinking and responding...',
254
- updating_memory: 'πŸ’Ύ Updating conversation memory...',
255
- memory_updated: 'βœ… Memory updated successfully',
256
- complete: 'πŸŽ‰ Response complete!',
257
- };
258
- return statusMessages[status] || `πŸ“Š Status: ${status}`;
247
+ const mapStateWithLabel = (state) => {
248
+ switch (state) {
249
+ case 'data_processing_completed':
250
+ return 'πŸ“Š **Retrieving data**';
251
+ case 'tools_processing_completed':
252
+ return 'πŸ› οΈ **Choosing tools**';
253
+ case 'replying':
254
+ return '🧚 **Responding**';
255
+ case 'main_generation_completed':
256
+ return '✨ **Generation completed**';
257
+ case 'memory_updated':
258
+ return 'πŸ’Ύ Memory updated';
259
+ case 'updating_memory':
260
+ return 'πŸ’Ύ Updating memory...';
261
+ case 'init':
262
+ return 'πŸš€ Initializing...';
263
+ case 'initial_setup_completed':
264
+ return 'βœ… Setup completed';
265
+ case 'image_analysis_in_progress':
266
+ return 'πŸ–ΌοΈ Analyzing image...';
267
+ case 'video_analysis_in_progress':
268
+ return 'πŸŽ₯ Analyzing video...';
269
+ case 'audio_analysis_in_progress':
270
+ return '🎡 Analyzing audio...';
271
+ case 'image_generation_in_progress':
272
+ return '🎨 Generating image...';
273
+ case 'video_generation_in_progress':
274
+ return '🎬 Generating video...';
275
+ case '3D_model_generation_in_progress':
276
+ return 'πŸ—οΈ Creating 3D model...';
277
+ case 'code_generation_in_progress':
278
+ return 'πŸ’» Generating code...';
279
+ case 'code_execution_in_progress':
280
+ return '⚑ Executing code...';
281
+ case 'internet_search_in_progress':
282
+ return 'πŸ” Searching internet...';
283
+ case 'planning_in_progress':
284
+ return 'πŸ—ΊοΈ Planning response...';
285
+ case 'handed_off_to_human':
286
+ return 'πŸ‘€ Handed off to human';
287
+ case 'completed':
288
+ return 'πŸŽ‰ Completed';
289
+ default:
290
+ return `πŸ“Š ${state}`;
291
+ }
259
292
  };
260
293
 
261
294
  if (options.output === 'json') {
@@ -287,18 +320,22 @@ program
287
320
  // Text mode: show live streaming
288
321
  let currentSpinner = null;
289
322
 
290
- // Function to update display
291
- const updateDisplay = (text, type = 'response') => {
323
+ // Function to update display with status filtering
324
+ const updateDisplay = (text, agentStatus, messageId, type = 'response') => {
292
325
  if (currentSpinner) {
293
326
  currentSpinner.stop();
294
327
  currentSpinner = null;
295
328
  }
296
329
 
297
- // Clear previous lines if we're updating the same response
298
- if (text && type === 'response') {
299
- // For real-time streaming, we overwrite the current line
300
- process.stdout.write('\r\x1b[K'); // Clear current line
301
- process.stdout.write(chalk.green('🧚 Response: ') + text);
330
+ // Only show text when agent is actually replying
331
+ if (text && type === 'response' && agentStatus === 'replying') {
332
+ // Check if text is actually new/different
333
+ if (text !== currentText) {
334
+ // For real-time streaming, we overwrite the current line
335
+ process.stdout.write('\r\x1b[K'); // Clear current line
336
+ process.stdout.write(chalk.green('🧚 Response: ') + text.trim());
337
+ currentText = text;
338
+ }
302
339
  }
303
340
  };
304
341
 
@@ -324,52 +361,90 @@ program
324
361
  );
325
362
  }
326
363
 
327
- if (eventType === 'status') {
328
- if (eventData.status === 'connected') {
329
- if (options.showProgress) {
330
- console.log(
331
- chalk.green('πŸ”— Connected to streaming server')
332
- );
333
- }
334
- } else if (eventData.status === 'complete') {
335
- if (options.showProgress) {
336
- console.log(
337
- chalk.green('\nπŸŽ‰ Stream completed successfully!')
338
- );
364
+ // Handle connection status events
365
+ if (eventData.status === 'connected') {
366
+ if (options.showProgress) {
367
+ console.log(chalk.green('πŸ”— Connected to streaming server'));
368
+ }
369
+ return;
370
+ }
371
+
372
+ if (eventData.status === 'complete') {
373
+ if (options.showProgress) {
374
+ console.log(chalk.green('\nπŸŽ‰ Stream completed successfully!'));
375
+ }
376
+ return;
377
+ }
378
+
379
+ // Handle message events
380
+ if (eventData.type === 'message') {
381
+ let metadata = {};
382
+ let agentStatus = null;
383
+
384
+ // Parse metadata if available
385
+ if (eventData.metadata) {
386
+ try {
387
+ metadata = JSON.parse(eventData.metadata);
388
+ agentStatus = metadata.agent_processing_status;
389
+ } catch (e) {
390
+ // Metadata parsing failed, continue without it
339
391
  }
340
392
  }
341
- } else if (eventType === 'progress') {
342
- // Agent processing status updates
343
- const newStatus = eventData.processing_status;
344
- if (newStatus && newStatus !== processingStatus) {
345
- processingStatus = newStatus;
393
+
394
+ // Handle status changes
395
+ if (agentStatus && agentStatus !== processingStatus) {
396
+ processingStatus = agentStatus;
346
397
  if (options.showProgress) {
347
- const statusMsg = formatStatusMessage(processingStatus);
398
+ const statusMsg = mapStateWithLabel(processingStatus);
348
399
  if (currentSpinner) {
349
400
  currentSpinner.stop();
350
401
  }
351
402
  currentSpinner = ora(chalk.yellow(statusMsg)).start();
352
403
  }
353
404
  }
354
- } else if (eventType === 'data') {
355
- // Streaming text data
356
- if (eventData.text) {
357
- currentText = eventData.text;
358
- updateDisplay(currentText.trim());
405
+
406
+ // Handle progressive text streaming
407
+ if (eventData.text && agentStatus === 'replying') {
408
+ updateDisplay(
409
+ eventData.text,
410
+ agentStatus,
411
+ eventData.message_id,
412
+ 'response'
413
+ );
359
414
  }
360
- } else if (eventType === 'complete') {
361
- // Final response with all metadata
362
- finalResponse = eventData;
363
- if (currentText) {
364
- // Ensure we have a clean final display - just add the final emoji
365
- if (currentSpinner) {
366
- currentSpinner.stop();
367
- currentSpinner = null;
415
+
416
+ // Handle fulfilled status (final response)
417
+ if (eventData.status === 'fulfilled') {
418
+ finalResponse = eventData;
419
+ if (currentText) {
420
+ // Clean final display with magic wand emoji
421
+ if (currentSpinner) {
422
+ currentSpinner.stop();
423
+ currentSpinner = null;
424
+ }
425
+ process.stdout.write('\r\x1b[K'); // Clear current line
426
+ process.stdout.write(chalk.blue('πŸͺ„ ') + currentText.trim());
368
427
  }
369
- process.stdout.write('\r\x1b[K'); // Clear current line
370
- process.stdout.write(chalk.blue('πŸͺ„ ') + currentText.trim());
371
428
  }
372
- } else if (eventType === 'error') {
429
+
430
+ // Handle additional metadata events (images, files, callback metadata)
431
+ if (eventData.images !== undefined || eventData.files !== undefined) {
432
+ // These are attachment events - could show notification if needed
433
+ if (options.verbose) {
434
+ console.log(chalk.dim('\nπŸ“Ž Attachments processed'));
435
+ }
436
+ }
437
+
438
+ if (eventData.callbackMetadata) {
439
+ // Function execution metadata
440
+ if (options.verbose) {
441
+ console.log(chalk.dim('\nβš™οΈ Function execution metadata received'));
442
+ }
443
+ }
444
+ }
445
+
446
+ // Handle errors
447
+ if (eventType === 'error') {
373
448
  const errorMsg = eventData.message || 'Unknown streaming error';
374
449
  if (currentSpinner) {
375
450
  currentSpinner.stop();
@@ -389,19 +464,38 @@ program
389
464
 
390
465
  if (options.verbose && finalResponse) {
391
466
  // Show final response metadata in verbose mode
392
- console.log(chalk.cyan.bold('πŸ“Š Final Response Metadata'));
393
- console.log('─'.repeat(40));
394
-
395
- if (finalResponse.metadata_parsed) {
396
- const metadata = finalResponse.metadata_parsed;
397
- for (const [key, value] of Object.entries(metadata)) {
398
- if (key !== 'agent_processing_status') {
399
- // Already shown during streaming
400
- console.log(chalk.cyan(`${key}:`), String(value));
467
+ console.log(chalk.cyan.bold('\nπŸ“Š Final Response Metadata'));
468
+ console.log('─'.repeat(50));
469
+
470
+ // Parse and display metadata from the final response
471
+ if (finalResponse.metadata) {
472
+ try {
473
+ const metadata = JSON.parse(finalResponse.metadata);
474
+ for (const [key, value] of Object.entries(metadata)) {
475
+ if (key === 'agent_processing_status') {
476
+ console.log(chalk.cyan(`${key}:`), chalk.green(value));
477
+ } else if (key === 'duration') {
478
+ console.log(chalk.cyan(`${key}:`), chalk.yellow(`${value}s`));
479
+ } else if (key === 'sources' && Array.isArray(value)) {
480
+ console.log(chalk.cyan(`${key}:`), value.length > 0 ? value.join(', ') : 'None');
481
+ } else {
482
+ console.log(chalk.cyan(`${key}:`), String(value));
483
+ }
401
484
  }
485
+ } catch (e) {
486
+ console.log(chalk.red('Could not parse metadata'));
402
487
  }
403
488
  }
404
- console.log('─'.repeat(40));
489
+
490
+ // Show additional response fields
491
+ if (finalResponse.message_id) {
492
+ console.log(chalk.cyan('message_id:'), finalResponse.message_id);
493
+ }
494
+ if (finalResponse.t_text_summary) {
495
+ console.log(chalk.cyan('summary:'), finalResponse.t_text_summary);
496
+ }
497
+
498
+ console.log('─'.repeat(50));
405
499
  }
406
500
 
407
501
  if (!currentText) {
@@ -683,7 +777,7 @@ program
683
777
  program
684
778
  .command('config-show')
685
779
  .description('Show current configuration')
686
- .action(async (options, command) => {
780
+ .action(async (command) => {
687
781
  try {
688
782
  const globalOptions = command.parent.opts();
689
783
  const config = loadConfig(globalOptions.config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toothfairyai/cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Command-line interface for ToothFairy AI API",
5
5
  "main": "index.js",
6
6
  "bin": {