1
1
import { parseBooleanFromText , IAgentRuntime } from "@elizaos/core" ;
2
- import { z } from "zod" ;
2
+ import { z , ZodError } from "zod" ;
3
+
3
4
export const DEFAULT_MAX_TWEET_LENGTH = 280 ;
4
5
5
6
const twitterUsernameSchema = z . string ( )
6
7
. min ( 1 )
7
8
. max ( 15 )
8
- . regex ( / ^ [ A - Z a - z ] [ A - Z a - z 0 - 9 _ ] * [ A - Z a - z 0 - 9 ] $ | ^ [ A - Z a - z ] $ / , 'Invalid Twitter username format' ) ;
9
+ . regex (
10
+ / ^ [ A - Z a - z ] [ A - Z a - z 0 - 9 _ ] * [ A - Z a - z 0 - 9 ] $ | ^ [ A - Z a - z ] $ / ,
11
+ "Invalid Twitter username format"
12
+ ) ;
9
13
14
+ /**
15
+ * This schema defines all required/optional environment settings,
16
+ * including new fields like TWITTER_SPACES_ENABLE.
17
+ */
10
18
export const twitterEnvSchema = z . object ( {
11
19
TWITTER_DRY_RUN : z . boolean ( ) ,
12
20
TWITTER_USERNAME : z . string ( ) . min ( 1 , "Twitter username is required" ) ,
@@ -51,25 +59,23 @@ export const twitterEnvSchema = z.object({
51
59
ENABLE_ACTION_PROCESSING : z . boolean ( ) ,
52
60
ACTION_INTERVAL : z . number ( ) . int ( ) ,
53
61
POST_IMMEDIATELY : z . boolean ( ) ,
62
+ TWITTER_SPACES_ENABLE : z . boolean ( ) . default ( false ) ,
54
63
} ) ;
55
64
56
65
export type TwitterConfig = z . infer < typeof twitterEnvSchema > ;
57
66
58
- function parseTargetUsers ( targetUsersStr ?:string | null ) : string [ ] {
67
+ /**
68
+ * Helper to parse a comma-separated list of Twitter usernames
69
+ * (already present in your code).
70
+ */
71
+ function parseTargetUsers ( targetUsersStr ?: string | null ) : string [ ] {
59
72
if ( ! targetUsersStr ?. trim ( ) ) {
60
73
return [ ] ;
61
74
}
62
-
63
75
return targetUsersStr
64
- . split ( ',' )
65
- . map ( user => user . trim ( ) )
66
- . filter ( Boolean ) ; // Remove empty usernames
67
- /*
68
- .filter(user => {
69
- // Twitter username validation (basic example)
70
- return user && /^[A-Za-z0-9_]{1,15}$/.test(user);
71
- });
72
- */
76
+ . split ( "," )
77
+ . map ( ( user ) => user . trim ( ) )
78
+ . filter ( Boolean ) ;
73
79
}
74
80
75
81
function safeParseInt ( value : string | undefined | null , defaultValue : number ) : number {
@@ -78,94 +84,115 @@ function safeParseInt(value: string | undefined | null, defaultValue: number): n
78
84
return isNaN ( parsed ) ? defaultValue : Math . max ( 1 , parsed ) ;
79
85
}
80
86
81
- // This also is organized to serve as a point of documentation for the client
82
- // most of the inputs from the framework (env/character)
83
-
84
- // we also do a lot of typing/parsing here
85
- // so we can do it once and only once per character
86
- export async function validateTwitterConfig (
87
- runtime : IAgentRuntime
88
- ) : Promise < TwitterConfig > {
87
+ /**
88
+ * Validates or constructs a TwitterConfig object using zod,
89
+ * taking values from the IAgentRuntime or process.env as needed.
90
+ */
91
+ export async function validateTwitterConfig ( runtime : IAgentRuntime ) : Promise < TwitterConfig > {
89
92
try {
90
93
const twitterConfig = {
91
94
TWITTER_DRY_RUN :
92
95
parseBooleanFromText (
93
96
runtime . getSetting ( "TWITTER_DRY_RUN" ) ||
94
97
process . env . TWITTER_DRY_RUN
95
98
) ?? false , // parseBooleanFromText return null if "", map "" to false
99
+
96
100
TWITTER_USERNAME :
97
- runtime . getSetting ( "TWITTER_USERNAME" ) ||
101
+ runtime . getSetting ( "TWITTER_USERNAME" ) ||
98
102
process . env . TWITTER_USERNAME ,
103
+
99
104
TWITTER_PASSWORD :
100
105
runtime . getSetting ( "TWITTER_PASSWORD" ) ||
101
106
process . env . TWITTER_PASSWORD ,
107
+
102
108
TWITTER_EMAIL :
103
109
runtime . getSetting ( "TWITTER_EMAIL" ) ||
104
110
process . env . TWITTER_EMAIL ,
105
- MAX_TWEET_LENGTH : // number as string?
111
+
112
+ MAX_TWEET_LENGTH :
106
113
safeParseInt (
107
114
runtime . getSetting ( "MAX_TWEET_LENGTH" ) ||
108
- process . env . MAX_TWEET_LENGTH
109
- , DEFAULT_MAX_TWEET_LENGTH ) ,
110
- TWITTER_SEARCH_ENABLE : // bool
115
+ process . env . MAX_TWEET_LENGTH ,
116
+ DEFAULT_MAX_TWEET_LENGTH
117
+ ) ,
118
+
119
+ TWITTER_SEARCH_ENABLE :
111
120
parseBooleanFromText (
112
121
runtime . getSetting ( "TWITTER_SEARCH_ENABLE" ) ||
113
122
process . env . TWITTER_SEARCH_ENABLE
114
123
) ?? false ,
115
- TWITTER_2FA_SECRET : // string passthru
124
+
125
+ TWITTER_2FA_SECRET :
116
126
runtime . getSetting ( "TWITTER_2FA_SECRET" ) ||
117
127
process . env . TWITTER_2FA_SECRET || "" ,
118
- TWITTER_RETRY_LIMIT : // int
128
+
129
+ TWITTER_RETRY_LIMIT :
119
130
safeParseInt (
120
131
runtime . getSetting ( "TWITTER_RETRY_LIMIT" ) ||
121
- process . env . TWITTER_RETRY_LIMIT
122
- , 5 ) ,
123
- TWITTER_POLL_INTERVAL : // int in seconds
132
+ process . env . TWITTER_RETRY_LIMIT ,
133
+ 5
134
+ ) ,
135
+
136
+ TWITTER_POLL_INTERVAL :
124
137
safeParseInt (
125
138
runtime . getSetting ( "TWITTER_POLL_INTERVAL" ) ||
126
- process . env . TWITTER_POLL_INTERVAL
127
- , 120 ) , // 2m
128
- TWITTER_TARGET_USERS : // comma separated string
139
+ process . env . TWITTER_POLL_INTERVAL ,
140
+ 120
141
+ ) ,
142
+
143
+ TWITTER_TARGET_USERS :
129
144
parseTargetUsers (
130
145
runtime . getSetting ( "TWITTER_TARGET_USERS" ) ||
131
146
process . env . TWITTER_TARGET_USERS
132
147
) ,
133
- POST_INTERVAL_MIN : // int in minutes
148
+
149
+ POST_INTERVAL_MIN :
134
150
safeParseInt (
135
151
runtime . getSetting ( "POST_INTERVAL_MIN" ) ||
136
- process . env . POST_INTERVAL_MIN
137
- , 90 ) , // 1.5 hours
138
- POST_INTERVAL_MAX : // int in minutes
152
+ process . env . POST_INTERVAL_MIN ,
153
+ 90
154
+ ) ,
155
+
156
+ POST_INTERVAL_MAX :
139
157
safeParseInt (
140
158
runtime . getSetting ( "POST_INTERVAL_MAX" ) ||
141
- process . env . POST_INTERVAL_MAX
142
- , 180 ) , // 3 hours
143
- ENABLE_ACTION_PROCESSING : // bool
159
+ process . env . POST_INTERVAL_MAX ,
160
+ 180
161
+ ) ,
162
+
163
+ ENABLE_ACTION_PROCESSING :
144
164
parseBooleanFromText (
145
165
runtime . getSetting ( "ENABLE_ACTION_PROCESSING" ) ||
146
166
process . env . ENABLE_ACTION_PROCESSING
147
167
) ?? false ,
148
- ACTION_INTERVAL : // int in minutes (min 1m)
168
+
169
+ ACTION_INTERVAL :
149
170
safeParseInt (
150
171
runtime . getSetting ( "ACTION_INTERVAL" ) ||
151
- process . env . ACTION_INTERVAL
152
- , 5 ) , // 5 minutes
153
- POST_IMMEDIATELY : // bool
172
+ process . env . ACTION_INTERVAL ,
173
+ 5
174
+ ) ,
175
+
176
+ POST_IMMEDIATELY :
154
177
parseBooleanFromText (
155
178
runtime . getSetting ( "POST_IMMEDIATELY" ) ||
156
179
process . env . POST_IMMEDIATELY
157
180
) ?? false ,
181
+
182
+ TWITTER_SPACES_ENABLE :
183
+ parseBooleanFromText (
184
+ runtime . getSetting ( "TWITTER_SPACES_ENABLE" ) ||
185
+ process . env . TWITTER_SPACES_ENABLE
186
+ ) ?? false ,
158
187
} ;
159
188
160
189
return twitterEnvSchema . parse ( twitterConfig ) ;
161
190
} catch ( error ) {
162
- if ( error instanceof z . ZodError ) {
191
+ if ( error instanceof ZodError ) {
163
192
const errorMessages = error . errors
164
193
. map ( ( err ) => `${ err . path . join ( "." ) } : ${ err . message } ` )
165
194
. join ( "\n" ) ;
166
- throw new Error (
167
- `Twitter configuration validation failed:\n${ errorMessages } `
168
- ) ;
195
+ throw new Error ( `Twitter configuration validation failed:\n${ errorMessages } ` ) ;
169
196
}
170
197
throw error ;
171
198
}
0 commit comments