@toothfairyai/cli 1.1.5 → 1.4.0
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/README.md +352 -123
- package/bin/toothfairy.js +636 -72
- package/package.json +7 -5
- package/src/api.js +62 -15
- package/src/config.js +7 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toothfairyai/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Command-line interface for ToothFairyAI API",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -37,18 +37,20 @@
|
|
|
37
37
|
},
|
|
38
38
|
"homepage": "https://gitea.toothfairyai.com/ToothFairyAI/tooth-fairy-website/toothfairy-cli#readme",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"commander": "^9.4.1",
|
|
41
40
|
"axios": "^1.4.0",
|
|
42
41
|
"chalk": "^4.1.2",
|
|
42
|
+
"commander": "^9.4.1",
|
|
43
43
|
"dotenv": "^16.0.3",
|
|
44
|
+
"eventsource": "^2.0.2",
|
|
45
|
+
"glob": "^10.3.0",
|
|
44
46
|
"js-yaml": "^4.1.0",
|
|
45
47
|
"ora": "^5.4.1",
|
|
46
|
-
"table": "^6.8.1"
|
|
47
|
-
"eventsource": "^2.0.2"
|
|
48
|
+
"table": "^6.8.1"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"eslint": "^8.32.0",
|
|
51
|
-
"jest": "^29.3.1"
|
|
52
|
+
"jest": "^29.3.1",
|
|
53
|
+
"typescript": "^5.9.3"
|
|
52
54
|
},
|
|
53
55
|
"engines": {
|
|
54
56
|
"node": ">=14.0.0"
|
package/src/api.js
CHANGED
|
@@ -367,6 +367,8 @@ class ToothFairyAPI {
|
|
|
367
367
|
* @param {Function} onEvent - Callback function called for each event
|
|
368
368
|
* @param {Object} attachments - File attachments (images, audios, videos, files)
|
|
369
369
|
* @param {boolean} showProgress - Show all progress events from SSE endpoint (default: false)
|
|
370
|
+
* @param {string|null} chatId - Existing chat ID to continue conversation (default: null, creates new chat)
|
|
371
|
+
* @param {boolean} rawStream - Enable raw streaming mode for chunk-by-chunk output (default: false)
|
|
370
372
|
* @returns {Promise<void>} - Promise resolves when streaming is complete
|
|
371
373
|
*
|
|
372
374
|
* Event Types Explained:
|
|
@@ -399,7 +401,8 @@ class ToothFairyAPI {
|
|
|
399
401
|
onEvent,
|
|
400
402
|
attachments = {},
|
|
401
403
|
showProgress = false,
|
|
402
|
-
chatId = null
|
|
404
|
+
chatId = null,
|
|
405
|
+
rawStream = false
|
|
403
406
|
) {
|
|
404
407
|
try {
|
|
405
408
|
// Use defaults for optional parameters
|
|
@@ -463,6 +466,7 @@ class ToothFairyAPI {
|
|
|
463
466
|
chatid: chatId,
|
|
464
467
|
messages: [messageData],
|
|
465
468
|
agentid: agentId,
|
|
469
|
+
raw_stream: rawStream,
|
|
466
470
|
};
|
|
467
471
|
|
|
468
472
|
// Stream the agent response using the dedicated streaming URL
|
|
@@ -511,7 +515,14 @@ class ToothFairyAPI {
|
|
|
511
515
|
}
|
|
512
516
|
|
|
513
517
|
// Standard event processing (always executed for backward compatibility)
|
|
514
|
-
|
|
518
|
+
// Handle raw_stream token events (streaming text chunks)
|
|
519
|
+
if (eventData.type === 'token' && eventData.chunk !== undefined) {
|
|
520
|
+
// Token streaming event - emit as 'data' with text field for compatibility
|
|
521
|
+
onEvent('data', {
|
|
522
|
+
...eventData,
|
|
523
|
+
text: eventData.chunk,
|
|
524
|
+
});
|
|
525
|
+
} else if (eventData.status) {
|
|
515
526
|
if (eventData.status === 'connected') {
|
|
516
527
|
onEvent('status', eventData);
|
|
517
528
|
} else if (eventData.status === 'complete') {
|
|
@@ -520,10 +531,15 @@ class ToothFairyAPI {
|
|
|
520
531
|
// Parse metadata to understand what's happening
|
|
521
532
|
let metadata = {};
|
|
522
533
|
if (eventData.metadata) {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
534
|
+
// metadata can be an object or a JSON string
|
|
535
|
+
if (typeof eventData.metadata === 'object') {
|
|
536
|
+
metadata = eventData.metadata;
|
|
537
|
+
} else {
|
|
538
|
+
try {
|
|
539
|
+
metadata = JSON.parse(eventData.metadata);
|
|
540
|
+
} catch (e) {
|
|
541
|
+
metadata = { raw_metadata: eventData.metadata };
|
|
542
|
+
}
|
|
527
543
|
}
|
|
528
544
|
}
|
|
529
545
|
|
|
@@ -550,8 +566,17 @@ class ToothFairyAPI {
|
|
|
550
566
|
eventData.text &&
|
|
551
567
|
eventData.type === 'message'
|
|
552
568
|
) {
|
|
553
|
-
// This is streaming text data
|
|
569
|
+
// This is streaming text data (non-raw_stream mode)
|
|
554
570
|
onEvent('data', eventData);
|
|
571
|
+
} else if (
|
|
572
|
+
eventData.type === 'message' &&
|
|
573
|
+
eventData.chat_created === true
|
|
574
|
+
) {
|
|
575
|
+
// Chat creation event from raw_stream mode
|
|
576
|
+
onEvent('chat_created', {
|
|
577
|
+
...eventData,
|
|
578
|
+
chatId: eventData.chatid,
|
|
579
|
+
});
|
|
555
580
|
} else if (
|
|
556
581
|
eventData.type === 'message' &&
|
|
557
582
|
eventData.images !== undefined
|
|
@@ -568,7 +593,7 @@ class ToothFairyAPI {
|
|
|
568
593
|
eventData.type === 'chat_created' ||
|
|
569
594
|
eventData.event === 'chat_created'
|
|
570
595
|
) {
|
|
571
|
-
// Chat creation event
|
|
596
|
+
// Chat creation event (legacy format)
|
|
572
597
|
onEvent('chat_created', eventData);
|
|
573
598
|
} else {
|
|
574
599
|
// Generic event data
|
|
@@ -660,6 +685,7 @@ class ToothFairyAPI {
|
|
|
660
685
|
customerId: customerId,
|
|
661
686
|
providerId: providerId,
|
|
662
687
|
customerInfo: customerInfo,
|
|
688
|
+
raw_stream: rawStream,
|
|
663
689
|
};
|
|
664
690
|
|
|
665
691
|
// Stream the agent response using the dedicated streaming URL
|
|
@@ -708,7 +734,14 @@ class ToothFairyAPI {
|
|
|
708
734
|
}
|
|
709
735
|
|
|
710
736
|
// Standard event processing (always executed for backward compatibility)
|
|
711
|
-
|
|
737
|
+
// Handle raw_stream token events (streaming text chunks)
|
|
738
|
+
if (eventData.type === 'token' && eventData.chunk !== undefined) {
|
|
739
|
+
// Token streaming event - emit as 'data' with text field for compatibility
|
|
740
|
+
onEvent('data', {
|
|
741
|
+
...eventData,
|
|
742
|
+
text: eventData.chunk,
|
|
743
|
+
});
|
|
744
|
+
} else if (eventData.status) {
|
|
712
745
|
if (eventData.status === 'connected') {
|
|
713
746
|
onEvent('status', eventData);
|
|
714
747
|
} else if (eventData.status === 'complete') {
|
|
@@ -717,10 +750,15 @@ class ToothFairyAPI {
|
|
|
717
750
|
// Parse metadata to understand what's happening
|
|
718
751
|
let metadata = {};
|
|
719
752
|
if (eventData.metadata) {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
753
|
+
// metadata can be an object or a JSON string
|
|
754
|
+
if (typeof eventData.metadata === 'object') {
|
|
755
|
+
metadata = eventData.metadata;
|
|
756
|
+
} else {
|
|
757
|
+
try {
|
|
758
|
+
metadata = JSON.parse(eventData.metadata);
|
|
759
|
+
} catch (e) {
|
|
760
|
+
metadata = { raw_metadata: eventData.metadata };
|
|
761
|
+
}
|
|
724
762
|
}
|
|
725
763
|
}
|
|
726
764
|
|
|
@@ -747,8 +785,17 @@ class ToothFairyAPI {
|
|
|
747
785
|
eventData.text &&
|
|
748
786
|
eventData.type === 'message'
|
|
749
787
|
) {
|
|
750
|
-
// This is streaming text data
|
|
788
|
+
// This is streaming text data (non-raw_stream mode)
|
|
751
789
|
onEvent('data', eventData);
|
|
790
|
+
} else if (
|
|
791
|
+
eventData.type === 'message' &&
|
|
792
|
+
eventData.chat_created === true
|
|
793
|
+
) {
|
|
794
|
+
// Chat creation event from raw_stream mode
|
|
795
|
+
onEvent('chat_created', {
|
|
796
|
+
...eventData,
|
|
797
|
+
chatId: eventData.chatid,
|
|
798
|
+
});
|
|
752
799
|
} else if (
|
|
753
800
|
eventData.type === 'message' &&
|
|
754
801
|
eventData.images !== undefined
|
|
@@ -765,7 +812,7 @@ class ToothFairyAPI {
|
|
|
765
812
|
eventData.type === 'chat_created' ||
|
|
766
813
|
eventData.event === 'chat_created'
|
|
767
814
|
) {
|
|
768
|
-
// Chat creation event
|
|
815
|
+
// Chat creation event (legacy format)
|
|
769
816
|
onEvent('chat_created', eventData);
|
|
770
817
|
} else {
|
|
771
818
|
// Generic event data
|
package/src/config.js
CHANGED
|
@@ -4,13 +4,14 @@ const os = require('os');
|
|
|
4
4
|
const yaml = require('js-yaml');
|
|
5
5
|
|
|
6
6
|
class ToothFairyConfig {
|
|
7
|
-
constructor(baseUrl, aiUrl, aiStreamUrl, apiKey, workspaceId, userId) {
|
|
7
|
+
constructor(baseUrl, aiUrl, aiStreamUrl, apiKey, workspaceId, userId, defaultAgentId = '') {
|
|
8
8
|
this.baseUrl = baseUrl;
|
|
9
9
|
this.aiUrl = aiUrl;
|
|
10
10
|
this.aiStreamUrl = aiStreamUrl;
|
|
11
11
|
this.apiKey = apiKey;
|
|
12
12
|
this.workspaceId = workspaceId;
|
|
13
13
|
this.userId = userId;
|
|
14
|
+
this.defaultAgentId = defaultAgentId;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
static fromEnv() {
|
|
@@ -20,7 +21,8 @@ class ToothFairyConfig {
|
|
|
20
21
|
process.env.TF_AI_STREAM_URL || 'https://ais.toothfairyai.com',
|
|
21
22
|
process.env.TF_API_KEY || '',
|
|
22
23
|
process.env.TF_WORKSPACE_ID || '',
|
|
23
|
-
process.env.TF_USER_ID || ''
|
|
24
|
+
process.env.TF_USER_ID || '',
|
|
25
|
+
process.env.TF_DEFAULT_AGENT_ID || ''
|
|
24
26
|
);
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -44,7 +46,8 @@ class ToothFairyConfig {
|
|
|
44
46
|
data.ai_stream_url || 'https://ais.toothfairyai.com',
|
|
45
47
|
data.api_key || '',
|
|
46
48
|
data.workspace_id || '',
|
|
47
|
-
data.user_id || ''
|
|
49
|
+
data.user_id || '',
|
|
50
|
+
data.default_agent_id || ''
|
|
48
51
|
);
|
|
49
52
|
}
|
|
50
53
|
|
|
@@ -64,6 +67,7 @@ class ToothFairyConfig {
|
|
|
64
67
|
api_key: this.apiKey,
|
|
65
68
|
workspace_id: this.workspaceId,
|
|
66
69
|
user_id: this.userId,
|
|
70
|
+
default_agent_id: this.defaultAgentId,
|
|
67
71
|
};
|
|
68
72
|
}
|
|
69
73
|
}
|