@@ -7,9 +7,11 @@ import {
7
7
Memory ,
8
8
State ,
9
9
UUID ,
10
+ ModelClass ,
10
11
} from "../core/types.ts" ;
11
- import { embeddingZeroVector } from "../core/memory.ts" ;
12
- import { log_to_file } from "../core/logger.ts" ;
12
+
13
+ import { composeContext } from "../core/context.ts" ;
14
+ import { generateText } from "../core/generation.ts" ;
13
15
14
16
const API_URL = "https://api.dexscreener.com" ;
15
17
@@ -52,33 +54,41 @@ interface DexScreenerResponse {
52
54
schemaVersion : string ;
53
55
pairs : TokenPair [ ] ;
54
56
}
57
+ export const cashtagHandlerTemplate = `
58
+
59
+ {{recentMessages}}
60
+
61
+ {{attachments}}
62
+
63
+ {{messageDirections}}
64
+
65
+ # Instructions: Respond with a short message max 50 words in responses the users last message - respond in PLAIN TEXT (do not use Markdown) with the asked for token information always include the Dexscreener URL and Current Market Cap unless asked otherwise` ;
55
66
56
67
/**
57
68
* Cleans a string by removing dollar signs, spaces, and converting to lowercase
58
- *
69
+ *
59
70
* @param {string } input - The string to clean
60
71
* @returns {string } The cleaned string
61
72
* @throws {Error } If input is not a string
62
- *
73
+ *
63
74
* @example
64
75
* cleanString("$Hello World$") // returns "helloworld"
65
76
* cleanString("$100.00 USD") // returns "100.00usd"
66
77
* cleanString(" MIXED case $STRING$ ") // returns "mixedcasestring"
67
78
*/
68
79
function cleanString ( input ) {
69
80
// Input validation
70
- if ( typeof input !== ' string' ) {
71
- throw new Error ( ' Input must be a string' ) ;
81
+ if ( typeof input !== " string" ) {
82
+ throw new Error ( " Input must be a string" ) ;
72
83
}
73
84
74
85
// Remove dollar signs, remove spaces, and convert to lowercase
75
86
return input
76
- . replace ( / \$ / g, '' ) // Remove all dollar signs
77
- . replace ( / \s + / g, '' ) // Remove all whitespace (spaces, tabs, newlines)
78
- . toLowerCase ( ) ; // Convert to lowercase
87
+ . replace ( / \$ / g, "" ) // Remove all dollar signs
88
+ . replace ( / \s + / g, "" ) // Remove all whitespace (spaces, tabs, newlines)
89
+ . toLowerCase ( ) ; // Convert to lowercase
79
90
}
80
91
81
-
82
92
function calculatePairScore ( pair : TokenPair ) : number {
83
93
let score = 0 ;
84
94
@@ -153,7 +163,7 @@ export const cashtags: Action = {
153
163
description :
154
164
"Searches for the best matching token pair (ca) or $cashtag ($SOL) based on age, liquidity, volume, and transaction count" ,
155
165
validate : async ( runtime : IAgentRuntime , message : Memory , state : State ) => {
156
- return true
166
+ return true ;
157
167
} ,
158
168
handler : async (
159
169
runtime : IAgentRuntime ,
@@ -165,16 +175,16 @@ export const cashtags: Action = {
165
175
const userId = runtime . agentId ;
166
176
const { roomId } = message ;
167
177
168
-
169
178
// Extract cashtag from message
170
179
const cashtag = message . content . text
171
180
. match ( / \$ [ A - Z a - z ] + / ) ?. [ 0 ]
172
181
?. replace ( "$" , "" ) ;
182
+ let responseContent ;
173
183
174
184
const callbackData : Content = {
175
185
text : undefined ,
176
186
action : "FIND_BEST_MATCH_RESPONSE" ,
177
- source : "DexScreener " ,
187
+ source : "DEXSCREENER " ,
178
188
attachments : [ ] ,
179
189
} ;
180
190
@@ -184,12 +194,16 @@ export const cashtags: Action = {
184
194
// action: "FIND_BEST_MATCH_RESPONSE",
185
195
// source: "DexScreener",
186
196
// });
187
- callbackData . text = "No cashtag found in the message. Please include a cashtag (e.g. $PNUT)" ;
188
-
197
+ callbackData . text =
198
+ "No cashtag found in the message. Please include a cashtag (e.g. $PNUT)" ;
199
+
189
200
return ;
190
201
}
191
202
192
- console . log ( `[${ roomId } ] Processing FIND_BEST_MATCH request... $` , cashtag ) ;
203
+ console . log (
204
+ `[${ roomId } ] Processing FIND_BEST_MATCH request... $` ,
205
+ cashtag
206
+ ) ;
193
207
194
208
try {
195
209
const { data : bestMatch , error } = await searchCashTags ( cashtag ) ;
@@ -199,13 +213,12 @@ export const cashtags: Action = {
199
213
// callback(callbackData);
200
214
return ;
201
215
}
202
- console . log ( bestMatch ) ;
203
216
204
217
// Format response
205
218
const responseText = `
206
219
Best match for $${ cashtag } :
207
220
Token: ${ bestMatch . baseToken . name } (${ bestMatch . baseToken . symbol } )
208
- MCAP: $${ ( bestMatch . marketCap ) . toFixed ( 2 ) } M
221
+ MCAP: $${ bestMatch . marketCap . toFixed ( 2 ) } M
209
222
Age: ${ Math . floor ( ( Date . now ( ) - bestMatch . pairCreatedAt ) / ( 1000 * 60 * 60 * 24 ) ) } days
210
223
Liquidity: $${ bestMatch . liquidity . usd . toLocaleString ( ) }
211
224
24h Volume: $${ bestMatch . volume . h24 . toLocaleString ( ) }
@@ -216,10 +229,7 @@ export const cashtags: Action = {
216
229
217
230
URL: ${ bestMatch . url } ` ;
218
231
219
- callbackData . text = `Create a reply with the token information for $${ cashtag } .
220
- Message from user - ${ message . content . text }
221
- Token information - ${ responseText }
222
- ` ;
232
+ callbackData . text = responseText ;
223
233
224
234
// Store the full response as an attachment
225
235
const attachmentId =
@@ -230,12 +240,10 @@ export const cashtags: Action = {
230
240
id : attachmentId ,
231
241
url : bestMatch . url ,
232
242
title : `Best Match for $${ cashtag } ` ,
233
- source : "DexScreener " ,
243
+ source : "DEXSCREENER " ,
234
244
description : `Token analysis for ${ bestMatch . baseToken . symbol } ` ,
235
- text : JSON . stringify ( bestMatch , null , 2 )
236
- } )
237
-
238
- // callback(callbackData);
245
+ text : JSON . stringify ( bestMatch , null , 2 ) ,
246
+ } ) ;
239
247
240
248
// Log to database
241
249
runtime . databaseAdapter . log ( {
@@ -244,30 +252,60 @@ export const cashtags: Action = {
244
252
roomId,
245
253
type : "dexscreener" ,
246
254
} ) ;
247
-
248
- // Create memory
249
- const memory = {
250
- userId,
251
- agentId : runtime . agentId ,
252
- content : callbackData ,
253
- roomId,
254
- embedding : embeddingZeroVector ,
255
- } ;
256
-
257
-
258
- await runtime . messageManager . createMemory ( memory ) ;
259
- const response = await runtime . evaluate ( message , state ) ;
260
-
261
-
262
255
} catch ( error ) {
263
256
console . error ( "Error in findBestMatch:" , error ) ;
264
257
callbackData . text = `Error processing request: ${ error . message } ` ;
265
258
callback ( callbackData ) ;
259
+ return ;
260
+ }
261
+
262
+ const memory : Memory = {
263
+ agentId : runtime . agentId ,
264
+ userId,
265
+ roomId,
266
+ content : callbackData ,
267
+ createdAt : Date . now ( ) ,
268
+ } ;
269
+
270
+ // Update state with the new memory
271
+ state = await runtime . composeState ( memory ) ;
272
+
273
+ const context = composeContext ( {
274
+ state,
275
+ template : cashtagHandlerTemplate ,
276
+ } ) ;
277
+
278
+ responseContent = await generateText ( {
279
+ runtime,
280
+ context,
281
+ modelClass : ModelClass . SMALL ,
282
+ } ) ;
283
+
284
+ if ( ! responseContent ) {
285
+ return ;
266
286
}
287
+ const agentMessage = {
288
+ userId,
289
+ roomId,
290
+ agentId : runtime . agentId ,
291
+ } ;
267
292
268
- console . log ( callbackData ) ;
269
- typeof callback === "function" && callback ( callbackData ) ;
293
+ const content = {
294
+ text : responseContent ,
295
+ action : "FIND_BEST_MATCH_RESPONSE" ,
296
+ source : "DEXSCREENER" ,
297
+ } ;
298
+
299
+ // save response to memory
300
+ const responseMessage = {
301
+ ...agentMessage ,
302
+ userId : runtime . agentId ,
303
+ content : content ,
304
+ } ;
270
305
306
+ await runtime . messageManager . createMemory ( responseMessage ) ;
307
+ callbackData . content = responseContent ;
308
+ callback ( content ) ;
271
309
return callbackData ;
272
310
} ,
273
311
examples : [
0 commit comments