1
+ import { elizaLogger } from "@elizaos/core" ;
2
+ import {
3
+ Action ,
4
+ HandlerCallback ,
5
+ IAgentRuntime ,
6
+ Memory ,
7
+ State ,
8
+ } from "@elizaos/core" ;
9
+ import { generateWebSearch } from "@elizaos/core" ;
10
+ import { SearchResult } from "@elizaos/core" ;
11
+ import { encodingForModel , TiktokenModel } from "js-tiktoken" ;
12
+
13
+ const DEFAULT_MAX_WEB_SEARCH_TOKENS = 4000 ;
14
+ const DEFAULT_MODEL_ENCODING = "gpt-3.5-turbo" ;
15
+
16
+ function getTotalTokensFromString (
17
+ str : string ,
18
+ encodingName : TiktokenModel = DEFAULT_MODEL_ENCODING
19
+ ) {
20
+ const encoding = encodingForModel ( encodingName ) ;
21
+ return encoding . encode ( str ) . length ;
22
+ }
23
+
24
+ function MaxTokens (
25
+ data : string ,
26
+ maxTokens : number = DEFAULT_MAX_WEB_SEARCH_TOKENS
27
+ ) : string {
28
+ if ( getTotalTokensFromString ( data ) >= maxTokens ) {
29
+ return data . slice ( 0 , maxTokens ) ;
30
+ }
31
+ return data ;
32
+ }
33
+
34
+ export const webSearch : Action = {
35
+ name : "WEB_SEARCH" ,
36
+ similes : [
37
+ "SEARCH_WEB" ,
38
+ "INTERNET_SEARCH" ,
39
+ "LOOKUP" ,
40
+ "QUERY_WEB" ,
41
+ "FIND_ONLINE" ,
42
+ "SEARCH_ENGINE" ,
43
+ "WEB_LOOKUP" ,
44
+ "ONLINE_SEARCH" ,
45
+ "FIND_INFORMATION" ,
46
+ ] ,
47
+ description :
48
+ "Perform a web search to find information related to the message." ,
49
+ validate : async ( runtime : IAgentRuntime , message : Memory ) => {
50
+ const tavilyApiKeyOk = ! ! runtime . getSetting ( "TAVILY_API_KEY" ) ;
51
+
52
+ return tavilyApiKeyOk ;
53
+ } ,
54
+ handler : async (
55
+ runtime : IAgentRuntime ,
56
+ message : Memory ,
57
+ state : State ,
58
+ options : any ,
59
+ callback : HandlerCallback
60
+ ) => {
61
+ elizaLogger . log ( "Composing state for message:" , message ) ;
62
+ state = ( await runtime . composeState ( message ) ) as State ;
63
+ const userId = runtime . agentId ;
64
+ elizaLogger . log ( "User ID:" , userId ) ;
65
+
66
+ const webSearchPrompt = message . content . text ;
67
+ elizaLogger . log ( "web search prompt received:" , webSearchPrompt ) ;
68
+
69
+ elizaLogger . log ( "Generating image with prompt:" , webSearchPrompt ) ;
70
+ const searchResponse = await generateWebSearch (
71
+ webSearchPrompt ,
72
+ runtime
73
+ ) ;
74
+
75
+ if ( searchResponse && searchResponse . results . length ) {
76
+ const responseList = searchResponse . answer
77
+ ? `${ searchResponse . answer } ${
78
+ Array . isArray ( searchResponse . results ) &&
79
+ searchResponse . results . length > 0
80
+ ? `\n\nFor more details, you can check out these resources:\n${ searchResponse . results
81
+ . map (
82
+ ( result : SearchResult , index : number ) =>
83
+ `${ index + 1 } . [${ result . title } ](${ result . url } )`
84
+ )
85
+ . join ( "\n" ) } `
86
+ : ""
87
+ } `
88
+ : "" ;
89
+
90
+ callback ( {
91
+ text : MaxTokens ( responseList , DEFAULT_MAX_WEB_SEARCH_TOKENS ) ,
92
+ } ) ;
93
+ } else {
94
+ elizaLogger . error ( "search failed or returned no data." ) ;
95
+ }
96
+ } ,
97
+ examples : [
98
+ [
99
+ {
100
+ user : "{{user1}}" ,
101
+ content : {
102
+ text : "Find the latest news about SpaceX launches." ,
103
+ } ,
104
+ } ,
105
+ {
106
+ user : "{{agentName}}" ,
107
+ content : {
108
+ text : "Here is the latest news about SpaceX launches:" ,
109
+ action : "WEB_SEARCH" ,
110
+ } ,
111
+ } ,
112
+ ] ,
113
+ [
114
+ {
115
+ user : "{{user1}}" ,
116
+ content : {
117
+ text : "Can you find details about the iPhone 16 release?" ,
118
+ } ,
119
+ } ,
120
+ {
121
+ user : "{{agentName}}" ,
122
+ content : {
123
+ text : "Here are the details I found about the iPhone 16 release:" ,
124
+ action : "WEB_SEARCH" ,
125
+ } ,
126
+ } ,
127
+ ] ,
128
+ [
129
+ {
130
+ user : "{{user1}}" ,
131
+ content : {
132
+ text : "What is the schedule for the next FIFA World Cup?" ,
133
+ } ,
134
+ } ,
135
+ {
136
+ user : "{{agentName}}" ,
137
+ content : {
138
+ text : "Here is the schedule for the next FIFA World Cup:" ,
139
+ action : "WEB_SEARCH" ,
140
+ } ,
141
+ } ,
142
+ ] ,
143
+ [
144
+ {
145
+ user : "{{user1}}" ,
146
+ content : { text : "Check the latest stock price of Tesla." } ,
147
+ } ,
148
+ {
149
+ user : "{{agentName}}" ,
150
+ content : {
151
+ text : "Here is the latest stock price of Tesla I found:" ,
152
+ action : "WEB_SEARCH" ,
153
+ } ,
154
+ } ,
155
+ ] ,
156
+ [
157
+ {
158
+ user : "{{user1}}" ,
159
+ content : {
160
+ text : "What are the current trending movies in the US?" ,
161
+ } ,
162
+ } ,
163
+ {
164
+ user : "{{agentName}}" ,
165
+ content : {
166
+ text : "Here are the current trending movies in the US:" ,
167
+ action : "WEB_SEARCH" ,
168
+ } ,
169
+ } ,
170
+ ] ,
171
+ [
172
+ {
173
+ user : "{{user1}}" ,
174
+ content : {
175
+ text : "What is the latest score in the NBA finals?" ,
176
+ } ,
177
+ } ,
178
+ {
179
+ user : "{{agentName}}" ,
180
+ content : {
181
+ text : "Here is the latest score from the NBA finals:" ,
182
+ action : "WEB_SEARCH" ,
183
+ } ,
184
+ } ,
185
+ ] ,
186
+ [
187
+ {
188
+ user : "{{user1}}" ,
189
+ content : { text : "When is the next Apple keynote event?" } ,
190
+ } ,
191
+ {
192
+ user : "{{agentName}}" ,
193
+ content : {
194
+ text : "Here is the information about the next Apple keynote event:" ,
195
+ action : "WEB_SEARCH" ,
196
+ } ,
197
+ } ,
198
+ ] ,
199
+ ] ,
200
+ } as Action ;
0 commit comments