@@ -10,6 +10,7 @@ import {
10
10
type UUID ,
11
11
truncateToCompleteSentence ,
12
12
parseJSONObjectFromText ,
13
+ extractAttributes ,
13
14
} from "@elizaos/core" ;
14
15
import { elizaLogger } from "@elizaos/core" ;
15
16
import type { ClientBase } from "./base.ts" ;
@@ -463,6 +464,22 @@ export class TwitterPostClient {
463
464
}
464
465
}
465
466
467
+ /**
468
+ * Cleans a JSON-like response string by removing unnecessary markers, line breaks, and extra whitespace.
469
+ * This is useful for handling improperly formatted JSON responses from external sources.
470
+ *
471
+ * @param response - The raw JSON-like string response to clean.
472
+ * @returns The cleaned string, ready for parsing or further processing.
473
+ */
474
+
475
+ cleanJsonResponse ( response : string ) : string {
476
+ return response
477
+ . replace ( / ` ` ` j s o n \s * / g, "" ) // Remove ```json
478
+ . replace ( / ` ` ` \s * / g, "" ) // Remove any remaining ```
479
+ . replace ( / ( \r \n | \n | \r ) / g, "" ) // Remove line breaks
480
+ . trim ( ) ;
481
+ }
482
+
466
483
/**
467
484
* Generates and posts a new tweet. If isDryRun is true, only logs what would have been posted.
468
485
*/
@@ -512,11 +529,7 @@ export class TwitterPostClient {
512
529
modelClass : ModelClass . SMALL ,
513
530
} ) ;
514
531
515
- const newTweetContent = response
516
- . replace ( / ` ` ` j s o n \s * / g, "" ) // Remove ```json
517
- . replace ( / ` ` ` \s * / g, "" ) // Remove any remaining ```
518
- . replace ( / ( \r \n | \n | \r ) / g, "" ) // Remove line break
519
- . trim ( ) ;
532
+ const newTweetContent = this . cleanJsonResponse ( response ) ;
520
533
521
534
// First attempt to clean content
522
535
let cleanedContent = "" ;
@@ -544,6 +557,13 @@ export class TwitterPostClient {
544
557
. trim ( ) ;
545
558
}
546
559
560
+ if ( ! cleanedContent ) {
561
+ cleanedContent = truncateToCompleteSentence (
562
+ extractAttributes ( newTweetContent , [ "text" ] ) . text ,
563
+ this . client . twitterConfig . MAX_TWEET_LENGTH ,
564
+ ) ;
565
+ }
566
+
547
567
if ( ! cleanedContent ) {
548
568
elizaLogger . error (
549
569
"Failed to extract valid content from response:" ,
@@ -634,25 +654,29 @@ export class TwitterPostClient {
634
654
elizaLogger . log ( "generate tweet content response:\n" + response ) ;
635
655
636
656
// First clean up any markdown and newlines
637
- const cleanedResponse = response
638
- . replace ( / ` ` ` j s o n \s * / g, "" ) // Remove ```json
639
- . replace ( / ` ` ` \s * / g, "" ) // Remove any remaining ```
640
- . replace ( / ( \r \n | \n | \r ) / g, "" ) // Remove line break
641
- . trim ( ) ;
657
+ const cleanedResponse = this . cleanJsonResponse ( response ) ;
642
658
643
659
// Try to parse as JSON first
644
660
try {
645
661
const jsonResponse = parseJSONObjectFromText ( cleanedResponse ) ;
646
662
if ( jsonResponse . text ) {
647
- return this . trimTweetLength ( jsonResponse . text ) ;
663
+ const truncateContent = truncateToCompleteSentence (
664
+ jsonResponse . text ,
665
+ this . client . twitterConfig . MAX_TWEET_LENGTH ,
666
+ ) ;
667
+ return truncateContent ;
648
668
}
649
669
if ( typeof jsonResponse === "object" ) {
650
670
const possibleContent =
651
671
jsonResponse . content ||
652
672
jsonResponse . message ||
653
673
jsonResponse . response ;
654
674
if ( possibleContent ) {
655
- return this . trimTweetLength ( possibleContent ) ;
675
+ const truncateContent = truncateToCompleteSentence (
676
+ possibleContent ,
677
+ this . client . twitterConfig . MAX_TWEET_LENGTH ,
678
+ ) ;
679
+ return truncateContent ;
656
680
}
657
681
}
658
682
} catch ( error ) {
@@ -664,24 +688,21 @@ export class TwitterPostClient {
664
688
response ,
665
689
) ;
666
690
}
667
- // If not JSON or no valid content found, clean the raw text
668
- return this . trimTweetLength ( cleanedResponse ) ;
669
- }
670
691
671
- // Helper method to ensure tweet length compliance
672
- private trimTweetLength ( text : string , maxLength = 280 ) : string {
673
- if ( text . length <= maxLength ) return text ;
692
+ let truncateContent = truncateToCompleteSentence (
693
+ extractAttributes ( cleanedResponse , [ "text" ] ) . text ,
694
+ this . client . twitterConfig . MAX_TWEET_LENGTH ,
695
+ ) ;
674
696
675
- // Try to cut at last sentence
676
- const lastSentence = text . slice ( 0 , maxLength ) . lastIndexOf ( "." ) ;
677
- if ( lastSentence > 0 ) {
678
- return text . slice ( 0 , lastSentence + 1 ) . trim ( ) ;
697
+ if ( ! truncateContent ) {
698
+ // If not JSON or no valid content found, clean the raw text
699
+ truncateContent = truncateToCompleteSentence (
700
+ cleanedResponse ,
701
+ this . client . twitterConfig . MAX_TWEET_LENGTH ,
702
+ ) ;
679
703
}
680
704
681
- // Fallback to word boundary
682
- return (
683
- text . slice ( 0 , text . lastIndexOf ( " " , maxLength - 3 ) ) . trim ( ) + "..."
684
- ) ;
705
+ return truncateContent ;
685
706
}
686
707
687
708
/**
0 commit comments